schannel-rs icon indicating copy to clipboard operation
schannel-rs copied to clipboard

Needs to handle SEC_I_INCOMPLETE_CREDENTIALS from InitializeSecurityContext

Open sdroege opened this issue 7 years ago • 2 comments

https://github.com/steffengy/schannel-rs/blob/d475251df6b271156acb95d8bd94aae50d43efcb/src/tls_stream.rs#L394

The server might request credentials (i.e. a client-side certificate for authentication), but does not necessarily actually require it (SEC_E_INCOMPLETE_CREDENTIALS at a later time, note the I vs. E). When getting SEC_I_INCOMPLETE_CREDENTIALS, InitializeSecurityContext() just has to be called again like the first time (without any input) and will produce new output then.

Alternatively one can create a new credentials handle with any client certificates before doing the above.

sdroege avatar Jun 28 '17 15:06 sdroege

Since we pass ISC_REQ_USE_SUPPLIED_CREDS https://github.com/steffengy/schannel-rs/pull/24 InitializeSecurityContext() will never return the informational status code SEC_I_INCOMPLETE_CREDENTIALS.

The documentation is wrong on this one. It says:

When the server requests client authentication, the client must send the server one of its certificates. By default, Schannel will, with no notification to the client, attempt to locate a client certificate and send it to the server. To disable this feature, clients specify ISC_REQ_USE_SUPPLIED_CREDS when calling the InitializeSecurityContext (Schannel) function. When this flag is specified, Schannel will return SEC_I_INCOMPLETE_CREDENTIALS to the client when the server requests authentication and the client has not previously supplied a certificate.

After experimenting, I discovered the following for the case that no client cert was explicitly specified and the server sends a CertificateRequest:

  • If SCH_CRED_NO_DEFAULT_CREDS is set in AcquireCredentialsHandle(), then any available client certs from the store are ignored, they will not automatically be used. If the flag is not set, then an available client certificate will automatically be selected from the store when the server requests client auth.
  • If ISC_REQ_USE_SUPPLIED_CREDS is set in InitializeSecurityContext(), no informational status code will be returned. When a client cert is available (explicitly specified or automatically retrieved from the store) it will be sent, if not then no certificate will be sent (and the server can decide to terminate the connection). If the flag is not set, then upon a CertificateRequest by the server but no available client cert, InitializeSecurityContext() will return SEC_I_INCOMPLETE_CREDENTIALS, giving us the chance to maybe prompt the user for a certificate, set it in the credential and continue by calling ISC again.

heinzelotto avatar Mar 21 '20 13:03 heinzelotto

I think I will need this feature for implementing https://github.com/sfackler/rust-native-tls/issues/232. My thought for that is to provide the ability to specify a client certificate beforehand, as well as a callback for if you don't do that. The callback should take a list of valid CAs (retrieved through QueryContextAttributes) and return a certificate.

obsgolem avatar Aug 29 '22 18:08 obsgolem