The X.509 standard is used to secure the Web. Every website using SSL out there (serving pages on HTTPS), have an X.509 certificate on their web server and use it to encrypt and decrypt data on-the-fly.
There can be implementation problems if you don't assign the X.509 extensions properly to your certificate. For example, the extensions field BasicConstraints
is a criticalattribute
that defines whether or not the owner of the certificate can act as a CA. So we set this extension as TRUE when generating a RootCA certificate but then mark it as False
for any other type of certificate.
You can add X.509 extensions to a certificate at two stages
- When creating the Certificate Signing Request
- When signing the certificate using the RootCA certificate
Now as I have explained previously, there are two methods to sign a certificate i.e. using openssl ca command or using openssl x509 command.
I have tested the steps from this article using both the methods and the below steps worked as expected. So for my demonstration I will only use openssl x509
command to sign and generate certificate with custom x509 extensions.
Certificate Extensions Overview
- The most widely accepted format for certificates is the X.509 format, first introduced in 1988. There are three versions of the format, known as X.509v1, X.509v2, and X.509v3.
- Version 3 extensions allow a certificate to contain additional fields beyond those defined by previous versions of the X.509 standard.
- The additional fields may be standard in X.509v3, such as the
basicConstraints
orkeyUsage
fields, or they may be completely nonstandard, perhaps recognized only by a single application. - The X.509v3 standard defines 14 extensions in an effort to consolidate the most common extensions implemented by third parties.
- Of the 14 standard extensions defined by X.509v3, only 4 are well-supported and in widespread use. Only one of them must be designated critical according to the standard, while the other three may or may not be.
Recommended X.509 Extensions for different types of certificates
Here I have consolidated a list of X.509 extensions which are recommended as per Baseline Requirements for the Issuance and Management of Publicly‐Trusted Certificates
RootCA Certificate Extensions
This section specifies the recommended X.509 extensions to be used for RootCA Certificates.
Extension | Value | Comments |
---|---|---|
basicConstraints |
critical,CA:TRUE | This extension MUST appear as a critical extension. The CA field MUST be set true. The pathLenConstraint field SHOULD NOT be present. |
subjectKeyIdentifier |
hash | |
authorityKeyIdentifier |
keyid:always,issuer | |
keyUsage |
critical,keyCertSign,cRLSign | If the Root CA Private Key is used for signing OCSP responses, then the digitalSignature bit MUST be set. |
certificatePolicies |
NA | This extension SHOULD NOT be present. |
extKeyUsage |
NA | This extension MUST NOT be present. |
Intermediate Certificate Extensions
This section specifies the recommended X.509 extensions to be used for Intermediate Certificates.
Extension | Value | Comments |
---|---|---|
basicConstraints |
critical,CA:TRUE,pathlen:0 | This extension MUST appear as a critical extension. The CA field MUST be set true. The pathlen parameter indicates the maximum number of CAs that can appear below this one in a chain. |
subjectKeyIdentifier |
hash | |
authorityKeyIdentifier |
keyid:always,issuer | This extension MUST be present and MUST NOT be marked critical. It MUST contain a keyIdentifier field and it MUST NOT contain aauthorityCertIssuer or authorityCertSerialNumber field |
keyUsage |
critical,keyCertSign,cRLSign | If the Intermediate CA Private Key is used for signing OCSP responses, then the digitalSignature bit MUST be set. |
certificatePolicies |
NA | This extension SHOULD NOT be present. |
Server Certificate Extensions
This section specifies the recommended X.509 extensions to be used for Server Certificates.
Extension | Value | Comments |
---|---|---|
basicConstraints |
CA:FALSE | The CA field MUST NOT be true. |
authorityKeyIdentifier |
keyid,issuer | This extension MUST be present and MUST NOT be marked critical. It MUST contain a keyIdentifier field and it MUST NOT contain aauthorityCertIssuer or authorityCertSerialNumber field. |
subjectKeyIdentifier |
hash | |
keyUsage |
digitalSignature,nonRepudiation,keyEncipherment,dataEncipherment | keyCertSign and cRLSign MUST NOT be set. |
extKeyUsage |
serverAuth | For SSL server certificates. The valueanyExtendedKeyUsage MUST NOT be present. |
Client Certificate Extensions
This section specifies the recommended X.509 extensions to be used for Client Certificates.
Extension | Value | Comments |
---|---|---|
basicConstraints |
CA:FALSE | The CA field MUST NOT be true. |
authorityKeyIdentifier |
keyid,issuer | This extension MUST be present and MUST NOT be marked critical. It MUST contain a keyIdentifier field and it MUST NOT contain aauthorityCertIssuer or authorityCertSerialNumber field. |
subjectKeyIdentifier |
hash | |
keyUsage |
digitalSignature,nonRepudiation,keyEncipherment,dataEncipherment | keyCertSign and cRLSign MUST NOT be set. |
extendedKeyUsage |
clientAuth | For SSL client certificates. The valueanyExtendedKeyUsage MUST NOT be present. |
Scenario-1: Add X.509 extensions to RootCA certificate
In this section I will create a RootCA certificate with custom X.509 extensions.
Step-1: Generate private key
First we would need a private key to generate the rootCA certificate:
[root@controller certs_x509]# openssl genrsa -out cakey.pem 4096
Step-2: Create openssl configuration file
Next we will create one custom openssl configuration file required to generate the Certificate Signing request and add X.509 extensions to our RootCA certificate:
[root@controller certs_x509]# cat openssl.cnf
[ req ]
distinguished_name = req_distinguished_name
policy = policy_match
x509_extensions = v3_ca
# For the CA policy
[ policy_match ]
countryName = optional
stateOrProvinceName = optional
organizationName = optional
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
[ req_distinguished_name ]
countryName = Country Name (2 letter code)
countryName_default = IN
countryName_min = 2
countryName_max = 2
stateOrProvinceName = State or Province Name (full name) ## Print this message
stateOrProvinceName_default = KARNATAKA ## This is the default value
localityName = Locality Name (eg, city) ## Print this message
localityName_default = BANGALORE ## This is the default value
0.organizationName = Organization Name (eg, company) ## Print this message
0.organizationName_default = GoLinuxCloud ## This is the default value
organizationalUnitName = Organizational Unit Name (eg, section) ## Print this message
organizationalUnitName_default = Admin ## This is the default value
commonName = Common Name (eg, your name or your server hostname) ## Print this message
commonName_max = 64
emailAddress = Email Address ## Print this message
emailAddress_max = 64
[ v3_ca ]
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
basicConstraints = critical,CA:true
nsComment = "OpenSSL Generated Certificate"
Here I have added
- policy which must be applied to the RootCA certificate which is used while signing any certificate
- distinguised_name which will be used to write the CSR
- v3_ca field is used to define the X.509 extensions which will be added to the RootCA certificate
Step-3: Generate RootCA certificate
Let us go ahead and create our RootCA certificate:
[root@controller certs_x509]# openssl req -new -x509 -days 3650 -config openssl.cnf -key cakey.pem -out cacert.pem
Step-4: Verify X.509 Extensions inside RootCA certificate
Our rootca certificate has successfully been created. let us verify the content of the certificate to make sure that our extensions were properly added:
[root@controller certs_x509]# openssl x509 -text -noout -in cacert.pem | grep -A10 "X509v3 extensions" X509v3 extensions: X509v3 Subject Key Identifier: D2:84:32:48:45:86:23:E4:8F:02:22:BC:4D:E8:37:39:EF:FD:AF:7C X509v3 Authority Key Identifier: keyid:D2:84:32:48:45:86:23:E4:8F:02:22:BC:4D:E8:37:39:EF:FD:AF:7C X509v3 Basic Constraints: critical CA:TRUE Netscape Comment: OpenSSL Generated Certificate Signature Algorithm: sha256WithRSAEncryption
Scenario-2: Add X.509 extensions to Certificate Signing Request (CSR)
In this section I will share the steps required to add X.509 extensions to a certificate Signing request which can be used to sign any server or client certificate later.
Step-1: Generate private key
First let us generate a private key for the server certificate:
[root@controller certs_x509]# openssl genrsa -out server.key.pem 4096
Step-2: Configure openssl.cnf to add X.509 Extensions
We will create our own custom openssl.cnf
to add X.509 extensions to the Certificate Signing Request. Following is our sample openssl.cnf
file:
[root@controller certs_x509]# cat openssl.cnf
[ req ]
distinguished_name = req_distinguished_name
policy = policy_match
x509_extensions = user_crt
req_extensions = v3_req
[ req_distinguished_name ]
countryName = Country Name (2 letter code)
countryName_default = IN
countryName_min = 2
countryName_max = 2
stateOrProvinceName = State or Province Name (full name) ## Print this message
stateOrProvinceName_default = KARNATAKA ## This is the default value
localityName = Locality Name (eg, city) ## Print this message
localityName_default = BANGALORE ## This is the default value
0.organizationName = Organization Name (eg, company) ## Print this message
0.organizationName_default = GoLinuxCloud ## This is the default value
organizationalUnitName = Organizational Unit Name (eg, section) ## Print this message
organizationalUnitName_default = Admin ## This is the default value
commonName = Common Name (eg, your name or your server hostname) ## Print this message
commonName_max = 64
emailAddress = Email Address ## Print this message
emailAddress_max = 64
[ user_crt ]
nsCertType = client, server, email
nsComment = "OpenSSL Generated Certificate"
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer
[ v3_req ]
basicConstraints = CA:FALSE
extendedKeyUsage = serverAuth, clientAuth, codeSigning, emailProtection
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
Here I have added separate section for X.509 Extensions and Request Extensions which will be applied to the CSR.
Step-3: Generate CSR with X.509 Extensions
Next let us generate our CSR file using the above configuration file:
[root@controller certs_x509]# openssl req -config openssl.cnf -new -key server.key.pem -out server.csr
Step-4: Verify X.509 Extension in CSR
You can check the content of the CSR which we just created to make sure all the extensions are properly added.
[root@controller certs_x509]# openssl req -text -in server.csr | grep -A 6 "Requested Extensions:" Requested Extensions: X509v3 Basic Constraints: CA:FALSE X509v3 Extended Key Usage: TLS Web Server Authentication, TLS Web Client Authentication, Code Signing, E-mail Protection X509v3 Key Usage: Digital Signature, Non Repudiation, Key Encipherment
So, all our extensions are properly added to the CSR file.
Step-5: Generate server certificate
Next we will generate our server certificate using this CSR and rootca certificate:
[root@controller certs_x509]# openssl x509 -req -days 365 -in server.csr -CA cacert.pem -CAkey cakey.pem -CAcreateserial -out server.crt
Signature ok
subject=C = IN, ST = KARNATAKA, L = BANGALORE, O = GoLinuxCloud, OU = Admin, CN = controller.example.com
Getting CA Private Key
Step-6: Verify X.509 extension in the certificate
Now let us verify the content of the server certificate to make sure our X509 extensions are still available:
[root@controller certs_x509]# openssl x509 -text -noout -in server.crt | grep -A10 "X509v3 extensions:" [root@controller certs_x509]#
Looks like all the X509 extensions are missing from the certificate?
Step-7: X509 extensions cannot be transferred from CSR to Certificate
As per the official documentation from openssl,
Extensions in certificates are not transferred to certificate requests and vice versa.
So, what we just observed was an expected behaviour. To fix this we must again define the list of extensions to the openssl command while generating the certificate. We need to use -extfile <CONF_FILE>
along with the -extensions <EXTENSION_NAME>
which contains the X.509 extension in the CONF_FILE
.
Let us re-run our command to generate the certificate with these changes, we will use our existing configuration file:
[root@controller certs_x509]# openssl x509 -req -days 365 -in server.csr -CA cacert.pem -CAkey cakey.pem -CAcreateserial -out server.crt -extensions user_crt -extfile openssl.cnf
Signature ok
subject=C = IN, ST = KARNATAKA, L = BANGALORE, O = GoLinuxCloud, OU = Admin, CN = controller.example.com
Getting CA Private Key
Now verify the X.509 extension inside the certificate:
[root@controller certs_x509]# openssl x509 -text -noout -in server.crt | grep -A10 "X509v3 extensions:" X509v3 extensions: Netscape Cert Type: SSL Client, SSL Server, S/MIME Netscape Comment: OpenSSL Generated Certificate X509v3 Subject Key Identifier: E1:54:D9:2F:CA:1B:AF:ED:60:06:A3:D4:20:DD:D2:85:7E:E9:37:4D X509v3 Authority Key Identifier: keyid:D2:84:32:48:45:86:23:E4:8F:02:22:BC:4D:E8:37:39:EF:FD:AF:7C Signature Algorithm: sha256WithRSAEncryption
So, this time all our X.509 extensions are intact inside the certificate.
Scenario-3: Generate certificate with X.509 extensions
We have partially covered this topic in the previous section. But I will take a simple example here which you can use to add X.509 extensions to your server or client certificate directly.
Step-1: Generate Private Key and CSR
We will quickly generate private key and CSR for the certificate. This time we will not use any configuration file while generating the CSR.
[root@controller certs_x509]# openssl genrsa -out server.key.pem 4096 [root@controller certs_x509]# openssl req -new -key server.key.pem -out server.csr
Step-2: Prepare X.509 Extensions configuration file
Next we will create a configuration file with the list of X.509 extensions to be added into the certificate:
[root@controller certs_x509]# cat custom_openssl.cnf authorityKeyIdentifier=keyid,issuer basicConstraints=CA:FALSE keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment extendedKeyUsage = serverAuth, clientAuth
Step-3: Generate server certificate with X.509 Extensions
Now that we have everything we need, let's quickly create our server certificate:
[root@controller certs_x509]# openssl x509 -req -in server.csr -CA /root/tls/certs/cacert.pem -CAkey /root/tls/private/cakey.pem -out server.crt -CAcreateserial -CAserial serial -days 365 -sha512 -extfile custom_openssl.cnf
Signature ok
subject=C = IN, ST = KARNATAKA, L = Bengaluru, O = GoLinuxCloud, OU = Admin, CN = controller.example.com
Getting CA Private Key
Step-4: Verify X.509 Extension in the server certificate
Let us verify the content of the server certificate we just generated to make sure all the extensions are properly added:
[root@controller certs_x509]# openssl x509 -text -noout -in server.crt | grep -A10 "X509v3 extensions:" X509v3 extensions: X509v3 Authority Key Identifier: keyid:5E:F8:6F:A9:DB:9E:60:81:A2:51:E4:72:81:C4:D2:4D:F0:80:90:F8 X509v3 Basic Constraints: CA:FALSE X509v3 Key Usage: Digital Signature, Non Repudiation, Key Encipherment, Data Encipherment X509v3 Extended Key Usage: TLS Web Server Authentication, TLS Web Client Authentication Signature Algorithm: sha512WithRSAEncryption
So all good then.
Summary
In this tutorial we covered different scenarios to add X.509 Extensions to Certificates, CSR and Root CA certificate. We shared detailed examples for each scenarios to help you understand the concept properly.
We also learned that if we add X509 extensions in the CSR then those will not be transferred to the certificate automatically and we must re-assign those extensions into the certificate again.
So it is better that we directly assign the extensions into the certificate rather than repeating the same task again but then again we may have different use case, so you can decide which solution suits you better.
Lastly I hope the steps from the article to add X.509 extensions to certificates using openssl was helpful. So, let me know your suggestions and feedback using the comment section.
Further Reading
man page for openssl x509
man page for openssl x509 extensions
Standard X.509 v3 Certificate Extension Reference
Some issues with x509.
How to generate a p12 certificate for Windows to double-click and import.
I tried using OpenSSL CA to create an intermediate CA, create a certificate chain, and generate P12. When importing, the root certificate and personal certificate will be automatically imported. And verify that it is normal.
Directly converting CA certificates to P12 is not possible, only personal certificates will be automatically imported. Verification is not normal.
Is x509 missing an intermediate CA server?
Generate an intermediate CA for x509 and issue an x509 certificate using the intermediate CA?
What I have successfully tested now is:
Use the CA command to issue an intermediate CA, create a certificate chain, generate a p12, and import it into the Windows terminal.
SSL server, use the x509 command to issue CA signed server certificates.
It seems that P12 automatically imports the root certificate.
The SSL server still uses server certificates issued by CA.
I feel that the certificate chain has not been implemented.
I have never created certificate for Windows so nothing much I can help at this stage, may be some other reader here can help. But I will try to learn the same and prepare an article on this topic.
Perhaps the problem lies in not using the X905 intermediate CA server to sign user certificates?
Hi,
Whether mTLS will work, if server is using self-signed certificates and client using CA signed certificates signed by some authority?
Though, client has installed server chain certificates in its trusted category and also, server has installed client root certificate chain at its end.
Is this scenario supported in mTLS?
So if I understand, server has generated it’s own CA and used that to sign server certificate. The client then used the same CA certificate as generated by server and used that to sign client certificate. So in this case yes MTLS will work. It is explained here Setup & verify mutual TLS authentication (MTLS) with openssl