Description | This article describes how to request an SSL digital certificate from a public CA for FortiClient EMS using OpenSSL to create the CSR. | ||||||||||||
Scope | FortiClient EMS and general x.509 certification operations. | ||||||||||||
Solution |
Adding the -nodes or -noenc switch to the OpenSSL req utility will create an unprotected private key from the beginning, which is not recommended. The same commands can be used with OpenSSL on any platform, including Linux, Mac, Android, and others.
EMS uses certificates for the following services. If EMS is currently using a certificate for a certain service, EMS Server Certificates display this information in the Assigned To column.
The Complete Picture:
To obtain an SSL certificate from a trusted public CA (such as DigiCert or Comodo), you need to provide them with a CSR (Certificate Signing Request). However, to be precise, it no longer uses SSL; these certificates are now used for TLS communication. Here is a history of SSL and TLS:
SSL/TLS certificates are not special certificates. They are created in the same way as any other X.509 certificate. However, they have their own set of Extended Key Usage (EKU) attributes, which make them fit for client-server TLS secure communication (RFC 5280). These attributes ensure that the TLS certificates can be used to establish secure connections over protocols like HTTPS, ensuring data encryption and server authentication.
One of the fastest and most convenient ways of generating a CSR is through OpenSSL. OpenSSL is installed with the EMS server and is available inside the directory ‘c:\Program Files (x86)\Fortinet\FortiClientEMS\Apache24\bin’. This can be verified by running the command ‘openssl.exe version’ inside that directory.
Creating the CSR on the EMS server is not mandatory. It is possible to generate the CSR using OpenSSL on any platform, even on an Android phone. Nevertheless, it is advisable to perform this on the EMS server as it involves generating the public-private key pair. Doing so on the server mitigates any risks related to transferring the private key. Ultimately, it will be necessary to upload both the public and private keys to the EMS server via the web UI management console.
Indeed, creating a CSR involves generating a key pair for asymmetric encryption in TLS. The Certificate Signing Request is usually encoded following the PKCS #10 standard, which comprises the public key, identification details, and a digital signature. It is then Base64 encoded and enclosed within distinct header and footer lines to facilitate easy transfer.
Here is what a CSR looks like in its encoded form:
-----BEGIN CERTIFICATE REQUEST----- MIICsDCCAZgCAQAwazELMAkGA1UEBhMCRUcxDjAMBgNVBAgMBUNhaXJvMREwDwYD VQQHDAhTaGVyYXRvbjEMMAoGA1UECgwDRm9vMQ4wDAYDVQQLDAVGb29JVDEbMBkG -----END CERTIFICATE REQUEST-----
The 'identifying information' and metadata of a CSR include fields such as the following and are governed under RFC 5280.
Additionally, RFC 2818, titled ‘HTTP Over TLS’, specifies SAN as the preferred method of adding DNS names to certificates, deprecating the previous method of putting DNS names in the Common Name (CN) field. The reason why it is possible to see the DNS used in both CN and Subject Alternative Name (SAN) fields is for the sake of backward compatibility with old implementations.
SAN allows multiple fields and wildcard domains and is a much better fit for today’s internet. It is interesting to note that major web browsers no longer check the ‘commonName’ for certificate verification (Google Chrome starting with version 58 and Mozilla Firefox starting with version 48).
How to create CSR with OpenSSL:
openssl.exe req -newkey rsa:2048 -keyout private.key -out public.csr -subj "/C=xx/ST=xxxxx/L=xxxxx/O=xxxxx/OU=xxxxx/CN=my.domain.com/emailAddress=admin@xxx.yyy" -addext "subjectAltName=DNS:my.domain.com" req: certificate request and certificate generating utility.
It has been selected nodes to create an unencrypted private key. If this switch is not used, OpenSSL will prompt for a password which will be used to encrypt the locally stored private key file. FortiClient EMS does not support uploading password-protected private key files. If preferring a password-protected key file, then it is recommended to use the pkcs12 format.
The recommended method is to password-protect and encrypt the private key (not using -nodes switch), and then convert the Digital Certificate to a password-protected pkcs12 format.
In the next section, let's proceed with creating the private local Certificate Authority (CA) to simulate the complete process. For the sake of completeness, the CA will consist of one Root CA and three underlying intermediate CAs. Then include all the intermediate CAs’ digital certificates to create a PKCS#12 bundle of the private certificate. This way, the end user can verify the public digital certificate issued by an intermediate CA by simply having the Root CA in their trusted root CA inventory, without the need to have the intermediate CAs’ in their certificate store. Use the following interactive Bash script to create the four-level CA with OpenSSL in Linux. In this script, each intermediate certificate is signed by the certificate one level above it in the hierarchy, creating a chain of trust from rootCA to intermediateCA3.
#!/bin/bash # Ask user for input read -p "Enter Country Name: " COUNTRY read -p "Enter State or Province Name: " STATE read -p "Enter Locality Name: " LOCALITY read -p "Enter Organization Name: " ORGANIZATION
# Create the OpenSSL configuration file echo "Creating OpenSSL configuration file..." cat > config.cnf <<EOF [v3_ca] basicConstraints = CA:TRUE keyUsage = critical, digitalSignature, cRLSign, keyCertSign EOF echo ""
# Generate private key for Root CA echo "Generating private key for Root CA..." openssl genrsa -out rootCA.key 2048 echo ""
# Create self-signed root certificate UNIT="RootCA" echo "Creating self-signed root certificate..." openssl req -x509 -new -nodes -key rootCA.key -sha256 -days 1024 -out rootCA.crt -subj "/C=$COUNTRY/ST=$STATE/L=$LOCALITY/O=$ORGANIZATION/OU=$UNIT/CN=$UNIT" -config config.cnf echo ""
# Generate private keys and CSRs for Intermediate CAs for i in {1..3} do UNIT="IntermediateCA${i}" echo "Generating private key and CSR for $UNIT..." openssl genrsa -out ${UNIT}.key 2048 openssl req -new -key ${UNIT}.key -out ${UNIT}.csr -subj "/C=$COUNTRY/ST=$STATE/L=$LOCALITY/O=$ORGANIZATION/OU=$UNIT/CN=$UNIT" -config config.cnf echo "" done
# Sign CSRs to create Intermediate CA certificates using the v3_ca extension echo "Creating certificate for IntermediateCA1..." openssl x509 -req -in IntermediateCA1.csr -CA rootCA.crt -CAkey rootCA.key -CAcreateserial -out IntermediateCA1.crt -days 500 -sha256 -extensions v3_ca -extfile config.cnf echo "" echo "Creating certificate for IntermediateCA2..." openssl x509 -req -in IntermediateCA2.csr -CA IntermediateCA1.crt -CAkey IntermediateCA1.key -CAcreateserial -out IntermediateCA2.crt -days 500 -sha256 -extensions v3_ca -extfile config.cnf echo "" echo "Creating certificate for IntermediateCA3..." openssl x509 -req -in IntermediateCA3.csr -CA IntermediateCA2.crt -CAkey IntermediateCA2.key -CAcreateserial -out IntermediateCA3.crt -days 500 -sha256 -extensions v3_ca -extfile config.cnf echo "" echo "All done!"
First, create a RootCA.key private key, then use this key to sign a RootCA.crt certificate without having a CSR, hence the term 'Self-Signed'. It is signed by the owner of the private key.
A CSR includes the public key, and here there is no CSR! It is also known that the RootCA.crt is something that can be published publicly. It must include a public key… So it is important to know where the public key is.
So far, it has been referred to the key file as a private key, but the truth is that when creating the private key using 'openssl genrsa -out private_key.pem 2048', the private_key.pem file is indeed hosting the complete key pair, including both the private key and the public key (complete details available in RFC 8017).
Currently, there are two major asymmetric encryption algorithms. These algorithms define the complex mathematical foundations behind generating the public-private key pair. They mathematically prove that there exists no other matching key for any private or public key. They guarantee the uniqueness of the key pair. These algorithms are listed in RFC 3279 and standard X.509 certs must obey them.
It is possible to extract the public key from a key-pair file (which is called a private key file in general) using OpenSSL:
For the ECDSA algorithm:
For DH (Diffie-Helman) algorithm:
Let’s get back to the personal CA with three intermediate CAs. It has been generated 14 different files. The '-extensions v3_ca' adds the Certificate Signing capabilities to the intermediate CA.
rootCA.key > rootCA.crt [Self signed by rootCA private key] Now that the private CA has been created, it is possible to use it to sign others’ CSRs. Let’s generate a CSR for our EMS server and sign it using the third intermediate CA (IntermediateCA3.crt).
Upon opening the output file (MyEmsPrivate.key), we see the following structure: -----BEGIN PRIVATE KEY----- MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDVvn7nD+Z359fx VX+LZPedHPfM6CBpkmvuiVcm1w== -----END PRIVATE KEY-----
This means that the private key is stored in clear text format, which is not recommended. Adding -aes256 to our previous command instructs OpenSSL to ask for a passphrase and use the AES-256 symmetric encryption algorithm to password-protect the generated PEM file. This is asking to password-protect the .zip file. openssl genrsa -aes256 -out MyEncryptedEmsPrivate.key 2048
Now, upon opening the output file (MyEncryptedEmsPrivate.key), it is possible to see the following structure:
-----BEGIN ENCRYPTED PRIVATE KEY----- MIIFNTBfBgkqhkiG9w0BBQ0wUjAxBgkqhkiG9w0BBQwwJAQQnD/uIKaZcY5781v6 nuSig7dsZjEk8Z1Hj0MdeIp2F/hw7kVbM8LUuKgtKw9CqdHxJKhkJoo= -----END ENCRYPTED PRIVATE KEY-----
The header and footer of the key file clearly indicate the difference.
openssl req -new -key MyEncryptedEmsPrivate.key -out MyEmsPublickey.csr -subj "/C=US/ST=California/L=LA/O=MyCompany/OU=TechnologyDepartment/CN=my.domain.com/emailAddress=abc@xxx.yyy" -addext "subjectAltName=DNS:my.domain.com"
OpenSSL will ask for the passphrase of MyEncryptedEmsPrivate.key and create MyEmsPublickey.csr. It is also possible to create the RSA key inside the req utility of OpenSSL using 'newkey rsa:2048 -keyout private_key_encrypted.pem' which generates a new RSA key and then the CSR request using it.
openssl x509 -req -in MyEmsPublickey.csr -CA IntermediateCA3.crt -CAkey IntermediateCA3.key -CAcreateserial -out MyEmsSignedCert.crt -days 1000 -sha256 -extensions Web_Server_KeyUsage -extfile <(cat <<EOF [Web_Server_KeyUsage] keyUsage = critical, digitalSignature, keyEncipherment extendedKeyUsage = serverAuth EOF ) This creates a MyEmsSignedCert.crt file which will expire in 1000 days. It is possible to open this file and confirm the different properties of this Digital Certificate file.
It is possible to see that the status of this certificate shows that 'The issuer of this certificate could not be found'. After adding rootCA.crt, IntermediateCA1.crt, IntermediateCA2.crt, and IntermediateCA3.crt to my OS Trusted Root Certification Authorities, the chain of trust is shown in the certificate properties.
Now let's remove IntermediateCA1 from the system Trusted Store and see what happens:
It is possible to see the message 'The issuer of this certificate could not be found'. This shows the concept of a 'Chain of Trust'. There is nothing magical about the certificate used on google.com versus the one created. It is just about trusting the issuer in our operating system or web browser inventory. This clearly amplifies the importance of protecting the Trust Store from any untrusted certifications to be installed on it.
So far it has been installed all the four CA certifications in the trusted store to verify the chain of trust. If it is desired to trust just the RooCA, let's see what has to be done. Furthermore, intermediate CAs can change all the time and it is not easy to keep all endpoints updated with intermediate CAs.
The answer is to bundle all the intermediate CAs’ into the public digital certificate. This is also called certificate chaining which can be easily done by including all certificates in one file. Technical details of certificate chaining are covered in RFC 5246 Section 7.4.2: The sender's certificate must come first in the list.
Each following certificate must directly certify the one preceding it. Because certificate validation requires that root keys be distributed independently, the self-signed certificate that specifies the root certificate authority may be omitted from the chain, under the assumption that the remote end must already possess it to validate it in any case.
Unfortunately, Microsoft implementation does not show a certificate tree for chained or bundled certificates. OpenSSL, gnu certtool, or scripts such as cert_tree.py can be used to verify this:
python3 cert_tree.py ./MyEmsSignedCertBundelled.crt ━ RootCA ┗━ IntermediateCA1 ┗━ IntermediateCA2 ┗━ IntermediateCA3 ┗━ my.domain.com, emailAddress = abc@xxx.yyy
openssl crl2pkcs7 -nocrl -certfile .\MyEmsSignedCertBundled.crt | openssl pkcs7 -print_certs -noout subject=C=US, ST=California, L=LA, O=MyCompany, OU=TechnologyDepartment, CN=my.domain.com, emailAddress=abc@xxx.yyy issuer=C=US, ST=California, L=San Jose, O=My Personal CA Labs, OU=IntermediateCA3, CN=IntermediateCA3 subject=C=US, ST=California, L=San Jose, O=My Personal CA Labs, OU=IntermediateCA3, CN=IntermediateCA3 issuer=C=US, ST=California, L=San Jose, O=My Personal CA Labs, OU=IntermediateCA2, CN=IntermediateCA2 subject=C=US, ST=California, L=San Jose, O=My Personal CA Labs, OU=IntermediateCA2, CN=IntermediateCA2 issuer=C=US, ST=California, L=San Jose, O=My Personal CA Labs, OU=IntermediateCA1, CN=IntermediateCA1 subject=C=US, ST=California, L=San Jose, O=My Personal CA Labs, OU=IntermediateCA1, CN=IntermediateCA1 issuer=C=US, ST=California, L=San Jose, O=My Personal CA Labs, OU=RootCA, CN=RootCA
With certificate bundling, put all intermediate certificates chained to their own public digital certificate and the user needs to just trust the root certificate. So if the CA signs the CSR with an intermediate CA that is not installed publicly on operating systems, it is possible to simply bundle them in a single CRT file by adding them together in order.
The final step is to upload the certificate for EMS usage. EMS supports uploading password-protected certificates in PKCS12 format or in pem format, then the private key must not be encrypted (password protected). If having created the private key without the -aes256 or the CSR with the -nodes or -noenc, then the private key is already unprotected and it is possible to upload it via the EMS web interface together with the digital certificate file.
If having a protected private key, remove its encryption and save it as plain text using OpenSSL:
openssl rsa -in private_key_encrypted.pem -out private_key_plaintext.pem
OpenSSL will ask for the key password and save it as plain text.
Another method is to create a PKCS#12 archive file, which can contain multiple objects in a single file. These objects include the private key, the digital certificate, and any intermediate digital certificates that are desired to be delivered to the user during the handshake (refer to the concepts of certificate bundling or certificate chaining discussed previously).
openssl pkcs12 -export -out MyEmsServerCertBundle.pfx -inkey MyEncryptedEmsPrivate.key -in MyEmsSignedCert.crt -certfile <(cat IntermediateCA1.crt IntermediateCA2.crt IntermediateCA3.crt rootCA.crt)
OpenSSL will ask for the passphrase of MyEncryptedEmsPrivate.key, if provided correctly then it will ask to set a password for the MyEmsServerCertBundle.pfx and it will bundle all the provided keys together in a single pkcsd12 file. The pkcs12 file can be verified using OpenSSL:
openssl pkcs12 -info -nokeys -in MyEmsServerCertBundle.pfx
It is of utmost importance to note that this file includes the private key and is meant to be hosted securely with proper access permissions on the webserver (in this case EMS server).
A note on public-private key (asymmetrical) encryption:
In RSA encryption, it is possible to technically use either the public key or the private key to encrypt a message, and then use the other key to decrypt it. This property is what enables RSA to be used for both encryption/decryption and digital signatures.
For encryption/decryption:
For digital signatures:
However, it is important to note that while the mathematics allows for this, the actual usage depends on the specific protocol and the security requirements of the system.
While it is technically possible to encrypt a message with a private key and decrypt it with the corresponding public key, this is not typically how RSA encryption is used for secure communication. Here is why:
In practice, RSA is often used in a protocol like SSL/TLS for secure internet traffic. The server’s public key is used to encrypt a symmetric session key, which is then used for the bulk of the encryption/decryption. The server’s private key is used to decrypt the session key. This combines the efficiency of symmetric encryption with the security of public-key encryption.
Self-Signing CSRs with Subject Alternative Name (SAN): When you create a Certificate Signing Request (CSR), you can specify SAN fields. However, these are just requests. The CA has the final say on what goes into the issued certificate. During the signing process, the CA will validate the information and then include the approved SAN fields in the issued certificate.
It is important to note that having SAN fields in the CSR is not enough to have a SAN-enabled digital certificate! The field must also be confirmed and added to the X.509 certificate by the signing CA. In our case, we can use the following code to sign a CSR using rootCA and add multiple DNS and IPs to SAN. Technically the Certificate Authority (CA) can add Subject Alternative Name (SAN) entries during the certificate signing process, even if they were not included in the original Certificate Signing Request (CSR)!
openssl x509 -req -in csr.csr -CA rootCA.crt -CAkey rootCA.key -CAcreateserial -out cert.crt -days 1000 -sha256 -extensions Web_Server_KeyUsage -extfile <(cat <<EOF
If generating the CSR using FortiGate, it is possible to add the Subject Alternative Name with the following format:
Commands in this article have been tested with the following OpenSSL version:
|
The Fortinet Security Fabric brings together the concepts of convergence and consolidation to provide comprehensive cybersecurity protection for all users, devices, and applications and across all network edges.
Copyright 2024 Fortinet, Inc. All Rights Reserved.