OpenSSL 完全指南
openssl
OpenSSL 是一个强大的安全套接字层密码库,囊括主要的密码算法、常用的密钥和证书封装管理功能及SSL协议,并提供丰富的应用程序供测试或其它目的使用。
在OpenSSL被曝出现严重安全漏洞后,发现多数通过SSL协议加密的网站使用名为OpenSSL的开源软件包。由于这是互联网应用最广泛的安全传输方法,被网银、在线支付、电商网站、门户网站、电子邮件等重要网站广泛使用,所以该漏洞影响范围广大。
OpenSSL有两种运行模式:交互模式和批处理模式。
直接输入openssl回车进入交互模式,输入带命令选项的openssl进入批处理模式。
OpenSSL整个软件包大概可以分成三个主要的功能部分:
- 密码算法库
- SSL协议库
- 应用程序。
OpenSSL的目录结构自然也是围绕这三个功能部分进行规划的。
1.对称加密算法
OpenSSL一共提供了8种对称加密算法,其中7种是分组加密算法,仅有的一种流加密算法是RC4。这7种分组加密算法分别是AES、DES、Blowfish、CAST、IDEA、RC2、RC5,都支持电子密码本模式(ECB)、加密分组链接模式(CBC)、加密反馈模式(CFB)和输出反馈模式(OFB)四种常用的分组密码加密模式。其中,AES使用的加密反馈模式(CFB)和输出反馈模式(OFB)分组长度是128位,其它算法使用的则是64位。事实上,DES算法里面不仅仅是常用的DES算法,还支持三个密钥和两个密钥3DES算法。
2.非对称加密算法
OpenSSL一共实现了4种非对称加密算法,包括DH算法、RSA算法、DSA算法和椭圆曲线算法(EC)。DH算法一般用户密钥交换。RSA算法既可以用于密钥交换,也可以用于数字签名,当然,如果你能够忍受其缓慢的速度,那么也可以用于数据加密。DSA算法则一般只用于数字签名。
3.信息摘要算法
OpenSSL实现了5种信息摘要算法,分别是MD2、MD5、MDC2、SHA(SHA1)和RIPEMD。SHA算法事实上包括了SHA和SHA1两种信息摘要算法,此外,OpenSSL还实现了DSS标准中规定的两种信息摘要算法DSS和DSS1。
4.密钥和证书管理
密钥和证书管理是PKI的一个重要组成部分,OpenSSL为之提供了丰富的功能,支持多种标准。
首先,OpenSSL实现了ASN.1的证书和密钥相关标准,提供了对证书、公钥、私钥、证书请求以及CRL等数据对象的DER、PEM和BASE64的编解码功能。OpenSSL提供了产生各种公开密钥对和对称密钥的方法、函数和应用程序,同时提供了对公钥和私钥的DER编解码功能。并实现了私钥的PKCS#12和PKCS#8的编解码功能。OpenSSL在标准中提供了对私钥的加密保护功能,使得密钥可以安全地进行存储和分发。
在此基础上,OpenSSL实现了对证书的X.509标准编解码、PKCS#12格式的编解码以及PKCS#7的编解码功能。并提供了一种文本数据库,支持证书的管理功能,包括证书密钥产生、请求产生、证书签发、吊销和验证等功能。
事实上,OpenSSL提供的CA应用程序就是一个小型的证书管理中心(CA),实现了证书签发的整个流程和证书管理的大部分机制。
openssl 用法
介绍
查看OpenSSL是什么版本?
使用version选项
$ openssl version
OpenSSL 0.9.8zh 14 Jan 2016
跟上-a选项能得到更多的信息:
$ openssl versoin -a
OpenSSL 0.9.8zh 14 Jan 2016
built on: May 15 2016
platform: darwin64-x86_64-llvm
options: bn(64,64) md2(int) rc4(ptr,char) des(idx,cisc,16,int) blowfish(idx)
compiler: -arch x86_64 -fmessage-length=0 -pipe -Wno-trigraphs -fpascal-strings -fasm-blocks -O3 -D_REENTRANT -DDSO_DLFCN -DHAVE_DLFCN_H -DL_ENDIAN -DMD32_REG_T=int -DOPENSSL_NO_IDEA -DOPENSSL_PIC -DOPENSSL_THREADS -DZLIB -mmacosx-version-min=10.6
OPENSSLDIR: "/System/Library/OpenSSL"
查看有哪些命令选项?
内置的查看命令(比如openssl list-standard-commands)只能查出一组,有个技巧是加上一个无效的选项(比如help或-h),就可以得到所有的结果。
$ openssl help
openssl:Error: 'help' is an invalid command.
Standard commands
asn1parse ca ciphers crl crl2pkcs7
dgst dh dhparam dsa dsaparam
ec ecparam enc engine errstr
gendh gendsa genrsa nseq ocsp
passwd pkcs12 pkcs7 pkcs8 prime
rand req rsa rsautl s_client
s_server s_time sess_id smime speed
spkac verify version x509
Message Digest commands (see the `dgst' command for more details)
md2 md4 md5 mdc2 rmd160
sha sha1
Cipher commands (see the `enc' command for more details)
aes-128-cbc aes-128-ecb aes-192-cbc aes-192-ecb aes-256-cbc
aes-256-ecb base64 bf bf-cbc bf-cfb
bf-ecb bf-ofb cast cast-cbc cast5-cbc
cast5-cfb cast5-ecb cast5-ofb des des-cbc
des-cfb des-ecb des-ede des-ede-cbc des-ede-cfb
des-ede-ofb des-ede3 des-ede3-cbc des-ede3-cfb des-ede3-ofb
des-ofb des3 desx rc2 rc2-40-cbc
rc2-64-cbc rc2-cbc rc2-cfb rc2-ecb rc2-ofb
rc4 rc4-40 seed seed-cbc seed-cfb
seed-ecb seed-ofb
所谓“Standard commands”就是openssl后跟的第一个命令选项,可以使用同样的技巧查看有哪些可执行的子选项。
$ openssl dgst -h
unknown option '-h'
options are
-c to output the digest with separating colons
-d to output debug info
-hex output as hex dump
-binary output in binary form
-sign file sign digest using private key in file
-verify file verify a signature using public key in file
-prverify file verify a signature using private key in file
-keyform arg key file format (PEM or ENGINE)
-signature file signature to verify
-binary output in binary form
-hmac key create hashed MAC with key
-engine e use engine e, possibly a hardware device.
-md5 to use the md5 message digest algorithm (default)
-md4 to use the md4 message digest algorithm
-md2 to use the md2 message digest algorithm
-sha1 to use the sha1 message digest algorithm
-sha to use the sha message digest algorithm
-sha224 to use the sha224 message digest algorithm
-sha256 to use the sha256 message digest algorithm
-sha384 to use the sha384 message digest algorithm
-sha512 to use the sha512 message digest algorithm
-mdc2 to use the mdc2 message digest algorithm
-ripemd160 to use the ripemd160 message digest algorithm
你也可是使用man openssl查看详细。
查看支持哪些算法?
使用ciphers选项,更多用法参见ciphers的说明文档。
# 列出所有可用的算法
openssl ciphers -v
# 列出符合TLSv1协议的算法
openssl ciphers -v -tls1
# 列出高级别加密的算法(密钥长度大于128位)
openssl ciphers -v 'HIGH'
# 列出使用了AES的高级别加密算法
openssl ciphers -v 'AES+HIGH'
性能测试
如何测试当前系统的运算性能?
OpenSSL的开发者在库里内置了测性能的套件,通过speed命令选项来使用。它测试在给定的时间内可以进行多少运算,而不是指定的运算需要多少时间。这样处理是很合理的,因此测试程序在性能好坏的系统上运行的时间不会相差太多。
只使用speed选项,测试所有算法的性能。
openssl speed
有两组结果,第一组表示指定的算法每秒可以处理多少字节的数据,第二组表示一次签名/验证花费的时间。
下面是在2.7GHZ Intel Xeon E5处理器上的测试结果:
The 'numbers' are in 1000s of bytes per second processed.
type 16 bytes 64 bytes 256 bytes 1024 bytes 8192 bytes
md2 2540.48k 5184.66k 6989.57k 7651.67k 7872.51k
mdc2 0.00 0.00 0.00 0.00 0.00
md4 83248.41k 261068.18k 624212.82k 940529.32k 1128846.68k
md5 62411.57k 184768.36k 408835.75k 586930.52k 678061.98k
hmac(md5) 48713.62k 148265.56k 359626.67k 563050.68k 670255.79k
sha1 68829.72k 195087.40k 431001.51k 623344.42k 729505.79k
rmd160 38598.59k 96226.86k 183336.45k 235962.71k 257526.44k
rc4 480093.57k 678565.35k 783765.42k 818297.51k 838205.99k
des cbc 69500.17k 71184.75k 71491.50k 71641.77k 72010.15k
des ede3 26433.63k 26717.01k 26772.99k 26788.18k 26907.57k
idea cbc 95690.28k 99334.17k 100835.40k 100787.54k 100900.86k
seed cbc 76871.40k 77238.46k 77736.50k 77452.97k 77545.47k
rc2 cbc 48984.63k 49589.03k 50188.07k 50103.98k 50066.77k
rc5-32/12 cbc 0.00 0.00 0.00 0.00 0.00
blowfish cbc 122583.30k 129550.92k 130876.67k 131111.94k 131394.22k
cast cbc 109471.38k 114523.31k 115934.46k 116200.45k 116331.86k
aes-128 cbc 128352.23k 138604.76k 141173.42k 142832.25k 142682.79k
aes-192 cbc 107703.93k 114456.79k 117716.65k 118847.36k 118784.00k
aes-256 cbc 93374.87k 99521.51k 101198.51k 101382.49k 101635.41k
camellia-128 cbc 99270.57k 150412.42k 170346.33k 176311.91k 177913.86k
camellia-192 cbc 85896.60k 117356.52k 128556.97k 132759.72k 133425.83k
camellia-256 cbc 87351.27k 117695.15k 128972.03k 132130.47k 133455.87k
sha256 52372.61k 117766.12k 204825.69k 249974.10k 270914.90k
sha512 41278.19k 165820.37k 258298.69k 365981.70k 419864.58k
whirlpool 24803.02k 53047.07k 87593.90k 104570.54k 111159.98k
aes-128 ige 128441.31k 132981.88k 133269.08k 133738.15k 133966.51k
aes-192 ige 107831.37k 111507.07k 111800.66k 112156.67k 112219.48k
aes-256 ige 94382.07k 96351.17k 96750.68k 96958.46k 97446.44k
ghash 888644.92k 1452788.80k 1696788.74k 1763055.96k 1799086.49k
sign verify sign/s verify/s
rsa 512 bits 0.000049s 0.000004s 20547.1 248266.2
rsa 1024 bits 0.000194s 0.000011s 5146.0 90735.4
rsa 2048 bits 0.001194s 0.000037s 837.3 27277.1
rsa 4096 bits 0.008560s 0.000137s 116.8 7324.5
sign verify sign/s verify/s
dsa 512 bits 0.000048s 0.000046s 20667.7 21701.8
dsa 1024 bits 0.000113s 0.000126s 8831.9 7951.8
dsa 2048 bits 0.000362s 0.000430s 2762.0 2322.9
sign verify sign/s verify/s
256 bit ecdsa (nistp256) 0.0001s 0.0004s 9856.1 2524.4
384 bit ecdsa (nistp384) 0.0002s 0.0008s 5103.6 1191.7
521 bit ecdsa (nistp521) 0.0004s 0.0018s 2679.0 550.3
op op/s
256 bit ecdh (nistp256) 0.0003s 3063.8
384 bit ecdh (nistp384) 0.0007s 1447.3
521 bit ecdh (nistp521) 0.0015s 666.2
也可以只测试指定的算法:
# 测试RSA的速度
openssl speed rsa
# 在多核系统中并行两组测试
openssl speed rsa -multi 2
如何测试远程连接的耗时?
使用s_time选项可以测试连接性能,直接调用会运行30秒,使用任意的加密算法,统计每秒钟通过SSL握手建立的连接数,结果分为新会话和重用会话两组:
openssl s_time -connect romete.host:443
# 译者注:可以拿百度来测试
openssl s_time -connect baidu.com:443
除了直接调用外,s_time选项也提供了很多测试的子选项
# 只通过新会话获取远端test.html页面
openssl s_time -connect remote.host:443 -www /test.html -new
# 使用SSL v3和高级别加密算法
openssl s_time \
-connect remote.hot:443 -www /test.html -new \
-ssl3 -cipher HIGH
# 测试不同加密算法的性能,每种算法测试10秒
IFS=":"
for c in $(openssl ciphers -ssl3 RSA); do
echo $C
openssl s_time -connect remote.host:443 \
-www / -new -time 10 -cipher $c 2>&1 | \
grep bytes
echo
done
如果你没有可测的启用SSL的服务端,可以使用s_server选项来创建一个。
# 在一台主机上创建服务端,默认使用4433端口
openssl s_server -cert mycert.pem -www
# 在另一台主机上(可以跟服务端同一台),运行s_time
openssl s_time -connect myhost:4433 -www / -new -ssl3
证书
如何生成自签名的证书?
首先考虑是否要对私钥进行加密。
加密私钥的好处是更加安全,有人拿走了也无法使用。坏处是需要把密码保存在某个文件或每次启动服务时手动输入。
我个人倾向不加密私钥,这样不用每次手动输入。(当你厌烦输入时,要知道去除密码保护也是可以的。)
下面的例子会生成一个mycert.pem证书文件,其中证书的有效期是365天,私钥不加密(-ndoes决定的)。
openssl req \
-x509 -nodes -days 365 -sha256 \
-newkey rsa:2048 -keyout mycert.pem -out mycert.pem
这个文件中有两部分信息:RSA私钥和证书。
cat mycert.pem
-----BEGIN RSA PRIVATE KEY-----
...
-----END RSA PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
证书部分包含公钥。
openssl x509 -in mycert.pem -pubkey -noout
-----BEGIN PUBLIC KEY-----
...
-----END PUBLIC KEY-----
使用这个指令后,会要求你回答一系列的问题:国家,省市,公司,职位等等。当回答“Common Name”这个问题要注意点,你可能会填写主机名或域名,如果服务器的真实地址是mybox.mydomain.com,但用户是通过www.mydomain.com来访问的,那么你应填写用户访问的地址。
可以通过-subj选项来直接写入这些回答,对生成证书来说惟一有用的就是Common Name(CN)字段。
openssl req \
-x509 -nodes -days 365 -sha256 \
-subj '/C=US/ST=Oregon/L=Portland/CN=www.madboa.com' \
-newkey rsa:2048 -keyout mycert.pem -out mycert.pem
如何生成VeriSign的证书请求?
向认证机构(比如VeriSign)申请签名证书是相当繁杂和官僚的,在创建证书请求前要先准备好需要的书面文件(营业执照等)。
上一节说到,你需要考虑是否加密私钥,下面的例子假设不加密,最后会得到两个文件:私钥文件mykey.pem,证书请求文件myreq.pem。
openssl req \
-new -sha256 -newkey rsa:2048 -nodes \
-keyout mykey.pem -out myreq.pem
如果是使用已有的私钥文件生成证书请求,语法更简单点:
openssl req -new -key mykey.pem -out myreq.pem
同样的,你也可以在命令中直接写入要回答的问题:
openssl req \
-new -sha256 -newkey rsa:2048 -nodes \
-subj '/CN=www.mydom.com/O=My Dom. Inc./C=US/ST=Oregon/L=Portland' \
-keyout mykey.pem -out myreq.pem
在跟像VeriSign这样的机构打交道时,要特别注意在创建证书请求时填写的信息。根据我个人的经验,比如填写组织名字时用and代替&,都会造成申请不通过。
需要仔细确认证书请求中的签名、组织等信息。
# 验证签名
openssl req -in myreq.pem -noout -verify -key mykey.pem
# 检查信息
openssl req -in myreq.pem -noout -text
将私钥文件保存在安全的地方,要使用VeriSign发回给你证书必须要用到它。证书请求一般是通过VeriSign的线上表单提交。
如何测试一个新证书?
s_server选项提供了一个简单有效的测试方法。下面的例子假设你已经把私钥和证书合并为一个文件(也可以是上面生成的自签名证书):mycert.pem。
首先启动测试服务端,默认使用4433端口,可以使用-accept选项修改。
openssl s_server -cert mycert.pem -www
如果服务端正常启动,没有报错信息,说明证书就可以使用了。
可以在浏览器里访问测试服务器https://yourserver:4433/。注意是https,打开这个界面可以看到可用的加密算法以及连接相关的统计。如果是自签名的证书,浏览器会提示你是否相信此证书。
怎么得到远端的证书?
只要配合使用openssl和sed命令,就能取到远端的证书信息。
#!/bin/sh
#
# usage: retrieve-cert.sh remote.host.name [port]
#
REMHOST=$1
REMPORT=${2:-443}
echo |\
openssl s_client -connect ${REMHOST}:${REMPORT} 2>&1 |\
sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p'
也可以把得到信息再交给openssl处理,比如检查证书的日期:
#!/bin/sh
#
for CERT in \
www.yourdomain.com:443 \
ldap.yourdomain.com:636 \
imap.yourdomain.com:993
do
echo |\
openssl s_client -connect ${CERT} 2>/dev/null |\
sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' |\
openssl x509 -noout -subject -dates
done
怎么查看证书中的信息?
一个SSL证书包含很多信息:颁发者,有效期,持有者,算法,公钥等。使用x509选项可以查看这些信息,下面的例子假设有一个名为cert.pem的证书文件。
使用-text选项能同时以可读文本的形式展示信息。
openssl x509 -text -in cert.pem
还有一些选项可以指定展示某项信息。
# 查看颁发者
openssl x509 -noout -in cert.pem -issuer
# 查看持有者
openssl x509 -noout -in cert.pem -subject
# 有效期
openssl x509 -noout -in cert.pem -dates
# 以上全部
openssl x509 -noout -in cert.pem -issuer -subject -dates
# 哈希值
openssl x509 -noout -in cert.pem -hash
# MD5指纹
openssl x509 -noout -in cert.pem -fingerprint
如何导入/导出PKCS#12格式的证书?
PKCS#12格式的证书被许多程序使用,比如微软的IIS,这种证书文件的后缀通常是.pfx。
创建PKCS#12格式的证书,需要私钥和证书。转换时,你会被要求输入密码(可以为空)来对证书进行加密。
# 创建一个包含私钥的自签名证书
openssl req \
-x509 -sha256 -nodes -days 365 \
-newkey rsa:2048 -keyout mycert.pem -out mycert.pem
# 将mycert.pem导出为PKCS#12格式的证书,mycert.pfx
openssl pkcs12 -export \
-out mycert.pfx -in mycert.pem \
-name "My Certificate"
如果你拿到PKCS#12格式的证书和它的密码(如果有的话),可以把它导出为标准的PEM格式。
# 无密码情况下
openssl pkcs12 -in mycert.pfx -out mycert.pem -nodes
# 有密码情况下
openssl pkcs12 -in mycert.pfx -out mycert.pem
证书验证
使用OpenSSL库可以验证授权机构颁发的证书
如何验证证书?
使用verify选项来验证证书。
openssl verify cert.pem
验证成功,会返回“OK”。
$ openssl verify mycert.pem
mycert.pem: /C=CN/ST=JS/L=WX/O=Internet Widgits Pty Ltd/CN=Calle Zhang
error 18 at 0 depth lookup:self signed certificate
OK
如果异常会看到错误消息,比如
证书过期,通常证书都是有有效期的,一般是一年:
error 10 at 0 depth lookup:certificate has expired
自签名证书:
error 18 at 0 depth lookup:self signed certificate
OpenSSL都认可哪些证书颁发机构?
在编译OpenSSL库时需要制定OpenSSL的文件目录(--openssldir参数指定),这个目录保存着认可的证书颁发机构信息。
默认的目录是/usr/local/ssl,很多操作系统会把它放到别处,比如/usr/share/ssl(Red Hat/Fedora),/etc/ssl(Gentoo),/usr/lib/ssl(Debian),/System/Library/OpenSSL(Macintosh OS X)。
使用version选项加上-d查看目录在什么位置
openssl version -d
这个目录下有个certs子目录,在certs里可能会有三种类型的文件:
- 有一个名为cert.pem的大文件,里面包含了许多认可机构(比如VeriSign,Thawte)的证书。
- 一些以.pem为后缀的小文件,每个文件包含一个认可机构的一个证书。
- 一些奇怪名字的链接文件,比如052eae11.0,通常是指向.pem文件。这个文件名字的第一部分其实是.pem文件里证书的hash值,后缀是序列号,因为多个链接文件可以指向同一证书。以我的Gentoo系统为例,有个指向vsignss.pem的链接文件叫f73e89fd.0,可以肯定里面证书的哈希值就是这个文件名:
$ openssl x509 -noout -hash -in vsingss.pem f73e89fd 当OpenSSL要验证一个证书,它会查看cert.pem里面是否包含这个证书,如果没有再查看这个目录下是否存在以证书哈希值为名的文件,如果存在就验证通过。
有意思的是,有些程序(比如Sendmail)会在运行时让你指定你信任证书的存储位置。
如何让OpenSSL信任某个证书?
把这个证书放入上文说的certs目录下,然后创建一个以哈希值命名的链接文件,下面的脚本可以完成这样的任务:
#!/bin/sh
#
# usage: certlink.sh filename [filename ...]
for CERTFILE in $*; do
# make sure file exists and is a valid cert
test -f "$CERTFILE" || continue
HASH=$(openssl x509 -noout -hash -in "$CERTFILE")
test -n "$HASH" || continue
# use lowest available iterator for symlink
for ITER in 0 1 2 3 4 5 6 7 8 9; do
test -f "${HASH}.${ITER}" && continue
ln -s "$CERTFILE" "${HASH}.${ITER}"
test -L "${HASH}.${ITER}" && break
done
done
加密/解密
如何使用base64编码?
使用enc -base64选项
# 对文件file.txt里的内容进行base64编码
openssl enc -base64 -in file.txt
# 将编码结果输出到file.txt.enc
openssl enc -base64 -in file.txt -out file.txt.enc
通过命令行编码指定的字符串:
$ echo "encode me" | openssl enc -base64
ZW5jb2RlIG1lCg==
注意echo会在字符串结尾添加一个换行符,可以使用-n选项去除。当你对一些认证信息编码时,这点很重要。
$ echo -n "encode me" | openssl enc -base64
ZW5jb2RlIG1l
使用-d选项可以解码:
$ echo "ZW5jb2RlIG1lCg==" | openssl enc -base64 -d
encode me
如何简单的加密一个文件?
有时候我们只是想简单的通过密码加密一个文件,不想使用专业的工具,也不想创建私钥/证书之类的。
这是很简单,你需要记住密码以及使用的加密算法。
首先选一个加密算法,可以通过下面的方法列出可用的算法:
# ‘Cipher commands’下的列表
openssl -h
# 算法列表,每行一个
openssl list-cipher-commands
选完加密算法后,还要决定是否对加密后数据进行base64编码,base64编码后数据方便查看,不编码就是二进制的形式。
# 使用256位AES算法CBC模式,加密file.txt为file.enc。
openssl enc -aes-256-cbc -salt -in file.txt -out file.enc
# 对加密后数据进行base64编码(-a或-base64)
openssl enc -aes-256-cbc -a -salt -in file.txt -out file.enc
解密file.enc
# 解密二进制file.enc
openssl enc -d -aes-256-cbc -in file.enc
# 解密base64格式的
openssl enc -d -aes-256-cbc -a -in file.enc
如果你不想每次加解密时都输入密码,可以直接在命令中提供:
# 在命令行提供密码
openssl enc -aes-256-cbc -salt -in file.txt \
-out file.enc -pass pass:mySillyPassword
# 在一个文件中提供密码
openssl enc -aes-256-cbc -salt -in file.txt \
-out file.enc -pass file:/path/to/secret/password.txt
openssl 安装
openssl 没有windows安装包,不过可以通过其他平台下载:
- https://slproweb.com/products/Win32OpenSSL.html
# 生成证书
# 在要存放证书的文件夹下打开命令行窗口(或者切换到目录)
# 输入下面命令生成证书:
openssl genrsa 1024 > key.pem
# 输入下面命令生成安全证书:
openssl req -x509 -new -key key.pem > key-cert.pem