查看openssl可用命令
因为openssl没有查看可用命令的命令,但是我们可以输入一个错误的命令来让openssl显示所有可用的命令。
openssl help
创建trust store
因为openssl并没有带有任何受信任的根证书,所以我们必须从别的地方获取。一种方式是使用操作系统自带的,但通常不是最新的;另一种方式是使用Mozilla花费很大努力维护的信任库,我们可以直接下载。下载到的文件格式并不能直接使用我们可以使用第三方工具将其转换为Privacy-Enhanced Mail(PEM)格式。我们使用Curl项目提供的一个Perl脚本,来转换格式。
wget https://raw.github.com/bagder/curl/master/lib/mk-ca-bundle.pl
./mk-ca-bundle.pl
私钥与证书
一般我们使用openssl的目的是为了让我们的web服务器支持ssl,这个过程包含三步。
- 创建增强的私钥。
- 生成一个Certificate Signing Report (CSR),并把它放送给CA。
- 在web服务器上安装CA提供的证书。
生成私钥
生成私钥是第一步,在生成私钥前我们需要了解三个概念:
私钥算法
openssl支持RSA,DSA,ECDSA,所有的网站服务器都使用RSA,因为DSA尺寸被限制1024位(Internet Explorer不能支持更多的尺寸),ECDSA还并未被CA广泛支持。
私钥尺寸
默认的私钥尺寸可能不安全,所以我们要手动指定私钥尺寸,RSA默认尺寸是512位。目前,2048位的RSA、2048位的DSA、至少256位的ECDSA被认为是安全的尺寸。
私钥加密
使用密码加密私钥是可选的,但是是被推荐的。被加密的私钥可以安全的存储、传输、备份。但同时这却不方便,因为使用的时候必须使用密码,例如每次重启网站服务器时都要重新输入密码。
使用以下命令来生成私钥和公钥:
#生成2048位的pem格式的rsa私钥,并使用128位的aes进行加密
openssl genrsa -aes128 -out private.key 2048
#查看生成的私钥
openssl rsa -text -in private.key
#生成公钥
openssl rsa -in private.key -pubout -out public.key
生成证书注册请求CSR(Certificate Signing Requests)
有了私钥后就能生成CSR,CSR是我们向CA请求签发证书的正式请求格式,CSR中包含公钥和相关的实体信息。在生成CSR的过程中,我们可以输入.
来设置默认值。
#生成csr
openssl req -new -key private.key -out request.csr
#验证生成内容
openssl req -text -in request.csr -noout
#使用现有证书生成CSR
openssl x509 -x509toreq -in web.crt -out request.csr -signkey private.key
创建自签名证书
如果我们安装TLS服务器是自用的,那么我们就不需要向CA申请证书,我们可以创建一个自签名的证书。
#使用CSR创建自签名证书
openssl x509 -req -days 365 -in request.csr -signkey private.key -out web.crt
#不生成中间文件CSR,直接生成自签名证书
openssl req -new -x509 -days 365 -key private.key -out web.crt
#验证证书内容
openssl x509 -text -in web.crt -noout
有关自签名证书和TLS如何工作的,可以参考这里。
私钥与证书的存储格式
私钥和证书的存储格式有很多种,我们可能经常需要在各种格式中转换,常用格式如下:
Binary(DER)格式证书
包含X.509证书原始格式,使用DER ASN.1编码。
ASCII(PEM)格式证书
使用base64编码的DER格式证书,以-----BEGIN CERTIFICATE-----
作为文件第一行内容,-----END CERTIFICATE-----
作为文件最后一行内容
Binary(DER)格式密钥
包含密钥原始内容,使用DER ASN.1编码。
ASCII(PEM)格式密钥
包含使用base64编码的DER格式密钥,有时会包含额外信息,例如保护私钥的密码。
PKCS#7格式证书
用来传输被签名或者加密的数据的复杂格式,常见扩展名有p7b、p7c,可包含整个证书链,Java的keytool工具支持这种格式。
PKCS#12(PFX)格式的密钥和证书
一种用来存储和保存密钥及证书的复杂格式,常见扩展名有p12、pfx,微软的产品经常会使用到。
PEM与DER格式之间的转换:
#证书 PEM格式转DER
openssl x509 -inform PEM -in web.crt -outform DER -out web.der
#证书 DER格式转PEM
openssl x509 -inform DER -in web.der -outform PEM -out web.crt
#密钥 PEM格式转DER,替换rsa为你使用的密钥算法即可
openssl rsa -inform PEM -in private.key -outform DER -out private.der
#密钥 DER格式转PEM,替换rsa为你使用的密钥算法即可
openssl rsa -inform DER -in private.der -outform PEM -out private.key
PEM与PKCS#7证书格式之间的转换:
- 将PEM格式的证书(web.crt),中间证书(web-intermediate.crt)转换为PKCS#7文件。
openssl crl2pkcs7 -nocrl -out saved.p7b -certfile web.crt -certfile web-intermediate.crt
- 将PKCS#7转换为PEM格式,由于结果都存放在一个文件中,我们需要将combined.pem文件里的内容手动分离出来。
openssl pkcs7 -in saved.p7b -print_certs -out combined.pem
PEM与PKCS#12格式之间的转换:
- 将PEM格式的私钥(private.key),证书(web.crt),中间证书(web-intermediate.crt)转换为PKCS#12文件。
openssl pkcs12 -export -name "Certificate Name" -out saved.p12 -inkey private.key -in web.crt -certifile web-intermediate.crt
- 将PKCS#12转换为PEM格式就不这么直接了,因为转换的结果放在一个文件里面,所以我们必须手动的将combined.pem里的内容分离。
openssl pkcs12 -in saved.p12 -out combined.pem -nodes
TLS配置
在发布TLS时,第一步就是加密套件的选择,所有使用OpenSSL的软件都要使用其提供的套件配置机制。例如nginx中配置加密套件:
ssl_ciphers HIGH:!aNULL:!MD5
其中HIGH:!aNULL:!MD5
是加密套件的关键字和相关操作符的组合来选择一组加密套件。
以下是四类操作符的说明。
-
:
与即冒号与空格
通过这两个操作符都可添加新的加密套件到结果列表中,例如RSA:AES
或者RSA AES
。 -
-
与关键字组合从现有列表中移除指定的加密套件,被移除的套件可以被后续的关键字再次引入。例如RSA-DES
。 -
!
永久移除关键字指定的加密套件。例如!MD5
。 -
+
通过制定多个关键字来组合起来筛选加密套件。例如RSA+AES
。
有关于所有可用的关键字,可以参考这里。
我们可以使用以下命令来验证关键字与操作符组合选择的加密套件:
#"RSA:AES"可换乘其他组合
openssl ciphers -v "RSA:AES"
测量指定加密算法或者摘要算法速度时(测量的结果只是大概,如果想多线程测试,可查询speed的选项),我们可以使用以下命令:
#aes可替换为其他值
openssl speed aes
创建私有CA
- 创建CA配置信息。
对于创建CA这种复杂的操作,我们可以创建一个配置文件(root_ca.conf)来简化我们的操作。
一个配置文件可以分为很多节,每一节都以[section_name]作为起始行,直到碰到另一节的起始行或者到文件结尾,则该节结束。每节的名称只能是字母数字下划线。
配置文件中的第一节是特殊的,被认为是[default]节,通常是不命令的,当碰到另一个命名的节时,该默认节即结束。当查询一个名字时,先从命名的节中查询,最后再查询默认节。
环境变量被映射到名为ENV的节中。
配置文件中的注释以#开头。
配置文件中的每一节都包含有键值对,形式如name=value. 键的可选字符集是[alphanumeric . , ; _], 值对应着=后面的所有字符,去除头尾空格。值中可以包含变量展开,形式是$name或者${name},这将会使用在本节中查找到的name对应的值进行替换;如果想要使用其他节中的值进行替换,可以使用$section::name或者${section::name};如果想要使用环境变量进行替换可以使用形式$ENV::name。如果value最后一个字符是\,则value是可以跨行的,同时也可以包含任意转义字符。
以下是配置信息的示例。
#基本的CA配置信息
[default]
name=root_ca
domain_suffix=example.com
aia_url=http://$name.$domain_suffix/$name.crt
crl_url=http://$name.$domain_suffix/$name.crl
ocsp_url=http://ocsp.$name.$domain_suffix:9080
default_ca=ca_default
name_opt=utf8,esc_ctrl,multiline,lname,align
#供req节中键distinguished_name使用
[ca_dn]
countryName="GB"
organizationName="Example"
commonName="Root CA"
#控制CA操作的配置信息,可通过man ca命令来查看所有可选参数
[ca_default]
home=.
database=$home/db/index
serial=$home/db/serial
crlnumber=$home/db/crlnumber
certificate=$home/$name.crt
private_key=$home/private/$name.key
RANDFILE=$home/private/random
new_certs_dir=$home/certs
unique_subject=no
copy_extensions=none
default_days=3650
default_crl_days=365
default_md=sha256
#指定所有从本CA签发的证书的策略,策略内容在policy_c_o_match节中
policy=policy_c_o_match
#策略要求被签发证书的countryName和organizationName必须匹配根CA
[policy_c_o_match]
countryName=match
stateOrProvinceName=optional
organizationName=match
organizationalUnitName=optional
commonName=supplied
emailAddress=optional
#req命令的配置信息,仅被使用一次来创建自签名根证书
[req]
default_bits=4096
encypt_key=yes
default_md=sha256
utf8=yes
string_mask=utf8only
prompt=no
distinguished_name=ca_dn
req_extensions=ca_ext
[ca_ext]
#标识证书是CA
basicConstraints=critical,CA:true
keyUsage=critical,keyCertSign,cRLSign
subjectKeyIdentifier=hash
#由根CA签发的证书的配置信息
[sub_ca_ext]
authorityInfoAccess=@issuer_info
authorityKeyIdentifier=keyid:always
#CA:true表示创建的证书是CA,pathlen:0表示由CA签发的证书创建的下级证书不能是CA
basicConstraints=critical,CA:true,pathlen:0
crlDistributionPoints=@crl_info
#TLS客户端和服务器
extendedKeyUsage=clientAuth,serverAuth
keyUsage=critical,keyCertSign,cRLSign
nameConstraints=@name_constraints
subjectKeyIdentifier=hash
[crl_info]
URI.0=$crl_url
[issuer_info]
caIssuers;URI.0=$aia_url
OCSP;URI.0=$ocsp_url
[name_constraints]
#限定域名
permitted;DNS.0=example.com
permitted;DNS.1=example.org
#以下两个限制来源于 CA/Browser Forum‘s Baseline Requirements
excluded;IP.0=0.0.0.0/0.0.0.0
excluded;IP.1=0:0:0:0:0:0:0:0/0:0:0:0:0:0:0:0
#用于OCSP报文签名的证书拓展项,为了运行OCSP服务器,我们创建一个特殊证书并且代理OCSP签名。
[ocsp_ext]
authorityKeyIdentifier=keyid:always
#该证书不是CA
basicConstraints=critical,CA:false
extendedKeyUsage=OCSPSigning
keyUsage=critical,digitalSignature
subjectKeyIdentifier=hash
目前对于nameConstraints的支持还不是很全面,详情可以参照这里和这里。
- 创建CA目录
mkdir root_ca
cd root_ca
mkdir certs db private
chmod 700 private
touch db/index
#如果创建共用distinguished_name的CA证书时,每次都要重新生成serial
openssl rand -hex 16 > db/serial
echo 1001 > db/crlnumber
以下是各个目录作用的说明:
-
certs/
存储生成的证书。 -
db/
存放证书数据库(index),证书和CRL的序列号,或者openssl创建的额外文件。 -
private/
CA和OCSP的私钥。
- 创建根CA
第一步创建私钥和CSR。
openssl req -new -config root_ca.conf -out root_ca.csr -keyout private/root_ca.key
第二步创建自签名证书。
openssl ca -selfsign -config root_ca.conf -in root_ca.csr -out root_ca.crt -extensions ca_ext
创建完CA证书后我们会在当前文件夹(root_ca.crt)和certs文件夹内(XXXX.pem)得到一样的证书。我们可以查看db/index得到生成的证书的记录。
V 270818135219Z DDBBFB87753B0599CC2C6B26C36017CB unknown/C=GB/O=Example/CN=Root CA
第一列:状态标识,可选值有V (valid)R (revoked)E(expired)。
第二列:过期日期,格式为(YYMMDDHHMMSSZ)。
第三列:注销日起,如果没有即为空。
第四列:序列号,十六进制。
第五列:文件位置,如果未知值为unknown。
第六列:标识名。
- 根CA操作
- 从CA生成CRL
openssl ca -gencrl -config root_ca.conf -out root_ca.crl
- 签发证书
生成的证书存储在certs/存在certs文件夹内,文件名是序列号,你可以通过db/index的标识名来在certs文件夹内查询对应的证书文件。同时你指定的web.crt文件也会被生成。
#sub_ca.csr是你生成证书的请求
openssl ca -config root_ca.conf -in request.csr -out web.crt -extensions sub_ca_ext
- 撤销证书
撤销原因可以通过crl_reason来指定,可选值有unspecified、keyCompromise、CACompromise、CACompromise、affiliationChanged、superseded、cessationOfOperation、certificateHold、removeFromCRL
#DDBBFB87753B0599CC2C6B26C36017CB.pem是你要吊销的证书,通过db/index文件来查询。
openssl ca -config root_ca.conf -revoke certs/DDBBFB87753B0599CC2C6B26C36017CB.pem -crl_reason keyCompromise
- 创建OCSP签名证书
第一步为OCSP响应器创建私钥和CSR。
#rsa:2048代表创建2048位的rsa私钥;subj选项对应的值中C代表countryName,O代表organizationName,CN代表commonName。
openssl req -new -newkey rsa:2048 -subj "/C=GB/O=Example/CN=OCSP Root Responder" -keyout private/root_ocsp.key -out root_ocsp.csr
第二步使用根CA签发证书,使用-extensions ocsp_ext
来确保正确签发OCSP证书,同时通过days 30
调整证书过期时间,越短越好,因为OCSP证书不包含撤销信息,无法被撤销。
openssl ca -config root_ca.conf -in root_ocsp.csr -out root_ocsp.crt -extensions ocsp_ext -days 30
我们可以通过以下命令来测试生成的OCSP证书。
#启动本地的OCSP响应器,一般不要放在根CA所在的机器
openssl ocsp -port 9080 -index db/index -rsigner root_ocsp.crt -rkey private/root_ocsp.key -CA root_ca.crt -text
#验证OCSP响应器操作
openssl ocsp -issuer root_ca.crt -CAfile root_ca.crt -cert root_ocsp.crt -url http://127.0.0.1:9080
验证成功后,会得到类似于以下的内容:
Response verify OK
root_ocsp.crt: good
This Update: Aug 21 09:37:03 2017 GMT
创建下级CA
- 创建下级CA和创建根CA步骤是一样的,我们以根CA的配置文件(sub_ca.conf)为基础,做了以下列出来的修改,注意单词拼写,如果有错误的话对照着错误提示或者下面的示例来更改:
[default]
name=sub_ca
ocsp_url=http://ocsp.$name.$domain_suffix:9081
[ca_dn]
countryName="GB"
organizationName="Example"
commonName="Sub CA"
[ca_default]
default_days=365
default_crl_days=30
#copy代表CSR的extensions会被拷贝到证书中
copy_extensions=copy
新增了server_ext和client_ext两个节:
[server_ext]
authorityInfoAccess=@issuer_info
authorityKeyIdentifier=keyid:always
basicConstraints=critical,CA:false
crlDistributionPoints=@crl_info
extendedKeyUsage=clientAuth,serverAuth
keyUsage=critical,digitalSignature,keyEncipherment
subjectKeyIdentifier=hash
[client_ext]
authorityInfoAccess=@issuer_info
authorityKeyIdentifier=keyid:always
basicConstraints=critical,CA:false
crlDistributionPoints=@crl_info
extendedKeyUsage=clientAuth
keyUsage=critical,digitalSignature
subjectKeyIdentifier=hash
- 生成下级CA
- 首先参照根CA创建CA目录。
- 生成下级CA私钥和CSR
openssl req -new -config sub_ca.conf -out sub_ca.csr -keyout private/sub_ca.key
- 使用根CA签发下级CA证书
#开关extensions指定root_ca.conf中的sub_ca_ext节来配置下级CA的extensions。注意文件路径。
openssl ca -config root_ca.conf -in sub_ca.csr -out sub_ca.crt -extensions sub_ca_ext
- 下级CA的操作
- 签发服务端证书
执行以下命令时可能会提示db/index.attr文件找不到,该文件内仅仅包含一条信息unique_subject=no/yes
对应着我们在sub_ca.conf文件中的配置,我们可以创建这个文件并将信息输入进去。有关这个错误的介绍可以参照这里。
openssl ca -config sub_ca.conf -in server.csr -out server.crt -extensions server_ext
- 签发客户端证书
openssl ca -config sub_ca.conf -in client.csr -out client.crt -extensions client_ext