sm2 验签不通过
This commit is contained in:
parent
6e95e8a1b1
commit
f9d9203349
@ -253,24 +253,25 @@ function extractInfoFromJsrsasignP7(base64Data) {
|
|||||||
*/
|
*/
|
||||||
module.exports.verifyPKCS7 = function (p7sign, originalData) {
|
module.exports.verifyPKCS7 = function (p7sign, originalData) {
|
||||||
// 处理输入数据
|
// 处理输入数据
|
||||||
let pemData
|
let base64Data
|
||||||
if (Buffer.isBuffer(p7sign)) {
|
if (Buffer.isBuffer(p7sign)) {
|
||||||
pemData = p7sign.toString('ascii')
|
base64Data = p7sign.toString('base64')
|
||||||
} else if (typeof p7sign === 'string') {
|
} else if (typeof p7sign === 'string') {
|
||||||
// 判断是否是 PEM 格式
|
// 判断是否是 PEM 格式
|
||||||
if (p7sign.includes('-----BEGIN PKCS7-----')) {
|
if (p7sign.includes('-----BEGIN PKCS7-----')) {
|
||||||
pemData = p7sign
|
// 提取 base64 部分
|
||||||
|
base64Data = p7sign
|
||||||
|
.replace(/-----BEGIN PKCS7-----\n?/, '')
|
||||||
|
.replace(/-----END PKCS7-----\n?/, '')
|
||||||
|
.replace(/\n/g, '')
|
||||||
} else {
|
} else {
|
||||||
// 如果不是 PEM 格式,假设是 base64,包装成 PEM
|
// 如果不是 PEM 格式,假设是 base64
|
||||||
pemData = `-----BEGIN PKCS7-----\n${p7sign}\n-----END PKCS7-----`
|
base64Data = p7sign
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
throw new Error('Invalid input type for p7sign')
|
throw new Error('Invalid input type for p7sign')
|
||||||
}
|
}
|
||||||
|
|
||||||
// 解析 PKCS7 数据
|
|
||||||
const p7 = forge.pkcs7.messageFromPem(pemData)
|
|
||||||
|
|
||||||
// 准备验证所需的数据
|
// 准备验证所需的数据
|
||||||
let verifyData
|
let verifyData
|
||||||
if (originalData) {
|
if (originalData) {
|
||||||
@ -282,17 +283,22 @@ module.exports.verifyPKCS7 = function (p7sign, originalData) {
|
|||||||
} else {
|
} else {
|
||||||
throw new Error('Invalid input type for originalData')
|
throw new Error('Invalid input type for originalData')
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
// 当没有提供原始数据时,从 PKCS7 中提取数据进行验证(attach 模式)
|
|
||||||
if (p7.content) {
|
|
||||||
verifyData = Buffer.from(p7.content.getBytes(), 'binary')
|
|
||||||
} else {
|
|
||||||
throw new Error('No content found in PKCS7 signature for attach mode')
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 验证签名
|
// 尝试使用 node-forge 解析和验证(支持 RSA)
|
||||||
try {
|
try {
|
||||||
|
const pemData = `-----BEGIN PKCS7-----\n${base64Data}\n-----END PKCS7-----`
|
||||||
|
const p7 = forge.pkcs7.messageFromPem(pemData)
|
||||||
|
|
||||||
|
// 如果没有提供原始数据,从 PKCS7 中提取(attach 模式)
|
||||||
|
if (!verifyData) {
|
||||||
|
if (p7.content) {
|
||||||
|
verifyData = Buffer.from(p7.content.getBytes(), 'binary')
|
||||||
|
} else {
|
||||||
|
throw new Error('No content found in PKCS7 signature for attach mode')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 对于 RSA 签名,使用公钥手动验证
|
// 对于 RSA 签名,使用公钥手动验证
|
||||||
if (p7.certificates && p7.certificates.length > 0) {
|
if (p7.certificates && p7.certificates.length > 0) {
|
||||||
const publicKey = p7.certificates[0].publicKey
|
const publicKey = p7.certificates[0].publicKey
|
||||||
@ -309,22 +315,79 @@ module.exports.verifyPKCS7 = function (p7sign, originalData) {
|
|||||||
|
|
||||||
// 如果 RSA 验证失败或不适用,尝试使用 node-forge 的 verify(如果支持)
|
// 如果 RSA 验证失败或不适用,尝试使用 node-forge 的 verify(如果支持)
|
||||||
return p7.verify()
|
return p7.verify()
|
||||||
} catch (error) {
|
} catch (forgeError) {
|
||||||
// 如果验证失败,尝试使用 SM2 验证
|
// 如果 node-forge 解析失败,尝试使用 jsrsasign 解析和验证(支持 SM2)
|
||||||
try {
|
try {
|
||||||
// 提取签名值和公钥
|
return verifyPKCS7WithJsrsasign(base64Data, verifyData)
|
||||||
const signInfo = module.exports.getInfoFromPKCS7(p7sign)
|
} catch (jsrsasignError) {
|
||||||
if (!signInfo.publicKey || !signInfo.signature) {
|
// 静默处理错误,直接返回 false
|
||||||
throw new Error('Cannot extract public key or signature from PKCS7')
|
|
||||||
}
|
|
||||||
|
|
||||||
// 使用 SM2 验证签名
|
|
||||||
const hash = sm3(verifyData.toString())
|
|
||||||
return sm2.doVerify(hash, signInfo.signature, signInfo.publicKey)
|
|
||||||
} catch (sm2Error) {
|
|
||||||
console.error('SM2 verification error:', sm2Error)
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 使用 jsrsasign 验证 PKCS7 签名(支持 SM2)
|
||||||
|
*/
|
||||||
|
function verifyPKCS7WithJsrsasign(base64Data, verifyData) {
|
||||||
|
const parser = new rs.KJUR.asn1.cms.CMSParser()
|
||||||
|
const p7 = parser.getCMSSignedData(rs.b64tohex(base64Data))
|
||||||
|
|
||||||
|
// 如果没有提供原始数据,从 PKCS7 中提取(attach 模式)
|
||||||
|
if (!verifyData) {
|
||||||
|
if (p7.econtent && p7.econtent.hex) {
|
||||||
|
// econtent.hex 是原始数据的 hex 编码
|
||||||
|
verifyData = Buffer.from(p7.econtent.hex, 'hex')
|
||||||
|
} else {
|
||||||
|
throw new Error('No content found in PKCS7 signature for attach mode')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取签名信息
|
||||||
|
if (!p7.sinfos || p7.sinfos.length === 0) {
|
||||||
|
throw new Error('No signer info found in PKCS7')
|
||||||
|
}
|
||||||
|
|
||||||
|
const signer = p7.sinfos[0]
|
||||||
|
|
||||||
|
// 获取证书和公钥
|
||||||
|
if (!p7.certs || !p7.certs.array || p7.certs.array.length === 0) {
|
||||||
|
throw new Error('No certificate found in PKCS7')
|
||||||
|
}
|
||||||
|
|
||||||
|
const certPem = p7.certs.array[0]
|
||||||
|
const x509 = new rs.X509()
|
||||||
|
x509.readCertPEM(certPem)
|
||||||
|
|
||||||
|
// 判断签名算法
|
||||||
|
const sigAlg = signer.sigalg
|
||||||
|
|
||||||
|
// SM2 签名算法 OID: 1.2.156.10197.1.301.1 或 1.2.156.10197.1.501
|
||||||
|
if (sigAlg === '1.2.156.10197.1.301.1' || sigAlg === '1.2.156.10197.1.501' || sigAlg.includes('sm2')) {
|
||||||
|
// SM2 验证
|
||||||
|
// 提取公钥 hex
|
||||||
|
const certHex = rs.pemtohex(certPem)
|
||||||
|
const tbsCert = rs.ASN1HEX.getTLVbyList(certHex, 0, [0])
|
||||||
|
const spki = rs.ASN1HEX.getTLVbyList(tbsCert, 0, [6])
|
||||||
|
const publicKeyBitString = rs.ASN1HEX.getTLVbyList(spki, 0, [1])
|
||||||
|
const publicKeyHex = publicKeyBitString.substring(6) // 跳过 tag, length, unused bits
|
||||||
|
|
||||||
|
// 计算 SM3 哈希
|
||||||
|
const hash = sm3(verifyData.toString())
|
||||||
|
|
||||||
|
// 使用 SM2 验证签名 (注意:使用 doVerifySignature,不是 doVerify)
|
||||||
|
return sm2.doVerifySignature(hash, signer.sighex, publicKeyHex)
|
||||||
|
} else {
|
||||||
|
// RSA 验证(通过 jsrsasign)
|
||||||
|
try {
|
||||||
|
const pubKey = x509.getPublicKey()
|
||||||
|
const sig = new rs.KJUR.crypto.Signature({ alg: 'SHA256withRSA' })
|
||||||
|
sig.init(pubKey)
|
||||||
|
sig.updateString(verifyData.toString())
|
||||||
|
return sig.verify(signer.sighex)
|
||||||
|
} catch (e) {
|
||||||
|
throw new Error('RSA verification failed: ' + e.message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
25
kit/test/debug_sm2_api.js
Normal file
25
kit/test/debug_sm2_api.js
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
const smCrypto = require('sm-crypto');
|
||||||
|
|
||||||
|
console.log('=== 调试 sm-crypto API ===');
|
||||||
|
console.log('sm-crypto 模块:', Object.keys(smCrypto));
|
||||||
|
console.log('sm2 对象:', Object.keys(smCrypto.sm2));
|
||||||
|
console.log('sm3 对象:', typeof smCrypto.sm3);
|
||||||
|
|
||||||
|
// 测试 SM3
|
||||||
|
const testData = 'test';
|
||||||
|
const hash = smCrypto.sm3(testData);
|
||||||
|
console.log('\nSM3 哈希:', hash);
|
||||||
|
|
||||||
|
// 生成密钥对
|
||||||
|
const keypair = smCrypto.sm2.generateKeyPairHex();
|
||||||
|
console.log('\n生成的密钥对:');
|
||||||
|
console.log(' 私钥:', keypair.privateKey.substring(0, 20) + '...');
|
||||||
|
console.log(' 公钥:', keypair.publicKey.substring(0, 20) + '...');
|
||||||
|
|
||||||
|
// 签名
|
||||||
|
const sig = smCrypto.sm2.doSignature(hash, keypair.privateKey);
|
||||||
|
console.log('\n签名:', sig);
|
||||||
|
|
||||||
|
// 验证签名
|
||||||
|
const verifyResult = smCrypto.sm2.doVerifySignature(hash, sig, keypair.publicKey);
|
||||||
|
console.log('验证结果:', verifyResult);
|
||||||
80
kit/test/debug_sm2_verify.js
Normal file
80
kit/test/debug_sm2_verify.js
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
const rs = require('jsrsasign');
|
||||||
|
const sm2 = require('sm-crypto').sm2;
|
||||||
|
const sm3 = require('sm-crypto').sm3;
|
||||||
|
|
||||||
|
// 用户提供的 SM2 PKCS7 签名数据
|
||||||
|
const sm2P7Base64 = 'MIIDKgYKKoEcz1UGAQQCAqCCAxowggMWAgEBMQ4wDAYIKoEcz1UBgxEFADAMBgoqgRzPVQYBBAIBoIICNzCCAjMwggHWoAMCAQICBgD1tfRoKTAMBggqgRzPVQGDdQUAMEAxCzAJBgNVBAYTAkNOMQ8wDQYDVQQKDAZQQkNDUkMxIDAeBgNVBAMMF1BCQ0NSQyBTTTIgT3BlcmF0aW9uIENBMB4XDTI2MDQwMjA4MDEzOVoXDTM2MDMzMDA4MDEzOVowTTELMAkGA1UEBhMCQ04xDzANBgNVBAoMBlBCQ0NSQzEtMCsGA1UEAwwkOTRmMWY5MzgtZjBiZC00NzYyLTkyOGUtZjY4YTdjY2UxNDFkMFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAEu3dU5Vn20VjVL9xGCCRPB/EpATY6HW24+zIZv46Cfv0R2PGM+ZJs/dYarw7qJCnpIbe5T0PKmyyJITNVrVnnMaOBrDCBqTAfBgNVHSMEGDAWgBRUqfVQHMpD+o+YdrPK1JlRJL757zAJBgNVHRMEAjAAME8GA1UdHwRIMEYwRKBCoECkPjA8MQ4wDAYDVQQDDAVjcmw3MTEMMAoGA1UECwwDY3JsMQ8wDQYDVQQKDAZQQkNDUkMxCzAJBgNVBAYTAkNOMAsGA1UdDwQEAwIHgDAdBgNVHQ4EFgQU5bG6U0lYzWtkPJE74M/3HdafKKcwDAYIKoEcz1UBg3UFAANJADBGAiEAuLTE36/Eobcui23bFiPvOU4MOT0O0r9SyyHZ1JuvLwMCIQCejuSk03jyUAkbh1SaPx5n7WlDjI6tx9v9RJ7iw5rlojGBtzCBtAIBATBKMEAxCzAJBgNVBAYTAkNOMQ8wDQYDVQQKDAZQQkNDUkMxIDAeBgNVBAMMF1BCQ0NSQyBTTTIgT3BlcmF0aW9uIENBAgYA9bX0aCkwDAYIKoEcz1UBgxEFADANBgkqgRzPVQGCLQEFAARGMEQCIALTgWMD7io1JHfzInBwzDQpe9bonchuLFSED//JLDtnAiBmEUtr+ssAQIzFG4wY0CAj9QZxhENyCU2UYL1fhaysUA==';
|
||||||
|
|
||||||
|
// 测试用的原始数据
|
||||||
|
const mockOriginalData = 'QDJNHHVB_FWQ';
|
||||||
|
|
||||||
|
console.log('=== 调试 SM2 PKCS7 验证 ===');
|
||||||
|
console.log('原始数据:', mockOriginalData);
|
||||||
|
|
||||||
|
const parser = new rs.KJUR.asn1.cms.CMSParser();
|
||||||
|
const p7 = parser.getCMSSignedData(rs.b64tohex(sm2P7Base64));
|
||||||
|
|
||||||
|
console.log('\nPKCS7 信息:');
|
||||||
|
console.log('版本:', p7.version);
|
||||||
|
console.log('哈希算法:', p7.hashalgs);
|
||||||
|
console.log('签名者数量:', p7.sinfos ? p7.sinfos.length : 0);
|
||||||
|
|
||||||
|
if (p7.sinfos && p7.sinfos.length > 0) {
|
||||||
|
const signer = p7.sinfos[0];
|
||||||
|
console.log('\n签名者信息:');
|
||||||
|
console.log(' 签名算法:', signer.sigalg);
|
||||||
|
console.log(' 签名值 (hex):', signer.sighex);
|
||||||
|
console.log(' 签名值长度:', signer.sighex ? signer.sighex.length / 2 : 0, '字节');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 提取原始数据(econtent)
|
||||||
|
if (p7.econtent && p7.econtent.hex) {
|
||||||
|
const extractedData = Buffer.from(p7.econtent.hex, 'hex').toString();
|
||||||
|
console.log('\n从 PKCS7 提取的原始数据:', extractedData);
|
||||||
|
console.log('与提供的原始数据匹配:', extractedData === mockOriginalData);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 提取公钥
|
||||||
|
if (p7.certs && p7.certs.array && p7.certs.array.length > 0) {
|
||||||
|
const certPem = p7.certs.array[0];
|
||||||
|
const certHex = rs.pemtohex(certPem);
|
||||||
|
const tbsCert = rs.ASN1HEX.getTLVbyList(certHex, 0, [0]);
|
||||||
|
const spki = rs.ASN1HEX.getTLVbyList(tbsCert, 0, [6]);
|
||||||
|
const publicKeyBitString = rs.ASN1HEX.getTLVbyList(spki, 0, [1]);
|
||||||
|
const publicKeyHex = publicKeyBitString.substring(6);
|
||||||
|
|
||||||
|
console.log('\n公钥信息:');
|
||||||
|
console.log(' 公钥 (hex):', publicKeyHex.substring(0, 50) + '...');
|
||||||
|
console.log(' 公钥长度:', publicKeyHex.length / 2, '字节');
|
||||||
|
|
||||||
|
// 尝试验证签名
|
||||||
|
if (p7.sinfos && p7.sinfos.length > 0) {
|
||||||
|
const signer = p7.sinfos[0];
|
||||||
|
|
||||||
|
// 计算 SM3 哈希
|
||||||
|
const hash = sm3(mockOriginalData);
|
||||||
|
console.log('\nSM3 哈希:', hash);
|
||||||
|
|
||||||
|
// 尝试验证
|
||||||
|
console.log('\n尝试使用 sm-crypto 验证:');
|
||||||
|
try {
|
||||||
|
// sm-crypto 的 doVerify 需要 hash 和公钥
|
||||||
|
// 注意:sm-crypto 的 API 可能需要不同的格式
|
||||||
|
const result = sm2.doVerify(hash, signer.sighex, publicKeyHex);
|
||||||
|
console.log('验证结果:', result);
|
||||||
|
} catch (e) {
|
||||||
|
console.error('验证错误:', e.message);
|
||||||
|
|
||||||
|
// 尝试其他格式
|
||||||
|
console.log('\n尝试其他格式...');
|
||||||
|
try {
|
||||||
|
// 可能需要去掉 04 前缀
|
||||||
|
const pubKeyWithoutPrefix = publicKeyHex.substring(2);
|
||||||
|
const result = sm2.doVerify(hash, signer.sighex, pubKeyWithoutPrefix);
|
||||||
|
console.log('验证结果 (去掉前缀):', result);
|
||||||
|
} catch (e2) {
|
||||||
|
console.error('验证错误 (去掉前缀):', e2.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
32
kit/test/verify_sm2_with_real_data.js
Normal file
32
kit/test/verify_sm2_with_real_data.js
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
const crypto = require('../src/crypto.js');
|
||||||
|
|
||||||
|
// 用户提供的 SM2 PKCS7 签名数据
|
||||||
|
const sm2P7Base64 = 'MIIDKgYKKoEcz1UGAQQCAqCCAxowggMWAgEBMQ4wDAYIKoEcz1UBgxEFADAMBgoqgRzPVQYBBAIBoIICNzCCAjMwggHWoAMCAQICBgD1tfRoKTAMBggqgRzPVQGDdQUAMEAxCzAJBgNVBAYTAkNOMQ8wDQYDVQQKDAZQQkNDUkMxIDAeBgNVBAMMF1BCQ0NSQyBTTTIgT3BlcmF0aW9uIENBMB4XDTI2MDQwMjA4MDEzOVoXDTM2MDMzMDA4MDEzOVowTTELMAkGA1UEBhMCQ04xDzANBgNVBAoMBlBCQ0NSQzEtMCsGA1UEAwwkOTRmMWY5MzgtZjBiZC00NzYyLTkyOGUtZjY4YTdjY2UxNDFkMFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAEu3dU5Vn20VjVL9xGCCRPB/EpATY6HW24+zIZv46Cfv0R2PGM+ZJs/dYarw7qJCnpIbe5T0PKmyyJITNVrVnnMaOBrDCBqTAfBgNVHSMEGDAWgBRUqfVQHMpD+o+YdrPK1JlRJL757zAJBgNVHRMEAjAAME8GA1UdHwRIMEYwRKBCoECkPjA8MQ4wDAYDVQQDDAVjcmw3MTEMMAoGA1UECwwDY3JsMQ8wDQYDVQQKDAZQQkNDUkMxCzAJBgNVBAYTAkNOMAsGA1UdDwQEAwIHgDAdBgNVHQ4EFgQU5bG6U0lYzWtkPJE74M/3HdafKKcwDAYIKoEcz1UBg3UFAANJADBGAiEAuLTE36/Eobcui23bFiPvOU4MOT0O0r9SyyHZ1JuvLwMCIQCejuSk03jyUAkbh1SaPx5n7WlDjI6tx9v9RJ7iw5rlojGBtzCBtAIBATBKMEAxCzAJBgNVBAYTAkNOMQ8wDQYDVQQKDAZQQkNDUkMxIDAeBgNVBAMMF1BCQ0NSQyBTTTIgT3BlcmF0aW9uIENBAgYA9bX0aCkwDAYIKoEcz1UBgxEFADANBgkqgRzPVQGCLQEFAARGMEQCIALTgWMD7io1JHfzInBwzDQpe9bonchuLFSED//JLDtnAiBmEUtr+ssAQIzFG4wY0CAj9QZxhENyCU2UYL1fhaysUA==';
|
||||||
|
|
||||||
|
const rs = require('jsrsasign');
|
||||||
|
|
||||||
|
console.log('=== 使用真实原始数据验证 SM2 PKCS7 ===');
|
||||||
|
|
||||||
|
// 从 PKCS7 中提取原始数据
|
||||||
|
const parser = new rs.KJUR.asn1.cms.CMSParser();
|
||||||
|
const p7 = parser.getCMSSignedData(rs.b64tohex(sm2P7Base64));
|
||||||
|
|
||||||
|
let realOriginalData = null;
|
||||||
|
if (p7.econtent && p7.econtent.hex) {
|
||||||
|
realOriginalData = Buffer.from(p7.econtent.hex, 'hex').toString();
|
||||||
|
console.log('从 PKCS7 提取的原始数据:', realOriginalData);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 使用正确的原始数据进行验证
|
||||||
|
if (realOriginalData) {
|
||||||
|
console.log('\n使用提取的原始数据进行验证:');
|
||||||
|
const result = crypto.verifyPKCS7(sm2P7Base64, realOriginalData);
|
||||||
|
console.log('验证结果:', result);
|
||||||
|
} else {
|
||||||
|
console.log('无法从 PKCS7 中提取原始数据');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 也测试一下不提供原始数据的情况(attach 模式)
|
||||||
|
console.log('\n使用 attach 模式(不提供原始数据):');
|
||||||
|
const result2 = crypto.verifyPKCS7(sm2P7Base64);
|
||||||
|
console.log('验证结果:', result2);
|
||||||
Loading…
Reference in New Issue
Block a user