Преглед изворни кода

1.上传根证书校验是否有ca扩展,是否是自签证书

wangkun пре 3 недеља
родитељ
комит
86d940dc7f

+ 33 - 8
src/main/java/com/ymwk/icvp/pki/service/impl/CertificateServiceImpl.java

@@ -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());
 

+ 4 - 2
src/main/resources/application.yaml

@@ -1,7 +1,6 @@
 spring:
   application:
     name: ICVP
-
   datasource:
     # 驱动类 (使用 MySQL 8.0 及以上版本推荐驱动)
     driver-class-name: com.mysql.cj.jdbc.Driver
@@ -12,8 +11,11 @@ spring:
     # 数据库密码
     password: 4RtmJimtscsK7XiN
 
+server:
+  port: 9050
+
 ocsp:
-  responder-url: http://localhost:8080/api/v1/certificate/ocsp
+  responder-url: http://10.10.10.30:9050/api/v1/certificate/ocsp
 
 minio:
   endpoint: http://10.10.10.25:9020