cpdfsignature

Generate PKCS7 Signature with CryptSignMessage / e-token


I'm generating a p7s with CryptSignMessage and etoken (safenet), but after inserting it into the PDF, Adobe indicates that the signature cannot be validated because the document was modified or corrupted.

This is my C function:

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;
}

the p7s generated is: firma.p7s test pdf signed: pdf

I've tried several different PDFs. I've also verified the SHA256 hashes before and after signing. I've analyzed the PDF structure with different tools, such as QPDF. Therefore, I think the problem is in PKCS7, some attribute, or the signature itself that's preventing Adobe from validating it. I've also checked with the ANS.1 decoder, and even though I've corrected some things, the error remains the same.


Solution

  • I don't know the details of creating signatures with CryptSignMessage, so I could only analyze your signed PDF. Some observations:

    I hope these observations help you to fix the issues in your code.