In this article we will explore Elliptic Curve Cryptography (ECC) and generate ECC certificates using OpenSSL. We will be creating CA certificate, server and client certificates using ECC private key and later we will use this certificate with Apache server for demonstration.
1. Overview on Elliptic Curve Cryptography (ECC)
- Elliptic Curve Cryptography (ECC) is an encryption technique that provides public-key encryption similar to RSA.
- While the security strength of RSA is based on very large prime numbers, ECC uses the mathematical theory of elliptic curves and achieves the same security level with much smaller keys.
- ECC does not replace RSA for authenticating the communication partners, but is used for generating the ephemeral DH session key with the help of an EC private key. RSA is still used for providing authentication.
- The main advantage of Elliptic Curve Cryptography with Diffie-Hellman (ECDHE-RSA) over plain Diffie-Hellman (DHE-RSA) is better performance and the same level of security with less key bits.
- A disadvantage is the additional effort for creating and maintaining the EC key.
2. RSA vs ECC keys
Compared to traditional algorithms such as RSA, ECC makes it possible to create smaller keys, with obvious advantages both in terms of computational efficiency and the required working memory.
In the following table we have a comparison between different size of the RSA and ECC keys to achieve the same level of security:
RSA size (in bits) | ECC size |
---|---|
1024 | 160 |
2048 | 224 |
3072 | 256 |
7680 | 384 |
15360 | 521 |
However, ECC is mainly used in the management of key exchange and digital signatures, rather than in encryption. Even in the case of ECC, once a secure key exchange protocol has been established between two counterparts, it is possible to share a symmetric encryption key to carry out efficient communication encoding.
3. List available ECC curves
ECC is based on domain parameters defined by various standards. You can see the list of all available standards defined and recommended elliptical cryptography curves using the following openssl command.
[root@server ~]# openssl ecparam -list_curves
secp256k1 : SECG curve over a 256 bit prime field
secp384r1 : NIST/SECG curve over a 384 bit prime field
secp521r1 : NIST/SECG curve over a 521 bit prime field
prime256v1: X9.62/SECG curve over a 256 bit prime field
The recommended ECC key size is 256-bit so we wll use prime256v1
to generate all our ECC private keys in this tutorial. If greater encryption strength is required, your other private key option is secp384r1
.
I will be using following version of openssl for this article:
[root@server ~]# rpm -q openssl
openssl-1.0.2k-19.el7.x86_64
4. Lab Environment
I will be using two virtual machines to generate and validate the ECC certificates. These virtual machines are running on Oracle VirtualBox and installed with CentOS 7 and 8. Out of these two VMs, one will act as a server will the other will act as a client. I will use the server node to generate all the certificates. The hostname of the server node is server.example.com
with an IP address of 192.168.0.114
while the hostname of client node is server-2.example.com
with an IP address of 192.168.0.152
5. Create CA certificate with ECC Key
First we would need a CA certificate required to sign the server and client certificate. We will use ECC private key to generate the root CA certificate. For this purpose I will create a separate directory structure to store the CA certificate, keys and index database:
[root@server ~]# mkdir /root/tls [root@server tls]# cd /root/tls
In this directory I will create separate directory to store the private key and the CA certificate
[root@server tls]# mkdir private certs
Additionally we also need a serial
and index.txt
to track of the certificates that have been issued by the CA.
[root@server tls]# touch index.txt [root@server tls]# echo 01 > serial
We will also need an openssl configuration file. You can take openssl.cnf
file available inside /etc/pki/CA
. I have created a new file for me inside /root/tls
with the following content. You can read more about each section at Configure openssl.cnf for Root CA Certificate
[root@server tls]# cat /root/tls/openssl.cnf # # OpenSSL example configuration file. # This is mostly being used for generation of certificate requests. # # This definition stops the following lines choking if HOME isn't # defined. HOME = . RANDFILE = $ENV::HOME/.rnd # Extra OBJECT IDENTIFIER info: #oid_file = $ENV::HOME/.oid oid_section = new_oids # To use this configuration file with the "-extfile" option of the # "openssl x509" utility, name here the section containing the # X.509v3 extensions to use: # extensions = # (Alternatively, use a configuration file that has only # X.509v3 extensions in its main [= default] section.) [ new_oids ] # We can add new OIDs in here for use by 'ca', 'req' and 'ts'. # Add a simple OID like this: # testoid1=1.2.3.4 # Or use config file substitution like this: # testoid2=${testoid1}.5.6 # Policies used by the TSA examples. tsa_policy1 = 1.2.3.4.1 tsa_policy2 = 1.2.3.4.5.6 tsa_policy3 = 1.2.3.4.5.7 #################################################################### [ 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 database = $dir/index.txt # database index file. # several certs with same subject. new_certs_dir = $dir/certs # default place for new certs. certificate = $dir/certs/ec-cacert.pem # The CA certificate serial = $dir/serial # The current serial number crlnumber = $dir/crlnumber # the current crl number # must be commented out to leave a V1 CRL private_key = $dir/private/ec-cakey.pem # The private key name_opt = ca_default # Subject Name options cert_opt = ca_default # Certificate field options default_days = 365 # how long to certify for default_crl_days= 30 # how long before next CRL default_md = sha256 # use SHA-256 by default preserve = no # keep passed DN ordering policy = policy_match # For the CA policy [ policy_match ] countryName = match stateOrProvinceName = match organizationName = match 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 = 2048 default_md = sha256 default_keyfile = privkey.pem distinguished_name = req_distinguished_name attributes = req_attributes x509_extensions = v3_ca # The extentions to add to the self signed cert [ 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 server\'s 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 [ v3_req ] # Extensions to add to a certificate request basicConstraints = CA:FALSE keyUsage = nonRepudiation, digitalSignature, keyEncipherment [ v3_ca ] # Extensions for a typical CA subjectKeyIdentifier=hash authorityKeyIdentifier=keyid:always,issuer basicConstraints = critical,CA:true [ crl_ext ] # issuerAltName=issuer:copy authorityKeyIdentifier=keyid:always
5.1 Create ECC Private key
We will create ECC private key using openssl command:
[root@server tls]# openssl ecparam -out private/ec-cakey.pem -name prime256v1 -genkey
By default, when generating a private key, openssl will only store the name of the curve in the generated parameters or key file, not the full set of explicit parameters associated with that name. For example:
[root@server tls]# openssl ecparam -in private/ec-cakey.pem -text -noout
ASN1 OID: prime256v1
NIST CURVE: P-256
5.2 Generate CA certificate
Next we will generate CA certificate using the ECC private key we created earlier.
[root@server tls]# openssl req -new -x509 -days 3650 -config openssl.cnf -extensions v3_ca -key private/ec-cakey.pem -out certs/ec-cacert.pem
Sample output snippet from my terminal:
Next you can verify the content of the CA certificate and the signing algorithm used:
[root@server tls]# openssl x509 -noout -text -in certs/ec-cacert.pem | grep -i algorithm Signature Algorithm: ecdsa-with-SHA256 Public Key Algorithm: id-ecPublicKey Signature Algorithm: ecdsa-with-SHA256
As you can see, we have used ECDSA Signature Algorithm to create our rootCA certificate instead of RSA Encryption algorithm.
5.3 Verify the CA certificate with private key
If you wish to verify a certificate with an private key (including ECDSA key) using openssl then get the public key from the certificate:
[root@server tls]# openssl x509 -noout -pubkey -in certs/ec-cacert.pem
Sample output from my terminal:
Similarly, get the public key from the private key:
[root@server tls]# openssl pkey -pubout -in private/ec-cakey.pem
Sample output from my terminal:
Now you can match both the public keys from certificate and the private key. As you can check, both are exactly same in my case.
6. Generate server certificate
We will now create server certificate using ECC private key. To store these server certificates I will create another directory /root/server_certs
:
[root@server tls]# mkdir /root/server_certs/ [root@server tls]# cd /root/server_certs/
6.1 Generate ECC private key
We would need a private key for the server certificate. We will again use prime256v1 curve to generate this ECC key:
[root@server server_certs]# openssl ecparam -out server.key -name prime256v1 -genkey
Verify the name of the curve used in the private key:
[root@server server_certs]# openssl ecparam -in server.key -text -noout
ASN1 OID: prime256v1
NIST CURVE: P-256
6.2 Create Certificate Signing Request (CSR)
Next we need to create a CSR to sign the server certificate. The following command will prompt for multiple details such as Country Name, State or Province name, Locality name etc. It is important that you fill this data properly.
These data would be matched against the CA certificate while creating the server certificate. Our CA certificate was created using v3_ca
extension from the openssl.cnf
which contains following:
# For the CA policy
[ policy_match ]
countryName = match
stateOrProvinceName = match
organizationName = match
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
So here the CA certificate will match Country Name, state or Province Name and Organization Name. SO the values you provide for your CSR of server certificate must match with what we gave earlier for the CA certificate.
The Common Name must be the hostname/FQDN name of the server node. The Name is the one which will be used by the client to connect and authenticate with the server. If you feel there can be more than one FQDN of the server, for example a client can send request via IP address of the server, or only the hostname or using a FQDN so in such case you should create a SAN certificate.
Execute the following command to generate the CSR:
[root@server server_certs]# openssl req -new -key server.key -out server.csr -sha256
Sample output from my terminal:
6.3 Create server certificate
Now we will create our server certificate which would require the ECC CA private key, CA certificate to sign the certificate along with server.csr
which we created in the previous step:
[root@server server_certs]# openssl ca -keyfile /root/tls/private/ec-cakey.pem -cert /root/tls/certs/ec-cacert.pem -in server.csr -out server.crt -config /root/tls/openssl.cnf Using configuration from /root/tls/openssl.cnf Check that the request matches the signature Signature ok Certificate Details: Serial Number: 1 (0x1) Validity Not Before: Apr 9 18:09:14 2021 GMT Not After : Apr 9 18:09:14 2022 GMT Subject: countryName = IN stateOrProvinceName = Karnataka organizationName = GoLinuxCloud organizationalUnitName = Test commonName = server emailAddress = admin@golinuxcloud.com Certificate is to be certified until Apr 9 18:09:14 2022 GMT (365 days) Sign the certificate? [y/n]:y 1 out of 1 certificate requests certified, commit? [y/n]y Write out database with 1 new entries Data Base Updated
6.4 Validate the server certificate
Verify the server certificate against the CA certificate:
[root@server server_certs]# openssl verify -CAfile /root/tls/certs/ec-cacert.pem server.crt
server.crt: OK
You can also verify the Signature Algorithm to make sure it is using ECC Private Key:
[root@server server_certs]# openssl x509 -noout -text -in server.crt | grep -i algorithm Signature Algorithm: ecdsa-with-SHA256 Public Key Algorithm: id-ecPublicKey Signature Algorithm: ecdsa-with-SHA256
Verify the index.txt
contain which should contain the detail of the server certificate which we just signed using the CA certificate. Here 01 is the serial which we have assigned at the starting of this article. Henceforth every time a certificate is signed, the serial file value will be incremented.
[root@server client_certs]# cat /root/tls/index.txt
V 220409180914Z 01 unknown /C=IN/ST=Karnataka/O=GoLinuxCloud/OU=Test/CN=server/emailAddress=admin@golinuxcloud.com
7. Generate client certificate
We will also create a client certificate to have mutual TLS authentication (MTLS). If you only have a requirement of server certificate then you can ignore this step.
I will create a separate directory to create and store the client certificate:
[root@server ~]# mkdir /root/client_certs/ [root@server ~]# cd /root/client_certs/
7.1 Generate ECC private key
We would again need a private key for the client certificate. Since this article is all about generating ECC certificates so our private key should be of ECC format:
[root@server client_certs]# openssl ecparam -out client.key -name prime256v1 -genkey
Verify the name of the curve used in the private key:
[root@server server_certs]# openssl ecparam -in client.key -text -noout
ASN1 OID: prime256v1
NIST CURVE: P-256
7.2 Create Certificate Signing Request (CSR)
We will now create a certificate signing request for the client certificate. All the rules I explained under "Creating CSR for server certificate" section, also applies here. If you are using the openssl.cnf
which I have shared then make sure the Country Name, State or Province Name and Organization Name matches with what we gave in the CA certificate.
[root@server client_certs]# openssl req -new -key client.key -out client.csr -sha256
The Common Name must contain the FQDN or hostname of the client node. In my case the FQDN of my client node is server-2.example.com
which will send the authentication request to the server. You may also choose to create a SAN certificate with multiple Subject Alternative Names.
Sample output from my terminal:
7.3 Create client certificate
Now we have everything needed to create our client certificate using openssl:
[root@server client_certs]# openssl ca -keyfile /root/tls/private/ec-cakey.pem -cert /root/tls/certs/ec-cacert.pem -in client.csr -out client.crt -config /root/tls/openssl.cnf Using configuration from /root/tls/openssl.cnf Check that the request matches the signature Signature ok Certificate Details: Serial Number: 2 (0x2) Validity Not Before: Apr 9 18:13:16 2021 GMT Not After : Apr 9 18:13:16 2022 GMT Subject: countryName = IN stateOrProvinceName = Karnataka organizationName = GoLinuxCloud organizationalUnitName = Dummy commonName = server-2.example.com emailAddress = admin@golinuxcloud.com Certificate is to be certified until Apr 9 18:13:16 2022 GMT (365 days) Sign the certificate? [y/n]:y 1 out of 1 certificate requests certified, commit? [y/n]y Write out database with 1 new entries Data Base Updated
You can also verify the index.txt
to make sure, the database is updated and it contains the detail of server-2.example.com getting signed from the CA certificate:
[root@server client_certs]# cat /root/tls/index.txt
V 220409180914Z 01 unknown /C=IN/ST=Karnataka/O=GoLinuxCloud/OU=Test/CN=server/emailAddress=admin@golinuxcloud.com
V 220409181316Z 02 unknown /C=IN/ST=Karnataka/O=GoLinuxCloud/OU=Dummy/CN=server-2.example.com/emailAddress=admin@golinuxcloud.com
8. Configure Apache with SSL (HTTPS) with ECC certificates
We will validate our ECC certificates using a simple apache server.
8.1 Install Apache packages
So first let us install the required packages to setup an HTTPS web server:
[root@server ~]# yum -y install httpd mod_ssl
8.2 Configure apache server
I will create a new directory certs under /etc/httpd/conf.d
where I will store all the server certificates and the same path is provided in our httpd.conf
[root@server ~]# mkdir /etc/httpd/conf.d/certs [root@server ~]# cd /etc/httpd/conf.d/certs
Next we will copy the server certificates to this location:
[root@server certs]# cp -v /root/server_certs/* .
‘/root/server_certs/server.crt’ -> ‘./server.crt’
‘/root/server_certs/server.csr’ -> ‘./server.csr’
‘/root/server_certs/server.key’ -> ‘./server.key’
If you are setting up apache on a different server then you can copy these certificates to different node using scp or rsync accordingly.
We would also need the CA certificate here:
[root@server certs]# cp -v /root/tls/certs/ec-cacert.pem .
‘/root/tls/certs/ec-cacert.pem’ -> ‘./ec-cacert.pem’
We will change the port number of the apache server to 8443 in /etc/httpd/conf/httpd.conf
:
Listen 8443
Also add the following content to the end of /etc/httpd/conf/httpd.conf
file to configure virtual hosting:
<VirtualHost *:8443> SSLEngine On SSLCertificateFile /etc/httpd/conf.d/certs/server.crt SSLCertificateChainFile /etc/httpd/conf.d/certs/ec-cacert.pem SSLCertificateKeyFile /etc/httpd/conf.d/certs/server.key ServerAdmin root@server.example.com DocumentRoot /var/www/html ServerName server.example.com ErrorLog logs/server.example.com-error_log CustomLog logs/server.example.com-access_log common </VirtualHost>
You can check the man page of mod_ssl to get more details on these individual parameters.
Enable port 8443
in the firewall on the server node, I am using firewalld in my setup:
[root@server certs]# firewall-cmd --add-port=8443/tcp --permanent success [root@server certs]# firewall-cmd --reload success
I will add some content to my index.html on the web server:
[root@server certs]# echo "Welcome to server.example.com" > /var/www/html/index.html
Restart the apache service to activate the changes:
[root@server certs]# systemctl restart httpd
Make sure port 8443 is in LISTEN state used by httpd:
[root@server certs]# netstat -ntlp | grep 8443
tcp6 0 0 :::8443 :::* LISTEN 7832/httpd
9. Configure client node for authentication
We will copy our client certificates over to the client node. I have already created a directory /root/certs on the client node to store the certificates and private key:
[root@server certs]# scp -r /root/client_certs/* 192.168.0.152:/root/certs/
root@192.168.0.152's password:
client.crt 100% 2084 3.6MB/s 00:00
client.csr 100% 554 1.1MB/s 00:00
client.key 100% 302 637.3KB/s 00:00
We would also need the CA certificate for the mutual TLS authentication:
[root@server certs]# scp -r /root/tls/certs/ec-cacert.pem 192.168.0.152:/root/certs/
root@192.168.0.152's password:
ec-cacert.pem 100% 940 1.5MB/s 00:00
10. Validate mutual TLS authentication with ECC certificates
Since I don't have any internal DNS to resolve the hostname of the server and client node, I will update the /etc/hosts of the client node with the server details:
[root@server-2 ~]# cat /etc/hosts
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
192.168.0.114 server server.example.com
Now we will use curl
to connect to our web server from the client node:
[root@server-2 ~]# curl --key /root/certs/client.key --cert /root/certs/client.crt --cacert /root/certs/ec-cacert.pem https://server:8443 -v * Rebuilt URL to: https://server:8443/ * Trying 192.168.0.114... * TCP_NODELAY set * Connected to server (192.168.0.114) port 8443 (#0) * ALPN, offering h2 * ALPN, offering http/1.1 * successfully set certificate verify locations: * CAfile: /root/certs/ec-cacert.pem CApath: none * TLSv1.3 (OUT), TLS handshake, Client hello (1): * TLSv1.3 (IN), TLS handshake, Server hello (2): * TLSv1.2 (IN), TLS handshake, Certificate (11): * TLSv1.2 (IN), TLS handshake, Server key exchange (12): * TLSv1.2 (IN), TLS handshake, Server finished (14): * TLSv1.2 (OUT), TLS handshake, Client key exchange (16): * TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1): * TLSv1.2 (OUT), TLS handshake, Finished (20): * TLSv1.2 (IN), TLS handshake, Finished (20): * SSL connection using TLSv1.2 / ECDHE-ECDSA-AES256-GCM-SHA384 * ALPN, server did not agree to a protocol * Server certificate: * subject: C=IN; ST=Karnataka; O=GoLinuxCloud; OU=Test; CN=server; emailAddress=admin@golinuxcloud.com * start date: Apr 9 18:09:14 2021 GMT * expire date: Apr 9 18:09:14 2022 GMT * common name: server (matched) * issuer: C=IN; ST=Karnataka; L=BANGALORE; O=GoLinuxCloud; OU=GoLinuxCloud; CN=ca-server; emailAddress=admin@golinuxcloud.com * SSL certificate verify ok. > GET / HTTP/1.1 > Host: server:8443 > User-Agent: curl/7.61.1 > Accept: */* > < HTTP/1.1 200 OK < Date: Fri, 09 Apr 2021 19:41:07 GMT < Server: Apache/2.4.6 (CentOS) OpenSSL/1.0.2k-fips < Last-Modified: Fri, 19 Mar 2021 09:40:58 GMT < ETag: "1e-5bde083680e36" < Accept-Ranges: bytes < Content-Length: 30 < Content-Type: text/html; charset=UTF-8 < Welcome to server.example.com * Connection #0 to host server left intact
As you can see the connection was successful. So our ECC cretifates are working as expected.
11. Summary
In this tutorial we covered following topics
- We learned about Elliptic Curve Cryptography (ECC) encryption algorithm.
- We understood the difference between RSA and ECC keys
- We created ECC private keys andverify the algorithm
- We created CA certificate, server and client certificate using ECC private keys
- We then validated our certificate authentication using an apache server.
12. Further Readings
What is Elliptic Curve Cryptography?
Command Line Elliptic Curve Operations
Elliptic Curve Cryptography (ECC) Cipher Suites for Transport Layer Security (TLS)
OpenSSL ECDSA
Related Searches: openssl ecdsa, generate ecdsa certificate openssl, openssl ecdsa example, openssl ecdsa sha256, openssl generate ecc certificate, openssl generate ecc certificate, generate ecdsa certificate openssl, ecdsa certificate example, openssl ec private key, ecdsa key generation
I have all of these and I never installed anything. I am a victim of Cyber hacking. What do I do next?
Just have a certificate will not secure you completely. You have to also secure your network with proper firewalls and polices for un-authorized access.
Good tutorial ! Great. There is a mistake while creating the directory ‘cert’ at the beginning. It should be ‘certs’.
Thanks for highlighting this. Updated the article