windows-nt/Source/XPSP1/NT/ds/security/cryptoapi/pkisign/mssign32/mssign32.cpp
2020-09-26 16:20:57 +08:00

1196 lines
38 KiB
C++

//+-------------------------------------------------------------------------
//
// 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 <stdio.h>
//--------------------------------------------------------------------------
//
// 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; dwCertIndex<sSignedInfo.cCertEncoded; dwCertIndex++)
{
if((sSignedInfo.rgCertEncoded[dwCertIndex]).cbData==pCert->cbCertEncoded)
{
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;
}