diff --git a/chsm-common/src/main/java/com/sunyard/chsm/mapper/CertMapper.java b/chsm-common/src/main/java/com/sunyard/chsm/mapper/AppCertMapper.java similarity index 67% rename from chsm-common/src/main/java/com/sunyard/chsm/mapper/CertMapper.java rename to chsm-common/src/main/java/com/sunyard/chsm/mapper/AppCertMapper.java index 1e64cd4..29d141a 100644 --- a/chsm-common/src/main/java/com/sunyard/chsm/mapper/CertMapper.java +++ b/chsm-common/src/main/java/com/sunyard/chsm/mapper/AppCertMapper.java @@ -2,7 +2,7 @@ package com.sunyard.chsm.mapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; -import com.sunyard.chsm.model.entity.Cert; +import com.sunyard.chsm.model.entity.AppCert; import org.apache.ibatis.annotations.Mapper; import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; @@ -14,13 +14,13 @@ import java.util.List; * @since 2024/11/6 */ @Mapper -public interface CertMapper extends BaseMapper { +public interface AppCertMapper extends BaseMapper { - default Cert selectBySN(String sn) { + default AppCert selectBySN(String sn) { Assert.hasText(sn, "证书序列号不能为空"); - List certs = selectList(new LambdaQueryWrapper() - .eq(Cert::getSerialNumber, sn) + List certs = selectList(new LambdaQueryWrapper() + .eq(AppCert::getSerialNumber, sn) ); if (CollectionUtils.isEmpty(certs)) { return null; diff --git a/chsm-common/src/main/java/com/sunyard/chsm/model/entity/Cert.java b/chsm-common/src/main/java/com/sunyard/chsm/model/entity/AppCert.java similarity index 91% rename from chsm-common/src/main/java/com/sunyard/chsm/model/entity/Cert.java rename to chsm-common/src/main/java/com/sunyard/chsm/model/entity/AppCert.java index 599ad3d..814b8f8 100644 --- a/chsm-common/src/main/java/com/sunyard/chsm/model/entity/Cert.java +++ b/chsm-common/src/main/java/com/sunyard/chsm/model/entity/AppCert.java @@ -11,8 +11,8 @@ import java.util.Date; * @since 2024/11/6 */ @Data -@TableName("sp_cert") -public class Cert { +@TableName("sp_app_cert") +public class AppCert { private Long id; private Long applicationId; @@ -22,6 +22,7 @@ public class Cert { private String keyAlg; // ENC, SIGN, CERT_CHAIN private String certType; + private String status; private Boolean single; private String version; private String subject; diff --git a/chsm-web-manage/src/main/java/com/sunyard/chsm/controller/AppCertController.java b/chsm-web-manage/src/main/java/com/sunyard/chsm/controller/AppCertController.java new file mode 100644 index 0000000..a5f7bb0 --- /dev/null +++ b/chsm-web-manage/src/main/java/com/sunyard/chsm/controller/AppCertController.java @@ -0,0 +1,57 @@ +package com.sunyard.chsm.controller; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.sunyard.chsm.dto.CertDTO; +import com.sunyard.chsm.model.R; +import com.sunyard.chsm.service.AppCertService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; +import javax.validation.Valid; + +/** + * 应用证书管理接口 + * + * @author liulu + * @since 2024/11/6 + */ +@Slf4j +@RestController +@RequestMapping("/app/cert") +public class AppCertController { + + @Resource + private AppCertService appCertService; + + /** + * 分页查询应用证书列表 + * + * @param query 查询条件 + * @return 应用列表 + */ + @GetMapping("/pageList") + public R> queryPageList(CertDTO.Query query) { + + Page page = appCertService.selectPageList(query); + + return R.data(page); + } + + + /** + * 导入证书 + * + * @param importCert 证书 + */ + @PostMapping("/import") + public void importCert(@Valid @RequestBody CertDTO.ImportCert importCert) { + appCertService.importCert(importCert); + } + + +} diff --git a/chsm-web-manage/src/main/java/com/sunyard/chsm/controller/CertController.java b/chsm-web-manage/src/main/java/com/sunyard/chsm/controller/CertController.java deleted file mode 100644 index 4f37f66..0000000 --- a/chsm-web-manage/src/main/java/com/sunyard/chsm/controller/CertController.java +++ /dev/null @@ -1,40 +0,0 @@ -package com.sunyard.chsm.controller; - -import com.sunyard.chsm.dto.CertDTO; -import com.sunyard.chsm.service.CertService; -import lombok.extern.slf4j.Slf4j; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -import javax.annotation.Resource; -import javax.validation.Valid; - -/** - * 应用证书管理接口 - * - * @author liulu - * @since 2024/11/6 - */ -@Slf4j -@RestController -@RequestMapping -public class CertController { - - @Resource - private CertService certService; - - - /** - * 导入证书 - * - * @param importCert 证书 - */ - @PostMapping("/app/cert/import") - public void importCert(@Valid @RequestBody CertDTO.ImportCert importCert) { - certService.importCert(importCert); - } - - -} diff --git a/chsm-web-manage/src/main/java/com/sunyard/chsm/dto/CertDTO.java b/chsm-web-manage/src/main/java/com/sunyard/chsm/dto/CertDTO.java index d5530e7..3033557 100644 --- a/chsm-web-manage/src/main/java/com/sunyard/chsm/dto/CertDTO.java +++ b/chsm-web-manage/src/main/java/com/sunyard/chsm/dto/CertDTO.java @@ -1,9 +1,13 @@ package com.sunyard.chsm.dto; +import com.sunyard.chsm.model.PageQuery; import lombok.Data; +import lombok.EqualsAndHashCode; import javax.validation.constraints.NotEmpty; import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; +import java.util.Date; /** * @author liulu @@ -11,6 +15,53 @@ import javax.validation.constraints.NotNull; */ public abstract class CertDTO { + @EqualsAndHashCode(callSuper = true) + @Data + public static class Query extends PageQuery { + + private Long appId; + /** + * 证书类型: encrypt_decrypt 加密证书, sign_verify 签名证书 + */ + private String certType; + } + + + @Data + public static class ACView { + private Long id; + private Long applicationId; + private String appName; + /** + * 密钥算法 + */ + private String keyAlg; + // 证书类型 + private String certType; + private String certTypeText; + /** + * 证书DN + */ + private String subject; + /** + * 序列号 + */ + private String serialNumber; + /** + * 颁发着 + */ + private String issuerDn; + /** + * 开始时间 + */ + private Date notBefore; + /** + * 结束时间 + */ + private Date notAfter; + private String remark; + private LocalDateTime createTime; + } @Data public static class ImportCert { diff --git a/chsm-web-manage/src/main/java/com/sunyard/chsm/service/CertService.java b/chsm-web-manage/src/main/java/com/sunyard/chsm/service/AppCertService.java similarity index 51% rename from chsm-web-manage/src/main/java/com/sunyard/chsm/service/CertService.java rename to chsm-web-manage/src/main/java/com/sunyard/chsm/service/AppCertService.java index 5e12771..720d634 100644 --- a/chsm-web-manage/src/main/java/com/sunyard/chsm/service/CertService.java +++ b/chsm-web-manage/src/main/java/com/sunyard/chsm/service/AppCertService.java @@ -1,13 +1,15 @@ package com.sunyard.chsm.service; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.sunyard.chsm.dto.CertDTO; /** * @author liulu * @since 2024/11/6 */ -public interface CertService { +public interface AppCertService { + + Page selectPageList(CertDTO.Query query); void importCert(CertDTO.ImportCert importCert); - } diff --git a/chsm-web-manage/src/main/java/com/sunyard/chsm/service/impl/CertServiceImpl.java b/chsm-web-manage/src/main/java/com/sunyard/chsm/service/impl/AppCertServiceImpl.java similarity index 70% rename from chsm-web-manage/src/main/java/com/sunyard/chsm/service/impl/CertServiceImpl.java rename to chsm-web-manage/src/main/java/com/sunyard/chsm/service/impl/AppCertServiceImpl.java index 87c0d58..1a9b436 100644 --- a/chsm-web-manage/src/main/java/com/sunyard/chsm/service/impl/CertServiceImpl.java +++ b/chsm-web-manage/src/main/java/com/sunyard/chsm/service/impl/AppCertServiceImpl.java @@ -1,17 +1,22 @@ package com.sunyard.chsm.service.impl; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.sunyard.chsm.dto.CertDTO; import com.sunyard.chsm.enums.KeyCategory; import com.sunyard.chsm.enums.KeyStatus; import com.sunyard.chsm.enums.KeyUsage; -import com.sunyard.chsm.mapper.CertMapper; +import com.sunyard.chsm.mapper.AppCertMapper; +import com.sunyard.chsm.mapper.ApplicationMapper; import com.sunyard.chsm.mapper.KeyInfoMapper; import com.sunyard.chsm.mapper.SpKeyRecordMapper; -import com.sunyard.chsm.model.entity.Cert; +import com.sunyard.chsm.model.entity.AppCert; +import com.sunyard.chsm.model.entity.Application; import com.sunyard.chsm.model.entity.KeyInfo; import com.sunyard.chsm.model.entity.KeyRecord; import com.sunyard.chsm.sdf.SdfApiService; -import com.sunyard.chsm.service.CertService; +import com.sunyard.chsm.service.AppCertService; import com.sunyard.chsm.utils.gm.BCECUtils; import com.sunyard.chsm.utils.gm.BCSM2Utils; import com.sunyard.chsm.utils.gm.BCSM4Utils; @@ -29,10 +34,13 @@ import org.bouncycastle.crypto.params.ECPrivateKeyParameters; import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey; import org.bouncycastle.util.BigIntegers; import org.bouncycastle.util.encoders.Hex; +import org.springframework.beans.BeanUtils; import org.springframework.data.util.Pair; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.Assert; +import org.springframework.util.CollectionUtils; +import org.springframework.util.StringUtils; import javax.annotation.Resource; import java.math.BigInteger; @@ -42,7 +50,11 @@ import java.security.cert.X509Certificate; import java.time.LocalDateTime; import java.util.Arrays; import java.util.Base64; +import java.util.List; +import java.util.Map; import java.util.Objects; +import java.util.Optional; +import java.util.stream.Collectors; /** * @author liulu @@ -51,10 +63,12 @@ import java.util.Objects; @Slf4j @Service @Transactional -public class CertServiceImpl implements CertService { +public class AppCertServiceImpl implements AppCertService { @Resource - private CertMapper certMapper; + private AppCertMapper appCertMapper; + @Resource + private ApplicationMapper applicationMapper; @Resource private SpKeyRecordMapper spKeyRecordMapper; @Resource @@ -62,6 +76,45 @@ public class CertServiceImpl implements CertService { @Resource private SdfApiService sdfApiService; + @Override + public Page selectPageList(CertDTO.Query query) { + + IPage page = appCertMapper.selectPage( + new Page<>(query.getPageNumber(), query.getPageSize()), + new LambdaQueryWrapper() + .eq(Objects.nonNull(query.getAppId()), AppCert::getApplicationId, query.getAppId()) + .eq(StringUtils.hasText(query.getCertType()), AppCert::getCertType, query.getCertType()) + .orderByDesc(AppCert::getCreateTime) + ); + List records = page.getRecords(); + if (CollectionUtils.isEmpty(records)) { + return new Page<>(page.getCurrent(), page.getSize(), page.getTotal()); + } + List appIds = records.stream().map(AppCert::getApplicationId).collect(Collectors.toList()); + Map appNameMap = applicationMapper.selectBatchIds(appIds) + .stream().collect(Collectors.toMap(Application::getId, Application::getName)); + + List viewList = records.stream() + .map(it -> { + CertDTO.ACView view = new CertDTO.ACView(); + BeanUtils.copyProperties(it, view); + Optional.ofNullable(it.getApplicationId()).map(appNameMap::get).ifPresent(view::setAppName); + KeyUsage keyUsage = KeyUsage.valueOf(it.getCertType().toUpperCase()); + switch (keyUsage) { + case ENCRYPT_DECRYPT: + view.setCertTypeText("加密证书"); + break; + case SIGN_VERIFY: + view.setCertTypeText("签名证书"); + break; + } + return view; + }) + .collect(Collectors.toList()); + + return new Page(page.getCurrent(), page.getSize(), page.getTotal()).setRecords(viewList); + } + @Override public void importCert(CertDTO.ImportCert importCert) { if (importCert.getSingle()) { @@ -98,11 +151,11 @@ public class CertServiceImpl implements CertService { && now.isBefore(keyInfo.getExpiredTime()), "此证书对应的密钥ID:" + keyInfo.getId() + "不是启用状态,无法导入"); - Cert exist = certMapper.selectBySN(x509Cert.getSerialNumber().toString()); + AppCert exist = appCertMapper.selectBySN(x509Cert.getSerialNumber().toString()); Assert.isNull(exist, "此证书已经存在"); - Cert cert = genCert(x509Cert, keyInfo.getApplicationId(), record, importCert); - certMapper.insert(cert); + AppCert cert = genCert(x509Cert, keyInfo.getApplicationId(), record, importCert); + appCertMapper.insert(cert); } @@ -140,28 +193,28 @@ public class CertServiceImpl implements CertService { } Assert.isTrue(Objects.equals(encPkHex, keys.getFirst()), "加密证书和私钥不匹配"); - Cert exist = certMapper.selectBySN(signCert.getSerialNumber().toString()); + AppCert exist = appCertMapper.selectBySN(signCert.getSerialNumber().toString()); Assert.isNull(exist, "签名证书已经存在"); - exist = certMapper.selectBySN(encCert.getSerialNumber().toString()); + exist = appCertMapper.selectBySN(encCert.getSerialNumber().toString()); Assert.isNull(exist, "加密证书已经存在"); importCert.setCertType(KeyUsage.SIGN_VERIFY.getCode()); importCert.setCertText(importCert.getSignCertText()); - Cert sign = genCert(signCert, keyInfo.getApplicationId(), record, importCert); - certMapper.insert(sign); + AppCert sign = genCert(signCert, keyInfo.getApplicationId(), record, importCert); + appCertMapper.insert(sign); importCert.setCertType(KeyUsage.ENCRYPT_DECRYPT.getCode()); importCert.setCertText(importCert.getEncCertText()); - Cert enc = genCert(encCert, keyInfo.getApplicationId(), record, importCert); + AppCert enc = genCert(encCert, keyInfo.getApplicationId(), record, importCert); enc.setPubKey(keys.getFirst()); byte[] encPri = sdfApiService.encryptByTMK(keys.getSecond()); enc.setEncPriKey(Hex.toHexString(encPri)); - certMapper.insert(enc); + appCertMapper.insert(enc); } - private Cert genCert(X509Certificate x509Cert, Long appId, KeyRecord record, CertDTO.ImportCert importCert) { - Cert cert = new Cert(); + private AppCert genCert(X509Certificate x509Cert, Long appId, KeyRecord record, CertDTO.ImportCert importCert) { + AppCert cert = new AppCert(); cert.setApplicationId(appId); cert.setKeyId(record.getKeyId()); cert.setKeyRecordId(record.getId()); diff --git a/chsm-web-manage/src/main/java/com/sunyard/chsm/service/impl/KeyInfoServiceImpl.java b/chsm-web-manage/src/main/java/com/sunyard/chsm/service/impl/KeyInfoServiceImpl.java index 6f843f1..7b49f7a 100644 --- a/chsm-web-manage/src/main/java/com/sunyard/chsm/service/impl/KeyInfoServiceImpl.java +++ b/chsm-web-manage/src/main/java/com/sunyard/chsm/service/impl/KeyInfoServiceImpl.java @@ -168,7 +168,7 @@ public class KeyInfoServiceImpl implements KeyInfoService { Assert.notNull(keyTemplate, "密钥模版不存在"); Application app = applicationMapper.selectById(save.getApplicationId()); Assert.notNull(app, "所属应用不存在"); - Assert.isTrue(EnableStatus.DISABLED.getCode().equals(app.getStatus()), "应用不是启用状态"); + Assert.isTrue(EnableStatus.ENABLED.getCode().equals(app.getStatus()), "应用不是启用状态"); LocalDateTime now = LocalDateTime.now(); diff --git a/chsm-web-manage/src/main/resources/application.yml b/chsm-web-manage/src/main/resources/application.yml index 35ae75c..16ca350 100644 --- a/chsm-web-manage/src/main/resources/application.yml +++ b/chsm-web-manage/src/main/resources/application.yml @@ -54,6 +54,9 @@ spring: max-file-size: 50MB #默认上传文件总大小是10MB max-request-size: 50MB + jackson: + time-zone: GMT+8 + date-format: yyyy-MM-dd HH:mm:ss #开启切面 aop: proxy-target-class: true diff --git a/doc/ssp_dm.sql b/doc/ssp_dm.sql index 424a6b9..d147470 100644 --- a/doc/ssp_dm.sql +++ b/doc/ssp_dm.sql @@ -160,6 +160,7 @@ CREATE TABLE sp_key_record ( key_id BIGINT NOT NULL COMMENT '密钥id', key_index VARCHAR(100) NOT NULL DEFAULT '' COMMENT '密钥索引', key_data VARCHAR(255) NOT NULL DEFAULT '' COMMENT '密钥密文', + pub_idx VARCHAR(10) NOT NULL DEFAULT '' COMMENT '公钥', pub_key VARCHAR(400) NOT NULL DEFAULT '' COMMENT '公钥', check_alg VARCHAR(30) NOT NULL DEFAULT '' COMMENT '校验算法', check_value VARCHAR(255) NOT NULL DEFAULT '' COMMENT '校验值', @@ -170,6 +171,8 @@ CREATE TABLE sp_key_record ( create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP(), PRIMARY KEY (id) ); +CREATE INDEX idx_kid ON sp_key_record(key_id); +CREATE INDEX idx_pk ON sp_key_record(pub_idx); -- 证书请求记录 CREATE TABLE sp_key_csr ( @@ -185,4 +188,29 @@ CREATE TABLE sp_key_csr ( update_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP(), create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP(), PRIMARY KEY (id) +); +-- 证书 +CREATE TABLE sp_app_cert ( + id BIGINT NOT NULL COMMENT 'id', + application_id BIGINT NOT NULL COMMENT '应用id', + key_id BIGINT NOT NULL COMMENT '密钥id', + key_record_id BIGINT NOT NULL COMMENT '密钥记录id', + key_alg VARCHAR(30) NOT NULL DEFAULT '' COMMENT '密钥算法', + cert_type VARCHAR(30) NOT NULL DEFAULT '' COMMENT '证书类型,加密|签名', + status VARCHAR(30) DEFAULT '' COMMENT '状态', + single TINYINT NOT NULL DEFAULT 0 COMMENT '是否单证', + version VARCHAR(10) NOT NULL DEFAULT '' COMMENT '证书版本', + subject VARCHAR(255) NOT NULL DEFAULT '' COMMENT 'DN', + serial_number VARCHAR(255) NOT NULL DEFAULT '' COMMENT '证书号', + issuer_dn VARCHAR(255) NOT NULL DEFAULT '' COMMENT '颁发者', + not_before TIMESTAMP NOT NULL COMMENT '开始时间', + not_after TIMESTAMP NOT NULL COMMENT '结束时间', + key_usage VARCHAR(200) NOT NULL DEFAULT '' COMMENT '密钥用途', + pub_key VARCHAR(255) NOT NULL DEFAULT '' COMMENT '公钥', + enc_pri_key VARCHAR(255) NOT NULL DEFAULT '' COMMENT '加密后的私钥', + cert_text VARCHAR(4099) NOT NULL DEFAULT '' COMMENT '证书', + remark VARCHAR(500) NOT NULL DEFAULT '' COMMENT '备注', + update_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP(), + create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP(), + PRIMARY KEY (id) ); \ No newline at end of file