FortiGate supports the auto-enrollment of certificates using SCEP.
This can be done in 2 ways:
- Directly from the FortiGate device itself (via GUI or CLI).
- Using Certificate Templates on FortiManager.
This article will focus on the first option. A separate article exists for instructions on how to use FortiManager:
Technical Tip: Certificate Template with SCEP enrollment using FortiAuthenticator as external CA.
Note:
The beginning of the above article details how to enable SCEP on FortiAuthenticator, if using a FortiAuthenticator to serve SCEP requests this should be enabled otherwise requests will fail.
To create a certificate via the GUI and enroll with SCEP, go to System -> Certificates and select Generate CSR.
Fill in the necessary fields. On the enrollment method, select Online SCEP and fill in the fields correctly:

Alternatively, the CLI can be used to do this:
execute vpn certificate local generate rsa IPSECVPNTest 2048 myvpn NL NH Amsterdam Fortinet "" ipsecvpntest@fortinet.com "" http://10.5.59.172/app/cert/scep/ <challenge_password>
Successful enrollment can be observed with the following debug:
diagnose debug application scep -1
diagnose debug enable
scep_parse_header: server returned status code 200 scep_parse_header: MIME header: application/x-x509-ca-cert __process_ca_cert_reply: Reply type 1 __process_ca_cert_reply: loaded cacert __read_ca_cert_cb: loaded signing cert __read_ca_cert_cb: loaded CA new_scep_transaction: transaction id: 2B9E443E5E0A9BA816785A1915AA2E99 pkcs7_wrap:1120 creating inner PKCS#7 pkcs7_wrap: data payload size: 775 bytes pkcs7_wrap: successfully encrypted payload pkcs7_wrap: envelope size: 1280 bytes pkcs7_wrap: creating outer PKCS#7 pkcs7_wrap: signature added successfully pkcs7_wrap: adding signed attributes __add_attribute_string: adding string attribute transId __add_attribute_string: adding string attribute messageType __add_attribute_octet: adding octet attribute senderNonce pkcs7_wrap: PKCS#7 data written successfully pkcs7_wrap: applying base64 encoding pkcs7_wrap: base64 encoded payload size: 3953 bytes scep_parse_header: server returned status code 200 scep_parse_header: MIME header: x-pki-message pkcs7_unwrap: reading outer PKCS#7 pkcs7_unwrap: PKCS#7 payload size: 756 bytes pkcs7_unwrap: PKCS#7 contains 0 bytes of enveloped data pkcs7_unwrap: verifying signature pkcs7_unwrap: signature ok pkcs7_unwrap: finding signed attributes __get_attribute: finding attribute transId __get_signed_attribute: allocating 32 bytes for attribute pkcs7_unwrap: reply transaction id: 2B9E443E5E0A9BA816785A1915AA2E99 __get_attribute: finding attribute messageType __get_signed_attribute: allocating 1 bytes for attribute pkcs7_unwrap: reply message type is good __get_attribute: finding attribute senderNonce __get_signed_attribute: allocating 16 bytes for attribute pkcs7_unwrap: senderNonce in reply: 65DCB45E9FCB8CBB4395C99D8B17BD92 __get_attribute: finding attribute recipientNonce __get_signed_attribute: allocating 16 bytes for attribute pkcs7_unwrap: recipientNonce in reply: 57E9E8B7D23E2912BCADE9BCACA90F08 __get_attribute: finding attribute pkiStatus __get_signed_attribute: allocating 1 bytes for attribute pkcs7_unwrap: pkistatus: PENDING pkcs7_wrap:1138 creating issuer_and_subject PKCS#7 pkcs7_wrap: data payload size: 267 bytes pkcs7_wrap: successfully encrypted payload pkcs7_wrap: envelope size: 776 bytes pkcs7_wrap: creating outer PKCS#7 pkcs7_wrap: signature added successfully pkcs7_wrap: adding signed attributes __add_attribute_string: adding string attribute transId __add_attribute_string: adding string attribute messageType __add_attribute_octet: adding octet attribute senderNonce pkcs7_wrap: PKCS#7 data written successfully pkcs7_wrap: applying base64 encoding pkcs7_wrap: base64 encoded payload size: 3271 bytes scep_parse_header: server returned status code 200 scep_parse_header: MIME header: x-pki-message pkcs7_unwrap: reading outer PKCS#7 pkcs7_unwrap: PKCS#7 payload size: 5996 bytes pkcs7_unwrap: PKCS#7 contains 2899 bytes of enveloped data pkcs7_unwrap: verifying signature pkcs7_unwrap: signature ok pkcs7_unwrap: finding signed attributes __get_attribute: finding attribute transId __get_signed_attribute: allocating 32 bytes for attribute pkcs7_unwrap: reply transaction id: 2B9E443E5E0A9BA816785A1915AA2E99 __get_attribute: finding attribute messageType __get_signed_attribute: allocating 1 bytes for attribute pkcs7_unwrap: reply message type is good __get_attribute: finding attribute senderNonce __get_signed_attribute: allocating 16 bytes for attribute pkcs7_unwrap: senderNonce in reply: 976C51687F9263B79BF8CDF964136EF6 __get_attribute: finding attribute recipientNonce __get_signed_attribute: allocating 16 bytes for attribute pkcs7_unwrap: recipientNonce in reply: 40460901E83309A3022FF353C7EA1183 __get_attribute: finding attribute pkiStatus __get_signed_attribute: allocating 1 bytes for attribute pkcs7_unwrap: pkistatus: SUCCESS pkcs7_unwrap: reading inner PKCS#7 pkcs7_unwrap: decrypting inner PKCS#7 pkcs7_unwrap: PKCS#7 payload size: 2384 bytes scep_write_local_cert: found certificate with subject: /ST=NH/L=Amsterdam/O=Fortinet/OU=AS/CN=myvpn/emailAddress=ipsecvpntest@fortinet.com issuer: /C=NL/ST=NH/L=Amsterdam/O=Fortinet/OU=AS/CN=sceptest/emailAddress=sceptest@fortinet.com scep_write_local_cert: writing cert scep_write_local_cert: certificate written as /tmp/IPSECVPNTest
As of v7.0.4: if a certificate signing is made by an intermediate CA, the root certificate needs to be in the SCEP client certificate repository so that the intermediate CA's issuer can be checked.
Once the certificate is successfully imported, the auto-regenerate option can be configured in the CLI if it is required. It will ensure that the certificate will automatically renew before expiry:
config vpn certificate local
edit <name>
set auto-regenerate-days {integer}
set auto-regenerate-days-warning {integer}
next
end
- auto-regenerate-days: How many days before expiry does the unit request an updated local certificate. The default is 0, certificates are not renewed and expire.
- auto-regenerate-days-warning: How many days before local certificate expiry the FortiGate generate a warning message. The default is 0, with no warning.
Once auto-regenerate-days is configured, FortiGate will send a renewal request for the expiring certificate configured amount of days before expiry.
If the CA does not respond or the request is rejected (e.g. due to the CA not accepting renewal requests too many days before expiry of the current certificate or not allowing renewals for expired certificates), FortiGate will try to continuously renew the certificate until a new certificate is issue with higher validity period than auto-regenerate days.
Note: If the certificate expires before successful renewal and the CA does not support renewing expired certificates, it is necessary to create a new CSR by following this KB and replace the relevant references in the FortiGate configuration.
Note: If auto-regenerate-days is misconfigured and does not comply with CA policies, FortiGate may send an excessive amount of renewal requests to the CA.
When a certificate is successfully renewed or generated using SCEP, a 'Certificate is loaded' log entry can be found on FortiGate VPN logs, which includes the certificate name.

Additionally, the General System Events log contains logs relevant to SCEP renewal.
'Successfully signed local certificate via SCEP' indicates renewal or enrollment has been completed. 'Failed to connect SCEP Server' indicates an issue with SCEP server connectivity 'Failed to sign local certificate via SCEP-(null)' indicates that FortiGate is able to contact the SCEP server, but the renewal or enrollment request is unsuccessful. A reason for the failure may be included. In case the reason stated is null, this can indicate the CA does not allow renewals this far in advance of expiry, it does not allow renewal of expired certificates or other reason specific to the CA. Logs on the SCEP server need to be examined to determine the exact reason.
The log action 'certificate-generate' displays all relevant FortiGate logs.

|