All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.shepherdviolet.glacimon.java.crypto.AdvancedPKCS12KeyStoreUtils Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (C) 2022-2022 S.Violet
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * Project GitHub: https://github.com/shepherdviolet/glacimon
 * Email: [email protected]
 */

package com.github.shepherdviolet.glacimon.java.crypto;

import com.github.shepherdviolet.glacimon.java.crypto.base.BouncyCastleProviderUtils;
import org.bouncycastle.asn1.ASN1Encoding;
import org.bouncycastle.asn1.DERBMPString;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.cert.jcajce.JcaX509ExtensionUtils;
import org.bouncycastle.crypto.engines.DESedeEngine;
import org.bouncycastle.crypto.engines.RC2Engine;
import org.bouncycastle.crypto.modes.CBCBlockCipher;
import org.bouncycastle.pkcs.*;
import org.bouncycastle.pkcs.bc.BcPKCS12MacCalculatorBuilder;
import org.bouncycastle.pkcs.bc.BcPKCS12PBEOutputEncryptorBuilder;
import org.bouncycastle.pkcs.jcajce.JcaPKCS12SafeBagBuilder;
import com.github.shepherdviolet.glacimon.java.misc.CloseableUtils;

import java.io.*;
import java.security.*;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;

/**
 * 

PKCS12密钥文件工具(p12/pfx), BouncyCastle版本

* *

* OPENSSL查看p12文件信息: * openssl pkcs12 -in pkcs12-test.p12 -info -noout *

* *

* Windows查看证书信息: * certmgr.msc *

* * @author shepherdviolet */ public class AdvancedPKCS12KeyStoreUtils extends PKCS12KeyStoreUtils { private static final String ALGORITHM = "PKCS12"; static { BouncyCastleProviderUtils.installProvider(); } /** * 将证书和私钥保存到p12/pfx文件中, BouncyCastle实现, 支持SM2 * * @param keyStorePath keyStore的文件路径 * @param keystorePassword keyStore的密码 * @param alias 证书和私钥的别名 * @param privateKey 证书对应的私钥(如果为空, 则仅保存证书) * @param certificateChain 证书链, 通常传入一个证书即可, 用户证书/CA证书/根证书一般会分别导出独立的文件. 如果需要一次性导出整个 * 证书链到一个文件, 也可以传入多个证书, 顺序是个人证书->二级CA证书->根证书, {userCertificate, subCaCertificate, rootCertificate} */ public static void storeCertificateAndKeyAdvanced(String keyStorePath, String keystorePassword, String alias, PrivateKey privateKey, X509Certificate... certificateChain) throws NoSuchAlgorithmException, IOException, PKCSException { File keyStoreFile = new File(keyStorePath); File dirFile = keyStoreFile.getParentFile(); if (dirFile != null && !dirFile.exists()){ if (!dirFile.mkdirs()){ throw new IOException("Can not make directory for keyStore, path:" + dirFile.getAbsolutePath()); } } try (OutputStream outputStream = new FileOutputStream(keyStoreFile)) { storeCertificateAndKeyAdvanced(outputStream, keystorePassword, alias, privateKey, certificateChain); } } /** * 将证书和私钥保存到p12/pfx文件中, BouncyCastle实现, 支持SM2 * * @param outputStream keyStore的输出流, 完成后会关闭 * @param keystorePassword keyStore的密码 * @param alias 证书和私钥的别名 * @param privateKey 证书对应的私钥(如果为空, 则仅保存证书) * @param certificateChain 证书链, 通常传入一个证书即可, 用户证书/CA证书/根证书一般会分别导出独立的文件. 如果需要一次性导出整个 * 证书链到一个文件, 也可以传入多个证书, 顺序是个人证书->二级CA证书->根证书, {userCertificate, subCaCertificate, rootCertificate} */ public static void storeCertificateAndKeyAdvanced(OutputStream outputStream, String keystorePassword, String alias, PrivateKey privateKey, X509Certificate... certificateChain) throws NoSuchAlgorithmException, IOException, PKCSException { try { byte[] pfxData = parseCertificateAndKeyToPkcs12Advanced(keystorePassword, alias, privateKey, certificateChain); outputStream.write(pfxData); } finally { CloseableUtils.closeQuiet(outputStream); } } /** * 将证书和私钥转换为PKCS12格式的数据(p12/pfx的数据), BouncyCastle实现, 支持SM2 * * @param keystorePassword keyStore的密码 * @param alias 证书和私钥的别名 * @param privateKey 证书对应的私钥(如果为空, 则仅保存证书) * @param certificateChain 证书链, 通常传入一个证书即可, 用户证书/CA证书/根证书一般会分别导出独立的文件. 如果需要一次性导出整个 * 证书链到一个文件, 也可以传入多个证书, 顺序是个人证书->二级CA证书->根证书, {userCertificate, subCaCertificate, rootCertificate} */ public static byte[] parseCertificateAndKeyToPkcs12Advanced(String keystorePassword, String alias, PrivateKey privateKey, X509Certificate... certificateChain) throws NoSuchAlgorithmException, IOException, PKCSException { if (certificateChain == null || certificateChain.length == 0) { throw new NullPointerException("certificateChain is null or empty"); } PublicKey publicKey = certificateChain[0].getPublicKey(); char[] passwordChars = keystorePassword.toCharArray(); JcaX509ExtensionUtils extensionUtils = new JcaX509ExtensionUtils(); //certificate chain PKCS12SafeBag[] bags = new PKCS12SafeBag[certificateChain.length]; for (int i = 0; i < certificateChain.length; i++) { PKCS12SafeBagBuilder bagBuilder = new JcaPKCS12SafeBagBuilder(certificateChain[i]); //证书设置了alias反而会导致读取的时候读取不到全部的证书, 不知为何 // bagBuilder.addBagAttribute( // PKCSObjectIdentifiers.pkcs_9_at_friendlyName, // new DERBMPString(alias)); if (i == 0) { bagBuilder.addBagAttribute( PKCSObjectIdentifiers.pkcs_9_at_localKeyId, extensionUtils.createSubjectKeyIdentifier(publicKey)); } bags[i] = bagBuilder.build(); } //key PKCS12SafeBagBuilder keyBagBuilder = new JcaPKCS12SafeBagBuilder( privateKey, new BcPKCS12PBEOutputEncryptorBuilder( PKCSObjectIdentifiers.pbeWithSHAAnd3_KeyTripleDES_CBC, new CBCBlockCipher(new DESedeEngine())).build(passwordChars)); keyBagBuilder.addBagAttribute( PKCSObjectIdentifiers.pkcs_9_at_friendlyName, new DERBMPString(alias)); keyBagBuilder.addBagAttribute( PKCSObjectIdentifiers.pkcs_9_at_localKeyId, extensionUtils.createSubjectKeyIdentifier(publicKey)); //pfx builder PKCS12PfxPduBuilder pfxPduBuilder = new PKCS12PfxPduBuilder(); //add certificates pfxPduBuilder.addEncryptedData( new BcPKCS12PBEOutputEncryptorBuilder( PKCSObjectIdentifiers.pbeWithSHAAnd40BitRC2_CBC, new CBCBlockCipher(new RC2Engine())).build(passwordChars), bags); //add key pfxPduBuilder.addData(keyBagBuilder.build()); //build pfx return pfxPduBuilder.build(new BcPKCS12MacCalculatorBuilder(), passwordChars) .getEncoded(ASN1Encoding.DER); } /** * 从p12/pfx文件中遍历alias, BouncyCastle实现, 支持SM2 * *
{@code
     *      Enumeration aliases = PKCS12KeyStoreUtils.loadAliases(
     *          "ca-cert.p12",
     *          "000000"
     *          );
     * }
* * @param keyStorePath keyStore路径 * @param keystorePassword keyStore密码 */ public static Enumeration loadAliasesAdvanced(String keyStorePath, String keystorePassword) throws KeyStoreException, CertificateException, NoSuchAlgorithmException, IOException, UnrecoverableKeyException, NoSuchProviderException { File keyStoreFile = new File(keyStorePath); if (!keyStoreFile.exists()){ throw new IOException("Can not find keyStore file, path:" + keyStoreFile.getAbsolutePath()); } return loadAliasesAdvanced(new FileInputStream(keyStoreFile), keystorePassword); } /** * 从p12/pfx文件中遍历alias, BouncyCastle实现, 支持SM2 * *
{@code
     *      Enumeration aliases = PKCS12KeyStoreUtils.loadAliases(
     *          inputStream,
     *          "000000"
     *          );
     * }
* * @param inputStream keyStore输入流, 完成后会关闭 * @param keystorePassword keyStore密码 */ public static Enumeration loadAliasesAdvanced(InputStream inputStream, String keystorePassword) throws KeyStoreException, CertificateException, NoSuchAlgorithmException, IOException, UnrecoverableKeyException, NoSuchProviderException { try { KeyStore keyStore = KeyStore.getInstance(ALGORITHM, BouncyCastleProviderUtils.getProviderName()); keyStore.load(inputStream, keystorePassword != null ? keystorePassword.toCharArray() : null); return keyStore.aliases(); } finally { CloseableUtils.closeQuiet(inputStream); } } /** * 从p12/pfx文件中读取证书和私钥, BouncyCastle实现, 支持SM2 * *
{@code
     *      PKCS12KeyStoreUtils.CertificateChainAndKey certificateChainAndKey = PKCS12KeyStoreUtils.loadCertificateAndKey(
     *          "ca-cert.p12",
     *          "000000",
     *          "Glacijava test ca alias"
     *          );
     * }
* * @param keyStorePath keyStore路径 * @param keystorePassword keyStore密码 * @param alias 证书和私钥的别名 */ public static CertificateChainAndKey loadCertificateAndKeyAdvanced(String keyStorePath, String keystorePassword, String alias) throws KeyStoreException, CertificateException, NoSuchAlgorithmException, IOException, UnrecoverableKeyException, NoSuchProviderException { File keyStoreFile = new File(keyStorePath); if (!keyStoreFile.exists()){ throw new IOException("Can not find keyStore file, path:" + keyStoreFile.getAbsolutePath()); } return loadCertificateAndKeyAdvanced(new FileInputStream(keyStoreFile), keystorePassword, alias); } /** * 从p12/pfx文件中读取证书和私钥, BouncyCastle实现, 支持SM2 * *
{@code
     *      PKCS12KeyStoreUtils.CertificateChainAndKey certificateChainAndKey = PKCS12KeyStoreUtils.loadCertificateAndKey(
     *          inputStream,
     *          "000000",
     *          "Glacijava test ca alias"
     *          );
     * }
* * @param inputStream keyStore输入流, 完成后会关闭 * @param keystorePassword keyStore密码 * @param alias 证书和私钥的别名 */ public static CertificateChainAndKey loadCertificateAndKeyAdvanced(InputStream inputStream, String keystorePassword, String alias) throws KeyStoreException, CertificateException, NoSuchAlgorithmException, IOException, UnrecoverableKeyException, NoSuchProviderException { try { KeyStore keyStore = KeyStore.getInstance(ALGORITHM, BouncyCastleProviderUtils.getProviderName()); keyStore.load(inputStream, keystorePassword != null ? keystorePassword.toCharArray() : null); java.security.cert.Certificate[] certificateChain = keyStore.getCertificateChain(alias); if (certificateChain == null){ java.security.cert.Certificate certificate = keyStore.getCertificate(alias); if (certificate != null) { certificateChain = new java.security.cert.Certificate[]{certificate}; } } return new CertificateChainAndKey(alias, certificateChain, (PrivateKey) keyStore.getKey(alias, keystorePassword != null ? keystorePassword.toCharArray() : null)); } finally { CloseableUtils.closeQuiet(inputStream); } } /** * 从p12/pfx文件中读取证书和私钥, BouncyCastle实现, 支持SM2 * *
{@code
     *      List certificateChainAndKeyList = PKCS12KeyStoreUtils.loadAllCertificateAndKey(
     *          "ca-cert.p12",
     *          "000000"
     *          );
     * }
* * @param keyStorePath keyStore路径 * @param keystorePassword keyStore密码 */ public static List loadAllCertificateAndKeyAdvanced(String keyStorePath, String keystorePassword) throws KeyStoreException, CertificateException, NoSuchAlgorithmException, IOException, UnrecoverableKeyException, NoSuchProviderException { File keyStoreFile = new File(keyStorePath); if (!keyStoreFile.exists()){ throw new IOException("Can not find keyStore file, path:" + keyStoreFile.getAbsolutePath()); } return loadAllCertificateAndKeyAdvanced(new FileInputStream(keyStoreFile), keystorePassword); } /** * 从p12/pfx文件中读取证书和私钥, BouncyCastle实现, 支持SM2 * *
{@code
     *      List certificateChainAndKeyList = PKCS12KeyStoreUtils.loadAllCertificateAndKey(
     *          inputStream,
     *          "000000"
     *          );
     * }
* * @param inputStream keyStore输入流, 完成后会关闭 * @param keystorePassword keyStore密码 */ public static List loadAllCertificateAndKeyAdvanced(InputStream inputStream, String keystorePassword) throws KeyStoreException, CertificateException, NoSuchAlgorithmException, IOException, UnrecoverableKeyException, NoSuchProviderException { try { KeyStore keyStore = KeyStore.getInstance(ALGORITHM, BouncyCastleProviderUtils.getProviderName()); keyStore.load(inputStream, keystorePassword != null ? keystorePassword.toCharArray() : null); List list = new ArrayList<>(1); Enumeration aliases = keyStore.aliases(); while (aliases.hasMoreElements()) { String alias = aliases.nextElement(); java.security.cert.Certificate[] certificateChain = keyStore.getCertificateChain(alias); if (certificateChain == null) { java.security.cert.Certificate certificate = keyStore.getCertificate(alias); if (certificate != null) { certificateChain = new Certificate[]{certificate}; } } list.add(new CertificateChainAndKey(alias, certificateChain, (PrivateKey) keyStore.getKey(alias, keystorePassword != null ? keystorePassword.toCharArray() : null))); } return list; } finally { CloseableUtils.closeQuiet(inputStream); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy