//+-------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1996-1998 // // copied from K2 SDK policy.cpp. // modified by GregKr for expolicy. // // File: expolicy.cpp // // Contents: KMS-specific Cert Server Policy Module implementation // //--------------------------------------------------------------------------- #include "pch.cpp" #pragma hdrstop #include "policy.h" #include "celib.h" //#include "newcert.h" #include #include // Exchange build version (rmj et al) #include // strings used by both KMS and ExPolicy #ifndef DBG_CERTSRV #error -- DBG_CERTSRV not defined! #endif BOOL fDebug = DBG_CERTSRV; #if DBG_CERTSRV #define EXP_FLAVOR L" debug" #else #define EXP_FLAVOR #endif #define MAKEFILEVERSION(_rmaj, _rmin, _bmaj, _bmin) \ L#_rmaj L"." L#_rmin L"." L#_bmaj L"." L#_bmin EXP_FLAVOR #define MAKE_FILEVERSION_STR(_rmaj, _rmin, _bmaj, _bmin) \ MAKEFILEVERSION(_rmaj, _rmin, _bmaj, _bmin) #define VER_FILEVERSION_STR \ MAKE_FILEVERSION_STR(rmj, rmn, rmm, rup) const WCHAR g_wszDescription[] = L"Microsoft Exchange KMServer Policy Module " VER_FILEVERSION_STR; // worker HRESULT GetServerCallbackInterface( OUT ICertServerPolicy **ppServer, IN LONG Context) { HRESULT hr; if (NULL == ppServer) { hr = E_POINTER; _JumpError(hr, error, "NULL parm"); } hr = CoCreateInstance( CLSID_CCertServerPolicy, NULL, // pUnkOuter CLSCTX_INPROC_SERVER, IID_ICertServerPolicy, (VOID **) ppServer); _JumpIfError(hr, error, "CoCreateInstance"); if (*ppServer == NULL) { hr = E_UNEXPECTED; _JumpError(hr, error, "NULL *ppServer"); } // only set context if nonzero if (0 != Context) { hr = (*ppServer)->SetContext(Context); _JumpIfError(hr, error, "Policy:SetContext"); } error: return(hr); } WCHAR const * const s_rgpwszRegMultiStrValues[] = { wszREGLDAPISSUERCERTURL_OLD, wszREGISSUERCERTURL_OLD, wszREGFTPISSUERCERTURL_OLD, wszREGFILEISSUERCERTURL_OLD, wszREGLDAPREVOCATIONCRLURL_OLD, wszREGREVOCATIONCRLURL_OLD, wszREGFTPREVOCATIONCRLURL_OLD, wszREGFILEREVOCATIONCRLURL_OLD, }; typedef struct _REGDWORDVALUE { WCHAR const *pwszName; DWORD dwValueDefault; } REGDWORDVALUE; const REGDWORDVALUE s_rgRegDWordValues[] = { { wszREGREQUESTDISPOSITION, REQDISP_ISSUE }, { wszREGISSUERCERTURLFLAGS, ISSCERT_ENABLE | ISSCERT_LDAPURL_OLD | ISSCERT_HTTPURL_OLD | ISSCERT_FTPURL_OLD | ISSCERT_FILEURL_OLD }, { wszREGREVOCATIONTYPE, REVEXT_CDPENABLE | REVEXT_CDPLDAPURL_OLD | REVEXT_CDPHTTPURL_OLD | REVEXT_CDPFTPURL_OLD | REVEXT_CDPFILEURL_OLD }, }; HRESULT CopyMultiStrRegValue( IN HKEY hkeySrc, IN HKEY hkeyDest, IN WCHAR const *pwszName) { HRESULT hr; DWORD cbValue; DWORD dwType; WCHAR *pwszzAlloc = NULL; WCHAR *pwszzValue; hr = RegQueryValueEx(hkeyDest, pwszName, NULL, &dwType, NULL, &cbValue); if (S_OK == hr && REG_MULTI_SZ == dwType) { goto error; // preserve existing value } hr = RegQueryValueEx(hkeySrc, pwszName, NULL, &dwType, NULL, &cbValue); if (S_OK == hr && REG_MULTI_SZ == dwType && sizeof(WCHAR) < cbValue) { pwszzAlloc = (WCHAR *) LocalAlloc(LMEM_FIXED, cbValue); if (NULL == pwszzAlloc) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "LocalAlloc"); } hr = RegQueryValueEx( hkeySrc, pwszName, NULL, &dwType, (BYTE *) pwszzAlloc, &cbValue); _JumpIfError(hr, error, "RegQueryValueEx"); pwszzValue = pwszzAlloc; } else { pwszzValue = L"\0"; cbValue = 2 * sizeof(WCHAR); } hr = RegSetValueEx( hkeyDest, pwszName, NULL, REG_MULTI_SZ, (BYTE const *) pwszzValue, cbValue); _JumpIfError(hr, error, "RegSetValueEx"); error: if (NULL != pwszzAlloc) { LocalFree(pwszzAlloc); } return(ceHError(hr)); } HRESULT CopyDWordRegValue( IN HKEY hkeySrc, IN HKEY hkeyDest, IN REGDWORDVALUE const *prdv) { HRESULT hr; DWORD cbValue; DWORD dwType; DWORD dwValue; hr = RegQueryValueEx(hkeyDest, prdv->pwszName, NULL, &dwType, NULL, &cbValue); if (S_OK == hr && REG_DWORD == dwType) { goto error; // preserve existing value } cbValue = sizeof(dwValue); hr = RegQueryValueEx( hkeySrc, prdv->pwszName, NULL, &dwType, (BYTE *) &dwValue, &cbValue); if (S_OK != hr || REG_DWORD != dwType || sizeof(dwValue) != cbValue) { dwValue = prdv->dwValueDefault; } hr = RegSetValueEx( hkeyDest, prdv->pwszName, NULL, REG_DWORD, (BYTE const *) &dwValue, sizeof(dwValue)); _JumpIfError(hr, error, "RegSetValueEx"); error: return(ceHError(hr)); } HRESULT PopulateRegistryDefaults( OPTIONAL IN WCHAR const *pwszMachine, IN WCHAR const *pwszStorageLocation) { HRESULT hr; HRESULT hr2; HKEY hkeyHKLM = NULL; HKEY hkeyDest = NULL; HKEY hkeySrc = NULL; DWORD dwDisposition; WCHAR const *pwsz; WCHAR *pwszSrc = NULL; DWORD cwcPrefix; DWORD cwc; DWORD i; DBGPRINT((TRUE, "pwszDest: '%ws'\n", pwszStorageLocation)); pwsz = wcsrchr(pwszStorageLocation, L'\\'); if (NULL == pwsz) { hr = E_INVALIDARG; _JumpError(hr, error, "Invalid registry path"); } pwsz++; cwcPrefix = SAFE_SUBTRACT_POINTERS(pwsz, pwszStorageLocation); cwc = cwcPrefix + WSZARRAYSIZE(wszCLASS_CERTPOLICY); pwszSrc = (WCHAR *) LocalAlloc(LMEM_FIXED, (cwc + 1) * sizeof(WCHAR)); if (NULL == pwszSrc) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "LocalAlloc"); } CopyMemory(pwszSrc, pwszStorageLocation, cwcPrefix * sizeof(WCHAR)); wcscpy(&pwszSrc[cwcPrefix], wszCLASS_CERTPOLICY); assert(wcslen(pwszSrc) == cwc); DBGPRINT((TRUE, "pwszSrc: '%ws'\n", pwszSrc)); if (NULL != pwszMachine) { hr = RegConnectRegistry( pwszMachine, HKEY_LOCAL_MACHINE, &hkeyHKLM); _JumpIfError(hr, error, "RegConnectRegistry"); } // open destination storage location for write hr = RegCreateKeyEx( NULL == pwszMachine? HKEY_LOCAL_MACHINE : hkeyHKLM, pwszStorageLocation, 0, NULL, 0, KEY_READ | KEY_WRITE, NULL, &hkeyDest, &dwDisposition); if (hr != S_OK) { _JumpError(hr, error, "RegOpenKeyEx"); } // open source storage location for read hr = RegOpenKeyEx( NULL == pwszMachine? HKEY_LOCAL_MACHINE : hkeyHKLM, pwszSrc, 0, KEY_READ, &hkeySrc); _JumpIfError(hr, error, "RegOpenKeyEx"); hr = S_OK; for (i = 0; i < ARRAYSIZE(s_rgpwszRegMultiStrValues); i++) { hr2 = CopyMultiStrRegValue( hkeySrc, hkeyDest, s_rgpwszRegMultiStrValues[i]); if (S_OK != hr2) { _PrintErrorStr( hr2, "CopyMultiStrRegValue", s_rgpwszRegMultiStrValues[i]); if (S_OK == hr) { hr = hr2; } } } for (i = 0; i < ARRAYSIZE(s_rgRegDWordValues); i++) { hr2 = CopyDWordRegValue( hkeySrc, hkeyDest, &s_rgRegDWordValues[i]); if (S_OK != hr2) { _PrintErrorStr( hr2, "CopyDWordRegValue", s_rgRegDWordValues[i].pwszName); if (S_OK == hr) { hr = hr2; } } } error: if (NULL != pwszSrc) { LocalFree(pwszSrc); } if (NULL != hkeyHKLM) { RegCloseKey(hkeyHKLM); } if (NULL != hkeyDest) { RegCloseKey(hkeyDest); } if (NULL != hkeySrc) { RegCloseKey(hkeySrc); } return(ceHError(hr)); } //+-------------------------------------------------------------------------- // CCertPolicyExchange::~CCertPolicyExchange -- destructor // // free memory associated with this instance //+-------------------------------------------------------------------------- CCertPolicyExchange::~CCertPolicyExchange() { _Cleanup(); } VOID CCertPolicyExchange::_FreeStringArray( IN OUT DWORD *pcString, IN OUT LPWSTR **papstr) { BSTR *apstr = *papstr; DWORD i; if (NULL != apstr) { for (i = *pcString; i-- > 0; ) { if (NULL != apstr[i]) { DBGPRINT((fDebug, "_FreeStringArray[%u]: '%ws'\n", i, apstr[i])); LocalFree(apstr[i]); } } LocalFree(apstr); *papstr = NULL; } *pcString = 0; } //+-------------------------------------------------------------------------- // CCertPolicyExchange::_Cleanup -- free memory associated with this instance // // free memory associated with this instance //+-------------------------------------------------------------------------- VOID CCertPolicyExchange::_Cleanup() { // RevocationExtension variables: _FreeStringArray(&m_cCDPRevocationURL, &m_ppwszCDPRevocationURL); if (NULL != m_pwszASPRevocationURL) { LocalFree(m_pwszASPRevocationURL); m_pwszASPRevocationURL = NULL; } // AuthorityInfoAccessExtension variables: _FreeStringArray(&m_cIssuerCertURL, &m_ppwszIssuerCertURL); if (NULL != m_bstrMachineDNSName) { SysFreeString(m_bstrMachineDNSName); m_bstrMachineDNSName = NULL; } if (NULL != m_bstrCASanitizedName) { SysFreeString(m_bstrCASanitizedName); m_bstrCASanitizedName = NULL; } } HRESULT CCertPolicyExchange::_ReadRegistryString( IN HKEY hkey, IN BOOL fURL, IN WCHAR const *pwszRegName, IN WCHAR const *pwszSuffix, OUT LPWSTR *ppwszOut) { HRESULT hr; WCHAR *pwszRegValue = NULL; DWORD cbValue; DWORD dwType; *ppwszOut = NULL; hr = RegQueryValueEx( hkey, pwszRegName, NULL, // lpdwReserved &dwType, NULL, &cbValue); _JumpIfErrorStr2(hr, error, "RegQueryValueEx", pwszRegName, ERROR_FILE_NOT_FOUND); if (REG_SZ != dwType && REG_MULTI_SZ != dwType) { hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA); _JumpErrorStr(hr, error, "RegQueryValueEx TYPE", pwszRegName); } if (NULL != pwszSuffix) { cbValue += wcslen(pwszSuffix) * sizeof(WCHAR); } pwszRegValue = (WCHAR *) LocalAlloc(LMEM_FIXED, cbValue + sizeof(WCHAR)); if (NULL == pwszRegValue) { hr = E_OUTOFMEMORY; _JumpErrorStr(hr, error, "LocalAlloc", pwszRegName); } hr = RegQueryValueEx( hkey, pwszRegName, NULL, // lpdwReserved &dwType, (BYTE *) pwszRegValue, &cbValue); _JumpIfErrorStr(hr, error, "RegQueryValueEx", pwszRegName); // Handle malformed registry values cleanly: pwszRegValue[cbValue / sizeof(WCHAR)] = L'\0'; if (NULL != pwszSuffix) { wcscat(pwszRegValue, pwszSuffix); } hr = ceFormatCertsrvStringArray( fURL, // fURL m_bstrMachineDNSName, // pwszServerName_p1_2 m_bstrCASanitizedName, // pwszSanitizedName_p3_7 m_iCert, // iCert_p4 MAXDWORD, // iCertTarget_p4 L"", // pwszDomainDN_p5 L"", // pwszConfigDN_p6 m_iCRL, // iCRL_p8 FALSE, // fDeltaCRL_p9, FALSE, // fDSAttrib_p10_11, 1, // cStrings (LPCWSTR *) &pwszRegValue, // apwszStringsIn ppwszOut); // apwszStringsOut _JumpIfError(hr, error, "ceFormatCertsrvStringArray"); error: if (NULL != pwszRegValue) { LocalFree(pwszRegValue); } return(ceHError(hr)); } #if DBG_CERTSRV VOID CCertPolicyExchange::_DumpStringArray( IN char const *pszType, IN DWORD cpwsz, IN WCHAR const * const *ppwsz) { DWORD i; WCHAR const *pwszName; for (i = 0; i < cpwsz; i++) { pwszName = L""; if (iswdigit(ppwsz[i][0])) { pwszName = ceGetOIDName(ppwsz[i]); // Static: do not free! } DBGPRINT(( fDebug, "%hs[%u]: %ws%hs%ws\n", pszType, i, ppwsz[i], L'\0' != *pwszName? " -- " : "", pwszName)); } } #endif // DBG_CERTSRV HRESULT CCertPolicyExchange::_AddStringArray( IN WCHAR const *pwszzValue, IN BOOL fURL, IN OUT DWORD *pcStrings, IN OUT LPWSTR **papstrRegValues) { HRESULT hr = S_OK; DWORD cString = 0; WCHAR const *pwsz; LPCWSTR *awszFormatStrings = NULL; LPWSTR *awszOutputStrings = NULL; // Count the number of strings we're adding for (pwsz = pwszzValue; L'\0' != *pwsz; pwsz += wcslen(pwsz) + 1) { cString++; } if (0 == cString) // no strings { goto error; } awszFormatStrings = (LPCWSTR *) LocalAlloc( LMEM_FIXED | LMEM_ZEROINIT, cString * sizeof(LPWSTR)); if (NULL == awszFormatStrings) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "LocalAlloc"); } cString = 0; for (pwsz = pwszzValue; L'\0' != *pwsz; pwsz += wcslen(pwsz) + 1) { // Skip strings that start with a an unescaped minus sign. // Strings with an escaped minus sign (2 minus signs) are not skipped. if (L'-' == *pwsz) { pwsz++; if (L'-' != *pwsz) { continue; } } awszFormatStrings[cString++] = pwsz; } // if no strings to add, don't modify if (cString > 0) { awszOutputStrings = (LPWSTR *) LocalAlloc( LMEM_FIXED | LMEM_ZEROINIT, (cString + *pcStrings) * sizeof(LPWSTR)); if (NULL == awszOutputStrings) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "LocalAlloc"); } if (0 != *pcStrings) { assert(NULL != *papstrRegValues); CopyMemory(awszOutputStrings, *papstrRegValues, *pcStrings * sizeof(LPWSTR)); } hr = ceFormatCertsrvStringArray( fURL, // fURL m_bstrMachineDNSName, // pwszServerName_p1_2 m_bstrCASanitizedName, // pwszSanitizedName_p3_7 m_iCert, // iCert_p4 MAXDWORD, // iCertTarget_p4 L"", // pwszDomainDN_p5 L"", // pwszConfigDN_p6 m_iCRL, // iCRL_p8 FALSE, // fDeltaCRL_p9, FALSE, // fDSAttrib_p10_11, cString, // cStrings awszFormatStrings, // apwszStringsIn &awszOutputStrings[*pcStrings]); // apwszStringsOut _JumpIfError(hr, error, "ceFormatCertsrvStringArray"); *pcStrings = (*pcStrings) + cString; if (*papstrRegValues) { LocalFree(*papstrRegValues); } *papstrRegValues = awszOutputStrings; awszOutputStrings = NULL; } error: if (awszOutputStrings) { LocalFree(awszOutputStrings); } if (awszFormatStrings) { LocalFree(awszFormatStrings); } return(ceHError(hr)); } HRESULT CCertPolicyExchange::_ReadRegistryStringArray( IN HKEY hkey, IN BOOL fURL, IN DWORD dwFlags, IN DWORD cRegNames, IN DWORD *aFlags, IN WCHAR const * const *apwszRegNames, IN OUT DWORD *pcStrings, IN OUT LPWSTR **papstrRegValues) { HRESULT hr; DWORD i; WCHAR *pwszzValue = NULL; DWORD cbValue; DWORD dwType; for (i = 0; i < cRegNames; i++) { if (0 == (dwFlags & aFlags[i])) { continue; } if (NULL != pwszzValue) { LocalFree(pwszzValue); pwszzValue = NULL; } hr = RegQueryValueEx( hkey, apwszRegNames[i], NULL, // lpdwReserved &dwType, NULL, &cbValue); if (S_OK != hr) { _PrintErrorStr2(hr, "RegQueryValueEx", apwszRegNames[i], ERROR_FILE_NOT_FOUND); continue; } if (REG_SZ != dwType && REG_MULTI_SZ != dwType) { hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA); _PrintErrorStr(hr, "RegQueryValueEx TYPE", apwszRegNames[i]); continue; } // Handle malformed registry values cleanly by adding two WCHAR L'\0's // allocate space for 3 WCHARs to allow for unaligned (odd) cbValue; pwszzValue = (WCHAR *) LocalAlloc( LMEM_FIXED, cbValue + 3 * sizeof(WCHAR)); if (NULL == pwszzValue) { hr = E_OUTOFMEMORY; _JumpErrorStr(hr, error, "LocalAlloc", apwszRegNames[i]); } hr = RegQueryValueEx( hkey, apwszRegNames[i], NULL, // lpdwReserved &dwType, (BYTE *) pwszzValue, &cbValue); if (S_OK != hr) { _PrintErrorStr(hr, "RegQueryValueEx", apwszRegNames[i]); continue; } // Handle malformed registry values cleanly: pwszzValue[cbValue / sizeof(WCHAR)] = L'\0'; pwszzValue[cbValue / sizeof(WCHAR) + 1] = L'\0'; hr = _AddStringArray(pwszzValue, fURL, pcStrings, papstrRegValues); _JumpIfErrorStr(hr, error, "_AddStringArray", apwszRegNames[i]); } hr = S_OK; error: if (NULL != pwszzValue) { LocalFree(pwszzValue); } return(hr); } //+-------------------------------------------------------------------------- // CCertPolicyExchange::_InitRevocationExtension // //+-------------------------------------------------------------------------- VOID CCertPolicyExchange::_InitRevocationExtension( IN HKEY hkey) { HRESULT hr; DWORD dwType; DWORD cb; DWORD adwFlags[] = { REVEXT_CDPLDAPURL_OLD, REVEXT_CDPHTTPURL_OLD, REVEXT_CDPFTPURL_OLD, REVEXT_CDPFILEURL_OLD, }; WCHAR *apwszRegNames[] = { wszREGLDAPREVOCATIONCRLURL_OLD, wszREGREVOCATIONCRLURL_OLD, wszREGFTPREVOCATIONCRLURL_OLD, wszREGFILEREVOCATIONCRLURL_OLD, }; cb = sizeof(m_dwRevocationFlags); hr = RegQueryValueEx( hkey, wszREGREVOCATIONTYPE, NULL, // lpdwReserved &dwType, (BYTE *) &m_dwRevocationFlags, &cb); if (S_OK != hr || REG_DWORD != dwType || sizeof(m_dwRevocationFlags) != cb) { goto error; } DBGPRINT((fDebug, "Revocation Flags = %x\n", m_dwRevocationFlags)); // clean up from previous call if (NULL != m_ppwszCDPRevocationURL) { _FreeStringArray(&m_cCDPRevocationURL, &m_ppwszCDPRevocationURL); } if (NULL != m_pwszASPRevocationURL) { LocalFree(m_pwszASPRevocationURL); m_pwszASPRevocationURL = NULL; } if (REVEXT_CDPENABLE & m_dwRevocationFlags) { assert(ARRAYSIZE(adwFlags) == ARRAYSIZE(apwszRegNames)); hr = _ReadRegistryStringArray( hkey, TRUE, // fURL m_dwRevocationFlags, ARRAYSIZE(adwFlags), adwFlags, apwszRegNames, &m_cCDPRevocationURL, &m_ppwszCDPRevocationURL); _JumpIfError(hr, error, "_ReadRegistryStringArray"); _DumpStringArray("CDP", m_cCDPRevocationURL, m_ppwszCDPRevocationURL); } if (REVEXT_ASPENABLE & m_dwRevocationFlags) { hr = _ReadRegistryString( hkey, TRUE, // fURL wszREGREVOCATIONURL, // pwszRegName L"?", // pwszSuffix &m_pwszASPRevocationURL); // pstrRegValue _JumpIfErrorStr(hr, error, "_ReadRegistryString", wszREGREVOCATIONCRLURL_OLD); _DumpStringArray("ASP", 1, &m_pwszASPRevocationURL); } error: ; } //+-------------------------------------------------------------------------- // CCertPolicyExchange::_InitAuthorityInfoAccessExtension // //+-------------------------------------------------------------------------- VOID CCertPolicyExchange::_InitAuthorityInfoAccessExtension( IN HKEY hkey) { HRESULT hr; DWORD dwType; DWORD cb; DWORD adwFlags[] = { ISSCERT_LDAPURL_OLD, ISSCERT_HTTPURL_OLD, ISSCERT_FTPURL_OLD, ISSCERT_FILEURL_OLD, }; WCHAR *apwszRegNames[] = { wszREGLDAPISSUERCERTURL_OLD, wszREGISSUERCERTURL_OLD, wszREGFTPISSUERCERTURL_OLD, wszREGFILEISSUERCERTURL_OLD, }; // clean up from previous call if (NULL != m_ppwszIssuerCertURL) { _FreeStringArray(&m_cIssuerCertURL, &m_ppwszIssuerCertURL); } cb = sizeof(m_dwIssuerCertURLFlags); hr = RegQueryValueEx( hkey, wszREGISSUERCERTURLFLAGS, NULL, // lpdwReserved &dwType, (BYTE *) &m_dwIssuerCertURLFlags, &cb); if (S_OK != hr || REG_DWORD != dwType || sizeof(m_dwIssuerCertURLFlags) != cb) { goto error; } DBGPRINT((fDebug, "Issuer Cert Flags = %x\n", m_dwIssuerCertURLFlags)); if (ISSCERT_ENABLE & m_dwIssuerCertURLFlags) { assert(ARRAYSIZE(adwFlags) == ARRAYSIZE(apwszRegNames)); hr = _ReadRegistryStringArray( hkey, TRUE, // fURL m_dwIssuerCertURLFlags, ARRAYSIZE(adwFlags), adwFlags, apwszRegNames, &m_cIssuerCertURL, &m_ppwszIssuerCertURL); _JumpIfError(hr, error, "_ReadRegistryStringArray"); _DumpStringArray("Issuer Cert", m_cIssuerCertURL, m_ppwszIssuerCertURL); } error: ; } //+-------------------------------------------------------------------------- // CCertPolicyExchange::Initialize // // Returns S_OK on success. //+-------------------------------------------------------------------------- STDMETHODIMP CCertPolicyExchange::Initialize( /* [in] */ BSTR const strConfig) { HRESULT hr; HKEY hkey = NULL; VARIANT varValue; ICertServerPolicy *pServer = NULL; BSTR strName = NULL; VariantInit(&varValue); _Cleanup(); hr = GetServerCallbackInterface(&pServer, 0); _JumpIfError(hr, error, "GetServerCallbackInterface"); // get storage location strName = SysAllocString(wszPROPMODULEREGLOC); if (NULL == strName) { hr = E_OUTOFMEMORY; _JumpIfError(hr, error, "SysAllocString"); } hr = pServer->GetCertificateProperty( strName, PROPTYPE_STRING, &varValue); _JumpIfError(hr, error, "GetCertificateProperty : wszPROPMODULEREGLOC"); m_pwszRegStorageLoc = (WCHAR *) LocalAlloc( LMEM_FIXED, (wcslen(varValue.bstrVal) + 1) * sizeof(WCHAR)); if (NULL == m_pwszRegStorageLoc) { hr = E_OUTOFMEMORY; _JumpIfError(hr, error, "LocalAlloc"); } wcscpy(m_pwszRegStorageLoc, varValue.bstrVal); VariantClear(&varValue); hr = PopulateRegistryDefaults(NULL, m_pwszRegStorageLoc); _PrintIfError(hr, "Policy:PopulateRegistryDefaults"); hr = RegOpenKeyEx( HKEY_LOCAL_MACHINE, m_pwszRegStorageLoc, 0, // dwReserved KEY_ENUMERATE_SUB_KEYS | KEY_EXECUTE | KEY_QUERY_VALUE, &hkey); if ((HRESULT) ERROR_SUCCESS != hr) { hr = HRESULT_FROM_WIN32(hr); _JumpIfError(hr, error, "RegOpenKeyEx"); } // Initialize the insertion string array. // Machine DNS name (%1) SysFreeString(strName); strName = SysAllocString(wszPROPMACHINEDNSNAME); if (NULL == strName) { hr = E_OUTOFMEMORY; _JumpIfError(hr, error, "SysAllocString"); } hr = pServer->GetCertificateProperty( strName, PROPTYPE_STRING, &varValue); _JumpIfErrorStr(hr, error, "GetCertificateProperty", strName); m_bstrMachineDNSName = SysAllocString(varValue.bstrVal); if (NULL == m_bstrMachineDNSName) { hr = E_OUTOFMEMORY; _JumpIfError(hr, error, "SysAllocString"); } VariantClear(&varValue); SysFreeString(strName); strName = SysAllocString(wszPROPCERTCOUNT); if (NULL == strName) { hr = E_OUTOFMEMORY; _JumpIfError(hr, error, "SysAllocString"); } hr = pServer->GetCertificateProperty( strName, PROPTYPE_LONG, &varValue); _JumpIfErrorStr(hr, error, "GetCertificateProperty", strName); m_iCert = varValue.lVal - 1; SysFreeString(strName); strName = SysAllocString(wszPROPCRLINDEX); if (NULL == strName) { hr = E_OUTOFMEMORY; _JumpIfError(hr, error, "SysAllocString"); } hr = pServer->GetCertificateProperty( strName, PROPTYPE_LONG, &varValue); _JumpIfErrorStr(hr, error, "GetCertificateProperty", strName); m_iCRL = varValue.lVal; // get sanitized name SysFreeString(strName); strName = SysAllocString(wszPROPSANITIZEDCANAME); if (NULL == strName) { hr = E_OUTOFMEMORY; _JumpIfError(hr, error, "SysAllocString"); } hr = pServer->GetCertificateProperty( strName, PROPTYPE_STRING, &varValue); _JumpIfErrorStr(hr, error, "GetCertificateProperty", strName); m_bstrCASanitizedName = SysAllocString(varValue.bstrVal); if (NULL == m_bstrCASanitizedName) { hr = E_OUTOFMEMORY; _JumpIfError(hr, error, "SysAllocString"); } VariantClear(&varValue); _InitRevocationExtension(hkey); _InitAuthorityInfoAccessExtension(hkey); hr = S_OK; error: VariantClear(&varValue); if (NULL != strName) { SysFreeString(strName); } if (NULL != hkey) { RegCloseKey(hkey); } if (NULL != pServer) { pServer->Release(); } return(hr); } HRESULT EnumerateExtensions( IN ICertServerPolicy *pServer) { HRESULT hr; HRESULT hr2; BSTR strName = NULL; LONG ExtFlags; VARIANT varValue; BOOL fClose = FALSE; VariantInit(&varValue); hr = pServer->EnumerateExtensionsSetup(0); _JumpIfError(hr, error, "EnumerateExtensionsSetup"); fClose = TRUE; while (TRUE) { hr = pServer->EnumerateExtensions(&strName); if (S_OK != hr) { if (S_FALSE == hr) { hr = S_OK; break; } _JumpError(hr, error, "EnumerateExtensions"); } hr = pServer->GetCertificateExtension( strName, PROPTYPE_BINARY, &varValue); _JumpIfError(hr, error, "GetCertificateExtension"); hr = pServer->GetCertificateExtensionFlags(&ExtFlags); _JumpIfError(hr, error, "GetCertificateExtensionFlags"); if (fDebug) { wprintf( L"Policy:EnumerateExtensions(%ws, Flags=%x, %x bytes)\n", strName, ExtFlags, SysStringByteLen(varValue.bstrVal)); } VariantClear(&varValue); } error: if (fClose) { hr2 = pServer->EnumerateExtensionsClose(); if (S_OK != hr2) { _PrintError(hr2, "Policy:EnumerateExtensionsClose"); if (S_OK == hr) { hr = hr2; } } } if (NULL != strName) { SysFreeString(strName); } VariantClear(&varValue); return(hr); } HRESULT EnumerateAttributes( IN ICertServerPolicy *pServer) { HRESULT hr; HRESULT hr2; BSTR strName = NULL; BOOL fClose = FALSE; BSTR strValue = NULL; hr = pServer->EnumerateAttributesSetup(0); _JumpIfError(hr, error, "EnumerateAttributesSetup"); fClose = TRUE; while (TRUE) { hr = pServer->EnumerateAttributes(&strName); if (S_OK != hr) { if (S_FALSE == hr) { hr = S_OK; break; } _JumpError(hr, error, "EnumerateAttributes"); } hr = pServer->GetRequestAttribute(strName, &strValue); _JumpIfError(hr, error, "GetRequestAttribute"); if (fDebug) { wprintf( L"Policy:EnumerateAttributes(%ws = %ws)\n", strName, strValue); } if (NULL != strValue) { SysFreeString(strValue); strValue = NULL; } } error: if (fClose) { hr2 = pServer->EnumerateAttributesClose(); if (S_OK != hr2) { _PrintError(hr2, "Policy:EnumerateAttributesClose"); if (S_OK == hr) { hr = hr2; } } } if (NULL != strName) { SysFreeString(strName); } if (NULL != strValue) { SysFreeString(strValue); } return(hr); } HRESULT CheckRequestProperties( IN ICertServerPolicy *pServer) { HRESULT hr; VARIANT varValue; BSTR strName = NULL; VariantInit(&varValue); strName = SysAllocString(wszPROPREQUESTREQUESTID); if (NULL == strName) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "SysAllocString"); } hr = pServer->GetRequestProperty(strName, PROPTYPE_LONG, &varValue); _JumpIfError(hr, error, "GetRequestProperty"); if (fDebug) { wprintf( L"Policy:CheckRequestProperties(%ws = %x)\n", strName, varValue.lVal); } VariantClear(&varValue); error: if (NULL != strName) { SysFreeString(strName); } return(hr); } //+-------------------------------------------------------------------------- // CCertPolicyExchange::_AddRevocationExtension // // Returns S_OK on success. //+-------------------------------------------------------------------------- HRESULT CCertPolicyExchange::_AddRevocationExtension( IN ICertServerPolicy *pServer) { HRESULT hr = S_OK; ICertEncodeCRLDistInfo *pCRLDist = NULL; BSTR strCDPName = NULL; BSTR strCDPExtension = NULL; BSTR strName = NULL; BSTR strExtension = NULL; VARIANT varExtension; DWORD i; varExtension.vt = VT_BSTR; if (NULL != m_ppwszCDPRevocationURL) { hr = CoCreateInstance( CLSID_CCertEncodeCRLDistInfo, NULL, // pUnkOuter CLSCTX_INPROC_SERVER, IID_ICertEncodeCRLDistInfo, (VOID **) &pCRLDist); _JumpIfError(hr, error, "CoCreateInstance"); hr = pCRLDist->Reset(m_cCDPRevocationURL); _JumpIfError(hr, error, "Reset"); for (i = 0; i < m_cCDPRevocationURL; i++) { DWORD j; hr = pCRLDist->SetNameCount(i, 1); _JumpIfError(hr, error, "SetNameCount"); for (j = 0; j < 1; j++) { BSTR str = SysAllocString(m_ppwszCDPRevocationURL[i]); if (NULL == str) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "SysAllocString"); } hr = pCRLDist->SetNameEntry(i, j, CERT_ALT_NAME_URL, str); SysFreeString(str); _JumpIfError(hr, error, "SetNameEntry"); } } hr = pCRLDist->Encode(&strCDPExtension); _JumpIfError(hr, error, "Encode"); strCDPName = SysAllocString(TEXT(szOID_CRL_DIST_POINTS)); varExtension.bstrVal = strCDPExtension; hr = pServer->SetCertificateExtension( strCDPName, PROPTYPE_BINARY, 0, &varExtension); _JumpIfErrorStr(hr, error, "SetCertificateExtension", L"CDP"); } if (NULL != m_pwszASPRevocationURL) { strName = SysAllocString(TEXT(szOID_NETSCAPE_REVOCATION_URL)); strExtension = SysAllocString(m_pwszASPRevocationURL); if (NULL == strName || NULL == strExtension) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "SysAllocString"); } varExtension.bstrVal = strExtension; hr = pServer->SetCertificateExtension( strName, PROPTYPE_STRING, 0, &varExtension); _JumpIfErrorStr(hr, error, "SetCertificateExtension", L"ASP"); VariantClear(&varExtension); } error: if (NULL != strName) { SysFreeString(strName); } if (NULL != strExtension) { SysFreeString(strExtension); } if (NULL != strCDPName) { SysFreeString(strCDPName); } if (NULL != strCDPExtension) { SysFreeString(strCDPExtension); } if (NULL != pCRLDist) { pCRLDist->Release(); } return(hr); } //+-------------------------------------------------------------------------- // CCertPolicyExchange::_AddAuthorityInfoAccessExtension // // Returns S_OK on success. //+-------------------------------------------------------------------------- HRESULT CCertPolicyExchange::_AddAuthorityInfoAccessExtension( IN ICertServerPolicy *pServer) { HRESULT hr = S_OK; BYTE *pbEncoded = NULL; DWORD cbEncoded; BSTR strName = NULL; BSTR strExtension = NULL; VARIANT varExtension; DWORD i; CERT_AUTHORITY_INFO_ACCESS caio; caio.rgAccDescr = NULL; if (NULL == m_ppwszIssuerCertURL) { goto error; } caio.cAccDescr = m_cIssuerCertURL; caio.rgAccDescr = (CERT_ACCESS_DESCRIPTION *) LocalAlloc( LMEM_FIXED, sizeof(CERT_ACCESS_DESCRIPTION) * m_cIssuerCertURL); if (NULL == caio.rgAccDescr) { hr = E_OUTOFMEMORY; _JumpIfError(hr, error, "LocalAlloc"); } for (i = 0; i < m_cIssuerCertURL; i++) { caio.rgAccDescr[i].pszAccessMethod = szOID_PKIX_CA_ISSUERS; caio.rgAccDescr[i].AccessLocation.dwAltNameChoice = CERT_ALT_NAME_URL; caio.rgAccDescr[i].AccessLocation.pwszURL = m_ppwszIssuerCertURL[i]; } if (!ceEncodeObject( X509_ASN_ENCODING, X509_AUTHORITY_INFO_ACCESS, &caio, 0, FALSE, &pbEncoded, &cbEncoded)) { hr = ceHLastError(); _JumpIfError(hr, error, "Policy:ceEncodeObject"); } if (!ceConvertWszToBstr( &strExtension, (WCHAR const *) pbEncoded, cbEncoded)) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "ceConvertWszToBstr"); } strName = SysAllocString(TEXT(szOID_AUTHORITY_INFO_ACCESS)); if (NULL == strName) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "SysAllocString"); } varExtension.vt = VT_BSTR; varExtension.bstrVal = strExtension; hr = pServer->SetCertificateExtension( strName, PROPTYPE_BINARY, 0, &varExtension); _JumpIfError(hr, error, "SetCertificateExtension(AuthInfoAccess)"); error: if (NULL != pbEncoded) { LocalFree(pbEncoded); } if (NULL != strName) { SysFreeString(strName); } if (NULL != strExtension) { SysFreeString(strExtension); } if (NULL != caio.rgAccDescr) { LocalFree(caio.rgAccDescr); } return(hr); } //+-------------------------------------------------------------------------- // CCertPolicyExchange::_AddIssuerAltName2Extension // // Returns S_OK on success. //+-------------------------------------------------------------------------- HRESULT CCertPolicyExchange::_AddIssuerAltName2Extension( IN ICertServerPolicy *pServer) { HRESULT hr = S_OK; BSTR strExtension = NULL; VARIANT varExtension; BSTR strCertType = NULL; BSTR strName = NULL; BSTR strValue = NULL; BSTR strKMServerName = NULL; LPBYTE pbEncName = NULL; ULONG cbEncName = 0; LPBYTE pbEncExten = NULL; ULONG cbEncExten = 0; CERT_ALT_NAME_ENTRY cane = { 0 }; CERT_ALT_NAME_INFO cani = { 0 }; strKMServerName = SysAllocString(k_wszKMServerName); if (NULL == strKMServerName) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "SysAllocString"); } hr = pServer->GetRequestAttribute(strKMServerName, &strValue); _JumpIfErrorStr( hr, error, CERTSRV_E_PROPERTY_EMPTY == hr? "MISSING ATTRIBUTE -- GetRequestAttribute" : "GetRequestAttribute", k_wszKMServerName); // CertStrToName to turn string into encoded name blob if (!CertStrToNameW( X509_ASN_ENCODING, strValue, CERT_X500_NAME_STR, NULL, NULL, &cbEncName, NULL)) { hr = E_INVALIDARG; _JumpError(hr, error, "CertStrToNameW"); } pbEncName = new BYTE [cbEncName]; if (NULL == pbEncName) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "new"); } if (!CertStrToNameW( X509_ASN_ENCODING, strValue, CERT_X500_NAME_STR, NULL, pbEncName, &cbEncName, NULL)) { hr = E_INVALIDARG; _JumpError(hr, error, "CertStrToNameW"); } // fill in alt name info cane.dwAltNameChoice = CERT_ALT_NAME_DIRECTORY_NAME; cane.DirectoryName.cbData = cbEncName; cane.DirectoryName.pbData = pbEncName; cani.cAltEntry = 1; cani.rgAltEntry = &cane; // encode alt name info if (!CryptEncodeObject( X509_ASN_ENCODING, X509_ALTERNATE_NAME, &cani, NULL, &cbEncExten)) { hr = E_INVALIDARG; _JumpError(hr, error, "CryptEncodeObject"); } pbEncExten = new BYTE [cbEncExten]; if (NULL == pbEncExten) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "new"); } if (!CryptEncodeObject( X509_ASN_ENCODING, X509_ALTERNATE_NAME, &cani, pbEncExten, &cbEncExten)) { hr = E_INVALIDARG; _JumpError(hr, error, "CryptEncodeObject"); } strName = SysAllocString(TEXT(szOID_ISSUER_ALT_NAME2)); strExtension = SysAllocStringByteLen((char *) pbEncExten, cbEncExten); if (NULL == strName || NULL == strExtension) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "SysAllocString"); } // add extension varExtension.vt = VT_BSTR; varExtension.bstrVal = strExtension; hr = pServer->SetCertificateExtension( strName, PROPTYPE_BINARY, 0, &varExtension); _JumpIfError(hr, error, "SetCertificateExtension(IssuerAltName2)"); error: delete [] pbEncName; delete [] pbEncExten; if (NULL != strName) { SysFreeString(strName); } if (NULL != strExtension) { SysFreeString(strExtension); } if (NULL != strKMServerName) { SysFreeString(strKMServerName); } return(hr); } //+-------------------------------------------------------------------------- // CCertPolicyExchange::_AddSubjectAltName2Extension // // Returns S_OK on success. // Returns S_FALSE for special request. //+-------------------------------------------------------------------------- HRESULT CCertPolicyExchange::_AddSubjectAltName2Extension( IN ICertServerPolicy *pServer) { HRESULT hr = S_OK; BSTR strExtension = NULL; VARIANT varExtension; BSTR strCertType = NULL; BSTR strName = NULL; BSTR strDisplay = NULL; BSTR strRFC822 = NULL; BSTR strSubjAltNameRFC822 = NULL; BSTR strSubjAltNameDisplay = NULL; LPBYTE pbEncName = NULL; ULONG cbEncName = 0; LPBYTE pbEncExten = NULL; ULONG cbEncExten = 0; CERT_RDN_ATTR rdnattr = { 0 }; CERT_RDN rdn = { 0 }; CERT_NAME_INFO cni = { 0 }; CERT_ALT_NAME_ENTRY acane [2] = { 0 }; CERT_ALT_NAME_INFO cani = { 0 }; strSubjAltNameDisplay = SysAllocString(k_wszSubjAltNameDisplay); if (NULL == strSubjAltNameDisplay) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "SysAllocString"); } hr = pServer->GetRequestAttribute(strSubjAltNameDisplay, &strDisplay); _JumpIfErrorStr( hr, error, CERTSRV_E_PROPERTY_EMPTY == hr? "MISSING ATTRIBUTE -- GetRequestAttribute" : "GetRequestAttribute", k_wszSubjAltNameDisplay); strSubjAltNameRFC822 = SysAllocString(k_wszSubjAltNameRFC822); if (NULL == strSubjAltNameRFC822) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "SysAllocString"); } hr = pServer->GetRequestAttribute(strSubjAltNameRFC822, &strRFC822); _JumpIfErrorStr( hr, error, CERTSRV_E_PROPERTY_EMPTY == hr? "MISSING ATTRIBUTE -- GetRequestAttribute" : "GetRequestAttribute", k_wszSubjAltNameRFC822); // this identifies special request from KMS if (0 == lstrcmpW(strDisplay, k_wszSpecialAttribute) && 0 == lstrcmpW(strRFC822, k_wszSpecialAttribute)) { hr = _AddSpecialAltNameExtension(pServer); _JumpIfError(hr, error, "_AddSpecialAltNameExtension"); // there are no subject names to add, so exit goto error; } // encode display name rdnattr.pszObjId = szOID_COMMON_NAME; rdnattr.dwValueType = CERT_RDN_UNICODE_STRING; rdnattr.Value.cbData = SysStringByteLen(strDisplay); rdnattr.Value.pbData = (LPBYTE) strDisplay; rdn.cRDNAttr = 1; rdn.rgRDNAttr = &rdnattr; cni.cRDN = 1; cni.rgRDN = &rdn; if (!CryptEncodeObject( X509_ASN_ENCODING, X509_NAME, &cni, NULL, &cbEncName)) { hr = E_INVALIDARG; _JumpError(hr, error, "CryptEncodeObject"); } pbEncName = new BYTE [cbEncName]; if (NULL == pbEncName) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "new"); } if (!CryptEncodeObject( X509_ASN_ENCODING, X509_NAME, &cni, pbEncName, &cbEncName)) { hr = E_INVALIDARG; _JumpError(hr, error, "CryptEncodeObject"); } // fill in alt name info acane[0].dwAltNameChoice = CERT_ALT_NAME_DIRECTORY_NAME; acane[0].DirectoryName.cbData = cbEncName; acane[0].DirectoryName.pbData = pbEncName; acane[1].dwAltNameChoice = CERT_ALT_NAME_RFC822_NAME; acane[1].pwszRfc822Name = strRFC822; cani.cAltEntry = 2; cani.rgAltEntry = acane; // encode alt name info if (!CryptEncodeObject( X509_ASN_ENCODING, X509_ALTERNATE_NAME, &cani, NULL, &cbEncExten)) { hr = E_INVALIDARG; _JumpError(hr, error, "CryptEncodeObject"); } pbEncExten = new BYTE [cbEncExten]; if (NULL == pbEncExten) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "new"); } if (!CryptEncodeObject( X509_ASN_ENCODING, X509_ALTERNATE_NAME, &cani, pbEncExten, &cbEncExten)) { hr = E_INVALIDARG; _JumpError(hr, error, "CryptEncodeObject"); } strName = SysAllocString(TEXT(szOID_SUBJECT_ALT_NAME2)); strExtension = SysAllocStringByteLen((char *) pbEncExten, cbEncExten); if (NULL == strName || NULL == strExtension) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "SysAllocString"); } // add extension varExtension.vt = VT_BSTR; varExtension.bstrVal = strExtension; hr = pServer->SetCertificateExtension( strName, PROPTYPE_BINARY, 0, &varExtension); _JumpIfError(hr, error, "SetCertificateExtension"); error: if (NULL != strName) { SysFreeString(strName); } if (NULL != strExtension) { SysFreeString(strExtension); } if (NULL != strSubjAltNameRFC822) { SysFreeString(strSubjAltNameRFC822); } if (NULL != strSubjAltNameDisplay) { SysFreeString(strSubjAltNameDisplay); } return(hr); } //+-------------------------------------------------------------------------- // CCertPolicyExchange::_AddSpecialAltNameExtension // // in response to request with both display and RFC822 equal to special value, // fetch version info for CertSrv.exe and ExPolicy.dll, encode as multi-byte // int, and set as IssuerAltName, marked critical. this should make cert // unusable. // // Returns S_OK on success. //+-------------------------------------------------------------------------- HRESULT CCertPolicyExchange::_AddSpecialAltNameExtension( IN ICertServerPolicy *pServer) { HRESULT hr = S_OK; BSTR strName = NULL; BSTR strExtension = NULL; VARIANT varExtension; HRSRC hExeVersion = NULL; HGLOBAL hExeVersionInMem = NULL; LPBYTE pExeVersion = NULL; // [0] to [3] are ExPolicy version. // [4] to [7] are CertServer version. WORD awVersions [] = { rmj, rmn, rmm, rup, 0, 0, 0, 0 }; ULONG ndxCertServer = 4; CRYPT_INTEGER_BLOB intblobVersions = { 0 }; LPBYTE pbEncExten = NULL; ULONG cbEncExten = 0; // fill in version info if (NULL == (hExeVersion = FindResource(NULL, MAKEINTRESOURCE(1), RT_VERSION)) || NULL == (hExeVersionInMem = LoadResource(NULL, hExeVersion)) || NULL == (pExeVersion = (LPBYTE) LockResource(hExeVersionInMem))) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "Find/Load/LockResource"); } awVersions[ndxCertServer] = ((LPWORD)pExeVersion)[25]; awVersions[ndxCertServer + 1] = ((LPWORD)pExeVersion)[24]; awVersions[ndxCertServer + 2] = ((LPWORD)pExeVersion)[27]; awVersions[ndxCertServer + 3] = ((LPWORD)pExeVersion)[26]; intblobVersions.cbData = sizeof(awVersions); intblobVersions.pbData = (LPBYTE) awVersions; // encode version info if (!CryptEncodeObject( X509_ASN_ENCODING, X509_MULTI_BYTE_INTEGER, &intblobVersions, NULL, &cbEncExten)) { hr = E_INVALIDARG; _JumpError(hr, error, "CryptEncodeObject"); } pbEncExten = new BYTE [cbEncExten]; if (NULL == pbEncExten) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "new"); } if (!CryptEncodeObject( X509_ASN_ENCODING, X509_MULTI_BYTE_INTEGER, &intblobVersions, pbEncExten, &cbEncExten)) { hr = E_INVALIDARG; _JumpError(hr, error, "CryptEncodeObject"); } strName = SysAllocString(TEXT(szOID_ISSUER_ALT_NAME)); strExtension = SysAllocStringByteLen((char *) pbEncExten, cbEncExten); if (NULL == strName || NULL == strExtension) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "SysAllocString"); } // add extension varExtension.vt = VT_BSTR; varExtension.bstrVal = strExtension; hr = pServer->SetCertificateExtension( strName, PROPTYPE_BINARY, EXTENSION_CRITICAL_FLAG, &varExtension); _JumpIfError(hr, error, "SetCertificateExtension"); error: if (NULL != strName) { SysFreeString(strName); } if (NULL != strExtension) { SysFreeString(strExtension); } delete [] pbEncExten; return(hr); } //+-------------------------------------------------------------------------- // CCertPolicyExchange::_AddBasicConstraintsExtension // // Returns S_OK on success. //+-------------------------------------------------------------------------- HRESULT CCertPolicyExchange::_AddBasicConstraintsExtension( IN ICertServerPolicy *pServer) { HRESULT hr = S_OK; BYTE *pbEncoded = NULL; DWORD cbEncoded; CERT_BASIC_CONSTRAINTS2_INFO bc2i; BSTR strName = NULL; BSTR strExtension = NULL; VARIANT varExtension; bc2i.fCA = FALSE; bc2i.fPathLenConstraint = FALSE; bc2i.dwPathLenConstraint = 0; if (!ceEncodeObject( X509_ASN_ENCODING, X509_BASIC_CONSTRAINTS2, &bc2i, 0, FALSE, &pbEncoded, &cbEncoded)) { hr = GetLastError(); _JumpError(hr, error, "ceEncodeObject"); } if (!ceConvertWszToBstr( &strExtension, (WCHAR const *) pbEncoded, cbEncoded)) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "ceConvertWszToBstr"); } strName = SysAllocString(TEXT(szOID_BASIC_CONSTRAINTS2)); if (NULL == strName) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "SysAllocString"); } varExtension.vt = VT_BSTR; varExtension.bstrVal = strExtension; hr = pServer->SetCertificateExtension( strName, PROPTYPE_BINARY, 0, &varExtension); _JumpIfError(hr, error, "SetCertificateExtension"); error: if (NULL != pbEncoded) { LocalFree(pbEncoded); } if (NULL != strName) { SysFreeString(strName); } if (NULL != strExtension) { SysFreeString(strExtension); } return(hr); } //+-------------------------------------------------------------------------- // CCertPolicyExchange::_AddKeyUsageExtension // // Returns S_OK on success. //+-------------------------------------------------------------------------- HRESULT CCertPolicyExchange::_AddKeyUsageExtension( IN ICertServerPolicy *pServer) { HRESULT hr = S_OK; BSTR strName = NULL; ICertEncodeBitString *pBitString = NULL; BSTR strExtension = NULL; VARIANT varExtension; BYTE KeyUsage = 0; BSTR strBitString = NULL; BSTR strKeyUsage = NULL; BSTR strValue = NULL; strKeyUsage = SysAllocString(k_wszKeyUsage); if (NULL == strKeyUsage) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "SysAllocString"); } hr = pServer->GetRequestAttribute(strKeyUsage, &strValue); _JumpIfErrorStr( hr, error, CERTSRV_E_PROPERTY_EMPTY == hr? "MISSING ATTRIBUTE -- GetRequestAttribute" : "GetRequestAttribute", k_wszKeyUsage); if (0 == wcscmp(strValue, k_wszUsageSealing)) { KeyUsage = CERT_KEY_ENCIPHERMENT_KEY_USAGE; } else if (0 == wcscmp(strValue, k_wszUsageSigning)) { KeyUsage = CERT_DIGITAL_SIGNATURE_KEY_USAGE | CERT_NON_REPUDIATION_KEY_USAGE; } else { hr = E_INVALIDARG; _JumpError(hr, error, "KeyUsage"); } hr = CoCreateInstance( CLSID_CCertEncodeBitString, NULL, // pUnkOuter CLSCTX_INPROC_SERVER, IID_ICertEncodeBitString, (VOID **) &pBitString); _JumpIfError(hr, error, "CoCreateInstance"); if (!ceConvertWszToBstr( &strBitString, (WCHAR const *) &KeyUsage, sizeof(KeyUsage))) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "ceConvertWszToBstr"); } hr = pBitString->Encode( sizeof(KeyUsage) * 8, strBitString, &strExtension); _JumpIfError(hr, error, "Encode"); if (!ceConvertWszToBstr(&strName, TEXT(szOID_KEY_USAGE), -1)) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "ceConvertWszToBstr"); } varExtension.vt = VT_BSTR; varExtension.bstrVal = strExtension; hr = pServer->SetCertificateExtension( strName, PROPTYPE_BINARY, EXTENSION_CRITICAL_FLAG, &varExtension); _JumpIfError(hr, error, "SetCertificateExtension"); error: if (NULL != strName) { SysFreeString(strName); } if (NULL != strExtension) { SysFreeString(strExtension); } if (NULL != strBitString) { SysFreeString(strBitString); } if (NULL != strKeyUsage) { SysFreeString(strKeyUsage); } if (NULL != strValue) { SysFreeString(strValue); } if (NULL != pBitString) { pBitString->Release(); } return(hr); } //+-------------------------------------------------------------------------- // CCertPolicyExchange::_AddEnhancedKeyUsageExtension // // Returns S_OK on success. //+-------------------------------------------------------------------------- HRESULT CCertPolicyExchange::_AddEnhancedKeyUsageExtension( IN ICertServerPolicy *pServer) { HRESULT hr = S_OK; BSTR strName = NULL; BSTR strExtension = NULL; VARIANT varExtension; BYTE *pbEncoded = NULL; DWORD cbEncoded; CERT_ENHKEY_USAGE ceu; LPSTR pszEnhUsage = szOID_PKIX_KP_EMAIL_PROTECTION; ceu.cUsageIdentifier = 1; ceu.rgpszUsageIdentifier = &pszEnhUsage; // array of pszObjId if (!ceEncodeObject( X509_ASN_ENCODING, X509_ENHANCED_KEY_USAGE, &ceu, 0, FALSE, &pbEncoded, &cbEncoded)) { hr = GetLastError(); _JumpError(hr, error, "ceEncodeObject"); } if (!ceConvertWszToBstr( &strExtension, (WCHAR const *) pbEncoded, cbEncoded)) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "ceConvertWszToBstr"); } if (!ceConvertWszToBstr(&strName, TEXT(szOID_ENHANCED_KEY_USAGE), -1)) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "ceConvertWszToBstr"); } varExtension.vt = VT_BSTR; varExtension.bstrVal = strExtension; hr = pServer->SetCertificateExtension( strName, PROPTYPE_BINARY, 0, &varExtension); _JumpIfError(hr, error, "SetCertificateExtension"); error: if (NULL != pbEncoded) { LocalFree(pbEncoded); } if (NULL != strName) { SysFreeString(strName); } if (NULL != strExtension) { SysFreeString(strExtension); } return(hr); } //+-------------------------------------------------------------------------- // CCertPolicyExchange::VerifyRequest // // Returns S_OK on success. //+-------------------------------------------------------------------------- STDMETHODIMP CCertPolicyExchange::VerifyRequest( /* [in] */ BSTR const strConfig, /* [in] */ LONG Context, /* [in] */ LONG bNewRequest, /* [in] */ LONG Flags, /* [out, retval] */ LONG __RPC_FAR *pDisposition) { HRESULT hr; ICertServerPolicy *pServer = NULL; hr = GetServerCallbackInterface(&pServer, Context); _JumpIfError(hr, error, "GetServerCallbackInterface"); if (fDebug) { hr = EnumerateAttributes(pServer); _JumpIfError(hr, error, "EnumerateAttributes"); hr = EnumerateExtensions(pServer); _JumpIfError(hr, error, "EnumerateExtensions"); } hr = _AddIssuerAltName2Extension(pServer); _JumpIfError(hr, error, "_AddIssuerAltName2Extension"); // also handles 'special' KMS request hr = _AddSubjectAltName2Extension(pServer); _JumpIfError(hr, error, "_AddSubjectAltName2Extension"); hr = _AddBasicConstraintsExtension(pServer); _JumpIfError(hr, error, "_AddBasicConstraintsExtension"); hr = _AddRevocationExtension(pServer); _JumpIfError(hr, error, "_AddRevocationExtension"); hr = _AddAuthorityInfoAccessExtension(pServer); _JumpIfError(hr, error, "_AddAuthorityInfoAccessExtension"); hr = _AddKeyUsageExtension(pServer); _JumpIfError(hr, error, "_AddKeyUsageExtension"); hr = _AddEnhancedKeyUsageExtension(pServer); _JumpIfError(hr, error, "_AddEnhancedKeyUsageExtension"); if (fDebug) { hr = EnumerateExtensions(pServer); _JumpIfError(hr, error, "EnumerateExtensions"); } hr = CheckRequestProperties(pServer); _JumpIfError(hr, error, "_AddRevocationExtension"); error: *pDisposition = S_OK == hr? VR_INSTANT_OK : VR_INSTANT_BAD; if (NULL != pServer) { pServer->Release(); } return(hr); } //+-------------------------------------------------------------------------- // CCertPolicyExchange::GetDescription // // Returns S_OK on success. //+-------------------------------------------------------------------------- STDMETHODIMP CCertPolicyExchange::GetDescription( /* [out, retval] */ BSTR __RPC_FAR *pstrDescription) { HRESULT hr = S_OK; *pstrDescription = SysAllocString(g_wszDescription); if (NULL == *pstrDescription) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "SysAllocString"); } error: return(hr); } //+-------------------------------------------------------------------------- // CCertPolicyExchange::ShutDown // // Returns S_OK on success. //+-------------------------------------------------------------------------- STDMETHODIMP CCertPolicyExchange::ShutDown(VOID) { return(S_OK); } //+-------------------------------------------------------------------------- // CCertPolicyExchange::GetManageModule // // Returns S_OK on success. //+-------------------------------------------------------------------------- STDMETHODIMP CCertPolicyExchange::GetManageModule( /* [out, retval] */ ICertManageModule **ppManageModule) { HRESULT hr; *ppManageModule = NULL; hr = CoCreateInstance( CLSID_CCertManagePolicyModuleExchange, NULL, // pUnkOuter CLSCTX_INPROC_SERVER, IID_ICertManageModule, (VOID **) ppManageModule); _JumpIfError(hr, error, "CoCreateInstance"); error: return(hr); } STDMETHODIMP CCertPolicyExchange::InterfaceSupportsErrorInfo(REFIID riid) { static const IID *arr[] = { &IID_ICertPolicy, }; for (int i = 0; i < sizeof(arr)/sizeof(arr[0]); i++) { if (InlineIsEqualGUID(*arr[i], riid)) { return(S_OK); } } return(S_FALSE); }