-
Notifications
You must be signed in to change notification settings - Fork 527
Client certificates are disposed before request can use them #830
Comments
If it would help, I could put together a PR. |
@shanewalters That would be great. I think rather than copying |
|
Using Handle is probably a bad idea. Do we know what the handle lifetime is? What happens if we dispose the cert? |
I don't see EDIT |
I verified that instantiating a new certificate based off the handle, and later disposing the original certificate (from |
I wouldn't bother Disposing/Resetting SslStream.RemoteCertificate. We dispose SslStream in Connection.OnSocketClosed, and we never new up RemoteCertificate ourselves. Considering we weren't resetting the property before, I don't see why we'd start now. |
I was going to put together a PR, but when I update
|
Functional impact
When using Kestrel with HTTPS and requiring client certificates, the client certificate added to context feature collection is disposed after the callback to
userCertificateValidationCallback()
has completed. In a subsequent controller action, a request toHttpContext.Connection.ClientCertificate
returns an instance of the disposed certificate.Minimal repro steps
Startup
class, inUseKestrel()
, calloptions.UseHttps()
withClientCertificateMode = ClientCertificateMode.RequireCertificate
, andClientCertificateValidation = (x, y, z) => x.Verify()
Test/Index()
, that derives fromMicrosoft.AspNetCore.Mvc.Controller
.HttpContext.Connection.ClientCertificate.Verify()
Expected result
The client certificate should not be disposed, and can be examined.
Actual result
An exception is thrown when trying to use the certificate:
System.Security.Cryptography.CryptographicException: m_safeCertContext is an invalid handle.
Further technical details
In the
userCertificateValidationCallback()
method, at the very end of the call, a reference is made to the valid certificate (clientCertificate = certificate2
); however, because the caller ofuserCertificateValidationCallback()
callscertificate.Reset()
after validation, the local variable (clientCertificate
) is now a reference to a disposed certificate. This disposed certificate is then added to the feature collection:features.Set<ITlsConnectionFeature>(new TlsConnectionFeature { ClientCertificate = clientCertificate });
Observations
I observed that simply cloning the certificate did not appear to resolve the issue (such as a call to
new X509Certificate2(clientCertificate)
from insideuserCertificateValidationCallback()
); however, if I stored theRawData
byte array (from insideuserCertificateValidationCallback()
), then callfeatures.Set<ITlsConnectionFeature>(new TlsConnectionFeature { ClientCertificate = new X509Certificate2(rawData) });
, the certificate was available, but I don't know if this is the correct solution or not.Related File
https://github.com/aspnet/KestrelHttpServer/blob/c828fafe1b39279d590ad1a18b62844bae76d77b/src/Microsoft.AspNetCore.Server.Kestrel.Https/HttpsConnectionFilter.cs
The text was updated successfully, but these errors were encountered: