用JAVA签发数字证书

前一篇http://zhuyuehua.iteye.com/blog/1101041 说到创建TOMCAT下HTTPS项目,现在接着说,如何签发证书。

打开cmd

1.输入D:

 

2.输入cd keys

 

3.输入命令查看创建的密钥库的证书列表

keytool -list -v -keystore mykey.keystore -storepass 123456

如下图:

 



 4. 之前导出过server.cer文件,把这个文件安装到操作系统,过程默认。

 

5.创建一个密钥对,和之前一样,输入如下命令:

 

--创建密钥对

keytool -genkey -dname "CN=tmp, OU=NC, O=Shanghai University, L=ZB, ST=Shanghai,C=CN" -alias client  -keyalg RSA -keystore myclientkey.store -keypass 654321 -storepass 654321 -validity 1000

 

--导出公钥

keytool -export -trustcacerts -alias client  -file client.cer -keystore  myclientkey.store -storepass 654321

 

双击client.cer可以看到:



 该证书不被系统信任,且颁发者和颁发给都是tmp

 

5.签发证书,这里采用的是JAVA程序来签发。可以用OPENSSL签发或者到正式CA机构签发。

 

由于已经把server.cer安装到客户机电脑上,所以客户机操作系统会信任server.cer中的机构签发的证书。

 

这里就用server.cer中的机构来签发client.cer

 

签发代码:

package com.syspro.test;

import java.io.*;
import java.security.*;
import java.security.cert.*;
import java.util.*;
import java.math.*;
import sun.security.x509.*;
public class SignCert {
	
	private String mKeystore = "D:/keys/mykey.keystore"; // 密锁库路径
	private char[] mKeystorePass = "123456".toCharArray();// 密锁库密码
	private char[] mSignPrivateKeyPass = "123456".toCharArray();// 取得签发者私锁所需的密码
	private String mSignCertAlias = "keytest";// 签发者别名
	private String mSignedCert = "D:/keys/client.cer"; // 被签证书
	private String mNewCert = "D:/keys/clientSignKey.cer"; // 签发后的新证书全名
	private int mValidityDay = 3000; // 签发后的新证书有效期(天)

	private PrivateKey mSignPrivateKey = null;// 签发者的私锁
	private X509CertInfo mSignCertInfo = null;// 签发证书信息
	private X509CertInfo mSignedCertInfo = null;// 被签证书信息
	   
	 public void  Sign() throws Exception{
			try {
				/**
				 * 证书签名
				 */
				getSignCertInfo(); // 获取签名证书信息
				signCertificate(); // 用签名证书信息签发待签名证书
				createNewCertificate(); // 创建并保存签名后的新证书
			} catch (Exception e) {
				System.out.println("Error:" + e.getMessage());
			}
	 }
	 
	 /**
	 * 取得签名证书信息
	 * @throws Exception
	 */
	 private void getSignCertInfo() throws Exception
	 {
	 FileInputStream vFin=null;
	 KeyStore vKeyStore=null;
	 java.security.cert.Certificate vCert=null;
	 X509CertImpl vCertImpl=null;
	 byte[] vCertData=null;

	 //获取签名证书密锁库
	 vFin=new FileInputStream(mKeystore); 
	 vKeyStore=KeyStore.getInstance("JKS");
	 vKeyStore.load(vFin,mKeystorePass);
	 //获取签名证书
	 vCert= vKeyStore.getCertificate(mSignCertAlias);
	 vCertData=vCert.getEncoded();
	 vCertImpl=new X509CertImpl(vCertData);
	 //获取签名证书信息
	 mSignCertInfo=(X509CertInfo)vCertImpl.get(X509CertImpl.NAME+"."+X509CertImpl.INFO);
	 mSignPrivateKey=(PrivateKey)vKeyStore.getKey(mSignCertAlias,mSignPrivateKeyPass);
	 vFin.close();
	 }



 	/**
 	 * 取得待签证书信息,并签名待签证书
 	 * 
 	 * @throws Exception
 	 */
 	private void signCertificate() throws Exception {
 		FileInputStream vFin = null;
 		java.security.cert.Certificate vCert = null;
 		CertificateFactory vCertFactory = null;
 		byte[] vCertData = null;
 		X509CertImpl vCertImpl = null;

 		// 获取待签名证书
 		vFin = new FileInputStream(mSignedCert);
 		vCertFactory = CertificateFactory.getInstance("X.509");
 		vCert = vCertFactory.generateCertificate(vFin);
 		vFin.close();
 		vCertData = vCert.getEncoded();
 		// 设置签名证书信息:有效日期、序列号、签名者、数字签名算发
 		vCertImpl = new X509CertImpl(vCertData);
 		mSignedCertInfo = (X509CertInfo) vCertImpl.get(X509CertImpl.NAME + "."
 				+ X509CertImpl.INFO);
 		mSignedCertInfo.set(X509CertInfo.VALIDITY, getCertValidity());
 		mSignedCertInfo.set(X509CertInfo.SERIAL_NUMBER, getCertSerualNumber());
 		mSignedCertInfo.set(X509CertInfo.ISSUER + "."
 				+ CertificateIssuerName.DN_NAME,
 				mSignCertInfo.get(X509CertInfo.SUBJECT + "."
 						+ CertificateIssuerName.DN_NAME));
 		mSignedCertInfo.set(CertificateAlgorithmId.NAME + "."
 				+ CertificateAlgorithmId.ALGORITHM, getAlgorithm());

 	}

 	/**
 	 * 待签签证书被签名后,保存新证书
 	 * 
 	 * @throws Exception
 	 */
 	private void createNewCertificate() throws Exception {
 		FileOutputStream vOut = null;
 		X509CertImpl vCertImpl = null;
 		// 用新证书信息封成为新X.509证书
 		vCertImpl = new X509CertImpl(mSignedCertInfo);
 		// 生成新正书验证码
 		vCertImpl.sign(mSignPrivateKey, "MD5WithRSA");
 		vOut = new FileOutputStream(mNewCert );
 		// 保存为der编码二进制X.509格式证书
 		vCertImpl.derEncode(vOut);
 		vOut.close();

 	}

 	// 辅助方法===========================================================================

 	/**
 	 * 得到新证书有效日期
 	 * 
 	 * @throws Exception
 	 * @return CertificateValidity
 	 */
 	private CertificateValidity getCertValidity() throws Exception {
 		long vValidity = (60 * 60 * 24 * 1000L) * mValidityDay;
 		Calendar vCal = null;
 		Date vBeginDate = null, vEndDate = null;
 		vCal = Calendar.getInstance();
 		vBeginDate = vCal.getTime();
 		vEndDate = vCal.getTime();
 		vEndDate.setTime(vBeginDate.getTime() + vValidity);
 		return new CertificateValidity(vBeginDate, vEndDate);
 	}

 	/**
 	 * 得到新证书的序列号
 	 * 
 	 * @return CertificateSerialNumber
 	 */
 	private CertificateSerialNumber getCertSerualNumber() {
 		Calendar vCal = null;
 		vCal = Calendar.getInstance();
 		int vSerialNum = 0;
 		vSerialNum = (int) (vCal.getTimeInMillis() / 1000);
 		return new CertificateSerialNumber(vSerialNum);
 	}

 	/**
 	 * 得到新证书的签名算法
 	 * 
 	 * @return AlgorithmId
 	 */
 	private AlgorithmId getAlgorithm() {
 		AlgorithmId vAlgorithm = new AlgorithmId(
 				AlgorithmId.md5WithRSAEncryption_oid);
 		return vAlgorithm;
 	}
 	
 	public static void main(String args[]) throws UnsupportedEncodingException
	{
		SignCert s = new SignCert();
		try {
			s.Sign();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

} 

 打开签名完成后的新证书clientSignKey.cer,如下图:

 



 会看到此时,操作系统会信任该证书,而且颁发者变成了server.cer中的localhost

 

再将签名后的数字证书clientSignKey.cer和CA证书server.cer导入myclientkey.store库中,命令如下:注意先后顺序

先倒入CA证书
keytool -import -alias ca -keystore D:\keys\myclientkey.store  -trustcacerts -file D:\keys\server.cer -storepass 654321

注意-alias 和之前的不一样。

再导入签名后的证书:

keytool -import -alias client -keystore D:\keys\myclientkey.store  -trustcacerts -file D:\keys\

clientSignKey.cer -storepass 654321

 

注意-alias 和之前的一样。

 

操作完后修改tomcat的server.xml文件,如下:

  <Connector protocol="org.apache.coyote.http11.Http11NioProtocol" 
				port="8443"  enableLookups="true" 
				disableUploadTimeout="true" acceptCount="100" 
				maxThreads="200" scheme="https" secure="true" 
				SSLEnabled="true"  sslProtocol="TLS" 
				clientAuth="false"
				keystoreFile="D:\keys\myclientkey.store" 
				keystorePass="654321" />

 然后启动tomcat,就会发现不会再提示了。

 

注:由于myclientkey.store的cn不是localhost,所以之前那样的设置打开网站时还是会提示不信任的证书。解决办法是将

myclientkey.store的cn写成localhost(你需要访问的网站地址),当然之前那个CA的密钥库的CN就不要写成localhost了,

随便写个别的就好。

 

 

注意,这样之后httpclient还是不会信任该证书,可以这样操作:

切换到<java-home>\jar\lib\security\目录下:

keytool -import -noprompt -keystore cacerts -storepass changeit -alias yourEntry1 -file

clientSignKey.cer

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值