|
|
//+--------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1996 - 1999
//
// File: request.cpp
//
// Contents: Cert Server client implementation
//
// History: 24-Aug-96 vich created
//
//---------------------------------------------------------------------------
#include "pch.cpp"
#pragma hdrstop
#include <objbase.h>
#include "certsrvd.h"
#include "csdisp.h"
#include "certrpc.h"
#include <certca.h>
#include "request.h"
#define __dwFILE__ __dwFILE_CERTCLI_REQUEST_CPP__
#define CR_RPC_CANCEL_TIMEOUT 5
#define CR_RPC_REQUEST_TIMEOUT 60000 /* 60 seconds for the request timeout */
typedef struct _RPC_TIMEOUT_CONTEXT { HANDLE hWait; HANDLE hEvent; HANDLE hThread; HRESULT hrRpcError; } RPC_TIMEOUT_CONTEXT, *PRPC_TIMEOUT_CONTEXT;
typedef struct _WZR_RPC_BINDING_LIST { LPWSTR pszProtSeq; LPWSTR pszEndpoint; } WZR_RPC_BINDING_LIST;
WZR_RPC_BINDING_LIST g_awzrBindingList[] = { { L"ncacn_ip_tcp", NULL }, { L"ncacn_np", L"\\pipe\\cert" } };
INT g_cwzrBindingList = sizeof(g_awzrBindingList)/sizeof(g_awzrBindingList[0]);
typedef struct _WZR_RPC_ATHN_LIST { DWORD dwAuthnLevel; DWORD dwAuthnService; } WZR_RPC_ATHN_LIST;
WZR_RPC_ATHN_LIST g_awzrAthnList[] = { { RPC_C_AUTHN_LEVEL_PKT_INTEGRITY, RPC_C_AUTHN_GSS_NEGOTIATE}, { RPC_C_AUTHN_LEVEL_NONE, RPC_C_AUTHN_NONE } };
INT g_cwzrAthnList = sizeof(g_awzrAthnList)/sizeof(g_awzrAthnList[0]);
HRESULT crRegisterRPCCallTimeout( IN DWORD dwMilliseconds, OUT PRPC_TIMEOUT_CONTEXT pTimeout);
HRESULT crCloseRPCCallTimeout( IN PRPC_TIMEOUT_CONTEXT pTimeout);
HRESULT crSetRPCSecurity( IN handle_t hRPCCertServer, IN OUT INT *prpcAuthProtocol) { HRESULT hr = S_OK; LPWSTR pwszCAPrinceName = NULL; INT rpcAuthProtocol = *prpcAuthProtocol;
// Set the RPC connect as the SNEGO connect, which can authenticate
// a machine if supported by the system.
// Don't need to check the return value since not supported by NT4/Win9x.
if (rpcAuthProtocol >= g_cwzrAthnList) { hr = RPC_S_UNKNOWN_AUTHN_SERVICE; goto error; } for ( ; rpcAuthProtocol < g_cwzrAthnList; rpcAuthProtocol++) { pwszCAPrinceName = NULL; if (RPC_C_AUTHN_NONE != g_awzrAthnList[rpcAuthProtocol].dwAuthnService) { hr = RpcMgmtInqServerPrincName( hRPCCertServer, g_awzrAthnList[rpcAuthProtocol].dwAuthnService, &pwszCAPrinceName); if (hr == RPC_S_UNKNOWN_AUTHN_SERVICE) { continue; } }
hr = RpcBindingSetAuthInfo( hRPCCertServer, pwszCAPrinceName, g_awzrAthnList[rpcAuthProtocol].dwAuthnLevel, g_awzrAthnList[rpcAuthProtocol].dwAuthnService, NULL, RPC_C_AUTHZ_NONE);
if (NULL != pwszCAPrinceName) { RpcStringFree(&pwszCAPrinceName); } if (hr != RPC_S_UNKNOWN_AUTHN_SERVICE) { break; } }
error: *prpcAuthProtocol = rpcAuthProtocol; return(hr); }
HRESULT crOpenRPCConnection( IN WCHAR const *pwszServerName, IN OUT INT *prpcAuthProtocol, OUT handle_t *phRPCCertServer) { HRESULT hr = S_OK; INT i; WCHAR *pwszStringBinding = NULL;
for (i = 0; i < g_cwzrBindingList; i++) { if (RPC_S_OK != RpcNetworkIsProtseqValid( g_awzrBindingList[i].pszProtSeq)) { continue; }
hr = RpcStringBindingCompose( NULL, g_awzrBindingList[i].pszProtSeq, const_cast<WCHAR *>(pwszServerName), g_awzrBindingList[i].pszEndpoint, NULL, &pwszStringBinding); if (S_OK != hr) { continue; }
hr = RpcBindingFromStringBinding( pwszStringBinding, phRPCCertServer); if (NULL != pwszStringBinding) { RpcStringFree(&pwszStringBinding); } if (S_OK != hr) { continue; }
hr = RpcEpResolveBinding( *phRPCCertServer, ICertPassage_v0_0_c_ifspec); if (S_OK == hr) { break; } } _JumpIfError(hr, error, "RPC Resolve Binding Loop");
hr = crSetRPCSecurity(*phRPCCertServer, prpcAuthProtocol); _JumpIfError(hr, error, "_SetRPCSecurity");
error: if (NULL != pwszStringBinding) { RpcStringFree(&pwszStringBinding); } return(hr); }
VOID crCloseRPCConnection( IN OUT handle_t *phRPCCertServer) { if (NULL != *phRPCCertServer) { RpcBindingFree(phRPCCertServer); *phRPCCertServer = NULL; } }
HRESULT crCertServerRequest( IN handle_t hRPCCertServer, IN OUT INT *prpcAuthProtocol, IN DWORD Flags, IN WCHAR const *pwszAuthority, IN OUT DWORD *pRequestId, OUT DWORD *pDisposition, IN CERTTRANSBLOB const *pctbAttrib, IN CERTTRANSBLOB const *pctbSerial, IN CERTTRANSBLOB const *pctbRequest, OUT CERTTRANSBLOB *pctbCertChain, OUT CERTTRANSBLOB *pctbCert, OUT CERTTRANSBLOB *pctbDispositionMessage) { HRESULT hr;
RPC_TIMEOUT_CONTEXT Timeout = {NULL, NULL, NULL, S_OK}; do { // Midl_user_allocate registers memory in RPC case
hr = crRegisterRPCCallTimeout(CR_RPC_REQUEST_TIMEOUT, &Timeout); _JumpIfError(hr, error, "crRegisterRPCCallTimeout");
__try { hr = CertServerRequest( hRPCCertServer, Flags, pwszAuthority, pRequestId, pDisposition, pctbAttrib, pctbRequest, pctbCertChain, pctbCert, pctbDispositionMessage); } __except( HRESULT_FROM_WIN32(RPC_S_CALL_CANCELLED) == myHEXCEPTIONCODE()? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) { hr = Timeout.hrRpcError; }
crCloseRPCCallTimeout(&Timeout);
_PrintIfError(hr, "CertServerRequest");
if (hr == RPC_S_UNKNOWN_AUTHN_SERVICE) { (*prpcAuthProtocol)++; hr = crSetRPCSecurity(hRPCCertServer, prpcAuthProtocol); if (hr == RPC_S_UNKNOWN_AUTHN_SERVICE) { break; } if (hr == S_OK) { continue; } } } while (hr == RPC_S_UNKNOWN_AUTHN_SERVICE); error: return(hr); }
HRESULT crRequestCertificate( IN DWORD Flags, OPTIONAL IN BYTE const *pbRequest, IN DWORD cbRequest, IN DWORD RequestId, OPTIONAL IN WCHAR const *pwszRequestAttributes, OPTIONAL IN WCHAR const *pwszSerialNumber, IN WCHAR const *pwszServerName, IN WCHAR const *pwszAuthority, OUT CERTSERVERENROLL **ppcsEnroll) // free via CertServerFreeMemory
{ HRESULT hr; handle_t hRPCCertServer = NULL; INT rpcAuthProtocol = 0; CERTTRANSBLOB ctbRequest; CERTTRANSBLOB ctbAttrib; CERTTRANSBLOB ctbSerial; CERTTRANSBLOB ctbCert = { 0, NULL }; CERTTRANSBLOB ctbCertChain = { 0, NULL }; CERTTRANSBLOB ctbDispositionMessage = { 0, NULL }; CERTSERVERENROLL csEnroll; CERTSERVERENROLL *pcsEnroll = NULL; BYTE *pbOut; DWORD cbAlloc;
if (NULL == pwszServerName || NULL == pwszAuthority || NULL == ppcsEnroll) { hr = E_POINTER; _JumpError(hr, error, "NULL parm"); } *ppcsEnroll = NULL;
ZeroMemory(&csEnroll, sizeof(csEnroll)); csEnroll.hrLastStatus = E_FAIL; csEnroll.Disposition = CR_DISP_ERROR; csEnroll.RequestId = RequestId;
ctbRequest.pb = const_cast<BYTE *>(pbRequest); ctbRequest.cb = cbRequest;
ctbAttrib.pb = (BYTE *) pwszRequestAttributes; ctbAttrib.cb = 0; if (NULL != pwszRequestAttributes) { ctbAttrib.cb = (wcslen(pwszRequestAttributes) + 1) * sizeof(WCHAR); }
ctbSerial.pb = (BYTE *) pwszSerialNumber; ctbSerial.cb = 0; if (NULL != pwszSerialNumber) { ctbSerial.cb = (wcslen(pwszSerialNumber) + 1) * sizeof(WCHAR); }
hr = crOpenRPCConnection(pwszServerName, &rpcAuthProtocol, &hRPCCertServer); _JumpIfError(hr, error, "crOpenRPCConnection");
hr = crCertServerRequest( hRPCCertServer, &rpcAuthProtocol, Flags, pwszAuthority, &csEnroll.RequestId, &csEnroll.Disposition, &ctbAttrib, &ctbSerial, &ctbRequest, &ctbCertChain, &ctbCert, &ctbDispositionMessage); _JumpIfError(hr, error, "crCertServerRequest");
csEnroll.hrLastStatus = hr; if (FAILED(csEnroll.Disposition)) { csEnroll.hrLastStatus = csEnroll.Disposition; csEnroll.Disposition = CR_DISP_DENIED; }
cbAlloc = sizeof(*pcsEnroll) + DWORDROUND(ctbCert.cb) + DWORDROUND(ctbCertChain.cb) + DWORDROUND(ctbDispositionMessage.cb);
pcsEnroll = (CERTSERVERENROLL *) LocalAlloc(LMEM_FIXED, cbAlloc); if (NULL == pcsEnroll) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "LocalAlloc"); } *pcsEnroll = csEnroll; // structure copy
pbOut = (BYTE *) &pcsEnroll[1]; if (0 != ctbCert.cb) { CSASSERT(NULL != ctbCert.pb); pcsEnroll->pbCert = pbOut; pcsEnroll->cbCert = ctbCert.cb; CopyMemory(pbOut, ctbCert.pb, ctbCert.cb); pbOut += DWORDROUND(ctbCert.cb); } if (0 != ctbCertChain.cb) { CSASSERT(NULL != ctbCertChain.pb); pcsEnroll->pbCertChain = pbOut; pcsEnroll->cbCertChain = ctbCertChain.cb; CopyMemory(pbOut, ctbCertChain.pb, ctbCertChain.cb); pbOut += DWORDROUND(ctbCertChain.cb); } if (0 != ctbDispositionMessage.cb) { CSASSERT(NULL != ctbDispositionMessage.pb); pcsEnroll->pwszDispositionMessage = (WCHAR *) pbOut; CopyMemory(pbOut, ctbDispositionMessage.pb, ctbDispositionMessage.cb); pbOut += DWORDROUND(ctbDispositionMessage.cb); } CSASSERT(pbOut == &((BYTE *) pcsEnroll)[cbAlloc]);
*ppcsEnroll = pcsEnroll;
error: if (NULL != ctbCert.pb) { MIDL_user_free(ctbCert.pb); } if (NULL != ctbCertChain.pb) { MIDL_user_free(ctbCertChain.pb); } if (NULL != ctbDispositionMessage.pb) { MIDL_user_free(ctbDispositionMessage.pb); } crCloseRPCConnection(&hRPCCertServer); return(hr); }
HRESULT CertServerSubmitRequest( IN DWORD Flags, IN BYTE const *pbRequest, IN DWORD cbRequest, OPTIONAL IN WCHAR const *pwszRequestAttributes, IN WCHAR const *pwszServerName, IN WCHAR const *pwszAuthority, OUT CERTSERVERENROLL **ppcsEnroll) // free via CertServerFreeMemory
{ HRESULT hr;
if (NULL == pbRequest) { hr = E_POINTER; _JumpError(hr, error, "NULL parm"); } if (CR_IN_BINARY != (CR_IN_ENCODEMASK & Flags)) { hr = E_INVALIDARG; _JumpError(hr, error, "not CR_IN_BINARY"); } hr = crRequestCertificate( Flags, pbRequest, cbRequest, 0, // RequestId
pwszRequestAttributes, NULL, // pwszSerialNumber
pwszServerName, pwszAuthority, ppcsEnroll); _JumpIfError(hr, error, "crRequestCertificate");
error: return(hr); }
HRESULT CertServerRetrievePending( IN DWORD RequestId, OPTIONAL IN WCHAR const *pwszSerialNumber, IN WCHAR const *pwszServerName, IN WCHAR const *pwszAuthority, OUT CERTSERVERENROLL **ppcsEnroll) // free via CertServerFreeMemory
{ HRESULT hr;
if ((0 == RequestId) ^ (NULL != pwszSerialNumber)) { hr = E_INVALIDARG; _JumpError(hr, error, "use RequestId OR pwszSerialNumber"); } hr = crRequestCertificate( 0, // Flags
NULL, // pbRequest
0, // cbRequest
RequestId, NULL, // pwszRequestAttributes
pwszSerialNumber, pwszServerName, pwszAuthority, ppcsEnroll); _JumpIfError(hr, error, "crRequestCertificate");
error: return(hr); }
VOID CertServerFreeMemory( IN VOID *pv) { LocalFree(pv); }
//+--------------------------------------------------------------------------
// CCertRequest::~CCertRequest -- destructor
//
// free memory associated with this instance
//+--------------------------------------------------------------------------
CCertRequest::~CCertRequest() { _Cleanup(); }
//+--------------------------------------------------------------------------
// CCertRequest::_CleanupOldConnection -- free memory
//
// free memory associated with this instance
//+--------------------------------------------------------------------------
VOID CCertRequest::_CleanupOldConnection() { // bytes returned from interfaces are MIDL_user_allocate
if (NULL != m_pwszDispositionMessage) { MIDL_user_free(m_pwszDispositionMessage); m_pwszDispositionMessage = NULL; } if (NULL != m_pbCert) { MIDL_user_free(m_pbCert); m_pbCert = NULL; } if (NULL != m_pbCertificateChain) { MIDL_user_free(m_pbCertificateChain); m_pbCertificateChain = NULL; } if (NULL != m_pbFullResponse) { MIDL_user_free(m_pbFullResponse); m_pbFullResponse = NULL; } if (NULL != m_pbRequest) { LocalFree(m_pbRequest); m_pbRequest = NULL; } if (NULL != m_pCAPropInfo) { MIDL_user_free(m_pCAPropInfo); m_pCAPropInfo = NULL; } if (NULL != m_rgResponse) { FreeCMCResponse(m_rgResponse, m_cResponse); m_rgResponse = NULL; } if (NULL != m_hStoreResponse) { CertCloseStore(m_hStoreResponse, CERT_CLOSE_STORE_CHECK_FLAG); m_hStoreResponse = NULL; } m_cResponse = 0; m_LastStatus = S_OK; m_RequestId = 0; m_Disposition = 0; _CleanupCAPropInfo(); }
//+--------------------------------------------------------------------------
// CCertRequest::_Cleanup -- free memory
//
// free memory associated with this instance
//+--------------------------------------------------------------------------
VOID CCertRequest::_Cleanup() { _CloseConnection(); _CleanupOldConnection(); }
//+--------------------------------------------------------------------------
// CCertRequest::_OpenRPCConnection -- establish RPC connection
//
// establish RPC connection
//+--------------------------------------------------------------------------
HRESULT CCertRequest::_OpenRPCConnection( IN WCHAR const *pwszConfig, OUT BOOL *pfNewConnection, OUT WCHAR const **ppwszAuthority) { HRESULT hr; WCHAR *pwszServerName = NULL; WCHAR *pwsz; DWORD cwc;
CSASSERT(NULL != pwszConfig && NULL != pfNewConnection);
*pfNewConnection = FALSE; pwsz = wcschr(pwszConfig, L'\\'); if (NULL == pwsz) { cwc = wcslen(pwszConfig); *ppwszAuthority = &pwszConfig[cwc]; } else { cwc = SAFE_SUBTRACT_POINTERS(pwsz, pwszConfig); *ppwszAuthority = &pwsz[1]; } pwszServerName = (WCHAR *) LocalAlloc( LMEM_FIXED, (cwc + 1) * sizeof(WCHAR)); if (NULL == pwszServerName) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "LocalAlloc"); } CopyMemory(pwszServerName, pwszConfig, cwc * sizeof(WCHAR)); pwszServerName[cwc] = L'\0';
if (NULL == m_hRPCCertServer || NULL == m_pwszServerName || 0 != lstrcmpi(pwszServerName, m_pwszServerName)) { _CloseConnection(); CSASSERT(NULL == m_pwszServerName); m_pwszServerName = pwszServerName; pwszServerName = NULL;
hr = crOpenRPCConnection( m_pwszServerName, &m_rpcAuthProtocol, &m_hRPCCertServer); _JumpIfError(hr, error, "crOpenRPCConnection");
*pfNewConnection = TRUE; } hr = S_OK;
error: if (S_OK != hr) { _CloseConnection(); hr = myHError(hr); } if (NULL != pwszServerName) { LocalFree(pwszServerName); } return(hr); }
//+--------------------------------------------------------------------------
// CCertRequest::_OpenConnection -- establish RPC connection
//
//+--------------------------------------------------------------------------
HRESULT CCertRequest::_OpenConnection( IN BOOL fRPC, IN WCHAR const *pwszConfig, IN DWORD RequiredVersion, OUT WCHAR const **ppwszAuthority) { HRESULT hr; BOOL fNewConnection = FALSE;
if (NULL == pwszConfig) { hr = E_POINTER; _JumpError(hr, error, "pwszConfig"); } if (fRPC) { if (NULL != m_pICertRequestD) { _CloseConnection(); // switching to RPC
} hr = _OpenRPCConnection(pwszConfig, &fNewConnection, ppwszAuthority); _JumpIfError(hr, error, "_OpenRPCConnection");
CSASSERT(NULL != m_hRPCCertServer); CSASSERT(0 == m_dwServerVersion); } else { if (NULL != m_hRPCCertServer) { _CloseConnection(); // switching to DCOM
} hr = myOpenRequestDComConnection( pwszConfig, ppwszAuthority, &m_pwszServerName, &fNewConnection, &m_dwServerVersion, &m_pICertRequestD); _JumpIfError(hr, error, "myOpenRequestDComConnection");
CSASSERT(NULL != m_pICertRequestD); CSASSERT(0 != m_dwServerVersion); } if (m_dwServerVersion < RequiredVersion) { hr = RPC_E_VERSION_MISMATCH; _JumpError(hr, error, "old server"); } if (fNewConnection) { _CleanupOldConnection(); }
error: return(hr); }
//+--------------------------------------------------------------------------
// CCertRequest::_CloseConnection -- release DCOM object
//
//+--------------------------------------------------------------------------
VOID CCertRequest::_CloseConnection() { crCloseRPCConnection(&m_hRPCCertServer); myCloseDComConnection((IUnknown **) &m_pICertRequestD, &m_pwszServerName); m_dwServerVersion = 0; }
//+--------------------------------------------------------------------------
// CCertRequest::Submit -- Submit a cert request and return the disposition.
//
// Submit the passed certificate request to the Certificate Server and retrieve
// the certificate from the server, if it is immediately available. If the
// returned disposition so indicates, other CCertRequest methods may be called
// to return the certificate or certificate chain to the caller.
//
// All state from previous method calls is cleared.
//
// After the Submit method completes execution, the GetDispositionMessage and
// GetLastStatus methods may be called to retrieve informational disposition
// text and a more specific error code.
//
// Flags contains flags that describe the input data format as defined above.
//
// strRequest points to the input request data, in base64-encoded form.
//
// strAttributes is optional. When non-NULL, it points to a string containing
// attribute value pairs, one pair per line. The attribute name and value
// strings may contain any text of the caller's choosing. Only the syntax of a
// colon-separated attribute name and value string followed by a newline is
// enforced. Attribute names that are not understood by the Certificate Server
// will be available to Policy Modules, but are otherwise ignored by the
// Certificate Server.
// Example:
// "Phone: 0424-12-3456\r\nServer: Microsoft Key Manager for IIS 2.0\r\n"
// "Version: 3\r\nRequestType: Client\r\n"
//
// strConfig points to a string that contains the server name and Certificate
// Authority name. See the ICertConfig interface.
//
// pDisposition points to the returned disposition of the request as defined
// above. When the request cannot be immediately granted or denied (some off-
// line processing may be required), *pDisposition is set to
// CR_DISP_UNDER_SUBMISSION. After CR_DISP_UNDER_SUBMISSION is returned for
// the initial request's disposition, the RetrievePending method may be called
// to interrogate the disposition again and to retrieve the certificate if it
// has been issued. If the returned disposition so indicates, RetrievePending
// will retrieve the certificate and allow the other methods defined here to
// return the certificate to the caller. If denied, the appropriate
// disposition code will be returned. If the request has still not been
// processed, CR_DISP_UNDER_SUBMISSION will again be returned by the
// RetrievePending method.
//
// Returns S_OK if the method completed execution. Errors are indicated by
// the returned disposition.
//+--------------------------------------------------------------------------
STDMETHODIMP CCertRequest::Submit( /* [in] */ LONG Flags, /* [in] */ BSTR const strRequest, /* [in] */ BSTR const strAttributes, /* [in] */ BSTR const strConfig, /* [out, retval] */ LONG __RPC_FAR *pDisposition) { HRESULT hr;
if ((NULL == strRequest) || (NULL == pDisposition)) { hr = E_POINTER; _JumpError(hr, error, "strRequest or pDisposition"); } hr = _RequestCertificate( Flags, 0, // RequestId
strRequest, strAttributes, NULL, // pwszSerialNumber
strConfig, (CR_IN_RPC & Flags)? 0 : 1, // RequiredVersion
pDisposition); _JumpIfError2( hr, error, "_RequestCertificate", HRESULT_FROM_WIN32(ERROR_INVALID_DATA));
error: return(_SetErrorInfo(hr, L"CCertRequest::Submit")); }
//+--------------------------------------------------------------------------
// CCertRequest::RetrievePending -- Retrieve pending request disposition.
//
// Interrogate the Certificate Server and retrieve the certificate identified
// by the passed RequestId, if it is now available. If the returned
// disposition so indicates, other CCertRequest methods may be called to return
// the certificate or certificate chain to the caller.
//
// All state from previous method calls is cleared.
//
// After the RetrievePending method completes execution, the
// GetDispositionMessage and GetLastStatus methods may be called to retrieve
// informational disposition text and a more specific error code.
//
// RequestId identifies a previously submitted request.
//
// strConfig points to a string that contains the server name and Certificate
// Authority name.
//
// pDisposition points to the returned disposition of the pending request.
//
// Returns S_OK if the method completed execution. Errors are indicated by
// the returned disposition.
//+--------------------------------------------------------------------------
STDMETHODIMP CCertRequest::RetrievePending( /* [in] */ LONG RequestId, /* [in] */ BSTR const strConfig, /* [out, retval] */ LONG __RPC_FAR *pDisposition) { HRESULT hr; WCHAR *pwszConfig = strConfig; WCHAR *pwszSerialNumber = NULL;
if (NULL == pDisposition || NULL == strConfig) { hr = E_POINTER; _JumpError(hr, error, "NULL param"); }
if (0 == RequestId) { DWORD cwc; pwszSerialNumber = wcschr(pwszConfig, L'\\'); if (NULL != pwszSerialNumber) { pwszSerialNumber = wcschr(&pwszSerialNumber[1], L'\\'); } if (NULL == pwszSerialNumber) { hr = E_INVALIDARG; _JumpError(hr, error, "Missing SerialNumber"); }
cwc = SAFE_SUBTRACT_POINTERS(pwszSerialNumber, pwszConfig); pwszSerialNumber++; pwszConfig = (WCHAR *) LocalAlloc( LMEM_FIXED, (cwc + 1) * sizeof(WCHAR)); if (NULL == pwszConfig) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "LocalAlloc"); } CopyMemory(pwszConfig, strConfig, cwc * sizeof(WCHAR)); pwszConfig[cwc] = L'\0'; }
hr = _RequestCertificate( 0, // Flags
RequestId, NULL, // strRequest
pwszSerialNumber, // strAttributes
NULL, // pwszSerialNumber
pwszConfig, 1, // RequiredVersion
pDisposition); _JumpIfError(hr, error, "_RequestCertificate");
error: if (NULL != pwszConfig && strConfig != pwszConfig) { LocalFree(pwszConfig); } return(_SetErrorInfo(hr, L"CCertRequest::RetrievePending")); }
//+--------------------------------------------------------------------------
// CCertRequest::GetIssuedCertificate -- Get an issued Certificate
//
// Returns S_OK on success.
//+--------------------------------------------------------------------------
STDMETHODIMP CCertRequest::GetIssuedCertificate( /* [in] */ const BSTR strConfig, /* [in] */ LONG RequestId, /* [in] */ const BSTR strSerialNumber, // OPTIONAL
/* [out, retval] */ LONG __RPC_FAR *pDisposition) { HRESULT hr; WCHAR const *pwszSerialNumber = NULL;
if (NULL == pDisposition || NULL == strConfig) { hr = E_POINTER; _JumpError(hr, error, "NULL param"); }
// VB callers pass "" instead of NULL, so treat them identically.
if (NULL != strSerialNumber && L'\0' != *strSerialNumber) { pwszSerialNumber = strSerialNumber; } hr = _RequestCertificate( 0, // Flags
RequestId, NULL, // strRequest
NULL, // strAttributes
pwszSerialNumber, // pwszSerialNumber
strConfig, 2, // RequiredVersion
pDisposition); _JumpIfError(hr, error, "_RequestCertificate");
error: return(_SetErrorInfo(hr, L"CCertRequest::GetIssuedCertificate")); }
//+--------------------------------------------------------------------------
// CCertRequest::_RequestCertificate -- Submit the request
//
// Returns S_OK on success.
//+--------------------------------------------------------------------------
HRESULT CCertRequest::_RequestCertificate( IN LONG Flags, IN LONG RequestId, OPTIONAL IN BSTR const strRequest, OPTIONAL IN BSTR const strAttributes, OPTIONAL IN WCHAR const *pwszSerialNumber, IN BSTR const strConfig, IN DWORD RequiredVersion, OUT LONG *pDisposition) { HRESULT hr; WCHAR const *pwszAuthority; WCHAR *pwszAttrib = strAttributes; WCHAR *pwszAttribAlloc = NULL; BYTE *pbT = NULL; CERTTRANSBLOB ctbRequest = { 0, NULL }; CERTTRANSBLOB ctbCert = { 0, NULL }; CERTTRANSBLOB ctbCertChain = { 0, NULL }; CERTTRANSBLOB ctbFullResponse = { 0, NULL }; CERTTRANSBLOB ctbDispositionMessage = { 0, NULL }; DWORD adwEncode[] = { CR_IN_BASE64HEADER, CR_IN_BASE64, CR_IN_BINARY }; DWORD dwEncode; DWORD *pdwEncode; DWORD cEncode; WCHAR *pwszDnsName = NULL;
if (NULL == pDisposition) { hr = E_POINTER; _JumpError(hr, error, "NULL parm"); } _Cleanup(); *pDisposition = CR_DISP_INCOMPLETE;
hr = _OpenConnection( (CR_IN_RPC & Flags)? TRUE : FALSE, strConfig, RequiredVersion, &pwszAuthority); _JumpIfError(hr, error, "_OpenConnection");
// If a new request, point at the attributes & decode the Base64 request.
if (NULL != strRequest) { DWORD cchHeader; DWORD cwc; WCHAR *pch;
CSASSERT(CR_IN_BASE64HEADER == CRYPT_STRING_BASE64HEADER); CSASSERT(CR_IN_BASE64 == CRYPT_STRING_BASE64); CSASSERT(CR_IN_BINARY == CRYPT_STRING_BINARY);
hr = myGetMachineDnsName(&pwszDnsName); _JumpIfError(hr, error, "myGetMachineDnsName");
dwEncode = CR_IN_ENCODEMASK & Flags; switch (dwEncode) { case CR_IN_BASE64HEADER: case CR_IN_BASE64: case CR_IN_BINARY: cEncode = 1; pdwEncode = &dwEncode; break;
case CR_IN_ENCODEANY: cEncode = ARRAYSIZE(adwEncode); pdwEncode = adwEncode; break;
default: hr = E_INVALIDARG; _JumpError(hr, error, "Flags"); } while (TRUE) { hr = DecodeCertString( strRequest, *pdwEncode, &m_pbRequest, (DWORD *) &m_cbRequest); if (S_OK == hr) { Flags = (~CR_IN_ENCODEMASK & Flags) | *pdwEncode; break; } if (1 == cEncode || HRESULT_FROM_WIN32(ERROR_INVALID_DATA) != hr) { _JumpError(hr, error, "DecodeCertString"); } _PrintErrorStr2( hr, "DecodeCertString", L"CR_IN_ENCODEANY", HRESULT_FROM_WIN32(ERROR_INVALID_DATA)); cEncode--; pdwEncode++; } CSASSERT(0 < cEncode); CSASSERT(S_OK == hr);
ctbRequest.pb = m_pbRequest; ctbRequest.cb = m_cbRequest;
cchHeader = 0; if (CR_IN_BASE64HEADER == *pdwEncode) { DWORD cb;
hr = myCryptStringToBinary( strRequest, wcslen(strRequest), CRYPT_STRING_BASE64HEADER, &pbT, &cb, &cchHeader, NULL); if (S_OK != hr) { cchHeader = 0; } } cwc = cchHeader; if (NULL != pwszAttrib) { cwc += 1 + wcslen(pwszAttrib); } cwc += 1 + WSZARRAYSIZE(wszPROPCERTCLIENTMACHINE) + 1 + wcslen(pwszDnsName); pwszAttribAlloc = (WCHAR *) LocalAlloc( LMEM_FIXED, (cwc + 1) * sizeof(WCHAR)); if (NULL == pwszAttribAlloc) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "alloc attributes"); } pch = pwszAttribAlloc; if (0 != cchHeader) { CopyMemory(pch, strRequest, cchHeader * sizeof(WCHAR)); pch += cchHeader; } *pch = L'\0'; if (NULL != pwszAttrib) { *pch++ = L'\n'; wcscpy(pch, (WCHAR const *) pwszAttrib); } wcscat(pch, L"\n" wszPROPCERTCLIENTMACHINE L":"); wcscat(pch, pwszDnsName); CSASSERT(wcslen(pwszAttribAlloc) == cwc);
pwszAttrib = pwszAttribAlloc; } m_RequestId = RequestId;
__try { Flags |= CR_IN_FULLRESPONSE; if (NULL != m_hRPCCertServer) { CERTTRANSBLOB ctbAttrib; CERTTRANSBLOB ctbSerial;
ctbAttrib.cb = 0; ctbAttrib.pb = (BYTE *) pwszAttrib; if (NULL != pwszAttrib) { ctbAttrib.cb = (wcslen(pwszAttrib) + 1) * sizeof(WCHAR); }
ctbSerial.cb = 0; ctbSerial.pb = (BYTE *) pwszSerialNumber; if (NULL != pwszSerialNumber) { ctbAttrib.cb = (wcslen(pwszSerialNumber) + 1) * sizeof(WCHAR); }
hr = crCertServerRequest( m_hRPCCertServer, &m_rpcAuthProtocol, Flags, pwszAuthority, (DWORD *) &m_RequestId, (DWORD *) &m_Disposition, &ctbAttrib, &ctbSerial, &ctbRequest, &ctbCertChain, &ctbCert, &ctbDispositionMessage); _PrintIfError(hr, "crCertServerRequest"); } else { if (2 <= m_dwServerVersion) { hr = m_pICertRequestD->Request2( pwszAuthority, Flags, pwszSerialNumber, (DWORD *) &m_RequestId, (DWORD *) &m_Disposition, pwszAttrib, &ctbRequest, &ctbFullResponse, &ctbCert, &ctbDispositionMessage); _PrintIfError(hr, "m_pICertRequestD->Request2"); } else { Flags &= ~CR_IN_FULLRESPONSE; hr = m_pICertRequestD->Request( Flags, pwszAuthority, (DWORD *) &m_RequestId, (DWORD *) &m_Disposition, pwszAttrib, &ctbRequest, &ctbCertChain, &ctbCert, &ctbDispositionMessage); _PrintIfError(hr, "m_pICertRequestD->Request"); }
// Midl_user_allocate registers memory in RPC case
if (NULL != ctbCertChain.pb) { myRegisterMemAlloc( ctbCertChain.pb, ctbCertChain.cb, CSM_COTASKALLOC); } if (NULL != ctbFullResponse.pb) { myRegisterMemAlloc( ctbFullResponse.pb, ctbFullResponse.cb, CSM_COTASKALLOC); } if (NULL != ctbCert.pb) { myRegisterMemAlloc(ctbCert.pb, ctbCert.cb, CSM_COTASKALLOC); } if (NULL != ctbDispositionMessage.pb) { myRegisterMemAlloc( ctbDispositionMessage.pb, ctbDispositionMessage.cb, CSM_COTASKALLOC); } } } __except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER) { }
if (HRESULT_FROM_WIN32(RPC_X_WRONG_STUB_VERSION) == hr) { _PrintError(hr, "Compile with MIDL_NO_ROBUST=1 to run on NT 4"); }
m_LastStatus = hr; _JumpIfError(hr, error, "Request");
if (FAILED(m_Disposition)) { m_LastStatus = m_Disposition; m_Disposition = CR_DISP_DENIED; }
*pDisposition = m_Disposition; m_pbCertificateChain = ctbCertChain.pb; // CoTaskMem*
m_cbCertificateChain = ctbCertChain.cb; m_pbFullResponse = ctbFullResponse.pb; // CoTaskMem*
m_cbFullResponse = ctbFullResponse.cb; m_pbCert = ctbCert.pb; // CoTaskMem*
m_cbCert = ctbCert.cb; m_pwszDispositionMessage = (WCHAR *) ctbDispositionMessage.pb; // CoTaskMem*
CSASSERT(0 == (ctbDispositionMessage.cb & (sizeof(WCHAR) - 1))); CSASSERT( NULL == m_pwszDispositionMessage || L'\0' == m_pwszDispositionMessage[ctbDispositionMessage.cb/sizeof(WCHAR) - 1]);
if (S_OK == hr && NULL != ctbFullResponse.pb) { hr = ParseCMCResponse( m_pbFullResponse, m_cbFullResponse, &m_hStoreResponse, &m_rgResponse, &m_cResponse); #if 0 // When all Whistler servers are upgraded to return full responses...
if (S_OK != hr && NULL != m_hRPCCertServer) #else
if (S_OK != hr) #endif
{ // Must be an old RPC cert server that ignored CR_IN_FULLRESPONSE,
// and returned a PKCS7 chain instead.
CSASSERT(NULL == m_pbCertificateChain); m_pbCertificateChain = m_pbFullResponse; m_cbCertificateChain = m_cbFullResponse; m_pbFullResponse = NULL; m_cbFullResponse = 0; hr = S_OK; } _JumpIfError(hr, error, "ParseCMCResponse"); }
error: if (NULL != pwszDnsName) { LocalFree(pwszDnsName); } if (NULL != pwszAttribAlloc) { LocalFree(pwszAttribAlloc); } if (NULL != pbT) { LocalFree(pbT); } return(myHError(hr)); }
//+--------------------------------------------------------------------------
// CCertRequest::GetLastStatus -- Get the status of the last request
//
// One of the Submit, RetrievePending or GetCACertificate methods must
// have been previously called for the returned status to be meaningful.
//
// Returns S_OK on success.
//+--------------------------------------------------------------------------
STDMETHODIMP CCertRequest::GetLastStatus( /* [out, retval] */ LONG __RPC_FAR *pLastStatus) { HRESULT hr;
if (NULL == pLastStatus) { hr = E_POINTER; _JumpError(hr, error, "pLastStatus"); } *pLastStatus = m_LastStatus; hr = S_OK;
error: return(_SetErrorInfo(hr, L"CCertRequest::GetLastStatus")); }
//+--------------------------------------------------------------------------
// CCertRequest::GetRequestId -- Get the RequestId of the last request
//
// The Submit or RetrievePending method must have been previously called for
// the returned RequestId to be meaningful.
//
// Returns S_OK on success.
//+--------------------------------------------------------------------------
STDMETHODIMP CCertRequest::GetRequestId( /* [out, retval] */ LONG __RPC_FAR *pRequestId) { HRESULT hr;
if (NULL == pRequestId) { hr = E_POINTER; _JumpError(hr, error, "pRequestId"); } *pRequestId = m_RequestId; hr = S_OK;
error: return(_SetErrorInfo(hr, L"CCertRequest::GetRequestId")); }
//+--------------------------------------------------------------------------
// CCertRequest::GetDispositionMessage -- Get the Disposition Message
//
// The Submit or RetrievePending method must have been previously called for
// the returned disposition message text to be meaningful.
//
// Returns S_OK on success.
//+--------------------------------------------------------------------------
STDMETHODIMP CCertRequest::GetDispositionMessage( /* [out, retval] */ BSTR __RPC_FAR *pstrDispositionMessage) { HRESULT hr = S_OK;
if (NULL == pstrDispositionMessage) { hr = E_POINTER; _JumpError(hr, error, "pstrDispositionMessage"); } if (NULL != *pstrDispositionMessage) { SysFreeString(*pstrDispositionMessage); *pstrDispositionMessage = NULL; } if (NULL != m_pwszDispositionMessage) { if (!ConvertWszToBstr( pstrDispositionMessage, m_pwszDispositionMessage, -1)) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "ConvertWszToBstr"); } }
error: return(_SetErrorInfo(hr, L"CCertRequest::GetDispositionMessage")); }
//+--------------------------------------------------------------------------
// CCertRequest::_BuildIssuedCertificateChain -- Build issued cert chain
//
// Returns S_OK on success.
//+--------------------------------------------------------------------------
HRESULT CCertRequest::_BuildIssuedCertificateChain( OPTIONAL IN BYTE const *pbCertHash, IN DWORD cbCertHash, IN BOOL fIncludeCRLs, OUT BYTE **ppbCertChain, OUT DWORD *pcbCertChain) { HRESULT hr; CERT_CONTEXT const *pccIssued = NULL; CERT_CHAIN_PARA CertChainPara; CERT_CHAIN_CONTEXT const *pCertChainContext = NULL; CERT_SIMPLE_CHAIN *pSimpleChain; CRYPT_SIGN_MESSAGE_PARA csmp; CRYPT_ALGORITHM_IDENTIFIER DigestAlgorithm = { szOID_OIWSEC_sha1, 0, 0 }; CERT_CONTEXT const **ppcc; CRL_CONTEXT const **ppCRL; DWORD i;
*ppbCertChain = NULL;
// init csmp for empty signature
ZeroMemory(&csmp, sizeof(csmp)); csmp.cbSize = sizeof(csmp); csmp.dwMsgEncodingType = PKCS_7_ASN_ENCODING; //csmp.pSigningCert = NULL;
csmp.HashAlgorithm = DigestAlgorithm; //csmp.cMsgCert = 0;
//csmp.rgpMsgCert = NULL;
//csmp.cMsgCrl = 0;
//csmp.rgpMsgCrl = NULL;
hr = _FindIssuedCertificate(pbCertHash, cbCertHash, &pccIssued); _JumpIfError(hr, error, "_FindIssuedCertificate");
// build the user cert chain
ZeroMemory(&CertChainPara, sizeof(CertChainPara)); CertChainPara.cbSize = sizeof(CertChainPara);
if (!CertGetCertificateChain( HCCE_LOCAL_MACHINE, pccIssued, NULL, // pTime
m_hStoreResponse, &CertChainPara, fIncludeCRLs? (CERT_CHAIN_REVOCATION_CHECK_END_CERT | CERT_CHAIN_REVOCATION_CHECK_CHAIN) : 0, NULL, // pvReserved
&pCertChainContext)) { hr = myHLastError(); _JumpError(hr, error, "CertGetCertificateChain"); }
// make sure there is at least 1 simple chain
if (0 == pCertChainContext->cChain) { hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA); _JumpError(hr, error, "No user chain"); } pSimpleChain = pCertChainContext->rgpChain[0];
csmp.cMsgCert = pSimpleChain->cElement; if (0 == csmp.cMsgCert) { hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA); _JumpError(hr, error, "no certs"); }
csmp.rgpMsgCert = (CERT_CONTEXT const **) LocalAlloc( LMEM_FIXED, csmp.cMsgCert * sizeof(csmp.rgpMsgCert[0])); if (NULL == csmp.rgpMsgCert) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "LocalAlloc"); }
if (fIncludeCRLs) { csmp.rgpMsgCrl = (CRL_CONTEXT const **) LocalAlloc( LMEM_FIXED, 2 * csmp.cMsgCert * sizeof(csmp.rgpMsgCrl[0])); if (NULL == csmp.rgpMsgCrl) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "LocalAlloc"); } }
ppcc = csmp.rgpMsgCert; for (i = 0; i < csmp.cMsgCert; i++) { *ppcc++ = pSimpleChain->rgpElement[i]->pCertContext; if (fIncludeCRLs) { CERT_REVOCATION_INFO *pRevocationInfo;
pRevocationInfo = pSimpleChain->rgpElement[i]->pRevocationInfo;
if (NULL != pRevocationInfo && CCSIZEOF_STRUCT(CERT_REVOCATION_INFO, pCrlInfo) <= pRevocationInfo->cbSize && NULL != pRevocationInfo->pCrlInfo) { CERT_REVOCATION_CRL_INFO *pCrlInfo;
pCrlInfo = pRevocationInfo->pCrlInfo; if (NULL != pCrlInfo) { if (NULL != pCrlInfo->pBaseCrlContext) { csmp.rgpMsgCrl[csmp.cMsgCrl++] = pCrlInfo->pBaseCrlContext; } if (NULL != pCrlInfo->pDeltaCrlContext) { csmp.rgpMsgCrl[csmp.cMsgCrl++] = pCrlInfo->pDeltaCrlContext; } } } } } CSASSERT(csmp.cMsgCrl <= 2 * csmp.cMsgCert);
if (!myCryptSignMessage( &csmp, pccIssued->pbCertEncoded, pccIssued->cbCertEncoded, CERTLIB_USE_LOCALALLOC, ppbCertChain, pcbCertChain)) { hr = myHLastError(); _JumpError(hr, error, "myCryptSignMessage"); } hr = S_OK;
error: if (NULL != csmp.rgpMsgCert) { LocalFree(csmp.rgpMsgCert); } if (NULL != csmp.rgpMsgCrl) { LocalFree(csmp.rgpMsgCrl); } if (NULL != pccIssued) { CertFreeCertificateContext(pccIssued); } return(hr); }
//+--------------------------------------------------------------------------
// CCertRequest::_FindIssuedCertificate -- Find Issued cert in store.
//
// Returns S_OK on success.
//+--------------------------------------------------------------------------
HRESULT CCertRequest::_FindIssuedCertificate( OPTIONAL IN BYTE const *pbCertHash, IN DWORD cbCertHash, OUT CERT_CONTEXT const **ppccIssued) { HRESULT hr; CRYPT_HASH_BLOB BlobHash;
*ppccIssued = NULL;
if (NULL == pbCertHash) { if (1 < m_cResponse || NULL == m_pbCert) { hr = CERTSRV_E_PROPERTY_EMPTY; _JumpError(hr, error, "no cert"); } *ppccIssued = CertCreateCertificateContext( X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, m_pbCert, m_cbCert); if (NULL == *ppccIssued) { hr = myHLastError(); _JumpError(hr, error, "CertCreateCertificateContext"); } } else { BlobHash.pbData = const_cast<BYTE *>(pbCertHash); BlobHash.cbData = cbCertHash;
*ppccIssued = CertFindCertificateInStore( m_hStoreResponse, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0, // dwFindFlags
CERT_FIND_HASH, &BlobHash, // pvFindPara
NULL); // pPrevCertContext
if (NULL == *ppccIssued) { hr = myHLastError(); _JumpError(hr, error, "CertFindCertificateInStore"); } } hr = S_OK;
error: return(hr); }
//+--------------------------------------------------------------------------
// CCertRequest::GetCertificate -- Get the Certificate encoding as requested
//
// The Submit or RetrievePending method must have previously returned
// CR_DISP_ISSUED, or this method will fail.
//
// Returns S_OK on success.
//+--------------------------------------------------------------------------
STDMETHODIMP CCertRequest::GetCertificate( /* [in] */ LONG Flags, /* [out, retval] */ BSTR __RPC_FAR *pstrCertificate) { HRESULT hr; BYTE *pbChain = NULL; DWORD cbChain; BYTE *pbCert; DWORD cbCert;
if (NULL == pstrCertificate) { hr = E_POINTER; _JumpError(hr, error, "pstrCertificate"); } pbCert = m_pbCert; cbCert = m_cbCert; if (CR_OUT_CHAIN & Flags) { pbCert = m_pbCertificateChain; cbCert = m_cbCertificateChain; if (NULL == m_pbCertificateChain) { hr = _BuildIssuedCertificateChain( NULL, // pbCertHash
0, // cbCertHash
0 != (CR_OUT_CRLS & Flags), &pbChain, &cbChain); _JumpIfError(hr, error, "_BuildIssuedCertificateChain");
pbCert = pbChain; cbCert = cbChain; } }
CSASSERT(CR_OUT_BASE64HEADER == CRYPT_STRING_BASE64HEADER); CSASSERT(CR_OUT_BASE64 == CRYPT_STRING_BASE64); CSASSERT(CR_OUT_BINARY == CRYPT_STRING_BINARY);
hr = EncodeCertString( pbCert, cbCert, ~(CR_OUT_CHAIN | CR_OUT_CRLS) & Flags, pstrCertificate); _JumpIfError(hr, error, "EncodeCertString");
error: if (NULL != pbChain) { LocalFree(pbChain); } hr = myHError(hr); return(_SetErrorInfo(hr, L"CCertRequest::GetCertificate")); }
//+--------------------------------------------------------------------------
// CCertRequest::GetCACertificate -- Get the specified CA Certificate
//
// Interrogate the Certificate Server and retrieve the base64-encoded exchange
// or signature site certificate as indicated by fExchangeCertificate.
//
// All state from previous method calls is cleared.
//
// After the GetCACertificate method completes execution, the GetLastStatus
// method may be called to retrieve a more specific error code.
//
// fExchangeCertificate is TRUE to retrieve the Certificate Server's Exchange
// certificate. fExchangeCertificate is FALSE to retrieve the Certificate
// Server's Signature site certificate.
//
// Returns S_OK on success.
//+--------------------------------------------------------------------------
STDMETHODIMP CCertRequest::GetCACertificate( /* [in] */ LONG fExchangeCertificate, /* [in] */ BSTR const strConfig, /* [in] */ LONG Flags, /* [out, retval] */ BSTR __RPC_FAR *pstrCACertificate) { HRESULT hr; CERTTRANSBLOB ctbSite = { 0, NULL }; WCHAR const *pwszAuthority; WCHAR const *pwszOut = NULL; CAINFO const *pCAInfo; BYTE *pbOut; BOOL fCallServer; DWORD Index; WCHAR wszBuf[5 * (10 + 1)]; // enough for 5 numbers
if (NULL == pstrCACertificate) { hr = E_POINTER; _JumpError(hr, error, "pstrCACertificate"); }
fCallServer = TRUE; switch (fExchangeCertificate) { case GETCERT_ERRORTEXT1: case GETCERT_ERRORTEXT2: pwszOut = myGetErrorMessageText( Flags, // error code passed in Flags parm
GETCERT_ERRORTEXT2 == fExchangeCertificate); if (NULL == pwszOut) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "LocalAlloc"); } Flags = CR_OUT_BINARY; pbOut = (BYTE *) pwszOut; fCallServer = FALSE; break; } switch (GETCERT_BYINDEXMASK & fExchangeCertificate) { case GETCERT_CACERTSTATEBYINDEX: case GETCERT_CRLSTATEBYINDEX: if (CR_OUT_CHAIN & Flags) { hr = E_INVALIDARG; _JumpError(hr, error, "Flags"); } Index = GETCERT_INDEXVALUEMASK & fExchangeCertificate; fExchangeCertificate &= ~GETCERT_INDEXVALUEMASK;
fCallServer = NULL == ((GETCERT_CACERTSTATEBYINDEX == fExchangeCertificate)? m_pbCACertState : m_pbCRLState); break; } if (fCallServer) { hr = _OpenConnection(FALSE, strConfig, 1, &pwszAuthority); _JumpIfError(hr, error, "_OpenConnection");
if (CR_OUT_CHAIN & Flags) { fExchangeCertificate |= GETCERT_CHAIN; if (CR_OUT_CRLS & Flags) { fExchangeCertificate |= GETCERT_CRLS; } }
__try { hr = m_pICertRequestD->GetCACert( fExchangeCertificate, pwszAuthority, &ctbSite); } __except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER) { } _JumpIfError2( hr, error, "GetCACert", HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND));
// must register this memory
myRegisterMemAlloc(ctbSite.pb, ctbSite.cb, CSM_COTASKALLOC); pbOut = ctbSite.pb; }
CSASSERT(CR_OUT_BASE64HEADER == CRYPT_STRING_BASE64HEADER); CSASSERT(CR_OUT_BASE64 == CRYPT_STRING_BASE64); CSASSERT(CR_OUT_BINARY == CRYPT_STRING_BINARY);
switch (fExchangeCertificate) { // Serialize CAType into a string:
case GETCERT_CATYPE: wsprintf(wszBuf, L"%u", *(ENUM_CATYPES const *) pbOut); pwszOut = wszBuf; pbOut = (BYTE *) pwszOut; break;
// Serialize CAInfo into a string:
case GETCERT_CAINFO: pCAInfo = (CAINFO const *) pbOut; if (CCSIZEOF_STRUCT(CAINFO, cCASignatureCerts) > pCAInfo->cbSize) { hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA); _JumpError(hr, error, "CAINFO size"); } wsprintf( wszBuf, L"%u,%u", pCAInfo->CAType, pCAInfo->cCASignatureCerts); pwszOut = wszBuf; pbOut = (BYTE *) pwszOut; break;
case GETCERT_CACERTSTATEBYINDEX: case GETCERT_CRLSTATEBYINDEX: { BYTE **ppb; DWORD *pcb; if (GETCERT_CACERTSTATEBYINDEX == fExchangeCertificate) { ppb = &m_pbCACertState; pcb = &m_cbCACertState; } else { ppb = &m_pbCRLState; pcb = &m_cbCRLState; } if (fCallServer) { CSASSERT(NULL == *ppb); CSASSERT(NULL != ctbSite.pb); *pcb = ctbSite.cb; *ppb = ctbSite.pb; ctbSite.pb = NULL; } if (Index >= *pcb) { hr = E_INVALIDARG; _JumpError(hr, error, "Index"); } wsprintf(wszBuf, L"%u", (*ppb)[Index]); pwszOut = wszBuf; pbOut = (BYTE *) pwszOut; break; }
// If retrieving a CRL in Base64, use "-----BEGIN X509 CRL..."
default: if (GETCERT_CRLBYINDEX != (GETCERT_BYINDEXMASK & fExchangeCertificate)) { break; } // FALLTHROUGH
case GETCERT_CURRENTCRL: if (CR_OUT_BASE64HEADER == (~CR_OUT_CHAIN & Flags)) { Flags = CRYPT_STRING_BASE64X509CRLHEADER; } break; } hr = EncodeCertString( pbOut, pbOut == (BYTE *) pwszOut? wcslen(pwszOut) * sizeof(WCHAR) : ctbSite.cb, ~CR_OUT_CHAIN & Flags, pstrCACertificate); _JumpIfError(hr, error, "EncodeCertString");
error: m_LastStatus = hr; if (NULL != pwszOut && wszBuf != pwszOut) { LocalFree(const_cast<WCHAR *>(pwszOut)); } if (NULL != ctbSite.pb) { CoTaskMemFree(ctbSite.pb); } return(_SetErrorInfo(hr, L"CCertRequest::GetCACertificate")); }
//+--------------------------------------------------------------------------
// CCertRequest::GetErrorMessageText -- Get error message text
//
// Returns S_OK on success.
//+--------------------------------------------------------------------------
STDMETHODIMP CCertRequest::GetErrorMessageText( /* [in] */ LONG hrMessage, /* [in] */ LONG Flags, /* [out, retval] */ BSTR __RPC_FAR *pstrErrorMessageText) { HRESULT hr; WCHAR const *pwszError = NULL;
if (~CR_GEMT_HRESULT_STRING & Flags) { hr = E_INVALIDARG; _JumpError(hr, error, "not CR_IN_BINARY"); }
pwszError = myGetErrorMessageText( hrMessage, 0 != (CR_GEMT_HRESULT_STRING & Flags)); if (NULL == pwszError) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "LocalAlloc"); } if (!ConvertWszToBstr( pstrErrorMessageText, pwszError, -1)) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "ConvertWszToBstr"); } hr = S_OK;
error: if (NULL != pwszError) { LocalFree(const_cast<WCHAR *>(pwszError)); } return(_SetErrorInfo(hr, L"CCertRequest::GetErrorMessageText")); }
// for ICertRequest2::GetFullResponseProperty
CAPROP s_aFRProp[] = { { FR_PROP_FULLRESPONSE, PROPTYPE_BINARY, }, { FR_PROP_FULLRESPONSENOPKCS7, PROPTYPE_BINARY, }, { FR_PROP_STATUSINFOCOUNT, PROPTYPE_LONG, }, { FR_PROP_BODYPARTSTRING, PROPTYPE_STRING | PROPFLAGS_INDEXED, }, { FR_PROP_STATUS, PROPTYPE_LONG | PROPFLAGS_INDEXED, }, { FR_PROP_STATUSSTRING, PROPTYPE_STRING | PROPFLAGS_INDEXED, }, { FR_PROP_OTHERINFOCHOICE, PROPTYPE_LONG | PROPFLAGS_INDEXED, }, { FR_PROP_FAILINFO, PROPTYPE_LONG | PROPFLAGS_INDEXED, }, { FR_PROP_PENDINFOTOKEN, PROPTYPE_BINARY | PROPFLAGS_INDEXED, }, { FR_PROP_PENDINFOTIME, PROPTYPE_DATE | PROPFLAGS_INDEXED, }, { FR_PROP_ISSUEDCERTIFICATEHASH, PROPTYPE_BINARY | PROPFLAGS_INDEXED, }, { FR_PROP_ISSUEDCERTIFICATE, PROPTYPE_BINARY | PROPFLAGS_INDEXED, }, { FR_PROP_ISSUEDCERTIFICATECHAIN, PROPTYPE_BINARY | PROPFLAGS_INDEXED, }, { FR_PROP_ISSUEDCERTIFICATECRLCHAIN, PROPTYPE_BINARY | PROPFLAGS_INDEXED, }, { FR_PROP_ENCRYPTEDKEYHASH, PROPTYPE_BINARY | PROPFLAGS_INDEXED, }, };
//+--------------------------------------------------------------------------
// CCertRequest::GetFullResponseProperty -- Get CMC Response property
//
// Returns S_OK on success.
//+--------------------------------------------------------------------------
STDMETHODIMP CCertRequest::GetFullResponseProperty( /* [in] */ LONG PropId, // FR_PROP_*
/* [in] */ LONG PropIndex, /* [in] */ LONG PropType, // PROPTYPE_*
/* [in] */ LONG Flags, // CR_OUT_*
/* [out, retval] */ VARIANT *pvarPropertyValue) { HRESULT hr; DWORD i; BYTE const *pbOut; WCHAR const *pwszOut; DWORD cbOut; DWORD dw; XCMCRESPONSE *pResponse = NULL; CERT_CONTEXT const *pccIssued = NULL; BYTE *pbChain = NULL; DWORD cbChain;
if (NULL == pvarPropertyValue) { hr = E_POINTER; _JumpError(hr, error, "NULL parm"); } VariantInit(pvarPropertyValue);
hr = E_INVALIDARG; for (i = 0; PropId != s_aFRProp[i].lPropId; i++) { if (i >= ARRAYSIZE(s_aFRProp)) { _JumpError(hr, error, "PropId"); } } if ((PROPTYPE_MASK & s_aFRProp[i].lPropFlags) != PropType) { _JumpError(hr, error, "PropType"); } if (PROPFLAGS_INDEXED & s_aFRProp[i].lPropFlags) { if ((DWORD) PropIndex >= m_cResponse) { _JumpError(hr, error, "PropIndex"); } pResponse = &m_rgResponse[PropIndex]; } else if (0 != PropIndex) { _JumpError(hr, error, "non-zero PropIndex"); }
pbOut = NULL; pwszOut = NULL; switch (PropId) { case FR_PROP_FULLRESPONSE: case FR_PROP_FULLRESPONSENOPKCS7: pbOut = m_pbFullResponse; cbOut = m_cbFullResponse; if (NULL == pbOut && FR_PROP_FULLRESPONSE == PropId) { pbOut = m_pbCertificateChain; cbOut = m_cbCertificateChain; } break;
case FR_PROP_STATUSINFOCOUNT: pbOut = (BYTE const *) &m_cResponse; cbOut = sizeof(m_cResponse); break;
case FR_PROP_BODYPARTSTRING: if (pResponse == NULL) { hr = E_POINTER; _JumpError(hr, error, "Bad switch setup: NULL pResponse"); } pwszOut = pResponse->pwszBodyPart; break;
case FR_PROP_STATUS: if (pResponse == NULL) { hr = E_POINTER; _JumpError(hr, error, "Bad switch setup: NULL pResponse"); } pbOut = (BYTE const *) &pResponse->StatusInfo.dwStatus; cbOut = sizeof(pResponse->StatusInfo.dwStatus); break;
case FR_PROP_STATUSSTRING: if (pResponse == NULL) { hr = E_POINTER; _JumpError(hr, error, "Bad switch setup: NULL pResponse"); } pwszOut = pResponse->StatusInfo.pwszStatusString; break;
case FR_PROP_OTHERINFOCHOICE: if (pResponse == NULL) { hr = E_POINTER; _JumpError(hr, error, "Bad switch setup: NULL pResponse"); } pbOut = (BYTE const *) &pResponse->StatusInfo.dwOtherInfoChoice; cbOut = sizeof(pResponse->StatusInfo.dwOtherInfoChoice); break;
case FR_PROP_FAILINFO: if (pResponse == NULL) { hr = E_POINTER; _JumpError(hr, error, "Bad switch setup: NULL pResponse"); } if (CMC_OTHER_INFO_FAIL_CHOICE == pResponse->StatusInfo.dwOtherInfoChoice) { pbOut = (BYTE const *) &pResponse->StatusInfo.dwFailInfo; cbOut = sizeof(pResponse->StatusInfo.dwFailInfo); } break;
case FR_PROP_PENDINFOTOKEN: if (pResponse == NULL) { hr = E_POINTER; _JumpError(hr, error, "Bad switch setup: NULL pResponse"); } if (CMC_OTHER_INFO_PEND_CHOICE == pResponse->StatusInfo.dwOtherInfoChoice) { pbOut = (BYTE const *) &dw; cbOut = sizeof(dw); pbOut = pResponse->StatusInfo.pPendInfo->PendToken.pbData; cbOut = pResponse->StatusInfo.pPendInfo->PendToken.cbData; } break;
case FR_PROP_PENDINFOTIME: if (pResponse == NULL) { hr = E_POINTER; _JumpError(hr, error, "Bad switch setup: NULL pResponse"); } if (CMC_OTHER_INFO_PEND_CHOICE == pResponse->StatusInfo.dwOtherInfoChoice) { pbOut = (BYTE const *) &pResponse->StatusInfo.pPendInfo->PendTime; cbOut = sizeof(pResponse->StatusInfo.pPendInfo->PendTime); } break;
case FR_PROP_ISSUEDCERTIFICATEHASH: if (pResponse == NULL) { hr = E_POINTER; _JumpError(hr, error, "Bad switch setup: NULL pResponse"); } pbOut = pResponse->pbCertHash; cbOut = pResponse->cbCertHash; break;
case FR_PROP_ENCRYPTEDKEYHASH: if (pResponse == NULL) { hr = E_POINTER; _JumpError(hr, error, "Bad switch setup: NULL pResponse"); } pbOut = pResponse->pbEncryptedKeyHash; cbOut = pResponse->cbEncryptedKeyHash; break;
case FR_PROP_ISSUEDCERTIFICATE: if (pResponse == NULL) { hr = E_POINTER; _JumpError(hr, error, "Bad switch setup: NULL pResponse"); } hr = _FindIssuedCertificate( pResponse->pbCertHash, pResponse->cbCertHash, &pccIssued); _JumpIfError(hr, error, "_FindIssuedCertificate");
pbOut = pccIssued->pbCertEncoded; cbOut = pccIssued->cbCertEncoded; break;
case FR_PROP_ISSUEDCERTIFICATECHAIN: case FR_PROP_ISSUEDCERTIFICATECRLCHAIN: if (pResponse == NULL) { hr = E_POINTER; _JumpError(hr, error, "Bad switch setup: NULL pResponse"); } hr = _BuildIssuedCertificateChain( pResponse->pbCertHash, pResponse->cbCertHash, FR_PROP_ISSUEDCERTIFICATECRLCHAIN == PropId || 0 != (CR_OUT_CRLS & Flags), &pbChain, &cbChain); _JumpIfError(hr, error, "_BuildIssuedCertificateChain");
pbOut = pbChain; cbOut = cbChain; break; } if (NULL != pwszOut) { pbOut = (BYTE const *) pwszOut; cbOut = (wcslen(pwszOut) + 1) * sizeof(WCHAR); } if (NULL == pbOut || 0 == cbOut) { hr = CERTSRV_E_PROPERTY_EMPTY; _JumpError2(hr, error, "Empty", CERTSRV_E_PROPERTY_EMPTY); } __try { hr = myUnmarshalFormattedVariant( Flags, CR_PROP_CASIGCERT, PropType, cbOut, pbOut, pvarPropertyValue); } __except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER) { } _JumpIfError(hr, error, "myUnmarshalFormattedVariant");
error: if (NULL != pccIssued) { CertFreeCertificateContext(pccIssued); } if (S_OK != hr && NULL != pvarPropertyValue) { VariantClear(pvarPropertyValue); } if (NULL != pbChain) { LocalFree(pbChain); } return(_SetErrorInfo(hr, L"CCertRequest::GetFullResponseProperty")); }
#define CCERTREQUEST
#include "csprop2.cpp"
HRESULT CCertRequest::_SetErrorInfo( IN HRESULT hrError, IN WCHAR const *pwszDescription) { CSASSERT(FAILED(hrError) || S_OK == hrError || S_FALSE == hrError); if (FAILED(hrError)) { HRESULT hr;
hr = DispatchSetErrorInfo( hrError, pwszDescription, wszCLASS_CERTREQUEST, &IID_ICertRequest); CSASSERT(hr == hrError); } return(hrError); }
VOID crRPCTimeoutCallback( IN OUT VOID *pVoid, IN BOOLEAN fTimeout) {
PRPC_TIMEOUT_CONTEXT pTimeout = (RPC_TIMEOUT_CONTEXT *) pVoid;
if(fTimeout) { RpcCancelThreadEx(pTimeout->hThread, CR_RPC_CANCEL_TIMEOUT); pTimeout->hrRpcError = RPC_E_TIMEOUT; }
}
HRESULT crRegisterRPCCallTimeout( IN DWORD dwMilliseconds, OUT PRPC_TIMEOUT_CONTEXT pTimeout) { HRESULT hr = S_OK;
pTimeout->hrRpcError = RPC_S_CALL_CANCELLED;
if (!DuplicateHandle( GetCurrentProcess(), // hSourceProcessHandle
GetCurrentThread(), // hSourceHandle
GetCurrentProcess(), // hTargetProcessHandle
&pTimeout->hThread, // lpTargetHandle
0, // dwDesiredAccess
FALSE, // bInheritHandle
DUPLICATE_SAME_ACCESS)) // dwOptions
{ hr = myHLastError(); _JumpError(hr, error, "DuplicateHandle"); }
pTimeout->hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); if(pTimeout->hEvent == NULL) { hr = myHLastError(); _JumpError(hr, error, "CreateEvent"); }
if (!RegisterWaitForSingleObject(&pTimeout->hWait, pTimeout->hEvent, crRPCTimeoutCallback, (PVOID)pTimeout , dwMilliseconds, WT_EXECUTEONLYONCE)) { hr = myHLastError(); _JumpError(hr, error, "RegisterWaitForSingleObject"); }
error: if (S_OK != hr) { crCloseRPCCallTimeout(pTimeout); } return hr;
}
HRESULT crCloseRPCCallTimeout( IN PRPC_TIMEOUT_CONTEXT pTimeout) { if(pTimeout->hWait) { UnregisterWait(pTimeout->hWait); pTimeout->hWait = NULL; }
if(pTimeout->hEvent) { CloseHandle(pTimeout->hEvent); pTimeout->hEvent = NULL; }
if(pTimeout->hThread) { CloseHandle(pTimeout->hThread); pTimeout->hThread = NULL; }
return S_OK; }
|