/*
* <p>Title: </p>
*
* <p>Description: </p>
*
* <p>Copyright: Copyright (c) 2007</p>
*
* <p>Company: </p>
*
* @author ifwater
* @version 1.0
*/
/*CA簽發數位憑證應該使用自己的私密金鑰,CA自身的認證並不包含私密金鑰的資訊,因此需要從密鑰庫mykeystore中提取。此外,由於被簽發的認證還需要知道CA的名字,這可以從XA認證中獲得。簽發認證實際上是一個建立了一個新的認證,在這裡,使用的是I2SDK內部使用的sun.security.x509包中建立的X509CertImpl類來建立新的認證,該類的構造器中傳入有關的新的認證各種資訊,主要資訊來自被簽發的if.cer,只是對某些必須修改的資訊如序號、有效期間、簽發者等進行重新設定。最後使用X509CertImpl類的sign()方法用CA的私密金鑰進行簽名。可以列印新的認證的資訊,也可以將其儲存在密鑰庫中。*/
import java.io.*;
import java.security.*;
import java.security.cert.*;
import java.util.*;
import java.math.*;
import sun.security.x509.*;
public class SignCert {
public static void main(String args[]) throws Exception{
char[] storepass="wshn.ut".toCharArray();
char[] cakeypass="wshn.ut".toCharArray();
String alias="mytest";
String name="mykeystore";
//Cert of CA從密鑰庫讀取CA的認證
//這裡的name的值為“mykeystore”,alias的值為“mytest”
FileInputStream in=new FileInputStream(name);
KeyStore ks=KeyStore.getInstance("JKS");
ks.load(in,storepass);
java.security.cert.Certificate cl=ks.getCertificate(alias);
//從密鑰庫讀取CA的私密金鑰
//執行KeyStore對象的getKey()方法,擷取其參數對應的條目的私密金鑰,保護私密金鑰的口令也通過方法的參數傳入
PrivateKey caprk=(PrivateKey)ks.getKey(alias,cakeypass);
in.close();
//從CA的認證中提取簽發者的資訊
//首先提取CA認證的編碼,然後用該編碼建立X509CerImpl類型的對象,通過該對象的get()方法擷取X509CerInfo類型的對象,該對象封裝的全部內容,最後通過該對象的get()方法獲得X509Name類型的簽發者資訊
byte[] encoal=cl.getEncoded();
X509CertImpl cimpl=new X509CertImpl(encoal);
X509CertInfo cinfol=(X509CertInfo)cimpl.get(X509CertImpl.NAME+"."+X509CertImpl.INFO);
X500Name issuer=(X500Name)cinfol.get(X509CertInfo.SUBJECT+"."+CertificateIssuerName.DN_NAME);
//擷取待簽發的認證
CertificateFactory of=CertificateFactory.getInstance("X.509");
FileInputStream in2=new FileInputStream(args[0]);
java.security.cert.Certificate c2=of.generateCertificate(in2);
//從待簽發的數位憑證提取認證的資訊
//先提取待簽發者的認證編碼,然後建立X509CertImpl類型的對象,最後通過該對象的get()方法擷取X509CertInfo類型的對象,以後就可以使用該對象建立新的認證了
byte[] encod2=c2.getEncoded();
X509CertImpl cimp2 =new X509CertImpl(encod2);
X509CertInfo cinfo2=(X509CertInfo)cimp2.get(X509CertImpl.NAME+"."+X509CertImpl.INFO);
//設定新認證有效期間
//新認證的開始生效時間是從簽發之時開始,因此首先使用new Date()擷取但是時間。
//認證有效時間為15分鐘
//同過兩個日期建立CertificateValidity類型的對象,並且把它作為參數傳遞給上一步得到X509CertInfo對象的set()方法已設定有效期間
Date begindate=new Date();
Date enddate=new Date(begindate.getTime()+15*60*1000L);
CertificateValidity cv=new CertificateValidity(begindate,enddate);
cinfo2.set(X509CertInfo.VALIDITY,cv);
//設定新認證序號。每個認證都有唯一的一個序號。這裡以目前時間(以秒為單位)為序號,建立CertificateSerialNumber對象,並作為參數傳遞給X509CertInfo對象的set()方法以設定序號
int sn=(int)(begindate.getTime()/1000);
CertificateSerialNumber csn=new CertificateSerialNumber(sn);
cinfo2.set(X509CertInfo.SERIAL_NUMBER,csn);
//設定新認證的簽發者。執行X509CertInfo對象的set()方法設定簽發者,傳入參數即從CA的認證中提取的簽發者資訊
cinfo2.set(X509CertInfo.ISSUER+"."+CertificateIssuerName.DN_NAME,issuer);
//設定新認證的簽名演算法資訊
//首先產生AlgorithmId類型的對象,在其構造器中指定CA簽名該認證所使用的演算法為md5WithRSA,然後將其作為參數傳遞給X509CertInfo對象的set()方法以設定簽名演算法資訊
AlgorithmId alogorithm=new AlgorithmId(AlgorithmId.md2WithRSAEncryption_oid);
cinfo2.set(CertificateAlgorithmId.NAME+"."+CertificateAlgorithmId.ALGORITHM,algoritbm);
//建立認證並使用CA的私密金鑰對其簽名
//X509CertImpl是X509認證的底層實現,將待簽發的認證資訊傳遞給其構造器,將得到新的認證,執行其sign()方法,將使用CA
X509CertImpl newcert=new X509CertImpl(cinfo2);
newcert.sign(caprk,"MDSWithRSA");
//將新的認證存入密鑰庫
ks.setCertificateEntry("if_signed",newcert);
/*
snivateKey prk=(Frivatekey)ks.getkey("Lf","wishnout".toCharArray);
java.security.cert.Certificate[] conai=(new cert);
ks.setKeyEntry("if_signed,prk","newpass",oCharArray(),conain);
*/
FileOutputStream out=new FileOutputStream("newstore");
ks.store(out,"newpass".toCharArray());
out.close();
};
}