网络安全--Java代码生成自颁发 cer证书、base64 cer证书文件

举报
吾日三省贾斯汀 发表于 2021/09/27 18:26:42 2021/09/27
【摘要】 ​ 目录一、说明二、实现代码三、结果分析一、说明最近在做一个项目,涉及到数字证书这一块的内容,其中有一个需求是,根据前端维护上送参数, 后台Java实现生成cer自签名证书,证书要求跟openssl命令生成的一样 ,我的java环境是JDK1.8。网络--keytool CA签名SSL证书(收费)网络--keytool自签名SSL证书(免费)以及私钥签名、公钥验签二、实现代码package ...

 目录

一、说明

二、实现代码

三、结果分析


一、说明

最近在做一个项目,涉及到数字证书这一块的内容,其中有一个需求是,根据前端维护上送参数, 后台Java实现生成cer自签名证书,证书要求跟openssl命令生成的一样 ,我的java环境是JDK1.8。

网络--keytool CA签名SSL证书(收费)
网络--keytool自签名SSL证书(免费)以及私钥签名、公钥验签

二、实现代码

package com.justin.key;

import java.io.File;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.math.BigInteger;
import java.security.InvalidKeyException;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.SecureRandom;
import java.security.Security;
import java.security.SignatureException;
import java.security.cert.CertificateEncodingException;
import java.security.cert.X509Certificate;
import java.util.Date;
import java.util.HashMap;

import org.bouncycastle.asn1.x509.X509Name;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.x509.X509V3CertificateGenerator;

import sun.misc.BASE64Encoder;

/**
 * Java代码生成自颁发 cer证书、base64 cer证书文件
 * @author justin
 *
 */
public class CreateCerFile {
    
    private String path = "E:/";
    
    private static String CTFC_DOMAIN_NAME = "domainName";			//CN:用户姓名或域名
    private static String CTFC_ORG_UNIT_NAME = "orgUnitName";       //OU:组织单位名称
    private static String CTFC_ORG_NAME = "orgName";                //O:组织名称
    private static String CTFC_COUNTRY_CODE = "countryCode";        //C:单位的两字母国家代码
    private static String CTFC_CITY = "city";                       //L:城市或区域
    private static String CTFC_PROVINCE = "province";               //ST:省份或州
    
    private static String CTFC_VALID_START_TIME = "validStartTime"; //证书有效起始时间                       
    private static String CTFC_VALID_END_TIME = "validEndTime";     //证书有效截止时间                       
    private static String CTFC_SERIAL_NUMBER = "serialNumber";      //序列号域                          
    private static String CTFC_SIG_AlG = "signatureAlgorithm";      //签名算法
    private static String CTFC_ENCRYPT_TYPE = "encryptType";      	//加密类型
    private static String CTFC_ENCRYPT_NUM = "encryptNum";      	//加密位数
    private static String CTFC_PROVIDER = "provider";      			//提供人
    
    
    /**
     * 证书提供人:BC
     */
    static {
        Security.addProvider(new BouncyCastleProvider());
    }

   /**
    * 生成cer证书
    * @param infoMap
    * @param keyPair_root
    * @param keyPair_user
    * @return
    * @throws InvalidKeyException
    * @throws NoSuchProviderException
    * @throws SecurityException
    * @throws SignatureException
    */
    public X509Certificate generateCert(HashMap<String,Object> infoMap, KeyPair keyPair_root, KeyPair keyPair_user)
            throws InvalidKeyException, NoSuchProviderException, SecurityException, SignatureException {
        X509V3CertificateGenerator certGen = new X509V3CertificateGenerator();
        X509Certificate cert = null;
        certGen.setSerialNumber((BigInteger)infoMap.get(CTFC_SERIAL_NUMBER));
        
        //证书颁发者,这里自颁发,颁发者和使用者一致,可以只是用户或域名,也可以是部分或完整的用户信息(OU:组织单位名称、O:组织单位、C:单位的两字母国家代码、L:城市或区域、ST:省份或州)
        certGen.setIssuerDN(new X509Name("CN="+ (String)infoMap.get(CTFC_DOMAIN_NAME)));
//        certGen.setIssuerDN(new X509Name("CN="+ (String)infoMap.get(CTFC_DOMAIN_NAME)
//        	+ ", OU=" + (String)infoMap.get(CTFC_ORG_UNIT_NAME)
//        		+ ", O=" + (String)infoMap.get(CTFC_ORG_NAME)
//        			+ ", C=" + (String)infoMap.get(CTFC_COUNTRY_CODE)
//        				+ ", L=" + (String)infoMap.get(CTFC_CITY)
//        					+ ", ST=" + (String)infoMap.get(CTFC_PROVINCE)));
        
        certGen.setNotBefore((Date)infoMap.get(CTFC_VALID_START_TIME));
        certGen.setNotAfter((Date)infoMap.get(CTFC_VALID_END_TIME));
        
        //证书使用者,这里自颁发,使用者和颁发者一致,可以只是用户或域名,也可以是完整的用户信息(组织单位名称、组织单位、国家代码、城市或区域、省份或州)
        certGen.setSubjectDN(new X509Name("CN=" + (String)infoMap.get(CTFC_DOMAIN_NAME)));
//        certGen.setSubjectDN(new X509Name("CN="+ (String)infoMap.get(CTFC_DOMAIN_NAME)
//        		+ ", OU=" + (String)infoMap.get(CTFC_ORG_UNIT_NAME)
//        			+ ", O=" + (String)infoMap.get(CTFC_ORG_NAME)
//        				+ ", C=" + (String)infoMap.get(CTFC_COUNTRY_CODE)
//        					+ ", L=" + (String)infoMap.get(CTFC_CITY)
//        						+ ", ST=" + (String)infoMap.get(CTFC_PROVINCE)));
        certGen.setPublicKey(keyPair_user.getPublic());
        certGen.setSignatureAlgorithm((String)infoMap.get(CTFC_SIG_AlG));
        
        
        cert = certGen.generateX509Certificate(keyPair_root.getPrivate(), (String)infoMap.get(CTFC_PROVIDER)); //BC:证书提供人
        return cert;
    }

    /**
     * 生成密钥对
     * @param 生成cer证书需要的参数
     * @param seed
     * @return
     * @throws NoSuchAlgorithmException
     */
    public KeyPair generateKeyPair(HashMap<String,Object> infoMap,int seed) throws NoSuchAlgorithmException {
        KeyPairGenerator kpg = KeyPairGenerator.getInstance((String)infoMap.get(CTFC_ENCRYPT_TYPE));
        kpg.initialize((int)infoMap.get(CTFC_ENCRYPT_NUM),new SecureRandom(new byte[seed]));
        KeyPair keyPair = kpg.generateKeyPair();
        return keyPair;
    }
    
    /**
     * 生成原格式 cer证书
     * @param 生成cer证书需要的参数
     * @return
     */
    public boolean createCerFile(HashMap<String,Object> infoMap) {
        try {
            KeyPair keyPair_root = generateKeyPair(infoMap,10);
            KeyPair keyPair_user = generateKeyPair(infoMap,10);
            
            X509Certificate cert = generateCert(infoMap, keyPair_root, keyPair_user);
//            System.out.println(cert.toString());
//            String cerString = new BASE64Encoder().encode(cert.getEncoded());
//            System.out.println(cerString);
            
            //生成cer证书文件
            String certPath = path + infoMap.get(CTFC_DOMAIN_NAME) + ".cer";
            FileOutputStream fos = new FileOutputStream(certPath);
            fos.write(cert.getEncoded()); //证书可以二进制形式存入库表,存储字段类型为BLOB
            fos.close();
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("createPublicKey error:" + e.getMessage());
            return false;
        }
    }
    
    /**
     * 生成base64格式 cer证书
     * @param infoMap
     * @return
     */
    public boolean createBase64CerFileByDecode(HashMap<String,Object> infoMap) {
        try {
            KeyPair keyPair_root = generateKeyPair(infoMap,10);
            KeyPair keyPair_user = generateKeyPair(infoMap,10);
            X509Certificate cert = generateCert(infoMap, keyPair_root, keyPair_user);
            String certPath = path + infoMap.get(CTFC_DOMAIN_NAME) + "_base64.cer";
            
            String encode = new BASE64Encoder().encode(cert.getEncoded());
            String base64EncodeCer = "-----BEGIN CERTIFICATE-----\r\n" + encode + "\r\n-----END CERTIFICATE-----\r\n";
//            System.out.println(base64EncodeCer);
            
            //生成base64 cer证书文件
            FileWriter wr = new java.io.FileWriter(new File(certPath));
            wr.write(base64EncodeCer);
            wr.flush();
            wr.close();
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("createPublicKeyByDecode error:" + e.getMessage());
            return false;
        }
    }

	public static void main(String[] args) throws NoSuchAlgorithmException, InvalidKeyException,
            NoSuchProviderException, SecurityException, SignatureException, CertificateEncodingException, IOException {
        
		CreateCerFile dataCertCreate = new CreateCerFile();
		Date validStartTime = new Date();
		Date validEndTime = new Date(validStartTime.getTime() + 10*365L*24L*60L*60L*1000L);
        BigInteger serialNumber = new BigInteger(String.valueOf(validStartTime.getTime() / 1000L));
        
        //构建生成证书请求参数
        HashMap<String,Object> infoMap = new HashMap<String,Object>();
	    infoMap.put(CTFC_DOMAIN_NAME, "www.justinqin.com");		//CN:用户姓名或域名       
	    infoMap.put(CTFC_ORG_UNIT_NAME, "orgUnitName");         //OU:组织单位名称              
	    infoMap.put(CTFC_ORG_NAME, "orgName");          		//O:组织名称               
	    infoMap.put(CTFC_COUNTRY_CODE, "CN");           		//C:单位的两字母国家代码         
	    infoMap.put(CTFC_CITY, "深圳市");              			//L:城市或区域             
	    infoMap.put(CTFC_PROVINCE, "广东省");          			//ST:省份或州
	    
        infoMap.put(CTFC_VALID_START_TIME, validStartTime); 	//证书有效起始时间              
        infoMap.put(CTFC_VALID_END_TIME, validEndTime);   		//证书有效截止时间              
        infoMap.put(CTFC_SERIAL_NUMBER, serialNumber);  		//序列号域        
        infoMap.put(CTFC_SIG_AlG, "SHA256withRSA");  			//签名算法
        infoMap.put(CTFC_ENCRYPT_TYPE, "RSA");  				//加密类型
        infoMap.put(CTFC_ENCRYPT_NUM, 2048);  					//加密位数
        infoMap.put(CTFC_PROVIDER, "BC");  						//提供人
       
        // 生成公钥
        boolean createCerFileRs = dataCertCreate.createCerFile(infoMap);
        System.out.println("createCerFile, result==" + createCerFileRs);

        boolean createBase64CerFileByDecodeRs = dataCertCreate.createBase64CerFileByDecode(infoMap);
        System.out.println("createBase64CerFileByDecode, result==" + createBase64CerFileByDecodeRs);

    }
}


三、结果分析

实现代码运行结果:

createCerFile, result==true

createBase64CerFileByDecode, result==true

生成cer证书文件信息如下:

PS:

生成cer证书的generateCert()方法需要确保,certGen赋值足够的参数,否则可能会生成证书失败,抛异常信息,例如我们把generateCert()方法中设置证书有效起始时间 、证书有效截止时间的代码注释掉,再运行

// certGen.setNotBefore((Date)infoMap.get(CTFC_VALID_START_TIME));

// certGen.setNotAfter((Date)infoMap.get(CTFC_VALID_END_TIME));

则报错提示如下:

java.lang.IllegalStateException: not all mandatory fields set in V3 TBScertificate generatorcreatePublicKey error:not all mandatory fields set in V3 TBScertificate generator

createCerFile, result==false


at org.bouncycastle.asn1.x509.V3TBSCertificateGenerator.generateTBSCertificate(Unknown Source)

at org.bouncycastle.x509.X509V3CertificateGenerator.generateTbsCert(Unknown Source)

at org.bouncycastle.x509.X509V3CertificateGenerator.generate(Unknown Source)

at org.bouncycastle.x509.X509V3CertificateGenerator.generateX509Certificate(Unknown Source)

at org.bouncycastle.x509.X509V3CertificateGenerator.generateX509Certificate(Unknown Source)

at com.justin.key.CreateCerFile.generateCert(CreateCerFile.java:97)

at com.justin.key.CreateCerFile.createCerFile(CreateCerFile.java:125)

at com.justin.key.CreateCerFile.main(CreateCerFile.java:198)

createPublicKeyByDecode error:not all mandatory fields set in V3 TBScertificate generator

createBase64CerFileByDecode, result==false

java.lang.IllegalStateException: not all mandatory fields set in V3 TBScertificate generator

at org.bouncycastle.asn1.x509.V3TBSCertificateGenerator.generateTBSCertificate(Unknown Source)

at org.bouncycastle.x509.X509V3CertificateGenerator.generateTbsCert(Unknown Source)

at org.bouncycastle.x509.X509V3CertificateGenerator.generate(Unknown Source)

at org.bouncycastle.x509.X509V3CertificateGenerator.generateX509Certificate(Unknown Source)

at org.bouncycastle.x509.X509V3CertificateGenerator.generateX509Certificate(Unknown Source)

at com.justin.key.CreateCerFile.generateCert(CreateCerFile.java:97)

at com.justin.key.CreateCerFile.createBase64CerFileByDecode(CreateCerFile.java:152)

at com.justin.key.CreateCerFile.main(CreateCerFile.java:201)








【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。