PKI

From Smithnet Wiki
Jump to navigation Jump to search

Background

  • Public Key Encryption: Public/Private key pair are generated. Information encrypted with public key can only be decrypted with the private key. SSL uses this to allow a client to encrypt a symmetric key for the subsequent exchange of subsequent data.
  • Public Key Certificate ("Digital Certificate"): data is encrypted with private key, can be decrypted by anyone with the public key. If identify information is used, this is bound to the public key - so a public key can be verified that it belongs to an individual/organisation and cannot be forged (as only the person with access to the private key could have generated it).
  • Certificate: Public Key and ID bound by a CA signature.
    • CA Certificate: Used by a CA to sign certificates and CRLs.
    • Root Certificate: Self-signed CA Certificate. This is the PKI trust anchor.
    • Cross Certificate: CA certificate issued by an CA external to the primary PKI hierarchy. Used to connect two PKIs, so normally are in pairs.
    • User Certificate: Used by end users to purposes such as securing email, server authorisation, client authorisation, code signing, etc. Cannot sign other certificates.
  • Certificate Authority (CA): The organisation that issues certificates and CRLs.
    • Root CA: The root of a PKI hierarchy, and has a self-signed certificate. Only issues other CA certificates.
    • Intermediate CA: A level down from the Root CA but above a signing CA. Only issues other CA certificates.
    • Signing CA: At the bottom of the PKI hierarchy, issues only user certificates.
  • Certificate Signing Request (CSR): A request for certification that is sent to a CA. Contains a public key and ID to be certified.
  • Certificate Revocation List (CRL): A list of revoked certificates that were issued by a CA, but were later revoked and considered invalid.
  • Online Certificate Status Protocol (OCSP): A protocol allowing a client to check with the CA that a certificate presented by a server is/is not revoked by the signing CA.

See also:

File Formats

  • Privacy Enhanced Mail (PEM): ASCII based format (preferred by OpenSSL, Apache, etc) that can include multiple certificates and keys. Base-64 encoded separated by headers/footers like "-----BEGIN CERTIFICATE-----". Typically .pem extension.
  • Distingushed Encoding Rules (DER): Binary format preferred by by Windows, typically .der, .cer or .crt extension.
  • PKCS7: Format for storing multiple certificates, no password protection.
  • PKCS8: Format for storing private key information. Typically .key extension.
  • PKCS10: Format for a CSR. Typically .csr extension.
  • PKCS12: Common format for storing multiple private keys and public certificates in a single file, protected by password-based encryption. Typically .pfx or .p12 extension.

OpenSSL Useful Commands

Show readable contents of key, CSR and certificates:

openssl rsa -in ca.key -text -noout
openssl req -in newreq.csr -text -noout
openssl x509 -in cert.crt -text -noout
openssl x509 -in cert.der -inform DER -text -noout

Some data contents may not be shown, eg:

...
X509v3 Subject Alternative Name: 
othername:<unsupported>, othername:<unsupported>
...

Parse this like:

openssl asn1parse -in cert.pem
...
700:d=4  hl=2 l= 109 cons: SEQUENCE          
702:d=5  hl=2 l=   3 prim: OBJECT            :X509v3 Subject Alternative Name
707:d=5  hl=2 l= 100 prim: OCTET STRING      [HEX DUMP]:0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF01234567
907:d=1  hl=2 l=  13 cons: SEQUENCE   
 ...

and then expand the hex dump of interest:

# openssl asn1parse -in certificate.pem -strparse 707
 0:d=0  hl=2 l= 100 cons: SEQUENCE          
 2:d=1  hl=2 l=  47 prim: cont [ 2 ]        
51:d=1  hl=2 l=   4 prim: cont [ 7 ]        
57:d=1  hl=2 l=  29 cons: cont [ 0 ]        
59:d=2  hl=2 l=   3 prim: OBJECT            :1.2.3.4
64:d=2  hl=2 l=  22 cons: cont [ 0 ]        
66:d=3  hl=2 l=  20 prim: UTF8STRING        :some-testing-value-1
88:d=1  hl=2 l=  12 cons: cont [ 0 ]        
90:d=2  hl=2 l=   3 prim: OBJECT            :1.2.3.5
95:d=2  hl=2 l=   5 cons: cont [ 0 ]        
97:d=3  hl=2 l=  13 prim: UTF8STRING        :other-value-2

Convert a PEM-format certificate into a DER-format certificate:

openssl x509 -inform PEM -outform DER -in yourcert.pem -out yourcert.der

Convert a DER-format certificate into a PEM-format certificate:

openssl x509 -in yourcert.der -out yourcert.pem -inform DER -outform PEM

Extract keys and/or certificates from PKCS12 file (add -nocerts or -nokeys as required):

openssl pkcs12 -in certsandkeys.p12 -out certs.pem -nodes -nokeys 

Extract modulus from private key, and generate its hash:

openssl rsa -in yourkey.pem -noout -modulus | openssl md5

This modules should be the same as that in the cert received back from the CA:

openssl x509 -in yourcert.pem -noout -modulus | openssl md5

Verify a cert against a CA:

openssl verify -verbose -CAfile ca.pem yourcert.pem

Connect to a server, grab certificate and check against CA bundle:

openssl s_client -connect 192.168.0.1:443 -CAfile ca.pem

which will show the certificate chain, SSL handshake, negotiated protocol version and cypher. If all goes well, a 0 return code will be given. Code 19 means a self-signed cert has been reached, which it doesn't trust (typically the CA cert is not in the CA bundle specified).

Show ECC curves that OpenSSL supports:

openssl ecparam -list_curves
  • secp256k1 : SECG curve over a 256 bit prime field
  • secp384r1 : NIST/SECG curve over a 384 bit prime field (higher CPU resources, fairly high compatibility)
  • secp521r1 : NIST/SECG curve over a 521 bit prime field (highest security, low compatibility)
  • prime256v1: X9.62/SECG curve over a 256 bit prime field (good compatibility)

OpenSSL CA Setup

Customer openssl.conf

Root CA

Create a base directory, eg /root/CA/root

Create structure:

# mkdir root
# cd root
# mkdir certs crl newcerts private
# chmod 700 private
# touch index.txt
# echo 1000 > serial

Generate root key. Either RSA:

# openssl genrsa -aes256 -out private/ca.key.pem 4096

or ECC:

# openssl ecparam -genkey -out private/ca.key.pem -name secp384r1
# chmod 400 private/ca.key.pem

Use the root key (ca.key.pem) to create a root cert (ca.cert.pem), lasting for many years:

# openssl req -config openssl.conf -key private/ca.key.pem -new -x509 -days 7300 -sha256 -extensions v3_ca -out certs/ca.cert.pem

(Enter the root CA key password if RSA was chosen. Choose a CN such as "MyOrg Root CA")

# chmod 444 certs/ca.cert.pem

Observe root cert:

# openssl x509 -noout -text -in certs/ca.cert.pem

Intermediate (Signing) CA

# mkdir int1
# cd int1
# mkdir certs crl csr newcerts private
# chmod 700 private
# touch index.txt
# echo 1000 > serial

Add crlnumber to keep track of CRLs

# echo 1000 > crl/number

Copy openssl.conf from root, and change:

dir               = /root/CA/int1
policy            = policy_loose

Create intermediate key:

# openssl genrsa -aes256 -out private/ca.key.pem 4096

(Enter intermediate CA password)

OR:

# openssl ecparam -genkey -out private/ca.key.pem -name secp384r1
# chmod 400 private/ca.key.pem

Create intermediate certificate (matching details apart from CN: "MyOrg Intermediate CA"):

# openssl req -config openssl.conf -new -sha256 -key private/ca.key.pem -out csr/ca.csr.pem
# cd ../root
# openssl ca -config openssl.conf -extensions v3_intermediate_ca -days 365 -notext -md sha256 -in ../int1/csr/ca.csr.pem -out ../int1/certs/ca.cert.pem
# chmod 444 ../int1/certs/ca.cert.pem

The index.txt file should contain an entry of the intermediate cert.

Verify intermediate cert:

# cd ../int1
# openssl x509 -noout -text -in certs/ca.cert.pem
# openssl verify -CAfile ../root/certs/ca.cert.pem certs/ca.cert.pem

Create a certificate chain file (or if the Root CA cert is to be distributed to clients, only the intermediate cert):

# cat certs/ca.cert.pem ../root/certs/ca.cert.pem > certs/ca-chain.cert.pem
# chmod 444 certs/ca-chain.cert.pem

NOTE: normally duplicate certificate entries are not allowed - "ERROR:There is already a certificate for /C=UK/ST=England/L=London/O...". To changes this behavour, make sure index.txt.attr contains:

unique_subject = no

Sign Server and Client Certs

Either obtain a CSR from a client, or generate one:

# cd ../int1
# openssl genrsa -aes256 -out private/myserver.myorg.com.key.pem 2048
# chmod 400 private/myserver.myorg.com.key.pem

or:

# cd ../int1
# openssl ecparam -genkey -out private/myserver.myorg.com.key.pem -name secp384r1
# chmod 400 private/myserver.myorg.com.key.pem

Create a certificate signing request: (for server certs, CN is a FQDN, for client certs it is anything unique, like email):

# openssl req -config openssl.conf -key private/myserver.myorg.com.key.pem -new -sha256 -out csr/myserver.myorg.com.csr.pem

Sign request as CA (For server use server_cert extension, for client, use usr_cert extension):

# openssl ca -config openssl.conf -extensions server_cert -days 365 -notext -md sha256 -in csr/myserver.myorg.com.csr.pem -out certs/myserver.myorg.com.cert.pem
# chmod 444 certs/myserver.myorg.com.cert.pem

The index.txt should now have an entry for the newly signed cert.

Verify:

# openssl x509 -noout -text -in certs/myserver.myorg.com.cert.pem
# openssl verify -CAfile certs/ca-chain.cert.pem certs/myserver.myorg.com.cert.pem

Deploy Certificates

If the CSR was from a 3rd party, just send them the certs/myserver.myorg.com.cert.pem certificate and certs/ca

Eg in Apache (ssl.conf):

SSLCertificateFile /etc/pki/tls/certs/myserver.myorg.com.cert.pem
SSLCertificateKeyFile /etc/pki/tls/private/myserver.myorg.com.key.pem

If using client authentication, additionally:

SSLCACertificateFile /etc/pki/tls/certs/SmithnetCA-chain.cert.pem

(This directive sets the all-in-one file where you can assemble the Certificates of Certification Authorities whose clients you deal with. Such a file is simply the concatenation of the various PEM-encoded Certificate files, in order of preference. This can be used alternatively and/or additionally to SSLCACertificatePath.)

Subject Alternative Name

Before creating a key and CSR, edit openssl.conf to uncomment:

req_extensions = v3_req
[ v3_req ]
...
subjectAltName = @alt_names
[alt_names]
DNS.1 = server.example.com
DNS.2 = www.example.com
  • ALL* names should be listed: if SAN is present, CN is ignored. CSR should then have the SANs present.

However a subsequent CA signing also has to have them defined (not just in the CSR):

[ server cert ]
...
subjectAltName = @alt_names

PKCS#12

If required, the CA public certificate can be packaged as a PFX file, with additional "Friendly Name" and optional export password:

openssl pkcs12 -export -in cacert.pem -out cacert.pfx -inkey cakey.pem -name "Smithnet CA"

User Certificates

Generate key:

# openssl ecparam -genkey -name secp384r1 -out private/joebloggs.key.pem

Generate CSR:

# openssl req -config openssl.conf -new -key private/joebloggs.key.pem -out csr/joebloggs.csr.pem

Sign with CA:

# openssl ca -config openssl.conf -extensions usr_cert -days 720 -notext -md sha256 -in csr/joebloggs.csr.pem -out certs/joebloggs.cert.pem

Package key and cert with password, to be imported into browser:

# openssl pkcs12 -export -clcerts -in certs/joebloggs.cert.pem -inkey private/joebloggs.key.pem -out joebloggs.p12

Configure Apache to check client certificate:

SSLCACertificateFile /etc/pki/tls/certs/ca-chain.cert.pem
SSLVerifyClient require
SSLVerifyDepth 2
<Location>
  SSLRequireSSL
  SSLRequire %{SSL_CIPHER} !~ m/^(EXP|NULL)/ and %{SSL_CLIENT_S_DN_O} eq "MyOrg" and %{SSL_CLIENT_S_DN_OU} in {"IT", "Staff"}
</Location>

Tomcat

Java Keystore

Java keytool supports keystore formats:

  • JKS
  • PKCS7 - package multiple certs in a single package, no password
  • PKCS10 - CSR
  • PKCS11
  • PKCS12 - package multiple certs in a single package, with a password, used my OpenSSL and Microsoft Key-Manager

See also full list here

Entry types:

  • PrivateKeyEntry - Private key with key chain
  • secretKeyEntry
  • trustedCertEntry - Public key of another entity that we trust (eg root CA)

List entries in truststore:

keytool -list -v -keystore cacerts.p12 -storepass changeit -storetype PKCS12 -providername JsafeJCE

List entries in keystore:

keytool -list -v -keystore keystore.p12 -storepass internal -storetype PKCS12 -providername JsafeJCE

List entries in JVM keystore (CA certificates):

$JAVA_HOME/jdk/bin/keytool -list -storepass changeit -keystore $JAVA_HOME/jdk/jre/lib/security/cacerts

See here for other examples.

HTTPS connector

  • Configured in server.xml
  • If keyAlias on the connector is not specified, the first certificate in the keystore will be used.

JSSE Mode

cd /etc/tomcat
keytool -genkey -alias tomcat -keyalg RSA -keystore keystore.p12 -keysize 2048 -storetype pkcs12 -storepass password
keytool -certreq -alias tomcat -keyalg RSA -keystore keystore.p12 -storetype pkcs12 -storepass password -file certreq.csr

Send CSR to CA and obtain signed cert newcert.pem and CA root cert RootCA.pem

keytool -importcert -trustcacerts -alias rootca -keystore /usr/lib/jvm/java-1.7.0-openjdk-1.7.0.60-2.4.2.4.fc19.x86_64/jre/lib/security/cacerts -storepass changeit -file RootCA.pem
keytool -importcert -trustcacerts -alias tomcat -keyalg RSA -keystore keystore.p12 -storetype pkcs12 -storepass password -file newcert.pem

Configuration in server.xml:

<Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"
             keystorefile="/etc/tomcat/keystore.p12" keystorePass="password" keystoreType="PKCS12"
             maxThreads="150" scheme="https" secure="true"
             clientAuth="false" sslProtocol="TLS" />

APR Mode (using OpenSSL)

TBC