locked
What I have done wrong?the funtion of CryptEncrypt doesn't work. RRS feed

  • Question

  • hello sir/madam

          I'm not familar with cryptoapi programming and not very familar with C++,however,I have searched Google,have written the following code,My Question is when I calling CryptEncrypt funtion,why the smart card doesn't pop-up the PIN dialog to verify PIN code and the CryptEncrypt didn't encrypt the strings that I want,what I have done wrong?any help would be appeciated.

    #include "stdafx.h"

    #include <windows.h>
    #include <wincrypt.h>
    #include "iostream"

    #pragma comment(lib,"crypt32.lib")

    using namespace std;

    void MyHandleError(char *s);

    int _tmain(int argc, _TCHAR* argv[])
    {
        
        PCCERT_CONTEXT m_pCertContext;
        HCERTSTORE m_hStore;
        HCRYPTPROV hCryptProv;         // CSP handle
        DWORD dwKeySpec;
        // Store handle
        m_pCertContext = NULL;
        m_hStore = NULL;
        HCRYPTHASH hCryptHash;
        HCRYPTKEY hCryptKey;

    if(m_pCertContext == NULL)
        {

         
            string strOName("Organization ClassA CA");

         
            TCHAR* lpszStoreName =_T("MY");
             HCERTSTORE m_hStore = CertOpenSystemStore(NULL, lpszStoreName);

            if (m_hStore)
            {    
              
                CERT_RDN certRDN;

                certRDN.cRDNAttr = 1;
                certRDN.rgRDNAttr = new CERT_RDN_ATTR;
                certRDN.rgRDNAttr->pszObjId = szOID_ORGANIZATIONAL_UNIT_NAME;
                certRDN.rgRDNAttr->dwValueType = CERT_RDN_ANY_TYPE;
                certRDN.rgRDNAttr->Value.pbData = (BYTE *) strOName.c_str();
                certRDN.rgRDNAttr->Value.cbData = strlen(strOName.c_str());

            
                PCCERT_CONTEXT pCurrent = NULL;

              
                pCurrent = CertFindCertificateInStore(    m_hStore,
                                                        X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
                                                        0,
                                                        CERT_FIND_ISSUER_ATTR,
                                                        &certRDN,
                                                        NULL);
                while(pCurrent != NULL)
                {
                    BOOL bRet = FALSE;
                    byte bUsage;

                 
                    bRet = CertGetIntendedKeyUsage(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, pCurrent->pCertInfo, &bUsage, 1);
                   if(bRet)
                   {
                
                    if((bUsage & CERT_DIGITAL_SIGNATURE_KEY_USAGE) && (bUsage & CERT_NON_REPUDIATION_KEY_USAGE))
                    {
                   
                        bRet = CryptFindCertificateKeyProvInfo(pCurrent,0,NULL);

                    }
                    if(!bRet)
                    {
                        m_pCertContext = pCurrent;
                        pCurrent = NULL;


                        break;
                    }
                    pCurrent = CertFindCertificateInStore(    m_hStore,
                                                        X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
                                                        0,
                                                        CERT_FIND_ISSUER_ATTR,
                                                        &certRDN,
                                                        pCurrent);

                    //20160214start
                   if (!pCurrent)

        {

            MyHandleError("Cert not found.\n");

        }

    //---------------------------------------------------------------

    // Get a handle to a cryptographic provider.

    if( !(CryptAcquireCertificatePrivateKey(

            pCurrent ,

            0,

            NULL,

            &hCryptProv,

            &dwKeySpec,

            NULL)))

        {

            MyHandleError("CryptAcquireContext failed");

        }

        CHAR pszName[1000];

        DWORD cbName;

    //---------------------------------------------------------------

    // Read the name of the CSP.

        cbName = 1000;

    if(CryptGetProvParam(

            hCryptProv,

            PP_NAME,

            (BYTE*)pszName,

            &cbName,

            0))

        {

            _tprintf(TEXT("CryptGetProvParam succeeded.\n"));

            printf("Provider name: %s\n", pszName);

        }

    else

        {

            MyHandleError("Error reading CSP name.\n");

        }

    //---------------------------------------------------------------

    // Read the name of the key container.

        cbName = 1000;

    if(CryptGetProvParam(

            hCryptProv,

            PP_CONTAINER,

            (BYTE*)pszName,

            &cbName,

            0))

        {

            _tprintf(TEXT("CryptGetProvParam succeeded.\n"));

            printf("Key Container name: %s\n", pszName);

        }

    else

        {

            MyHandleError("Error reading key container name.\n");

        }


       if(CryptCreateHash(
            hCryptProv,
            CALG_MD5,
            0,
            0,
            &hCryptHash))
       {
               _tprintf(TEXT("CryptCreateHash successful.\n"));

       
       }

        static char szHash[]="PISAHASHDATA";
        DWORD dwLen=strlen(szHash);
        if(CryptHashData(hCryptHash,(BYTE*)szHash,dwLen,0))
        {
             _tprintf(TEXT("CryptHashData  successful.\n"));

           
        }
        if(CryptDeriveKey(hCryptProv,CALG_RC2,hCryptHash,0,&hCryptKey))
        {
              _tprintf(TEXT("CryptDeriveKey successful.\n"));

        }
        static char szEntry[]="PISA2002";
        DWORD dwLenIn=strlen(szEntry);
        DWORD dwLenOut=dwLenIn;
        if (CryptEncrypt(hCryptKey,0,TRUE,0,(BYTE*)szEntry,&dwLenOut,dwLenIn))
        {
           _tprintf(TEXT("CryptEncrypt successful.\n"));
        }//although it's sucessful in debug model I can see,but the szEntry I can see it has not changed.
        CryptDestroyKey(hCryptKey);
        CryptDestroyHash(hCryptHash);*

       CertCloseStore(m_hStore, CERT_CLOSE_STORE_FORCE_FLAG);

        CryptReleaseContext(hCryptProv, 0);
        pCurrent = NULL;
                 //20160214end

                }
                

                delete certRDN.rgRDNAttr;        
            }

     
            if(m_pCertContext == NULL)
            {
                if (m_pCertContext) {
            CertFreeCertificateContext(m_pCertContext);
            m_pCertContext = NULL;
                }
        if (m_hStore) {
            CertCloseStore(m_hStore, CERT_CLOSE_STORE_FORCE_FLAG);
            m_hStore = NULL;
        }
            }
            }

        
        

        
        }
            return 0;
    }

    void MyHandleError(char *s)

    {

        fprintf(stderr,"An error occurred in running the program. \n");

        fprintf(stderr,"%s\n",s);

        fprintf(stderr,"Error number %x.\n",GetLastError());

        fprintf(stderr,"Program terminating. \n");

        exit(1);

    }

    best regards

    Ken



    • Edited by ken yup Sunday, February 14, 2016 10:46 AM
    Sunday, February 14, 2016 10:45 AM

All replies

  • Generally the public key encrypts, and the private key protected by a PIN on the smartcard decrypts.  So if you don't do a command that uses a private key on the card, no pin prompt occurs.

    Lets start with the basic information.

    What kind of a smartcard are you using?  A PIV card issued by the federal government that operates according to FIPS 201 (NIST SP800-73) and is supported by the Microsoft PIV mini-driver or a proprietary smartcard? 

    Are you intending to authenticate the cardholder, or use the card to decrypt data or sign data?

    Sunday, February 14, 2016 3:13 PM
  • I'm just trying to sign data,not to decrypt,I'm not doing the bad things.
    I'm not a hacker

    best

    Ken

    • Edited by ken yup Monday, February 15, 2016 1:11 PM
    Monday, February 15, 2016 12:44 PM
  • I just trying 1)verify the PIN code 2)sign a XML

    the XML sample is the following

    the original XML was:

    <?xml version="1.0" ?>

    <jh xmlns="http://cmsland.com/yjj_qyjk_cgrk.xsd">

    <dj ysjl="normal" clr="censor" wdjl="23" ysjssj="2013-01-01T13:09:09" yskssj="2013-01-01T09:12:20" yssb="transport" xsdh="listnoA1" ghqy="med-company" rqrq="2013-01-01" djbh="depno1"><tm bz="memo" sl="500" yxqz="2015-05-01" scrq="2012-05-01" scph="20120501" bzgg="24tablets*240boxes/bag" bwm="86902160000015"/><tm sl="200" yxqz="2015-05-02" scrq="2012-05-02" scph="20120502" bzgg="30tablets/box" bwm="86901693000066"/></dj>

    <dj ysjl="normal" clr="censor" xsdh="listnoB1" ghqy="b-company" rqrq="2013-01-01" djbh="depno2"><tm sl="500" yxqz="2015-05-01" scrq="2012-05-01" scph="20120501" bzgg="50tablets/box" bwm="86900310000083"/><tm sl="200" yxqz="2015-05-02" scrq="2012-05-02" scph="20120502" bzgg="40tablets/box" bwm="86901507000282"/></dj>

    </jh>

    and signed XML  goes to

    <?xml version="1.0"?>

    <Signature xmlns="http://www.w3.org/2000/09/xmldsig#">

    <SignedInfo>

    <CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>

    <SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>

    <Reference URI="#DataObjectId"><Transforms>

    <Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>

    </Transforms>

    <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>

    <DigestValue>bFemPaZ+ERSZCZTfkxY2lUE3XXg=</DigestValue>

    </Reference>

    </SignedInfo>

    <SignatureValue>Q/Gpl+Wi5xT4glKEhC2igtFWsAseFqdkbODdqZKBwRbhmUWseljs6/bLsHAuheZWAWmo7voJfImJ362oKySCvfzkTg1orGWdSwXhW4DfDTZ+T+ZxYnKxoYTOqWTpSEFeOO964QlIR+aQKFsOOjM7/UqCfRRzNhq8TrQ/jNLQfuk=</SignatureValue>

    <KeyInfo>

    <X509Data><X509IssuerSerial>

    <X509IssuerName>CN=NETCA Individual ClassA CA, OU=Individual ClassA CA, O=NETCA Certificate Authority, C=CN</X509IssuerName>

    <X509SerialNumber>81795886028495042323800393625097362204</X509SerialNumber>

    </X509IssuerSerial><X509Certificate>MIIEBjCCAu6gAwIBAgIQPYlQiyH4Ks50d1Pg0NZbHDANBgkqhkiG9w0BAQUFADB3MQswCQYDVQQGEwJDTjEkMCIGA1UEChMbTkVUQ0EgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MR0wGwYDVQQLExRJbmRpdmlkdWFsIENsYXNzQSBDQTEjMCEGA1UEAxMaTkVUQ0EgSW5kaXZpZHVhbCBDbGFzc0EgQ0EwHhcNMTIwNDE4MTYwMDAwWhcNMTMwNDE5MTU1OTU5WjBzMQswCQYDVQQGEwJDTjESMBAGA1UECBMJR3Vhbmdkb25nMQ0wCwYDVQQHHgRef13eMSUwIwYDVQQDHhxOKk66bUuL1QAyADAAMQAxADAANAAyADIAMAAxMRowGAYJKoZIhvcNAQkBFgt6c0BjbmNhLm5ldDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1DO/NjAy1++niPTgcVcR3WwQ5z0uiq0qkg/g1mwhXDWZ7V5cAtrGsQVl82SYXBIxaVMPEXPI2ess8rYY7w7KJD/WFMpdRHmK57ZkDsqJbh55D0ylMBPovwJwfmJ6mJwu9+9oU13zlKKetL3eVAIomp3i37YVPWWpRbWTU2GcnG0CAwEAAaOCARQwggEQMB8GA1UdIwQYMBaAFLFHZEQZX2XMQLsGS+l5BOAe7LVOMB0GA1UdDgQWBBShjFOEYwPh3wcsixILjbcCat+4XjBXBgNVHSAEUDBOMEwGCisGAQQBgZJIAQowPjA8BggrBgEFBQcCARYwaHR0cDovL3d3dy5jbmNhLm5ldC9jcy9rbm93bGVkZ2Uvd2hpdGVwYXBlci9jcHMvMBYGA1UdEQQPMA2BC3pzQGNuY2EubmV0MAwGA1UdEwEB/wQCMAAwDgYDVR0PAQH/BAQDAgbAMD8GA1UdHwQ4MDYwNKAyoDCGLmh0dHA6Ly9jbGFzc2FjYTEuY25jYS5uZXQvY3JsL0luZGl2aWR1YWxDQS5jcmwwDQYJKoZIhvcNAQEFBQADggEBAAdTQ0s+EYNLchwSoAb5MvGGFWh24XuQGLJLJ+81F3ww11Ah31GSRqJVoXzhozH9GPym0M77LjUiasWCN47tOuhTN3aVGZfGq2daMq2+j+p6LOya/mbq7w3SdhGa1vTrTjkxXNCRnFHDsLR1ujv40WrQM7HfBJ9TOckDSzGbDXSog14mbGTWJaP+FwDb/4YEH7W4Wy2vcPG5/gbWYWwujvSTDBtK9QXhM48Car2oExnmYAbxiu81z4CPPB0LB/GyxtzsYbB4YItFWTY4E8jcQb+VDRbYruX5k1ndk4zLAu45bqrhInAknr9tlMu01VofDNexz0xqmScEkWqdtLhMDow=</X509Certificate>

    </X509Data></KeyInfo>

    <Object Id="DataObjectId">

    <jh xmlns="http://cmsland.com/yjj_qyjk_cgrk.xsd">

    <dj ysjl="normal" clr="censor" wdjl="23" ysjssj="2013-01-01T13:09:09" yskssj="2013-01-01T09:12:20" yssb="transport" xsdh="listnoA1" ghqy="med-company" rqrq="2013-01-01" djbh="depno1"><tm bz="memo" sl="500" yxqz="2015-05-01" scrq="2012-05-01" scph="20120501" bzgg="24tablets*240boxes/bag" bwm="86902160000015"/><tm sl="200" yxqz="2015-05-02" scrq="2012-05-02" scph="20120502" bzgg="30tablets/box" bwm="86901693000066"/></dj>

    <dj ysjl="normal" clr="censor" xsdh="listnoB1" ghqy="b-company" rqrq="2013-01-01" djbh="depno2"><tm sl="500" yxqz="2015-05-01" scrq="2012-05-01" scph="20120501" bzgg="50tablets/box" bwm="86900310000083"/><tm sl="200" yxqz="2015-05-02" scrq="2012-05-02" scph="20120502" bzgg="40tablets/box" bwm="86901507000282"/></dj>

    </jh><

    /Object>

    </Signature>



    the format of XML is weired which is signed,it's different than the sample which is signed on MSDN. I can't figure out how can I do it



    • Edited by ken yup Monday, February 15, 2016 1:11 PM
    Monday, February 15, 2016 12:53 PM
  • There is a C  CRYPTXML signing sample in the SDK

    winsdk_samples_security_cryptoapi_cryptxml_cpp_cryptxml_cpp
    winsdk_samples_security_cryptoapi_cryptxml_cpp_cryptxml_sln
    winsdk_samples_security_cryptoapi_cryptxml_cpp_cryptxml_vcproj
    winsdk_samples_security_cryptoapi_cryptxml_cpp_pch_h
    winsdk_samples_security_cryptoapi_cryptxml_cpp_resolver_cpp
    winsdk_samples_security_cryptoapi_cryptxml_cpp_sign_cpp
    winsdk_samples_security_cryptoapi_cryptxml_cpp_verify_cpp
    winsdk_samples_security_cryptoapi_cryptxml_readme_txt

    The crucial API calls are:

    CryptXmlOpenToEncode and CryptXmlSign

    Hope this helps.

    // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
    // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
    // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
    // PARTICULAR PURPOSE.
    //
    // Copyright (c) Microsoft Corporation. All rights reserved.
    
    #include "pch.h"
    
    /*****************************************************************************
     HrWriteXmlToFileCallback
    
      The callback for CryptXmlEncode, 
      used to write the XML Signature to file.
    
      CryptXmlEncode will call this function for each XML chunk available
      during encoding.
    
    *****************************************************************************/
    static
    HRESULT 
    CALLBACK
    HrWriteXmlToFileCallback(
    	void                *pvCallbackState, 
    	const BYTE          *pbData, 
        ULONG               cbData
        )
    {
        HRESULT hr = S_FALSE;
        HANDLE  hFile = (HANDLE)pvCallbackState;
        DWORD   dwNumberOfBytesWritten = 0;
    
        if( INVALID_HANDLE_VALUE == hFile )
        {
            hr = E_INVALIDARG;
            goto CleanUp;
        }
        else
        if( !WriteFile(
                        hFile,
                        pbData,
                        cbData,
                        &dwNumberOfBytesWritten,
                        NULL ))
        {
            hr = HRESULT_FROM_WIN32( GetLastError() );
            goto CleanUp;
        }
    
        hr = S_OK;
    
    CleanUp:
    
        return hr;
    }
    
    /*****************************************************************************
     HrGetSignerKeyAndChain
    
      This function retrieves a signing certificate from the local user’s 
      certificate store, builds certificates chain and returns key handle 
      for the signing key.”
    
      NOTE:
      The phCryptProvOrNCryptKey is cached and must not be released by the caller.
    
    *****************************************************************************/
    static
    HRESULT
    HrGetSignerKeyAndChain(
        LPCWSTR                 wszSubject,
        PCCERT_CHAIN_CONTEXT    *ppChainContext,
        HCRYPTPROV_OR_NCRYPT_KEY_HANDLE* phCryptProvOrNCryptKey,    
        DWORD                   *pdwKeySpec
        )
    {
        HRESULT         hr = S_FALSE;
        HCERTSTORE      hStore = NULL;
        PCCERT_CONTEXT  pCert = NULL;
        BOOL            fCallerFreeProvOrNCryptKey = FALSE;
    
        CERT_CHAIN_PARA  ChainPara         = {0};
        ChainPara.cbSize = sizeof(ChainPara);
    
        *ppChainContext = NULL;
        *phCryptProvOrNCryptKey = NULL;
        *pdwKeySpec = 0;
    
        //
        // Open the local user store to search for certificates
        //
    
        hStore = CertOpenStore(
                                CERT_STORE_PROV_SYSTEM_W,
                                X509_ASN_ENCODING,
                                NULL,
                                CERT_SYSTEM_STORE_CURRENT_USER | CERT_STORE_DEFER_CLOSE_UNTIL_LAST_FREE_FLAG,
                                L"MY"
                                );
        
        if( NULL == hStore )
        {
            hr = HRESULT_FROM_WIN32( GetLastError() );
            goto CleanUp;
        }
    
        if( NULL != wszSubject && 0 != *wszSubject )
        {
            //
            // Search by Name
            //
    
            while( NULL != ( pCert = CertFindCertificateInStore(
                                hStore,
                                X509_ASN_ENCODING,
                                0,
                                CERT_FIND_SUBJECT_STR,
                                wszSubject,
                                pCert
                                )))
            {
                if( CryptAcquireCertificatePrivateKey(
                                pCert,
                                CRYPT_ACQUIRE_CACHE_FLAG,
                                NULL,
                                phCryptProvOrNCryptKey,
                                pdwKeySpec,
                                &fCallerFreeProvOrNCryptKey
                                ))
                {
                    break;
                }
            }
        }
        else
        {
            //
            // Get the first available certificate in the store
            //
    
            while( NULL != ( pCert = CertEnumCertificatesInStore(
                                hStore,
                                pCert
                                )))
            {
                if( CryptAcquireCertificatePrivateKey(
                                pCert,
                                CRYPT_ACQUIRE_CACHE_FLAG,
                                NULL,
                                phCryptProvOrNCryptKey,
                                pdwKeySpec,
                                &fCallerFreeProvOrNCryptKey
                                ))
                {
                    break;
                }
            }
        }
    
        if( NULL == pCert )
        {
            hr = CRYPT_XML_E_SIGNER;
            goto CleanUp;
        }
    
        //
        // Build the certificate chain without revocation check.
        //
    
        if( !CertGetCertificateChain(
                                    NULL,                   // use the default chain engine
                                    pCert,                  // pointer to the end certificate
                                    NULL,                   // use the default time
                                    NULL,                   // search no additional stores
                                    &ChainPara,            
                                    0,                      // no revocation check
                                    NULL,                   // currently reserved
                                    ppChainContext ))       // return a pointer to the chain created
        {
            hr = HRESULT_FROM_WIN32( GetLastError() );
            goto CleanUp;
        }
    
    CleanUp:
    
        if( FAILED(hr) )
        {
            *phCryptProvOrNCryptKey = NULL;
            *pdwKeySpec = 0;
        }
    
        if( NULL != pCert )
        {
            CertFreeCertificateContext( pCert );
        }
    
        if( NULL != hStore )
        {
            CertCloseStore( hStore, 0 );
        }
    
        return hr;
    }
    
    /*****************************************************************************
     HrSign
    
        Creates XML signature
    *****************************************************************************/
    HRESULT
    HrSign(
        LPCWSTR         wszFileOut,
        const SIGN_PARA *pPara,
        ULONG           argc,
        LPWSTR          argv[]
        )
    {
        HCRYPTXML               hSig = NULL;
        HCRYPTXML               hRef = NULL;
        HRESULT                 hr = S_FALSE;
        ULONG                   i;
    
        const CRYPT_XML_ALGORITHM_INFO* pAlgInfo = NULL;
    
        PCCERT_CHAIN_CONTEXT    pChainContext = NULL;
        HCRYPTPROV_OR_NCRYPT_KEY_HANDLE hCryptProvOrNCryptKey = NULL; // No release
        DWORD                   dwKeySpec = 0;
        PCCERT_CONTEXT          pCert = NULL;   // No release
        CRYPT_XML_STATUS    Status = {0};
    
        ULONG               cTransform = 0;
        CRYPT_XML_ALGORITHM *pTransform = NULL;
    
        const CRYPT_XML_REFERENCE *pRef = NULL;
        CRYPT_XML_DATA_PROVIDER DataProvider = {0};
    
        CRYPT_XML_PROPERTY  Properties[] = {
            {
                //
                // This property is required for Enveloped or Enveloping signatures
                //
                CRYPT_XML_PROPERTY_SIGNATURE_LOCATION,
                NULL,
                sizeof(LPCWSTR)
            },
        };
        ULONG   cProperties = 0;
    
        CRYPT_XML_BLOB   Encoded = { CRYPT_XML_CHARSET_AUTO, 0, NULL };
    
        CRYPT_XML_ALGORITHM xmlAlg_CanonicalizationMethod = {
                                    sizeof( CRYPT_XML_ALGORITHM ),
                                    (LPWSTR)pPara->wszCanonicalizationMethod,
                                    CRYPT_XML_CHARSET_AUTO,
                                    0,
                                    NULL
                                    };
    
        CRYPT_XML_ALGORITHM xmlAlg_SignatureMethod = {
                                    sizeof( CRYPT_XML_ALGORITHM ),
                                    NULL,
                                    CRYPT_XML_CHARSET_AUTO,
                                    0,
                                    NULL
                                    };
    
        CRYPT_XML_ALGORITHM xmlAlg_DigestMethod = {
                                    sizeof( CRYPT_XML_ALGORITHM ),
                                    NULL,
                                    CRYPT_XML_CHARSET_AUTO,
                                    0,
                                    NULL
                                    };
    
        CRYPT_XML_ALGORITHM xmlAlg_Enveloped = {
                                    sizeof( CRYPT_XML_ALGORITHM ),
                                    wszURI_XMLNS_TRANSFORM_ENVELOPED,
                                    CRYPT_XML_CHARSET_AUTO,
                                    0,
                                    NULL
                                    };
        
        HANDLE  hFile = INVALID_HANDLE_VALUE;
    
        //
        // Create the output file.
        // This handle will be used by HrWriteXmlToFileCallback and must be closed
        // at the exit.
        //
    
        hFile = CreateFile(
                                            wszFileOut,
                                            GENERIC_WRITE,
                                            0,
                                            NULL,
                                            CREATE_ALWAYS,
                                            FILE_ATTRIBUTE_NORMAL,
                                            NULL
                                            );
    
        if( INVALID_HANDLE_VALUE == hFile )
        {
            hr = HRESULT_FROM_WIN32( GetLastError() );
            wprintf( L"ERROR: Unable to create file: '%s'.\r\n", wszFileOut );
    
            goto CleanUp;
        }
    
        //
        // Find the signing certificate
        //
    
        hr = HrGetSignerKeyAndChain(
                                            pPara->wszSubject,
                                            &pChainContext,
                                            &hCryptProvOrNCryptKey,    
                                            &dwKeySpec
                                            );
        if( FAILED(hr) )
        {
            wprintf( L"ERROR: 0x%08x - Unable to get signing certificate.\r\n", hr );
            goto CleanUp;
        }
    
        //
        // Determine the Digest Method
        //
    
        {
            pAlgInfo = CryptXmlFindAlgorithmInfo(
                                            CRYPT_XML_ALGORITHM_INFO_FIND_BY_CNG_ALGID,
                                            pPara->wszHashAlgName,
                                            CRYPT_XML_GROUP_ID_HASH,
                                            0
                                            );
            if( NULL == pAlgInfo )
            {
                hr = CRYPT_XML_E_ALGORITHM;
                goto CleanUp;
            }
    
            xmlAlg_DigestMethod.wszAlgorithm = pAlgInfo->wszAlgorithmURI;
        }
    
        //
        // Determine the Signature Method
        //
        
        pCert = pChainContext->rgpChain[0]->rgpElement[0]->pCertContext;
        {
            PCCRYPT_OID_INFO pOIDInfo = NULL;
            LPCWSTR pwszCNGAlgid[2] = {0};
    
            //
            // First, find the Public Key algorithm name
            //
    
            pOIDInfo = CryptFindOIDInfo(
                                                CRYPT_OID_INFO_OID_KEY,
                                                pCert->pCertInfo->SubjectPublicKeyInfo.Algorithm.pszObjId,
                                                CRYPT_PUBKEY_ALG_OID_GROUP_ID
                                                );
    
            if( NULL == pOIDInfo || NULL == pOIDInfo->pwszCNGAlgid )
            {
                hr = CRYPT_XML_E_ALGORITHM;
                goto CleanUp;
            }
    
            //
            // Second, find XML DigSig URI that corresponds to 
            // combined HASH and  Public Key algorithm names.
            //
    
            pwszCNGAlgid[0] = pPara->wszHashAlgName;
            pwszCNGAlgid[1] = pOIDInfo->pwszCNGAlgid;
    
            pAlgInfo = CryptXmlFindAlgorithmInfo(
                                                CRYPT_XML_ALGORITHM_INFO_FIND_BY_CNG_SIGN_ALGID,
                                                pwszCNGAlgid,
                                                CRYPT_XML_GROUP_ID_SIGN,
                                                0
                                                );
            if( NULL == pAlgInfo )
            {
                hr = CRYPT_XML_E_ALGORITHM;
                goto CleanUp;
            }
            xmlAlg_SignatureMethod.wszAlgorithm = pAlgInfo->wszAlgorithmURI;
        }
    
        //
        // Load input XML file. This must be provided for Enveloped or Enveloping signature
        //
    
        if( NULL != pPara->wszFileIn )
        {
            hr = HrLoadFile(
                                                pPara->wszFileIn,
                                                &Encoded.pbData,
                                                &Encoded.cbData
                                                );
            if( FAILED(hr) )
            {
                goto CleanUp;
            }
        }
    
        //
        // Create the document context
        //
    
        if( NULL != pPara->wszSignatureLocation && 0 != *pPara->wszSignatureLocation )
        {
            // The <Signature> element will be added into this location
            Properties[0].pvValue = &pPara->wszSignatureLocation;
            cProperties++;
        }
    
        hr = CryptXmlOpenToEncode(
                                                NULL,                   // No custom transforms
                                                0,
                                                pPara->wszSignatureId,
                                                Properties,
                                                cProperties,
                                                (Encoded.cbData > 0 ) ? &Encoded : NULL,
                                                &hSig
                                                );
        if( FAILED(hr) )
        {
            goto CleanUp;
        }
    
        //
        // Create references
        //
    
        for( i=0; i<argc; i++ )
        {
            DWORD       dwReferenceFlags = 0;
            LPCWSTR     wsRefId = NULL;
            LPCWSTR     wsUri = NULL;
    
            if( L'#' != *argv[i] )
            {
                wprintf( L"ERROR: Invalid reference: %s.\r\n", argv[i] );
                hr = E_INVALIDARG;
                goto CleanUp;
            }
    
            wsUri = argv[i];
            
            if( 0 == wsUri[1] && 1==argc )
            {
                //
                // Special case for Enveloped
                // The URI must be ""
                //
                
                wsUri = L"";
                cTransform = 1;
                pTransform = &xmlAlg_Enveloped;
            }
            else
            if( i+1 < argc )
            {
                //
                // Check if external file is specified
                //
    
                if( L'#' != *argv[i+1] )
                {
                    i++;
                    wsRefId = wsUri+1;
                    wsUri = argv[i];
                }
    
                cTransform = 0;
                pTransform = NULL;
            }
    
            hr = CryptXmlCreateReference(
                                            hSig,               // Parent
                                            dwReferenceFlags,   // Flags
                                            wsRefId,
                                            wsUri,
                                            NULL,
                                            &xmlAlg_DigestMethod,
                                            cTransform,   	
                                            pTransform,
                                            &hRef
                                            );
            if( FAILED(hr) )
            {
                goto CleanUp;
            }
    
            hr = CryptXmlGetStatus( hRef, &Status );
            if( FAILED(hr) )
            {
                goto CleanUp;
            }
    
            if( 0 != ( Status.dwErrorStatus & CRYPT_XML_STATUS_ERROR_NOT_RESOLVED ))
            {
                //
                // Resolve the external references only.
                // The internal references will be resolved by CryptXml during CryptXmlSign
                //
    
                if( 0 == ( Status.dwInfoStatus & CRYPT_XML_STATUS_INTERNAL_REFERENCE ))
                {
                    hr = CryptXmlGetReference(  hRef, &pRef );
                    if( FAILED(hr) )
                    {
                        goto CleanUp;
                    }
    
                    hr = HrSampleResolveExternalXmlReference(
                                            pRef->wszUri,
                                            &DataProvider
                                            );
                    if( FAILED(hr) )
                    {
                        goto CleanUp;
                    }
    
                    if( NULL == DataProvider.pfnRead )
                    {
                        //
                        // Unable to open file for reading
                        //
    
                        hr = CRYPT_XML_E_UNRESOLVED_REFERENCE;
                        goto CleanUp;
                    }
    
                    //
                    // Digest the reference
                    //
    
                    hr = CryptXmlDigestReference(
                                                    hRef,
                                                    0,
                                                    &DataProvider
                                                    );
                    if( FAILED(hr) )
                    {
                        goto CleanUp;
                    }
    
                    //
                    // Provider must be released by the callee, which is CryptXmlDigestReference
                    //
                    ZeroMemory( &DataProvider, sizeof DataProvider );
                }
            }
        }
    
        {
            //
            // Sign 
            //
            DWORD   dwSignFlags = 0;
            CRYPT_XML_KEYINFO_PARAM KeyInfoParam = {0};
            CERT_BLOB               rgCertificate[8] = {0};
            DWORD c;
    
            //
            // Include the chain up to the Root
            //
            for( c=0; c<pChainContext->rgpChain[0]->cElement-1 && c<ARRAYSIZE(rgCertificate); c++ )
            {
                rgCertificate[c].pbData = pChainContext->rgpChain[0]->rgpElement[c]->pCertContext->pbCertEncoded;
                rgCertificate[c].cbData = pChainContext->rgpChain[0]->rgpElement[c]->pCertContext->cbCertEncoded;
            }
    
            KeyInfoParam.cCertificate = c;
            KeyInfoParam.rgCertificate = rgCertificate;
    
            KeyInfoParam.wszId = pPara->wszKeyInfoId;
    
            if( pPara->fKV )
            {
                dwSignFlags |= CRYPT_XML_SIGN_ADD_KEYVALUE;
            }
    
            hr = CryptXmlSign(
                                            hSig,
                                            hCryptProvOrNCryptKey,
                                            dwKeySpec,
                                            dwSignFlags,
                                            CRYPT_XML_KEYINFO_SPEC_PARAM,
                                            &KeyInfoParam,
                                            &xmlAlg_SignatureMethod,
                                            &xmlAlg_CanonicalizationMethod
                                            );
            if( FAILED(hr) )
            {
                wprintf( L"FAIL: 0x%08x CryptXmlSign\r\n", hr );
                goto CleanUp;
            }
            wprintf( L"Successfully signed and created signature.\r\n" );
        }
    
        {
            //
            // Encode the Signature to file
            //
    
            static BOOL fTRUE = TRUE;
            CRYPT_XML_PROPERTY rgEncodeProperty[] = {
                {
                    //
                    // This property is used to produce the declaration at the top of XML.
                    //   <?xml version="1.0" encoding="utf-8" standalone="yes"?>
                    //
                    CRYPT_XML_PROPERTY_DOC_DECLARATION,
                    &fTRUE,
                    sizeof(fTRUE)
                },
            };
    
            hr = CryptXmlEncode(
                                            hSig,
                                            CRYPT_XML_CHARSET_UTF8,
                                            rgEncodeProperty,
                                            ARRAYSIZE(rgEncodeProperty),
                                            hFile,
                                            HrWriteXmlToFileCallback
                                            );
            if( FAILED(hr) )
            {
                goto CleanUp;
            }
    
            wprintf( L"Successfully encoded signature to '%s'.\r\n", wszFileOut );
        }
    CleanUp:
    
        if( INVALID_HANDLE_VALUE != hFile )
        {
            CloseHandle( hFile );
        }
    
        if( NULL != Encoded.pbData )
        {
            LocalFree( Encoded.pbData );
        }
    
        if( NULL != pChainContext )
        {
            CertFreeCertificateChain(pChainContext);
        }
    
        if( NULL != hSig )
        {
            CryptXmlClose( hSig );
        }
    
        return hr;
    }
    
    // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
    // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
    // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
    // PARTICULAR PURPOSE.
    //
    // Copyright (c) Microsoft Corporation. All rights reserved.
    
    #include "pch.h"
    
    /*****************************************************************************
      HrLoadFile
    
        Load file into allocated (*ppbData). 
        The caller must free the memory by LocalFree().
    *****************************************************************************/
    HRESULT
    HrLoadFile(
        LPCWSTR     wszFileName,
        BYTE        **ppbData,
        DWORD       *pcbData
        )
    {
        HANDLE      hFile = INVALID_HANDLE_VALUE;
        DWORD       cbRead = 0;
        HRESULT     hr = S_OK;
    
        *ppbData = NULL;
        *pcbData = 0;
    
        hFile = CreateFileW( 
    						wszFileName, 
                            GENERIC_READ,
                            0,
                            NULL, 
                            OPEN_EXISTING, 
                            0, 
                            NULL );
    
        if( INVALID_HANDLE_VALUE == hFile )
        {
            hr = HRESULT_FROM_WIN32( GetLastError() );
            
            goto CleanUp;
        }
    
        *pcbData = GetFileSize( hFile, NULL );
        if( *pcbData == 0 ) 
        {
            hr = S_FALSE;
            goto CleanUp;
        }
    
        *ppbData = (PBYTE)LocalAlloc( LPTR, *pcbData );
        if( NULL == *ppbData )
        {
            hr = HRESULT_FROM_WIN32( ERROR_OUTOFMEMORY );
            
            goto CleanUp;
        }
    
        if( !ReadFile( hFile, *ppbData, *pcbData, &cbRead, NULL ))
        {
            hr = HRESULT_FROM_WIN32( GetLastError() );
            
            goto CleanUp;
        }
    
    CleanUp:
    
        if (hFile != INVALID_HANDLE_VALUE )
        {
            CloseHandle(hFile);
        }
    
        if( FAILED(hr) )
        {
            if( NULL != *ppbData )
            {
                LocalFree( *ppbData );
            }
    
            *ppbData = NULL;
            *pcbData = 0;
        }
    
        return hr;
    }
    
    #define WSZ_CMD_VERIFY  L"VERIFY"
    #define WSZ_CMD_SIGN    L"SIGN"
    
    /*****************************************************************************
     Usage
    
    *****************************************************************************/
    void Usage()
    {
        wprintf( L"CryptXml.exe [Options] {COMMAND}\r\n" );
        wprintf( L"    Options:\r\n" );
        wprintf( L"     -h {CNGAlgName}     - SIGN: Hash name, default - SHA1\r\n" );
        wprintf( L"     -cm {URI}           - SIGN: Canonicalization method, default - Exclusive C14N.\r\n" );
        wprintf( L"     -kid {ID}           - SIGN: <KeyInfo> Id attribute.\r\n" );
        wprintf( L"     -kv                 - SIGN: Create <KeyValue> from the key handle.\r\n" );
        wprintf( L"     -n {SubjectName}    - SIGN: Subject Name of certificate in MY store used to sign.\r\n" );
        wprintf( L"     -sid {ID}           - SIGN: <Signature> Id attribute.\r\n" );
        wprintf( L"\r\n    COMMAND:\r\n" );
        wprintf( L"        %s {FileIn}\r\n", WSZ_CMD_VERIFY );
        wprintf( L"          | Parse and verify signature.\r\n" );
        wprintf( L"        %s {FileOut} [FileIn XPath] {#RefId [file]} .... {#RefId [file]} \r\n", WSZ_CMD_SIGN );
        wprintf( L"          | Create XML Signature.\r\n" );
        wprintf( L"          | Both FileIn and XPath must be specified for Enveloped or Enveloping signature.\r\n" );
        wprintf( L"          | If [file] is not specified, then #RefId is internal reference in FileIn.\r\n" );
    }
    
    /*****************************************************************************
     wmain
    
    *****************************************************************************/
    DWORD
    __cdecl
    wmain(
        int     argc,
        LPWSTR  argv[]
        )
    {
        HRESULT         hr = S_FALSE;
        int             i=0;
        LPCWSTR         wszFile = NULL;
    
        SIGN_PARA       Para = {0};
    
        Para.wszCanonicalizationMethod = wszURI_CANONICALIZATION_EXSLUSIVE_C14N;
        Para.wszHashAlgName = BCRYPT_SHA1_ALGORITHM;
    
        //
        // Options
        //
    
        for( i=1; i<argc; i++ )
        {
            if ( 0 == lstrcmpW (argv[i], L"/?") ||
                 0 == lstrcmpW (argv[i], L"-?") ) 
            {
                Usage();
                goto CleanUp;
            }
    
            if( *argv[i] != L'-' )
                break;
    
            if ( 0 == lstrcmpW (argv[i], L"-kv") )
            {
                Para.fKV = TRUE;
            }
            else
            if ( 0 == lstrcmpW (argv[i], L"-cm") )
            {
                if( i+1 >= argc )
                {
                    goto InvalidCommandLine;
                }
    
                Para.wszCanonicalizationMethod = argv[++i];
            }
            else
            if ( 0 == lstrcmpW (argv[i], L"-h") )
            {
                if( i+1 >= argc )
                {
                    goto InvalidCommandLine;
                }
    
                Para.wszHashAlgName = argv[++i];
            }
            else
            if ( 0 == lstrcmpW (argv[i], L"-n") )
            {
                if( i+1 >= argc )
                {
                    goto InvalidCommandLine;
                }
    
                Para.wszSubject = argv[++i];
            }
            else
            if ( 0 == lstrcmpW (argv[i], L"-kid") )
            {
                if( i+1 >= argc )
                {
                    goto InvalidCommandLine;
                }
    
                Para.wszKeyInfoId = argv[++i];
            }
            else
            if ( 0 == lstrcmpW (argv[i], L"-sid") )
            {
                if( i+1 >= argc )
                {
                    goto InvalidCommandLine;
                }
    
                Para.wszSignatureId = argv[++i];
            }
        }
    
        //
        // Commands
        //
    
        if( i >= argc )
        {
            goto InvalidCommandLine;
        }
    
        if( 0 == lstrcmpW( argv[i], WSZ_CMD_VERIFY ))
        {
            i++;
            if( i >= argc )
            {
                goto InvalidCommandLine;
            }
    
            wszFile = argv[i];
    
            hr = HrVerify( 
                                            wszFile 
                                            );
    
            if( FAILED(hr) )
            {
                goto CleanUp;
            }
        }
        else
        if( 0 == lstrcmpW( argv[i], WSZ_CMD_SIGN ))
        {
            i++;
            if( i+1 >= argc )
            {
                goto InvalidCommandLine;
            }
    
            wszFile = argv[i++];
    
            if( L'#' != *argv[i] )
            {
                if( i+2 >= argc )
                {
                    goto InvalidCommandLine;
                }
    
                Para.wszFileIn  = argv[i++];
                Para.wszSignatureLocation = argv[i++];
            }
            
            if( i >= argc )
            {
                goto InvalidCommandLine;
            }
    
            // The rest of the command line must be {#Reference| [File] }
    
            hr = HrSign( 
                                            wszFile, 
                                            &Para, 
                                            (ULONG)(argc-i),
                                            &argv[i]
                                            );
            if( FAILED(hr) )
            {
                goto CleanUp;
            }
        }
        else
        {
            goto InvalidCommandLine;
        }
    
        //
        // End
        //
    
        hr = S_OK;
        goto CleanUp;
    
    InvalidCommandLine:
    
        wprintf( L"ERROR: Invalid command line.\r\n" );
    
    CleanUp:
    
        if( FAILED(hr) )
        {
            wprintf( L"ERROR: 0x%08x\r\n", hr );
        }
    
        return 0;
    }

    // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
    // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
    // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
    // PARTICULAR PURPOSE.
    //
    // Copyright (c) Microsoft Corporation. All rights reserved.
    
    //
    // This file contains sample of CRYPT_XML_DATA_PROVIDER implementation
    // to resolve extrenal references
    //
    
    #include "pch.h"
    
    /****************************************************************************
     SAMPLE_FILE_DATA_PROVIDER_CLOSE
    
     This is a callback function for CRYPT_XML_DATA_PROVIDER,
     used to release the resources created by this data provider.
    
    ****************************************************************************/
    static
    HRESULT
    CALLBACK 
    SAMPLE_FILE_DATA_PROVIDER_CLOSE(
        void                *pvCallbackState
        )
    {
        HRESULT hr = NO_ERROR;
        HANDLE hFile = (HANDLE)pvCallbackState;
    
        if( INVALID_HANDLE_VALUE != hFile )
        {
            if( !CloseHandle( hFile ) )
            {
                hr = HRESULT_FROM_WIN32( GetLastError() );
            }
        }
    
        return hr;
    }
    
    /****************************************************************************
     SAMPLE_FILE_DATA_PROVIDER_READ
    
     This is a callback function for CRYPT_XML_DATA_PROVIDER,
     used to read data from external reference (FILE).
    
    ****************************************************************************/
    static
    HRESULT
    CALLBACK 
    SAMPLE_FILE_DATA_PROVIDER_READ(
        void                *pvCallbackState,
    	BYTE                *pbData,
        ULONG               cbData,
    	ULONG               *pcbRead
        )
    {
        HRESULT hr = NO_ERROR;
        HANDLE hFile = (HANDLE)pvCallbackState;
    
        if( INVALID_HANDLE_VALUE == hFile )
        {
            hr = E_INVALIDARG;
        }
        else
        if( !ReadFile( 
                                        hFile,
                                        pbData,
                                        cbData,
                                        pcbRead,
                                        NULL 
                                        ))
        {
            hr = HRESULT_FROM_WIN32( GetLastError() );
        }
    
        return hr;
    }
    
    
    /****************************************************************************
     HrSampleResolveExternalXmlReference
    
     This function creates CRYPT_XML_DATA_PROVIDER for the provided URI.
     For the sample purposes, it supports local files only.
    
     For more information, see documentation on CryptXmlDigestReference.
    ****************************************************************************/
    HRESULT 
    WINAPI 
    HrSampleResolveExternalXmlReference(
    	LPCWSTR                 wszUri,
        CRYPT_XML_DATA_PROVIDER *pProviderOut
        )
    {
        HRESULT                 hr = S_FALSE;
        HANDLE hFile = INVALID_HANDLE_VALUE;
    
        static  WCHAR _wsHttp[] = L"http://";
        const ULONG cwHttp = 7;
        static  WCHAR _wsHttps[] = L"https://";
        const ULONG cwHttps = 8;
    
        static  WCHAR _wsFile[] = L"file://";
        const ULONG cwFile = 7;
    
        ULONG cw = 0;
    
        ZeroMemory( pProviderOut, sizeof( CRYPT_XML_DATA_PROVIDER ));
    
        if( NULL == wszUri || 0 == *wszUri )
        {
            goto CleanUp;
        }
        
        LPWSTR wsUri = (LPWSTR)wszUri;
        cw = lstrlenW( wsUri );
    
        //
        // Try http
        //
    
        if( ( cw > cwHttp && 
                CSTR_EQUAL == CompareStringW(
                                            LOCALE_NEUTRAL,
                                            NORM_IGNORECASE,
                                            wsUri,
                                            cwHttp,
                                            _wsHttp,
                                            cwHttp
                                            )) ||
            ( cw > cwHttps && 
                CSTR_EQUAL == CompareStringW(
                                            LOCALE_NEUTRAL,
                                            NORM_IGNORECASE,
                                            wsUri,
                                            cwHttps,
                                            _wsHttps,
                                            cwHttps
                                            )))
        {
            //
            // TODO: Retrive from HTTP
            //      Add here your implementation to retrieve URI from HTTP
            //
    
            hr = E_NOTIMPL;
            goto CleanUp;
        }
        else
        if( cw > cwFile && 
                CSTR_EQUAL == CompareStringW(
                                            LOCALE_NEUTRAL,
                                            NORM_IGNORECASE,
                                            wsUri,
                                            cwFile,
                                            _wsFile,
                                            cwFile
                                            ))
        {
            wsUri += cwFile;
        }
        else
        {
            //
            // Not supported schema
            //
            // hr = E_INVALIDARG;
            // goto CleanUp;
    
            // SAMPLE: here we accept URI without the schema, just a file name
        }
    
        //
        // Open the file
        //
    
        hFile = CreateFileW(
                                            wsUri,
                                            GENERIC_READ,
                                            FILE_SHARE_READ,
                                            NULL,
                                            OPEN_EXISTING,
                                            FILE_ATTRIBUTE_NORMAL,
                                            NULL
                                            );
        if( INVALID_HANDLE_VALUE != hFile )
        {
            pProviderOut->pvCallbackState = hFile;
            pProviderOut->cbBufferSize = 0;
            pProviderOut->pfnRead = SAMPLE_FILE_DATA_PROVIDER_READ;
            pProviderOut->pfnClose = SAMPLE_FILE_DATA_PROVIDER_CLOSE;
    
            hr = NO_ERROR;
            goto CleanUp;
        }
    
    CleanUp:
    
        return hr;
    }


    Monday, February 15, 2016 2:57 PM