出于某些原因,我必须在没有支付平台的情况下处理苹果支付支付令牌。根据official document,我需要首先“ 验证签名”。该签名是采用base64编码的独立PKCS#7签名。我想用node.js或openssl进行验证。
因为node-forge是一种非常方便的加密工具,目前尚不支持“带有sha256的ECDSA”(link),我找不到其他替代品。我转向openssl。经过调查,似乎签名以“ CMS签名数据”格式打包。因此,我发现openssl手册中的此命令应该可以完成此工作:
openssl cms -verify -inform DER -in signature.der -content content.txt
Apple文档说:“ 确保签名是ephemeralPublicKey,data,transactionId和applicationData密钥的串联值的有效ECDSA签名”。因此,我通过从我的测试令牌中隐藏这些字段来生成我的测试内容。但是结果是:
Verification failure
C0:25:34:08:01:00:00:00:error:CMS routines:CMS_SignerInfo_verify_content:verification failure:crypto/cms/cms_sd.c:901:
C0:25:34:08:01:00:00:00:error:CMS routines:CMS_verify:content verify error:crypto/cms/cms_smime.c:399:
cms_sd.c:901正在验证签名者,因此我认为此命令是我所需要的。那我做错了吗?
更新:我发现PKI.js可以完成这项工作。详细答案如下。
PKI.js example下面的代码片段显示了如何解析现有的CMSSignedData。
const testData = "<TOKEN_SIGNATURE>";
const cmsSignedBuffer = stringToArrayBuffer(fromBase64(testData));
const asn1 = asn1js.fromBER(cmsSignedBuffer);
const cmsContentSimpl = new ContentInfo({ schema: asn1.result });
const cmsSignedSimpl = new SignedData({ schema: cmsContentSimpl.content });
此后,我们可以提取证书和签名者信息以进行进一步处理。
检查OID]:
:cmsSignedSimpl.certificates[0].extensions.find(x => x.extnID === '1.2.840.113635.100.6.29') // leaf certificate cmsSignedSimpl.certificates[1].extensions.find(x => x.extnID === '1.2.840.113635.100.6.2.14') // intermediate certificate
验证签名和信任链
:cmsSignedSimpl.verify({ signer: 0, trustedCerts: [AppleRootCA_G3], data: signedData, checkChain: true, // check x509 chain of trust extendedMode: true, // enable to show signature validation result });
检查演唱时间
const attrs = cmsSignedSimpl.signerInfos[0].signedAttrs.attributes;
const signingTimeAttr = attrs.find(x => x.type === '1.2.840.113549.1.9.5');
const signingTime = new Date(signingTimeAttr.value[0].toDate());