msquic
msquic copied to clipboard
Support Dynamic Client Certificate
Describe the feature you'd like supported
Dynamic cert: The caller provides a callback that is invoked when the server asks for a certificate. The input is the issuers list (is there any other data available?) and the result is an optional certificate. (Compare to SslStream's callback).
Describe the feature you'd like supported
Dynamic cert: The caller provides a callback that is invoked when the server asks for a certificate. The input is the issuers list (is there any other data available?) and the result is an optional certificate. (Compare to SslStream's callback).
The callback will often involve user interaction. Also, the user will often only have oracle access to the key.
For the last comment, I think we should support QUIC_STATUS_PENDING to park the handshake and allow async lookup or UI thread to get what is needed.
@wfurt Often, the actual signing will itself need to be async, too. Consider a key on a smart card, which is very slow.
@wfurt could you please provide a bit more context and priority on this issue? I'm not sure about supporting this.
This could have multiple parts (or levels of completeness): For SslStream and HTTP/1.1, HTTP/2 we let user to provide certificate via callback instead of specifying it upfront. So if Server asks for it and no certificate was provided so far, I think MsQuic should raise event and wait for certificate. That can be either valid handle or it can be null of client does not have (or wishes to send) certificate. This should be symmetric with server side e.g. we should be able to give you some answer or return QUIC_STATUS_PENDING and give the answer later. Ability to park would be nice but not necessary as LocalCertificateSelectionCallback is synchronous API.
Note that https://docs.microsoft.com/en-us/dotnet/api/system.net.security.localcertificateselectioncallback?view=net-6.0 also has acceptableIssuers. If the server provided list of CAs, we would populate the array with that list. This part is nice to have IMHO and was broken for while on all platforms but Windows.
This was marked as high priority because it is gap to previous HTTP versions. cc: @rzikm @manickap
Ability to park would be nice but not necessary as LocalCertificateSelectionCallback is synchronous API
Note that it is a user-provided callback, which we would need to call directly from the MsQuic connection event callback (same for RemoteCertificateValidationCallback for doing user-provided validation of the peer's certificate). While we generally try not to do too much work in the callback in order to not delay the MsQuic thread, we can't really guarantee how long those user-provided callbacks will take. Ability to "park the handshake", as wfurt puts it, would give us an option to do these callbacks on a different thread, if we find that executing them inline causes problems.
That problem also already exist for server side. There we offer true async option so this may be less intuitive to the user.
We (.NET runtime networking team) have changed the priority of the original issue, so this change is no longer needed for 7.0 and can wait for future version.
The suggested API would probably be another Connection event (say, CERT_NEEDED) which would expose the list of trusted issuers (if server sent any). It would also be good to have the event occur after the event with peer certificate. The app would then somehow provide the cert to be used).
There were some questions about how to implement this with Schannel. The way .NET supports this for SslStream is that when InitializeSecurityContext returns CredentialsNeeded, we drop the previous Credentials structure and create a new one with the right certificate and simply call InitializeSecurityContext again. The relevant parts of the source are at
https://github.com/rzikm/dotnet-runtime/blob/MsQuic-stream-refactorings/src/libraries/System.Net.Security/src/System/Net/Security/SslStream.Protocol.cs
NextMessagemethod checks forCredentialsNeededstatus and retries with different credentials if necessary.SslStreamPalused in the source above is just some wrapper around SSPI https://github.com/rzikm/dotnet-runtime/blob/MsQuic-stream-refactorings/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamPal.Windows.cs#L93