#include <stdio.h> #include <stdlib.h> #include <string.h> #include <windows.h> #include <wincrypt.h> #define MY_ENCODING_TYPE (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING) void MyHandleError(char *s); int main(int argc, char *argv[]) { HANDLE hFile; HCRYPTMSG hMsg; DWORD dwContentType; DWORD dwSignerInfo; DWORD cbEncoded; PCCERT_CONTEXT pSignerCert = NULL; BOOL fResult; DWORD dwEncoding, dwFormatType; HCERTSTORE hStoreHandle; HCRYPTPROV hCryptProv; CERT_INFO CertInfo; BOOL fCallerFreeProvOrNCryptKey; PCCERT_CONTEXT pCertContext; DWORD dwKeySpec; BOOL fResult2; DWORD cbData; PBYTE pbData; DWORD cbSize; DWORD dwCount; PCCERT_CONTEXT pCertContext2; BOOL fResult3; BOOL fResult4; BOOL fResult5; BOOL fResult6; BOOL fResult7; //------------------------------------------------------------------- // Begin processing. if(argc != 3) { printf("Usage: SignTool <file to sign> <file to copy to>\n"); printf("Example: SignTool C:\\Test\\Test.exe C:\\Test\\Test2.exe\n"); exit(1); } //------------------------------------------------------------------- // Open the message. hFile = CreateFile(argv[1], GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if(hFile == NULL) { MyHandleError("Could not open file!"); } fResult = CryptQueryObject(CERT_QUERY_OBJECT_FILE, argv[1], CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED, CERT_QUERY_FORMAT_FLAG_BINARY, 0, &dwContentType, &dwEncoding, &dwFormatType, &hStoreHandle, &hMsg, NULL); if(!fResult) { MyHandleError("Could not open file!"); } //------------------------------------------------------------------- // Get signer information size. fResult = CryptMsgGetParam(hMsg, CMSG_SIGNER_INFO_PARAM, 0, NULL, &cbEncoded); if(!fResult) { MyHandleError("CryptMsgGetParam failed."); } //------------------------------------------------------------------- // Allocate memory for signer information. pSignerCert = (PCERT_CONTEXT) malloc(cbEncoded); if(!pSignerCert) { MyHandleError("Memory allocation failed."); } //------------------------------------------------------------------- // Get Signer Information. fResult = CryptMsgGetParam(hMsg, CMSG_SIGNER_INFO_PARAM, 0, (PVOID) pSignerCert, &cbEncoded); if(!fResult) { MyHandleError("CryptMsgGetParam failed."); } //------------------------------------------------------------------- // Get a handle to the certificate context. CertInfo.Issuer = pSignerCert->pCertInfo->Issuer; CertInfo.SerialNumber = pSignerCert->pCertInfo->SerialNumber; pCertContext = CertFindCertificateInStore(hStoreHandle, MY_ENCODING_TYPE, 0, CERT_FIND_SUBJECT_CERT, (PVOID) &CertInfo, NULL); if(!pCertContext) { MyHandleError("CertFindCertificateInStore failed."); } //------------------------------------------------------------------- // Get a handle to the private key. fResult = CryptAcquireCertificatePrivateKey(pCertContext, 0, NULL, &hCryptProv, &dwKeySpec, &fCallerFreeProvOrNCryptKey); if(!fResult) { MyHandleError("CryptAcquireCertificatePrivateKey failed."); } //------------------------------------------------------------------- // Get the size of the file's signature. fResult = CryptGetMessageSignerCount(dwEncoding, hMsg, &dwSignerInfo); if(!fResult) { MyHandleError("CryptGetMessageSignerCount failed."); } if(dwSignerInfo != 1) { MyHandleError("This file has more than one signature."); } //------------------------------------------------------------------- // Get the size of the signature. fResult = CryptGetMessageSignature(dwEncoding, hMsg, 0, NULL, &cbData, NULL); if(!fResult) { MyHandleError("CryptGetMessageSignature failed."); } //------------------------------------------------------------------- // Allocate memory for the signature. pbData = (BYTE *) malloc(cbData); if(!pbData) { MyHandleError("Memory allocation failed."); } //------------------------------------------------------------------- // Get the signature. fResult = CryptGetMessageSignature(dwEncoding, hMsg, 0, pbData, &cbData, NULL); if(!fResult) { MyHandleError("CryptGetMessageSignature failed."); } //------------------------------------------------------------------- // Get the size of the certificate store. fResult = CertGetStoreProperty(hStoreHandle, CERT_STORE_CERTIFICATE_CONTEXT_PROP_ID, NULL, &cbSize); if(!fResult) { MyHandleError("CertGetStoreProperty failed."); } //------------------------------------------------------------------- // Allocate memory for the certificate store. pCertContext2 = (PCCERT_CONTEXT) malloc(cbSize); if(!pCertContext2) { MyHandleError("Memory allocation failed."); } //------------------------------------------------------------------- // Get a pointer to the certificate store. fResult = CertGetStoreProperty(hStoreHandle, CERT_STORE_CERTIFICATE_CONTEXT_PROP_ID, pCertContext2, &cbSize); if(!fResult) { MyHandleError("CertGetStoreProperty failed."); } //------------------------------------------------------------------- // Count the number of certificates in the store. dwCount = 0; while(pCertContext2 != NULL) { dwCount++; pCertContext2 = CertEnumCertificatesInStore(hStoreHandle, pCertContext2); } //------------------------------------------------------------------- // Allocate memory for an array of pointers to the certificates. pCertContext2 = (PCCERT_CONTEXT *) malloc(sizeof(PCCERT_CONTEXT) * dwCount); if(!pCertContext2) { MyHandleError("Memory allocation failed."); } //------------------------------------------------------------------- // Get the first certificate context. pCertContext2[0] = CertEnumCertificatesInStore(hStoreHandle, NULL); if(!pCertContext2[0]) { MyHandleError("CertEnumCertificatesInStore failed."); } //------------------------------------------------------------------- // Get the rest of the certificate contexts. for(dwCount = 1; dwCount < dwCount; dwCount++) { pCertContext2[dwCount] = CertEnumCertificatesInStore(hStoreHandle, pCertContext2[dwCount - 1]); if(!pCertContext2[dwCount]) { MyHandleError("CertEnumCertificatesInStore failed."); } } //------------------------------------------------------------------- // Open the message to be signed. hFile = CreateFile(argv[2], GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if(hFile == NULL) { MyHandleError("Could not open file!"); } //------------------------------------------------------------------- // Sign the message. fResult = CryptSignMessage(NULL, FALSE, dwCount, (const PCCERT_CONTEXT *) pCertContext2, pbData, &cbData); if(!fResult) { MyHandleError("CryptSignMessage failed."); } //------------------------------------------------------------------- // Write the signature to the file. fResult = WriteFile(hFile, pbData, cbData, &cbSize, NULL); if(!fResult) { MyHandleError("WriteFile failed."); } //------------------------------------------------------------------- // Clean up. fResult2 = CloseHandle(hFile); fResult3 = CertFreeCertificateContext(pCertContext); fResult4 = CertCloseStore(hStoreHandle, 0); fResult5 = CryptReleaseContext(hCryptProv, 0); fResult6 = CryptMsgClose(hMsg); fResult7 = CloseHandle(hFile); if(!fResult2 || !fResult3 || !fResult4 || !fResult5 || !fResult6 || !fResult7) { MyHandleError("CloseHandle failed."); } printf("The file was signed.\n"); return 0; } //------------------------------------------------------------------- // This example uses the function MyHandleError, a simple error // handling function, to print an error message to the // standard error (stderr) file and exit the program. // For most applications, replace this function with one // that does more extensive error reporting. void MyHandleError(char *s) { fprintf(stderr,"An error occurred in running the program. \n"); fprintf(stderr,"%s\n",s); fprintf(stderr, "Error number %x.\n", GetLastError()); fprintf(stderr, "Program terminating. \n"); exit(1); }