public SafeFreeCertContext(SafeX509Handle certificate) : base(IntPtr.Zero, true) { // In certain scenarios (eg. server querying for a client cert), the // input certificate may be invalid and this is OK if ((null != certificate) && !certificate.IsInvalid) { bool gotRef = false; certificate.DangerousAddRef(ref gotRef); Debug.Assert(gotRef, "Unexpected failure in AddRef of certificate"); _certificate = certificate; handle = _certificate.DangerousGetHandle(); } }
internal static SafeSslHandle AllocateSslContext(SslProtocols protocols, SafeX509Handle certHandle, SafeEvpPKeyHandle certKeyHandle, EncryptionPolicy policy, bool isServer, bool remoteCertRequired) { SafeSslHandle context = null; IntPtr method = GetSslMethod(protocols); using (SafeSslContextHandle innerContext = Ssl.SslCtxCreate(method)) { if (innerContext.IsInvalid) { throw CreateSslException(SR.net_allocate_ssl_context_failed); } // Configure allowed protocols. It's ok to use DangerousGetHandle here without AddRef/Release as we just // create the handle, it's rooted by the using, no one else has a reference to it, etc. Ssl.SetProtocolOptions(innerContext.DangerousGetHandle(), protocols); // The logic in SafeSslHandle.Disconnect is simple because we are doing a quiet // shutdown (we aren't negotiating for session close to enable later session // restoration). // // If you find yourself wanting to remove this line to enable bidirectional // close-notify, you'll probably need to rewrite SafeSslHandle.Disconnect(). // https://www.openssl.org/docs/manmaster/ssl/SSL_shutdown.html Ssl.SslCtxSetQuietShutdown(innerContext); if (!Ssl.SetEncryptionPolicy(innerContext, policy)) { throw new PlatformNotSupportedException(SR.Format(SR.net_ssl_encryptionpolicy_notsupported, policy)); } bool hasCertificateAndKey = certHandle != null && !certHandle.IsInvalid && certKeyHandle != null && !certKeyHandle.IsInvalid; if (hasCertificateAndKey) { SetSslCertificate(innerContext, certHandle, certKeyHandle); } if (remoteCertRequired) { Debug.Assert(isServer, "isServer flag should be true"); Ssl.SslCtxSetVerify(innerContext, s_verifyClientCertificate); //update the client CA list UpdateCAListFromRootStore(innerContext); } context = SafeSslHandle.Create(innerContext, isServer); Debug.Assert(context != null, "Expected non-null return value from SafeSslHandle.Create"); if (context.IsInvalid) { context.Dispose(); throw CreateSslException(SR.net_allocate_ssl_context_failed); } if (hasCertificateAndKey) { bool hasCertReference = false; try { certHandle.DangerousAddRef(ref hasCertReference); using (X509Certificate2 cert = new X509Certificate2(certHandle.DangerousGetHandle())) { using (X509Chain chain = TLSCertificateExtensions.BuildNewChain(cert, includeClientApplicationPolicy: false)) { if (chain != null && !Ssl.AddExtraChainCertificates(context, chain)) throw CreateSslException(SR.net_ssl_use_cert_failed); } } } finally { if (hasCertReference) certHandle.DangerousRelease(); } } } return context; }
private int TlsClientCertCallback(IntPtr ssl, out IntPtr certHandle, out IntPtr privateKeyHandle) { Interop.Crypto.CheckValidOpenSslHandle(ssl); using (SafeSslHandle sslHandle = new SafeSslHandle(ssl, false)) { certHandle = IntPtr.Zero; privateKeyHandle = IntPtr.Zero; VerboseTrace("libssl's client certificate callback"); ISet<string> issuerNames = GetRequestCertificateAuthorities(sslHandle); X509Certificate2 certificate; X509Chain chain; if (!GetClientCertificate(issuerNames, out certificate, out chain)) { VerboseTrace("no cert or chain"); return 0; } Interop.Crypto.CheckValidOpenSslHandle(certificate.Handle); using (RSAOpenSsl rsa = certificate.GetRSAPrivateKey() as RSAOpenSsl) { if (rsa != null) { _privateKeyHandle = rsa.DuplicateKeyHandle(); } else { using (ECDsaOpenSsl ecdsa = certificate.GetECDsaPrivateKey() as ECDsaOpenSsl) { if (ecdsa != null) { _privateKeyHandle = ecdsa.DuplicateKeyHandle(); } } } } if (_privateKeyHandle == null || _privateKeyHandle.IsInvalid) { VerboseTrace("invalid private key"); return 0; } _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)) { VerboseTrace("failed to add extra chain cert"); return -1; } } } certHandle = _certHandle.DangerousGetHandle(); privateKeyHandle = _privateKeyHandle.DangerousGetHandle(); return 1; } }
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(); } }