Java管理SSL证书

SSL证书结构

Java管理SSL证书_第1张图片

根证书的生成分为三个部分:

  • 生成根证书的公钥和私钥
  • 构建证书的原始证书,包括公钥、加密算法、生效时间、过期时间等信息。
  • 用根证书私钥对原始证书进行签名,生成合法的根证书。
  • 根证书安装,将根证书安装到客户端,比如手机、电脑中。
    代码

 

Java管理SSL证书_第2张图片           

 

生成服务器证书

      

         Java管理SSL证书_第3张图片

 

服务器证书的生成过程与根证书类似,只是给服务器原始证书签名的不是自己生成的私钥,而是根证书的私钥。

客户端证书校验过程

  • 客户端收到服务端发送的服务器SSL证书。
  • 解析获得服务器证书的颁发者
  • 找到已安装在客户端的颁发者根证书,如果没找到则服务器证书非法,停止校验。
  • 用根证书的公钥解析服务器证书的签名信息,完成解析认证成功,否则失败。

我们采用keytool生成相应的根秘钥库、服务器秘钥库、客户端秘钥库

1.从根秘钥库导出根原始证书;

2.从服务器秘钥库导出服务器原始证书;

3.从客户端秘钥库导出客户端原始证书;

4.制作根证书:采用java程序用根私钥对根原始证书签名,issuer与subject保持一致;

5.制作服务器证书:采用java程序用根私钥对服务器原始证书签名,subject的CN为服务器标识,表示专为某服务器签发;

6.制作客户端证书:采用java程序用根私钥对客户端原始证书签名,subject的CN为用户标识,表示专为某用户会话临时签发;


1生成根证书

keytool -list -v -keystore client20210427.keystore -storepass 'clientPassword'

1.1.生成秘钥
keytool -genkey -dname "CN=xx.domain.com, OU=domain, O=xx, L=bj, ST=cy, C=China" -alias root-alias -keypass 'rootPassword' -keyalg RSA -keystore root-key.store -validity 3600

1.2.生成根原始证书 service.cer
keytool -export -alias root-alias -storepass 'rootPassword' -file root-src.cer -keystore root-key.store

1.3.java程序用根私钥对原始证书进行签名




2生成服务器证书
2.1.生成服务器秘钥
keytool -genkey -dname "CN=xx.domain.com, OU=domain, O=xx, L=bj, ST=cy, C=China" -alias server-alias -keyalg RSA -keystore server-key.store -keypass 'serverPassword' -storepass 'serverPassword' -validity 1100
clientPassword
2.2.生成服务器原始证书 service.cer
keytool -export -alias server-alias -storepass 'serverPassword' -file server-src.cer -keystore server-key.store

2.3.java程序用根私钥对原始证书进行签名


3生成客户端证书
3.1.生成客户端秘钥
keytool -genkey -dname "CN=xx.domain.com, OU=domain, O=xx, L=bj, ST=cy, C=China" -alias client-alias -keyalg RSA -keystore client-key.store -keypass 'clientPassword' -storepass 'clientPassword' -validity 1100

3.2.生成客户端原始证书 service.cer
keytool -export -alias client-alias -storepass 'clientPassword' -file client-src.cer -keystore client-key.store

3.3.java程序用根私钥对原始证书进行签名





导出数字证书
keytool -exportcert -alias myCertificate -keystore myKeystore.keystore -file myCer.cer -rfc
各参数含义如下:
-exportcert  表示证书导出操作
-alias     指定别名
-keystore   指定密钥库文件
-file      指定导出证书的文件路径
-rfc      指定以Base64编码格式输出

打印证书

查看数字证书方法
keytool -printcert -file client.cer


再用openssl 验证一下是否正常
openssl x509 -inform DER -in root-sign.cer -text -noout

subject
C=China, ST=cy, L=bj, O=xx, OU=domain, CN=xx.domain.com





 

所有代码在jdk1.8下验证完成

/**
     * 获取证书信息,并自签名待签证书 这里是自签名 得到根证书
     *
     * @param certPath : 待签证书地址
     * @throws Exception
     */
    public X509CertInfo createRootCert(String certPath) throws Exception {

        // 获取待签名证书
        FileInputStream is = new FileInputStream(certPath);
        CertificateFactory vCertFactory = CertificateFactory.getInstance("X.509");
        Certificate certificate = vCertFactory.generateCertificate(is);
        is.close();

        byte[] certData = certificate.getEncoded();
        // 设置签名证书信息:有效日期、序列号、签名者、数字签名算发
        X509CertImpl certImpl = new X509CertImpl(certData);
        X509CertInfo cert = (X509CertInfo) certImpl.get(X509CertImpl.NAME + "." + X509CertImpl.INFO);
        cert.set(X509CertInfo.VALIDITY, getCertValidity());
        cert.set(X509CertInfo.SERIAL_NUMBER, getCertSerualNumber());
        cert.set(X509CertInfo.ISSUER + "." + CertificateIssuerName.DN_NAME, cert.get(X509CertInfo.SUBJECT + "." + CertificateIssuerName.DN_NAME));
        cert.set(CertificateAlgorithmId.NAME + "." + CertificateAlgorithmId.ALGORITHM, getAlgorithm());
        return cert;
    }

签发

/**
     * 取得待签证书信息,并签名待签证书
     *
     * @throws Exception
     */
    public X509CertInfo signCert(CertInfo ci, X509CertInfo cert, String certSavePath) throws Exception {

        X509CertImpl certImpl = new X509CertImpl(cert);

        // 生成新正书验证码
        certImpl.sign(ci.getPk(), "MD5WithRSA");

        BASE64Encoder base64 = new BASE64Encoder();

        File file = new File(certSavePath);
        file.createNewFile();

        FileOutputStream os = new FileOutputStream(certSavePath);

        base64.encodeBuffer(certImpl.getEncoded(), os);

//        certImpl.derEncode(os);
        os.close();

        return cert;
    }

    public X509CertInfo signCert2(CertInfo ci, X509CertInfo cert, String certSavePath) throws Exception {

        X509CertImpl certImpl = new X509CertImpl(cert);

        // 生成新正书验证码
        certImpl.sign(ci.getPk(), "MD5WithRSA");

        FileUtil.writeToFile(certSavePath, certImpl.getEncoded());

        return cert;
    }

    public String signCertBase64(CertInfo ci, X509CertInfo cert) throws Exception {

        X509CertImpl certImpl = new X509CertImpl(cert);

        // 生成新正书验证码
        certImpl.sign(ci.getPk(), "MD5WithRSA");

        BASE64Encoder encoder = new BASE64Encoder();

        String encoded = encoder.encode(certImpl.getEncoded());
        StringBuilder sb = new StringBuilder();
        sb.append("-----BEGIN RSA PRIVATE KEY-----\r\n");
        sb.append(encoded);
        sb.append("\r\n-----END RSA PRIVATE KEY-----");

        return sb.toString();
    }

创建证书

X509CertInfo info = new X509CertInfo();
info.set(X509CertInfo.VERSION, new CertificateVersion(CertificateVersion.V3));
info.set(X509CertInfo.SERIAL_NUMBER, new CertificateSerialNumber(new java.util.Random().nextInt() & 0x7fffffff));
info.set(X509CertInfo.ALGORITHM_ID, new CertificateAlgorithmId(AlgorithmId.get("SHA256withRSA")));
info.set(X509CertInfo.SUBJECT, subject);
info.set(X509CertInfo.KEY, new CertificateX509Key(subjectKeyPair.getPublic()));
info.set(X509CertInfo.VALIDITY, validity);
info.set(X509CertInfo.ISSUER, x509Certificate.getIssuerDN());

 

创建X509CertInfo.SUBJECT 证书使用者信息

    /**
     * 创建证书使用者信息
     * @param CN comonName
     * @param OU organizationalUnitName
     * @param O organizationName
     * @param C countryName
     * @param L localityName
     * @param ST stateOrProvinceName
     * @return
     * @throws IOException
     */
    public static X500Name createSubject(String CN,String OU,String O,String C,String L,String ST) throws IOException {
        X500Name subject = new X500Name(new StringBuilder()
                .append("CN=").append(CN)
                .append(",OU=").append(OU)
                .append(",O=").append(O)
                .append(",C=").append(C)
                .append(",L=").append(L)
                .append(",ST=").append("abc").toString());
        return subject;
    }

对原始证书签名,并签入使用者信息,这里subject就是使用者信息,签名采用根证书私钥

public X509CertInfo createCert(String pin, InputStream is) throws Exception {

        X500Name subject = createSubject(new SignInfo(), pin);

        // 获取待签名证书
        CertificateFactory vCertFactory = CertificateFactory.getInstance("X.509");
        Certificate certificate = vCertFactory.generateCertificate(is);
        is.close();

        byte[] certData = certificate.getEncoded();
        // 设置签名证书信息:有效日期、序列号、签名者、数字签名算发
        X509CertImpl certImpl = new X509CertImpl(certData);
        X509CertInfo cert = (X509CertInfo) certImpl.get(X509CertImpl.NAME + "." + X509CertImpl.INFO);
        cert.set(X509CertInfo.VALIDITY, getCertValidity());
        cert.set(X509CertInfo.SERIAL_NUMBER, getCertSerualNumber());
        cert.set(X509CertInfo.ISSUER + "." + CertificateIssuerName.DN_NAME, cert.get(X509CertInfo.SUBJECT + "." + CertificateIssuerName.DN_NAME));
        cert.set(CertificateAlgorithmId.NAME + "." + CertificateAlgorithmId.ALGORITHM, getAlgorithm());
        cert.set(X509CertInfo.SUBJECT, subject);
        return cert;
}

 

maven 打包证书的过程中不断提示:IOException: Invalid keystore format

做以下两步操作即可解决

Java管理SSL证书_第4张图片

设置不替换的变量:p12  jks

这个p12是后缀的意思,不想让他去修改什么文件,就在这里面添加条目即可


     org.apache.maven.plugins
     maven-resources-plugin
     
         
              p12
              jks
         
     

 

这样签发的证书在linux完美通过验证,but在windows上不能通过验证,于是我们对linux和windows上的证书格式进行比较,发现windows上根证书必须要包含X509v3 Basic Constraints,CA:True

    private CertificateExtensions createCertificateExtensions2() throws IOException {
        CertificateExtensions exts = new CertificateExtensions();
        BasicConstraintsExtension bce = new BasicConstraintsExtension(true, true, -1);
        exts.set(BasicConstraintsExtension.NAME, new BasicConstraintsExtension(false, bce.getExtensionValue()));

        return exts;
    }


//对根证书签名代码增加如下一行,写入extension
 cert.set(X509CertInfo.EXTENSIONS, extensions);

 

参考
https://www.jianshu.com/p/ed6486f0e608
https://blog.csdn.net/JustinQin/article/details/100052500

https://blog.csdn.net/jxctx/article/details/45970199

 

你可能感兴趣的:(信息安全,数字证书,根证书,x509cert,公钥,私钥)