OpenSSL
💡以下内容参考学习自《OpenSSL攻略》,右侧随书下载。
原文:https://www.feistyduck.com/library/openssl-cookbook/online/
加密基元
密码学加密基元说明:
- 散列函数(散列(hash)、指纹、消息摘要、摘要算法、杂凑函数):把任意长度的输入消息数据转化成固定长度的输出数据的一种密码算法。
- 消息验证代码:验证数据完整性。
- 数字签名:RSA私钥加密,公钥解密,结合散列函数。验证消息真实性。
- 伪随机函数(PRF):生成任意数量的伪随机数据
- RSA:可以同时用于密钥交换和身份验证。
- DHE_RSA:DHE:密钥交换,RSA:身份验证。
- ECDHE_RSA: ECDHE:密钥交换,RSA:身份验证。
- ECDHE_ECDSA :ECDHE:密钥交换,ECDSA:身份验证。
补充:分组密码工作模式/操作模式
分组密码都有固定的分组长度,实际应用中需要加密的明文都大大长于这个分组长度。如何对明文进行分组、填充,分组后的明文组和密文组之间有没有关系,这些要素形成了分组密码的不同工作模式。在实际应用中,分组密码主要有4种运行模式:
- 电子密码本模式(ECB):不适用于长报文、高度结构化报文。
- 密文块链接模式(CBC)
- 密文反馈模式(CFB):分组密码转换为流密码
- 输出反馈模式(OFB):缺点:难以检测对密文的篡改。
分组加密的操作模式
- 加密操作模式:只保护数据的私密性,无需验证数据来源。
ECB、CBC、OFB、CFB、CTR。 - 验证操作模式:不在乎数据的保密性,只想确保数据的发送来源。
CMAC。 - 验证加密操作模式:既想保密要传输的数据,还要确认数据的来源。
CCM、GCM、KW/KWP/TKW
TLS服务安全部署
TLS服务安全部署OpenSSL 的结构及目录功能
OpenSSL 的结构OpenSSL 目录功能对照表
目录名 | 功能描述 |
---|---|
Crypto | 存放 OpenSSL 所有加密算法源码文件和相关标注如 X.509 源码文件,是 OpenSSL 中最重要的目录,包含了 OpenSSL 密码算法库的所有内容 |
SSL | 存放 OpenSSL 中 SSL 协议各个版本和 TLS 1.0 协议源码文件,包含了 OpenSSL 协议库的所有内容 |
Apps | 存放 OpenSSL 中所有应用程序源码文件,如 CA、X509 等应用程序的源文件就存放在这里 |
Doc | 存放了 OpenSSL 中所有的使用说明文档,包含三个部分:应用程序说明文档、加密算法库 API 说明文档及 SSL 协议API说明文档 |
Demos | 存放了一些基于 OpenSSL 的应用程序例子,这些例子一般都很简单,演示怎么使用 OpenSSL 中的一个功能 |
Include | 存放了使用 OpenSSL 的库时需要的头文件 |
Test | 存放了 OpenSSL 自身功能测试程序的源码文件 |
构建 OpenSSL
# 查看当前系统使用的 OpenSSL 版本
$ openssl version
OpenSSL 1.0.2g 1 Mar 2016
# 获取完整的版本信息
$ openssl version -a
...
OPENSSLDIR: "/usr/lib/ssl" # OpenSSL 默认查找和配置证书目录
# 下载 OpenSSL
$ wget https://www.openssl.org/source/openssl-1.0.2o.tar.gz
$ wget https://www.openssl.org/source/openssl-1.1.1.tar.gz
# 解压缩
$ tar -xzvf openssl-1.0.2o.tar.gz ## 先调用 gzip 解压缩,再解开文件。
# 配置
$ cd openssl-1.0.2o/
$ ./config \
--prefix=/opt/openssl \
--openssldir=/opt/openssl \ # 安装目录
enable-ec_nistp_64_gcc_128 # 使用优化后的常用椭圆曲线算法
$ make depend # 生成可执行文件
$ make # 编译
$ sudo make install # 安装
# OpenSSL 安装在 /opt/openssl/ 目录下
$ cd /opt/openssl/
$ ls -l
total 40
drwxr-xr-x 2 root root 4096 Jun 15 08:08 bin
drwxr-xr-x 2 root root 4096 Jun 15 08:08 certs # 根证书目录、可信证书库
drwxr-xr-x 3 root root 4096 Jun 15 08:08 include
drwxr-xr-x 4 root root 4096 Jun 15 08:08 lib
drwxr-xr-x 6 root root 4096 Jun 15 08:08 man
drwxr-xr-x 2 root root 4096 Jun 15 08:08 misc # 补充脚本
-rw-r--r-- 1 root root 10835 Jun 15 08:08 openssl.cnf
drwxr-xr-x 2 root root 4096 Jun 15 08:08 private # 私钥目录
查看可用命令:openssl help
# ------ 所有可用工具 ------
Standard commands
asn1parse ca ciphers cms
crl crl2pkcs7 dgst dh
dhparam dsa dsaparam ec
ecparam enc engine errstr
gendh gendsa genpkey genrsa
nseq ocsp passwd pkcs12
pkcs7 pkcs8 pkey pkeyparam
pkeyutl prime rand req
rsa rsautl s_client s_server
s_time sess_id smime speed
spkac srp ts verify
version x509
# man + 工具名称,显示某一命令的详细信息
# man ciphers,显示如何配置密码套件
# ------ 消息摘要命令 ------
Message Digest commands (see the `dgst' command for more details)
md4 md5 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
camellia-128-cbc camellia-128-ecb camellia-192-cbc camellia-192-ecb
camellia-256-cbc camellia-256-ecb 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
创建可信证书库
-
从 Mozilla CA Certificate Store 获取开源的可信证书库:Source file with all of the included root certificates。下载完成后,可以使用 Perl 脚本或者 Go 脚本将 certdata.txt 文件转换为 PEM 格式。
-
从 Curl 获取最新的 PEM 格式的可信证书库:CA certificates extracted from Mozilla。
密钥和证书管理
image首先,使用 OpenSSL 生成一个非对称加密算法的私钥,可选的密钥算法及密钥长度如下:
非对称加密算法1.1 生成 RSA-2048 密钥 (.pem文件)
# 使用 genrsa 命令生成 RSA-2048 位的密钥
$ openssl genrsa -out rsa_private.key 2048
# 使用 genrsa 命令生成 RSA-2048 位的密钥,并使用 AES-128 位算法保存密钥。
# **********************************************************
# 使用密码方式保护私钥只有在私钥并没有被放在生产环境服务器上的时候才有用。
# **********************************************************
$ openssl genrsa -aes128 -out fd.key 2048
Generating RSA private key, 2048 bit long modulus
....+++
..........................+++
e is 65537 (0x10001) # e 表示公用指数,默认情况下会被设置为65 537。这是所谓的短公用指数(short public exponent),它可以显著提高RSA的验证性能。
Enter pass phrase for fd.key:huqilin0321
Verifying - Enter pass phrase for fd.key:huqilin0321
# 私钥以 PEM 格式存储
$ cat /opt/openssl/private/fd.key
-----BEGIN RSA PRIVATE KEY----- # 第一行,表明它是一个私钥文件
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-128-CBC,AEDB3A0F4369376615B5AB3D9E4E5FEA
j9CwxBMf08WKTkQvM3Vi1W6TOQV6uEpfHtYxjy8/JhYsvhqH+EdMyB1ZSMPz+W8e
...
jZoL/+0fcuzX1O5oQkTpaoh1ZafJJROHSZh0nPiuGdIRWJtHUlmt1GgzXvOyIqzm
-----END RSA PRIVATE KEY-----
# 解析私钥结构
$ openssl rsa -text -in fd.key
...
# 生成密钥的公开部分
$ openssl rsa -in fd.key -pubout -out fd-public.key
Enter pass phrase for fd.key:
writing RSA key
root@ip-172-31-8-201:/opt/openssl/private# ls -l
total 8
-rw-r--r-- 1 root root 451 Jun 15 10:08 fd-public.key # 生成的密钥公开部分文件(公钥)
-rw-r--r-- 1 root root 1766 Jun 15 09:39 fd.key # 私钥
# 查看密钥的公开部分
$ cat fd-public.key
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1M4fNC/NgH0bnb/oXcXH
9hudaPYk2+xwDnMxzZBhhuPrOpq6wGkJMPl/5cN2zZRGE7wtdLa2Y1gPVlkVd7zv
mSnZYLcXr1CW/Ipzs4Zqavz4aWIi3DiKElLG2lcR2YQY3d4YjEnHvzDotyvuQ7km
rXwKx0TNr3xo0tQ8qwsGHMuyE6FSD9JxwpGHeLd4r9X9qrsGVTfx5yRdRTrgb+d0
YFR+hV6Cv1JQVGHw5UTACioQ4WziABG8mZY1zzAENmB73zWB6NqunCr00R7RwwDP
jfOt5cNRYdEBRy79FG/7RVY+QVvYwm/bv9nOnT2Kjdm/elLkHTcLCgO6M0QDmR/F
oQIDAQAB
-----END PUBLIC KEY-----
1.2 生成 ECDSA-256 密钥(.pem文件)
# 使用 secp256r1 命名曲线创建一个256位长度的 ECDSA 密钥,并使用 AES-128 位算法保存密钥。
$ openssl ecparam -genkey -name secp256r1 | openssl ec -out ec.key -aes128
2 创建证书签名申请(CSR文件)
CSR 是要求 CA 给证书签名的一种正式申请,该申请包含申请证书的实体的公钥以及该实体的某些信息。
-
交互方式生成 CSR 文件:
# 使用私钥(fd.key)生成 CSR 文件(fd.csr) $ sudo openssl req -new -key fd.key -out fd.csr Enter pass phrase for fd.key: You are about to be asked to enter information that will be incorporated into your certificate request. What you are about to enter is what is called a Distinguished Name or a DN. There are quite a few fields but you can leave some blank For some fields there will be a default value, If you enter '.', the field will be left blank. # ⚠️ 输入一个点(.),该字段为空。键入回车键,则设置为默认值。 ----- Country Name (2 letter code) [AU]:CN # 国家 State or Province Name (full name) [Some-State]:Shanghai # 省市 Locality Name (eg, city) []:Shanghai # 地区 Organization Name (eg, company) [Internet Widgits Pty Ltd]:Shanghai Clumsiest Information Co., Ltd. # 组织机构 Organizational Unit Name (eg, section) []: # 单位部门 Common Name (e.g. server FQDN or YOUR name) []: # 通用名 Email Address []:clumsiest@outlook.com # 邮箱地址 Please enter the following 'extra' attributes # 质询密码,留空 to be sent with your certificate request A challenge password []:. An optional company name []:. # 检查 CSR 格式 $ openssl req -text -noout -in fd.csr
-
用当前证书生成 CSR 文件:
更新一张证书,并且不想对里面的信息作任何更改。
$ openssl x509 -x509toreq -in fd.crt -out fd.csr -signkey fd.key
-
非交互方式生成 CSR 文件:
# 3.1如果想自动生成www.feistyduck.com的CSR文件,可以先创建一个fd.cnf文件: [req] prompt = no distinguished_name = dn req_extensions = ext input_password = PASSPHRASE [dn] CN = www.feistyduck.com emailAddress = webmaster@feistyduck.com 0 = Feisty Duck Ltd L = London C = GB [ext] subjectAltName = DNS:www.feistyduck.com,NDS:feistyduck.com # 3.2 使用如下命令直接创建 CSR 文件 $ openssl req -new -config fd.cnf -key fd.key -out fd.csr
3.1 自签名证书
-
使用 CSR 创建自签名证书:
$ sudo openssl x509 -req -days 365 -in fd.csr -signkey fd.key -out fd.crt
-
直接使用私钥创建自签名证书:
$ sudo openssl req -new -x509 -days 365 -key fd.key -out fd.crt Enter pass phrase for fd.key: You are about to be asked to enter information that will be incorporated into your certificate request. What you are about to enter is what is called a Distinguished Name or a DN. There are quite a few fields but you can leave some blank For some fields there will be a default value, If you enter '.', the field will be left blank. ----- Country Name (2 letter code) [AU]: State or Province Name (full name) [Some-State]: Locality Name (eg, city) []: Organization Name (eg, company) [Internet Widgits Pty Ltd]: Organizational Unit Name (eg, section) []: Common Name (e.g. server FQDN or YOUR name) []: Email Address []:
-
使用私钥非交互式创建自签名证书:
$ sudo openssl req -new -x509 -days 365 -key fd.key -out fd.crt -subj "/C=GB/L=London/O=Feisty Duck Ltd/CN=www.feistyduck.com"
3.2 创建对多个主机名有效的证书
默认情况下,OpenSSL 创建的证书只包含一个公用名而且只能设置一个主机名。
在一张证书中支持多主机名的两种方式:
-
在 X.509 的使用者可选名称(SAN)扩展字段里面列出所有要使用的主机名;
-
将扩展信息放在单独的文本文件中(fd.ext),在该文件中指定扩展的名称:
subjectAltName = DNS:*.feistyduck.com, DNS:feistyduck.com
-
签发证书时,使用 -extfile 开关引用上述文件:
openssl x509 -req -days 365 -in fd.csr -signkey fd.key -out fd.crt -extfile fd.ext
-
-
使用泛域名证书;
3.3 检查证书
x509 命令可以帮助我们解析并查看证书内容:
# -text:打印证书内容
# -noout:不打印编码后的证书内容,以减少信息干扰
$ openssl x509 -text -noout -in fd.crt
使用 OpenSSL 快速创建自签名证书
⚠️ 请勿在生产环境中使用自签名证书,自签名证书的唯一目的是测试。
# 1.使用 genrsa 命令生成 RSA-2048 位私钥
$ openssl genrsa -out rsa_private.key 2048
# 2.通过私钥生成证书
$ openssl req -new -x509 -days 365 -key rsa_private.key -out rsa_public.crt
# 3.查看打印证书
$ openssl x509 -text -noout -in rsa_public.crt
密钥和证书格式转换
证书文件的类型
参考:主流字证书都有哪些格式?
- *.DER 或 *.CER 文件: 这样的证书文件是二进制格式,只含有证书信息,不包含私钥。
- *.CRT 文件: 这样的证书文件可以是二进制格式,也可以是文本格式,一般均为文本格式,功能与 *.DER 及 *.CER 证书文件相同。
- *.PEM 文件: 这样的证书文件一般是文本格式,可以存放证书或私钥,或者两者都包含。 *.PEM 文件如果只包含私钥,一般用 *.KEY 文件代替。
- *.PFX 或 *.P12 文件: 这样的证书文件是二进制格式,同时包含证书和私钥,且一般有密码保护。
PEM 和 DER 转换
使用x509工具进行PEM和DER格式之间的证书转换:
# 1. 从 PEM 转换到 DER:
$ openssl x509 -inform PEM -in fd.pem -outform DER -out fd.der
# 2. 从 DER 转换到 PEM:
$ openssl x509 -infrom DER -in fd.der -outform PEM -out fd.pem
PKCS#12(PFX)转换
PKCS#7转换
# 1. 将 PEM 转换成 PKCS#7 格式:
$ openssl crl2pkcs7 -nocrl -out fd.p7b -certfile fd.crt -certfile fd-chain.crt
# 2. 将 PKCS#7 转换成 PEM 格式:
$ openssl pkcs7 -in fd.p7b -print_certs -out fd.pem
配置
密码套件的配置
# 密码套件名称构成:密钥交换算法-身份验证算法-加密算法(加密方法-加密强度-模式)-MAC或PRF
# 密钥交换方法:ECDHE > DHE > RSA
# 身份验证方法:ECDSA 256 > RSA 2048
# 加密算法:AES-256-GCM、
# PRF(伪随机函数):HMAC、SHA256
# 如:TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
# 如:TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
列出所有支持的套件列表
$ openssl ciphers -V 'ALL:COMPLEMENTOFALL'
# 推荐的配置,同时满足强加密和高性能
ECDHE-ECDSA-AES128-GCM-SHA256
ECDHE-ECDSA-AES256-GCM-SHA384
ECDHE-ECDSA-AES128-SHA
ECDHE-ECDSA-AES256-SHA
ECDHE-ECDSA-AES128-SHA256
ECDHE-ECDSA-AES256-SHA384
ECDHE-RSA-AES128-GCM-SHA256
ECDHE-RSA-AES256-GCM-SHA384
ECDHE-RSA-AES128-SHA
ECDHE-RSA-AES256-SHA
ECDHE-RSA-AES128-SHA256
ECDHE-RSA-AES256-SHA384
DHE-RSA-AES128-GCM-SHA256
DHE-RSA-AES256-GCM-SHA384
DHE-RSA-AES128-SHA
DHE-RSA-AES256-SHA
DHE-RSA-AES128-SHA256
DHE-RSA-AES256-SHA256
EDH-RSA-DES-CBC3-SHA
性能评测
使用 speed 命令评测系统的能力和上限
$ openssl speed rc4 aes rsa ecdh sha
# 让speed命令并发使用4核测试
$ openssl speed -multi 4 rsa
# 支持AES-NI指令的服务器可以加速AES计算,使用-evp开关激活硬件加速卡
$ openssl speed -evp aes-128-cbc
创建私有证书颁发机构
运行私有CA的最大挑战
如何保证基础结构的安全?
- 根密钥必须离线保存。
- CRL和OSCP响应程序证书必须定期进行更新,而这会要求根密钥保持联机。
创建全新CA的步骤:
- 根CA配置;
- 创建根CA的目录结构和初始化密钥文件;
- 生成根CA的密钥和证书;
# CA 中心生成自身私钥
root@ip-172-31-8-201:/opt/openssl# (umask 077; openssl genrsa -out private/cakey.pem 2048)
Generating RSA private key, 2048 bit long modulus
...............+++
...............................................................+++
e is 65537 (0x10001)
// 为了保证CA机构私钥的安全,需要把私钥文件权限设置为077
# CA 签发自身公钥
root@ip-172-31-8-201:/opt/openssl# openssl req -new -x509 -key private/cakey.pem -out cacert.pem -days 365
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:CN
State or Province Name (full name) [Some-State]:Shanghai
Locality Name (eg, city) []:Shanghai
Organization Name (eg, company) [Internet Widgits Pty Ltd]:shanghai Clumsiest Information Co., Ltd.
Organizational Unit Name (eg, section) []:Development Team
Common Name (e.g. server FQDN or YOUR name) []:arlingbc.com
Email Address []:clumsiest@outlook.com
# 创建数据库文件及证书序列文件
root@ip-172-31-8-201:/opt/openssl# ls -l
total 52
drwxr-xr-x 2 root root 4096 Jun 15 08:08 bin
-rw-r--r-- 1 root root 1558 Aug 24 03:21 cacert.pem # CA 自身证书文件
drwxr-xr-x 2 root root 4096 Jun 15 09:24 certs # 客户端证书存放目录
drwxr-xr-x 2 root root 4096 Aug 24 05:54 crl # CA 吊销的客户端证书存放目录*
drwxr-xr-x 3 root root 4096 Jun 15 08:08 include
-rw-r--r-- 1 root root 0 Aug 24 05:56 index.txt # 存放客户端证书信息*
drwxr-xr-x 4 root root 4096 Jun 15 08:08 lib
drwxr-xr-x 6 root root 4096 Jun 15 08:08 man
drwxr-xr-x 2 root root 4096 Jun 15 08:08 misc
drwxr-xr-x 2 root root 4096 Aug 24 05:55 newcerts # 生成新证书存放目录*
-rw-r--r-- 1 root root 10835 Jun 15 08:08 openssl.cnf
drwxr-xr-x 2 root root 4096 Aug 24 03:11 private # 存放 CA 自身私钥的目录
-rw-r--r-- 1 root root 0 Aug 24 05:57 serial # 客户端证书编号(编号可以自定义),用于识别客户端证书*