最近公司的项目需要使用到设备证书,之前也没有接触过。最近学习了一把,然后把一些学习内容总结下来。
电子认证服务机构的简称。CA是网络身份认证的管理机构,是网上安全电子交易中具有权威和公证性的可信懒的第三方机构。CA为电子事务的各参与方签发标识其身份的数字证书,并对数字证书进行更新、撤销等一系列管理。
CA分为公有的CA和私有的CA
公有CA:公开的CA,一个知名的,可达的,全局(互联网),受信任的证书服务器,由一些专业的公司进行操作与维护,这些知名的公司有Verisign,Entrust,GlobalSign和Thawte。这类CA颁发机构,我们操作系统一般会内置了他们的根证书,所以通常情况下他颁发的证书,我们是无需再去安装根证书的。
私有CA:一个公司或者部门内部使用的证书服务器。优势就是免费和不受约束,劣势当然也非常突出,就是信任关系有限。如果出了你这个范围,其他用户都是对你不信任的,所以你所颁发的证书在其他用户的计算机是不认的。当然,除非他特意安装了你的根证书除外。
注册机构的简称。RA是CA认证体系的对外服务机构,负责对数字证书进行资格审核,并决定是否同意给该申请者颁发数字证书,以及更新数字证书和撤销工作。
数字证书撤销列表的简称。CRL中记录所有在原定失效日期到达之前被撤销的数字证书,供数字证书订户、依赖方在验证对方数字证书时查询使用,由CA周期性签发。CRL通常又被称为数字证书黑名单、数字证书废止列表等。内容通常包含列表签发者、发行日期、下次撤销列表的预订签发日期、被撤销的数字证书序号,并说明被撤销的时间与可能存在的理由。如下图:
在线数字证书状态查询协议的简称,用于支持实时查询数字证书状态。功能和CRL类似,但优点比CRL要更好些。
有时候直接称为证书。它是由证书认证机构签名的包含公开秘钥拥有者信息、公开秘钥、芊发者信息、有效期以及一些扩展信息的数字文件。它是用来标志和证明网络通信双方身份的数字信息文件,与司机驾照或者日常生活中的身份证相似。在网络上进行电子商务活动时,交易双方需要使用数字证书来表明自己的身份,并使用数字证书来进行有关交易操作。
注意:数字证书公钥持有者是谁?我该不该信任它的问题。它的作用就是用来帮助确认身份。
采用密码技术对数据进行运算得到的附加在数据上的前面数据,或者是对数据所作的密码交换,用来确认数据来源及其完整性,防止被别人串改或者伪造。
说得简单点就是用户对明文的数据进行组装,然后通过散列码算法生成散列值,用户私钥私钥对散列值进行加密得到新的值,这个新的值就是数字签名。
数字签名是解决
数据完整性验证、源认证问题
步骤:
1、用户1将重要的明文数据,按照与用户2预定好的规则组装好,使用与用户2预定好的散列算法对封装好的数据进行计算,生成散列值1
。
2、用户1使用私钥、使用非常对称加密算法(RSA),对散列值1
进行加密,生成数字签名
。
3、用户1将数字签名和明文的信息封装成数据包,发给用户2.
4、用户2在数据包中提取数字签名,然后使用用户1分配的用户1公钥
对书签签名进行解密,得到散列值1
。
5、用户2再在数据包中提取明文的信息,按照与用户1预定好的规则组装好,使用与用户1预定好的散列算法对封装好的数据进行计算,生成散列值2
6、用户2使用散列1和散列值2进行对比,如果散列值相同,数据是原数据,没有被串改过。
注意:
这个认证是存在一个安全隐患的,就是公钥的如果被公开后,只有持有公钥的人,都能够给去验证这个数据。无法保证公钥的持有者是谁的。
所以这种认证方式是不利于大规模传输公钥信息的。解决这个问题,那么就需要引用数字证书。
对数据进行密码变换成密文的过程
用于证明加密公钥的数字证书
用于证明签名公钥的数字证书
公开秘钥基础设施的简称。PKI为支持基于证书的公开秘钥算法计算的实现和运作的相关体系、组织、计算、操作和程序的集合。
PKI是一个服架构,需要支持大范围部署的基于公钥的技术,为证书颁发而推出的一系列软硬件措施、法律架构的支持。
CA和证书就是PKI其中的一部分。
其中CA类似于我们生活中的公安局,是一个受大家信任的第三方,它在一个网络中签名所有的公钥。
证书就类似于我们生活中的身份证,是一个被CA签名的文档,被绑定了名字和公钥。
身份证合不合法,是不是假的,过期没过期我们生活中可以去公安局要求出证明证实。在PKI系统中,我们的证书过期没过期,是不是伪造的,该不该信任它,我们就可以找CA帮鉴定。
是一种不能开工、由持有者秘密保管的数字签名,用于创建数字签名、解密报文或者相应的公开秘钥一起加密机要文件。
可以开工的数字秘钥,用于验证相应的私钥签名报文,也可以用来加密报文、文件、由相应的私钥解密。
实现密码运行功能的,相应独立的软件、硬件、固件或者组合
RSA是由Rivest、Shamir及Adelman所发明的一种公开秘钥加密算法,以数论的欧拉定律为基础,它的安全性依赖于大数的因数分解的困难性,算法长度越长,因数分解也就越困难。
X.509是ITU定制的X.500系列的目录标准的其中一个。它为公钥证书定义了一个框架。
The Public-Key Cryptography Standards (PKCS)是由美国RSA数据安全公司及其合作伙伴制定的一组公钥密码学标准,其中包括证书申请、证书更新、证书作废表发布、扩展证书内容以及数字签名、数字信封的格式等方面的一系列相关协议。
公钥加密标准(Public Key Cryptography Standards, PKCS),此一标准的设计与发布皆由RSA信息安全公司所制定。
RSA信息安全公司旗下的RSA实验室为了发扬公开密钥技术的使用,便发展了一系列的公开密钥密码编译标准。只不过,虽然该标准具有相当大的象征性,也被信息界的产业所认同;但是,若RSA公司认为有必要,这些标准的内容仍然可能会更动。所幸,这些变动并不大;此外,这几年RSA公司也与其他组织(比较知名的有IETF、PKIX)将标准的制定通过standards track程序来达成。
PKCS简介
到1999年底,PKCS已经公布了以下标准:
PKCS#1:定义RSA公开密钥算法加密和签名机制,主要用于组织PKCS#7中所描述的数字签名和数字信封[22]。
PKCS#3:定义Diffie-Hellman密钥交换协议。
PKCS#5:描述一种利用从口令派生出来的安全密钥加密字符串的方法。使用MD2或MD5 从口令中派生密钥,并采用DES-CBC模式加密。主要用于加密从一个计算机传送到另一个计算机的私人密钥,不能用于加密消息。
PKCS#6:描述了公钥证书的标准语法,主要描述X.509证书的扩展格式。
PKCS#7:定义一种通用的消息语法,包括数字签名和加密等用于增强的加密机制,PKCS#7与PEM兼容,所以不需其他密码操作,就可以将加密的消息转换成PEM消息,文件扩展名.p7b,.p7c。PKCS#7是一个封装数据的标准,在一个PKCS#7里边可以,可以放置一个用户证书和颁发机构的根证书链
PKCS#8:描述私有密钥信息格式,该信息包括公开密钥算法的私有密钥以及可选的属性集等。
PKCS#9:定义一些用于PKCS#6证书扩展、PKCS#7数字签名和PKCS#8私钥加密信息的属性类型。
PKCS#10:描述证书请求语法。文件扩展名.csr
PKCS#11:称为Cyptoki,定义了一套独立于技术的程序设计接口,用于智能卡和PCMCIA卡之类的加密设备。
PKCS#12:用于在一个单一文件中交换公共和私有对象,它包含证书和关联的私钥。它提供了一个加密的机制,因此私钥是能够被保护的。文件扩展名.p12,.pfx
PKCS#13:椭圆曲线密码体制标准。
PKCS#14:伪随机数生成标准。
PKCS#15:密码令牌信息格式标准。
在表格中展示如下:
PKCS标准汇总 | |||
---|---|---|---|
版本 | 名称 | 简介 | |
PKCS #1 | 2.1 | RSA密码编译标准(RSA Cryptography Standard) | 定义了RSA的数理基础、公/私钥格式,以及加/解密、签/验章的流程。1.5版本曾经遭到攻击。 |
PKCS #2 | - | 撤销 | 原本是用以规范RSA加密摘要的转换方式,现已被纳入PKCS#1之中。 |
PKCS #3 | 1.4 | DH密钥协议标准(Diffie-Hellman key agreement Standard) | 规范以DH密钥协议为基础的密钥协议标准。其功能,可以让两方通过金议协议,拟定一把会议密钥(Session key)。 |
PKCS #4 | - | 撤销 | 原本用以规范转换RSA密钥的流程。已被纳入PKCS#1之中。 |
PKCS #5 | 2.0 | 密码基植加密标准(Password-based Encryption Standard) | 参见RFC 2898与PBKDF2。 |
PKCS #6 | 1.5 | 证书扩展语法标准(Extended-Certificate Syntax Standard) | 将原本X.509的证书格式标准加以扩充。 |
PKCS #7 | 1.5 | 密码消息语法标准(Cryptographic Message Syntax Standard) | 参见RFC 2315。规范了以公开密钥基础设施(PKI)所产生之签名/密文之格式。其目的一样是为了拓展数字证书的应用。其中,包含了S/MIME与CMS。 |
PKCS #8 | 1.2 | 私钥消息表示标准(Private-Key Information Syntax Standard). | Apache读取证书私钥的标准。 |
PKCS #9 | 2.0 | 选择属性格式(Selected Attribute Types) | 定义PKCS#6、7、8、10的选择属性格式。 |
PKCS #10 | 1.7 | 证书申请标准(Certification Request Standard) | 参见RFC 2986。规范了向证书中心申请证书之CSR(certificate signing request)的格式。 |
[PKCS #11](https://baike.baidu.com/item/PKCS %2311) | 2.20 | 密码设备标准接口(Cryptographic Token Interface (Cryptoki)) | 定义了密码设备的应用程序接口(API)之规格。 |
PKCS #12 | 1.0 | 个人消息交换标准(Personal Information Exchange Syntax Standard) | 定义了包含私钥与公钥证书(public key certificate)的文件格式。私钥采密码(password)保护。常见的PFX就履行了PKCS#12。 |
PKCS #13 | – | 椭圆曲线密码学标准(Elliptic curve cryptography Standard) | 制定中。规范以椭圆曲线密码学为基础所发展之密码技术应用。椭圆曲线密码学是新的密码学技术,其强度与效率皆比现行以指数运算为基础之密码学算法来的优秀。然而,该算法的应用尚不普及。 |
PKCS #14 | – | 拟随机数产生器标准(Pseudo-random Number Generation) | 制定中。规范拟随机数产生器的使用与设计。 |
PKCS #15 | 1.1 | 密码设备消息格式标准(Cryptographic Token Information Format Standard) | 定义了密码设备内部数据的组织结构。 |
下面主要讲解PKCS #10、PKCS#7、PKCS#12
因为这个这种格式在使用中大家接触最多。
PKCS #10因为是用来申请请求申请证书用的一个种格式,所以通常情况下我们称为p10文件、证书请求等。一个p10文件就是xxx.csr.文件内容是使用base64编码的。如下:
-----BEGIN CERTIFICATE-----
MIIDXTCCAkWgAwIBAgIJAMsVsoNWvs+CMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV
BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX
aWRnaXRzIFB0eSBMdGQwHhcNMjAwNDA5MDYyOTUxWhcNMjEwNDA5MDYyOTUxWjBF
MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50
ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
CgKCAQEA7WZDMEU8x6ZOSYzTSWcdc33B4jKMaQvShI0iA3VH5qZ6a2en6rfAUkNg
+2HsPTmPK8n92MVTuCJCbASoV15ioUKQaWX4pur528hro8w1EDGxjsQB2V6yzj0v
yBbkj24HrnlCRmWPWy700ymp/26M/5XGFID6al0BJBhfK4cH4ltYiwFT7++/C/sZ
wfpWPooSBBCI1QdNbq3jQebD4NDaR2qQc6hNp+lSUWEpy8LrdqhwAtcvSjVt/iKp
rtor0cShNf8/BNiK5kK0SUae4u5yCItuHSLRZ4LdqOuJbAOhvRZJOrLL/LSjGB0P
zkW5TLMuuxYIgxEaC+gTIaYWBq2pOQIDAQABo1AwTjAdBgNVHQ4EFgQUHCzauL5m
m8t9E9Xg5wIFXF9YRH0wHwYDVR0jBBgwFoAUHCzauL5mm8t9E9Xg5wIFXF9YRH0w
DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAodSIPBRdss72qk/6CHwA
KmJZFSTQ85jsgOprIOWk7xWVU+Nqi2N/fPIAiuTwmT8FWxMcUpJCqm3J815BQtRp
W8NCfVJwBv0T3GpPVvczTn8KE9/I/VB8FZKjEIgk97gNGXzi+RIGkyfHnl9blfmr
YdQpYQ3Ezz993z8BzpEqgRAF0z0tXblapS7UudX+gs0pzQyEFuBmNQPmIjZBTK7P
TtbZQzbP0U7Vk9Q3kV0uxywynL8s7IQK7aLPqgu3TF0LKR319AtI9O+pBTJNc6/J
o5xhjai+2OYibVc2IrwVY9ge+/Vd+G3a+eqQ+g/sKZLu+tohTXrQnjdsS38lcGj/
8Q==
-----END CERTIFICATE-----
将上面的编码拷贝记事本,改为certReq.cer
就是一个p10文件了。
/**
* @author lyl
* @version 2020/5/14 0014 01:56:26
*/
public class P10Test {
public static CertificateRequest genCertificateRequest() {
try {
String signalg = "SHA256WithRSA";
int alglength = 2048;
String keyAlg = "RSA";
String o = "00276DF";
String ou = "SN_TEST_008";
String cn = o + "_" + ou;
X500NameBuilder x500NameBld = new X500NameBuilder(BCStyle.INSTANCE);
x500NameBld.addRDN(BCStyle.CN, cn);
x500NameBld.addRDN(BCStyle.C, "China");
x500NameBld.addRDN(BCStyle.ST, "Guangdong");
x500NameBld.addRDN(BCStyle.L, "Tianhe");
x500NameBld.addRDN(BCStyle.O, o);
x500NameBld.addRDN(BCStyle.OU, ou);
x500NameBld.addRDN(BCStyle.EmailAddress, "[email protected]");
X500Name subject = x500NameBld.build();
//秘钥对改为自己的,这里使用自动生成
KeyPairGenerator keyGen = KeyPairGenerator.getInstance(keyAlg);
keyGen.initialize(alglength);
KeyPair kp = keyGen.generateKeyPair();
PublicKey publicKey = kp.getPublic();
PrivateKey privateKey = kp.getPrivate();
PKCS10CertificationRequestBuilder builder = new PKCS10CertificationRequestBuilder(subject, SubjectPublicKeyInfo.getInstance(publicKey.getEncoded()));
JcaContentSignerBuilder jcaContentSignerBuilder = new JcaContentSignerBuilder(signalg);
ContentSigner contentSigner = jcaContentSignerBuilder.build(kp.getPrivate());
PKCS10CertificationRequest pkcs10 = builder.build(contentSigner);
String p10Str = Base64.getMimeEncoder().encodeToString(pkcs10.getEncoded());
String publicKeyStr = Base64.getMimeEncoder().encodeToString(publicKey.getEncoded());
String privateKeyStr = Base64.getMimeEncoder().encodeToString(privateKey.getEncoded());
return CertificateRequest.builder()
.p10Str(CertHelper.wrapP10(p10Str))
.publicKeyStr(CertHelper.wrapPublicKey(publicKeyStr))
.privateKeyStr(CertHelper.wrapPrivateKey(privateKeyStr))
.build();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
@Builder
@Data
static class CertificateRequest {
private String publicKeyStr;
private String privateKeyStr;
private String p10Str;
}
public static void main(String[] args) {
CertificateRequest certificateRequest = genCertificateRequest();
System.out.println(certificateRequest.getP10Str());
System.out.println(certificateRequest.getPrivateKeyStr());
System.out.println(certificateRequest.getPublicKeyStr());
}
}
参考我另外的一篇文章:https://blog.csdn.net/sumlyl/article/details/106445239
openssl req -in certReq.csr -text
显示内容如下:
Certificate Request: # 此为证书请求文件头
Data:
Version: 0 (0x0)
Subject: C=CN, ST=GD, O=DX # 此为提供的个人信息,注意左侧标头为"Subject",这是很重要的一项
Subject Public Key Info:
Public Key Algorithm: rsaEncryption # 使用的公钥算法
Public-Key: (2048 bit) # 公钥的长度
Modulus:
00:ed:66:43:30:45:3c:c7:a6:4e:49:8c:d3:49:67:
1d:73:7d:c1:e2:32:8c:69:0b:d2:84:8d:22:03:75:
47:e6:a6:7a:6b:67:a7:ea:b7:c0:52:43:60:fb:61:
ec:3d:39:8f:2b:c9:fd:d8:c5:53:b8:22:42:6c:04:
a8:57:5e:62:a1:42:90:69:65:f8:a6:ea:f9:db:c8:
6b:a3:cc:35:10:31:b1:8e:c4:01:d9:5e:b2:ce:3d:
2f:c8:16:e4:8f:6e:07:ae:79:42:46:65:8f:5b:2e:
f4:d3:29:a9:ff:6e:8c:ff:95:c6:14:80:fa:6a:5d:
01:24:18:5f:2b:87:07:e2:5b:58:8b:01:53:ef:ef:
bf:0b:fb:19:c1:fa:56:3e:8a:12:04:10:88:d5:07:
4d:6e:ad:e3:41:e6:c3:e0:d0:da:47:6a:90:73:a8:
4d:a7:e9:52:51:61:29:cb:c2:eb:76:a8:70:02:d7:
2f:4a:35:6d:fe:22:a9:ae:da:2b:d1:c4:a1:35:ff:
3f:04:d8:8a:e6:42:b4:49:46:9e:e2:ee:72:08:8b:
6e:1d:22:d1:67:82:dd:a8:eb:89:6c:03:a1:bd:16:
49:3a:b2:cb:fc:b4:a3:18:1d:0f:ce:45:b9:4c:b3:
2e:bb:16:08:83:11:1a:0b:e8:13:21:a6:16:06:ad:
a9:39
Exponent: 65537 (0x10001)
Attributes:
a0:00
Signature Algorithm: sha256WithRSAEncryption # 为请求文件数字签名时使用的算法
50:09:53:fa:f4:d3:95:e8:5b:df:6f:44:f2:24:94:d3:49:6f:
16:35:d5:a1:cf:53:1c:33:8c:8e:aa:b4:37:e0:1d:e6:92:7d:
77:71:a8:80:3c:18:b5:ac:cb:f0:cc:c8:10:e4:c3:dc:a2:09:
5d:ea:62:e5:0d:98:55:6a:43:5e:74:48:d8:13:15:38:05:6b:
56:ae:22:0a:d5:d3:e2:42:ca:e4:67:fa:5b:43:65:80:7a:0d:
1f:7b:e2:80:05:a5:df:6d:a6:59:c2:86:8b:c3:99:30:e3:77:
c2:2e:6b:25:3a:88:07:df:9a:7b:ca:d2:d2:26:dd:a4:80:ab:
cc:66:81:49:73:87:fc:e0:1a:9f:5f:92:e8:b5:01:45:e3:f0:
06:51:09:f3:73:64:af:87:fe:96:95:d5:24:fe:fb:bd:2a:9d:
58:65:30:f1:45:ad:b2:74:9c:b3:b8:5a:dd:1b:1c:bd:70:3f:
5f:88:d3:5b:1e:cd:49:04:a9:48:e7:44:36:0a:c1:75:9c:15:
66:b6:fd:00:ef:ff:3e:9e:83:bf:7d:16:67:4a:f7:f5:1c:c3:
51:6c:50:21:a3:1b:bd:83:c0:0d:24:d7:a8:4b:d4:38:c2:aa:
96:ae:0e:a8:3e:0e:af:5a:16:96:93:8d:9c:36:80:3d:8a:fe:
fc:e7:83:00
-----BEGIN CERTIFICATE REQUEST----- # 公钥
MIICijCCAXICAQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUx
ITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDCCASIwDQYJKoZIhvcN
AQEBBQADggEPADCCAQoCggEBAO1mQzBFPMemTkmM00lnHXN9weIyjGkL0oSNIgN1
R+amemtnp+q3wFJDYPth7D05jyvJ/djFU7giQmwEqFdeYqFCkGll+Kbq+dvIa6PM
NRAxsY7EAdless49L8gW5I9uB655QkZlj1su9NMpqf9ujP+VxhSA+mpdASQYXyuH
B+JbWIsBU+/vvwv7GcH6Vj6KEgQQiNUHTW6t40Hmw+DQ2kdqkHOoTafpUlFhKcvC
63aocALXL0o1bf4iqa7aK9HEoTX/PwTYiuZCtElGnuLucgiLbh0i0WeC3ajriWwD
ob0WSTqyy/y0oxgdD85FuUyzLrsWCIMRGgvoEyGmFgatqTkCAwEAAaAAMA0GCSqG
SIb3DQEBCwUAA4IBAQBQCVP69NOV6Fvfb0TyJJTTSW8WNdWhz1McM4yOqrQ34B3m
kn13caiAPBi1rMvwzMgQ5MPcogld6mLlDZhVakNedEjYExU4BWtWriIK1dPiQsrk
Z/pbQ2WAeg0fe+KABaXfbaZZwoaLw5kw43fCLmslOogH35p7ytLSJt2kgKvMZoFJ
c4f84BqfX5LotQFF4/AGUQnzc2Svh/6WldUk/vu9Kp1YZTDxRa2ydJyzuFrdGxy9
cD9fiNNbHs1JBKlI50Q2CsF1nBVmtv0A7/8+noO/fRZnSvf1HMNRbFAhoxu9g8AN
JNeoS9Q4wqqWrg6oPg6vWhaWk42cNoA9iv7854MA
-----END CERTIFICATE REQUEST-----
public static String getPublicKeyByP10() {
try {
//模拟读取PKCS10格式文件得到的数据
String p10str =
"-----BEGIN CERTIFICATE REQUEST-----\n" +
"MIIDBTCCAe0CAQAwejELMAkGA1UEBhMCQ04xCzAJBgNVBAgMAmdkMQswCQYDVQQH\n" +
"DAJnejELMAkGA1UECgwCY3QxDTALBgNVBAsMBFRlc3QxHzAdBgkqhkiG9w0BCQEW\n" +
"EHRlc3RAZXhhbXBsZS5jb20xFDASBgNVBAMMCzE5Mi4xNzguMS4xMIIBIjANBgkq\n" +
"hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA7WZDMEU8x6ZOSYzTSWcdc33B4jKMaQvS\n" +
"hI0iA3VH5qZ6a2en6rfAUkNg+2HsPTmPK8n92MVTuCJCbASoV15ioUKQaWX4pur5\n" +
"28hro8w1EDGxjsQB2V6yzj0vyBbkj24HrnlCRmWPWy700ymp/26M/5XGFID6al0B\n" +
"JBhfK4cH4ltYiwFT7++/C/sZwfpWPooSBBCI1QdNbq3jQebD4NDaR2qQc6hNp+lS\n" +
"UWEpy8LrdqhwAtcvSjVt/iKprtor0cShNf8/BNiK5kK0SUae4u5yCItuHSLRZ4Ld\n" +
"qOuJbAOhvRZJOrLL/LSjGB0PzkW5TLMuuxYIgxEaC+gTIaYWBq2pOQIDAQABoEYw\n" +
"RAYJKoZIhvcNAQkOMTcwNTAzBgNVHREELDAqghB0ZXN0LmV4YW1wbGUuY29tghB0\n" +
"ZXN0LmV4bWFwbGUubmV0hwTAsgEBMA0GCSqGSIb3DQEBCwUAA4IBAQCE0Gqeq+b9\n" +
"EnrhWbcpKzDwA84V+Ac3tUgJmMb5xSTNXw1ljk77NV9h4LAdzb7PH6OCZjsdWDwV\n" +
"duh1wav3Kvl4vlqfQUz1bBcqL9k4LKa2jfTtVRsr1PRJnAJVAukIS78c/lUjYBP7\n" +
"Duf27tsfDnFL1g1uGcPQvcSk5yEDMEp3KRGy+bjZvN13UTFqOm2BDQbS6xM9lJ4f\n" +
"dLkMOziEVNQd7gSiHgwuahcabsj2Vvqolrv8oB4DOIAZ4pEFE1buO9h8ROwDpUAA\n" +
"HHpMwjJvoLDXlcUSBtCPsgFXbxT0DqVBCDBZkEQoEKVKEZU94ATgszPXXiE97ZaI\n" +
"DXO6Cz0pk/nZ\n" +
"-----END CERTIFICATE REQUEST-----";
p10str = CertHelper.removeTagP10(p10str); -- 这个方法是为了把开始和结束标签去掉
//创建证书请求
PKCS10CertificationRequest pkcs10CertificationRequest = new PKCS10CertificationRequest(Base64.getMimeDecoder().decode(p10str));
System.out.println(pkcs10CertificationRequest.getSubject());
//获取公钥
SubjectPublicKeyInfo subjectPublicKeyInfo = pkcs10CertificationRequest.getSubjectPublicKeyInfo();
System.out.println(Base64.getMimeEncoder().encodeToString(subjectPublicKeyInfo.getEncoded()));
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
使用SCEP进行证书申请的时候,同时会使用PKCS#7和PKCS#10。PKCS#10对证书请求进行编码,PKCS#7对PKCS#10的请求内容,或者请求得到的证书进行封装。我做的项目是最请求得到的证书,对根证书链进行封装。
下面就是一个“xxx.p7b”文件。里面封装了2个根证书的证书链。
用于在一个单一文件中交换公共和私有对象,它包含证书和关联的私钥。它提供了一个加密的机制,因此私钥是能够被保护的。文件扩展名.p12,.pfx
下面是一段伪代码,但是大概意思就是这样吧。
/***
* 生成.JKS数字证书
* @param certInfo 证书详情
*/
public static void generateJKS(KeyStoreInfo certInfo) {
generateDigitalCert(
KEY_STORE_TYPE_JKS, SIGN_ALGORITHM_SHA256,
KEY_PAIR_ALGORITHM_RSA, SECURE_RANDOM_ALGORITHM,
SECURE_RANDOM_PROVIDER, certInfo.getAlias(),
certInfo.getKeyStorePass(), certInfo.getCertPass(),
certInfo.getCN(), certInfo.getOU(), certInfo.getO(),
certInfo.getL(), certInfo.getST(), certInfo.getC(),
certInfo.getStart(), certInfo.getValidityDays(),
certInfo.getPathAndFileName(), true
);
}
/***
* 创作CA根证书
* @param keyStoreType 秘钥库类型(jks、pkcs12)
* @param signAlgorithm 数字签名算法
* @param keyPairAlgorithm 秘钥对算法
* @param secureRandomAlgorithm 安全随机数算法(RNG算法的名称)
* @param secureRandomProvider 安全随机数算法提供者的名称
* @param alias 别名
* @param keyStorePass 秘钥库密码
* @param certPass 证书密码
* @param CN 证书拥有者通用名
* @param OU 组织单位名称
* @param O 组织名称
* @param L 城市或区域名称
* @param ST 州或省份名称
* @param C 国家名称
* @param start 证书有效期开始日期/时间
* @param validityDays 证书有效期天数
* @param pathAndFileName 文件路径
* @param createNew 是否创建新的
*/
public static void generateDigitalCert(String keyStoreType,
String signAlgorithm, String keyPairAlgorithm,
String secureRandomAlgorithm, String secureRandomProvider,
String alias, String keyStorePass, String certPass, String CN,
String OU, String O, String L, String ST, String C, Date start,
long validityDays, String pathAndFileName, boolean createNew) {
FileOutputStream out = null;
try {
//一个高强度的随机数发生器(RNG)
SecureRandom sr = SecureRandom.getInstance(secureRandomAlgorithm, secureRandomProvider);
//证书注册机,生成秘钥对。参数分别为秘钥对算法、签名算法
CertAndKeyGen cakg = new CertAndKeyGen(keyPairAlgorithm, signAlgorithm);
cakg.setRandom(sr);
//生成一对key参数为key的长度 对于RSA不能小于512
cakg.generate(2048);
//证书拥有者subject的描述name
X500Name subject = new X500Name("CN=" + CN + ",OU=" + OU + ",O=" + O + ",L=" + L + ",ST=" + ST + ",C=" + C);
//给证书配置扩展信息
// PublicKey publicKey = cakg.getPublicKey();
// PrivateKey privateKey = cakg.getPrivateKey();
// CertificateExtensions certExts = new CertificateExtensions();
// certExts.set("SubjectKeyIdentifier", new SubjectKeyIdentifierExtension((new KeyIdentifier(publicKey)).getIdentifier()));
// certExts.set("AuthorityKeyIdentifier", new AuthorityKeyIdentifierExtension(new KeyIdentifier(publicKey), null, null));
// certExts.set("BasicConstraints", new BasicConstraintsExtension(false,true,0));
// X509Certificate certificate = cakg.getSelfCertificate(subject, start, validityDays * 24L * 60L * 60L,certExts);
//配置证书的有效期,并生成根证书(自签名证书)
X509Certificate certificate = cakg.getSelfCertificate(subject, start, validityDays * 24L * 60L * 60L);
//创建KeyStore,存储证书
KeyStore outStore = KeyStore.getInstance(keyStoreType);
if (createNew) {
outStore.load(null, keyStorePass.toCharArray());
/**
*
* 将给定密钥(已经被保护)分配给给定别名。如果受保护密钥的类型为
* java.security.PrivateKey,则它必须附带证明相应公钥的证书链。
* 如果底层 keystore 实现的类型为jks,则必须根据 PKCS#8 标准中的定义将 key 编码为 EncryptedPrivateKeyInfo。
* 如果给定别名已经存在,则与别名关联的 keystore ,信息将被给定密钥(还可能包括证书链)重写。
* **/
outStore.setKeyEntry(alias, cakg.getPrivateKey(), certPass.toCharArray(), new Certificate[]{certificate});
} else {
//将新的证书加入到证书库
File f = new File(pathAndFileName);
if (!f.exists()) {
throw new FileNotFoundException("证书库文件不存在,不能把新的证书加入到证书库!!!!!!!");
}
FileInputStream fis = new FileInputStream(f);
outStore.load(fis, keyStorePass.toCharArray());
fis.close();
outStore.setKeyEntry(alias, cakg.getPrivateKey(), certPass.toCharArray(), new Certificate[]{certificate});
}
out = new FileOutputStream(pathAndFileName);
//将此 keystore 存储到给定输出流,并用给定密码保护其完整性。
outStore.store(out, keyStorePass.toCharArray());
} catch (NoSuchAlgorithmException | NoSuchProviderException | InvalidKeyException | IOException | CertificateException | SignatureException | KeyStoreException e) {
e.printStackTrace();
} finally {
try {
if (out != null) {
out.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
格式 : JKS
扩展名 : .jks/.ks
描述 : 【Java Keystore】密钥库的Java实现版本,provider为SUN
特点 : 密钥库和私钥用不同的密码进行保护
格式 : JCEKS
扩展名 : .jce
描述 : 【JCE Keystore】密钥库的JCE实现版本,provider为SUN JCE
特点 : 相对于JKS安全级别更高,保护Keystore私钥时采用TripleDES
格式 : PKCS12
扩展名 : .p12/.pfx
描述 : 【PKCS #12】个人信息交换语法标准
特点 : 1、包含私钥、公钥及其证书
2、密钥库和私钥用相同密码进行保护
格式 : BKS
扩展名 : .bks
描述 : Bouncycastle Keystore】密钥库的BC实现版本,provider为BC
特点 : 基于JCE实现
格式 : UBER
扩展名 : .ubr
描述 : 【Bouncycastle UBER Keystore】密钥库的BC更安全实现版本,provider为BC
格式 : DER
扩展名 : .cer/.crt/.rsa
描述 : 【ASN .1 DER】用于存放证书
特点 : 不含私钥、二进制
格式 : PKCS7
扩展名 : .p7b/.p7r
描述 : 【PKCS #7】加密信息语法标准
特点 : 1、p7b以树状展示证书链,不含私钥
2、p7r为CA对证书请求签名的回复,只能用于导入
格式 : CMS
扩展名 : .p7c/.p7m/.p7s
描述 : 【Cryptographic Message Syntax】
特点 : 1、p7c只保存证书
2、p7m:signature with enveloped data
3、p7s:时间戳签名文件
格式 : PEM
扩展名 : .pem
描述 : 【Printable Encoded Message】
特点 : 1、该编码格式在RFC1421中定义,其实PEM是【Privacy-Enhanced Mail】的简写,但他也同样广泛运用于密钥管理
2、ASCII文件
3、一般基于base 64编码
格式 : PKCS10
扩展名 : .p10/.csr
描述 : 【PKCS #10】公钥加密标准【Certificate Signing Request】
特点 : 1、证书签名请求文件
2、ASCII文件
3、CA签名后以p7r文件回复
格式 : SPC
扩展名 : .pvk/.spc
描述 : 【Software Publishing Certificate】
特点 : 微软公司特有的双证书文件格式,经常用于代码签名,其中
1、pvk用于保存私钥
2、spc用于保存公钥
1、部署证书服务(私有的,如果你用公钥的就不需要啦)
2、客户端产生秘钥对。每一个实体在申请证书之前,都需要预先产生RSA的秘钥对。
3、客户端产生证书请求文件。
4、向证书服务器提交证书请求。
5、CA证书服务器管理员审核证书请求,审核通过颁发生成个人证书同时附带一份根证书(公有的CA一般系统内置了)
6、客户端安装根证书。
7、客户端和客户端之间交换证书。交换证书,证明实体与公钥直接的关联,公钥的具体作用由运用来决定。
IKE是因特网秘钥交换协议。下图是一个IKE实例,讲解证书的在网络传输中的使用。数字签名是解决“数据完整性验证、源认证问题”。而证书在网络传输中主要是解决“公钥持有者是谁?我该不该信任它的问题。”所以引用了CA证书帮助做鉴定。
1、 发起方自己生成秘钥对(公钥和私钥),然后使用私钥生成P10证书请求。证书请求里面包含了公钥和证书持有者信息。
2、 发起方将证书请求发送给CA证书颁发机构(可以线上或者线下),CA证书颁发机构通过发起方提交的P10证书请求给发起方颁发个人证书。个人证书的内容就是包含了发起方的个人信息,发起方的公钥,证书服务器签名(使用CA证书颁发机构的私钥签的),同时也会另外附带一份根证书(自己下载或者离线给)。
3、 发起方和接收方约定好,大家都信任这个证书颁发机构,大家都安装这个CA证书颁发机构的根证书。根证书包含了CA个人信息,CA公钥,证书服务器签名(CA上一级机构给它签的)
4、 这样基础设施就搭建好,发起方开始给接收方发送信息。
5、 发起方将明文的数据,如公钥、其他收发方都知道的内容,协商好的策略内容等,通过将内容封装,使用协商好的散列码算法生成散列码1.
6、 发起方再使用私钥加密散列码1,形成数字签名。
7、 发起方将数字签名、发起方个人证书、Hostname、Header等封装成请求包发送给接收方。
8、 接收方接收到信息包,首先在请求包中提取发起方的个人证书,同时加载本地安装的CA根证书。
9、 接收方提取CA根证书中的CA公钥,同时提取发起方个人证书的证书服务器签名,使用CA公钥去解密证书服务器签名,得到CA散列值1.然后再将发起方个人证书的个人信息和公钥等等其他公开信息封装,使用CA指定的散列码算法,生成散列码2
10、将CA散列码1和CA散列码2进行对比,如果相同,则就认为这个证书持有者是合法的,不是伪造的证书。
注意:流程9、10实际上这个验证过程有专门的类。CA散列值也不需要自己生成,直接把发起方个人证书和根证书链放进去就可以了。
参考:
java.security.cert.CertPathValidator
里面的
CertPathValidator.getInstance("SHA256withRSA").validate(CertPath certPath,CertPathParameters params)
11、 接收方接下来再在发起方个人证书提取证书的有效期,判定是否还有效。再去证书吊销列表看,该证书是否已经被吊销等等。如果都没有问题,则认为该证书是有效的。
22、 接收方从发起方个人证书中提取公钥,使用公钥解密发起方的数字签名,取得发起方封装的散列码1,接收方再使用公钥、其他收发方都知道的内容,协商好的策略内容等,将内容封装,使用协商好的散列码算法生成散列码2
13、将散列码1和散列码2进行对比,如果匹配,那么数据完整性验证、源认证问题,就可以认为这个请求是可信合法的。