OpenSSL

From Segfault
Jump to navigation Jump to search

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 ciphers
make 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 resulting ca-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



References

  1. Compilation and Installation
  2. $LD_LIBRARY_PATH oder doch nicht?!
  3. HOWTO certificates (Archive)
  4. OpenSSL generate different types of self signed certificate
  5. OpenSSL 1.1.0 Series Release Notes
  6. (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."
  7. OpenSSL 1.1.1 Series Release Notes
  8. Why does openssl writes EC parameters when generating private key?
  9. SafeCurves: choosing safe curves for elliptic-curve cryptography
  10. Safe ECC curves (2014-01-01)
  11. Which elliptic curve should I use?
  12. Command Line Elliptic Curve Operations
  13. Ballot SC47v2: Sunset subject:organizationalUnitName
  14. Provide subjectAltName to openssl directly on the command line
  15. Intent to Remove: Support for commonName matching in certificates
  16. OpenVPN dhparam
  17. How does RSA work?
  18. How can you check if a private key and certificate match in OpenSSL with ECDSA?
  19. remove the passphrase from a pkcs12 certificate
  20. How can I split a CA certificate bundle into separate files?
  21. GNU/coreutils
  22. Debian #213086 - ca-certificates: Please include CAcert.org certificate
  23. Debian #718434 - ca-certificates: should CAcert.org be included?
  24. Debian and CAcert
  25. OpenSSL Certificate Authority
  26. ECDSA Certificate Authorities and Certificates With OpenSSL
  27. Bug 110161 - (ocspdefault) enable OCSP by default
  28. Revocation checking and Chrome's CRL (2012-02-05)
  29. SSLUseStapling (Apache 2.4)
  30. nginx-announce: nginx-1.3.7
  31. Check For Server Certificate Revocation checkbox is confusing
  32. OCSP Stapling in Firefox
  33. OpenSSL: Manually verify a certificate against an OCSP
  34. Checking OCSP revocation using OpenSSL
  35. OCSP unknown status when passing cert, good status when passing serial
  36. ocsp - Online Certificate Status Protocol utility
  37. OCSP stapling with certificate servers behind CloudFlare