openssl ca vs openssl x509 comparison [With Examples]


Written by - Deepak Prasad

openssl ca vs openssl x509 comparison

Here's a table that compares the key features and functionalities of the openssl ca and openssl x509 commands:

Feature/Functionality openssl ca openssl x509
Primary Purpose To sign certificate requests and manage a CA database. To display, convert, and manage certificates.
Handling CSRs Specifically designed to sign CSRs. Can convert a CSR to a certificate but does not sign it.
Managing Extensions Can include extensions from a CSR in the signed certificate. Uses openssl.cnf for configuration. Limited support for handling extensions. Extensions must be specified manually if required.
Certificate Authority (CA) Operations Manages a CA database, handling multiple certificate signings, revocations, and renewals. Does not manage CA operations.
Certificate Conversion Not intended for format conversion. Converts certificates between various formats (e.g., PEM, DER).
Certificate Display Limited display capabilities. Mainly shows details of the signing process. Extensive display options for certificate contents.
Configuration File Dependency Heavily relies on openssl.cnf for CA configurations and extension handling. Can use openssl.cnf for certain operations, but generally less dependent on the configuration file.
Use in Automation/Scripts Commonly used in automated CA environments for signing batches of CSRs. Often used in scripts for certificate conversion and information extraction tasks.

Let us understand the comparison with some examples

 

Generate RootCA Certificate

We would need a rootCA certificate to sign the certificates so first let use create one rootCA certificate.

 

Create directory structure

We will create our directory structure to keep all our rootCA related certificates.

Here index.txt is used to keep a track of all the certificates which will be signed by our RootCA certificate. The serial and crlnumber file will be used to keep the serial number for every certificate which is either signed or revoked respectively.

[root@controller tls]# mkdir /root/tls/{certs,private,crl}
[root@controller tls]# touch serial crlnumber index.txt
[root@controller tls]# echo 01 > serial
[root@controller tls]# echo 1000 > crlnumber

You can add any number into the serial and crlnumber file to start with, now going forward every time we sign or revoke a certificate, respective file's entry will be incremented by 1.

List the available files under our /root/tls directory:

[root@controller tls]# ls -l
total 28
drwxr-xr-x 2 root root 4096 Aug 28 17:23 certs
drwxr-xr-x 2 root root 4096 Aug 28 17:23 crl
-rw-r--r-- 1 root root    5 Aug 28 17:25 crlnumber
-rw-r--r-- 1 root root    0 Aug 28 17:25 index.txt
drwxr-xr-x 2 root root 4096 Aug 28 17:23 private
-rw-r--r-- 1 root root    3 Aug 28 17:25 serial

 

Sample openssl.cnf

Below is our sample openssl.cnf file which we have created under /root/tls directory:

[root@controller tls]# cat openssl.cnf

Sample Output:

[ ca ]
default_ca      = CA_default            # The default ca section

[ CA_default ]
dir             = /root/tls             # Where everything is kept
certs           = $dir/certs            # Where the issued certs are kept
crl_dir         = $dir/crl              # Where the issued crl are kept
database        = $dir/index.txt        # database index file.
new_certs_dir   = $dir/certs            # default place for new certs.
certificate     = $dir/certs/cacert.pem         # The CA certificate
serial          = $dir/serial           # The current serial number
crlnumber       = $dir/crlnumber        # the current crl number
crl             = $dir/crl.pem          # The current CRL
private_key     = $dir/private/cakey.pem # The private key
x509_extensions = v3_ca                 # The extensions to add to the cert
default_days    = 3650                  # how long to certify for
default_crl_days= 30                    # how long before next CRL
default_md      = sha512                # use SHA-256 by default
preserve        = no                    # keep passed DN ordering
policy          = policy_match

## This section is used to generate CSR for RootCA
[ policy_match ] 
countryName             = match  ## Must match RootCA CSR and any certificate this RootCA signs
stateOrProvinceName     = match  ## Must match RootCA CSR and any certificate this RootCA signs
organizationName        = match  ## Must match RootCA CSR and any certificate this RootCA signs
organizationalUnitName  = optional
commonName              = supplied
emailAddress            = optional

[ policy_anything ]
countryName             = optional
stateOrProvinceName     = optional
localityName            = optional
organizationName        = optional
organizationalUnitName  = optional
commonName              = supplied
emailAddress            = optional

[ req ]
default_bits            = 4096
default_md              = sha512
default_keyfile         = privkey.pem
distinguished_name      = req_distinguished_name
attributes              = req_attributes
x509_extensions = v3_ca # The extensions to add to the self signed cert
string_mask = utf8only

[ 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)
stateOrProvinceName_default     = Some-State
localityName                    = Locality Name (eg, city)
localityName_default            = BANGALORE
0.organizationName              = Organization Name (eg, company)
0.organizationName_default      = GoLinuxCloud
organizationalUnitName          = Organizational Unit Name (eg, section)
commonName                      = Common Name (eg, your name or your servers hostname)
commonName_max                  = 64
emailAddress                    = Email Address
emailAddress_max                = 64

[ req_attributes ]
challengePassword               = A challenge password
challengePassword_min           = 4
challengePassword_max           = 20
unstructuredName                = An optional company name

## Extensions used for RootCA certificate
[ v3_ca ]  
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
basicConstraints = critical,CA:true
nsComment = "OpenSSL Generated Certificate"

[ v3_req ]
# Extensions to add to a certificate request
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment

Generate private key

Generate a private key for the rootCA certificate:

[root@controller tls]# openssl genrsa -out private/cakey.pem 4096
Generating RSA private key, 4096 bit long modulus (2 primes)
......................................................................++++
...............++++
e is 65537 (0x010001)

 

Generate RootCA certificate

IMPORTANT NOTE:
Many people miss most important points when they are creating a CSR. If you are not sure about what should be added for individual fields then I would recommend to read this article before you generate CSR:

Things to consider when creating CSR with OpenSSL

Next we will create our RootCA certificate using openssl x509 command. We have explicitly defined v3_ca extension to be used for the rootCA certificate. We have already defined v3_ca field with the x509 extensions required for RootCA.

[root@controller tls]# openssl req -new -x509 -days 3650 -config openssl.cnf -extensions v3_ca -key private/cakey.pem -out certs/cacert.pem
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [IN]:
State or Province Name (full name) [Some-State]:Karnataka
Locality Name (eg, city) [BANGALORE]:
Organization Name (eg, company) [GoLinuxCloud]:
Organizational Unit Name (eg, section) []:RootCA
Common Name (eg, your name or your server's hostname) []:rootca.com
Email Address []:

Following are the list of files available under /root/tls at this stage:

[root@controller tls]# tree .

Sample Output:
openssl ca vs openssl x509 comparison [With Examples]

 

Verify RootCA certificate X509 Extensions

Verify the x509 extensions from the rootca certificate:

[root@controller tls]# openssl x509 -noout -text -in certs/cacert.pem | grep -A10 "X509v3 extensions:"
        X509v3 extensions:
            X509v3 Subject Key Identifier:
                61:01:DC:7C:C2:5D:41:BF:2B:BE:B2:D8:33:69:23:7A:15:C2:B1:A5
            X509v3 Authority Key Identifier:
                keyid:61:01:DC:7C:C2:5D:41:BF:2B:BE:B2:D8:33:69:23:7A:15:C2:B1:A5

            X509v3 Basic Constraints: critical
                CA:TRUE
            Netscape Comment:
                OpenSSL Generated Certificate
    Signature Algorithm: sha512WithRSAEncryption

 

Generate and sign certificate using openssl x509 command

In this section we will generate and sign certificates using openssl x509 command. I will use /certs_x509 directory to store the certificates we create in this section.

 

Generate private key

First let us generate the private key for the server certificate:

[root@controller certs_x509]# openssl genrsa -out server.key.pem 4096
Generating RSA private key, 4096 bit long modulus (2 primes)
....................................................................................................................................++++
................................................................................................................................++++
e is 65537 (0x010001)

 

Generate Certificate Signing request

Next we will generate CSR for the server certificate:

[root@controller certs_x509]# openssl req -new -key server.key.pem -out server.csr
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [XX]:IN
State or Province Name (full name) []:KARNATAKA
Locality Name (eg, city) [Default City]:BENGALURU
Organization Name (eg, company) [Default Company Ltd]:GOLINUXCLOUD
Organizational Unit Name (eg, section) []:ADMIN
Common Name (eg, your name or your server's hostname) []:controller.example.com
Email Address []:admin@golinuxcloud.com

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
NOTE:
I have provided different values for State name, locality name and organization name compared to the CSR I used for RootCA certificate. Now this may not be important in this section but this will be important factor when we use openssl ca command to generate and sign certificates

 

Generate and sign certificate using openssl x509 command

Next we will use openssl x509 command to sign and generate 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.cert.pem  -CAcreateserial -CAserial serial -days 365 -sha256
Signature ok
subject=C = IN, ST = KARNATAKA, L = BENGALURU, O = GOLINUXCLOUD, OU = ADMIN, CN = controller.example.com, emailAddress = admin@golinuxcloud.com
Getting CA Private Key

Here,

  • -CA specifies the CA certificate to be used for signing.
  • -CAkey sets the CA private key to sign a certificate with.
  • -out specifies the output filename to write to or standard output by default.
  • -CAcreateserial with this option the CA serial number file is created if it does not exist.
  • -CAserial serial sets the CA serial number file to use.
  • -days specifies the number of days to make a certificate valid for.

Verify if the certificate and the serial file have been created in the current working directory:

[root@controller certs_x509]# ls -l
total 16
-rw-r--r-- 1 root root   41 Aug 28 17:51 serial
-rw-r--r-- 1 root root 2009 Aug 28 17:51 server.cert.pem
-rw-r--r-- 1 root root 1781 Aug 28 17:45 server.csr
-rw------- 1 root root 3243 Aug 28 17:44 server.key.pem

Check the content of the serial file:

[root@controller certs_x509]# cat serial
7E107B565C51DFD2F24B279953215D2AAF689F16

You can also check the serial of the certificate using following command:

[root@controller certs_x509]#  openssl x509 -in server.cert.pem -noout -serial
serial=7E107B565C51DFD2F24B279953215D2AAF689F16

 

What would happen if I sign the same certificate again?

Let us try to sign the same certificate again using the rootCA:

[root@controller certs_x509]# openssl x509 -req -in server.csr  -CA /root/tls/certs/cacert.pem -CAkey /root/tls/private/cakey.pem -out server.cert.pem  -CAcreateserial -CAserial serial -days 365 -sha256
Signature ok
subject=C = IN, ST = KARNATAKA, L = BENGALURU, O = GOLINUXCLOUD, OU = ADMIN, CN = controller.example.com, emailAddress = admin@golinuxcloud.com
Getting CA Private Key

As you case see, the openssl x509 has again signed the certificate without any issues. It has also updated the serial number of the certificate:

[root@controller certs_x509]# cat serial
7E107B565C51DFD2F24B279953215D2AAF689F17

[root@controller certs_x509]#  openssl x509 -in server.cert.pem -noout -serial
serial=7E107B565C51DFD2F24B279953215D2AAF689F17

This is because openssl x509 does not maintain a database of the certificate it signs using the root CA certificate. So it can sign the same certificate multiple times without the need of revocation.

 

Generate and sign certificate using openssl ca command

Now in this section we will generate and sign certificates using openssl ca command. This should give you a basic idea of the difference between both the command.

I will store all the certificates generated at this section under /certs_ca directory.

 

Generate private key

First of all let us generate a private key for the server certificate:

[root@controller certs_ca]# openssl genrsa -out server.key.pem 4096
Generating RSA private key, 4096 bit long modulus (2 primes)
.......................................................................................++++
.....................++++
e is 65537 (0x010001)

 

Generate CSR

Next we will generate the Certificate Signing Request. Here also we will intentionally provide a different value for respective fields compared to what we provided with RootCA CSR:

[root@controller certs_ca]# openssl req -new -key server.key.pem -out server.csr                                         
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [XX]:IN
State or Province Name (full name) []:Karnataka
Locality Name (eg, city) [Default City]:Bengaluru
Organization Name (eg, company) [Default Company Ltd]:Some Company
Organizational Unit Name (eg, section) []:Admin
Common Name (eg, your name or your server's hostname) []:controller.example.com
Email Address []:

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:

 

Generate and sign server certificate

Now let us use openssl ca to generate and sign the certificate. With openssl we must provide a valid openssl.cnf file which will contain all the details such as location of certificates, serial and index.txt files etc. We will use the openssl.cnf which we had created for rootCA certificate.

[root@controller certs_ca]# openssl ca -config /root/tls/openssl.cnf  -days 2650 -notext -batch  -in server.csr -out server.crt
Using configuration from /root/tls/openssl.cnf
Check that the request matches the signature
Signature ok
The Subject's Distinguished Name is as follows
countryName           :PRINTABLE:'IN'
stateOrProvinceName   :ASN.1 12:'Karnataka'
localityName          :ASN.1 12:'Bengaluru'
organizationName      :ASN.1 12:'Some Company'
organizationalUnitName:ASN.1 12:'Admin'
commonName            :ASN.1 12:'controller.example.com'
The organizationName field is different between
CA certificate (GoLinuxCloud) and the request (Some Company)

As expected the openssl ca command failed to sign the certificate because the State Name is different in the rootCA CSR compared to the CSR which we generated for our server certificate.

This is another difference between openssl ca and openssl x509 commands. The openssl x509 command doesn't aggressively match the Subject details between Issuer and the consumer while openssl ca command follows the policy section of openssl.cnf to match these values.

I had already explained this part in Things to consider when creating CSR with OpenSSL

You can check the policy section used for RootCA in our openssl.cnf:

[ policy_match ]
countryName             = match
stateOrProvinceName     = match
organizationName        = match
organizationalUnitName  = optional
commonName              = supplied
emailAddress            = optional

So the rootCA expects that countryName, stateOrProvinceName and organizationName is exactly the same between RootCA and certificate which wants to get signed from this rootCA.

You may also modify the policy and generate your RootCA accordingly.

But for now, we will re-generate our CSR for the server certificate with the same values as used for RootCA:

[root@controller certs_ca]# openssl req -new -key server.key.pem -out server.csr                                         
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [XX]:IN
State or Province Name (full name) []:Karnataka
Locality Name (eg, city) [Default City]:BANGALORE
Organization Name (eg, company) [Default Company Ltd]:GoLinuxCloud
Organizational Unit Name (eg, section) []:Dev
Common Name (eg, your name or your server's hostname) []:controller.example.com
Email Address []:

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:

Next re-attempt to sign and generate a server certificate using openssl ca command:

[root@controller certs_ca]# openssl ca -config /root/tls/openssl.cnf  -days 2650 -notext -batch  -in server.csr -out server.crt
Using configuration from /root/tls/openssl.cnf
Check that the request matches the signature
Signature ok
The Subject's Distinguished Name is as follows
countryName           :PRINTABLE:'IN'
stateOrProvinceName   :ASN.1 12:'Karnataka'
localityName          :ASN.1 12:'BANGALORE'
organizationName      :ASN.1 12:'GoLinuxCloud'
organizationalUnitName:ASN.1 12:'Dev'
commonName            :ASN.1 12:'controller.example.com'
Certificate is to be certified until Nov 29 13:15:29 2028 GMT (2650 days)

Write out database with 1 new entries
Data Base Updated

We have successfully signed and generated a server certificate.

Verify the index.txt and serial file content inside /root/tls:

[root@controller certs_ca]# cat /root/tls/index.txt
V       281129131529Z           01      unknown /C=IN/ST=Karnataka/O=GoLinuxCloud/OU=Dev/CN=controller.example.com

[root@controller certs_ca]#  openssl x509 -in server.crt -noout -serial
serial=01

[root@controller certs_ca]# cat /root/tls/serial
02

As you can see, serial=01 is assigned to the certificate which we just created and the same has been updated in /root/tls/index.txt file. Since 01 serial number is assigned to a certificate so the serial number has automatically been incremented to 02.

This proves what I mentioned earlier, openssl ca command maintains a database of all the certificates signed.

 

What would happen if I sign the same certificate again?

But let us try to re-sign the same certificate again. If you remember this had worked with openssl x509 command in the previous section:

[root@controller certs_ca]# openssl ca -config /root/tls/openssl.cnf  -days 2650 -notext -batch  -in server.csr -out server.crt
Using configuration from /root/tls/openssl.cnf
Check that the request matches the signature
Signature ok
The Subject's Distinguished Name is as follows
countryName           :PRINTABLE:'IN'
stateOrProvinceName   :ASN.1 12:'Karnataka'
localityName          :ASN.1 12:'BANGALORE'
organizationName      :ASN.1 12:'GoLinuxCloud'
organizationalUnitName:ASN.1 12:'Dev'
commonName            :ASN.1 12:'controller.example.com'
ERROR:There is already a certificate for /C=IN/ST=Karnataka/O=GoLinuxCloud/OU=Dev/CN=controller.example.com
The matching entry has the following details
Type          :Valid
Expires on    :281129131529Z
Serial Number :01
File name     :unknown
Subject Name  :/C=IN/ST=Karnataka/O=GoLinuxCloud/OU=Dev/CN=controller.example.com

So unlike openssl x509 command, the openssl ca command will not allow you to sign the same certificate again as the database already contains an entry for this Common Name.

To sign the same certificate again, you must first revoke this certificate and then you can sign it again.

 

Summary

In this article I have explained and covered the similarities and difference between openssl ca and openssl x509 commands. You must choose your command only based on your requirement. As for lab use cases when we may want to have a common certificate for multiple servers, then we may choose openssl x509 to sign the certificate but if you want to maintain a proper database of all the certificates signed then in such case you should go for openssl ca command to sign the certificates.

I hope I have covered all the scenarios related to this topic, let me know if you have any questions or feedback using the comments section below.

 

Further Reading

man page for openssl ca command
man page for openssl x509 command

 

Deepak Prasad

He is the founder of GoLinuxCloud and brings over a decade of expertise in Linux, Python, Go, Laravel, DevOps, Kubernetes, Git, Shell scripting, OpenShift, AWS, Networking, and Security. With extensive experience, he excels in various domains, from development to DevOps, Networking, and Security, ensuring robust and efficient solutions for diverse projects. You can reach out to him on his LinkedIn profile or join on Facebook page.

Can't find what you're searching for? Let us assist you.

Enter your query below, and we'll provide instant results tailored to your needs.

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 send mail to admin@golinuxcloud.com

Thank You for your support!!

Leave a Comment

X