|
|
//+-------------------------------------------------------------------------
//
// 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); }
|