How to create Self-Signed CA Certificate with OpenSSL


OpenSSL

In most cases you can get away by using self-signed certificate for internal testing but there are scenarios where you may need a certificate signed by CA certificate. Now obviously for local testing it is not possible for everyone to have a certificate signed by third party CA so in such case we can create our own self-signed CA certificate. This CA certificate will act as a fake authority and sign the certificate. This is perfect for internal testing but not recommended for production environments.

In this article I will share the steps to create your own Self-Signed Certificate Authority which we can use to sign any CSR and get the certificate. I will be using Ubuntu distribution for all my tests but the openssl commands are distribution independent and they should work globally. Although some arguments may be version specific so if you face any issues with the arguments used in this tutorial then you can use comments section to report your concern.

 

Step 1: Install OpenSSL

First, make sure OpenSSL is installed on your system. On Debian based distribution you can use apt package manager to install it using the following command:

sudo apt-get update
sudo apt-get install openssl

On Red Hat based distribution you can use yum or dnf package manager:

dnf -y install openssl

It is possible that openssl is installed by default in most Linux distribution which you can verify using:

openssl version

I will be using following version for the demonstration:

OpenSSL 3.0.2 15 Mar 2022 (Library: OpenSSL 3.0.2 15 Mar 2022)

 

Step 2: Generate a Private Key

Generate a private key for your CA using the following command. You can choose either RSA or ECDSA. Based on the algorithm the key size would also vary. You can read more at RSA vs ECC Keys .

In this article we will use RSA Key but it wouldn't make any difference for signing purpose. You can sign a RSA certificate using a CA certificate generated with ECC Key and vice versa.

openssl genrsa -out ca.key 4096

 

Step 3: Create Self-Signed CA Certificate

Now there are couple of ways using which we can generate self-signed CA certificate. It depends on the kind of testing you intend to perform and your requirement. For example if you want to perform certificate signing, revocation and you want to maintain a database or you just don't care about database and you just want to sign the certificate.

I will cover steps for both the methods so you can check and choose accordingly based on your requirement:

 

1. Without maintaining database

In this section the idea is to just have a self-signed CA certificate which can be used to sign CSR but we don't want to maintain any database of all the list of signed or revoked certificates.

Create a small config file with following content, we will name it extfile.cnf:

[ req ]
distinguished_name = req_distinguished_name
x509_extensions = v3_ca
prompt = no

[ req_distinguished_name ]
C = IN
ST = Karnataka
L = Bengaluru
O = GoLinuxCloud
OU = Sme Organizational Unit
CN = RootCA

[ v3_ca ]
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
basicConstraints = critical,CA:true
keyUsage = critical, digitalSignature, cRLSign, keyCertSign

You can update the req_distinguished_name based on your environment. Next use this config file to generate self-signed CA certificate:

openssl req -new -x509 -days 3650 -key ca.key -out ca.crt -config extfile.cnf

Verify the CA certificate content:

openssl x509 -in ca.crt -text -noout
How to create Self-Signed CA Certificate with OpenSSL

Now any certificate signed by this certificate will have the same Issuer details:

Issuer: C = IN, ST = Karnataka, L = Bengaluru, O = GoLinuxCloud, OU = Sme Organizational Unit, CN = RootCA

 

2. Maintain database of signed and revoked certificates

In this section we will setup our environment so that we can maintain the list of all the signed and revoked certificates. This is helpful for security audits and tracking. I have covered this in more detail under OpenSSL create certificate chain [Root & Intermediate CA]

Let me create a directory structure where I will store certificates, keys, index etc.

mkdir -p ~/myCA/rootCA/{certs,crl,newcerts,private,csr}

Create a serial file which will be used to keep track of all the issued certificates. We can use any starting integer such as 0 or 1 or 500 any other number. This will act as starting integer and will get incremented the next time this CA will issue a certificate.

echo 1000 > ~/myCA/rootCA/serial

Similarly we need to create a serial file for tracking all revoked certificates which we will name as crlnumber. We will use a different integer for tracking revoked certificates.

echo 0100 > ~/myCA/rootCA/crlnumber 

Next create index.txt which will keep track of all issued certificates:

touch ~/myCA/rootCA/index.txt

Now we will need our openss.cnf which will capture all config and path related data, the same will be used to generate the CA certificate. We had created a smaller version of this file in the previous section but to maintain a database we need some additional config options:

[ ca ]                                                   # The default CA section
default_ca = CA_default # The default CA name

[ CA_default ] # Default settings for the CA
dir = /home/deepak/myCA/rootCA # CA directory
certs = $dir/certs # Certificates directory
crl_dir = $dir/crl # CRL directory
new_certs_dir = $dir/newcerts # New certificates directory
database = $dir/index.txt # Certificate index file
serial = $dir/serial # Serial number file
RANDFILE = $dir/private/.rand # Random number file
private_key = $dir/private/ca.key # Root CA private key
certificate = $dir/certs/ca.crt # Root CA certificate
crl = $dir/crl/ca.crl.pem # Root CA CRL
crlnumber = $dir/crlnumber # Root CA CRL number
crl_extensions = crl_ext # CRL extensions
default_crl_days = 30 # Default CRL validity days
default_md = sha256 # Default message digest
preserve = no # Preserve existing extensions
email_in_dn = no # Exclude email from the DN
name_opt = ca_default # Formatting options for names
cert_opt = ca_default # Certificate output options
policy = policy_strict # Certificate policy
unique_subject = no # Allow multiple certs with the same DN

[ policy_strict ] # Policy for stricter validation
countryName = optional # Must match the issuer's country
stateOrProvinceName = optional # Must match the issuer's state
organizationName = optional # Must match the issuer's organization
organizationalUnitName = optional # Organizational unit is optional
commonName = supplied # Must provide a common name
emailAddress = optional # Email address is optional

[ req ] # Request settings
default_bits = 2048 # Default key size
distinguished_name = req_distinguished_name # Default DN template
string_mask = utf8only # UTF-8 encoding
default_md = sha256 # Default message digest
prompt = no # Non-interactive mode

[ req_distinguished_name ] # Template for the DN in the CSR
countryName = Country Name (2 letter code)
stateOrProvinceName = State or Province Name (full name)
localityName = Locality Name (city)
0.organizationName = Organization Name (company)
organizationalUnitName = Organizational Unit Name (section)
commonName = Common Name (your domain)
emailAddress = Email Address

[ v3_ca ] # Root CA certificate extensions
subjectKeyIdentifier = hash # Subject key identifier
authorityKeyIdentifier = keyid:always,issuer # Authority key identifier
basicConstraints = critical, CA:true # Basic constraints for a CA
keyUsage = critical, keyCertSign, cRLSign # Key usage for a CA

[ crl_ext ] # CRL extensions
authorityKeyIdentifier = keyid:always,issuer # Authority key identifier

[ v3_intermediate_ca ]
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
basicConstraints = critical, CA:true, pathlen:0
keyUsage = critical, digitalSignature, cRLSign, keyCertSign

We will move the ca.key which we created in Step-2 to ~/myCA/rootCA/private/ maintain the structure and secure the file with limited permission:

cp ca.key ~/myCA/rootCA/private/
chmod 400 ~/myCA/rootCA/private/ca.key

Now we are ready to create our self-signed CA certificate:

openssl req -config openssl_root.cnf -key ~/myCA/rootCA/private/ca.key -new -x509 -days 7300 -sha256 -extensions v3_ca -out ~/myCA/rootCA/certs/ca.crt -subj "/C=US/ST=California/L=San Francisco/O=Example Corp/OU=IT Department/CN=RootCA"

Verify the CA certificate:

openssl x509 -noout -text -in ~/myCA/rootCA/certs/ca.crt
How to create Self-Signed CA Certificate with OpenSSL

Now any certificate you sign using the CA certificate will maintain a record or issued certificates.

For testing purpose I will create and sign a certificate using this CA:

# Generate private key
openssl genrsa -out private/server.key.pem 4096

# Generate CSR
openssl req -new -key private/server.key.pem -out csr/server-1.csr

# Issue certificate
openssl ca -config ~/myCA/rootCA/openssl.cnf -in csr/server-1.csr -out certs/server-1.crt -days 2650 -notext -batch

Once the certificate is issued, you can check the index.txt file which should contain the information of signed certificate:

$ cat index.txt
V 310726121603Z 1000 unknown /C=AU/ST=Some-State/O=Internet Widgits Pty Ltd/CN=hostname

and the serial file will get incremented as 1000 is now assigned to an issued certificate:

$ cat serial
1001

Similarly you can attempt to revoke the certificate and validate the crlnumber and index.txt which should contain the revoked certificate details.

 

This concludes our article but you should not stop learning, checkout out other articles on certificate management using OpenSSL in the Left Menu and enhance your knowledge. Let us know if you face any issues or have any questions in the comment section.

 

Deepak Prasad

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 connect with him on his LinkedIn profile.

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!!

15 thoughts on “How to create Self-Signed CA Certificate with OpenSSL”

  1. Thank you very much for your brilliant tutorial!

    1. “openss.cfg” should become “openssl.cfg”
    2. No need to assign permissions to “ca.crt” (e.g. “chmod 400 /path_to/ca.crt”)?

    Reply
  2. Hi,
    Thanks for the neat explanation..
    I able to create a certs properly, so my understanding is Signing with CA means we will be the CA authority which literally own CA.
    when I tried to verify it whether CA signed or not I am getting an error message as below.
    ———–

    $openssl verify -verbose -CAfile ca.cert.pem server.crt
    C = US, ST = Denver, L = Colorado, O = domain INC, OU = Quantum, CN = domain.com, emailAddress = veera@domain.com
    error 18 at 0 depth lookup: self signed certificate
    error server.crt: verification failed

    please suggest how can I verify its CA signed or not ?

    Reply
  3. Hi

    Very helpful articles so thanks for sharing this information.

    Followed the guidance in this article on how to create and use a CA for signing certificates but unfortunately could not get it to work with curl on my Windows 10 machine

    curl -X POST --cacert cacert.pem -d @data.json https://my.domain.com/api -H "Content-Type:application/json"
    
    curl: (60) schannel: CertGetCertificateChain trust error CERT_TRUST_REVOCATION_STATUS_UNKNOWN
    More details here: https://curl.se/docs/sslcerts.html

    curl failed to verify the legitimacy of the server and therefore could not
    establish a secure connection to it. To learn more about this situation and
    how to fix it, please visit the web page mentioned above.

    curl -V
    curl 7.83.1 (Windows) libcurl/7.83.1 Schannel
    Release-Date: 2022-05-13
    Protocols: dict file ftp ftps http https imap imaps pop3 pop3s smtp smtps telnet tftp
    Features: AsynchDNS HSTS IPv6 Kerberos Largefile NTLM SPNEGO SSL SSPI UnixSockets

    I was able to use curl with self-signed certificates but this CA certificate just isn’t working. I’ve searched online but advice appears to be related to using the curl lib rather then the cmdline.

    Any ideas ?

    Thanks

    Reply
  4. Nice article, really helpful – Thanks!

    But in the “HINT” at the end, to remove the password from the server.key file, I think the command needs to also take the pass file, ie:

    openssl rsa -in server.key -out server.key.insecure --inpass file:mypass.enc

    ?

    Reply
    • Yes, you are correct. Thanks for highlighting, I have tested the same and updated the article
      To encrypt:

      openssl genrsa -des3 -passout file:mypass.enc -out server.key 4096

      To decrypt:

      # openssl rsa -in server.key -out server.key.insecure -passin file:mypass.enc
      writing RSA key
      Reply
  5. Thanks for providing this! i have a question, if i want to authenticate client by a his certificate, should i use a root CA ( as you did in the next article ) or i just generate a client key and CSR then sign it with the same CA as the server ?
    ( i am using Apache server locally on my virtual machine).

    Reply
    • Hello, root CA and the CA I use here are not different. it is just that the root CA you are referring was used to create a certificate chain. So you can just create your own CA and use that to sign your certificate along with CSR

      Reply
        • one more question please! should i use more than 1 virtual machine as u did in “OpenSSL create client certificate & server certificate with example” article ? you mentionned that we need to have a CentOS 8 running on Oracle VirtualBox? should i do the same here?

          Reply
            • Hi Admin,

              i have created certificate with Root CA and intermediate and then self-sign but still, it’s showing your CA is not valid as it was from un authorized CA store so how can I resolve the issues ??

              Reply
              • Can you post the exact error you get and what are you trying to do when you get this error? apache server?.
                CAN not valid would generally mean that you are not using the CA which was used to sign the certificate

                Reply

Leave a Comment