Enrollment over Secure Transport for automatic certificate management
The FortiProxy supports Enrollment over Secure Transport (EST) and the RFC 7030 standards when generating a new CSR request, performing automatic renewals, or manually regenerating a certificate. EST provides more security for automatic certificate management than Simple Certificate Enrollment Protocol (SCEP), which is commonly used for certificate enrollment.
Background
SCEP helps automate and simplify the process for obtaining a digital certificate from a certificate authority (CA). However, SCEP does not natively support secure connections, and instead relies on the underlying transport protocol to provide security. EST was developed, which uses TLS to establish a secure communication channel over which subsequent certificate management protocol messages like initial certificate enroll and certificate renewal messages are exchanged.
On the FortiProxy, when generating a certificate signing request (CSR), you can use the SCEP method to send the request to an SCEP server, or use EST to send the request to an EST server to be signed by a CA.
To configure the enrollment protocol settings for a local certificate:
config vpn certificate local edit <name> set enroll-protocol est set est-server <string> set est-ca-id <string> set est-http-username <string> set est-http-password <string> set est-client-cert <certificate> set est-server-cert <certificate> set est-srp-username <string> set est-srp-password <string> next end
est-server <string> |
Enter the address and port for EST server (such as https://example.com:1234). |
est-ca-id <string> |
Enter the CA identifier of the CA server for signing with EST. |
est-http-username <string> |
Enter the HTTP Authentication username for signing with EST. |
est-http-password <string> |
Enter the HTTP Authentication password for signing with EST. |
est-client-cert <certificate> |
Enter the certificate used to authenticate this FortiProxy to the EST server. |
est-server-cert <certificate> |
Enter the EST server's certificate that has to be verifiable by the specified certificate on the FortiProxy. |
est-srp-username <string> |
Enter the EST SRP authentication username. |
est-srp-password <string> |
Enter the EST SRP authentication password. |
To manually generate a CSR for the EST server to be signed by a CA:
# execute vpn certificate local generate est {reqired_1} {reqired_2} {reqired_3} [options]
option 1 (required) |
Name of the local server certificate. |
option 2 (required) |
Cryptography algorithm: |
option 3 (required) |
URL and listening port of the remote EST responder. |
option 4 (optional) |
Server certificate subject in the certificate enroll request. Separate fields by a comma (,). |
option 5 (optional) |
Subject Alternative Name (SAN). This can be an FQDN and/or IP. Use DNS:<FQDN>,IP:<IP_address> for example. If the issuing CA does not support SAN, this option will be ignored. Separate fields by a comma (,). |
option 6 (optional) |
HTTP authentication username. |
option 7 (optional) |
HTTP authentication password. |
option 8 (optional) |
CA identifier. |
option 9 (optional) |
CA certificate used to verify the remote EST responder server certificate and certificates issued by a remote PKI. |
option 10 (optional) |
Password for the private key. |
option 11 (optional) |
Client certificate. |
option 12 (optional) |
Source IP for communications to the CA server. |
option 13 (optional) |
TLS-SRP username. |
option 14 (optional) |
TLS-SRP password. |
Example 1: enrolling for a new FortiProxy server certificate with EST
To enroll for a new FortiProxy server certificate with EST:
-
Verify that the FortiProxy can communicate with remote EST responder (testrfc7030.com):
# execute ping testrfc7030.com PING testrfc7030.com (54.70.32.33): 56 data bytes 64 bytes from 54.70.32.33: icmp_seq=0 ttl=31 time=13.6 ms 64 bytes from 54.70.32.33: icmp_seq=1 ttl=31 time=19.1 ms 64 bytes from 54.70.32.33: icmp_seq=2 ttl=31 time=16.5 ms ^C --- testrfc7030.com ping statistics --- 3 packets transmitted, 3 packets received, 0% packet loss round-trip min/avg/max = 13.6/16.4/19.1 ms
-
Start running debugs to track the progress of the enrollment:
# diagnose debug application est -1 # diagnose debug enable
-
Create a new server CSR file locally and send it to the remote EST responder:
# execute vpn certificate local generate est est-test101 ec-secp256r1 https://testrfc7030.com:8443 CN=firewall-portal1,DC=local,DC=COM DNS:firewall-portal1.local.ca,IP:172.18.60.184 estuser estpwd G_CA_Cert_1
The CA certificate (G_CA_Cert_1) is used to verify the remote EST responder server certificate and certificates issued by a remote PKI.
testrfc7030.com is a self-signed CA, which by default is not in the local trusted root store and must be imported prior to enrollment.
If the CA that issues the server certificate is not in the local root store, an error would appear in the debug messages:
# diagnose debug application est -1 # diagnose debug enable ... [1795] est_curl_req: Error buf: SSL certificate problem: self-signed certificate in certificate chain, [2402] est_simple_enroll: Failed to get ca certs: -1. ...
-
If the enrollment was successful, in a few seconds, a
Done
message appears. Verify the debugs to view the enrollment process.-
The remote CA's certificate is retrieved and stored locally in the EST configuration after being verified with the CA in the trusted root store:
[1962] __est_curl_set_auth: trace [2046] __est_curl_set_auth: HTTP Authentication username is set [2050] __est_curl_set_auth: HTTP Authentication password is set [2075] __est_get_ca_certs: ============STARTED============ [1728] est_curl_req: URL: https://testrfc7030.com:8443/.well-known/est/cacerts [1776] est_curl_req: HTTP GET [143] __curl_ssl_ctx_finalizer: global CAs are loaded. [165] __curl_ssl_ctx_finalizer: SSL_CTX ex data is set. [1651] curl_header_debug_func: Header received:HTTP/1.1 200 OK
-
The debug displays the CA used by the remote EST responder:
[1191] save_pkcs7_certs: Saving pkcs7 response [505] est_print_pkcs7: Certs: (1 in total) [507] est_print_pkcs7: Cert 1: [427] est_print_x509: Version: 3 (0x2) Serial Number: ab:e8:32:e1:f6:6a:6b:43 Issuer: CN=estExampleCA Subject: CN=estExampleCA X509v3 extensions: X509v3 Basic Constraints: CA:TRUE X509v3 Subject Key Identifier: 1A:DF:39:84:C2:56:E6:6C:CF:2A:B4:26:A5:FD:0C:D2:43:F5:3D:3E [1220] save_pkcs7_certs: Received 1 certs [1228] save_pkcs7_certs: Saving cert(s): is_global:1 est_url:https://testrfc7030.com:8443 source_ip:NULL ca_identifier:NULL
-
The CA certificate is imported. FortiProxy sends a query to learn about the attributes supported by the CA in the certificate request and will then create the CSR accordingly:
[1288] save_pkcs7_certs: CA certs imported! [2101] __est_get_csr_attrs: ============STARTED============ [1728] est_curl_req: URL: https://testrfc7030.com:8443/.well-known/est/csrattrs [1776] est_curl_req: HTTP GET [1651] curl_header_debug_func: Header received:HTTP/1.1 200 OK [1651] curl_header_debug_func: Header received:Status: 200 OK [1651] curl_header_debug_func: Header received:Content-Type: application/csrattrs [1651] curl_header_debug_func: Header received:Content-Transfer-Encoding: base64 [1651] curl_header_debug_func: Header received:Content-Length: 57 [1651] curl_header_debug_func: Header received: [1787] est_curl_req: Response 200 [1788] est_curl_req: Buffer:MCYGBysGAQEBARYGCSqGSIb3DQEJAQYFK4EEACIGCWCGSAFlAwQCAg== [1439] decode_csrattrs_callback: Decoding csrattrs, resp->len: 57 [1474] decode_csrattrs_callback: Object: 1.3.6.1.1.1.1.22 undefined [1474] decode_csrattrs_callback: Object: 1.2.840.113549.1.9.1 emailAddress [1474] decode_csrattrs_callback: Object: 1.3.132.0.34 secp384r1 [1474] decode_csrattrs_callback: Object: 2.16.840.1.101.3.4.2.2 sha384
-
The CSR information is generated, which is sent to the remote EST responder:
est_ctx: is_global:1 vfid:0 svr_original_url:https://testrfc7030.com:8443 svr_hostinfo:Exists ca_identifier:(null) http_username:estuser http_password:estpwd clt_cert:(null) svr_cert:(null) srp_username:(null) srp_password:(null) source_ip:(null) need_pop:0 newcert_name:est-test101 passwd:(null) rsa_keysize:0 ec_curvename:secp256r1 subject:CN=firewall-portal1,DC=local,DC=COM sub_alt_name:DNS:firewall-portal1.local.ca,IP:172.18.60.184 svr_cert_x509:NULL csr_attrs:Exists csr:NULL pkey:NULL header_ptr:NULL tmp_p10:NULL [2259] __est_simple_enroll: ============STARTED============
-
The CSR is sent to the EST responder:
[1728] est_curl_req: URL: https://testrfc7030.com:8443/.well-known/est/simpleenroll [1753] est_curl_req: HTTP POST [1651] curl_header_debug_func: Header received:HTTP/1.1 200 OK [1651] curl_header_debug_func: Header received:Status: 200 OK [1651] curl_header_debug_func: Header received:Content-Type: application/pkcs7-mime; smime-type=certs-only [1651] curl_header_debug_func: Header received:Content-Transfer-Encoding: base64 [1651] curl_header_debug_func: Header received:Content-Length: 585 [1651] curl_header_debug_func: Header received:
-
The CA issues the certificate and sends it back in a PKCS #7 structure:
[1787] est_curl_req: Response 200 [1788] est_curl_req: Buffer:MIIBqwYJKoZIhvcNAQcCoIIBnDCCAZgCAQExADALBgkqhkiG9w0BBwGgggGAMIIB fDCCASOgAwIBAgIDB0aXMAoGCCqGSM49BAMCMBcxFTATBgNVBAMTDGVzdEV4YW1w ...
-
The FortiProxy decodes and displays the attributes of the certificate, then saves the certificate:
[1191] save_pkcs7_certs: Saving pkcs7 response [505] est_print_pkcs7: Certs: (1 in total) [507] est_print_pkcs7: Cert 1: [427] est_print_x509: Version: 3 (0x2) Serial Number: 476823 (0x74697) Issuer: CN=estExampleCA Subject: CN=firewall-portal1 X509v3 extensions: X509v3 Basic Constraints: CA:FALSE X509v3 Key Usage: Digital Signature X509v3 Subject Key Identifier: 9B:F8:39:D5:21:E6:FF:49:FF:AC:02:57:5B:FC:4C:1A:8B:1E:5D:8F X509v3 Authority Key Identifier: 1A:DF:39:84:C2:56:E6:6C:CF:2A:B4:26:A5:FD:0C:D2:43:F5:3D:3E [1220] save_pkcs7_certs: Received 1 certs [1228] save_pkcs7_certs: Saving cert(s): is_global:1 est_url:https://testrfc7030.com:8443 source_ip:NULL ca_identifier:NULL [1246] save_pkcs7_certs: Received 1 cert(s) [427] est_print_x509: Version: 3 (0x2) Serial Number: 476823 (0x74697) Issuer: CN=estExampleCA Subject: CN=firewall-portal1 X509v3 extensions: X509v3 Basic Constraints: CA:FALSE X509v3 Key Usage: Digital Signature X509v3 Subject Key Identifier: 9B:F8:39:D5:21:E6:FF:49:FF:AC:02:57:5B:FC:4C:1A:8B:1E:5D:8F X509v3 Authority Key Identifier: 1A:DF:39:84:C2:56:E6:6C:CF:2A:B4:26:A5:FD:0C:D2:43:F5:3D:3E [827] est_cmdb_update_cert: Cert est-test101 updated in CMDB [1276] save_pkcs7_certs: The cert is saved! [592] est_ctx_clear_tmp_data: trace [2408] est_simple_enroll: POST ret:0 [592] est_ctx_clear_tmp_data: trace Done.
-
Example 2: automatically renewing a FortiProxy server certificate with EST
When the time for certificate renewal is up, the FortiProxy will use the existing EST parameters to perform an automatic renewal. This example demonstrates the renewal process through debugs.
To automatically renew a FortiProxy server certificate with EST:
-
Verify the current local certificate configuration:
config vpn certificate local (local) # get est-test101 name : est-test101 password : * comments : private-key : * certificate : Subject: CN = firewall-portal1 Issuer: CN = estExampleCA Valid from: 2023-04-06 22:37:34 GMT Valid to: 2024-04-05 22:37:34 GMT Fingerprint: AE:67:11:CF:7D:F9:57:A4:09:8B:55:0A:F1:B1:7A:CF ... state : OK range : global source : user source-ip : 0.0.0.0 ike-localid-type : asn1dn enroll-protocol : est est-server : https://testrfc7030.com:8443 est-ca-id : est-http-username : estuser est-http-password : estpwd est-client-cert : est-server-cert : est-srp-username : est-srp-password : auto-regenerate-days: 0 auto-regenerate-days-warning: 0
Note that the current
Valid to
date and time is2024-04-05 22:37:34 GMT
, which is one year from the issue date. -
Start running debugs to track the progress of the renewal:
# diagnose debug application est -1 # diagnose debug enable
-
For demonstration purposes, update the
auto-regenerate-days
setting to 364 days to trigger the automatic renewal on the FortiProxy:config vpn certificate local edit est-test101 set auto-regenerate-days 364 next end
-
Verify the debugs to confirm that the certificate was renewed.
-
The FortiProxy uses the content of the current certificate to create a new CSR. User credentials used for the initial enrollment are stored in local certificate configuration, but they are not used for renewal:
[1024] reconstruct_est_ctx: Reconstruction succeeded est_ctx: is_global:1 vfid:0 svr_original_url:https://testrfc7030.com:8443 svr_hostinfo:NULL ca_identifier: http_username:estuser http_password:estpwd clt_cert: svr_cert: srp_username: srp_password: source_ip:(null) need_pop:0 newcert_name:est-test101 passwd:f51da8548af5fef820edfe6267b0c178e76f7c3eae40ee0900318fc77ab6bd rsa_keysize:0 ec_curvename:(null) subject:(null) sub_alt_name:(null) svr_cert_x509:NULL csr_attrs:NULL csr:NULL pkey:NULL header_ptr:NULL tmp_p10:NULL
-
The FortiProxy sends the current server certificate for authentication/authorization and not the username/password used for initial enrollment:
[2453] est_simple_reenroll: Try to use est-test101 as client cert to authenticate [1962] __est_curl_set_auth: trace [2011] __est_curl_set_auth: Warning: cert est-test101 may not have the correct key usage for TLS client authentication [2014] __est_curl_set_auth: Will use cert est-test101 to prove my identity ... [1651] curl_header_debug_func: Header received: [1787] est_curl_req: Response 200 [1788] est_curl_req: Buffer:MCYGBysGAQEBARYGCSqGSIb3DQEJAQYFK4EEACIGCWCGSAFlAwQCAg== [1439] decode_csrattrs_callback: Decoding csrattrs, resp->len: 57 [1474] decode_csrattrs_callback: Object: 1.3.6.1.1.1.1.22 undefined [1474] decode_csrattrs_callback: Object: 1.2.840.113549.1.9.1 emailAddress [1474] decode_csrattrs_callback: Object: 1.3.132.0.34 secp384r1 [1474] decode_csrattrs_callback: Object: 2.16.840.1.101.3.4.2.2 sha384 est_ctx: is_global:1 vfid:0 svr_original_url:https://testrfc7030.com:8443 svr_hostinfo:Exists ca_identifier: http_username:estuser http_password:estpwd clt_cert:est-test101 svr_cert: srp_username: srp_password: source_ip:(null) need_pop:0 newcert_name:est-test101 passwd:f51da8548af5fef820edfe6267b0c178e76f7c3eae40ee0900318fc77ab6bd rsa_keysize:0 ec_curvename:(null) subject:(null) sub_alt_name:(null) svr_cert_x509:NULL csr_attrs:Exists csr:NULL pkey:NULL header_ptr:NULL tmp_p10:NULL [2274] __est_simple_reenroll: ============STARTED============
-
The CSR for renewal is successfully generated:
[965] est_generate_csr_from_cert: Successfully generated CSR for est-test101 [2200] __est_simple_post: Data to be posted: |||MIIBQDCB5gIBAjAbMRkwFwYDVQQDDBBmaXJld2FsbC1wb3J0YWwxMFkwEwYHKoZI zj0CAQYIKoZIzj0DAQcDQgAEQoJQmPedxPNUcfCyRvpqyt1oiiJX/me+TdButUSu 8hg+9nPF6+xNf+5LmtG/YKHeXyCKG6xB9OmJf255Zmx+5qBpMGcGCSqGSIb3DQEJ DjFaMFgwCQYDVR0TBAIwADALBgNVHQ8EBAMCB4AwHQYDVR0OBBYEFJv4OdUh5v9J /6wCV1v8TBqLHl2PMB8GA1UdIwQYMBaAFBrfOYTCVuZszyq0JqX9DNJD9T0+MAoG CCqGSM49BAMCA0kAMEYCIQCK3Li51F7fXsyKZwtIcYMFvDobY3cKKTTDixtN7QZ2 jwIhAKUkqfWPAzwcxQaNQw6pyYvo18ymB9aEheeIXZfGI+tV ||| [1728] est_curl_req: URL: https://testrfc7030.com:8443/.well-known/est/simplereenroll [1753] est_curl_req: HTTP POST [1651] curl_header_debug_func: Header received:HTTP/1.1 200 OK [1651] curl_header_debug_func: Header received:Status: 200 OK [1651] curl_header_debug_func: Header received:Content-Type: application/pkcs7-mime; smime-type=certs-only [1651] curl_header_debug_func: Header received:Content-Transfer-Encoding: base64 [1651] curl_header_debug_func: Header received:Content-Length: 590 [1651] curl_header_debug_func: Header received: [1787] est_curl_req: Response 200
-
The new certificate is received in PKCS #7 and is saved:
[1788] est_curl_req: Buffer:MIIBrQYJKoZIhvcNAQcCoIIBnjCCAZoCAQExADALBgkqhkiG9w0BBwGgggGCMIIB fjCCASOgAwIBAgIDB0aYMAoGCCqGSM49BAMCMBcxFTATBgNVBAMTDGVzdEV4YW1w ... [1191] save_pkcs7_certs: Saving pkcs7 response [505] est_print_pkcs7: Certs: (1 in total) ... [1220] save_pkcs7_certs: Received 1 certs [1228] save_pkcs7_certs: Saving cert(s): is_global:1 est_url:https://testrfc7030.com:8443 source_ip:NULL ca_identifier: [1246] save_pkcs7_certs: Received 1 cert(s) [427] est_print_x509: Version: 3 (0x2) Serial Number: 476824 (0x74698) Issuer: CN=estExampleCA Subject: CN=firewall-portal1 X509v3 extensions: X509v3 Basic Constraints: CA:FALSE X509v3 Key Usage: Digital Signature X509v3 Subject Key Identifier: 9B:F8:39:D5:21:E6:FF:49:FF:AC:02:57:5B:FC:4C:1A:8B:1E:5D:8F X509v3 Authority Key Identifier: 1A:DF:39:84:C2:56:E6:6C:CF:2A:B4:26:A5:FD:0C:D2:43:F5:3D:3E [827] est_cmdb_update_cert: Cert est-test101 updated in CMDB [1276] save_pkcs7_certs: The cert is saved! [592] est_ctx_clear_tmp_data: trace [2477] est_simple_reenroll: POST ret:0 [592] est_ctx_clear_tmp_data: trace
-
-
Verify the renewed local certificate configuration:
config vpn certificate local (local) # get est-test101 name : est-test101 password : * comments : private-key : * certificate : Subject: CN = firewall-portal1 Issuer: CN = estExampleCA Valid from: 2023-04-06 22:55:09 GMT Valid to: 2024-04-05 22:55:09 GMT Fingerprint: D9:51:6C:EF:04:E9:79:8D:A0:EE:10:23:4A:F4:46:B7 Root CA: No Version: 3 Serial Num: 07:46:a5 Extensions: Name: X509v3 Basic Constraints Critical: no Content:
Note that the
Valid to
date and time is now2024-04-05 22:55:09 GMT
.
Example 3: manually regenerating a local certificate with EST
Note that manually regenerating the certificate will not generate a new server key pair.
To manually regenerate a local certificate with EST:
-
Run the following command:
# execute vpn certificate local generate est est-test101 Certificate 'est-test101' already exists, re-generate will ignore all the options you have provided. Are you sure to re-generate the certificate? Do you want to continue? (y/n) y
-
Verify the debugs to confirm that the certificate was generated:
# diagnose debug application est -1 # diagnose debug enable ... [1024] reconstruct_est_ctx: Reconstruction succeeded est_ctx: is_global:1 vfid:0 svr_original_url:https://testrfc7030.com:8443 svr_hostinfo:NULL ca_identifier: http_username:estuser http_password:estpwd clt_cert: svr_cert: srp_username: srp_password: source_ip:(null) need_pop:0 newcert_name:est-test101 passwd:f51da8548af5fef820edfe6267b0c178e76f7c3eae40ee0900318fc77ab6bd rsa_keysize:0 ec_curvename:(null) subject:(null) sub_alt_name:(null) svr_cert_x509:NULL csr_attrs:NULL csr:NULL pkey:NULL header_ptr:NULL tmp_p10:NULL [2453] est_simple_reenroll: Try to use est-test101 as client cert to authenticate [1962] __est_curl_set_auth: trace ...
-
Once the certificate is saved, verify the local certificate configuration:
config vpn certificate local (local) # get est-test101 name : est-test101 password : * comments : private-key : * certificate : Subject: CN = firewall-portal1 Issuer: CN = estExampleCA Valid from: 2023-04-13 17:23:40 GMT Valid to: 2024-04-12 17:23:40 GMT Fingerprint: 4A:96:E1:73:6D:D3:64:FE:A3:A8:28:56:1D:39:05:37 Root CA: No Version: 3 Serial Num: 07:47:02 Extensions: Name: X509v3 Basic Constraints Critical: no Content: CA:FALSE Name: X509v3 Key Usage Critical: no Content: Digital Signature Name: X509v3 Subject Key Identifier Critical: no Content: 9B:F8:39:D5:21:E6:FF:49:FF:AC:02:57:5B:FC:4C:1A:8B:1E:5D:8F Name: X509v3 Authority Key Identifier Critical: no Content: 1A:DF:39:84:C2:56:E6:6C:CF:2A:B4:26:A5:FD:0C:D2:43:F5:3D:3E state : OK range : global source : user source-ip : 0.0.0.0 ike-localid-type : asn1dn enroll-protocol : est est-server : https://testrfc7030.com:8443 est-ca-id : est-http-username : estuser est-http-password : estpwd est-client-cert : est-server-cert : est-srp-username : est-srp-password : auto-regenerate-days: 0 auto-regenerate-days-warning: 0
The Subject Key Identifier is the same, so no new key pair was generated.