验证Apple Pay付款令牌签名

时间:2020-05-04 10:17:20

标签: node.js openssl applepay

由于某些原因,我必须在没有支付平台的情况下处理苹果支付支付令牌。根据{{​​3}},我需要先“ 验证签名”。该签名是采用base64编码的独立PKCS#7签名。我想用node.js或openssl进行验证。

由于node-forge(一种非常方便的加密工具)尚不支持“带有sha256的ECDSA”(official document),因此找不到其他替代产品。我转向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正在验证签名者,因此我认为此命令是我所需要的。那我做错了什么?

更新:我发现link可以胜任。详细答案如下。

1 个答案:

答案 0 :(得分:0)

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());