Skip to content

Latest commit

 

History

History
659 lines (470 loc) · 21.1 KB

openssl_cookbook.md

File metadata and controls

659 lines (470 loc) · 21.1 KB

OpenSSL Cookbook

Getting Started

$ openssl version -a
LibreSSL 3.3.6
built on: date not available
platform: information not available
options:  bn(64,64) rc4(16x,int) des(idx,cisc,16,int) blowfish(idx)
compiler: information not available
OPENSSLDIR: "/private/etc/ssl"

The last line in the output (/private/etc/ssl) tell you where OpenSSL will look for its configuration and certificates.

$ls /private/etc/ssl
cert.pem    certs       openssl.cnf x509v3.cnf

Examine Available Commands

$ openssl -h

The first part of the help output lists all available utilities.

Standard commands
asn1parse         ca                certhash          ciphers
...
gendh             gendsa            genpkey           genrsa
pkcs7             pkcs8             pkey              pkeyparam
...
x509

To get more information about a particular utility, say ciphers,

$ openssl ciphers -h
usage: ciphers [-hVv] [-tls1] [cipherlist]
 -tls1              This option is deprecated since it is the default
 -v                 Provide cipher listing
 -V                 Provide cipher listing with cipher suite values

In the second part, you get the list of message digest commands:

Message Digest commands (see the `dgst' command for more details)
gost-mac          md4               md5               md_gost94
ripemd160         sha1              sha224            sha256
sha384            sha512            sm3               sm3WithRSAEncryption
streebog256       streebog512       whirlpool

In the third part, you’ll see the list of all cipher commands:

aes-128-cbc       aes-128-ecb       aes-192-cbc       aes-192-ecb       
aes-256-cbc       aes-256-ecb       base64            bf                
...

Building a Trust Store

OpenSSL does not come with any trusted root certificates (also known as a trust store).

One possibility is to use the trust store built into your operating system.

Or use the one Mozilla maintains, but you need extra work to convert it to proprietary format.

https://hg.mozilla.org/mozilla-central/raw-file/tip/security/nss/lib/ckfw/builtins...
/certdata.txt
# download convert tool
$ wget https://raw.github.com/agl/extract-nss-root-certs/master/convert_mozilla_certdata.go
# download Mozilla’s certificate data:
$ wget https://hg.mozilla.org/mozilla-central/raw-file/tip/security/nss/lib/ckfw/builtins/certdata.txt
# convert the file
$ go run convert_mozilla_certdata.go > ca-certificates

Key and Certificate Management

Most users turn to OpenSSL because they wish to configure and run a web server that supports SSL.

That process consists of three steps:

  1. generate a strong private key
  2. create a Certificate Signing Request (CSR) and send it to a CA
  3. install the CA-provided certificate in your web server.

Before you begin, you must make several decisions:

  • Key algorithm
    • OpenSSL supports RSA, DSA, and ECDSA keys.
    • For web server keys everyone uses RSA, because DSA keys are effectively limited to 1,024 bits, and ECDSA keys are yet to be widely supported by CAs.
    • For SSH, DSA and RSA are widely used, whereas ECDSA might not be supported by all clients.
  • Key size
    • The default key sizes might not be secure.
      • For example, the default for RSA keys is only 512 bits, which is simply insecure. An intruder could take your certificate and use brute force to recover your private key
    • Today, 2,048-bit RSA keys are considered secure, and that’s what you should use.
    • Aim also to use 2,048 bits for DSA keys and at least 256 bits for ECDSA.
  • Passphrase
    • Using a passphrase with a key is optional, but strongly recommended.
    • But using protected keys are inconvenient, and in production does not actually increase the security much, if at all (once activated, private keys are kept unprotected in program memory).
    • Thus, passphrases should be viewed only as a mechanism for protecting private keys when they are not installed on production systems.

Key Pair Generation

Note: If you’re using OpenSSL 1.0.2, you can save yourself time by always generating your keys using the genpkey command

To generate an RSA key

$ openssl genrsa -out serv.key 2048
Generating RSA private key, 2048 bit long modulus
...................+++++
.......................+++++
e is 65537 (0x10001)

This key is in PKCS1 ( Public Key Cryptography Standards ) format.

If you want to use passphrase, add -aes128 (or -aes192, -aes256), and it's best to stay away from the other algorithms (DES, 3DES, and SEED).

$ openssl genrsa -aes128 -out serv.key 2048

Private keys are stored in the so-called PEM format, which is just text:

$ cat serv.key 
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-128-CBC,30666299C618C15D7C38ACAB4DE673BE

sDNj92sqonfL9zDryoH04bLdvgGdKh/gk3+DixhROUCSDM8Ii2LohJsi/7rYCXJC
...
vRbvP2NH7cQyZP8HwFMrD9dQ6jYnODQsd2YKAM12hU22vBNu1qBob1ds1jLhQGtP
-----END RSA PRIVATE KEY-----

Extract Public Key from Private Key

$ openssl rsa -in serv.key -pubout -out serv-public.key

$ cat serv-public.key
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuQgy4mnd07n137wNVcHE
...
+QIDAQAB
-----END PUBLIC KEY-----

If you want to generate the obsoluted RSA PUBLIC KEY, add -RSAPublicKey_out

$ openssl rsa -in serv.key -pubout -out serv-rsa-pub.key -RSAPublicKey_out
$cat serv-rsa-pub.key                
-----BEGIN RSA PUBLIC KEY-----
...

The "RSA PUBLIC KEY" format was used in very early SSLeay, which evolved into OpenSSL, but obsoleted before 2000. Although this format is long obsolete, OpenSSL still supports it. "RSA PUBLIC KEY" format is the RSA-specific format from PKCS#1, whereas "PUBLIC KEY" is the X.509 generic structure that handles numerous (and extensible) algorithm.

Generate DSA/EDDSA Key

# DSA
$ openssl dsaparam -genkey 2048 | openssl dsa -out dsa.key [-aes128]
# ECDSA
$ openssl ecparam -genkey -name secp256r1 | openssl ec -out ec.key [-aes128]

Creating Certificate Signing Requests

Once you have a private key, you can proceed to create a Certificate Signing Request (CSR).

This is a formal request asking a CA to sign a certificate, and it contains the public key, and some information about the entity.

$ openssl req -new -key serv.key -out serv.csr
-----
Country Name (2 letter code) []:PK
State or Province Name (full name) []:ISB
Locality Name (eg, city) []:ISB
Organization Name (eg, company) []:fakecom
Organizational Unit Name (eg, section) []:fakecom
Common Name (eg, fully qualified host name) []:*.example.com
Email Address []:[email protected]

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:

For test purpose, only the Common Name is important.

CSR Verification

After a CSR is generated, use it to sign your own certificate and/or send it to a public CA and ask them to sign the certificate.

But before you do that, it’s a good idea to double-check that the CSR is correct.

$ openssl req -text -in serv.csr -noout -verify
verify OK
Certificate Request:
    Data:
        Version: 0 (0x0)
        Subject: C=PK, ST=ISB, L=ISB, O=fakecom, OU=fakecom, CN=*.example.com/[email protected]
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                RSA Public-Key: (2048 bit)

Everything that you provided is showing here. If you find that anything is wrong, you can still regenerate your CSR.

Self Signed Certificate

If you’re installing a TLS server for your own use, you probably don’t want to go to a CA for a publicly trusted certificate. It’s much easier to just use a self-signed certificate.

$ openssl x509 -in serv.csr -out serv.crt -req -signkey serv.key -days 3650
Signature ok
subject=/C=PK/ST=ISB/L=ISB/O=fakecom/OU=fakecom/CN=*.example.com/[email protected]
Getting Private key

serv.crt is our signed x509 certificate.

X.509是密码学里公钥证书的格式标准。 X.509证书已应用在包括TLS/SSL在内的众多网络协议里,同时它也用在很多非在线应用场景里,比如电子签名服务。 X.509证书里含有公钥、身份信息(比如网络主机名,组织的名称或个体名称等)和签名信息(可以是证书签发机构CA的签名,也可以是自签名)

You don’t actually have to create a CSR in a separate step. User openssl req to create both CSR and CRT.

$ openssl req -new -x509 -days 3650 -key serv.key -out serv.crt

If you don’t wish to be asked any questions, use the -subj to provide the informations.

One line command to self-assign:

$ openssl req -new -x509 -days 3650 -key serv.key -out serv.crt \
    -subj "/C=PK/ST=ISB/L=ISB/O=fakecom/OU=fakecom/CN=*.example.com/[email protected]"

We can take a look inside the certificate.

$ openssl x509 -text -in serv.crt -noout

Key and Certificate Conversion

Private keys and certificates can be stored in a variety of formats:

  • Binary (DER) certificate
    • Contains an X.509 certificate in its raw form, using DER ASN.1 encoding.
  • ASCII (PEM) certificate(s)
    • Contains a base64-encoded DER certificate, with -----BEGIN CERTIFICATE----- used as the header and -----END CERTIFICATE----- as the footer.
  • Binary (DER) key
    • Contains a private key in its raw form, using DER ASN.1 encoding.
    • OpenSSL creates keys in its own traditional (SSLeay) format
    • There’s also an alternative format called PKCS#8 (defined in RFC 5208), but it’s not widely used.
    • OpenSSL can convert to and from PKCS#8 format using the pkcs8 command.
  • ASCII (PEM) key
    • Contains a base64-encoded DER key, sometimes with additional metadata(e.g., the algorithm used for password protection).
  • PKCS#7 certificate(s)
    • It’s usually seen with .p7b and .p7c extensions and can include the entire certificate chain as needed. This format is supported by Java’s keytool utility.
  • PKCS#12 (PFX) key and certificate(s)
    • A complex format that can store and protect a server key along with an entire certificate chain.
    • It’s commonly seen with .p12 and .pfx extensions. This format is commonly used in Microsoft products, but is also used for client certificates.

PEM and DER Conversion

Convert X.509 certificate:

openssl x509 -in cert.cer -inform der -out cert.crt -outform pem
openssl x509 -in cert.crt -inform pem -out cert.cer -outform der

The syntax is identical if you need to convert private keys between DER and PEM formats, but different commands are used: rsa for RSA keys, and dsa for DSA keys.

convert between PKCS#1 and PKCS#8

# #1 -> #8
openssl pkcs8 -in private-pkcs1.pem -topk8 -out private-pkcs8.pem -nocrypt
openssl pkcs8 -in private-pkcs1.pem -topk8 -out private-pkcs8-enc.pem
# #8 -> #1
openssl rsa -in private-pkcs8.pem -out private-pkcs1.pem

Testing with OpenSSL

Connecting to SSL Services

OpenSSL comes with a client tool, this tool is similar to telnet or nc, in the sense that it handles the SSL/TLS layer but allows you to fully control the layer that comes next.

$ openssl s_client -connect openai.com:443

Once you type the command, you’re going to see a lot of diagnostic output,

followed by an opportunity to type whatever you want.

Because we’re talking to an HTTP server, the most sensible thing to do is to submit an HTTP request.

HEAD / HTTP/1.0
HOST: openai.com

HTTP/1.1 200 OK
...
closed

Now, let’s go back to the diagnostic output.

The first couple of lines show the information about the server certificate:

CONNECTED(00000006)
depth=2 C = US, O = DigiCert Inc, OU = www.digicert.com, CN = DigiCert Global Root G2
verify return:1
depth=1 C = US, O = Microsoft Corporation, CN = Microsoft Azure TLS Issuing CA 01
verify return:1
depth=0 C = US, ST = WA, L = Redmond, O = Microsoft Corporation, CN = *.azureedge.net
verify return:1

The next section in the output lists all the certificates presented by the server in the order in which they were delivered:

Certificate chain
 0 s:/C=US/ST=WA/L=Redmond/O=Microsoft Corporation/CN=*.azureedge.net
   i:/C=US/O=Microsoft Corporation/CN=Microsoft Azure TLS Issuing CA 01
 1 s:/C=US/O=Microsoft Corporation/CN=Microsoft Azure TLS Issuing CA 01
   i:/C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert Global Root G2

For each certificate, the first line shows the subject and the second line shows the issuer information.

The next item in the output is the server certificate.

Server certificate
-----BEGIN CERTIFICATE-----
MIIIvDCCBqSgAwIBAgITMwCJVYBSn8/jQ4R/UwAAAIlVgDANBgkqhkiG9w0BAQwF
...
-----END CERTIFICATE-----
subject=/C=US/ST=WA/L=Redmond/O=Microsoft Corporation/CN=*.azureedge.net
issuer=/C=US/O=Microsoft Corporation/CN=Microsoft Azure TLS Issuing CA 01

The following is a lot of information about the TLS connection.

No client certificate CA names sent
Server Temp Key: ECDH, P-384, 384 bits
---
SSL handshake has read 4286 bytes and written 445 bytes
---
New, TLSv1/SSLv3, Cipher is ECDHE-RSA-AES256-GCM-SHA384
Server public key is 2048 bit
Secure Renegotiation IS supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
SSL-Session:
    Protocol  : TLSv1.2
    Cipher    : ECDHE-RSA-AES256-GCM-SHA384
    ...

The most important information here is the protocol version (TLS 1.2), and cipher suite used ECDHE-RSA-AES256-GCM-SHA384.

Extracting Remote Certificates

If you need the server certificate for any reason, you can copy it from the scroll-back buffer.

Or use this command line as a shortcut:

# Following command is for MacOSX. On Linux, you may replace `-n` with `--quiet`
echo | openssl s_client -connect openai.com:443 2>&1 | sed -n '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > openai.crt
$ cat openai.crt
-----BEGIN CERTIFICATE-----
MIIIvDCCBqSgAwIBAgITMwCJVYBSn8/jQ4R/UwAAAIlVgDANBgkqhkiG9w0BAQwF
...
-----END CERTIFICATE-----

Testing Protocol Support

By default, s_client will try to use the best protocol to talk to the remote server and report the negotiated version in output.

    Protocol  : TLSv1.2

If you need to test support for specific protocol versions

 -no_tls1           Disable the use of TLSv1
 -no_tls1_1         Disable the use of TLSv1.1
 -no_tls1_2         Disable the use of TLSv1.2
 -no_tls1_3         Disable the use of TLSv1.3

 -tls1              Just use TLSv1
 -tls1_1            Just use TLSv1.1
 -tls1_2            Just use TLSv1.2
 -tls1_3            Just use TLSv1.3

e.g.

$ openssl s_client -connect openai.com:443 -tls1_1

Testing Session Reuse

When coupled with the -reconnect switch, the s_client command can be used to test session reuse.

$ echo | openssl s_client -connect baidu.com:443 -reconnect 2>/dev/null |  grep 'New\|Reuse'
New, TLSv1/SSLv3, Cipher is ECDHE-RSA-AES128-GCM-SHA256
Reused, TLSv1/SSLv3, Cipher is ECDHE-RSA-AES128-GCM-SHA256
Reused, TLSv1/SSLv3, Cipher is ECDHE-RSA-AES128-GCM-SHA256
Reused, TLSv1/SSLv3, Cipher is ECDHE-RSA-AES128-GCM-SHA256
Reused, TLSv1/SSLv3, Cipher is ECDHE-RSA-AES128-GCM-SHA256
Reused, TLSv1/SSLv3, Cipher is ECDHE-RSA-AES128-GCM-SHA256

Other Commands

rand

Generate random bytes, can be encoded as -base64 or -hex

To generate a random password in hex format:

$ openssl rand -hex 20
a23b977ca0fac4ced01de8cb69f0dfb73bdb41ab

To generate the random password in base64:

$ openssl rand -base64 20
ocrioY+RhvmV3OfWl6D7BhyXmjY=

dgst

Calculate hash

$ echo -m hello | openssl dgst -md5
8f5dbe1b32c6881ddc8a74238d52ef2a
$ echo -m hello | md5 # verify
8f5dbe1b32c6881ddc8a74238d52ef2a
$ echo -m hello | openssl dgst -sha1
9fe12ce55bf59bc5d099870e8bcc20a433e78bb8
$ echo -m hello | shasum # verify
9fe12ce55bf59bc5d099870e8bcc20a433e78bb8  -

OpenSSH Key

SSH RSA Public Key

An RSA public key formatted by OpenSSH , can be generated by ssh-keygen

$ ssh-keygen -b 2048 -t rsa

SSH keys are used for secure connections across a network, usually they are all in one line.

ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAQB/nAmOjTmezNUDKYvEeIRf2YnwM9/uUG1d0BYsc8/tRtx+RGi7N2lUbp728MXGwdnL9od4cItzky/zVdLZE2cycOa18xBK9cOWmcKS0A8FYBxEQWJ/q9YVUgZbFKfYGaGQxsER+A0w/fX8ALuk78ktP31K69LcQgxIsl7rNzxsoOQKJ/CIxOGMMxczYTiEoLvQhapFQMs3FL96didKr/QbrfB1WT6s3838SEaXfgZvLef1YB2xmfhbT9OXFE3FXvh2UPBfN+ffE7iiayQf/2XR+8j4N4bW30DiPtOQLGUrH1y5X/rpNZNlWW2+jGIxqZtgWg7lTy3mXy5x836Sj/6L

The standard ssh2 file format for use in Secure Shell.

$ ssh-keygen -b 2048 -t rsa -e
  • -e
    • The export format is “RFC4716”
---- BEGIN SSH2 PUBLIC KEY ----
Comment: "2048-bit RSA, ..."
AAAAB3NzaC1yc2EAAAABJQAAAQB/nAmOjTmezNUDKYvEeIRf2YnwM9/uUG1d0BYs
c8/tRtx+RGi7N2lUbp728MXGwdnL9od4cItzky/zVdLZE2cycOa18xBK9cOWmcKS
0A8FYBxEQWJ/q9YVUgZbFKfYGaGQxsER+A0w/fX8ALuk78ktP31K69LcQgxIsl7r
NzxsoOQKJ/CIxOGMMxczYTiEoLvQhapFQMs3FL96didKr/QbrfB1WT6s3838SEaX
fgZvLef1YB2xmfhbT9OXFE3FXvh2UPBfN+ffE7iiayQf/2XR+8j4N4bW30DiPtOQ
LGUrH1y5X/rpNZNlWW2+jGIxqZtgWg7lTy3mXy5x836Sj/6L
---- END SSH2 PUBLIC KEY ----

Convert between different formats...

The ssh-keygen utility is used to covert SSH keys between the different formats.

  • convert to OpenSSH format.
    • -i : this option will read an unencrypted private (or public) key file in the format specified by the -m option and print an OpenSSH compatible private (or public) key to stdout.
      • The default import format is “RFC4716”(SSH2).
    # -mPKCS8  to specify the input format
    ssh-keygen -f pub1key.pub -i -mPKCS8

-m key_format Specify a key format for the -i (import) or -e (export) conversion options. The supported key formats are: “RFC4716” (RFC 4716/SSH2 public or private key), “PKCS8” (PEM PKCS8 public key) or “PEM” (PEM public key). The default conversion format is “RFC4716”.

  • to convert OpenSSH format(ssh-rsa) to SSH2 format
    • -e: read a private or public OpenSSH key file and print to stdout a public key in one of the formats specified by the -m option
      • The default export format is “RFC4716”(SSH2).
    ssh-keygen -e -f ./openssh.pub