private int TlsClientCertCallback(IntPtr ssl, out IntPtr certHandle, out IntPtr privateKeyHandle) { EventSourceTrace("SSL: {0}", ssl); const int CertificateSet = 1, NoCertificateSet = 0, SuspendHandshake = -1; certHandle = IntPtr.Zero; privateKeyHandle = IntPtr.Zero; if (ssl == IntPtr.Zero) { Debug.Fail("Expected valid SSL pointer"); EventSourceTrace("Invalid SSL pointer in callback"); return(NoCertificateSet); } SafeSslHandle sslHandle = null; X509Chain chain = null; X509Certificate2 certificate = null; try { sslHandle = new SafeSslHandle(ssl, ownsHandle: false); ISet <string> issuerNames = GetRequestCertificateAuthorities(sslHandle); if (_clientCertificates != null) // manual mode { // If there's one certificate, just use it. Otherwise, try to find the best one. int certCount = _clientCertificates.Count; if (certCount == 1) { EventSourceTrace("Single certificate. Building chain."); certificate = _clientCertificates[0]; chain = TLSCertificateExtensions.BuildNewChain(certificate, includeClientApplicationPolicy: false); } else { EventSourceTrace("Finding the best of {0} certificates", certCount); if (!_clientCertificates.TryFindClientCertificate(issuerNames, out certificate, out chain)) { EventSourceTrace("No certificate set."); return(NoCertificateSet); } } EventSourceTrace("Chain built."); } else if (!GetAutomaticClientCertificate(issuerNames, out certificate, out chain)) // automatic mode { EventSourceTrace("No automatic certificate or chain."); return(NoCertificateSet); } SafeEvpPKeyHandle privateKeySafeHandle = null; Interop.Crypto.CheckValidOpenSslHandle(certificate.Handle); using (RSAOpenSsl rsa = certificate.GetRSAPrivateKey() as RSAOpenSsl) { if (rsa != null) { privateKeySafeHandle = rsa.DuplicateKeyHandle(); EventSourceTrace("RSA key"); } else { using (ECDsaOpenSsl ecdsa = certificate.GetECDsaPrivateKey() as ECDsaOpenSsl) { if (ecdsa != null) { privateKeySafeHandle = ecdsa.DuplicateKeyHandle(); EventSourceTrace("ECDsa key"); } } } } if (privateKeySafeHandle == null || privateKeySafeHandle.IsInvalid) { EventSourceTrace("Invalid private key"); return(NoCertificateSet); } SafeX509Handle certSafeHandle = Interop.Crypto.X509UpRef(certificate.Handle); Interop.Crypto.CheckValidOpenSslHandle(certSafeHandle); if (chain != null) { if (!Interop.Ssl.AddExtraChainCertificates(sslHandle, chain)) { EventSourceTrace("Failed to add extra chain certificate"); return(SuspendHandshake); } } certHandle = certSafeHandle.DangerousGetHandle(); privateKeyHandle = privateKeySafeHandle.DangerousGetHandle(); EventSourceTrace("Client certificate set: {0}", certificate); // Ownership has been transferred to OpenSSL; do not free these handles certSafeHandle.SetHandleAsInvalid(); privateKeySafeHandle.SetHandleAsInvalid(); return(CertificateSet); } finally { if (_clientCertificates == null) { certificate?.Dispose(); // only dispose cert if it's automatic / newly created } chain?.Dispose(); sslHandle?.Dispose(); } }
private int TlsClientCertCallback(IntPtr ssl, out IntPtr certHandle, out IntPtr privateKeyHandle) { const int CertificateSet = 1, NoCertificateSet = 0, SuspendHandshake = -1; certHandle = IntPtr.Zero; privateKeyHandle = IntPtr.Zero; if (ssl == IntPtr.Zero) { Debug.Fail("Expected valid SSL pointer"); EventSourceTrace("Invalid SSL pointer in callback"); return(NoCertificateSet); } SafeSslHandle sslHandle = null; X509Chain chain = null; X509Certificate2 certificate = null; try { sslHandle = new SafeSslHandle(ssl, ownsHandle: false); ISet <string> issuerNames = GetRequestCertificateAuthorities(sslHandle); if (_clientCertificates != null) // manual mode { // If there's one certificate, just use it. Otherwise, try to find the best one. if (_clientCertificates.Count == 1) { certificate = _clientCertificates[0]; chain = TLSCertificateExtensions.BuildNewChain(certificate, includeClientApplicationPolicy: false); } else if (!_clientCertificates.TryFindClientCertificate(issuerNames, out certificate, out chain)) { EventSourceTrace("No manual certificate or chain."); return(NoCertificateSet); } } else if (!GetAutomaticClientCertificate(issuerNames, out certificate, out chain)) // automatic mode { EventSourceTrace("No automatic certificate or chain."); return(NoCertificateSet); } Interop.Crypto.CheckValidOpenSslHandle(certificate.Handle); using (RSAOpenSsl rsa = certificate.GetRSAPrivateKey() as RSAOpenSsl) { if (rsa != null) { _privateKeyHandle = rsa.DuplicateKeyHandle(); EventSourceTrace("RSA key"); } else { using (ECDsaOpenSsl ecdsa = certificate.GetECDsaPrivateKey() as ECDsaOpenSsl) { if (ecdsa != null) { _privateKeyHandle = ecdsa.DuplicateKeyHandle(); EventSourceTrace("ECDsa key"); } } } } if (_privateKeyHandle == null || _privateKeyHandle.IsInvalid) { EventSourceTrace("Invalid private key"); return(NoCertificateSet); } _certHandle = Interop.Crypto.X509Duplicate(certificate.Handle); Interop.Crypto.CheckValidOpenSslHandle(_certHandle); if (chain != null) { for (int i = chain.ChainElements.Count - 2; i > 0; i--) { SafeX509Handle dupCertHandle = Interop.Crypto.X509Duplicate(chain.ChainElements[i].Certificate.Handle); Interop.Crypto.CheckValidOpenSslHandle(dupCertHandle); if (!Interop.Ssl.SslAddExtraChainCert(sslHandle, dupCertHandle)) { EventSourceTrace("Failed to add extra chain certificate"); return(SuspendHandshake); } } } certHandle = _certHandle.DangerousGetHandle(); privateKeyHandle = _privateKeyHandle.DangerousGetHandle(); EventSourceTrace("Client certificate set: {0}", certificate); return(CertificateSet); } finally { if (_clientCertificates == null) { certificate?.Dispose(); // only dispose cert if it's automatic / newly created } chain?.Dispose(); sslHandle?.Dispose(); } }