keytool 命令选项如下所示:
可以看出 功能基本分为 四类:
1 生成证书请求,生成证书,生成秘钥,生成秘钥对(证书库)
2 导出证书,导入口令,导入证书或者证书链,导入秘钥库的条目
3 更改条目别名,删除条目,更改条目秘钥口令,更改秘钥库口令
4 列出秘钥库条目,打印证书内容,打印证书请求内容,打印CRL文件内容。
1 创建秘钥对:
keytool -genkeypair -help 可以查看生成秘钥对可用的选项。其中加密算法必须是非对称加密算法,签名算法也要和非对称加密算法配套才可以。
这几个选项默认值如下:
-alias "mykey"
-keyalg "DSA"
-keysize 1024
-validity 90
keytool -genkeypair -alias "test1" -keyalg "RSA" -keystore "test.keystore" 这样就可以生成一个秘钥对
复杂一点的例子 如下:
keytool -genkeypair -alias "tomcat" -keyalg "RSA" -keystore "d:\mykeystore.keystore" -dname "CN=localhost, OU=localhost, O=localhost, L=SH, ST=SH, C=CN" -keypass "123456" -storepass "changeit" -validity 180
keytool -genkeypair -alias "test1" -keyalg "RSA" -storetype JKS -keystore "test.jks"
storetype 一共有JKS PCKS12 JCEKS BKS UBER 五种类型
2 查看证书库内容
keytool -list -keystore test.keystore
返回:
输入密钥库口令:
密钥库类型: JKS
密钥库提供方: SUN
您的密钥库包含 1 个条目
test, 2019-3-23, PrivateKeyEntry,
证书指纹 (SHA1): 37:0E:D4:C0:EA:5E:0F:68:8B:53:2E:38:C0:F7:19:BF:32:7E:E0:97
3 导出证书库中的别名为test的证书
keytool -export -alias test -file test.crt -keystore test.keystore
这个命令需要交互输入秘钥库的密码,如果不想交互可以直接这样写
keytool -export -alias tomcat -keystore d:\mykeystore -file d:\mycerts.cer -storepass 123456
export 有一个选项是 "-rfc" 表示以base64输出文件,否则以二进制输出。
keytool -export -alias test -file test2.crt -rfc -keystore test1.keystore
这样导出的文件内容如下
-----BEGIN CERTIFICATE-----
MIIDdzCCAl+gAwIBAgIEfKCA9DANBgkqhkiG9w0BAQsFADBsMRAwDgYDVQQGEwdVbmtub3duMRAw
DgYDVQQIEwdVbmtub3duMRAwDgYDVQQHEwdVbmtub3duMRAwDgYDVQQKEwdVbmtub3duMRAwDgYD
-----END CERTIFICATE-----
4 导入证书到证书库
首先按照刚才步骤创建一个新的证书库keytool -genkeypair -alias "test1" -keyalg "RSA" -keystore "test1.keystore"
然后使用 keytool -import -keystore test1.keystore -file test.crt 就把证书导入到了test1.keystore 中。
这之后再次查看新的证书库发现变成了2个条目:
5 查看证书信息
keytool -printcert -file "test.crt"
返回 :
所有者: CN=Unknown, OU=Unknown, O=Unknown, L=Unknown, ST=Unknown, C=Unknown
发布者: CN=Unknown, OU=Unknown, O=Unknown, L=Unknown, ST=Unknown, C=Unknown
序列号: 7ca080f4
有效期开始日期: Sat Mar 23 23:09:08 CST 2019, 截止日期: Fri Jun 21 23:09:08 CST 2019
证书指纹: //这是当前证书用不同的算法获得的不同签名结果
MD5: B6:B3:F5:F1:E3:72:DD:0D:C9:CB:05:E9:4A:C7:D4:63
SHA1: 06:4E:16:62:2F:A6:2B:CB:14:FD:77:9C:60:3B:6A:F2:2C:75:6A:EB
SHA256: E0:97:95:A5:D6:08:E9:80:78:CB:D7:BE:A8:15:24:D8:13:17:03:52:B3:13:F5:DC:E3:01:03:6C:15:A0:17:E6
签名算法名称: SHA256withRSA //这是证书的默认签名算法
版本: 3
扩展:
#1: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: 93 76 E3 A5 6B 3E C9 51 F1 77 38 3E 62 2A 3F 76 .v..k>.Q.w8>b*?v
0010: 26 26 EB A8 &&..
]
]
6 修改秘钥库中某个条目的秘钥口令
keytool -keypasswd -alias test -keystore test.keystore
7 修改条目的别名
keytool -changealias -keystore test.keystore -alias test -destalias newone
8 删除秘钥库中的条目
keytool -delete -keystore test.keystore -alias test
9不同类型的秘钥库之间的转化
jks类型秘钥库转化为 pcks12 类型秘钥库
keytool -importkeystore -srckeystore test.jks -srcstoretype JKS -deststoretype PKCS12 -destkeystore test.p12
pcks12 类型秘钥库转化为 jks类型秘钥库
keytool -importkeystore -srckeystore test.p12 -srcstoretype PKCS12 -deststoretype JKS -destkeystore test.jks
pcks12 类型秘钥库转化为 jce 类型秘钥库
keytool -importkeystore -srckeystore test.p12 -srcstoretype PKCS12 -deststoretype JCEKS -destkeystore test.jce
jks类型秘钥库转化为 jce类型秘钥库
keytool -importkeystore -srckeystore test.jks -srcstoretype JKS -deststoretype JCEKS -destkeystore test.jce
keytool -importkeystore -srckeystore test.p12 -srcstoretype PKCS12 -deststoretype BKS -destkeystore test.bks
keytool 错误: java.security.KeyStoreException: BKS not found
keytool -importkeystore -srckeystore test.p12 -srcstoretype PKCS12 -deststoretype UBER -destkeystore test.ubr
keytool 错误: java.security.KeyStoreException: UBER not found
not found 的错误是因为本机没有安装必要的组件。
证书编码格式
同样的X.509证书,可能有不同的编码格式,目前有以下两种编码格式.
PEM - Privacy Enhanced Mail,打开看文本格式,以"-----BEGIN..."开头, "-----END..."结尾,内容是BASE64编码.
查看PEM格式证书的信息:openssl x509 -in certificate.pem -text -noout
Apache和*NIX服务器偏向于使用这种编码格式.
DER - Distinguished Encoding Rules,打开看是二进制格式,不可读.
查看DER格式证书的信息:openssl x509 -in certificate.der -inform der -text -noout
Java和Windows服务器偏向于使用这种编码格式.
证书编码的转换
PEM转为DER openssl x509 -in cert.crt -outform der -out cert.der
DER转为PEM openssl x509 -in cert.crt -inform der -outform pem -out cert.pem
(提示:要转换KEY文件也类似,只不过把x509换成rsa,要转CSR的话,把x509换成req...)
相关的文件扩展名
这是比较误导人的地方,虽然我们已经知道有PEM和DER这两种编码格式,但文件扩展名并不一定就叫"PEM"或者"DER",常见的扩展名除了PEM和DER还有以下这些,它们除了编码格式可能不同之外,内容也有差别,但大多数都能相互转换编码格式.
CRT - CRT应该是certificate的三个字母,其实还是证书的意思,常见于*NIX系统,有可能是PEM编码,也有可能是DER编码,大多数应该是PEM编码,相信你已经知道怎么辨别.
CER - 还是certificate,还是证书,常见于Windows系统,同样的,可能是PEM编码,也可能是DER编码,大多数应该是DER编码.
KEY - 通常用来存放一个公钥或者私钥,并非X.509证书,编码同样的,可能是PEM,也可能是DER.
查看KEY的办法:openssl rsa -in mykey.key -text -noout
如果是DER格式的话,同理应该这样了:openssl rsa -in mykey.key -text -noout -inform der
CSR - Certificate Signing Request,即证书签名请求,这个并不是证书,而是向权威证书颁发机构获得签名证书的申请,其核心内容是一个公钥(当然还附带了一些别的信息),在生成这个申请的时候,同时也会生成一个私钥,私钥要自己保管好.做过iOS APP的朋友都应该知道是怎么向苹果申请开发者证书的吧.
查看的办法:openssl req -noout -text -in my.csr (如果是DER格式的话照旧加上-inform der,这里不写了)
PFX/P12 - predecessor of PKCS#12,对*nix服务器来说,一般CRT和KEY是分开存放在不同文件中的,但Windows的IIS则将它们存在一个PFX文件中,(因此这个文件包含了证书及私钥)这样会不会不安全?应该不会,PFX通常会有一个"提取密码",你想把里面的东西读取出来的话,它就要求你提供提取密码,PFX使用的时DER编码,如何把PFX转换为PEM编码?
openssl pkcs12 -in for-iis.pfx -out for-iis.pem -nodes
这个时候会提示你输入提取代码. for-iis.pem就是可读的文本.
生成pfx的命令类似这样:openssl pkcs12 -export -in certificate.crt -inkey privateKey.key -out certificate.pfx -certfile CACert.crt
其中CACert.crt是CA(权威证书颁发机构)的根证书,有的话也通过-certfile参数一起带进去.这么看来,PFX其实是个证书密钥库.
JKS - 即Java Key Storage,这是Java的专利,跟OpenSSL关系不大,利用Java的一个叫"keytool"的工具,可以将PFX转为JKS,当然了,keytool也能直接生成JKS,不过在此就不多表了.
openssl 命令学习
https://blog.youkuaiyun.com/liao20081228/article/details/77159039
PEM 转换 DER
openssl x509 -outform der -in certificate.pem -out certificate.der //红色部分指定out文件的编码方式
PEM 转换 P7B
openssl crl2pkcs7 -nocrl -certfile certificate.cer -out certificate.p7b -certfile CAcert.cer //ca机构的根证书
PEM 转换 PFX
openssl pkcs12 -export -out certificate.pfx -inkey privateKey.key -in certificate.crt -certfile CAcert.crt
DER 转换 PEM
openssl x509 -inform der -in certificate.cer -out certificate.pem //红色部分指定in文件的编码方式
P7B 转换 PEM
openssl pkcs7 -print_certs -in certificate.p7b -out certificate.cer
PFX 转换 PEM
$ openssl pkcs12 -in certificate.pfx -out certificate.cer -nodes
1如何加载秘钥库
public static KeyStore getKeyInfo(String pfxkeyfile, String keypwd,
String type) throws IOException {
LogUtil.writeLog("加载签名证书==>" + pfxkeyfile);
FileInputStream fis = null;
try {
KeyStore ks = null;
if ("JKS".equals(type)) {
ks = KeyStore.getInstance(type);
} else if ("PKCS12".equals(type)) {
String jdkVendor = System.getProperty("java.vm.vendor");
String javaVersion = System.getProperty("java.version");
LogUtil.writeLog("java.vm.vendor=[" + jdkVendor + "]");
LogUtil.writeLog("java.version=[" + javaVersion + "]");
// Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
if (null != jdkVendor && jdkVendor.startsWith("IBM")) {
// 如果使用IBMJDK,则强制设置BouncyCastleProvider的指定位置,解决使用IBMJDK时兼容性问题
Security.insertProviderAt(
new org.bouncycastle.jce.provider.BouncyCastleProvider(),
1);
printSysInfo();
}else{
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
}
// ks = KeyStore.getInstance(type, "BC");
ks = KeyStore.getInstance(type);
}
LogUtil.writeLog("Load RSA CertPath=[" + pfxkeyfile + "],Pwd=["
+ keypwd + "]");
fis = new FileInputStream(pfxkeyfile);
char[] nPassword = null;
nPassword = null == keypwd || "".equals(keypwd.trim()) ? null
: keypwd.toCharArray();
if (null != ks) {
ks.load(fis, nPassword);
}
return ks;
} catch (Exception e) {
if (Security.getProvider("BC") == null) {
LogUtil.writeLog("BC Provider not installed.");
}
LogUtil.writeErrorLog("getKeyInfo Error", e);
if ((e instanceof KeyStoreException) && "PKCS12".equals(type)) {
Security.removeProvider("BC");
}
return null;
}finally{
if(null!=fis)
fis.close();
}
}
2 如何从秘钥库中获取公钥证书
public static PublicKey getSignPublicKey() {
try {
Enumeration<String> aliasenum = keyStore.aliases();
String keyAlias = null;
if (aliasenum.hasMoreElements()) // we are readin just one
// certificate.
{
keyAlias = (String) aliasenum.nextElement();
}
Certificate cert = keyStore.getCertificate(keyAlias);
PublicKey pubkey = cert.getPublicKey();
return pubkey;
} catch (Exception e) {
LogUtil.writeErrorLog(e.toString());
return null;
}
}
3 从秘钥库中获取私钥
PrivateKey privateKey = (PrivateKey) keystore.getKey(keyAlias, certPwd.toCharArray());
4: 从x509证书文件中读取获取证书对象
/**
*
* @param path
* @return
*/
private static X509Certificate initCert(String path) {
X509Certificate encryptCertTemp = null;
CertificateFactory cf = null;
FileInputStream in = null;
try {
cf = CertificateFactory.getInstance("X.509");
in = new FileInputStream(path);
encryptCertTemp = (X509Certificate) cf.generateCertificate(in);
// 打印证书加载信息,供测试阶段调试
LogUtil.writeLog("[" + path + "][CertId="
+ encryptCertTemp.getSerialNumber().toString() + "]");
} catch (CertificateException e) {
LogUtil.writeErrorLog("InitCert Error", e);
} catch (FileNotFoundException e) {
LogUtil.writeErrorLog("InitCert Error File Not Found", e);
} finally {
if (null != in) {
try {
in.close();
} catch (IOException e) {
LogUtil.writeErrorLog(e.toString());
}
}
}
return encryptCertTemp;
}