1866 lines
48 KiB
C++
1866 lines
48 KiB
C++
/*===================================================================
|
|
Microsoft Denali
|
|
|
|
Microsoft Confidential.
|
|
Copyright 1996 Microsoft Corporation. All Rights Reserved.
|
|
|
|
Component: Request, Response objects
|
|
|
|
File: clcert.cpp
|
|
|
|
Owner: DGottner
|
|
|
|
This file contains the code for the implementation of the
|
|
Request.ClientCertificate
|
|
===================================================================*/
|
|
|
|
#include "denpre.h"
|
|
#pragma hdrstop
|
|
|
|
#include <schnlsp.h>
|
|
|
|
#include "objbase.h"
|
|
#include "request.h"
|
|
#include "clcert.h"
|
|
|
|
#include "memchk.h"
|
|
|
|
#pragma warning (disable: 4355) // ignore: "'this' used in base member init
|
|
|
|
#define UUENCODEDSIZE(a) ((((a)+3)*4)/3+1)
|
|
|
|
#define BLOB_AS_ARRAY
|
|
|
|
HRESULT
|
|
SetVariantAsByteArray(
|
|
VARIANT* pvarReturn,
|
|
DWORD cbLen,
|
|
LPBYTE pbIn
|
|
);
|
|
|
|
//
|
|
// Taken from NCSA HTTP and wwwlib.
|
|
//
|
|
// NOTE: These conform to RFC1113, which is slightly different then the Unix
|
|
// uuencode and uudecode!
|
|
//
|
|
|
|
const int _pr2six[256]={
|
|
64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
|
|
64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,62,64,64,64,63,
|
|
52,53,54,55,56,57,58,59,60,61,64,64,64,64,64,64,64,0,1,2,3,4,5,6,7,8,9,
|
|
10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,64,64,64,64,64,64,26,27,
|
|
28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,
|
|
64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
|
|
64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
|
|
64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
|
|
64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
|
|
64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
|
|
64,64,64,64,64,64,64,64,64,64,64,64,64
|
|
};
|
|
|
|
char _six2pr[64] = {
|
|
'A','B','C','D','E','F','G','H','I','J','K','L','M',
|
|
'N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
|
|
'a','b','c','d','e','f','g','h','i','j','k','l','m',
|
|
'n','o','p','q','r','s','t','u','v','w','x','y','z',
|
|
'0','1','2','3','4','5','6','7','8','9','+','/'
|
|
};
|
|
|
|
const int _pr2six64[256]={
|
|
64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
|
|
64,64,64,64,64,64,64,64, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,
|
|
16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,
|
|
40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,
|
|
0,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
|
|
64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
|
|
64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
|
|
64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
|
|
64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
|
|
64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
|
|
64,64,64,64,64,64,64,64,64,64,64,64,64
|
|
};
|
|
|
|
char _six2pr64[64] = {
|
|
'`','!','"','#','$','%','&','\'','(',')','*','+',',',
|
|
'-','.','/','0','1','2','3','4','5','6','7','8','9',
|
|
':',';','<','=','>','?','@','A','B','C','D','E','F',
|
|
'G','H','I','J','K','L','M','N','O','P','Q','R','S',
|
|
'T','U','V','W','X','Y','Z','[','\\',']','^','_'
|
|
};
|
|
|
|
/*------------------------------------------------------------------
|
|
* X B F
|
|
*/
|
|
|
|
BOOL XBF::Extend( int cA )
|
|
{
|
|
if ( cA > m_cAlloc )
|
|
{
|
|
int cNew = (( cA + XBF_EXTEND )/XBF_EXTEND)*XBF_EXTEND;
|
|
LPSTR pN = (LPSTR)malloc( cNew );
|
|
if ( pN == NULL )
|
|
{
|
|
return FALSE;
|
|
}
|
|
if ( m_cSize )
|
|
{
|
|
memcpy( pN, m_pV, m_cSize );
|
|
}
|
|
if ( m_cAlloc )
|
|
{
|
|
free( m_pV );
|
|
}
|
|
m_pV = pN;
|
|
m_cAlloc = cNew;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
/*------------------------------------------------------------------
|
|
* C C l C e r t S u p p o r t E r r
|
|
*/
|
|
|
|
/*===================================================================
|
|
CClCertSupportErr::CClCertSupportErr
|
|
|
|
constructor
|
|
===================================================================*/
|
|
|
|
CClCertSupportErr::CClCertSupportErr(CClCert *pClCert)
|
|
{
|
|
m_pClCert = pClCert;
|
|
}
|
|
|
|
|
|
|
|
/*===================================================================
|
|
CClCertSupportErr::QueryInterface
|
|
CClCertSupportErr::AddRef
|
|
CClCertSupportErr::Release
|
|
|
|
Delegating IUnknown members for CClCertSupportErr object.
|
|
===================================================================*/
|
|
|
|
STDMETHODIMP CClCertSupportErr::QueryInterface(const IID &idInterface, void **ppvObj)
|
|
{
|
|
return m_pClCert->QueryInterface(idInterface, ppvObj);
|
|
}
|
|
|
|
STDMETHODIMP_(ULONG) CClCertSupportErr::AddRef()
|
|
{
|
|
return m_pClCert->AddRef();
|
|
}
|
|
|
|
STDMETHODIMP_(ULONG) CClCertSupportErr::Release()
|
|
{
|
|
return m_pClCert->Release();
|
|
}
|
|
|
|
|
|
|
|
/*===================================================================
|
|
CClCertSupportErr::InterfaceSupportsErrorInfo
|
|
|
|
Report back to OA about which interfaces we support that return
|
|
error information
|
|
===================================================================*/
|
|
|
|
STDMETHODIMP CClCertSupportErr::InterfaceSupportsErrorInfo(const GUID &idInterface)
|
|
{
|
|
if (idInterface == IID_IDispatch)
|
|
return S_OK;
|
|
|
|
return S_FALSE;
|
|
}
|
|
|
|
|
|
|
|
/*------------------------------------------------------------------
|
|
* C R e a d C l C e r t
|
|
*/
|
|
|
|
/*===================================================================
|
|
CReadClCert::CReadClCert
|
|
|
|
constructor
|
|
===================================================================*/
|
|
|
|
CReadClCert::CReadClCert(CClCert *pClCert)
|
|
{
|
|
m_pClCert = pClCert;
|
|
CDispatch::Init(IID_IRequestDictionary);
|
|
}
|
|
|
|
|
|
|
|
/*===================================================================
|
|
CReadClCert::QueryInterface
|
|
CReadClCert::AddRef
|
|
CReadClCert::Release
|
|
|
|
Delegating IUnknown members for CReadClCert object.
|
|
===================================================================*/
|
|
|
|
STDMETHODIMP CReadClCert::QueryInterface(const IID &idInterface, void **ppvObj)
|
|
{
|
|
return m_pClCert->QueryInterface(idInterface, ppvObj);
|
|
}
|
|
|
|
STDMETHODIMP_(ULONG) CReadClCert::AddRef()
|
|
{
|
|
return m_pClCert->AddRef();
|
|
}
|
|
|
|
STDMETHODIMP_(ULONG) CReadClCert::Release()
|
|
{
|
|
return m_pClCert->Release();
|
|
}
|
|
|
|
|
|
/*===================================================================
|
|
CReadClCert::get_Item
|
|
|
|
Retrieve a value in the clcert dictionary.
|
|
===================================================================*/
|
|
|
|
STDMETHODIMP CReadClCert::get_Item(VARIANT varKey, VARIANT *pVarReturn)
|
|
{
|
|
VariantInit(pVarReturn); // default return value is Empty
|
|
VARIANT *pvarKey = &varKey;
|
|
HRESULT hres;
|
|
|
|
// BUG 937: VBScript passes VT_VARIANT|VT_BYREF when passing obect
|
|
// produced by IEnumVariant
|
|
//
|
|
// Use VariantResolveDispatch which will:
|
|
//
|
|
// * Copy BYREF variants for us using VariantCopyInd
|
|
// * handle E_OUTOFMEMORY for us
|
|
// * get the default value from an IDispatch, which seems
|
|
// like an appropriate conversion.
|
|
//
|
|
VARIANT varKeyCopy;
|
|
VariantInit(&varKeyCopy);
|
|
if (V_VT(pvarKey) != VT_BSTR) {
|
|
if (FAILED(VariantResolveDispatch(&varKeyCopy, &varKey, IID_IRequestDictionary, IDE_REQUEST)))
|
|
goto LExit;
|
|
|
|
pvarKey = &varKeyCopy;
|
|
}
|
|
|
|
switch (V_VT(pvarKey)) {
|
|
case VT_BSTR:
|
|
break;
|
|
|
|
case VT_ERROR:
|
|
if (V_ERROR(pvarKey) == DISP_E_PARAMNOTFOUND) {
|
|
// simple value, URLEncoding NOT a good idea in this case
|
|
if (m_pClCert->m_szValue) {
|
|
V_VT(pVarReturn) = VT_BSTR;
|
|
switch( m_pClCert->m_veType ) {
|
|
case VT_BSTR: {
|
|
BSTR bstrT;
|
|
if ( FAILED(SysAllocStringFromSz(m_pClCert->m_szValue, 0, &bstrT )) ) {
|
|
ExceptionId(IID_IRequestDictionary, IDE_REQUEST, IDE_OOM);
|
|
VariantClear(&varKeyCopy);
|
|
return E_FAIL;
|
|
}
|
|
V_BSTR(pVarReturn) = bstrT;
|
|
break;
|
|
}
|
|
|
|
case VT_DATE:
|
|
V_VT(pVarReturn) = VT_DATE;
|
|
V_DATE(pVarReturn) = *(UNALIGNED64 DATE*)m_pClCert->m_szValue;
|
|
break;
|
|
|
|
case VT_I4:
|
|
V_VT(pVarReturn) = VT_I4;
|
|
V_I4(pVarReturn) = *(UNALIGNED64 DWORD*)m_pClCert->m_szValue;
|
|
break;
|
|
|
|
case VT_BLOB:
|
|
#if defined(BLOB_AS_ARRAY)
|
|
if ( FAILED( hres = SetVariantAsByteArray( pVarReturn,
|
|
m_pClCert->m_cLen,
|
|
(LPBYTE)m_pClCert->m_szValue ) ) ) {
|
|
ExceptionId(IID_IRequestDictionary, IDE_REQUEST, IDE_OOM);
|
|
VariantClear(&varKeyCopy);
|
|
return hres;
|
|
}
|
|
#else
|
|
V_BSTR(pVarReturn) = SysAllocStringByteLen(m_pClCert->m_szValue, m_pClCert->m_cLen );
|
|
#endif
|
|
break;
|
|
|
|
default:
|
|
Assert( FALSE );
|
|
}
|
|
}
|
|
|
|
// dictionary value, must URLEncode to prevent '&', '=' from being misinterpreted
|
|
else {
|
|
}
|
|
|
|
VariantClear(&varKeyCopy);
|
|
return S_OK;
|
|
}
|
|
|
|
default:
|
|
ExceptionId(IID_IRequestDictionary, IDE_REQUEST, IDE_EXPECTING_STR);
|
|
VariantClear(&varKeyCopy);
|
|
return E_FAIL;
|
|
}
|
|
LExit:
|
|
VariantClear(&varKeyCopy);
|
|
return S_OK;
|
|
}
|
|
|
|
/*===================================================================
|
|
CReadClCert::get_Key
|
|
|
|
Function called from DispInvoke to get keys from the QueryString collection.
|
|
|
|
Parameters:
|
|
vKey VARIANT [in], which parameter to get the key of
|
|
pvarReturn VARIANT *, [out] value of the requested parameter
|
|
|
|
Returns:
|
|
S_OK on success, E_FAIL on failure.
|
|
===================================================================*/
|
|
|
|
HRESULT CReadClCert::get_Key(VARIANT varKey, VARIANT *pVar)
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
/*===================================================================
|
|
CReadClCert::get_Count
|
|
|
|
Parameters:
|
|
pcValues - count is stored in *pcValues
|
|
===================================================================*/
|
|
|
|
STDMETHODIMP CReadClCert::get_Count(int *pcValues)
|
|
{
|
|
HRESULT hrReturn = S_OK;
|
|
|
|
*pcValues = 0;
|
|
|
|
return hrReturn;
|
|
}
|
|
|
|
/*===================================================================
|
|
CReadClCert::get__NewEnum
|
|
|
|
Return an enumerator object.
|
|
===================================================================*/
|
|
|
|
STDMETHODIMP CReadClCert::get__NewEnum(IUnknown **ppEnum)
|
|
{
|
|
*ppEnum = NULL;
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
|
|
|
|
/*------------------------------------------------------------------
|
|
* C C l C e r t
|
|
*/
|
|
|
|
/*===================================================================
|
|
CClCert::CClCert
|
|
|
|
constructor
|
|
===================================================================*/
|
|
|
|
CClCert::CClCert(IUnknown *pUnkOuter, PFNDESTROYED pfnDestroy)
|
|
: m_ReadClCertInterface(this),
|
|
m_ClCertSupportErrorInfo(this)
|
|
{
|
|
m_szValue = NULL;
|
|
m_veType = VT_BSTR;
|
|
m_pfnDestroy = pfnDestroy;
|
|
m_cRefs = 1;
|
|
}
|
|
|
|
|
|
|
|
/*===================================================================
|
|
CClCert::~CClCert
|
|
|
|
Destructor
|
|
===================================================================*/
|
|
|
|
CClCert::~CClCert()
|
|
{
|
|
}
|
|
|
|
|
|
|
|
/*===================================================================
|
|
CClCert::Init
|
|
|
|
initialize the clcert. This initializes the clcert's value hashing
|
|
table
|
|
===================================================================*/
|
|
|
|
HRESULT CClCert::Init()
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
/*===================================================================
|
|
CClCert::QueryInterface
|
|
CClCert::AddRef
|
|
CClCert::Release
|
|
|
|
IUnknown members for CClCert object.
|
|
|
|
Note on CClCert::QueryInterface: The Query for IDispatch is
|
|
ambiguous because it can either refer to DIRequestDictionary or
|
|
DIWriteClCert. To resolve this, we resolve requests for IDispatch
|
|
to IRequestDictionary.
|
|
===================================================================*/
|
|
|
|
STDMETHODIMP CClCert::QueryInterface(const IID &idInterface, void **ppvObj)
|
|
{
|
|
if (idInterface == IID_IUnknown)
|
|
*ppvObj = this;
|
|
|
|
else if (idInterface == IID_IRequestDictionary || idInterface == IID_IDispatch)
|
|
*ppvObj = &m_ReadClCertInterface;
|
|
|
|
else if (idInterface == IID_ISupportErrorInfo)
|
|
*ppvObj = &m_ClCertSupportErrorInfo;
|
|
|
|
else
|
|
*ppvObj = NULL;
|
|
|
|
if (*ppvObj != NULL)
|
|
{
|
|
static_cast<IUnknown *>(*ppvObj)->AddRef();
|
|
return S_OK;
|
|
}
|
|
|
|
return ResultFromScode(E_NOINTERFACE);
|
|
}
|
|
|
|
|
|
STDMETHODIMP_(ULONG) CClCert::AddRef()
|
|
{
|
|
return ++m_cRefs;
|
|
}
|
|
|
|
|
|
STDMETHODIMP_(ULONG) CClCert::Release(void)
|
|
{
|
|
if (--m_cRefs != 0)
|
|
return m_cRefs;
|
|
|
|
if (m_pfnDestroy != NULL)
|
|
(*m_pfnDestroy)();
|
|
|
|
delete this;
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
/*===================================================================
|
|
CClCert::AddValue
|
|
|
|
Set the clcert's primary value. One you set the primary value,
|
|
you can't reset it.
|
|
===================================================================*/
|
|
|
|
HRESULT CClCert::AddValue(char *szValue, VARENUM ve, UINT l )
|
|
{
|
|
if (m_szValue != NULL) // clcert already is marked as single-valued
|
|
return E_FAIL;
|
|
|
|
m_szValue = szValue;
|
|
|
|
m_veType = ve;
|
|
m_cLen = l;
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
/*===================================================================
|
|
CClCert::GetHTTPClCertSize
|
|
|
|
Return the number of bytes required for the expansion of the clcert
|
|
===================================================================*/
|
|
|
|
size_t CClCert::GetHTTPClCertSize()
|
|
{
|
|
if (m_szValue)
|
|
return URLEncodeLen(m_szValue);
|
|
else
|
|
return 1;
|
|
}
|
|
|
|
|
|
/*===================================================================
|
|
CClCert::GetHTTPClCert
|
|
|
|
Return the URL Encoded value a single clcert
|
|
|
|
Parameters:
|
|
szBuffer - pointer to the destination buffer to store the
|
|
URL encoded value
|
|
|
|
Returns:
|
|
Returns a pointer to the terminating NUL character.
|
|
===================================================================*/
|
|
|
|
char *CClCert::GetHTTPClCert(char *szBuffer)
|
|
{
|
|
if (m_szValue)
|
|
return URLEncode(szBuffer, m_szValue);
|
|
|
|
else
|
|
{
|
|
char *szDest = szBuffer;
|
|
*szDest = '\0';
|
|
|
|
return szDest;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/*===================================================================
|
|
CClCert::GetClCertHeaderSize
|
|
|
|
Return the number of bytes required to allocate for the "Set-ClCert" header.
|
|
|
|
Parameters:
|
|
szName - the name of the cookie (the size of the name is added to the value)
|
|
|
|
Returns:
|
|
Returns 0 if *this does not contain a cookie value.
|
|
===================================================================*/
|
|
|
|
size_t CClCert::GetClCertHeaderSize(const char *szName)
|
|
{
|
|
int cbClCert = sizeof "Set-ClCert: "; // initialize and add NUL terminator now
|
|
|
|
// Add size of the URL Encoded name, a character for the '=', and the size
|
|
// of the URL Encoded cookie value. URLEncodeLen, and GetHttpClCertSize
|
|
// compensate for the NUL terminator, so we actually SUBTRACT 1. (-2 for
|
|
// these two function calls, +1 for the '=' sign
|
|
//
|
|
cbClCert += URLEncodeLen(szName) + GetHTTPClCertSize() - 1;
|
|
|
|
return cbClCert;
|
|
}
|
|
|
|
|
|
|
|
/*===================================================================
|
|
CClCert::GetClCertHeader
|
|
|
|
Construct the appropriate "Set-ClCert" header for a clcert.
|
|
|
|
Parameters:
|
|
szName - the name of the clcert (the size of the name is added to the value)
|
|
|
|
Returns:
|
|
Returns 0 if *this does not contain a clcert value.
|
|
===================================================================*/
|
|
|
|
char *CClCert::GetClCertHeader(const char *szName, char *szBuffer)
|
|
{
|
|
// write out the clcert name and value
|
|
//
|
|
char *szDest = strcpyExA(szBuffer, "Set-ClCert: ");
|
|
szDest = URLEncode(szDest, szName);
|
|
szDest = strcpyExA(szDest, "=");
|
|
szDest = GetHTTPClCert(szDest);
|
|
|
|
return szDest;
|
|
}
|
|
|
|
|
|
|
|
/*------------------------------------------------------------------
|
|
* C C e r t R e q u e s t
|
|
*/
|
|
|
|
|
|
/*===================================================================
|
|
CCertRequest::AddStringPair
|
|
|
|
Add a string element in the collection
|
|
|
|
Parameters:
|
|
Source - variable type ( CLCERT, COOKIE, ... )
|
|
szName - name of element
|
|
szValue - ptr to value as string
|
|
pxbf - ptr to buffer where to store name
|
|
|
|
Returns:
|
|
S_OK if success, E_OUTOFMEMORY or E_FAIL otherwise
|
|
===================================================================*/
|
|
|
|
HRESULT
|
|
CCertRequest::AddStringPair(
|
|
CollectionType Source,
|
|
LPSTR szName,
|
|
LPSTR szValue,
|
|
XBF *pxbf,
|
|
BOOL fDuplicate,
|
|
UINT lCodePage
|
|
)
|
|
{
|
|
HRESULT hResult;
|
|
CRequestHit *pReqHit;
|
|
|
|
if ( fDuplicate )
|
|
{
|
|
if ( (szValue = pxbf->AddStringZ( szValue )) == NULL )
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
|
|
if (FAILED(hResult = AddName( szName, &pReqHit, pxbf)))
|
|
{
|
|
if ( hResult == E_FAIL )
|
|
{
|
|
// assume duplicate value found
|
|
// if out of memore, OUT_OF_MEMORY would have been returned
|
|
|
|
hResult = S_OK;
|
|
}
|
|
return hResult;
|
|
}
|
|
|
|
if (FAILED(hResult = pReqHit->AddValue( Source, szValue, NULL, lCodePage )))
|
|
{
|
|
return hResult;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
/*===================================================================
|
|
CCertRequest::AddDatePair
|
|
|
|
Add a date element in the collection
|
|
|
|
Parameters:
|
|
Source - variable type ( CLCERT, COOKIE, ... )
|
|
szName - name of element
|
|
pValue - ptr to date as FILETIME
|
|
pxbf - ptr to buffer where to store name
|
|
|
|
Returns:
|
|
S_OK if success, E_OUTOFMEMORY or E_FAIL otherwise
|
|
===================================================================*/
|
|
|
|
HRESULT
|
|
CCertRequest::AddDatePair(
|
|
CollectionType Source,
|
|
LPSTR szName,
|
|
FILETIME* pValue,
|
|
XBF *pxbf
|
|
)
|
|
{
|
|
HRESULT hResult;
|
|
CRequestHit *pReqHit;
|
|
DATE Date;
|
|
SYSTEMTIME st;
|
|
LPBYTE pVal;
|
|
|
|
if ( !FileTimeToSystemTime( pValue, &st ) )
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
SystemTimeToVariantTime( &st, &Date );
|
|
|
|
if ( (pVal = (LPBYTE)pxbf->AddBlob( (LPSTR)&Date, sizeof(Date) )) == NULL )
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
if (FAILED(hResult = AddName( szName, &pReqHit, pxbf)))
|
|
{
|
|
return hResult;
|
|
}
|
|
|
|
if (FAILED(hResult = pReqHit->AddCertValue( VT_DATE, pVal, sizeof(Date) )))
|
|
{
|
|
return hResult;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
|
|
/*===================================================================
|
|
CCertRequest::AddDwordPair
|
|
|
|
Add a DWORD element in the collection
|
|
|
|
Parameters:
|
|
Source - variable type ( CLCERT, COOKIE, ... )
|
|
szName - name of element
|
|
pValue - ptr to date as DWORD
|
|
pxbf - ptr to buffer where to store name
|
|
|
|
Returns:
|
|
S_OK if success, E_OUTOFMEMORY or E_FAIL otherwise
|
|
===================================================================*/
|
|
|
|
HRESULT
|
|
CCertRequest::AddDwordPair(
|
|
CollectionType Source,
|
|
LPSTR szName,
|
|
DWORD* pValue,
|
|
XBF *pxbf
|
|
)
|
|
{
|
|
HRESULT hResult;
|
|
CRequestHit *pReqHit;
|
|
LPBYTE pVal;
|
|
|
|
if ( (pVal = (LPBYTE)pxbf->AddBlob( (LPSTR)pValue, sizeof(DWORD) )) == NULL )
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
if (FAILED(hResult = AddName( szName, &pReqHit, pxbf)))
|
|
{
|
|
return hResult;
|
|
}
|
|
|
|
if (FAILED(hResult = pReqHit->AddCertValue( VT_I4, pVal, sizeof(DWORD) )))
|
|
{
|
|
return hResult;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
|
|
/*===================================================================
|
|
CCertRequest::AddBinaryPair
|
|
|
|
Add a binary element in the collection
|
|
Each byte is converted to UNICODE character so that mid() & asc() work
|
|
|
|
Parameters:
|
|
Source - variable type ( CLCERT, COOKIE, ... )
|
|
szName - name of element
|
|
pValue - ptr to value as byte array
|
|
cValue - # of bytes pointed to by pValue
|
|
pxbf - ptr to buffer where to store name
|
|
|
|
Returns:
|
|
S_OK if success, E_OUTOFMEMORY or E_FAIL otherwise
|
|
===================================================================*/
|
|
|
|
HRESULT
|
|
CCertRequest::AddBinaryPair(
|
|
CollectionType Source,
|
|
LPSTR szName,
|
|
LPBYTE pValue,
|
|
DWORD cValue,
|
|
XBF *pxbf,
|
|
UINT lCodePage
|
|
)
|
|
{
|
|
HRESULT hResult;
|
|
CRequestHit *pReqHit;
|
|
LPBYTE pVal;
|
|
|
|
#if defined(BLOB_AS_ARRAY)
|
|
|
|
if ( (pVal = (LPBYTE)pxbf->ReserveRange( cValue )) == NULL )
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
memcpy( pVal, pValue, cValue );
|
|
|
|
pxbf->SkipRange( cValue );
|
|
|
|
if (FAILED(hResult = AddName( szName, &pReqHit, pxbf)))
|
|
{
|
|
return hResult;
|
|
}
|
|
|
|
if (FAILED(hResult = pReqHit->AddCertValue( VT_BLOB, pVal, cValue )))
|
|
{
|
|
return hResult;
|
|
}
|
|
|
|
#else
|
|
|
|
if ( (pVal = (LPBYTE)pxbf->ReserveRange( cValue * sizeof(WCHAR), sizeof(WCHAR))) == NULL )
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
if ( !(cValue = MultiByteToWideChar( lCodePage, 0, (LPSTR)pValue, cValue, (WCHAR*)pVal, cValue)) )
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
pxbf->SkipRange( cValue * sizeof(WCHAR), sizeof(WCHAR));
|
|
|
|
if (FAILED(hResult = AddName( szName, &pReqHit, pxbf)))
|
|
{
|
|
return hResult;
|
|
}
|
|
|
|
if (FAILED(hResult = pReqHit->AddCertValue( VT_BLOB, pVal, cValue * sizeof(WCHAR) )))
|
|
{
|
|
return hResult;
|
|
}
|
|
|
|
#endif
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
BOOL IISuuencode( BYTE * bufin,
|
|
DWORD nbytes,
|
|
BYTE * outptr,
|
|
BOOL fBase64 )
|
|
{
|
|
unsigned int i;
|
|
char *six2pr = fBase64 ? _six2pr64 : _six2pr;
|
|
|
|
for (i=0; i<nbytes; i += 3) {
|
|
*(outptr++) = six2pr[*bufin >> 2]; /* c1 */
|
|
*(outptr++) = six2pr[((*bufin << 4) & 060) | ((bufin[1] >> 4) & 017)]; /*c2*/
|
|
*(outptr++) = six2pr[((bufin[1] << 2) & 074) | ((bufin[2] >> 6) & 03)];/*c3*/
|
|
*(outptr++) = six2pr[bufin[2] & 077]; /* c4 */
|
|
|
|
bufin += 3;
|
|
}
|
|
|
|
/* If nbytes was not a multiple of 3, then we have encoded too
|
|
* many characters. Adjust appropriately.
|
|
*/
|
|
if(i == nbytes+1) {
|
|
/* There were only 2 bytes in that last group */
|
|
outptr[-1] = '=';
|
|
} else if(i == nbytes+2) {
|
|
/* There was only 1 byte in that last group */
|
|
outptr[-1] = '=';
|
|
outptr[-2] = '=';
|
|
}
|
|
|
|
*outptr = '\0';
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/*===================================================================
|
|
CCertRequest::AddUuBinaryPair
|
|
|
|
Add a binary element in the collection
|
|
buffer is uuencoded then converted to UNICODE character so that mid() & asc() work
|
|
|
|
Parameters:
|
|
Source - variable type ( CLCERT, COOKIE, ... )
|
|
szName - name of element
|
|
pValue - ptr to value as byte array
|
|
cValue - # of bytes pointed to by pValue
|
|
pxbf - ptr to buffer where to store name
|
|
|
|
Returns:
|
|
S_OK if success, E_OUTOFMEMORY or E_FAIL otherwise
|
|
===================================================================*/
|
|
|
|
HRESULT
|
|
CCertRequest::AddUuBinaryPair(
|
|
CollectionType Source,
|
|
LPSTR szName,
|
|
LPBYTE pValue,
|
|
DWORD cValue,
|
|
XBF *pxbf,
|
|
UINT lCodePage
|
|
)
|
|
{
|
|
HRESULT hResult;
|
|
CRequestHit *pReqHit;
|
|
LPBYTE pVal;
|
|
|
|
if ( (pVal = (LPBYTE)pxbf->ReserveRange( UUENCODEDSIZE(cValue) )) == NULL )
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
if ( !IISuuencode( (LPBYTE)pValue, cValue, pVal, FALSE ) )
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
Assert( (strlen((LPSTR)pVal)+1) <= UUENCODEDSIZE(cValue) );
|
|
|
|
pxbf->SkipRange( strlen((LPSTR)pVal)+1 );
|
|
|
|
if (FAILED(hResult = AddName( szName, &pReqHit, pxbf)))
|
|
{
|
|
return hResult;
|
|
}
|
|
|
|
if (FAILED(hResult = pReqHit->AddValue( Source, (LPSTR)pVal, NULL, lCodePage )))
|
|
{
|
|
return hResult;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
/*===================================================================
|
|
CCertRequest::AddName
|
|
|
|
Add a named entry to the collection
|
|
|
|
Parameters:
|
|
szName - name of entry
|
|
ppReqHit - updated with ptr to created entry
|
|
pxbf - ptr to buffer where to store name
|
|
|
|
Returns:
|
|
S_OK if success, E_OUTOFMEMORY or E_FAIL otherwise
|
|
===================================================================*/
|
|
|
|
HRESULT
|
|
CCertRequest::AddName(
|
|
LPSTR szName,
|
|
CRequestHit **ppReqHit,
|
|
XBF *pxbf
|
|
)
|
|
{
|
|
if ( (szName = pxbf->AddStringZ( szName )) == NULL )
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
// Add this object to the Request
|
|
CRequestHit *pRequestHit = (CRequestHit *)(pReq->CertStoreFindElem(szName, strlen(szName)));
|
|
if (pRequestHit == NULL)
|
|
{
|
|
pRequestHit = new CRequestHit;
|
|
if (pRequestHit == NULL)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
if (FAILED(pRequestHit->Init(szName)))
|
|
{
|
|
delete pRequestHit;
|
|
return E_FAIL;
|
|
}
|
|
|
|
pReq->CertStoreAddElem( (CLinkElem*) pRequestHit );
|
|
}
|
|
else if (pRequestHit->m_pClCertData) // a clcert by this name already exists
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
if (!pReq->m_pData->m_ClCerts.AddRequestHit(pRequestHit))
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
*ppReqHit = pRequestHit;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
typedef struct _MAP_ASN {
|
|
LPSTR pAsnName;
|
|
LPSTR pTextName;
|
|
} MAP_ASN;
|
|
|
|
|
|
//
|
|
// definition of ASN.1 <> X.509 name conversion
|
|
//
|
|
|
|
MAP_ASN aMapAsn[] = {
|
|
{ szOID_COUNTRY_NAME, "C" },
|
|
{ szOID_ORGANIZATION_NAME, "O" },
|
|
{ szOID_ORGANIZATIONAL_UNIT_NAME, "OU" },
|
|
{ szOID_COMMON_NAME, "CN" },
|
|
{ szOID_LOCALITY_NAME, "L" },
|
|
{ szOID_STATE_OR_PROVINCE_NAME, "S" },
|
|
{ szOID_TITLE, "T" },
|
|
{ szOID_GIVEN_NAME, "GN" },
|
|
{ szOID_INITIALS, "I" },
|
|
{ "1.2.840.113549.1.9.1", "EMAIL" },
|
|
} ;
|
|
|
|
|
|
LPSTR MapAsnName(
|
|
LPSTR pAsnName
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Convert ASN.1 name ( as ANSI string ) to X.509 member name
|
|
|
|
Arguments:
|
|
|
|
pAsnName - ASN.1 name
|
|
|
|
Return Value:
|
|
|
|
ptr to converted name if ASN.1 name was recognized, else ASN.1 name
|
|
|
|
--*/
|
|
{
|
|
UINT x;
|
|
for ( x = 0 ; x < sizeof(aMapAsn)/sizeof(MAP_ASN) ; ++x )
|
|
{
|
|
if ( !strcmp( pAsnName, aMapAsn[x].pAsnName ) )
|
|
{
|
|
return aMapAsn[x].pTextName;
|
|
}
|
|
}
|
|
|
|
return pAsnName;
|
|
}
|
|
|
|
|
|
BOOL
|
|
DecodeRdn(
|
|
CERT_NAME_BLOB* pNameBlob,
|
|
PCERT_NAME_INFO* ppNameInfo
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Create a PNAME_INFO from PNAME_BLOB
|
|
|
|
Arguments:
|
|
|
|
pNameBlob - ptr to name blob to decode
|
|
ppNameInfo - updated with ptr to name info
|
|
|
|
Return Value:
|
|
|
|
TRUE on success, FALSE on failure
|
|
|
|
--*/
|
|
{
|
|
PCERT_NAME_INFO pNameInfo = NULL;
|
|
DWORD cbNameInfo;
|
|
|
|
if (!CryptDecodeObject(X509_ASN_ENCODING,
|
|
(LPCSTR)X509_NAME,
|
|
pNameBlob->pbData,
|
|
pNameBlob->cbData,
|
|
0,
|
|
NULL,
|
|
&cbNameInfo))
|
|
{
|
|
ExceptionId(IID_IRequestDictionary, IDE_REQUEST, IDE_CERTIFICATE_BAD_CERT);
|
|
return FALSE;
|
|
}
|
|
|
|
if (NULL == (pNameInfo = (PCERT_NAME_INFO)malloc(cbNameInfo)))
|
|
{
|
|
ExceptionId(IID_IRequestDictionary, IDE_REQUEST, IDE_OOM);
|
|
return FALSE;
|
|
}
|
|
|
|
if (!CryptDecodeObject(X509_ASN_ENCODING,
|
|
(LPCSTR)X509_NAME,
|
|
pNameBlob->pbData,
|
|
pNameBlob->cbData,
|
|
0,
|
|
pNameInfo,
|
|
&cbNameInfo))
|
|
{
|
|
ExceptionId(IID_IRequestDictionary, IDE_REQUEST, IDE_CERTIFICATE_BAD_CERT);
|
|
free( pNameInfo );
|
|
return FALSE;
|
|
}
|
|
|
|
*ppNameInfo = pNameInfo;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
VOID
|
|
FreeDecodedRdn(
|
|
PCERT_NAME_INFO pNameInfo
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Free a PNAME_BLOB created by DecodeRdn()
|
|
|
|
Arguments:
|
|
|
|
pNameInfo - ptr to name info created by DecodeRdn()
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
free( pNameInfo );
|
|
}
|
|
|
|
|
|
BOOL
|
|
BuildRdnList(
|
|
PCERT_NAME_INFO pNameInfo,
|
|
XBF* pxbf,
|
|
BOOL fXt
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Build a clear text representation of the Rdn list in pNameInfo
|
|
Format as "C=US, O=Ms, CN=name"
|
|
|
|
Arguments:
|
|
|
|
pNameInfo - ptr to name info
|
|
pxbf - ptr to buffer receiving output
|
|
fXt - TRUE if buffer to be extended, FALSE does not extend ( buffer
|
|
must be big enough before calling this function or FALSE will
|
|
be returned )
|
|
|
|
Return Value:
|
|
|
|
TRUE on success, FALSE on failure
|
|
|
|
--*/
|
|
{
|
|
DWORD cRDN;
|
|
DWORD cAttr;
|
|
PCERT_RDN pRDN;
|
|
PCERT_RDN_ATTR pAttr;
|
|
BOOL fFirst = TRUE;
|
|
|
|
for (cRDN = pNameInfo->cRDN, pRDN = pNameInfo->rgRDN; cRDN > 0; cRDN--, pRDN++)
|
|
{
|
|
for ( cAttr = pRDN->cRDNAttr, pAttr = pRDN->rgRDNAttr ; cAttr > 0 ; cAttr--, ++pAttr )
|
|
{
|
|
if ( !fFirst )
|
|
{
|
|
if ( !pxbf->AddBlob( ", ", sizeof(", ")-1, fXt ) )
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
fFirst = FALSE;
|
|
}
|
|
|
|
if ( pAttr->dwValueType == CERT_RDN_UNICODE_STRING )
|
|
{
|
|
INT iRet;
|
|
BYTE abBuffer[ 512 ];
|
|
DWORD cbNameBuffer;
|
|
PBYTE pNameBuffer = NULL;
|
|
|
|
//
|
|
// Need to convert unicode string to MBCS :(
|
|
//
|
|
|
|
iRet = WideCharToMultiByte( CP_ACP,
|
|
0,
|
|
(LPWSTR) pAttr->Value.pbData,
|
|
-1,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
NULL );
|
|
|
|
if ( !iRet )
|
|
{
|
|
return FALSE;
|
|
}
|
|
else
|
|
{
|
|
cbNameBuffer = (DWORD) iRet;
|
|
if ( (DWORD) iRet > sizeof( abBuffer ) )
|
|
{
|
|
pNameBuffer = (PBYTE) LocalAlloc( LPTR,
|
|
(DWORD) iRet );
|
|
if ( !pNameBuffer )
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pNameBuffer = abBuffer;
|
|
}
|
|
}
|
|
|
|
iRet = WideCharToMultiByte( CP_ACP,
|
|
0,
|
|
(LPWSTR) pAttr->Value.pbData,
|
|
-1,
|
|
(LPSTR) pNameBuffer,
|
|
cbNameBuffer,
|
|
NULL,
|
|
NULL );
|
|
|
|
if ( !iRet )
|
|
{
|
|
if ( pNameBuffer != abBuffer )
|
|
{
|
|
LocalFree( pNameBuffer );
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Now stuff the MBCS string back into the blob. I do this
|
|
// because there is other code that re-reads and re-processes
|
|
// the CRYPTAPI blob.
|
|
//
|
|
|
|
if ( cbNameBuffer <= pAttr->Value.cbData )
|
|
{
|
|
memcpy( pAttr->Value.pbData,
|
|
pNameBuffer,
|
|
cbNameBuffer );
|
|
pAttr->Value.cbData = cbNameBuffer;
|
|
pAttr->dwValueType = CERT_RDN_OCTET_STRING;
|
|
}
|
|
|
|
if ( pNameBuffer != abBuffer )
|
|
{
|
|
LocalFree( pNameBuffer );
|
|
pNameBuffer = NULL;
|
|
}
|
|
}
|
|
|
|
if ( !pxbf->AddString( MapAsnName( pAttr->pszObjId ), fXt ) ||
|
|
!pxbf->AddBlob( "=", sizeof("=")-1, fXt ) ||
|
|
!pxbf->AddString( (LPSTR) pAttr->Value.pbData, fXt ) )
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
return pxbf->AddBlob( "", sizeof(""), fXt ) != NULL;
|
|
}
|
|
|
|
|
|
/*===================================================================
|
|
CCertRequest::ParseRDNS
|
|
|
|
Function called to parse a certificate into a OA collection
|
|
|
|
Parameters:
|
|
pNameInfo - ptr to name structure ( cf. CAPI 2 )
|
|
pszPrefix - prefix to prepend to members name
|
|
pxbf - ptr to buffer to hold result
|
|
|
|
Returns:
|
|
S_OK on success, E_OUTOFMEMORY if out of memory or E_FAIL for
|
|
other errors
|
|
===================================================================*/
|
|
|
|
HRESULT
|
|
CCertRequest::ParseRDNS(
|
|
PCERT_NAME_INFO pNameInfo,
|
|
LPSTR pszPrefix,
|
|
XBF *pxbf,
|
|
UINT lCodePage
|
|
)
|
|
{
|
|
DWORD cRDN;
|
|
DWORD cAttr;
|
|
PCERT_RDN pRDN;
|
|
PCERT_RDN_ATTR pAttr;
|
|
DWORD cRDNs;
|
|
DWORD cAttrs;
|
|
PCERT_RDN pRDNs;
|
|
PCERT_RDN_ATTR pAttrs;
|
|
LPSTR pszFullName = NULL;
|
|
HRESULT hRes = S_OK;
|
|
LPSTR pName;
|
|
UINT cL;
|
|
LPSTR pVal = NULL;
|
|
|
|
|
|
for (cRDN = pNameInfo->cRDN, pRDN = pNameInfo->rgRDN; cRDN > 0; cRDN--, pRDN++)
|
|
{
|
|
for ( cAttr = pRDN->cRDNAttr, pAttr = pRDN->rgRDNAttr ; cAttr > 0 ; cAttr--, ++pAttr )
|
|
{
|
|
if ( pAttr->dwValueType & 0x80000000 )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// scan for attr of same name
|
|
|
|
pAttr->dwValueType |= 0x80000000;
|
|
cL = 0;
|
|
pVal = NULL;
|
|
for ( cRDNs = cRDN, pRDNs = pRDN;
|
|
cRDNs > 0;
|
|
cRDNs--, pRDNs++)
|
|
{
|
|
for ( cAttrs = pRDNs->cRDNAttr, pAttrs = pRDNs->rgRDNAttr ;
|
|
cAttrs > 0 ;
|
|
cAttrs--, ++pAttrs )
|
|
{
|
|
if ( !(pAttrs->dwValueType & 0x80000000) &&
|
|
!strcmp( pAttr->pszObjId, pAttrs->pszObjId ) )
|
|
{
|
|
cL += strlen( (LPSTR)pAttrs->Value.pbData ) + 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// if attributes of the same name found, concatenate their
|
|
// values separated by ';'
|
|
//
|
|
|
|
if ( cL )
|
|
{
|
|
pVal = (LPSTR)malloc( cL + strlen((LPSTR)pAttr->Value.pbData) + 1 );
|
|
if ( pVal == NULL )
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
strcpy( pVal, (LPSTR)pAttr->Value.pbData );
|
|
for ( cRDNs = cRDN, pRDNs = pRDN;
|
|
cRDNs > 0;
|
|
cRDNs--, pRDNs++)
|
|
{
|
|
for ( cAttrs = pRDNs->cRDNAttr, pAttrs = pRDNs->rgRDNAttr ;
|
|
cAttrs > 0 ;
|
|
cAttrs--, ++pAttrs )
|
|
{
|
|
if ( !(pAttrs->dwValueType & 0x80000000) &&
|
|
!strcmp( pAttr->pszObjId, pAttrs->pszObjId ) )
|
|
{
|
|
strcat( pVal, ";" );
|
|
strcat( pVal, (LPSTR)pAttrs->Value.pbData );
|
|
pAttrs->dwValueType |= 0x80000000;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
pName = MapAsnName( pAttr->pszObjId );
|
|
if ( (pszFullName = (LPSTR)malloc( strlen(pszPrefix)+strlen(pName)+1 )) == NULL )
|
|
{
|
|
hRes = E_OUTOFMEMORY;
|
|
goto cleanup;
|
|
}
|
|
strcpy( pszFullName, pszPrefix );
|
|
strcat( pszFullName, pName );
|
|
if ( (hRes = AddStringPair( CLCERT,
|
|
pszFullName,
|
|
pVal ? pVal : (LPSTR)pAttr->Value.pbData,
|
|
pxbf,
|
|
TRUE,
|
|
lCodePage )) != S_OK )
|
|
{
|
|
if ( pVal != NULL )
|
|
{
|
|
free( pVal );
|
|
}
|
|
goto cleanup;
|
|
}
|
|
if ( pVal != NULL )
|
|
{
|
|
free( pVal );
|
|
pVal = NULL;
|
|
}
|
|
free( pszFullName );
|
|
pszFullName = NULL;
|
|
}
|
|
}
|
|
|
|
cleanup:
|
|
if ( pszFullName != NULL )
|
|
{
|
|
free( pszFullName );
|
|
}
|
|
|
|
return hRes;
|
|
}
|
|
|
|
|
|
/*===================================================================
|
|
CCertRequest::ParseCertificate
|
|
|
|
Function called to parse a certificate into a OA collection
|
|
|
|
Parameters:
|
|
pspcRCI - client certificate structure
|
|
|
|
Returns:
|
|
S_OK on success, E_OUTOFMEMORY if out of memory or E_FAIL for
|
|
other errors
|
|
===================================================================*/
|
|
|
|
HRESULT
|
|
CCertRequest::ParseCertificate(
|
|
LPBYTE pbCert,
|
|
DWORD cCert,
|
|
DWORD dwEncoding,
|
|
DWORD dwFlags,
|
|
UINT lCodePage
|
|
)
|
|
{
|
|
XBF xbf( pReq->GetCertStoreBuf(), pReq->GetCertStoreSize() );
|
|
HRESULT hRes = S_OK;
|
|
PCERT_NAME_INFO pNameInfo = NULL;
|
|
UINT cStore;
|
|
UINT x;
|
|
LPSTR pVal;
|
|
PCCERT_CONTEXT pCert;
|
|
|
|
|
|
if (NULL == (pCert = CertCreateCertificateContext(dwEncoding,
|
|
pbCert,
|
|
cCert))) {
|
|
ExceptionId(IID_IRequestDictionary, IDE_REQUEST, IDE_OOM);
|
|
hRes = E_FAIL;
|
|
goto cleanup;
|
|
}
|
|
|
|
// estimate size of buffer holding values
|
|
|
|
cStore = pCert->cbCertEncoded + // for clear text format
|
|
sizeof("ISSUER") +
|
|
sizeof("BINARYISSUER") + (UUENCODEDSIZE(pCert->pCertInfo->Issuer.cbData)*sizeof(WCHAR)) +
|
|
sizeof("BINARYSUBJECT") + (UUENCODEDSIZE(pCert->pCertInfo->Subject.cbData)*sizeof(WCHAR)) +
|
|
sizeof("SUBJECT") + ((pCert->cbCertEncoded + 2) * 2 * sizeof(WCHAR)) + // store fields
|
|
sizeof("CERTIFICATE") + ((pCert->cbCertEncoded +2)* sizeof(WCHAR)) +
|
|
sizeof("SERIALNUMBER") + (pCert->pCertInfo->SerialNumber.cbData * 3) +
|
|
sizeof("PUBLICKEY") + ((pCert->pCertInfo->SubjectPublicKeyInfo.PublicKey.cbData+2) * sizeof(WCHAR)) +
|
|
sizeof("VALIDFROM") + sizeof(DATE) +
|
|
sizeof("VALIDUNTIL") + sizeof(DATE) +
|
|
sizeof("FLAGS") + sizeof(DWORD) +
|
|
sizeof("ENCODING") + sizeof(DWORD);
|
|
;
|
|
|
|
if ( !xbf.Extend( cStore ) ) {
|
|
ExceptionId(IID_IRequestDictionary, IDE_REQUEST, IDE_OOM);
|
|
hRes = E_OUTOFMEMORY;
|
|
goto cleanup;
|
|
}
|
|
|
|
//
|
|
// Build Issuer clear text format & fields collection
|
|
//
|
|
|
|
if ( !DecodeRdn( &pCert->pCertInfo->Issuer, &pNameInfo ) )
|
|
{
|
|
hRes = E_FAIL;
|
|
goto cleanup;
|
|
}
|
|
pVal = xbf.ReserveRange( 0 );
|
|
if ( !BuildRdnList( pNameInfo, &xbf, FALSE ) )
|
|
{
|
|
ExceptionId(IID_IRequestDictionary, IDE_REQUEST, IDE_OOM);
|
|
hRes = E_FAIL;
|
|
goto cleanup;
|
|
}
|
|
if ( (hRes = AddStringPair( CLCERT, "ISSUER", pVal, &xbf, FALSE, lCodePage ))
|
|
!= S_OK )
|
|
{
|
|
goto cleanup;
|
|
}
|
|
|
|
if ( (hRes=AddUuBinaryPair( CLCERT,
|
|
"BINARYISSUER",
|
|
pCert->pCertInfo->Issuer.pbData,
|
|
pCert->pCertInfo->Issuer.cbData,
|
|
&xbf,
|
|
lCodePage ))!=S_OK ) {
|
|
ExceptionId(IID_IRequestDictionary, IDE_REQUEST, IDE_OOM);
|
|
goto cleanup;
|
|
}
|
|
|
|
if ( (hRes=ParseRDNS( pNameInfo, "ISSUER", &xbf, lCodePage )) != S_OK ) {
|
|
ExceptionId(IID_IRequestDictionary, IDE_REQUEST, IDE_OOM);
|
|
goto cleanup;
|
|
}
|
|
FreeDecodedRdn( pNameInfo );
|
|
|
|
//
|
|
// Build Subject clear text format & fields collection
|
|
//
|
|
|
|
if ( !DecodeRdn( &pCert->pCertInfo->Subject, &pNameInfo ) )
|
|
{
|
|
ExceptionId(IID_IRequestDictionary, IDE_REQUEST, IDE_OOM);
|
|
return E_FAIL;
|
|
}
|
|
pVal = xbf.ReserveRange( 0 );
|
|
if ( !BuildRdnList( pNameInfo, &xbf, FALSE ) )
|
|
{
|
|
ExceptionId(IID_IRequestDictionary, IDE_REQUEST, IDE_OOM);
|
|
hRes = E_FAIL;
|
|
goto cleanup;
|
|
}
|
|
if ( (hRes = AddStringPair( CLCERT, "SUBJECT", pVal, &xbf, FALSE, lCodePage ))
|
|
!= S_OK )
|
|
{
|
|
ExceptionId(IID_IRequestDictionary, IDE_REQUEST, IDE_OOM);
|
|
goto cleanup;
|
|
}
|
|
|
|
if ( (hRes=AddUuBinaryPair( CLCERT,
|
|
"BINARYSUBJECT",
|
|
pCert->pCertInfo->Subject.pbData,
|
|
pCert->pCertInfo->Subject.cbData,
|
|
&xbf,
|
|
lCodePage ))!=S_OK )
|
|
{
|
|
ExceptionId(IID_IRequestDictionary, IDE_REQUEST, IDE_OOM);
|
|
goto cleanup;
|
|
}
|
|
|
|
if ( (hRes=ParseRDNS( pNameInfo, "SUBJECT", &xbf, lCodePage )) != S_OK )
|
|
{
|
|
ExceptionId(IID_IRequestDictionary, IDE_REQUEST, IDE_OOM);
|
|
goto cleanup;
|
|
}
|
|
FreeDecodedRdn( pNameInfo );
|
|
|
|
if ( (hRes=AddBinaryPair( CLCERT, "CERTIFICATE", pCert->pbCertEncoded, pCert->cbCertEncoded, &xbf, lCodePage ))!=S_OK )
|
|
{
|
|
ExceptionId(IID_IRequestDictionary, IDE_REQUEST, IDE_OOM);
|
|
goto cleanup;
|
|
}
|
|
|
|
//
|
|
// SerialNumber
|
|
// The certificate's serial number. (Decoded as a multiple byte integer.
|
|
// SerialNumber.pbData[0] is the least significant byte. SerialNumber.pbData[
|
|
// SerialNumber.cbData - 1] is the most significant byte.)
|
|
//
|
|
char achSerNum[128];
|
|
UINT cbSN;
|
|
|
|
DBG_ASSERT(pCert->pCertInfo->SerialNumber.cbData > 1);
|
|
cbSN = pCert->pCertInfo->SerialNumber.cbData;
|
|
if (cbSN > 0)
|
|
{
|
|
cbSN--;
|
|
}
|
|
else
|
|
{
|
|
ExceptionId(IID_IRequestDictionary, IDE_REQUEST, IDE_OOM);
|
|
goto cleanup;
|
|
}
|
|
|
|
UINT iOffSet;
|
|
for ( x = 0, iOffSet = 0; x < pCert->pCertInfo->SerialNumber.cbData ; ++x )
|
|
{
|
|
iOffSet = (cbSN-x)*3; // start with the least significant byte
|
|
achSerNum[iOffSet] = "0123456789abcdef"[((LPBYTE)pCert->pCertInfo->SerialNumber.pbData)[x]>>4];
|
|
achSerNum[iOffSet+1] = "0123456789abcdef"[pCert->pCertInfo->SerialNumber.pbData[x]&0x0f];
|
|
if ( x != 0 ) {
|
|
achSerNum[iOffSet+2] = '-';
|
|
}
|
|
else
|
|
{
|
|
achSerNum[iOffSet+2] = '\0';
|
|
}
|
|
}
|
|
|
|
if ( (hRes=AddStringPair( CLCERT, "SERIALNUMBER", achSerNum, &xbf, TRUE, lCodePage ))!=S_OK )
|
|
{
|
|
ExceptionId(IID_IRequestDictionary, IDE_REQUEST, IDE_OOM);
|
|
goto cleanup;
|
|
}
|
|
|
|
if ( (hRes=AddBinaryPair( CLCERT, "PUBLICKEY", pCert->pCertInfo->SubjectPublicKeyInfo.PublicKey.pbData, pCert->pCertInfo->SubjectPublicKeyInfo.PublicKey.cbData, &xbf, lCodePage ))!=S_OK )
|
|
{
|
|
ExceptionId(IID_IRequestDictionary, IDE_REQUEST, IDE_OOM);
|
|
goto cleanup;
|
|
}
|
|
|
|
if ( (hRes=AddDatePair( CLCERT, "VALIDFROM", &pCert->pCertInfo->NotBefore, &xbf ))!=S_OK )
|
|
{
|
|
ExceptionId(IID_IRequestDictionary, IDE_REQUEST, IDE_OOM);
|
|
goto cleanup;
|
|
}
|
|
|
|
if ( (hRes=AddDatePair( CLCERT, "VALIDUNTIL", &pCert->pCertInfo->NotAfter, &xbf ))!=S_OK )
|
|
{
|
|
ExceptionId(IID_IRequestDictionary, IDE_REQUEST, IDE_OOM);
|
|
goto cleanup;
|
|
}
|
|
|
|
if ( (hRes=AddDwordPair( CLCERT, "FLAGS", &dwFlags, &xbf ))!=S_OK )
|
|
{
|
|
ExceptionId(IID_IRequestDictionary, IDE_REQUEST, IDE_OOM);
|
|
goto cleanup;
|
|
}
|
|
|
|
if ( (hRes=AddDwordPair( CLCERT, "ENCODING", &dwEncoding, &xbf ))!=S_OK )
|
|
{
|
|
ExceptionId(IID_IRequestDictionary, IDE_REQUEST, IDE_OOM);
|
|
goto cleanup;
|
|
}
|
|
|
|
cleanup:
|
|
if ( pCert )
|
|
{
|
|
CertFreeCertificateContext( pCert );
|
|
}
|
|
|
|
pReq->SetCertStore( xbf.QueryBuf(), xbf.QueryAllocSize() );
|
|
|
|
xbf.Reset();
|
|
|
|
return hRes;
|
|
}
|
|
|
|
|
|
/*===================================================================
|
|
CCertRequest::NoCertificate
|
|
|
|
Function called to create NULL certificate info into a OA collection
|
|
|
|
Parameters:
|
|
None
|
|
|
|
Returns:
|
|
S_OK on success, E_OUTOFMEMORY if out of memory or E_FAIL for
|
|
other errors
|
|
===================================================================*/
|
|
|
|
HRESULT
|
|
CCertRequest::NoCertificate(
|
|
)
|
|
{
|
|
#if 1
|
|
|
|
return S_OK;
|
|
|
|
#else
|
|
|
|
XBF xbf( pReq->GetCertStoreBuf(), pReq->GetCertStoreSize() );
|
|
HRESULT hRes = S_OK;
|
|
UINT cStore;
|
|
FILETIME ft;
|
|
|
|
// estimate size of buffer holding values
|
|
|
|
cStore =
|
|
sizeof("ISSUER") + 2*sizeof(WCHAR) +
|
|
sizeof("BINARYISSUER") + 2*sizeof(WCHAR) +
|
|
sizeof("BINARYSUBJECT") + 2*sizeof(WCHAR) +
|
|
sizeof("SUBJECT") + 2*sizeof(WCHAR) +
|
|
sizeof("CERTIFICATE") + 2 * sizeof(WCHAR) +
|
|
sizeof("SERIALNUMBER") + 2 * sizeof(WCHAR) +
|
|
sizeof("PUBLICKEY") + 2 * sizeof(WCHAR) +
|
|
sizeof("VALIDFROM") + sizeof(DATE) +
|
|
sizeof("VALIDUNTIL") + sizeof(DATE)
|
|
;
|
|
|
|
if ( !xbf.Extend( cStore ) )
|
|
{
|
|
hRes = E_OUTOFMEMORY;
|
|
goto cleanup;
|
|
}
|
|
|
|
ft.dwLowDateTime = 0;
|
|
ft.dwHighDateTime = 0;
|
|
|
|
//
|
|
// Build Issuer clear text format & fields collection
|
|
//
|
|
|
|
if ( (hRes = AddStringPair( CLCERT, "ISSUER", "", &xbf, FALSE, lCodePage ))
|
|
!= S_OK )
|
|
{
|
|
goto cleanup;
|
|
}
|
|
|
|
if ( (hRes = AddStringPair( CLCERT, "BINARYISSUER", "", &xbf, FALSE, lCodePage ))
|
|
!= S_OK )
|
|
{
|
|
goto cleanup;
|
|
}
|
|
|
|
if ( (hRes = AddStringPair( CLCERT, "SUBJECT", "", &xbf, FALSE, lCodePage ))
|
|
!= S_OK )
|
|
{
|
|
goto cleanup;
|
|
}
|
|
|
|
if ( (hRes = AddStringPair( CLCERT, "BINARYSUBJECT", "", &xbf, FALSE, lCodePage ))
|
|
!= S_OK )
|
|
{
|
|
goto cleanup;
|
|
}
|
|
|
|
if ( (hRes = AddStringPair( CLCERT, "CERTIFICATE", "", &xbf, FALSE, lCodePage ))
|
|
!= S_OK )
|
|
{
|
|
goto cleanup;
|
|
}
|
|
|
|
if ( (hRes=AddStringPair( CLCERT, "SERIALNUMBER", "", &xbf, TRUE, lCodePage ))!=S_OK )
|
|
{
|
|
goto cleanup;
|
|
}
|
|
|
|
if ( (hRes=AddStringPair( CLCERT, "PUBLICKEY", "", &xbf, TRUE, lCodePage ))!=S_OK )
|
|
{
|
|
goto cleanup;
|
|
}
|
|
|
|
if ( (hRes=AddDatePair( CLCERT, "VALIDFROM", &ft, &xbf ))!=S_OK )
|
|
{
|
|
goto cleanup;
|
|
}
|
|
|
|
if ( (hRes=AddDatePair( CLCERT, "VALIDUNTIL", &ft, &xbf ))!=S_OK )
|
|
{
|
|
goto cleanup;
|
|
}
|
|
|
|
cleanup:
|
|
|
|
pReq->SetCertStore( xbf.QueryBuf(), xbf.QueryAllocSize() );
|
|
|
|
xbf.Reset();
|
|
|
|
return hRes;
|
|
|
|
#endif
|
|
}
|
|
|
|
|
|
/*===================================================================
|
|
RequestSupportTerminate
|
|
|
|
Function called to initialize certificate support
|
|
|
|
Parameters:
|
|
None
|
|
|
|
Returns:
|
|
TRUE on success, otherwise FALSE
|
|
===================================================================*/
|
|
|
|
BOOL
|
|
RequestSupportInit(
|
|
)
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/*===================================================================
|
|
RequestSupportTerminate
|
|
|
|
Function called to terminate certificate support
|
|
|
|
Parameters:
|
|
None
|
|
|
|
Returns:
|
|
Nothing
|
|
===================================================================*/
|
|
|
|
VOID
|
|
RequestSupportTerminate(
|
|
)
|
|
{
|
|
}
|
|
|
|
|
|
HRESULT
|
|
SetVariantAsByteArray(
|
|
VARIANT* pvarReturn,
|
|
DWORD cbLen,
|
|
LPBYTE pbIn
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Create variant as byte array
|
|
|
|
Arguments:
|
|
|
|
pVarReturn - ptr to created variant
|
|
cbLen - byte count
|
|
pbIn - byte array
|
|
|
|
Returns:
|
|
|
|
COM status
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr;
|
|
SAFEARRAYBOUND rgsabound[1];
|
|
BYTE * pbData = NULL;
|
|
|
|
// Set the variant type of the output parameter
|
|
|
|
V_VT(pvarReturn) = VT_ARRAY|VT_UI1;
|
|
V_ARRAY(pvarReturn) = NULL;
|
|
|
|
// Allocate a SafeArray for the data
|
|
|
|
rgsabound[0].lLbound = 0;
|
|
rgsabound[0].cElements = cbLen;
|
|
|
|
V_ARRAY(pvarReturn) = SafeArrayCreate(VT_UI1, 1, rgsabound);
|
|
if (V_ARRAY(pvarReturn) == NULL)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
if (FAILED(SafeArrayAccessData(V_ARRAY(pvarReturn), (void **) &pbData)))
|
|
{
|
|
return E_UNEXPECTED;
|
|
}
|
|
|
|
memcpy(pbData, pbIn, cbLen );
|
|
|
|
SafeArrayUnaccessData(V_ARRAY(pvarReturn));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|