OpenSSL
Installation
From a tarball:
wget https://www.openssl.org/source/openssl-1.1.0.tar.gz{,.sha256,.asc} sha256sum openssl*.tar.gz | grep --color `cat openssl*.tar.gz.sha256` gpg --verify openssl*.tar.gz.asc # → PGP Key IDs tar -xzvf openssl*.tar.gz
From the Git repository:
git clone git://git.openssl.org/openssl.git openssl-git
Install prerequisites:
apt-get install zlib1g-dev perl # Debian, Ubuntu dnf install zlib-devel perl-Pod-Html # Fedora, CentOS
Build and install:[1]
./Configure --prefix=/opt/openssl no-idea no-mdc2 no-rc5 no-zlib no-ssl3 no-ssl3-method shared linux-$(uname -m) ./config --prefix=/opt/openssl no-shared enable-weak-ssl-ciphers # To explicitly enable weak ciphersmake depend# Only needed for OpenSSL 1.0.2 and below. make && sudo make install
Note: we're using the shared option to install libssl.so
. You may have to utilize LD_LIBRARY_PATH
[2] later on though :-\
You man want to run some tests afterwards:
make test
Usage
Private key
Certificates need a private key to be generated from[3][4]. To generate an RSA key:
openssl genrsa -out privkey.pem 4096 # Add -aes128 to encrypt the private key.
For a DSA key:
openssl dsaparam -out dsaparam.pem 4096 openssl gendsa -out privkey.pem dsaparam.pem # Add -aes128 to encrypt the private key.
Or, for an ECC key:
openssl ecparam -name prime256v1 -genkey -noout -out privkey.pem # Encrypt with: openssl ec -in privkey.pem -aes128 -out privkey_enc.pem
Newer versions of OpenSSL support[5] support X25519, but we cannot sign certificates with that key[6] and we'll have to use an even newer version[7] to use Ed25519 for our key:
openssl genpkey -algorithm ed25519 -out privkey.pem # Add -aes128 to encrypt the private key.
Notes:
- Use the
-noout
option to omit the EC parameters, as they may not be needed.[8] In lieu of a SafeCurves OpenSSL implementation[9][10],we shall choose P-256 (or P-384)[11] for now.- Add
-param_enc explicit
to EC key generation[12] to include the curve's parameters into the key.
Public key
To get the public key from the private' key we just generated, use:
openssl rsa -in privkey.pem -pubout openssl dsa -in privkey.pem -pubout openssl ec -in privkey.pem -pubout openssl pkey -in privkey.pem -pubout # Should work for all key types.
Certificate requests
Create a configuration file:
$ cat openssl.cnf [req] distinguished_name = req_distinguished_name req_extensions = req_ext prompt = no [req_distinguished_name] C = DK ST = Hovedstaden L = Copenhagen O = Example Corp OU = Accounting CN = test.example.net [req_ext] subjectAltName = @alt_names [alt_names] DNS.1 = test.example.net DNS.2 = foobar.example.net
Note: the OU
field has been deprecated[13] but we're listing it here for historical reasons.
In one step:
openssl req -newkey rsa:4096 -nodes -keyout key.pem -out req.pem -config openssl.cnf # RSA openssl ecparam -name prime256v1 -out ecparam.pem # ECC openssl req -newkey ec:ecparam.pem -keyout key.pem -nodes -out req.pem -config openssl.cnf
In two steps:
openssl genrsa -out key.pem 4096 # RSA openssl ecparam -name prime256v1 -genkey -noout -out key.pem # ECC openssl req -new -key key.pem -out req.pem -config openssl.cnf
Verify the CSR:
$ openssl req -in req.pem -noout -text Certificate Request: [...] Subject: C = DK, ST = Hovedstaden, L = Copenhagen, O = Example Corp, OU = Accounting, CN = test.example.net X509v3 Subject Alternative Name: DNS:test.example.net, DNS:foobar.example.net
Self-signed certificate
Self-signed certificates can be created without a Certificate Authority (CA):
SAN="subjectAltName = DNS:localhost" # SANs are more important than the CN now.[14][15] SUBJECT="/C=US/ST=CA/L=SF/O=None/OU=None/CN=localhost/emailAddress=admin@localhost" openssl req -new -x509 -sha512 -days 3650 -key privkey.pem -out cert.pem -subj "${SUBJECT}" -addext "${SAN}" # For DSA keys, use -sha256 instead. openssl dhparam -out dhparam.pem 2048 # This may take a long time to complete.[16]
The generated certificate can now be used, for example for a webserver:
openssl s_server -tls1_3 -www -accept localhost:8443 -key privkey.pem -cert cert.pem -dhparam dhparam.pem
Connect via:
curl -k https://localhost:8443 # Using -insecure because it's a self-signed certificate openssl s_client -connect localhost:8443
Verification
For RSA keys, we can check if the modulus[17] of the certificate matches the key; this is sometimes useful to see if a certificate (generated by a 3rd party) would match our key:
$ openssl rsa -in privkey.pem -noout -modulus | md5sum 56184f0a09279f188ee20cfc715bad99 -
openssl x509 -in cert.pem -noout -modulus | md5sum 56184f0a09279f188ee20cfc715bad99 -
EC keys have no RSA modulus, but we can still check if the public part matches:[18]
$ openssl ec -in privkey.pem -text -noout 2>/dev/null | awk '/^pub:/,/ASN1/' pub: 04:2c:53:6b:0a:5b:15:bd:6f:dd:7b:af:ce:fd:0c: 09:11:25:f1:71:69:b2:47:da:49:b9:d0:39:df:91: 31:29:d5:60:cc:be:cf:da:35:70:49:f5:35:8e:12: 3c:d8:eb:a6:11:42:40:fc:49:47:20:e5:24:f3:8f: 64:50:18:b8:e2 ASN1 OID: prime256v1 $ openssl ec -in privkey.pem -pubout 2>/dev/null 297e4cf3d550560f1549fe1e920683c9 -
Or, more generally (this will work for Ed25519 keys too):
$ openssl pkey -in privkey.pem -text -noout pub: 04:d3:4b:1d:fd:72:4f:e0:6e:04:6f:32:dc:80:37: 6a:55:6c:82:94:de:db:e2:c8:44:5c:75:4b:28:24: 46:2c:5b:88:a7:4e:45:a4:25:c8:8c:1c:37:b8:ed: 78:f7:1d:cd:4d:22:35:b8:09:da:19:f1:81:7f:e7: 47:6c:84:03:54 $ openssl pkey -in privkey.pem -pubout | md5sum 297e4cf3d550560f1549fe1e920683c9 -
And for the certificate:
$ openssl x509 -in cert.pem -text -noout pub: 04:2c:53:6b:0a:5b:15:bd:6f:dd:7b:af:ce:fd:0c: 09:11:25:f1:71:69:b2:47:da:49:b9:d0:39:df:91: 31:29:d5:60:cc:be:cf:da:35:70:49:f5:35:8e:12: 3c:d8:eb:a6:11:42:40:fc:49:47:20:e5:24:f3:8f: 64:50:18:b8:e2
$ openssl x509 -in cert.pem -noout -pubkey | md5sum 297e4cf3d550560f1549fe1e920683c9 -
PKCS12
PKCS 12 is a file format used to store a privat key along with its certificate, protected with a password-based symmetric key. Sometimes it's necessary to remove the password[19] from the pkcs12
file.
openssl pkcs12 -in file.p12 -nodes -out file.pem openssl pkcs12 -in file.pem -export -out file_plain.p12 rm file.pem
Certificate bundles
Sometimes we need to split up[20] a certificate bundle into separate certificate files. With awk
:
awk 'BEGIN {c=0;} /BEGIN CERT/{c++} {print > "cert." c ".pem"}' < ../bundle.pem c_rehash .
Or, if csplit
[21] is available:
csplit -k -b '%02d.pem' -f cert- ../bundle.pem '/END CERTIFICATE/+1' {1000} c_rehash .
Root CAs
ACME
Nowadays various CAs support the ACME ("Automatic Certificate Management Environment") protocol, see: ACME Certificate Authorities.
CAcert
Since Debian does no longer[22][23][24] ship the CAcert Root Certificate, we have to install it ourselves:
wget https://www.cacert.org/certs/root.crt # Find the predicament! :-) sudo mkdir /usr/local/share/ca-certificates/cacert/ sudo mv root.crt /usr/local/share/ca-certificates/cacert/ sudo update-ca-certificates
Now the CAcert certificate should be usable.
Self-Signed
This will explain[25], in short, how to be our own self-signed certificate authority (CA).
SUBJECT="/C=US/ST=CA/L=SF/O=Foobar CA/OU=None/CN=Foobar CA/emailAddress=ca@example.org" openssl req -new -x509 -sha512 -days 3650 -extensions v3_ca -keyout cakey.pem -newkey rsa:4096 -sha512 -nodes -out cacert.pem -subj "${SUBJECT}"
Or, for EC[26] keys:
openssl ecparam -genkey -name prime256v1 -out cakey.pem
openssl req -new -x509 -sha512 -days 3650 -key cakey.pem -nodes -out cacert.pem -subj "${SUBJECT}"
Notes:
- With
-nodes
, the resultingca-key.pem
will not be encrypted. - The Organization Name (
O
) must match the one from the certificate request we're about to create. - The Organizational UnitName (
ON
) is optional, but we included it here for completeness.
Create the certificate request:
SAN="subjectAltName = DNS:server.example.org" SUBJECT="/C=US/ST=CA/L=SF/O=Foobar CA/OU=None/CN=server.example.org/emailAddress=root@example.org" openssl req -new -out server-req.pem -keyout server-key.pem -newkey rsa:4096 -sha512 -nodes -subj "${SUBJECT}" -addext "${SAN}"
Again, for EC keys:
openssl ecparam -genkey -name prime256v1 -out server-key.pem openssl req -new -sha512 -key server-key.pem -nodes -out server-req.pem -subj "${SUBJECT}" -addext "${SAN}"
Sign the request by our CA and generate the certificate:
openssl x509 -req -sha256 -days 730 -in server-req.pem -CA cacert.pem -CAkey cakey.pem -CAcreateserial -out server-cert.pem
OCSP
OCSP is used to check the revocation status of certificates. Firefox uses OCSP since version 3[27], Google Chrome stopped using OCSP in 2012 [28], citing latency and privacy issues.
In Firefox, OCSP is enabled with:
security.OCSP.enabled = 1 # Default security.OCSP.require = false # Assume that the certificate is not revoked as a fallback mechanism security.OCSP.GET.enabled = false # Use POST requests to the OCSP responder by default
OCSP stapling can be used as an alternative to OCSP: the server will append a previously received signed OCSP response to the client, thus eliminating the need for the client to contact the CA. OCSP stapling needs to be supported by both the server and the client.[29][30]
On the client side, OCSP stapling seems to be enabled by default in Google Chrome[31] and in Firefox with version 26[32]:
security.ssl.enable_ocsp_stapling = true # Default
Let's try to check the revocation status of a certificate[33][34], using the CA's OCSP responder:
openssl s_client -connect example.net:443 -showcerts < /dev/null > showcerts
If more than one certificat has been received, we need to extract them and then chain them together[35]:
i=1; while [ $i -le $(grep -c BEGIN showcerts) ]; do awk "/-----BEGIN/,/-----END/ {if(++m==1)n++;if(n=="$i") print;if(/-----END/)m=0}" showcerts > showcerts_${i} i=$((i+1)) done cat showcerts_[0-9] > showcerts_chained
Get the OCSP responder URI of the leaf certificate:
$ openssl x509 -in showcerts_1 -noout -ocsp_uri
http://ocsp.digicert.com
For the next step, we need to specify the issuer certificate too:
$ openssl x509 -in showcerts -noout -issuer
issuer=C = US, O = DigiCert Inc, CN = DigiCert TLS RSA SHA256 2020 CA1
$ openssl x509 -in showcerts_2 -noout -subject
subject=C = US, O = DigiCert Inc, CN = DigiCert TLS RSA SHA256 2020 CA1
Send a request to the responder:
$ openssl ocsp -issuer showcerts_2 -cert showcerts -url http://ocsp.digicert.com -no_nonce -text Response verify OK OCSP Request Data: Version: 1 (0x0) Requestor List: Certificate ID: Hash Algorithm: sha1 Issuer Name Hash: E4E395A229D3D4C1C31FF0980C0B4EC0098AABD8 Issuer Key Hash: B76BA2EAA8AA848C79EAB4DA0F98B2C59576B9F4 Serial Number: 0C1FCB184518C7E3866741236D6B73F1 OCSP Response Data: OCSP Response Status: successful (0x0) Response Type: Basic OCSP Response Version: 1 (0x0) Responder Id: B76BA2EAA8AA848C79EAB4DA0F98B2C59576B9F4 Produced At: Feb 28 00:43:24 2023 GMT Responses: Certificate ID: Hash Algorithm: sha1 Issuer Name Hash: E4E395A229D3D4C1C31FF0980C0B4EC0098AABD8 Issuer Key Hash: B76BA2EAA8AA848C79EAB4DA0F98B2C59576B9F4 Serial Number: 0C1FCB184518C7E3866741236D6B73F1 Cert Status: good This Update: Feb 28 00:27:01 2023 GMT Next Update: Mar 6 23:42:01 2023 GMT Signature Algorithm: sha256WithRSAEncryption Signature Value: [...] showcerts: good This Update: Feb 28 00:27:01 2023 GMT Next Update: Mar 6 23:42:01 2023 GMT
- Use
-no_nonce
to not send a nonce to the responder, as some might not support it. - Use
-noverify
to skip verification on the response. This is sometimes needed. - Sometimes the
(undocumented)-header
option[36][37] is needed, otherwise responders might answer with "Code=400,Reason=Bad Request
"
See also
Links
- DFN-CERT: OpenSSL-Kurzreferenz / Aufbau und Betrieb einer Zertifizierungsinstanz
- OpenSSL Command-Line HOWTO
- NCSA CyberSecurity: Useful OpenSSL Commands
- OpenSSL generate different types of self signed certificate
- Can I create my own S/MIME certificate for email encryption?
- Mozilla Included CA Certificate List
- Qualys SSL Server Test / SSL Client Test
- Observatory by Mozilla
- Mozilla SSL Configuration Generator
- badssl.com
References
- ↑ Compilation and Installation
- ↑ $LD_LIBRARY_PATH oder doch nicht?!
- ↑ HOWTO certificates (Archive)
- ↑ OpenSSL generate different types of self signed certificate
- ↑ OpenSSL 1.1.0 Series Release Notes
- ↑ (no subject) - "It is not possible to "self-sign" an X25519 certificate because X25519 is a key-exchange algorithm only, not a digital signature algorithm."
- ↑ OpenSSL 1.1.1 Series Release Notes
- ↑ Why does openssl writes EC parameters when generating private key?
- ↑ SafeCurves: choosing safe curves for elliptic-curve cryptography
- ↑ Safe ECC curves (2014-01-01)
- ↑ Which elliptic curve should I use?
- ↑ Command Line Elliptic Curve Operations
- ↑ Ballot SC47v2: Sunset subject:organizationalUnitName
- ↑ Provide subjectAltName to openssl directly on the command line
- ↑ Intent to Remove: Support for commonName matching in certificates
- ↑ OpenVPN dhparam
- ↑ How does RSA work?
- ↑ How can you check if a private key and certificate match in OpenSSL with ECDSA?
- ↑ remove the passphrase from a pkcs12 certificate
- ↑ How can I split a CA certificate bundle into separate files?
- ↑ GNU/coreutils
- ↑ Debian #213086 - ca-certificates: Please include CAcert.org certificate
- ↑ Debian #718434 - ca-certificates: should CAcert.org be included?
- ↑ Debian and CAcert
- ↑ OpenSSL Certificate Authority
- ↑ ECDSA Certificate Authorities and Certificates With OpenSSL
- ↑ Bug 110161 - (ocspdefault) enable OCSP by default
- ↑ Revocation checking and Chrome's CRL (2012-02-05)
- ↑ SSLUseStapling (Apache 2.4)
- ↑ nginx-announce: nginx-1.3.7
- ↑ Check For Server Certificate Revocation checkbox is confusing
- ↑ OCSP Stapling in Firefox
- ↑ OpenSSL: Manually verify a certificate against an OCSP
- ↑ Checking OCSP revocation using OpenSSL
- ↑ OCSP unknown status when passing cert, good status when passing serial
- ↑ ocsp - Online Certificate Status Protocol utility
- ↑ OCSP stapling with certificate servers behind CloudFlare