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