前幾次我已經基本上把如何做CA所需要的基礎知識講得差不多了,今天直接講如何用Java程序來實現一個CA應該就不是什么太困難的事情了.
要做CA,第一步要準備好自己的證書和私鑰.私鑰如何從文件里面讀取出來前面已經講過了.從文件系統中讀出證書的代碼如下:
CertificateFactory certCF = CertificateFactory.getInstance("X.509");
X509Certificate caCert = certCF.generateCertificate(certBIS);
這里cerBIS是一個InputStream類型的對象.例如一個標準的X509v3格式的證書文件所形成的輸入流.
第二步就是從用戶那里獲取輸入,然后構造主體名稱結構DN,如何構造DN上次已經說過了,如何從用戶那里獲取輸入,這個不在本文討論范圍之內.
下一步就是獲取用戶的公鑰,好和他所需要的證書對應起來.也有不少CA的做法就是在這里替用戶現場生成一對密鑰對,然后把公鑰放到證書中簽發給用戶.這個應該看實際需要選擇合適的方式.
現在一切信息都已經準備好了,可以簽發證書了,下面的代碼說明了這個過程:
//構造一個證書生成器對象
X509V3CertificateGenerator certGen = new X509V3CertificateGenerator();
// 從CA的證書中獲取簽發者的主體名稱(DN)
// 這里有一點小技巧,我們要把JCE中定義的
// 用來表示DN的對象X500Principal轉化成在
// BC Provider中的相應的對象X509Name
// 先從CA的證書中讀取出CA的DN進行DER編碼
DERInputStream dnStream =
new DERInputStream(
new ByteArrayInputStream(
caCert.getSubjectX500Principal().
getEncoded()));
// 馬上又從編碼后的字節流中讀取DER編碼對象
DERConstructedSequence dnSequence =
(DERConstructedSequence)dnStream.readObject();
// 利用讀取出來的DER編碼對象創建X509Name
// 對象,并設置為證書生成器中的"簽發者DN"
certGen.setIssuerDN(new X509Name(dnSequence));
// 設置好證書生成器中的"接收方DN"
certGen.setSubjectDN(subjectDN);
// 設置好一些擴展字段,包括簽發者和
// 接收者的公鑰標識
certGen.addExtension(X509Extensions.SubjectKeyIdentifier, false,
createSubjectKeyId(keyToCertify));
certGen.addExtension(X509Extensions.AuthorityKeyIdentifier, false,
createAuthorityKeyId(caCert.getPublicKey()));
// 設置證書的有效期和序列號
certGen.setNotBefore(startDate);
certGen.setNotAfter(endDate);
certGen.setSerialNumber(serialNumber);
// 設置簽名算法,本例中使用MD5hash后RSA
// 簽名,并且設置好主體的公鑰
certGen.setSignatureAlgorithm("MD5withRSA");
certGen.setPublicKey(keyToCertify);
// 如果以上一切都正常地話,就可以生成證書了
X509Certificate cert = null;
cert = certGen.generateX509Certificate(caPrivateKey);
這里是上面用到的生成簽發者公鑰標識的函數:
protected AuthorityKeyIdentifier createAuthorityKeyId(PublicKey pubKey)
{
AuthorityKeyIdentifier authKeyId = null;
try
{
ByteArrayInputStream bIn = new ByteArrayInputStream(pubKey.getEncoded());
SubjectPublicKeyInfo info = new SubjectPublicKeyInfo(
(DERConstructedSequence)new DERInputStream(bIn).readObject());
authKeyId = new AuthorityKeyIdentifier(info);
}
catch (IOException e)
{
System.err.println("Error generating SubjectKeyIdentifier: " +
e.toString());
System.exit(1);
}
return authKeyId;
}
生成主體公鑰標識的函數和上面的類似,把AuthorityKeyIdentifier替換成SubjectKeyIdentifier就可以了.
這里要注意的是,CA的公鑰也是在一份證書里,這種證書的特點是簽發者DN和接收者DN一樣,也就是說,這種證書是CA自己給自己頒發的證書,也就是"自
簽名證書",它上面的公鑰是CA自身的公鑰,用來簽名的私鑰就是該公鑰對應的私鑰.一般每個CA都要有這么一份證書,除非該CA不是根CA,即它的權威性
不是由它自己證明,而是由它的上級CA證明.但是,最后總歸要有一個根CA,它為各個安全應用程序的用戶所信賴.
到這里我們已經把CA最基本的功能如何用Java實現講完了,下一次講如何從PKCS#10格式證書請求文件中讀取出用戶信息,然后直接簽發公鑰.