//+---------------------------------------------------------------------------
//
//  Microsoft Windows
//  Copyright (C) Microsoft Corporation, 1992 - 1999
//
//  File:       timereq.cpp
//
//  Contents:   Digital Timestamping APIs
//
//  History:    June-25-1997	Xiaohs    Created
//----------------------------------------------------------------------------

#include "global.hxx"
#include <stdio.h>

static char szCrypt32[]="crypt32.dll";
//The version for crtyp32.dll which shipped with NT sp3: "4.0.1381.4"
static DWORD	dwLowVersion=0x05650004;
static DWORD	dwHighVersion=0x00040000;

HRESULT WINAPI 
GetSignedMessageSignerInfoSubj(IN  DWORD dwEncodingType,
                           IN  HCRYPTPROV hCryptProv,
                           IN  LPSIP_SUBJECTINFO pSipInfo,  
						   IN  DWORD*     pdwIndex,
                           IN  OUT PBYTE* ppbSignerInfo,    
                           IN  OUT DWORD* pcbSignerInfo)
{
    HRESULT hr = S_OK;
    SIP_DISPATCH_INFO sSip;  ZERO(sSip); // Table of sip functions
    DWORD cbSignedMsg = 0;
    PBYTE pbSignedMsg = 0;
    DWORD dwCertEncoding = 0;
    DWORD dwMsgType = 0;
    HCRYPTMSG hMsg = NULL;
    DWORD   cbSignerInfo=0;
    BYTE    *pbSignerInfo=NULL;

    PKITRY {

        if(!pcbSignerInfo || !ppbSignerInfo)
            PKITHROW(E_INVALIDARG);

        //init
        *pcbSignerInfo=0;
        *ppbSignerInfo=NULL;


       // Load up the sip functions. 
        if(!CryptSIPLoad(pSipInfo->pgSubjectType,   // GUID for the requried sip
                         0,               // Reserved
                         &sSip))          // Table of functions
            PKITHROW(SignError());
            
        sSip.pfGet(pSipInfo, 
                   &dwCertEncoding,
                   *pdwIndex, 
                   &cbSignedMsg,
                   NULL);
        if(cbSignedMsg == 0) PKITHROW(SignError());
        
        pbSignedMsg = (PBYTE) malloc(cbSignedMsg);
        if (!pbSignedMsg) PKITHROW(E_OUTOFMEMORY);
        
        if(!sSip.pfGet(pSipInfo, 
                       &dwCertEncoding,
                       *pdwIndex, 
                       &cbSignedMsg,
                       pbSignedMsg))
            PKITHROW(SignError()); // Real error.
       if(pSipInfo->dwUnionChoice != MSSIP_ADDINFO_BLOB)
       {
        if(dwCertEncoding != dwEncodingType) 
            PKITHROW(TRUST_E_NOSIGNATURE); 
       }
        
        if ((GET_CMSG_ENCODING_TYPE(dwEncodingType) & PKCS_7_ASN_ENCODING) &&
                SignNoContentWrap(pbSignedMsg, cbSignedMsg))
                dwMsgType = CMSG_SIGNED;
            
        // Use CryptMsg to crack the encoded PKCS7 Signed Message
        if (!(hMsg = CryptMsgOpenToDecode(dwEncodingType,
                                          0,              // dwFlags
                                          dwMsgType,
                                          hCryptProv,
                                          NULL,           // pRecipientInfo
                                          NULL))) 
            PKITHROW(E_UNEXPECTED);
        
        if (!CryptMsgUpdate(hMsg,
                            pbSignedMsg,
                            cbSignedMsg,
                            TRUE))                    // fFinal
            PKITHROW(SignError());

        if(!CryptMsgGetParam(hMsg,
                             CMSG_ENCODED_SIGNER,
                             0, // First signer
                             NULL,
                             &cbSignerInfo))
             PKITHROW(SignError());

        pbSignerInfo=(PBYTE)malloc(cbSignerInfo);
        if(!pbSignerInfo)
            PKITHROW(E_OUTOFMEMORY);

        if(!CryptMsgGetParam(hMsg,
                             CMSG_ENCODED_SIGNER,
                             0, // First signer
                             pbSignerInfo,
                             &cbSignerInfo))
             PKITHROW(SignError());

        //copy to the out put
        *ppbSignerInfo=pbSignerInfo;
        *pcbSignerInfo=cbSignerInfo;

        hr=S_OK;

        
    }
    PKICATCH(err) {
        hr = err.pkiError;
    } PKIEND;

    if (hMsg) 
        CryptMsgClose(hMsg);
    if(pbSignedMsg)
        free(pbSignedMsg);
    if( (hr!=S_OK) && (pbSignerInfo))
        free(pbSignerInfo);
    return hr;
}



HRESULT WINAPI 
GetSignedMessageSignerInfo(IN  HCRYPTPROV				hCryptProv,
						   IN  SIGNER_SUBJECT_INFO		*pSubjectInfo,	
						   IN  LPVOID					pSipInfo,
						   IN  OUT PBYTE*				ppbSignerInfo,    
                           IN  OUT DWORD*				pcbSignerInfo)
{
    HRESULT    hr = S_OK;
    HANDLE     hFile = NULL;
	BOOL	   fFileOpen=FALSE;

    GUID			gSubjectGuid; // The subject guid used to load the sip
	MS_ADDINFO_BLOB	sBlob;
    SIP_SUBJECTINFO sSubjInfo; ZERO(sSubjInfo);
    
    DWORD dwEncodingType = X509_ASN_ENCODING | PKCS_7_ASN_ENCODING; // For this version we default to this.

    PKITRY {
        if(!pcbSignerInfo || !ppbSignerInfo)
            PKITHROW(E_INVALIDARG);
        
        sSubjInfo.dwEncodingType = dwEncodingType;
        sSubjInfo.cbSize = sizeof(SIP_SUBJECTINFO); // Version
        sSubjInfo.pgSubjectType = (GUID*) &gSubjectGuid;
		sSubjInfo.hProv=hCryptProv;
        
		//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)))
					PKITHROW(hr);

				fFileOpen=TRUE;
			}
			else
				hFile=pSubjectInfo->pSignerFileInfo->hFile;

			// Get the subject type.
            if(S_OK != (hr=SignGetFileType(hFile, pSubjectInfo->pSignerFileInfo->pwszFileName, &gSubjectGuid)))
					PKITHROW(hr);


			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;
		}


        hr = GetSignedMessageSignerInfoSubj(
										dwEncodingType,
                                        hCryptProv,
                                        &sSubjInfo,
										pSubjectInfo->pdwIndex,
                                        ppbSignerInfo,
                                        pcbSignerInfo);

    if ((hFile) && (fFileOpen == TRUE) && !(sSubjInfo.hFile)) 
    {
        fFileOpen = FALSE;  // we opened it, but, the SIP closed it!
    }

        if(hr != S_OK) PKITHROW(hr);
    }
    PKICATCH(err) {
        hr = err.pkiError;
    } PKIEND;
    if(hFile && (fFileOpen==TRUE)) CloseHandle(hFile);
    return hr;
}

HRESULT WINAPI
SignerAddTimeStampResponse(
			IN  SIGNER_SUBJECT_INFO		*pSubjectInfo,			//Required: The subject to which the timestamp request should be added 
             IN PBYTE					pbTimeStampResponse,
             IN DWORD					cbTimeStampResponse,
			 IN LPVOID					pSipData)
{
    return SignerAddTimeStampResponseEx(
            0,
            pSubjectInfo,		
            pbTimeStampResponse, 
            cbTimeStampResponse, 
            pSipData,
            NULL);            
}



HRESULT WINAPI
SignerAddTimeStampResponseEx(
             IN  DWORD                  dwFlags,                //Reserved: Has to be set to 0.
			 IN  SIGNER_SUBJECT_INFO    *pSubjectInfo,			//Required: The subject to which the timestamp request should be added 
             IN PBYTE					pbTimeStampResponse,
             IN DWORD					cbTimeStampResponse,
			 IN LPVOID					pSipData,
             OUT SIGNER_CONTEXT         **ppSignerContext      
             )
{
    HRESULT    hr = S_OK;
    HANDLE     hFile = NULL;
	BOOL	   fFileOpen=FALSE;


    DWORD dwEncodingType = X509_ASN_ENCODING | PKCS_7_ASN_ENCODING;


    GUID			gSubjectGuid; // The subject guid used to load the sip
    SIP_SUBJECTINFO sSubjInfo; ZERO(sSubjInfo);
	MS_ADDINFO_BLOB	sBlob;
    HCRYPTPROV		hCryptProv = NULL;

	DWORD	        cbSignerInfo=0;
	BYTE        	*pbSignerInfo=NULL;

    PBYTE           pbEncodedMessage=NULL;			
    DWORD           cbEncodedMessage=0;			


    PKITRY {

        //init
       if(ppSignerContext)
           *ppSignerContext=NULL;

	   if(FALSE==CheckSigncodeSubjectInfo(pSubjectInfo))
            PKITHROW(E_INVALIDARG);

        // Use the default provider
        if(!CryptAcquireContext(&hCryptProv,
                                NULL,
                                MS_DEF_PROV,
                                PROV_RSA_FULL,
                                CRYPT_VERIFYCONTEXT))
            PKITHROW(SignError());
        

		//retrieve the enccoded signer info
		hr = GetSignedMessageSignerInfo(hCryptProv,
										pSubjectInfo,
										pSipData,
                                        &pbSignerInfo,
                                        &cbSignerInfo);

		if(hr != S_OK) PKITHROW(hr);


        
        sSubjInfo.hProv = hCryptProv;
        sSubjInfo.DigestAlgorithm.pszObjId = NULL;
        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)))
					PKITHROW(hr);

				fFileOpen=TRUE;
			}
			else
				hFile=pSubjectInfo->pSignerFileInfo->hFile;

			// Get the subject type.
			if(S_OK != (hr=SignGetFileType(hFile, pSubjectInfo->pSignerFileInfo->pwszFileName, &gSubjectGuid)))
					PKITHROW(hr);


			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;
		}

        
        hr = AddTimeStampSubj(dwEncodingType,
                              hCryptProv,
                              &sSubjInfo,
							  pSubjectInfo->pdwIndex,
                              pbTimeStampResponse,
                              cbTimeStampResponse,
							  pbSignerInfo,
							  cbSignerInfo,
                              &pbEncodedMessage,
                              &cbEncodedMessage);

        if ((hFile) && (fFileOpen == TRUE) && !(sSubjInfo.hFile)) 
        {
            fFileOpen = FALSE;  // we opened it, but, the SIP closed it!
        }

        if(hr != S_OK) PKITHROW(hr);
        
        //set up the signer context
        if(ppSignerContext)
        {
            //set up the context information
            *ppSignerContext=(SIGNER_CONTEXT *)malloc(sizeof(SIGNER_CONTEXT));

            if(NULL==(*ppSignerContext))
            {
                hr=E_OUTOFMEMORY;
                PKITHROW(hr);
            }

            (*ppSignerContext)->cbSize=sizeof(SIGNER_CONTEXT);
            (*ppSignerContext)->cbBlob=cbEncodedMessage;
            (*ppSignerContext)->pbBlob=pbEncodedMessage;
            pbEncodedMessage=NULL;
        }

        hr=S_OK;

    }
    PKICATCH(err) {
        hr = err.pkiError;
    } PKIEND;
    if(hFile && (fFileOpen==TRUE)) CloseHandle(hFile);
    if(hCryptProv) CryptReleaseContext(hCryptProv, 0); 
	if(pbSignerInfo) free(pbSignerInfo);
    if(pbEncodedMessage) 
        free(pbEncodedMessage);
        
    return hr;
}


HRESULT WINAPI
AddTimeStampSubj(IN DWORD dwEncodingType,
                 IN HCRYPTPROV hCryptProv,
                 IN LPSIP_SUBJECTINFO pSipInfo,
				 IN DWORD *pdwIndex,
                 IN PBYTE pbTimeStampResponse,
                 IN DWORD cbTimeStampResponse,
				 IN PBYTE pbEncodedSignerInfo,
				 IN DWORD cbEncodedSignerInfo,
                 OUT PBYTE* ppbMessage,				
                 OUT DWORD* pcbMessage			
)
{
    HRESULT hr = S_OK;
    SIP_DISPATCH_INFO sSip;  ZERO(sSip); // Table of sip functions

    DWORD cbSignedMsg = 0;
    PBYTE pbSignedMsg = 0;
    DWORD dwCertEncoding = 0;
    DWORD dwMsgType = 0;
    HCRYPTMSG hMsg = NULL;
    PBYTE pbEncodedSigner = NULL;
    DWORD cbEncodedSigner = 0;
    PBYTE pbEncodedSignMsg = NULL; // Encoding for the statement attribute
    DWORD cbEncodedSignMsg  = 0;    //    :

    PBYTE pbCounterSign = NULL;
    DWORD cbCounterSign = 0;

	CERT_INFO	*pbCertInfo = NULL;
	DWORD		cbCertInfo = 0;

    HCERTSTORE hTmpCertStore=NULL;
    PCCERT_CONTEXT pCert = NULL;
    PCCRL_CONTEXT pCrl = NULL;

    PCRYPT_ATTRIBUTES pbUnauth = NULL;
    DWORD             cbUnauth = 0;
	DWORD			  dwFileVersionSize=0;
	DWORD			  dwFile=0;
	BYTE			  *pVersionInfo=NULL;
	VS_FIXEDFILEINFO  *pFixedFileInfo=NULL;
	UINT			  unitFixedFileInfo=0; 	

    
    PKITRY {
        
		// Use CryptMsg to crack the encoded PKCS7 Signed Message
        if (!(hMsg = CryptMsgOpenToDecode(dwEncodingType,
                                          0,              // dwFlags
                                          dwMsgType,
                                          hCryptProv,
                                          NULL,           // pRecipientInfo
                                          NULL))) 
            PKITHROW(E_UNEXPECTED);
        
        if (!CryptMsgUpdate(hMsg,
                            pbTimeStampResponse,
                            cbTimeStampResponse,
                            TRUE))                    // fFinal
            PKITHROW(SignError());

		//get the encoded signer BLOB
        CryptMsgGetParam(hMsg,
                         CMSG_ENCODED_SIGNER,
                         0,
                         NULL,               
                         &cbEncodedSigner);
        if (cbEncodedSigner == 0) PKITHROW(S_FALSE); // no attributes
        
        pbEncodedSigner = (PBYTE) malloc(cbEncodedSigner);
        if(!pbEncodedSigner) PKITHROW(E_OUTOFMEMORY);
        
        if (!CryptMsgGetParam(hMsg,
                              CMSG_ENCODED_SIGNER,
                              0,
                              pbEncodedSigner,
                              &cbEncodedSigner))
            PKITHROW(SignError());

		//get the timestamp signer's cert info
        if(!CryptMsgGetParam(hMsg,
                         CMSG_SIGNER_CERT_INFO_PARAM,
                         0,
                         NULL,               
                         &cbCertInfo))
			PKITHROW(SignError());

        if (cbCertInfo == 0) PKITHROW(SignError()); 
        
        pbCertInfo = (CERT_INFO *) malloc(cbCertInfo);
        if(!pbCertInfo) PKITHROW(E_OUTOFMEMORY);
        
        if (!CryptMsgGetParam(hMsg,
                              CMSG_SIGNER_CERT_INFO_PARAM,
                              0,
                              pbCertInfo,
                              &cbCertInfo))
            PKITHROW(SignError());


		// get the cert store from the timestamp response
		hTmpCertStore = CertOpenStore(CERT_STORE_PROV_MSG,
                                      dwEncodingType,
                                      hCryptProv,
                                      CERT_STORE_NO_CRYPT_RELEASE_FLAG,
                                      hMsg);

		if (hTmpCertStore == NULL) PKITHROW(SignError()); 

		//find the timestamper's certificate
		pCert = CertGetSubjectCertificateFromStore(
					hTmpCertStore,
					X509_ASN_ENCODING,
					pbCertInfo);

		if(NULL == pCert)
		{
			hr=HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
			PKITHROW(hr);
		}	

		//make sure the timestamper's certiricate is either from verisign, 
		// or has the correct key usage
	/*	if(!ValidTimestampCert(pCert))
		{
			hr=TRUST_E_TIME_STAMP;
			PKITHROW(hr);
		}  	   */


		//Compare hashed signature of the orinigal signed message
		//with the authenticated attribute from the timestamp respoonse.
		//they have to match
		if(pbEncodedSignerInfo!=NULL && cbEncodedSignerInfo!=0)
		{			
			//verify the signature of the timestamp
			if(0==CryptMsgControl(hMsg,0,CMSG_CTRL_VERIFY_SIGNATURE,
				 pCert->pCertInfo))
			{
				hr=HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
				PKITHROW(hr);
			}

			//verify the signatures
			if(!CryptMsgVerifyCountersignatureEncoded(
				hCryptProv,
				dwEncodingType,
				pbEncodedSignerInfo,
				cbEncodedSignerInfo,
				pbEncodedSigner,
				cbEncodedSigner,
				pCert->pCertInfo))
			{
				hr=HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
				PKITHROW(hr);
			}	
		
		}//end of the counter signature verificate
		
		//release the cert context
		if(pCert)
		{
			CertFreeCertificateContext(pCert);
			pCert=NULL;
		}

		//close the certstore
		if(hTmpCertStore)
		{
			CertCloseStore(hTmpCertStore, 0);
			hTmpCertStore=NULL;
		}

        // get the cert store from the file
        hTmpCertStore = CertOpenStore(CERT_STORE_PROV_MSG,
                                      dwEncodingType,
                                      hCryptProv,
                                      CERT_STORE_NO_CRYPT_RELEASE_FLAG,
                                      hMsg);
        if (hTmpCertStore == NULL) PKITHROW(SignError());
            
        CryptMsgClose(hMsg);
		hMsg = NULL;
        
        // Load up the sip functions. 
        if(!CryptSIPLoad(pSipInfo->pgSubjectType,   // GUID for the requried sip
                         0,							// Reserved
                         &sSip))					// Table of functions
            PKITHROW(SignError());

        sSip.pfGet(pSipInfo, 
                   &dwCertEncoding,
                   *pdwIndex, 
                   &cbSignedMsg,
                   NULL);
        if(cbSignedMsg == 0) PKITHROW(SignError());
        
        pbSignedMsg = (PBYTE) malloc(cbSignedMsg);
        if (!pbSignedMsg) PKITHROW(E_OUTOFMEMORY);
        
        if(!sSip.pfGet(pSipInfo, 
                       &dwCertEncoding,
                       *pdwIndex, 
                       &cbSignedMsg,
                       pbSignedMsg))
            PKITHROW(SignError()); // Real error.

        if(pSipInfo->dwUnionChoice != MSSIP_ADDINFO_BLOB)
        {
            if(dwCertEncoding != dwEncodingType) 
                PKITHROW(TRUST_E_NOSIGNATURE); 
        }
        
        if ((GET_CMSG_ENCODING_TYPE(dwEncodingType) & PKCS_7_ASN_ENCODING) &&
            SignNoContentWrap(pbSignedMsg, cbSignedMsg))
            dwMsgType = CMSG_SIGNED;
        

        // Use CryptMsg to crack the encoded PKCS7 Signed Message
        if (!(hMsg = CryptMsgOpenToDecode(dwEncodingType,
                                          0,              // dwFlags
                                          dwMsgType,
                                          hCryptProv,
                                          NULL,           // pRecipientInfo
                                          NULL))) 
            PKITHROW(E_UNEXPECTED);
        
        if (!CryptMsgUpdate(hMsg,
                            pbSignedMsg,
                            cbSignedMsg,
                            TRUE))                    // fFinal
            PKITHROW(SignError());


        // Encode up the signer info from the timestamp response and
        // add it as an unauthenticated attribute.
        CRYPT_ATTRIBUTE sAttr;
        CRYPT_ATTR_BLOB sSig;

        sSig.pbData = pbEncodedSigner;
        sSig.cbData = cbEncodedSigner;
        sAttr.pszObjId = szOID_RSA_counterSign;
        sAttr.cValue = 1;
        sAttr.rgValue = &sSig;

        CryptEncodeObject(dwEncodingType,
                          PKCS_ATTRIBUTE,
                          &sAttr,
                          pbCounterSign,
                          &cbCounterSign);
        if(cbCounterSign == 0) PKITHROW(SignError());
        
        pbCounterSign = (PBYTE) malloc(cbCounterSign);
        if(!pbCounterSign) PKITHROW(E_OUTOFMEMORY);

        if(!CryptEncodeObject(dwEncodingType,
                              PKCS_ATTRIBUTE,
                              &sAttr,
                              pbCounterSign,
                              &cbCounterSign))
            PKITHROW(SignError());
        

        CryptMsgGetParam(hMsg,
                         CMSG_SIGNER_UNAUTH_ATTR_PARAM,
                         0,
                         NULL,
                         &cbUnauth);
        if(cbUnauth) 
		{
            
			//check the version of "crytp32.dll".  If it is more than
			//"4.0.1381.4", we should be able to timestamp a timestamped
			//file



			dwFileVersionSize=GetFileVersionInfoSize(szCrypt32,&dwFile);

			if(!dwFileVersionSize)
				PKITHROW(SignError());

			pVersionInfo=(BYTE *)malloc(dwFileVersionSize);

			if(!pVersionInfo)
				 PKITHROW(SignError());

			if(!GetFileVersionInfo(szCrypt32, NULL,dwFileVersionSize,
				pVersionInfo))
				  PKITHROW(SignError());

			if(!VerQueryValue(pVersionInfo, "\\", (LPVOID *)&pFixedFileInfo,
				&unitFixedFileInfo))
			  PKITHROW(SignError());

			if(pFixedFileInfo->dwFileVersionMS <= dwHighVersion &&
				pFixedFileInfo->dwFileVersionLS <= dwLowVersion)
				PKITHROW(SignError());


			// we delete any existing time stamps since our policy provider
			//only support one timestamp per file
		
			pbUnauth = (PCRYPT_ATTRIBUTES) malloc(cbUnauth);
            if(!pbUnauth) PKITHROW(E_OUTOFMEMORY);
            
            if(!CryptMsgGetParam(hMsg,
                                 CMSG_SIGNER_UNAUTH_ATTR_PARAM,
                                 0,
                                 pbUnauth,
                                 &cbUnauth))
                PKITHROW(SignError());
            
            
            CMSG_CTRL_DEL_SIGNER_UNAUTH_ATTR_PARA  sAttrDel; ZERO(sAttrDel);
            sAttrDel.cbSize = sizeof(CMSG_CTRL_DEL_SIGNER_UNAUTH_ATTR_PARA);
			//we always assume there is only one signer
            sAttrDel.dwSignerIndex = 0;
            for(DWORD ii = 0; ii < pbUnauth->cAttr; ii++) 
			{
                if(strcmp(pbUnauth->rgAttr[ii].pszObjId, szOID_RSA_counterSign) == 0) 
				{
                        sAttrDel.dwUnauthAttrIndex = ii;
                        if (!CryptMsgControl(hMsg,
                                             0,
                                             CMSG_CTRL_DEL_SIGNER_UNAUTH_ATTR,
                                             &sAttrDel))
                            PKITHROW(SignError());
                }
            }  
        }
            
        CMSG_CTRL_ADD_SIGNER_UNAUTH_ATTR_PARA  sAttrPara; ZERO(sAttrPara);
        sAttrPara.cbSize = sizeof(CMSG_CTRL_ADD_SIGNER_UNAUTH_ATTR_PARA);
        sAttrPara.dwSignerIndex = 0;
        sAttrPara.blob.pbData = pbCounterSign;
        sAttrPara.blob.cbData = cbCounterSign;
        if (!CryptMsgControl(hMsg,
                             0,
                             CMSG_CTRL_ADD_SIGNER_UNAUTH_ATTR,
                             &sAttrPara))
            PKITHROW(SignError());
        // merge all the certificates from the time stamp response
        DWORD dwFlags = 0;

        while ((pCert = CertEnumCertificatesInStore(hTmpCertStore, pCert))) {
            CRYPT_DATA_BLOB blob;
            blob.pbData = pCert->pbCertEncoded;
            blob.cbData = pCert->cbCertEncoded;
            if (!CryptMsgControl(hMsg,
                                 0,
                                 CMSG_CTRL_ADD_CERT,
                                 &blob))
                PKITHROW(SignError());
        }

        while ((pCrl = CertGetCRLFromStore(hTmpCertStore, NULL, pCrl, &dwFlags))) {
            CRYPT_DATA_BLOB blob;
            blob.pbData = pCrl->pbCrlEncoded;
            blob.cbData = pCrl->cbCrlEncoded;
            if (!CryptMsgControl(hMsg,
                                 0,
                                 CMSG_CTRL_ADD_CRL,
                                 &blob))
                PKITHROW(SignError());
        }

        // Re-encode up the message and away we go.
        CryptMsgGetParam(hMsg,
                         CMSG_ENCODED_MESSAGE,
                         0,                      // dwIndex
                         NULL,                   // pbSignedData
                         &cbEncodedSignMsg);
        if (cbEncodedSignMsg == 0) PKITHROW(SignError());
        
        pbEncodedSignMsg = (PBYTE) malloc(cbEncodedSignMsg);
        if(!pbEncodedSignMsg) PKITHROW(E_OUTOFMEMORY);
        
        if (!CryptMsgGetParam(hMsg,
                              CMSG_ENCODED_MESSAGE,
                              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;
        }

    }
    PKICATCH(err) {
        hr = err.pkiError;
    } PKIEND;

    if(pbUnauth)
        free(pbUnauth);
    if(pCert)
        CertFreeCertificateContext(pCert);
    if(pCrl)
        CertFreeCRLContext(pCrl);
    if(hTmpCertStore)
        CertCloseStore(hTmpCertStore, 0);
    if(pbCounterSign)
        free(pbCounterSign);
    if(pbEncodedSignMsg)
        free(pbEncodedSignMsg);
    if (hMsg) 
        CryptMsgClose(hMsg);
    if(pbEncodedSigner)
        free(pbEncodedSigner);
    if(pbSignedMsg)
        free(pbSignedMsg);
	if(pVersionInfo)
		free(pVersionInfo);
	if(pbCertInfo)
		free(pbCertInfo);

    return hr;
}            


HRESULT WINAPI 
SignerCreateTimeStampRequest(
					   IN  SIGNER_SUBJECT_INFO		*pSubjectInfo,		//Required: The subject based on which to create a timestamp request 
                       IN  PCRYPT_ATTRIBUTES psRequest,         // Optional, attributes added to Time stamp request 
					   IN  LPVOID	pSipData,
                       OUT PBYTE pbTimeStampRequest,
                       IN OUT DWORD* pcbTimeStampRequest)
{
    HRESULT    hr = S_OK;
	BOOL		fResult=FALSE;

    DWORD dwEncodingType = X509_ASN_ENCODING | PKCS_7_ASN_ENCODING; // For this version we default to this.

    PBYTE pbDigest = NULL;
    DWORD cbDigest = 0;

    PKITRY {
        if((!pcbTimeStampRequest) ||(FALSE==CheckSigncodeSubjectInfo(pSubjectInfo)))
            PKITHROW(E_INVALIDARG);

        if(*pcbTimeStampRequest == 0)
            pbTimeStampRequest = NULL;

            
        // Retrieve the digest from the signature on the file.

		hr = GetSignedMessageDigest(pSubjectInfo,
									  pSipData,
                                       &pbDigest,
                                        &cbDigest);

		if(hr != S_OK) PKITHROW(hr);

        hr = TimeStampRequest(dwEncodingType,
                              psRequest,
                              pbDigest,
                              cbDigest,
                              pbTimeStampRequest,
                              pcbTimeStampRequest);
        if(hr != S_OK) PKITHROW(hr);
    }
    PKICATCH(err) {
        hr = err.pkiError;
    } PKIEND;

    if(pbDigest) free(pbDigest);

    return hr;
}    
            

HRESULT WINAPI 
GetSignedMessageDigest(IN  SIGNER_SUBJECT_INFO		*pSubjectInfo,		//Required: The subject based on which to create a timestamp request 
					   IN  LPVOID					pSipData,
                       IN  OUT PBYTE*				ppbDigest,    
                       IN  OUT DWORD*				pcbDigest)
{
    HRESULT    hr = S_OK;
    HANDLE     hFile = NULL; 
	BOOL	   fFileOpen=FALSE;


    GUID				gSubjectGuid; // The subject guid used to load the sip
	MS_ADDINFO_BLOB		sBlob;
    SIP_SUBJECTINFO		sSubjInfo; ZERO(sSubjInfo);
    
    DWORD dwEncodingType = X509_ASN_ENCODING | PKCS_7_ASN_ENCODING; // For this version we default to this.

    PKITRY {
        if((!pcbDigest) || (!ppbDigest) || (FALSE==CheckSigncodeSubjectInfo(pSubjectInfo)))
            PKITHROW(E_INVALIDARG);

		*ppbDigest = NULL;

        
        // Set up the sip information (this is based on mssip.h)
        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)))
					PKITHROW(hr);

				fFileOpen=TRUE;
			}
			else
				hFile=pSubjectInfo->pSignerFileInfo->hFile;

			// Get the subject type.
			if(S_OK != (hr=SignGetFileType(hFile, pSubjectInfo->pSignerFileInfo->pwszFileName, &gSubjectGuid)))
					PKITHROW(hr);


			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;
		}

        hr = GetSignedMessageDigestSubj(dwEncodingType,
                                        NULL,
                                        &sSubjInfo,
										pSubjectInfo->pdwIndex,
                                        ppbDigest,
                                        pcbDigest);

        if ((hFile) && (fFileOpen == TRUE) && !(sSubjInfo.hFile)) 
        {
            fFileOpen = FALSE;  // we opened it, but, the SIP closed it!
        }


        if(hr != S_OK) PKITHROW(hr);
    }
    PKICATCH(err) {
        hr = err.pkiError;
    } PKIEND;
    if(hFile && (fFileOpen==TRUE)) CloseHandle(hFile);
    return hr;
}


HRESULT WINAPI 
GetSignedMessageDigestSubj(IN  DWORD dwEncodingType,
                           IN  HCRYPTPROV hCryptProv,
                           IN  LPSIP_SUBJECTINFO pSipInfo,  
						   IN  DWORD	  *pdwIndex,
                           IN  OUT PBYTE* ppbTimeDigest,    
                           IN  OUT DWORD* pcbTimeDigest)
{
    HRESULT hr = S_OK;
    SIP_DISPATCH_INFO sSip;  ZERO(sSip); // Table of sip functions
    DWORD cbSignedMsg = 0;
    PBYTE pbSignedMsg = 0;
    DWORD dwCertEncoding = 0;
    DWORD dwMsgType = 0;
    HCRYPTMSG hMsg = NULL;
    BOOL fAcquiredCryptProv = FALSE;
	DWORD	cbTimeDigest=0;
	BYTE	*pbTimeDigest=NULL;

    PKITRY {

        if(!pcbTimeDigest || !ppbTimeDigest)
            PKITHROW(E_INVALIDARG);

		*ppbTimeDigest=NULL;
        *pcbTimeDigest=0;

        if(hCryptProv == NULL) 
		{
            if(!CryptAcquireContext(&hCryptProv,
                                    NULL,
                                    MS_DEF_PROV,
                                    PROV_RSA_FULL,
                                    CRYPT_VERIFYCONTEXT))
                PKITHROW(SignError());
            fAcquiredCryptProv = TRUE;

			//update the subject Info
			if(NULL==(pSipInfo->hProv))
				pSipInfo->hProv=hCryptProv;
        }            

        // Load up the sip functions. 
        if(!CryptSIPLoad(pSipInfo->pgSubjectType,   // GUID for the requried sip
                         0,               // Reserved
                         &sSip))          // Table of functions
            PKITHROW(SignError());
            
        sSip.pfGet(pSipInfo, 
                   &dwCertEncoding,
                   *pdwIndex, 
                   &cbSignedMsg,
                   NULL);
        if(cbSignedMsg == 0) PKITHROW(SignError());
        
        pbSignedMsg = (PBYTE) malloc(cbSignedMsg);
        if (!pbSignedMsg) PKITHROW(E_OUTOFMEMORY);
        
        if(!sSip.pfGet(pSipInfo, 
                       &dwCertEncoding,
                       *pdwIndex, 
                       &cbSignedMsg,
                       pbSignedMsg))
            PKITHROW(SignError()); // Real error.
        if(pSipInfo->dwUnionChoice != MSSIP_ADDINFO_BLOB)
        {
             if(dwCertEncoding != dwEncodingType) 
                    PKITHROW(TRUST_E_NOSIGNATURE); 
        }
        
        if ((GET_CMSG_ENCODING_TYPE(dwEncodingType) & PKCS_7_ASN_ENCODING) &&
                SignNoContentWrap(pbSignedMsg, cbSignedMsg))
                dwMsgType = CMSG_SIGNED;
            
        // Use CryptMsg to crack the encoded PKCS7 Signed Message
        if (!(hMsg = CryptMsgOpenToDecode(dwEncodingType,
                                          0,              // dwFlags
                                          dwMsgType,
                                          hCryptProv,
                                          NULL,           // pRecipientInfo
                                          NULL))) 
            PKITHROW(E_UNEXPECTED);
        
        if (!CryptMsgUpdate(hMsg,
                            pbSignedMsg,
                            cbSignedMsg,
                            TRUE))                    // fFinal
            PKITHROW(SignError());
						                
        if(!CryptMsgGetParam(hMsg,
                             CMSG_ENCRYPTED_DIGEST,
                             0, 
                             NULL,
                             &cbTimeDigest))
              PKITHROW(SignError());

        //allocate memory
        pbTimeDigest = (PBYTE)malloc(cbTimeDigest);
        if(!pbTimeDigest)
            PKITHROW(E_OUTOFMEMORY);


        if(!CryptMsgGetParam(hMsg,
                             CMSG_ENCRYPTED_DIGEST,
                             0,
                             pbTimeDigest,
                             &cbTimeDigest))
              PKITHROW(SignError());

        //copy the information
        *ppbTimeDigest=pbTimeDigest;
        *pcbTimeDigest=cbTimeDigest;

        hr=S_OK;
    }
    PKICATCH(err) {
        hr = err.pkiError;
    } PKIEND;

    if (hMsg) 
        CryptMsgClose(hMsg);
    if(pbSignedMsg)
        free(pbSignedMsg);
    if((hr!=S_OK) && (pbTimeDigest))
        free(pbTimeDigest);
    if(fAcquiredCryptProv)
        CryptReleaseContext(hCryptProv, 0);
    return hr;
}

HRESULT WINAPI 
TimeStampRequest(IN  DWORD dwEncodingType,
                 IN  PCRYPT_ATTRIBUTES psRequest,
                 IN  PBYTE pbDigest,
                 IN  DWORD cbDigest,
                 OUT PBYTE pbTimeRequest,      
                 IN  OUT DWORD* pcbTimeRequest)
{
    HRESULT    hr = S_OK;

    CRYPT_TIME_STAMP_REQUEST_INFO sTimeRequest; ZERO(sTimeRequest);
    PBYTE pbEncodedRequest = NULL;
    DWORD cbEncodedRequest = 0;



    PKITRY {
        if(!pcbTimeRequest) 
            PKITHROW(E_INVALIDARG);
        
        if(*pcbTimeRequest == 0)
            pbTimeRequest = NULL;

        sTimeRequest.pszTimeStampAlgorithm = SPC_TIME_STAMP_REQUEST_OBJID;
        sTimeRequest.pszContentType = szOID_RSA_data;
        sTimeRequest.Content.pbData = pbDigest;
        sTimeRequest.Content.cbData = cbDigest;
        if(psRequest) {
            sTimeRequest.cAttribute = psRequest->cAttr;
            sTimeRequest.rgAttribute = psRequest->rgAttr;
        }
        
        CryptEncodeObject(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
                          PKCS_TIME_REQUEST,
                          &sTimeRequest,
                          pbEncodedRequest,
                          &cbEncodedRequest);

        if(cbEncodedRequest == 0) PKITHROW(SignError());

        pbEncodedRequest = (PBYTE) malloc(cbEncodedRequest);
        if(!pbEncodedRequest) PKITHROW(E_OUTOFMEMORY);
        
        if(!CryptEncodeObject(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
                              PKCS_TIME_REQUEST,
                              &sTimeRequest,
                              pbEncodedRequest,
                              &cbEncodedRequest))
            PKITHROW(SignError());
        
		//return the infomation
		if(*pcbTimeRequest==0)
		{
			*pcbTimeRequest=cbEncodedRequest;
			hr=S_OK;
		}
		else
		{
			if(*pcbTimeRequest < cbEncodedRequest)
			{
				hr=ERROR_MORE_DATA;
				PKITHROW(SignError());
			}
			else
			{
				memcpy(pbTimeRequest, pbEncodedRequest, cbEncodedRequest);
				hr=S_OK;
			}
		}
        
        
    }
    PKICATCH(err) {
        hr = err.pkiError;
    } PKIEND;

    if(pbEncodedRequest)
        free(pbEncodedRequest);
    return hr;
}