/**********************************************************************/ /** Microsoft Passport **/ /** Copyright(c) Microsoft Corporation, 1999 - 2001 **/ /**********************************************************************/ /* PassportCrypt.cpp FILE HISTORY: */ // PassportCrypt.cpp : Implementation of CCrypt #include "stdafx.h" #include "Passport.h" #include "PassportCrypt.h" #include /* moved into passport.idl -- so consumer of the COM API can see it // max blocks + 10 should be multiples of 3 for simplicity #define ENC_MAX_SIZE 2045 // I don't trust the compiler... (((2045+10)*4)/3)+9 = 2749 * sizeof(wchar) #define DEC_MAX_SIZE 5498 */ //=========================================================================== // // CCrypt // CCrypt::CCrypt() : m_crypt(NULL), m_szSiteName(NULL), m_szHostName(NULL) { m_pUnkMarshaler = NULL; m_keyVersion = 0; CRegistryConfig* crc = g_config->checkoutRegistryConfig(); if( crc ) { m_keyVersion = crc->getCurrentCryptVersion(); crc->getCrypt(m_keyVersion, &m_validUntil); crc->Release(); } } ///////////////////////////////////////////////////////////////////////////// // CCrypt //=========================================================================== // // InterfaceSupportsErrorInfo // STDMETHODIMP CCrypt::InterfaceSupportsErrorInfo(REFIID riid) { static const IID* arr[] = { &IID_IPassportCrypt, }; for (int i=0;iisValid()) // Guarantees config is non-null { AtlReportError(CLSID_Manager, PP_E_NOT_CONFIGUREDSTR, IID_IPassportManager, PP_E_NOT_CONFIGURED); hr = PP_E_NOT_CONFIGURED; } try { // Get Request Object Pointer piRequest = ((IScriptingContextPtr)piUnk)->Request; // // Use the request object to get the server name being requested // so we can get the correct registry config. But only do this // if we have some configured sites. // if(g_config->HasSites()) { piRequest->get_ServerVariables(&piServerVariables); vtItemName.vt = VT_BSTR; vtItemName.bstrVal = SysAllocString(L"SERVER_NAME"); if (NULL == vtItemName.bstrVal) { hr = E_OUTOFMEMORY; goto exit; } piServerVariables->get_Item(vtItemName, &vtServerName); if(vtServerName.vt != VT_BSTR) VariantChangeType(&vtServerName, &vtServerName, 0, VT_BSTR); VariantClear(&vtItemName); vtItemName.vt = VT_BSTR; vtItemName.bstrVal = SysAllocString(L"SERVER_PORT"); if (NULL == vtItemName.bstrVal) { hr = E_OUTOFMEMORY; goto exit; } piServerVariables->get_Item(vtItemName, &vtServerPort); if(vtServerPort.vt != VT_BSTR) VariantChangeType(&vtServerPort, &vtServerPort, 0, VT_BSTR); VariantClear(&vtItemName); vtItemName.vt = VT_BSTR; vtItemName.bstrVal = SysAllocString(L"HTTPS"); if (NULL == vtItemName.bstrVal) { hr = E_OUTOFMEMORY; goto exit; } hr = piServerVariables->get_Item(vtItemName, &vtHTTPS); if(vtHTTPS.vt != VT_BSTR) VariantChangeType(&vtHTTPS, &vtHTTPS, 0, VT_BSTR); // If not default port, append ":port" to server name. bHasPort = (lstrcmpiW(L"off", vtHTTPS.bstrVal) == 0 && lstrcmpW(L"80", vtServerPort.bstrVal) != 0) || (lstrcmpiW(L"on", vtHTTPS.bstrVal) == 0 && lstrcmpW(L"443", vtServerPort.bstrVal) != 0); dwServerNameLen = bHasPort ? lstrlenW(vtServerName.bstrVal) + lstrlenW(vtServerPort.bstrVal) + 2 : lstrlenW(vtServerName.bstrVal) + 1; m_szHostName = new CHAR[dwServerNameLen]; if( !m_szHostName ) { hr = E_OUTOFMEMORY; goto exit; } WideCharToMultiByte(CP_ACP, 0, vtServerName.bstrVal, -1, m_szHostName, dwServerNameLen, NULL, NULL); if(bHasPort) { USES_CONVERSION; lstrcatA(m_szHostName, ":"); lstrcatA(m_szHostName, W2A(vtServerPort.bstrVal)); } crc = g_config->checkoutRegistryConfig(m_szHostName); } else { crc = g_config->checkoutRegistryConfig(); } m_keyVersion = 0; if (crc) { m_keyVersion = crc->getCurrentCryptVersion(); crc->getCrypt(m_keyVersion,&m_validUntil); } } catch(...) { hr = S_OK; } exit: if( crc ) crc->Release(); return hr; } //=========================================================================== // // Encrypt // STDMETHODIMP CCrypt::Encrypt(BSTR rawData, BSTR *pEncrypted) { if (!rawData) return E_INVALIDARG; if (SysStringLen(rawData) > ENC_MAX_SIZE) { AtlReportError(CLSID_Crypt, L"Passport.Crypt: Data too large", IID_IPassportCrypt, E_FAIL); return E_FAIL; } if (m_crypt) { if (!m_crypt->Encrypt(m_keyVersion, (LPSTR)rawData, SysStringByteLen(rawData), pEncrypted)) { AtlReportError(CLSID_Crypt, L"Encryption failed", IID_IPassportCrypt, E_FAIL); return E_FAIL; } } else { CRegistryConfig* crc = ObtainCRC(); if (!crc) { AtlReportError(CLSID_Crypt, L"Passport misconfigured", IID_IPassportCrypt, E_FAIL); return E_FAIL; } CCoCrypt *cr = crc->getCrypt(m_keyVersion,&m_validUntil); if (!cr) { AtlReportError(CLSID_Crypt, L"No such key version", IID_IPassportCrypt, E_FAIL); crc->Release(); return E_FAIL; } if (!cr->Encrypt(m_keyVersion,(LPSTR)rawData,SysStringByteLen(rawData),pEncrypted)) { AtlReportError(CLSID_Crypt, L"Encryption failed", IID_IPassportCrypt, E_FAIL); crc->Release(); return E_FAIL; } crc->Release(); } return S_OK; } //=========================================================================== // // Decrypt // STDMETHODIMP CCrypt::Decrypt(BSTR rawData, BSTR *pUnencrypted) { if (rawData == NULL) { *pUnencrypted = NULL; return S_OK; } if (SysStringLen(rawData) > DEC_MAX_SIZE) { AtlReportError(CLSID_Crypt, L"Passport.Crypt: Data too large", IID_IPassportCrypt, E_FAIL); return E_FAIL; } if (m_crypt) // Just do our job, no questions { if (m_crypt->Decrypt(rawData, SysStringByteLen(rawData), pUnencrypted)) { return S_OK; } if(g_pAlert) g_pAlert->report(PassportAlertInterface::WARNING_TYPE, PM_FAILED_DECRYPT); *pUnencrypted = NULL; return S_OK; } // First find the key version int kv = CCoCrypt::getKeyVersion(rawData); time_t vU, now; CRegistryConfig* crc = ObtainCRC(); if (!crc) { AtlReportError(CLSID_Crypt, L"Passport misconfigured", IID_IPassportCrypt, PP_E_NOT_CONFIGURED); return PP_E_NOT_CONFIGURED; } CCoCrypt *cr = crc->getCrypt(kv, &vU); time(&now); if ((vU != 0 && now > vU) || cr == NULL) { *pUnencrypted = NULL; if(g_pAlert) g_pAlert->report(PassportAlertInterface::WARNING_TYPE, PM_FAILED_DECRYPT); crc->Release(); return S_OK; } if (cr->Decrypt(rawData, SysStringByteLen(rawData), pUnencrypted)) { crc->Release(); return S_OK; } if(g_pAlert) g_pAlert->report(PassportAlertInterface::WARNING_TYPE, PM_FAILED_DECRYPT); crc->Release(); *pUnencrypted = NULL; return S_OK; } //=========================================================================== // // get_keyVersion // STDMETHODIMP CCrypt::get_keyVersion(int *pVal) { *pVal = m_keyVersion; return S_OK; } //=========================================================================== // // put_keyVersion // STDMETHODIMP CCrypt::put_keyVersion(int newVal) { m_keyVersion = newVal; if (m_crypt) { delete m_crypt; m_crypt = NULL; } return S_OK; } //=========================================================================== // // vget_IsValid // STDMETHODIMP CCrypt::get_IsValid(VARIANT_BOOL *pVal) { // fix 6695 PassportCrypt.IsValid is inconsistent to end users. // *pVal = (m_crypt != NULL) ? VARIANT_TRUE : VARIANT_FALSE; *pVal = (g_config->isValid()) ? VARIANT_TRUE : VARIANT_FALSE; return S_OK; } //=========================================================================== // // put_keyMaterial // STDMETHODIMP CCrypt::put_keyMaterial(BSTR newVal) { CCoCrypt *pcccTemp = new CCoCrypt(); if (pcccTemp == NULL) { return E_OUTOFMEMORY; } if (m_crypt) { delete m_crypt; } m_crypt = pcccTemp; m_crypt->setKeyMaterial(newVal); return S_OK; } //=========================================================================== // // Compress // STDMETHODIMP CCrypt::Compress( BSTR bstrIn, BSTR* pbstrCompressed ) { HRESULT hr; UINT nInLen; // // Check inputs. // if(bstrIn == NULL || pbstrCompressed == NULL) { hr = E_POINTER; goto Cleanup; } // // nInLen does not include the terminating NULL. // nInLen = SysStringLen(bstrIn); // // Always want to allocate an even number of bytes // so that the corresponding decompress does not // lose characters. // if(nInLen & 0x1) nInLen++; // // Allocate a BSTR of the correct length. // *pbstrCompressed = SysAllocStringByteLen(NULL, nInLen); if(*pbstrCompressed == NULL) { hr = E_OUTOFMEMORY; goto Cleanup; } // // We allocated a total of nInLen + 2 bytes. Zero it out. // memset(*pbstrCompressed, 0, nInLen + sizeof(OLECHAR)); // // Convert to multibyte. // if (0 == WideCharToMultiByte(CP_ACP, 0, bstrIn, nInLen, (LPSTR)*pbstrCompressed, nInLen + 1, // this is how many bytes were allocated by // SysAllocStringByteLen NULL, NULL)) { hr = E_FAIL; } else { hr = S_OK; } Cleanup: return hr; } //=========================================================================== // // Decompress // STDMETHODIMP CCrypt::Decompress( BSTR bstrIn, BSTR* pbstrDecompressed ) { HRESULT hr; CHAR *pch; UINT nInLen; if(bstrIn == NULL || pbstrDecompressed == NULL) { hr = E_POINTER; goto Cleanup; } // // nInLen is number of mbc's, and does not include the terminating NULL. // nInLen = SysStringByteLen(bstrIn); // // 13386: return NULL if 0 length // if (nInLen == 0) { *pbstrDecompressed = NULL; hr = S_OK; goto Cleanup; } pch = (CHAR*)bstrIn; if ('\0' == pch[nInLen - 1]) { nInLen--; } // // Allocate a BSTR of the correct length. // *pbstrDecompressed = SysAllocStringLen(NULL, nInLen); if(*pbstrDecompressed == NULL) { hr = E_OUTOFMEMORY; goto Cleanup; } // // We allocated a total of (nOutLen+1) * sizeof(OLECHAR) bytes, since // SysAllocStringLen allocs an extra character. Zero it all out. // memset(*pbstrDecompressed, 0, (nInLen + 1) * sizeof(OLECHAR)); // // Convert to wide. // if (0 == MultiByteToWideChar(CP_ACP, 0, (LPCSTR)bstrIn, -1, *pbstrDecompressed, nInLen + 1)) { hr = E_FAIL; } else { hr = S_OK; } Cleanup: return hr; } //=========================================================================== // // put_site // STDMETHODIMP CCrypt::put_site( BSTR bstrSiteName ) { HRESULT hr; int nLen; LPSTR szNewSiteName; CRegistryConfig* crc; if(!bstrSiteName) { if(m_szSiteName) delete [] m_szSiteName; m_szSiteName = NULL; } else { nLen = SysStringLen(bstrSiteName) + 1; szNewSiteName = new CHAR[nLen]; if(!szNewSiteName) { hr = E_OUTOFMEMORY; goto Cleanup; } WideCharToMultiByte(CP_ACP, 0, bstrSiteName, -1, szNewSiteName, nLen, NULL, NULL); Cleanup(); m_szSiteName = szNewSiteName; } crc = ObtainCRC(); if (!crc) { m_keyVersion = 0; } else { m_keyVersion = crc->getCurrentCryptVersion(); crc->getCrypt(m_keyVersion,&m_validUntil); crc->Release(); } hr = S_OK; Cleanup: return hr; } //=========================================================================== // // put_host // STDMETHODIMP CCrypt::put_host( BSTR bstrHostName ) { HRESULT hr; int nLen; LPSTR szNewHostName; CRegistryConfig* crc; if(!bstrHostName) { if(m_szHostName) delete [] m_szHostName; m_szHostName = NULL; } else { nLen = SysStringLen(bstrHostName) + 1; szNewHostName = new CHAR[nLen]; if(!szNewHostName) { hr = E_OUTOFMEMORY; goto Cleanup; } WideCharToMultiByte(CP_ACP, 0, bstrHostName, -1, szNewHostName, nLen, NULL, NULL); Cleanup(); m_szHostName = szNewHostName; crc = ObtainCRC(); if (!crc) { m_keyVersion = 0; } else { m_keyVersion = crc->getCurrentCryptVersion(); crc->getCrypt(m_keyVersion,&m_validUntil); crc->Release(); } } hr = S_OK; Cleanup: return hr; } //=========================================================================== // // Cleanup // void CCrypt::Cleanup() { if( m_szSiteName ) { delete [] m_szSiteName; m_szSiteName = NULL; } if( m_szHostName ) { delete [] m_szHostName; m_szHostName = NULL; } } //=========================================================================== // // ObtainCRC // CRegistryConfig* CCrypt::ObtainCRC() { CRegistryConfig* crc = NULL; if( m_szHostName && m_szSiteName ) { // we are in bad state now Cleanup(); goto exit; } if( m_szHostName ) crc = g_config->checkoutRegistryConfig(m_szHostName); if( m_szSiteName ) crc = g_config->checkoutRegistryConfigBySite(m_szSiteName); // if we still can't get crc at this moment, try the default one if( !crc ) crc = g_config->checkoutRegistryConfig(); exit: return crc; } ///////////////////////////////////////////////////////////////////////////// // IPassportService implementation //=========================================================================== // // Initialize // STDMETHODIMP CCrypt::Initialize(BSTR configfile, IServiceProvider* p) { HRESULT hr; // Initialize. if (!g_config->isValid()) { AtlReportError(CLSID_Crypt, PP_E_NOT_CONFIGUREDSTR, IID_IPassportService, PP_E_NOT_CONFIGURED); hr = PP_E_NOT_CONFIGURED; goto Cleanup; } hr = S_OK; Cleanup: return hr; } //=========================================================================== // // Shutdown // STDMETHODIMP CCrypt::Shutdown() { return S_OK; } //=========================================================================== // // ReloadState // STDMETHODIMP CCrypt::ReloadState(IServiceProvider*) { return S_OK; } //=========================================================================== // // CommitState // STDMETHODIMP CCrypt::CommitState(IServiceProvider*) { return S_OK; } //=========================================================================== // // DumpState // STDMETHODIMP CCrypt::DumpState(BSTR* pbstrState) { ATLASSERT( *pbstrState != NULL && "CCrypt:DumpState - " "Are you sure you want to hand me a non-null BSTR?" ); HRESULT hr = S_OK; return hr; }