How to add X.509 extensions to certificate OpenSSL

Add X.509 extensions to certificate using OpenSSL

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.

Advertisement

 

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 or keyUsage 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.

ExtensionValueComments
basicConstraintscritical,CA:TRUEThis extension MUST appear as a critical extension.
The CA field MUST be set true.
The pathLenConstraint field SHOULD NOT be present.
subjectKeyIdentifierhash
authorityKeyIdentifierkeyid:always,issuer
keyUsagecritical,keyCertSign,cRLSignIf the Root CA Private Key is used for
signing OCSP responses, then the digitalSignature bit MUST be set.
certificatePoliciesNAThis extension SHOULD NOT be present.
extKeyUsageNAThis extension MUST NOT be present.

 

Intermediate Certificate Extensions

This section specifies the recommended X.509 extensions to be used for Intermediate Certificates.

ExtensionValueComments
basicConstraintscritical,CA:TRUE,pathlen:0This 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.
subjectKeyIdentifierhash
authorityKeyIdentifierkeyid:always,issuerThis extension MUST be present and MUST NOT be marked critical. It MUST
contain a keyIdentifier field and it MUST NOT contain a
authorityCertIssuer or authorityCertSerialNumber field
keyUsagecritical,keyCertSign,cRLSignIf the Intermediate CA Private Key is used for
signing OCSP responses, then the digitalSignature bit MUST be set.
certificatePoliciesNAThis extension SHOULD NOT be present.
Advertisement

 

Server Certificate Extensions

This section specifies the recommended X.509 extensions to be used for Server Certificates.

ExtensionValueComments
basicConstraintsCA:FALSEThe CA field MUST NOT be true.
authorityKeyIdentifierkeyid,issuerThis extension MUST be present and MUST NOT be marked critical. It MUST
contain a keyIdentifier field and it MUST NOT contain a
authorityCertIssuer or authorityCertSerialNumber field.
subjectKeyIdentifierhash
keyUsagedigitalSignature,nonRepudiation,keyEncipherment,dataEnciphermentkeyCertSign and cRLSign MUST NOT be set.
extKeyUsageserverAuthFor SSL server certificates. The value
anyExtendedKeyUsage MUST NOT be present.

 

Client Certificate Extensions

This section specifies the recommended X.509 extensions to be used for Client Certificates.

ExtensionValueComments
basicConstraintsCA:FALSEThe CA field MUST NOT be true.
authorityKeyIdentifierkeyid,issuerThis extension MUST be present and MUST NOT be marked critical. It MUST
contain a keyIdentifier field and it MUST NOT contain a
authorityCertIssuer or authorityCertSerialNumber field.
subjectKeyIdentifierhash
keyUsagedigitalSignature,nonRepudiation,keyEncipherment,dataEnciphermentkeyCertSign and cRLSign MUST NOT be set.
extendedKeyUsageclientAuthFor SSL client certificates. The value
anyExtendedKeyUsage 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:

Advertisement
[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

 

Didn't find what you were looking for? Perform a quick search across GoLinuxCloud

If my articles on GoLinuxCloud has helped you, kindly consider buying me a coffee as a token of appreciation.

Buy GoLinuxCloud a Coffee

For any other feedbacks or questions you can either use the comments section or contact me form.

Thank You for your support!!

Leave a Comment