/*

The contents of this file are subject to the Mozilla Public License
Version 1.1 (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.mozilla.org/MPL/

Software distributed under the License is distributed on an "AS IS"
basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
License for the specific language governing rights and limitations
under the License.

The Original Code is a portion of the Path Development API developed
by CygnaCom Solutions, Inc.

Portions created by CygnaCom Solutions, Inc. are Copyright (C) CygnaCom 
Solutions, Inc. All Rights Reserved.

Contributor(s): ______________________________________.

*/

/*------------------------------------------------------------------------*\
|  Project Name  :   Path Development API
|  File Name     :   CertsRec.cpp
|  Creation Date :   May 17, 1999
|  Author        :   Matt Cooper (mcooper@cygnacom.com)
|  Last Mode Date:   May 17, 1999
|  Modification History:
|--------------------------------------------------------------------------
|
|     Known Bugs:   None
|                   
|--------------------------------------------------------------------------
| Cryptographic devices and technical data regarding them are subject to
| Federal Government export controls as specified in Title 22, Code of
| Federal Regulations, Parts 121 through 128.  Cryptographic devices
| implementing the Data Encryption Standard (DES) and technical data
| regarding them must comply with these Federal regulations
|--------------------------------------------------------------------------
| Copyright (c) 1999, CygnaCom Solutions, Inc.
| All Rights Reserved.
\*------------------------------------------------------------------------*/

// CertsRec.cpp: implementation of the CCertsRec class.
//
//////////////////////////////////////////////////////////////////////
#if defined(_WIN32)
	#if defined(_AFXDLL)
		#include "stdafx.h"
	#else
		#include "windows.h"
	#endif
#endif

#ifdef VX /* Added by Masanori Satake. */
#include "vxWorks.h"
#include "vxdbg.h"
#ifdef KCM_MEMDBG
#include <stdio.h>
#endif
#endif

#include "CertsRec.h"
#include "cmapi.h"
#include <string.h>
#include "utils.h"
#include "CMAPIInterface.h"

#ifdef VX /* Added by Masanori Satake. */
#ifdef KCM_MEMDBG
extern "C" {
#include "kcmlmlog.h"
}
#endif
#endif

#if !defined(__cplusplus)
	#error C++ compiler required.
#endif

#if defined(_WIN32) && defined(_DEBUG)
	#if !defined(ASSERT)
		#if defined(_ASSERTE)
			#include <crtdbg.h>
			#define ASSERT _ASSERTE
		#else
			#include <assert.h>
			#define ASSERT assert
		#endif
	#endif
#endif

#if !defined(_WIN32)
#include "stristr.h"
#endif

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//#define _DEBUG_VERBOSE

extern CCMAPIInterface *pCMAPIInterface;

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CCertsRec::CCertsRec()
{
	m_lpszKey = NULL;
	NextRec = NULL;
	m_flag = 0;
	m_entryNumber = 0;
	m_lpCerts = NULL;
	m_modified = 0;
	m_searched = 0;
}

#define _SHOW_DESTRUCTOR

CCertsRec::~CCertsRec()
{

#if defined(_DEBUG) && defined(_SHOW_DESTRUCTOR)
#ifdef _WIN32 /* Added by Masanori Satake. */
	afxDump << "CCertsRec::~CCertsRec()\n";
#else /* _UNIX or VX */
	PRINTERR("CCertsRec::~CCertsRec()\n");
#endif /* #ifdef _WIN32 */
#endif

	FreeEntry();

	// Delete chain if it exists
	if ( NextRec != NULL )
	{
		delete NextRec;
		NextRec = NULL;
	}
}

#ifdef _SHOW_DESTRUCTOR
#undef _SHOW_DESTRUCTOR
#endif

/*-------------------------------------------------------------------------*\
|  Function Name :   CCertsRec::operator==
|  Creation Date :   April 12, 1999
|  Author        :   Matt Cooper
|  Last Mode Date:   April 12, 1999
|---------------------------------------------------------------------------
|  Purpose:	Compares key equality for two CCertsRecs
|---------------------------------------------------------------------------
|  Inputs Params:   N/a
|  Return values:   true if same / false if not
\*-------------------------------------------------------------------------*/
bool CCertsRec::operator==(const CCertsRec& other) const
{ 
	char *rec2 = other.get_key();

	if ( CPLI_IsSameDN(rec2,m_lpszKey)  )
	{
		return true; 
	}
	return false;
}
/*
bool CCertsRec::operator==(const CCertsRec *other)
{ 
	char *rec2 = other->get_key();

//	if ( strcmp(rec2,m_lpszKey) == 0 )
	{
		return true; 
	}
	return false;
}
*/

/*-------------------------------------------------------------------------*\
|  Function Name :   CopyFrom
|  Creation Date :   April 12, 1999
|  Author        :   Matt Cooper
|  Last Mode Date:   April 12, 1999
|---------------------------------------------------------------------------
|  Purpose:	Implements copy function required by CMemCache
|---------------------------------------------------------------------------
|  Inputs Params:   ptr to other CCertsRec
\*-------------------------------------------------------------------------*/
void CCertsRec::CopyFrom( CCertsRec *rec )
{
	set_entry( rec->get_key() );
	set_entry( rec->m_lpCerts, rec->get_flag());
	m_entryNumber = rec->m_entryNumber;
	m_modified = -1;
}

/*-------------------------------------------------------------------------*\
|  Function Name :   set_entry
|  Creation Date :   April 12, 1999
|  Author        :   Matt Cooper
|  Last Mode Date:   April 12, 1999
|---------------------------------------------------------------------------
|	        
|  Purpose:	Copies cert list, flag, and rootDN
|	        Sets key from first cert in list
|	        
|  Exception Handling: None
|---------------------------------------------------------------------------
|  Inputs Params:   cert list and flag to copy
|	                
|  Pre-Conditions:  None
|  Post-Conditions: CCertsRec filled
|  Return values:   0 on success
|	                
\*-------------------------------------------------------------------------*/
long CCertsRec::set_entry(LPCERTCACHE_ENTRY_STRUCT lpCertListHead, 
						 unsigned long flag							)
{
	if( NULL == lpCertListHead )
	{
		return CCERTSREC_REQUIRED_PARAM_MISSING;
	}

	// Free existing data, if any
	FreeEntry();

	long rv = 0;
	LPCERTCACHE_ENTRY_STRUCT pCurRec = NULL;
	LPCERTCACHE_ENTRY_STRUCT pHead = lpCertListHead;

	// Copy and parse 1st cert
	rv = CopyEntryStruct(pHead, &pCurRec);
	if( 0 != rv )
	{
		m_lpCerts = NULL;
		return rv;
	}

	// Set this as list head
	m_lpCerts = pCurRec;
	pHead = pHead->pNext;

	// Verify subjectDN exists
	if( NULL == m_lpCerts->pCert->subject )
	{
		return CCERTSREC_INVALID_CERT;
	}

	// Allocate and copy the subjectDN
	m_lpszKey = new char[strlen(m_lpCerts->pCert->subject) + 2];
	if( NULL == m_lpszKey )
	{
		return CCERTSREC_ALLOC_FAIL;
	}
	strcpy(m_lpszKey,m_lpCerts->pCert->subject);
	CPLI_SquashSpacesInDN(m_lpszKey);

	// Copy and parse the remainder of the certs
	while( pHead != NULL )
	{
		rv = CopyEntryStruct(pHead, &pCurRec->pNext);
		if( 0 != rv )
		{
			pCurRec->pNext = NULL;
			return rv;
		}
		pCurRec = pCurRec->pNext;
		pHead = pHead->pNext;
	}

	return 0;
}


/*-------------------------------------------------------------------------*\
|  Function Name :   FreeEntry
|  Creation Date :   April 12, 1999
|  Author        :   Matt Cooper
|  Last Mode Date:   April 12, 1999
|---------------------------------------------------------------------------
|	        
|  Purpose:	Frees all memory associated with the CCertsRec
|	        
|	        
|  Exception Handling: None
|---------------------------------------------------------------------------
|  Inputs Params:   N/a
|  Pre-Conditions:  N/a
|  Post-Conditions: Mem freed
|  Return values:   N/a
\*-------------------------------------------------------------------------*/
void CCertsRec::FreeEntry()
{
	FreeCertList(&m_lpCerts);

	if ( NULL != m_lpszKey )
	{	
		delete []m_lpszKey;
		m_lpszKey = NULL;
	}
}

/*-------------------------------------------------------------------------*\
|  Function Name :   FreeCertList
|  Creation Date :   April 12, 1999
|  Author        :   Matt Cooper
|  Last Mode Date:   April 12, 1999
|---------------------------------------------------------------------------
|	        
|  Purpose:	Frees linked cert list
|	        
|	        
|  Exception Handling: Only in release build
|---------------------------------------------------------------------------
|  Inputs Params:   pointer to cert list
|	                
|  Pre-Conditions:  cert list pointer is valid
|  Post-Conditions: cert list pointer set to NULL
|  Return values:   N/a
|	                
\*-------------------------------------------------------------------------*/
void CCertsRec::FreeCertList(LPCERTCACHE_ENTRY_STRUCT *pListHead)
{

	LPCERTCACHE_ENTRY_STRUCT pListItem = *pListHead;
	LPCERTCACHE_ENTRY_STRUCT pTmp = NULL;

#ifndef VX /* Added by Masanori Satake. */
#if !defined(_DEBUG)
	try
	{
#else
        #ifdef _WIN32 /* Added by Masanori Satake. */
		afxDump << "CCertsRec::FreeCertList(" << *pListHead << ")\n";
        #else /* _UNIX or VX */
		PRINTERR("CCertsRec::FreeCertList(");
		PRINTERR(*pListHead);
		PRINTERR(")\n");
        #endif /* #ifdef _WIN32 */
#endif
#endif
	while( NULL != pListItem )
	{
		// Free cert 
		pCMAPIInterface->FreeCert(&(pListItem->pCert));
		delete []pListItem->binCert.data;

		pTmp = pListItem;
		pListItem = pTmp->pNext;
		delete pTmp;
	}

	*pListHead = NULL;
	
	m_modified = 0;

#ifndef VX /* Added by Masanori Satake. */
#if !defined(_DEBUG)
	}
	catch(...){}
#endif
#endif
}

/*-------------------------------------------------------------------------*\
|  Function Name :   CopyEntryStruct
|  Creation Date :   April 12, 1999
|  Author        :   Matt Cooper
|  Last Mode Date:   April 12, 1999
|---------------------------------------------------------------------------
|	        
|  Purpose:	copies a CERTCACHE_ENTRY_STRUCT
|	        
|	        
|  Exception Handling: None
|---------------------------------------------------------------------------
|  Inputs Params:   LPCERTCACHE_ENTRY_STRUCT to a valid entry
|	                LPCERTCACHE_ENTRY_STRUCT *copy to recieve new struct 
|	                ***  *copy should be NULL!!  ***
|  Pre-Conditions:  input points to valid CERTCACHE_ENTRY_STRUCT
|  Post-Conditions: CERTCACHE_ENTRY_STRUCT alloced and returned in *copy
|  Return values:   0 on success
|	                
\*-------------------------------------------------------------------------*/
long CCertsRec::CopyEntryStruct(LPCERTCACHE_ENTRY_STRUCT input, LPCERTCACHE_ENTRY_STRUCT *copy)
{
	long rv = 0;

	if( NULL == input || NULL == copy )
	{
		return CCERTSREC_REQUIRED_PARAM_MISSING;
	}

	LPCERTCACHE_ENTRY_STRUCT pCopy = NULL;

	*copy = new CERTCACHE_ENTRY_STRUCT;
	if( NULL == *copy )
	{
		return CCERTSREC_ALLOC_FAIL;
	}
	pCopy = *copy;

	pCopy->binCert.num = input->binCert.num;
	pCopy->binCert.data = new unsigned char[pCopy->binCert.num + 2];
	if( NULL == pCopy->binCert.data )
	{
		return CCERTSREC_ALLOC_FAIL;
	}
	memcpy(pCopy->binCert.data,input->binCert.data,pCopy->binCert.num);

	pCopy->flag = input->flag;
	pCopy->pNext = NULL;
	pCopy->type = input->type;

	rv = pCMAPIInterface->DecodeCert(pCopy->binCert.data, &pCopy->pCert );
	if( 0 != rv )
	{
		if( NULL != pCopy->pCert )
		{
			pCMAPIInterface->FreeCert(&pCopy->pCert);
			pCopy->pCert = NULL;
		}
	}

	return rv;
}

long CCertsRec::AddCert(Bytes_struct *pBinCert, long type )
{
	long rv = 0;
	Cert_struct *pCert = NULL;
	LPCERTCACHE_ENTRY_STRUCT pEntry = NULL;
	LPCERTCACHE_ENTRY_STRUCT pParent = NULL;
//	unsigned char *pN1 = NULL, *pN2 = NULL;

#undef RETURN
#ifndef VX /* Added by Masanori Satake. */
#define RETURN(r){if( NULL != pCert ) {	try{ pCMAPIInterface->FreeCert(&pCert); }catch(...){} } if( NULL != pEntry ){	if( NULL != pEntry->binCert.data )	{ 	try	{	delete []pEntry->binCert.data; }	catch(...){}	} 	try{ delete pEntry; }catch(...){}  	if( NULL != pParent ){	pParent->pNext = NULL; } else{	m_lpCerts = NULL; } }  return r; }		
#else
#define RETURN(r){if( NULL != pCert ) {pCMAPIInterface->FreeCert(&pCert);} if( NULL != pEntry ){ if( NULL != pEntry->binCert.data ){delete []pEntry->binCert.data;} delete pEntry; if( NULL != pParent ){ pParent->pNext = NULL; } else{ m_lpCerts = NULL; } }  return r; }		
#endif

	#if defined(_DEBUG) && defined(_DEBUG_VERBOSE)
        #ifdef _WIN32 /* Added by Masanori Satake. */
		afxDump << "CCertsRec::AddCert(" << (void*)pBinCert << "," << type << ")\n";
        #else /* _UNIX or VX */
		PRINTERR("CCertsRec::AddCert(");
		PRINTERR((void *)pBinCert);
		PRINTERR(")\n");
        #endif /* #ifdef _WIN32 */
	#endif

	if( NULL == pBinCert )
	{
		return CCERTSREC_REQUIRED_PARAM_MISSING;
	}

	if( NULL == pBinCert->data || 0 == pBinCert->num )
	{
		return CCERTSREC_REQUIRED_PARAM_MISSING;
	}


	// decode the cert
	rv = pCMAPIInterface->DecodeCert(pBinCert->data, &pCert );
	if( 0 != rv )
	{
		RETURN(rv);
	}

	if( IsBadCert(pCert) )
	{
		RETURN(CCERTSREC_INVALID_CERT);
	}

	if( m_lpszKey == NULL )
	{
		m_lpszKey  = new char[strlen(pCert->subject)+2];
		if( NULL == m_lpszKey )
		{
			RETURN(CCERTSREC_ALLOC_FAIL);
		}
		strcpy(m_lpszKey,pCert->subject);
		CPLI_SquashSpacesInDN(m_lpszKey);
	}
	else if( !CPLI_IsSameDN( m_lpszKey,pCert->subject ) )
	{
		#if defined(_DEBUG) && defined(_DEBUG_VERBOSE)
                #ifdef _WIN32 /* Added by Masanori Satake. */
			afxDump << "\tError: Incorrect subject DN for this record: " << pCert->subject << "\n\tReturning CCERTSREC_INCORRECT_CERT\n";
                #else /* _UNIX or VX */
			PRINTERR("\tError: Incorrect subject DN for this record: ");
			PRINTERR(pCert->subject);
			PRINTERR("\n\tReturning CCERTSREC_INCORRECT_CERT\n");
                #endif /* #ifdef _WIN32 */
		#endif
		RETURN(CCERTSREC_INCORRECT_CERT);
	}

	// Find the end of the cert list, check each cert in list for 
	// duplicate of one being added
	if( NULL != m_lpCerts )
	{
		pEntry = m_lpCerts;
		pParent = pEntry;

		if( pEntry->pCert->serial_num.num == pCert->serial_num.num ) 
		{
			if( CPLI_IsSameDN( pEntry->pCert->issuer, pCert->issuer ) )
			{
				if( 0 == memcmp(pEntry->pCert->serial_num.data,pCert->serial_num.data,pCert->serial_num.num) )
				{
					pEntry = NULL;
					// duplicate cert - no err
					#if defined(_DEBUG) && defined(_DEBUG_VERBOSE)
                                        #ifdef _WIN32 /* Added by Masanori Satake. */
						afxDump << "\tDuplicate cert for " << pCert->subject;
						afxDump << "\n\tIssuer: " << pCert->issuer << "\n";
                                        #else /* _UNIX or VX */
						PRINTERR("\tDuplicate cert for ");
						PRINTERR(pCert->subject);
						PRINTERR("\n\tIssuer: ");
						PRINTERR(pCert->issuer);
						PRINTERR("\n");
                                        #endif /* #ifdef _WIN32 */
					#endif
					RETURN(0);
				}
			}
		}

		while( NULL != pEntry->pNext )
		{
			pEntry = pEntry->pNext;

			if( pEntry->pCert->serial_num.num == pCert->serial_num.num )
			{
				if( CPLI_IsSameDN( pEntry->pCert->issuer, pCert->issuer ) )
				{
					if( 0 == memcmp(pEntry->pCert->serial_num.data,pCert->serial_num.data,pCert->serial_num.num) )
					{
						pEntry = NULL;
						// duplicate cert - no err
						#if defined(_DEBUG) && defined(_DEBUG_VERBOSE)
                                                #ifdef _WIN32 /* Added by Masanori Satake. */
							afxDump << "\tDuplicate cert for " << pCert->subject;
							afxDump << "\n\tIssuer: " << pCert->issuer << "\n";
                                                #else /* _UNIX or VX */
							PRINTERR("\tDuplicate cert for ");
							PRINTERR(pCert->subject);
							PRINTERR("\n\tIssuer: ");
							PRINTERR(pCert->issuer);
							PRINTERR("\n");
                                                #endif /* #ifdef _WIN32 */
						#endif
						RETURN(0);
					}
				}
			}

		}

		pEntry->pNext = new CERTCACHE_ENTRY_STRUCT;
		pParent = pEntry;
		pEntry = pEntry->pNext;
	}
	else
	{
		m_lpCerts = new CERTCACHE_ENTRY_STRUCT;
		pEntry = m_lpCerts;
		pParent = NULL;
	}
	
	if( NULL == pEntry )
	{
		RETURN(CCERTSREC_ALLOC_FAIL);
	}

	pEntry->pNext = NULL;
	pEntry->flag = 0;
	pEntry->type = type;
	// save decoded cert pointer
	pEntry->pCert = pCert;
	pEntry->binCert.num = pBinCert->num;

	pEntry->binCert.data = new unsigned char[pEntry->binCert.num + 2];
	if( NULL == pEntry->binCert.data )
	{
		RETURN(CCERTSREC_ALLOC_FAIL);
	}

	memcpy(pEntry->binCert.data,pBinCert->data, pEntry->binCert.num );

	#if defined(_DEBUG)
		pEntry->binCert.data[pEntry->binCert.num] = 0x00;
	#endif

	#if defined(_DEBUG) && defined(_DEBUG_VERBOSE)
        #ifdef _WIN32 /* Added by Masanori Satake. */
		afxDump << "\tCert added for " << pCert->subject;
		afxDump << "\n\tIssuer: " << pCert->issuer << "\n";
        #else /* _UNIX or VX */
		PRINTERR("\tCert added for ");
		PRINTERR(pCert->subject);
		PRINTERR("\n\tIssuer: ");
		PRINTERR(pCert->issue);
		PRINTERR("\n");
        #endif /* #ifdef _WIN32 */
	#endif

	// MUST set these to null! (See RETURN(r))
	pCert = NULL;
	pEntry = NULL;

	m_modified = -1;


	RETURN(0);
}

// Uses optimal bubble sort - tail moves down on each loop
long CCertsRec::SortCerts(char *trustedRootDN, char **acceptablePolicySet)
{
//CPLI_CompareCertPriority(LPCERTCACHE_ENTRY_STRUCT cert1, LPCERTCACHE_ENTRY_STRUCT cert2, char* trustedRootDN, const char** acceptablePolicySet )

	if( NULL == m_lpCerts )
		return 0;

	if( NULL == m_lpCerts->pNext )
		return 0;

	LPCERTCACHE_ENTRY_STRUCT pCertStruct;
	LPCERTCACHE_ENTRY_STRUCT pTmp;
	LPCERTCACHE_ENTRY_STRUCT pTail = NULL;
	LPCERTCACHE_ENTRY_STRUCT pPrev = NULL;

	BOOL CertsNotSorted = TRUE;
	long rv = 0;
	// int loop = 0;

	while( CertsNotSorted )
	{
		pCertStruct = m_lpCerts;
		CertsNotSorted = FALSE;

		while( NULL != pCertStruct )
		{
			if( NULL == pCertStruct->pNext )
				break;

			rv = CPLI_CompareCertPriority(pCertStruct,pCertStruct->pNext,trustedRootDN,acceptablePolicySet);

			if( 2 == rv )
			{
				if( m_lpCerts == pCertStruct )
				{
					pTmp = m_lpCerts;
					m_lpCerts = m_lpCerts->pNext;
					pTmp->pNext = pTmp->pNext->pNext;
					m_lpCerts->pNext = pTmp;
				}
				else
				{
					pPrev->pNext = pCertStruct->pNext; // set first to point at third cert
					pCertStruct->pNext = pPrev->pNext->pNext; // set new third to point to fourth
					pPrev->pNext->pNext = pCertStruct; // set 2nd to point at third
					// 8/24/99 fixed bug whereas after swap, the swapped cert was not compared
					// with the next cert, rather, the sort skipped ahead to the next cert
					// the line below tagged "see above" sets the cert to the swapped one.
					pCertStruct = pPrev->pNext;
				}

				CertsNotSorted = TRUE;

			}
			else if( 1 != rv )
			{
				// Not good...
				#if defined(_WIN32) && defined(_DEBUG)
						ASSERT(FALSE);
				#endif

				CertsNotSorted = FALSE;
				break;
			}

			rv = 0;

			if( pCertStruct->pNext == pTail )
			{
				pTail = pCertStruct;
				break;
			}

			pPrev = pCertStruct;
			// 8/24/99 - see above
			pCertStruct = pCertStruct->pNext;

		}

	}

	m_modified = 0;

	return rv;
}

long CCertsRec::set_entry(char *subjectDN)
{

	if( NULL == subjectDN )
	{
		return CCERTSREC_REQUIRED_PARAM_MISSING;
	}

	// This function can not be called on records containing
	// certs - AddCert already set the subjectDN
	if( NULL != m_lpCerts )
	{
		#if defined(_WIN32) && defined(_DEBUG)
			ASSERT( NULL == m_lpCerts );
		#endif
		return CCERTSREC_FUNC_INVALID_ON_THIS;
	}

	#if defined(_WIN32)
		if(IsBadStringPtr(subjectDN,1024))
			return CCERTSREC_ADDRESS_INVALID;
	#endif

	#if defined(_WIN32) && defined(_DEBUG)
		ASSERT( 1024 > strlen(subjectDN) );
	#endif

	if( NULL != m_lpszKey )
	{
		delete []m_lpszKey;
		m_lpszKey = NULL;
	}

	// Allocate and copy the subjectDN
	m_lpszKey = new char[strlen(subjectDN) + 2];
	if( NULL == m_lpszKey )
	{
		return CCERTSREC_ALLOC_FAIL;
	}
	strcpy(m_lpszKey,subjectDN);
	CPLI_SquashSpacesInDN(m_lpszKey);


	return 0;
}

// if returns 0 - you will *not* need to free pCert.  pBinCert will copied 
// and still req a delete or free this saves a cert decode and free
long CCertsRec::AddCert(Cert_struct *pCert, Bytes_struct *pBinCert, long type)
{
	long rv = 0;
	LPCERTCACHE_ENTRY_STRUCT pEntry = NULL;
	LPCERTCACHE_ENTRY_STRUCT pParent = NULL;

#ifdef KCM_MEMDBG/* Added by Masanori Satake in '02/03/13. */
	struct Dist_pts_struct	*distPts = NULL;
	struct Gen_names_struct	*genNames = NULL;
	struct Policy_struct	*certPol = NULL;
	struct Pol_maps_struct	*polMaps = NULL;
	struct Qualifier_struct	*qualSt = NULL;
	struct Ext_key_use_LL	*extKeyUse = NULL;
	struct Auth_key_struct	*authKey = NULL;
	struct Unkn_extn_LL	*unknExt = NULL;
#endif

#undef RETURN
#ifndef VX /* Added by Masanori Satake. */
#define RETURN(r){if( NULL != pEntry ){	if( NULL != pEntry->binCert.data )	{ 	try	{	delete []pEntry->binCert.data; }	catch(...){}	} 	try{ delete pEntry; }catch(...){}  	if( NULL != pParent ){	pParent->pNext = NULL; } else{	m_lpCerts = NULL; } 	}  return r; }	
#else
#define RETURN(r){if( NULL != pEntry ){	if( NULL != pEntry->binCert.data ) { delete []pEntry->binCert.data;} delete pEntry; if( NULL != pParent ){ pParent->pNext = NULL; } else{ m_lpCerts = NULL; } }  return r; }	
#endif

	if( NULL == pCert || NULL == pBinCert )
	{
		return CCERTSREC_REQUIRED_PARAM_MISSING;
	}

	if( NULL == pBinCert->data || 0 == pBinCert->num )
	{
		return CCERTSREC_REQUIRED_PARAM_MISSING;
	}


	if( IsBadCert(pCert) )
	{
		RETURN(CCERTSREC_INVALID_CERT);
	}

	if( m_lpszKey == NULL )
	{
		m_lpszKey  = new char[strlen(pCert->subject)+2];
		if( NULL == m_lpszKey )
		{
			RETURN(CCERTSREC_ALLOC_FAIL);
		}
		strcpy(m_lpszKey,pCert->subject);
		CPLI_SquashSpacesInDN(m_lpszKey);
	}
	else if( !CPLI_IsSameDN( m_lpszKey,pCert->subject ) )
	{
		RETURN(CCERTSREC_INCORRECT_CERT);
	}

	// Find the end of the cert list, check each cert in list for 
	// duplicate of one being added
	if( NULL != m_lpCerts )
	{
		pEntry = m_lpCerts;

		if( pEntry->pCert->serial_num.num == pCert->serial_num.num ) 
		{
			if( CPLI_IsSameDN( pEntry->pCert->issuer, pCert->issuer ) )
			{
				if( 0 == memcmp(pEntry->pCert->serial_num.data,pCert->serial_num.data,pCert->serial_num.num) )
				{
					// duplicate cert - no err
					pEntry->type = type;
					pEntry = NULL;
					RETURN(CCERTSREC_DUPLICATE_CERT);
				}
			}
		}

		while( NULL != pEntry->pNext )
		{
			pEntry = pEntry->pNext;

			if( pEntry->pCert->serial_num.num == pCert->serial_num.num )
			{
				if( CPLI_IsSameDN( pEntry->pCert->issuer, pCert->issuer ) )
				{
					if( 0 == memcmp(pEntry->pCert->serial_num.data,pCert->serial_num.data,pCert->serial_num.num) )
					{
						// duplicate cert - no err
						pEntry->type = type;
						pEntry = NULL;
						RETURN(CCERTSREC_DUPLICATE_CERT);
					}
				}
			}

		}

		pEntry->pNext = new CERTCACHE_ENTRY_STRUCT;
		pParent = pEntry;
		pEntry = pEntry->pNext;
	}
	else
	{
		m_lpCerts = new CERTCACHE_ENTRY_STRUCT;
		pEntry = m_lpCerts;
		pParent = NULL;
	}
	
	if( NULL == pEntry )
	{
		RETURN(CCERTSREC_ALLOC_FAIL);
	}

	pEntry->pNext = NULL;
	pEntry->flag = 0;
	pEntry->type = type;
	// save passed cert pointer
	pEntry->pCert = pCert;
	pEntry->binCert.num = pBinCert->num;

#ifdef KCM_MEMDBG
	/*   */
	KcmMLogSetContents(pCert,			"(CPD)CC:pCert");
	KcmMLogSetContents(pCert->serial_num.data,	"(CPD)CC:serial_num.data");
	KcmMLogSetContents(pCert->signature,		"(CPD)CC:signature");
	KcmMLogSetContents(pCert->issuer,		"(CPD)CC:issuer");
	KcmMLogSetContents(pCert->val_not_before,	"(CPD)CC:val_not_before");
	KcmMLogSetContents(pCert->val_not_after,	"(CPD)CC:val_not_after");
	KcmMLogSetContents(pCert->subject,		"(CPD)CC:subject");
	/* PubKey. */
	KcmMLogSetContents(pCert->pub_key.oid,"(CPD)CC:PubKey OID");
	if((strcmp(pCert->pub_key.oid,gDSA_OID) == 0) ||
	   (strcmp(pCert->pub_key.oid,gOIW_DSA) == 0)){
	  KcmMLogSetContents(pCert->pub_key.params.dsa,"(CPD)CC:params dsa");
	  KcmMLogSetContents(pCert->pub_key.params.dsa->p.data,"(CPD)CC:params dsa p.data");
	  KcmMLogSetContents(pCert->pub_key.params.dsa->q.data,"(CPD)CC:params dsa q.data");
	  KcmMLogSetContents(pCert->pub_key.params.dsa->g.data,"(CPD)CC:params dsa g.data");
	  KcmMLogSetContents(pCert->pub_key.key.y,"(CPD)CC:PubKey y");
	  KcmMLogSetContents(pCert->pub_key.key.y->data,"(CPD)CC:PubKey y.data");
	}else if(strcmp(pCert->pub_key.oid,gKEA_OID) == 0){
	  KcmMLogSetContents(pCert->pub_key.params.kea,"(CPD)CC:params kea");
	  KcmMLogSetContents(pCert->pub_key.params.kea->data,"(CPD)CC:params kea");
	  KcmMLogSetContents(pCert->pub_key.key.y,"(CPD)CC:PubKey y");
	  KcmMLogSetContents(pCert->pub_key.key.y->data,"(CPD)CC:PubKey y.data");
	}else if(strcmp(pCert->pub_key.oid,gDH_OID) == 0){
	  KcmMLogSetContents(pCert->pub_key.params.dh,"(CPD)CC:params dh");
	  KcmMLogSetContents(pCert->pub_key.params.dh->data,"(CPD)CC:params dh");
	  KcmMLogSetContents(pCert->pub_key.key.y,"(CPD)CC:PubKey y");
	  KcmMLogSetContents(pCert->pub_key.key.y->data,"(CPD)CC:PubKey y.data");
	}else if(strcmp(pCert->pub_key.oid,gDSA_KEA_OID) == 0){
	  KcmMLogSetContents(pCert->pub_key.key.combo,"(CPD)CC:PubKey combo");
	  KcmMLogSetContents(pCert->pub_key.key.combo->dsa_y.data,"(CPD)CC:Combo DSA y.data");
	  KcmMLogSetContents(pCert->pub_key.key.combo->kea_y.data,"(CPD)CC:Combo KEA y.data");
	  KcmMLogSetContents(pCert->pub_key.key.combo->dsa_privs.data,"(CPD)CC:Combo DSA privs.data");
	  KcmMLogSetContents(pCert->pub_key.key.combo->kea_privs.data,"(CPD)CC:Combo KEA privs.data");
	  KcmMLogSetContents(pCert->pub_key.key.combo->kea_clearance.data,"(CPD)CC:Combo clearance.data");
	  if(pCert->pub_key.key.combo->diff_kea){
	    KcmMLogSetContents(pCert->pub_key.key.combo->diff_kea,"(CPD)CC:Combo diff_kea");
	    KcmMLogSetContents(pCert->pub_key.key.combo->diff_kea->p.data,"(CPD)CC:DiffKea P");
	    KcmMLogSetContents(pCert->pub_key.key.combo->diff_kea->q.data,"(CPD)CC:DiffKea Q");
	    KcmMLogSetContents(pCert->pub_key.key.combo->diff_kea->g.data,"(CPD)CC:DiffKea G");
	  }
	  KcmMLogSetContents(pCert->pub_key.params.dsa_kea,"(CPD)CC:params dsa_kea");
	  KcmMLogSetContents(pCert->pub_key.params.dsa_kea->p.data,"(CPD)CC:params dsa_kea p.data");
	  KcmMLogSetContents(pCert->pub_key.params.dsa_kea->q.data,"(CPD)CC:params dsa_kea q.data");
	  KcmMLogSetContents(pCert->pub_key.params.dsa_kea->g.data,"(CPD)CC:params dsa_kea g.data");
	}else if(strcmp(pCert->pub_key.oid,gRSA_OID) == 0){
	  KcmMLogSetContents(pCert->pub_key.key.rsa,"(CPD)CC:RSA PubKey");
	  KcmMLogSetContents(pCert->pub_key.key.rsa->publicExponent.data,"(CPD)CC:RSA PubExp.data");
	  KcmMLogSetContents(pCert->pub_key.key.rsa->modulus.data,"(CPD)CC:RSA Modulus.data");
	}else{
	  printf("KcmMLogSetAreaInfoToPubKey:unknown.");
	}

	if(pCert->issuer_id){
	  KcmMLogSetContents(pCert->issuer_id,		"(CPD)CC:issID");
	  KcmMLogSetContents(pCert->issuer_id->data,	"(CPD)CC:issID->data");
	}
	if(pCert->subj_id){
	  KcmMLogSetContents(pCert->subj_id,		"(CPD)CC:subjID");
	  KcmMLogSetContents(pCert->subj_id->data,	"(CPD)CC:subjID->data");
	}

	/* Exts */
	if(pCert->exts){
	  KcmMLogSetContents(pCert->exts,"(CPD)CCE");
	  if(pCert->exts->authKeyID){
	    KcmMLogSetContents(pCert->exts->authKeyID,"(CPD)CCE:authKeyID");
	    KcmMLogSetContents(pCert->exts->authKeyID->oid,"(CPD)CCEO:authKeyID");
	    if(pCert->exts->authKeyID->value){
	      authKey = (struct Auth_key_struct *)pCert->exts->authKeyID->value;
	      KcmMLogSetContents(authKey,"(CPD)CCEV:authKeyID");
	      if(authKey->id){
		KcmMLogSetContents(authKey->id,"(CPD)CCEV:authKeyID");
		KcmMLogSetContents(authKey->id->data,"(CPD)CCEV:authKeyID");
	      }
	      /* Gen-Names */
	      for(genNames = (struct Gen_names_struct *)authKey->issuer;genNames;genNames = genNames->next){
		KcmMLogSetContents(genNames,"(CPD)CCEV:dist:crlISS");
		switch(genNames->gen_name.flag){
		case CM_OTHER_NAME:
		  KcmMLogSetContents(genNames->gen_name.name.other_name,"(CPD)CCEV:distPts:genNC");
		  KcmMLogSetContents(genNames->gen_name.name.other_name->oid,"(CPD)CCEV:distPts:genNC:oid");
		  KcmMLogSetContents(genNames->gen_name.name.other_name->data,"(CPD)CCEV:distPts:genNC:oiddata");
		  KcmMLogSetContents(genNames->gen_name.name.other_name->data->data,"(CPD)CCEV:distPts:genNC:oiddata2");
		  break;
		case CM_EDI_NAME:
		  KcmMLogSetContents(genNames->gen_name.name.ediParty,"(CPD)CCEV:distPts:genNC");
		  KcmMLogSetContents(genNames->gen_name.name.ediParty->name_assigner,"(CPD)CCEV:distPts:genNC:na");
		  KcmMLogSetContents(genNames->gen_name.name.ediParty->party_name,"(CPD)CCEV:distPts:genNC:pn");
		  break;
		default:
		  KcmMLogSetContents(genNames->gen_name.name.oid,"(CPD)CCEV:distPts:genNC");
		  break;
		}
	      }
	      if(authKey->serial_num != NULL){
		KcmMLogSetContents(authKey->serial_num,"(CPD)CCEV:authKeyID");
		KcmMLogSetContents(authKey->serial_num->data,"(CPD)CCEV:authKeyID");
	      }
	    }
	  }
	  if(pCert->exts->subjKeyID){
	    KcmMLogSetContents(pCert->exts->subjKeyID,"(CPD)CCE:subjKeyID");
	    KcmMLogSetContents(pCert->exts->subjKeyID->oid,"(CPD)CCEO:subjKeyID");
	    if(pCert->exts->subjKeyID->value){
	      KcmMLogSetContents(pCert->exts->subjKeyID->value,"(CPD)CCEV:subjKeyID");
	      KcmMLogSetContents(((Bytes_struct *)pCert->exts->subjKeyID->value)->data,"(CPD)CCEV:subjKeyID");
	    }
	  }
	  if(pCert->exts->keyUsage){
	    KcmMLogSetContents(pCert->exts->keyUsage,"(CPD)CCE:keyUsage");
	    KcmMLogSetContents(pCert->exts->keyUsage->oid,"(CPD)CCEO:keyUsage");
	    KcmMLogSetContents(pCert->exts->keyUsage->value,"(CPD)CCEV:keyUsage");
	  }
	  if(pCert->exts->extKeyUse){
	    KcmMLogSetContents(pCert->exts->extKeyUse,"(CPD)CCE:extKeyUse");
	    KcmMLogSetContents(pCert->exts->extKeyUse->oid,"(CPD)CCEO:extKeyUse");
	    for(extKeyUse = (struct Ext_key_use_LL *)pCert->exts->extKeyUse->value;extKeyUse;extKeyUse = extKeyUse->next){
	      KcmMLogSetContents(extKeyUse,"(CPD)CCEV:extKeyUse");
	      KcmMLogSetContents(extKeyUse->oid,"(CPD)CCEV:extKeyUseOID");
	    }
	  }
	  if(pCert->exts->privKeyVal){
	    KcmMLogSetContents(pCert->exts->privKeyVal,"(CPD)CCE:privKeyVal");
	    KcmMLogSetContents(pCert->exts->privKeyVal->oid,"(CPD)CCEO:privKeyVal");
	    KcmMLogSetContents(pCert->exts->privKeyVal->value,"(CPD)CCEV:privKeyVal");
	  }
	  if(pCert->exts->certPolicies){
	    KcmMLogSetContents(pCert->exts->certPolicies,"(CPD)CCE:certPol");
	    KcmMLogSetContents(pCert->exts->certPolicies->oid,"(CPD)CCEO:certPol");
	    for(certPol = (struct Policy_struct *)pCert->exts->certPolicies->value;certPol;certPol = certPol->next){
	      KcmMLogSetContents(certPol,"(CPD)CCEV:certPol");
	      KcmMLogSetContents(certPol->policy_id,"(CPD)CCEV:certPolID");
	      for(qualSt = (struct Qualifier_struct *)certPol->qualifiers;qualSt;qualSt = qualSt->next){
		KcmMLogSetContents(qualSt,"(CPD)CCEV:certP:qual");
		KcmMLogSetContents(qualSt->qualifier_id,"(CPD)CCEV:certP:qualID");
		if(qualSt->qualifier){
		  KcmMLogSetContents(qualSt->qualifier,"(CPD)CCEV:certP:qualifier");
		  KcmMLogSetContents(qualSt->qualifier->data,"(CPD)CCEV:certP:qualifier");
		}
	      }
	    }
	  }
	  if(pCert->exts->policyMaps){
	    KcmMLogSetContents(pCert->exts->policyMaps,"(CPD)CCE:policyMaps");
	    KcmMLogSetContents(pCert->exts->policyMaps->oid,"(CPD)CCEO:policyMaps");
	    for(polMaps = (struct Pol_maps_struct *)pCert->exts->policyMaps->value;polMaps;polMaps = polMaps->next){
	      KcmMLogSetContents(polMaps,"(CPD)CCEV:polMaps");
	      KcmMLogSetContents(polMaps->issuer_pol_id,"(CPD)CCEV:polMaps:issID");
	      KcmMLogSetContents(polMaps->subj_pol_id,"(CPD)CCEV:polMaps:subjID");
	    }
	  }
	  if(pCert->exts->subjAltName){
	    KcmMLogSetContents(pCert->exts->subjAltName,"(CPD)CCE:subjALtName");
	    KcmMLogSetContents(pCert->exts->subjAltName->oid,"(CPD)CCEO:subjAltName");
	    KcmMLogSetContents(pCert->exts->subjAltName->value,"(CPD)CCEV:subjAltName");
	    for(genNames = (struct Gen_names_struct *)pCert->exts->subjAltName->value;genNames;genNames = genNames->next){
	      KcmMLogSetContents(genNames,"(CPD)CCEV:subjAName:genN");
	      switch(genNames->gen_name.flag){
	      case CM_OTHER_NAME:
		KcmMLogSetContents(genNames->gen_name.name.other_name,"(CPD)CCEV:subjAName:genNC");
		KcmMLogSetContents(genNames->gen_name.name.other_name->oid,"(CPD)CCEV:subjAName:genNC:oid");
		KcmMLogSetContents(genNames->gen_name.name.other_name->data,"(CPD)CCEV:subjAName:genNC:oiddata");
		KcmMLogSetContents(genNames->gen_name.name.other_name->data->data,"(CPD)CCEV:subjAName:genNC:oiddata2");
		break;
	      case CM_EDI_NAME:
		KcmMLogSetContents(genNames->gen_name.name.ediParty,"(CPD)CCEV:subjAName:genNC");
		KcmMLogSetContents(genNames->gen_name.name.ediParty->name_assigner,"(CPD)CCEV:subjAName:genNC:na");
		KcmMLogSetContents(genNames->gen_name.name.ediParty->party_name,"(CPD)CCEV:subjAName:genNC:pn");
		break;
	      default:
		KcmMLogSetContents(genNames->gen_name.name.oid,"(CPD)CCEV:subjAName:genNC");
		break;
	      }
	    }
	  }
	  if(pCert->exts->issuerAltName){
	    KcmMLogSetContents(pCert->exts->issuerAltName,"(CPD)CCE:issuerAltName");
	    KcmMLogSetContents(pCert->exts->issuerAltName->oid,"(CPD)CCEO:issuerAltName");
	    for(genNames = (struct Gen_names_struct *)pCert->exts->issuerAltName->value;genNames;genNames = genNames->next){
	      KcmMLogSetContents(genNames,"(CPD)CCEV:issAName:genN");
	      switch(genNames->gen_name.flag){
	      case CM_OTHER_NAME:
		KcmMLogSetContents(genNames->gen_name.name.other_name,"(CPD)CCEV:issAName:genNC");
		KcmMLogSetContents(genNames->gen_name.name.other_name->oid,"(CPD)CCEV:issAName:genNC:oid");
		KcmMLogSetContents(genNames->gen_name.name.other_name->data,"(CPD)CCEV:issAName:genNC:oiddata");
		KcmMLogSetContents(genNames->gen_name.name.other_name->data->data,"(CPD)CCEV:issAName:genNC:oiddata2");
		break;
	      case CM_EDI_NAME:
		KcmMLogSetContents(genNames->gen_name.name.ediParty,"(CPD)CCEV:issAName:genNC");
		KcmMLogSetContents(genNames->gen_name.name.ediParty->name_assigner,"(CPD)CCEV:issAName:genNC:na");
		KcmMLogSetContents(genNames->gen_name.name.ediParty->party_name,"(CPD)CCEV:issAName:genNC:pn");
		break;
	      default:
		KcmMLogSetContents(genNames->gen_name.name.oid,"(CPD)CCEV:issAName:genNC");
		break;
	      }
	    }
	  }
	  if(pCert->exts->subjDirAtts){
	    KcmMLogSetContents(pCert->exts->subjDirAtts,"(CPD)CCE:subjDirAtts");
	    KcmMLogSetContents(pCert->exts->subjDirAtts->oid,"(CPD)CCEO:subjDirAtts");
	    KcmMLogSetContents(pCert->exts->subjDirAtts->value,"(CPD)CCEV:subjDirAtts");
	  }
	  if(pCert->exts->basicCons){
	    KcmMLogSetContents(pCert->exts->basicCons,"(CPD)CCE:basicCons");
	    KcmMLogSetContents(pCert->exts->basicCons->oid,"(CPD)CCEO:basicCons");
	    KcmMLogSetContents(pCert->exts->basicCons->value,"(CPD)CCEV:basicCons");
	  }
	  if(pCert->exts->nameCons){
	    KcmMLogSetContents(pCert->exts->nameCons,"(CPD)CCE:nameCons");
	    KcmMLogSetContents(pCert->exts->nameCons->oid,"(CPD)CCEO:nameCons");
	    KcmMLogSetContents(pCert->exts->nameCons->value,"(CPD)CCEV:nameCons");
	  }
	  if(pCert->exts->policyCons){
	    KcmMLogSetContents(pCert->exts->policyCons,"(CPD)CCE:policyCons");
	    KcmMLogSetContents(pCert->exts->policyCons->oid,"(CPD)CCEO:policyCons");
	    KcmMLogSetContents(pCert->exts->policyCons->value,"(CPD)CCEV:policyCons");
	  }
	  if(pCert->exts->distPts){
	    KcmMLogSetContents(pCert->exts->distPts,"(CPD)CCE:distPts");
	    KcmMLogSetContents(pCert->exts->distPts->oid,"(CPD)CCEO:distPts");
	    for(distPts = (struct Dist_pts_struct *)pCert->exts->distPts->value;distPts;distPts = distPts->next){
	      KcmMLogSetContents(distPts,"(CPD)CCEV:distPts");
	      if(distPts->dist_pt_flag == CM_DIST_PT_FULL_NAME){
		for(genNames = distPts->dist_pt.full_name;genNames;genNames=genNames->next){
		  KcmMLogSetContents(genNames,"(CPD)CCEV:distP:genNames");
		  switch(genNames->gen_name.flag){
		  case CM_OTHER_NAME:
		    KcmMLogSetContents(genNames->gen_name.name.other_name,"(CPD)CCEV:distPts:genNC");
		    KcmMLogSetContents(genNames->gen_name.name.other_name->oid,"(CPD)CCEV:distPts:genNC:oid");
		    KcmMLogSetContents(genNames->gen_name.name.other_name->data,"(CPD)CCEV:distPts:genNC:oiddata");
		    KcmMLogSetContents(genNames->gen_name.name.other_name->data->data,"(CPD)CCEV:distPts:genNC:oiddata2");
		    break;
		  case CM_EDI_NAME:
		    KcmMLogSetContents(genNames->gen_name.name.ediParty,"(CPD)CCEV:distPts:genNC");
		    KcmMLogSetContents(genNames->gen_name.name.ediParty->name_assigner,"(CPD)CCEV:distPts:genNC:na");
		    KcmMLogSetContents(genNames->gen_name.name.ediParty->party_name,"(CPD)CCEV:distPts:genNC:pn");
		    break;
		  default:
		    KcmMLogSetContents(genNames->gen_name.name.oid,"(CPD)CCEV:distPts:genNC");
		    break;
		  }
		}
	      }else if(distPts->dist_pt_flag == CM_DIST_PT_RELATIVE_NAME){
		if(distPts->dist_pt.full_name)
		  KcmMLogSetContents(distPts->dist_pt.relative_name,"(CPD)CCEV:distP:dist_pt");
	      }
	      if(distPts->reasons)
		KcmMLogSetContents(distPts->reasons,"(CPD)CCEV:distP:reason");
	      /* Gen-Names */
	      for(genNames = distPts->crl_issuer;genNames;genNames = genNames->next){
		KcmMLogSetContents(genNames,"(CPD)CCEV:dist:crlISS");
		switch(genNames->gen_name.flag){
		case CM_OTHER_NAME:
		  KcmMLogSetContents(genNames->gen_name.name.other_name,"(CPD)CCEV:distPts:genNC");
		  KcmMLogSetContents(genNames->gen_name.name.other_name->oid,"(CPD)CCEV:distPts:genNC:oid");
		  KcmMLogSetContents(genNames->gen_name.name.other_name->data,"(CPD)CCEV:distPts:genNC:oiddata");
		  KcmMLogSetContents(genNames->gen_name.name.other_name->data->data,"(CPD)CCEV:distPts:genNC:oiddata2");
		  break;
		case CM_EDI_NAME:
		  KcmMLogSetContents(genNames->gen_name.name.ediParty,"(CPD)CCEV:distPts:genNC");
		  KcmMLogSetContents(genNames->gen_name.name.ediParty->name_assigner,"(CPD)CCEV:distPts:genNC:na");
		  KcmMLogSetContents(genNames->gen_name.name.ediParty->party_name,"(CPD)CCEV:distPts:genNC:pn");
		  break;
		default:
		  KcmMLogSetContents(genNames->gen_name.name.oid,"(CPD)CCEV:distPts:genNC");
		  break;
		}
	      }
	    }
	  }
	  if(pCert->exts->unknown){
	    for(unknExt = (struct Unkn_extn_LL *)pCert->exts->unknown;unknExt;unknExt = unknExt->next){
	      KcmMLogSetContents(unknExt,"(CPD)CCE:unkn");
	      KcmMLogSetContents(unknExt->oid,"(CPD)CCEO:unkn:OID");
	      if(unknExt->value){
		KcmMLogSetContents(unknExt->value,"(CPD)CCEV:unkn:val");
		KcmMLogSetContents(unknExt->value->data,"(CPD)CCEV:unkn:valData");
	      }
	    }
	  }
	}

	/* Sig */
	KcmMLogSetContents(pCert->sig.alg,"(CPD)CC:SigAlg");
	if ((strcmp(pCert->sig.alg, gRSA_MD2_OID) == 0) ||
	    (strcmp(pCert->sig.alg, gRSA_MD4_OID) == 0) ||
	    (strcmp(pCert->sig.alg, gRSA_MD5_OID) == 0) ||
	    (strcmp(pCert->sig.alg, gRSA_SHA1_OID) == 0)){
	  KcmMLogSetContents(pCert->sig.value.rsa,"(CPD)CC:SigValRSA");
	  KcmMLogSetContents(pCert->sig.value.rsa->data,"(CPD)CC:SigValRSA");
	}else{
	  /* DSA Sig */
	  KcmMLogSetContents(pCert->sig.value.dsa,"(CPD)CC:SigValDSAR");
	  KcmMLogSetContents(pCert->sig.value.dsa->r.data,"(CPD)CC:SigValDSAR");
	  KcmMLogSetContents(pCert->sig.value.dsa->s.data,"(CPD)CC:SigValDSAS");
       }
#endif

	pEntry->binCert.data = new unsigned char[pEntry->binCert.num + 2];
	if( NULL == pEntry->binCert.data )
	{
		RETURN(CCERTSREC_ALLOC_FAIL);
	}

	memcpy(pEntry->binCert.data,pBinCert->data, pEntry->binCert.num );

	#if defined(_DEBUG)
		pEntry->binCert.data[pEntry->binCert.num] = 0x00;
	#endif

	// MUST set these to null! (See RETURN(r))
	pEntry = NULL;

	m_modified = -1;

	RETURN(0);
}

/*
#define RAM_LOC			0x00000001
#define CLIENT_LOC		0x00000002
#define SERVER_LOC		0x00000004
#define DSA_LOC			0x00000008
  */

   
int CCertsRec::IsServerSearched()
{
	return CPLI_is_bit_set(SERVER_LOC,m_searched);
}

int CCertsRec::IsRAMSearched()
{
	return CPLI_is_bit_set(RAM_LOC,m_searched);
}

int CCertsRec::IsClientSearched()
{
	return CPLI_is_bit_set(CLIENT_LOC,m_searched);
}

int CCertsRec::IsDSASearched()
{
	return CPLI_is_bit_set(DSA_LOC,m_searched);
}

void CCertsRec::SetServerSearched()
{
	m_searched |= SERVER_LOC;
}

void CCertsRec::SetRAMSearched()
{
	m_searched |= SERVER_LOC;
}

void CCertsRec::SetClientSearched()
{
	m_searched |= SERVER_LOC;
}

void CCertsRec::SetDSASearched()
{
	m_searched |= SERVER_LOC;
}

void CCertsRec::ClearCheckedFlags(ULONG sessionMask)
{
	LPCERTCACHE_ENTRY_STRUCT pEntry = NULL;

	if( NULL != m_lpCerts )
	{
		pEntry = m_lpCerts;

		while( NULL != pEntry )
		{
			CPLI_unset_bit(&pEntry->flag,sessionMask);
			pEntry = pEntry->pNext;
		}
	}
}

LPCERTCACHE_ENTRY_STRUCT CCertsRec::GetNextUncheckedCert(ULONG sessionMask, LPCPL_SESSION_INFO sessInfo)
{
	LPCERTCACHE_ENTRY_STRUCT pEntry = NULL;
	
	if( m_modified )
	{
		// only sorting based on primary trust root
		SortCerts(sessInfo->rootDN[0], sessInfo->acceptablePolicySetArray);
	}

	if( NULL != m_lpCerts )
	{
		pEntry = m_lpCerts;

		do
		{
			if( (pEntry->flag & sessionMask) != sessionMask )
			{
				pEntry->flag |= sessionMask;
				break;
			}

			pEntry = pEntry->pNext;
		}
		while( NULL != pEntry );

	}

	return pEntry;
}

#ifdef _DEBUG_VERBOSE
#undef _DEBUG_VERBOSE
#endif
