OpenSSL

From Segfault
Jump to: navigation, 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                                           # Debian, Ubuntu
dnf install zlib-devel                                               # 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-`arch`
make depend && 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 secp256k1 -genkey -noout -out privkey.pem          # Encrypt with:
                                                                         # openssl ec -in privkey.pem -aes128 -out

Notes:

  • Use the -noout option to omit the EC parameters![5]
  • In lieu of a SafeCurves OpenSSL implementation[6][7], we shall choose P-256 (or P-384)[8] for now.
  • Add -param_enc explicit to EC key generation[9] 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

Self-signed certificate

Self-signed certificates can be created without a Certificate Authority (CA):

SUBJECT='/C=US/ST=CA/L=SF/O=None/OU=None/CN=localhost/emailAddress=root@localhost'
openssl req -new -x509 -sha512 -days 3650 -key privkey.pem -out cert.pem -subj $SUBJECT          # For DSA keys, use -sha256 instead.

The generated certificate can now be used, for example for a webserver:

openssl dhparam -out dhparam.pem 2048
openssl s_server -accept 8443 -key privkey.pem -cert cert.pem -dhparam dhparam.pem -tls1_2 -www

Notes:

  • We use custom DH parameters in this example.[10]
  • If an intermediate certificate was appended to cert.pem, we would add the -chain option.

Connect via:

curl -k https://localhost:8443                                     # Using -insecure because it's a self-signed certificate
openssl s_client -connect localhost:8443


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[11] from the pkcs12 file.

openssl pkcs12 -in file.p12 -nodes -out file.pem
openssl pkcs12 -export -in file.pem -out file_plain.p12
rm file.pem

Root CAs

Let's Encrypt

TBD

CAcert

Since Debian does no longer[12][13][14] 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.

StartCom

For StartSSL, we have to create a private key and a certificate request:

SUBJECT='/C=CA/ST=None/L=None/O=None/OU=None/CN=example.net/emailAddress=admin@example.net'
openssl req -newkey rsa:4096 -sha512 -nodes -keyout example-key.pem -out example.csr -subj $SUBJECT

The example.csr can be sent to StartCom, they'll return the server certificate.

Note: it may take a while until the certificate will be usable[15], Firefox may display the following error for a fresh certificate:

Secure Connection Failed
An error occurred during a connection to example.net. The OCSP server has no
status for the certificate. (Error code: sec_error_ocsp_unknown_cert)

We could work around this by temporarily changing the following settings[16][17] in Firefox:

security.OCSP.enabled=0
security.OCSP.require=true

Be sure to switch back to 1/false afterwards!

Once the certificate is working, Debian still had problems connecting to it:

$ curl https://example.net
curl: (60) SSL certificate problem: unable to get local issuer certificate

Let's find out which CA issued our new certificate:

$ openssl s_client -connect example.net:443 < /dev/null 2>&1
[...]
Certificate chain
0 s:/C=CA/CN=example.net/emailAddress=admin@example.net
  i:/C=IL/O=StartCom Ltd./OU=Secure Digital Certificate Signing/CN=StartCom Class 1 Primary Intermediate Server CA

But we don't seem to have the Intermediate Server CA installed on our system yet:

$ ls /etc/ssl/certs/ | grep Start
StartCom_Certification_Authority_2.pem
StartCom_Certification_Authority_G2.pem
StartCom_Certification_Authority.pem

Let's get the correct[18] certficate:

$ wget https://www.startssl.com/certs/ca.crt
$ openssl x509 -in sub.class1.server.sha1.ca.pem -noout -text  | grep Intermediate
       Subject: C=IL, O=StartCom Ltd., OU=Secure Digital Certificate Signing, CN=StartCom Class 1 Primary Intermediate Server CA

...and add it to our trust store. Note: update-ca-certificatesexpects certificates to end in .crt![19]

$ sudo mkdir -p /usr/local/share/ca-certificates/startssl
$ sudo mv sub.class1.server.sha1.ca.pem /usr/local/share/ca-certificates/startssl/sub.class1.server.sha1.ca.crt
1 sudo update-ca-certificates --verbose
[...]
1 added, 0 removed; done.
Running hooks in /etc/ca-certificates/update.d....
Adding debian:sub.class1.server.sha1.ca.pem
done.
done.

Now we should be able to connect:

$ openssl s_client -CApath /etc/ssl/ -connect example.net:443 < /dev/null 2>&1
[...]
depth=2 C = IL, O = StartCom Ltd., OU = Secure Digital Certificate Signing, CN = StartCom Certification Authority
verify return:1
depth=1 C = IL, O = StartCom Ltd., OU = Secure Digital Certificate Signing, CN = StartCom Class 1 Primary Intermediate Server CA
verify return:1
depth=0 C = DE, CN = example.net, emailAddress = admin@example.net
verify return:1
CONNECTED(00000003)

Note: adding the correct CA certificate to the trust store is also required if we want to login to StartCom with our client certificate we received from StartCom!

Self

This will explain[20], in short, how to be our own self-signed certificate authority (CA).

SUBJECT='/C=US/ST=CA/L=SF/O=None/OU=None/CN=localhost/emailAddress=ca@localhost'
openssl req -new -x509 -sha512 -days 3650 -extensions v3_ca -keyout cakey.pem -newkey rsa:2048 -sha512 -nodes -out cacert.pem -subj $SUBJECT 

Notes:

  • With -nodes, the resulting ca-key.pem will not be encrypted.
  • The O=None must match the one from the certificate request we're about to create.

Create the certificate request:

SUBJECT='/C=US/ST=CA/L=SF/O=None/OU=None/CN=server.local/emailAddress=server@localhost'
openssl req -new -out server-req.pem -keyout server-key.pem -newkey rsa:2048 -sha512 -nodes -subj $SUBJECT

Sign the request by our CA and generate the certificate:

$ mkdir -p demoCA/newcerts && touch demoCA/index.txt && echo 01 > demoCA/serial

$ openssl ca -days 730 -md sha512 -keyfile cakey.pem -cert cacert.pem -in server-req.pem -out server-cert.pem
Using configuration from /usr/lib/ssl/openssl.cnf
Check that the request matches the signature
Signature ok
Certificate Details:
       Serial Number: 1 (0x1)
       Validity
           Not Before: Nov 17 07:26:26 2015 GMT
           Not After : Nov 16 07:26:26 2017 GMT
       Subject:
           countryName               = US
           stateOrProvinceName       = CA
           organizationName          = None
           organizationalUnitName    = None
           commonName                = server.local
           emailAddress              = server@localhost
       X509v3 extensions:
           X509v3 Basic Constraints: 
               CA:FALSE
           Netscape Comment: 
               OpenSSL Generated Certificate
           X509v3 Subject Key Identifier: 
               0F:F2:94:B3:9D:AD:10:4A:44:F8:7C:B2:D2:D1:C5:1E:5B:7B:AE:9D
           X509v3 Authority Key Identifier: 
               keyid:EE:D2:E2:FF:64:34:8E:45:D9:4A:20:65:0D:20:FB:6F:D0:B0:16:72

Certificate is to be certified until Nov 16 07:26:26 2017 GMT (730 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

The resulting server-cert.pem will be the same as demoCA/newcerts/01.pem.

OCSP

OCSP is used to check the revocation status of certificates. Firefox uses OCSP since version 3[21], Google Chrome stopped using OCSP in 2012 [22], 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.[23][24]

On the client side, OCSP stapling seems to be enabled by default in Google Chrome[25] and in Firefox with version 26[26]:

security.ssl.enable_ocsp_stapling = true          # Default

Let's try to check the revocation status of a certificate[27][28], using the CA's OCSP responder:

openssl s_client -CApath /etc/ssl -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[29]:

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:

$ openssl x509 -in showcerts_1 -noout -ocsp_uri
http://ocsp.startssl.com/sub/class1/server/ca

Send a request to the responder.

  • Use -noverify to skip verification on the response. This is sometimes needed.
  • Use -no_nonce to not send a nonce to the responder, as some might not support it.
  • We use the (undocumented) -header option[30][31], otherwise responders might answer with "Code=400,Reason=Bad Request"
$ openssl ocsp -issuer showcerts_chained -cert showcerts_1 \
          -url http://ocsp.startssl.com/sub/class1/server/ca -header HOST ocsp.startssl.com -text

OCSP Request Data:
   Version: 1 (0x0)
   Requestor List:
       Certificate ID:
         Hash Algorithm: sha1
         Issuer Name Hash: 6568874F40750F016A3475625E1F5C93E5A26D58
         Issuer Key Hash: 607D48F437F0E4A850500BE9C2122FBEEC081235
         Serial Number: 05DA538DDBD6C2
   Request Extensions:
       OCSP Nonce:
           0410517917662E9B1DA2DE389DDDDE9527B7
OCSP Response Data:
   OCSP Response Status: successful (0x0)
   Response Type: Basic OCSP Response
   Version: 1 (0x0)
   Responder Id: C = IL, O = StartCom Ltd. (Start Commercial Limited), CN = StartCom Class 1 Server OCSP Signer
   Produced At: Aug 24 02:13:04 2015 GMT
   Responses:
   Certificate ID:
     Hash Algorithm: sha1
     Issuer Name Hash: 6568874F40750F016A3475625E1F5C93E5A26D58
     Issuer Key Hash: EB4234D098B0AB9FF41B6B08F7CC642EEF0E2C45
     Serial Number: 05DA538DDBD6C2
   Cert Status: good
   This Update: Aug 24 02:13:04 2015 GMT
   Next Update: Aug 26 02:13:04 2015 GMT
[...]
showcerts_1: ERROR: No Status found.

The OCSP responder replied with "successful" to our request - alas, OpenSSL thinks that no status has been found because the "Responses" field was empty[27] :-\

See also

TODO

  • Get all this into a foolproof script
  • Provide server and client configuration details
    • apache, lighttpd, dovecot, courier, exim, stunnel
    • mozilla clients, pine/alpine, fetchmail
  • Advanced topics like
    • changing passphrase of CA
    • renew certificates/CA
    • wildcard certs
    • revoking certs
    • client cert authentication

Links

Bookmarks



References