/*$Header:  /Utilities/CompressionManager/OIPCompressionManager/source/XMLSignatureVerifier.cpp v30934  04/24/2013 12:22:40 PM BrendKM $*/
////////////////////////////////////////////////////////
//
// Copyright 2011 Caterpillar Inc.  All Rights Reserved.
// This work contains Caterpillar's proprietary 
// information which may constitute a trade secret
// secret and/or be confidential.  Copyright notice 
// is precautionary only and does not imply publication.
//
//     Class: CXMLSignatureVerifier
//
// File Name: XMLSignatureVerifier.cpp
//
//  Abstract: Verifies the integrity of an XML signature.
//
////////////////////////////////////////////////////////

#include "stdafx.h"
#include "XMLSignatureVerifier.h"

//These defines must go before the libXML, xslt, and xmlsec includes.
#define XMLSEC_CRYPTO_MSCRYPTO
#define LIBXML_STATIC
#define LIBXSLT_STATIC
#define LIBEXSLT_STATIC
#define XMLSEC_STATIC

#include <libxml/tree.h>
#include <libxml/xmlmemory.h>
#include <libxml/parser.h>

#include <libxslt/xslt.h>
#include <libxslt/security.h>

#include <xmlsec/xmlsec.h>
#include <xmlsec/xmltree.h>
#include <xmlsec/xmldsig.h>
#include <xmlsec/crypto.h>
#include "xmlsec/base64.h"
#include "xmlsec/errors.h"
#include "xmlsec/io.h"

CXMLSignatureVerifier* g_pCXMLSignatureVerifier(nullptr);

const int XML_SEC_CURRENT_VERSION = 1;
const int CAT_CERT_DEV_SIZE = 894;
const int CAT_CERT_PROD_SIZE = 826;
const int SIS_CERT_PROD_SIZE = 826;
const int SIS_CERT_PROD_DISPLAY_SIZE = 894;

//Cat development certificate authority
static const BYTE CAT_CERT_DEV[CAT_CERT_DEV_SIZE] = { 0
};

//cat prod certificate authority
static const BYTE CAT_CERT_PROD[CAT_CERT_PROD_SIZE] = { 0
};

//SIS prod certificate authority.
static const BYTE SIS_CERT_PROD[SIS_CERT_PROD_SIZE] = { 0
};

static const BYTE CAT_CERT_PROD_DISPLAY[SIS_CERT_PROD_DISPLAY_SIZE] = { 0
};

void OutputStringInDebugMode(const CATLString& StringToOutput)
{
#ifdef _DEBUG
	OutputDebugString(StringToOutput);
	OutputDebugString(_T("\r\n"));
#endif
}

struct CXMLSignatureVerifier::SXMLHiddenVariables
{
	xsltSecurityPrefsPtr m_xsltSecPrefs;
};

class CXMLSecCallbacks
{
public:
	static XMLPUBFUN int XMLCALL CustomxmlFileMatch(const char *filename)
	{
		int RetVal(0);	//0 for fail, 1 for success.

		_ASSERTE(g_pCXMLSignatureVerifier && _T("CustomxmlFileMatch - g_pCXMLSignatureVerifier cannot be null when verifying a file package."));

		if(g_pCXMLSignatureVerifier)
		{
			if(g_pCXMLSignatureVerifier->m_spCallback->XMLFileMatch(CATLString(CA2T(filename))))
			{
				RetVal = 1;
			}
		}

		return RetVal;
	}

	static XMLPUBFUN void * XMLCALL CustomxmlFileOpen(const char *filename)
	{
		HANDLE RetVal(nullptr);
		HANDLE pFileHandle;

		_ASSERTE(g_pCXMLSignatureVerifier && _T("CustomxmlFileOpen - g_pCXMLSignatureVerifier cannot be null when verifying a file package."));

		if(g_pCXMLSignatureVerifier)
		{
			if(g_pCXMLSignatureVerifier->m_spCallback->XMLFileOpen(CATLString(CA2T(filename)), pFileHandle))
			{
				RetVal = pFileHandle;
			}
		}

		return RetVal;
	}

	static XMLPUBFUN int XMLCALL CustomxmlFileRead(void * context, char * buffer, int len)
	{
		int RetVal(-1);	//Must be -1 for a failure.
		DWORD BytesRead = 0;

		_ASSERTE(g_pCXMLSignatureVerifier && _T("CustomxmlFileRead - g_pCXMLSignatureVerifier cannot be null when verifying a file package."));

		if(g_pCXMLSignatureVerifier)
		{
			if(g_pCXMLSignatureVerifier->m_spCallback->XMLFileRead((HANDLE)context, (BYTE*)buffer, len, BytesRead))
			{
				RetVal = (int)BytesRead;
			}
		}

		return RetVal;
	}

	static XMLPUBFUN int XMLCALL CustomxmlFileClose(void * context)
	{
		int RetVal(-1);	//Must be -1 for a failure.

		_ASSERTE(g_pCXMLSignatureVerifier && _T("CustomxmlFileClose - g_pCXMLSignatureVerifier cannot be null when verifying a file package."));

		if(g_pCXMLSignatureVerifier)
		{
			if(g_pCXMLSignatureVerifier->m_spCallback->CustomxmlFileClose((HANDLE)context))
			{
				RetVal = 0;
			}
		}

		return RetVal;
	}

	static void ErrorFunc(const char* file, int line, const char* func, const char* errorObject, const char* errorSubject, int reason, const char* msg)
	{
		DWORD Error = GetLastError();
		CATLString File;
		CATLString Function;
		CATLString ErrorObject;
		CATLString ErrorSubject;
		CATLString Message;
		CATLString ErrorMessage;

		if(file)
		{
			File = CA2T(file);
		}

		if(func)
		{
			Function = CA2T(func);
		}

		if(errorObject)
		{
			ErrorObject = CA2T(errorObject);
		}

		if(errorSubject)
		{
			ErrorSubject = CA2T(errorSubject);
		}

		if(msg)
		{
			Message = CA2T(msg);
		}

		ErrorMessage.Format(_T("XMLSec Error:\r\nfunc=%s; file=%s; line=%d; obj=%s; subj=%s; WindowsError(only valid for certain functions)=%d; Reason=%d; Msg=%s\r\n"), Function, File, line, ErrorObject, ErrorSubject, Error, reason, Message);
		OutputStringInDebugMode(ErrorMessage);
	}
};

CXMLSignatureVerifier::CXMLSignatureVerifier()
	: m_Initialized(false)
{
	g_pCXMLSignatureVerifier = this;
	m_spVariables.reset(new SXMLHiddenVariables);

	xmlInitParser();

	xmlLoadExtDtdDefaultValue = XML_DETECT_IDS | XML_COMPLETE_ATTRS;
	xmlSubstituteEntitiesDefault(1);
	xmlIndentTreeOutput = 1;

    m_spVariables->m_xsltSecPrefs = xsltNewSecurityPrefs(); 
    xsltSetSecurityPrefs(m_spVariables->m_xsltSecPrefs,  XSLT_SECPREF_READ_FILE,        xsltSecurityAllow);
    xsltSetSecurityPrefs(m_spVariables->m_xsltSecPrefs,  XSLT_SECPREF_WRITE_FILE,       xsltSecurityForbid);
    xsltSetSecurityPrefs(m_spVariables->m_xsltSecPrefs,  XSLT_SECPREF_CREATE_DIRECTORY, xsltSecurityForbid);
    xsltSetSecurityPrefs(m_spVariables->m_xsltSecPrefs,  XSLT_SECPREF_READ_NETWORK,     xsltSecurityForbid);
    xsltSetSecurityPrefs(m_spVariables->m_xsltSecPrefs,  XSLT_SECPREF_WRITE_NETWORK,    xsltSecurityForbid);
    xsltSetDefaultSecurityPrefs(m_spVariables->m_xsltSecPrefs);
}

CXMLSignatureVerifier::~CXMLSignatureVerifier()
{
	g_pCXMLSignatureVerifier = nullptr;

	if(m_Initialized)
	{
		xmlSecCryptoShutdown();
		xmlSecCryptoAppShutdown();
		xmlSecShutdown();
	}

	xmlSecIOCleanupCallbacks();

	if(m_spVariables->m_xsltSecPrefs != nullptr)
	{
		xsltFreeSecurityPrefs(m_spVariables->m_xsltSecPrefs);
	}

	xsltCleanupGlobals(); 

	xmlCleanupParser();

	m_Initialized = false;
}

bool CXMLSignatureVerifier::Initialize()
{
	m_Initialized = false;
	int SecInitRetVal = -1;
	int SecVersionRetVal = -1;
	int SecCryptoAppInitRetVal = -1;
	int SecCryptoInitRetVal = -1;
	CATLString ErrorMessage;

	LIBXML_TEST_VERSION

	if((SecInitRetVal = xmlSecInit()) >= 0)
	{
		if((SecVersionRetVal = xmlSecCheckVersion()) == XML_SEC_CURRENT_VERSION)
		{
			if((SecCryptoAppInitRetVal = xmlSecCryptoAppInit(NULL)) >= 0)
			{
				if((SecCryptoInitRetVal = xmlSecCryptoInit()) >= 0)
				{
					xmlSecErrorsSetCallback(CXMLSecCallbacks::ErrorFunc);

					m_Initialized = true;
				}
				else
				{
					ErrorMessage.Format(_T("CXMLSignatureVerifier::Initialize - xmlSecCryptoInit failure: %d"), SecCryptoInitRetVal);
					OutputStringInDebugMode(ErrorMessage);
				}
			}
			else
			{
				ErrorMessage.Format(_T("CXMLSignatureVerifier::Initialize - xmlSecCryptoAppInit failure: %d"), SecCryptoAppInitRetVal);
				OutputStringInDebugMode(ErrorMessage);
			}
		}
		else
		{
			ErrorMessage.Format(_T("CXMLSignatureVerifier::Initialize - xmlSecCheckVersion returned %d, expected %d"), SecVersionRetVal, XML_SEC_CURRENT_VERSION);
			OutputStringInDebugMode(ErrorMessage);
		}
	}
	else
	{
		ErrorMessage.Format(_T("CXMLSignatureVerifier::Initialize - xmlSecInit Init Failure: %d"), SecInitRetVal);
		OutputStringInDebugMode(ErrorMessage);
	}

	//Be sure to clean up if something failed because the destructor only cleans up if everything succeeds.
	if(!m_Initialized)
	{
		if(SecCryptoInitRetVal >= 0)
		{
			xmlSecCryptoShutdown();
		}

		if(SecCryptoAppInitRetVal >= 0)
		{
			xmlSecCryptoAppShutdown();
		}

		if(SecInitRetVal >= 0)
		{
			xmlSecShutdown();
		}
	}

	return m_Initialized;
}

static int
xmlSecDSigCtxProcessManifestNodeForFile(xmlSecDSigCtxPtr dsigCtx, xmlNodePtr node, const char* FileName) {
    xmlSecDSigReferenceCtxPtr dsigRefCtx;
    xmlNodePtr cur;
    int ret;
	xmlChar* URI;
	bool NodeFound = false;

    xmlSecAssert2(dsigCtx != NULL, -1);
    xmlSecAssert2(dsigCtx->status == xmlSecDSigStatusUnknown, -1);
    xmlSecAssert2(node != NULL, -1);

    /* calculate references */
    cur = xmlSecGetNextElementNode(node->children);
    while((cur != NULL) && (xmlSecCheckNodeName(cur, xmlSecNodeReference, xmlSecDSigNs)) && !NodeFound) {

		URI = xmlGetProp(cur, xmlSecAttrURI);

		//if(strcmp(FileName, (const char*)URI) == 0)
		{
			/* create reference */
			dsigRefCtx = xmlSecDSigReferenceCtxCreate(dsigCtx, xmlSecDSigReferenceOriginManifest);
			if(dsigRefCtx == NULL) {
				xmlSecError(XMLSEC_ERRORS_HERE,
							NULL,
							"xmlSecDSigReferenceCtxCreate",
							XMLSEC_ERRORS_R_XMLSEC_FAILED,
							XMLSEC_ERRORS_NO_MESSAGE);
				return(-1);
			}

			/* add to the list */
			ret = xmlSecPtrListAdd(&(dsigCtx->manifestReferences), dsigRefCtx);
			if(ret < 0) {
				xmlSecError(XMLSEC_ERRORS_HERE,
							NULL,
							"xmlSecPtrListAdd",
							XMLSEC_ERRORS_R_XMLSEC_FAILED,
							XMLSEC_ERRORS_NO_MESSAGE);
				xmlSecDSigReferenceCtxDestroy(dsigRefCtx);
				return(-1);
			}

			/* process */
			ret = xmlSecDSigReferenceCtxProcessNode(dsigRefCtx, cur);
			if(ret < 0) {
				xmlSecError(XMLSEC_ERRORS_HERE,
							NULL,
							"xmlSecDSigReferenceCtxProcessNode",
							XMLSEC_ERRORS_R_XMLSEC_FAILED,
							"node=%s",
							xmlSecErrorsSafeString(xmlSecNodeGetName(cur)));
				return(-1);
			}

			if(dsigRefCtx->digestMethod->status != xmlSecTransformStatusOk)
			{
				dsigCtx->status = xmlSecDSigStatusInvalid;
				NodeFound = true;
			}			
		}

		xmlFree(URI);

        cur = xmlSecGetNextElementNode(cur->next);
    }

    /* we should have nothing else here */
    if(cur != NULL) {
        xmlSecError(XMLSEC_ERRORS_HERE,
                    NULL,
                    xmlSecErrorsSafeString(xmlSecNodeGetName(cur)),
                    XMLSEC_ERRORS_R_UNEXPECTED_NODE,
                    XMLSEC_ERRORS_NO_MESSAGE);
        return(-1);
    }
    return(0);
}

static int
xmlSecDSigCtxProcessObjectNodeForFile(xmlSecDSigCtxPtr dsigCtx, xmlNodePtr node, const char* FileName) {
    xmlNodePtr cur;
    int ret;

    xmlSecAssert2(dsigCtx != NULL, -1);
    xmlSecAssert2(dsigCtx->status == xmlSecDSigStatusUnknown, -1);
    xmlSecAssert2(node != NULL, -1);

    /* we care about Manifest nodes only; ignore everything else */
    cur = xmlSecGetNextElementNode(node->children);
    while(cur != NULL) {
        if(xmlSecCheckNodeName(cur, xmlSecNodeManifest, xmlSecDSigNs)) {
            ret = xmlSecDSigCtxProcessManifestNodeForFile(dsigCtx, cur, FileName);
            if(ret < 0){
                xmlSecError(XMLSEC_ERRORS_HERE,
                            NULL,
                            "xmlSecDSigCtxProcessManifestNode",
                            XMLSEC_ERRORS_R_XMLSEC_FAILED,
                            XMLSEC_ERRORS_NO_MESSAGE);
                return(-1);
            }
        }
        cur = xmlSecGetNextElementNode(cur->next);
    }
    return(0);
}

int
xmlSecDSigCtxVerifyFile(xmlSecDSigCtxPtr dsigCtx, xmlNodePtr node, const char* FileName) 
{
    int ret;
	xmlNodePtr cur;
    xmlNodePtr signedInfoNode = NULL;
    xmlNodePtr keyInfoNode = NULL;

    xmlSecAssert2(dsigCtx != NULL, -1);
    xmlSecAssert2(node != NULL, -1);
    xmlSecAssert2(node->doc != NULL, -1);

    /* add ids for Signature nodes */
    dsigCtx->operation  = xmlSecTransformOperationVerify;
    dsigCtx->status     = xmlSecDSigStatusUnknown;
    
	xmlSecAssert2(dsigCtx != NULL, -1);
    xmlSecAssert2((dsigCtx->operation == xmlSecTransformOperationSign) || (dsigCtx->operation == xmlSecTransformOperationVerify), -1);
    xmlSecAssert2(dsigCtx->status == xmlSecDSigStatusUnknown, -1);
    xmlSecAssert2(dsigCtx->signValueNode == NULL, -1);
    xmlSecAssert2(dsigCtx->signMethod == NULL, -1);
    xmlSecAssert2(dsigCtx->c14nMethod == NULL, -1);
    xmlSecAssert2(node != NULL, -1);

    if(!xmlSecCheckNodeName(node, xmlSecNodeSignature, xmlSecDSigNs)) {
        xmlSecError(XMLSEC_ERRORS_HERE,
                    NULL,
                    xmlSecErrorsSafeString(xmlSecNodeGetName(node)),
                    XMLSEC_ERRORS_R_INVALID_NODE,
                    "expected=%s",
                    xmlSecErrorsSafeString(xmlSecNodeSignature));
        return(-1);
    }

    /* read node data */
    xmlSecAssert2(dsigCtx->id == NULL, -1);
    dsigCtx->id = xmlGetProp(node, xmlSecAttrId);

    /* first node is required SignedInfo */
    cur = xmlSecGetNextElementNode(node->children);
    if((cur == NULL) || (!xmlSecCheckNodeName(cur, xmlSecNodeSignedInfo, xmlSecDSigNs))) {
        xmlSecError(XMLSEC_ERRORS_HERE,
                    NULL,
                    xmlSecErrorsSafeString(xmlSecNodeGetName(cur)),
                    XMLSEC_ERRORS_R_INVALID_NODE,
                    "expected=%s",
                    xmlSecErrorsSafeString(xmlSecNodeSignedInfo));
        return(-1);
    }
    signedInfoNode = cur;
    cur = xmlSecGetNextElementNode(cur->next);

    /* next node is required SignatureValue */
    if((cur == NULL) || (!xmlSecCheckNodeName(cur, xmlSecNodeSignatureValue, xmlSecDSigNs))) {
        xmlSecError(XMLSEC_ERRORS_HERE,
                    NULL,
                    xmlSecErrorsSafeString(xmlSecNodeGetName(cur)),
                    XMLSEC_ERRORS_R_INVALID_NODE,
                    "expected=%s",
                    xmlSecErrorsSafeString(xmlSecNodeSignatureValue));
        return(-1);
    }
    dsigCtx->signValueNode = cur;
    cur = xmlSecGetNextElementNode(cur->next);

    /* next node is optional KeyInfo */
    if((cur != NULL) && (xmlSecCheckNodeName(cur, xmlSecNodeKeyInfo, xmlSecDSigNs))) {
        keyInfoNode = cur;
        cur = xmlSecGetNextElementNode(cur->next);
    } else {
        keyInfoNode = NULL;
    }

    /* next nodes are optional Object nodes */
    while((cur != NULL) && (xmlSecCheckNodeName(cur, xmlSecNodeObject, xmlSecDSigNs))) {
        /* read manifests from objects */
        ret = xmlSecDSigCtxProcessObjectNodeForFile(dsigCtx, cur, FileName);
        if(ret < 0) {
            xmlSecError(XMLSEC_ERRORS_HERE,
                        NULL,
                        "xmlSecDSigCtxProcessObjectNode",
                        XMLSEC_ERRORS_R_XMLSEC_FAILED,
                        XMLSEC_ERRORS_NO_MESSAGE);
            return(-1);
        }
        
        cur = xmlSecGetNextElementNode(cur->next);
    }

    /* if there is something left than it's an error */
    if(cur != NULL) {
        xmlSecError(XMLSEC_ERRORS_HERE,
                    NULL,
                    xmlSecErrorsSafeString(xmlSecNodeGetName(cur)),
                    XMLSEC_ERRORS_R_UNEXPECTED_NODE,
                    XMLSEC_ERRORS_NO_MESSAGE);
        return(-1);
    }

    /* set status and we are done */
    if(dsigCtx->status == xmlSecDSigStatusUnknown) {	//The digest verifier will only set the status on failure.
        dsigCtx->status = xmlSecDSigStatusSucceeded;
    } else {
        dsigCtx->status = xmlSecDSigStatusInvalid;
    }

	return (0);
}


class CXMLSecHandler
{
public:
	CXMLSecHandler() : m_pDoc(nullptr), m_pMngr(nullptr), m_pDsigCtx(nullptr) {}
	~CXMLSecHandler();

	bool Init(const CATLString& XMLFile);

	xmlDocPtr GetDocument() { return m_pDoc; }
	xmlSecKeysMngrPtr GetKeysManager() { return m_pMngr; }
	xmlSecDSigCtxPtr GetSignatureContext() { return m_pDsigCtx; }
private:
	xmlDocPtr m_pDoc;
	xmlSecKeysMngrPtr m_pMngr;
	xmlSecDSigCtxPtr m_pDsigCtx;
};

CXMLSecHandler::~CXMLSecHandler()
{
	if(m_pDoc != nullptr)
	{
		xmlFreeDoc(m_pDoc);
	}

	if(m_pMngr != nullptr)
	{
		xmlSecKeysMngrDestroy(m_pMngr);
	}

	if(m_pDsigCtx != nullptr)
	{
		xmlSecDSigCtxDestroy(m_pDsigCtx);
	}
}

bool CXMLSecHandler::Init(const CATLString& XMLFile)
{
	bool RetVal = false;
	xmlDocPtr pDoc = nullptr;
	xmlSecKeysMngrPtr pMngr = nullptr;
	xmlSecDSigCtxPtr pDsigCtx = nullptr;
	bool CertsLoaded = false;
	CATLString ErrorMessage;

	if(m_pDoc == nullptr)
	{
		if((pDoc = xmlParseFile(CT2A(XMLFile))) != nullptr)
		{
			if((pMngr = xmlSecKeysMngrCreate()) != nullptr)
			{
				if(xmlSecCryptoAppDefaultKeysMngrInit(pMngr) >= 0)
				{
					CertsLoaded = xmlSecMSCryptoAppKeysMngrCertLoadMemory(pMngr, CAT_CERT_PROD, CAT_CERT_PROD_SIZE, xmlSecKeyDataFormatCertDer, xmlSecKeyDataTypeTrusted) >= 0;
					CertsLoaded = CertsLoaded && xmlSecMSCryptoAppKeysMngrCertLoadMemory(pMngr, SIS_CERT_PROD, SIS_CERT_PROD_SIZE, xmlSecKeyDataFormatCertDer, xmlSecKeyDataTypeTrusted) >= 0;
					CertsLoaded = CertsLoaded && xmlSecMSCryptoAppKeysMngrCertLoadMemory(pMngr, CAT_CERT_PROD_DISPLAY, SIS_CERT_PROD_DISPLAY_SIZE, xmlSecKeyDataFormatCertDer, xmlSecKeyDataTypeTrusted) >= 0;
					
					if(CertsLoaded)
					{
						if((pDsigCtx = xmlSecDSigCtxCreate(pMngr)) != nullptr)
						{
							RetVal = true;
							m_pDoc = pDoc;
							m_pMngr = pMngr;
							m_pDsigCtx = pDsigCtx;
						}
						else
						{
							ErrorMessage = _T("CXMLSecHandler::Init - Unable to create the signature context.");
							OutputStringInDebugMode(ErrorMessage);
						}
					}
					else
					{
						ErrorMessage = _T("CXMLSecHandler::Init - Unable to load the certificates.");
						OutputStringInDebugMode(ErrorMessage);
					}
				}
				else
				{
					ErrorMessage = _T("CXMLSecHandler::Init - Unable to initialize the key manager.");
					OutputStringInDebugMode(ErrorMessage);
				}
			}
			else
			{
				ErrorMessage = _T("CXMLSecHandler::Init - Unable to create the key manager.");
				OutputStringInDebugMode(ErrorMessage);
			}
		}
		else
		{
			ErrorMessage.Format(_T("CXMLSecHandler::Init - Error parsing file %s"), XMLFile);
			OutputStringInDebugMode(ErrorMessage);
		}

		if(!RetVal)
		{
			if(pDoc != nullptr)
			{
				xmlFreeDoc(pDoc);
			}

			if(pMngr != nullptr)
			{
				xmlSecKeysMngrDestroy(pMngr);
			}

			if(pDsigCtx != nullptr)
			{
				xmlSecDSigCtxDestroy(pDsigCtx);
			}
		}
	}
	else
	{
		RetVal = true;
	}

	return RetVal;
}

bool CXMLSignatureVerifier::ValidateObjectNodes(const CATLString& XMLFile)
{
	xmlNodePtr pNode = nullptr;
	bool RetVal = false;
	CATLString ErrorMessage;
	int VerifyRetVal = -1;
	bool CertsLoaded = false;

	if(m_Initialized)
	{
		g_pCXMLSignatureVerifier = this;

		{	//CXMLSecHandler must destruct before g_pCXMLSignatureVerifier is set to null.

			CXMLSecHandler Handler;

			if(Handler.Init(XMLFile))
			{
				if((pNode = xmlSecFindNode(xmlDocGetRootElement(Handler.GetDocument()), xmlSecNodeSignature, xmlSecDSigNs)) != nullptr)
				{
					if((VerifyRetVal = xmlSecDSigCtxVerifyFile(Handler.GetSignatureContext(), pNode, CT2A(XMLFile))) >= 0)
					{
						RetVal = Handler.GetSignatureContext()->status == xmlSecDSigStatusSucceeded;
					}
					else
					{
						ErrorMessage.Format(_T("CXMLSignatureVerifier::ValidateFile - Failure in xmlSecDSigCtxVerify: %d"), VerifyRetVal);
						OutputStringInDebugMode(ErrorMessage);
					}
				}
				else
				{
					ErrorMessage.Format(_T("CXMLSignatureVerifier::ValidateFile - Error obtaining signature node in %s"), XMLFile);
					OutputStringInDebugMode(ErrorMessage);
				}
			}
		}

		g_pCXMLSignatureVerifier = nullptr;
	}

	return RetVal;
}

bool CXMLSignatureVerifier::ValidateFile(const CATLString& XMLFile)
{
	xmlNodePtr pNode = nullptr;
	bool RetVal = false;
	CATLString ErrorMessage;
	int VerifyRetVal = -1;
	bool CertsLoaded = false;

	if(m_Initialized)
	{
		g_pCXMLSignatureVerifier = this;

		{	//Important, make sure everything is unloaded before the call to ValidateObjectNodes
			CXMLSecHandler Handler;

			if(Handler.Init(XMLFile))
			{
				if((pNode = xmlSecFindNode(xmlDocGetRootElement(Handler.GetDocument()), xmlSecNodeSignature, xmlSecDSigNs)) != nullptr)
				{
					Handler.GetSignatureContext()->flags |= XMLSEC_DSIG_FLAGS_IGNORE_MANIFESTS;	//Manifests have to be validated by hand when the file specified in the manifest is requested.

					if((VerifyRetVal = xmlSecDSigCtxVerify(Handler.GetSignatureContext(), pNode)) >= 0)
					{
						RetVal = Handler.GetSignatureContext()->status == xmlSecDSigStatusSucceeded;
					}
					else
					{
						ErrorMessage.Format(_T("CXMLSignatureVerifier::ValidateFile - Failure in xmlSecDSigCtxVerify: %d"), VerifyRetVal);
						OutputStringInDebugMode(ErrorMessage);
					}
				}
				else
				{
					ErrorMessage.Format(_T("CXMLSignatureVerifier::ValidateFile - Error obtaining signature node in %s"), XMLFile);
					OutputStringInDebugMode(ErrorMessage);
				}
			}
		}

		if(RetVal)
		{
			RetVal = ValidateObjectNodes(XMLFile);	//Verify all manifest files.
		}

		/*if((pDoc = xmlParseFile(CT2A(XMLFile))) != nullptr)
		{
			if((pNode = xmlSecFindNode(xmlDocGetRootElement(pDoc), xmlSecNodeSignature, xmlSecDSigNs)) != nullptr)
			{
				if((pMngr = xmlSecKeysMngrCreate()) != nullptr)
				{
					if(xmlSecCryptoAppDefaultKeysMngrInit(pMngr) >= 0)
					{
						CertsLoaded = xmlSecMSCryptoAppKeysMngrCertLoadMemory(pMngr, CAT_CERT_PROD, CAT_CERT_PROD_SIZE, xmlSecKeyDataFormatCertDer, xmlSecKeyDataTypeTrusted) >= 0;
						CertsLoaded = CertsLoaded && xmlSecMSCryptoAppKeysMngrCertLoadMemory(pMngr, SIS_CERT_PROD, SIS_CERT_PROD_SIZE, xmlSecKeyDataFormatCertDer, xmlSecKeyDataTypeTrusted) >= 0;

						if(CertsLoaded)
						{
							if((pDsigCtx = xmlSecDSigCtxCreate(pMngr)) != nullptr)
							{
								pDsigCtx->flags |= XMLSEC_DSIG_FLAGS_IGNORE_MANIFESTS;	//Manifests have to be validated by hand when the file specified in the manifest is requested.

								if((VerifyRetVal = xmlSecDSigCtxVerify(pDsigCtx, pNode)) >= 0)
								{
									RetVal = pDsigCtx->status == xmlSecDSigStatusSucceeded;
								}
								else
								{
									ErrorMessage.Format(_T("CXMLSignatureVerifier::ValidateFile - Failure in xmlSecDSigCtxVerify: %d"), VerifyRetVal);
									OutputStringInDebugMode(ErrorMessage);
								}

								xmlSecDSigCtxDestroy(pDsigCtx);
							}
							else
							{
								ErrorMessage = _T("CXMLSignatureVerifier::ValidateFile - Unable to create the signature context.");
								OutputStringInDebugMode(ErrorMessage);
							}
						}
						else
						{
							ErrorMessage = _T("CXMLSignatureVerifier::ValidateFile - Unable to load the certificate.");
							OutputStringInDebugMode(ErrorMessage);
						}
					}
					else
					{
						ErrorMessage = _T("CXMLSignatureVerifier::ValidateFile - Unable to initialize the key manager.");
						OutputStringInDebugMode(ErrorMessage);
					}

					xmlSecKeysMngrDestroy(pMngr);
				}
				else
				{
					ErrorMessage = _T("CXMLSignatureVerifier::ValidateFile - Unable to create the key manager.");
					OutputStringInDebugMode(ErrorMessage);
				}
			}
			else
			{
				ErrorMessage.Format(_T("CXMLSignatureVerifier::ValidateFile - Error obtaining signature node in %s"), XMLFile);
				OutputStringInDebugMode(ErrorMessage);
			}

			xmlFreeDoc(pDoc);
		}
		else
		{
			ErrorMessage.Format(_T("CXMLSignatureVerifier::ValidateFile - Error parsing file %s"), XMLFile);
			OutputStringInDebugMode(ErrorMessage);
		}*/

		g_pCXMLSignatureVerifier = nullptr;
	}

	return RetVal;
}

void CXMLSignatureVerifier::SetXMLSignatureCallback(XMLSignatureCallbackSharedPtr spCallback)
{
	if(m_Initialized)
	{
		m_spCallback = spCallback;

		xmlSecIOCleanupCallbacks();
		xmlSecIORegisterCallbacks(CXMLSecCallbacks::CustomxmlFileMatch, CXMLSecCallbacks::CustomxmlFileOpen, CXMLSecCallbacks::CustomxmlFileRead, CXMLSecCallbacks::CustomxmlFileClose);
	}
}

void CXMLSignatureVerifier::ResetCallback()
{
	m_spCallback.reset();

	xmlSecIOCleanupCallbacks();
}


////////////////////////////////////////////////////////
//  Revision History:
/* $Log: /STPL/FlashServer/source/XMLSignatureVerifier.cpp $
 * 
 * 04/24/2013 12:22:40 PM  BrendKM
 * SCR#E04483 - Added signature validation.
 * 
 * 1     3/14/12 4:08p Brendkm
 * SCR#E04483 - Support for CSVID.
 */
////////////////////////////////////////////////////////
