这一次主要记录一下PKI证书是如何生成的,以及如何从证书库中导出证书

1.使用keytool生成根CA自签名证书

#KeyTool是JDK自带的一个证书相关的工具
#-genkey 产生证书
#-alias 证书别名
#-keyStore 证书库路径
#-ketalg 密钥算法
#-keysize 密钥长度
#-validity 证书有效期
keytool -genkey -alias root -keyStore identity.jks -Keyalg RSA -keysize 1024 -validity 3650

2.为注册用户生成根CA签名的证书

/*
 *先指定根CA的X500Name
 *X500Name:X.500 names are used to identify entities,
 *         such as those which are identified by X.509 certificates.
 *然后从密钥库中取得根CA的私钥,用于对证书签名
 */
X500Name x500Name = new X500Name("CN=root, OU=UESTC, O=UESTC, L=Chengdu, ST=Sichuan, C=CN");
KeyStore ks = KeyStore.getInstance("JKS");
FileInputStream in = new FileInputStream("E:/workspace/CurriculumDesign/src/main/resources/identity.jks");
String storePass = "123456";
ks.load(in, storePass.toCharArray());
PrivateKey pk = (PrivateKey) ks.getKey("root", storePass.toCharArray());
in.close();

接下去为用户生成证书,并签名

/*
 *先为用户生成公私钥对:username为用户名
 *然后指定X509证书中的相关信息,包括:
 *		1.证书版本号
 *		2.证书序列号
 *		3.证书签名算法
 *		4.证书使用者
 *		5.证书使用者公钥
 *		6.证书有效期
 *		7.证书颁发者
 *		8.证书签名
 *将证书存入到证书库中
 */
KeyPairGenerator kg = KeyPairGenerator.getInstance("RSA");
kg.initialize(1024, new SecureRandom());  
KeyPair keyPair = kg.generateKeyPair();

String name = "CN=" + username +", OU=UESTC, O=UESTC, L=Chengdu, ST=Sichuan, C=CN";
X500Name owner = new X500Name(name);
X509CertInfo x509CertInfo = new X509CertInfo();
x509CertInfo.set(X509CertInfo.VERSION, new CertificateVersion(1));
x509CertInfo.set(X509CertInfo.SERIAL_NUMBER, new CertificateSerialNumber((int) (System.currentTimeMillis() / 1000L)));
Signature signature = Signature.getInstance("MD5WithRSA"); 
X500Signer signer = new X500Signer(signature, x500Name);
AlgorithmId algorithmId = signer.getAlgorithmId();
x509CertInfo.set(X509CertInfo.ALGORITHM_ID, new CertificateAlgorithmId(algorithmId));
x509CertInfo.set(X509CertInfo.SUBJECT, new CertificateSubjectName(owner));
x509CertInfo.set(X509CertInfo.KEY, new CertificateX509Key(keyPair.getPublic()));
CertificateValidity interval = new CertificateValidity(new Date(), new Date(System.currentTimeMillis() + 365000000000L));
x509CertInfo.set(X509CertInfo.VALIDITY, interval);
x509CertInfo.set(X509CertInfo.ISSUER, new CertificateIssuerName(signer.getSigner()));
X509CertImpl x509CertImpl = new X509CertImpl(x509CertInfo);
x509CertImpl.sign(pk, "MD5WithRSA");

KeyStore ks = KeyStore.getInstance("JKS");
FileInputStream in = new FileInputStream("E:/workspace/CurriculumDesign/src/main/resources/identity.jks");
String storePass = "123456";
ks.load(in, storePass.toCharArray());
in.close();

ks.setCertificateEntry(username,x509CertImpl);
FileOutputStream out = new FileOutputStream(new File("E:/workspace/CurriculumDesign/src/main/resources/identity.jks"));
ks.store(out, storePass.toCharArray());
out.close();

3.证书导出

/*
 *从证书库中导出用户的证书文件:username为用户名
 */
String storePass = "123456";
KeyStore ks = KeyStore.getInstance("JKS");
FileInputStream in = new FileInputStream("E:/workspace/CurriculumDesign/src/main/resources/identity.jks");
ks.load(in,storePass.toCharArray());
Certificate cert = ks.getCertificate(username);
byte[] encoded = cert.getEncoded();
in.close();
Writer writer = new OutputStreamWriter( new FileOutputStream(basePath + "/" + username + ".cer"));
writer.write( new BASE64Encoder().encode(encoded));
writer.close();
System.out.println("导出"+username+"证书成功");

4.证书下载

/*
 *文件下载可以直接使用文件的物理路径,但是这样就暴露了服务器目录信息
 *下面使用的是流式文件下载,将文件写入到http响应输出流中
 */
@RequestMapping("/download")
public void download(HttpServletRequest request,HttpServletResponse response){
	String basePath = request.getSession().getServletContext().getRealPath("/WEB-INF/upload");
	String fileName = ((Student)request.getSession().getAttribute("student")).getUsername() + ".cer";
	
	response.setCharacterEncoding("utf-8");
	response.setContentType("multipart/form-data");
	response.setHeader("Content-Disposition", "attachment;fileName="+fileName);
	
	try {
		File file=new File(basePath + "/" + fileName);
		InputStream inputStream=new FileInputStream(file);
		OutputStream os=response.getOutputStream();
		byte[] b=new byte[1024];
		int length;
		while((length=inputStream.read(b))>0){
			os.write(b,0,length);
		}
		inputStream.close();
	} catch (FileNotFoundException e) {
		e.printStackTrace();
	} catch (IOException e) {
		e.printStackTrace();
	}
}


blog comments powered by Disqus

Published

03 June 2013

Category

program