//+------------------------------------------------------------------------- // // Microsoft Windows // // Copyright (C) Microsoft Corporation, 1996 - 1999 // // File: signer.cpp // // Contents: Microsoft Internet Security Signing API // // History: June-25-97 xiaohs created // //-------------------------------------------------------------------------- #include "global.hxx" #include //-------------------------------------------------------------------------- // // InternalSign: // The signing routine called by signer.dll internally. This is the // function that actually does the job. // //-------------------------------------------------------------------------- HRESULT WINAPI InternalSign(IN DWORD dwEncodingType, // Encoding type IN HCRYPTPROV hCryptProv, // CAPI provider, opened for signing private key IN DWORD dwKeySpec, // Type of signing key, AT_SIGNATURE or AT_EXCHANGE IN LPCSTR pszAlgorithmOid, // Algorithm id used to create digest IN LPSIP_SUBJECTINFO pSipInfo, // SIP information IN DWORD *pdwIndex, // signer index IN PCCERT_CONTEXT psSigningContext, // Cert context to the signing certificate IN HCERTSTORE hSpcStore, // The credentials to use in the signing IN LPCWSTR pwszOpusName, // Optional, the name of the program to appear in IN LPCWSTR pwszOpusInfo, // Optional, the unparsed name of a link to more IN BOOL fIncludeCerts, // add the certificates to the signature IN BOOL fCommercial, // commerical signing IN BOOL fIndividual, // individual signing IN BOOL fAuthcode, // whether use fCommercial as an attributes IN PCRYPT_ATTRIBUTES psAuthenticated, // Optional, authenticated attributes added to signature IN PCRYPT_ATTRIBUTES psUnauthenticated, // Optional, unauthenticated attributes added to signature OUT PBYTE* ppbDigest, //Optional: return the Digest of the file OUT DWORD* pcbDigest, //Optional: return the size of the digest OUT PBYTE* ppbMessage, //Optional: return the encoded signed message OUT DWORD* pcbMessage) //Optional: return the size of encoded signed message { HRESULT hr = S_OK; SIP_DISPATCH_INFO sSip; ZERO(sSip); // Table of sip functions PBYTE pbOpusAttribute = NULL; // Encoding for the opus attribute DWORD cbOpusAttribute = 0; // : PBYTE pbStatementAttribute = NULL; // Encoding for the statement attribute DWORD cbStatementAttribute = 0; // : PCRYPT_ATTRIBUTE rgpAuthAttributes = NULL; DWORD dwAuthAttributes = 0; PCRYPT_ATTRIBUTE rgpUnauthAttributes = NULL; DWORD dwUnauthAttributes = 0; PSIP_INDIRECT_DATA psIndirectData = NULL; // Indirect data structure DWORD dwIndirectData = 0; PBYTE pbIndirectBlob = NULL; // Encoding Indirect blob DWORD cbIndirectBlob = 0; // : PBYTE pbGetBlob=NULL; DWORD cbGetBlob=0; CRYPT_DATA_BLOB PKCS7Blob; HCERTSTORE hPKCS7CertStore=NULL; DWORD dwPKCS7Certs=0; PCERT_BLOB rgPKCS7Certs=NULL; PBYTE pbEncodedSignMsg = NULL; // Encoding for the statement attribute DWORD cbEncodedSignMsg = 0; // : HCRYPTMSG hMsg = NULL; CMSG_SIGNER_ENCODE_INFO sSignerInfo; CMSG_SIGNED_ENCODE_INFO sSignedInfo; PCERT_BLOB rgpCryptMsgCertificates = NULL; DWORD dwCryptMsgCertificates = 0; PCRL_BLOB rgpCryptMsgCrls = NULL; DWORD dwCryptMsgCrls = 0; PBYTE pbSignerData = NULL; DWORD cbSignerData = 0; BOOL fSignCommercial=FALSE; BOOL fCTLFile =FALSE; PCTL_CONTEXT pCTLContext=NULL; GUID CTLGuid=CRYPT_SUBJTYPE_CTL_IMAGE; GUID CATGuid=CRYPT_SUBJTYPE_CATALOG_IMAGE; DWORD dwCertIndex=0; BOOL fFound=FALSE; BOOL fNeedStatementType=FALSE; PKITRY { //init memory ZeroMemory(&sSignerInfo, sizeof(CMSG_SIGNER_ENCODE_INFO)); ZeroMemory(&sSignedInfo, sizeof(CMSG_SIGNED_ENCODE_INFO)); // Load up the sip functions. if(!CryptSIPLoad(pSipInfo->pgSubjectType, // GUID for the requried sip 0, // Reserved &sSip)) // Table of functions PKITHROW(SignError()); // Set up the attributes (AUTHENTICODE Specific, replace with your attributes) // Encode the opus information up into an attribute if(fAuthcode) { hr = CreateOpusInfo(pwszOpusName, pwszOpusInfo, &pbOpusAttribute, &cbOpusAttribute); if(hr != S_OK) PKITHROW(hr); //Check to see if we need to put the statement type attributes if(NeedStatementTypeAttr(psSigningContext, fCommercial, fIndividual)) { fNeedStatementType=TRUE; // Check signing certificate to see if its signing cabablity complies //with the request if(S_OK!=(hr=CheckCommercial(psSigningContext,fCommercial, fIndividual, &fSignCommercial))) PKITHROW(hr); if(S_OK !=(hr = CreateStatementType(fSignCommercial, &pbStatementAttribute, &cbStatementAttribute))) PKITHROW(hr); } else fNeedStatementType=FALSE; } // Create Authenticode attributes and append additional authenticated attributes. // Allocate and add StatementType and SpOpusInfo (add room for one blob per attribute, which we need) DWORD dwAttrSize = 0; //get the number of authenticated attributes if(fAuthcode) { if(fNeedStatementType) dwAuthAttributes = 2; // StatementType + opus else dwAuthAttributes= 1; } else dwAuthAttributes= 0; if(psAuthenticated) dwAuthAttributes += psAuthenticated->cAttr; dwAttrSize = sizeof(CRYPT_ATTRIBUTE) * dwAuthAttributes + 2 * sizeof(CRYPT_ATTR_BLOB); rgpAuthAttributes = (PCRYPT_ATTRIBUTE) malloc(dwAttrSize); if(!rgpAuthAttributes) PKITHROW(E_OUTOFMEMORY); ZeroMemory(rgpAuthAttributes, dwAttrSize); PCRYPT_ATTR_BLOB pValue = (PCRYPT_ATTR_BLOB) (rgpAuthAttributes + dwAuthAttributes); //the start of the authenticated attributes dwAttrSize=0; //add the authenticode specific attributes if(fAuthcode) { // Update SpOpusInfo rgpAuthAttributes[dwAttrSize].pszObjId = SPC_SP_OPUS_INFO_OBJID; rgpAuthAttributes[dwAttrSize].cValue = 1; rgpAuthAttributes[dwAttrSize].rgValue = &pValue[dwAttrSize]; pValue[dwAttrSize].pbData = pbOpusAttribute; pValue[dwAttrSize].cbData = cbOpusAttribute; dwAttrSize++; // Update StatementType if(fNeedStatementType) { rgpAuthAttributes[dwAttrSize].pszObjId = SPC_STATEMENT_TYPE_OBJID; rgpAuthAttributes[dwAttrSize].cValue = 1; rgpAuthAttributes[dwAttrSize].rgValue = &pValue[dwAttrSize]; pValue[dwAttrSize].pbData = pbStatementAttribute; pValue[dwAttrSize].cbData = cbStatementAttribute; dwAttrSize++; } } if(psAuthenticated) { for(DWORD i = dwAttrSize, ii = 0; ii < psAuthenticated->cAttr; ii++, i++) rgpAuthAttributes[i] = psAuthenticated->rgAttr[ii]; } // Get the Unauthenticated attributes if(psUnauthenticated) { rgpUnauthAttributes = psUnauthenticated->rgAttr; dwUnauthAttributes = psUnauthenticated->cAttr; } //check to see if the file is either a catalog file or a CTL file if((CTLGuid == (*(pSipInfo->pgSubjectType))) || (CATGuid == (*(pSipInfo->pgSubjectType))) ) fCTLFile=TRUE; else { // Get the indirect data struct from the SIP if(!sSip.pfCreate(pSipInfo, &dwIndirectData, psIndirectData)) PKITHROW(SignError()); psIndirectData = (PSIP_INDIRECT_DATA) malloc(dwIndirectData); if(!psIndirectData) PKITHROW(E_OUTOFMEMORY); if(!sSip.pfCreate(pSipInfo, &dwIndirectData, psIndirectData)) PKITHROW(SignError()); // Encode the indirect data CryptEncodeObject(dwEncodingType, SPC_INDIRECT_DATA_CONTENT_STRUCT, psIndirectData, pbIndirectBlob, &cbIndirectBlob); if (cbIndirectBlob == 0) PKITHROW(SignError()); pbIndirectBlob = (PBYTE) malloc(cbIndirectBlob); if(!pbIndirectBlob) PKITHROW(E_OUTOFMEMORY); if (!CryptEncodeObject(dwEncodingType, SPC_INDIRECT_DATA_CONTENT_STRUCT, psIndirectData, pbIndirectBlob, &cbIndirectBlob)) PKITHROW(SignError()); } // Encode the signed message // Setup the signing info ZeroMemory(&sSignerInfo, sizeof(CMSG_SIGNER_ENCODE_INFO)); sSignerInfo.cbSize = sizeof(CMSG_SIGNER_ENCODE_INFO); sSignerInfo.pCertInfo = psSigningContext->pCertInfo; sSignerInfo.hCryptProv = hCryptProv; sSignerInfo.dwKeySpec = dwKeySpec; sSignerInfo.HashAlgorithm.pszObjId = (char*) pszAlgorithmOid; sSignerInfo.cAuthAttr = dwAuthAttributes; sSignerInfo.rgAuthAttr = rgpAuthAttributes; sSignerInfo.cUnauthAttr = dwUnauthAttributes; sSignerInfo.rgUnauthAttr = rgpUnauthAttributes; // Setup the signing structures ZeroMemory(&sSignedInfo, sizeof(CMSG_SIGNED_ENCODE_INFO)); sSignedInfo.cbSize = sizeof(CMSG_SIGNED_ENCODE_INFO); sSignedInfo.cSigners = 1; sSignedInfo.rgSigners = &sSignerInfo; // if there are certificates to add change them to the // form required by CryptMsg... functions // load up the certificates into a vector // Count the number of certs in the store if(fIncludeCerts && hSpcStore) { PCCERT_CONTEXT pCert = NULL; while ((pCert = CertEnumCertificatesInStore(hSpcStore, pCert))) dwCryptMsgCertificates++; // Get the encoded blobs of the CERTS if (dwCryptMsgCertificates > 0) { rgpCryptMsgCertificates = (PCERT_BLOB) malloc(sizeof(CERT_BLOB) * dwCryptMsgCertificates); if(!rgpCryptMsgCertificates) PKITHROW(E_OUTOFMEMORY); ZeroMemory(rgpCryptMsgCertificates, sizeof(CERT_BLOB) * dwCryptMsgCertificates); PCERT_BLOB pCertPtr = rgpCryptMsgCertificates; pCert = NULL; DWORD c = 0; while ((pCert = CertEnumCertificatesInStore(hSpcStore, pCert)) && c < dwCryptMsgCertificates) { pCertPtr->pbData = pCert->pbCertEncoded; pCertPtr->cbData = pCert->cbCertEncoded; c++; pCertPtr++; } } sSignedInfo.cCertEncoded = dwCryptMsgCertificates; sSignedInfo.rgCertEncoded = rgpCryptMsgCertificates; rgpCryptMsgCertificates=NULL; // Get the encoded blobs of the CRLS DWORD crlFlag = 0; PCCRL_CONTEXT pCrl = NULL; while ((pCrl = CertGetCRLFromStore(hSpcStore, NULL, pCrl, &crlFlag))) dwCryptMsgCrls++; if (dwCryptMsgCrls > 0) { rgpCryptMsgCrls = (PCRL_BLOB) malloc(sizeof(CRL_BLOB) * dwCryptMsgCrls); if(!rgpCryptMsgCrls) PKITHROW(E_OUTOFMEMORY); ZeroMemory(rgpCryptMsgCrls, sizeof(CRL_BLOB) * dwCryptMsgCrls); PCRL_BLOB pCrlPtr = rgpCryptMsgCrls; pCrl = NULL; DWORD c = 0; while ((pCrl = CertGetCRLFromStore(hSpcStore, NULL, pCrl, &crlFlag)) && c < dwCryptMsgCrls) { pCrlPtr->pbData = pCrl->pbCrlEncoded; pCrlPtr->cbData = pCrl->cbCrlEncoded; c++; pCrlPtr++; } } sSignedInfo.cCrlEncoded = dwCryptMsgCrls; sSignedInfo.rgCrlEncoded = rgpCryptMsgCrls; rgpCryptMsgCrls=NULL; } //check to see if the subject is a CTL file. If it is, we need to preserve //all the certificates in the original signer Info if(CTLGuid == (*(pSipInfo->pgSubjectType))) { PCCERT_CONTEXT pCert = NULL; //call Get the get the original signer information sSip.pfGet(pSipInfo, &dwEncodingType, *pdwIndex, &cbGetBlob, NULL); if (cbGetBlob < 1) { PKITHROW(SignError()); } if (!(pbGetBlob = (BYTE *)malloc(cbGetBlob))) { PKITHROW(E_OUTOFMEMORY); } if (!(sSip.pfGet(pSipInfo, &dwEncodingType, *pdwIndex, &cbGetBlob, pbGetBlob))) { PKITHROW(SignError()); } //open the PKCS7 BLOB as a certificate store PKCS7Blob.cbData=cbGetBlob; PKCS7Blob.pbData=pbGetBlob; hPKCS7CertStore=CertOpenStore(CERT_STORE_PROV_PKCS7, dwEncodingType, NULL, 0, &PKCS7Blob); if(!hPKCS7CertStore) PKITHROW(SignError()); //enum all the certificate in the store while ((pCert = CertEnumCertificatesInStore(hPKCS7CertStore, pCert))) dwPKCS7Certs++; //Get the encoded blobs of the CERTS if (dwPKCS7Certs > 0) { sSignedInfo.rgCertEncoded = (PCERT_BLOB) realloc(sSignedInfo.rgCertEncoded, sizeof(CERT_BLOB) * (sSignedInfo.cCertEncoded+dwPKCS7Certs)); if(!sSignedInfo.rgCertEncoded) PKITHROW(E_OUTOFMEMORY); PCERT_BLOB pCertPtr = (sSignedInfo.rgCertEncoded + sSignedInfo.cCertEncoded); pCert = NULL; DWORD c = 0; while ((pCert = CertEnumCertificatesInStore(hPKCS7CertStore, pCert)) && c < dwPKCS7Certs) { fFound=FALSE; //we need to make sure that we do not add duplicated certificates for(dwCertIndex=0; dwCertIndexcbCertEncoded) { if(0==memcmp((sSignedInfo.rgCertEncoded[dwCertIndex]).pbData, pCert->pbCertEncoded, pCert->cbCertEncoded)) { fFound=TRUE; break; } } } //we only add the certificates that do not duplicates the signer's //certificates if(FALSE==fFound) { pCertPtr->pbData = pCert->pbCertEncoded; pCertPtr->cbData = pCert->cbCertEncoded; c++; pCertPtr++; } } sSignedInfo.cCertEncoded += c; } } if (fCTLFile) { // // get the signed message if we need to // if(NULL==pbGetBlob) { // sSip.pfGet(pSipInfo, &dwEncodingType, *pdwIndex, &cbGetBlob, NULL); if (cbGetBlob < 1) { PKITHROW(SignError()); } if (!(pbGetBlob = (BYTE *)malloc(cbGetBlob))) { PKITHROW(E_OUTOFMEMORY); } if (!(sSip.pfGet(pSipInfo, &dwEncodingType, *pdwIndex, &cbGetBlob, pbGetBlob))) { PKITHROW(SignError()); } } // // extract the inner content // pCTLContext = (PCTL_CONTEXT)CertCreateCTLContext( PKCS_7_ASN_ENCODING | X509_ASN_ENCODING, pbGetBlob, cbGetBlob); if (!(pCTLContext)) { PKITHROW(SignError()); } if (!(pCTLContext->pbCtlContent)) { PKITHROW(SignError()); } // // add singer info! (e.g.: sign it!) // cbEncodedSignMsg = 0; CryptMsgSignCTL(dwEncodingType, pCTLContext->pbCtlContent, pCTLContext->cbCtlContent, &sSignedInfo, 0, NULL, &cbEncodedSignMsg); if (cbEncodedSignMsg < 1) { PKITHROW(SignError()); } if (!(pbEncodedSignMsg = (BYTE *)malloc(cbEncodedSignMsg))) { PKITHROW(E_OUTOFMEMORY); } if (!(CryptMsgSignCTL(dwEncodingType, pCTLContext->pbCtlContent, pCTLContext->cbCtlContent, &sSignedInfo, 0, pbEncodedSignMsg, &cbEncodedSignMsg))) { PKITHROW(SignError()); } CertFreeCTLContext(pCTLContext); pCTLContext = NULL; } else { hMsg = CryptMsgOpenToEncode(dwEncodingType, 0, // dwFlags CMSG_SIGNED, &sSignedInfo, SPC_INDIRECT_DATA_OBJID, NULL); if(hMsg == NULL) PKITHROW(SignError()); if (!CryptMsgUpdate(hMsg, pbIndirectBlob, cbIndirectBlob, TRUE)) // Final PKITHROW(SignError()); CryptMsgGetParam(hMsg, CMSG_CONTENT_PARAM, 0, // dwIndex NULL, // pbSignedData &cbEncodedSignMsg); if (cbEncodedSignMsg == 0) PKITHROW(SignError()); pbEncodedSignMsg = (PBYTE) malloc(cbEncodedSignMsg); if(!pbEncodedSignMsg) PKITHROW(E_OUTOFMEMORY); if (!CryptMsgGetParam(hMsg, CMSG_CONTENT_PARAM, 0, // dwIndex pbEncodedSignMsg, &cbEncodedSignMsg)) PKITHROW(SignError()); } //put the signatures if we are dealing with anything other than the BLOB if(pSipInfo->dwUnionChoice != MSSIP_ADDINFO_BLOB) { // Purge all the signatures in the subject sSip.pfRemove(pSipInfo, *pdwIndex); // Store the Signed Message in the sip if(!(sSip.pfPut( pSipInfo, dwEncodingType, pdwIndex, cbEncodedSignMsg, pbEncodedSignMsg))) { PKITHROW(SignError()); } } if(ppbMessage && pcbMessage) { *ppbMessage = pbEncodedSignMsg; pbEncodedSignMsg = NULL; *pcbMessage = cbEncodedSignMsg; } if(ppbDigest && pcbDigest) { // Get the encrypted digest pbSignerData = NULL; CryptMsgGetParam(hMsg, CMSG_ENCRYPTED_DIGEST, 0, // dwIndex pbSignerData, &cbSignerData); if(cbSignerData == 0) PKITHROW(SignError()); pbSignerData = (PBYTE) malloc(cbSignerData); if(!pbSignerData) PKITHROW(E_OUTOFMEMORY); if(!CryptMsgGetParam(hMsg, CMSG_ENCRYPTED_DIGEST, 0, // dwIndex pbSignerData, &cbSignerData)) PKITHROW(SignError()); *ppbDigest = pbSignerData; pbSignerData = NULL; *pcbDigest = cbSignerData; } } PKICATCH(err) { hr = err.pkiError; } PKIEND; if (pCTLContext) { CertFreeCTLContext(pCTLContext); } if (pbSignerData) free(pbSignerData); if(pbEncodedSignMsg) free(pbEncodedSignMsg); if(hMsg) CryptMsgClose(hMsg); if(sSignedInfo.rgCrlEncoded) free(sSignedInfo.rgCrlEncoded); if(sSignedInfo.rgCertEncoded) free(sSignedInfo.rgCertEncoded); if(pbIndirectBlob) free(pbIndirectBlob); if(pbGetBlob) free(pbGetBlob); if(hPKCS7CertStore) CertCloseStore(hPKCS7CertStore,0); if(psIndirectData) free(psIndirectData); if(rgpAuthAttributes) free(rgpAuthAttributes); if(pbStatementAttribute) free(pbStatementAttribute); if(pbOpusAttribute) free(pbOpusAttribute); return hr; } //-------------------------------------------------------------------------- // // SignerTimeStamp: // Timestamp a file. // //-------------------------------------------------------------------------- HRESULT WINAPI SignerTimeStamp( IN SIGNER_SUBJECT_INFO *pSubjectInfo, //Required: The subject to be timestamped IN LPCWSTR pwszHttpTimeStamp, // Required: timestamp server HTTP address IN PCRYPT_ATTRIBUTES psRequest, // Optional, attributes added to the timestamp IN LPVOID pSipData // Optional: The additional data passed to sip funcitons ) { return SignerTimeStampEx(0, pSubjectInfo, pwszHttpTimeStamp, psRequest, pSipData, NULL); } //-------------------------------------------------------------------------- // // SignerTimeStampEx: // Timestamp a file. // //-------------------------------------------------------------------------- HRESULT WINAPI SignerTimeStampEx( IN DWORD dwFlags, //Reserved: Has to be set to 0. IN SIGNER_SUBJECT_INFO *pSubjectInfo, //Required: The subject to be timestamped IN LPCWSTR pwszHttpTimeStamp, // Required: timestamp server HTTP address IN PCRYPT_ATTRIBUTES psRequest, // Optional, attributes added to the timestamp IN LPVOID pSipData, // Optional: The additional data passed to sip funcitons OUT SIGNER_CONTEXT **ppSignerContext // Optional: The signed BLOB. User has to free // the context via SignerFreeSignerContext ) { HRESULT hr=E_FAIL; DWORD dwTimeStampRequest=0; BYTE *pbTimeStampRequest=NULL; DWORD dwTimeStampResponse=0; BYTE *pbTimeStampResponse=NULL; CHttpTran cTran; BOOL fOpen=FALSE; DWORD err; LPSTR szURL=NULL; DWORD dwEncodingType=OCTET_ENCODING; CHAR *pEncodedRequest=NULL; DWORD dwEncodedRequest=0; CHAR *pEncodedResponse=NULL; DWORD dwEncodedResponse=0; //input parameter check if((!pwszHttpTimeStamp) ||(FALSE==CheckSigncodeSubjectInfo(pSubjectInfo))) return E_INVALIDARG; //request a time stamp hr=SignerCreateTimeStampRequest(pSubjectInfo, psRequest, pSipData, NULL, &dwTimeStampRequest); if(hr!=S_OK) goto CLEANUP; pbTimeStampRequest=(BYTE *)malloc(dwTimeStampRequest); if(!pbTimeStampRequest) { hr=E_OUTOFMEMORY; goto CLEANUP; } hr=SignerCreateTimeStampRequest(pSubjectInfo, psRequest, pSipData, pbTimeStampRequest, &dwTimeStampRequest); if(hr!=S_OK) goto CLEANUP; //conver the WSTR of URL to STR if((hr=WSZtoSZ((LPWSTR)pwszHttpTimeStamp,&szURL))!=S_OK) goto CLEANUP; //base64 encode the request if(S_OK!=(hr=BytesToBase64(pbTimeStampRequest, dwTimeStampRequest, &pEncodedRequest, &dwEncodedRequest))) goto CLEANUP; //estalish the connection between the http site err=cTran.Open( szURL, GTREAD|GTWRITE); if(err!=ERROR_SUCCESS) { hr=E_FAIL; goto CLEANUP; } //mark that we have open the connection successful fOpen=TRUE; //send the request err=cTran.Send(dwEncodingType,dwEncodedRequest,(BYTE *)pEncodedRequest); if(err!=ERROR_SUCCESS) { hr=HRESULT_FROM_WIN32(ERROR_INVALID_FUNCTION); goto CLEANUP; } //send the request err=cTran.Receive(&dwEncodingType,&dwEncodedResponse,(BYTE **)&pEncodedResponse); if(err!=ERROR_SUCCESS) { hr=E_FAIL; goto CLEANUP; } //make sure the encoding type is correct // if(dwEncodingType!=OCTET_ENCODING) // { // hr=E_FAIL; // goto CLEANUP; // } //base64 decode the response if(S_OK != (hr=Base64ToBytes( pEncodedResponse, dwEncodedResponse, &pbTimeStampResponse, &dwTimeStampResponse))) goto CLEANUP; //add the timestamp response to the time hr=SignerAddTimeStampResponseEx(0, pSubjectInfo,pbTimeStampResponse, dwTimeStampResponse, pSipData, ppSignerContext); CLEANUP: if(pEncodedRequest) free(pEncodedRequest); if(pbTimeStampResponse) free(pbTimeStampResponse); if(pbTimeStampRequest) free(pbTimeStampRequest); if(szURL) free(szURL); if(fOpen) { if(pEncodedResponse) cTran.Free((BYTE *)pEncodedResponse); cTran.Close(); } return hr; } //+----------------------------------------------------------------------- // // SignerSign: // Sign and/or timestamp a file. // //------------------------------------------------------------------------ HRESULT WINAPI SignerSign( IN SIGNER_SUBJECT_INFO *pSubjectInfo, //Required: The subject to be signed and/or timestamped IN SIGNER_CERT *pSignerCert, //Required: The signing certificate to use IN SIGNER_SIGNATURE_INFO *pSignatureInfo, //Required: The signature information during signing process IN SIGNER_PROVIDER_INFO *pProviderInfo, //Optional: The crypto security provider to use. // This parameter has to be set unless // certStoreInfo is set in *pSignerCert // and the signing certificate has provider // information associated with it IN LPCWSTR pwszHttpTimeStamp, //Optional: Timestamp server http address. If this parameter // is set, the file will be timestamped. IN PCRYPT_ATTRIBUTES psRequest, //Optional: Attributes added to Time stamp request. Ignored // unless pwszHttpTimeStamp is set IN LPVOID pSipData //Optional: The additional data passed to sip funcitons ) { return SignerSignEx( 0, pSubjectInfo, pSignerCert, pSignatureInfo, pProviderInfo, pwszHttpTimeStamp, psRequest, pSipData, NULL); } //+----------------------------------------------------------------------- // // SignerSignEx: // Sign and/or timestamp a file. // //------------------------------------------------------------------------ HRESULT WINAPI SignerSignEx( IN DWORD dwFlags, //Reserved: Has to be set to 0. IN SIGNER_SUBJECT_INFO *pSubjectInfo, //Required: The subject to be signed and/or timestamped IN SIGNER_CERT *pSignerCert, //Required: The signing certificate to use IN SIGNER_SIGNATURE_INFO *pSignatureInfo, //Required: The signature information during signing process IN SIGNER_PROVIDER_INFO *pProviderInfo, //Optional: The crypto security provider to use. // This parameter has to be set unless // certStoreInfo is set in *pSignerCert // and the signing certificate has provider // information associated with it IN LPCWSTR pwszHttpTimeStamp, //Optional: Timestamp server http address. If this parameter // is set, the file will be timestamped. IN PCRYPT_ATTRIBUTES psRequest, //Optional: Attributes added to Time stamp request. Ignored // unless pwszHttpTimeStamp is set IN LPVOID pSipData, //Optional: The additional data passed to sip funcitons OUT SIGNER_CONTEXT **ppSignerContext //Optional: The signed BLOB. User has to free // the context via SignerFreeSignerContext ) { HRESULT hr = S_OK; HANDLE hFile = NULL; // File to sign BOOL fFileOpen=FALSE; HCERTSTORE hSpcStore = NULL; // Certificates added to signature PCCERT_CONTEXT psSigningContext = NULL; // Cert context to the signing certificate GUID gSubjectGuid; // The subject guid used to load the sip SIP_SUBJECTINFO sSubjInfo; ZERO(sSubjInfo); MS_ADDINFO_BLOB sBlob; HCRYPTPROV hCryptProv = NULL; // Crypto provider, uses private key container HCRYPTPROV hMSBaseProv = NULL; //This is the MS base provider for hashing purpose LPWSTR pwszTmpContainer = NULL; // Pvk container (opened up pvk file) LPWSTR pwszProvName=NULL; DWORD dwProvType; BOOL fAcquired=FALSE; LPCWSTR pwszPvkFile = NULL; LPCWSTR pwszKeyContainerName = NULL; BOOL fAuthcode=FALSE; BOOL fCertAcquire=FALSE; //set dwKeySpec to 0. That is, we allow any key specification //for code signing DWORD dwKeySpec = 0; DWORD dwEncodingType = X509_ASN_ENCODING | PKCS_7_ASN_ENCODING; // For this version we default to this. LPCSTR pszAlgorithmOid = NULL; WCHAR wszPublisher[40]; PBYTE pbEncodedMessage=NULL; DWORD cbEncodedMessage=0; //input parameter checking if(!CheckSigncodeParam(pSubjectInfo, pSignerCert, pSignatureInfo, pProviderInfo)) return E_INVALIDARG; //determine if this is an authenticode specific signing if(pSignatureInfo->dwAttrChoice==SIGNER_AUTHCODE_ATTR) fAuthcode=TRUE; //init if(ppSignerContext) *ppSignerContext=NULL; // Acquire a context for the specified provider // First,try to acquire the provider context based on the properties on a cert if(pSignerCert->dwCertChoice==SIGNER_CERT_STORE) { if(GetCryptProvFromCert(pSignerCert->hwnd, (pSignerCert->pCertStoreInfo)->pSigningCert, &hCryptProv, &dwKeySpec, &fAcquired, &pwszTmpContainer, &pwszProvName, &dwProvType)) //mark that we acquire the context via the cert's property fCertAcquire=TRUE; } // If the 1st failed, try to acquire the provider context based on //pPvkInfo if(hCryptProv==NULL) { //pProviderInfo has to be set if(!pProviderInfo) { hr=CRYPT_E_NO_PROVIDER; goto CLEANUP; } //decide the PVK file name or the key container name if(pProviderInfo->dwPvkChoice == PVK_TYPE_FILE_NAME) pwszPvkFile=pProviderInfo->pwszPvkFileName; else pwszKeyContainerName=pProviderInfo->pwszKeyContainer; //load from the resource of string L"publisher" if(0==LoadStringU(hInstance, IDS_Publisher, wszPublisher, 40)) { hr=SignError(); goto CLEANUP; } //acquire the context if(S_OK != (hr=PvkGetCryptProv( pSignerCert->hwnd, wszPublisher, pProviderInfo->pwszProviderName, pProviderInfo->dwProviderType, pwszPvkFile, pwszKeyContainerName, &(pProviderInfo->dwKeySpec), &pwszTmpContainer, &hCryptProv))) { hr=CRYPT_E_NO_PROVIDER; goto CLEANUP; } //mark the hCryptProv is acquired fAcquired=TRUE; //mark the key spec that we used dwKeySpec=pProviderInfo->dwKeySpec; } //now, acquire a MS base crypto provider for any operation other than //signing if(!CryptAcquireContext(&hMSBaseProv, NULL, MS_DEF_PROV, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) { hr=GetLastError(); goto CLEANUP; } //build a certificate store, which includes the signing certificate, //and all the certs necessary in the signature //get the signing certificate if(S_OK != (hr = BuildCertStore(hCryptProv, dwKeySpec, hMSBaseProv, dwEncodingType, pSignerCert, &hSpcStore, &psSigningContext))) goto CLEANUP; //check the time validity of the signing certificate if(0!=CertVerifyTimeValidity(NULL, psSigningContext->pCertInfo)) { hr=CERT_E_EXPIRED; goto CLEANUP; } // Determine the hashing algorithm pszAlgorithmOid = CertAlgIdToOID(pSignatureInfo->algidHash); // Set up the sip information sSubjInfo.hProv = hMSBaseProv; sSubjInfo.DigestAlgorithm.pszObjId = (char*) pszAlgorithmOid; sSubjInfo.dwEncodingType = dwEncodingType; sSubjInfo.cbSize = sizeof(SIP_SUBJECTINFO); // Version sSubjInfo.pClientData = pSipData; //set up file information if(pSubjectInfo->dwSubjectChoice==SIGNER_SUBJECT_FILE) { // Open up the file if((pSubjectInfo->pSignerFileInfo->hFile)==NULL || (pSubjectInfo->pSignerFileInfo->hFile)==INVALID_HANDLE_VALUE) { if(S_OK != (hr = SignOpenFile( pSubjectInfo->pSignerFileInfo->pwszFileName, &hFile))) goto CLEANUP; fFileOpen=TRUE; } else hFile=pSubjectInfo->pSignerFileInfo->hFile; // Get the subject type. if(S_OK != (hr=SignGetFileType(hFile, pSubjectInfo->pSignerFileInfo->pwszFileName, &gSubjectGuid))) goto CLEANUP; sSubjInfo.pgSubjectType = (GUID*) &gSubjectGuid; sSubjInfo.hFile = hFile; sSubjInfo.pwsFileName = pSubjectInfo->pSignerFileInfo->pwszFileName; } else { memset(&sBlob, 0, sizeof(MS_ADDINFO_BLOB)); sSubjInfo.pgSubjectType=pSubjectInfo->pSignerBlobInfo->pGuidSubject; sSubjInfo.pwsDisplayName=pSubjectInfo->pSignerBlobInfo->pwszDisplayName; sSubjInfo.dwUnionChoice=MSSIP_ADDINFO_BLOB; sSubjInfo.psBlob=&sBlob; sBlob.cbStruct=sizeof(MS_ADDINFO_BLOB); sBlob.cbMemObject=pSubjectInfo->pSignerBlobInfo->cbBlob; sBlob.pbMemObject=pSubjectInfo->pSignerBlobInfo->pbBlob; } //now call InternalSign to do the real work hr = InternalSign(dwEncodingType, hCryptProv, dwKeySpec, pszAlgorithmOid, &sSubjInfo, pSubjectInfo->pdwIndex, psSigningContext, hSpcStore, fAuthcode ? pSignatureInfo->pAttrAuthcode->pwszName : NULL, fAuthcode ? pSignatureInfo->pAttrAuthcode->pwszInfo : NULL, TRUE, fAuthcode ? pSignatureInfo->pAttrAuthcode->fCommercial : FALSE, fAuthcode ? pSignatureInfo->pAttrAuthcode->fIndividual : FALSE, fAuthcode, pSignatureInfo->psAuthenticated, pSignatureInfo->psUnauthenticated, NULL, NULL, &pbEncodedMessage, &cbEncodedMessage); if ((hFile) && (fFileOpen == TRUE) && !(sSubjInfo.hFile)) { fFileOpen = FALSE; // we opened it, but, the SIP closed it! } if(hr != S_OK) goto CLEANUP; //timestamp the file if requested if(pwszHttpTimeStamp) { if(S_OK != (hr =SignerTimeStampEx(0, pSubjectInfo,pwszHttpTimeStamp, psRequest,pSipData, ppSignerContext))) goto CLEANUP; } else { if(ppSignerContext) { //set up the context information *ppSignerContext=(SIGNER_CONTEXT *)malloc(sizeof(SIGNER_CONTEXT)); if(NULL==(*ppSignerContext)) { hr=E_OUTOFMEMORY; goto CLEANUP; } (*ppSignerContext)->cbSize=sizeof(SIGNER_CONTEXT); (*ppSignerContext)->cbBlob=cbEncodedMessage; (*ppSignerContext)->pbBlob=pbEncodedMessage; pbEncodedMessage=NULL; } } hr=S_OK; CLEANUP: //free the memory. if(pbEncodedMessage) free(pbEncodedMessage); if(psSigningContext) CertFreeCertificateContext(psSigningContext); if(hSpcStore) CertCloseStore(hSpcStore, 0); //free the CryptProvider if(hCryptProv) { if(fCertAcquire) { FreeCryptProvFromCert(fAcquired, hCryptProv, pwszProvName, dwProvType, pwszTmpContainer); } else { PvkFreeCryptProv(hCryptProv, pProviderInfo? pProviderInfo->pwszProviderName : NULL, pProviderInfo? pProviderInfo->dwProviderType : 0, pwszTmpContainer); } } if(hMSBaseProv) { CryptReleaseContext(hMSBaseProv, 0); } if(hFile && (fFileOpen==TRUE)) CloseHandle(hFile); #if (1) //DSIE: bug 306005. if (hr != S_OK && !HRESULT_SEVERITY(hr)) { // Some CAPIs does not return HRESULT. They return Win API errors, // so need to convert to HRESULT so that caller using the FAILED // macro will catch the error. hr = HRESULT_FROM_WIN32((DWORD) hr); } #endif return hr; } //+----------------------------------------------------------------------- // // SignerFreeSignerContext // //------------------------------------------------------------------------ HRESULT WINAPI SignerFreeSignerContext( IN SIGNER_CONTEXT *pSignerContext) { if(pSignerContext) { if(pSignerContext->pbBlob) free(pSignerContext->pbBlob); free(pSignerContext); } return S_OK; }