Java密码学 - 11.生成自签证书和签名证书

  1. 代码片段 Snippet
    1. 自签证书
    2. 非自签发证书 (签名证书)
    3. 双证书
    4. 延申

根证书是自签名的证书。本文介绍如何生成自签证书和签名证书。


代码片段 Snippet

自签证书

1
2
3
4
5
//sun.security.x509的自签名。
//CertAndKeyGen包含KeyPairGenerator类。
CertAndKeyGen gen = new CertAndKeyGen("RSA", "SHA1WithRSA");
gen.generate(1024);//generate private key for sign cert
X509Certificate cert = gen.getSelfCertificate(new X500Name("CN=caliburn"), (long) 50 * 365 * 24 * 3600);


非自签发证书 (签名证书)

非自签发证书,即需要申请证书。所以 需要发个request。

client端

1
2
3
4
5
6
GenerateKeys gk = new GenerateKeys(1024);//构造公钥和私钥
PKCS10CertificationRequestBuilder p10Builder = new JcaPKCS10CertificationRequestBuilder(
      new X500Principal("CN=Requested Test Certificate"), gk.getPublicKey());//CN和公钥
JcaContentSignerBuilder csBuilder = new JcaContentSignerBuilder("SHA256withRSA");//签名算法
ContentSigner signer = csBuilder.build(gk.getPrivateKey());//私钥签名
PKCS10CertificationRequest csr = p10Builder.build(signer);

这里生成的私钥需自己保存好,放到keystore或者文件中。


CA端 (sever端):

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
PKCS10CertificationRequest csr = ...;//获取申请

/*获取CA端的自证书, 用于构造信息, 这里需要注意, 我们要构造的是BC的X.509证书, 因为这个代码环境都是BC, 用java.security的证书类是不能操作的
*/
CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
		X509Certificate cacert = (X509Certificate) certFactory.generateCertificate(
				FileUtils.openInputStream(new File("project/4d/sever/rootcer.pem")));


//一大堆参数 ,填充到生成器里
AlgorithmIdentifier sigAlgId = new DefaultSignatureAlgorithmIdentifierFinder().find("SHA1withRSA");
		AlgorithmIdentifier digAlgId = new DefaultDigestAlgorithmIdentifierFinder().find(sigAlgId);
		org.bouncycastle.asn1.x500.X500Name issuer = new org.bouncycastle.asn1.x500.X500Name(cacert.getSubjectX500Principal().getName());
		BigInteger serial = new BigInteger(32, new SecureRandom());
		Date from = new Date();
		Date to = new Date(System.currentTimeMillis() + (365 * 80 * 86400000L));
		DigestCalculator digCalc = new BcDigestCalculatorProvider().get(new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1));
		X509v3CertificateBuilder certgen = new X509v3CertificateBuilder(issuer, serial, from, to, csr.getSubject(), csr.getSubjectPublicKeyInfo());
	
		
		//CA端进行签名, 才有具有法律效力
		ContentSigner signer = new BcRSAContentSignerBuilder(sigAlgId, digAlgId).build(PrivateKeyFactory.createKey(CA的私钥.getEncoded()));

		//生成BC结构的证书
		Security.addProvider(new BouncyCastleProvider());
		X509Certificate bc = new JcaX509CertificateConverter().setProvider("BC").getCertificate(certgen.build(signer));
		//最终生成的是java.security的证书



双证书

我国使用的是双证书,即,需添加一个加密证书。

过程:

1
2
3
4
5
1. 生成公钥A和私钥A
2. 从reques或刚刚生成签名证书里取相关信息( 公钥B和其他信息 )
3. 生成对称密钥C,用于加密私钥A。
4. 公钥B加密该对称密钥C
5. 共同放进一个自定义的协议ASN1Object

参考PPT:https://wenku.baidu.com/view/89796e20524de518974b7d60.html


从request获取公钥

先看request的ASN.1结构

RFC 2986 - PKCS #10: Certification Request Syntax

1
2
3
4
5
6
7
8
9
10
11
   CertificationRequestInfo ::= SEQUENCE {
        version       INTEGER { v1(0) } (v1,...),
        subject       Name,
        subjectPKInfo SubjectPublicKeyInfo,
        attributes    [0] Attributes
   }

   SubjectPublicKeyInfo { ALGORITHM : IOSet} ::= SEQUENCE {
        algorithm        AlgorithmIdentifier ,
        subjectPublicKey BIT STRING
   }

X.509格式则为 (X.509为证书公钥的结构)

1
2
3
 SubjectPublicKeyInfo ::= SEQUENCE {
   algorithm AlgorithmIdentifier,
   subjectPublicKey BIT STRING }

于是乎, 我们就明白编码结构为X.509 (除此以为, 还有PKCS#1结构, 该结构对应的是AlgorithmIdentifier, 可以通过该结构, 将X.509转换成PKCS#1)

所以,我们先获取该结构的字节码,再转换成X509类型, 最后通过工厂类进行操作即可

1
2
3
PKCS10CertificationRequest csr=...;
X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(csr.getSubjectPublicKeyInfo().toASN1Primitive().getEncoded());
PublicKey Signedpk =KeyFactory.getInstance("RSA").generatePublic(x509EncodedKeySpec);

笔者之前也说过, JCA(这里是BC)和JCE(Java自身的)之前的转换, 是通过Jca开头的类来转换

1
2
3
PKCS10CertificationRequest csr=...;
JcaPKCS10CertificationRequest jcaPKCS10CertificationRequest = new JcaPKCS10CertificationRequest(csr);
PublicKey Signedpk = jcaPKCS10CertificationRequest.getPublicKey();


延申

也可以通过转换成PKCS#1的结构,再进行提取(不建议)

1
2
3
4
5
PKCS10CertificationRequest csr=...

RSAKeyParameters rsa = (RSAKeyParameters) PublicKeyFactory.createKey(csr.getSubjectPublicKeyInfo());
RSAPublicKeySpec rsaSpec = new RSAPublicKeySpec(rsa.getModulus(), rsa.getExponent());
PublicKey Signedpk = KeyFactory.getInstance("RSA").generatePublic(rsaSpec);