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.

2691 lines
78 KiB

  1. /*++
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name :
  4. sslcontext.cxx
  5. Abstract:
  6. SSL stream context
  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. //static
  16. ALLOC_CACHE_HANDLER * SSL_STREAM_CONTEXT::sm_pachSslStreamContexts = NULL;
  17. //
  18. // By default we don't allow CAPI to automatically download intermediate certificates
  19. // off the network
  20. //
  21. //static
  22. BOOL SSL_STREAM_CONTEXT::sm_fCertChainCacheOnlyUrlRetrieval = TRUE;
  23. enum SSL_STREAM_CONTEXT::INIT_STATE
  24. SSL_STREAM_CONTEXT::s_InitState = INIT_NONE;
  25. //static
  26. HRESULT
  27. SSL_STREAM_CONTEXT::Initialize(
  28. VOID
  29. )
  30. /*++
  31. Routine Description:
  32. Initialize all SSL global data
  33. Arguments:
  34. None
  35. Return Value:
  36. HRESULT
  37. --*/
  38. {
  39. HRESULT hr = S_OK;
  40. ALLOC_CACHE_CONFIGURATION acConfig;
  41. HKEY hKeyParam = NULL;
  42. DWORD dwType = 0;
  43. DWORD dwValue = 0;
  44. hr = CERT_STORE::Initialize();
  45. if ( FAILED( hr ) )
  46. {
  47. goto Finished;
  48. }
  49. s_InitState = INIT_CERT_STORE;
  50. hr = SERVER_CERT::Initialize();
  51. if ( FAILED( hr ) )
  52. {
  53. goto Finished;
  54. }
  55. s_InitState = INIT_SERVER_CERT;
  56. hr = IIS_CTL::Initialize();
  57. if ( FAILED( hr ) )
  58. {
  59. goto Finished;
  60. }
  61. s_InitState = INIT_IIS_CTL;
  62. hr = SITE_CREDENTIALS::Initialize();
  63. if ( FAILED( hr ) )
  64. {
  65. goto Finished;
  66. }
  67. s_InitState = INIT_SITE_CREDENTIALS;
  68. //
  69. // ENDPOINT_CONFIG uses
  70. // SERVER_CERT,
  71. // SITE_CREDENTIALS and
  72. //
  73. hr = ENDPOINT_CONFIG::Initialize();
  74. if ( FAILED( hr ) )
  75. {
  76. goto Finished;
  77. }
  78. s_InitState = INIT_ENDPOINT_CONFIG;
  79. //
  80. // Setup allocation lookaside
  81. //
  82. acConfig.nConcurrency = 1;
  83. acConfig.nThreshold = 100;
  84. acConfig.cbSize = sizeof( SSL_STREAM_CONTEXT );
  85. DBG_ASSERT( sm_pachSslStreamContexts == NULL );
  86. sm_pachSslStreamContexts = new ALLOC_CACHE_HANDLER( "SSL_STREAM_CONTEXT",
  87. &acConfig );
  88. if ( sm_pachSslStreamContexts == NULL )
  89. {
  90. hr = HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
  91. goto Finished;
  92. }
  93. s_InitState = INIT_ACACHE;
  94. //
  95. // Read registry parameters
  96. //
  97. if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  98. REGISTRY_KEY_HTTPFILTER_PARAMETERS_W,
  99. 0,
  100. KEY_READ,
  101. &hKeyParam ) == NO_ERROR )
  102. {
  103. DWORD dwBytes = sizeof( dwValue );
  104. DWORD dwErr = RegQueryValueExW( hKeyParam,
  105. SZ_REG_CERT_CHAIN_CACHE_ONLY_URL_RETRIEVAL,
  106. NULL,
  107. &dwType,
  108. ( LPBYTE )&dwValue,
  109. &dwBytes
  110. );
  111. if ( ( dwErr == ERROR_SUCCESS ) &&
  112. ( dwType == REG_DWORD ) )
  113. {
  114. //
  115. // Do double negation to convert DWORD to BOOL
  116. //
  117. sm_fCertChainCacheOnlyUrlRetrieval = !!dwValue;
  118. }
  119. RegCloseKey( hKeyParam );
  120. }
  121. Finished:
  122. if ( FAILED( hr ) )
  123. {
  124. Terminate();
  125. }
  126. return hr;
  127. }
  128. //static
  129. VOID
  130. SSL_STREAM_CONTEXT::Terminate(
  131. VOID
  132. )
  133. /*++
  134. Routine Description:
  135. Terminate SSL
  136. Arguments:
  137. None
  138. Return Value:
  139. None
  140. --*/
  141. {
  142. // This call must happen after the main threadpool has shutdown
  143. // However there still may be threads executing because of the change notification
  144. // callbacks
  145. //
  146. // ENDPOINT_CONFIG gets notified on http config changes but callbacks touch only
  147. // the ENDPOINT_CONFIG itself
  148. //
  149. // CERT_STORE gets notified on CAPI store changes. Callback function will
  150. // cause access to CERT_STORE, SERVER_CERT, IIS_CTL, ENDPOINT_CONFIG
  151. // That's why all the change notification handling for CERT_STORE
  152. // must be completed before all of the classes mentioned above are Terminated
  153. // Cleanup of ENDPOINT_CONFIG, IIS_CTL, SERVER_CERT and CERT_STORE will
  154. // assure that when Terminate is called, there are no outstanding threads partying
  155. // on any data owned by those classes and so it is indeed safe to terminate
  156. // Cleanup phase
  157. // Note: all INIT_* tags must be present in both Cleanup and Termination part
  158. switch ( s_InitState )
  159. {
  160. case INIT_ACACHE:
  161. case INIT_ENDPOINT_CONFIG:
  162. ENDPOINT_CONFIG::Cleanup();
  163. case INIT_SITE_CREDENTIALS:
  164. case INIT_IIS_CTL:
  165. IIS_CTL::Cleanup();
  166. case INIT_SERVER_CERT:
  167. SERVER_CERT::Cleanup();
  168. case INIT_CERT_STORE:
  169. CERT_STORE::Cleanup();
  170. case INIT_NONE:
  171. break;
  172. default:
  173. DBG_ASSERT( FALSE );
  174. }
  175. // Termination phase
  176. switch ( s_InitState )
  177. {
  178. case INIT_ACACHE:
  179. if ( sm_pachSslStreamContexts != NULL )
  180. {
  181. delete sm_pachSslStreamContexts;
  182. sm_pachSslStreamContexts = NULL;
  183. }
  184. case INIT_ENDPOINT_CONFIG:
  185. ENDPOINT_CONFIG::Terminate();
  186. case INIT_SITE_CREDENTIALS:
  187. SITE_CREDENTIALS::Terminate();
  188. case INIT_IIS_CTL:
  189. IIS_CTL::Terminate();
  190. case INIT_SERVER_CERT:
  191. SERVER_CERT::Terminate();
  192. case INIT_CERT_STORE:
  193. CERT_STORE::Terminate();
  194. case INIT_NONE:
  195. break;
  196. default:
  197. DBG_ASSERT( FALSE );
  198. }
  199. }
  200. SSL_STREAM_CONTEXT::SSL_STREAM_CONTEXT(
  201. FILTER_CHANNEL_CONTEXT * pFiltChannelContext
  202. )
  203. : STREAM_CONTEXT( pFiltChannelContext ),
  204. _pEndpointConfig( NULL ),
  205. _sslState( SSL_STATE_HANDSHAKE_START ),
  206. _fRenegotiate( FALSE ),
  207. _fExpectRenegotiationFromClient( FALSE ),
  208. _fValidContext( FALSE ),
  209. _cbToBeProcessedOffset( 0 ),
  210. _pClientCert( NULL ),
  211. _fDoCertMap( FALSE ),
  212. _cbDecrypted( 0 )
  213. {
  214. //
  215. // Initialize security buffer structs
  216. //
  217. //
  218. // Setup buffer to hold incoming raw data
  219. //
  220. DBG_ASSERT( s_InitState != INIT_NONE );
  221. ZeroMemory( &_hContext, sizeof( _hContext ) );
  222. ZeroMemory( &_ulSslInfo, sizeof( _ulSslInfo ) );
  223. ZeroMemory( &_ulCertInfo, sizeof( _ulCertInfo ) );
  224. _ulCertInfo.Token = NULL;
  225. }
  226. SSL_STREAM_CONTEXT::~SSL_STREAM_CONTEXT()
  227. {
  228. if ( _fValidContext )
  229. {
  230. DeleteSecurityContext( &_hContext );
  231. _fValidContext = FALSE;
  232. }
  233. if ( _pEndpointConfig != NULL )
  234. {
  235. _pEndpointConfig->DereferenceEndpointConfig();
  236. _pEndpointConfig = NULL;
  237. }
  238. if( _ulCertInfo.Token != NULL )
  239. {
  240. CloseHandle( _ulCertInfo.Token );
  241. _ulCertInfo.Token = NULL;
  242. }
  243. if( _pClientCert != NULL )
  244. {
  245. CertFreeCertificateContext( _pClientCert );
  246. _pClientCert = NULL;
  247. }
  248. }
  249. HRESULT
  250. SSL_STREAM_CONTEXT::ProcessNewConnection(
  251. CONNECTION_INFO * pConnectionInfo,
  252. ENDPOINT_CONFIG * pEndpointConfig
  253. )
  254. /*++
  255. Routine Description:
  256. Handle a new raw connection
  257. Arguments:
  258. pConnectionInfo - The magic connection information (not used)
  259. pEndpointConfig - endpoint configuration
  260. Return Value:
  261. HRESULT
  262. --*/
  263. {
  264. BOOL fLocalEndpointConfigReference = FALSE;
  265. DBG_ASSERT( _sslState == SSL_STATE_HANDSHAKE_START );
  266. if ( pEndpointConfig == NULL )
  267. {
  268. HRESULT hr = ENDPOINT_CONFIG::GetEndpointConfig( pConnectionInfo,
  269. &pEndpointConfig );
  270. if ( SUCCEEDED( hr ) )
  271. {
  272. fLocalEndpointConfigReference = TRUE;
  273. }
  274. else if ( hr == HRESULT_FROM_WIN32 ( ERROR_FILE_NOT_FOUND ) )
  275. {
  276. //
  277. // not found means that SSL is not enabled
  278. //
  279. QueryFiltChannelContext()->SetIsSecure( FALSE );
  280. return S_OK;
  281. }
  282. else if ( FAILED( hr ) )
  283. {
  284. return hr;
  285. }
  286. }
  287. DBG_ASSERT( pEndpointConfig != NULL );
  288. if ( !pEndpointConfig->QuerySslConfigured() )
  289. {
  290. // no endpoint config was found
  291. // or endpoint config was found built doesn't contain SSL stuff
  292. //
  293. QueryFiltChannelContext()->SetIsSecure( FALSE );
  294. }
  295. else
  296. {
  297. QueryFiltChannelContext()->SetIsSecure( TRUE );
  298. //
  299. // Store away the site config for this connection
  300. //
  301. pEndpointConfig->ReferenceEndpointConfig();
  302. _pEndpointConfig = pEndpointConfig;
  303. }
  304. if ( fLocalEndpointConfigReference )
  305. {
  306. // Local Endpoint Config lookup was made
  307. // within this function.
  308. // release the reference
  309. //
  310. pEndpointConfig->DereferenceEndpointConfig();
  311. pEndpointConfig = NULL;
  312. }
  313. return S_OK;
  314. }
  315. HRESULT
  316. SSL_STREAM_CONTEXT::ProcessRawReadData(
  317. RAW_STREAM_INFO * pRawStreamInfo,
  318. BOOL * pfReadMore,
  319. BOOL * pfComplete
  320. )
  321. /*++
  322. Routine Description:
  323. Handle an SSL read completion off the wire
  324. Arguments:
  325. pRawStreamInfo - Points to input stream and size
  326. pfReadMore - Set to TRUE if we should read more
  327. pfComplete - Set to TRUE if we should disconnect
  328. Return Value:
  329. HRESULT
  330. --*/
  331. {
  332. HRESULT hr = S_OK;
  333. BOOL fExtraData = FALSE;
  334. //
  335. // Do we have site config? If not, then this isn't an SSL connection
  336. //
  337. if ( _pEndpointConfig == NULL )
  338. {
  339. return S_OK;
  340. }
  341. //
  342. // Loop for extra data
  343. // Sometimes one RawStreamInfo buffer may contain multiple blobs
  344. // some to be processed by DoHandshake() and some by DoDecrypt()
  345. // The do-while loop enables switching between these 2 functions as needed
  346. //
  347. do
  348. {
  349. fExtraData = FALSE;
  350. *pfReadMore = FALSE;
  351. *pfComplete = FALSE;
  352. //
  353. // Either continue handshake or immediate decrypt data
  354. //
  355. switch ( _sslState )
  356. {
  357. case SSL_STATE_HANDSHAKE_START:
  358. case SSL_STATE_HANDSHAKE_IN_PROGRESS:
  359. hr = DoHandshake( pRawStreamInfo,
  360. pfReadMore,
  361. pfComplete,
  362. &fExtraData );
  363. break;
  364. case SSL_STATE_HANDSHAKE_COMPLETE:
  365. hr = DoDecrypt( pRawStreamInfo,
  366. pfReadMore,
  367. pfComplete,
  368. &fExtraData );
  369. break;
  370. default:
  371. DBG_ASSERT( FALSE );
  372. }
  373. if ( FAILED( hr ) )
  374. {
  375. break;
  376. }
  377. //
  378. // Is there still some extra data to be processed?
  379. //
  380. }while( fExtraData );
  381. return hr;
  382. }
  383. HRESULT
  384. SSL_STREAM_CONTEXT::ProcessRawWriteData(
  385. RAW_STREAM_INFO * pRawStreamInfo,
  386. BOOL * pfComplete
  387. )
  388. /*++
  389. Routine Description:
  390. Called on read completion from app. Data received
  391. from application must be encrypted and sent to client
  392. using RawWrite.
  393. Application may have also requested renegotiation
  394. (with or without mapping) if client certificate
  395. is not yet present
  396. Arguments:
  397. pRawStreamInfo - Points to input stream and size
  398. pfComplete - Set to TRUE if we should disconnect
  399. Return Value:
  400. HRESULT
  401. --*/
  402. {
  403. HRESULT hr;
  404. HTTP_FILTER_BUFFER_TYPE bufferType;
  405. if ( _pEndpointConfig == NULL )
  406. {
  407. //
  408. // We never found SSL to be relevent for this connection. Do nothing
  409. //
  410. return S_OK;
  411. }
  412. if ( _sslState != SSL_STATE_HANDSHAKE_COMPLETE )
  413. {
  414. //
  415. // HttpFilter is not able to reliably handle state
  416. // where renegotiation is in progress and response data is
  417. // requested to be sent to client
  418. // Ideally HttpFilter should not have any pending AppReads
  419. // for the duration of the renegotiation handshake
  420. // however in that case http.sys would not be able to inform
  421. // us about client closing connection.
  422. // So there are 2 ways around this problem
  423. //
  424. // a) the easy and cheesy is to detect that SSL handshake is
  425. // not complete and close connection
  426. //
  427. // b) we could buffer data to be sent and send it after handshake is done
  428. //
  429. // Option b) is ultimately more decent but due to the fact that
  430. // there is not much practical need for sending response data while renegotiating
  431. // we will implement the option a)
  432. //
  433. // One example of the scenario where data to be sent to client is received while in
  434. // the middle of the renegotiation is the following
  435. // a) Client sends Post with part of the response body
  436. // b) Http.sys gets headers and part of the response body and
  437. // passes it to IIS
  438. // c) Http.sys will keep receiving response
  439. // d) IIS will ask for renegotiation (because URL requires client cert)
  440. // e) while in the middle of renegotiation, http.sys finds out that
  441. // client closed it's end of the socket before all the bytes of the
  442. // response were sent.
  443. // f) Http.sys sends "400 Bad Request"
  444. // g) HttpFilter will eventually not be able to send the response because
  445. // we are in the middle of renegotiation. However there is not much
  446. // loss of the information if HttpFilter simply decides to close connection
  447. // because specific error will be stored in the http error log
  448. IF_DEBUG ( FLAG_ERROR )
  449. {
  450. DBGPRINTF(( DBG_CONTEXT,
  451. "Error: HttpFilter doesn't allow responses while in the middle of ssl handshake (connection will be closed)\n"
  452. ));
  453. }
  454. return HRESULT_FROM_WIN32( ERROR_INVALID_DATA );
  455. }
  456. bufferType = QueryFiltChannelContext()->QueryFilterBufferType();
  457. //
  458. // Is this data from the application, or a request for renegotiation?
  459. //
  460. if ( bufferType == HttpFilterBufferSslRenegotiate ||
  461. bufferType == HttpFilterBufferSslRenegotiateAndMap )
  462. {
  463. //
  464. // If we have already renegotiated a client certificate, then there
  465. // is nothing to do, but read again for stream data
  466. //
  467. if ( _fRenegotiate )
  468. {
  469. hr = S_OK;
  470. }
  471. else
  472. {
  473. if ( bufferType == HttpFilterBufferSslRenegotiateAndMap )
  474. {
  475. _fDoCertMap = TRUE;
  476. }
  477. hr = DoRenegotiate();
  478. }
  479. }
  480. else if ( bufferType == HttpFilterBufferHttpStream )
  481. {
  482. hr = DoEncrypt( pRawStreamInfo,
  483. pfComplete );
  484. }
  485. else
  486. {
  487. DBG_ASSERT( FALSE );
  488. hr = E_FAIL;
  489. }
  490. return hr;
  491. }
  492. HRESULT
  493. SSL_STREAM_CONTEXT::SendDataBack(
  494. RAW_STREAM_INFO * pRawStreamInfo
  495. )
  496. /*++
  497. Routine Description:
  498. Send back data (different then ProcessRawWrite because in this case
  499. the data was not received by the application, but rather a raw filter)
  500. Arguments:
  501. pRawStreamInfo - Points to input stream and size
  502. Return Value:
  503. HRESULT
  504. --*/
  505. {
  506. BOOL fComplete;
  507. HRESULT hr;
  508. if ( pRawStreamInfo == NULL )
  509. {
  510. DBG_ASSERT( FALSE );
  511. return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
  512. }
  513. if ( _pEndpointConfig != NULL )
  514. {
  515. //
  516. // We must have completed the handshake to get here, since this path
  517. // is only invoked by ISAPI filters
  518. //
  519. DBG_ASSERT( _sslState == SSL_STATE_HANDSHAKE_COMPLETE );
  520. hr = DoEncrypt( pRawStreamInfo,
  521. &fComplete );
  522. if ( FAILED( hr ) )
  523. {
  524. return hr;
  525. }
  526. }
  527. //
  528. // caller is responsible to send data
  529. //
  530. return S_OK;
  531. }
  532. //static
  533. HRESULT
  534. SSL_STREAM_CONTEXT::OnHandshakeRawWriteCompletion(
  535. PVOID pParam
  536. )
  537. /*++
  538. Routine Description:
  539. perform cleanup after RawWrite Completion
  540. Arguments:
  541. pParam - parameter passed by the caller of DoRawWrite along with completion function
  542. Return Value:
  543. HRESULT
  544. --*/
  545. {
  546. if ( pParam != NULL )
  547. {
  548. FreeContextBuffer( pParam );
  549. pParam = NULL;
  550. }
  551. return S_OK;
  552. }
  553. HRESULT
  554. SSL_STREAM_CONTEXT::DoHandshake(
  555. RAW_STREAM_INFO * pRawStreamInfo,
  556. BOOL * pfReadMore,
  557. BOOL * pfComplete,
  558. BOOL * pfExtraData
  559. )
  560. /*++
  561. Routine Description:
  562. Do the handshake thing with AcceptSecurityContext()
  563. Arguments:
  564. pRawStreamInfo - Raw data buffer
  565. pfReadMore - Set to true if more data should be read
  566. pfComplete - Set to true if we should disconnect
  567. Return Value:
  568. HRESULT
  569. --*/
  570. {
  571. SECURITY_STATUS secStatus = SEC_E_OK;
  572. HRESULT hr = E_FAIL;
  573. DWORD dwFlags = SSL_ASC_FLAGS;
  574. DWORD dwContextAttributes;
  575. TimeStamp tsExpiry;
  576. CtxtHandle hOutContext;
  577. // Buffers used for SSL Handshake (incoming handshake blob)
  578. // 4 is the schannel magic number
  579. SecBufferDesc MessageIn;
  580. SecBuffer InBuffers[ 4 ];
  581. // Buffers used for SSL Handshake (outgoing handshake blob)
  582. // 4 is the schannel magic number
  583. SecBufferDesc MessageOut;
  584. SecBuffer OutBuffers[ 4 ];
  585. if ( pRawStreamInfo == NULL ||
  586. pfReadMore == NULL ||
  587. pfComplete == NULL ||
  588. pfExtraData == NULL )
  589. {
  590. DBG_ASSERT( FALSE );
  591. hr = HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
  592. goto ExitPoint;
  593. }
  594. *pfReadMore = FALSE;
  595. *pfComplete = FALSE;
  596. *pfExtraData = FALSE;
  597. IF_DEBUG( SCHANNEL_CALLS )
  598. {
  599. DBGPRINTF(( DBG_CONTEXT,
  600. "DoHandshake(): _cbDecrypted = %d, _cbToBeProcessedOffset=%d\n",
  601. _cbDecrypted,
  602. _cbToBeProcessedOffset
  603. ));
  604. }
  605. DBG_ASSERT( _pEndpointConfig != NULL );
  606. if( pRawStreamInfo->cbData < _cbToBeProcessedOffset )
  607. {
  608. //
  609. // Inconsisent state of the SSL_STREAM_CONTEXT
  610. // This should never really happen, but because we
  611. // execute in lsass we don't want to see wrong offset calculations
  612. // cause much trouble in lsass
  613. //
  614. IF_DEBUG ( FLAG_ERROR )
  615. {
  616. DBGPRINTF(( DBG_CONTEXT,
  617. "Error: HttpFilter detected unexpected offset in it's internal data (connection will be closed)\n"
  618. ));
  619. }
  620. DBG_ASSERT( FALSE );
  621. return HRESULT_FROM_WIN32( ERROR_INVALID_DATA );
  622. }
  623. //
  624. // Setup input & output buffers for AcceptSecurityContext call
  625. //
  626. MessageIn.ulVersion = SECBUFFER_VERSION;
  627. MessageIn.cBuffers = 4;
  628. MessageIn.pBuffers = InBuffers;
  629. InBuffers[0].BufferType = SECBUFFER_TOKEN;
  630. InBuffers[0].pvBuffer = pRawStreamInfo->pbBuffer + _cbToBeProcessedOffset;
  631. InBuffers[0].cbBuffer = pRawStreamInfo->cbData - _cbToBeProcessedOffset;
  632. InBuffers[1].BufferType = SECBUFFER_EMPTY;
  633. InBuffers[2].BufferType = SECBUFFER_EMPTY;
  634. InBuffers[3].BufferType = SECBUFFER_EMPTY;
  635. MessageOut.ulVersion = SECBUFFER_VERSION;
  636. MessageOut.cBuffers = 4;
  637. MessageOut.pBuffers = OutBuffers;
  638. //
  639. // Note: OutBuffers[ 0 ].pvBuffer may get changed in AcceptSecurityContext
  640. // even if error is returned. In that case _OutBuffers[ 0 ].pvBuffer must
  641. // not be freed
  642. OutBuffers[0].pvBuffer = NULL;
  643. OutBuffers[0].cbBuffer = NULL;
  644. OutBuffers[0].BufferType = SECBUFFER_EMPTY;
  645. OutBuffers[1].BufferType = SECBUFFER_EMPTY;
  646. OutBuffers[2].BufferType = SECBUFFER_EMPTY;
  647. OutBuffers[3].BufferType = SECBUFFER_EMPTY;
  648. //
  649. // Are we renegotiating for client cert?
  650. // if _pEndpointConfig->QueryNegotiateClientCert() is TRUE
  651. // it means that Client certificates are enabled on root level
  652. // of the site. In that case we enable optimization where
  653. // client certificates are negotiated right away to eliminate
  654. // expensive renegotiation
  655. DBG_ASSERT( _pEndpointConfig != NULL );
  656. if ( _fRenegotiate || _pEndpointConfig->QueryNegotiateClientCert() )
  657. {
  658. dwFlags |= ASC_REQ_MUTUAL_AUTH;
  659. }
  660. if ( _sslState == SSL_STATE_HANDSHAKE_START )
  661. {
  662. ConditionalAddWorkerThread();
  663. secStatus = AcceptSecurityContext( QueryCredentials(),
  664. NULL,
  665. &MessageIn,
  666. dwFlags,
  667. SECURITY_NATIVE_DREP,
  668. &_hContext,
  669. &MessageOut,
  670. &dwContextAttributes,
  671. &tsExpiry );
  672. ConditionalRemoveWorkerThread();
  673. IF_DEBUG( SCHANNEL_CALLS )
  674. {
  675. DBGPRINTF(( DBG_CONTEXT,
  676. "AcceptSecurityContext() secStatus=0x%x\n",
  677. secStatus
  678. ));
  679. }
  680. if ( SUCCEEDED( secStatus ) )
  681. {
  682. _cbHeader = 0;
  683. _cbTrailer = 0;
  684. _cbBlockSize = 0;
  685. _cbMaximumMessage = 0;
  686. _fValidContext = TRUE;
  687. _sslState = SSL_STATE_HANDSHAKE_IN_PROGRESS;
  688. }
  689. }
  690. else
  691. {
  692. DBG_ASSERT( _sslState == SSL_STATE_HANDSHAKE_IN_PROGRESS );
  693. //
  694. // We already have a valid context. We can directly call
  695. // AcceptSecurityContext()!
  696. //
  697. hOutContext = _hContext;
  698. DBG_ASSERT( _fValidContext );
  699. ConditionalAddWorkerThread();
  700. secStatus = AcceptSecurityContext( QueryCredentials(),
  701. &_hContext,
  702. &MessageIn,
  703. dwFlags,
  704. SECURITY_NATIVE_DREP,
  705. &hOutContext,
  706. &MessageOut,
  707. &dwContextAttributes,
  708. &tsExpiry );
  709. ConditionalRemoveWorkerThread();
  710. IF_DEBUG( SCHANNEL_CALLS )
  711. {
  712. DBGPRINTF(( DBG_CONTEXT,
  713. "AcceptSecurityContext() secStatus=0x%x\n",
  714. secStatus
  715. ));
  716. }
  717. if ( SUCCEEDED( secStatus ) )
  718. {
  719. if ( memcmp(&_hContext,
  720. &hOutContext,
  721. sizeof( _hContext ) != 0 ) )
  722. {
  723. //
  724. // we always expect schannel to return same context handle
  725. // if it doesn't then we better bail out
  726. //
  727. IF_DEBUG( FLAG_ERROR )
  728. {
  729. DBGPRINTF(( DBG_CONTEXT,
  730. "AcceptSecurityContext() return context different from the one on input\n"
  731. ));
  732. }
  733. DBG_ASSERT( FALSE );
  734. hr = HRESULT_FROM_WIN32( ERROR_INVALID_DATA );
  735. goto ExitPoint;
  736. }
  737. }
  738. }
  739. //
  740. // Either way, the secStatus tells us how to proceed
  741. //
  742. if ( SUCCEEDED( secStatus ) )
  743. {
  744. //
  745. // AcceptSecurityContext succeeded
  746. //
  747. //
  748. // We haven't failed yet. But we may not be complete. First
  749. // send back any data to the client
  750. //
  751. if ( OutBuffers[ 0 ].pvBuffer != NULL &&
  752. OutBuffers[ 0 ].cbBuffer != 0 )
  753. {
  754. //
  755. // the following asynchronous Write will not do anything
  756. // upon completion other then to simply delete OVERLAPPED_CONTEXT
  757. // There will be no outstanding RawRead (that would cause trouble)
  758. // because we are in RawRead completion handling phase
  759. // That's why it is safe to continue with execution
  760. // (typically after async there is return and all the cleanup
  761. // or whatever needs to be done happens in completion)
  762. // This async call was originally synchronous and by making
  763. // it ASYNC we eliminate long blocking problem with
  764. // slow client while leaving the rest of original synchronous
  765. // execution intact.
  766. //
  767. //
  768. // FreeContextBuffer will have to be called in the callback function
  769. // upon completion
  770. //
  771. hr = QueryFiltChannelContext()->DoRawWrite(
  772. UL_CONTEXT_FLAG_ASYNC |
  773. UL_CONTEXT_FLAG_COMPLETION_CALLBACK,
  774. OutBuffers[ 0 ].pvBuffer,
  775. OutBuffers[ 0 ].cbBuffer,
  776. NULL, // pcbWritten
  777. OnHandshakeRawWriteCompletion,
  778. OutBuffers[ 0 ].pvBuffer );
  779. if ( FAILED( hr ) )
  780. {
  781. goto ExitPoint;
  782. }
  783. else
  784. {
  785. //
  786. // DoRawWrite completion will take care of cleanup
  787. //
  788. OutBuffers[ 0 ].pvBuffer = NULL;
  789. OutBuffers[ 0 ].cbBuffer = 0;
  790. }
  791. }
  792. if ( secStatus == SEC_E_OK )
  793. {
  794. //
  795. // We must be done with handshake
  796. //
  797. hr = DoHandshakeCompleted();
  798. if ( FAILED( hr ) )
  799. {
  800. goto ExitPoint;
  801. }
  802. }
  803. //
  804. // If the input buffer has more info to be SChannel'ized, then do
  805. // so now. If we haven't completed handshake, then call DoHandShake
  806. // again. Otherwise, call DoDecrypt
  807. //
  808. if ( InBuffers[ 1 ].BufferType == SECBUFFER_EXTRA )
  809. {
  810. IF_DEBUG( SCHANNEL_CALLS )
  811. {
  812. for ( int i = 1; i < 4; i++ )
  813. {
  814. if( InBuffers[ i ].BufferType != 0 )
  815. {
  816. DBGPRINTF(( DBG_CONTEXT,
  817. "AcceptSecurityContext returned extra buffer"
  818. " - %d bytes buffer type: %d\n",
  819. InBuffers[ i ].cbBuffer,
  820. InBuffers[ i ].BufferType
  821. ));
  822. }
  823. }
  824. }
  825. //
  826. // We better have valid extra data
  827. // only cbBuffer is used, pvBuffer is not used with SECBUFFER_EXTRA
  828. //
  829. DBG_ASSERT( InBuffers[ 1 ].cbBuffer != 0 );
  830. //
  831. // Move extra data right after decrypted data (if any)
  832. //
  833. memmove( pRawStreamInfo->pbBuffer + _cbDecrypted,
  834. pRawStreamInfo->pbBuffer + pRawStreamInfo->cbData
  835. - InBuffers[ 1 ].cbBuffer,
  836. InBuffers[ 1 ].cbBuffer
  837. );
  838. //
  839. // Now we have to adjust pRawStreamInfo->cbData and _cbToBeProcessedOffset
  840. //
  841. pRawStreamInfo->cbData = ( _cbDecrypted +
  842. InBuffers[ 1 ].cbBuffer );
  843. _cbToBeProcessedOffset = _cbDecrypted;
  844. *pfExtraData = TRUE;
  845. //
  846. // caller has to detect that some data is
  847. // still in the buffer not processed and
  848. //
  849. hr = S_OK;
  850. goto ExitPoint;
  851. }
  852. else // no extra buffer
  853. {
  854. //
  855. // There is no extra data to be processed
  856. // If we got here as the result of renegotiation
  857. // there may be some decrypted data in StreamInfo buffer already
  858. //
  859. // (without renegotiation _cbDecryted must always be 0
  860. // because SEC_I_RENEGOTIATE is the only way to get
  861. // from DoDecrypt() to DoHandshake() )
  862. //
  863. DBG_ASSERT ( _fRenegotiate || _cbDecrypted == 0 );
  864. pRawStreamInfo->cbData = _cbDecrypted;
  865. _cbToBeProcessedOffset = _cbDecrypted;
  866. if ( _sslState != SSL_STATE_HANDSHAKE_COMPLETE )
  867. {
  868. //
  869. // If we have no more data, and we still haven't completed the
  870. // handshake, then read some more data
  871. //
  872. *pfReadMore = TRUE;
  873. hr = S_OK;
  874. goto ExitPoint;
  875. }
  876. }
  877. //
  878. // final return from DoHandshake on handshake completion
  879. // Cleanup _cbDecrypted and _cbToBeProcessedOffset to make
  880. // sure that next ProcessRawReadData() will work fine
  881. //
  882. _cbToBeProcessedOffset = 0;
  883. _cbDecrypted = 0;
  884. hr = S_OK;
  885. goto ExitPoint;
  886. }
  887. else
  888. {
  889. //
  890. // Note: _OutBuffers[ 0 ].pvBuffer may be changed in AcceptSecurityContext
  891. // even if error is returned.
  892. // Per JBanes, FreeContextBuffer() should be called in the case of error
  893. // only if ASC_RET_EXTENDED_ERROR flag is set in ContextAttributes.
  894. // Otherwise value should be ignored. We will NULL it out to prevent problems
  895. //
  896. if ( !( dwContextAttributes & ASC_RET_EXTENDED_ERROR ) )
  897. {
  898. OutBuffers[0].pvBuffer = NULL;
  899. OutBuffers[0].cbBuffer = 0;
  900. }
  901. //
  902. // AcceptSecurityContext() failed!
  903. //
  904. if ( secStatus == SEC_E_INCOMPLETE_MESSAGE )
  905. {
  906. *pfReadMore = TRUE;
  907. hr = S_OK;
  908. goto ExitPoint;
  909. }
  910. else
  911. {
  912. IF_DEBUG( FLAG_ERROR )
  913. {
  914. DBGPRINTF(( DBG_CONTEXT,
  915. "AcceptSecurityContext() failed with secStatus=0x%x\n",
  916. secStatus
  917. ));
  918. }
  919. //
  920. // Maybe we can send a more useful message to the client
  921. //
  922. if ( dwContextAttributes & ASC_RET_EXTENDED_ERROR )
  923. {
  924. if ( OutBuffers[ 0 ].pvBuffer!= NULL &&
  925. OutBuffers[ 0 ].cbBuffer != 0 )
  926. {
  927. //
  928. // FreeContextBuffer will have to be called in the callback function
  929. // upon completion
  930. //
  931. hr = QueryFiltChannelContext()->DoRawWrite(
  932. UL_CONTEXT_FLAG_ASYNC |
  933. UL_CONTEXT_FLAG_COMPLETION_CALLBACK,
  934. OutBuffers[ 0 ].pvBuffer,
  935. OutBuffers[ 0 ].cbBuffer,
  936. NULL, // pcbWritten
  937. OnHandshakeRawWriteCompletion,
  938. OutBuffers[ 0 ].pvBuffer );
  939. if ( FAILED( hr ) )
  940. {
  941. goto ExitPoint;
  942. }
  943. else
  944. {
  945. //
  946. // DoRawWrite completion will take care of cleanup
  947. //
  948. OutBuffers[ 0 ].pvBuffer = NULL;
  949. OutBuffers[ 0 ].cbBuffer = 0;
  950. }
  951. }
  952. }
  953. }
  954. hr = secStatus;
  955. }
  956. ExitPoint:
  957. if ( OutBuffers[ 0 ].pvBuffer != NULL )
  958. {
  959. FreeContextBuffer( OutBuffers[ 0 ].pvBuffer );
  960. OutBuffers[ 0 ].pvBuffer = NULL;
  961. OutBuffers[ 0 ].cbBuffer = 0;
  962. }
  963. return hr;
  964. }
  965. HRESULT
  966. SSL_STREAM_CONTEXT::DoHandshakeCompleted()
  967. {
  968. HRESULT hr = S_OK;
  969. SECURITY_STATUS secStatus = SEC_E_OK;
  970. SecPkgContext_StreamSizes StreamSizes;
  971. HTTP_FILTER_BUFFER ulFilterBuffer;
  972. _sslState = SSL_STATE_HANDSHAKE_COMPLETE;
  973. //
  974. // Get some buffer size info for this connection. We only need
  975. // to do this on completion of the initial handshake, and NOT
  976. // subsequent renegotiation handshake (if any)
  977. //
  978. if ( !_cbHeader && !_cbTrailer )
  979. {
  980. secStatus = QueryContextAttributes( &_hContext,
  981. SECPKG_ATTR_STREAM_SIZES,
  982. &StreamSizes );
  983. if ( FAILED( secStatus ) )
  984. {
  985. return secStatus;
  986. }
  987. _cbHeader = StreamSizes.cbHeader;
  988. _cbTrailer = StreamSizes.cbTrailer;
  989. _cbBlockSize = StreamSizes.cbBlockSize;
  990. _cbMaximumMessage = StreamSizes.cbMaximumMessage;
  991. }
  992. //
  993. // Build up a message for the application indicating stuff
  994. // about the negotiated connection
  995. //
  996. // If this is a renegotiate request, then we have already sent
  997. // and calculated the SSL_INFO, so just send the CERT_INFO
  998. //
  999. if ( !_fRenegotiate )
  1000. {
  1001. //
  1002. // send SSL info only if not in renegotiation loop
  1003. // because otherwise http.sys has the info already
  1004. //
  1005. hr = BuildSslInfo();
  1006. if ( FAILED( hr ) )
  1007. {
  1008. return hr;
  1009. }
  1010. ulFilterBuffer.BufferType = HttpFilterBufferSslInitInfo;
  1011. ulFilterBuffer.pBuffer = (PBYTE) &_ulSslInfo;
  1012. ulFilterBuffer.BufferSize = sizeof( _ulSslInfo );
  1013. hr = QueryFiltChannelContext()->DoAppWrite( UL_CONTEXT_FLAG_SYNC,
  1014. &ulFilterBuffer,
  1015. NULL );
  1016. if ( FAILED( hr ) )
  1017. {
  1018. return hr;
  1019. }
  1020. }
  1021. //
  1022. // Pass client certificate information to http.sys
  1023. // if client certificates are required on the site level then
  1024. // inform about client certificate even in the case when
  1025. // client cert is not present not to cause double negotiation
  1026. //
  1027. if ( _pClientCert != NULL ||
  1028. _fRenegotiate ||
  1029. _pEndpointConfig->QueryNegotiateClientCert() )
  1030. {
  1031. //
  1032. // Renegotiation time is monitored by timer
  1033. // because http.sys doesn't monitor this particular
  1034. // code path because of the way filter works
  1035. //
  1036. QueryFiltChannelContext()->StopTimeoutTimer();
  1037. if ( SUCCEEDED( RetrieveClientCertAndToken() ) )
  1038. {
  1039. hr = BuildClientCertInfo();
  1040. if ( FAILED( hr ) )
  1041. {
  1042. return hr;
  1043. }
  1044. }
  1045. //
  1046. // CODEWORK:
  1047. // It would be better to eliminate HttpFilterBufferSslClientCertAndMap
  1048. // and let HTTP.SYS to check on token value. If it is NULL then mapping
  1049. // did not happen
  1050. //
  1051. if ( _ulCertInfo.Token != NULL )
  1052. {
  1053. ulFilterBuffer.BufferType = HttpFilterBufferSslClientCertAndMap;
  1054. }
  1055. else
  1056. {
  1057. ulFilterBuffer.BufferType = HttpFilterBufferSslClientCert;
  1058. }
  1059. //
  1060. // If client certificate was not negotiated, then structure will be empty.
  1061. // HTTP.SYS is able to handle it.
  1062. //
  1063. ulFilterBuffer.pBuffer = (PBYTE) &_ulCertInfo;
  1064. ulFilterBuffer.BufferSize = sizeof( _ulCertInfo );
  1065. //
  1066. // Write the client certificate information to the application
  1067. // (it will be cached by HTTP.sys for the lifetime of the connection)
  1068. //
  1069. hr = QueryFiltChannelContext()->DoAppWrite( UL_CONTEXT_FLAG_SYNC,
  1070. &ulFilterBuffer,
  1071. NULL );
  1072. if ( FAILED( hr ) )
  1073. {
  1074. return hr;
  1075. }
  1076. }
  1077. return hr;
  1078. }
  1079. HRESULT
  1080. SSL_STREAM_CONTEXT::DoRenegotiate(
  1081. VOID
  1082. )
  1083. /*++
  1084. Routine Description:
  1085. Trigger a renegotiate for a client certificate
  1086. Arguments:
  1087. None
  1088. Return Value:
  1089. HRESULT
  1090. --*/
  1091. {
  1092. SECURITY_STATUS secStatus = SEC_E_OK;
  1093. CtxtHandle hOutContext;
  1094. DWORD dwContextAttributes = 0;
  1095. TimeStamp tsExpiry;
  1096. DWORD dwFlags = SSL_ASC_FLAGS |
  1097. ASC_REQ_MUTUAL_AUTH;
  1098. HRESULT hr = S_OK;
  1099. // Buffers used for SSL Handshake (incoming handshake blob)
  1100. // 4 is the schannel magic number
  1101. SecBufferDesc MessageIn;
  1102. SecBuffer InBuffers[ 4 ];
  1103. // Buffers used for SSL Handshake (outgoing handshake blob)
  1104. // 4 is the schannel magic number
  1105. SecBufferDesc MessageOut;
  1106. SecBuffer OutBuffers[ 4 ];
  1107. DBG_ASSERT( _pEndpointConfig != NULL );
  1108. //
  1109. // Remember that we're renegotiating since we now have to pass the
  1110. // MUTUAL_AUTH flag into AcceptSecurityContext() from here on out. Also
  1111. // we can only request renegotiation once per connection
  1112. //
  1113. DBG_ASSERT( _fRenegotiate == FALSE );
  1114. _fRenegotiate = TRUE;
  1115. QueryFiltChannelContext()->StartTimeoutTimer();
  1116. //
  1117. // Try to get the client certificate. If we don't, that's OK. We will
  1118. // renegotiate
  1119. //
  1120. hr = RetrieveClientCertAndToken();
  1121. if ( SUCCEEDED ( hr ) )
  1122. {
  1123. //
  1124. // we have client certificate available for this session
  1125. // there is no need to continue with renegotiation
  1126. //
  1127. hr = DoHandshakeCompleted();
  1128. return hr;
  1129. }
  1130. //
  1131. // Reset the HRESULT
  1132. // Previous error failing to retrieve client certificate is OK,
  1133. // it just means that renegotiation is necessary since
  1134. // no client certificate is currently available
  1135. hr = S_OK;
  1136. //
  1137. // Restart the handshake
  1138. //
  1139. //
  1140. // Setup input & output buffers for AcceptSecurityContext call
  1141. //
  1142. MessageIn.ulVersion = SECBUFFER_VERSION;
  1143. MessageIn.cBuffers = 4;
  1144. MessageIn.pBuffers = InBuffers;
  1145. InBuffers[0].BufferType = SECBUFFER_TOKEN;
  1146. InBuffers[0].pvBuffer = "";
  1147. InBuffers[0].cbBuffer = 0;
  1148. InBuffers[1].BufferType = SECBUFFER_EMPTY;
  1149. InBuffers[2].BufferType = SECBUFFER_EMPTY;
  1150. InBuffers[3].BufferType = SECBUFFER_EMPTY;
  1151. MessageOut.ulVersion = SECBUFFER_VERSION;
  1152. MessageOut.cBuffers = 4;
  1153. MessageOut.pBuffers = OutBuffers;
  1154. OutBuffers[0].pvBuffer = NULL;
  1155. OutBuffers[0].cbBuffer = NULL;
  1156. OutBuffers[0].BufferType = SECBUFFER_EMPTY;
  1157. OutBuffers[1].BufferType = SECBUFFER_EMPTY;
  1158. OutBuffers[2].BufferType = SECBUFFER_EMPTY;
  1159. OutBuffers[3].BufferType = SECBUFFER_EMPTY;
  1160. hOutContext = _hContext;
  1161. ConditionalAddWorkerThread();
  1162. secStatus = AcceptSecurityContext( QueryCredentials(),
  1163. &_hContext,
  1164. &MessageIn,
  1165. dwFlags,
  1166. SECURITY_NATIVE_DREP,
  1167. &hOutContext,
  1168. &MessageOut,
  1169. &dwContextAttributes,
  1170. &tsExpiry );
  1171. ConditionalRemoveWorkerThread();
  1172. IF_DEBUG( SCHANNEL_CALLS )
  1173. {
  1174. DBGPRINTF(( DBG_CONTEXT,
  1175. "AcceptSecurityContext() secStatus=0x%x\n",
  1176. secStatus
  1177. ));
  1178. }
  1179. if ( secStatus == SEC_E_UNSUPPORTED_FUNCTION )
  1180. {
  1181. //
  1182. // Renegotiation is not suppported for current protocol
  1183. // (SSL2 would be example of such protocol)
  1184. // Change state to HandhakeCompleted
  1185. //
  1186. hr = DoHandshakeCompleted();
  1187. }
  1188. else if ( SUCCEEDED( secStatus ) )
  1189. {
  1190. if ( memcmp( &_hContext,
  1191. &hOutContext,
  1192. sizeof( _hContext ) != 0 ) )
  1193. {
  1194. //
  1195. // we always expect schannel to return same context handle
  1196. // if it doesn't then we better bail out
  1197. //
  1198. IF_DEBUG( FLAG_ERROR )
  1199. {
  1200. DBGPRINTF(( DBG_CONTEXT,
  1201. "AcceptSecurityContext() return context different from the one on input\n"
  1202. ));
  1203. }
  1204. DBG_ASSERT( FALSE );
  1205. hr = HRESULT_FROM_WIN32( ERROR_INVALID_DATA );
  1206. goto ExitPoint;
  1207. }
  1208. if ( OutBuffers[0].pvBuffer != NULL &&
  1209. OutBuffers[0].cbBuffer != 0 )
  1210. {
  1211. //
  1212. // _fExpectRenegotiationFromClient flag will be used to eliminate
  1213. // client triggered renegotiation by enabling client data to cause
  1214. // renegotiation only if fExpectRenegotiationFromClient is already set
  1215. // That will prove that it is server initiated renegotiation
  1216. // If we don't prevent client triggered renegotiation there may
  1217. // be some wierd race conditions because client triggered renegotiation
  1218. // could interfere with the outgoing data stream (due to full duplex
  1219. // for incoming and outgoing data)
  1220. // Do interlocked because we check the value on the incoming data handling path
  1221. // in the DecryptMessage()
  1222. //
  1223. // Note: It is possible that after _fExpectRenegotiationFromClient is set
  1224. // client may try to send renegotiation request (client initiated renegotiation)
  1225. // Our flag is set already so that before we execute DoRawWrite
  1226. // there could be a thread executing DoHandshake
  1227. // Care must be used when modifying anything past the InterlockedExchange
  1228. // to eliminate any potential race with DoHandhshake function
  1229. //
  1230. InterlockedExchange( (LONG *)&_fExpectRenegotiationFromClient, (LONG) TRUE );
  1231. hr = QueryFiltChannelContext()->DoRawWrite(
  1232. UL_CONTEXT_FLAG_ASYNC |
  1233. UL_CONTEXT_FLAG_COMPLETION_CALLBACK,
  1234. OutBuffers[0].pvBuffer,
  1235. OutBuffers[0].cbBuffer,
  1236. NULL, // pcbWritten
  1237. OnHandshakeRawWriteCompletion,
  1238. OutBuffers[0].pvBuffer );
  1239. if ( FAILED( hr ) )
  1240. {
  1241. goto ExitPoint;
  1242. }
  1243. else
  1244. {
  1245. // callback after DoRawWrite is responsible to cleanup pvOutBuffer
  1246. OutBuffers[0].pvBuffer = NULL;
  1247. OutBuffers[0].cbBuffer = 0;
  1248. }
  1249. }
  1250. hr = secStatus;
  1251. }
  1252. else
  1253. {
  1254. IF_DEBUG( FLAG_ERROR )
  1255. {
  1256. DBGPRINTF(( DBG_CONTEXT,
  1257. "AcceptSecurityContext() for renegotiation failed with secStatus=0x%x\n",
  1258. secStatus
  1259. ));
  1260. }
  1261. if ( dwContextAttributes & ASC_RET_EXTENDED_ERROR )
  1262. {
  1263. if ( OutBuffers[0].pvBuffer != NULL &&
  1264. OutBuffers[0].cbBuffer != 0 )
  1265. {
  1266. hr = QueryFiltChannelContext()->DoRawWrite(
  1267. UL_CONTEXT_FLAG_ASYNC |
  1268. UL_CONTEXT_FLAG_COMPLETION_CALLBACK,
  1269. OutBuffers[0].pvBuffer,
  1270. OutBuffers[0].cbBuffer,
  1271. NULL, // pcbWritten
  1272. OnHandshakeRawWriteCompletion,
  1273. OutBuffers[0].pvBuffer );
  1274. if ( FAILED( hr ) )
  1275. {
  1276. goto ExitPoint;
  1277. }
  1278. else
  1279. {
  1280. // callback after DoRawWrite is responsible to cleanup pvOutBuffer
  1281. OutBuffers[0].pvBuffer = NULL;
  1282. OutBuffers[0].cbBuffer = 0;
  1283. }
  1284. }
  1285. }
  1286. else
  1287. {
  1288. //
  1289. // Note: _OutBuffers[ 0 ].pvBuffer may be changed in AcceptSecurityContext
  1290. // even if error is returned.
  1291. // Per JBanes, FreeContextBuffer() should be called in the case of error
  1292. // only if ASC_RET_EXTENDED_ERROR flag is set in ContextAttributes.
  1293. // Otherwise value should be ignored. We will NULL it out to prevent problems
  1294. //
  1295. OutBuffers[0].pvBuffer = NULL;
  1296. OutBuffers[0].cbBuffer = 0;
  1297. }
  1298. hr = secStatus;
  1299. }
  1300. ExitPoint:
  1301. if ( OutBuffers[0].pvBuffer != NULL )
  1302. {
  1303. FreeContextBuffer( OutBuffers[0].pvBuffer );
  1304. OutBuffers[0].pvBuffer = NULL;
  1305. }
  1306. return hr;
  1307. }
  1308. HRESULT
  1309. SSL_STREAM_CONTEXT::DoDecrypt(
  1310. RAW_STREAM_INFO * pRawStreamInfo,
  1311. BOOL * pfReadMore,
  1312. BOOL * pfComplete,
  1313. BOOL * pfExtraData
  1314. )
  1315. /*++
  1316. Routine Description:
  1317. Decrypt some data
  1318. Arguments:
  1319. pRawStreamInfo - Raw data buffer
  1320. pfReadMore - Set to true if we should read more data
  1321. pfComplete - Set to true if we should disconnect
  1322. Return Value:
  1323. HRESULT
  1324. --*/
  1325. {
  1326. SECURITY_STATUS secStatus = SEC_E_OK;
  1327. INT iExtra;
  1328. BOOL fDecryptAgain = TRUE;
  1329. UCHAR FirstByte = 0; //used only for debug output
  1330. // Buffers used for SSL Handshake (incoming handshake blob)
  1331. // 4 is the schannel magic number
  1332. SecBufferDesc Message;
  1333. SecBuffer Buffers[ 4 ];
  1334. if ( pRawStreamInfo == NULL ||
  1335. pfReadMore == NULL ||
  1336. pfComplete == NULL ||
  1337. pfExtraData == NULL )
  1338. {
  1339. DBG_ASSERT( FALSE );
  1340. return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
  1341. }
  1342. *pfReadMore = FALSE;
  1343. *pfComplete = FALSE;
  1344. *pfExtraData = FALSE;
  1345. IF_DEBUG( SCHANNEL_CALLS )
  1346. {
  1347. DBGPRINTF(( DBG_CONTEXT,
  1348. "DoDecrypt(): _cbDecrypted = %d, _cbToBeProcessedOffset=%d\n",
  1349. _cbDecrypted,
  1350. _cbToBeProcessedOffset
  1351. ));
  1352. }
  1353. //
  1354. // Setup an DecryptMessage call. The input buffer is the _buffRaw plus
  1355. // an offset. The offset is non-zero if we had to do another read to
  1356. // get more data for a previously incomplete message
  1357. //
  1358. if( pRawStreamInfo->cbData < _cbToBeProcessedOffset )
  1359. {
  1360. //
  1361. // Inconsisent state of the SSL_STREAM_CONTEXT
  1362. // This should never really happen, but because we
  1363. // execute in lsass we don't want to see wrong offset calculations
  1364. // cause much trouble in lsass
  1365. //
  1366. IF_DEBUG ( FLAG_ERROR )
  1367. {
  1368. DBGPRINTF(( DBG_CONTEXT,
  1369. "Error: HttpFilter detected unexpected offset in it's internal data (connection will be closed)\n"
  1370. ));
  1371. }
  1372. DBG_ASSERT( FALSE );
  1373. return HRESULT_FROM_WIN32( ERROR_INVALID_DATA );
  1374. }
  1375. //
  1376. // Prepare message buffers to be passed to the DecryptMessage
  1377. //
  1378. Message.ulVersion = SECBUFFER_VERSION;
  1379. Message.cBuffers = 4;
  1380. Message.pBuffers = Buffers;
  1381. Buffers[ 0 ].pvBuffer = pRawStreamInfo->pbBuffer + _cbToBeProcessedOffset;
  1382. Buffers[ 0 ].cbBuffer = pRawStreamInfo->cbData - _cbToBeProcessedOffset;
  1383. Buffers[ 0 ].BufferType = SECBUFFER_DATA;
  1384. Buffers[ 1 ].BufferType = SECBUFFER_EMPTY;
  1385. Buffers[ 2 ].BufferType = SECBUFFER_EMPTY;
  1386. Buffers[ 3 ].BufferType = SECBUFFER_EMPTY;
  1387. while ( fDecryptAgain )
  1388. {
  1389. fDecryptAgain = FALSE;
  1390. IF_DEBUG( SCHANNEL_CALLS )
  1391. {
  1392. //
  1393. // remember first byte because Decrypt will alter it
  1394. //
  1395. FirstByte = (unsigned char) *((char *)Buffers[ 0 ].pvBuffer);
  1396. }
  1397. secStatus = DecryptMessage( &_hContext,
  1398. &Message,
  1399. 0,
  1400. NULL );
  1401. IF_DEBUG( SCHANNEL_CALLS )
  1402. {
  1403. DBGPRINTF(( DBG_CONTEXT,
  1404. "DecryptMessage( bytes:%d, first byte:0x%x ) secStatus=0x%x\n",
  1405. pRawStreamInfo->cbData - _cbToBeProcessedOffset,
  1406. FirstByte,
  1407. secStatus
  1408. ));
  1409. }
  1410. if ( FAILED( secStatus ) )
  1411. {
  1412. if ( secStatus == SEC_E_INCOMPLETE_MESSAGE )
  1413. {
  1414. //
  1415. // Setup another read since the message is incomplete. Remember
  1416. // where the new data is going to since we only pass this data
  1417. // to the next DecryptMessage call
  1418. //
  1419. _cbToBeProcessedOffset = (DWORD) DIFF( (BYTE *)Buffers[ 0 ].pvBuffer -
  1420. pRawStreamInfo->pbBuffer );
  1421. QueryFiltChannelContext()->SetNextRawReadSize( Buffers[ 1 ].cbBuffer );
  1422. *pfReadMore = TRUE;
  1423. return S_OK;
  1424. }
  1425. IF_DEBUG( FLAG_ERROR )
  1426. {
  1427. DBGPRINTF(( DBG_CONTEXT,
  1428. "DecryptMessage() failed with secStatus=0x%x\n",
  1429. secStatus
  1430. ));
  1431. }
  1432. return secStatus;
  1433. }
  1434. if ( secStatus == SEC_E_OK )
  1435. {
  1436. //
  1437. // Encrypted data contains header and trailer
  1438. // AppWrite expects continuous buffer
  1439. // so we have to move currently decrypted message block
  1440. // just after the already Decrypted data (if any - otherwise the
  1441. // begining of the buffer)
  1442. //
  1443. memmove( pRawStreamInfo->pbBuffer + _cbDecrypted,
  1444. Buffers[ 1 ].pvBuffer,
  1445. Buffers[ 1 ].cbBuffer );
  1446. _cbDecrypted += Buffers[ 1 ].cbBuffer;
  1447. }
  1448. //
  1449. // Locate extra data (may be available)
  1450. //
  1451. iExtra = 0;
  1452. for ( int i = 1; i < 4; i++ )
  1453. {
  1454. IF_DEBUG( SCHANNEL_CALLS )
  1455. {
  1456. if( Buffers[ i ].BufferType != 0 )
  1457. {
  1458. DBGPRINTF(( DBG_CONTEXT,
  1459. "DecryptMessage returned extra buffer"
  1460. " - %d bytes buffer type: %d\n",
  1461. Buffers[ i ].cbBuffer,
  1462. Buffers[ i ].BufferType
  1463. ));
  1464. }
  1465. }
  1466. if ( Buffers[ i ].BufferType == SECBUFFER_EXTRA )
  1467. {
  1468. iExtra = i;
  1469. break;
  1470. }
  1471. }
  1472. if ( iExtra != 0 )
  1473. {
  1474. //
  1475. // Process extra buffer
  1476. //
  1477. _cbToBeProcessedOffset = (DWORD) DIFF( (PBYTE) Buffers[ iExtra ].pvBuffer -
  1478. pRawStreamInfo->pbBuffer );
  1479. if ( secStatus != SEC_I_RENEGOTIATE )
  1480. {
  1481. //
  1482. // There are more message blocks in the blob received from client
  1483. //
  1484. Buffers[ 0 ].pvBuffer = Buffers[ iExtra ].pvBuffer;
  1485. Buffers[ 0 ].cbBuffer = Buffers[ iExtra ].cbBuffer;
  1486. Buffers[ 0 ].BufferType = SECBUFFER_DATA;
  1487. Buffers[ 1 ].BufferType = SECBUFFER_EMPTY;
  1488. Buffers[ 2 ].BufferType = SECBUFFER_EMPTY;
  1489. Buffers[ 3 ].BufferType = SECBUFFER_EMPTY;
  1490. fDecryptAgain = TRUE;
  1491. continue;
  1492. }
  1493. else // secStatus == SEC_I_RENEGOTIATE
  1494. {
  1495. //
  1496. // we will accept renegotiation
  1497. // only if _fExpectRenegotiationFromClient is already set
  1498. // That means that renegotiation was started by server
  1499. // We reject client initiated renegotiations because
  1500. // that may cause problems with our state handling
  1501. // and could possibly make us prone to attacks
  1502. // Also reset _fExpectRenegotiationFromClient to FALSE so that
  1503. // client is not allowed to try more than once
  1504. if ( InterlockedExchange( (LONG *)&_fExpectRenegotiationFromClient, (LONG) FALSE ) )
  1505. {
  1506. //
  1507. // If a renegotiation is triggered, resume the handshake state
  1508. //
  1509. _sslState = SSL_STATE_HANDSHAKE_IN_PROGRESS;
  1510. //
  1511. // Caller has to detect that some data is
  1512. // still in the buffer not processed and
  1513. // That will signal to call DoHandshake()
  1514. // for that extra data
  1515. //
  1516. *pfExtraData = TRUE;
  1517. return S_OK;
  1518. }
  1519. else
  1520. {
  1521. secStatus = SEC_E_UNSUPPORTED_FUNCTION;
  1522. if ( ( DEBUG_FLAG_ERROR & GET_DEBUG_FLAGS() )
  1523. && FAILED(secStatus) )
  1524. {
  1525. DBGPRINTF(( DBG_CONTEXT,
  1526. "Client initiated renegotiation is not supported by IIS. secStatus=0x%x\n",
  1527. secStatus
  1528. ));
  1529. }
  1530. return secStatus;
  1531. }
  1532. }
  1533. }
  1534. }
  1535. //
  1536. // there would have been extra data with SEC_I_RENEGOTIATE
  1537. // so we must never get here when renegotiating
  1538. //
  1539. DBG_ASSERT( secStatus != SEC_I_RENEGOTIATE );
  1540. //
  1541. // Adjust cbData to include only decrypted data
  1542. //
  1543. pRawStreamInfo->cbData = _cbDecrypted;
  1544. //
  1545. // We have final decrypted buffer and no extra data left
  1546. // Cleanup _cbDecrypted and _cbToBeProcessedOffset to make sure that
  1547. // next ProcessRawReadData() will work fine.
  1548. //
  1549. _cbDecrypted = 0;
  1550. _cbToBeProcessedOffset = 0;
  1551. return S_OK;
  1552. }
  1553. HRESULT
  1554. SSL_STREAM_CONTEXT::DoEncrypt(
  1555. RAW_STREAM_INFO * pRawStreamInfo,
  1556. BOOL * pfComplete
  1557. )
  1558. /*++
  1559. Routine Description:
  1560. Encrypt data from the application
  1561. Arguments:
  1562. pRawStreamInfo - Raw data buffer
  1563. pfComplete - Set to true if we should disconnect
  1564. Return Value:
  1565. HRESULT
  1566. --*/
  1567. {
  1568. SECURITY_STATUS secStatus = SEC_E_OK;
  1569. // number of chunks the data to be encrypted will be split to
  1570. DWORD dwChunks = 0;
  1571. // current Data chunk size to be encrypted
  1572. DWORD cbDataChunk = 0;
  1573. // bytes already encrypted from the source
  1574. DWORD cbDataProcessed = 0;
  1575. // offset to *pbufRawWrite where new chunk should be placed
  1576. DWORD cbRawWriteOffset = 0;
  1577. // buffer acquired from FILTER_CHANNEL_CONTEXT to store data for RawWrite
  1578. // it is necessary to use buffer owned by FILTER_CHANNEL_CONTEXT to
  1579. // allow 2 outstanding RawWrites
  1580. PBYTE pbRawWrite = NULL;
  1581. DWORD cbRawWrite = 0;
  1582. HRESULT hr = E_FAIL;
  1583. // Buffer for encrypting clear text data from application
  1584. // to be sent back to client
  1585. // 4 is magic number coming from schannel
  1586. SecBufferDesc Message;
  1587. SecBuffer EncryptBuffers[ 4 ];
  1588. if ( pRawStreamInfo == NULL ||
  1589. pfComplete == NULL )
  1590. {
  1591. DBG_ASSERT( FALSE );
  1592. return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
  1593. }
  1594. *pfComplete = FALSE;
  1595. //
  1596. // Each protocol has limit on maximum size of message
  1597. // that can be encrypted with one EncryptMessage() call
  1598. //
  1599. DBG_ASSERT( _cbMaximumMessage != 0 );
  1600. //
  1601. // Calculate number of chunks based on _cbMaximumMessage
  1602. //
  1603. dwChunks = pRawStreamInfo->cbData / _cbMaximumMessage;
  1604. if ( pRawStreamInfo->cbData % _cbMaximumMessage != 0 )
  1605. {
  1606. dwChunks++;
  1607. }
  1608. //
  1609. // ask FILTER_CHANNEL_CONTEXT for one buffer for RawWrite
  1610. // (FILTER_CHANNEL_CONTEXT maintains 2 buffer to allow 2 outstanding RawWrites
  1611. // to handle the TCP's DELAYED_ACK issue - see Windows Bugs 394511)
  1612. // buffer doesn't have to be released in the error case because
  1613. // error will cause connection to get closed and FILTER_CHANNEL_CONTEXT will
  1614. // handle cleanup.
  1615. //
  1616. //
  1617. // Allocate a large enough buffer for encrypted data
  1618. // ( remember that each chunk needs header and trailer )
  1619. //
  1620. cbRawWrite = pRawStreamInfo->cbData +
  1621. dwChunks * _cbHeader +
  1622. dwChunks * _cbTrailer;
  1623. hr = QueryFiltChannelContext()->AcquireRawWriteBuffer(
  1624. &pbRawWrite,
  1625. cbRawWrite );
  1626. if ( FAILED ( hr ) )
  1627. {
  1628. return hr;
  1629. }
  1630. DBG_ASSERT( pbRawWrite != NULL );
  1631. //
  1632. // Loop to encrypt required data in chunks each not exceeding _cbMaximumMessage
  1633. //
  1634. for ( DWORD dwCurrentChunk = 0; dwCurrentChunk < dwChunks; dwCurrentChunk++ )
  1635. {
  1636. DBG_ASSERT( cbRawWrite > cbRawWriteOffset );
  1637. cbDataChunk = min( pRawStreamInfo->cbData - cbDataProcessed,
  1638. _cbMaximumMessage );
  1639. memcpy( pbRawWrite + _cbHeader + cbRawWriteOffset,
  1640. pRawStreamInfo->pbBuffer + cbDataProcessed,
  1641. cbDataChunk );
  1642. //
  1643. // Setup buffer for app data to be encrypted
  1644. //
  1645. Message.ulVersion = SECBUFFER_VERSION;
  1646. Message.cBuffers = 4;
  1647. Message.pBuffers = EncryptBuffers;
  1648. EncryptBuffers[ 0 ].pvBuffer = pbRawWrite +
  1649. cbRawWriteOffset;
  1650. EncryptBuffers[ 0 ].cbBuffer = _cbHeader;
  1651. EncryptBuffers[ 0 ].BufferType = SECBUFFER_STREAM_HEADER;
  1652. EncryptBuffers[ 1 ].pvBuffer = pbRawWrite +
  1653. _cbHeader +
  1654. cbRawWriteOffset;
  1655. EncryptBuffers[ 1 ].cbBuffer = cbDataChunk;
  1656. EncryptBuffers[ 1 ].BufferType = SECBUFFER_DATA;
  1657. EncryptBuffers[ 2 ].pvBuffer = pbRawWrite +
  1658. _cbHeader +
  1659. cbDataChunk +
  1660. cbRawWriteOffset;
  1661. EncryptBuffers[ 2 ].cbBuffer = _cbTrailer;
  1662. EncryptBuffers[ 2 ].BufferType = SECBUFFER_STREAM_TRAILER;
  1663. EncryptBuffers[ 3 ].BufferType = SECBUFFER_EMPTY;
  1664. secStatus = EncryptMessage( &_hContext,
  1665. 0,
  1666. &Message,
  1667. 0 );
  1668. IF_DEBUG( SCHANNEL_CALLS )
  1669. {
  1670. DBGPRINTF(( DBG_CONTEXT,
  1671. "EncryptMessage() secStatus=0x%x\n",
  1672. secStatus
  1673. ));
  1674. }
  1675. if(SUCCEEDED(secStatus))
  1676. {
  1677. //
  1678. // next chunk was successfully encrypted
  1679. //
  1680. cbDataProcessed += cbDataChunk;
  1681. cbRawWriteOffset += EncryptBuffers[ 0 ].cbBuffer +
  1682. EncryptBuffers[ 1 ].cbBuffer +
  1683. EncryptBuffers[ 2 ].cbBuffer;
  1684. }
  1685. else
  1686. {
  1687. //
  1688. // Set cbData to 0 just for the case that caller ignored error
  1689. // and tried to send not encrypted data to client
  1690. //
  1691. pRawStreamInfo->cbData = 0;
  1692. IF_DEBUG( FLAG_ERROR )
  1693. {
  1694. DBGPRINTF(( DBG_CONTEXT,
  1695. "EncryptMessage() failed with secStatus=0x%x\n",
  1696. secStatus
  1697. ));
  1698. }
  1699. return secStatus;
  1700. }
  1701. }
  1702. //
  1703. // Replace the raw stream buffer with the encrypted data
  1704. //
  1705. pRawStreamInfo->pbBuffer = pbRawWrite;
  1706. pRawStreamInfo->cbBuffer = cbRawWrite;
  1707. pRawStreamInfo->cbData = cbRawWriteOffset;
  1708. return S_OK;
  1709. }
  1710. HRESULT
  1711. SSL_STREAM_CONTEXT::BuildSslInfo(
  1712. VOID
  1713. )
  1714. /*++
  1715. Routine Description:
  1716. Build UL_SSL_INFO structure based on Schannel context handle
  1717. Arguments:
  1718. None
  1719. Return Value:
  1720. HRESULT
  1721. --*/
  1722. {
  1723. SECURITY_STATUS secStatus;
  1724. SecPkgContext_ConnectionInfo ConnectionInfo;
  1725. SERVER_CERT * pServerCert = NULL;
  1726. HRESULT hr = S_OK;
  1727. //
  1728. // Negotiated key size
  1729. //
  1730. //
  1731. // Negotiated key size
  1732. //
  1733. if ( _ulSslInfo.ConnectionKeySize == 0 )
  1734. {
  1735. secStatus = QueryContextAttributes( &_hContext,
  1736. SECPKG_ATTR_CONNECTION_INFO,
  1737. &ConnectionInfo );
  1738. if ( SUCCEEDED( secStatus ) )
  1739. {
  1740. _ulSslInfo.ConnectionKeySize = (USHORT) ConnectionInfo.dwCipherStrength;
  1741. }
  1742. }
  1743. //
  1744. // A bunch of parameters are based off the server certificate. Get that
  1745. // cert now
  1746. //
  1747. DBG_ASSERT( _pEndpointConfig != NULL );
  1748. pServerCert = _pEndpointConfig->QueryServerCert();
  1749. DBG_ASSERT( pServerCert != NULL );
  1750. //
  1751. // Server cert strength
  1752. //
  1753. if ( _ulSslInfo.ServerCertKeySize == 0 )
  1754. {
  1755. _ulSslInfo.ServerCertKeySize = pServerCert->QueryPublicKeySize();
  1756. }
  1757. //
  1758. // Server Cert Issuer
  1759. //
  1760. if ( _ulSslInfo.pServerCertIssuer == NULL )
  1761. {
  1762. DBG_ASSERT( _ulSslInfo.ServerCertIssuerSize == 0 );
  1763. _ulSslInfo.pServerCertIssuer = pServerCert->QueryIssuer()->QueryStr();
  1764. _ulSslInfo.ServerCertIssuerSize = pServerCert->QueryIssuer()->QueryCCH();
  1765. }
  1766. //
  1767. // Server Cert subject
  1768. //
  1769. if ( _ulSslInfo.pServerCertSubject == NULL )
  1770. {
  1771. DBG_ASSERT( _ulSslInfo.ServerCertSubjectSize == 0 );
  1772. _ulSslInfo.pServerCertSubject = pServerCert->QuerySubject()->QueryStr(),
  1773. _ulSslInfo.ServerCertSubjectSize = pServerCert->QuerySubject()->QueryCCH();
  1774. }
  1775. return hr;
  1776. }
  1777. HRESULT
  1778. SSL_STREAM_CONTEXT::RetrieveClientCertAndToken(
  1779. VOID
  1780. )
  1781. /*++
  1782. Routine Description:
  1783. Query client certificate and token from the SSL context
  1784. Arguments:
  1785. none
  1786. Return Value:
  1787. HRESULT
  1788. --*/
  1789. {
  1790. SECURITY_STATUS secStatus = SEC_E_OK;
  1791. //
  1792. // If client certificate has already been retrieved then simply return
  1793. // with success
  1794. //
  1795. if ( _pClientCert != NULL )
  1796. {
  1797. return SEC_E_OK;
  1798. }
  1799. secStatus = QueryContextAttributes( &_hContext,
  1800. SECPKG_ATTR_REMOTE_CERT_CONTEXT,
  1801. &_pClientCert );
  1802. if ( SUCCEEDED( secStatus ) )
  1803. {
  1804. DBG_ASSERT( _pClientCert != NULL );
  1805. }
  1806. else
  1807. {
  1808. goto ExitPoint;
  1809. }
  1810. //
  1811. // If we got a client cert and mapping is enabled, then
  1812. // request Schannel mapping
  1813. //
  1814. if( _ulCertInfo.Token != NULL )
  1815. {
  1816. CloseHandle( _ulCertInfo.Token );
  1817. _ulCertInfo.Token = NULL;
  1818. }
  1819. //
  1820. // Only DS mapper is executed in streamfilt
  1821. // IIS mapper is executed in w3core as part of IISCertmap Auth Provider
  1822. //
  1823. DBG_ASSERT( _pEndpointConfig != NULL );
  1824. //
  1825. // If DSMapper is enabled, we have to query the token and pass it
  1826. // to HTTP service regardless if mapping was requested by worker process
  1827. // for this specific request
  1828. // the reason is that http.sys will cache client certificate and token
  1829. // for the connection and next time new request in worker process coming through
  1830. // the same connection may require DS certificate mappings and if http.sys doesn't
  1831. // have token cached for the connection only client certificate,
  1832. // the worker process will not be able to retrieve it any more
  1833. //
  1834. if ( _pEndpointConfig->QueryUseDSMapper() )
  1835. {
  1836. secStatus = QuerySecurityContextToken( &_hContext,
  1837. &_ulCertInfo.Token );
  1838. if ( SUCCEEDED( secStatus ) )
  1839. {
  1840. DBG_ASSERT( _ulCertInfo.Token != NULL );
  1841. }
  1842. }
  1843. if ( FAILED ( secStatus ) )
  1844. {
  1845. //
  1846. // if token from mapping is not available
  1847. // it is OK, no mapping was found or
  1848. // denied access mapping was used
  1849. //
  1850. // BUGBUG - some errors should probably be logged
  1851. //
  1852. secStatus = SEC_E_OK;
  1853. }
  1854. ExitPoint:
  1855. return secStatus;
  1856. }
  1857. HRESULT
  1858. SSL_STREAM_CONTEXT::BuildClientCertInfo(
  1859. VOID
  1860. )
  1861. /*++
  1862. Routine Description:
  1863. Get client certificate info
  1864. Arguments:
  1865. None
  1866. Return Value:
  1867. HRESULT
  1868. --*/
  1869. {
  1870. HCERTCHAINENGINE hCertEngine = NULL;
  1871. HRESULT hr = S_OK;
  1872. CERT_CHAIN_PARA chainPara;
  1873. BOOL fRet;
  1874. PCCERT_CHAIN_CONTEXT pChainContext = NULL;
  1875. DWORD dwRevocationFlags = 0;
  1876. DWORD dwCacheFlags = 0;
  1877. HTTPSPolicyCallbackData HTTPSPolicy;
  1878. CERT_CHAIN_POLICY_PARA PolicyPara;
  1879. CERT_CHAIN_POLICY_STATUS PolicyStatus;
  1880. DBG_ASSERT( _pClientCert != NULL );
  1881. //
  1882. // Do the easy stuff!
  1883. //
  1884. _ulCertInfo.CertEncodedSize = _pClientCert->cbCertEncoded;
  1885. _ulCertInfo.pCertEncoded = _pClientCert->pbCertEncoded;
  1886. _ulCertInfo.CertFlags = 0;
  1887. //
  1888. // Now for the hard stuff. We need to validate the server does indeed
  1889. // accept the client certificate. Accept means we trusted the
  1890. // transitive trust chain to the CA, that the cert isn't revoked, etc.
  1891. //
  1892. // We use CAPI chaining functionality to check the certificate.
  1893. //
  1894. DBG_ASSERT( _pEndpointConfig != NULL );
  1895. //
  1896. // Default chain engine
  1897. //
  1898. hCertEngine = HCCE_LOCAL_MACHINE;
  1899. if ( !( _pEndpointConfig->QueryCertCheckMode() &
  1900. MD_CERT_NO_REVOC_CHECK ) )
  1901. {
  1902. dwRevocationFlags |= CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT;
  1903. }
  1904. if ( _pEndpointConfig->QueryCertCheckMode() &
  1905. MD_CERT_CACHE_RETRIEVAL_ONLY )
  1906. {
  1907. dwCacheFlags |= CERT_CHAIN_REVOCATION_CHECK_CACHE_ONLY;
  1908. }
  1909. if ( sm_fCertChainCacheOnlyUrlRetrieval )
  1910. {
  1911. dwCacheFlags |= CERT_CHAIN_CACHE_ONLY_URL_RETRIEVAL;
  1912. }
  1913. //
  1914. // Let'r rip
  1915. //
  1916. ZeroMemory( &chainPara, sizeof( chainPara ) );
  1917. chainPara.cbSize = sizeof( chainPara );
  1918. chainPara.dwUrlRetrievalTimeout =
  1919. _pEndpointConfig->QueryRevocationUrlRetrievalTimeout();
  1920. chainPara.dwRevocationFreshnessTime =
  1921. _pEndpointConfig->QueryRevocationFreshnessTime();
  1922. chainPara.fCheckRevocationFreshnessTime =
  1923. !!( _pEndpointConfig->QueryCertCheckMode() &
  1924. MD_CERT_CHECK_REVOCATION_FRESHNESS_TIME );
  1925. LPSTR UsageIdentifiers[1] = { szOID_PKIX_KP_CLIENT_AUTH };
  1926. if ( !(_pEndpointConfig->QueryCertCheckMode() &
  1927. MD_CERT_NO_USAGE_CHECK ) )
  1928. {
  1929. chainPara.RequestedUsage.dwType = USAGE_MATCH_TYPE_AND;
  1930. chainPara.RequestedUsage.Usage.cUsageIdentifier = 1;
  1931. chainPara.RequestedUsage.Usage.rgpszUsageIdentifier =
  1932. UsageIdentifiers;
  1933. }
  1934. //
  1935. // CertGetCertificateChain may eventually block
  1936. // such as in the case of the CRL retrieval.
  1937. // We got to bump up the soft thread limit
  1938. //
  1939. QueryFiltChannelContext()->AddWorkerThread();
  1940. fRet = CertGetCertificateChain( hCertEngine,
  1941. _pClientCert,
  1942. NULL,
  1943. NULL,
  1944. &chainPara,
  1945. dwRevocationFlags | dwCacheFlags,
  1946. NULL,
  1947. &pChainContext );
  1948. QueryFiltChannelContext()->RemoveWorkerThread();
  1949. if ( !fRet )
  1950. {
  1951. //
  1952. // Bad. Couldn't get the chain at all.
  1953. //
  1954. hr = HRESULT_FROM_WIN32( GetLastError() );
  1955. goto ExitPoint;
  1956. }
  1957. //
  1958. // Validate certificate chain using CertVerifyCertificateChainPolicy.
  1959. //
  1960. ZeroMemory( &HTTPSPolicy, sizeof(HTTPSPolicy));
  1961. HTTPSPolicy.cbStruct = sizeof(HTTPSPolicyCallbackData);
  1962. HTTPSPolicy.dwAuthType = AUTHTYPE_CLIENT;
  1963. HTTPSPolicy.fdwChecks = 0;
  1964. HTTPSPolicy.pwszServerName = NULL;
  1965. ZeroMemory( &PolicyPara, sizeof( PolicyPara ) );
  1966. PolicyPara.cbSize = sizeof( PolicyPara );
  1967. PolicyPara.pvExtraPolicyPara = &HTTPSPolicy;
  1968. ZeroMemory( &PolicyStatus, sizeof( PolicyStatus) );
  1969. PolicyStatus.cbSize = sizeof( PolicyStatus );
  1970. if ( !CertVerifyCertificateChainPolicy( CERT_CHAIN_POLICY_SSL,
  1971. pChainContext,
  1972. &PolicyPara,
  1973. &PolicyStatus ) )
  1974. {
  1975. hr = HRESULT_FROM_WIN32( GetLastError() );
  1976. DBGPRINTF((DBG_CONTEXT,
  1977. "CertVerifyCertificateChainPolicy failed. hr = 0x%x\n",
  1978. hr ));
  1979. goto ExitPoint;
  1980. }
  1981. if ( PolicyStatus.dwError == CRYPT_E_NO_REVOCATION_CHECK )
  1982. {
  1983. {
  1984. //
  1985. // If a cert in the chain has no CDP we will NOT take it as error
  1986. // reset the dwError
  1987. // Note: This is based on the advice from Crypto team
  1988. //
  1989. PolicyStatus.dwError = ERROR_SUCCESS;
  1990. }
  1991. }
  1992. if ( PolicyStatus.dwError != ERROR_SUCCESS )
  1993. {
  1994. //
  1995. // Client certificate
  1996. //
  1997. _ulCertInfo.CertFlags = PolicyStatus.dwError;
  1998. }
  1999. else
  2000. {
  2001. //
  2002. // Now verify CTL - IIS uses unsigned CTLs
  2003. // and since CAPI doesn't support unsigned CTL verification
  2004. // it is necessary to verify manually
  2005. //
  2006. if ( _pEndpointConfig->IsCtlRequired() )
  2007. {
  2008. PCERT_SIMPLE_CHAIN pSimpleChain = pChainContext->rgpChain[pChainContext->cChain - 1];
  2009. PCERT_CHAIN_ELEMENT pChainElement =
  2010. pSimpleChain->rgpElement[pSimpleChain->cElement - 1];
  2011. PCCERT_CONTEXT pChainTop = pChainElement->pCertContext;
  2012. DBG_ASSERT( pChainTop != NULL );
  2013. IIS_CTL * pIisCtl = _pEndpointConfig->QueryIisCtl();
  2014. BOOL fCtlContainsCert = FALSE;
  2015. if ( pIisCtl != NULL )
  2016. {
  2017. hr = pIisCtl->VerifyContainsCert( pChainTop, &fCtlContainsCert );
  2018. if ( FAILED( hr ) || !fCtlContainsCert )
  2019. {
  2020. _ulCertInfo.CertFlags = (ULONG) CERT_E_UNTRUSTEDROOT;
  2021. }
  2022. }
  2023. else
  2024. {
  2025. //
  2026. // CTL not available but site requires it.
  2027. // Request must fail
  2028. //
  2029. _ulCertInfo.CertFlags = (ULONG) CERT_E_UNTRUSTEDROOT;
  2030. }
  2031. }
  2032. }
  2033. IF_DEBUG( CLIENT_CERT_INFO )
  2034. {
  2035. //
  2036. // Dump out some debug info about the certificate
  2037. //
  2038. DumpCertDebugInfo( PolicyStatus.dwError );
  2039. }
  2040. //
  2041. // the mapped user token was already assigned (in RetrieveClientCertAndToken)
  2042. //
  2043. hr = S_OK;
  2044. ExitPoint:
  2045. if ( pChainContext != NULL )
  2046. {
  2047. CertFreeCertificateChain( pChainContext );
  2048. }
  2049. return hr;
  2050. }
  2051. VOID
  2052. SSL_STREAM_CONTEXT::DumpCertDebugInfo(
  2053. DWORD dwPolicyStatus
  2054. )
  2055. /*++
  2056. Routine Description:
  2057. On checked builds, dumps certificate (and chain) information to
  2058. debugger
  2059. Arguments:
  2060. dwPolicyStatus - policy status (result of CertVerifyCertificateChainPolicy)
  2061. Return Value:
  2062. None
  2063. --*/
  2064. {
  2065. PCERT_PUBLIC_KEY_INFO pPublicKey;
  2066. DWORD cbKeyLength;
  2067. WCHAR achBuffer[ 512 ];
  2068. //
  2069. // Get certificate public key size
  2070. //
  2071. pPublicKey = &(_pClientCert->pCertInfo->SubjectPublicKeyInfo);
  2072. cbKeyLength = CertGetPublicKeyLength( X509_ASN_ENCODING,
  2073. pPublicKey );
  2074. DBGPRINTF(( DBG_CONTEXT,
  2075. "Client cert key length = %d bits\n",
  2076. cbKeyLength ));
  2077. //
  2078. // Get issuer string
  2079. //
  2080. if ( CertGetNameString( _pClientCert,
  2081. CERT_NAME_SIMPLE_DISPLAY_TYPE,
  2082. CERT_NAME_ISSUER_FLAG,
  2083. NULL,
  2084. achBuffer,
  2085. sizeof( achBuffer ) / sizeof( WCHAR ) ) )
  2086. {
  2087. DBGPRINTF(( DBG_CONTEXT,
  2088. "Client cert issuer = %ws\n",
  2089. achBuffer ));
  2090. }
  2091. else
  2092. {
  2093. DBGPRINTF(( DBG_CONTEXT,
  2094. "Error determining client cert issuer. Win32 = %d\n",
  2095. GetLastError() ));
  2096. }
  2097. //
  2098. // Get subject string
  2099. //
  2100. if ( CertGetNameString( _pClientCert,
  2101. CERT_NAME_SIMPLE_DISPLAY_TYPE,
  2102. 0,
  2103. NULL,
  2104. achBuffer,
  2105. sizeof( achBuffer ) / sizeof( WCHAR ) ) )
  2106. {
  2107. DBGPRINTF(( DBG_CONTEXT,
  2108. "Client cert subject = %ws\n",
  2109. achBuffer ));
  2110. }
  2111. else
  2112. {
  2113. DBGPRINTF(( DBG_CONTEXT,
  2114. "Error determining client cert subject. Win32 = %d\n",
  2115. GetLastError() ));
  2116. }
  2117. //
  2118. // Dump Policy Status
  2119. //
  2120. LPSTR pszName = NULL;
  2121. switch( dwPolicyStatus )
  2122. {
  2123. case CERT_E_EXPIRED:
  2124. pszName = "CERT_E_EXPIRED"; break;
  2125. case CERT_E_VALIDITYPERIODNESTING:
  2126. pszName = "CERT_E_VALIDITYPERIODNESTING"; break;
  2127. case CERT_E_ROLE:
  2128. pszName = "CERT_E_ROLE"; break;
  2129. case CERT_E_PATHLENCONST:
  2130. pszName = "CERT_E_PATHLENCONST"; break;
  2131. case CERT_E_CRITICAL:
  2132. pszName = "CERT_E_CRITICAL"; break;
  2133. case CERT_E_PURPOSE:
  2134. pszName = "CERT_E_PURPOSE"; break;
  2135. case CERT_E_ISSUERCHAINING:
  2136. pszName = "CERT_E_ISSUERCHAINING"; break;
  2137. case CERT_E_MALFORMED:
  2138. pszName = "CERT_E_MALFORMED"; break;
  2139. case CERT_E_UNTRUSTEDROOT:
  2140. pszName = "CERT_E_UNTRUSTEDROOT"; break;
  2141. case CERT_E_CHAINING:
  2142. pszName = "CERT_E_CHAINING"; break;
  2143. case TRUST_E_FAIL:
  2144. pszName = "TRUST_E_FAIL"; break;
  2145. case CERT_E_REVOKED:
  2146. pszName = "CERT_E_REVOKED"; break;
  2147. case CERT_E_UNTRUSTEDTESTROOT:
  2148. pszName = "CERT_E_UNTRUSTEDTESTROOT"; break;
  2149. case CERT_E_REVOCATION_FAILURE:
  2150. pszName = "CERT_E_REVOCATION_FAILURE"; break;
  2151. case CERT_E_CN_NO_MATCH:
  2152. pszName = "CERT_E_CN_NO_MATCH"; break;
  2153. case CERT_E_WRONG_USAGE:
  2154. pszName = "CERT_E_WRONG_USAGE"; break;
  2155. case CRYPT_E_NO_REVOCATION_CHECK:
  2156. pszName = "CRYPT_E_NO_REVOCATION_CHECK";break;
  2157. case CRYPT_E_REVOKED:
  2158. pszName = "CRYPT_E_REVOKED";break;
  2159. case CRYPT_E_REVOCATION_OFFLINE:
  2160. pszName = "CRYPT_E_REVOCATION_OFFLINE";break;
  2161. case ERROR_SUCCESS:
  2162. pszName = "SUCCESS";break;
  2163. default:
  2164. pszName = "(unknown)"; break;
  2165. }
  2166. DBGPRINTF((DBG_CONTEXT,
  2167. "Client cert verification result = 0x%x (%s)\n",
  2168. dwPolicyStatus, pszName));
  2169. }
  2170. CredHandle *
  2171. SSL_STREAM_CONTEXT::QueryCredentials(
  2172. VOID
  2173. )
  2174. /*++
  2175. Routine Description:
  2176. Get the applicable credentials (depending on whether we're mapping or not)
  2177. Arguments:
  2178. None
  2179. Return Value:
  2180. CredHandle *
  2181. --*/
  2182. {
  2183. DBG_ASSERT( _pEndpointConfig != NULL );
  2184. return _pEndpointConfig->QueryCredentials();
  2185. }