Linux SSL/TLS

From Ever changing code
Jump to navigation Jump to search

The main SSL tools on Linux to manage certificates are

Terminology

DER|PEM
These are encoding formats. The DER option uses an ASN1 DER encoded form compatible with the PKCS#10. The PEM form consists of the DER format base64 encoded with additional header and footer lines.
.p12|.pfx

SSL configuration in httpd.conf

$ grep SSLCertificate /etc/httpd/conf.d
SSLCertificateChainFile "/etc/httpd/conf.d/ssl.pem/example.pem"          #certificate chain
SSLCertificateFile "/etc/httpd/conf.d/ssl.crt/exmple.crt"                #domain certificate (private key signed by 3rd party CA)
SSLCertificateKeyFile "/etc/httpd/conf.d/ssl.key/exmple.key"             #private key file

OpenSSL

Renew a certificate based on the current certificate

openssl x509 -x509toreq -in current_certificate.crt -out request.csr -signkey current_certificate_private.key

Search installed certificates

Example searches

find -H / -name "*.crt" | while read line ; do echo $line ; openssl x509 -in certificate.crt -text | egrep -i 'Algorithm|Issuer' ; done
find -H / -name "*.crt" | while read line ; do echo $line ; openssl x509 -in $line -text | egrep -i 'Algorithm|Issuer|Not After' ; done
find -H / -name cacerts | while read line ; do echo $line ; /usr/bin/keytool -list -v -keystore $line -storepass changeit -noprompt | egrep -i 'Alias|Owner|algorithm|SHA1' ; done;
find -H / -path /usr/share/doc -prune -o -name "*.pem" | while read line ; do echo $line ; openssl x509 -in $line -text | egrep -i 'Algorithm|Issuer|After' ; done
find -H / -path "/usr/share/doc /proc" -prune -o -name "*.pem" | while read line ; do echo $line ; openssl x509 -in $line -text | egrep -i 'Algorithm|Issuer|After' ; done

-H do not follow symbolic links
-path "pattern" file name matches shell pattern
-prune -o ignores a whole directory tree if the pattern matches a directory path

Verify a Certificate was Signed by a CA

Use this command to verify that a certificate (domain.crt) was signed by a specific CA certificate (ca.crt). This can be a chain certificate that contains signing certificate.

$ openssl verify -verbose -CAFile ca.crt domain.crt 
domain.crt: OK

Verify a certificate from a CLI

Insecure option tells libcurl to not verify the peer.

curl --insecure -v https://www.example.com/mgm-your-account 2>&1 \
  | awk 'BEGIN { cert=0 } /^\* Server certificate:/ { cert=1 } /^\*/ { if (cert) print }'


If your webserver uses SNI scheme is not IP based, specify the vhost server using -servername option, otherwise can be skipped

echo \
  | openssl s_client -connect <web_server_IP>:443 -servername www.example.com 2>/dev/null \
  | openssl x509 -inform pem -noout -text
                                                          Hosted_website
                              Apache_server          in_virtual_host_directive
                                      |                           |
server1# openssl s_client -connect 10.0.0.1:443 -servername www.example.com

Verify a Private Key Matches a Certificate

The private key contains a series of numbers. Two of those numbers form the public key, the others are part of your private key. The public key bits are also embedded in your Certificate (we get them from your CSR). To check that the public key in your cert matches the public portion of your private key, you need to view the cert and the key and compare the numbers. To view the Certificate and the key run the commands:

$ openssl x509 -noout -text -in server.crt
$ openssl rsa -noout -text -in server.key

The modulus and the public exponent portions in the key and the Certificate must match. But since the public exponent is usually 65537 and it's bothering comparing long modulus you can use the following approach:

$ openssl x509 -noout -modulus -in server.crt | openssl md5
$ openssl rsa -noout -modulus -in server.key | openssl md5

To check to which key or certificate a particular CSR belongs you can compute

$ openssl req -noout -modulus -in server.csr | openssl md5

OpenSSL test modules

With Server Name Indication (SNI), a web server can have multiple SSL certificates installed on the same IP address. SNI-capable browsers will specify the hostname of the server they’re trying to reach during the initial handshake process. This allows the web server to determine the correct SSL certificate to use for the connection. If you try to connect to Small Sites server with s_client, you’ll find that you receive the default SSL certificate installed on my server and not the one for this site. Therefore we need to use the -servername argument and s_client will do the additional SNI negotiation step.


OpenSSL provides three modules that allow you to test SSL connections: s_client, s_server and s_time. The first two, as the names suggest, are for simulating a client and a server in an SSL connection. The third one is for connection timing tests. I’ll start with a closer look at the s_client module.

S_client is particularly useful for checking which protocols and which ciphers the server agrees to use. This information is useful in security and functionality audits. For example, you could use this protocol information to find servers that don’t accept a legitimate protocol or cipher, thus preventing a legitimate client from connecting. You could also locate servers that accept weak protocols or ciphers and could thus allow a malicious attack.

s_client - output interpretation - https://www.feistyduck.com/library/openssl-cookbook/online/ch-testing-with-openssl.html

Preview a certificate from CLI

openssl x509 -in /etc/httpd/conf/ssl.crt/certificate.crt -text -noout

Preview CSR request from CLI

openssl req -in certificate.csr -text -noout

Disabling Diffie-Hellman on Apache Servers

On each web server, in the ssl.conf file or, in some cases, the main Apache conf file, add the !DH: identifier to the start of the SSLCipherSuite config option string.

Procedure In Apache's conf directory, locate file: ssl.conf or httpd.conf

Look for the SSLCipherSuite keyword, whose string value must be similar to the following string:

"ALL:!ADH:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP"

Add !DH: after the ALL: list so that the line looks like the following string:

"ALL:!DH:!ADH:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP"

Note: The !ADH: string in the above string is now redundant and can be removed. Repeat this edit in every SSL config section, if you are not using one global section. Save the file. Restart the web server for the changes to take effect.

Control Apache server

ssh apache.server.com "apachectl configtest"
ssh apache.server.com "apachectl graceful"
ssh apache.server.com "service httpd status"

Chain certificate structure

Apache ChainSSL is in PEM format containing all certificates from domain one to Root CA

# cat www_example_com_chain_cert-PEM.crt

-----BEGIN CERTIFICATE-----          #Domain certificate, eg. www_example_com.crt
MIIHkTCCBnmgAwIBAgIUZDLrn0fQy7z62YTRnsd/BsvWI1swDQYJKoZIhvcNAQEL
   < output obmitted >
TlXvxzWXBaAm4YzdMQt0owFUbeItrgn8IcfotEesUU6OMSGOSFi+WTlSC6rJmZM+
eNyDv54nHqqlCpbvZI3umxDx015/
-----END CERTIFICATE-----

 -----BEGIN CERTIFICATE-----          #Intermitennt CA, eg. QuoVadis_EV_SSL_ICA_G1.crt
MIIFeTCCA2GgAwIBAgIUc9pa+iPZP7qELgog9AHJ2G4k/F0wDQYJKoZIhvcNAQEL
   < output obmitted >
OUKBHeWRPmCuv59UkTZXA/LT/tHt2JC6htu2pYislARuJGsnq4Bgrw76c0AS3UF8
wxZChJIYvI+fVDAKwQ==
-----END CERTIFICATE-----

-----BEGIN CERTIFICATE-----          #Root certificate, eg. QuoVadis_Root_CA_2.crt
MIIFtzCCA5+gAwIBAgICBQkwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0x
   < output obmitted >
ohEUGW6yhhtoPkg3Goi3XZZenMfvJ2II4pEZXNLxId26F0KCl3GBUzGpn/Z9Yr9y
8eOx79+Rj1QqCyXBJhnEUhAFZdWCEOrCMc0u
-----END CERTIFICATE-----

Java Keytool certificate management

SAN Names

Oracle Java Keytool internally uses the class sun.security.x509.DNSName to check the input. DNSName enforces the syntax specified in RFC 1034. That's why its complaining when we use * wildcard in the DNS. Instead you can use openssl to create Microsoft .p12 keystore or java KeyExplorer gui tool.

Quote from its Javadoc comment:

The name MUST be in the "preferred name syntax," as specified by RFC 1034.

<domain> ::= <subdomain> | " "
<subdomain> ::= <label> | <subdomain> "." <label>
<label> ::= <letter> [ [ <ldh-str> ] <let-dig> ]
<ldh-str> ::= <let-dig-hyp> | <let-dig-hyp> <ldh-str>
<let-dig-hyp> ::= <let-dig> | "-"
<let-dig> ::= <letter> | <digit>
<letter> ::= any one of the 52 alphabetic characters A through Z in upper case and a through z in lower case
<digit> ::= any one of the ten digits 0 through 9


So according to this syntax, domain names have to begin with a letter (A-Z, a-z). Newer RFCs (e.g. RFC 2181, RFC 1123) are relaxing these restrictions, so this can be considered a bug in Java. There are already several related bug reports: JDK-8016345, JDK-8007706

Default password

changeit

Types of Java keystores

Terms like keyStore and trustStore are often used interchangeably and the same file can act as keystore as well as trustStore it just matter of pointing javax.net.ssl.keyStore and javax.net.ssl.trustStore properties to that file but there is a slight difference between keystore and trustStore.

  • Trustedstore - a keystore containing system wide available Root certificates
  • Java keystore - a keystore used by an application

Typical locations of a keystores

  • located in server.xml file of Tomcat / Jboss server
  • /etc/pki/tls/certs/ca-bundle.crt
  • Trustedstore - JAVA_HOME/jre/lib/security/cacerts

Keytool useful commands

List a keystore

keytool -list -v -keystore tomcat.jks

Import Trusted Certificate into keystore

keytool -import -trustcacerts -file GoDaddy_rootCA.cer -alias rootCA -keystore cacerts.jks

Import Signed Certificate into keystore

keytool -importcert -file <signed cert file> -alias <alias> -keystore <key store file>

Remove

keytool -delete -alias godaddy_rootCA -keystore cacerts.jks

Preview a trusted store of different format than JKS. You can also add -storetype parameter for pkms7, 10 or 12 stores listing

keytool --printcert -file /etc/pki/tls/certs/ca-bundle.crt

Create CSR with SANs names. Note that Java 7+ does not allow for wildcards '*' in the names adhering strictly to one of latest RFC standards.

keytool -certreq -file test.csr -keystore keystore.jks -alias wso2carbon -storepass PASS -ext SAN=dns:*.dev.company.com,dns:*.test.company.com

Generate self signed keystore with KeyUsage extension

This example can be used for WSO2 Secure Vault implementation where Key Usage: keyEncipherment,dataEncipherment is mandatory.

keytool -genkey -alias wso2carbon -keyalg RSA -keysize 2048 -noprompt \
-dname "CN=wso2carbon-passwords-encryption,OU=IT Department,O=CompanyPLC,L=City,S=Shire,C=GB" \
-ext KeyUsage=digitalSignature,keyCertSign,keyEncipherment,dataEncipherment \
-keystore wso2carbon-data-encryption.jks -keypass "password1" -storepass "password1"

Renew a cert in .jks based on the current private key

Convert .jks to .pkcs12. This is required as in essence .jks architecture does not allow for the private key to be moved.

keytool -importkeystore -srckeystore keystore.jks -destkeystore keystore.p12 -destkeypass PASSWORD -srcstorepass PASSWORD -deststoretype PKCS12

Export private key using openssl in PKCS8 format. Openssl by default uses .PEM format.

openssl pkcs12 -in keystore.p12 -nodes -nocerts -out keystore_pkcs8_format.key

#Example beginning of the key file
Bag Attributes
    friendlyName: mycertificate
    localKeyID: 54 69 6D 65 20 31 35 32 38 30 35 35 31 31 31 34 33 34 
Key Attributes: <No Attributes>
-----BEGIN PRIVATE KEY-----

Export private key using openssl in .PEM format this is the same format as KSE below.

openssl pkcs12 -in keystore.p12 -nocerts -nodes | openssl rsa > keystore_pem_format.key

#Example beginning of the key file
-----BEGIN RSA PRIVATE KEY-----

Export private key using KSE in .PEM format that can be used by openssl.

java -jar kse.jar
#Export Private Key > No encryption > PEM format > keystore_pem_format_from_kse.key

#Example beginning of the key file
-----BEGIN RSA PRIVATE KEY-----

Generate CSR using openssl

openssl req -new -key keystore_pem_format.key -config openssl.cnf -out keystore.csr

Sign the certificate, using internal CA, external CA, free CA like Let's Encrypt

#<... more steps to follow ...>

Generate .p12 keystore from the key (keystore_pem_format.key) and signed certificate

openssl pkcs12 -export -in signedcertificate.cer -inkey keystore_pem_format.key -out new.p12 -name mycertificate

Convert .p12 keystore into .jks keystore

keytool -importkeystore -deststorepass PASSWORD -destkeypass PASSWORD -destkeystore new.jks -srckeystore keystore.p12 -srcstoretype PKCS12 -srcstorepass PASSWORD -alias mycertificate

Windows keystore .p12

When working with Windows .p12 is a keystore format that can hold multiple cryptographic objects. It's Microsoft's successor of .pfx format. Both .p12 and .pfx are interchangeable. Example usage is for:

  • Octopus Deploy, requires to import .key and cert into own hosting application. Therefore it needs to be .p12 (with a private key and cert) imported into Local Computer 'Web Hosting' or 'Personal' store first.
  • Strongswan VPN private identity certificate to be copied into /etc/ipsec.d/private/

Convert .cer to .p12

#convert x509(DER format) -> PEM. It'll fail if wrong format
openssl x509   -out cert.pem -outform PEM    -in cert.cer -inform DER
#convert x509 -> PEM
openssl x509   -out cert.pem -outform PEM    -in cert.cer 
#create .p12 keystore            
openssl pkcs12 -out cert.p12 -inkey cert.key -in cert.pem -export

CFSSL - CloudFlare's PKI toolkit

Install

wget -q --show-progress --https-only --timestamping \
  https://pkg.cfssl.org/R1.2/cfssl_linux-amd64 \
  https://pkg.cfssl.org/R1.2/cfssljson_linux-amd64

chmod +x cfssl_linux-amd64 cfssljson_linux-amd64
sudo mv cfssl_linux-amd64     /usr/local/bin/cfssl
sudo mv cfssljson_linux-amd64 /usr/local/bin/cfssljson

cfssl version

Resources

Build your own CA / PKI

Follow this blog to create own CA PKI infrastructure based on openssl openssl-certificate-authority

Certificates atributes

Key usage extension

Digital signature
Use when the public key is used with a digital signature mechanism to support security services other than non-repudiation, certificate signing, or CRL signing. A digital signature is often used for entity authentication and data origin authentication with integrity.
Non-repudiation
Use when the public key is used to verify digital signatures used to provide a non-repudiation service. Non-repudiation protects against the signing entity falsely denying some action (excluding certificate or CRL signing).
Key encipherment
Use when a certificate will be used with a protocol that encrypts keys. An example is S/MIME enveloping, where a fast (symmetric) key is encrypted with the public key from the certificate. SSL protocol also performs key encipherment.
Data encipherment
Use when the public key is used for encrypting user data, other than cryptographic keys.
Key agreement
Use when the sender and receiver of the public key need to derive the key without using encryption. This key can then can be used to encrypt messages between the sender and receiver. Key agreement is typically used with Diffie-Hellman ciphers.
Certificate signing
Use when the subject public key is used to verify a signature on certificates. This extension can be used only in CA certificates.
CRL signing
Use when the subject public key is to verify a signature on revocation information, such as a CRL.
Encipher only
Use only when key agreement is also enabled. This enables the public key to be used only for enciphering data while performing key agreement.
Decipher only
Use only when key agreement is also enabled. This enables the public key to be used only for deciphering data while performing key agreement.

SSL Scanners

sslscan

sudo apt-get install sslscan
Ssltest.sh screenshot

testssl.sh

git clone --depth 1 https://github.com/drwetter/testssl.sh.git

Resources