摘要:本文力求从理论到工具,从工具到代码,从代码到实际应用介绍所有和 Certificate (广义)相关的知识。
JKS (Java KeyStore)
KeyStore 介绍
从 JKS
说起 (Java KeyStore
),首先我们看一下 Wiki:
A Java KeyStore (JKS) is a repository of security certificates – either authorization certificates or public key certificates – plus corresponding private keys, used for instance in SSL encryption.
In IBM WebSphere Application Server and Oracle WebLogic Server, a file with extension jks serves as keystore.
The Java Development Kit maintains a CA keystore in folder jre/lib/security/cacerts. JDKs provide a tool named keytool[1] to manipulate the keystore. keytool has no functionality to extract the private key out of the keystore, but this is possible with third-party tools like jksExportKey, CERTivity,[2] Portecle[3] and KeyStore Explorer.[4]
直观的说,KeyStore
只是一个载体,是 Certificate
的载体,在一个 KeyStore
文件中可以有多个公钥和私钥对。每对公私钥通过别名 alias
来区分。对于 KeyStore
, 我们使用 KeyTool
工具来进行操作。
关键点:
- keystore 包含若干对公私钥,通过别名区分及提取
- keystore 工具是 keytool
- keystore 本身有密码
使用 keytool
生成 JKS
,并且生成公钥和私钥对:
1 | keytool -genkey -alias mydomain -keyalg RSA -keystore keystore.jks -keysize 2048 |
说明:
- -genkey 生成公私钥
- -alias 指定公私钥对的别名
- -keyalg 指定算法
- -keystore 指定输出的文件名
- -keysize 指定密钥长度
该命令是一个交互式的,需要用户指定以下内容,这里需要两个密码:
- keystore password (JKS 文件本身密码)
- key password (私钥密码)
1 | keytool -genkey -alias mengxin.science -keyalg RSA -keystore mxsci.jks -keysize 2048 |
查看 keystore 内的公私钥信息
1 | # Check a stand-alone certificate** |
CSR (Certificate Signing Request)
介绍
In public key infrastructure (PKI) systems, a certificate signing request (also CSR or certification request) is a message sent from an applicant to a certificate authority in order to apply for a digital identity certificate. It usually contains the public key for which the certificate should be issued, identifying information (such as a domain name) and integrity protection (e.g., a digital signature). The most common format for CSRs is the PKCS #10 specification and another is the Signed Public Key and Challenge SPKAC format generated by some web browsers.
也就是说 CSR
是一个概念,其通常承载的文件格式是 PKCS #10
和 SPKAC
。CSR
本质上是一个消息,这个消息一般是包含公钥,唯一身份信息和数字签名,用来向 CA
申请数字认证的。
我们要知道,一个证书 (或者说是一对公私钥),理论上只有被某个 CA
信任了,才能在实际中真正的发挥作用。
JKS 生成 CSR
1 | keytool -certreq -alias mydomain -keystore keystore.jks -file mydomain.csr |
说明
- certreq 表示生成 CSR
- alias 指定使用哪个key 对
- keystore 指定 jks 文件
- file 指定说出的额 csr 文件
在执行过程中需要输入 keystore 和 key 的 password,如果输入错误,将会得到错误。比如 key 密码输入错误,则会报错: keytool error: java.security.UnrecoverableKeyException: Cannot recover key
1 | keytool -certreq -alias mengxin.science -keystore mxsci.jks -file mxsci.csr |
这时候生成的 CSR
为
1 | # cat mxsci.csr |
公私钥及证书系统
在开始介绍之前,我们需要首先明确,我们需要哪些知识,这些知识将会有什么用?
- 需要知道各种文件格式的意义
- 需要知道各种文件格式中包含的内容
- 需要知道各种文件格式之间的转化
- 需要知道各种文件格式一般的用途
标准:
- PKCS stands for “Public Key Cryptography Standards”
编码:
- PEM
- DER
文件后缀
jks
: Java KeyStorecsr
: Certificate Signing Request (PKCS1 #10)p12
: (PKCS1 #12) same with pfx, change extention name, see thispfx
: Personal Information Exchange Format (PFX)pem
: Privacy-Enhanced Mailkey
: The KEY extension is used both for public and private PKCS#8 keys. The keys may be encoded as binary DER or as ASCII PEM.key.unsecure
crt
: certificate, The CRT extension is used for certificates. The certificates may be encoded as binary DER or as ASCII PEM. The CER and CRT extensions are nearly synonymous. Most common among *nix systemssrl
:cer
: certificate, alternate form of .crt (Microsoft Convention) You can use MS to convert .crt to .cer (.both DER encoded .cer, or base64[PEM] encoded .cer) The .cer file extension is also recognized by IE as a command to run a MS cryptoAPI command (specifically rundll32.exe cryptext.dll,CryptExtOpenCER) which displays a dialogue for importing and/or viewing certificate contents.der
: Distinguished Encoding Rules, The DER file extension is primarily associated with a DER- (Distinguished Encoding Rules) encoded X509 digital certificate file.
crt 和 cer
.crt stands simply for certificate, usually an X509v3 certificate, again the encoding could be PEM or DER; a certificate contains the public key, but it contains much more information (most importantly the signature by the Certificate Authority over the data and public key, of course).
这个就是 General 的 Certificate 文件,一般就是 X509v3
的证书 (只有公钥和签名等信息,没有私钥),其编码可以是 PEM
和 DER
。
1 | keytool -export -alias server-alias -storepass changeit |
结果
1 | keytool -export -alias mengxin.science -storepass changeit -file mxsci.cer -keystore mxsci.jks |
这个 cer
是 DER
格式,我们可以用 openssl
来查看该证书:
1 | openssl x509 -in mxsci.cer -inform der -text -noout |
我们参考该文章,可以转换格式
DER exchange PEM
1 | openssl x509 -in mxsci.cer -inform der -outform pem -out mxsci.pem |
查看 PEM
证书信息,该信息和上面的是一致的
1 | openssl x509 -in mxsci.pem -text -noout |
同理我们也可以把 PEM
转化为 DER
1 | openssl x509 -in mxsci.pem -inform pem -outform der -out mxsci-from-pem.der |
我们会发现 mxsci-from-pem.der
实际上和原来的 mxsci.cer
是一样的。
crt 和 cer 的转化
参考该回答
File extensions for cryptographic certificates aren’t really as standardized as you’d expect. Windows by default treats double-clicking a .crt file as a request to import the certificate into the Windows Root Certificate store, but treats a .cer file as a request just to view the certificate. So, they’re different in that sense, at least, that Windows has some inherent different meaning for what happens when you double click each type of file.
But the way that Windows handles them when you double-click them is about the only difference between the two. Both extensions just represent that it contains a public certificate. You can rename a file or use one in place of the other in any system or configuration file that I’ve seen. And on non-Windows platforms (and even on Windows), people aren’t particularly careful about which extension they use, and treat them both interchangeably, as there’s no difference between them as long as the contents of the file are correct.
实际上这两个文件是一样的,只是不同的操作系统的传统定义方式和打开方式的动作有所不同,我们同样可以用 openssl
来转化,这里我们可以针对 pem
和 der
两个格式转化。
1 | openssl x509 -in mxsci.cer -inform DER -outform DER -out mxsci.crt |
同样生成的 mxsci.crt
和 mxsci.cer
也是完全一样的文件。
我们也可以直接转化为 pem
格式的 crt
1 | openssl x509 -in mxsci.cer -inform DER -outform PEM -out mxsci.pem.crt |
然后我们会发现,这个文件 mxsci.pem.crt
和之前的 mxsci.pem
是一样的。
总之我们需要区分来
- PEM 和 DER:编码格式,在
openssl
工具中,需要通过-inform
指定 (PEM 默认, DER 需要显式的指定) - CRT 和 CER:都是 x509 certificate,基本是相同,理论上改个后缀就行了。
key
该文件一般存放私钥
我们可以通过 keytool
从 jks
中提取出私钥。
这里需要指出,之前我们在使用 keytool
总是会有一个警告,这是告诉我们,jks
不是一个标准,而 PKCS12
才是一个标准,keytool
推荐我们将其转化为标准文件,这样可以使用其他工具,比如 openssl
对其进行进一步操作。
1 | Warning: |
这里还需要说明一个问题,就是 jks
支持 store
的 password
和 key
的 password
是两个密码,但是 PKCS12
理论上并不支持,因为这个文件被其他工具使用的时候,只接受一样的密码,所以 keytool
在转化 jsk
到 pkcs12
的时候,如果密码不一样,会报错,这一点,我们可以参考该 issue
1 | keytool error: java.lang.Exception: The destination pkcs12 keystore has different storepass and keypass. Please retry with -destkeypass specified. |
所以我们需要将密码改成一致,这里改 key 或者 store 的 password 都可以。
修改 jks 的 key 和 keystore 的密码
keystore 密码
1 | keytool -storepasswd -new newpassword -keystore server.keystore |
key 密码
1 | keytool -keypasswd -alias server -keypass changeit -new newpassword -keystore server.keystore -storepass newpassword |
实践
1 | keytool -storepasswd -new changeit1 -keystore mxsci.jks -storepass changeit |
jks 生成 key
这时候,两个密码都改为了 changeit1
,下面我们就可以开始将其转化为 pkcs12
进而生成 key
1 | keytool -importkeystore -srckeystore mxsci.jks -storepass changeit1 -destkeystore mxsci.jks -deststoretype pkcs12 |
通过这两个命令发现,其目标的keystore 可以是任意文件扩展,虽然扩展名一样 (都是 jks),但是实际上内容格式已经不一样,因为如果使用 keytool
查看该 jks
发现,旧的 jks 会有一个警告,但是新的 jks 没有警告,然后我们还可以指定成 p12
格式的文件。
有了 p12
,我们就可以使用 openssl
生成 key
了。
1 | # concert PKCS12 key to unencrypted PEM: |
生成的 key
是非加密的私钥,并且是 PEM
格式,生成过程需要输入密码。
当然这里我们还可以生成 crt
证书文件
1 | openssl pkcs12 -in keystore.p12 -nokeys -out my_key_store.crt |
我们会发现这个生成的 crt
也是 PEM
格式的,比之前生成的 crt
多了个头部信息,证书的 base64 字符串是一样的:
1 | Bag Attributes |
https://serverfault.com/a/715856/398427
Nginx 配置 SSL
公私钥的使用场景最典型的就是 SSL (TSL) 安全套接字,其构建了整个网络世界的安全基础。
http://www.ruanyifeng.com/blog/2014/02/ssl_tls.html
http://www.ruanyifeng.com/blog/2014/09/illustration-ssl.html
https://www.cnblogs.com/chjbbs/p/5748369.html
一般在 Nginx 配置文件中配置 SSL 的时候,需要分别配置 key
和 certificate
1 | server { |
其中 key
需要保密,而 crt
是需要公开出去的。一般情况下,这个 crt
是需要某个权威的 CA
认证的,从而保证这个证书无法被篡改。对于如何使用这对公私钥保证数据传输安全保密,参考该文,概括的讲就是浏览器需要从服务器获取证书也就是公钥,首先验证公钥的有效性,然后使用公钥对数据进行加密再传输到服务器,服务器使用私钥解密获取明文。当然这个过程需要考虑很多细节,比如加密本身资源消耗大,所以采用和对称加密结合的方式,只是用公钥加密对称密钥,然后数据使用对称密钥加密,而服务通过私钥获取对称密钥,然后在解密密文。
刚才我们提到 crt
一般是通过某个 CA
认证,这个认证过程是通过使用 csr
文件向 CA
申请的。
CA 签发证书
首先我们先生成一个 CA
证书。
Subject: C = UK, ST = London, L = London, O = Deepnet Security Ltd, OU = Certificate Authority, CN = Deepnet CA
https://gist.github.com/Soarez/9688998#ca-key-and-self-signed-certificate
1 | openssl genrsa -out ca.key 2048 |
key + crt to pfx
https://www.ssl.com/how-to/create-a-pfx-p12-certificate-file-using-openssl/
1 | openssl pkcs12 -export -out certificate.pfx -inkey privateKey.key -in certificate.crt -certfile more.crt |
https://www.sslshopper.com/article-most-common-openssl-commands.html
NetScaler Certificate
对于 NetScaler 的配置,配置面板中给出了一张图,我们可以看到它所需要的 certificate-key pair
文件,所以我们需要自己生成这个问题。
openssl/keytool 总结
实际中,我们最常用的主要是通过命令查看转换证书文件等。下面我们对这些命令进行一下总结:
openssl
该命令有二级子命令,目前我们用到的有: x509,rsa,req,genrsa,pkcs12。下面我们总结一下每个子命令通用的选项:
- -in 输入的文件
- -inform 主要制定输入的格式 PEM/DER
- -out 输出的文件
- -outform 主要制定输出的格式 PEM/DER
- -text 用于输出内容,和 -noout 组合使用查看
- -noout 不输出任何文件
典型应用
- openssl x509 -in mxsci.cer -inform der -text -noout
- DER 转 PEM:
openssl x509 -in mxsci.cer -inform der -outform pem -out mxsci.pem
- 查看 PEM:
openssl x509 -in mxsci.pem -text -noout
- PEM 转 DER:
openssl x509 -in mxsci.pem -inform pem -outform der -out mxsci-from-pem.der
- 查看 DER:
openssl x509 -in mxsci-from-pem.der -inform der -text -noout
- 生成 key:
openssl genrsa -out ca.key 2048
- 生成 self sign 证书:
openssl req -new -x509 -key ca.key -out ca.crt
- 通过 csr 签发 crt
openssl x509 -req -in example.org.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out example.org.crt
- crt+key 生成 pfx:
openssl pkcs12 -export -out certificate.pfx -inkey privateKey.key -in certificate.crt -certfile more.crt
- pfx 生成 key:
openssl pkcs12 -in keystore.p12 -nodes -nocerts -out mydomain.key
- pfx 生成 crt:
openssl pkcs12 -in keystore.p12 -nokeys -out my_key_store.crt
keytool
主要是各个选项的组合使用
- -keystore keystore.jks 指定 keystore 文件,一般为 jks 或 p12
- -alias mydomain 指定别名
- -storepass changeit 指定 store password
- -export 输出证书
- -file 输出文件名
- -storepasswd -new 修改 store password
- -keypasswd 修改 key password
- -keypass 指定 key password
- -importkeystore 用于转换 keystore 格式,import
- -destkeystore 用于转换 keystore 格式,destination 文件名
- -deststoretype 用于转换 keystore 格式,destination store 类型,比如 pkcs12
- -genkey 生成 key pair
- -keyalg 生成使用的算法
- -keysize 生成 key 的 size
- -printcert 打印 certificate
- -v it signifies “verbose” mode; more information will be output.
- -list Prints (to stdout) the contents of the keystore entry identified by alias. If no alias is specified, the contents of the entire keystore are printed.
- -certreq 创建 csr
典型应用
- 生成 key:
keytool -genkey -alias mydomain -keyalg RSA -keystore keystore.jks -keysize 2048
- 导出证书:
keytool -printcert -v -file mydomain.crt
- 查看所有:
keytool -list -v -keystore keystore.jks
- 查看某一个:
keytool -list -v -keystore keystore.jks -alias mydomain
- 创建 csr:
keytool -certreq -alias mydomain -keystore keystore.jks -file mydomain.csr
- 都出 cer:
keytool -export -alias server-alias -storepass changeit -file server.cer -keystore keystore.jks
- 修改 store pass:
keytool -storepasswd -new newpassword -keystore server.keystore -storepass
- 修改 key pass:
keytool -keypasswd -alias mengxin.science -keypass changeitkey -new changeit1 -keystore mxsci.jks -storepass changeit1
- 生成 p12:
keytool -importkeystore -srckeystore mxsci.jks -storepass changeit1 -destkeystore mxsci.p12 -deststoretype pkcs12