/**************************************************************
 * 
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 * 
 *************************************************************/



// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_xmlsecurity.hxx"

#ifdef _MSC_VER
#pragma warning(push,1)
#endif
#include "Windows.h"
#include "WinCrypt.h"
#ifdef _MSC_VER
#pragma warning(pop)
#endif
#include <sal/config.h>
#include <osl/thread.h>
#include "securityenvironment_mscryptimpl.hxx"

#ifndef _X509CERTIFICATE_NSSIMPL_HXX_
#include "x509certificate_mscryptimpl.hxx"
#endif
#include <rtl/uuid.h>

#include <xmlsec/xmlsec.h>
#include <xmlsec/keysmngr.h>
#include <xmlsec/crypto.h>
#include <xmlsec/base64.h>

#include <xmlsecurity/biginteger.hxx>

#include "xmlsec/keysmngr.h"
#include "xmlsec/mscrypto/akmngr.h"

//CP : added by CP
#include <rtl/locale.h>
#include <osl/nlsupport.h> 
#include <osl/process.h>

//CP : end
#include <rtl/memory.h>

#include "../diagnose.hxx"

using namespace xmlsecurity;
using namespace ::com::sun::star::uno ;
using namespace ::com::sun::star::lang ;
using ::com::sun::star::lang::XMultiServiceFactory ;
using ::com::sun::star::lang::XSingleServiceFactory ;
using ::rtl::OUString ;

using ::com::sun::star::xml::crypto::XSecurityEnvironment ;
using ::com::sun::star::security::XCertificate ;
namespace css = ::com::sun::star;

extern X509Certificate_MSCryptImpl* MswcryCertContextToXCert( PCCERT_CONTEXT cert ) ;

struct CertErrorToString{
    DWORD error;
    char * name;
};

CertErrorToString arErrStrings[] =
{
    { 0x00000000, "CERT_TRUST_NO_ERROR"},
    { 0x00000001, "CERT_TRUST_IS_NOT_TIME_VALID"},
    { 0x00000002, "CERT_TRUST_IS_NOT_TIME_NESTED"},
    { 0x00000004, "CERT_TRUST_IS_REVOKED" },
    { 0x00000008, "CERT_TRUST_IS_NOT_SIGNATURE_VALID" },
    { 0x00000010, "CERT_TRUST_IS_NOT_SIGNATURE_VALID"},
    { 0x00000020, "CERT_TRUST_IS_UNTRUSTED_ROOT"},
    { 0x00000040, "CERT_TRUST_REVOCATION_STATUS_UNKNOWN"},
    { 0x00000080, "CERT_TRUST_IS_CYCLIC"},
    { 0x00000100, "CERT_TRUST_INVALID_EXTENSION"},
    { 0x00000200, "CERT_TRUST_INVALID_POLICY_CONSTRAINTS"},
    { 0x00000400, "CERT_TRUST_INVALID_BASIC_CONSTRAINTS"},
    { 0x00000800, "CERT_TRUST_INVALID_NAME_CONSTRAINTS"},
    { 0x00001000, "CERT_TRUST_HAS_NOT_SUPPORTED_NAME_CONSTRAINT"},
    { 0x00002000, "CERT_TRUST_HAS_NOT_DEFINED_NAME_CONSTRAINT"},
    { 0x00004000, "CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT"},
    { 0x00008000, "CERT_TRUST_HAS_EXCLUDED_NAME_CONSTRAINT"},
    { 0x01000000, "CERT_TRUST_IS_OFFLINE_REVOCATION"},
    { 0x02000000, "CERT_TRUST_NO_ISSUANCE_CHAIN_POLICY"},
    { 0x04000000, "CERT_TRUST_IS_EXPLICIT_DISTRUST"},
    { 0x08000000, "CERT_TRUST_HAS_NOT_SUPPORTED_CRITICAL_EXT"},
    //Chain errors
    { 0x00010000, "CERT_TRUST_IS_PARTIAL_CHAIN"},
    { 0x00020000, "CERT_TRUST_CTL_IS_NOT_TIME_VALID"},
    { 0x00040000, "CERT_TRUST_CTL_IS_NOT_SIGNATURE_VALID"},
    { 0x00080000, "CERT_TRUST_CTL_IS_NOT_VALID_FOR_USAGE"}
};

void traceTrustStatus(DWORD err)
{
    int numErrors = sizeof(arErrStrings) / sizeof(CertErrorToString);
    xmlsec_trace("The certificate error status is: ");
    if (err == 0)
        xmlsec_trace("%s", arErrStrings[0].name);
    for (int i = 1; i < numErrors; i++)
    {
        if (arErrStrings[i].error & err)
            xmlsec_trace("%s", arErrStrings[i].name);
    }
}

SecurityEnvironment_MSCryptImpl :: SecurityEnvironment_MSCryptImpl( const Reference< XMultiServiceFactory >& aFactory ) : m_hProv( NULL ) , m_pszContainer( NULL ) , m_hKeyStore( NULL ), m_hCertStore( NULL ), m_tSymKeyList() , m_tPubKeyList() , m_tPriKeyList(), m_xServiceManager( aFactory ), m_bEnableDefault( sal_False ), m_hMySystemStore(NULL), m_hRootSystemStore(NULL), m_hTrustSystemStore(NULL), m_hCaSystemStore(NULL){

}

SecurityEnvironment_MSCryptImpl :: ~SecurityEnvironment_MSCryptImpl() {

	if( m_hProv != NULL ) {
		CryptReleaseContext( m_hProv, 0 ) ;
		m_hProv = NULL ;
	}

	if( m_pszContainer != NULL ) {
		//TODO: Don't know whether or not it should be released now.
		m_pszContainer = NULL ;
	}

	if( m_hCertStore != NULL ) {
		CertCloseStore( m_hCertStore, CERT_CLOSE_STORE_FORCE_FLAG ) ;
		m_hCertStore = NULL ;
	}

	if( m_hKeyStore != NULL ) {
		CertCloseStore( m_hKeyStore, CERT_CLOSE_STORE_FORCE_FLAG ) ;
		m_hKeyStore = NULL ;
	}

	//i120675, close the store handles 
	if( m_hMySystemStore != NULL ) {
		CertCloseStore( m_hMySystemStore, CERT_CLOSE_STORE_CHECK_FLAG ) ;
		m_hMySystemStore = NULL ;
	}

	if( m_hRootSystemStore != NULL ) {
		CertCloseStore( m_hRootSystemStore, CERT_CLOSE_STORE_CHECK_FLAG ) ;
		m_hRootSystemStore = NULL ;
	}

	if( m_hTrustSystemStore != NULL ) {
		CertCloseStore( m_hTrustSystemStore, CERT_CLOSE_STORE_CHECK_FLAG ) ;
		m_hTrustSystemStore = NULL ;
	}

	if( m_hCaSystemStore != NULL ) {
		CertCloseStore( m_hCaSystemStore, CERT_CLOSE_STORE_CHECK_FLAG ) ;
		m_hCaSystemStore = NULL ;
	}

	if( !m_tSymKeyList.empty()  ) {
		std::list< HCRYPTKEY >::iterator symKeyIt ;

		for( symKeyIt = m_tSymKeyList.begin() ; symKeyIt != m_tSymKeyList.end() ; symKeyIt ++ )
			CryptDestroyKey( *symKeyIt ) ;
	}

	if( !m_tPubKeyList.empty()  ) {
		std::list< HCRYPTKEY >::iterator pubKeyIt ;

		for( pubKeyIt = m_tPubKeyList.begin() ; pubKeyIt != m_tPubKeyList.end() ; pubKeyIt ++ )
			CryptDestroyKey( *pubKeyIt ) ;
	}

	if( !m_tPriKeyList.empty()  ) {
		std::list< HCRYPTKEY >::iterator priKeyIt ;

		for( priKeyIt = m_tPriKeyList.begin() ; priKeyIt != m_tPriKeyList.end() ; priKeyIt ++ )
			CryptDestroyKey( *priKeyIt ) ;
	}
	
}

/* XInitialization */
void SAL_CALL SecurityEnvironment_MSCryptImpl :: initialize( const Sequence< Any >& /*aArguments*/ ) throw( Exception, RuntimeException ) {
	//TODO
} ;

/* XServiceInfo */
OUString SAL_CALL SecurityEnvironment_MSCryptImpl :: getImplementationName() throw( RuntimeException ) {
	return impl_getImplementationName() ;
}

/* XServiceInfo */
sal_Bool SAL_CALL SecurityEnvironment_MSCryptImpl :: supportsService( const OUString& serviceName) throw( RuntimeException ) {
	Sequence< OUString > seqServiceNames = getSupportedServiceNames() ;
	const OUString* pArray = seqServiceNames.getConstArray() ;
	for( sal_Int32 i = 0 ; i < seqServiceNames.getLength() ; i ++ ) {
		if( *( pArray + i ) == serviceName )
			return sal_True ;
	}
	return sal_False ;
}

/* XServiceInfo */
Sequence< OUString > SAL_CALL SecurityEnvironment_MSCryptImpl :: getSupportedServiceNames() throw( RuntimeException ) {
	return impl_getSupportedServiceNames() ;
}

//Helper for XServiceInfo
Sequence< OUString > SecurityEnvironment_MSCryptImpl :: impl_getSupportedServiceNames() {
	::osl::Guard< ::osl::Mutex > aGuard( ::osl::Mutex::getGlobalMutex() ) ;
	Sequence< OUString > seqServiceNames( 1 ) ;
	seqServiceNames.getArray()[0] = OUString::createFromAscii( "com.sun.star.xml.crypto.SecurityEnvironment" ) ;
	return seqServiceNames ;
}

OUString SecurityEnvironment_MSCryptImpl :: impl_getImplementationName() throw( RuntimeException ) {
	return OUString::createFromAscii( "com.sun.star.xml.security.bridge.xmlsec.SecurityEnvironment_MSCryptImpl" ) ;
}

//Helper for registry
Reference< XInterface > SAL_CALL SecurityEnvironment_MSCryptImpl :: impl_createInstance( const Reference< XMultiServiceFactory >& aServiceManager ) throw( RuntimeException ) {
	return Reference< XInterface >( *new SecurityEnvironment_MSCryptImpl( aServiceManager ) ) ;
}

Reference< XSingleServiceFactory > SecurityEnvironment_MSCryptImpl :: impl_createFactory( const Reference< XMultiServiceFactory >& aServiceManager ) {
	return ::cppu::createSingleFactory( aServiceManager , impl_getImplementationName() , impl_createInstance , impl_getSupportedServiceNames() ) ;
}

/* XUnoTunnel */
sal_Int64 SAL_CALL SecurityEnvironment_MSCryptImpl :: getSomething( const Sequence< sal_Int8 >& aIdentifier ) 
	throw( RuntimeException )
{
	if( aIdentifier.getLength() == 16 && 0 == rtl_compareMemory( getUnoTunnelId().getConstArray(), aIdentifier.getConstArray(), 16 ) ) { 
		return ( sal_Int64 )this ;
	}
	return 0 ;
}

/* XUnoTunnel extension */
const Sequence< sal_Int8>& SecurityEnvironment_MSCryptImpl :: getUnoTunnelId() {
	static Sequence< sal_Int8 >* pSeq = 0 ;
	if( !pSeq ) {
		::osl::Guard< ::osl::Mutex > aGuard( ::osl::Mutex::getGlobalMutex() ) ;
		if( !pSeq ) {
			static Sequence< sal_Int8> aSeq( 16 ) ;
			rtl_createUuid( ( sal_uInt8* )aSeq.getArray() , 0 , sal_True ) ;
			pSeq = &aSeq ;
		}
	}
	return *pSeq ;
}

/* XUnoTunnel extension */
SecurityEnvironment_MSCryptImpl* SecurityEnvironment_MSCryptImpl :: getImplementation( const Reference< XInterface > xObj ) {
	Reference< XUnoTunnel > xUT( xObj , UNO_QUERY ) ;
	if( xUT.is() ) {
		return ( SecurityEnvironment_MSCryptImpl* )xUT->getSomething( getUnoTunnelId() ) ;
	} else
		return NULL ;
}

/* Native methods */
HCRYPTPROV SecurityEnvironment_MSCryptImpl :: getCryptoProvider() throw( ::com::sun::star::uno::Exception , ::com::sun::star::uno::RuntimeException ) {
	return m_hProv ;
}

void SecurityEnvironment_MSCryptImpl :: setCryptoProvider( HCRYPTPROV aProv ) throw( ::com::sun::star::uno::Exception , ::com::sun::star::uno::RuntimeException ) {
	if( m_hProv != NULL ) {
		CryptReleaseContext( m_hProv, 0 ) ;
		m_hProv = NULL ;
	}

	if( aProv != NULL ) {
		/*- Replaced by direct adopt for WINNT support ----
		if( !CryptContextAddRef( aProv, NULL, NULL ) )
			throw Exception() ;
		else
			m_hProv = aProv ;
		----*/
		m_hProv = aProv ;
	}
}

LPCTSTR SecurityEnvironment_MSCryptImpl :: getKeyContainer() throw( ::com::sun::star::uno::Exception , ::com::sun::star::uno::RuntimeException ) {
	return m_pszContainer ;
}

void SecurityEnvironment_MSCryptImpl :: setKeyContainer( LPCTSTR aKeyContainer ) throw( ::com::sun::star::uno::Exception , ::com::sun::star::uno::RuntimeException ) {
	//TODO: Don't know whether or not it should be copied.
	m_pszContainer = aKeyContainer ;
}


HCERTSTORE SecurityEnvironment_MSCryptImpl :: getCryptoSlot() throw( Exception , RuntimeException ) {
	return m_hKeyStore ;
}

void SecurityEnvironment_MSCryptImpl :: setCryptoSlot( HCERTSTORE aSlot) throw( Exception , RuntimeException ) {
	if( m_hKeyStore != NULL ) {
		CertCloseStore( m_hKeyStore, CERT_CLOSE_STORE_FORCE_FLAG ) ;
		m_hKeyStore = NULL ;
	}

	if( aSlot != NULL ) {
		m_hKeyStore = CertDuplicateStore( aSlot ) ;
	}
}

HCERTSTORE SecurityEnvironment_MSCryptImpl :: getCertDb() throw( Exception , RuntimeException ) {
	return m_hCertStore ;
}

void SecurityEnvironment_MSCryptImpl :: setCertDb( HCERTSTORE aCertDb ) throw( Exception , RuntimeException ) {
	if( m_hCertStore != NULL ) {
		CertCloseStore( m_hCertStore, CERT_CLOSE_STORE_FORCE_FLAG ) ;
		m_hCertStore = NULL ;
	}

	if( aCertDb != NULL ) {
		m_hCertStore = CertDuplicateStore( aCertDb ) ;
	}
}

void SecurityEnvironment_MSCryptImpl :: adoptSymKey( HCRYPTKEY aSymKey ) throw( Exception , RuntimeException ) {
	HCRYPTKEY	symkey ;
	std::list< HCRYPTKEY >::iterator keyIt ;

	if( aSymKey != NULL ) {
		//First try to find the key in the list
		for( keyIt = m_tSymKeyList.begin() ; keyIt != m_tSymKeyList.end() ; keyIt ++ ) {
			if( *keyIt == aSymKey )
				return ;
		}

		//If we do not find the key in the list, add a new node
		/*- Replaced with directly adopt for WINNT 4.0 support ----
		if( !CryptDuplicateKey( aSymKey, NULL, 0, &symkey ) )
			throw RuntimeException() ;
		----*/
		symkey = aSymKey ;

		try {
			m_tSymKeyList.push_back( symkey ) ;
		} catch ( Exception& ) {
			CryptDestroyKey( symkey ) ;
		}
	}
}

void SecurityEnvironment_MSCryptImpl :: rejectSymKey( HCRYPTKEY aSymKey ) throw( Exception , RuntimeException ) {
	HCRYPTKEY symkey ;
	std::list< HCRYPTKEY >::iterator keyIt ;

	if( aSymKey != NULL ) {
		for( keyIt = m_tSymKeyList.begin() ; keyIt != m_tSymKeyList.end() ; keyIt ++ ) {
			if( *keyIt == aSymKey ) {
				symkey = *keyIt ;
				CryptDestroyKey( symkey ) ;
				m_tSymKeyList.erase( keyIt ) ;
				break ;
			}
		}
	}
}

HCRYPTKEY SecurityEnvironment_MSCryptImpl :: getSymKey( unsigned int position ) throw( Exception , RuntimeException ) {
	HCRYPTKEY symkey ;
	std::list< HCRYPTKEY >::iterator keyIt ;
	unsigned int pos ;

	symkey = NULL ;
	for( pos = 0, keyIt = m_tSymKeyList.begin() ; pos < position && keyIt != m_tSymKeyList.end() ; pos ++ , keyIt ++ ) ;

	if( pos == position && keyIt != m_tSymKeyList.end() )
		symkey = *keyIt ;

	return symkey ;
}

void SecurityEnvironment_MSCryptImpl :: adoptPubKey( HCRYPTKEY aPubKey ) throw( Exception , RuntimeException ) {
	HCRYPTKEY	pubkey ;
	std::list< HCRYPTKEY >::iterator keyIt ;

	if( aPubKey != NULL ) {
		//First try to find the key in the list
		for( keyIt = m_tPubKeyList.begin() ; keyIt != m_tPubKeyList.end() ; keyIt ++ ) {
			if( *keyIt == aPubKey )
				return ;
		}

		//If we do not find the key in the list, add a new node
		/*- Replaced with directly adopt for WINNT 4.0 support ----
		if( !CryptDuplicateKey( aPubKey, NULL, 0, &pubkey ) )
			throw RuntimeException() ;
		----*/
		pubkey = aPubKey ;

		try {
			m_tPubKeyList.push_back( pubkey ) ;
		} catch ( Exception& ) {
			CryptDestroyKey( pubkey ) ;
		}
	}
}

void SecurityEnvironment_MSCryptImpl :: rejectPubKey( HCRYPTKEY aPubKey ) throw( Exception , RuntimeException ) {
	HCRYPTKEY pubkey ;
	std::list< HCRYPTKEY >::iterator keyIt ;

	if( aPubKey != NULL ) {
		for( keyIt = m_tPubKeyList.begin() ; keyIt != m_tPubKeyList.end() ; keyIt ++ ) {
			if( *keyIt == aPubKey ) {
				pubkey = *keyIt ;
				CryptDestroyKey( pubkey ) ;
				m_tPubKeyList.erase( keyIt ) ;
				break ;
			}
		}
	}
}

HCRYPTKEY SecurityEnvironment_MSCryptImpl :: getPubKey( unsigned int position ) throw( Exception , RuntimeException ) {
	HCRYPTKEY pubkey ;
	std::list< HCRYPTKEY >::iterator keyIt ;
	unsigned int pos ;

	pubkey = NULL ;
	for( pos = 0, keyIt = m_tPubKeyList.begin() ; pos < position && keyIt != m_tPubKeyList.end() ; pos ++ , keyIt ++ ) ;

	if( pos == position && keyIt != m_tPubKeyList.end() )
		pubkey = *keyIt ;

	return pubkey ;
}

void SecurityEnvironment_MSCryptImpl :: adoptPriKey( HCRYPTKEY aPriKey ) throw( Exception , RuntimeException ) {
	HCRYPTKEY	prikey ;
	std::list< HCRYPTKEY >::iterator keyIt ;

	if( aPriKey != NULL ) {
		//First try to find the key in the list
		for( keyIt = m_tPriKeyList.begin() ; keyIt != m_tPriKeyList.end() ; keyIt ++ ) {
			if( *keyIt == aPriKey )
				return ;
		}

		//If we do not find the key in the list, add a new node
		/*- Replaced with directly adopt for WINNT 4.0 support ----
		if( !CryptDuplicateKey( aPriKey, NULL, 0, &prikey ) )
			throw RuntimeException() ;
		----*/
		prikey = aPriKey ;

		try {
			m_tPriKeyList.push_back( prikey ) ;
		} catch ( Exception& ) {
			CryptDestroyKey( prikey ) ;
		}
	}
}

void SecurityEnvironment_MSCryptImpl :: rejectPriKey( HCRYPTKEY aPriKey ) throw( Exception , RuntimeException ) {
	HCRYPTKEY	prikey ;
	std::list< HCRYPTKEY >::iterator keyIt ;

	if( aPriKey != NULL ) {
		for( keyIt = m_tPriKeyList.begin() ; keyIt != m_tPriKeyList.end() ; keyIt ++ ) {
			if( *keyIt == aPriKey ) {
				prikey = *keyIt ;
				CryptDestroyKey( prikey ) ;
				m_tPriKeyList.erase( keyIt ) ;
				break ;
			}
		}
	}
}

HCRYPTKEY SecurityEnvironment_MSCryptImpl :: getPriKey( unsigned int position ) throw( Exception , RuntimeException ) {
	HCRYPTKEY prikey ;
	std::list< HCRYPTKEY >::iterator keyIt ;
	unsigned int pos ;

	prikey = NULL ;
	for( pos = 0, keyIt = m_tPriKeyList.begin() ; pos < position && keyIt != m_tPriKeyList.end() ; pos ++ , keyIt ++ ) ;

	if( pos == position && keyIt != m_tPriKeyList.end() )
		prikey = *keyIt ;

	return prikey ;
}

//Methods from XSecurityEnvironment
Sequence< Reference < XCertificate > > SecurityEnvironment_MSCryptImpl :: getPersonalCertificates() throw( SecurityException , RuntimeException ) 
{
	sal_Int32 length ;
	X509Certificate_MSCryptImpl* xcert ;
	std::list< X509Certificate_MSCryptImpl* > certsList ;
	PCCERT_CONTEXT pCertContext = NULL;

	//firstly, we try to find private keys in given key store.
	if( m_hKeyStore != NULL ) {
		pCertContext = CertEnumCertificatesInStore( m_hKeyStore, pCertContext );
		while (pCertContext)
        {
			xcert = MswcryCertContextToXCert( pCertContext ) ;
			if( xcert != NULL )
				certsList.push_back( xcert ) ;
            pCertContext = CertEnumCertificatesInStore( m_hKeyStore, pCertContext );
		}
	}

	//secondly, we try to find certificate from registered private keys.
	if( !m_tPriKeyList.empty()  ) {
		//TODO: Don't know whether or not it is necessary ans possible.
	}

	//Thirdly, we try to find certificate from system default key store.
	if( m_bEnableDefault ) {
		HCERTSTORE hSystemKeyStore ;
		DWORD      dwKeySpec;
		HCRYPTPROV hCryptProv;

		/*
		hSystemKeyStore = CertOpenStore(
				CERT_STORE_PROV_SYSTEM ,
				0 ,
				NULL ,
				CERT_SYSTEM_STORE_CURRENT_USER | CERT_STORE_READONLY_FLAG | CERT_STORE_OPEN_EXISTING_FLAG ,
				L"MY"
			) ;
		*/
		hSystemKeyStore = CertOpenSystemStore( 0, "MY" ) ;
		if( hSystemKeyStore != NULL ) {
			pCertContext = CertEnumCertificatesInStore( hSystemKeyStore, pCertContext );
			while (pCertContext)
            {
				// Add By CP for checking whether the certificate is a personal certificate or not.
				if(!(CryptAcquireCertificatePrivateKey(pCertContext,
						CRYPT_ACQUIRE_COMPARE_KEY_FLAG,
						NULL,
						&hCryptProv,
						&dwKeySpec,
						NULL)))
				{
					// Not Privatekey found. SKIP this one; By CP
                    pCertContext = CertEnumCertificatesInStore( hSystemKeyStore, pCertContext );
					continue;
				}
				// then TODO : Check the personal cert is valid or not.

				// end CP
				xcert = MswcryCertContextToXCert( pCertContext ) ;
				if( xcert != NULL )
					certsList.push_back( xcert ) ;
                pCertContext = CertEnumCertificatesInStore( hSystemKeyStore, pCertContext );
			}
		}

		CertCloseStore( hSystemKeyStore, CERT_CLOSE_STORE_CHECK_FLAG ) ;
	}

	length = certsList.size() ;
	if( length != 0 ) {
		int i ;
		std::list< X509Certificate_MSCryptImpl* >::iterator xcertIt ;
		Sequence< Reference< XCertificate > > certSeq( length ) ;

		for( i = 0, xcertIt = certsList.begin(); xcertIt != certsList.end(); xcertIt ++, i++ ) {
			certSeq[i] = *xcertIt ;
		}

		return certSeq ;
	}

	return Sequence< Reference< XCertificate > >() ;
}


Reference< XCertificate > SecurityEnvironment_MSCryptImpl :: getCertificate( const OUString& issuerName, const Sequence< sal_Int8 >& serialNumber ) throw( SecurityException , RuntimeException ) {
	unsigned int i ;
//	sal_Int8 found = 0 ;
	LPSTR	pszName ;
	X509Certificate_MSCryptImpl *xcert = NULL ;
	PCCERT_CONTEXT pCertContext = NULL ;
	HCERTSTORE hCertStore = NULL ;
	CRYPT_INTEGER_BLOB cryptSerialNumber ;
	CERT_INFO certInfo ;

	// By CP , for correct encoding
	sal_uInt16 encoding ;
	rtl_Locale *pLocale = NULL ;
	osl_getProcessLocale( &pLocale ) ;
	encoding = osl_getTextEncodingFromLocale( pLocale ) ;
	// CP end

	//Create cert info from issue and serial
	rtl::OString oissuer = rtl::OUStringToOString( issuerName , encoding ) ;
	pszName = ( char* )oissuer.getStr() ;

	if( ! ( CertStrToName(
		X509_ASN_ENCODING | PKCS_7_ASN_ENCODING ,
		pszName ,
		CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG | CERT_NAME_STR_ENABLE_UTF8_UNICODE_FLAG,
		NULL ,
		NULL ,
		&certInfo.Issuer.cbData, NULL ) )
	) {
		return NULL ;
	}

    certInfo.Issuer.pbData = ( BYTE* )malloc( certInfo.Issuer.cbData );
	if(!certInfo.Issuer.pbData)
		throw RuntimeException() ;

	if( ! ( CertStrToName(
		X509_ASN_ENCODING | PKCS_7_ASN_ENCODING ,
		pszName ,
		CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG | CERT_NAME_STR_ENABLE_UTF8_UNICODE_FLAG,
		NULL ,
		( BYTE* )certInfo.Issuer.pbData ,
		&certInfo.Issuer.cbData, NULL ) )
	) {
		free( certInfo.Issuer.pbData ) ;
		return NULL ;
	}

	//Get the SerialNumber
	cryptSerialNumber.cbData = serialNumber.getLength() ;
    cryptSerialNumber.pbData = ( BYTE* )malloc( cryptSerialNumber.cbData); 
	if (!cryptSerialNumber.pbData) 
	{
		free( certInfo.Issuer.pbData ) ;
		throw RuntimeException() ;
	}
	for( i = 0; i < cryptSerialNumber.cbData; i ++ )
		cryptSerialNumber.pbData[i] = serialNumber[ cryptSerialNumber.cbData - i - 1 ] ;

	certInfo.SerialNumber.cbData = cryptSerialNumber.cbData ;
	certInfo.SerialNumber.pbData = cryptSerialNumber.pbData ;
		
	// Get the Cert from all store.
	for( i = 0 ; i < 6 ; i ++ )
	{
		switch(i)
		{
		case 0:
			if(m_hKeyStore == NULL) continue ;
			hCertStore = m_hKeyStore ;
			break;
		case 1:
			if(m_hCertStore == NULL) continue ;
			hCertStore = m_hCertStore ;
			break;
		case 2:
			hCertStore = CertOpenSystemStore( 0, "MY" ) ;
			if(hCertStore == NULL || !m_bEnableDefault) continue ;
			break;
		case 3:
			hCertStore = CertOpenSystemStore( 0, "Root" ) ;
			if(hCertStore == NULL || !m_bEnableDefault) continue ;
			break;
		case 4:
			hCertStore = CertOpenSystemStore( 0, "Trust" ) ;
			if(hCertStore == NULL || !m_bEnableDefault) continue ;
			break;
		case 5:
			hCertStore = CertOpenSystemStore( 0, "CA" ) ;
			if(hCertStore == NULL || !m_bEnableDefault) continue ;
			break;
		default:
			i=6;
			continue;
		}

/******************************************************************************* 
 * This code reserved for remind us there are another way to find one cert by 
 * IssuerName&serialnumber. You can use the code to replaced the function 
 * CertFindCertificateInStore IF and ONLY IF you must find one special cert in
 * certStore but can not be found by CertFindCertificateInStore , then , you 
 * should also change the same part in libxmlsec/.../src/mscrypto/x509vfy.c#875.
 * By Chandler Peng(chandler.peng@sun.com)
 *****/
/*******************************************************************************
		pCertContext = NULL ;
		found = 0;
		do{
			//	1. enum the certs has same string in the issuer string.
			pCertContext = CertEnumCertificatesInStore( hCertStore , pCertContext ) ;
			if( pCertContext != NULL )
			{
				// 2. check the cert's issuer name .
				char* issuer = NULL ;
				DWORD cbIssuer = 0 ;

				cbIssuer = CertNameToStr(
					X509_ASN_ENCODING | PKCS_7_ASN_ENCODING ,
					&( pCertContext->pCertInfo->Issuer ),
					CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG ,
					NULL, 0
				) ;
				
				if( cbIssuer == 0 ) continue ; // discard this cert;

				issuer = (char *)malloc( cbIssuer ) ;
				if( issuer == NULL )  // discard this cert;
				{
					free( cryptSerialNumber.pbData) ;
					free( certInfo.Issuer.pbData ) ;
					CertFreeCertificateContext( pCertContext ) ;
					if(i != 0 && i != 1) CertCloseStore( hCertStore, CERT_CLOSE_STORE_CHECK_FLAG ) ;
					throw RuntimeException() ;
				}

				cbIssuer = CertNameToStr(
					X509_ASN_ENCODING | PKCS_7_ASN_ENCODING ,
					&( pCertContext->pCertInfo->Issuer ),
					CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG ,
					issuer, cbIssuer
				) ;

				if( cbIssuer <= 0 )
				{
					free( issuer ) ;
					continue ;// discard this cert;
				}

				if(strncmp(pszName , issuer , cbIssuer) != 0) 
				{
					free( issuer ) ;
					continue ;// discard this cert;
				}
				free( issuer ) ;

				// 3. check the serial number.
				if( memcmp( cryptSerialNumber.pbData , pCertContext->pCertInfo->SerialNumber.pbData  , cryptSerialNumber.cbData ) != 0 )
				{
					continue ;// discard this cert;
				}

				// 4. confirm and break;
				found = 1;
				break ;
			}

		}while(pCertContext);
		
		if(i != 0 && i != 1) CertCloseStore( hCertStore, CERT_CLOSE_STORE_CHECK_FLAG ) ;
		if( found != 0 ) break; // Found the certificate.
********************************************************************************/

		pCertContext = CertFindCertificateInStore(
			hCertStore,
			X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
			0,
			CERT_FIND_SUBJECT_CERT,
			&certInfo,
			NULL
		) ;
	
		if(i != 0 && i != 1) CertCloseStore( hCertStore, CERT_CLOSE_STORE_CHECK_FLAG ) ;
		if( pCertContext != NULL ) break ; // Found the certificate.

	}

	if( cryptSerialNumber.pbData ) free( cryptSerialNumber.pbData ) ;
	if( certInfo.Issuer.pbData ) free( certInfo.Issuer.pbData ) ;

	if( pCertContext != NULL ) {
		xcert = MswcryCertContextToXCert( pCertContext ) ;
		if( pCertContext ) CertFreeCertificateContext( pCertContext ) ;
	} else {
		xcert = NULL ;
	}

	return xcert ;
}

Reference< XCertificate > SecurityEnvironment_MSCryptImpl :: getCertificate( const OUString& issuerName, const OUString& serialNumber ) throw( SecurityException , RuntimeException ) {
	Sequence< sal_Int8 > serial = numericStringToBigInteger( serialNumber ) ;
	return getCertificate( issuerName, serial ) ;
}

Sequence< Reference < XCertificate > > SecurityEnvironment_MSCryptImpl :: buildCertificatePath( const Reference< XCertificate >& begin ) throw( SecurityException , RuntimeException ) {
	PCCERT_CHAIN_CONTEXT pChainContext ;
	PCCERT_CONTEXT pCertContext ;
	const X509Certificate_MSCryptImpl* xcert ;

	CERT_ENHKEY_USAGE	enhKeyUsage ;
	CERT_USAGE_MATCH	certUsage ;
	CERT_CHAIN_PARA		chainPara ;

	enhKeyUsage.cUsageIdentifier = 0 ;
	enhKeyUsage.rgpszUsageIdentifier = NULL ;
	certUsage.dwType = USAGE_MATCH_TYPE_AND ;
	certUsage.Usage = enhKeyUsage ;
	chainPara.cbSize = sizeof( CERT_CHAIN_PARA ) ;
	chainPara.RequestedUsage = certUsage ;

	Reference< XUnoTunnel > xCertTunnel( begin, UNO_QUERY ) ;
	if( !xCertTunnel.is() ) {
		throw RuntimeException() ;
	}

	xcert = ( X509Certificate_MSCryptImpl* )xCertTunnel->getSomething( X509Certificate_MSCryptImpl::getUnoTunnelId() ) ;
	if( xcert == NULL ) {
		throw RuntimeException() ;
	}

	pCertContext = xcert->getMswcryCert() ;

	pChainContext = NULL ;

    BOOL bChain = FALSE;
    if( pCertContext != NULL )
    {
        HCERTSTORE hAdditionalStore = NULL;
        HCERTSTORE hCollectionStore = NULL;
        if (m_hCertStore && m_hKeyStore)
        {
            //Merge m_hCertStore and m_hKeyStore into one store.
            hCollectionStore = CertOpenStore(
				CERT_STORE_PROV_COLLECTION ,
				0 ,
				NULL ,
				0 ,
				NULL
                ) ;
            if (hCollectionStore != NULL)
            {
                CertAddStoreToCollection (
 					hCollectionStore ,
 					m_hCertStore ,
 					CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG ,
 					0) ;
                CertAddStoreToCollection (
 					hCollectionStore ,
 					m_hCertStore ,
 					CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG ,
 					0) ;
                hAdditionalStore = hCollectionStore;
            }

        }

        //if the merge of both stores failed then we add only m_hCertStore
        if (hAdditionalStore == NULL && m_hCertStore)
            hAdditionalStore = m_hCertStore;
        else if (hAdditionalStore == NULL && m_hKeyStore)
            hAdditionalStore = m_hKeyStore;
        else
            hAdditionalStore = NULL;

        //CertGetCertificateChain searches by default in MY, CA, ROOT and TRUST
    	bChain = CertGetCertificateChain(
		    NULL ,
		    pCertContext ,
		    NULL , //use current system time
		    hAdditionalStore,
		    &chainPara ,
		    CERT_CHAIN_REVOCATION_CHECK_CHAIN | CERT_CHAIN_TIMESTAMP_TIME ,
		    NULL ,
		    &pChainContext);
        if (!bChain)
			pChainContext = NULL;
		
        //Close the additional store
       CertCloseStore(hCollectionStore, CERT_CLOSE_STORE_CHECK_FLAG);
    }

	if(bChain &&  pChainContext != NULL && pChainContext->cChain > 0 )
    {
		PCCERT_CONTEXT pCertInChain ;
		PCERT_SIMPLE_CHAIN pCertChain ;
		X509Certificate_MSCryptImpl* pCert ;

		pCertChain = pChainContext->rgpChain[0] ;
		if( pCertChain->cElement ) {
			Sequence< Reference< XCertificate > > xCertChain( pCertChain->cElement ) ;

			for( unsigned int i = 0 ; i < pCertChain->cElement ; i ++ ) {
				if( pCertChain->rgpElement[i] )
					pCertInChain = pCertChain->rgpElement[i]->pCertContext ;
				else
					pCertInChain = NULL ;

				if( pCertInChain != NULL ) {
					pCert = MswcryCertContextToXCert( pCertInChain ) ;
					if( pCert != NULL )
						xCertChain[i] = pCert ;
				}
			}

			CertFreeCertificateChain( pChainContext ) ;
			pChainContext = NULL ;

			return xCertChain ;
		}
	}
    if (pChainContext)
        CertFreeCertificateChain(pChainContext);

	return Sequence< Reference < XCertificate > >();
}

Reference< XCertificate > SecurityEnvironment_MSCryptImpl :: createCertificateFromRaw( const Sequence< sal_Int8 >& rawCertificate ) throw( SecurityException , RuntimeException ) {
	X509Certificate_MSCryptImpl* xcert ;

	if( rawCertificate.getLength() > 0 ) {
		xcert = new X509Certificate_MSCryptImpl() ;
		if( xcert == NULL )
			throw RuntimeException() ;

		xcert->setRawCert( rawCertificate ) ;
	} else {
		xcert = NULL ;
	}

	return xcert ;
}

Reference< XCertificate > SecurityEnvironment_MSCryptImpl :: createCertificateFromAscii( const OUString& asciiCertificate ) throw( SecurityException , RuntimeException ) {
	xmlChar* chCert ;
	xmlSecSize certSize ;

	rtl::OString oscert = rtl::OUStringToOString( asciiCertificate , RTL_TEXTENCODING_ASCII_US ) ;

	chCert = xmlStrndup( ( const xmlChar* )oscert.getStr(), ( int )oscert.getLength() ) ;

	certSize = xmlSecBase64Decode( chCert, ( xmlSecByte* )chCert, xmlStrlen( chCert ) ) ;

	Sequence< sal_Int8 > rawCert( certSize ) ;
	for( unsigned int i = 0 ; i < certSize ; i ++ )
		rawCert[i] = *( chCert + i ) ;

	xmlFree( chCert ) ;

	return createCertificateFromRaw( rawCert ) ;
}


HCERTSTORE getCertStoreForIntermediatCerts(
    const Sequence< Reference< ::com::sun::star::security::XCertificate > >& seqCerts)
{
    HCERTSTORE store = NULL;
    store = CertOpenStore(
        CERT_STORE_PROV_MEMORY, 0, NULL, 0, NULL);
    if (store == NULL)
        return NULL;

    for (int i = 0; i < seqCerts.getLength(); i++)
    {
        xmlsec_trace("Added temporary certificate: \n%s",
                     OUStringToOString(seqCerts[i]->getSubjectName(),
                                       osl_getThreadTextEncoding()).getStr());


        Sequence<sal_Int8> data = seqCerts[i]->getEncoded();
        PCCERT_CONTEXT cert = CertCreateCertificateContext(
            X509_ASN_ENCODING, ( const BYTE* )&data[0], data.getLength());
        //Adding the certificate creates a copy and not just increases the ref count
        //Therefore we free later the certificate that we now add
        CertAddCertificateContextToStore(store, cert, CERT_STORE_ADD_ALWAYS, NULL);
        CertFreeCertificateContext(cert);
    }
    return store;
}

//We return only valid or invalid, as long as the API documentation expresses
//explicitly that all validation steps are carried out even if one or several
//errors occur. See also
//http://wiki.services.openoffice.org/wiki/Certificate_Path_Validation#Validation_status
sal_Int32 SecurityEnvironment_MSCryptImpl :: verifyCertificate( 
    const Reference< ::com::sun::star::security::XCertificate >& aCert,
    const Sequence< Reference< ::com::sun::star::security::XCertificate > >& seqCerts) 
    throw( ::com::sun::star::uno::SecurityException, ::com::sun::star::uno::RuntimeException ) 
{
	sal_Int32 validity = 0;
	PCCERT_CHAIN_CONTEXT pChainContext = NULL;
	PCCERT_CONTEXT pCertContext = NULL;
	const X509Certificate_MSCryptImpl* xcert = NULL;
    
	Reference< XUnoTunnel > xCertTunnel( aCert, UNO_QUERY ) ;
	if( !xCertTunnel.is() ) {
		throw RuntimeException() ;
	}

    xmlsec_trace("Start verification of certificate: \n %s",
                 OUStringToOString(
                     aCert->getSubjectName(), osl_getThreadTextEncoding()).getStr());

	xcert = ( X509Certificate_MSCryptImpl* )xCertTunnel->getSomething( X509Certificate_MSCryptImpl::getUnoTunnelId() ) ;
	if( xcert == NULL ) {
		throw RuntimeException() ;
	}
    
	pCertContext = xcert->getMswcryCert() ;

	CERT_ENHKEY_USAGE	enhKeyUsage ;
	CERT_USAGE_MATCH	certUsage ;
	CERT_CHAIN_PARA		chainPara ;
    rtl_zeroMemory(&chainPara, sizeof(CERT_CHAIN_PARA));
    
    //Prepare parameter for CertGetCertificateChain
	enhKeyUsage.cUsageIdentifier = 0 ;
	enhKeyUsage.rgpszUsageIdentifier = NULL ;
	certUsage.dwType = USAGE_MATCH_TYPE_AND ;
	certUsage.Usage = enhKeyUsage ;
	chainPara.cbSize = sizeof( CERT_CHAIN_PARA ) ;
	chainPara.RequestedUsage = certUsage ;


    HCERTSTORE hCollectionStore = NULL;
    HCERTSTORE hIntermediateCertsStore = NULL;
	BOOL bChain = FALSE;
	if( pCertContext != NULL )
    {
        hIntermediateCertsStore =
            getCertStoreForIntermediatCerts(seqCerts);

        //Merge m_hCertStore and m_hKeyStore and the store of the intermediate 
        //certificates into one store.
        hCollectionStore = CertOpenStore(
			CERT_STORE_PROV_COLLECTION ,
			0 ,
			NULL ,
			0 ,
			NULL
            ) ;
        if (hCollectionStore != NULL)
        {
            CertAddStoreToCollection (
				hCollectionStore ,
				m_hCertStore ,
				CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG ,
				0) ;
            CertAddStoreToCollection (
				hCollectionStore ,
				m_hCertStore ,
				CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG ,
				0) ;
            CertAddStoreToCollection (
                hCollectionStore,
                hIntermediateCertsStore,
                CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG,
                0);
                
        }
        
        //CertGetCertificateChain searches by default in MY, CA, ROOT and TRUST
        //We do not check revocation of the root. In most cases there are none.
        //Then we would get CERT_TRUST_REVOCATION_STATUS_UNKNOWN
        xmlsec_trace("Verifying cert using revocation information.");
        bChain = CertGetCertificateChain(
            NULL ,
            pCertContext ,
            NULL , //use current system time
            hCollectionStore,
            &chainPara ,
            CERT_CHAIN_REVOCATION_CHECK_CHAIN | CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT, 
            NULL ,
        	&pChainContext);

        if (bChain && pChainContext->cChain > 0)
        {
            xmlsec_trace("Overall error status (all chains):");
            traceTrustStatus(pChainContext->TrustStatus.dwErrorStatus);
            //highest quality chains come first
            PCERT_SIMPLE_CHAIN pSimpleChain = pChainContext->rgpChain[0];
            xmlsec_trace("Error status of first chain: ");
            traceTrustStatus(pSimpleChain->TrustStatus.dwErrorStatus);

            //CERT_TRUST_REVOCATION_STATUS_UNKNOWN is also set if a certificate
            //has no AIA(OCSP) or CRLDP extension and there is no CRL locally installed.
            DWORD revocationFlags = CERT_TRUST_REVOCATION_STATUS_UNKNOWN |
                CERT_TRUST_IS_OFFLINE_REVOCATION;
            DWORD otherErrorsMask = ~revocationFlags;
            if( !(pSimpleChain->TrustStatus.dwErrorStatus & otherErrorsMask))

            {
                //No errors except maybe those caused by missing revocation information
                //Check if there are errors
                if ( pSimpleChain->TrustStatus.dwErrorStatus & revocationFlags)
                {
                    //No revocation information. Because MSDN documentation is not
                    //clear about if all other tests are performed if an error occurrs,
                    //we test again, without requiring revocation checking.
                    CertFreeCertificateChain(pChainContext);
                    pChainContext = NULL;
                    xmlsec_trace("Checking again but without requiring revocation information.");
                    bChain = CertGetCertificateChain(
                        NULL ,
                        pCertContext ,
                        NULL , //use current system time
                        hCollectionStore,
                        &chainPara ,
                        0,
                        NULL ,
                        &pChainContext);
                    if (bChain
                        && pChainContext->cChain > 0
                        && pChainContext->rgpChain[0]->TrustStatus.dwErrorStatus == CERT_TRUST_NO_ERROR)
                    {
                        xmlsec_trace("Certificate is valid.\n");
                        validity = ::com::sun::star::security::CertificateValidity::VALID;
                    }
                    else
                    {
                        xmlsec_trace("Certificate is invalid.\n");
                    }
                }
                else
                {
                    //valid and revocation information available
                    xmlsec_trace("Certificate is valid.\n");
                    validity = ::com::sun::star::security::CertificateValidity::VALID;
                }
            }
            else
            {
                //invalid
                xmlsec_trace("Certificate is invalid.\n");
                validity = ::com::sun::star::security::CertificateValidity::INVALID ;
            }
        }
        else
        {
            xmlsec_trace("CertGetCertificateChaine failed.\n");
        }
    }

    if (pChainContext)
    {
        CertFreeCertificateChain(pChainContext);
        pChainContext = NULL;
    }

    //Close the additional store, do not destroy the contained certs
    CertCloseStore(hCollectionStore, CERT_CLOSE_STORE_CHECK_FLAG);
    //Close the temporary store containing the intermediate certificates and make
    //sure all certificates are deleted.
    CertCloseStore(hIntermediateCertsStore, CERT_CLOSE_STORE_CHECK_FLAG);

	return validity ;
}

sal_Int32 SecurityEnvironment_MSCryptImpl :: getCertificateCharacters( const ::com::sun::star::uno::Reference< ::com::sun::star::security::XCertificate >& aCert ) throw( ::com::sun::star::uno::SecurityException, ::com::sun::star::uno::RuntimeException ) {
	sal_Int32 characters ;
	PCCERT_CONTEXT pCertContext ;
	const X509Certificate_MSCryptImpl* xcert ;

	Reference< XUnoTunnel > xCertTunnel( aCert, UNO_QUERY ) ;
	if( !xCertTunnel.is() ) {
		throw RuntimeException() ;
	}

	xcert = ( X509Certificate_MSCryptImpl* )xCertTunnel->getSomething( X509Certificate_MSCryptImpl::getUnoTunnelId() ) ;
	if( xcert == NULL ) {
		throw RuntimeException() ;
	}

	pCertContext = xcert->getMswcryCert() ;

	characters = 0x00000000 ;

	//Firstly, make sentence whether or not the cert is self-signed.
	if( CertCompareCertificateName( X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, &(pCertContext->pCertInfo->Subject), &(pCertContext->pCertInfo->Issuer) ) ) {
		characters |= ::com::sun::star::security::CertificateCharacters::SELF_SIGNED ;
	} else {
		characters &= ~ ::com::sun::star::security::CertificateCharacters::SELF_SIGNED ;
	}

	//Secondly, make sentence whether or not the cert has a private key.
	{
		BOOL	fCallerFreeProv ;
		DWORD	dwKeySpec ;
		HCRYPTPROV	hProv ;
		if( CryptAcquireCertificatePrivateKey( pCertContext ,
				   0 ,
				   NULL ,
				   &( hProv ) ,
				   &( dwKeySpec ) ,
				   &( fCallerFreeProv ) )
		) {
			characters |=  ::com::sun::star::security::CertificateCharacters::HAS_PRIVATE_KEY ;

			if( hProv != NULL && fCallerFreeProv )
				CryptReleaseContext( hProv, 0 ) ;
		} else {
			characters &= ~ ::com::sun::star::security::CertificateCharacters::HAS_PRIVATE_KEY ;
		}
	}
	return characters ;
}

void SecurityEnvironment_MSCryptImpl :: enableDefaultCrypt( sal_Bool enable ) throw( Exception, RuntimeException ) {
	m_bEnableDefault = enable ;
}

sal_Bool SecurityEnvironment_MSCryptImpl :: defaultEnabled() throw( Exception, RuntimeException ) {
	return m_bEnableDefault ;
}

X509Certificate_MSCryptImpl* MswcryCertContextToXCert( PCCERT_CONTEXT cert )
{
	X509Certificate_MSCryptImpl* xcert ;

	if( cert != NULL ) {
		xcert = new X509Certificate_MSCryptImpl() ;
		if( xcert != NULL ) {
			xcert->setMswcryCert( cert ) ;
		}
	} else {
		xcert = NULL ;
	}

	return xcert ;
}

::rtl::OUString SecurityEnvironment_MSCryptImpl::getSecurityEnvironmentInformation() throw( ::com::sun::star::uno::RuntimeException )
{
	return rtl::OUString::createFromAscii("Microsoft Crypto API");
}

/* Native methods */
xmlSecKeysMngrPtr SecurityEnvironment_MSCryptImpl :: createKeysManager() throw( Exception, RuntimeException ) {

	unsigned int i ;
	HCRYPTKEY symKey ;
	HCRYPTKEY pubKey ;
	HCRYPTKEY priKey ;
	xmlSecKeysMngrPtr pKeysMngr = NULL ;

	/*-
	 * The following lines is based on the of xmlsec-mscrypto crypto engine
	 */
	pKeysMngr = xmlSecMSCryptoAppliedKeysMngrCreate( m_hKeyStore , m_hCertStore ) ;
	if( pKeysMngr == NULL )
		throw RuntimeException() ;

	/*-
	 * Adopt symmetric key into keys manager
	 */
	for( i = 0 ; ( symKey = getSymKey( i ) ) != NULL ; i ++ ) {
		if( xmlSecMSCryptoAppliedKeysMngrSymKeyLoad( pKeysMngr, symKey ) < 0 ) {
			throw RuntimeException() ;
		}
	}

	/*-
	 * Adopt asymmetric public key into keys manager
	 */
	for( i = 0 ; ( pubKey = getPubKey( i ) ) != NULL ; i ++ ) {
		if( xmlSecMSCryptoAppliedKeysMngrPubKeyLoad( pKeysMngr, pubKey ) < 0 ) {
			throw RuntimeException() ;
		}
	}

	/*-
	 * Adopt asymmetric private key into keys manager
	 */
	for( i = 0 ; ( priKey = getPriKey( i ) ) != NULL ; i ++ ) {
		if( xmlSecMSCryptoAppliedKeysMngrPriKeyLoad( pKeysMngr, priKey ) < 0 ) {
			throw RuntimeException() ;
		}
	}

	/*-
	 * Adopt system default certificate store.
	 */
	if( defaultEnabled() ) {
		//Add system key store into the keys manager.
		m_hMySystemStore = CertOpenSystemStore( 0, "MY" ) ;
		if( m_hMySystemStore != NULL ) {
			if( xmlSecMSCryptoAppliedKeysMngrAdoptKeyStore( pKeysMngr, m_hMySystemStore ) < 0 ) {
				CertCloseStore( m_hMySystemStore, CERT_CLOSE_STORE_CHECK_FLAG ) ;
				m_hMySystemStore = NULL;
				throw RuntimeException() ;
			}
		}

		//Add system root store into the keys manager.
		m_hRootSystemStore = CertOpenSystemStore( 0, "Root" ) ;
		if( m_hRootSystemStore != NULL ) {
			if( xmlSecMSCryptoAppliedKeysMngrAdoptTrustedStore( pKeysMngr, m_hRootSystemStore ) < 0 ) {
				CertCloseStore( m_hRootSystemStore, CERT_CLOSE_STORE_CHECK_FLAG ) ;
				m_hRootSystemStore = NULL;
				throw RuntimeException() ;
			}
		}

		//Add system trusted store into the keys manager.
		m_hTrustSystemStore = CertOpenSystemStore( 0, "Trust" ) ;
		if( m_hTrustSystemStore != NULL ) {
			if( xmlSecMSCryptoAppliedKeysMngrAdoptUntrustedStore( pKeysMngr, m_hTrustSystemStore ) < 0 ) {
				CertCloseStore( m_hTrustSystemStore, CERT_CLOSE_STORE_CHECK_FLAG ) ;
				m_hTrustSystemStore = NULL;
				throw RuntimeException() ;
			}
		}

		//Add system CA store into the keys manager.
		m_hCaSystemStore = CertOpenSystemStore( 0, "CA" ) ;
		if( m_hCaSystemStore != NULL ) {
			if( xmlSecMSCryptoAppliedKeysMngrAdoptUntrustedStore( pKeysMngr, m_hCaSystemStore ) < 0 ) {
				CertCloseStore( m_hCaSystemStore, CERT_CLOSE_STORE_CHECK_FLAG ) ;
				m_hCaSystemStore = NULL;
				throw RuntimeException() ;
			}
		}
	}

	return pKeysMngr ;
}
void SecurityEnvironment_MSCryptImpl :: destroyKeysManager(xmlSecKeysMngrPtr pKeysMngr) throw( Exception, RuntimeException ) {
	if( pKeysMngr != NULL ) {
		xmlSecKeysMngrDestroy( pKeysMngr ) ;
	}
}
