Freigeben über


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)

Comments

  • Anonymous
    July 05, 2010
    Great article! How do you go about adding the description and description url attributes (/d and /du options for signtool)?
  • Anonymous
    July 06, 2010
    Figured it out, in case anyone else is wondering:// Prepare the SIGNER_ATTR_AUTHCODE structSIGNER_ATTR_AUTHCODE att;att.cbSize = sizeof(SIGNER_ATTR_AUTHCODE);att.fCommercial = true;att.fIndividual = false;att.pwszName = L"MY DESCRIPTION";att.pwszInfo = L"MY DESCRIPTION URL";// Prepare SIGNER_SIGNATURE_INFO structSIGNER_SIGNATURE_INFO signerSignatureInfo;signerSignatureInfo.cbSize = sizeof(SIGNER_SIGNATURE_INFO);signerSignatureInfo.algidHash = CALG_SHA1;// Set the SIGNER_SIGNATURE_INFO object to have authenticode attributessignerSignatureInfo.dwAttrChoice = SIGNER_AUTHCODE_ATTR;// Set the pointer to the Authenticode Attribute struct to the address of 'att'signerSignatureInfo.pAttrAuthcode = &att;signerSignatureInfo.psAuthenticated = NULL;signerSignatureInfo.psUnauthenticated = NULL;
  • Anonymous
    July 06, 2010
    Great! Thx for sharing!
  • Anonymous
    September 30, 2013
    Alejandro, hi!I found following SignerSignEx behaviour trying to sign my DLL on Windows Server 2008 R2 x64:1) signerFileInfo.hFile = NULL, no timestamp - file is signed successfully without timestamp2) signerFileInfo.hFile = valid handle, no timestamp - file is signed successfully without timestamp3) signerFileInfo.hFile = NULL, valid timestamp - I get 0x80070020, but my file is not signed at all, instead of yours"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"4) signerFileInfo.hFile = valid handle, valid timestamp - file is successfully signed and timestampedAlso I succeeded to first sign file as in (1) and then timestamp it using SignerTimeStampEx.Another thing, MSDN says following about SIGNER_SUBJECT_INFO pdwIndex member "This member is reserved. It must be set to zero.", but you'll get 0x80070057 if zero it. So usedwIndex = 0;signerSubjectInfo.pdwIndex = &dwIndex;Regards, Andrew
  • Anonymous
    October 01, 2013
    Sorry, an error was in my code, (3) works as you mentioned - SignerSignEx returns 0x80070020 but the file is signed without timestamp.Regards, Andrew
  • Anonymous
    October 01, 2013
    Hello again.I used Geoff's sample and discovered that specifying      att.fCommercial = true;leads to 0x80028ca0 be returned from SignerSignEx call. Instead you must set fCommercial to false.Regards, Andrew