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
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
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.
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”)?
Just to say “thank you” for this amazing tutorial.
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.
———–
please suggest how can I verify its CA signed or not ?
This would mean that the
ca.cert.pem
was not used to signserver.crt
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 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.
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
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:
?
Yes, you are correct. Thanks for highlighting, I have tested the same and updated the article
To encrypt:
To decrypt:
Great, thanks again.
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).
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
Thanks a lot ! that was helpful 😀
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?
You can use any machine that wouldn’t matter, just make sure you use proper CN while generating CSR as that is all what matters.
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 ??
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