fix:p10生成签名问题

This commit is contained in:
waner
2026-04-28 15:21:58 +08:00
parent bba2d5f259
commit cd647e8b00
12 changed files with 508 additions and 16 deletions
@@ -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;
}
}