ROOT证书、CA证书和使用CA签发的X.509证书
简介
日常开发中,我们程序员不怎么会接触证书相关的问题,对信息安全领域相关的内容知之甚少。因为平时主要实现的业务很少要直接面向底层的通信,也就很少关注这证书这样的知识。在一般情况下,我们仅仅只是在使用一些高层的依赖中会引入证书、加密相关的依赖包,比如:
<!-- https://mvnrepository.com/artifact/org.bouncycastle/bcprov-jdk15on -->
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.58</version>
</dependency>
然而, bouncy castle这样广泛使用证书密码项目(Github)并不是广受关注的明星项目,文档也就不怎么完备,甚至有点儿法语焉不详,不够系统完整。而且,这方面的内容包含了很多密码学方面专业名词,文档读起来就更晦涩难懂。可以参与bouncy castle的WIKI。我将大致的列举一下BC在证书方面的使用方法。
概念
ROOT证书、CA证书和使用CA证签发的X.509证书之间的联系,其实就是一个使用私钥签发(issue)的关系。使用ROOT证书的私钥签发CA证书,再使用CA证书签发其他的X.509证书,这样就形成了一条可以信的Path。在被签发的证书中含有使用签发者使用自己私钥加过密的签名(sign)、签名算法(比如Sha256WithHash)以及签名者的一些身份信息,这个我们可以在验证签名的过程中得过启发。
从上面可以看出,我们可以把一个证书主要分为两类:自签名和Ca签名,并且我在上面提到的证书中只有ROOT的是自签名的。
使用Bouncy Castle
生成一个签名证书
ROOT证书是用来签发和验证CA证书的,在整个可信证书链条中处于最上层的地位,它是一个自签名的证书。签名的作用是防止在不知道签名者私钥的情况下恶意篡改证书的内容,这是证书可信保证重要的步骤。如下代码是生成一个签名的证书:
// must add BC Provider before use it in code
Security.addProvider(new BouncyCastleProvider());
// generate EC key pair
ECGenParameterSpec ecGenSpec = new ECGenParameterSpec("prime192v1");
KeyPairGenerator generator = KeyPairGenerator.getInstance("ECDSA", "BC");
generator.initialize(ecGenSpec, new SecureRandom());
KeyPair kp = generator.genKeyPair();
Date startDate = new Date(System.currentTimeMillis() - 24 * 60 * 60 * 1000);
Date endDate = new Date(System.currentTimeMillis() + 365 * 24 * 60 * 60 * 1000);
// create x.509 certificate build
X509v3CertificateBuilder v3CertGen = new JcaX509v3CertificateBuilder(
new X500Principal("CN=Test"),
BigInteger.valueOf(System.currentTimeMillis()),
startDate, endDate,
new X500Principal("CN=Test"),
kp.getPublic());
// Content Signer
ContentSigner signer = new JcaContentSignerBuilder("SHA256withECDSA")
.setProvider("BC").build(kp.getPrivate());
// build x.509 certificate
X509CertificateHolder holder = v3CertGen.build(signer);
X509Certificate cert = new JcaX509CertificateConverter().getCertificate(holder