SignerSignEx returns error 0x80070020

Hi all,

A customer of mine used my code in How to sign EXE files with an Authenticode certificate (part 2) and followed my recommendations in SignerSignEx returns error 0x800b0003 to be able to sign all type of files (EXEs, DLLs, OCXs, MSIs, etc.) with SignerSignEx. This worked fine.

But when passing a valid time stamp server URL to the API's pwszHttpTimeStamp parameter in order to time stamp the signature, he got the following error when signing i.e. EXEs: 0x80070020 / -2147024864 / ERROR_SHARING_VIOLATION / "The process cannot access the file because it is being used by another process" .

Note he didn't get the error when signing i.e. MSIs. Also note that after the API failed, the file was correctly signed as we could see with i.e. Explorer, but signature was not time stamped as expected.

Fortunatelly we could time stamp the signatures of all file types by doing the following: first, call SignerSignEx without passing time stamp server URL, so it signs all type of files without returning the error above. Immediately after that, call SignerTimeStampEx to time stamp the signature. The following sample shows how to achieve this:

 #include "windows.h"
#include "Wincrypt.h"
#include "stdio.h"
#include "conio.h"


// STRUCTS

typedef struct _SIGNER_FILE_INFO {  
 DWORD cbSize;  
 LPCWSTR pwszFileName;  
 HANDLE hFile;
} SIGNER_FILE_INFO,  *PSIGNER_FILE_INFO;

typedef struct _SIGNER_BLOB_INFO {  
   DWORD cbSize;  
 GUID *pGuidSubject;  
   DWORD cbBlob;  
 BYTE *pbBlob;  
 LPCWSTR pwszDisplayName;
} SIGNER_BLOB_INFO,  *PSIGNER_BLOB_INFO;

typedef struct _SIGNER_SUBJECT_INFO {  
 DWORD cbSize;  
 DWORD *pdwIndex;  
  DWORD dwSubjectChoice;  
    union {    
     SIGNER_FILE_INFO *pSignerFileInfo;    
      SIGNER_BLOB_INFO *pSignerBlobInfo;  
    } ;
} SIGNER_SUBJECT_INFO,  *PSIGNER_SUBJECT_INFO;

typedef struct _SIGNER_CERT_STORE_INFO {  
 DWORD cbSize;  
 PCCERT_CONTEXT pSigningCert;  
  DWORD dwCertPolicy;  
   HCERTSTORE hCertStore;
} SIGNER_CERT_STORE_INFO,  *PSIGNER_CERT_STORE_INFO;

typedef struct _SIGNER_SPC_CHAIN_INFO {  
 DWORD cbSize;  
 LPCWSTR pwszSpcFile;  
  DWORD dwCertPolicy;  
   HCERTSTORE hCertStore;
} SIGNER_SPC_CHAIN_INFO,  *PSIGNER_SPC_CHAIN_INFO;

typedef struct _SIGNER_CERT {  
 DWORD cbSize;  
 DWORD dwCertChoice;  
   union {    
     LPCWSTR pwszSpcFile;    
        SIGNER_CERT_STORE_INFO *pCertStoreInfo;    
     SIGNER_SPC_CHAIN_INFO *pSpcChainInfo;  
 } ;  
   HWND hwnd;
} SIGNER_CERT,  *PSIGNER_CERT;

typedef struct _SIGNER_ATTR_AUTHCODE {  
    DWORD cbSize;  
 BOOL fCommercial;  
 BOOL fIndividual;  
 LPCWSTR pwszName;  
 LPCWSTR pwszInfo;
} SIGNER_ATTR_AUTHCODE,  *PSIGNER_ATTR_AUTHCODE;

typedef struct _SIGNER_SIGNATURE_INFO {  
  DWORD cbSize;  
 ALG_ID algidHash;  
 DWORD dwAttrChoice;  
   union {    
     SIGNER_ATTR_AUTHCODE *pAttrAuthcode;  
  } ;  
   PCRYPT_ATTRIBUTES psAuthenticated;  
    PCRYPT_ATTRIBUTES psUnauthenticated;
} SIGNER_SIGNATURE_INFO,  *PSIGNER_SIGNATURE_INFO;

typedef struct _SIGNER_PROVIDER_INFO {  
  DWORD cbSize;  
 LPCWSTR pwszProviderName;  
 DWORD dwProviderType;  
 DWORD dwKeySpec;  
  DWORD dwPvkChoice;  
    union {    
     LPWSTR pwszPvkFileName;    
     LPWSTR pwszKeyContainer;  
  } ;
} SIGNER_PROVIDER_INFO,  *PSIGNER_PROVIDER_INFO;

typedef struct _SIGNER_CONTEXT {  
   DWORD cbSize;  
 DWORD cbBlob;  
 BYTE *pbBlob;
} SIGNER_CONTEXT,  *PSIGNER_CONTEXT;


// EXPORTS 

typedef HRESULT (WINAPI* SignerFreeSignerContextType)(
  __in  SIGNER_CONTEXT *pSignerContext
);

typedef HRESULT (WINAPI *SignerSignExType)(
  __in      DWORD dwFlags,
  __in      SIGNER_SUBJECT_INFO *pSubjectInfo,
  __in      SIGNER_CERT *pSignerCert,
  __in      SIGNER_SIGNATURE_INFO *pSignatureInfo,
  __in_opt  SIGNER_PROVIDER_INFO *pProviderInfo,
  __in_opt  LPCWSTR pwszHttpTimeStamp,
  __in_opt  PCRYPT_ATTRIBUTES psRequest,
  __in_opt  LPVOID pSipData,
  __out     SIGNER_CONTEXT **ppSignerContext
);

typedef HRESULT (WINAPI *SignerTimeStampExType)(
  __reserved  DWORD dwFlags,
  __in        SIGNER_SUBJECT_INFO *pSubjectInfo,
  __in        LPCWSTR pwszHttpTimeStamp,
  __in        PCRYPT_ATTRIBUTES psRequest,
  __in        LPVOID pSipData,
  __out       SIGNER_CONTEXT **ppSignerContext 
);

// MAIN

void main()
{
    // PARAMETERS

   // File to sign
 LPCWSTR pwszFileName = L"C:\\PathToFile\\FileToSign.msi";

   // Signing Cert Subject
 LPCWSTR pwszCertSubject = L"My cert Subject";

   // VARIABLES
    HRESULT hResult = S_OK;
 BOOL bResult = TRUE;
    HMODULE hMssign32 = NULL;
   SignerSignExType pfSignerSignEx = NULL;
 SignerTimeStampExType pfSignerTimeStampEx = NULL;   
    SignerFreeSignerContextType pfSignerFreeSignerContext = NULL;
   HCERTSTORE hCertStore = NULL; 
  PCCERT_CONTEXT pCertContext = NULL;
 DWORD dwIndex = 0;
  SIGNER_FILE_INFO signerFileInfo;
    SIGNER_SUBJECT_INFO signerSubjectInfo;
  SIGNER_CERT_STORE_INFO signerCertStoreInfo;
 SIGNER_CERT signerCert;
 SIGNER_SIGNATURE_INFO signerSignatureInfo;
  SIGNER_CONTEXT * pSignerContext = NULL;

 // MAIN

 // Attach a debugger now!
   printf("<< Press any key to continue>>\n");
 _getch();

   // Load library containing SignerSignEx and SignerFreeSignerContext
 printf("LoadLibrary...");
   hMssign32 = LoadLibrary(L"Mssign32.dll");
   if (!hMssign32)
 {
       printf("Error #%d\n", GetLastError()); goto cleanup;
    }
   printf("Done!\n");

  // Get SignerSignEx function
    printf("GetProcAddress(SignerSignEx)...");
  pfSignerSignEx = (SignerSignExType) GetProcAddress(hMssign32, "SignerSignEx");
  if (!pfSignerSignEx)
    {
       printf("Error #%d\n", GetLastError()); goto cleanup;
    }
   printf("Done!\n");

  // Get SignerTimeStampEx function
   printf("GetProcAddress(SignerTimeStampEx)...");
 pfSignerTimeStampEx = (SignerTimeStampExType) GetProcAddress(hMssign32, "SignerTimeStampEx");
   if (!pfSignerTimeStampEx)
   {
       printf("Error #%d\n", GetLastError()); goto cleanup;
    }
   printf("Done!\n");

  // Get SignerFreeSignerContext function
 printf("GetProcAddress(SignerFreeSignerContext)...");
   pfSignerFreeSignerContext = (SignerFreeSignerContextType) GetProcAddress(hMssign32, "SignerFreeSignerContext");
 if (!pfSignerFreeSignerContext)
 {
       printf("Error #%d\n", GetLastError()); goto cleanup;
    }
   printf("Done!\n");

  // Open MY cert store
   printf("CertOpenStore...");
 hCertStore = CertOpenStore(
     CERT_STORE_PROV_SYSTEM, 
        0,
      NULL,
       CERT_SYSTEM_STORE_CURRENT_USER,
     L"MY"
   );                 
 if (!hCertStore)
    {
       printf("Error #%d\n", GetLastError()); goto cleanup;
    }
   printf("Done!\n");

  // Find signing cert in MY cert store
   printf("CertFindCertificateInStore...");
    pCertContext = CertFindCertificateInStore(
      hCertStore,
     X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
        0,
      CERT_FIND_SUBJECT_STR,
      (void *)pwszCertSubject,
        NULL
    );
  if (!pCertContext)
  {
       printf("Error #%d\n", GetLastError()); goto cleanup;
    }
   printf("Done!\n");

  // Prepare SIGNER_FILE_INFO struct
  signerFileInfo.cbSize = sizeof(SIGNER_FILE_INFO);
   signerFileInfo.pwszFileName = pwszFileName;
 signerFileInfo.hFile = NULL;

    // Prepare SIGNER_SUBJECT_INFO struct
   signerSubjectInfo.cbSize = sizeof(SIGNER_SUBJECT_INFO);
 dwIndex = 0;
    signerSubjectInfo.pdwIndex = &dwIndex;
  signerSubjectInfo.dwSubjectChoice = 1; // SIGNER_SUBJECT_FILE
   signerSubjectInfo.pSignerFileInfo = &signerFileInfo;

    // Prepare SIGNER_CERT_STORE_INFO struct
    signerCertStoreInfo.cbSize = sizeof(SIGNER_CERT_STORE_INFO);
    signerCertStoreInfo.pSigningCert = pCertContext;
    signerCertStoreInfo.dwCertPolicy = 2; // SIGNER_CERT_POLICY_CHAIN
   signerCertStoreInfo.hCertStore = NULL;

  // Prepare SIGNER_CERT struct
   signerCert.cbSize = sizeof(SIGNER_CERT);
    signerCert.dwCertChoice = 2; // SIGNER_CERT_STORE
   signerCert.pCertStoreInfo = &signerCertStoreInfo;
   signerCert.hwnd = NULL;

 // Prepare SIGNER_SIGNATURE_INFO struct
 signerSignatureInfo.cbSize = sizeof(SIGNER_SIGNATURE_INFO);
 signerSignatureInfo.algidHash = CALG_SHA1;
  signerSignatureInfo.dwAttrChoice = 0; // SIGNER_NO_ATTR
 signerSignatureInfo.pAttrAuthcode = NULL;
   signerSignatureInfo.psAuthenticated = NULL;
 signerSignatureInfo.psUnauthenticated = NULL;

   // Sign file with cert
  printf("SignerSignEx...");
  hResult = pfSignerSignEx(
       0,
      &signerSubjectInfo,
     &signerCert,
        &signerSignatureInfo,
       NULL,
       NULL,
       NULL,
       NULL,
       &pSignerContext
 );
  if (S_OK != hResult)
    {
       printf("Error #%d\n", hResult); goto cleanup;
   }
   printf("Done!\n");

  // Time stamp the signature
 printf("SignerTimeStampEx...");
 hResult = pfSignerTimeStampEx(
      0,
      &signerSubjectInfo,
     L"https://timestamp.globalsign.com/scripts/timstamp.dll",
        NULL,
       NULL,
       &pSignerContext
 );
  if (S_OK != hResult)
    {
       printf("Error #%d\n", hResult); goto cleanup;
   }
   printf("Done!\n");

  printf("\nSUCCESS!!!\n");

   // Clean up
cleanup:

 if (pSignerContext)
 {
       hResult = pfSignerFreeSignerContext(pSignerContext);
    }

   if (pCertContext)
   {
       bResult = CertFreeCertificateContext(pCertContext);
 }

   if (hCertStore)
 {
       bResult = CertCloseStore(hCertStore, CERT_CLOSE_STORE_CHECK_FLAG);
  }

   if (hMssign32)
  {
       bResult = FreeLibrary(hMssign32);
   }

   // Exit
 printf("<< Press any key to exit >>\n");
    _getch();
   return;
}

Note that this sample also deals with error 0x800b0003 commented at the beginning of this post.

Regards,

 

Alex (Alejandro Campos Magencio)