我正在使用 CryptSignMessage 和 etoken(safenet)生成 p7s,但将其插入 PDF 后,Adobe 表示无法验证签名,因为文档已被修改或损坏。
这是我的 C 函数:
int GeneratePKCS7Signature(const BYTE * pbData, DWORD cbData,
const CERTIFICATES_INFO * certInfo, BYTE ** ppbPkcs7, DWORD * pcbPkcs7) {
if (!pbData || cbData == 0 || !certInfo || !certInfo -> signerCert || !ppbPkcs7 || !pcbPkcs7) {
printf("Invalid parameters.\n");
return 1;
}
printf("Start GeneratePKCS7Signature\n");
// Verify that the signing certificate has its private key associated (using SafeNet etoken)
NCRYPT_KEY_HANDLE hKey = 0;
BOOL freeKey = FALSE;
if (!CryptAcquireCertificatePrivateKey(certInfo -> signerCert,
CRYPT_ACQUIRE_ALLOW_NCRYPT_KEY_FLAG,
NULL,
(HCRYPTPROV_OR_NCRYPT_KEY_HANDLE * ) & hKey,
NULL, &
freeKey)) {
printf("Error searching for the private key of the signing certificate: %lu\n", GetLastError());
return 1;
}
if (freeKey && hKey)
NCryptFreeObject(hKey);
// Build the array of certificates to be included in thePKCS#7:
// The signing certificate is included, then the intermediate certificates and finally the root certificates
size_t totalCertCount = 1 + certInfo -> numIntermediates + certInfo -> numRoots;
PCCERT_CONTEXT * rgpCerts = (PCCERT_CONTEXT * ) malloc(totalCertCount * sizeof(PCCERT_CONTEXT));
if (!rgpCerts) {
printf("Error allocating memory for the certificate array.\n");
return 1;
}
size_t idx = 0;
rgpCerts[idx++] = certInfo -> signerCert;
for (size_t i = 0; i < certInfo -> numIntermediates; i++) {
rgpCerts[idx++] = certInfo -> intermediates[i];
}
for (size_t i = 0; i < certInfo -> numRoots; i++) {
rgpCerts[idx++] = certInfo -> roots[i];
}
// Configure the structure CRYPT_SIGN_MESSAGE_PARA.
CRYPT_SIGN_MESSAGE_PARA signPara;
memset( & signPara, 0, sizeof(signPara));
signPara.cbSize = sizeof(CRYPT_SIGN_MESSAGE_PARA);
signPara.dwMsgEncodingType = PKCS_7_ASN_ENCODING | X509_ASN_ENCODING;
signPara.pSigningCert = certInfo -> signerCert;
signPara.HashAlgorithm.pszObjId = OID_RSA_SHA256; // SHA256
signPara.cMsgCert = (DWORD) totalCertCount;
signPara.rgpMsgCert = rgpCerts;
signPara.cAuthAttr = 0;
signPara.dwFlags = 0;
signPara.dwInnerContentType = 0;
// Prepare the parameters for the function CryptSignMessage.
const BYTE * rgpbToBeSigned[1] = {
pbData
};
DWORD rgcbToBeSigned[1] = {
cbData
};
// First call to get the required size of the PKCS#7.
DWORD cbPkcs7 = 0;
if (!CryptSignMessage( & signPara,
TRUE, // Sign detached
1,
rgpbToBeSigned,
rgcbToBeSigned,
NULL, &
cbPkcs7)) {
printf("Error calculating the size of the PKCS#7: 0x%x\n", GetLastError());
free(rgpCerts);
return 1;
}
BYTE * pbPkcs7 = (BYTE * ) HeapAlloc(GetProcessHeap(), 0, cbPkcs7);
if (!pbPkcs7) {
printf("Error allocating memory for the PKCS#7.\n");
free(rgpCerts);
return 1;
}
// Second call to generate the PKCS#7.
if (!CryptSignMessage( & signPara,
TRUE, // Sign detached
1,
rgpbToBeSigned,
rgcbToBeSigned,
pbPkcs7, &
cbPkcs7)) {
printf("Error generating the PKCS#7: 0x%x\n", GetLastError());
HeapFree(GetProcessHeap(), 0, pbPkcs7);
free(rgpCerts);
return 1;
}
* ppbPkcs7 = pbPkcs7;
* pcbPkcs7 = cbPkcs7;
free(rgpCerts);
return 0;
}
生成的 p7s 是:firma.p7s 测试 pdf 签名:pdf
我尝试了几个不同的 PDF 文件,并在签名前后验证了 SHA256 哈希值。我还使用 QPDF 等不同工具分析了 PDF 结构。因此,我认为问题出在 PKCS7、某些属性或签名本身,导致 Adobe 无法验证。我还使用 ANS.1 解码器进行了检查,尽管我修正了一些问题,但错误仍然存在。