在本文中,我将讨论使用 bouncy castle API 在 java 程序中建立 SSL 证书。 Bouncy castle 是一种轻量级加密 API。它是 Java Cryptography Extension(JCE)和 Java Cryptography Architecture(JCA)的实现。java
我将建立很是基本的证书,其中只包含必要的属性。您能够浏览 API 以获取可应用于证书的更多操做和属性git
请在代码中导入如下依赖项。算法
<!-- https://mvnrepository.com/artifact/org.bouncycastle/bcpkix-jdk15on -->
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-jdk15on</artifactId>
<version>1.55</version>
</dependency>
<!-- https://mvnrepository.com/artifact/joda-time/joda-time -->
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<version>2.9.4</version>
</dependency>
复制代码
我在代码中执行如下步骤: 步骤: 1)建立自签名根证书。 2)建立在步骤 1 中建立的根证书签名的中间证书. 3)建立在步骤 2 中建立的中间证书签名的最终用户证书。浏览器
代码:dom
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x509.BasicConstraints;
import org.bouncycastle.asn1.x509.Extension;
import org.bouncycastle.asn1.x509.KeyUsage;
import org.bouncycastle.cert.X509v3CertificateBuilder;
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.operator.OperatorCreationException;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
import org.joda.time.DateTime;
import java.io.FileOutputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.security.*;
import java.security.cert.CertificateEncodingException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Random;
public class App {
public static void main(String[] args) throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException, OperatorCreationException, InvalidKeyException, NoSuchProviderException, SignatureException, UnrecoverableKeyException {
Security.addProvider(new BouncyCastleProvider());
// Create self signed Root CA certificate
KeyPair rootCAKeyPair = generateKeyPair();
X509v3CertificateBuilder builder = new JcaX509v3CertificateBuilder(
new X500Name("CN=rootCA"), // issuer authority
BigInteger.valueOf(new Random().nextInt()), //serial number of certificate
DateTime.now().toDate(), // start of validity
new DateTime(2025, 12, 31, 0, 0, 0, 0).toDate(), //end of certificate validity
new X500Name("CN=rootCA"), // subject name of certificate
rootCAKeyPair.getPublic()); // public key of certificate
// key usage restrictions
builder.addExtension(Extension.keyUsage, true, new KeyUsage(KeyUsage.keyCertSign));
builder.addExtension(Extension.basicConstraints, false, new BasicConstraints(true));
X509Certificate rootCA = new JcaX509CertificateConverter().getCertificate(builder
.build(new JcaContentSignerBuilder("SHA256withRSA").setProvider("BC").
build(rootCAKeyPair.getPrivate()))); // private key of signing authority , here it is self signed
saveToFile(rootCA, "D:\\rootCA.cer");
//create Intermediate CA cert signed by Root CA
KeyPair intermedCAKeyPair = generateKeyPair();
builder = new JcaX509v3CertificateBuilder(
rootCA, // here rootCA is issuer authority
BigInteger.valueOf(new Random().nextInt()), DateTime.now().toDate(),
new DateTime(2025, 12, 31, 0, 0, 0, 0).toDate(),
new X500Name("CN=IntermedCA"), intermedCAKeyPair.getPublic());
builder.addExtension(Extension.keyUsage, true, new KeyUsage(KeyUsage.keyCertSign));
builder.addExtension(Extension.basicConstraints, false, new BasicConstraints(true));
X509Certificate intermedCA = new JcaX509CertificateConverter().getCertificate(builder
.build(new JcaContentSignerBuilder("SHA256withRSA").setProvider("BC").
build(rootCAKeyPair.getPrivate())));// private key of signing authority , here it is signed by rootCA
saveToFile(intermedCA, "D:\\intermedCA.cer");
//create end user cert signed by Intermediate CA
KeyPair endUserCertKeyPair = generateKeyPair();
builder = new JcaX509v3CertificateBuilder(
intermedCA, //here intermedCA is issuer authority
BigInteger.valueOf(new Random().nextInt()), DateTime.now().toDate(),
new DateTime(2025, 12, 31, 0, 0, 0, 0).toDate(),
new X500Name("CN=endUserCert"), endUserCertKeyPair.getPublic());
builder.addExtension(Extension.keyUsage, true, new KeyUsage(KeyUsage.digitalSignature));
builder.addExtension(Extension.basicConstraints, false, new BasicConstraints(false));
X509Certificate endUserCert = new JcaX509CertificateConverter().getCertificate(builder
.build(new JcaContentSignerBuilder("SHA256withRSA").setProvider("BC").
build(intermedCAKeyPair.getPrivate())));// private key of signing authority , here it is signed by intermedCA
saveToFile(endUserCert, "D:\\endUserCert.cer");
}
private static KeyPair generateKeyPair() throws NoSuchAlgorithmException, NoSuchProviderException {
KeyPairGenerator kpGen = KeyPairGenerator.getInstance("RSA", "BC");
kpGen.initialize(2048, new SecureRandom());
return kpGen.generateKeyPair();
}
private static void saveToFile(X509Certificate certificate, String filePath) throws IOException, CertificateEncodingException {
FileOutputStream fileOutputStream = new FileOutputStream(filePath);
fileOutputStream.write(certificate.getEncoded());
fileOutputStream.flush();
fileOutputStream.close();
}
}
复制代码
在这里你能够看到,对于 rootCA,我使用本身的私钥来签署证书。对于 intermedCA,我使用 rootCA 私钥进行签名。对于最终用户证书,我使用 IntermedCA 私钥进行签名。 在现实生活中,您还能够看到与此相似的证书链。从浏览器打开任何 HTTPS 链接证书,并观察证书链和每一个证书的属性。ide
“SHA256withRSA”是我用它来签名证书的签名算法。 在 keyUsage 中,“keyCertSign”仅限制证书使用以签署其余证书。虽然 SSL 客户端须要“digitalSignature”使用,但咱们的 Web 浏览器使用该证书进行实体身份验证和数据源身份验证的完整性。工具
BasicConstraints 中的“true”标志将证书标记为能够签署其余证书的 CA 证书。“false”标志将证书标记为证书链的最终实体。ui
做为此程序的出现,您将在指定的文件路径中拥有 3 个证书。加密
如今首先打开 rootCA:spa
您能够看到证书不可信的消息。所以,咱们将此证书添加到受信任的根证书存储区中
1)单击“安装证书”按钮。 2)选择“本地计算机”,单击下一步 3)选择“将全部证书放在如下存储中”的第二个选项 4)浏览并选择“受信任的根证书颁发机构” 5)单击“下一步”,而后单击“完成”。 6)导入成功。
对于“Intermed CA”证书执行相同的操做,仅在步骤 4 中进行更改:浏览并选择“中间证书颁发机构”。
如今关闭证书并从新打开它。 让咱们如今检查每一个证书:
还有其余方法能够建立证书和证书链。例如:java“keytool”命令或使用“keystore explorer”之类的工具.... 但不少时候你必须从程序中进行证书操做。 因此这在当时会很是有用。
在下一篇文章中,我将更多地介绍证书的主题以及您可使用 java 程序中的 bouncy castle 执行的操做。