本文最后编辑于 前,其中的内容可能需要更新。
自签CA流程
自签CA流程如图

公网的CA机构签发证书的流程和原理基本也是如此,不过根CA的压力会比较大,所以延伸出了二级ca等,以此保证证书链的完整和有效。
一般的操作系统出厂时都会内置可用的公网CA的证书拉作为信任证书源,以保证用户访问的网站使用新签发的证书时,通过证书验证。
所以,一般在双向认证场景下,我们可以只用一套根CA,不断为新的服务签发证书,每个服务只信任根CA签发的证书。
JDK自带的keytool是一个证书工具,位于\bin\keytool.exe(linux同理),用它也可以生成ssl证书,但笔者觉得openssl更好用些,keytool用于p12格式和jks格式密钥库的转换就行了
使用 keytool -help
查看可用命令
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| -certreq 生成证书请求 -changealias 更改条目的别名 -delete 删除条目 -exportcert 导出证书 -genkeypair 生成密钥对 -genseckey 生成密钥 -gencert 根据证书请求生成证书 -importcert 导入证书或证书链 -importpass 导入口令 -importkeystore 从其他密钥库导入一个或所有条目 -keypasswd 更改条目的密钥口令 -list 列出密钥库中的条目 -printcert 打印证书内容 -printcertreq 打印证书请求的内容 -printcrl 打印 CRL 文件的内容 -storepasswd 更改密钥库的存储口令
|
使用keytool -command_name -help
查看命令用法。
keystore 和 truststore
Keytool 将密钥(key)和证书(certificates)存在一个称为 keystore 的文件中,在 keystore 里,包含两种数据:
- 密钥实体(Key entity)— 密钥(secret key)又或者是私钥和配对公钥(采用非对称加密),包含了私钥,所以是一个需要保密的文件
- 可信任的证书实体(trusted certificate entries)— 只包含公钥
证书库中的一条证书可以导出数字证书文件,数字证书文件只包括主体信息和对应的公钥;
keystore 和 truststore 从其文件格式来看其实是一个东西,只是为了方便管理将其分开;
keystore 中一般保存的是我们的私钥,用来加解密或者为别人做签名。
truststore 中保存的是一些可信任的证书,主要是 java 在代码中访问某个 https 的时候对被访问者进行认证的,以确保其实可信任的。
truststore 里存放的是只包含公钥的数字证书,代表了可以信任的证书,而 keystore 是包含私钥的;
生成密钥库
密钥库可以当作证书仓库来看
keytool -genkeypair [option]
或keytool -genkey [option]
选项:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| -alias <alias> 要处理的条目的别名 -keyalg <keyalg> 密钥算法名称 -keysize <keysize> 密钥位大小 -sigalg <sigalg> 签名算法名称 -destalias <destalias> 目标别名 -dname <dname> 唯一判别名 -startdate <startdate> 证书有效期开始日期/时间 -ext <value> X.509 扩展 -validity <valDays> 有效天数 -keypass <arg> 密钥口令 -keystore <keystore> 密钥库名称 -storepass <arg> 密钥库口令 -storetype <storetype> 密钥库类型 -providername <providername> 提供方名称 -providerclass <providerclass> 提供方类名 -providerarg <arg> 提供方参数 -providerpath <pathlist> 提供方类路径 -v 详细输出 -protected 通过受保护的机制的口令
|
其中:
- -storetype 指定仓库类型, JKS、 JCEKS、 PKCS12等,默认JKS
- -keyalg 指定密钥的算法, RSA、 DSA 等,默认DSA
- -keysize 指定密钥长度,默认2048
- -alias 指定密钥对的别名,该别名是公开的
- -keystore 密钥库的路径及名称
例:
1 2 3 4
| # 根据提示挨个输入参数 keytool -genkey -alias <密钥库别名> -storetype <密钥库类型> -keyalg <密钥算法名称> -keystore <密钥库路径> # 输入参数完毕后将在当前路径生成证书 keytool -genkey -alias test -storetype jks -keyalg RSA -keystore test-keystore.jks
|
1 2 3 4
| # 一次性搞定 keytool -genkey -alias <密钥库别名> -storetype <密钥库类型> -keystore <密钥库路径> -keyalg <密钥算法名称> -keysize <密钥位大小> -storepass <密钥库口令> -keypass <密钥口令> -validity <有效天数> -dname <dname> # 直接在当前路径生成证书,CN可填多个如:"CN=test1.com, CN=test2.com, OU=test.com, O=ChinaHonker, L=Beijing, S=Beijing, C=086" keytool -genkey -alias ws-ssl-server-keystore -storetype jks -keystore ws-ssl-server-keystore.jks -keyalg RSA -keysize 2048 -storepass 123456serverstore -keypass 123456serverkey -validity 3650 -dname "CN=WindShadow, OU=WindShadow,O=WS-Server, L=Beijing, S=Beijing, C=086"
|
dname详解
- CN:Common Name 公用名称,对于 SSL 证书,一般为网站域名;而对于代码签名证书则为申请单位名称;而对于客户端证书则为证书申请者的姓名
- OU:Organization Name 单位名称,对于 SSL 证书,一般为网站域名;而对于代码签名证书则为申请单位名称;而对于客户端单位证书则为证书申请者所在单位名称
- O:Organization 组织
- L: Locality 所在城市
- S:State 所在省份
- C:Country 所在国家,只能填代表国家的双字母或地区代码,如中国:CN或086
导出证书(.cer文件)
1 2
| keytool -keystore <密钥库路径> -alias <密钥库别名> -storepass <密钥库口令> -export -file <证书路径> keytool -keystore ws-ssl-server-keystore.jks -alias ws-ssl-server-keystore -storepass 123456serverstore -export -file ws-ssl-server-keystore.cer
|
导入证书(.cer文件)到密钥库
1 2
| keytool -import -alias <密钥库别名> -storepass <密钥库口令> -file <证书路径> -keystore <密钥库路径> keytool -import -alias ws-ssl-server-keystore -storepass 123456serverstore -file ws-ssl-server-keystore.cer -keystore ws-ssl-trust-keystore.jks
|
转换密钥库格式
jks转pkcs12,p12的密钥库其实不需要使用keypass
,但是使用keytool进行转换还是要指定一下参数
1 2 3 4 5
| keytool -importkeystore \ -srckeystore <源密钥库路径> -srcstoretype <源密钥库类型> -srcalias <源密钥库别名> -srcstorepass <源密钥库口令> -srcstorepass <源密钥口令> \ -destkeystore <目标密钥库路径> -deststoretype <目标密钥库类型> -destalias <源密钥库别名> -deststorepass <目标密钥库口令> -destkeypass <目标密钥口令>
keytool -importkeystore -srckeystore ws-ssl-server-keystore.jks -srcstoretype jks -srcalias ws-ssl-server-keystore -srcstorepass 123456serverstore -srckeypass 123456serverkey -destkeystore ws-ssl-server-keystore.p12 -deststoretype pkcs12 -destalias ws-ssl-server-keystore -deststorepass 123456serverstore -destkeypass 123456serverkey
|
列出密钥库条目
1 2 3
| keytool -list -keystore <密钥库路径> -storepass <密钥库口令> -keypass <密钥口令>
keytool -list -keystore ws-ssl-server-keystore.jks -storepass 123456serverstore -keypass 123456serverkey
|
openssl自签ca示例
cagen.sh脚本(Linux),用到的openssl配置文件可从此地址下载:http://web.mit.edu/crypto/openssl.cnf
1 2 3
| . ├── cagen.sh └── openssl.cnf
|
cagen.sh
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
| # readonly rootca="ws-rootca" readonly rootcaKeyPwd="rootcaKeyPwd" readonly rootDname="/CN=WindShadow-root/OU=WindShadow/O=WS/L=Beijing/S=Beijing/C=CN" readonly opensslCnf="openssl.cnf" readonly globalValidity=3650
readonly trustKeystore="ws-trust" readonly trustKeystorePwd="ws-trustKeystorePwd"
function clean() {
rm -f *.p12 rm -f *.jks rm -f *.cer rm -f *.csr rm -f *.crt rm -f *.key rm -f *.pem rm -f *.crl rm -f *.pass rm -rf ./demoCA rm -rf ./gen }
function CrtToP12() {
crtFile=${1} keyFile=${2} keyPwd=${3} keystore=${4} keystoreAlias=${5}
openssl pkcs12 -export -clcerts \ -in ${crtFile} \ -inkey ${keyFile} -passin pass:${keyPwd} \ -out ${keystore} -name ${keystoreAlias} -password pass:${keyPwd} }
function CrtToCer() {
crtFile=${1} cerFile=${2} openssl x509 -in ${crtFile} -out ${cerFile} -outform der }
function genRootCA() {
# #
# 无加密 openssl genrsa -out ${rootca}.key 2048 # 加密为 pkcs8 openssl pkcs8 -topk8 -in ${rootca}.key -out ${rootca}.key.e -passout pass:${rootcaKeyPwd} \ && rm -f ${rootca}.key \ && mv ${rootca}.key.e ${rootca}.key openssl req -new -key ${rootca}.key -passin pass:${rootcaKeyPwd} \ -out ${rootca}.csr \ -days ${globalValidity} \ -subj ${rootDname}
openssl x509 -req \ -in ${rootca}.csr \ -signkey ${rootca}.key -passin pass:${rootcaKeyPwd} \ -extfile ${opensslCnf} -extensions v3_ca \ -out ${rootca}.crt \ -days ${globalValidity}
CrtToCer ${rootca}.crt ${rootca}.cer rm -f ${rootca}.csr }
function rootCAIssue() {
caName=${1} keyPwd=${2} dname=${3} validity=${4}
openssl genrsa -out ${caName}.key 2048 openssl pkcs8 -topk8 -in ${caName}.key -out ${caName}.key.e -passout pass:${keyPwd} \ && rm -f ${caName}.key \ && mv ${caName}.key.e ${caName}.key openssl req -new -key ${caName}.key -passin pass:${keyPwd} \ -out ${caName}.csr \ -days ${validity} \ -subj ${dname}
openssl x509 -req \ -in ${caName}.csr \ -CAkey ${rootca}.key -passin pass:${rootcaKeyPwd} \ -CA ${rootca}.crt -CAcreateserial \ -extfile ${opensslCnf} -extensions v3_ca \ -out ${caName}.crt \ -days ${validity}
rm -f ${caName}.csr }
function add2Trust() {
caName=${1} caFile=${2} keytool -importcert -trustcacerts -deststoretype pkcs12 -alias ${caName} -keystore ${trustKeystore}.p12 -storepass ${trustKeystorePwd} -file ${caFile} -noprompt }
function main() {
### serverca readonly serverca="ws-serverca" readonly servercaKeyPwd="ws-servercaKeyPwd" readonly serverDname="/CN=WindShadow-server/OU=WindShadow/O=WS/L=Beijing/S=Beijing/C=CN" rootCAIssue ${serverca} ${servercaKeyPwd} ${serverDname} ${globalValidity}
### CrtToP12 ${rootca}.crt ${rootca}.key ${rootcaKeyPwd} ${rootca}.p12 ${rootca} CrtToP12 ${serverca}.crt ${serverca}.key ${servercaKeyPwd} ${serverca}.p12 ${serverca}
### 高版本jdk的keytool的p12密钥库在低版本JDK使用时不兼容
# 导入rootCa根证书到信任库中 add2Trust ${rootca} ${rootca}.cer
### 整理 cp ${rootca}.crt ${trustKeystore}.crt mkdir -p gen/ca/ mkdir -p gen/certificate/ mkdir -p gen/trust/ mv ${rootca}.* gen/ca/ mv ${serverca}.* gen/certificate/ mv ${trustKeystore}.* gen/trust/
} set -x clean genRootCA main
|
得到以下文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| gen ├── ca │ ├── ws-rootca.cer │ ├── ws-rootca.crt │ ├── ws-rootca.key │ ├── ws-rootca.p12 │ └── ws-rootca.srl ├── certificate │ ├── ws-serverca.crt │ ├── ws-serverca.key │ └── ws-serverca.p12 └── trust ├── ws-trust.crt └── ws-trust.p12
|
serverca可以部署到服务上作为服务端证书,trust可作为双向认证时的可信证书(crt)或可信密钥库(p12),保存rootca可用于新服务证书的签发