locked
Memory leak after call to CryptXmlOpenToDecode even after calling CryptXmlClose on the handle RRS feed

  • Question

  • I have been trying to find documentation on how to properly cleanup structures used to verify an XML signature.  The only reference to how to cleanup memory in the documentation is that a call to CryptXmlClose is required on the handle.  How are the other allocated structures returned (i.e. pDoc, pSig and pRef)?

    Here is a code snippet that is being flagged as a memory leak during memory analysis because of the call to CryptXmlOpenToDecode even though the handle is closed before exiting the function.

    Any help would be greatly appreciated as I can find NO documentation and the sample code does not even include the call to CryptXmlClose.

    {
        HRESULT hr = S_FALSE;
        HCRYPTXML hDoc = NULL;
        const CRYPT_XML_DOC_CTXT  *pDoc = NULL;
        const CRYPT_XML_SIGNATURE *pSig = NULL;
        const CRYPT_XML_REFERENCE *pRef = NULL;
        CRYPT_XML_STATUS Status = {0};
        CRYPT_XML_BLOB Encoded = { CRYPT_XML_CHARSET_AUTO, 0, NULL };

        BSTR body = NULL;
        if (FAILED(hr = pXMLDoc->get_xml(&body)))
           goto CleanUp;

        Encoded.pbData = (PBYTE)body;
        Encoded.cbData = (DWORD)wcslen(body)*2;

        if (FAILED(hr = CryptXmlOpenToDecode(NULL, 0, NULL, 0, &Encoded, &hDoc)))
           goto CleanUp;

        if (FAILED(hr = CryptXmlGetDocContext(hDoc, &pDoc)))
            goto CleanUp;

        if (pDoc->cSignature != 1)
            goto CleanUp;


        if (FAILED(hr = CryptXmlVerifySignature(pDoc->rgpSignature[0]->hSignature, m_hASValKey, 0)))
            goto CleanUp;


        if (FAILED(hr = CryptXmlGetSignature(pDoc->rgpSignature[0]->hSignature, &pSig)))
            goto CleanUp;

        if (pSig->SignedInfo.cReference == 1)
        { // verify the reference
            if (FAILED(hr = CryptXmlGetReference(pSig->SignedInfo.rgpReference[0]->hReference, &pRef)))
                goto CleanUp;

            if (FAILED(hr = CryptXmlGetStatus(pSig->SignedInfo.rgpReference[0]->hReference, &Status)))
                goto CleanUp;

            if (Status.dwErrorStatus & CRYPT_XML_STATUS_ERROR_NOT_RESOLVED)
            {
                hr = CRYPT_XML_E_UNRESOLVED_REFERENCE;
                goto CleanUp;
            }

            if (FAILED(hr = CryptXmlGetStatus(pDoc->rgpSignature[0]->hSignature, &Status)))
                goto CleanUp;

            if (Status.dwErrorStatus & CRYPT_XML_STATUS_ERROR_DIGEST_INVALID)
            {
                hr = CRYPT_XML_E_INVALID_DIGEST;
                goto CleanUp;
            }

            if (Status.dwErrorStatus & CRYPT_XML_STATUS_ERROR_NOT_RESOLVED)
            {
                hr = CRYPT_XML_E_UNRESOLVED_REFERENCE;
                goto CleanUp;
            }
        }

    CleanUp:
        if (body)
           SysFreeString(body);
        if (hDoc)
           CryptXmlClose(hDoc);
         return (hr == S_OK) ? TRUE : FALSE;
    }

    Friday, December 12, 2014 7:08 PM

Answers

  • Just wanted to make sure:-)

    I'm pretty sure that you need to call CryptMemFree for anything that it allocates for you (e.g. pSig, pDoc, pRef).  It states in the documentation for CryptMemAlloc that CryptMemAlloc is used by the cryptography library for buffers that are created by crypt32 and that CryptMemFree needs to be used to free buffers created by CryptMemAlloc.  I think that the statement also applies to CryptXML; if it doesn't work for you, let me know and I can look up what allocates them and what you need to free them.


    WinSDK Support Team Blog: http://blogs.msdn.com/b/winsdk/

    Friday, December 12, 2014 7:33 PM

All replies

  • Are you saying that you're seeing a memory leak in your program or in the service?

    WinSDK Support Team Blog: http://blogs.msdn.com/b/winsdk/

    Friday, December 12, 2014 7:13 PM
  • The memory leak is in my application (Windows service) in the code sample.  I am using Windows DebugDiag version 1.2 to analyze the memory leak and it shows the following stack trace numerous times:

    Function   Destination
    LeakTrack+13277   
    ntdll!RtlpInitializeUCRIndex+36   
    ntdll!RtlCreateHeap+8f7   
    KERNELBASE!HeapCreate+54   
    cryptxml!I_CryptXmlHandleAllocDocCtxt+57   
    cryptxml!CryptXmlOpenToDecode+120   
    USSL_Logon!CXmlCrypto::VerifyAuthServerXML+1ce   
    USSL_Logon!CAuthServerIF::ProcessXmlSession+179   
    USSL_Logon!CAuthServerIF::ProcessResponseData+634   
    USSL_Logon!CAuthServerIF::Process_Response+3a   
    USSL_Logon!CAuthServerIF::AuthServer_ThreadProc+81d   
    USSL_Logon!AuthServer_StartThread+ef   
    msvcr100!_callthreadstart+17   
    msvcr100!_threadstart+75   
    kernel32!BaseThreadInitThunk+d   
    ntdll!RtlUserThreadStart+1d

    Friday, December 12, 2014 7:26 PM
  • So what I want to know is what else do I need to do other than call CryptXmlClose on the document handle since that does not appear to be enough?  How do I free the other memory allocated in this code sample such as pSig, pRef and pDoc?

    Friday, December 12, 2014 7:28 PM
  • Just wanted to make sure:-)

    I'm pretty sure that you need to call CryptMemFree for anything that it allocates for you (e.g. pSig, pDoc, pRef).  It states in the documentation for CryptMemAlloc that CryptMemAlloc is used by the cryptography library for buffers that are created by crypt32 and that CryptMemFree needs to be used to free buffers created by CryptMemAlloc.  I think that the statement also applies to CryptXML; if it doesn't work for you, let me know and I can look up what allocates them and what you need to free them.


    WinSDK Support Team Blog: http://blogs.msdn.com/b/winsdk/

    Friday, December 12, 2014 7:33 PM
  •  I will give that a try.  Thank you!
    Friday, December 12, 2014 8:28 PM
  • So the recommended fix worked for the XML signature validation code, but I appear to also have a memory leak on the XML signing side of this code.  When I run DebugDiag I see that there is a 100% probability of a memory leak in CryptXmlOpenToEncode.

    I am returning the handle to the signature as documented but I cannot figure out how to return the handle to the reference.  I tried both CryptXmlClose and CryptMemFree both caused faults.

    The code currently looks like this:

    {
        HCRYPTXML hSig = NULL;
        HCRYPTXML hRef = NULL;
        HRESULT hr = S_OK;
        CRYPT_XML_STATUS Status = {0};
        PXML_SIGN_CONTEXT pContext = NULL;

        CRYPT_XML_PROPERTY Properties[] = {
                                   {  CRYPT_XML_PROPERTY_SIGNATURE_LOCATION,
                                       NULL,
                                       sizeof(LPCWSTR)
                                    },
        };

        CRYPT_XML_ALGORITHM xmlAlg_CanonicalizationMethod = {
                                    sizeof( CRYPT_XML_ALGORITHM ),
                                    (LPWSTR)wszURI_CANONICALIZATION_C14N,
                                    CRYPT_XML_CHARSET_AUTO,
                                    0,
                                    NULL
                                    };

        CRYPT_XML_ALGORITHM xmlAlg_SignatureMethod = {
                                    sizeof( CRYPT_XML_ALGORITHM ),
                                    (LPWSTR)wszURI_XMLNS_DIGSIG_RSA_SHA1,
                                    CRYPT_XML_CHARSET_AUTO,
                                    0,
                                    NULL
                                    };

        CRYPT_XML_ALGORITHM xmlAlg_DigestMethod = {
                                    sizeof( CRYPT_XML_ALGORITHM ),
                                    (LPWSTR)wszURI_XMLNS_DIGSIG_SHA1,
                                    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
                                    };
     
        CRYPT_XML_BLOB Encoded = { CRYPT_XML_CHARSET_AUTO, 0, NULL };

        // allocate the context structure
        pContext = (PXML_SIGN_CONTEXT)HEAPALLOC(sizeof(XML_SIGN_CONTEXT));
        if (NULL == pContext)
          goto CleanUp;
        ZeroMemory(pContext, sizeof(XML_SIGN_CONTEXT));

        *ppContext = pContext;

        BSTR body = NULL;
        if (FAILED(hr = pXMLDoc->get_xml(&body)))
           goto CleanUp;

        Encoded.pbData = (PBYTE)body;
        Encoded.cbData = (DWORD)wcslen(body)*2;

        PWCHAR pSession = L"/session";
        Properties[0].pvValue = &pSession;
        if ((FAILED(hr = CryptXmlOpenToEncode(NULL, 0, L"", Properties, 1, (Encoded.cbData > 0 ) ? &Encoded : NULL, &hSig))))
            goto CleanUp;

        if ((FAILED(hr = CryptXmlCreateReference(hSig, 0, NULL, L"", NULL, &xmlAlg_DigestMethod, 1, &xmlAlg_Enveloped, &hRef))))
            goto CleanUp;

        if ((FAILED(hr = CryptXmlGetStatus(hRef, &Status))))
            goto CleanUp;

        if ((FAILED(hr = CryptXmlSign(hSig, m_hValKey, CERT_NCRYPT_KEY_SPEC, 

                                                     0, CRYPT_XML_KEYINFO_SPEC_NONE,
                                                    NULL, &xmlAlg_SignatureMethod, &xmlAlg_CanonicalizationMethod))))
            goto CleanUp;

        if ((FAILED(hr = CryptXmlEncode(hSig, CRYPT_XML_CHARSET_UTF16LE, NULL, 0, pContext, SignXmlCallback))))
            goto CleanUp;
       
    CleanUp:
        if (NULL != hSig) CryptXmlClose(hSig);
     //   if (NULL != hRef) CryptXmlClose(hRef); // causes a fault with this line and a memory leak without it
        if (body) SysFreeString(body);
        return (hr == S_OK) ? TRUE : FALSE;
    }

    Wednesday, February 4, 2015 7:53 PM
  • From the comments in your code, it looks like you're seeing the crash cleaning up the data from CryptXmlCreateReference or a memory leak if you don't instead of from CryptXmlOpenToEncode.  If that's not the case, could you update the code to reflect what you're seeing?  Based on what is in the code, I don't understand the need to call CryptXmlCreateReference since you don't appear to be using it anywhere and are just cleaning it up.  Why not use your local hSig variable when calling CryptXmlGetStatus instead? Assuming you do need to use it for code external for this, you need to call CryptXmlClose on hRef before calling it on hSig since hSig is the parent of hRef.


    WinSDK Support Team Blog: http://blogs.msdn.com/b/winsdk/

    Thursday, February 5, 2015 2:53 PM
  • Ah that explains it!  I tried to close the hRef after closing the hSig. 

    You are correct that I am only using the hRef to get the status.  If I can use hSig instead then I will give that a try.  Thanks for the quick response!

    Thursday, February 5, 2015 3:00 PM