KEY 通常指私钥。
CSR 是 Certificate Signing Request 的缩写,即证书签名请求,这不是证书,只是包含申请证书的基本信息。生成证书时要把这个提交给权威的证书颁发机构,颁发机构审核通过之后,再根据这些申请信息生成相应的证书。
CRT 即 certificate的缩写,即证书。
X.509 是一种证书格式.对X.509证书来说,认证者总是CA或由CA指定的人,一份X.509证书是一些标准字段的集合,这些字段包含有关用户或设备及其相应公钥的信息。
X.509的证书文件,一般以.crt结尾,根据该文件的内容编码格式,可以分为以下二种格式:
// 输出 key 密钥文件。 openssl genrsa -des3 -out ca.key 2048 // 长度为2048
参数说明:
// 输入 key 文件, 输出 csr 请求文件。 openssl req -new -key ca.key -out ca.csr
参数说明:
运行此命令后进入交互模式,需要输入一些证书信息。
一般需要输入的信息如下:
正常的证书是你把上面生成的请求文件(.CSR)发送给可信机构(CA),让可信机构根据你的请求去生成和签署证书,再给你发回来。这里是自己给自己签署。
// 输入 csr 请求文件,指定签署的 key,输出证书 crt 文件。 openssl x509 -req -sha256 -days 3650 -in ca.csr -signkey ca.key -out ca.crt
参数说明:
以上 2、3 两步可以合成一步来执行:
// 输入 key 文件,输出证书 crt 文件。(自签署) openssl req -new -x509 -sha256 -days 3650 -key ca.key -out ca.crt
省去生成请求文件的步骤。
此时 CA 证书生成完成。
一般情况下,上面的 key 和 crt 可以直接拿来应用了。以下演示把当前的证书当成 CA 给其他的请求进行颁发证书。
// 输出 key 密钥文件。 openssl genrsa -out server.key 2048 // 长度为2048
参数说明:
// 输入 key 文件, 输出 csr 请求文件。 openssl req -new -key server.key -out server.csr
参数说明同上一节。
// 输入服务器给的 csr 请求文件,使用指定 CA 的私钥和证书来签署,输出服务器证书 crt。 openssl x509 -req -sha256 -days 3650 -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt
nginx 中使用 ssl 的方式是,在配置文件中加入以下语句:
ssl_certificate /path/to/your.crt; ssl_certificate_key /path/to/your.key;
在 IIS 中,需要的是一个 PFX 文件,这个文件需要包含 key 和 crt。生成方法如下:
// 输入 key 和 crt 文件,输出 pfx 文件。 openssl pkcs12 -export -inkey server.key -in server.crt -out server.pfx
执行上述命令时,会要求输入一个 export 密码。 该密码在导入 pfx 文件时需要。
在 IIS 中选择“导入证书”,文件选择该 pfx 文件,密码填写导出时的密码,导入位置选择“个人”。
如要修改证书的 friendly name ,则在证书管理中修改(需要从 mmc 中打开计算机级别的证书管理器)。
chrome 会查看当前域名是否在证书中声明,该声明由 subjectAltName 字段设置。上述的生成步骤默认未设置该字段。
解决方法如下:
新建一个文件,起名为 v3.ext (名字自定),编辑内容如下:
subjectAltName = @alt_names [alt_names] DNS.1 = www.company.com DNS.2 = company.com DNS.3 = *.company.net
域名要与你的证书实际绑定的域名一致。如有多个域名,按示例写多个。
在签署时,额外增加一个参数: -extfile v3.ext
// 这是上面服务器签署的示例,在最后增加一个参数,指定扩展字段设置文件。 openssl x509 -req -sha256 -days 3650 -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt -extfile v3.ext
新建一个文件,如 csr.cnf ,相应字段按自己需求修改:
[req] default_bits = 2048 prompt = no default_md = sha256 distinguished_name = req_distinguished_name [req_distinguished_name] C = CN ST = GuangDong L = ShenZhen O = Company.inc OU = ou CN = *.myserver.net emailAddress = admin@myserver.net
在生成请求文件时,额外增加参数: -config cat csr.cnf
// 指定配置文件,此时不会出现交互模式,相交信息自动设置。 openssl req -new -sha256 -key server.key -out server.csr -config csr.cnf
该情形适合于自签署证书时。
请求的配置和 ext 的配置可以写在一起,如下
[req] default_bits = 2048 prompt = no default_md = sha256 distinguished_name = req_distinguished_name x509_extensions = v3_req [req_distinguished_name] C = CN ST = GuangDong L = ShenZhen O = Company.inc OU = ou CN = *.myserver.net emailAddress = admin@myserver.net [v3_req] keyUsage = critical, digitalSignature, keyAgreement extendedKeyUsage = serverAuth subjectAltName = @alt_names [alt_names] DNS.1 = myserver.net DNS.2 = *.myserver.net
然后运行如下命令:
// 一句命令,输入配置文件 my.conf, 输出 key 和 crt 文件。适合于自签署证书。 openssl req -x509 -sha256 -nodes -days 3650 -newkey rsa:1024 -keyout app.key -out app.crt -config my.conf
关于 private key 和 public key 的一些补充。
在用程序读取密钥并进行加密、解密、签名、验签时,会遇到一些库只支持某种类型的密钥文件的问题。
比较普遍的有两种格式: PKCS#1
和 PKCS#8
。
它们的区别是:
PKCS#1
密钥
// 公钥 -----BEGIN RSA PUBLIC KEY----- BASE64 ENCODED DATA -----END RSA PUBLIC KEY----- // 私钥 -----BEGIN RSA PRIVATE KEY----- BASE64 ENCODED DATA -----END RSA PRIVATE KEY-----
PKCS#8
密钥
// 公钥 -----BEGIN PUBLIC KEY----- BASE64 ENCODED DATA -----END PUBLIC KEY----- // 私钥 -----BEGIN PRIVATE KEY----- BASE64 ENCODED DATA -----END PRIVATE KEY-----
参考资料: https://tls.mbed.org/kb/cryptography/asn1-key-structures-in-der-and-pem
经实验,使用以下命令生成的 private key 都是 PKCS#1
格式的
# 生成的key以 -----BEGIN RSA PRIVATE KEY----- 开头 openssl genrsa -out server.key 2048
生成 public key 的方式有以下几种,注意格式
# 通过 private key 导出 public key。 格式为 PKCS#8 openssl rsa -pubout -in server.key -out server.pub # 通过 cert 证书导出 public key 。 格式为 PKCS#8 openssl x509 -pubkey -in server.crt -noout > server.pub # 通过 private key 导出 public key。 格式为 PKCS#1 ,注意只是最后增加一个参数。 openssl rsa -pubout -in server.key -out server.pub -RSAPublicKey_out
如何转换两种格式的 public key 呢? 参考资料: https://stackoverflow.com/questions/18039401/how-can-i-transform-between-the-two-styles-of-public-key-format-one-begin-rsa
# convert from PKCS#8 to PKCS#1: openssl rsa -pubin -in <filename> -RSAPublicKey_out # convert from PKCS#1 to PKCS#8: openssl rsa -RSAPublicKey_in -in <filename> -pubout