diff --git a/pom.xml b/pom.xml index 6dcb507b..af9055ce 100644 --- a/pom.xml +++ b/pom.xml @@ -167,6 +167,13 @@ okhttp-brotli 4.12.0 + + + + io.github.hakky54 + ayza-for-pem + 10.0.1 + diff --git a/src/main/java/com/laker/postman/service/http/ssl/ClientCertificateLoader.java b/src/main/java/com/laker/postman/service/http/ssl/ClientCertificateLoader.java index 855854ae..4a37e47c 100644 --- a/src/main/java/com/laker/postman/service/http/ssl/ClientCertificateLoader.java +++ b/src/main/java/com/laker/postman/service/http/ssl/ClientCertificateLoader.java @@ -1,11 +1,16 @@ package com.laker.postman.service.http.ssl; +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.util.StrUtil; import com.laker.postman.model.ClientCertificate; import lombok.extern.slf4j.Slf4j; +import nl.altindag.ssl.pem.util.PemUtils; import javax.net.ssl.KeyManager; import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.X509ExtendedKeyManager; import javax.net.ssl.X509KeyManager; +import java.io.BufferedInputStream; import java.io.FileInputStream; import java.io.IOException; import java.net.Socket; @@ -70,82 +75,15 @@ private static KeyManager[] createKeyManagersFromPFX(ClientCertificate cert) thr * 从 PEM 文件创建 KeyManager */ private static KeyManager[] createKeyManagersFromPEM(ClientCertificate cert) throws Exception { - // 加载证书 - X509Certificate certificate = loadCertificateFromPEM(cert.getCertPath()); + log.debug("Loaded PEM certificate from: {} and key from: {}", cert.getCertPath(), cert.getKeyPath()); + try (BufferedInputStream certInputStream = FileUtil.getInputStream(cert.getCertPath()); + BufferedInputStream keyInputStream = FileUtil.getInputStream(cert.getKeyPath())) { - // 加载私钥 - PrivateKey privateKey = loadPrivateKeyFromPEM(cert.getKeyPath(), cert.getKeyPassword()); + X509ExtendedKeyManager keyManager = StrUtil.isNotBlank(cert.getKeyPassword()) + ? PemUtils.loadIdentityMaterial(certInputStream, keyInputStream, cert.getKeyPassword().toCharArray()) + : PemUtils.loadIdentityMaterial(certInputStream, keyInputStream); - // 创建 KeyStore 并添加证书和私钥 - KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); - keyStore.load(null, null); - - Certificate[] certChain = new Certificate[]{certificate}; - char[] keyPassword = cert.getKeyPassword() != null ? - cert.getKeyPassword().toCharArray() : new char[0]; - - keyStore.setKeyEntry("client-cert", privateKey, keyPassword, certChain); - - KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); - kmf.init(keyStore, keyPassword); - - log.debug("Loaded PEM certificate from: {} and key from: {}", - cert.getCertPath(), cert.getKeyPath()); - return kmf.getKeyManagers(); - } - - /** - * 从 PEM 文件加载 X509 证书 - */ - private static X509Certificate loadCertificateFromPEM(String certPath) throws IOException, CertificateException { - String content = new String(Files.readAllBytes(Paths.get(certPath))); - content = content.replace("-----BEGIN CERTIFICATE-----", "") - .replace("-----END CERTIFICATE-----", "") - .replaceAll("\\s", ""); - - byte[] certBytes = Base64.getDecoder().decode(content); - CertificateFactory cf = CertificateFactory.getInstance("X.509"); - return (X509Certificate) cf.generateCertificate( - new java.io.ByteArrayInputStream(certBytes)); - } - - /** - * 从 PEM 文件加载私钥 - */ - private static PrivateKey loadPrivateKeyFromPEM(String keyPath, String password) - throws IOException, GeneralSecurityException { - String content = new String(Files.readAllBytes(Paths.get(keyPath))); - - // 检查是否是加密的私钥 - if (content.contains("ENCRYPTED")) { - // 注意:password 参数预留用于未来支持加密私钥 - throw new IllegalArgumentException( - "Encrypted PEM private keys are not supported yet. " + - "Please use unencrypted PEM or convert to PFX/P12 format. " + - "Password parameter: " + (password != null ? "provided" : "not provided")); - } - - // 移除 PEM 头尾和空白字符 - content = content.replaceAll("-----BEGIN.*PRIVATE KEY-----", "") - .replaceAll("-----END.*PRIVATE KEY-----", "") - .replaceAll("\\s", ""); - - byte[] keyBytes = Base64.getDecoder().decode(content); - PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes); - - // 尝试 RSA - try { - KeyFactory kf = KeyFactory.getInstance("RSA"); - return kf.generatePrivate(spec); - } catch (Exception e) { - // 尝试 EC - try { - KeyFactory kf = KeyFactory.getInstance("EC"); - return kf.generatePrivate(spec); - } catch (Exception e2) { - throw new GeneralSecurityException( - "Failed to load private key. Supported algorithms: RSA, EC", e); - } + return new KeyManager[]{keyManager}; } }