Leaked source code of windows server 2003
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.

801 lines
18 KiB

  1. /*++
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name :
  4. servercert.cxx
  5. Abstract:
  6. Server Certificate wrapper
  7. Author:
  8. Bilal Alam (BAlam) 29-March-2000
  9. Environment:
  10. Win32 - User Mode
  11. Project:
  12. Stream Filter Worker Process
  13. --*/
  14. #include "precomp.hxx"
  15. SERVER_CERT_HASH * SERVER_CERT::sm_pServerCertHash;
  16. SERVER_CERT::SERVER_CERT(
  17. IN CREDENTIAL_ID * pCredentialId
  18. ) : _pCredentialId( pCredentialId ),
  19. _pCertContext( NULL ),
  20. _pCertStore( NULL ),
  21. _cRefs( 1 ),
  22. _usPublicKeySize( 0 ),
  23. _fUsesHardwareAccelerator( FALSE )
  24. {
  25. _dwSignature = SERVER_CERT_SIGNATURE;
  26. }
  27. SERVER_CERT::~SERVER_CERT()
  28. {
  29. if ( _pCertContext != NULL )
  30. {
  31. CertFreeCertificateContext( _pCertContext );
  32. _pCertContext = NULL;
  33. }
  34. if ( _pCertStore != NULL )
  35. {
  36. _pCertStore->DereferenceStore();
  37. _pCertStore = NULL;
  38. }
  39. if ( _pCredentialId != NULL )
  40. {
  41. delete _pCredentialId;
  42. _pCredentialId = NULL;
  43. }
  44. _dwSignature = SERVER_CERT_SIGNATURE_FREE;
  45. }
  46. //static
  47. HRESULT
  48. SERVER_CERT::Initialize(
  49. VOID
  50. )
  51. /*++
  52. Routine Description:
  53. Initialize server certificate globals
  54. Arguments:
  55. None
  56. Return Value:
  57. HRESULT
  58. --*/
  59. {
  60. sm_pServerCertHash = new SERVER_CERT_HASH();
  61. if ( sm_pServerCertHash == NULL )
  62. {
  63. return HRESULT_FROM_WIN32( ERROR_OUTOFMEMORY );
  64. }
  65. return NO_ERROR;
  66. }
  67. //static
  68. VOID
  69. SERVER_CERT::Terminate(
  70. VOID
  71. )
  72. /*++
  73. Routine Description:
  74. Cleanup server certificate globals
  75. Arguments:
  76. None
  77. Return Value:
  78. None
  79. --*/
  80. {
  81. if ( sm_pServerCertHash != NULL )
  82. {
  83. delete sm_pServerCertHash;
  84. sm_pServerCertHash = NULL;
  85. }
  86. }
  87. //static
  88. HRESULT
  89. SERVER_CERT::GetServerCertificate(
  90. IN PBYTE pbSslCertHash,
  91. IN DWORD cbSslCertHash,
  92. IN WCHAR * pszSslCertStoreName,
  93. OUT SERVER_CERT ** ppServerCert
  94. )
  95. /*++
  96. Routine Description:
  97. Find a suitable server certificate for use with the site represented by
  98. given site id
  99. Arguments:
  100. pbSslCertHash - certificate hash
  101. cbSslCertHash - certificate hash size
  102. pszSslCertStoreName - store name where certificate is stored (under LOCAL_MACHINE context)
  103. if NULL then the default MY store is assumed
  104. ppServerCert - Filled with a pointer to server certificate
  105. Return Value:
  106. HRESULT
  107. --*/
  108. {
  109. SERVER_CERT * pServerCert = NULL;
  110. CREDENTIAL_ID * pCredentialId = NULL;
  111. HRESULT hr = NO_ERROR;
  112. LK_RETCODE lkrc;
  113. STACK_STRU( strMBPath, 64 );
  114. if ( ppServerCert == NULL ||
  115. pbSslCertHash == NULL ||
  116. cbSslCertHash == 0 )
  117. {
  118. DBG_ASSERT( FALSE );
  119. return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
  120. }
  121. *ppServerCert = NULL;
  122. if ( pszSslCertStoreName == NULL )
  123. {
  124. //
  125. // Assume default store name
  126. //
  127. pszSslCertStoreName = L"MY";
  128. }
  129. //
  130. // First build up a Credential ID to use in looking up in our
  131. // server cert cache
  132. //
  133. pCredentialId = new CREDENTIAL_ID;
  134. if ( pCredentialId == NULL )
  135. {
  136. return HRESULT_FROM_WIN32( ERROR_OUTOFMEMORY );
  137. }
  138. hr = SERVER_CERT::BuildCredentialId( pbSslCertHash,
  139. cbSslCertHash,
  140. pCredentialId );
  141. if ( FAILED( hr ) )
  142. {
  143. //
  144. // Regardless of error, we are toast because we couldn't find
  145. // a server cert
  146. //
  147. delete pCredentialId;
  148. return hr;
  149. }
  150. DBG_ASSERT( sm_pServerCertHash != NULL );
  151. lkrc = sm_pServerCertHash->FindKey( pCredentialId,
  152. &pServerCert );
  153. if ( lkrc == LK_SUCCESS )
  154. {
  155. //
  156. // Server already contains a credential ID
  157. //
  158. delete pCredentialId;
  159. *ppServerCert = pServerCert;
  160. return NO_ERROR;
  161. }
  162. //
  163. // Ok. It wasn't in our case, we need to it there
  164. //
  165. // if SERVER_CERT construction succeeds then SERVER_CERT
  166. // takes ownership of pCredentialId and is responsible for freeing it
  167. //
  168. pServerCert = new SERVER_CERT( pCredentialId );
  169. if ( pServerCert == NULL )
  170. {
  171. hr = HRESULT_FROM_WIN32( ERROR_OUTOFMEMORY );
  172. delete pCredentialId;
  173. return hr;
  174. }
  175. hr = pServerCert->SetupCertificate( pbSslCertHash,
  176. cbSslCertHash,
  177. pszSslCertStoreName );
  178. if ( FAILED( hr ) )
  179. {
  180. //
  181. // Server certificate owns the reference to pCredentialId now
  182. //
  183. delete pServerCert;
  184. return hr;
  185. }
  186. hr = pServerCert->DetermineUseOfSSLHardwareAccelerator();
  187. if ( FAILED( hr ) )
  188. {
  189. //
  190. // We will not take this failure for fatal.
  191. // Information about the presence of SSL Hardware accelerator is
  192. // used only for performance tuning
  193. //
  194. hr = S_OK;
  195. }
  196. //
  197. // Now try to add cert to hash.
  198. //
  199. lkrc = sm_pServerCertHash->InsertRecord( pServerCert );
  200. //
  201. // Ignore the error. If it didn't get added then we will naturally
  202. // clean it up on the callers dereference
  203. //
  204. *ppServerCert = pServerCert;
  205. return NO_ERROR;
  206. }
  207. //static
  208. HRESULT
  209. SERVER_CERT::BuildCredentialId(
  210. IN PBYTE pbSslCertHash,
  211. IN DWORD cbSslCertHash,
  212. OUT CREDENTIAL_ID * pCredentialId
  213. )
  214. /*++
  215. Routine Description:
  216. Read the configured server cert and CTL hash. This forms the identifier
  217. for the credentials we need for this site
  218. Arguments:
  219. pbSslCertHash - server certificate hash
  220. cbSslCertHash - size of the hash
  221. pCredentialId - Filled with credential ID
  222. Return Value:
  223. HRESULT
  224. --*/
  225. {
  226. BYTE abBuff[ 64 ];
  227. BUFFER buff( abBuff, sizeof( abBuff ) );
  228. HRESULT hr = NO_ERROR;
  229. if ( pCredentialId == NULL )
  230. {
  231. DBG_ASSERT( FALSE );
  232. return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
  233. }
  234. if ( cbSslCertHash == 0 )
  235. {
  236. //
  237. // No server cert. Then we can't setup SSL
  238. //
  239. return HRESULT_FROM_WIN32( ERROR_FILE_NOT_FOUND );
  240. }
  241. else
  242. {
  243. //
  244. // Add to our credential ID
  245. //
  246. hr = pCredentialId->Append( pbSslCertHash,
  247. cbSslCertHash );
  248. if ( FAILED( hr ) )
  249. {
  250. return hr;
  251. }
  252. }
  253. return NO_ERROR;
  254. }
  255. HRESULT
  256. SERVER_CERT::SetupCertificate(
  257. IN PBYTE pbSslCertHash,
  258. IN DWORD cbSslCertHash,
  259. IN WCHAR * pszSslCertStoreName
  260. )
  261. /*++
  262. Routine Description:
  263. Find certificate in the given store
  264. Arguments:
  265. pbSslCertHash - certificate hash
  266. cbSslCertHash - certificate hash size
  267. pszSslCertStoreName - store name where certificate is stored (under LOCAL_MACHINE context)
  268. Return Value:
  269. HRESULT
  270. --*/
  271. {
  272. HRESULT hr = NO_ERROR;
  273. BYTE abBuff[ 128 ];
  274. BUFFER buff( abBuff, sizeof( abBuff ) );
  275. STACK_STRU( strStoreName, 256 );
  276. CERT_STORE * pCertStore = NULL;
  277. CRYPT_HASH_BLOB hashBlob;
  278. PCERT_PUBLIC_KEY_INFO pPublicKey;
  279. DWORD cbX500Name = 0;
  280. //
  281. // Get the required server certificate hash
  282. //
  283. if ( cbSslCertHash == 0 ||
  284. pszSslCertStoreName == NULL ||
  285. pszSslCertStoreName[0] == 0 )
  286. {
  287. //
  288. // No server cert. Then we can't setup SSL
  289. //
  290. return HRESULT_FROM_WIN32( ERROR_FILE_NOT_FOUND );
  291. }
  292. //
  293. // OK. We are ready to retrieve the certificate using CAPI APIs
  294. //
  295. //
  296. // First get the desired store and store it away for later!
  297. //
  298. hr = strStoreName.Copy( pszSslCertStoreName );
  299. if ( FAILED( hr ) )
  300. {
  301. goto Finished;
  302. }
  303. hr = CERT_STORE::OpenStore( strStoreName,
  304. &pCertStore );
  305. if ( FAILED( hr ) )
  306. {
  307. goto Finished;
  308. }
  309. DBG_ASSERT( pCertStore != NULL );
  310. _pCertStore = pCertStore;
  311. //
  312. // Now find the certificate hash in the store
  313. //
  314. hashBlob.cbData = cbSslCertHash;
  315. hashBlob.pbData = pbSslCertHash;
  316. _pCertContext = CertFindCertificateInStore( _pCertStore->QueryStore(),
  317. X509_ASN_ENCODING,
  318. 0,
  319. CERT_FIND_SHA1_HASH,
  320. (VOID*) &hashBlob,
  321. NULL );
  322. if ( _pCertContext == NULL )
  323. {
  324. hr = HRESULT_FROM_WIN32( GetLastError() );
  325. goto Finished;
  326. }
  327. //
  328. // Get certificate public key size
  329. //
  330. DBG_ASSERT( _usPublicKeySize == 0 );
  331. pPublicKey = &(_pCertContext->pCertInfo->SubjectPublicKeyInfo);
  332. _usPublicKeySize = (USHORT) CertGetPublicKeyLength( PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
  333. pPublicKey );
  334. if ( _usPublicKeySize == 0 )
  335. {
  336. //
  337. // Failed to receive public key size
  338. //
  339. hr = HRESULT_FROM_WIN32( GetLastError() );
  340. goto Finished;
  341. }
  342. //
  343. // Get issuer string
  344. //
  345. DBG_ASSERT( _pCertContext->pCertInfo != NULL );
  346. //
  347. // First find out the size of buffer required for issuer
  348. //
  349. cbX500Name = CertNameToStrA( PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
  350. &_pCertContext->pCertInfo->Issuer,
  351. CERT_X500_NAME_STR,
  352. NULL,
  353. 0);
  354. if( !buff.Resize( cbX500Name ) )
  355. {
  356. hr = HRESULT_FROM_WIN32( GetLastError() );
  357. goto Finished;
  358. }
  359. cbX500Name = CertNameToStrA( PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
  360. &_pCertContext->pCertInfo->Issuer,
  361. CERT_X500_NAME_STR,
  362. (LPSTR) buff.QueryPtr(),
  363. buff.QuerySize() );
  364. hr = _strIssuer.Copy( (LPSTR) buff.QueryPtr() );
  365. if ( FAILED( hr ) )
  366. {
  367. goto Finished;
  368. }
  369. //
  370. // Get subject string
  371. //
  372. //
  373. // First find out the size of buffer required for subject
  374. //
  375. cbX500Name = CertNameToStrA( PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
  376. &_pCertContext->pCertInfo->Subject,
  377. CERT_X500_NAME_STR,
  378. NULL,
  379. 0);
  380. if( !buff.Resize( cbX500Name ) )
  381. {
  382. hr = HRESULT_FROM_WIN32( GetLastError() );
  383. goto Finished;
  384. }
  385. cbX500Name = CertNameToStrA( PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
  386. &_pCertContext->pCertInfo->Subject,
  387. CERT_X500_NAME_STR,
  388. (LPSTR) buff.QueryPtr(),
  389. buff.QuerySize() );
  390. hr = _strSubject.Copy( (LPSTR) buff.QueryPtr() );
  391. if ( FAILED( hr ) )
  392. {
  393. goto Finished;
  394. }
  395. Finished:
  396. return hr;
  397. }
  398. HRESULT
  399. SERVER_CERT::DetermineUseOfSSLHardwareAccelerator(
  400. VOID
  401. )
  402. /*++
  403. Routine Description:
  404. Find out if SSL hardware accelerator is used.
  405. Currently there is no reliable way to ask
  406. schannel or CAPI if SSL hardware accelerator is indeed used
  407. we use optimistic lookup of config info based on magic
  408. instructions from John Banes (see Windows Bugs 510131)
  409. and based on that we make educated guess
  410. The only purpose to care about this is for performance tuning
  411. of the threadpool
  412. Arguments:
  413. none
  414. Return Value:
  415. HRESULT
  416. --*/
  417. {
  418. HRESULT hr = E_FAIL;
  419. HCRYPTPROV hProv = NULL;
  420. BOOL fUsesHardwareAccelerator = FALSE;
  421. CHAR *pszCSPName = NULL;
  422. DWORD dwKeySpec;
  423. DWORD dwImpType;
  424. DWORD cbData = 0;
  425. HKEY hKeyParam = NULL;
  426. if (!CryptAcquireCertificatePrivateKey(
  427. *QueryCertContext(),
  428. 0, // dwFlags
  429. NULL, // pvReserved
  430. &hProv,
  431. &dwKeySpec,
  432. NULL)) // pfCallerFreeProv
  433. {
  434. hr = HRESULT_FROM_WIN32( GetLastError() );
  435. goto Finished;
  436. }
  437. cbData = sizeof( dwImpType );
  438. if (!CryptGetProvParam( hProv,
  439. PP_IMPTYPE,
  440. (PBYTE) &dwImpType,
  441. &cbData, 0))
  442. {
  443. hr = HRESULT_FROM_WIN32(GetLastError());
  444. goto Finished;
  445. }
  446. //
  447. // Check implementation type.
  448. //
  449. if (dwImpType == CRYPT_IMPL_HARDWARE || dwImpType == CRYPT_IMPL_MIXED )
  450. {
  451. //
  452. // We can safely assume that hardware accelerator is used
  453. //
  454. fUsesHardwareAccelerator = TRUE;
  455. hr = S_OK;
  456. goto Finished;
  457. }
  458. //
  459. // lookup CSP Name
  460. // if MS_DEF_RSA_SCHANNEL_PROV_W then we will have to check registry
  461. // to find out if hardware accelerator is registered
  462. //
  463. if( !CryptGetProvParam( hProv,
  464. PP_NAME,
  465. NULL,
  466. &cbData,
  467. 0 ) )
  468. {
  469. hr = HRESULT_FROM_WIN32(GetLastError());
  470. goto Finished;
  471. }
  472. pszCSPName = new char [ cbData ];
  473. if ( pszCSPName == NULL )
  474. {
  475. hr = HRESULT_FROM_WIN32( ERROR_OUTOFMEMORY );
  476. goto Finished;
  477. }
  478. if( !CryptGetProvParam( hProv,
  479. PP_NAME,
  480. (BYTE *)pszCSPName,
  481. &cbData,
  482. 0 ))
  483. {
  484. hr = HRESULT_FROM_WIN32( GetLastError() );
  485. goto Finished;
  486. }
  487. if ( _stricmp ( pszCSPName, MS_DEF_RSA_SCHANNEL_PROV_A ) != 0 )
  488. {
  489. //
  490. // we cannot determine so we assume the answer is no
  491. //
  492. fUsesHardwareAccelerator = FALSE;
  493. hr = S_OK;
  494. goto Finished;
  495. }
  496. if ( RegOpenKeyExA( HKEY_LOCAL_MACHINE,
  497. "Software\\Microsoft\\Cryptography\\Offload",
  498. 0,
  499. KEY_READ,
  500. &hKeyParam ) == ERROR_SUCCESS )
  501. {
  502. DWORD dwType;
  503. cbData = 0;
  504. DWORD dwError = RegQueryValueExA( hKeyParam,
  505. EXPO_OFFLOAD_REG_VALUE,
  506. NULL,
  507. &dwType,
  508. ( LPBYTE ) NULL,
  509. &cbData
  510. );
  511. if ( ( dwError == ERROR_SUCCESS ) )
  512. {
  513. //
  514. // We don't really care to read the value
  515. // this is good enough indication that value exists
  516. // It means that we assume hardware accelerator is present
  517. //
  518. fUsesHardwareAccelerator = TRUE;
  519. hr = S_OK;
  520. goto Finished;
  521. }
  522. RegCloseKey( hKeyParam );
  523. fUsesHardwareAccelerator = FALSE;
  524. hr = S_OK;
  525. goto Finished;
  526. }
  527. Finished:
  528. if ( hKeyParam != NULL )
  529. {
  530. RegCloseKey( hKeyParam );
  531. }
  532. if ( pszCSPName != NULL )
  533. {
  534. delete [] pszCSPName;
  535. }
  536. if ( hProv != NULL )
  537. {
  538. CryptReleaseContext(hProv, 0);
  539. }
  540. _fUsesHardwareAccelerator = fUsesHardwareAccelerator;
  541. return hr;
  542. }
  543. //static
  544. LK_PREDICATE
  545. SERVER_CERT::CertStorePredicate(
  546. IN SERVER_CERT * pServerCert,
  547. IN void * pvState
  548. )
  549. /*++
  550. Description:
  551. DeleteIf() predicate used to find items which reference the
  552. CERT_STORE pointed to by pvState
  553. Arguments:
  554. pServerCert - Server cert
  555. pvState - Points to CERT_STORE
  556. Returns:
  557. LK_PREDICATE - LKP_PERFORM indicates removing the current
  558. cert store from certstore cache
  559. LKP_NO_ACTION indicates doing nothing.
  560. --*/
  561. {
  562. LK_PREDICATE lkpAction;
  563. CERT_STORE * pCertStore;
  564. DBG_ASSERT( pServerCert != NULL );
  565. pCertStore = (CERT_STORE*) pvState;
  566. DBG_ASSERT( pCertStore != NULL );
  567. if ( pServerCert->_pCertStore == pCertStore )
  568. {
  569. //
  570. // Before we delete the cert, flush any site which is referencing
  571. // it
  572. //
  573. ENDPOINT_CONFIG::FlushByServerCert( pServerCert );
  574. lkpAction = LKP_PERFORM;
  575. }
  576. else
  577. {
  578. lkpAction = LKP_NO_ACTION;
  579. }
  580. return lkpAction;
  581. }
  582. //static
  583. HRESULT
  584. SERVER_CERT::FlushByStore(
  585. IN CERT_STORE * pCertStore
  586. )
  587. /*++
  588. Routine Description:
  589. Flush any server certs which reference the given store
  590. Arguments:
  591. pCertStore - Cert store to check
  592. Return Value:
  593. HRESULT
  594. --*/
  595. {
  596. DBG_ASSERT( sm_pServerCertHash != NULL );
  597. sm_pServerCertHash->DeleteIf( SERVER_CERT::CertStorePredicate,
  598. pCertStore );
  599. return NO_ERROR;
  600. }
  601. //static
  602. VOID
  603. SERVER_CERT::Cleanup(
  604. VOID
  605. )
  606. /*++
  607. Routine Description:
  608. Cleanup must be called before Terminate
  609. Arguments:
  610. none
  611. Return Value:
  612. VOID
  613. --*/
  614. {
  615. sm_pServerCertHash->Clear();
  616. }