Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

672 lines
18 KiB

  1. // This file is the metadata version of the key storage object for the w3 server.
  2. // it knows nothing about the LSA storage and only interacts with the metabase. Likewise,
  3. // it does not convert old keyset.exe keys into a newer format. Any old LSA keys should have
  4. // automatically converted to the new metabase format by the setup utility.
  5. // file created 4/1/1997 by BoydM
  6. #include "stdafx.h"
  7. #include "KeyObjs.h"
  8. #include "iiscnfgp.h"
  9. #include "wrapmb.h"
  10. #include "cmnkey.h"
  11. #include "mdkey.h"
  12. #include "mdserv.h"
  13. #include "crackcrt.h"
  14. #include "resource.h"
  15. #include "ListRow.h"
  16. #include "bindsdlg.h"
  17. IMPLEMENT_DYNCREATE(CMDKey, CKey);
  18. #define MAX_LEN (METADATA_MAX_NAME_LEN * sizeof(WCHAR))
  19. #define DEFAULT_PORT 443
  20. extern HINSTANCE g_hInstance;
  21. //--------------------------------------------------------
  22. CMDKey::CMDKey() :
  23. m_fUpdateKeys( FALSE ),
  24. m_fUpdateFriendlyName( FALSE ),
  25. m_fUpdateIdent( FALSE ),
  26. m_fUpdateBindings( FALSE ),
  27. m_pService( NULL )
  28. {}
  29. //--------------------------------------------------------
  30. CMDKey::CMDKey(CMDKeyService* pService) :
  31. m_fUpdateKeys( FALSE ),
  32. m_fUpdateFriendlyName( FALSE ),
  33. m_fUpdateIdent( FALSE ),
  34. m_fUpdateBindings( FALSE ),
  35. m_pService( pService )
  36. {}
  37. //--------------------------------------------------------
  38. CMDKey::~CMDKey()
  39. {}
  40. //-------------------------------------------------------------
  41. void CMDKey::SetName( CString &szNewName )
  42. {
  43. CCmnKey::SetName( szNewName );
  44. m_fUpdateFriendlyName = TRUE;
  45. }
  46. //-------------------------------------------------------------
  47. // update the key's caption
  48. void CMDKey::UpdateCaption( void )
  49. {
  50. // specify the resources to use
  51. HINSTANCE hOldRes = AfxGetResourceHandle();
  52. AfxSetResourceHandle( g_hInstance );
  53. CString sz;
  54. // the caption is based on the name of the key
  55. CString szCaption = m_szName;
  56. // now we tack on info about the server it is attached to
  57. szCaption += _T(" <");
  58. switch( m_rgbszBindings.GetSize() )
  59. {
  60. case 0: // there are no bindings, do nothing
  61. sz.Empty();
  62. break;
  63. case 1: // if there is only one binding, use it in the brackets
  64. sz = m_rgbszBindings[0];
  65. // actually, we need to see if it is the non-localized default string
  66. if ( sz == MDNAME_DEFAULT )
  67. sz.LoadString( IDS_DEFAULT ); // load the localized default string
  68. break;
  69. default: // there are multiple bindings, say so
  70. sz.LoadString( IDS_MULTIPLE_BINDINGS );
  71. break;
  72. };
  73. // close the brackets
  74. szCaption += sz;
  75. szCaption += _T(">");
  76. // and setup the caption
  77. m_szItemName = szCaption;
  78. FSetCaption(szCaption);
  79. // update the icon too
  80. UpdateIcon();
  81. // restore the resources
  82. AfxSetResourceHandle( hOldRes );
  83. }
  84. //-------------------------------------------------------------
  85. // make a copy of the key
  86. //-------------------------------------------------------------
  87. CKey* CMDKey::PClone( void )
  88. {
  89. CMDKey* pClone = NULL;
  90. // TRY to make a new key object
  91. try
  92. {
  93. pClone = new CMDKey(m_pService);
  94. // copy over all the data
  95. pClone->CopyDataFrom( this );
  96. }
  97. catch( CException e )
  98. {
  99. // if the object had been made, delete it
  100. if ( pClone )
  101. delete pClone;
  102. return NULL;
  103. }
  104. return (CKey*)pClone;
  105. }
  106. //-------------------------------------------------------------
  107. // copy the members from a key into this key
  108. //-------------------------------------------------------------
  109. void CMDKey::CopyDataFrom( CKey* pKey )
  110. {
  111. // copy over the base data
  112. CKey::CopyDataFrom( pKey );
  113. // if the key we are copying from is a MD key, copy over
  114. // the w3MD specific information as well
  115. if ( pKey->IsKindOf(RUNTIME_CLASS(CMDKey)) )
  116. {
  117. CMDKey* pMDKey = (CMDKey*)pKey;
  118. m_szName = pMDKey->m_szName;
  119. }
  120. else
  121. {
  122. m_szName = pKey->m_szItemName;
  123. }
  124. }
  125. //-------------------------------------------------------------
  126. void CMDKey::OnProperties()
  127. {
  128. // specify the resources to use
  129. HINSTANCE hOldRes = AfxGetResourceHandle();
  130. AfxSetResourceHandle( g_hInstance );
  131. // if this key does not have a signed certificate, do not allow the user
  132. // to make any bindings to it
  133. if ( !m_pCertificate )
  134. {
  135. AfxMessageBox( IDS_DONT_BIND_UNSIGNED );
  136. // restore the resources
  137. AfxSetResourceHandle( hOldRes );
  138. return;
  139. }
  140. // the properties of the w3 key invove its ip address relationship
  141. CBindingsDlg dlg( m_pService->m_pszwMachineName );
  142. // give it this key
  143. dlg.m_pKey = this;
  144. // set the instance members of the dialog
  145. // run the dialog
  146. if ( dlg.DoModal() == IDOK )
  147. {
  148. // cause the name to rebuild
  149. UpdateCaption();
  150. // set it dirty
  151. SetDirty( TRUE );
  152. }
  153. // restore the resources
  154. AfxSetResourceHandle( hOldRes );
  155. }
  156. //--------------------------------------------------------
  157. // add a binding to the binding list
  158. void CMDKey::AddBinding( LPCSTR psz )
  159. {
  160. CString szBinding = psz;
  161. // filter out disabled or incomplete key bindings
  162. if ( (szBinding.Find(MDNAME_INCOMPLETE) >= 0) ||
  163. (szBinding.Find(MDNAME_DISABLED) >= 0) )
  164. {
  165. return;
  166. }
  167. // add the binding to the list
  168. m_rgbszBindings.Add( psz );
  169. // update the caption if we need to
  170. switch( m_rgbszBindings.GetSize() )
  171. {
  172. case 1: // the display changes on these
  173. case 2:
  174. UpdateCaption();
  175. };
  176. }
  177. //--------------------------------------------------------
  178. // is a given binding already associated with the key
  179. void CMDKey::RemoveBinding( CString szBinding )
  180. {
  181. DWORD nItems, iItem;
  182. // scan the binding list
  183. nItems = m_rgbszBindings.GetSize();
  184. for ( iItem = 0; iItem < nItems; iItem++ )
  185. {
  186. // look for the binding
  187. if ( szBinding == m_rgbszBindings[iItem] )
  188. {
  189. // found it!
  190. m_rgbszBindings.RemoveAt( iItem );
  191. m_fUpdateBindings = TRUE;
  192. // update the caption if we need to
  193. switch( m_rgbszBindings.GetSize() )
  194. {
  195. case 0: // the display changes on these
  196. case 1:
  197. UpdateCaption();
  198. };
  199. }
  200. }
  201. }
  202. //--------------------------------------------------------
  203. // is a given binding already associated with the key
  204. BOOL CMDKey::FContainsBinding( CString szBinding )
  205. {
  206. DWORD nItems, iItem;
  207. // scan the binding list
  208. nItems = m_rgbszBindings.GetSize();
  209. for ( iItem = 0; iItem < nItems; iItem++ )
  210. {
  211. // look for the binding
  212. if ( szBinding == m_rgbszBindings[iItem] )
  213. {
  214. // found it!
  215. return TRUE;
  216. }
  217. }
  218. // we did not find the binding
  219. return FALSE;
  220. }
  221. //--------------------------------------------------------
  222. BOOL CMDKey::FGetIdentString( CString &szIdent )
  223. {
  224. // make sure the cert is there
  225. if ( !m_pCertificate || !m_cbCertificate )
  226. return FALSE;
  227. return FGetIdentString( m_pCertificate, m_cbCertificate, szIdent );
  228. }
  229. //--------------------------------------------------------
  230. BOOL CMDKey::FGetIdentString( PVOID pCert, DWORD cbCert, CString &szIdent )
  231. {
  232. // declare the cracker object
  233. CCrackedCert cracker;
  234. // crack the cert
  235. if ( cracker.CrackCert( (PUCHAR)pCert, cbCert ) )
  236. {
  237. DWORD* pdw = cracker.PGetSerialNumber();
  238. szIdent.Format( "%d:%d:%d:%d", pdw[0], pdw[1], pdw[2], pdw[3] );
  239. // success
  240. return TRUE;
  241. }
  242. return FALSE;
  243. }
  244. //--------------------------------------------------------
  245. // does a given key name exist already in the metabase?
  246. BOOL CMDKey::FGetIdentString( CWrapMetaBase* pWrap, PCHAR pszObj, CString &szIdent )
  247. {
  248. BOOL fAnswer = FALSE;
  249. DWORD cbData;
  250. PVOID pData;
  251. CString sz;
  252. // if this is an incomplete key, fail
  253. if ( _tcsncmp(MDNAME_INCOMPLETE, pszObj, _tcslen(MDNAME_INCOMPLETE)) == 0 )
  254. return FALSE;
  255. // try and ready the cached ident directly.
  256. BOOL f = pWrap->GetString( pszObj, MD_SSL_IDENT, IIS_MD_UT_SERVER,
  257. sz.GetBuffer(MAX_LEN), MAX_LEN);
  258. sz.ReleaseBuffer();
  259. if ( f )
  260. {
  261. // good. It was cached.
  262. szIdent = sz;
  263. m_szIdent = szIdent;
  264. return TRUE;
  265. }
  266. // drat. We haven't cached the ident for this key before. we need to get it. This
  267. // means loading the certificate - and cracking it to get the serial number. If there
  268. // is no certificate (an incomplete key) we return false.
  269. pData = pWrap->GetData( pszObj, MD_SSL_PUBLIC_KEY, IIS_MD_UT_SERVER,
  270. BINARY_METADATA, &cbData, 0 );
  271. // we got the certificate and can now crack it
  272. if ( pData )
  273. {
  274. m_fUpdateIdent = FGetIdentString( (PUCHAR)pData, cbData, szIdent );
  275. fAnswer = m_fUpdateIdent;
  276. // cache the ident in memory. It will get written out on Commit
  277. m_szIdent = szIdent;
  278. /*
  279. // declare the cracker object
  280. CCrackedCert cracker;
  281. // crack the cert
  282. if ( cracker.CrackCert( (PUCHAR)pData, cbData ) )
  283. {
  284. DWORD* pdw = cracker.PGetSerialNumber();
  285. szIdent.Format( "%d:%d:%d:%d", pdw[0], pdw[1], pdw[2], pdw[3] );
  286. // cache the ident in memory. It will get written out on Commit
  287. m_szIdent = szIdent;
  288. m_fUpdateIdent = TRUE;
  289. // success
  290. fAnswer = TRUE;
  291. }
  292. */
  293. // free the buffer
  294. pWrap->FreeWrapData( pData );
  295. }
  296. else
  297. {
  298. // we did not get the certificate - return FALSE
  299. // fAnswer is already set to false
  300. }
  301. // return the answer;
  302. return fAnswer;
  303. }
  304. //--------------------------------------------------------
  305. BOOL CMDKey::FWriteKey( CWrapMetaBase* pWrap, DWORD iKey, CStringArray* prgbszTracker )
  306. {
  307. BOOL f;
  308. DWORD nBindings = m_rgbszBindings.GetSize();
  309. CString szBinding;
  310. BOOL fUpdateAll = FALSE;
  311. // if there are no assigned bindings, the key still gets stored with a object
  312. // name in the format of "disabled{iKey}". and if it is incomplete, then store
  313. // it with the name "incomplete{iKey}" Because the iKey can change and we don't
  314. // want any conflicts, re-write them
  315. if ( nBindings == 0 )
  316. {
  317. // build the binding name as appropriate
  318. if ( m_pCertificate )
  319. szBinding.Format( "%s%d", MDNAME_DISABLED, iKey );
  320. else
  321. szBinding.Format( "%s%d", MDNAME_INCOMPLETE, iKey );
  322. // set the update flag
  323. m_fUpdateBindings = TRUE;
  324. }
  325. // NOTE: pWrap has already been opened to /LM/W3Svc/SSLKeys
  326. // if the key is not dirty, its easy
  327. if ( !m_fUpdateKeys && !m_fUpdateFriendlyName && !m_fUpdateIdent && !m_fUpdateBindings && !FGetDirty() )
  328. {
  329. // add names of its bindings so it doesn't get deleted
  330. DWORD iBinding;
  331. for ( iBinding = 0; iBinding < nBindings; iBinding++ )
  332. prgbszTracker->Add( m_rgbszBindings[iBinding] );
  333. return TRUE;
  334. }
  335. // handle no bindings as a special case first
  336. if ( nBindings == 0 )
  337. {
  338. // tell the server about it
  339. prgbszTracker->Add((LPCSTR)szBinding);
  340. // ok. Create the key in the metabase.
  341. f = pWrap->AddObject( szBinding );
  342. // and save the data
  343. f = FWriteData( pWrap, szBinding, TRUE );
  344. // clear the dirty flag and exit
  345. SetDirty( FALSE );
  346. return TRUE;
  347. }
  348. // there are bindings to be saved... loop though them and update each
  349. DWORD iBinding;
  350. for ( iBinding = 0; iBinding < nBindings; iBinding++ )
  351. {
  352. // get the binding name
  353. szBinding = m_rgbszBindings[iBinding];
  354. // test code
  355. if ( szBinding.IsEmpty() )
  356. AfxMessageBox( "Empty Binding Alert!" );
  357. // now that we know where to save it, add the name to list of saved
  358. // objects being kept track of by the server object - (This is so that
  359. // the server knows what's been added)
  360. prgbszTracker->Add((LPCSTR)szBinding);
  361. // ok. Create the key in the metabase. Really, we may only need to do this
  362. // if m_fUpdateBindings is set - if the object is new - update all the data
  363. fUpdateAll = pWrap->AddObject( szBinding ) || m_fUpdateBindings;
  364. // write out the data
  365. FWriteData( pWrap, szBinding, fUpdateAll );
  366. }
  367. // clear the flags
  368. m_fUpdateKeys = FALSE;
  369. m_fUpdateFriendlyName = FALSE;
  370. m_fUpdateIdent = FALSE;
  371. m_fUpdateBindings = FALSE;
  372. // clear the dirty flag
  373. SetDirty( FALSE );
  374. return TRUE;
  375. }
  376. //--------------------------------------------------------
  377. // write out the data portion to a particular binding
  378. BOOL CMDKey::FWriteData( CWrapMetaBase* pWrap, CString szBinding, BOOL fWriteAll )
  379. {
  380. BOOL f;
  381. // write all the parts of the key - start with the certificate
  382. // start with the secure parts
  383. if ( m_fUpdateKeys || fWriteAll )
  384. {
  385. if ( m_pCertificate )
  386. f = pWrap->SetData( szBinding, MD_SSL_PUBLIC_KEY, IIS_MD_UT_SERVER, BINARY_METADATA,
  387. m_pCertificate, m_cbCertificate,
  388. METADATA_SECURE );
  389. // write out the private key
  390. if ( m_pPrivateKey )
  391. f = pWrap->SetData( szBinding, MD_SSL_PRIVATE_KEY, IIS_MD_UT_SERVER, BINARY_METADATA,
  392. m_pPrivateKey, m_cbPrivateKey,
  393. METADATA_SECURE );
  394. // write out the password - treat is ast secure binary data
  395. if ( !m_szPassword.IsEmpty() )
  396. f = pWrap->SetData( szBinding, MD_SSL_KEY_PASSWORD, IIS_MD_UT_SERVER, BINARY_METADATA,
  397. (PVOID)(LPCSTR)m_szPassword, m_szPassword.GetLength()+1,
  398. METADATA_SECURE );
  399. // write out the request
  400. if ( m_pCertificateRequest )
  401. f = pWrap->SetData( szBinding, MD_SSL_KEY_REQUEST, IIS_MD_UT_SERVER, BINARY_METADATA,
  402. m_pCertificateRequest, m_cbCertificateRequest,
  403. METADATA_SECURE );
  404. }
  405. // write out the cached serial number
  406. if ( m_fUpdateIdent || m_fUpdateKeys || fWriteAll )
  407. if ( !m_szIdent.IsEmpty() )
  408. {
  409. f = pWrap->SetString( szBinding, MD_SSL_IDENT, IIS_MD_UT_SERVER,
  410. m_szIdent, METADATA_SECURE );
  411. }
  412. // write out the friendly name of the key
  413. if ( m_fUpdateFriendlyName || fWriteAll )
  414. f = pWrap->SetString( szBinding, MD_SSL_FRIENDLY_NAME, IIS_MD_UT_SERVER,
  415. m_szName, 0 );
  416. return TRUE;
  417. }
  418. //--------------------------------------------------------
  419. BOOL CMDKey::FLoadKey( CWrapMetaBase* pWrap, PCHAR pszObj )
  420. {
  421. DWORD cbData;
  422. PVOID pData;
  423. // start with the public key
  424. pData = pWrap->GetData( pszObj, MD_SSL_PUBLIC_KEY, IIS_MD_UT_SERVER,
  425. BINARY_METADATA, &cbData, 0 );
  426. if ( pData )
  427. {
  428. // set the data into place
  429. m_pCertificate = (PVOID)GlobalAlloc( GPTR, cbData );
  430. // if we got the pointer, copy the rest of the data into place
  431. if( m_pCertificate)
  432. {
  433. m_cbCertificate = cbData;
  434. CopyMemory( m_pCertificate, pData, cbData );
  435. }
  436. // free the buffer
  437. pWrap->FreeWrapData( pData );
  438. }
  439. // now the private key
  440. pData = pWrap->GetData( pszObj, MD_SSL_PRIVATE_KEY, IIS_MD_UT_SERVER,
  441. BINARY_METADATA, &cbData, 0 );
  442. if ( pData )
  443. {
  444. // set the data into place
  445. m_pPrivateKey = (PVOID)GlobalAlloc( GPTR, cbData );
  446. // if we got the pointer, copy the rest of the data into place
  447. if( m_pPrivateKey)
  448. {
  449. m_cbPrivateKey = cbData;
  450. CopyMemory( m_pPrivateKey, pData, cbData );
  451. }
  452. // free the buffer
  453. pWrap->FreeWrapData( pData );
  454. }
  455. // now the password key
  456. pData = pWrap->GetData( pszObj, MD_SSL_KEY_PASSWORD, IIS_MD_UT_SERVER,
  457. BINARY_METADATA, &cbData, 0 );
  458. if ( pData )
  459. {
  460. // set the data into place - relatively easy in this case
  461. m_szPassword = (LPCSTR)pData;
  462. // free the buffer
  463. pWrap->FreeWrapData( pData );
  464. }
  465. // now the request
  466. pData = pWrap->GetData( pszObj, MD_SSL_KEY_REQUEST, IIS_MD_UT_SERVER,
  467. BINARY_METADATA, &cbData, 0 );
  468. if ( pData )
  469. {
  470. // set the data into place
  471. m_pCertificateRequest = (PVOID)GlobalAlloc( GPTR, cbData );
  472. // if we got the pointer, copy the rest of the data into place
  473. if( m_pCertificateRequest)
  474. {
  475. m_cbCertificateRequest = cbData;
  476. CopyMemory( m_pCertificateRequest, pData, cbData );
  477. }
  478. // free the buffer
  479. pWrap->FreeWrapData( pData );
  480. }
  481. // finally, retrieve the friendly name
  482. BOOL f = pWrap->GetString( pszObj, MD_SSL_FRIENDLY_NAME, IIS_MD_UT_SERVER,
  483. m_szName.GetBuffer(MAX_LEN), MAX_LEN, 0);
  484. m_szName.ReleaseBuffer();
  485. if ( !f )
  486. m_szName.Empty();
  487. // make this item's metabase name the first name in the list
  488. AddBinding( pszObj );
  489. // Success
  490. return TRUE;
  491. }
  492. //-------------------------------------------------------------
  493. // install a cert
  494. BOOL CMDKey::FInstallCertificate( PVOID pCert, DWORD cbCert, CString &szPass )
  495. {
  496. // first, we should test that the certificate and password are valid
  497. // for this particular key
  498. // cache the old certificate in case the new one fails
  499. DWORD old_cbCertificate = m_cbCertificate;
  500. PVOID old_pCertificate = m_pCertificate;
  501. // set the new one into place
  502. m_cbCertificate = cbCert;
  503. m_pCertificate = pCert;
  504. // verify the password - verify password puts up any error dialogs
  505. if ( !FVerifyValidPassword(szPass) )
  506. {
  507. // resore the old values
  508. m_cbCertificate = old_cbCertificate;
  509. m_pCertificate = old_pCertificate;
  510. // dispose of the new stuff
  511. GlobalFree( pCert );
  512. // return false
  513. return FALSE;
  514. }
  515. // now we need to see if this key has already been installed
  516. // get the identification string
  517. CString szIdentThis;
  518. if ( !FGetIdentString( pCert, cbCert, szIdentThis ) )
  519. return FALSE;
  520. // scan the existing keys, looking for one with the same ident string
  521. // if one is found, tell the user that it already exists and fail
  522. CString szIdentTest;
  523. CMDKey* pTestKey = m_pService->GetFirstMDKey();
  524. while ( pTestKey )
  525. {
  526. // if we are testing against this key, continue
  527. if ( pTestKey == this )
  528. goto GETNEXTKEY;
  529. // get the test ident string
  530. if ( !pTestKey->FGetIdentString( pTestKey->m_pCertificate,
  531. pTestKey->m_cbCertificate, szIdentTest ) )
  532. goto GETNEXTKEY;
  533. // test the ident strings
  534. if ( szIdentThis == szIdentTest )
  535. {
  536. // the key already exists
  537. AfxMessageBox( IDS_DUPLICATE_CERT );
  538. return FALSE;
  539. }
  540. GETNEXTKEY:
  541. // get the next key for the loop
  542. pTestKey = m_pService->GetNextMDKey(pTestKey);
  543. }
  544. // run the default action
  545. BOOL fDefault = CKey::FInstallCertificate(pCert, cbCert, szPass);
  546. // set the update keys flag
  547. m_fUpdateKeys = TRUE;
  548. // if everything worked so far then check to see if there is a key
  549. // on this service with the default binding. If there isn't, then
  550. // set this key to have the default binding.
  551. if ( fDefault )
  552. {
  553. // load the default binding string
  554. CString szBinding;
  555. szBinding = MDNAME_DEFAULT;
  556. // if no key has the default binding, then make it so
  557. if ( !m_pService->FIsBindingInUse(szBinding) )
  558. {
  559. m_rgbszBindings.Add( MDNAME_DEFAULT );
  560. }
  561. }
  562. // if it worked, force the icon to change
  563. if ( fDefault )
  564. UpdateIcon();
  565. // return the default answer
  566. return fDefault;
  567. }
  568.