|
1 | 1 | package com.laker.postman.service.http.ssl; |
2 | 2 |
|
| 3 | +import cn.hutool.core.io.FileUtil; |
| 4 | +import cn.hutool.core.util.StrUtil; |
3 | 5 | import com.laker.postman.model.ClientCertificate; |
4 | 6 | import lombok.extern.slf4j.Slf4j; |
| 7 | +import nl.altindag.ssl.pem.util.PemUtils; |
5 | 8 |
|
6 | 9 | import javax.net.ssl.KeyManager; |
7 | 10 | import javax.net.ssl.KeyManagerFactory; |
| 11 | +import javax.net.ssl.X509ExtendedKeyManager; |
8 | 12 | import javax.net.ssl.X509KeyManager; |
| 13 | +import java.io.BufferedInputStream; |
9 | 14 | import java.io.FileInputStream; |
10 | 15 | import java.io.IOException; |
11 | 16 | import java.net.Socket; |
@@ -70,82 +75,15 @@ private static KeyManager[] createKeyManagersFromPFX(ClientCertificate cert) thr |
70 | 75 | * 从 PEM 文件创建 KeyManager |
71 | 76 | */ |
72 | 77 | private static KeyManager[] createKeyManagersFromPEM(ClientCertificate cert) throws Exception { |
73 | | - // 加载证书 |
74 | | - X509Certificate certificate = loadCertificateFromPEM(cert.getCertPath()); |
| 78 | + log.debug("Loaded PEM certificate from: {} and key from: {}", cert.getCertPath(), cert.getKeyPath()); |
| 79 | + try (BufferedInputStream certInputStream = FileUtil.getInputStream(cert.getCertPath()); |
| 80 | + BufferedInputStream keyInputStream = FileUtil.getInputStream(cert.getKeyPath())) { |
75 | 81 |
|
76 | | - // 加载私钥 |
77 | | - PrivateKey privateKey = loadPrivateKeyFromPEM(cert.getKeyPath(), cert.getKeyPassword()); |
| 82 | + X509ExtendedKeyManager keyManager = StrUtil.isNotBlank(cert.getKeyPassword()) |
| 83 | + ? PemUtils.loadIdentityMaterial(certInputStream, keyInputStream, cert.getKeyPassword().toCharArray()) |
| 84 | + : PemUtils.loadIdentityMaterial(certInputStream, keyInputStream); |
78 | 85 |
|
79 | | - // 创建 KeyStore 并添加证书和私钥 |
80 | | - KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); |
81 | | - keyStore.load(null, null); |
82 | | - |
83 | | - Certificate[] certChain = new Certificate[]{certificate}; |
84 | | - char[] keyPassword = cert.getKeyPassword() != null ? |
85 | | - cert.getKeyPassword().toCharArray() : new char[0]; |
86 | | - |
87 | | - keyStore.setKeyEntry("client-cert", privateKey, keyPassword, certChain); |
88 | | - |
89 | | - KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); |
90 | | - kmf.init(keyStore, keyPassword); |
91 | | - |
92 | | - log.debug("Loaded PEM certificate from: {} and key from: {}", |
93 | | - cert.getCertPath(), cert.getKeyPath()); |
94 | | - return kmf.getKeyManagers(); |
95 | | - } |
96 | | - |
97 | | - /** |
98 | | - * 从 PEM 文件加载 X509 证书 |
99 | | - */ |
100 | | - private static X509Certificate loadCertificateFromPEM(String certPath) throws IOException, CertificateException { |
101 | | - String content = new String(Files.readAllBytes(Paths.get(certPath))); |
102 | | - content = content.replace("-----BEGIN CERTIFICATE-----", "") |
103 | | - .replace("-----END CERTIFICATE-----", "") |
104 | | - .replaceAll("\\s", ""); |
105 | | - |
106 | | - byte[] certBytes = Base64.getDecoder().decode(content); |
107 | | - CertificateFactory cf = CertificateFactory.getInstance("X.509"); |
108 | | - return (X509Certificate) cf.generateCertificate( |
109 | | - new java.io.ByteArrayInputStream(certBytes)); |
110 | | - } |
111 | | - |
112 | | - /** |
113 | | - * 从 PEM 文件加载私钥 |
114 | | - */ |
115 | | - private static PrivateKey loadPrivateKeyFromPEM(String keyPath, String password) |
116 | | - throws IOException, GeneralSecurityException { |
117 | | - String content = new String(Files.readAllBytes(Paths.get(keyPath))); |
118 | | - |
119 | | - // 检查是否是加密的私钥 |
120 | | - if (content.contains("ENCRYPTED")) { |
121 | | - // 注意:password 参数预留用于未来支持加密私钥 |
122 | | - throw new IllegalArgumentException( |
123 | | - "Encrypted PEM private keys are not supported yet. " + |
124 | | - "Please use unencrypted PEM or convert to PFX/P12 format. " + |
125 | | - "Password parameter: " + (password != null ? "provided" : "not provided")); |
126 | | - } |
127 | | - |
128 | | - // 移除 PEM 头尾和空白字符 |
129 | | - content = content.replaceAll("-----BEGIN.*PRIVATE KEY-----", "") |
130 | | - .replaceAll("-----END.*PRIVATE KEY-----", "") |
131 | | - .replaceAll("\\s", ""); |
132 | | - |
133 | | - byte[] keyBytes = Base64.getDecoder().decode(content); |
134 | | - PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes); |
135 | | - |
136 | | - // 尝试 RSA |
137 | | - try { |
138 | | - KeyFactory kf = KeyFactory.getInstance("RSA"); |
139 | | - return kf.generatePrivate(spec); |
140 | | - } catch (Exception e) { |
141 | | - // 尝试 EC |
142 | | - try { |
143 | | - KeyFactory kf = KeyFactory.getInstance("EC"); |
144 | | - return kf.generatePrivate(spec); |
145 | | - } catch (Exception e2) { |
146 | | - throw new GeneralSecurityException( |
147 | | - "Failed to load private key. Supported algorithms: RSA, EC", e); |
148 | | - } |
| 86 | + return new KeyManager[]{keyManager}; |
149 | 87 | } |
150 | 88 | } |
151 | 89 |
|
|
0 commit comments