fix:p10生成签名问题
This commit is contained in:
parent
bba2d5f259
commit
cd647e8b00
@ -0,0 +1,32 @@
|
||||
package com.cisd.tms.integration.crypto.pcie.model;
|
||||
|
||||
public class UserKeySm2SignRequest {
|
||||
|
||||
private int keyIndex;
|
||||
private byte[] data;
|
||||
private byte[] userId;
|
||||
|
||||
public int getKeyIndex() {
|
||||
return keyIndex;
|
||||
}
|
||||
|
||||
public void setKeyIndex(int keyIndex) {
|
||||
this.keyIndex = keyIndex;
|
||||
}
|
||||
|
||||
public byte[] getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public void setData(byte[] data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public byte[] getUserId() {
|
||||
return userId;
|
||||
}
|
||||
|
||||
public void setUserId(byte[] userId) {
|
||||
this.userId = userId;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,41 @@
|
||||
package com.cisd.tms.integration.crypto.pcie.model;
|
||||
|
||||
public class UserKeySm2VerifyRequest {
|
||||
|
||||
private int keyIndex;
|
||||
private byte[] data;
|
||||
private byte[] userId;
|
||||
private byte[] signature;
|
||||
|
||||
public int getKeyIndex() {
|
||||
return keyIndex;
|
||||
}
|
||||
|
||||
public void setKeyIndex(int keyIndex) {
|
||||
this.keyIndex = keyIndex;
|
||||
}
|
||||
|
||||
public byte[] getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public void setData(byte[] data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public byte[] getUserId() {
|
||||
return userId;
|
||||
}
|
||||
|
||||
public void setUserId(byte[] userId) {
|
||||
this.userId = userId;
|
||||
}
|
||||
|
||||
public byte[] getSignature() {
|
||||
return signature;
|
||||
}
|
||||
|
||||
public void setSignature(byte[] signature) {
|
||||
this.signature = signature;
|
||||
}
|
||||
}
|
||||
@ -81,6 +81,8 @@ import com.cisd.tms.integration.crypto.pcie.model.StandardKeyPairResult;
|
||||
import com.cisd.tms.integration.crypto.pcie.model.UpdateBackedKeyRequest;
|
||||
import com.cisd.tms.integration.crypto.pcie.model.UserKeyDecryptRequest;
|
||||
import com.cisd.tms.integration.crypto.pcie.model.UserKeyEncryptRequest;
|
||||
import com.cisd.tms.integration.crypto.pcie.model.UserKeySm2SignRequest;
|
||||
import com.cisd.tms.integration.crypto.pcie.model.UserKeySm2VerifyRequest;
|
||||
import com.cisd.tms.integration.crypto.pcie.model.UserKeySignRequest;
|
||||
import com.cisd.tms.integration.crypto.pcie.model.UserKeyVerifyRequest;
|
||||
import com.sun.jna.Memory;
|
||||
@ -102,6 +104,7 @@ public class JnaPcieCryptoService implements PcieCryptoService {
|
||||
private static final int HMAC_MAX_LENGTH = 64;
|
||||
private static final int ECC_CIPHER_PREFIX_LENGTH = (EccRefPublicKey.MAX_LEN * 2) + 32 + Integer.BYTES;
|
||||
private static final String DEFAULT_PRIVATE_KEY_ACCESS_PASSWORD = "88888888";
|
||||
private static final byte[] DEFAULT_SM2_USER_ID = "1234567812345678".getBytes(StandardCharsets.UTF_8);
|
||||
|
||||
private final PcieSessionTemplate sessionTemplate;
|
||||
private final boolean strictAlgIdValidation;
|
||||
@ -1697,6 +1700,29 @@ public class JnaPcieCryptoService implements PcieCryptoService {
|
||||
eccInternalVerify(verifyRequest);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BackupDataResult userKeySignWithSm2Sm3(UserKeySm2SignRequest request) {
|
||||
UserKeySm2SignRequest req = requireRequest("request", request);
|
||||
int keyIndex = requireNonNegative("keyIndex", req.getKeyIndex());
|
||||
byte[] digest = digestWithSm2Sm3(keyIndex, requireBytes("data", req.getData()), normalizeSm2UserId(req.getUserId()));
|
||||
|
||||
EccInternalSignRequest signRequest = new EccInternalSignRequest();
|
||||
signRequest.setKeyIndex(keyIndex);
|
||||
signRequest.setData(digest);
|
||||
return withDefaultPrivateKeyAccess(keyIndex, () -> eccInternalSign(signRequest));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void userKeyVerifyWithSm2Sm3(UserKeySm2VerifyRequest request) {
|
||||
UserKeySm2VerifyRequest req = requireRequest("request", request);
|
||||
int keyIndex = requireNonNegative("keyIndex", req.getKeyIndex());
|
||||
EccInternalVerifyRequest verifyRequest = new EccInternalVerifyRequest();
|
||||
verifyRequest.setKeyIndex(keyIndex);
|
||||
verifyRequest.setData(digestWithSm2Sm3(keyIndex, requireBytes("data", req.getData()), normalizeSm2UserId(req.getUserId())));
|
||||
verifyRequest.setSignature(requireNonEmptyBytes("signature", req.getSignature()));
|
||||
eccInternalVerify(verifyRequest);
|
||||
}
|
||||
|
||||
@Override
|
||||
public HmacResult hmac(HmacRequest request) {
|
||||
HmacRequest req = requireRequest("request", request);
|
||||
@ -2203,4 +2229,29 @@ public class JnaPcieCryptoService implements PcieCryptoService {
|
||||
digestRequest.setOutBufferSize(32);
|
||||
return requireNonEmptyBytes("sm3Digest", digest(digestRequest).getData());
|
||||
}
|
||||
|
||||
private byte[] digestWithSm2Sm3(int keyIndex, byte[] data, byte[] userId) {
|
||||
BackupDataResult publicKeyResult = exportSignPublicKeyEcc(keyIndex);
|
||||
EccRefPublicKey publicKey = toEccRefPublicKey("publicKey", publicKeyResult.getData());
|
||||
return sessionTemplate.withSession("SDF_HashFinal_SM2", (lib, deviceHandle, sessionHandle) -> {
|
||||
sessionTemplate.ensureSuccess(
|
||||
"SDF_HashInit",
|
||||
lib.SDF_HashInit(sessionHandle, Gm0018AlgorithmIds.SM3, publicKey, userId, userId.length)
|
||||
);
|
||||
if (data.length > 0) {
|
||||
sessionTemplate.ensureSuccess("SDF_HashUpdate", lib.SDF_HashUpdate(sessionHandle, data, data.length));
|
||||
}
|
||||
byte[] out = new byte[32];
|
||||
IntByReference outLen = new IntByReference(out.length);
|
||||
sessionTemplate.ensureSuccess("SDF_HashFinal", lib.SDF_HashFinal(sessionHandle, out, outLen));
|
||||
return requireNonEmptyBytes("sm2Sm3Digest", toBackupResult("SDF_HashFinal_SM2", out, outLen.getValue()).getData());
|
||||
});
|
||||
}
|
||||
|
||||
private static byte[] normalizeSm2UserId(byte[] userId) {
|
||||
if (userId == null || userId.length == 0) {
|
||||
return Arrays.copyOf(DEFAULT_SM2_USER_ID, DEFAULT_SM2_USER_ID.length);
|
||||
}
|
||||
return Arrays.copyOf(userId, userId.length);
|
||||
}
|
||||
}
|
||||
|
||||
@ -69,6 +69,8 @@ import com.cisd.tms.integration.crypto.pcie.model.StandardKeyPairResult;
|
||||
import com.cisd.tms.integration.crypto.pcie.model.UpdateBackedKeyRequest;
|
||||
import com.cisd.tms.integration.crypto.pcie.model.UserKeyDecryptRequest;
|
||||
import com.cisd.tms.integration.crypto.pcie.model.UserKeyEncryptRequest;
|
||||
import com.cisd.tms.integration.crypto.pcie.model.UserKeySm2SignRequest;
|
||||
import com.cisd.tms.integration.crypto.pcie.model.UserKeySm2VerifyRequest;
|
||||
import com.cisd.tms.integration.crypto.pcie.model.UserKeySignRequest;
|
||||
import com.cisd.tms.integration.crypto.pcie.model.UserKeyVerifyRequest;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
@ -748,6 +750,24 @@ public class MockPcieCryptoService implements PcieCryptoService {
|
||||
eccInternalVerify(verifyRequest);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BackupDataResult userKeySignWithSm2Sm3(UserKeySm2SignRequest request) {
|
||||
UserKeySm2SignRequest req = requireRequest("request", request);
|
||||
requireNonNegative("keyIndex", req.getKeyIndex());
|
||||
requireBytes("data", req.getData());
|
||||
requireBytes("userId", req.getUserId());
|
||||
return mockBackup(new EccSignature().size(), 0x4A);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void userKeyVerifyWithSm2Sm3(UserKeySm2VerifyRequest request) {
|
||||
UserKeySm2VerifyRequest req = requireRequest("request", request);
|
||||
requireNonNegative("keyIndex", req.getKeyIndex());
|
||||
requireBytes("data", req.getData());
|
||||
requireBytes("userId", req.getUserId());
|
||||
requireNonEmptyBytes("signature", req.getSignature());
|
||||
}
|
||||
|
||||
@Override
|
||||
public HmacResult hmac(HmacRequest request) {
|
||||
HmacRequest req = requireRequest("request", request);
|
||||
|
||||
@ -59,6 +59,8 @@ import com.cisd.tms.integration.crypto.pcie.model.StandardKeyPairResult;
|
||||
import com.cisd.tms.integration.crypto.pcie.model.UpdateBackedKeyRequest;
|
||||
import com.cisd.tms.integration.crypto.pcie.model.UserKeyDecryptRequest;
|
||||
import com.cisd.tms.integration.crypto.pcie.model.UserKeyEncryptRequest;
|
||||
import com.cisd.tms.integration.crypto.pcie.model.UserKeySm2SignRequest;
|
||||
import com.cisd.tms.integration.crypto.pcie.model.UserKeySm2VerifyRequest;
|
||||
import com.cisd.tms.integration.crypto.pcie.model.UserKeySignRequest;
|
||||
import com.cisd.tms.integration.crypto.pcie.model.UserKeyVerifyRequest;
|
||||
|
||||
@ -479,6 +481,16 @@ public interface PcieCryptoService {
|
||||
*/
|
||||
void userKeyVerifyWithSm3(UserKeyVerifyRequest request);
|
||||
|
||||
/**
|
||||
* 按标准 SM2-with-SM3 流程计算 ZA || 原文摘要,再使用用户签名密钥完成内部 ECC 签名。
|
||||
*/
|
||||
BackupDataResult userKeySignWithSm2Sm3(UserKeySm2SignRequest request);
|
||||
|
||||
/**
|
||||
* 按标准 SM2-with-SM3 流程计算 ZA || 原文摘要,再使用用户签名公钥完成内部 ECC 验签。
|
||||
*/
|
||||
void userKeyVerifyWithSm2Sm3(UserKeySm2VerifyRequest request);
|
||||
|
||||
/**
|
||||
* 使用 SD FE HMAC 流程计算 HMAC。
|
||||
*/
|
||||
|
||||
@ -1,14 +1,15 @@
|
||||
package com.cisd.tms.modules.cert.dto;
|
||||
|
||||
import lombok.Data;
|
||||
import org.bouncycastle.asn1.x500.X500Name;
|
||||
import org.bouncycastle.asn1.x500.X500NameBuilder;
|
||||
import org.bouncycastle.asn1.x500.style.BCStyle;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
@Data
|
||||
public class Subject {
|
||||
|
||||
private static final String COMMA = ",";
|
||||
|
||||
private String commonName;
|
||||
private String country;
|
||||
private String province;
|
||||
@ -17,28 +18,32 @@ public class Subject {
|
||||
private String orgUnit;
|
||||
|
||||
public String getDN() {
|
||||
return toX500Name().toString();
|
||||
}
|
||||
|
||||
public X500Name toX500Name() {
|
||||
Assert.hasText(commonName, "commonName must not be blank");
|
||||
StringBuilder builder = new StringBuilder();
|
||||
X500NameBuilder builder = new X500NameBuilder(BCStyle.INSTANCE);
|
||||
if (StringUtils.hasText(commonName)) {
|
||||
builder.append("CN=").append(commonName).append(COMMA);
|
||||
builder.addRDN(BCStyle.CN, commonName);
|
||||
}
|
||||
if (StringUtils.hasText(orgUnit)) {
|
||||
builder.append("OU=").append(orgUnit).append(COMMA);
|
||||
builder.addRDN(BCStyle.OU, orgUnit);
|
||||
}
|
||||
if (StringUtils.hasText(org)) {
|
||||
builder.append("O=").append(org).append(COMMA);
|
||||
builder.addRDN(BCStyle.O, org);
|
||||
}
|
||||
if (StringUtils.hasText(city)) {
|
||||
builder.append("L=").append(city).append(COMMA);
|
||||
builder.addRDN(BCStyle.L, city);
|
||||
}
|
||||
if (StringUtils.hasText(province)) {
|
||||
builder.append("ST=").append(province).append(COMMA);
|
||||
builder.addRDN(BCStyle.ST, province);
|
||||
}
|
||||
if (StringUtils.hasText(country)) {
|
||||
builder.append("C=").append(country).append(COMMA);
|
||||
Assert.isTrue(country.length() == 2, "country must be a 2-letter country code");
|
||||
builder.addRDN(BCStyle.C, country);
|
||||
}
|
||||
builder.deleteCharAt(builder.length() - 1);
|
||||
return builder.toString();
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
public static Subject fromDN(String dn) {
|
||||
|
||||
@ -6,7 +6,7 @@ import com.cisd.tms.common.exception.BizException;
|
||||
import com.cisd.tms.integration.crypto.pcie.PcieUserKeyType;
|
||||
import com.cisd.tms.integration.crypto.pcie.model.BackupDataResult;
|
||||
import com.cisd.tms.integration.crypto.pcie.model.GenerateKeyPairRequest;
|
||||
import com.cisd.tms.integration.crypto.pcie.model.UserKeySignRequest;
|
||||
import com.cisd.tms.integration.crypto.pcie.model.UserKeySm2SignRequest;
|
||||
import com.cisd.tms.integration.crypto.pcie.service.PcieCryptoService;
|
||||
import com.cisd.tms.modules.cert.dto.EntityCreateRequest;
|
||||
import com.cisd.tms.modules.cert.dto.EntityCreateResponse;
|
||||
@ -44,6 +44,7 @@ import java.util.List;
|
||||
public class EntityService {
|
||||
|
||||
private static final String SM2 = "SM2";
|
||||
private static final byte[] DEFAULT_SM2_USER_ID = "1234567812345678".getBytes(StandardCharsets.UTF_8);
|
||||
|
||||
private final KeyEntityRepository keyEntityRepository;
|
||||
private final CertificateRepository certificateRepository;
|
||||
@ -132,10 +133,11 @@ public class EntityService {
|
||||
public String generateP10(EntityGenP10Request request) {
|
||||
KeyEntity entity = getById(request.getId());
|
||||
Subject subject = request.getSubject();
|
||||
String subjectDn = subject.getDN();
|
||||
X500Name subjectName = subject.toX500Name();
|
||||
String subjectDn = subjectName.toString();
|
||||
PublicKey publicKey = Sm2KeySupport.toSm2PublicKey(Base64.getDecoder().decode(entity.getPublicKey()));
|
||||
PKCS10CertificationRequestBuilder builder =
|
||||
new JcaPKCS10CertificationRequestBuilder(new X500Name(subjectDn), publicKey);
|
||||
new JcaPKCS10CertificationRequestBuilder(subjectName, publicKey);
|
||||
PKCS10CertificationRequest csr = builder.build(new CardContentSigner(entity.getKeyIdx(), pcieCryptoService));
|
||||
String pem = encodePkcs10Pem(csr);
|
||||
entity.setSubjectDn(subjectDn);
|
||||
@ -229,10 +231,11 @@ public class EntityService {
|
||||
|
||||
@Override
|
||||
public byte[] getSignature() {
|
||||
UserKeySignRequest request = new UserKeySignRequest();
|
||||
UserKeySm2SignRequest request = new UserKeySm2SignRequest();
|
||||
request.setKeyIndex(keyIdx);
|
||||
request.setData(output.toByteArray());
|
||||
return Sm2KeySupport.rawSignatureToDer(pcieCryptoService.userKeySignWithSm3(request).getData());
|
||||
request.setUserId(DEFAULT_SM2_USER_ID);
|
||||
return Sm2KeySupport.rawSignatureToDer(pcieCryptoService.userKeySignWithSm2Sm3(request).getData());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -41,6 +41,8 @@ import com.cisd.tms.integration.crypto.pcie.model.SymmetricKekCryptoRequest;
|
||||
import com.cisd.tms.integration.crypto.pcie.model.StandardKeyPairResult;
|
||||
import com.cisd.tms.integration.crypto.pcie.model.UserKeyDecryptRequest;
|
||||
import com.cisd.tms.integration.crypto.pcie.model.UserKeyEncryptRequest;
|
||||
import com.cisd.tms.integration.crypto.pcie.model.UserKeySm2SignRequest;
|
||||
import com.cisd.tms.integration.crypto.pcie.model.UserKeySm2VerifyRequest;
|
||||
import com.cisd.tms.integration.crypto.pcie.model.UserKeySignRequest;
|
||||
import com.cisd.tms.integration.crypto.pcie.model.UserKeyVerifyRequest;
|
||||
import com.cisd.tms.integration.crypto.pcie.service.PcieDeviceStatusFormatter;
|
||||
@ -78,6 +80,7 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
public class CryptoCardController {
|
||||
|
||||
private static final String DEFAULT_USER_KEY_ACCESS_PASSWORD = "88888888";
|
||||
private static final byte[] DEFAULT_SM2_USER_ID = "1234567812345678".getBytes(StandardCharsets.UTF_8);
|
||||
|
||||
private final PcieCryptoService pcieCryptoService;
|
||||
|
||||
@ -598,6 +601,44 @@ public class CryptoCardController {
|
||||
return ApiResponse.success(Map.of("passed", true));
|
||||
}
|
||||
|
||||
@PostMapping("/user-key/sm2-sign")
|
||||
@Operation(summary = "用户密钥 SM2-with-SM3 签名", description = "使用用户签名密钥按标准 SM2 ZA + SM3 流程完成内部 ECC 签名。")
|
||||
public ApiResponse<Map<String, Object>> signUserKeyWithSm2Sm3(
|
||||
@Valid @RequestBody CryptoUserKeySm2SignInternalRequest request
|
||||
) {
|
||||
UserKeySm2SignRequest signRequest = new UserKeySm2SignRequest();
|
||||
signRequest.setKeyIndex(request.getKeyIndex());
|
||||
signRequest.setData(Base64.getDecoder().decode(request.getDataBase64()));
|
||||
signRequest.setUserId(request.getUserIdBase64() == null || request.getUserIdBase64().isBlank()
|
||||
? DEFAULT_SM2_USER_ID
|
||||
: Base64.getDecoder().decode(request.getUserIdBase64()));
|
||||
BackupDataResult result = pcieCryptoService.userKeySignWithSm2Sm3(signRequest);
|
||||
int length = result.getLength() > 0 && result.getLength() <= result.getData().length
|
||||
? result.getLength()
|
||||
: result.getData().length;
|
||||
byte[] signature = Arrays.copyOf(result.getData(), length);
|
||||
return ApiResponse.success(Map.of(
|
||||
"length", length,
|
||||
"signatureBase64", Base64.getEncoder().encodeToString(signature)
|
||||
));
|
||||
}
|
||||
|
||||
@PostMapping("/user-key/sm2-verify")
|
||||
@Operation(summary = "用户密钥 SM2-with-SM3 验签", description = "使用用户签名公钥按标准 SM2 ZA + SM3 流程完成内部 ECC 验签。")
|
||||
public ApiResponse<Map<String, Object>> verifyUserKeyWithSm2Sm3(
|
||||
@Valid @RequestBody CryptoUserKeySm2VerifyInternalRequest request
|
||||
) {
|
||||
UserKeySm2VerifyRequest verifyRequest = new UserKeySm2VerifyRequest();
|
||||
verifyRequest.setKeyIndex(request.getKeyIndex());
|
||||
verifyRequest.setData(Base64.getDecoder().decode(request.getDataBase64()));
|
||||
verifyRequest.setUserId(request.getUserIdBase64() == null || request.getUserIdBase64().isBlank()
|
||||
? DEFAULT_SM2_USER_ID
|
||||
: Base64.getDecoder().decode(request.getUserIdBase64()));
|
||||
verifyRequest.setSignature(Base64.getDecoder().decode(request.getSignatureBase64()));
|
||||
pcieCryptoService.userKeyVerifyWithSm2Sm3(verifyRequest);
|
||||
return ApiResponse.success(Map.of("passed", true));
|
||||
}
|
||||
|
||||
@PostMapping("/user-key/self-test")
|
||||
@Operation(summary = "执行用户密钥全流程自测", description = "依次执行 ECC 用户密钥生成、备份、删除、重建槽位、恢复和状态校验,返回备份 HEX 与关键状态。")
|
||||
public ApiResponse<Map<String, Object>> selfTestUserKey(
|
||||
|
||||
@ -0,0 +1,39 @@
|
||||
package com.cisd.tms.modules.device.dto.crypto.request;
|
||||
|
||||
import jakarta.validation.constraints.Min;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
|
||||
public class CryptoUserKeySm2SignInternalRequest {
|
||||
|
||||
@Min(0)
|
||||
private int keyIndex;
|
||||
|
||||
@NotBlank
|
||||
private String dataBase64;
|
||||
|
||||
private String userIdBase64;
|
||||
|
||||
public int getKeyIndex() {
|
||||
return keyIndex;
|
||||
}
|
||||
|
||||
public void setKeyIndex(int keyIndex) {
|
||||
this.keyIndex = keyIndex;
|
||||
}
|
||||
|
||||
public String getDataBase64() {
|
||||
return dataBase64;
|
||||
}
|
||||
|
||||
public void setDataBase64(String dataBase64) {
|
||||
this.dataBase64 = dataBase64;
|
||||
}
|
||||
|
||||
public String getUserIdBase64() {
|
||||
return userIdBase64;
|
||||
}
|
||||
|
||||
public void setUserIdBase64(String userIdBase64) {
|
||||
this.userIdBase64 = userIdBase64;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,50 @@
|
||||
package com.cisd.tms.modules.device.dto.crypto.request;
|
||||
|
||||
import jakarta.validation.constraints.Min;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
|
||||
public class CryptoUserKeySm2VerifyInternalRequest {
|
||||
|
||||
@Min(0)
|
||||
private int keyIndex;
|
||||
|
||||
@NotBlank
|
||||
private String dataBase64;
|
||||
|
||||
private String userIdBase64;
|
||||
|
||||
@NotBlank
|
||||
private String signatureBase64;
|
||||
|
||||
public int getKeyIndex() {
|
||||
return keyIndex;
|
||||
}
|
||||
|
||||
public void setKeyIndex(int keyIndex) {
|
||||
this.keyIndex = keyIndex;
|
||||
}
|
||||
|
||||
public String getDataBase64() {
|
||||
return dataBase64;
|
||||
}
|
||||
|
||||
public void setDataBase64(String dataBase64) {
|
||||
this.dataBase64 = dataBase64;
|
||||
}
|
||||
|
||||
public String getUserIdBase64() {
|
||||
return userIdBase64;
|
||||
}
|
||||
|
||||
public void setUserIdBase64(String userIdBase64) {
|
||||
this.userIdBase64 = userIdBase64;
|
||||
}
|
||||
|
||||
public String getSignatureBase64() {
|
||||
return signatureBase64;
|
||||
}
|
||||
|
||||
public void setSignatureBase64(String signatureBase64) {
|
||||
this.signatureBase64 = signatureBase64;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,136 @@
|
||||
package com.cisd.tms.modules.cert.service;
|
||||
|
||||
import com.cisd.tms.integration.crypto.pcie.jna.EccRefPublicKey;
|
||||
import com.cisd.tms.integration.crypto.pcie.jna.EccSignature;
|
||||
import com.cisd.tms.integration.crypto.pcie.model.BackupDataResult;
|
||||
import com.cisd.tms.integration.crypto.pcie.model.UserKeySignRequest;
|
||||
import com.cisd.tms.integration.crypto.pcie.model.UserKeySm2SignRequest;
|
||||
import com.cisd.tms.integration.crypto.pcie.service.PcieCryptoService;
|
||||
import com.cisd.tms.modules.cert.dto.EntityGenP10Request;
|
||||
import com.cisd.tms.modules.cert.dto.Subject;
|
||||
import com.cisd.tms.modules.cert.entity.KeyEntity;
|
||||
import com.cisd.tms.modules.cert.repository.CertificateRepository;
|
||||
import com.cisd.tms.modules.cert.repository.KeyEntityRepository;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.bouncycastle.asn1.x500.style.BCStyle;
|
||||
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
||||
import org.bouncycastle.openssl.PEMParser;
|
||||
import org.bouncycastle.pkcs.PKCS10CertificationRequest;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
import java.io.StringReader;
|
||||
import java.security.KeyPairGenerator;
|
||||
import java.security.Security;
|
||||
import java.security.interfaces.ECPublicKey;
|
||||
import java.security.spec.ECGenParameterSpec;
|
||||
import java.util.Base64;
|
||||
import java.util.Optional;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
|
||||
class EntityServiceTest {
|
||||
|
||||
@Test
|
||||
void shouldGenerateP10WithStandardSm2Sm3Signer() throws Exception {
|
||||
KeyEntityRepository keyEntityRepository = Mockito.mock(KeyEntityRepository.class);
|
||||
CertificateRepository certificateRepository = Mockito.mock(CertificateRepository.class);
|
||||
PcieCryptoService pcieCryptoService = Mockito.mock(PcieCryptoService.class);
|
||||
EntityService service = new EntityService(keyEntityRepository, certificateRepository, pcieCryptoService, new ObjectMapper());
|
||||
Mockito.when(keyEntityRepository.findById(10L)).thenReturn(Optional.of(keyEntity(10L, 5)));
|
||||
Mockito.when(keyEntityRepository.save(any())).thenAnswer(invocation -> invocation.getArgument(0));
|
||||
Mockito.when(pcieCryptoService.userKeySignWithSm3(any())).thenReturn(signatureResult());
|
||||
Mockito.when(pcieCryptoService.userKeySignWithSm2Sm3(any())).thenReturn(signatureResult());
|
||||
|
||||
service.generateP10(genP10Request("TMS-001"));
|
||||
|
||||
ArgumentCaptor<UserKeySm2SignRequest> sm2Captor = ArgumentCaptor.forClass(UserKeySm2SignRequest.class);
|
||||
Mockito.verify(pcieCryptoService).userKeySignWithSm2Sm3(sm2Captor.capture());
|
||||
Mockito.verify(pcieCryptoService, Mockito.never()).userKeySignWithSm3(any(UserKeySignRequest.class));
|
||||
assertEquals(5, sm2Captor.getValue().getKeyIndex());
|
||||
assertEquals("1234567812345678", new String(sm2Captor.getValue().getUserId()));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldPreserveSpecialCharactersInP10Subject() throws Exception {
|
||||
KeyEntityRepository keyEntityRepository = Mockito.mock(KeyEntityRepository.class);
|
||||
CertificateRepository certificateRepository = Mockito.mock(CertificateRepository.class);
|
||||
PcieCryptoService pcieCryptoService = Mockito.mock(PcieCryptoService.class);
|
||||
EntityService service = new EntityService(keyEntityRepository, certificateRepository, pcieCryptoService, new ObjectMapper());
|
||||
Mockito.when(keyEntityRepository.findById(10L)).thenReturn(Optional.of(keyEntity(10L, 5)));
|
||||
Mockito.when(keyEntityRepository.save(any())).thenAnswer(invocation -> invocation.getArgument(0));
|
||||
Mockito.when(pcieCryptoService.userKeySignWithSm3(any())).thenReturn(signatureResult());
|
||||
Mockito.when(pcieCryptoService.userKeySignWithSm2Sm3(any())).thenReturn(signatureResult());
|
||||
|
||||
String pem = service.generateP10(genP10Request("TMS,Entity+001"));
|
||||
|
||||
PKCS10CertificationRequest csr = (PKCS10CertificationRequest) new PEMParser(new StringReader(pem)).readObject();
|
||||
String commonName = csr.getSubject().getRDNs(BCStyle.CN)[0].getFirst().getValue().toString();
|
||||
assertEquals("TMS,Entity+001", commonName);
|
||||
}
|
||||
|
||||
private EntityGenP10Request genP10Request(String commonName) {
|
||||
Subject subject = new Subject();
|
||||
subject.setCommonName(commonName);
|
||||
subject.setOrgUnit("Cert");
|
||||
subject.setOrg("CISD");
|
||||
subject.setCity("南南市");
|
||||
subject.setProvince("陕西省");
|
||||
subject.setCountry("CN");
|
||||
EntityGenP10Request request = new EntityGenP10Request();
|
||||
request.setId(10L);
|
||||
request.setSubject(subject);
|
||||
return request;
|
||||
}
|
||||
|
||||
private KeyEntity keyEntity(Long id, int keyIdx) throws Exception {
|
||||
KeyEntity entity = new KeyEntity();
|
||||
entity.setId(id);
|
||||
entity.setKeyIdx(keyIdx);
|
||||
entity.setPublicKey(Base64.getEncoder().encodeToString(gm0018EccRefPublicKey(generateSm2PublicKey())));
|
||||
return entity;
|
||||
}
|
||||
|
||||
private BackupDataResult signatureResult() {
|
||||
EccSignature signature = new EccSignature();
|
||||
signature.r[EccRefPublicKey.MAX_LEN - 1] = 0x01;
|
||||
signature.s[EccRefPublicKey.MAX_LEN - 1] = 0x02;
|
||||
signature.write();
|
||||
BackupDataResult result = new BackupDataResult();
|
||||
result.setLength(signature.size());
|
||||
result.setData(signature.getPointer().getByteArray(0, signature.size()));
|
||||
return result;
|
||||
}
|
||||
|
||||
private ECPublicKey generateSm2PublicKey() throws Exception {
|
||||
if (Security.getProvider("BC") == null) {
|
||||
Security.addProvider(new BouncyCastleProvider());
|
||||
}
|
||||
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("EC", "BC");
|
||||
keyPairGenerator.initialize(new ECGenParameterSpec("sm2p256v1"));
|
||||
return (ECPublicKey) keyPairGenerator.generateKeyPair().getPublic();
|
||||
}
|
||||
|
||||
private byte[] gm0018EccRefPublicKey(ECPublicKey publicKey) {
|
||||
byte[] x = toFixed32(publicKey.getW().getAffineX().toByteArray());
|
||||
byte[] y = toFixed32(publicKey.getW().getAffineY().toByteArray());
|
||||
byte[] result = new byte[new EccRefPublicKey().size()];
|
||||
result[0] = 0x00;
|
||||
result[1] = 0x01;
|
||||
result[2] = 0x00;
|
||||
result[3] = 0x00;
|
||||
System.arraycopy(x, 0, result, 4 + 32, 32);
|
||||
System.arraycopy(y, 0, result, 4 + 64 + 32, 32);
|
||||
return result;
|
||||
}
|
||||
|
||||
private byte[] toFixed32(byte[] source) {
|
||||
byte[] result = new byte[32];
|
||||
int copyLen = Math.min(source.length, 32);
|
||||
System.arraycopy(source, source.length - copyLen, result, 32 - copyLen, copyLen);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@ -15,6 +15,8 @@ import com.cisd.tms.integration.crypto.pcie.model.PrivateKeyAccessRequest;
|
||||
import com.cisd.tms.integration.crypto.pcie.model.RecoverUserKeyRequest;
|
||||
import com.cisd.tms.integration.crypto.pcie.model.UserKeyDecryptRequest;
|
||||
import com.cisd.tms.integration.crypto.pcie.model.UserKeyEncryptRequest;
|
||||
import com.cisd.tms.integration.crypto.pcie.model.UserKeySm2SignRequest;
|
||||
import com.cisd.tms.integration.crypto.pcie.model.UserKeySm2VerifyRequest;
|
||||
import com.cisd.tms.integration.crypto.pcie.model.UserKeySignRequest;
|
||||
import com.cisd.tms.integration.crypto.pcie.model.UserKeyVerifyRequest;
|
||||
import com.cisd.tms.integration.crypto.pcie.service.PcieCryptoService;
|
||||
@ -393,6 +395,66 @@ class CryptoCardControllerTest {
|
||||
assertArrayEquals(new byte[] {0x11, 0x22, 0x33, 0x44}, captor.getValue().getSignature());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldSignUserKeyWithStandardSm2Sm3Endpoint() throws Exception {
|
||||
PcieCryptoService pcieCryptoService = Mockito.mock(PcieCryptoService.class);
|
||||
BackupDataResult result = new BackupDataResult();
|
||||
result.setLength(4);
|
||||
result.setData(new byte[] {0x11, 0x22, 0x33, 0x44});
|
||||
Mockito.when(pcieCryptoService.userKeySignWithSm2Sm3(Mockito.any())).thenReturn(result);
|
||||
|
||||
MockMvc mockMvc = MockMvcBuilders.standaloneSetup(new CryptoCardController(pcieCryptoService))
|
||||
.setControllerAdvice(new GlobalExceptionHandler())
|
||||
.build();
|
||||
|
||||
mockMvc.perform(post("/api/v1/device/crypto/user-key/sm2-sign")
|
||||
.contentType("application/json")
|
||||
.content("""
|
||||
{
|
||||
"keyIndex": 7,
|
||||
"dataBase64": "Y3Ny",
|
||||
"userIdBase64": "MTIzNDU2NzgxMjM0NTY3OA=="
|
||||
}
|
||||
"""))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(content().string(containsString("\"length\":4")))
|
||||
.andExpect(content().string(containsString("\"signatureBase64\":\"ESIzRA==\"")));
|
||||
|
||||
ArgumentCaptor<UserKeySm2SignRequest> captor = ArgumentCaptor.forClass(UserKeySm2SignRequest.class);
|
||||
Mockito.verify(pcieCryptoService).userKeySignWithSm2Sm3(captor.capture());
|
||||
assertEquals(7, captor.getValue().getKeyIndex());
|
||||
assertArrayEquals("csr".getBytes(java.nio.charset.StandardCharsets.UTF_8), captor.getValue().getData());
|
||||
assertArrayEquals("1234567812345678".getBytes(java.nio.charset.StandardCharsets.UTF_8), captor.getValue().getUserId());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldVerifyUserKeyWithStandardSm2Sm3Endpoint() throws Exception {
|
||||
PcieCryptoService pcieCryptoService = Mockito.mock(PcieCryptoService.class);
|
||||
|
||||
MockMvc mockMvc = MockMvcBuilders.standaloneSetup(new CryptoCardController(pcieCryptoService))
|
||||
.setControllerAdvice(new GlobalExceptionHandler())
|
||||
.build();
|
||||
|
||||
mockMvc.perform(post("/api/v1/device/crypto/user-key/sm2-verify")
|
||||
.contentType("application/json")
|
||||
.content("""
|
||||
{
|
||||
"keyIndex": 7,
|
||||
"dataBase64": "Y3Ny",
|
||||
"signatureBase64": "ESIzRA=="
|
||||
}
|
||||
"""))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(content().string(containsString("\"passed\":true")));
|
||||
|
||||
ArgumentCaptor<UserKeySm2VerifyRequest> captor = ArgumentCaptor.forClass(UserKeySm2VerifyRequest.class);
|
||||
Mockito.verify(pcieCryptoService).userKeyVerifyWithSm2Sm3(captor.capture());
|
||||
assertEquals(7, captor.getValue().getKeyIndex());
|
||||
assertArrayEquals("csr".getBytes(java.nio.charset.StandardCharsets.UTF_8), captor.getValue().getData());
|
||||
assertArrayEquals("1234567812345678".getBytes(java.nio.charset.StandardCharsets.UTF_8), captor.getValue().getUserId());
|
||||
assertArrayEquals(new byte[] {0x11, 0x22, 0x33, 0x44}, captor.getValue().getSignature());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldRunUserKeyCryptoSelfTestFlow() throws Exception {
|
||||
PcieCryptoService pcieCryptoService = Mockito.mock(PcieCryptoService.class);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user