#include "stdafx.h" #include "KeyObjs.h" #include "CmnKey.h" #include "W3Key.h" #include "W3Serv.h" #include "resource.h" #include "kmlsa.h" #include "CnctDlg.h" extern HINSTANCE g_hInstance; // defines taken from the old KeyGen utility #define MESSAGE_HEADER "-----BEGIN NEW CERTIFICATE REQUEST-----\r\n" #define MESSAGE_TRAILER "-----END NEW CERTIFICATE REQUEST-----\r\n" #define MIME_TYPE "Content-Type: application/x-pkcs10\r\n" #define MIME_ENCODING "Content-Transfer-Encoding: base64\r\n\r\n" IMPLEMENT_DYNCREATE(CW3Key, CKey); CW3Key::CW3Key() : m_fDefault(FALSE) { } CW3Key::~CW3Key() { } //------------------------------------------------------------- // update the key's caption void CW3Key::UpdateCaption( void ) { // specify the resources to use HINSTANCE hOldRes = AfxGetResourceHandle(); AfxSetResourceHandle( g_hInstance ); // the caption is based on the name of the key CString szCaption = m_szName; // if the key is not attached at all, do not put the brackets on at all if ( m_fDefault || !m_szIPAddress.IsEmpty() ) { // now we take on info about the server it is attached to szCaption += _T(" <"); if ( m_fDefault ) { CString szDefault; szDefault.LoadString( IDS_DEFAULT ); szCaption += szDefault; } else { szCaption += m_szIPAddress; } szCaption += _T(">"); } // and setup the caption m_szItemName = szCaption; FSetCaption(szCaption); // update the icon too UpdateIcon(); // restore the resources AfxSetResourceHandle( hOldRes ); } //------------------------------------------------------------- // init from keyset key //------------------------------------------------------------- BOOL CW3Key::FInitKey( HANDLE hPolicy, PWCHAR pwszName ) { ASSERT( hPolicy && pwszName ); // set the initial strings m_szName.LoadString( IDS_UNTITLED ); // import the w3 key information if ( !ImportW3Key(hPolicy, pwszName) ) return FALSE; // bring over the sz_ipaddress for the key m_szIPAddress = pwszName; // if it is the default key, flip the flag if ( m_szIPAddress == _T("Default") ) { m_fDefault = TRUE; m_szIPAddress.Empty(); } // build the caption name UpdateCaption(); return TRUE; } //------------------------------------------------------------- // init from stored keyset key //------------------------------------------------------------- BOOL CW3Key::FInitKey( PVOID pData, DWORD cbSrc) { ASSERT( pData ); // init from the data if ( !InitializeFromPointer( (PUCHAR)pData, cbSrc ) ) return FALSE; // build the caption name UpdateCaption(); return TRUE; } //------------------------------------------------------------- // make a copy of the key //------------------------------------------------------------- CKey* CW3Key::PClone( void ) { CW3Key* pClone = NULL; // TRY to make a new key object try { pClone = new CW3Key; // copy over all the data pClone->CopyDataFrom( this ); } catch( CException e ) { // if the object had been made, delete it if ( pClone ) delete pClone; return NULL; } return (CKey*)pClone; } //------------------------------------------------------------- // copy the members from a key into this key //------------------------------------------------------------- void CW3Key::CopyDataFrom( CKey* pKey ) { // copy over the base data CKey::CopyDataFrom( pKey ); // if the key we are copying from is a W3 key, copy over // the w3 specific information as well if ( pKey->IsKindOf(RUNTIME_CLASS(CW3Key)) ) { CW3Key* pW3Key = (CW3Key*)pKey; m_szName = pW3Key->m_szName; } else { m_szName = pKey->m_szItemName; } // we do NOT copy over the default-type settings m_fDefault = FALSE; m_szName.Empty(); } //------------------------------------------------------------- void CW3Key::OnProperties() { // specify the resources to use HINSTANCE hOldRes = AfxGetResourceHandle(); AfxSetResourceHandle( g_hInstance ); // the properties of the w3 key invove its ip address relationship CConnectionDlg dlg; // set the instance members of the dialog dlg.m_int_connection_type = CONNECTION_NONE; if ( m_fDefault ) dlg.m_int_connection_type = CONNECTION_DEFAULT; if ( !m_szIPAddress.IsEmpty() ) dlg.m_int_connection_type = CONNECTION_IPADDRESS; dlg.m_szIPAddress = m_szIPAddress; dlg.m_pKey = this; // run the dialog if ( dlg.DoModal() == IDOK ) { // get the ip address m_szIPAddress = dlg.m_szIPAddress; // get whether or not this is the default and set it if ( dlg.m_int_connection_type == CONNECTION_DEFAULT ) SetDefault(); else m_fDefault = FALSE; // cause the name to rebuild UpdateCaption(); // set it dirty SetDirty( TRUE ); } // restore the resources AfxSetResourceHandle( hOldRes ); } //------------------------------------------------------------- // install a cert - mostly just use the default action BOOL CW3Key::FInstallCertificate( PVOID pCert, DWORD cbCert, CString &szPass ) { // first, we should test that the certificate and password are valid // for this particular key // cache the old certificate in case the new one fails DWORD old_cbCertificate = m_cbCertificate; PVOID old_pCertificate = m_pCertificate; // set the new one into place m_cbCertificate = cbCert; m_pCertificate = pCert; // verify the password - verify password puts up any error dialogs if ( !FVerifyValidPassword(szPass) ) { // resore the old values m_cbCertificate = old_cbCertificate; m_pCertificate = old_pCertificate; // dispose of the new stuff GlobalFree( pCert ); // return false return FALSE; } // run the default action BOOL fDefault = CKey::FInstallCertificate(pCert, cbCert, szPass); // if the default works, then take into account the ip releationship if ( fDefault ) { // get the owning service object CW3KeyService* pService = (CW3KeyService*)PGetParent(); // if this key is not set to any ip addresses or the default, check to // see if there is a default on this service. If there isn't, then set // this key to be the default. if ( pService && !m_fDefault && m_szIPAddress.IsEmpty() ) { // get the service's default key CW3Key* pKeyDefault = pService->PGetDefaultKey(); // if there is no default key, then this is easy, just set the default flag if ( !pKeyDefault ) m_fDefault = TRUE; else // tell the user to select a connection option AfxMessageBox( IDS_SelectConnectMsg, MB_OK|MB_ICONINFORMATION ); // cause the name to rebuild UpdateCaption(); } } // return the default answer return fDefault; } //------------------------------------------------------------- void CW3Key::SetDefault() { // get the owning service object CW3KeyService* pService = (CW3KeyService*)PGetParent(); // get the service's default key CW3Key* pKeyDefault = pService->PGetDefaultKey(); // we only need to bother if there is a default key if ( pKeyDefault ) { // change the old default key from default to none and update its caption pKeyDefault->m_fDefault = FALSE; pKeyDefault->UpdateCaption(); } // set the default flag m_fDefault = TRUE; } //================ storage related methods //------------------------------------------------------------------------------ BOOL CW3Key::WriteKey( HANDLE hPolicy, WORD iKey, PWCHAR pwcharName ) { HGLOBAL hKeyData; PVOID pKeyData; SIZE_T cbKeyData; BOOL f = TRUE; DWORD err; // blank out the wide name of the string ASSERT( pwcharName ); wcscpy( pwcharName, L"" ); // now write out the normal part of the key PCHAR pName = (PCHAR)GlobalAlloc( GPTR, MAX_PATH+1 ); PWCHAR pWName = (PWCHAR)GlobalAlloc( GPTR, (MAX_PATH+1) * sizeof(WCHAR) ); // make sure we got the name buffers ASSERT( pName && pWName ); if ( !pName || !pWName ) return FALSE; // if this key should write out W3 compatible keys, then do so if ( m_fDefault || !m_szIPAddress.IsEmpty() ) { // if it is the default key, then the name is really easy if ( m_fDefault ) { f = WriteW3Keys( hPolicy, KEYSET_DEFAULT ); wcscpy( pwcharName, KEYSET_DEFAULT ); } else { // prepare the name MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED, m_szIPAddress, -1, pWName, MAX_PATH+1 ); // write the keys f = WriteW3Keys( hPolicy, pWName ); wcscpy( pwcharName, pWName ); } } // get the data from the key hKeyData = HGenerateDataHandle( TRUE ); if ( !hKeyData ) { GlobalFree( (HGLOBAL)pName ); GlobalFree( (HGLOBAL)pWName ); return FALSE; } // prepare the name of the secret. - Base name plus the number+1 sprintf( pName, "%s%d", KEY_NAME_BASE, iKey+1 ); // unicodize the name MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED, pName, -1, pWName, MAX_PATH+1 ); // lock it down and get its size cbKeyData = GlobalSize(hKeyData); pKeyData = GlobalLock(hKeyData); ASSERT( cbKeyData < 0xFFFF ); // write out the secret f &= FStoreLSASecret( hPolicy, pWName, pKeyData, (WORD)cbKeyData, &err ); // unlock the data and get rid of it GlobalUnlock(hKeyData); GlobalFree( hKeyData ); // free the string buffers GlobalFree( (HANDLE)pName ); GlobalFree( (HANDLE)pWName ); // set the dirty flag SetDirty( !f ); // return success return f; } //------------------------------------------------------------------------------ // If the key is being initialized from a keyset key, we must import the old W3 info BOOL CW3Key::ImportW3Key( HANDLE hPolicy, WCHAR* pWName ) { DWORD err; PWCHAR pWSecret = (PWCHAR)GlobalAlloc( GPTR, (MAX_PATH+1) * sizeof(WCHAR) ); PLSA_UNICODE_STRING pLSAData; #ifdef _DEBUG CString szName = pWName; #endif // make sure we got the buffers ASSERT( pWName && pWSecret ); if ( !pWSecret ) { AfxThrowMemoryException(); return FALSE; } // start by retrieving the private key swprintf( pWSecret, KEYSET_PRIV_KEY, pWName ); #ifdef _DEBUG szName = pWSecret; #endif pLSAData = FRetrieveLSASecret( hPolicy, pWSecret, &err ); if ( !pLSAData ) { AfxMessageBox( IDS_IMPORT_KEYSET_PRIV_ERROR ); return FALSE; } // make room for the public key and put it in its place m_cbPrivateKey = pLSAData->Length; m_pPrivateKey = GlobalAlloc( GPTR, m_cbPrivateKey ); if ( !m_pPrivateKey ) AfxThrowMemoryException(); CopyMemory( m_pPrivateKey, pLSAData->Buffer, m_cbPrivateKey ); // dispose of the data DisposeLSAData( pLSAData ); // start by retrieving the public key (certificate) swprintf( pWSecret, KEYSET_PUB_KEY, pWName ); #ifdef _DEBUG szName = pWSecret; #endif pLSAData = FRetrieveLSASecret( hPolicy, pWSecret, &err ); if ( !pLSAData ) { AfxMessageBox( IDS_IMPORT_KEYSET_PUB_ERROR ); return FALSE; } // make room for the public key and put it in its place m_cbCertificate = pLSAData->Length; m_pCertificate = GlobalAlloc( GPTR, m_cbCertificate ); if ( !m_pCertificate ) AfxThrowMemoryException(); CopyMemory( m_pCertificate, pLSAData->Buffer, m_cbCertificate ); // dispose of the data DisposeLSAData( pLSAData ); // lastly, get the password swprintf( pWSecret, KEYSET_PASSWORD, pWName ); #ifdef _DEBUG szName = pWSecret; #endif pLSAData = FRetrieveLSASecret( hPolicy, pWSecret, &err ); if ( !pLSAData ) { AfxMessageBox( IDS_IMPORT_KEYSET_PASS_ERROR ); return FALSE; } // this is actually really easy because CString does the work for us // this is NOT stored as UNICODE!!!! m_szPassword = (PSTR)pLSAData->Buffer; // dispose of the data DisposeLSAData( pLSAData ); // free the buffer for the secret names if ( pWSecret ) GlobalFree( pWSecret ); // return success return TRUE; } //------------------------------------------------------------------------------ // write the important parts of the key out to the server as W3 readable secrets // the name is put into the list elsewhere BOOL CW3Key::WriteW3Keys( HANDLE hPolicy, WCHAR* pWName ) { DWORD err; PWCHAR pWSecret = (PWCHAR)GlobalAlloc( GPTR, (MAX_PATH+1) * sizeof(WCHAR) ); BOOL f; // make sure we got the buffer ASSERT( pWName && pWSecret ); if ( !pWSecret ) { AfxThrowMemoryException(); return FALSE; } // write out the keys swprintf( pWSecret, KEYSET_PRIV_KEY, pWName ); ASSERT( m_cbPrivateKey < 0xFFFF ); ASSERT( m_pPrivateKey ); f = FStoreLSASecret( hPolicy, pWSecret, m_pPrivateKey, (WORD)m_cbPrivateKey, &err ); swprintf( pWSecret, KEYSET_PUB_KEY, pWName ); ASSERT( m_cbCertificate < 0xFFFF ); ASSERT( m_pCertificate ); if ( f ) f = FStoreLSASecret( hPolicy, pWSecret, m_pCertificate, (WORD)m_cbCertificate, &err ); // The password is NOT stored as UNICODE!!!!!!! swprintf( pWSecret, KEYSET_PASSWORD, pWName ); ASSERT( m_szPassword ); if ( f ) f = FStoreLSASecret( hPolicy, pWSecret, (void*)LPCSTR(m_szPassword), m_szPassword.GetLength()+1, &err ); // free the buffer for the secret names GlobalFree( (HANDLE)pWSecret ); // return whether or not we succeeded return f; }