Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2664 lines
80 KiB

//-------------------------------------------------------------------------
//
// Microsoft Windows
//
// Copyright (C) Microsoft Corporation, 1995 - 1997
//
// File: tdecode.cpp
//
// Contents: API testing of CryptEncodeObject/CryptDecodeObject.
//
// History: 22-January-97 xiaohs created
//
//--------------------------------------------------------------------------
#include "tdecode.h"
//--------------------------------------------------------------------------
// Globals
//--------------------------------------------------------------------------
//the count of errors in the program
DWORD g_dwErrCnt=0;
HCRYPTPROV g_hProv=NULL;
//--------------------------------------------------------------------------
// The utility function to display the parameters for the input.
//--------------------------------------------------------------------------
static void Usage(void)
{
printf("\n");
printf("Usage: tdecode [options] <FileTypes><Filename>\n");
printf("\n");
printf("FileTypes are(case sensitive):\n");
printf(" C -This is a certificate file\n");
printf(" R -This is a certificate request blob file\n");
printf(" S -This is a signed message file\n");
printf("\n");
printf("Options are(case sensitive):\n");
printf(" -i - A complete test on cbEncoded in CryptDecodeObject\n");
printf(" Default does not do the check\n");
printf(" -o - A complete test on *pcbStructInfo on CryptDecodeObject\n");
printf(" Default does not do the check\n");
printf(" -b - A complete test on *pcbStructInfo and cbEncoded\n");
printf(" Default does not do the check\n");
printf("\n");
return;
}
//--------------------------------------------------------------------------
// The utility function to display a message that the test is not exeucted
//--------------------------------------------------------------------------
static void NotExecuted(void)
{
printf("*****************************************************\n");
printf(" Summary information for TDecode Test \n");
printf("*****************************************************\n"); \
printf("\n");
printf("The test is not executed!\n");
return;
}
//--------------------------------------------------------------------------
// The main program that Decode/Encode Certifitcate, Certificate Request,
// and CRL.
//--------------------------------------------------------------------------
void _cdecl main(int argc, char * argv[])
{
BOOL fStructLengthCheck=FALSE;
BOOL fBLOBLengthCheck=FALSE;
DWORD dwFileType=0;
LPSTR pszFilename=NULL;
BYTE pbByte[100]=
{0x00, 0xa1, 0x23, 0x45, 0x56, 0x78, 0x9a, 0xbc,0xdf,0xee,
0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0XFF, 0xA6, 0x8f,0xe4, 0x0f,
0x00, 0xa1, 0x23, 0x45, 0x56, 0x78, 0x9a, 0xbc,0xdf,0xee,
0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0XFF, 0xA6, 0x8f,0xe4, 0x0f,
0x00, 0xa1, 0x23, 0x45, 0x56, 0x78, 0x9a, 0xbc,0xdf,0xee,
0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0XFF, 0xA6, 0x8f,0xe4, 0x0f,
0x00, 0xa1, 0x23, 0x45, 0x56, 0x78, 0x9a, 0xbc,0xdf,0xee,
0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0XFF, 0xA6, 0x8f,0xe4, 0x0f,
0x00, 0xa1, 0x23, 0x45, 0x56, 0x78, 0x9a, 0xbc,0xdf,0xee,
0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0XFF, 0xA6, 0x8f,0xe4, 0x0f};
//parsing through the command line input parameters
while (--argc>0)
{
if (**++argv == '-')
{
switch(argv[0][1])
{
case 'i':
fBLOBLengthCheck=TRUE;
break;
case 'o':
fStructLengthCheck=TRUE;
break;
case 'b':
fBLOBLengthCheck=TRUE;
fStructLengthCheck=TRUE;
break;
default:
Usage();
NotExecuted();
return;
}
}
else
{
//parsing through the file name
switch(**argv)
{
case 'C':
dwFileType=CERT_CRL_FILE;
break;
case 'R':
dwFileType=CERT_REQUEST_FILE;
break;
case 'S':
dwFileType=SIGNED_MSG_FILE;
break;
default:
Usage();
NotExecuted();
return;
}
//make sure there is a file name specified
if(argv[0][1]=='\0')
{
Usage();
NotExecuted();
return;
}
//get the file name
pszFilename = &(argv[0][1]);
}
}
//if the file name is NULL, something is wrong in the input parameter
if(!pszFilename)
{
Usage();
NotExecuted();
return;
}
//acquireContext
TESTC(CryptAcquireContext(&g_hProv,NULL,NULL,PROV_RSA_FULL,CRYPT_VERIFYCONTEXT),TRUE)
//test PKCS_UTC_TIME
TESTC(VerifyPKCS_UTC_TIME(fStructLengthCheck, fBLOBLengthCheck),TRUE)
//test PKCS_TIME_REQUEST
TESTC(VerifyPKCS_TIME_REQUEST(fStructLengthCheck, fBLOBLengthCheck),TRUE)
//decode the corresponding file types.
switch(dwFileType)
{
case CERT_CRL_FILE:
TESTC(DecodeCertFile(pszFilename,fStructLengthCheck,
fBLOBLengthCheck),TRUE)
break;
case CERT_REQUEST_FILE:
TESTC(DecodeCertReqFile(pszFilename,fStructLengthCheck,
fBLOBLengthCheck),TRUE)
break;
case SIGNED_MSG_FILE:
TESTC(DecodeSignedMsgFile(pszFilename,fStructLengthCheck,
fBLOBLengthCheck),TRUE)
break;
default:
break;
}
TCLEANUP:
//release the CSP
if(g_hProv)
TCHECK(CryptReleaseContext(g_hProv,0),TRUE);
//print out the test result
DisplayTestResult(g_dwErrCnt);
}
//--------------------------------------------------------------------------
// Local Functions
//--------------------------------------------------------------------------
///////////////////////////////////////////////////////////////////////////
//Error Manipulations
//--------------------------------------------------------------------------
// DisplayTestResult
//--------------------------------------------------------------------------
void DisplayTestResult(DWORD dwErrCnt)
{
printf("*****************************************************\n");
printf(" Summary information for TDecode Test \n");
printf("*****************************************************\n");
printf("\n");
if(!dwErrCnt)
printf("This test succeeded!\n");
else
printf("This test failed with total %d errors!\n",dwErrCnt);
return;
}
//--------------------------------------------------------------------------
// Validate the return code is the same as expected. If they are not the
// same, increment the error count and print out the file name and the line
// number.
//--------------------------------------------------------------------------
BOOL Validate(DWORD dwErr, BOOL fSame, char *szFile, DWORD dwLine)
{
if(fSame)
return TRUE;
printf("*****************************************************\n");
printf("Error: %d 0x%x occurred at file %s line %d\n\n",
dwErr, dwErr, szFile, dwLine);
g_dwErrCnt++;
return FALSE;
}
//--------------------------------------------------------------------------
// Output the two BLOBs. One is the original one, the other is the
// BLOB encoded by pvStructInfo.
//--------------------------------------------------------------------------
void OutputError(LPCSTR lpszStructType, DWORD cbSecondEncoded, DWORD cbEncoded,
BYTE *pbSecondEncoded, BYTE *pbEncoded)
{
DWORD cbMin=0;
printf("------------------------------------------------------\n");
printf("An inconsistency in BLOBs has been found!\n");
//print out the lpszStructType
if(((DWORD_PTR)lpszStructType)>>8 == 0)
printf("The lpszStructType is %d.\n",(DWORD)(DWORD_PTR)lpszStructType);
else
printf("The lpszStructType is %s.\n",lpszStructType);
printf("\n");
//print out the size of BLOBs
printf("The original cbEncoded is %d.\n",cbEncoded);
printf("The new cbEncoded is %d.\n",cbSecondEncoded);
printf("\n");
//see if the min of cbEncoded and cbSecondEncoded is the same
if(cbSecondEncoded>cbEncoded)
cbMin=cbEncoded;
else
cbMin=cbSecondEncoded;
if(memcmp(pbSecondEncoded,pbEncoded,cbMin)==0)
printf("The two blobs are the same up to %dth byte.\n",cbMin);
//print out all the bytes in the BLOBs
printf("The original BLOB is:\n");
PrintBytes(" ", pbEncoded, cbEncoded);
printf("\n");
printf("The new BLOB is:\n");
PrintBytes(" ",pbSecondEncoded, cbSecondEncoded);
return;
}
//--------------------------------------------------------------------------
// Print out the Byte in 16 bytes per row and their corresponding HEX.
//--------------------------------------------------------------------------
void PrintBytes(LPCSTR pszHdr, BYTE *pb, DWORD cbSize)
{
ULONG cb, i;
while (cbSize > 0)
{
printf("%s", pszHdr);
cb = min(CROW, cbSize);
cbSize -= cb;
for (i = 0; i<cb; i++)
printf(" %02X", pb[i]);
for (i = cb; i<CROW; i++)
printf(" ");
printf(" '");
for (i = 0; i<cb; i++)
if (pb[i] >= 0x20 && pb[i] <= 0x7f)
printf("%c", pb[i]);
else
printf(".");
pb += cb;
printf("'\n");
}
}
///////////////////////////////////////////////////////////////////////////
//General Testing routings
//--------------------------------------------------------------------------
// Validate CryptEncodeObject/CryptDecodeObject handle the NULL or invalid
// parameters correctly.
//--------------------------------------------------------------------------
BOOL ParameterTest(LPCSTR lpszStructType, DWORD cbEncoded, BYTE *pbEncoded)
{
BOOL fSucceeded=FALSE;
DWORD cbStructInfo=0;
void *pvStructInfo=NULL;
DWORD cbCorrectSize=0;
DWORD cbLengthOnly=0;
DWORD cbSecondEncoded=0;
BYTE *pbSecondEncoded=NULL;
DWORD dwReturn=0;
DWORD dwEncodingType=CRYPT_ENCODE_TYPE;
//init
assert(cbEncoded);
assert(pbEncoded);
assert(lpszStructType);
//We have different decoding type for PKCS7_SIGNER_INFO
if((DWORD_PTR)(lpszStructType)==(DWORD_PTR)(PKCS7_SIGNER_INFO))
dwEncodingType=MSG_ENCODING_TYPE;
cbSecondEncoded=cbEncoded;
pbSecondEncoded=(BYTE *)SAFE_ALLOC(cbEncoded);
CHECK_POINTER(pbSecondEncoded)
//Decode the BLOB correctly
cbStructInfo=1000;
TESTC(CryptDecodeObject(dwEncodingType,lpszStructType,pbEncoded,
cbEncoded,CRYPT_DECODE_NOCOPY_FLAG,NULL,&cbStructInfo),TRUE)
cbLengthOnly=cbStructInfo;
//allocate the memory
pvStructInfo=SAFE_ALLOC(cbStructInfo);
CHECK_POINTER(pvStructInfo);
TESTC(CryptDecodeObject(dwEncodingType,lpszStructType,pbEncoded,
cbEncoded,CRYPT_DECODE_NOCOPY_FLAG,pvStructInfo,&cbStructInfo),TRUE)
cbCorrectSize=cbStructInfo;
//Test incorrect ENCODING type
//pass X509_NDR_ENCODING
TESTC(CryptDecodeObject(X509_NDR_ENCODING,lpszStructType,pbEncoded,
cbEncoded,CRYPT_DECODE_NOCOPY_FLAG,pvStructInfo,&cbStructInfo),FALSE)
// Since we do not know the correct return code, make sure at least
//S_OK is not returned.
TCHECK(GetLastError()!=S_OK, TRUE);
TESTC(CryptEncodeObject(X509_NDR_ENCODING, lpszStructType,pvStructInfo,
pbSecondEncoded,&cbSecondEncoded),FALSE)
TCHECK(GetLastError()!=S_OK, TRUE);
//pass X509_NDR_ENCODING|X509_ASN_ENCODING
TESTC(CryptDecodeObject(X509_NDR_ENCODING|X509_ASN_ENCODING,lpszStructType,pbEncoded,
cbEncoded,CRYPT_DECODE_NOCOPY_FLAG,pvStructInfo,&cbStructInfo),FALSE)
TCHECK(GetLastError()!=S_OK, TRUE);
TESTC(CryptEncodeObject(X509_NDR_ENCODING|X509_ASN_ENCODING, lpszStructType,pvStructInfo,
pbSecondEncoded,&cbSecondEncoded),FALSE)
TCHECK(GetLastError()!=S_OK, TRUE);
//Test invalid/unsupported lpszStructType
//passing NULL for lpszStructType
TESTC(CryptDecodeObject(dwEncodingType,CRYPT_ENCODE_DECODE_NONE,pbEncoded,
cbEncoded,CRYPT_DECODE_NOCOPY_FLAG,pvStructInfo,&cbStructInfo),FALSE)
TCHECK(GetLastError()!=S_OK, TRUE);
TESTC(CryptEncodeObject(dwEncodingType, CRYPT_ENCODE_DECODE_NONE,pvStructInfo,
pbSecondEncoded,&cbSecondEncoded),FALSE)
TCHECK(GetLastError()!=S_OK, TRUE);
//passing invalid lpszStructType
TESTC(CryptDecodeObject(dwEncodingType,INVALID_LPSZSTRUCTTYPE,pbEncoded,
cbEncoded,CRYPT_DECODE_NOCOPY_FLAG,pvStructInfo,&cbStructInfo),FALSE)
TCHECK(GetLastError()!=S_OK, TRUE);
TESTC(CryptEncodeObject(dwEncodingType, INVALID_LPSZSTRUCTTYPE,pvStructInfo,
pbSecondEncoded,&cbSecondEncoded),FALSE)
TCHECK(GetLastError()!=S_OK, TRUE);
// CryptEncodeObject: pbEncoded is not NULL while cbEncoded is 0.
cbSecondEncoded=0;
TESTC(CryptEncodeObject(dwEncodingType, lpszStructType,pvStructInfo,
pbSecondEncoded,&cbSecondEncoded),FALSE)
TCHECK(GetLastError(),ERROR_MORE_DATA);
//CryptDecodeObject: pvStructInfo is not NULL while pcbStructInfo is 0
cbStructInfo=0;
TESTC(CryptDecodeObject(dwEncodingType,lpszStructType,pbEncoded,
cbEncoded,CRYPT_DECODE_NOCOPY_FLAG,pvStructInfo,&cbStructInfo),FALSE)
TCHECK(cbStructInfo,cbCorrectSize);
TCHECK(GetLastError(),ERROR_MORE_DATA);
//CryptDecodeObject: Pass invalid blobs
cbSecondEncoded=(DWORD)(cbEncoded/2);
TESTC(CryptDecodeObject(dwEncodingType,lpszStructType,pbEncoded,
cbEncoded-cbSecondEncoded,CRYPT_DECODE_NOCOPY_FLAG,pvStructInfo,&cbStructInfo),FALSE)
dwReturn=GetLastError();
// Ignore ASN1_ERR_EOD
if (dwReturn != 0x80093102) {
TCHECKALL(dwReturn,CRYPT_E_BAD_ENCODE, CRYPT_E_OSS_ERROR+DATA_ERROR);
}
//CryptDecodeObject: Pass cbEncoded=0
TESTC(CryptDecodeObject(dwEncodingType,lpszStructType,pbEncoded,
0,CRYPT_DECODE_NOCOPY_FLAG,pvStructInfo,&cbStructInfo),FALSE)
dwReturn=GetLastError();
if (dwReturn != 0x80093102) {
TCHECKALL(dwReturn,CRYPT_E_BAD_ENCODE, CRYPT_E_OSS_ERROR+MORE_INPUT);
}
//CryptDecodeObject: lpszStructType mismatches pbEncoded
TESTC(MismatchTest(lpszStructType, cbEncoded, pbEncoded,cbLengthOnly),TRUE)
fSucceeded=TRUE;
TCLEANUP:
//release memory
SAFE_FREE(pbSecondEncoded)
SAFE_FREE(pvStructInfo)
return fSucceeded;
}
//--------------------------------------------------------------------------
// The routine to test CryptDecodeObject() handles the mismatch between
// lpszStructType and pbEncoded
//
// PreCondition: This routine assumes that lpszStructType's high-order
// word is 0 and the low order word specifies the integer
// identifier for the type of the given structure.
//
// cbCorrectStructInfo is the correct size for pvStructInfo in CryptDecodeObject
//--------------------------------------------------------------------------
BOOL MismatchTest(LPCSTR lpszStructType, DWORD cbEncoded, BYTE *pbEncoded,
DWORD cbCorrectStructInfo)
{
BOOL fSucceeded=FALSE;
DWORD dwrgSize=0;
DWORD dwError=0;
ULONG iIndex=0;
void *pvStructInfo=NULL;
DWORD cbStructInfo=cbCorrectStructInfo;
DWORD dwEncodingType=CRYPT_ENCODE_TYPE;
LPCSTR rglpszStructType[]={X509_CERT_TO_BE_SIGNED,
X509_CERT_CRL_TO_BE_SIGNED,
X509_CERT_REQUEST_TO_BE_SIGNED,
X509_EXTENSIONS,
X509_NAME_VALUE,
X509_NAME,
X509_PUBLIC_KEY_INFO,
X509_AUTHORITY_KEY_ID,
X509_KEY_ATTRIBUTES,
X509_KEY_USAGE_RESTRICTION,
X509_ALTERNATE_NAME,
X509_BASIC_CONSTRAINTS,
X509_KEY_USAGE,
X509_BASIC_CONSTRAINTS2,
X509_CERT_POLICIES,
PKCS_UTC_TIME,
PKCS_TIME_REQUEST,
RSA_CSP_PUBLICKEYBLOB,
PKCS7_SIGNER_INFO};
//init
dwrgSize=sizeof(rglpszStructType)/sizeof(rglpszStructType[0]);
//We have different decoding type for PKCS7_SIGNER_INFO
if((DWORD_PTR)(lpszStructType)==(DWORD_PTR)(PKCS7_SIGNER_INFO))
dwEncodingType=MSG_ENCODING_TYPE;
pvStructInfo=SAFE_ALLOC(cbCorrectStructInfo);
CHECK_POINTER(pvStructInfo);
//start to decode the BLOB. Should fail when lpszStructType mismatches pbEncoded
for(iIndex=0; iIndex<dwrgSize; iIndex++)
{
cbStructInfo=cbCorrectStructInfo;
//skip the test if lpszStructType==X509_NAME_VALUE since the X509_NAME_VALUE
//allows any encoded type. It has the dwValueType CERT_RDN_ENCODED_BLOB.
if((DWORD_PTR)(rglpszStructType[iIndex])==(DWORD_PTR)X509_NAME_VALUE)
continue;
//if lpszStructType is the correct type, TRUE should be returned.
if((DWORD_PTR)lpszStructType==(DWORD_PTR)(rglpszStructType[iIndex]))
{
TESTC(CryptDecodeObject(dwEncodingType, rglpszStructType[iIndex],
pbEncoded,cbEncoded,CRYPT_DECODE_NOCOPY_FLAG,pvStructInfo,&cbStructInfo),TRUE)
}
else
{
//error should occur
TESTC(CryptDecodeObject(dwEncodingType, rglpszStructType[iIndex],
pbEncoded,cbEncoded,CRYPT_DECODE_NOCOPY_FLAG,pvStructInfo,&cbStructInfo),FALSE)
//test the return code
dwError=GetLastError();
//we are not sure that should be expected here. The following error has
//occurred:
//E_INVALIDARG, CRYPT_E_OSS_ERROR+PDU_MISMATCH, +DATA_ERROR, or
//+MORE_INPUT
//make sure at lease S_OK is not returned
TCHECK(dwError!=S_OK, TRUE);
}
}
fSucceeded=TRUE;
TCLEANUP:
//release the memory
SAFE_FREE(pvStructInfo)
return fSucceeded;
}
///////////////////////////////////////////////////////////////////////////////
//General Decode/Encode Testing routines
//--------------------------------------------------------------------------
// Get a BLOB based on an input file.
//
//--------------------------------------------------------------------------
BOOL RetrieveBLOBfromFile(LPSTR pszFileName,DWORD *pcbEncoded,BYTE **ppbEncoded)
{
BOOL fSucceeded=FALSE;
DWORD cCount=0;
HANDLE hFile=NULL;
assert(pszFileName);
assert(pcbEncoded);
assert(ppbEncoded);
if((hFile = CreateFile(pszFileName,
GENERIC_READ,
0, NULL, OPEN_EXISTING, 0, NULL))==INVALID_HANDLE_VALUE)
PROCESS_ERR_GOTO("Can not open the file!\n");
//Get the size of the file
cCount=GetFileSize(hFile, NULL);
//make sure the file is not empty
TESTC(cCount!=0, TRUE)
//allocate memory
*ppbEncoded=(BYTE *)SAFE_ALLOC(cCount);
*pcbEncoded=cCount;
//fill the buffer
TESTC(ReadFile( hFile,*ppbEncoded, *pcbEncoded,&cCount,NULL),TRUE)
//make sure that we have the right number of bytes
TESTC(cCount,*pcbEncoded)
fSucceeded=TRUE;
TCLEANUP:
if(hFile)
CloseHandle(hFile);
return fSucceeded;
}
//--------------------------------------------------------------------------
// A general routine to encode the singer info struct and
// add Attributes to the structur if there was none
//
//--------------------------------------------------------------------------
BOOL EncodeSignerInfoWAttr(PCMSG_SIGNER_INFO pSignerInfo,DWORD *pbSignerEncoded,
BYTE **ppbSignerEncoded)
{
BOOL fSucceeded=FALSE;
//add attribute to the CMSG_SINGER_INFO struct if necessary
//make up the attributes
BYTE rgAttribValue1[]={0x02, 0x02, 0x11, 0x11};
BYTE rgAttribValue2[]={0x02, 0x02, 0x11, 0x11};
//make 3 CRYPT_ATTRIBUTE
CRYPT_ATTRIBUTE rgCryptAttribute[3];
CRYPT_ATTR_BLOB rgAttribBlob[3];
rgAttribBlob[0].cbData=sizeof(rgAttribValue2);
rgAttribBlob[0].pbData=rgAttribValue2;
rgAttribBlob[1].cbData=sizeof(rgAttribValue2);
rgAttribBlob[1].pbData=rgAttribValue2;
rgAttribBlob[2].cbData=sizeof(rgAttribValue1);
rgAttribBlob[2].pbData=rgAttribValue1;
rgCryptAttribute[0].pszObjId="1.2.3.4";
rgCryptAttribute[0].cValue=0;
rgCryptAttribute[0].rgValue=NULL;
rgCryptAttribute[1].pszObjId="1.2.3.4";
rgCryptAttribute[1].cValue=1;
rgCryptAttribute[1].rgValue=rgAttribBlob;
rgCryptAttribute[2].pszObjId="1.2.3.4";
rgCryptAttribute[2].cValue=3;
rgCryptAttribute[2].rgValue=rgAttribBlob;
//if pSingerInfo does not include any attributes, add attributes
//to the struct
if(pSignerInfo->AuthAttrs.cAttr==0)
{
pSignerInfo->AuthAttrs.cAttr=1;
pSignerInfo->AuthAttrs.rgAttr=rgCryptAttribute;
}
if(pSignerInfo->UnauthAttrs.cAttr==0)
{
pSignerInfo->AuthAttrs.cAttr=3;
pSignerInfo->AuthAttrs.rgAttr=rgCryptAttribute;
}
//encode the struct
TESTC(CryptEncodeObject(MSG_ENCODING_TYPE,PKCS7_SIGNER_INFO,
pSignerInfo,NULL,pbSignerEncoded),TRUE)
//allocate memory
*ppbSignerEncoded=(BYTE *)SAFE_ALLOC(*pbSignerEncoded);
CHECK_POINTER(*ppbSignerEncoded);
//encode
TESTC(CryptEncodeObject(MSG_ENCODING_TYPE,PKCS7_SIGNER_INFO,
pSignerInfo,*ppbSignerEncoded,pbSignerEncoded),TRUE)
fSucceeded=TRUE;
TCLEANUP:
return fSucceeded;
}
//--------------------------------------------------------------------------
// A general routine compare two time stamp request
//
//--------------------------------------------------------------------------
BOOL CompareTimeStampRequest(CRYPT_TIME_STAMP_REQUEST_INFO *pReqNew,
CRYPT_TIME_STAMP_REQUEST_INFO *pReqOld)
{
BOOL fSucceeded=FALSE;
DWORD iIndex=0;
DWORD iValue=0;
TESTC(_stricmp(pReqNew->pszTimeStampAlgorithm,
pReqOld->pszTimeStampAlgorithm),0)
TESTC(_stricmp(pReqNew->pszContentType, pReqOld->pszContentType),0)
TESTC(pReqNew->Content.cbData, pReqOld->Content.cbData)
TESTC(memcmp(pReqNew->Content.pbData,pReqOld->Content.pbData,
pReqNew->Content.cbData),0)
TESTC(pReqNew->cAttribute, pReqOld->cAttribute)
for(iIndex=0; iIndex<pReqNew->cAttribute;iIndex++)
{
TESTC(_stricmp(pReqNew->rgAttribute[iIndex].pszObjId,
pReqOld->rgAttribute[iIndex].pszObjId),0)
TESTC(pReqNew->rgAttribute[iIndex].cValue,
pReqOld->rgAttribute[iIndex].cValue)
for(iValue=0;iValue<pReqNew->rgAttribute[iIndex].cValue;iValue++)
{
TESTC(pReqNew->rgAttribute[iIndex].rgValue[iValue].cbData,
pReqOld->rgAttribute[iIndex].rgValue[iValue].cbData)
TESTC(memcmp(pReqNew->rgAttribute[iIndex].rgValue[iValue].pbData,
pReqOld->rgAttribute[iIndex].rgValue[iValue].pbData,
pReqOld->rgAttribute[iIndex].rgValue[iValue].cbData),0)
}
}
fSucceeded=TRUE;
TCLEANUP:
return fSucceeded;
}
//--------------------------------------------------------------------------
// A general routine to verify the algorithm parameters is NULL.
//
// cbData==2 and pbData=0x05 0x00
//--------------------------------------------------------------------------
BOOL VerifyAlgorithParam(PCRYPT_ALGORITHM_IDENTIFIER pAlgorithm)
{
BOOL fSucceeded=FALSE;
TESTC((pAlgorithm->Parameters).cbData, 2);
TESTC((BYTE)((pAlgorithm->Parameters).pbData[0])==(BYTE)5,TRUE);
TESTC((BYTE)((pAlgorithm->Parameters).pbData[1])==(BYTE)0,TRUE);
fSucceeded=TRUE;
TCLEANUP:
return fSucceeded;
}
//--------------------------------------------------------------------------
// A general routine to verify the PKCS_UTC_TIME
//
//--------------------------------------------------------------------------
BOOL VerifyPKCS_UTC_TIME(BOOL fStructLengthCheck, BOOL fBLOBLengthCheck)
{
BOOL fSucceeded=FALSE;
DWORD cbEncoded=0;
BYTE *pbEncoded=NULL;
DWORD dwError;
FILETIME FileTime;
//setup the struct
FileTime.dwLowDateTime=0;
FileTime.dwHighDateTime=31457160;
//encode the struct into a BLOB
TESTC(CryptEncodeObject(CRYPT_ENCODE_TYPE,PKCS_UTC_TIME,
&FileTime,NULL,&cbEncoded),TRUE)
pbEncoded=(BYTE *)SAFE_ALLOC(cbEncoded);
CHECK_POINTER(pbEncoded)
TESTC(CryptEncodeObject(CRYPT_ENCODE_TYPE,PKCS_UTC_TIME,
&FileTime,pbEncoded,&cbEncoded),TRUE)
//decode the struct with COPY and NOCOPY options
TESTC(DecodeGenericBLOB(PKCS_UTC_TIME,cbEncoded, pbEncoded, CRYPT_DECODE_COPY_FLAG,
TRUE,fStructLengthCheck, fBLOBLengthCheck),TRUE)
TESTC(DecodeGenericBLOB(PKCS_UTC_TIME,cbEncoded, pbEncoded, CRYPT_DECODE_NOCOPY_FLAG,
TRUE,fStructLengthCheck, fBLOBLengthCheck),TRUE)
fSucceeded=TRUE;
TCLEANUP:
//print out the errors
if(!fSucceeded)
{
dwError=GetLastError();
printf("********The last error is %d\n",dwError);
//print out the pbEncoded
printf("The cbEncoded is %d, and pbEncoded is:\n",cbEncoded);
PrintBytes(" ",pbEncoded,cbEncoded);
printf("\n");
}
SAFE_FREE(pbEncoded);
return fSucceeded;
}
//--------------------------------------------------------------------------
// A general routine to verify the PKCS_TIME_REQUEST
//
//--------------------------------------------------------------------------
BOOL VerifyPKCS_TIME_REQUEST(BOOL fStructLengthCheck, BOOL fBLOBLengthCheck)
{
BOOL fSucceeded=TRUE;
CRYPT_TIME_STAMP_REQUEST_INFO TimeStampRequest;
void *pvStructInfo=NULL;
DWORD cbStructInfo=0;
DWORD cbEncoded=0;
BYTE *pbEncoded=NULL;
//make a hard-coded timestamp request
BYTE rgTestData[] = {
0x1b, 0xf6, 0x92, 0xee, 0x6c, 0x44, 0xc5, 0xed, 0x51};
BYTE rgAttribValue1[]={
0x02, 0x02, 0x11, 0x11};
BYTE rgAttribValue2[]={
0x02, 0x02, 0x11, 0x11};
//make 3 CRYPT_ATTRIBUTE
CRYPT_ATTRIBUTE rgCryptAttribute[3];
CRYPT_ATTR_BLOB rgAttribBlob[3];
rgAttribBlob[0].cbData=sizeof(rgAttribValue2);
rgAttribBlob[0].pbData=rgAttribValue2;
rgAttribBlob[1].cbData=sizeof(rgAttribValue2);
rgAttribBlob[1].pbData=rgAttribValue2;
rgAttribBlob[2].cbData=sizeof(rgAttribValue1);
rgAttribBlob[2].pbData=rgAttribValue1;
rgCryptAttribute[0].pszObjId="1.2.3.4";
rgCryptAttribute[0].cValue=0;
rgCryptAttribute[0].rgValue=NULL;
rgCryptAttribute[1].pszObjId="1.2.3.4";
rgCryptAttribute[1].cValue=1;
rgCryptAttribute[1].rgValue=rgAttribBlob;
rgCryptAttribute[2].pszObjId="1.2.3.4";
rgCryptAttribute[2].cValue=3;
rgCryptAttribute[2].rgValue=rgAttribBlob;
// initialize the timestamp structure
TimeStampRequest.pszTimeStampAlgorithm = szOID_RSA_signingTime;
TimeStampRequest.pszContentType = szOID_RSA_data;
TimeStampRequest.Content.cbData = sizeof(rgTestData);
TimeStampRequest.Content.pbData = rgTestData;
TimeStampRequest.cAttribute = 3;
TimeStampRequest.rgAttribute = rgCryptAttribute;
//encode the struct into a BLOB
TESTC(CryptEncodeObject(CRYPT_ENCODE_TYPE,PKCS_TIME_REQUEST,
&TimeStampRequest,NULL,&cbEncoded),TRUE)
pbEncoded=(BYTE *)SAFE_ALLOC(cbEncoded);
CHECK_POINTER(pbEncoded)
TESTC(CryptEncodeObject(CRYPT_ENCODE_TYPE,PKCS_TIME_REQUEST,
&TimeStampRequest,pbEncoded,&cbEncoded),TRUE)
//decode the struct with COPY and NOCOPY options
TESTC(DecodePKCS_TIME_REQUEST(cbEncoded, pbEncoded, CRYPT_DECODE_COPY_FLAG,
TRUE,fStructLengthCheck, fBLOBLengthCheck),TRUE)
TESTC(DecodePKCS_TIME_REQUEST(cbEncoded, pbEncoded, CRYPT_DECODE_NOCOPY_FLAG,
TRUE,fStructLengthCheck, fBLOBLengthCheck),TRUE)
//decode the struct and compare it with the original
TESTC(CryptDecodeObject(CRYPT_ENCODE_TYPE,PKCS_TIME_REQUEST,
pbEncoded, cbEncoded,CRYPT_DECODE_NOCOPY_FLAG,NULL,&cbStructInfo),TRUE)
pvStructInfo=SAFE_ALLOC(cbStructInfo);
CHECK_POINTER(pvStructInfo);
TESTC(CryptDecodeObject(CRYPT_ENCODE_TYPE,PKCS_TIME_REQUEST,
pbEncoded, cbEncoded,CRYPT_DECODE_NOCOPY_FLAG,pvStructInfo,&cbStructInfo),TRUE)
//compare two timstamp request
TESTC(CompareTimeStampRequest(&TimeStampRequest,
(CRYPT_TIME_STAMP_REQUEST_INFO *)pvStructInfo),TRUE)
fSucceeded=TRUE;
TCLEANUP:
SAFE_FREE(pbEncoded);
SAFE_FREE(pvStructInfo);
return fSucceeded;
}
//--------------------------------------------------------------------------
// A general routine to verify the CERT_PUBLIB_KEY_INFO.
//
// Encode and decode the structure. Call CryptImportPublicKeyInfo and
// CryptImportKey.
//--------------------------------------------------------------------------
BOOL VerifyPublicKeyInfo(PCERT_PUBLIC_KEY_INFO pPublicKeyInfo,
DWORD dwDecodeFlags, BOOL fEncode,
BOOL fStructLengthCheck, BOOL fBLOBLengthCheck)
{
BOOL fSucceeded=FALSE;
HCRYPTKEY hKey=NULL;
DWORD cbEncoded=0;
BYTE *pbEncoded=NULL;
//call CryptImportPublicKeyInfo
TESTC(CryptImportPublicKeyInfo(g_hProv,CRYPT_ENCODE_TYPE,
pPublicKeyInfo,&hKey),TRUE)
//verify the algorithm
TESTC(VerifyAlgorithParam(&(pPublicKeyInfo->Algorithm)),TRUE)
//encode CERT_PUBLIC_KEY_INFO
TESTC(EncodeStruct(X509_PUBLIC_KEY_INFO, pPublicKeyInfo,&cbEncoded,
&pbEncoded),TRUE)
//decode/encode the publicKeyInfo
TESTC(DecodeGenericBLOB(X509_PUBLIC_KEY_INFO, cbEncoded, pbEncoded, dwDecodeFlags,
fEncode,fStructLengthCheck,fBLOBLengthCheck),TRUE)
//decode/encode the RSA_CSP_PUBLICKEYBLOB
TESTC(DecodeRSA_CSP_PUBLICKEYBLOB(pPublicKeyInfo->PublicKey.cbData,
pPublicKeyInfo->PublicKey.pbData,dwDecodeFlags,fEncode,fStructLengthCheck,
fBLOBLengthCheck),TRUE)
fSucceeded=TRUE;
TCLEANUP:
if(hKey)
TCHECK(CryptDestroyKey(hKey),TRUE);
SAFE_FREE(pbEncoded)
return fSucceeded;
}
//--------------------------------------------------------------------------
// A general routine to verify the extentions in a cert.
//
//--------------------------------------------------------------------------
BOOL VerifyCertExtensions(DWORD cExtension, PCERT_EXTENSION rgExtension,
DWORD dwDecodeFlags, BOOL fEncode,
BOOL fStructLengthCheck, BOOL fBLOBLengthCheck)
{
BOOL fSucceeded=FALSE;
DWORD cbEncoded=0;
BYTE *pbEncoded=NULL;
CERT_EXTENSIONS CertExtensions;
DWORD cbTestEncoded=0;
BYTE *pbTestEncoded=NULL;
DWORD cbStructInfo=sizeof(CERT_EXTENSIONS);
CERT_EXTENSIONS CertTestExtensions;
//init
CertExtensions.cExtension=0;
CertExtensions.rgExtension=NULL;
//Check the NULL case
//length only calculation
TESTC(CryptEncodeObject(CRYPT_ENCODE_TYPE,X509_EXTENSIONS, &CertExtensions,NULL,
&cbTestEncoded),TRUE)
//allocate memory
pbTestEncoded=(BYTE *)SAFE_ALLOC(cbTestEncoded);
CHECK_POINTER(pbTestEncoded);
//EncodeObject
TESTC(CryptEncodeObject(CRYPT_ENCODE_TYPE,X509_EXTENSIONS, &CertExtensions,
pbTestEncoded, &cbTestEncoded),TRUE)
//DecodeObject
TESTC(CryptDecodeObject(CRYPT_ENCODE_TYPE,X509_EXTENSIONS,
pbTestEncoded,cbTestEncoded,dwDecodeFlags,&CertTestExtensions,&cbStructInfo),TRUE)
//Verify CertTestExtensions
TESTC(CertTestExtensions.cExtension, CertExtensions.cExtension)
//init again
CertExtensions.cExtension=cExtension;
CertExtensions.rgExtension=rgExtension;
//encode CERT_EXTENSIONS
TESTC(EncodeStruct(X509_EXTENSIONS, &CertExtensions,&cbEncoded,
&pbEncoded),TRUE)
//decode/encode X509_EXTENSIONS
TESTC(DecodeX509_EXTENSIONS(cbEncoded,
pbEncoded,dwDecodeFlags,fEncode,fStructLengthCheck,
fBLOBLengthCheck),TRUE)
fSucceeded=TRUE;
TCLEANUP:
SAFE_FREE(pbEncoded)
SAFE_FREE(pbTestEncoded)
return fSucceeded;
}
//--------------------------------------------------------------------------
// Return the corresponding lpStructInfo based on the objectID passed in
//--------------------------------------------------------------------------
LPCSTR MapObjID2StructType(LPSTR szObjectID)
{
if(szObjectID==NULL)
return NULL;
if(strcmp(szObjectID,szOID_AUTHORITY_KEY_IDENTIFIER)==0)
return X509_AUTHORITY_KEY_ID;
if(strcmp(szObjectID,szOID_KEY_ATTRIBUTES)==0)
return X509_KEY_ATTRIBUTES;
if(strcmp(szObjectID,szOID_KEY_USAGE_RESTRICTION)==0)
return X509_KEY_USAGE_RESTRICTION;
if(strcmp(szObjectID,szOID_SUBJECT_ALT_NAME)==0)
return X509_ALTERNATE_NAME;
if(strcmp(szObjectID,szOID_ISSUER_ALT_NAME)==0)
return X509_ALTERNATE_NAME;
if(strcmp(szObjectID,szOID_BASIC_CONSTRAINTS)==0)
return X509_BASIC_CONSTRAINTS;
if(strcmp(szObjectID,szOID_KEY_USAGE)==0)
return X509_KEY_USAGE;
if(strcmp(szObjectID,szOID_BASIC_CONSTRAINTS2)==0)
return X509_BASIC_CONSTRAINTS2;
if(strcmp(szObjectID,szOID_CERT_POLICIES)==0)
return X509_CERT_POLICIES;
return NULL;
}
///////////////////////////////////////////////////////////////////////////
//Certificate Manipulation Functions
//--------------------------------------------------------------------------
// Decode a storefile what has CRL and certificates
//--------------------------------------------------------------------------
BOOL DecodeCertFile(LPSTR pszFileName,BOOL fStructLengthCheck,
BOOL fBLOBLengthCheck)
{
BOOL fSucceeded=FALSE;
HCERTSTORE hCertStore=NULL;
DWORD cbCertEncoded=0;
BYTE *pbCertEncoded=NULL;
PCCERT_CONTEXT pCertContext=NULL;
PCCERT_CONTEXT pPrevCertContext=NULL;
PCCRL_CONTEXT pCrlContext=NULL;
PCCRL_CONTEXT pPrevCrlContext=NULL;
DWORD dwFlags=0;
DWORD cCount=0;
//open cert store
if(!(hCertStore=CertOpenStore(CERT_STORE_PROV_FILENAME_A, CRYPT_ENCODE_TYPE,
g_hProv,CERT_STORE_NO_CRYPT_RELEASE_FLAG,pszFileName)))
PROCESS_ERR_GOTO("Failed to open a store!\n")
//get a cert from the store one at a time
while((pCertContext=CertEnumCertificatesInStore(hCertStore,pPrevCertContext)))
{
cCount++;
printf("//-----------------------------------------\n");
printf("Decoding the %dth Certificate\n",cCount);
//retrieve the encoded X_509 BLOBs
cbCertEncoded=pCertContext->cbCertEncoded;
pbCertEncoded=pCertContext->pbCertEncoded;
//verify the hCertStore is connect
TESTC(hCertStore==pCertContext->hCertStore, TRUE)
//NULL/invalid parameter testing only once
if(cCount==1)
TESTC(ParameterTest(X509_CERT_TO_BE_SIGNED, cbCertEncoded, pbCertEncoded),TRUE)
//decode/encode the certificate blob with NOCOPY option
TESTC(DecodeX509_CERT(CERT_INFO_STRUCT,cbCertEncoded,pbCertEncoded, CRYPT_DECODE_NOCOPY_FLAG,
TRUE,fStructLengthCheck,fBLOBLengthCheck,pCertContext->pCertInfo),TRUE)
//decode/encode the certificate blob with COPY option
TESTC(DecodeX509_CERT(CERT_INFO_STRUCT,cbCertEncoded,pbCertEncoded, CRYPT_DECODE_COPY_FLAG,
TRUE,fStructLengthCheck,fBLOBLengthCheck,pCertContext->pCertInfo),TRUE)
pPrevCertContext=pCertContext;
}
cCount=0;
//get a CRL from the store one at a time
while((pCrlContext=CertGetCRLFromStore(hCertStore,NULL,pPrevCrlContext,&dwFlags)))
{
cCount++;
printf("//-----------------------------------------\n");
printf("Decoding the %dth CRL\n",cCount);
//retrieve the encoded X_509 BLOBs
cbCertEncoded=pCrlContext->cbCrlEncoded;
pbCertEncoded=pCrlContext->pbCrlEncoded;
//verify the hCertStore is connect
TESTC(hCertStore==pCrlContext->hCertStore, TRUE)
//NULL/invalid parameter testing only once
if(cCount==1)
TESTC(ParameterTest(X509_CERT_CRL_TO_BE_SIGNED, cbCertEncoded, pbCertEncoded),TRUE)
//decode/encode the certificate blob with NOCOPY option
TESTC(DecodeX509_CERT(CRL_INFO_STRUCT,cbCertEncoded,pbCertEncoded, CRYPT_DECODE_NOCOPY_FLAG,
TRUE,fStructLengthCheck,fBLOBLengthCheck,pCrlContext->pCrlInfo),TRUE)
//decode/encode the certificate blob with COPY option
TESTC(DecodeX509_CERT(CRL_INFO_STRUCT,cbCertEncoded,pbCertEncoded, CRYPT_DECODE_COPY_FLAG,
TRUE,fStructLengthCheck,fBLOBLengthCheck,pCrlContext->pCrlInfo),TRUE)
pPrevCrlContext=pCrlContext;
}
fSucceeded=TRUE;
TCLEANUP:
//release the cert context
if(pCertContext)
CertFreeCertificateContext(pCertContext);
//we do not need to free pPreCertContext since it is always freed by
//CertEnumCertificatesInStore.
//release the CRL contest
if(pCrlContext)
CertFreeCRLContext(pCrlContext);
//release the cert store
if(hCertStore)
TCHECK(CertCloseStore(hCertStore,CERT_CLOSE_STORE_FORCE_FLAG),TRUE);
return fSucceeded;
}
//--------------------------------------------------------------------------
// Decode a BLOB file that is an encoded certificate request
//--------------------------------------------------------------------------
BOOL DecodeCertReqFile(LPSTR pszFileName,BOOL fStructLengthCheck,
BOOL fBLOBLengthCheck)
{
BOOL fSucceeded=FALSE;
DWORD cbEncoded=0;
BYTE *pbEncoded=NULL;
//Get the cbEncoded and pEncoded BLOB from the file
TESTC(RetrieveBLOBfromFile(pszFileName,&cbEncoded,&pbEncoded),TRUE)
//do a parameter testing
TESTC(ParameterTest(X509_CERT_REQUEST_TO_BE_SIGNED, cbEncoded, pbEncoded),TRUE)
//decode the BLOB as X509_CERT with COPY option
TESTC(DecodeX509_CERT(CERT_REQUEST_INFO_STRUCT,cbEncoded,pbEncoded, CRYPT_DECODE_COPY_FLAG,
TRUE,fStructLengthCheck,fBLOBLengthCheck,NULL),TRUE)
//decode the BLOB as X509_CERT wiht NOCOPY option
TESTC(DecodeX509_CERT(CERT_REQUEST_INFO_STRUCT,cbEncoded,pbEncoded, CRYPT_DECODE_NOCOPY_FLAG,
TRUE,fStructLengthCheck,fBLOBLengthCheck,NULL),TRUE)
fSucceeded=TRUE;
TCLEANUP:
SAFE_FREE(pbEncoded)
return fSucceeded;
}
//--------------------------------------------------------------------------
// Decode a BLOB file that is an signed message
//--------------------------------------------------------------------------
BOOL DecodeSignedMsgFile(LPSTR pszFileName,BOOL fStructLengthCheck,
BOOL fBLOBLengthCheck)
{
BOOL fSucceeded=FALSE;
DWORD cbEncoded=0;
BYTE *pbEncoded=NULL;
DWORD cbSignerEncoded=0;
BYTE *pbSignerEncoded=NULL;
HCRYPTMSG hCryptMsg=NULL;
PCMSG_SIGNER_INFO pSignerInfo=NULL;
DWORD cbSize=0;
DWORD iIndex=0;
DWORD cSignerCount=0;
//Get the cbEncoded and pEncoded BLOB from the file
TESTC(RetrieveBLOBfromFile(pszFileName,&cbEncoded,&pbEncoded),TRUE)
//Get the SIGNER_INFO BLOB from the file BLOB
hCryptMsg=CryptMsgOpenToDecode(MSG_ENCODING_TYPE,0,0,g_hProv,NULL,NULL);
if(!hCryptMsg)
goto TCLEANUP;
TESTC(CryptMsgUpdate(hCryptMsg,pbEncoded,cbEncoded,TRUE),TRUE)
//Get the count of signer in the message
cbSize=sizeof(cSignerCount);
TESTC(CryptMsgGetParam(hCryptMsg,CMSG_SIGNER_COUNT_PARAM,
0,&cSignerCount,&cbSize),TRUE)
//go through the list of all signers
for(iIndex=0;iIndex<cSignerCount;iIndex++)
{
//get the CMSG_SINGER_INFO struct
TESTC(CryptMsgGetParam(hCryptMsg,CMSG_SIGNER_INFO_PARAM,
iIndex,NULL,&cbSize),TRUE)
//allocation memory
pSignerInfo=(PCMSG_SIGNER_INFO)SAFE_ALLOC(cbSize);
CHECK_POINTER(pSignerInfo);
TESTC(CryptMsgGetParam(hCryptMsg,CMSG_SIGNER_INFO_PARAM,
iIndex,pSignerInfo,&cbSize),TRUE)
//encode the struct info a BLOB. Add Attributes if possible
TESTC(EncodeSignerInfoWAttr(pSignerInfo,&cbSignerEncoded,
&pbSignerEncoded),TRUE)
//do a parameter testing for the 1st round
if(iIndex==0)
{
TESTC(ParameterTest(PKCS7_SIGNER_INFO, cbSignerEncoded, pbSignerEncoded),TRUE)
}
//decode the BLOB as PKCS7_SIGNER_INFO with COPY option
TESTC(DecodePKCS7_SIGNER_INFO(cbSignerEncoded,pbSignerEncoded, CRYPT_DECODE_COPY_FLAG,
TRUE,fStructLengthCheck,fBLOBLengthCheck),TRUE)
//decode the BLOB as PKCS7_SIGNER_INFO wiht NOCOPY option
TESTC(DecodePKCS7_SIGNER_INFO(cbSignerEncoded,pbSignerEncoded, CRYPT_DECODE_NOCOPY_FLAG,
TRUE,fStructLengthCheck,fBLOBLengthCheck),TRUE)
//release the memory
SAFE_FREE(pSignerInfo);
SAFE_FREE(pbSignerEncoded);
}
fSucceeded=TRUE;
TCLEANUP:
//close the msg handle
CryptMsgClose(hCryptMsg);
SAFE_FREE(pbEncoded)
SAFE_FREE(pbSignerEncoded)
SAFE_FREE(pSignerInfo)
return fSucceeded;
}
//--------------------------------------------------------------------------
// A general routine to encode a struct based on lpszStructType
//--------------------------------------------------------------------------
BOOL EncodeStruct(LPCSTR lpszStructType, void *pStructInfo,DWORD *pcbEncoded,
BYTE **ppbEncoded)
{
BOOL fSucceeded=FALSE;
DWORD cbEncoded=NULL;
BYTE *pbTestEncoded=NULL;
DWORD cbTestEncoded=0;
DWORD dwEncodingType=CRYPT_ENCODE_TYPE;
//init
*pcbEncoded=0;
*ppbEncoded=NULL;
assert(lpszStructType);
assert(pStructInfo);
//We have different decoding type for PKCS7_SIGNER_INFO
if((DWORD_PTR)(lpszStructType)==(DWORD_PTR)(PKCS7_SIGNER_INFO))
dwEncodingType=MSG_ENCODING_TYPE;
//length only calculation
TESTC(CryptEncodeObject(dwEncodingType,lpszStructType, pStructInfo,NULL,
&cbEncoded),TRUE)
//the struct has to be more than 0 byte
assert(cbEncoded);
//allocate the correct amount of memory
*ppbEncoded=(BYTE *)SAFE_ALLOC(cbEncoded);
CHECK_POINTER(*ppbEncoded);
//Encode the strcut with *pcbEncoded == the correct length
*pcbEncoded=cbEncoded;
//Encode the struct
TESTC(CryptEncodeObject(dwEncodingType,lpszStructType,pStructInfo,*ppbEncoded,
pcbEncoded),TRUE)
//the length returned has to be less or equal to cbEncoded
TESTC(cbEncoded>=(*pcbEncoded),TRUE)
//allocate memory to LENGTH_DELTA byte more than necessary to pbTestEncoded
pbTestEncoded=(BYTE *)SAFE_ALLOC(cbEncoded+LENGTH_MORE);
CHECK_POINTER(pbTestEncoded)
//Encode the struct with *pcbEncoded > the correct length
cbTestEncoded=cbEncoded+LENGTH_MORE;
TESTC(CryptEncodeObject(dwEncodingType,lpszStructType,pStructInfo,pbTestEncoded,
&cbTestEncoded),TRUE)
//*pcbEncoded should be the same as cbEncoded
TESTC(cbTestEncoded, *pcbEncoded)
//Verify the pbTestEncoded contain the same bytes as pcbEncoded, starting
//at the 1st byte of the BLOB
TESTC(memcmp(pbTestEncoded, *ppbEncoded,*pcbEncoded),0)
//Encode the struct with *pcbEncoded < the correct length
cbTestEncoded=(*pcbEncoded)-LENGTH_LESS;
TESTC(CryptEncodeObject(dwEncodingType,lpszStructType,pStructInfo,pbTestEncoded,
&cbTestEncoded),FALSE)
//*pcbEncoded should be the same as cbEncoded
TESTC(cbTestEncoded, *pcbEncoded)
//GetLastError should be ERROR_MORE_DATA
TESTC(GetLastError(),ERROR_MORE_DATA)
fSucceeded=TRUE;
TCLEANUP:
SAFE_FREE(pbTestEncoded)
return fSucceeded;
}
//--------------------------------------------------------------------------
// EncodeAndVerify
//
// Encode the pStructInfo and verify the encoded BLOB is the same
// as expected.
//--------------------------------------------------------------------------
BOOL EncodeAndVerify(LPCSTR lpszStructType, void *pvStructInfo, DWORD cbEncoded,
BYTE *pbEncoded)
{
DWORD cbSecondEncoded=0;
BYTE *pbSecondEncoded=0;
BOOL fSucceeded=FALSE;
assert(lpszStructType);
assert(pvStructInfo);
assert(cbEncoded);
assert(pbEncoded);
//encode the struct back to a BLOB
TESTC(EncodeStruct(lpszStructType,pvStructInfo,&cbSecondEncoded,&pbSecondEncoded),
TRUE)
//make sure the returned encoded BLOB is the same as the original BLOB
//the two encoded BLOB has to of the same length
if(!TCHECK(cbSecondEncoded, cbEncoded))
{
PROCESS_ERR(szEncodedSizeInconsistent)
OutputError(lpszStructType,cbSecondEncoded, cbEncoded,pbSecondEncoded,pbEncoded);
}
if (0 != memcmp(pbSecondEncoded,pbEncoded,cbEncoded)) {
if (X509_KEY_USAGE == lpszStructType) {
// Force the unused bits to be the same
if (3 <= cbSecondEncoded && 3 <= cbEncoded) {
BYTE bUnusedBits = pbSecondEncoded[2];
pbSecondEncoded[2] = pbEncoded[2];
if (0 == memcmp(pbSecondEncoded,pbEncoded,cbEncoded))
printf("Warning, difference in reencoded KeyUsage UnusedBit Count\n");
else
pbSecondEncoded[2] = bUnusedBits;
}
}
}
//the two encoded BLOB has to be of the same content
if(!TCHECK(memcmp(pbSecondEncoded,pbEncoded,cbEncoded),0))
{
PROCESS_ERR(szEncodedContentInconsistent)
OutputError(lpszStructType,cbSecondEncoded, cbEncoded,pbSecondEncoded,pbEncoded);
}
fSucceeded=TRUE;
TCLEANUP:
SAFE_FREE(pbSecondEncoded)
return fSucceeded;
}
//--------------------------------------------------------------------------
// A general routine to decode a BLOB based on lpszStructType
//
// fStructLengthCheck: Flag to indicate whether a length checking is necessary
// for *pcbStructInfo from 0 .. CorrectLength-1
//
// fBLOBLengthCheck: Flag to indicate whether a length checking is necessary
// for cbEncoded from 0 .. CorrentLength-1
//
//--------------------------------------------------------------------------
BOOL DecodeBLOB(LPCSTR lpszStructType,DWORD cbEncoded, BYTE *pbEncoded,
DWORD dwDecodeFlags, DWORD *pcbStructInfo, void **ppvStructInfo,
BOOL fStructLengthCheck,BOOL fBLOBLengthCheck)
{
BOOL fSucceeded=FALSE;
DWORD cbStructInfo=0;
LONG iIndex=0;
LONG cbUpperLimit=0;
DWORD cbTestStructInfo=0;
void *pvTestStructInfo=NULL;
DWORD dwEncodingType=CRYPT_ENCODE_TYPE;
//init
*pcbStructInfo=0;
*ppvStructInfo=NULL;
assert(lpszStructType);
assert(pbEncoded);
assert(cbEncoded);
//Decode
if((DWORD_PTR)(lpszStructType)==(DWORD_PTR)(PKCS7_SIGNER_INFO))
dwEncodingType=MSG_ENCODING_TYPE;
TESTC(CryptDecodeObject(dwEncodingType,lpszStructType,pbEncoded,cbEncoded,
dwDecodeFlags,NULL,&cbStructInfo),TRUE)
//the struct has to be more than 0 byte
assert(cbStructInfo);
*ppvStructInfo=(BYTE *)SAFE_ALLOC(cbStructInfo);
CHECK_POINTER(*ppvStructInfo);
//Decode the BLOB with *pcbStructInfo==correct length
*pcbStructInfo=cbStructInfo;
TESTC(CryptDecodeObject(dwEncodingType,lpszStructType,pbEncoded,cbEncoded,
dwDecodeFlags,*ppvStructInfo,pcbStructInfo),TRUE)
//make sure the correct length is less than cbStructInfo
TESTC(cbStructInfo>=(*pcbStructInfo),TRUE);
//Decode the BLOB with *pcbStructInfo>correct length
//allocate memory to be LENGTH_DELTA more byte than the correct length
pvTestStructInfo=SAFE_ALLOC(cbStructInfo+LENGTH_MORE);
CHECK_POINTER(pvTestStructInfo);
cbTestStructInfo=cbStructInfo+LENGTH_MORE;
TESTC(CryptDecodeObject(dwEncodingType,lpszStructType,pbEncoded,cbEncoded,
dwDecodeFlags,pvTestStructInfo,&cbTestStructInfo),TRUE)
//make sure the length is the same
TESTC(cbTestStructInfo, (*pcbStructInfo));
//Decode the BLOB with *pcbStructInfo < correct length
cbTestStructInfo=(*pcbStructInfo)-LENGTH_LESS;
TESTC(CryptDecodeObject(dwEncodingType,lpszStructType,pbEncoded,cbEncoded,
dwDecodeFlags,pvTestStructInfo,&cbTestStructInfo),FALSE)
TESTC(GetLastError(), ERROR_MORE_DATA)
//make sure the length is the same
TESTC(cbTestStructInfo, (*pcbStructInfo));
//if fStructLengthCheck is TRUE, we need to do a more rigorous test of *pcbStructInfo
if(fStructLengthCheck)
{
cbUpperLimit=(*pcbStructInfo)-1;
for(iIndex=cbUpperLimit; iIndex>=0; iIndex--)
{
cbTestStructInfo=iIndex;
//decode the BLOB with *pcbStructInfo<correct bytes
TESTC(CryptDecodeObject(dwEncodingType,lpszStructType,pbEncoded,cbEncoded,
dwDecodeFlags,pvTestStructInfo,&cbTestStructInfo),FALSE)
TESTC(GetLastError(), ERROR_MORE_DATA)
//make sure the length is the same
TESTC(cbTestStructInfo, *pcbStructInfo);
}
}
//if fBLOBLengthCheck is TRUE, we need to do a more rigorous test of cbEncoded
if(fBLOBLengthCheck)
{
cbUpperLimit=cbEncoded-1;
for(iIndex=cbUpperLimit; iIndex>=0; iIndex--)
{
cbTestStructInfo=cbStructInfo;
//decode the BLOB with cbEncoded < correct byte
TESTC(CryptDecodeObject(dwEncodingType,lpszStructType,pbEncoded,iIndex,
dwDecodeFlags,pvTestStructInfo,&cbTestStructInfo),FALSE)
//we are not sure that should be expected here. The following error has
//occurred:
//E_INVALIDARG, CRYPT_E_OSS_ERROR+PDU_MISMATCH, +DATA_ERROR, or
//+MORE_INPUT
//make sure at lease S_OK is not returned
TCHECK(GetLastError()!=S_OK, TRUE);
}
}
fSucceeded=TRUE;
TCLEANUP:
//reallocate memory
SAFE_FREE(pvTestStructInfo);
return fSucceeded;
}
//--------------------------------------------------------------------------
// Decode X509_CERT BLOBs
//
// fStructLengthCheck: Flag to indicate whether a length checking is necessary
// for *pcbStructInfo from 0 .. CorrectLength-1
//
// fBLOBLengthCheck: Flag to indicate whether a length checking is necessary
// for cbEncoded from 0 .. CorrentLength-1
//--------------------------------------------------------------------------
BOOL DecodeX509_CERT(DWORD dwCertType,DWORD cbEncoded, BYTE *pbEncoded, DWORD dwDecodeFlags,BOOL fEncode,
BOOL fStructLengthCheck, BOOL fBLOBLengthCheck,
void *pInfoStruct)
{
BOOL fSucceeded=FALSE;
DWORD cbStructInfo=0;
void *pStructInfo=NULL;
LPCSTR lpszStructType=NULL;
//init
lpszStructType=X509_CERT;
//Decode the encoded BLOB
TESTC(DecodeBLOB(lpszStructType,cbEncoded, pbEncoded,dwDecodeFlags,&cbStructInfo,
&pStructInfo,fStructLengthCheck, fBLOBLengthCheck),TRUE)
//verify the algorithm
TESTC(VerifyAlgorithParam(&(((PCERT_SIGNED_CONTENT_INFO)pStructInfo)->SignatureAlgorithm)),TRUE)
//Further Decode the X509_CERT_TO_BE_SIGNED
//Notice we should use the original cbData and pbData passed in for Decode
//but use ToBeSigned in CERT_SIGNED_CONTENT_INFO for encode purpose
switch(dwCertType)
{
case CERT_INFO_STRUCT:
TESTC(DecodeX509_CERT_TO_BE_SIGNED(cbEncoded,
pbEncoded,dwDecodeFlags,fEncode,
fStructLengthCheck, fBLOBLengthCheck,
(((PCERT_SIGNED_CONTENT_INFO)pStructInfo)->ToBeSigned).cbData,
(((PCERT_SIGNED_CONTENT_INFO)pStructInfo)->ToBeSigned).pbData
),TRUE)
//verify the pCertInfo should be encoded correctly
TCHECK(EncodeAndVerify(X509_CERT_TO_BE_SIGNED, pInfoStruct,
(((PCERT_SIGNED_CONTENT_INFO)pStructInfo)->ToBeSigned).cbData,
(((PCERT_SIGNED_CONTENT_INFO)pStructInfo)->ToBeSigned).pbData),TRUE);
break;
case CRL_INFO_STRUCT:
TESTC(DecodeX509_CERT_CRL_TO_BE_SIGNED(cbEncoded,
pbEncoded,dwDecodeFlags,fEncode,
fStructLengthCheck, fBLOBLengthCheck,
(((PCERT_SIGNED_CONTENT_INFO)pStructInfo)->ToBeSigned).cbData,
(((PCERT_SIGNED_CONTENT_INFO)pStructInfo)->ToBeSigned).pbData
),TRUE)
//verify the pCrlInfo should be encoded correctly
TCHECK(EncodeAndVerify(X509_CERT_CRL_TO_BE_SIGNED, pInfoStruct,
(((PCERT_SIGNED_CONTENT_INFO)pStructInfo)->ToBeSigned).cbData,
(((PCERT_SIGNED_CONTENT_INFO)pStructInfo)->ToBeSigned).pbData),TRUE);
break;
case CERT_REQUEST_INFO_STRUCT:
TESTC(DecodeX509_CERT_REQUEST_TO_BE_SIGNED(cbEncoded,
pbEncoded,dwDecodeFlags,fEncode,
fStructLengthCheck, fBLOBLengthCheck,
(((PCERT_SIGNED_CONTENT_INFO)pStructInfo)->ToBeSigned).cbData,
(((PCERT_SIGNED_CONTENT_INFO)pStructInfo)->ToBeSigned).pbData
),TRUE)
break;
}
//if requested, encode the BLOB back to what it was. Make sure no data is lost
//by checking the size of the encoded blob and do a memcmp.
if(fEncode)
TCHECK(EncodeAndVerify(lpszStructType, pStructInfo,cbEncoded, pbEncoded),TRUE);
fSucceeded=TRUE;
TCLEANUP:
SAFE_FREE(pStructInfo)
return fSucceeded;
}
//--------------------------------------------------------------------------
// Decode X509_CERT_TO_BE_SIGNED BLOBs
//
// fStructLengthCheck: Flag to indicate whether a length checking is necessary
// for *pcbStructInfo from 0 .. CorrectLength-1
//
// fBLOBLengthCheck: Flag to indicate whether a length checking is necessary
// for cbEncoded from 0 .. CorrentLength-1
//--------------------------------------------------------------------------
BOOL DecodeX509_CERT_TO_BE_SIGNED(DWORD cbEncoded, BYTE *pbEncoded, DWORD dwDecodeFlags,
BOOL fEncode,BOOL fStructLengthCheck, BOOL fBLOBLengthCheck,
BOOL cbExpectedEncoded, BYTE *pbExpectedEncoded)
{
BOOL fSucceeded=FALSE;
DWORD cbStructInfo=0;
void *pStructInfo=NULL;
LPCSTR lpszStructType=NULL;
//init
lpszStructType=X509_CERT_TO_BE_SIGNED;
//Decode the encoded BLOB
TESTC(DecodeBLOB(lpszStructType,cbEncoded, pbEncoded,dwDecodeFlags,&cbStructInfo,
&pStructInfo,fStructLengthCheck, fBLOBLengthCheck),TRUE)
//Verify the signaure algorithm
TESTC(VerifyAlgorithParam(&(((PCERT_INFO)pStructInfo)->SignatureAlgorithm)),TRUE)
//Verify the public Key information
TESTC(VerifyPublicKeyInfo(&(((PCERT_INFO)pStructInfo)->SubjectPublicKeyInfo),
dwDecodeFlags, fEncode,fStructLengthCheck, fBLOBLengthCheck),TRUE)
//Decode Issuer in CERT_INFO struct
TESTC(DecodeX509_NAME((((PCERT_INFO)pStructInfo)->Issuer).cbData,
(((PCERT_INFO)pStructInfo)->Issuer).pbData,dwDecodeFlags,fEncode,
fStructLengthCheck, fBLOBLengthCheck),TRUE)
//Decode Issuer to X509_UNICODE_NAME
TESTC(DecodeX509_UNICODE_NAME((((PCERT_INFO)pStructInfo)->Issuer).cbData,
(((PCERT_INFO)pStructInfo)->Issuer).pbData,dwDecodeFlags,fEncode,
fStructLengthCheck, fBLOBLengthCheck),TRUE)
//Decode Subject in CERT_INFO struct
TESTC(DecodeX509_NAME((((PCERT_INFO)pStructInfo)->Subject).cbData,
(((PCERT_INFO)pStructInfo)->Subject).pbData,dwDecodeFlags,fEncode,
fStructLengthCheck, fBLOBLengthCheck),TRUE)
//Decode Subject to X509_UNICODE_NAME
TESTC(DecodeX509_UNICODE_NAME((((PCERT_INFO)pStructInfo)->Subject).cbData,
(((PCERT_INFO)pStructInfo)->Subject).pbData,dwDecodeFlags,fEncode,
fStructLengthCheck, fBLOBLengthCheck),TRUE)
//Verify the extensions
TESTC(VerifyCertExtensions(((PCERT_INFO)pStructInfo)->cExtension,
((PCERT_INFO)pStructInfo)->rgExtension,dwDecodeFlags,fEncode,
fStructLengthCheck, fBLOBLengthCheck),TRUE)
//decode the extensions one by one
TESTC(DecodeCertExtensions(((PCERT_INFO)pStructInfo)->cExtension,
((PCERT_INFO)pStructInfo)->rgExtension,dwDecodeFlags,fEncode,
fStructLengthCheck, fBLOBLengthCheck),TRUE)
//if requested, encode the BLOB back to what it was. Make sure no data is lost
//by checking the size of the encoded blob and do a memcmp.
if(fEncode)
TCHECK(EncodeAndVerify(lpszStructType, pStructInfo,cbExpectedEncoded,
pbExpectedEncoded),TRUE);
fSucceeded=TRUE;
TCLEANUP:
SAFE_FREE(pStructInfo)
return fSucceeded;
}
//--------------------------------------------------------------------------
// Decode X509_CERT_CRL_TO_BE_SIGNED BLOBs
//
// fStructLengthCheck: Flag to indicate whether a length checking is necessary
// for *pcbStructInfo from 0 .. CorrectLength-1
//
// fBLOBLengthCheck: Flag to indicate whether a length checking is necessary
// for cbEncoded from 0 .. CorrentLength-1
//--------------------------------------------------------------------------
BOOL DecodeX509_CERT_CRL_TO_BE_SIGNED(DWORD cbEncoded, BYTE *pbEncoded, DWORD dwDecodeFlags,
BOOL fEncode,BOOL fStructLengthCheck, BOOL fBLOBLengthCheck,
BOOL cbExpectedEncoded, BYTE *pbExpectedEncoded)
{
BOOL fSucceeded=FALSE;
DWORD cbStructInfo=0;
void *pStructInfo=NULL;
DWORD iIndex=0;
PCRL_ENTRY pCrlEntry=NULL;
LPCSTR lpszStructType=NULL;
//init
lpszStructType=X509_CERT_CRL_TO_BE_SIGNED;
//Decode the encoded BLOB
TESTC(DecodeBLOB(lpszStructType,cbEncoded, pbEncoded,dwDecodeFlags,&cbStructInfo,
&pStructInfo,fStructLengthCheck, fBLOBLengthCheck),TRUE)
//Verify the signaure algorithm
TESTC(VerifyAlgorithParam(&(((PCRL_INFO)pStructInfo)->SignatureAlgorithm)),TRUE)
//Decode Issuer in CRL_INFO struct
TESTC(DecodeX509_NAME((((PCRL_INFO)pStructInfo)->Issuer).cbData,
(((PCRL_INFO)pStructInfo)->Issuer).pbData,dwDecodeFlags,fEncode,
fStructLengthCheck, fBLOBLengthCheck),TRUE)
//Decode Issuer to the X509_UNICODE_NAME
TESTC(DecodeX509_UNICODE_NAME((((PCRL_INFO)pStructInfo)->Issuer).cbData,
(((PCRL_INFO)pStructInfo)->Issuer).pbData,dwDecodeFlags,fEncode,
fStructLengthCheck, fBLOBLengthCheck),TRUE)
//Verify the CRL_ENTRY
for(iIndex=0; iIndex<((PCRL_INFO)pStructInfo)->cCRLEntry; iIndex++)
{
pCrlEntry=&(((PCRL_INFO)pStructInfo)->rgCRLEntry[iIndex]);
TESTC(DecodeCRLEntry(pCrlEntry,dwDecodeFlags,fEncode,
fStructLengthCheck, fBLOBLengthCheck),TRUE)
}
//Verify the extensions
TESTC(VerifyCertExtensions(((PCRL_INFO)pStructInfo)->cExtension,
((PCRL_INFO)pStructInfo)->rgExtension,dwDecodeFlags,fEncode,
fStructLengthCheck, fBLOBLengthCheck),TRUE)
//decode the extensions one by one
TESTC(DecodeCertExtensions(((PCRL_INFO)pStructInfo)->cExtension,
((PCRL_INFO)pStructInfo)->rgExtension,dwDecodeFlags,fEncode,
fStructLengthCheck, fBLOBLengthCheck),TRUE)
//if requested, encode the BLOB back to what it was. Make sure no data is lost
//by checking the size of the encoded blob and do a memcmp.
if(fEncode)
TCHECK(EncodeAndVerify(lpszStructType, pStructInfo,cbExpectedEncoded,
pbExpectedEncoded),TRUE);
fSucceeded=TRUE;
TCLEANUP:
SAFE_FREE(pStructInfo)
return fSucceeded;
}
//--------------------------------------------------------------------------
// Decode 509_CERT_REQUEST_TO_BE_SIGNED BLOBS
//
// fStructLengthCheck: Flag to indicate whether a length checking is necessary
// for *pcbStructInfo from 0 .. CorrectLength-1
//
// fBLOBLengthCheck: Flag to indicate whether a length checking is necessary
// for cbEncoded from 0 .. CorrentLength-1
//--------------------------------------------------------------------------
BOOL DecodeX509_CERT_REQUEST_TO_BE_SIGNED(DWORD cbEncoded, BYTE *pbEncoded, DWORD dwDecodeFlags,
BOOL fEncode,BOOL fStructLengthCheck, BOOL fBLOBLengthCheck,
BOOL cbExpectedEncoded, BYTE *pbExpectedEncoded)
{
BOOL fSucceeded=FALSE;
DWORD cbStructInfo=0;
void *pStructInfo=NULL;
DWORD cCount=0;
DWORD iIndex=0;
PCRYPT_ATTRIBUTE pCryptAttribute=NULL;
LPCSTR lpszStructType=NULL;
//init
lpszStructType=X509_CERT_REQUEST_TO_BE_SIGNED;
//Decode the encoded BLOB
TESTC(DecodeBLOB(lpszStructType,cbEncoded, pbEncoded,dwDecodeFlags,&cbStructInfo,
&pStructInfo,fStructLengthCheck, fBLOBLengthCheck),TRUE)
//Verify the public Key information
// TESTC(VerifyPublicKeyInfo(&(((PCERT_REQUEST_INFO)pStructInfo)->SubjectPublicKeyInfo),
// dwDecodeFlags, fEncode,fStructLengthCheck, fBLOBLengthCheck),TRUE)
//Decode Subject in CERT_REQUEST_INFO struct
TESTC(DecodeX509_NAME((((PCERT_REQUEST_INFO)pStructInfo)->Subject).cbData,
(((PCERT_REQUEST_INFO)pStructInfo)->Subject).pbData,dwDecodeFlags,fEncode,
fStructLengthCheck, fBLOBLengthCheck),TRUE)
//Decode Subject in CERT_REQUEST_INFO struct for X509_UNICODE_NAME
TESTC(DecodeX509_UNICODE_NAME((((PCERT_REQUEST_INFO)pStructInfo)->Subject).cbData,
(((PCERT_REQUEST_INFO)pStructInfo)->Subject).pbData,dwDecodeFlags,fEncode,
fStructLengthCheck, fBLOBLengthCheck),TRUE)
//Decode the rgAttribute in CERT_REQUEST_INFO
cCount=((PCERT_REQUEST_INFO)pStructInfo)->cAttribute;
for(iIndex=0; iIndex<cCount; iIndex++)
{
pCryptAttribute=&(((PCERT_REQUEST_INFO)pStructInfo)->rgAttribute[iIndex]);
TESTC(DecodeCryptAttribute(pCryptAttribute,dwDecodeFlags,fEncode,
fStructLengthCheck, fBLOBLengthCheck),TRUE)
}
//if requested, encode the BLOB back to what it was. Make sure no data is lost
//by checking the size of the encoded blob and do a memcmp.
if(fEncode)
TCHECK(EncodeAndVerify(lpszStructType, pStructInfo,cbExpectedEncoded,
pbExpectedEncoded),TRUE);
fSucceeded=TRUE;
TCLEANUP:
SAFE_FREE(pStructInfo)
return fSucceeded;
}
//--------------------------------------------------------------------------
// Decode RSA_CSP_PUBLICKEYBLOB
//
// fStructLengthCheck: Flag to indicate whether a length checking is necessary
// for *pcbStructInfo from 0 .. CorrectLength-1
//
// fBLOBLengthCheck: Flag to indicate whether a length checking is necessary
// for cbEncoded from 0 .. CorrentLength-1
//--------------------------------------------------------------------------
BOOL DecodeRSA_CSP_PUBLICKEYBLOB(DWORD cbEncoded, BYTE *pbEncoded, DWORD dwDecodeFlags,
BOOL fEncode,BOOL fStructLengthCheck, BOOL fBLOBLengthCheck)
{
BOOL fSucceeded=FALSE;
DWORD cbStructInfo=0;
void *pStructInfo=NULL;
LPCSTR lpszStructType=NULL;
HCRYPTKEY hKey=NULL;
//init
lpszStructType=RSA_CSP_PUBLICKEYBLOB;
//Decode the encoded BLOB
TESTC(DecodeBLOB(lpszStructType,cbEncoded, pbEncoded,dwDecodeFlags,&cbStructInfo,
&pStructInfo,fStructLengthCheck, fBLOBLengthCheck),TRUE)
//Make sure the pStructInfo can be used by CryptImportKey
TESTC(CryptImportKey(g_hProv,(BYTE *)pStructInfo,cbStructInfo,
0,0,&hKey),TRUE)
//if requested, encode the BLOB back to what it was. Make sure no data is lost
//by checking the size of the encoded blob and do a memcmp.
if(fEncode)
TCHECK(EncodeAndVerify(lpszStructType, pStructInfo,cbEncoded,
pbEncoded),TRUE);
fSucceeded=TRUE;
TCLEANUP:
if(hKey)
TCHECK(CryptDestroyKey(hKey),TRUE);
SAFE_FREE(pStructInfo)
return fSucceeded;
}
//--------------------------------------------------------------------------
// Decode PKCS_TIME_REQUEST
//
// fStructLengthCheck: Flag to indicate whether a length checking is necessary
// for *pcbStructInfo from 0 .. CorrectLength-1
//
// fBLOBLengthCheck: Flag to indicate whether a length checking is necessary
// for cbEncoded from 0 .. CorrentLength-1
//--------------------------------------------------------------------------
BOOL DecodePKCS_TIME_REQUEST(DWORD cbEncoded, BYTE *pbEncoded, DWORD dwDecodeFlags,
BOOL fEncode,BOOL fStructLengthCheck, BOOL fBLOBLengthCheck)
{
BOOL fSucceeded=FALSE;
DWORD cbStructInfo=0;
void *pStructInfo=NULL;
LPCSTR lpszStructType=NULL;
//init
lpszStructType=PKCS_TIME_REQUEST;
//Decode the encoded BLOB
TESTC(DecodeBLOB(lpszStructType,cbEncoded, pbEncoded,dwDecodeFlags,&cbStructInfo,
&pStructInfo,fStructLengthCheck, fBLOBLengthCheck),TRUE)
//if requested, encode the BLOB back to what it was. Make sure no data is lost
//by checking the size of the encoded blob and do a memcmp.
if(fEncode)
TCHECK(EncodeAndVerify(lpszStructType, pStructInfo,cbEncoded,
pbEncoded),TRUE);
fSucceeded=TRUE;
TCLEANUP:
SAFE_FREE(pStructInfo)
return fSucceeded;
}
//--------------------------------------------------------------------------
// Decode a genanric BLOB, encode is back to make sure that the same
// BLOB is returned.
//
// fStructLengthCheck: Flag to indicate whether a length checking is necessary
// for *pcbStructInfo from 0 .. CorrectLength-1
//
// fBLOBLengthCheck: Flag to indicate whether a length checking is necessary
// for cbEncoded from 0 .. CorrentLength-1
//--------------------------------------------------------------------------
BOOL DecodeGenericBLOB(LPCSTR lpszStructType, DWORD cbEncoded, BYTE *pbEncoded, DWORD dwDecodeFlags,
BOOL fEncode,BOOL fStructLengthCheck, BOOL fBLOBLengthCheck)
{
BOOL fSucceeded=FALSE;
DWORD cbStructInfo=0;
void *pStructInfo=NULL;
//Decode the encoded BLOB
TESTC(DecodeBLOB(lpszStructType,cbEncoded, pbEncoded,dwDecodeFlags,&cbStructInfo,
&pStructInfo,fStructLengthCheck, fBLOBLengthCheck),TRUE)
//if requested, encode the BLOB back to what it was. Make sure no data is lost
//by checking the size of the encoded blob and do a memcmp.
if(fEncode)
TCHECK(EncodeAndVerify(lpszStructType, pStructInfo,cbEncoded,
pbEncoded),TRUE);
fSucceeded=TRUE;
TCLEANUP:
SAFE_FREE(pStructInfo)
return fSucceeded;
}
//--------------------------------------------------------------------------
// Decode X509_NAME BLOBs
//
// fStructLengthCheck: Flag to indicate whether a length checking is necessary
// for *pcbStructInfo from 0 .. CorrectLength-1
//
// fBLOBLengthCheck: Flag to indicate whether a length checking is necessary
// for cbEncoded from 0 .. CorrentLength-1
//--------------------------------------------------------------------------
BOOL DecodeX509_NAME(DWORD cbEncoded, BYTE *pbEncoded, DWORD dwDecodeFlags,
BOOL fEncode,BOOL fStructLengthCheck, BOOL fBLOBLengthCheck)
{
BOOL fSucceeded=FALSE;
DWORD cbStructInfo=0;
void *pStructInfo=NULL;
LPCSTR lpszStructType=NULL;
DWORD cRDN=0;
DWORD cRDNAttr=0;
DWORD cRDNCount=0;
DWORD cRDNAttrCount=0;
//init
lpszStructType=X509_NAME;
//Decode the encoded BLOB
TESTC(DecodeBLOB(lpszStructType,cbEncoded, pbEncoded,dwDecodeFlags,&cbStructInfo,
&pStructInfo,fStructLengthCheck, fBLOBLengthCheck),TRUE)
//We need to further decode CERT_RDN_ATTR if dwValueType is CERT_RDN_ENCODED_BLOB
cRDNCount=((PCERT_NAME_INFO)pStructInfo)->cRDN;
for(cRDN=0;cRDN<cRDNCount;cRDN++)
{
cRDNAttrCount=(((PCERT_NAME_INFO)pStructInfo)->rgRDN[cRDN]).cRDNAttr;
for(cRDNAttr=0; cRDNAttr<cRDNAttrCount; cRDNAttr++)
{
//no need to do a length checking since the routine is written and
//installed by third party
if( (((PCERT_NAME_INFO)pStructInfo)->rgRDN[cRDN]).rgRDNAttr[cRDNAttr].dwValueType==
CERT_RDN_ENCODED_BLOB)
TESTC(DecodeBasedOnObjID(
(((PCERT_NAME_INFO)pStructInfo)->rgRDN[cRDN]).rgRDNAttr[cRDNAttr].pszObjId,
(((PCERT_NAME_INFO)pStructInfo)->rgRDN[cRDN]).rgRDNAttr[cRDNAttr].Value.cbData,
(((PCERT_NAME_INFO)pStructInfo)->rgRDN[cRDN]).rgRDNAttr[cRDNAttr].Value.pbData,
dwDecodeFlags, fEncode,fStructLengthCheck, fBLOBLengthCheck),TRUE)
}
}
//if requested, encode the BLOB back to what it was. Make sure no data is lost
//by checking the size of the encoded blob and do a memcmp.
if(fEncode)
TCHECK(EncodeAndVerify(lpszStructType, pStructInfo,cbEncoded, pbEncoded),TRUE);
fSucceeded=TRUE;
TCLEANUP:
SAFE_FREE(pStructInfo)
return fSucceeded;
}
//--------------------------------------------------------------------------
// Decode PKCS7_SIGNER_INFO
//
// fStructLengthCheck: Flag to indicate whether a length checking is necessary
// for *pcbStructInfo from 0 .. CorrectLength-1
//
// fBLOBLengthCheck: Flag to indicate whether a length checking is necessary
// for cbEncoded from 0 .. CorrentLength-1
//--------------------------------------------------------------------------
BOOL DecodePKCS7_SIGNER_INFO(DWORD cbEncoded, BYTE *pbEncoded, DWORD dwDecodeFlags,
BOOL fEncode,BOOL fStructLengthCheck, BOOL fBLOBLengthCheck)
{
BOOL fSucceeded=FALSE;
DWORD cbStructInfo=0;
void *pStructInfo=NULL;
LPCSTR lpszStructType=NULL;
//init
lpszStructType=PKCS7_SIGNER_INFO;
//Decode the encoded BLOB
TESTC(DecodeBLOB(lpszStructType,cbEncoded, pbEncoded,dwDecodeFlags,&cbStructInfo,
&pStructInfo,fStructLengthCheck, fBLOBLengthCheck),TRUE)
//further decode the issuser name
TESTC(DecodeX509_NAME((((PCMSG_SIGNER_INFO)pStructInfo)->Issuer).cbData,
(((PCMSG_SIGNER_INFO)pStructInfo)->Issuer).pbData,dwDecodeFlags,fEncode,
fStructLengthCheck, fBLOBLengthCheck),TRUE)
//further decode the attributes
TESTC(VerifyAttributes(((PCMSG_SIGNER_INFO)pStructInfo)->AuthAttrs.cAttr,
((PCMSG_SIGNER_INFO)pStructInfo)->AuthAttrs.rgAttr,
dwDecodeFlags,fEncode,
fStructLengthCheck, fBLOBLengthCheck),TRUE)
TESTC(VerifyAttributes(((PCMSG_SIGNER_INFO)pStructInfo)->UnauthAttrs.cAttr,
((PCMSG_SIGNER_INFO)pStructInfo)->UnauthAttrs.rgAttr,
dwDecodeFlags,fEncode,
fStructLengthCheck, fBLOBLengthCheck),TRUE)
//if requested, encode the BLOB back to what it was. Make sure no data is lost
//by checking the size of the encoded blob and do a memcmp.
if(fEncode)
TCHECK(EncodeAndVerify(lpszStructType, pStructInfo,cbEncoded,
pbEncoded),TRUE);
fSucceeded=TRUE;
TCLEANUP:
SAFE_FREE(pStructInfo)
return fSucceeded;
}
//--------------------------------------------------------------------------
// Decode an array of attributes
//
// fStructLengthCheck: Flag to indicate whether a length checking is necessary
// for *pcbStructInfo from 0 .. CorrectLength-1
//
// fBLOBLengthCheck: Flag to indicate whether a length checking is necessary
// for cbEncoded from 0 .. CorrentLength-1
//--------------------------------------------------------------------------
BOOL VerifyAttributes(DWORD cAttr, PCRYPT_ATTRIBUTE rgAttr,
DWORD dwDecodeFlags, BOOL fEncode, BOOL fStructLengthCheck, BOOL fBLOBLengthCheck)
{
BOOL fSucceeded=FALSE;
ULONG iIndex=0;
for(iIndex=0;iIndex<cAttr;iIndex++)
{
TESTC(DecodeCryptAttribute(&(rgAttr[iIndex]),dwDecodeFlags,fEncode,
fStructLengthCheck,fBLOBLengthCheck),TRUE)
}
fSucceeded=TRUE;
TCLEANUP:
return fSucceeded;
}
//--------------------------------------------------------------------------
// Decode X509_UNICODE_NAME BLOBs
//
// fStructLengthCheck: Flag to indicate whether a length checking is necessary
// for *pcbStructInfo from 0 .. CorrectLength-1
//
// fBLOBLengthCheck: Flag to indicate whether a length checking is necessary
// for cbEncoded from 0 .. CorrentLength-1
//--------------------------------------------------------------------------
BOOL DecodeX509_UNICODE_NAME(DWORD cbEncoded, BYTE *pbEncoded, DWORD dwDecodeFlags,
BOOL fEncode,BOOL fStructLengthCheck, BOOL fBLOBLengthCheck)
{
BOOL fSucceeded=FALSE;
DWORD cbStructInfo=0;
void *pStructInfo=NULL;
LPCSTR lpszStructType=NULL;
DWORD cRDN=0;
DWORD cRDNAttr=0;
DWORD cRDNCount=0;
DWORD cRDNAttrCount=0;
//init
lpszStructType=X509_UNICODE_NAME;
//Decode the encoded BLOB
TESTC(DecodeBLOB(lpszStructType,cbEncoded, pbEncoded,dwDecodeFlags,&cbStructInfo,
&pStructInfo,fStructLengthCheck, fBLOBLengthCheck),TRUE)
//We need to further decode CERT_RDN_ATTR if dwValueType is CERT_RDN_ENCODED_BLOB
cRDNCount=((PCERT_NAME_INFO)pStructInfo)->cRDN;
for(cRDN=0;cRDN<cRDNCount;cRDN++)
{
cRDNAttrCount=(((PCERT_NAME_INFO)pStructInfo)->rgRDN[cRDN]).cRDNAttr;
for(cRDNAttr=0; cRDNAttr<cRDNAttrCount; cRDNAttr++)
{
//no need to do a length checking since the routine is written and
//installed by third party
if( (((PCERT_NAME_INFO)pStructInfo)->rgRDN[cRDN]).rgRDNAttr[cRDNAttr].dwValueType==
CERT_RDN_ENCODED_BLOB)
TESTC(DecodeBasedOnObjID(
(((PCERT_NAME_INFO)pStructInfo)->rgRDN[cRDN]).rgRDNAttr[cRDNAttr].pszObjId,
(((PCERT_NAME_INFO)pStructInfo)->rgRDN[cRDN]).rgRDNAttr[cRDNAttr].Value.cbData,
(((PCERT_NAME_INFO)pStructInfo)->rgRDN[cRDN]).rgRDNAttr[cRDNAttr].Value.pbData,
dwDecodeFlags, fEncode,fStructLengthCheck, fBLOBLengthCheck),TRUE)
}
}
//if requested, encode the BLOB back to what it was. Make sure no data is lost
//by checking the size of the encoded blob and do a memcmp.
if(fEncode)
TCHECK(EncodeAndVerify(lpszStructType, pStructInfo,cbEncoded, pbEncoded),TRUE);
fSucceeded=TRUE;
TCLEANUP:
SAFE_FREE(pStructInfo)
return fSucceeded;
}
//--------------------------------------------------------------------------
// Decode X509_EXTENSIONS BLOB
//
// fStructLengthCheck: Flag to indicate whether a length checking is necessary
// for *pcbStructInfo from 0 .. CorrectLength-1
//
// fBLOBLengthCheck: Flag to indicate whether a length checking is necessary
// for cbEncoded from 0 .. CorrentLength-1
//--------------------------------------------------------------------------
BOOL DecodeX509_EXTENSIONS(DWORD cbEncoded, BYTE *pbEncoded, DWORD dwDecodeFlags,
BOOL fEncode,BOOL fStructLengthCheck, BOOL fBLOBLengthCheck)
{
BOOL fSucceeded=FALSE;
DWORD cbStructInfo=0;
void *pStructInfo=NULL;
LPCSTR lpszStructType=NULL;
//init
lpszStructType=X509_EXTENSIONS;
//Decode the encoded BLOB
TESTC(DecodeBLOB(lpszStructType,cbEncoded, pbEncoded,dwDecodeFlags,&cbStructInfo,
&pStructInfo,fStructLengthCheck, fBLOBLengthCheck),TRUE)
//Decode further the pStructInfo which points to an array of CERT_EXTENSION
TESTC(DecodeCertExtensions(((PCERT_EXTENSIONS)pStructInfo)->cExtension,
((PCERT_EXTENSIONS)pStructInfo)->rgExtension,dwDecodeFlags, fEncode,
fStructLengthCheck,fBLOBLengthCheck),TRUE)
//if requested, encode the BLOB back to what it was. Make sure no data is lost
//by checking the size of the encoded blob and do a memcmp.
if(fEncode)
TCHECK(EncodeAndVerify(lpszStructType, pStructInfo,cbEncoded,
pbEncoded),TRUE);
fSucceeded=TRUE;
TCLEANUP:
SAFE_FREE(pStructInfo)
return fSucceeded;
}
//--------------------------------------------------------------------------
// Decode an array of X509 cert extensions
//
// fStructLengthCheck: Flag to indicate whether a length checking is necessary
// for *pcbStructInfo from 0 .. CorrectLength-1
//
// fBLOBLengthCheck: Flag to indicate whether a length checking is necessary
// for cbEncoded from 0 .. CorrentLength-1
//--------------------------------------------------------------------------
BOOL DecodeCertExtensions(DWORD cExtension, PCERT_EXTENSION rgExtension, DWORD dwDecodeFlags,
BOOL fEncode,BOOL fStructLengthCheck, BOOL fBLOBLengthCheck)
{
DWORD iIndex=0;
BOOL fSucceeded=FALSE;
for(iIndex=0; iIndex<cExtension; iIndex++)
{
TESTC(DecodeBasedOnObjID((rgExtension[iIndex]).pszObjId,
(rgExtension[iIndex]).Value.cbData, (rgExtension[iIndex]).Value.pbData,
dwDecodeFlags, fEncode,fStructLengthCheck,fBLOBLengthCheck),TRUE)
}
fSucceeded=TRUE;
TCLEANUP:
return fSucceeded;
}
//--------------------------------------------------------------------------
// Decode CRYPT_ATTRIBUTE struct and encode
//
// fStructLengthCheck: Flag to indicate whether a length checking is necessary
// for *pcbStructInfo from 0 .. CorrectLength-1
//
// fBLOBLengthCheck: Flag to indicate whether a length checking is necessary
// for cbEncoded from 0 .. CorrentLength-1
//--------------------------------------------------------------------------
BOOL DecodeCryptAttribute(PCRYPT_ATTRIBUTE pCryptAttribute,DWORD dwDecodeFlags,
BOOL fEncode,BOOL fStructLengthCheck, BOOL fBLOBLengthCheck)
{
BOOL fSucceeded=FALSE;
DWORD iIndex=0;
for(iIndex=0; iIndex<pCryptAttribute->cValue;iIndex++)
{
TESTC(DecodeBasedOnObjID(pCryptAttribute->pszObjId,
(pCryptAttribute->rgValue)[iIndex].cbData,
(pCryptAttribute->rgValue)[iIndex].pbData,
dwDecodeFlags, fEncode,fStructLengthCheck,fBLOBLengthCheck),TRUE)
}
fSucceeded=TRUE;
TCLEANUP:
return fSucceeded;
}
//--------------------------------------------------------------------------
// Decode CRL_ENTRY struct and encode
//
// fStructLengthCheck: Flag to indicate whether a length checking is necessary
// for *pcbStructInfo from 0 .. CorrectLength-1
//
// fBLOBLengthCheck: Flag to indicate whether a length checking is necessary
// for cbEncoded from 0 .. CorrentLength-1
//--------------------------------------------------------------------------
BOOL DecodeCRLEntry(PCRL_ENTRY pCrlEntry, DWORD dwDecodeFlags,
BOOL fEncode,BOOL fStructLengthCheck, BOOL fBLOBLengthCheck)
{
BOOL fSucceeded=FALSE;
//Verify the extensions
TESTC(VerifyCertExtensions(pCrlEntry->cExtension,
pCrlEntry->rgExtension,dwDecodeFlags,fEncode,
fStructLengthCheck, fBLOBLengthCheck),TRUE)
//decode the extensions one by one
TESTC(DecodeCertExtensions(pCrlEntry->cExtension,
pCrlEntry->rgExtension,dwDecodeFlags,fEncode,
fStructLengthCheck, fBLOBLengthCheck),TRUE)
fSucceeded=TRUE;
TCLEANUP:
return fSucceeded;
}
//--------------------------------------------------------------------------
// Decode one X509 cert extension
//
// fStructLengthCheck: Flag to indicate whether a length checking is necessary
// for *pcbStructInfo from 0 .. CorrectLength-1
//
// fBLOBLengthCheck: Flag to indicate whether a length checking is necessary
// for cbEncoded from 0 .. CorrentLength-1
//--------------------------------------------------------------------------
BOOL DecodeBasedOnObjID(LPSTR szObjId, DWORD cbData, BYTE *pbData,
DWORD dwDecodeFlags, BOOL fEncode,
BOOL fStructLengthCheck, BOOL fBLOBLengthCheck)
{
BOOL fSucceeded=FALSE;
DWORD cbStructInfo=0;
void *pStructInfo=NULL;
DWORD iIndex=0;
DWORD cCount=0;
DWORD iIndexInner=0;
DWORD cCountInner=0;
CERT_NAME_BLOB *pBlob=NULL;
PCERT_ALT_NAME_ENTRY pCertAltNameEntry=NULL;
PCERT_POLICY_INFO pCertPolicyInfo=NULL;
PCERT_POLICY_QUALIFIER_INFO pCertPolicyQualifierInfo=NULL;
LPCSTR lpszStructType=NULL;
//init
lpszStructType=MapObjID2StructType(szObjId);
//return TRUE if we can not recognize the object ID. We can no longer
//go any further.
if(!lpszStructType)
return TRUE;
//Decode the encoded BLOB
TESTC(DecodeBLOB(lpszStructType,cbData, pbData,
dwDecodeFlags,&cbStructInfo,&pStructInfo,fStructLengthCheck, fBLOBLengthCheck),TRUE)
//further decode the extension if we know what the struct look like
switch((DWORD_PTR)lpszStructType)
{
//we need to further decode CertIssuer in CERT_AUTHORITY_KEY_ID_INFO
case (DWORD_PTR)(X509_AUTHORITY_KEY_ID):
pBlob=&(((PCERT_AUTHORITY_KEY_ID_INFO)pStructInfo)->CertIssuer);
TESTC(DecodeX509_NAME(pBlob->cbData, pBlob->pbData,
dwDecodeFlags, fEncode,fStructLengthCheck,fBLOBLengthCheck),TRUE)
//further decode the BLOB to X509_UNICODE_NAME
TESTC(DecodeX509_UNICODE_NAME(pBlob->cbData, pBlob->pbData,
dwDecodeFlags, fEncode,fStructLengthCheck,fBLOBLengthCheck),TRUE)
break;
//we need to further decode the CERT_ALT_NAME_ENTRY array
case (DWORD_PTR)(X509_ALTERNATE_NAME):
/* cCount=((PCERT_ALT_NAME_INFO)pStructInfo)->cAltEntry;
for(iIndex=0; iIndex<cCount; iIndex++)
{
pCertAltNameEntry=&(((PCERT_ALT_NAME_INFO)pStructInfo)->rgAltEntry[iIndex]);
TESTC(DecodeCertAltNameEntry(pCertAltNameEntry,dwDecodeFlags, fEncode,
fStructLengthCheck, fBLOBLengthCheck),TRUE)
}
*/
break;
//we need to further decode CERT_BASIC_CONSTRAINTS_INFO
case (DWORD_PTR)(X509_BASIC_CONSTRAINTS):
cCount=((PCERT_BASIC_CONSTRAINTS_INFO)pStructInfo)->cSubtreesConstraint;
//decode the array of CERT_NAME_BLOB in rgSubtreesConstraint
//of CERT_BASIC_CONSTRAINTS_INFO
for(iIndex=0; iIndex<cCount; iIndex++)
{
pBlob=&((((PCERT_BASIC_CONSTRAINTS_INFO)pStructInfo)->rgSubtreesConstraint)[iIndex]);
TESTC(DecodeX509_NAME(pBlob->cbData, pBlob->pbData,
dwDecodeFlags, fEncode,fStructLengthCheck,fBLOBLengthCheck),TRUE)
//further decode as X509_UNICODE_NAME
TESTC(DecodeX509_UNICODE_NAME(pBlob->cbData, pBlob->pbData,
dwDecodeFlags, fEncode,fStructLengthCheck,fBLOBLengthCheck),TRUE)
}
break;
case (DWORD_PTR)(X509_CERT_POLICIES ):
cCount=((PCERT_POLICIES_INFO)pStructInfo)->cPolicyInfo;
for(iIndex=0; iIndex<cCount;iIndex++)
{
pCertPolicyInfo=&(((PCERT_POLICIES_INFO)pStructInfo)->rgPolicyInfo[iIndex]);
cCountInner=pCertPolicyInfo->cPolicyQualifier;
for(iIndexInner=0; iIndexInner<cCountInner; iIndexInner++)
{
pCertPolicyQualifierInfo=&((pCertPolicyInfo->rgPolicyQualifier)[iIndexInner]);
//Although DecodeBasedOnObjID is called here, we have
//no risk of an infinite loop.
//This is a recursive call, which should
//end when there is no further decodable code, that is,
//the pszObjID should not be szOID_CERT_POLICIES
TESTC(DecodeBasedOnObjID(pCertPolicyQualifierInfo->pszPolicyQualifierId,
pCertPolicyQualifierInfo->Qualifier.cbData,
pCertPolicyQualifierInfo->Qualifier.pbData,
dwDecodeFlags, fEncode,fStructLengthCheck,
fBLOBLengthCheck),TRUE)
}
}
break;
default:
break;
}
//if requested, encode the BLOB back to what it was. Make sure no data is lost
//by checking the size of the encoded blob and do a memcmp.
if(fEncode)
TCHECK(EncodeAndVerify(lpszStructType, pStructInfo,cbData,
pbData),TRUE);
fSucceeded=TRUE;
TCLEANUP:
SAFE_FREE(pStructInfo)
return fSucceeded;
}
//--------------------------------------------------------------------------
// Decode one X509 cert extension
//
// fStructLengthCheck: Flag to indicate whether a length checking is necessary
// for *pcbStructInfo from 0 .. CorrectLength-1
//
// fBLOBLengthCheck: Flag to indicate whether a length checking is necessary
// for cbEncoded from 0 .. CorrentLength-1
//--------------------------------------------------------------------------
BOOL DecodeCertAltNameEntry(PCERT_ALT_NAME_ENTRY pCertAltNameEntry,
DWORD dwDecodeFlags, BOOL fEncode,
BOOL fStructLengthCheck, BOOL fBLOBLengthCheck)
{
BOOL fSucceeded=FALSE;
PCRYPT_ATTRIBUTE_TYPE_VALUE pAttributeTypeValue=NULL;
assert(pCertAltNameEntry);
switch(pCertAltNameEntry->dwAltNameChoice)
{
case CERT_ALT_NAME_DIRECTORY_NAME:
//further decode the NAME_BLOB in DirectoryName
TESTC(DecodeX509_NAME(pCertAltNameEntry->DirectoryName.cbData,
pCertAltNameEntry->DirectoryName.pbData,
dwDecodeFlags,fEncode,fStructLengthCheck,fBLOBLengthCheck),TRUE)
//decode it as UNICODE
TESTC(DecodeX509_UNICODE_NAME(pCertAltNameEntry->DirectoryName.cbData,
pCertAltNameEntry->DirectoryName.pbData,
dwDecodeFlags,fEncode,fStructLengthCheck,fBLOBLengthCheck),TRUE)
break;
default:
break;
}
fSucceeded=TRUE;
TCLEANUP:
return fSucceeded;
}