在本文中,我將討論使用 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 執行的操做。