OpenSSL: Generate ECC certificate & verify on Apache server - JohnHau/mis GitHub Wiki
https://www.golinuxcloud.com/openssl-generate-ecc-certificate/
Table of Contents
- Overview on Elliptic Curve Cryptography (ECC)
- RSA vs ECC keys
- List available ECC curves
- Lab Environment
- Create CA certificate with ECC Key 5.1 Create ECC Private key 5.2 Generate CA certificate 5.3 Verify the CA certificate with private key
- Generate server certificate 6.1 Generate ECC private key 6.2 Create Certificate Signing Request (CSR) 6.3 Create server certificate 6.4 Validate the server certificate
- Generate client certificate 7.1 Generate ECC private key 7.2 Create Certificate Signing Request (CSR) 7.3 Create client certificate
- Configure Apache with SSL (HTTPS) with ECC certificates 8.1 Install Apache packages 8.2 Configure apache server
- Configure client node for authentication
- Validate mutual TLS authentication with ECC certificates
- Summary
- Further Readings
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.
-
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.
-
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.
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.
- 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
-
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
-
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 cert 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
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
Similarly, get the public key from the private key:
[root@server tls]# openssl pkey -pubout -in private/ec-cakey.pem
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.
- 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) ALSO READ: 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 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
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 = [email protected] 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=[email protected]
- 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.
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 = [email protected] 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=[email protected] V 220409181316Z 02 unknown /C=IN/ST=Karnataka/O=GoLinuxCloud/OU=Dummy/CN=server-2.example.com/emailAddress=[email protected]
- 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 [email protected] DocumentRoot /var/www/html ServerName server.example.com ErrorLog logs/server.example.com-error_log CustomLog logs/server.example.com-access_log common 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
- 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/ [email protected]'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/ [email protected]'s password: ec-cacert.pem 100% 940 1.5MB/s 00:00
- 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=[email protected]
-
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=[email protected]
-
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.
- 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.
- 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