|
|
@@ -804,14 +804,14 @@ public class CertificateServiceImpl implements CertificateService {
|
|
|
@Override
|
|
|
public ResponseDTO<String> uploadRootCertificate(String pemCombined, String certName) throws Exception {
|
|
|
if (pemCombined == null || pemCombined.trim().isEmpty()) {
|
|
|
- throw new IllegalArgumentException("上传文件内容为空");
|
|
|
+ return ResponseDTO.error(100001, "上传文件内容为空");
|
|
|
}
|
|
|
|
|
|
// 提取第一个证书 PEM
|
|
|
int certBegin = pemCombined.indexOf("-----BEGIN CERTIFICATE-----");
|
|
|
int certEnd = pemCombined.indexOf("-----END CERTIFICATE-----", certBegin);
|
|
|
if (certBegin < 0 || certEnd < 0) {
|
|
|
- throw new IllegalArgumentException("未找到证书内容(PEM 格式)");
|
|
|
+ return ResponseDTO.error(100001, "未找到证书内容(PEM 格式)");
|
|
|
}
|
|
|
String certPem = pemCombined.substring(certBegin, certEnd + "-----END CERTIFICATE-----".length()).trim();
|
|
|
|
|
|
@@ -819,7 +819,8 @@ public class CertificateServiceImpl implements CertificateService {
|
|
|
String privateKeyPem = null;
|
|
|
String[][] privMarkers = {
|
|
|
{"-----BEGIN PRIVATE KEY-----", "-----END PRIVATE KEY-----"},
|
|
|
- {"-----BEGIN RSA PRIVATE KEY-----", "-----END RSA PRIVATE KEY-----"}
|
|
|
+ {"-----BEGIN RSA PRIVATE KEY-----", "-----END RSA PRIVATE KEY-----"},
|
|
|
+ {"-----BEGIN EC PRIVATE KEY-----", "-----END EC PRIVATE KEY-----"}
|
|
|
};
|
|
|
for (String[] m : privMarkers) {
|
|
|
int b = pemCombined.indexOf(m[0]);
|
|
|
@@ -832,7 +833,7 @@ public class CertificateServiceImpl implements CertificateService {
|
|
|
}
|
|
|
}
|
|
|
if (privateKeyPem == null) {
|
|
|
- throw new IllegalArgumentException("未找到私钥内容(PEM 格式),上传文件必须包含私钥");
|
|
|
+ return ResponseDTO.error(100001, "未找到私钥内容(PEM 格式),上传文件必须包含私钥");
|
|
|
}
|
|
|
|
|
|
// 解析证书对象
|
|
|
@@ -843,6 +844,34 @@ public class CertificateServiceImpl implements CertificateService {
|
|
|
cert = (X509Certificate) cf.generateCertificate(bais);
|
|
|
}
|
|
|
|
|
|
+ if (cert.getBasicConstraints() < 0) {
|
|
|
+ return ResponseDTO.error(100001, "上传证书不是 CA 证书(BasicConstraints 未标记 CA)");
|
|
|
+ }
|
|
|
+ boolean[] keyUsage = cert.getKeyUsage();
|
|
|
+ if (keyUsage == null || keyUsage.length <= 5 || !keyUsage[5]) {
|
|
|
+ return ResponseDTO.error(100001, "上传证书的 KeyUsage 未包含 keyCertSign");
|
|
|
+ }
|
|
|
+ if (!cert.getSubjectX500Principal().equals(cert.getIssuerX500Principal())) {
|
|
|
+ return ResponseDTO.error(100001, "上传的根证书不是自签名证书");
|
|
|
+ }
|
|
|
+ cert.verify(cert.getPublicKey());
|
|
|
+ cert.checkValidity();
|
|
|
+
|
|
|
+ String pubAlgo = cert.getPublicKey().getAlgorithm();
|
|
|
+ String certAlgo = ("EC".equalsIgnoreCase(pubAlgo) || "SM2".equalsIgnoreCase(pubAlgo)) ? "2" : "RSA";
|
|
|
+ PrivateKey privateKey = parsePrivateKeyPem(privateKeyPem, certAlgo);
|
|
|
+ java.security.Signature keyMatchSignature =
|
|
|
+ java.security.Signature.getInstance(cert.getSigAlgName(), "BC");
|
|
|
+ byte[] challenge = UUID.randomUUID().toString().getBytes(StandardCharsets.UTF_8);
|
|
|
+ keyMatchSignature.initSign(privateKey);
|
|
|
+ keyMatchSignature.update(challenge);
|
|
|
+ byte[] proof = keyMatchSignature.sign();
|
|
|
+ keyMatchSignature.initVerify(cert.getPublicKey());
|
|
|
+ keyMatchSignature.update(challenge);
|
|
|
+ if (!keyMatchSignature.verify(proof)) {
|
|
|
+ return ResponseDTO.error(100001, "上传的私钥与证书公钥不匹配");
|
|
|
+ }
|
|
|
+
|
|
|
// 构造序列号(与系统其它处一致的十六进制大写)
|
|
|
String serialHex = cert.getSerialNumber().toString(16).toUpperCase();
|
|
|
|
|
|
@@ -855,10 +884,6 @@ public class CertificateServiceImpl implements CertificateService {
|
|
|
return ResponseDTO.error(100001,"证书已存在");
|
|
|
}
|
|
|
|
|
|
- // 推断算法:EC/SM2 -> "2",否则视作 RSA 标识 "RSA"
|
|
|
- String pubAlgo = cert.getPublicKey().getAlgorithm();
|
|
|
- String certAlgo = ("EC".equalsIgnoreCase(pubAlgo) || "SM2".equalsIgnoreCase(pubAlgo)) ? "2" : "RSA";
|
|
|
-
|
|
|
// 公钥 PEM
|
|
|
String publicKeyPem = convertPublicKeyToPem(cert.getPublicKey());
|
|
|
|