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.
 
 
 
 
 
 

1572 lines
46 KiB

//+-------------------------------------------------------------------------
//
// Microsoft Windows
//
// Copyright (C) Microsoft Corporation, 1995 - 1999
//
// File: queryobj.cpp
//
// Contents: OID format functions
//
// Functions:
// CryptQueryObject
//
// History: 15-05-97 xiaohs created
//--------------------------------------------------------------------------
#include "global.hxx"
#include <dbgdef.h>
#include "frmtfunc.h"
#include "align.h"
#define ASN_ASCII_HEX_PREFIX "{ASN}"
#define ASN_ASCII_HEX_PREFIX_LEN ((DWORD) strlen(ASN_ASCII_HEX_PREFIX))
#define NOTEPAD_UNICODE_SPECIAL_WCHAR L'\xfeff'
//**************************************************************************
//
// The following section is for CryptQueryObject
//**************************************************************************
//+-------------------------------------------------------------------------
// CryptStringToBinaryA: Decode the BLOB
//
//--------------------------------------------------------------------------
BOOL DecodeBlobA(CHAR *pbByte,
DWORD cbByte,
BYTE **ppbData,
DWORD *pcbData)
{
DWORD err=0;
BOOL fResult=FALSE;
DWORD dwFlag=0;
*ppbData=NULL;
*pcbData=0;
__try {
if(!CryptStringToBinaryA(pbByte,
cbByte,
CRYPT_STRING_BASE64_ANY,
NULL,
pcbData,
NULL,
&dwFlag))
{
err = GetLastError();
goto DecodeErr;
}
}
__except (EXCEPTION_EXECUTE_HANDLER) {
err = GetExceptionCode();
goto DecodeErr;
}
*ppbData=(BYTE *)malloc(*pcbData);
if(NULL==*ppbData)
goto OutOfMemoryErr;
__try {
if(!CryptStringToBinaryA(pbByte,
cbByte,
dwFlag,
*ppbData,
pcbData,
NULL,
NULL))
{
err = GetLastError();
goto DecodeErr;
}
}
__except (EXCEPTION_EXECUTE_HANDLER) {
err = GetExceptionCode();
goto DecodeErr;
}
fResult=TRUE;
CommonReturn:
return fResult;
ErrorReturn:
if(*ppbData)
{
free(*ppbData);
*ppbData=NULL;
}
fResult=FALSE;
goto CommonReturn;
SET_ERROR_VAR(DecodeErr, err);
SET_ERROR(OutOfMemoryErr, E_OUTOFMEMORY);
}
//+-------------------------------------------------------------------------
// CryptStringToBinaryW: Decode the BLOB
//
//--------------------------------------------------------------------------
BOOL DecodeBlobW(WCHAR *pbByte,
DWORD cbByte,
BYTE **ppbData,
DWORD *pcbData)
{
DWORD err=0;
BOOL fResult=FALSE;
DWORD dwFlag=0;
*ppbData=NULL;
*pcbData=0;
__try {
if(!CryptStringToBinaryW(pbByte,
cbByte,
CRYPT_STRING_BASE64_ANY,
NULL,
pcbData,
NULL,
&dwFlag))
{
err = GetLastError();
goto DecodeErr;
}
}
__except (EXCEPTION_EXECUTE_HANDLER) {
err = GetExceptionCode();
goto DecodeErr;
}
*ppbData=(BYTE *)malloc(*pcbData);
if(NULL==*ppbData)
goto OutOfMemoryErr;
__try {
if(!CryptStringToBinaryW(pbByte,
cbByte,
dwFlag,
*ppbData,
pcbData,
NULL,
NULL))
{
err = GetLastError();
goto DecodeErr;
}
}
__except (EXCEPTION_EXECUTE_HANDLER) {
err = GetExceptionCode();
goto DecodeErr;
}
fResult=TRUE;
CommonReturn:
return fResult;
ErrorReturn:
if(*ppbData)
{
free(*ppbData);
*ppbData=NULL;
}
fResult=FALSE;
goto CommonReturn;
SET_ERROR_VAR(DecodeErr, err);
SET_ERROR(OutOfMemoryErr, E_OUTOFMEMORY);
}
//+-------------------------------------------------------------------------
// Decode the BLOB encoded as ASCII HEX.
//
// Note, pbByte has already been advanced past any leading prefix such as,
// "{ASN}"
//--------------------------------------------------------------------------
BOOL
DecodeAsciiHex(
const char *pch,
DWORD cch,
BYTE **ppbData,
DWORD *pcbData
)
{
DWORD err;
BOOL fResult;
DWORD cbData;
BYTE *pbData = NULL;
pbData = (BYTE *) malloc(cch/2 + 1);
if (NULL == pbData)
goto OutOfMemory;
__try {
BYTE bData;
BYTE *pb;
BOOL fUpperNibble;
fUpperNibble = TRUE;
for (pb = pbData; 0 < cch; cch--, pch++) {
BYTE b;
char ch;
// Convert ascii hex characters 0..9, a..f, A..F
// silently ignore all others
ch = *pch;
if (ch >= '0' && ch <= '9')
b = (BYTE)( ch - '0' );
else if (ch >= 'a' && ch <= 'f')
b = (BYTE)( 10 + ch - 'a' );
else if (ch >= 'A' && ch <= 'F')
b = (BYTE)( 10 + ch - 'A' );
else
goto InvalidData;
if (fUpperNibble) {
bData = (BYTE)( b << 4 );
fUpperNibble = FALSE;
} else {
bData = (BYTE)( bData | b );
*pb++ = bData;
fUpperNibble = TRUE;
}
}
cbData = (DWORD) (pb - pbData);
if (0 == cbData || !fUpperNibble)
goto InvalidData;
} __except (EXCEPTION_EXECUTE_HANDLER) {
err = GetExceptionCode();
goto ExceptionErr;
}
fResult = TRUE;
CommonReturn:
*ppbData = pbData;
*pcbData = cbData;
return fResult;
ErrorReturn:
if (pbData) {
free(pbData);
pbData = NULL;
}
cbData = 0;
fResult = FALSE;
goto CommonReturn;
SET_ERROR_VAR(ExceptionErr, err);
SET_ERROR(OutOfMemory, E_OUTOFMEMORY);
SET_ERROR(InvalidData, ERROR_INVALID_DATA);
}
//+-------------------------------------------------------------------------
// Skip over the identifier and length octets in an ASN encoded blob.
// Returns the number of bytes skipped.
//
// For an invalid identifier or length octet returns 0.
//--------------------------------------------------------------------------
DWORD SkipOverIdentifierAndLengthOctets(
IN const BYTE *pbDER,
IN DWORD cbDER
)
{
#define TAG_MASK 0x1f
DWORD cb;
DWORD cbLength;
const BYTE *pb = pbDER;
// Need minimum of 2 bytes
if (cbDER < 2)
return 0;
// Skip over the identifier octet(s)
if (TAG_MASK == (*pb++ & TAG_MASK)) {
// high-tag-number form
for (cb=2; *pb++ & 0x80; cb++) {
if (cb >= cbDER)
return 0;
}
} else
// low-tag-number form
cb = 1;
// need at least one more byte for length
if (cb >= cbDER)
return 0;
if (0x80 == *pb)
// Indefinite
cb++;
else if ((cbLength = *pb) & 0x80) {
cbLength &= ~0x80; // low 7 bits have number of bytes
cb += cbLength + 1;
if (cb > cbDER)
return 0;
} else
cb++;
return cb;
}
//--------------------------------------------------------------------------
//
// Skip over the tag and length
//----------------------------------------------------------------------------
BOOL SignNoContentWrap(IN const BYTE *pbDER, IN DWORD cbDER)
{
DWORD cb;
__try {
cb = SkipOverIdentifierAndLengthOctets(pbDER, cbDER);
if (cb > 0 && cb < cbDER && pbDER[cb] == 0x02)
return TRUE;
else
return FALSE;
}
__except(EXCEPTION_EXECUTE_HANDLER) {
SetLastError(GetExceptionCode());
}
return FALSE;
}
//--------------------------------------------------------------------------------
//
//get the bytes from the file name
//
//---------------------------------------------------------------------------------
HRESULT RetrieveBLOBFromFile(LPWSTR pwszFileName,DWORD *pcb,BYTE **ppb)
{
HRESULT hr=E_FAIL;
HANDLE hFile=NULL;
HANDLE hFileMapping=NULL;
DWORD cbData=0;
BYTE *pbData=0;
WIN32_FILE_ATTRIBUTE_DATA FileAttr;
if(!pcb || !ppb || !pwszFileName)
return E_INVALIDARG;
*ppb=NULL;
*pcb=0;
if (!GetFileAttributesExW(
pwszFileName,
GetFileExInfoStandard,
&FileAttr
))
{
hr=HRESULT_FROM_WIN32(GetLastError());
goto CLEANUP;
}
cbData = FileAttr.nFileSizeLow;
if ((FileAttr.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ||
(0 != FileAttr.nFileSizeHigh) ||
(0 == cbData))
{
hr=E_FAIL;
goto CLEANUP;
}
if ((hFile = CreateFileU(pwszFileName,
GENERIC_READ,
FILE_SHARE_READ,
NULL, // lpsa
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL)) == INVALID_HANDLE_VALUE)
{
hFile = NULL;
hr=HRESULT_FROM_WIN32(GetLastError());
goto CLEANUP;
}
//create a file mapping object
if(NULL == (hFileMapping=CreateFileMapping(
hFile,
NULL,
PAGE_READONLY,
0,
0,
NULL)))
{
hr=HRESULT_FROM_WIN32(GetLastError());
goto CLEANUP;
}
//create a view of the file
if(NULL == (pbData=(BYTE *)MapViewOfFile(
hFileMapping,
FILE_MAP_READ,
0,
0,
cbData)))
{
hr=HRESULT_FROM_WIN32(GetLastError());
goto CLEANUP;
}
hr=S_OK;
*pcb=cbData;
*ppb=pbData;
CLEANUP:
if(hFile)
CloseHandle(hFile);
if(hFileMapping)
CloseHandle(hFileMapping);
return hr;
}
//-------------------------------------------------------------------------
//
// Check to see if the BLOB has an embeded PKCS7 using SIP functions
//
//-------------------------------------------------------------------------
BOOL GetEmbeddedPKCS7(CERT_BLOB *pCertBlob,
LPWSTR pwszFileName,
BYTE **ppbData,
DWORD *pcbData,
DWORD *pdwEncodingType)
{
BOOL fResult=FALSE;
CHAR szTempPath[MAX_PATH];
CHAR szTempFileName[MAX_PATH];
LPSTR szPreFix="Tmp"; //we should not localize this string
//since it has to be in ANSCII characeter set
DWORD dwBytesWritten=0;
GUID gSubject;
SIP_DISPATCH_INFO SipDispatch;
SIP_SUBJECTINFO SubjectInfo;
HANDLE hFile=NULL;
LPWSTR pwszFileToUse=NULL;
//init the output
*ppbData=NULL;
*pcbData=0;
*pdwEncodingType=0;
//create a temporary file since SIP functions only takes a file name
if(NULL==pwszFileName)
{
if(0==GetTempPath(sizeof(szTempPath), szTempPath))
goto GetTempPathErr;
if(0==GetTempFileName(szTempPath, szPreFix, 0, szTempFileName))
goto GetTempFileNameErr;
if(INVALID_HANDLE_VALUE==(hFile=CreateFile(szTempFileName,
GENERIC_WRITE |GENERIC_READ,
FILE_SHARE_READ,
NULL,
CREATE_NEW,
FILE_ATTRIBUTE_NORMAL,
NULL)))
goto CreateFileErr;
//write the BLOB to the file
if(!WriteFile(hFile,
pCertBlob->pbData,
pCertBlob->cbData,
&dwBytesWritten,
NULL))
goto WriteFileErr;
if(dwBytesWritten != pCertBlob->cbData)
goto WriteBytesErr;
//close the file handle
if(!CloseHandle(hFile))
{
hFile=NULL;
goto CloseHandleErr;
}
hFile=NULL;
//get the unicode version of the file name
pwszFileToUse=MkWStr(szTempFileName);
if(NULL==pwszFileToUse)
goto MkWStrErr;
}
else
pwszFileToUse=pwszFileName;
//call the sip functions
//get the GUID
if (!CryptSIPRetrieveSubjectGuid(
pwszFileToUse,
NULL,
&gSubject))
goto CryptNoMatchErr;
//load the dispatch
memset(&SipDispatch, 0, sizeof(SipDispatch));
SipDispatch.cbSize = sizeof(SipDispatch);
if (!CryptSIPLoad(
&gSubject,
0,
&SipDispatch))
goto CryptNoMatchErr;
//fill out the subjectInfo
memset(&SubjectInfo, 0, sizeof(SubjectInfo));
SubjectInfo.cbSize = sizeof(SubjectInfo);
SubjectInfo.pgSubjectType = (GUID*) &gSubject;
SubjectInfo.hFile = INVALID_HANDLE_VALUE;
SubjectInfo.pwsFileName = pwszFileToUse;
SubjectInfo.dwEncodingType = *pdwEncodingType;
//get the embedded PKCS7
SipDispatch.pfGet(
&SubjectInfo,
pdwEncodingType,
0, // dwIndex
pcbData,
NULL // pbSignedData
);
if (0 == (*pcbData))
goto CryptNoMatchErr;
if (NULL == (*ppbData=(BYTE *)malloc(*pcbData)))
goto OutOfMemoryErr;
if (!SipDispatch.pfGet(
&SubjectInfo,
pdwEncodingType,
0, // dwIndex
pcbData,
*ppbData
))
goto CryptNoMatchErr;
fResult=TRUE;
CommonReturn:
//close the file handle
if(INVALID_HANDLE_VALUE!=hFile && NULL !=hFile)
CloseHandle(hFile);
//delete the file if it was created
if(NULL==pwszFileName)
{
DeleteFileU(pwszFileToUse);
FreeWStr(pwszFileToUse);
}
return fResult;
ErrorReturn:
fResult=FALSE;
if(*ppbData)
{
free(*ppbData);
*ppbData=NULL;
}
goto CommonReturn;
TRACE_ERROR(GetTempPathErr);
TRACE_ERROR(GetTempFileNameErr);
TRACE_ERROR(CreateFileErr);
TRACE_ERROR(WriteFileErr);
SET_ERROR(WriteBytesErr, E_FAIL);
TRACE_ERROR(CloseHandleErr);
TRACE_ERROR(MkWStrErr);
SET_ERROR(CryptNoMatchErr, CRYPT_E_NO_MATCH);
SET_ERROR(OutOfMemoryErr, E_OUTOFMEMORY);
}
BOOL
AddCertPairToStore(
IN HCERTSTORE hCertStore,
IN const BYTE *pbEncoded,
IN DWORD cbEncoded
)
{
BOOL fResult;
PCERT_PAIR pInfo = NULL;
DWORD cbInfo;
PCCERT_CONTEXT pCertForward = NULL;
// CryptDecodeObjectEX should be usable here, but since this object
// is included with XEnroll and XEnroll must run with Auth2UPD Crypt32
// we must stick with the old CryptDecodeObject 2 pass calls.
if (!CryptDecodeObject(
X509_ASN_ENCODING,
X509_CERT_PAIR,
pbEncoded,
cbEncoded,
CRYPT_DECODE_NOCOPY_FLAG,
NULL, // pInfo
&cbInfo
))
goto DecodeError;
if (NULL == (pInfo = (PCERT_PAIR) malloc(cbInfo)))
goto OutOfMemory;
if (!CryptDecodeObject(
X509_ASN_ENCODING,
X509_CERT_PAIR,
pbEncoded,
cbEncoded,
CRYPT_DECODE_NOCOPY_FLAG,
pInfo,
&cbInfo
))
goto DecodeError;
if (pInfo->Forward.cbData) {
if (!CertAddEncodedCertificateToStore(
hCertStore,
X509_ASN_ENCODING,
pInfo->Forward.pbData,
pInfo->Forward.cbData,
CERT_STORE_ADD_ALWAYS,
&pCertForward
))
goto AddCertError;
}
if (pInfo->Reverse.cbData) {
if (!CertAddEncodedCertificateToStore(
hCertStore,
X509_ASN_ENCODING,
pInfo->Reverse.pbData,
pInfo->Reverse.cbData,
CERT_STORE_ADD_ALWAYS,
NULL // ppCertContext
))
goto AddCertError;
}
if (pCertForward)
CertFreeCertificateContext(pCertForward);
fResult = TRUE;
CommonReturn:
if (pInfo)
free(pInfo);
return fResult;
DecodeError:
ErrorReturn:
fResult = FALSE;
if (pCertForward)
CertDeleteCertificateFromStore(pCertForward);
goto CommonReturn;
SET_ERROR(OutOfMemory, E_OUTOFMEMORY)
TRACE_ERROR(AddCertError)
}
//-------------------------------------------------------------------------
//
// The real implementation of CryptQueryObject
//
//-------------------------------------------------------------------------
BOOL I_CryptQueryObject(CERT_BLOB *pCertBlob,
LPWSTR pwszFileName,
DWORD dwContentTypeFlag,
DWORD dwFormatTypeFlag,
DWORD dwFlag,
DWORD *pdwMsgAndCertEncodingType,
DWORD *pdwContentType,
DWORD *pdwFormatType,
HCERTSTORE *phCertStore,
HCRYPTMSG *phMsg,
const void **ppvContext)
{
BOOL fResult=FALSE;
DWORD dwMsgEncodingType=PKCS_7_ASN_ENCODING;
DWORD dwEncodingType=X509_ASN_ENCODING;
DWORD dwPKCS7EncodingType=X509_ASN_ENCODING|PKCS_7_ASN_ENCODING;
DWORD dwContentType=0;
DWORD dwMsgType=0;
DWORD cbData=0;
BOOL fEmbedded=FALSE;
CERT_BLOB PKCS7Blob;
BYTE *pbPKCS7=NULL;
DWORD cbPKCS7=0;
HCERTSTORE hCertStore=NULL;
HCRYPTMSG hMsg=NULL;
PCCERT_CONTEXT pCertContext=NULL;
PCCRL_CONTEXT pCRLContext=NULL;
PCCTL_CONTEXT pCTLContext=NULL;
PCERT_REQUEST_INFO pReqInfo=NULL;
//NULL the output
if(pdwMsgAndCertEncodingType)
*pdwMsgAndCertEncodingType=0;
if(pdwContentType)
*pdwContentType=0;
if(pdwFormatType)
*pdwFormatType=0;
if(phCertStore)
*phCertStore=NULL;
if(phMsg)
*phMsg=NULL;
if(ppvContext)
*ppvContext=NULL;
//open a generic memory store
hCertStore=CertOpenStore(CERT_STORE_PROV_MEMORY,
0,
NULL,
0,
NULL);
if(NULL == hCertStore)
goto CertOpenStoreErr;
//single encoded cert
if(dwContentTypeFlag & CERT_QUERY_CONTENT_FLAG_CERT)
{
if(CertAddEncodedCertificateToStore(hCertStore,
dwEncodingType,
pCertBlob->pbData,
pCertBlob->cbData,
CERT_STORE_ADD_ALWAYS,
&pCertContext))
{
dwContentType=CERT_QUERY_CONTENT_CERT;
goto Found;
}
}
//an encoded CertificatePair (contains forward and/or reverse cross certs)
if(dwContentTypeFlag & CERT_QUERY_CONTENT_FLAG_CERT_PAIR)
{
if(AddCertPairToStore(hCertStore,
pCertBlob->pbData,
pCertBlob->cbData
))
{
dwContentType=CERT_QUERY_CONTENT_CERT_PAIR;
goto Found;
}
}
//single encoded CTL
if(dwContentTypeFlag & CERT_QUERY_CONTENT_FLAG_CTL)
{
if(CertAddEncodedCTLToStore(hCertStore,
dwEncodingType | dwMsgEncodingType,
pCertBlob->pbData,
pCertBlob->cbData,
CERT_STORE_ADD_ALWAYS,
&pCTLContext))
{
dwContentType=CERT_QUERY_CONTENT_CTL;
dwEncodingType |= dwMsgEncodingType;
goto Found;
}
}
//single encoded CRL
if(dwContentTypeFlag & CERT_QUERY_CONTENT_FLAG_CRL)
{
if(CertAddEncodedCRLToStore(hCertStore,
dwEncodingType,
pCertBlob->pbData,
pCertBlob->cbData,
CERT_STORE_ADD_ALWAYS,
&pCRLContext))
{
dwContentType=CERT_QUERY_CONTENT_CRL;
goto Found;
}
}
//PFX
if(dwContentTypeFlag & CERT_QUERY_CONTENT_FLAG_PFX)
{
if(PFXIsPFXBlob((CRYPT_DATA_BLOB*)pCertBlob))
{
dwContentType=CERT_QUERY_CONTENT_PFX;
//we need to close the temporary store
CertCloseStore(hCertStore, 0);
hCertStore=NULL;
goto Found;
}
}
//serialized CERT
if(dwContentTypeFlag & CERT_QUERY_CONTENT_FLAG_SERIALIZED_CERT)
{
if(CertAddSerializedElementToStore(hCertStore,
pCertBlob->pbData,
pCertBlob->cbData,
CERT_STORE_ADD_ALWAYS,
0,
CERT_STORE_CERTIFICATE_CONTEXT_FLAG,
NULL,
(const void **)&pCertContext))
{
dwContentType=CERT_QUERY_CONTENT_SERIALIZED_CERT;
dwEncodingType=pCertContext->dwCertEncodingType;
goto Found;
}
}
//serialized CTL
if(dwContentTypeFlag & CERT_QUERY_CONTENT_FLAG_SERIALIZED_CTL)
{
if(CertAddSerializedElementToStore(hCertStore,
pCertBlob->pbData,
pCertBlob->cbData,
CERT_STORE_ADD_ALWAYS,
0,
CERT_STORE_CTL_CONTEXT_FLAG,
NULL,
(const void **)&pCTLContext))
{
dwContentType=CERT_QUERY_CONTENT_SERIALIZED_CTL;
dwEncodingType=pCTLContext->dwMsgAndCertEncodingType;
goto Found;
}
}
//serialized CRL
if(dwContentTypeFlag & CERT_QUERY_CONTENT_FLAG_SERIALIZED_CRL)
{
if(CertAddSerializedElementToStore(hCertStore,
pCertBlob->pbData,
pCertBlob->cbData,
CERT_STORE_ADD_ALWAYS,
0,
CERT_STORE_CRL_CONTEXT_FLAG,
NULL,
(const void **)&pCRLContext))
{
dwContentType=CERT_QUERY_CONTENT_SERIALIZED_CRL;
dwEncodingType=pCRLContext->dwCertEncodingType;
goto Found;
}
}
//we need to close the temporary store
CertCloseStore(hCertStore, 0);
hCertStore=NULL;
//serialized store
if(dwContentTypeFlag & CERT_QUERY_CONTENT_FLAG_SERIALIZED_STORE)
{
if(hCertStore=CertOpenStore(
CERT_STORE_PROV_SERIALIZED,
dwEncodingType | dwMsgEncodingType,
NULL,
0,
pCertBlob))
{
dwContentType=CERT_QUERY_CONTENT_SERIALIZED_STORE;
dwEncodingType |= dwMsgEncodingType;
goto Found;
}
}
//PKCS7 signed message
if((dwContentTypeFlag & CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED) ||
(dwContentTypeFlag & CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED) )
{
//get the embedded signed pkcs7
if((CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED & dwContentTypeFlag))
{
if(GetEmbeddedPKCS7(pCertBlob, pwszFileName, &pbPKCS7, &cbPKCS7, &dwPKCS7EncodingType))
fEmbedded=TRUE;
else
{
if(dwContentTypeFlag & CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED)
{
//there is no embedded PKCS7
dwPKCS7EncodingType=dwEncodingType | dwMsgEncodingType;
pbPKCS7=pCertBlob->pbData;
cbPKCS7=pCertBlob->cbData;
}
else
pbPKCS7=NULL;
}
}
else
{
//there is no embedded PKCS7
dwPKCS7EncodingType=dwEncodingType | dwMsgEncodingType;
pbPKCS7=pCertBlob->pbData;
cbPKCS7=pCertBlob->cbData;
}
//proceed if there is a pkcs7 to decode
if(NULL != pbPKCS7)
{
//check if the header is missing
if(SignNoContentWrap(pbPKCS7, cbPKCS7))
dwMsgType=CMSG_SIGNED;
if(NULL==(hMsg=CryptMsgOpenToDecode(dwPKCS7EncodingType,
0,
dwMsgType,
NULL,
NULL,
NULL)))
goto CryptMsgOpenErr;
//update the message
if(CryptMsgUpdate(hMsg,
pbPKCS7,
cbPKCS7,
TRUE))
{
//get the message type
cbData=sizeof(dwMsgType);
if(!CryptMsgGetParam(hMsg,
CMSG_TYPE_PARAM,
0,
&dwMsgType,
&cbData))
goto CryptMsgGetParamErr;
if(CMSG_SIGNED == dwMsgType)
{
PKCS7Blob.cbData=cbPKCS7;
PKCS7Blob.pbData=pbPKCS7;
//open a certificate store
hCertStore=CertOpenStore(CERT_STORE_PROV_PKCS7,
dwPKCS7EncodingType,
NULL,
0,
&PKCS7Blob);
if(NULL==hCertStore)
goto CertOpenStoreErr;
//we succeeded in opening a signed PKCS7
dwEncodingType = dwPKCS7EncodingType;
if(TRUE==fEmbedded)
dwContentType=CERT_QUERY_CONTENT_PKCS7_SIGNED_EMBED;
else
dwContentType=CERT_QUERY_CONTENT_PKCS7_SIGNED;
goto Found;
}
}
//close the message
CryptMsgClose(hMsg);
hMsg=NULL;
}
}
//PKCS7 unsigned message, not embedded
if(dwContentTypeFlag & CERT_QUERY_CONTENT_FLAG_PKCS7_UNSIGNED)
{
//no need to check if the header is missing
if(NULL==(hMsg=CryptMsgOpenToDecode(dwEncodingType | dwMsgEncodingType,
0,
0,
NULL,
NULL,
NULL)))
goto CryptMsgOpenErr;
//update the message
if(CryptMsgUpdate(hMsg,
pCertBlob->pbData,
pCertBlob->cbData,
TRUE))
{
//get the message type
cbData=sizeof(dwMsgType);
if(!CryptMsgGetParam(hMsg,
CMSG_TYPE_PARAM,
0,
&dwMsgType,
&cbData))
goto CryptMsgGetParamErr;
if(CMSG_SIGNED != dwMsgType)
{
//we succeeded in opening a unsigned PKCS7
dwContentType=CERT_QUERY_CONTENT_PKCS7_UNSIGNED;
dwEncodingType =dwEncodingType | dwMsgEncodingType;
goto Found;
}
}
//close the message
CryptMsgClose(hMsg);
hMsg=NULL;
}
//PKCS10
if(dwContentTypeFlag & CERT_QUERY_CONTENT_FLAG_PKCS10)
{
//try to decode the BLOB
cbData = 0;
if(CryptDecodeObject(dwEncodingType,
X509_CERT_REQUEST_TO_BE_SIGNED,
pCertBlob->pbData,
pCertBlob->cbData,
0,
NULL,
&cbData))
{
dwContentType=CERT_QUERY_CONTENT_PKCS10;
// CryptDecodeObjectEX should be usable here, but since this object
// is included with XEnroll and XEnroll must run with Auth2UPD Crypt32
// we must stick with the old CryptDecodeObject 2 pass calls.
if( (dwFlag & CRYPT_DECODE_ALLOC_FLAG) == CRYPT_DECODE_ALLOC_FLAG ) {
// allocate the space, must use local alloc
if( NULL == (pReqInfo = (PCERT_REQUEST_INFO) LocalAlloc(LPTR, cbData)) )
goto LocalAllocErr;
// decode the request
if( !CryptDecodeObject(dwEncodingType,
X509_CERT_REQUEST_TO_BE_SIGNED,
pCertBlob->pbData,
pCertBlob->cbData,
0,
pReqInfo,
&cbData))
goto CryptDecodeObjectErr;
}
goto Found;
}
}
//we give up
goto NoMatchErr;
Found:
//fill in the output if required; Free the resources
if(pdwMsgAndCertEncodingType)
*pdwMsgAndCertEncodingType=dwEncodingType;
if(pdwContentType)
*pdwContentType=dwContentType;
if(phCertStore)
*phCertStore=hCertStore;
else
{
if(hCertStore)
CertCloseStore(hCertStore, 0);
}
if(phMsg)
*phMsg=hMsg;
else
{
if(hMsg)
CryptMsgClose(hMsg);
}
if(ppvContext)
{
//only one of pCertContext or pCRLContext or pCRLContext is set
if(pCertContext)
*ppvContext=pCertContext;
else
{
if(pCRLContext)
*ppvContext=pCRLContext;
else if(pReqInfo)
*ppvContext=pReqInfo;
else
*ppvContext=pCTLContext;
}
}
else
{
if(pCertContext)
CertFreeCertificateContext(pCertContext);
if(pCRLContext)
CertFreeCRLContext(pCRLContext);
if(pCTLContext)
CertFreeCTLContext(pCTLContext);
if(pReqInfo)
LocalFree(pReqInfo);
}
fResult=TRUE;
CommonReturn:
if(pbPKCS7)
{
if(TRUE==fEmbedded)
free(pbPKCS7);
}
return fResult;
ErrorReturn:
//relaset the stores and reset the local parameters
if(hCertStore)
CertCloseStore(hCertStore, 0);
if(hMsg)
CryptMsgClose(hMsg);
if(pCertContext)
CertFreeCertificateContext(pCertContext);
if(pCRLContext)
CertFreeCRLContext(pCRLContext);
if(pCTLContext)
CertFreeCTLContext(pCTLContext);
fResult=FALSE;
goto CommonReturn;
SET_ERROR(NoMatchErr,CRYPT_E_NO_MATCH);
SET_ERROR(LocalAllocErr, ERROR_OUTOFMEMORY);
TRACE_ERROR(CryptDecodeObjectErr);
TRACE_ERROR(CryptMsgOpenErr);
TRACE_ERROR(CryptMsgGetParamErr);
TRACE_ERROR(CertOpenStoreErr);
}
//-------------------------------------------------------------------------
//
// CryptQueryObject takes a CERT_BLOB or a file name and returns the
// information about the content in the blob or in the file.
//
// Parameters:
// INPUT dwObjectType:
// Indicate the type of the object. Should be one of the
// following:
// CERT_QUERY_OBJECT_FILE
// CERT_QUERY_OBJECT_BLOB
//
// INPUT pvObject:
// If dwObjectType == CERT_QUERY_OBJECT_FILE, it is a
// LPWSTR, that is, the pointer to a wchar file name
// if dwObjectType == CERT_QUERY_OBJECT_BLOB, it is a
// PCERT_BLOB, that is, a pointer to a CERT_BLOB
//
// INPUT dwExpectedContentTypeFlags:
// Indicate the expected contenet type.
// Can be one of the following:
// CERT_QUERY_CONTENT_FLAG_ALL (the content can be any type)
// CERT_QUERY_CONTENT_FLAG_CERT
// CERT_QUERY_CONTENT_FLAG_CTL
// CERT_QUERY_CONTENT_FLAG_CRL
// CERT_QUERY_CONTENT_FLAG_SERIALIZED_STORE
// CERT_QUERY_CONTENT_FLAG_SERIALIZED_CERT
// CERT_QUERY_CONTENT_FLAG_SERIALIZED_CTL
// CERT_QUERY_CONTENT_FLAG_SERIALIZED_CRL
// CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED
// CERT_QUERY_CONTENT_FLAG_PKCS7_UNSIGNED
// CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED
// CERT_QUERY_CONTENT_FLAG_PKCS10
// CERT_QUERY_CONTENT_FLAG_PFX
// CERT_QUERY_CONTENT_FLAG_CERT_PAIR
//
// INPUT dwExpectedFormatTypeFlags:
// Indicate the expected format type.
// Can be one of the following:
// CERT_QUERY_FORMAT_FLAG_ALL (the content can be any format)
// CERT_QUERY_FORMAT_FLAG_BINARY
// CERT_QUERY_FORMAT_FLAG_BASE64_ENCODED
// CERT_QUERY_FORMAT_FLAG_ASN_ASCII_HEX_ENCODED
//
//
// INPUT dwFlags
// Reserved flag. Should always set to 0
//
// OUTPUT pdwMsgAndCertEncodingType
// Optional output. If NULL != pdwMsgAndCertEncodingType,
// it contains the encoding type of the content as any
// combination of the following:
// X509_ASN_ENCODING
// PKCS_7_ASN_ENCODING
//
// OUTPUT pdwContentType
// Optional output. If NULL!=pdwContentType, it contains
// the content type as one of the the following:
// CERT_QUERY_CONTENT_CERT
// CERT_QUERY_CONTENT_CTL
// CERT_QUERY_CONTENT_CRL
// CERT_QUERY_CONTENT_SERIALIZED_STORE
// CERT_QUERY_CONTENT_SERIALIZED_CERT
// CERT_QUERY_CONTENT_SERIALIZED_CTL
// CERT_QUERY_CONTENT_SERIALIZED_CRL
// CERT_QUERY_CONTENT_PKCS7_SIGNED
// CERT_QUERY_CONTENT_PKCS7_UNSIGNED
// CERT_QUERY_CONTENT_PKCS7_SIGNED_EMBED
// CERT_QUERY_CONTENT_PKCS10
// CERT_QUERY_CONTENT_PFX
// CERT_QUERY_CONTENT_CERT_PAIR
//
// OUTPUT pdwFormatType
// Optional output. If NULL !=pdwFormatType, it
// contains the format type of the content as one of the
// following:
// CERT_QUERY_FORMAT_BINARY
// CERT_QUERY_FORMAT_BASE64_ENCODED
// CERT_QUERY_FORMAT_ASN_ASCII_HEX_ENCODED
//
//
// OUTPUT phCertStore
// Optional output. If NULL !=phStore,
// it contains a cert store that includes all of certificates,
// CRL, and CTL in the object if the object content type is
// one of the following:
// CERT_QUERY_CONTENT_CERT
// CERT_QUERY_CONTENT_CTL
// CERT_QUERY_CONTENT_CRL
// CERT_QUERY_CONTENT_SERIALIZED_STORE
// CERT_QUERY_CONTENT_SERIALIZED_CERT
// CERT_QUERY_CONTENT_SERIALIZED_CTL
// CERT_QUERY_CONTENT_SERIALIZED_CRL
// CERT_QUERY_CONTENT_PKCS7_SIGNED
// CERT_QUERY_CONTENT_PKCS7_SIGNED_EMBED
// CERT_QUERY_CONTENT_CERT_PAIR
//
// Caller should free *phCertStore via CertCloseStore.
//
//
// OUTPUT phMsg Optional output. If NULL != phMsg,
// it contains a handle to a opened message if
// the content type is one of the following:
// CERT_QUERY_CONTENT_PKCS7_SIGNED
// CERT_QUERY_CONTENT_PKCS7_UNSIGNED
// CERT_QUERY_CONTENT_PKCS7_SIGNED_EMBED
//
// Caller should free *phMsg via CryptMsgClose.
//
// OUTPUT pContext Optional output. If NULL != pContext,
// it contains either a PCCERT_CONTEXT or PCCRL_CONTEXT,
// or PCCTL_CONTEXT based on the content type.
//
// If the content type is CERT_QUERY_CONTENT_CERT or
// CERT_QUERY_CONTENT_SERIALIZED_CERT, it is a PCCERT_CONTEXT;
// Caller should free the pContext via CertFreeCertificateContext.
//
// If the content type is CERT_QUERY_CONTENT_CRL or
// CERT_QUERY_CONTENT_SERIALIZED_CRL, it is a PCCRL_CONTEXT;
// Caller should free the pContext via CertFreeCRLContext.
//
// If the content type is CERT_QUERY_CONTENT_CTL or
// CERT_QUERY_CONTENT_SERIALIZED_CTL, it is a PCCTL_CONTEXT;
// Caller should free the pContext via CertFreeCTLContext.
//
// If the *pbObject is of type CERT_QUERY_CONTENT_PKCS10 or CERT_QUERY_CONTENT_PFX, CryptQueryObject
// will not return anything in *phCertstore, *phMsg, or *ppvContext.
//--------------------------------------------------------------------------
BOOL
WINAPI
CryptQueryObject(DWORD dwObjectType,
const void *pvObject,
DWORD dwExpectedContentTypeFlags,
DWORD dwExpectedFormatTypeFlags,
DWORD dwFlags,
DWORD *pdwMsgAndCertEncodingType,
DWORD *pdwContentType,
DWORD *pdwFormatType,
HCERTSTORE *phCertStore,
HCRYPTMSG *phMsg,
const void **ppvContext)
{
BOOL fResult=FALSE;
DWORD err;
CERT_BLOB CertBlob;
DWORD cbData=0;
BYTE *pbData=NULL;
BYTE *pbToDecode=NULL;
DWORD cbToDecode=0;
DWORD cbDecodedData=0;
BYTE *pbDecodedData=NULL;
HRESULT hr=S_OK;
DWORD dwFormatType=0;
__try {
//check input parameters
if(NULL==pvObject)
goto InvalidArgErr;
//make sure we have a correct dwFormatTypeFlag
if(0==(dwExpectedFormatTypeFlags & CERT_QUERY_FORMAT_FLAG_ALL))
goto InvalidArgErr;
//make sure we have a correct dwContentTypeFlag
if(0==(dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_ALL))
goto InvalidArgErr;
//NULL out local variables
memset(&CertBlob, 0, sizeof(CERT_BLOB));
//get the BLOB
if(CERT_QUERY_OBJECT_FILE == dwObjectType)
{
if(S_OK!=(hr=RetrieveBLOBFromFile((LPWSTR)pvObject, &cbData, &pbData)))
goto RetrieveBLOBFromFileErr;
}
else
{
if(CERT_QUERY_OBJECT_BLOB == dwObjectType)
{
cbData=((PCERT_BLOB)pvObject)->cbData;
pbData=((PCERT_BLOB)pvObject)->pbData;
}
else
goto InvalidArgErr;
}
//make sure the input are valid
if(0==cbData || NULL==pbData)
goto InvalidArgErr;
//assume the BLOBs are ANSCII
CertBlob.cbData=cbData;
CertBlob.pbData=pbData;
//binary decoding
if(dwExpectedFormatTypeFlags & CERT_QUERY_FORMAT_FLAG_BINARY)
{
if(I_CryptQueryObject(
&CertBlob,
(CERT_QUERY_OBJECT_FILE == dwObjectType) ? (LPWSTR)pvObject : NULL,
dwExpectedContentTypeFlags,
dwExpectedFormatTypeFlags,
dwFlags,
pdwMsgAndCertEncodingType,
pdwContentType,
pdwFormatType,
phCertStore,
phMsg,
ppvContext))
{
dwFormatType=CERT_QUERY_FORMAT_BINARY;
goto Done;
}
}
if(dwExpectedFormatTypeFlags &
CERT_QUERY_FORMAT_FLAG_ASN_ASCII_HEX_ENCODED)
{
if (ASN_ASCII_HEX_PREFIX_LEN < cbData &&
0 == _strnicmp((char *) pbData, ASN_ASCII_HEX_PREFIX,
ASN_ASCII_HEX_PREFIX_LEN))
{
dwFormatType=CERT_QUERY_FORMAT_ASN_ASCII_HEX_ENCODED;
if (!DecodeAsciiHex(
(char *) (pbData + ASN_ASCII_HEX_PREFIX_LEN),
cbData - ASN_ASCII_HEX_PREFIX_LEN,
&pbDecodedData,
&cbDecodedData
))
goto InvalidAsciiHex;
CertBlob.cbData=cbDecodedData;
CertBlob.pbData=pbDecodedData;
if(I_CryptQueryObject(
&CertBlob,
NULL,
dwExpectedContentTypeFlags,
dwExpectedFormatTypeFlags,
dwFlags,
pdwMsgAndCertEncodingType,
pdwContentType,
pdwFormatType,
phCertStore,
phMsg,
ppvContext))
{
goto Done;
} else {
goto I_CryptQueryObjectErr;
}
}
}
if(dwExpectedFormatTypeFlags & CERT_QUERY_FORMAT_FLAG_BASE64_ENCODED)
{
pbToDecode = pbData;
cbToDecode = cbData;
if(!DecodeBlobA((CHAR *)pbToDecode, cbToDecode, &pbDecodedData, &cbDecodedData))
{
LPWSTR pwszUnicode = (LPWSTR) pbData;
DWORD cchUnicode = cbData / sizeof(WCHAR);
if(!POINTER_IS_ALIGNED(pwszUnicode, sizeof(WCHAR)) ||
!DecodeBlobW(pwszUnicode, cchUnicode, &pbDecodedData, &cbDecodedData))
{
//now we are conviced the BLOB is not base64 encoded
goto NoMatchErr;
}
}
//the BLOB has been properly decoded
dwFormatType=CERT_QUERY_FORMAT_BASE64_ENCODED;
//make sure the base64 decode routine worked
if(0==cbDecodedData || NULL==pbDecodedData)
goto BadEncodeErr;
CertBlob.cbData=cbDecodedData;
CertBlob.pbData=pbDecodedData;
//try the base64 decoded BLOB
if(!I_CryptQueryObject(
&CertBlob,
NULL,
dwExpectedContentTypeFlags,
dwExpectedFormatTypeFlags,
dwFlags,
pdwMsgAndCertEncodingType,
pdwContentType,
pdwFormatType,
phCertStore,
phMsg,
ppvContext))
goto I_CryptQueryObjectErr;
}
else
{
goto NoMatchErr;
}
Done:
//return the FormatType
if(NULL != pdwFormatType)
*pdwFormatType = dwFormatType;
fResult=TRUE;
} __except (EXCEPTION_EXECUTE_HANDLER) {
err = GetExceptionCode();
goto ExceptionErr;
}
CommonReturn:
//free memory
if(CERT_QUERY_OBJECT_FILE == dwObjectType)
{
if(pbData)
UnmapViewOfFile(pbData);
}
if(pbDecodedData)
free(pbDecodedData);
return fResult;
ErrorReturn:
fResult=FALSE;
goto CommonReturn;
SET_ERROR_VAR(RetrieveBLOBFromFileErr, hr);
SET_ERROR(InvalidArgErr,E_INVALIDARG);
TRACE_ERROR(I_CryptQueryObjectErr);
SET_ERROR(NoMatchErr, CRYPT_E_NO_MATCH);
SET_ERROR(BadEncodeErr, CRYPT_E_BAD_ENCODE);
TRACE_ERROR(InvalidAsciiHex);
SET_ERROR_VAR(ExceptionErr, err);
}