/*

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): ______________________________________.

http://www.cygnacom.com

*/
/*------------------------------------------------------------------------*\
|  Project Name  :   Path Development API
|  File Name     :   utils.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.
\*------------------------------------------------------------------------*/


#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"
#endif

#include "utils.h"
#include "CertCache.h"
#include "CertsRec.h"
#include "CMAPIInterface.h"
#include "PathCache.h"


extern LOCAL_SESSION_INFO sessionInfoArr[CPL_MAX_SESSION];
extern CCertCache *pCertCache;
extern CCMAPIInterface *pCMAPIInterface;

/* #ifdef _UNIX */ /* Deleted by Masanori Satake. */
#if defined(_UNIX) || defined(VX) /* Added by Masanori Satake. */
int stricmp(char *str1, char *str2)
/* This function performs a case-insensitive comparison of the two strings.  
The result of the comparison is returned and is identical to the standard strcmp()
function:
        < 0             str1 less than str2
        = 0             str1 identical to str2
        > 0             str1 greater than str2
*/
{
        /* Local variables */
        char c1, c2;

        /* Check parameters */
        if ((str1 == NULL) || (str2 == NULL))
                return CM_NULL_POINTER;

        do
        {
                c1 = *str1;
                if ((c1 >= 'A') && (c1 <= 'Z'))
                        c1 += 'a' - 'A';

                c2 = *str2;
                if ((c2 >= 'A') && (c2 <= 'Z'))
                        c2 += 'a' - 'A';

                str1++;
                str2++;
        } while (c1 && (c1 == c2));

        return (c1 - c2);
}
#endif /* #if defined(_UNIX) || defined(VX). Added Comment by Masanori Satake. */
  
long CPLI_IsValidTargetCert( LPLOCAL_SESSION_INFO pLocalInfo, LPCPL_SESSION_INFO sessionInfo, Cert_struct *pCert )
{
	do
	{
		if( !pLocalInfo || !sessionInfo || !pCert )
			break;

		// skid ? 
		if( NULL != pLocalInfo->skid.data )
		{
			if( NULL == pCert->exts  )
				break;
			
			if( NULL == pCert->exts->subjKeyID )
				break;

			Bytes_struct *pSKID = (Bytes_struct*)pCert->exts->subjKeyID->value;

			if( NULL == pSKID )
				break;
			
			if( NULL == pSKID->data || 0 == pSKID->num )
				break;

			if( !CPLI_IsSameBytesStruct( pSKID,&(pLocalInfo->skid) ) )
				break;
		}

		// key use ? // non-critical treated as critical
		if( pLocalInfo->keyUsage && NULL != pCert->exts  )
		{
			if( NULL != pCert->exts->keyUsage && NULL != pCert->exts->keyUsage->value )
			{
				if( 0 == ( pLocalInfo->keyUsage & (*(short*)(pCert->exts->keyUsage->value))) )
				{
					break;
				}
			}
		}
		
		// desired algs ?
		if( NULL != pLocalInfo->desiredAlgOIDArray )
		{
			if( !CPLI_IsStringInStringArray(pCert->pub_key.oid,pLocalInfo->desiredAlgOIDArray) )
			{
				break;
			}
		}

		// require explicit policy mapping?? ( 0 == require explicit
		if(	CPLI_REQUIRE_EXPLICIT_POLICY == pLocalInfo->requireExplicitPolicy )
		{
			// then make sure the cert has policies

			if( !(pCert->exts && pCert->exts->certPolicies) )
				break;

			// 0 means inhibit policy mapping, so at least one pol from 
			// the acceptable set must be in the cert
			if( CPLI_INHIBIT_POLICY_MAPPING == pLocalInfo->inhibitPolicyMapping && 
				sessionInfo->acceptablePolicySetArray && 
				sessionInfo->acceptablePolicySetArray[0] )
			{
				// Get ptr to cert policies extension
				Policy_struct* pPols = (Policy_struct*)(pCert->exts->certPolicies->value);

				if( NULL != pPols )
				{
					int tmprv = 0;
					char **pIntersection = NULL;
					int hasPolicy = 0;

					// Get intersection of cert policies and acceptable policies
					tmprv = CPLI_IntersectPolicyArrayAndPolicySet( sessionInfo->acceptablePolicySetArray, pPols, &pIntersection );
					if( 0 != tmprv )
					{	// Very bad
						#if defined(_DEBUG) && defined(_WIN32)
							ASSERT(FALSE);
						#endif
						break;
					}

					if(  NULL != pIntersection[0] )
					{
						hasPolicy = 1;
					}

					if( NULL != pIntersection )
						CPLI_FreeStringArray(&pIntersection);
				
					if( !hasPolicy )
						break;
				}
				else
				{
					break;
				}
			}

		}
		

		return 1;
	}
	while(FALSE);

	return 0;
}

long CPLI_IsSameBytesStruct( Bytes_struct *a, Bytes_struct* b )
{
	if( a && b )
	{
		if( a->num == b->num )
		{
			if( 0 == memcmp(a->data,b->data,b->num) )
			{
				return 1;
			}
		}
	}

	return 0;
}

long CPLI_IsTrustedDN( char **rootDNs, char *dn2 )
{
	int XX = 0;
	while( rootDNs[XX] )
	{
		if( CPLI_IsSameDN( rootDNs[XX], dn2 ) )
			return 1;

		XX++;
	}

	return 0;
}


long CPLI_IsSameDN( char *dn1, char *dn2 )
{
	int same = 0;
	
	if( dn1 && dn2 )
	{
		char *pDN1 = new char[strlen(dn1)+2];
		char *pDN2 = new char[strlen(dn2)+2];

		if( pDN1 && pDN2 )
		{
			strcpy(pDN1,dn1);
			strcpy(pDN2,dn2);

			CPLI_SquashSpacesInDN(pDN1);
			CPLI_SquashSpacesInDN(pDN2);

			if( 0 == stricmp(pDN1,pDN2) )
			{
				same = 1;
			}

			delete []pDN1;
			delete []pDN2;

			/*
			int c = CPLI_CountRDNs(dn1);
			if( c == CPLI_CountRDNs(dn2) )
			{
				if( c == CPLI_CountMatchingRDNs(dn1,dn2) )
				{
					return 1;
				}
			}
			*/
		}
	}

	return same;
}

long CPLI_CreateNewSession(		long* session, 
								char* subjectDN, 
								CPL_SESSION_INFO *sessionInfo,
								CertPath_struct *partialPath,
								int inhibitPolicyMapping,
								int requireExplicitPolicy,
								char** desiredAlgOIDArray, 
								unsigned short keyUsage, 
								Bytes_struct* skid				)
{
	long rv = 0;
	int XX = 0;
	LPLOCAL_SESSION_INFO pInfo = NULL;

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

	for(; XX < CPL_MAX_SESSION; XX++)
	{
		if(0 == sessionInfoArr[XX].IsInUse)
		{
			pInfo = &(sessionInfoArr[XX]);
			*session = XX+1;
			break;
		}
	}

	if( CPL_MAX_SESSION == XX )
		return CPL_NO_MORE_SESSIONS;

	if( NULL == pInfo )
		return CPL_UNEXPECTED_ERROR;

	memset(pInfo, 0, sizeof(LOCAL_SESSION_INFO) );

	pInfo->mask = CPLI_get_bit_mask((short)*session);
	pInfo->IsInUse = 1;
	pInfo->usePathCache = 1;
	pInfo->keyUsage = keyUsage;

	// set policy mapping && req flags
	if( 0 != inhibitPolicyMapping )
	{
		pInfo->inhibitPolicyMapping = CPLI_INHIBIT_POLICY_MAPPING;
	}
	else
	{
		pInfo->inhibitPolicyMapping = CPLI_DO_NOT_INHIBIT_POLICY_MAPPING;
	}

	if( 0 != requireExplicitPolicy )
	{
		pInfo->requireExplicitPolicy = CPLI_REQUIRE_EXPLICIT_POLICY;
	}
	else
	{
		pInfo->requireExplicitPolicy = CPLI_DO_NOT_REQUIRE_EXPLICIT_POLICY;
	}

	if( NULL == subjectDN )
	{
		if( NULL == partialPath )
			return CPL_PARAM_MISSING;

		Cert_struct *pCert = NULL;
		rv = pCMAPIInterface->DecodeCert(partialPath->asn1cert.data,&pCert);
		if( 0 != rv || pCert == NULL )
			return CPL_DECODE_CERT_FAIL;

		pInfo->subjectDN = new char[strlen(pCert->subject) + 2];
		
		if( NULL == pInfo->subjectDN )
		{
			memset(pInfo, 0, sizeof(LOCAL_SESSION_INFO) );
			return CPL_ALLOC_FAILURE;
		}

		strcpy(pInfo->subjectDN,pCert->subject);
		CPLI_SquashSpacesInDN(pInfo->subjectDN);

		pCMAPIInterface->FreeCert(&pCert);
	}
	else
	{
		pInfo->subjectDN = new char[strlen(subjectDN) + 2];
		
		if( NULL == pInfo->subjectDN )
		{
			memset(pInfo, 0, sizeof(LOCAL_SESSION_INFO) );
			return CPL_ALLOC_FAILURE;
		}

		strcpy(pInfo->subjectDN,subjectDN);
		CPLI_SquashSpacesInDN(pInfo->subjectDN);
	}
	
	if( NULL != desiredAlgOIDArray )
	{
		rv = CPLI_CopyStringArray(desiredAlgOIDArray,&pInfo->desiredAlgOIDArray);
		if( rv )
		{
			delete []pInfo->subjectDN;
			memset(pInfo, 0, sizeof(LOCAL_SESSION_INFO) );
			return rv;
		}
	}

	if( NULL != skid )
	{
		rv = CPLI_CopyBytesStruct(skid, &(pInfo->skid) );
		if( rv )
		{
#ifndef VX /* Added by Masanori Satake. */
			#if !defined(_DEBUG)
				try{
			#endif
#endif
				delete []pInfo->subjectDN;
				CPLI_FreeStringArray(&pInfo->desiredAlgOIDArray);
#ifndef VX /* Added by Masanori Satake. */
			#if !defined(_DEBUG)
				}catch(...){}
			#endif
#endif
			memset(pInfo, 0, sizeof(LOCAL_SESSION_INFO) );
			return rv;
		}
	}

	if( NULL != partialPath )
	{
		CertPath_struct *pEntry = partialPath;
		while( NULL != pEntry )
		{
			rv = pCertCache->AddEntry(&(pEntry->asn1cert),0);
			pEntry = pEntry->next;
		}

		pInfo->pPartialPath = new CertPath_struct;
		if( NULL == pInfo->pPartialPath || rv )
		{
#ifndef VX /* Added by Masanori Satake. */
			#if !defined(_DEBUG)
				try{
			#endif
#endif
				delete []pInfo->subjectDN;
				delete []pInfo->skid.data;
				CPLI_FreeStringArray(&pInfo->desiredAlgOIDArray);
#ifndef VX /* Added by Masanori Satake. */
			#if !defined(_DEBUG)
				}catch(...){}
			#endif
#endif
			memset(pInfo, 0, sizeof(LOCAL_SESSION_INFO) );
			return CPL_ALLOC_FAILURE;
		}

		memset(pInfo->pPartialPath, 0, sizeof(CertPath_struct));

		Cert_struct *pCert = NULL;
		rv = pCMAPIInterface->DecodeCert(partialPath->asn1cert.data,&pCert);
		if( 0 != rv || NULL == pCert )
		{
#ifndef VX /* Added by Masanori Satake. */
			#if !defined(_DEBUG)
				try{
			#endif
#endif
				delete []pInfo->subjectDN;
				delete []pInfo->skid.data;
				delete pInfo->pPartialPath;
				CPLI_FreeStringArray(&pInfo->desiredAlgOIDArray);
#ifndef VX /* Added by Masanori Satake. */
			#if !defined(_DEBUG)
				}catch(...){}
			#endif
#endif
			memset(pInfo, 0, sizeof(LOCAL_SESSION_INFO) );
			return CPL_DECODE_CERT_FAIL;
		}

		rv = CPLI_CopyBytesStruct(&(partialPath->asn1cert),&(pInfo->pPartialPath->asn1cert));

		if( !pInfo->pPartialPath->asn1cert.data || rv )
		{
#ifndef VX /* Added by Masanori Satake. */
			#if !defined(_DEBUG)
				try{
			#endif
#endif
				delete []pInfo->subjectDN;
				delete []pInfo->skid.data;
				delete pInfo->pPartialPath;
				CPLI_FreeStringArray(&pInfo->desiredAlgOIDArray);
#ifndef VX /* Added by Masanori Satake. */
			#if !defined(_DEBUG)
				}catch(...){}
			#endif
#endif
			memset(pInfo, 0, sizeof(LOCAL_SESSION_INFO) );

			if( rv )
				return rv;

			return CPL_ALLOC_FAILURE;
		}

		pInfo->pPartialPath->cert = pCert;

	}
	
	#if defined(_DEBUG)
		ASSERT( 0 == pCertCache->SortCerts(sessionInfo->rootDN[0],sessionInfo->acceptablePolicySetArray) );
	#else
		pCertCache->SortCerts(sessionInfo->rootDN[0],sessionInfo->acceptablePolicySetArray);
	#endif

	#if defined(_DEBUG)
                #ifdef _WIN32 /* Added by Masanori Satake. */
		afxDump << "Returning, session == " << *session << "\n";
                #else /* _UNIX or VX */
		PRINTERR("Returning, session == ");
		PRINTERR(*session);
		PRINTERR("\n");
                #endif /* #ifdef _WIN32 */
	#endif

	return 0;
}

/*
long CPLI_FreeLocalPathList( LPPATH_ENTRY_LIST *pList )
{

	if( NULL == pList )
		return CPL_PARAM_MISSING;

	if( NULL == *pList )
		return 0;

	LPPATH_ENTRY_LIST pEntry = *pList;
	LPPATH_ENTRY_LIST pTmp = NULL;


#if !defined(_DEBUG)
	try{
#endif

		*pList = NULL;

		while( pEntry != NULL )
		{

			delete [](pEntry->data.issuerCADN);
			delete [](pEntry->data.subjectIssuerDN);
			delete [](pEntry->data.issuerSerial.data);
			delete [](pEntry->data.subjectSerial.data);

			pTmp = pEntry;
			pEntry = pEntry->next;
			delete pTmp;
		}


#if !defined(_DEBUG)
	}catch(...){}
#endif

	return 0;
}
*/

long CPLI_CopyBytesStruct( Bytes_struct* src, Bytes_struct* dest )
{
	if( NULL == src || NULL == dest )
		return CPL_PARAM_MISSING;

	memset( dest,0,sizeof(Bytes_struct) );

	if( NULL == src->data )
		return 0;

	if( 0 == src->num )
		return CPL_INVALID_PARAM;

	dest->num = src->num;
	dest->data = new unsigned char[dest->num+2];
	memcpy(dest->data,src->data,dest->num);

	return 0;
}

long CPLI_CopyStringArray( char** src, char*** dest )
{
	if( NULL == src || NULL == dest )
		return CPL_PARAM_MISSING;

	int XX = 0, YY = 0, len = 0;
	char **pDest = NULL;

	while( src[XX] != NULL )
	{
		XX++;
	}
	
	pDest = new char*[XX+2];
	if( NULL == pDest )
	{
		return CPL_ALLOC_FAILURE;
	}

	memset(pDest,0,sizeof(char*)*(XX+2));
	*dest = pDest;

	if( 0 == XX )
	{
		return 0;
	}

	for(YY = 0; YY < XX; YY++ )
	{
		len = strlen(src[YY]);
		pDest[YY] = new char[len+2];
		strcpy(pDest[YY],src[YY]);
	}

	return 0;
}

long CPLI_IntersectStringArrays( char** arr1, char** arr2, char*** dest )
{
	if( NULL == arr1 || NULL == arr2 || NULL == dest )
		return CPL_PARAM_MISSING;

	int XX = 0, YY = 0, ZZ = 0, len = 0;
	char **pDest = NULL;

	while( arr1[XX] != NULL )
	{
		XX++;
	}

	pDest = new char*[XX+2];
	if( NULL == pDest )
	{
		return CPL_ALLOC_FAILURE;
	}

	memset(pDest,0,sizeof(char*)*(XX+2));
	*dest = pDest;

	if( 0 == XX || NULL == arr2[0] )
	{
		return 0;
	}

	for( ; YY < XX; YY++ )
	{
		if( CPLI_IsStringInStringArray( arr1[YY], arr2 ) )
		{
			len = strlen(arr1[YY]);
			pDest[ZZ] = new char[len+2];
			strcpy(pDest[ZZ],arr1[YY]);	
			ZZ++;
		}
	}

	return 0;
}

long CPLI_IntersectPolicyArrayAndPolicySet( char** arr1, Policy_struct* pPols, char*** dest )
{
	if( NULL == arr1 || NULL == pPols || NULL == dest )
		return CPL_PARAM_MISSING;

	// XX is count of oids in arr1, YY will contain count of oids in dest
	int XX = 0, YY = 0, len = 0;
	char **pDest = NULL;

	while( arr1[XX] != NULL )
	{
		XX++;
	}

	pDest = new char*[XX+2];
	if( NULL == pDest )
	{
		return CPL_ALLOC_FAILURE;
	}

	memset(pDest,0,sizeof(char*)*(XX+2));
	*dest = pDest;

	if( 0 == XX || NULL == pPols->policy_id )
	{
		return 0;
	}

	do
	{
		if( CPLI_IsStringInStringArray(pPols->policy_id, arr1) )
		{
			len = strlen(pPols->policy_id);
			pDest[YY] = new char[len+2];
			strcpy(pDest[YY],pPols->policy_id);	
			YY++;
		}
		pPols = pPols->next;
	}
	while(NULL != pPols );

	return 0;
}


long CPLI_IntersectPolicyArrayAndPolicySetInPlace( char*** policyArray, Policy_struct* pPols )
{
	if( NULL == policyArray || NULL == pPols )
		return CPL_PARAM_MISSING;

	if( NULL == *policyArray )
		return CPL_PARAM_MISSING;

	// XX is count of oids in arr1, YY will contain count of oids in dest
	int XX = 0, YY = 0, len = 0;
	char **pDest = NULL;
	char **arr1 = *policyArray;

	while( arr1[XX] != NULL )
	{
		XX++;
	}

	pDest = new char*[XX+2];
	if( NULL == pDest )
	{
		return CPL_ALLOC_FAILURE;
	}

	*policyArray = pDest;
	memset(pDest,0,sizeof(char*)*(XX+2));

	if( 0 == XX || NULL == pPols->policy_id )
	{
		CPLI_FreeStringArray( &arr1 );
		return 0;
	}

	do
	{
		if( CPLI_IsStringInStringArray(pPols->policy_id, arr1) )
		{
			len = strlen(pPols->policy_id);
			pDest[YY] = new char[len+2];
			strcpy(pDest[YY],pPols->policy_id);	
			YY++;
		}
		pPols = pPols->next;
	}
	while(NULL != pPols );

	CPLI_FreeStringArray( &arr1 );

	return 0;
}
//typedef struct Pol_maps_struct
//{
//   CM_OID issuer_pol_id;			/* Policy OID from issuer's domain */
//    CM_OID subj_pol_id;				/* Policy OID from subject's domain */
//    struct Pol_maps_struct *next;
//} Pol_maps_struct;

long CPLI_AddPolicyMappingsToPolicySet(char*** policySet, Pol_maps_struct* pMaps )
{
	if( !pMaps )
		return 0;

	if( !policySet )
		return CPL_PARAM_MISSING;

	if( !*policySet )
	{
		return CPL_PARAM_MISSING;
	}

	Pol_maps_struct *pTmp = pMaps;

	int XX = 0;

	while( pTmp )
	{
		pTmp = pTmp->next;
		XX++;
	}

	if( !CPLI_GrowStringArray(policySet,XX) )
		return 1;

	char **pPols = *policySet;

	XX = 0;
	while( pPols[++XX] ){}

	pTmp = pMaps;
	while( pTmp )
	{
		if( CPLI_IsStringInStringArray(pTmp->issuer_pol_id,pPols) )
		{
			pPols[XX] = new char[ strlen(pTmp->subj_pol_id) + 2 ];
			if( !pPols[XX] )
				return 0;
			strcpy(pPols[XX],pTmp->subj_pol_id);
			XX++;
		}
		pTmp = pTmp->next;
	}

	return 0;
}

long CPLI_CreateNewPolicyArrayFromPolicyStruct( Policy_struct* pPols, char ***dest )
{
	if( !pPols || !dest )
		return CPL_PARAM_MISSING;

	Policy_struct *pTmp = pPols;
	int XX = 0, YY = 0;

	while( pTmp )
	{
		pTmp = pTmp->next;
		XX++;
	}

	// XX == num of policies

	*dest = new char*[XX+2];
	memset(*dest,0,sizeof(char*)*(XX+2));

	char **pArr = *dest;

	pTmp = pPols;
	while(pTmp && pTmp->policy_id)
	{
		pArr[YY] = new char[strlen(pTmp->policy_id)+2];
		strcpy(pArr[YY],pTmp->policy_id);
		pTmp = pTmp->next;
		YY++;
	}

	return 0;
}

long CPLI_GrowStringArray( char*** arr, int numEntriesToAdd )
{
	if( !numEntriesToAdd )
		return 1;

	if( !arr )
		return 0;

	if( !(*arr) )
	{
		*arr = new char*[numEntriesToAdd+2];
		memset(*arr,0,sizeof(char*)*(numEntriesToAdd+2));
		return 1;
	}

	char **pArr = *arr;
	char **dest = NULL;
	int XX = 0;

	while( pArr[XX++] ){};

	dest = new char*[numEntriesToAdd+2+XX];
	memset(dest,0,sizeof(char*)*(numEntriesToAdd+2+XX));

	XX=0;

	while( pArr[XX] )
	{
		dest[XX] = pArr[XX];
		XX++;
	}

	delete []pArr;

	*arr = dest;

	return 1;
}
//typedef struct Pol_maps_struct
//{
//   CM_OID issuer_pol_id;			/* Policy OID from issuer's domain */
//    CM_OID subj_pol_id;				/* Policy OID from subject's domain */
//    struct Pol_maps_struct *next;
//} Pol_maps_struct;

//typedef struct Pol_cons_struct
//{
//    short req_explicit_pol;         /* Require explicit policy (optional) */
//    short inhibit_mapping;          /* Inhibit policy mapping (optional) */
//} Pol_cons_struct;                  /*    Set to CM_NOT_PRESENT if absent */

// if inhibitPolicyMapping reaches zero, mapping will be inhibited
// the user value of inhibitPolicyMapping is stored in the local info struct
// as is the requireExplicitMapping
long CPLI_IsValidPolicySetChain( char** policySet, CertPath_struct *pHead, int inhibitPolicyMapping, int RequireExplicitPolicy )
{

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

	if( NULL == pHead )
	{
		#if defined(_DEBUG)
                                #ifdef _WIN32 /* Added by Masanori Satake. */
				afxDump << "ERROR: CPLI_IsValidPolicySetChain: pHead is NULL\n";
                                #else /* _UNIX or VX */
				PRINTERR("ERROR: CPLI_IsValidPolicySetChain: pHead is NULL\n");
                                #endif /* #ifdef _WIN32 */
		#endif
		return 0;
	}

//	if( inhibitPolicyMapping )
//		inhibitPolicyMapping = 0xFFFF;

	char **localPolicySet  = NULL;
	Policy_struct* pPols   = NULL;
	CertPath_struct* pCert = NULL;
	Pol_maps_struct* pMaps = NULL;
	Pol_cons_struct* pCons = NULL;
	int pathFailed = 1; // set to fail
	int requireExplicitPolicy = RequireExplicitPolicy;
	long rv = 0;

	if( NULL != policySet )
	{
		// 0 indicates explicit is set.
		requireExplicitPolicy = 0;

		if( NULL != policySet[0] )
		{
			rv = CPLI_CopyStringArray(policySet,&localPolicySet);
			if( 0 != rv )
			{
#ifndef VX /* Added by Masanori Satake. */
				try{ CPLI_FreeStringArray(&localPolicySet); } catch(...){}
#else
				CPLI_FreeStringArray(&localPolicySet);
#endif
				#if defined(_DEBUG)
                                                #ifdef _WIN32 /* Added by Masanori Satake. */
						afxDump << "ERROR: CPLI_IsValidPolicySetChain: Failed to copy policy set.\n";
                                                #else /* _UNIX or VX */
						PRINTERR("ERROR: CPLI_IsValidPolicySetChain: Failed to copy policy set.\n");
                                                #endif /* #ifdef _WIN32 */
				#endif
				return rv;
			}
		}
	}

	int XX = 0, count = 0;
	pCert = pHead;
	while( pCert->next )
	{
		XX++;
		pCert = pCert->next;
	}

	count = XX+1;
	// pCert is root of path
	// XX is count of certs (zero based)
	// count is number of certs
	#if defined(_DEBUG)
                        #ifdef _WIN32 /* Added by Masanori Satake. */

			afxDump << "CPLI_IsValidPolicySetChain: " << count << " certs in path\n";
			afxDump << "\troot = " << pCert->cert->subject << "\n";
			if( 0 == requireExplicitPolicy )
				afxDump << "\trequireExplicitPolicy is set.\n";
			else
				afxDump << "\trequireExplicitPolicy is not set.\n";

			if( inhibitPolicyMapping != CPLI_DO_NOT_INHIBIT_POLICY_MAPPING )
				afxDump << "\tinhibitPolicyMapping is set.\n";
			else
				afxDump << "\tinhibitPolicyMapping is not set.\n";

                        #else /* _UNIX or VX */

			PRINTERR("CPLI_IsValidPolicySetChain: ");
			PRINTERR(count);
			PRINTERR(" certs in path\n");
			PRINTERR("\troot = ");
			PRINTERR(pCert->cert->subject);
			PRINTERR("\n");

			if( 0 == requireExplicitPolicy )
			  PRINTERR("\trequireExplicitPolicy is set.\n");
			else
			  PRINTERR("\trequireExplicitPolicy is not set.\n");

			if( inhibitPolicyMapping != CPLI_DO_NOT_INHIBIT_POLICY_MAPPING )
			  PRINTERR("\tinhibitPolicyMapping is set.\n");
			else
			  PRINTERR("\tinhibitPolicyMapping is not set.\n");

                        #endif /* #ifdef _WIN32 */
	#endif


	CertPath_struct **PathArray = new CertPath_struct*[count+2];
	memset( PathArray,0,sizeof(CertPath_struct*)*(count+2) );
	pCert = pHead;

	for( ; XX >= 0; XX-- )
	{
		PathArray[XX] = pCert;
		pCert = pCert->next;
	}
	//Path array now contains the root at [0] and the end entity at [count]

	#if defined(_DEBUG) && defined(_WIN32)
		ASSERT( !pCert );
	#endif

	XX = 0;
	pCert = PathArray[0]; // start at root entity

	do // while there are certs in the path
	{
		// Quick error/consistency check
		if( !pCert->cert )
		{
			#if defined(_DEBUG) && defined(_WIN32)
				ASSERT( pCert->cert );
			#endif
			break;
		}


		if( pCert->cert->exts )
		{
			// if the cert has policies 
			if( 0 == requireExplicitPolicy && pCert->cert->exts->certPolicies && pCert->cert->exts->certPolicies->value )
			{

				pPols = (Policy_struct*)(pCert->cert->exts->certPolicies->value);

				if( NULL == localPolicySet )
				{
					rv = CPLI_CreateNewPolicyArrayFromPolicyStruct(pPols,&localPolicySet);
				}
				else
				{
					rv = CPLI_IntersectPolicyArrayAndPolicySetInPlace(&localPolicySet,pPols);
				}

				if( rv )
				{
					#if defined(_DEBUG) && defined(_WIN32)
						ASSERT( FALSE );
					#endif
					break;
				}

				if( NULL == localPolicySet[0] )
				{
					// Intersection yielded empty set
					#if defined(_DEBUG)
                                                        #ifdef _WIN32 /* Added by Masanori Satake. */
							afxDump << "\tCPLI_IsValidPolicySetChain: Intersection of current policy set with cert policies is empty.\n";
                                                        #else /* _UNIX or VX */
							PRINTERR("\tCPLI_IsValidPolicySetChain: Intersection of current policy set with cert policies is empty.\n");
                                                        #endif /* #ifdef _WIN32 */
					#endif
					break;
				}

				if( 0 != inhibitPolicyMapping && pCert->cert->exts->policyMaps && pCert->cert->exts->policyMaps->value )
				{
					// Cert has policy mapping and we are not inhibiting mapping
					pMaps = (Pol_maps_struct*)(pCert->cert->exts->policyMaps->value);
					rv = CPLI_AddPolicyMappingsToPolicySet(&localPolicySet,pMaps);
					if( rv )
					{
						#if defined(_DEBUG) && defined(_WIN32)
							ASSERT( FALSE );
						#endif
						break;
					}
				}


			}// end if the cert has policies 
			else if( 0 == requireExplicitPolicy ) 
			{
				// No policies == FAIL
				#if defined(_DEBUG)
                                                #ifdef _WIN32 /* Added by Masanori Satake. */
						afxDump << "\tCPLI_IsValidPolicySetChain: requireExplicitPolicy set and cert has no policies.\n";
                                                #else /* _UNIX or VX */
						PRINTERR("\tCPLI_IsValidPolicySetChain: requireExplicitPolicy set and cert has no policies.\n");
                                                #endif /* #ifdef _WIN32 */
				#endif
				break;
			}

		} // end if exts
		else if( 0 == requireExplicitPolicy )
		{
			// No exts and req policy, so fail
			#if defined(_DEBUG)
                                        #ifdef _WIN32 /* Added by Masanori Satake. */
					afxDump << "\tCPLI_IsValidPolicySetChain: requireExplicitPolicy set and cert has no extensions.\n";
                                        #else /* _UNIX or VX */
					PRINTERR("\tCPLI_IsValidPolicySetChain: requireExplicitPolicy set and cert has no extensions.\n");
                                        #endif /* #ifdef _WIN32 */
			#endif
			break;
		}

		// decrement inhibitPolicyMapping indicator
		if( 0 != inhibitPolicyMapping )
			inhibitPolicyMapping--;

		if( 0 != inhibitPolicyMapping && pCert->cert->exts && pCert->cert->exts->policyCons && pCert->cert->exts->policyCons->value )
		{
			// We are not yet inhibiting mapping, and the cert has policy constraints
			pCons = (Pol_cons_struct*)pCert->cert->exts->policyCons->value;
			if( pCons->inhibit_mapping != CM_NOT_PRESENT && pCert->cert->exts->policyCons->critical)
			{
				if( pCons->inhibit_mapping < inhibitPolicyMapping )
					inhibitPolicyMapping = pCons->inhibit_mapping;

				#if defined(_DEBUG)
                                                #ifdef _WIN32 /* Added by Masanori Satake. */
						afxDump << "\tCPLI_IsValidPolicySetChain: inhibitPolicyMapping set to " << inhibitPolicyMapping << "\n";
                                                #else /* _UNIX or VX */
						PRINTERR("\tCPLI_IsValidPolicySetChain: inhibitPolicyMapping set to ");
						PRINTERR(inhibitPolicyMapping);
						PRINTERR("\n");
                                                #endif /* #ifdef _WIN32 */
				#endif
			}
		}

		// decrement requireExplicitPolicy indicator
		if( 0 != requireExplicitPolicy )
			requireExplicitPolicy--;

		if( 0 != requireExplicitPolicy && pCert->cert->exts && pCert->cert->exts->policyCons && pCert->cert->exts->policyCons->value)
		{
			pCons = (Pol_cons_struct*)pCert->cert->exts->policyCons->value;
			if( pCons->req_explicit_pol != CM_NOT_PRESENT  && pCert->cert->exts->policyCons->critical )
			{
				if( pCons->req_explicit_pol < requireExplicitPolicy )
					requireExplicitPolicy = pCons->req_explicit_pol;

				#if defined(_DEBUG)
                                                #ifdef _WIN32 /* Added by Masanori Satake. */
						afxDump << "\tCPLI_IsValidPolicySetChain: requireExplicitPolicy set to " << requireExplicitPolicy << "\n";
                                                #else /* _UNIX or VX */
						PRINTERR("\tCPLI_IsValidPolicySetChain: requireExplicitPolicy set to ");
						PRINTERR(requireExplicitPolicy);
						PRINTERR("\n");
                                                #endif /* #ifdef _WIN32 */
				#endif
			}
		}

		// get the next cert
		XX++;
		pCert = PathArray[XX];

		if( pCert == NULL )
			pathFailed = 0;

	}
	while(pCert);

	
	delete []PathArray;

	if( localPolicySet )
		CPLI_FreeStringArray(&localPolicySet);

	#if defined(_DEBUG)
                        #ifdef _WIN32 /* Added by Masanori Satake. */
			afxDump << "\tCPLI_IsValidPolicySetChain: Returning BOOL: " << !pathFailed << "\n";
                        #else /* _UNIX or VX */
			PRINTERR("\tCPLI_IsValidPolicySetChain: Returning BOOL: ");
			PRINTERR(!pathFailed);
			PRINTERR("\n");
                        #endif /* #ifdef _WIN32 */
	#endif

	if( pathFailed )
	{
		return 0;
	}
	else
	{
		return 1;
	}
}


long CPLI_IsStringInStringArray( char *str, char** strArray )
{
	if( str && strArray )
	{
		int XX = 0;
		while(strArray[XX])
		{
			if( 0 == strcmp( str, strArray[XX] ) )
			{
				return 1;
			}
			XX++;
		}

	}

	return 0;
}

long CPLI_FreeStringArray( char*** arr )
{
	if( arr == NULL )
		return CPL_PARAM_MISSING;

	if( *arr == NULL )
		return 0;

	int XX = 0;
	char **pArr = *arr;

#ifndef VX /* Added by Masanori Satake. */
	try
	{
#endif
		while( pArr[XX] != NULL )
		{
			delete [](pArr[XX]);
			pArr[XX] = NULL;
			XX++;
		}

		delete []pArr;
		*arr = NULL;
#ifndef VX /* Added by Masanori Satake. */
	}
	catch(...)
	{
		#if defined(_DEBUG)
                        #ifdef _WIN32 /* Added by Masanori Satake. */
			afxDump << "ERROR: Exception caught in CPLI_FreeStringArray\n";
                        #else /* _UNIX or VX */
			PRINTERR("ERROR: Exception caught in CPLI_FreeStringArray\n");
                        #endif /* #ifdef _WIN32 */
		#endif
	}
#endif
	return 0;
}

long CPLI_DestroySession( long session )
{
	if( session <= 0 || session > CPL_MAX_SESSION )
	{
		#if defined(_DEBUG)
                        #ifdef _WIN32 /* Added by Masanori Satake. */
			afxDump << "ERROR: Illegal session value of " << session << " in CPLI_GetSessionInfo.\n";
                        #else /* _UNIX or VX */
			PRINTERR("ERROR: Illegal session value of ");
			PRINTERR(session);
			PRINTERR(" in CPLI_GetSessionInfo.\n");
                        #endif /* #ifdef _WIN32 */
		#endif
		return CPL_INVALID_SESSION_HANDLE;
	}

	long rv = 0;
	session--;
	LPLOCAL_SESSION_INFO pInfo = &(sessionInfoArr[session]);

#ifndef VX /* Added by Masanori Satake. */
	#if !defined(_DEBUG)
	try
	{
	#endif
#endif
	if( 0 != pInfo->mask )
	{
		pCertCache->ClearAllFlags(pInfo->mask);
	}

	if( NULL != pInfo->desiredAlgOIDArray )
	{
		CPLI_FreeStringArray(&(pInfo->desiredAlgOIDArray));
	}

	if( NULL != pInfo->subjectDN )
	{
		delete [](pInfo->subjectDN);
		pInfo->subjectDN = NULL;
	}

	if( NULL != pInfo->skid.data )
	{
		delete [](pInfo->skid.data);
		pInfo->skid.data = NULL;
	}

	if( NULL != pInfo->pPartialPath )
	{
		CertPath_struct *pPath = pInfo->pPartialPath;
		CertPath_struct *pTmp = NULL;
		while( pPath )
		{
			if( NULL != pInfo->pPartialPath->cert )
			{
				pCMAPIInterface->FreeCert(&(pInfo->pPartialPath->cert));
			}

			if( NULL != pInfo->pPartialPath->asn1cert.data )
			{
				delete [](pInfo->pPartialPath->asn1cert.data);
			}

			pTmp = pPath;
			pPath = pPath->next;
			delete pTmp;
		}
	}

#ifndef VX /* Added by Masanori Satake. */
	#if !defined(_DEBUG)
	}
	catch(...){ rv = CPL_EXCEPTION_CAUGHT; }
	#endif
#endif
	memset(pInfo,0,sizeof(LOCAL_SESSION_INFO));

	return rv;
}


LPLOCAL_SESSION_INFO CPLI_GetSessionInfo( long session )
{
	if( session <= 0 || session > CPL_MAX_SESSION )
	{
		#if defined(_DEBUG)
                        #ifdef _WIN32 /* Added by Masanori Satake. */
			afxDump << "ERROR: Illegal session value of " << session << " in CPLI_GetSessionInfo.\n";
                        #else /* _UNIX or VX */
			PRINTERR("ERROR: Illegal session value of ");
			PRINTERR(session);
			PRINTERR(" in CPLI_GetSessionInfo.\n");
                        #endif /* #ifdef _WIN32 */
		#endif
		return NULL;
	}

	session--;

	if(  0 != sessionInfoArr[session].IsInUse )
	{
		return &(sessionInfoArr[session]);
	}

	return NULL;
}


/* returns 1 if cert1 has higher sort priority, 2 if cert2 is higher */
long CPLI_CompareCertPriority(LPCERTCACHE_ENTRY_STRUCT cert1, LPCERTCACHE_ENTRY_STRUCT cert2, char* trustedRootDN, char** acceptablePolicySet )
{
	// Check Params
	if( NULL == cert1 || NULL == cert2 )
	{
		#if defined(_WIN32) && defined(_DEBUG)
			ASSERT(FALSE);
		#endif
		return CCERTSREC_REQUIRED_PARAM_MISSING;
	}

	// Verify Cert Data
	if( NULL == cert1->pCert || NULL == cert2->pCert )
	{
		#if defined(_WIN32) && defined(_DEBUG)
			ASSERT(FALSE);
		#endif
		return CCERTSREC_REQUIRED_PARAM_MISSING;
	}


	//// Rule 1
// 1. Certificates retrieved from the cACertificate 
// attribute should have priority over certificates 
// retrieved from the crossCertificate attribute

	if( cert1->type != cert2->type )
	{
		if( cert1->type > cert2->type )
		{
			return 2;
		}
		return 1;
	}

	// tmp ptrs and vals for later use
	Cert_struct *pCert1 = cert1->pCert;
	Cert_struct *pCert2 = cert2->pCert;
	Policy_struct *pCert1Pol = NULL;
	Policy_struct *pCert2Pol = NULL;
	int tmpval1, tmpval2, XX;


	//// Rule 2
// 2. Certificates in which issuer algorithm OID = 
// subject algorithm OID should have priority

	if( NULL == pCert1->pub_key.oid )
	{
		return CCERTSREC_CERT1_INVALID;
	}
	if( NULL == pCert2->pub_key.oid )
	{
		return CCERTSREC_CERT2_INVALID;
	}

	// if pCert1->sig.alg exists, use it over pCert1->signature
	if( NULL != pCert1->sig.alg )
	{
		tmpval1 = strcmp(pCert1->pub_key.oid, pCert1->sig.alg );
	}
	else if( NULL != pCert1->signature )
	{
		tmpval1 = strcmp(pCert1->pub_key.oid, pCert1->signature );
	}
	else
	{ // No oid!?!
		return CCERTSREC_CERT1_INVALID;
	}

	// if pCert2->sig.alg exists, use it over pCert2->signature
	if( NULL != pCert2->sig.alg )
	{
		tmpval2 = strcmp(pCert2->pub_key.oid, pCert2->sig.alg );
	}
	else if( NULL != pCert2->signature )
	{
		tmpval2 = strcmp(pCert2->pub_key.oid, pCert2->signature );
	}
	else
	{ // No oid!?!
		return CCERTSREC_CERT2_INVALID;
	}

	if( tmpval1 != tmpval2 )
	{
		if( 0 == tmpval1 )
		{ // cert1s oids match
			return 1;
		}
		if( 0 == tmpval2 )
		{ // cert2s oids match
			return 2;
		}
		/* Both are different */
	}

// 3. Certificates that assert policies in the 
// initial-acceptable-policy-set should have priority
/*
// X.509 Certificate 
typedef struct Cert_struct
{
    short version;             
    Bytes_struct serial_num;   
    CM_OID signature;		
    CM_DN issuer;			
    CM_Time val_not_before;	
    CM_Time val_not_after;	
    CM_DN subject;			
    Pub_key_struct pub_key;    
    Bytes_struct *issuer_id;   
    Bytes_struct *subj_id;     
    Cert_exts_struct *exts;    
    Sig_struct sig;            
} Cert_struct;


typedef struct Policy_struct
{
    CM_OID policy_id;				// Certificate policy OID 
    Qualifier_struct *qualifiers;   // Pointer to first policy qualifier 
    struct Policy_struct *next;
} Policy_struct;


*/

	if( NULL != pCert1->exts )
	{
		if( NULL != pCert1->exts->certPolicies )
		{
			pCert1Pol = (Policy_struct*)(pCert1->exts->certPolicies->value);
		}
	}
	if( NULL != pCert2->exts )
	{
		if( NULL != pCert2->exts->certPolicies )
		{
			pCert2Pol = (Policy_struct*)(pCert2->exts->certPolicies->value);
		}
	}

	tmpval1 = tmpval2 = 0;

	if( pCert2Pol != pCert1Pol )
	{
		if( NULL == pCert2Pol )
			return 1;

		if( NULL == pCert1Pol )
			return 2;

		if( NULL != acceptablePolicySet )
		{
			int policyCount = 0;
			while( NULL != acceptablePolicySet[policyCount] )
			{
				policyCount++;
			}

			tmpval1 = 0;
			while( pCert1Pol != NULL )
			{
				if( NULL != pCert1Pol->policy_id )
				{
					for( XX = 0; XX < policyCount; XX++ )
					{
						if( 0 == strcmp(pCert1Pol->policy_id, acceptablePolicySet[XX]) )
						{
							tmpval1++;
							break;
						}
					}
				}
				pCert1Pol = pCert1Pol->next;
			}

			tmpval2 = 0;
			while( pCert2Pol != NULL )
			{
				if( NULL != pCert2Pol->policy_id )
				{
					for( XX = 0; XX < policyCount; XX++ )
					{
						if( 0 == strcmp(pCert2Pol->policy_id, acceptablePolicySet[XX]) )
						{
							tmpval1++;
							break;
						}
					}

				}
				pCert2Pol = pCert2Pol->next;
			}

			if( tmpval1 > tmpval2 )
			{
				return 1;
			}
			else if( tmpval2 > tmpval1 )
			{
				return 2;
			}
			
		}
		// else do nothing..
	}


// 4. Certificates with fewer RDN elements in the 
// Issuer DN should have priority
	if( NULL == pCert1->issuer )
		return CCERTSREC_CERT1_INVALID;

	if( NULL == pCert2->issuer )
		return CCERTSREC_CERT2_INVALID;

	tmpval1 = CPLI_CountRDNs(pCert1->issuer);
	tmpval2 = CPLI_CountRDNs(pCert2->issuer);

	if( tmpval1 != tmpval2 )
	{
		if( tmpval1 > tmpval2 )
		{
			return 2;
		}

		return 1;
	}

// 5. Certificates that match more RDNs between 
// the issuer DN and relying party trust anchor DN should have priority
	// ignored if NULL == trustedRootDN
	if( NULL != trustedRootDN )
	{
		tmpval1 = CPLI_CountMatchingRDNs(pCert1->issuer, trustedRootDN);
		tmpval2 = CPLI_CountMatchingRDNs(pCert2->issuer, trustedRootDN);

		if( tmpval1 > tmpval2 )
		{
			return 1;
		}
		else if( tmpval2 > tmpval1 )
		{
			return 2;
		}
	}

// 6. Certificates that match more RDNs between 
// the subject DN and the issuer DN should have priority

	if( NULL == pCert1->subject )
		return CCERTSREC_CERT1_INVALID;

	if( NULL == pCert2->subject )
		return CCERTSREC_CERT2_INVALID;

	tmpval1 = CPLI_CountMatchingRDNs(pCert1->subject, pCert1->issuer);
	tmpval2 = CPLI_CountMatchingRDNs(pCert2->subject, pCert2->issuer);

	if( tmpval1 > tmpval2 )
	{
		return 1;
	}
	else if( tmpval2 > tmpval1 )
	{
		return 2;
	}


// 7. Certificates with longer validity periods 
// (furthest notAfter date) should have priority
//typedef char CM_Time[CM_TIME_LEN];	 CM time string "yyyymmddhhmmssZ" 
	tmpval1 = strcmp( pCert1->val_not_after, pCert2->val_not_after );
	if( tmpval1 < 0 )
	{
		// cert2 expires later
		return 2;
	}
	else if( tmpval1 > 0 )
	{
		// cert1 expires later
		return 1;
	}



	// Priorities are equal
	return 1;
}

/*-------------------------------------------------------------------------*\
|  Function Name :   btoa(LPSTR byteval, LPSTR ascval, unsigned int blength)
|  Creation Date :   December 15, 1998
|  Author        :   Matt Cooper
|  Last Mode Date:   December 15, 1998
|---------------------------------------------------------------------------
|	        
|  Purpose:	Improved the speed of btoa by 500%.
|			Converts binary data to ASCII Hex.
|	        
|---------------------------------------------------------------------------
|  Inputs Params:	byteval - the binary data
|	                ascval - pointer alloc'd space > 2x the bin size
|	                blength - the length of the binary data
|  Pre-Conditions:	size of ascval MUST be > 2x blength. No overflow checking!
|  Post-Conditions:	ASCII Hex of byteval is in ascval
|  Return values:	None. (void)
|	                
\*-------------------------------------------------------------------------*/
#ifdef SOLARIS_COMPILER
const char *hex_list = "0123456789ABCDEF";
#else
static const char *hex_list = "0123456789ABCDEF";
#endif
void CPLI_btoa(char* byteval, char* ascval, unsigned int blength)
{
	if( 0 == blength || NULL == byteval || NULL == ascval )
		return;

	for( unsigned int XX = 0; XX < blength; XX++ )
	{
            *ascval++ = hex_list[(((unsigned char)(byteval[XX])) >> 4)];
            *ascval++ = hex_list[(byteval[XX] & 15)];
	}

	*ascval = '\0';
}


/*-------------------------------------------------------------------------*\
|  Function Name :   atob(LPSTR byteval, LPSTR ascval, unsigned int FAR *alength)
|  Creation Date :   December 15, 1998
|  Author        :   Matt Cooper
|  Last Mode Date:   December 15, 1998
|---------------------------------------------------------------------------
|  Purpose:	Improved the speed of previous atob by 560%
|	        Converts ASCII Hex to binary form.
|---------------------------------------------------------------------------
|  Inputs Params:	byteval - previously alloc'd buffer at least 1/2 size of
|	                the ASCII Hex string.
|	                ascval - pointer to ASCII Hex string.
|  Pre-Conditions:	byteval must be alloc'd and > 1/2 ASCII length
|  Post-Conditions:	Binary data stored in byteval
|  Return values:	0 on success
|	                
\*-------------------------------------------------------------------------*/
// Lookup table
#ifdef SOLARIS_COMPILER
const unsigned char binVal[256] =
#else
static const unsigned char binVal[256] =
#endif
{/* 0x0 0x1 0x2 0x3 0x4 0x5 0x6 0x7 0x8 0x9 0xA 0xB 0xC 0xD 0xE 0xF */
	0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0, /* 0x .............. */
	0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0, /* 1x .............. */
    0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0, /* 2x  !"#$%&'()*+,-./   */
    0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0, /* 3x 0123456789:;<=>?   */
    0xF0,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0, /* 4x @ABCDEFGHIJKLMNO   */
    0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0, /* 5X PQRSTUVWXYZ[\]^_   */
    0xF0,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0, /* 6x `abcdefghijklmno   */
    0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0, /* 7X PQRSTUVWXYZ[\]^_   */
    0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0, /* 8X PQRSTUVWXYZ[\]^_   */
    0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0, /* 9X PQRSTUVWXYZ[\]^_   */
    0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0, /* AX PQRSTUVWXYZ[\]^_   */
    0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0, /* BX PQRSTUVWXYZ[\]^_   */
    0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0, /* CX PQRSTUVWXYZ[\]^_   */
    0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0, /* DX PQRSTUVWXYZ[\]^_   */
    0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0, /* EX PQRSTUVWXYZ[\]^_   */
    0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0  /* FX PQRSTUVWXYZ[\]^_   */
};

// Test ASCII char for validity
#define ACCEPTABLE(a)   ( binVal[a] != 0xF0 )

// define the following for max speed, partial conversion len will NOT be returned
#define ATOB_ABS_MAX_SPEED
// if not defined, the length until an error was encountered will be returned.

int CPLI_atob(char* byteval, char* ascval, unsigned int *alength)
{
	//unsigned char *binstr = (unsigned char*)byteval;

	if( NULL == ascval || NULL == byteval || NULL == alength)
		return ATOB_EMPTY_INPUT;

#ifdef _DEBUG
	if( NULL != strstr(ascval," ") )
	{
		// You must remove spaces first.
		return ATOB_INVALID_INPUT_CHAR;
	}
#endif

	unsigned int alen = strlen(ascval);
	unsigned int outlen = 0;

	if( 0 == alen )
	{
		return ATOB_EMPTY_INPUT;
	}	


	if( 0 != (alen % 2) )
	{
		#ifdef ATOB_ABS_MAX_SPEED
			return ATOB_INVALID_INPUT_LENGTH;
		#else		
			// odd length string
			if( ACCEPTABLE( ascval[0] )  )
			{
				*byteval++ = binVal[(int)ascval[0]];
				ascval++;
				alen--;
				outlen++;
			}
			else
			{
				return ATOB_INVALID_INPUT_CHAR;
			}
		#endif
	}


	for(unsigned int  XX = 0; XX < alen; XX += 2 )
	{
		if( ACCEPTABLE(ascval[XX]) && ACCEPTABLE(ascval[XX+1])  )
		{
			*byteval++ = ( binVal[ascval[XX]] << 4 ) + ( binVal[ascval[XX+1]] );
			#ifndef ATOB_ABS_MAX_SPEED
				outlen++;
			#endif
		}
		else
		{
			return ATOB_INVALID_INPUT_CHAR;
		}
	}

	#ifdef ATOB_ABS_MAX_SPEED
		outlen += (alen >> 1);
	#endif

	*alength = outlen;
	return 0;
}


long CPLI_CreatePathRecFromCerts( CPathRec &pathRec, Cert_struct *subject, Cert_struct *issuer, unsigned long flag )
{

	if( NULL == subject )
	{
		return -1;
	}
	if( NULL == subject->serial_num.data || 
		0 == subject->serial_num.num ||
		NULL == subject->issuer )
	{
		return -1;
	}

	if( NULL != issuer )
	{
		if( NULL == issuer->serial_num.data || 
			0 == issuer->serial_num.num ||
			NULL == issuer->issuer )
		{
			return -1;
		}
	}

	if( NULL != issuer )
		return pathRec.set_entry(subject->issuer,&subject->serial_num,issuer->issuer, &issuer->serial_num, flag );
	else
		return pathRec.set_entry(subject->issuer,&subject->serial_num,NULL,NULL, flag );

}


int CPLI_CountRDNs( char* dn )
{
	if( NULL == dn )
		return -1;

	int quote = 0;
	int count = 0;

	int len = strlen(dn);
	for(int XX = 0; XX < len; XX++)
	{
		if( '"' == dn[XX] )
		{
			quote ^= 1;
		}
		if( '=' == dn[XX] )
		{
			if( 1 != quote )
				count++;
		}
	}

	return count;
}

void CPLI_SquashSpacesInDN( char *pDN )
{
	if( NULL == pDN )
		return;

	int len = strlen(pDN);
	char *dn = pDN;
	char *pCopy = NULL;
	int quote = 0;
	int lastSpace = 1;
	int identifier = 1;
	int endofident = 0;

	pCopy = new char[len+2];
	if( !pCopy )
		return;

	strcpy(pCopy,dn);

	int XX = 0;
	for( ; XX < len; XX++)
	{
		do
		{
			if( '"' == pCopy[XX] )
			{
				quote ^= 1;
			}
			else if( ',' == pCopy[XX] && !quote )
			{
				identifier ^= 1;
				if( dn != pDN )
				{
					if( ' ' == *(dn-1) || '\t' == *(dn-1) )
					{
						dn--;
					}
				}
			}
			else if( '=' == pCopy[XX] && !quote )
			{
				identifier ^= 1;
				endofident = 1;
				*dn++ = pCopy[XX];
				break;
			}

			if( '\t' == pCopy[XX] && !quote )
			{
				pCopy[XX] = ' ';
			}

			if( ' ' == pCopy[XX] && !quote)
			{
				if( identifier || lastSpace || endofident )
				{
					break;
				}
				lastSpace = 1;
			}
			else
			{
				lastSpace = 0;
				endofident = 0;
			}

			*dn++ = pCopy[XX];
			*dn = '\0';
		}
		while(FALSE);
	}

	delete []pCopy;

	dn = pDN;
	len = strlen(dn);
	if ( ' ' == dn[len-1] || '\t' == dn[len-1] )
	{
		dn[len-1] = '\0';
	}
}

int CPLI_CountMatchingRDNs( char* dn1, char* dn2 )
{
	if( NULL == dn1 || NULL == dn2 )
		return -1;

	int lastComma = 0, match = 0, quote = 0, len = 0;
	int count = 0, count2 = 0;
//	int XX, YY, II;
	int XX, YY;

	char *pDN = NULL, *pDN2 = NULL;
	char *pTmp = NULL, *pTmp2 = NULL;

	//copy 1st DN
	len = strlen(dn1);

	pDN = new char[len+2];
	if( NULL == pDN )
		return -1;

	pTmp = pDN;
	strcpy( pDN, dn1 );
	pDN[len+1] = '\0';

	CPLI_SquashSpacesInDN(pDN);

	// Null commas in 1st
	for( XX = 0; XX < len; XX++)
	{
		if( '"' == pDN[XX] )
		{
			quote ^= 1;
		}
		if( ',' == pDN[XX] )
		{
			lastComma = XX;
		}
		if( '=' == pDN[XX] )
		{
			if( 1 != quote )
			{

				if( 0 != lastComma )
				{
					pDN[lastComma] = '\0';
					//II = 1;
				}
				count++;
			}
		}
	}

	// copy 2nd DN
	len = strlen(dn2);

	pDN2 = new char[len+2];
	if( NULL == pDN2 )
	{
		delete []pDN;
		return -1;
	}

	pTmp2 = pDN2;
	strcpy( pDN2, dn2 );
	pDN2[len+1] = '\0';

	CPLI_SquashSpacesInDN(pDN2);

	// Null commas in 2nd
	quote = lastComma = 0;
	for( XX = 0; XX < len; XX++)
	{
		if( '"' == pDN2[XX] )
		{
			quote ^= 1;
		}
		if( ',' == pDN2[XX] )
		{
			lastComma = XX;
		}
		if( '=' == pDN2[XX] )
		{
			if( 1 != quote )
			{

				if( 0 != lastComma )
				{
					pDN2[lastComma] = '\0';
					//II = 1;
				}
				count2++;
			}
		}
	}

	for( XX = 0; XX < count; XX++ )
	{
		#if defined(_WIN32) && defined(_DEBUG)
			if( NULL == pTmp )
			{
				ASSERT(FALSE);
				break;
			}
		#endif

		pTmp2 = pDN2;

		for( YY = 0; YY < count2; YY++ )
		{

			#if defined(_WIN32) && defined(_DEBUG)
				if( NULL == pTmp2 )
				{
					ASSERT(FALSE);
					break;
				}
			#endif

			if( 0 == stricmp(pTmp,pTmp2) )
			{
				match++;
				break;
			}

			do
			{
				pTmp2++;
			}
			while(pTmp2[0] != '\0' );
			pTmp2++;
		}

		do
		{
			pTmp++;
		}
		while(pTmp[0] != '\0' );

		pTmp++;
	}

	delete []pDN;
	delete []pDN2;

	return match;
}



void CPLI_set_bit(unsigned long *flag, unsigned long bit) 
{ 
	*flag |= bit; 
}

void CPLI_unset_bit(unsigned long *flag, unsigned long bit)
{
	unsigned long setflag;
	memset(&setflag,0xFF,sizeof(unsigned long));
	setflag ^= bit;
	*flag &= setflag;
}

ULONG CPLI_invert_mask(unsigned long bits)
{
	unsigned long setflag;
	memset(&setflag,0xFF,sizeof(unsigned long));
	setflag ^= bits;
	return setflag;
}

int CPLI_is_bit_set(unsigned long flag, unsigned long bit)
{
	if( bit == (bit & flag) )
		return -1;
	return 0;
}

unsigned long CPLI_get_bit_mask( short OneBasedBitToSet )
{
//  0000 0000 0000 0000 0000 0000 0000 0000
// 32                                     1
	unsigned long tmp = 1;
	return (tmp <<= (OneBasedBitToSet-1));
}

int IsInErrRange( long rv, long errbase )
{
	if( (rv >= errbase) && (rv < errbase + 1000) )
	{
		return -1;
	}

	return 0;
}

// define to do read access checking under ms-win32 in this function ONLY
#define _USE_WIN32_PTR_VALIDATION

//BOOL IsBadReadPtr(  CONST VOID *lp,  // address of memory block
  //UINT ucb         // size of block);
int IsBadCert( Cert_struct *pCert )
{
	if( NULL == pCert )
	{
		return -1;
	}

	do
	{

		#if defined(_WIN32) && defined(_USE_WIN32_PTR_VALIDATION)
			if( IsBadReadPtr( pCert, sizeof(Cert_struct) ) )
				break;
		#endif
		
		if( NULL == pCert->issuer || NULL == pCert->subject )
			break;
		
		#if defined(_WIN32) && defined(_USE_WIN32_PTR_VALIDATION)
			if( IsBadStringPtr( pCert->issuer, 1024 ) )
				break;

			if( IsBadStringPtr( pCert->subject, 1024 ) )
				break;
		#endif

		if( NULL == pCert->sig.alg && NULL == pCert->signature )
			break;

		#if defined(_WIN32) && defined(_USE_WIN32_PTR_VALIDATION)
			if( NULL != pCert->sig.alg )
			{
				if( IsBadStringPtr( pCert->sig.alg, 64 ) )
					break;
			}
			if( NULL != pCert->signature )
			{
				if( IsBadStringPtr( pCert->signature, 64 ) )
					break;
			}
		#endif

		if( 0 == pCert->serial_num.num || NULL == pCert->serial_num.data )
			break;

		#if defined(_WIN32) && defined(_USE_WIN32_PTR_VALIDATION)
			if( IsBadReadPtr( pCert->serial_num.data, pCert->serial_num.num  ) )
				break;
		#endif

		if( 1 > pCert->version )
			break;

		if( NULL == pCert->val_not_after || NULL == pCert->val_not_before )
			break;

		#if defined(_WIN32) && defined(_USE_WIN32_PTR_VALIDATION)
			if( IsBadStringPtr( pCert->val_not_after, 64 ) )
				break;
			if( IsBadStringPtr( pCert->val_not_before, 64 ) )
				break;
			
			if( NULL != pCert->exts )
			{
				if( IsBadReadPtr( pCert->exts, sizeof(Cert_exts_struct)  )  )
					break;
			}
		#endif
		
		return 0;

	}
	while(FALSE);


	return -1;
}

/* #ifndef CPU=PPC603 */ /* Added by Masanori Satake. */
#ifndef VX /* Added by Masanori Satake. */
#define _X86_BYTE_ORDER
#endif /* #ifndef CPU=PPC603 */

ULONG CPLI_BinToLong( unsigned char* data, int len )
{
	if( len > 4 || NULL == data )
		return 0;

	unsigned char u[4] = {'\0','\0','\0','\0'};
	int pos = 3;
	
	while( len )
	{
		len--;
		u[pos] = data[len];
		pos--;
	}

	
#if defined(_X86_BYTE_ORDER)
	return (u[0] << 24) | (u[1] << 16) | (u[2] << 8) | u[3];
#else
	return *(ULONG*)(&(u[0]));
#endif
}

//	union { U8 b[4]; U32 l; } u;(ULONG*)

long CPLI_GetForwardCrossCert( Bytes_struct *pCrossCertPair, Bytes_struct *pForwardCert )
{
	if( !pCrossCertPair || !pForwardCert )
		return CPL_PARAM_MISSING;

	if( 0 >= pCrossCertPair->num || NULL == pCrossCertPair->data )
		return CPL_PARAM_MISSING;

	#if defined(_WIN32) && defined(_USE_WIN32_PTR_VALIDATION)
		if( IsBadReadPtr( pCrossCertPair->data, pCrossCertPair->num  )  )
		{
			#if defined(_DEBUG)
                                #ifdef _WIN32 /* Added by Masanori Satake. */
				afxDump << "ERROR: CPLI_GetForwardCrossCert: IsBadReadPtr( pCrossCertPair->data, pCrossCertPair->num  )\n";
                                #else /* _UNIX or VX */
				PRINTERR("ERROR: CPLI_GetForwardCrossCert: IsBadReadPtr( pCrossCertPair->data, pCrossCertPair->num  )\n");
                                #endif /* #ifdef _WIN32 */
			#endif
			return CPL_PTR_INVALID;
		}
	#endif

	long rv = CPLI_CROSSCERT_ASN_ERROR;
	long len = pCrossCertPair->num;
	unsigned char Tag = '\0';
	long len2 = 0;
	long DataLen = 0;
	unsigned char* pData = pCrossCertPair->data;

	#if defined(_DEBUG)
		if( sizeof(unsigned char) != 1 )
		{
			*(char*)NULL = '\0';
			// This code will not function under wide character
		}
	#endif

#ifndef VX /* Added by Masanori Satake. */
	#if !defined(_DEBUG)
	try	{
	#endif
#endif
	do
	{
		// check len
		if( len < 2 )
			break;

		// seq tag
		if( pData[0] != 0x30 )
			break;

		// pass over seq tag
		pData++; len--;

		// len tag
		Tag = pData[0];
		if( (Tag & 0x80) != 0x80 )
			break;

		// pass over len tag
		pData++; len--;

		// extract lower byte
		Tag &= 0x0F;
		len2 = (long)Tag;

		if( len2 > 4 || len < len2 )
			break;

		// covert len to x86
		DataLen = CPLI_BinToLong(&(pData[0]),len2);

		pData += len2; len -= len2;

		if( DataLen > len || DataLen == 0 )
			break;

		if( pData[0] != 0xA0 )
		{
			if( pData[0] == 0xA1 )
			{
				// reverse only
				rv = CPLI_NO_FORWARD_CERT;
			}
			
			break;
		}
		
		pData++; len--;

		// len tag for forward cert
		Tag = pData[0];
		if( (Tag & 0x80) != 0x80 )
			break;

		// pass over len tag
		pData++; len--;

		// extract lower byte
		Tag &= 0x0F;
		len2 = (long)Tag;

		if( len2 > 4 || len < len2 )
			break;

		// covert len to x86
		DataLen = CPLI_BinToLong(&(pData[0]),len2);

		pData += len2; len -= len2;

		if( DataLen > len )
			break;

		// pData points to forward cert, DataLen = cert len
		pForwardCert->num = DataLen;
		pForwardCert->data = pData;

		rv = 0;
	}
	while(FALSE);

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

long CPLI_TranslateErrorNumber(long errcode)
{
	if( !errcode )
		return 0;


	if (IsInErrRange(errcode, CPL_ERR_BASE))
	{
		return errcode;
	}
	else if (IsInErrRange(errcode, CCMAPIINTERFACE_ERR_BASE))
	{
		// CCMAPI Error
		if( errcode == CCMAPIINTERFACE_LOADLIB_FAILED )
		{
			errcode = CPL_LOAD_LIBRARY_CMAPI_FAIL;
		}
		else if( errcode == CCMAPIINTERFACE_ALLOC_ERR )
		{
			errcode = CPL_ALLOC_FAILURE;
		}
		else if( errcode == CCMAPIINTERFACE_CMAPI_EXCEPTION )
		{
			errcode = CPL_EXCEPTION_CAUGHT;
		}
		else
		{
			errcode = CPL_CMAPI_ERROR;
		}
	}
	else if (IsInErrRange(errcode, CCERTSREC_ERR_BASE))
	{
		// Memory Cert Cache Error
		if( errcode == CCERTSREC_INVALID_CERT )
		{
			errcode = CPL_DECODE_CERT_FAIL;
		}
		else if( errcode == CCERTSREC_ALLOC_FAIL )
		{
			errcode = CPL_ALLOC_FAILURE;
		}
		else
		{
			errcode = CPL_CERT_CACHE_ERROR;
		}
	}
	else if (IsInErrRange(errcode, CERTCACHE_ERRBASE))
	{
		// Memory Cert Cache Error
		if( errcode == CERTCACHE_ALLOC_FAIL )
		{
			errcode = CPL_ALLOC_FAILURE;
		}
		else if( errcode == CERTCACHE_NO_CALLBACK_PTR )
		{
			errcode = CPL_CALLBACK_PTRS_MISSING;
		}
		else if( errcode == CERTCACHE_FATAL_EXCEPTION )
		{
			errcode = CPL_EXCEPTION_CAUGHT;
		}
		else
		{
			errcode = CPL_CERT_CACHE_ERROR;
		}
	}
	else if (IsInErrRange(errcode, CPATHREC_ERR_BASE))
	{
		// Path Cache Error
		if( errcode == CPATHREC_ALLOC_FAIL )
		{
			errcode = CPL_ALLOC_FAILURE;
		}
		else
		{
			errcode = CPL_PATH_CACHE_ERROR;
		}
	}
	else if (IsInErrRange(errcode, PATHCACHE_ERRBASE))
	{
		// Path Cache Error
		if( errcode ==  PATHCACHE_INVALID_CERT_DATA )
		{
			errcode = CPL_DECODE_CERT_FAIL;
		}
		else if( errcode == PATHCACHE_ALLOC_FAIL )
		{
			errcode = CPL_ALLOC_FAILURE;
		}
		else if( errcode == PATHCACHE_OUTPUTFILE_FAIL )
		{
			errcode = CPL_CACHE_FILE_WRITE_FAIL;
		}
		else if( errcode == PATHCACHE_INPUTFILE_FAIL )
		{
			errcode = CPL_CACHE_FILE_READ_FAIL;
		}
		else if( errcode == PATHCACHE_EXCEPTION )
		{
			errcode = CPL_EXCEPTION_CAUGHT;
		}
		else if( errcode == PATH_CACHE_NO_DISK_PATH )
		{
			errcode = CPL_CACHE_DISK_PATH_MISSING;
		}
		else
		{
			errcode = CPL_PATH_CACHE_ERROR;
		}
	}
	else
	{
		errcode = CPL_UNEXPECTED_ERROR; // other error?
	}

	return errcode;

}

#ifdef _DEBUG_VERBOSE
#undef _DEBUG_VERBOSE
#endif

#undef _USE_WIN32_PTR_VALIDATION
