internal static unsafe partial void SslCtxSetCaching(SafeSslContextHandle ctx, int mode);
internal static unsafe partial void SslCtxSetVerify(SafeSslContextHandle ctx, delegate *unmanaged <int, IntPtr, int> callback);
internal static partial bool SetEncryptionPolicy(SafeSslContextHandle ctx, EncryptionPolicy policy);
internal static partial int SslCtxUseCertificate(SafeSslContextHandle ctx, SafeX509Handle certPtr);
internal static partial int SslCtxCheckPrivateKey(SafeSslContextHandle ctx);
internal static extern int SslCtxSetAlpnProtos(SafeSslContextHandle ctx, IntPtr protos, int len);
// This essentially wraps SSL_CTX* aka SSL_CTX_new + setting internal static SafeSslContextHandle AllocateSslContext(SafeFreeSslCredentials credential, SslAuthenticationOptions sslAuthenticationOptions, SslProtocols protocols, bool enableResume) { SafeX509Handle? certHandle = credential.CertHandle; SafeEvpPKeyHandle?certKeyHandle = credential.CertKeyHandle; // Always use SSLv23_method, regardless of protocols. It supports negotiating to the highest // mutually supported version and can thus handle any of the set protocols, and we then use // SetProtocolOptions to ensure we only allow the ones requested. SafeSslContextHandle sslCtx = Ssl.SslCtxCreate(Ssl.SslMethods.SSLv23_method); try { if (sslCtx.IsInvalid) { throw CreateSslException(SR.net_allocate_ssl_context_failed); } Ssl.SslCtxSetProtocolOptions(sslCtx, protocols); if (sslAuthenticationOptions.EncryptionPolicy != EncryptionPolicy.RequireEncryption) { // Sets policy and security level if (!Ssl.SetEncryptionPolicy(sslCtx, sslAuthenticationOptions.EncryptionPolicy)) { throw new SslException(SR.Format(SR.net_ssl_encryptionpolicy_notsupported, sslAuthenticationOptions.EncryptionPolicy)); } } byte[]? cipherList = CipherSuitesPolicyPal.GetOpenSslCipherList(sslAuthenticationOptions.CipherSuitesPolicy, protocols, sslAuthenticationOptions.EncryptionPolicy); Debug.Assert(cipherList == null || (cipherList.Length >= 1 && cipherList[cipherList.Length - 1] == 0)); byte[]? cipherSuites = CipherSuitesPolicyPal.GetOpenSslCipherSuites(sslAuthenticationOptions.CipherSuitesPolicy, protocols, sslAuthenticationOptions.EncryptionPolicy); Debug.Assert(cipherSuites == null || (cipherSuites.Length >= 1 && cipherSuites[cipherSuites.Length - 1] == 0)); unsafe { fixed(byte *cipherListStr = cipherList) fixed(byte *cipherSuitesStr = cipherSuites) { if (!Ssl.SslCtxSetCiphers(sslCtx, cipherListStr, cipherSuitesStr)) { Crypto.ErrClearError(); throw new PlatformNotSupportedException(SR.Format(SR.net_ssl_encryptionpolicy_notsupported, sslAuthenticationOptions.EncryptionPolicy)); } } } // 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(sslCtx); Ssl.SslCtxSetCaching(sslCtx, enableResume ? 1 : 0); if (sslAuthenticationOptions.IsServer && sslAuthenticationOptions.ApplicationProtocols != null && sslAuthenticationOptions.ApplicationProtocols.Count != 0) { unsafe { Interop.Ssl.SslCtxSetAlpnSelectCb(sslCtx, &AlpnServerSelectCallback, IntPtr.Zero); } } bool hasCertificateAndKey = certHandle != null && !certHandle.IsInvalid && certKeyHandle != null && !certKeyHandle.IsInvalid; if (hasCertificateAndKey) { SetSslCertificate(sslCtx, certHandle !, certKeyHandle !); } if (sslAuthenticationOptions.CertificateContext != null && sslAuthenticationOptions.CertificateContext.IntermediateCertificates.Length > 0) { if (!Ssl.AddExtraChainCertificates(sslCtx, sslAuthenticationOptions.CertificateContext.IntermediateCertificates)) { throw CreateSslException(SR.net_ssl_use_cert_failed); } } } catch { sslCtx.Dispose(); throw; } return(sslCtx); }
internal static SafeSslHandle AllocateSslContext(SslProtocols protocols, SafeX509Handle certHandle, SafeEvpPKeyHandle certKeyHandle, EncryptionPolicy policy, SslAuthenticationOptions sslAuthenticationOptions) { SafeSslHandle context = null; // Always use SSLv23_method, regardless of protocols. It supports negotiating to the highest // mutually supported version and can thus handle any of the set protocols, and we then use // SetProtocolOptions to ensure we only allow the ones requested. using (SafeSslContextHandle innerContext = Ssl.SslCtxCreate(Ssl.SslMethods.SSLv23_method)) { if (innerContext.IsInvalid) { throw CreateSslException(SR.net_allocate_ssl_context_failed); } // TLS 1.3 uses different ciphersuite restrictions than previous versions. // It has no equivalent to a NoEncryption option. if (policy == EncryptionPolicy.NoEncryption) { if (protocols == SslProtocols.None) { protocols = SslProtocols.Tls | SslProtocols.Tls11 | SslProtocols.Tls12; } else { protocols &= ~SslProtocols.Tls13; if (protocols == SslProtocols.None) { throw new SslException( SR.Format(SR.net_ssl_encryptionpolicy_notsupported, policy)); } } } // 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)) { Crypto.ErrClearError(); 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 (sslAuthenticationOptions.IsServer && sslAuthenticationOptions.RemoteCertRequired) { Ssl.SslCtxSetVerify(innerContext, s_verifyClientCertificate); } GCHandle alpnHandle = default; try { if (sslAuthenticationOptions.ApplicationProtocols != null) { if (sslAuthenticationOptions.IsServer) { alpnHandle = GCHandle.Alloc(sslAuthenticationOptions.ApplicationProtocols); Interop.Ssl.SslCtxSetAlpnSelectCb(innerContext, s_alpnServerCallback, GCHandle.ToIntPtr(alpnHandle)); } else { if (Interop.Ssl.SslCtxSetAlpnProtos(innerContext, sslAuthenticationOptions.ApplicationProtocols) != 0) { throw CreateSslException(SR.net_alpn_config_failed); } } } context = SafeSslHandle.Create(innerContext, sslAuthenticationOptions.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 (!sslAuthenticationOptions.IsServer) { // The IdnMapping converts unicode input into the IDNA punycode sequence. string punyCode = s_idnMapping.GetAscii(sslAuthenticationOptions.TargetHost); // Similar to windows behavior, set SNI on openssl by default for client context, ignore errors. if (!Ssl.SslSetTlsExtHostName(context, punyCode)) { Crypto.ErrClearError(); } } 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(); } } } context.AlpnHandle = alpnHandle; } catch { if (alpnHandle.IsAllocated) { alpnHandle.Free(); } throw; } } return(context); }
internal static extern void SetEncryptionPolicy(SafeSslContextHandle ctx, EncryptionPolicy policy);
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); }
internal static partial void SslCtxSetDefaultOcspCallback(SafeSslContextHandle ctx);
internal static partial SafeSslHandle SslCreate(SafeSslContextHandle ctx);
public static SafeSslHandle Create(SafeSslContextHandle context, bool isServer) { SafeBioHandle readBio = Crypto.CreateMemoryBio(); if (readBio.IsInvalid) { return(new SafeSslHandle()); } SafeBioHandle writeBio = Crypto.CreateMemoryBio(); if (writeBio.IsInvalid) { readBio.Dispose(); return(new SafeSslHandle()); } SafeSslHandle handle = SSL_new(context); if (handle.IsInvalid) { readBio.Dispose(); writeBio.Dispose(); return(handle); } handle._isServer = isServer; // After SSL_set_bio, the BIO handles are owned by SSL pointer // and are automatically freed by SSL_free. To prevent a double // free, we need to keep the ref counts bumped up till SSL_free bool gotRef = false; readBio.DangerousAddRef(ref gotRef); try { bool ignore = false; writeBio.DangerousAddRef(ref ignore); } catch { if (gotRef) { readBio.DangerousRelease(); } throw; } SSL_set_bio(handle, readBio, writeBio); handle._readBio = readBio; handle._writeBio = writeBio; if (isServer) { SSL_set_accept_state(handle); } else { SSL_set_connect_state(handle); } return(handle); }
internal static extern void SslCtxSetCertVerifyCallback(SafeSslContextHandle ctx, AppVerifyCallback cb, IntPtr arg);
internal static unsafe partial void SslCtxSetAlpnSelectCb(SafeSslContextHandle ctx, delegate *unmanaged <IntPtr, byte **, byte *, byte *, uint, IntPtr, int> callback, IntPtr arg);
internal static extern unsafe bool SetCiphers(SafeSslContextHandle ctx, byte *cipherList, byte *cipherSuites);
internal static unsafe partial int SslCtxSetCaching(SafeSslContextHandle ctx, int mode, delegate *unmanaged <IntPtr, IntPtr, int> neewSessionCallback, delegate *unmanaged <IntPtr, IntPtr, void> removeSessionCallback);
internal static partial void SslCtxSetProtocolOptions(SafeSslContextHandle ctx, SslProtocols protocols);
internal static extern unsafe void SslCtxSetAlpnSelectCb(SafeSslContextHandle ctx, SslCtxSetAlpnCallback callback, IntPtr arg);
internal static extern void SetProtocolOptions(SafeSslContextHandle ctx, SslProtocols protocols);
internal static partial bool SslCtxAddExtraChainCert(SafeSslContextHandle ctx, SafeX509Handle x509);
internal static extern void SslCtxSetVerify(SafeSslContextHandle ctx, SslCtxSetVerifyCallback callback);
internal static partial int SslCtxUsePrivateKey(SafeSslContextHandle ctx, SafeEvpPKeyHandle keyPtr);
internal static extern void SslCtxSetClientCAList(SafeSslContextHandle ctx, SafeX509NameStackHandle x509NameStackPtr);
internal static partial void SslCtxSetQuietShutdown(SafeSslContextHandle ctx);
internal static extern SafeSslHandle SslCreate(SafeSslContextHandle ctx);
internal static unsafe partial bool SslCtxSetCiphers(SafeSslContextHandle ctx, byte *cipherList, byte *cipherSuites);
internal static partial int SslCtxSetData(SafeSslContextHandle ctx, IntPtr data);
internal static SafeSslHandle AllocateSslContext(SslProtocols protocols, SafeX509Handle certHandle, SafeEvpPKeyHandle certKeyHandle, EncryptionPolicy policy, SslAuthenticationOptions sslAuthenticationOptions) { SafeSslHandle context = null; // Always use SSLv23_method, regardless of protocols. It supports negotiating to the highest // mutually supported version and can thus handle any of the set protocols, and we then use // SetProtocolOptions to ensure we only allow the ones requested. using (SafeSslContextHandle innerContext = Ssl.SslCtxCreate(Ssl.SslMethods.SSLv23_method)) { if (innerContext.IsInvalid) { throw CreateSslException(SR.net_allocate_ssl_context_failed); } if (!Interop.Ssl.Tls13Supported) { if (protocols != SslProtocols.None && CipherSuitesPolicyPal.WantsTls13(protocols)) { protocols = protocols & (~SslProtocols.Tls13); } } else if (CipherSuitesPolicyPal.WantsTls13(protocols) && CipherSuitesPolicyPal.ShouldOptOutOfTls13(sslAuthenticationOptions.CipherSuitesPolicy, policy)) { if (protocols == SslProtocols.None) { // we are using default settings but cipher suites policy says that TLS 1.3 // is not compatible with our settings (i.e. we requested no encryption or disabled // all TLS 1.3 cipher suites) protocols = SslProtocols.Tls | SslProtocols.Tls11 | SslProtocols.Tls12; } else { // user explicitly asks for TLS 1.3 but their policy is not compatible with TLS 1.3 throw new SslException( SR.Format(SR.net_ssl_encryptionpolicy_notsupported, policy)); } } if (CipherSuitesPolicyPal.ShouldOptOutOfLowerThanTls13(sslAuthenticationOptions.CipherSuitesPolicy, policy)) { if (!CipherSuitesPolicyPal.WantsTls13(protocols)) { // We cannot provide neither TLS 1.3 or non TLS 1.3, user disabled all cipher suites throw new SslException( SR.Format(SR.net_ssl_encryptionpolicy_notsupported, policy)); } protocols = SslProtocols.Tls13; } // 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); // Sets policy and security level if (!Ssl.SetEncryptionPolicy(innerContext, policy)) { throw new SslException( SR.Format(SR.net_ssl_encryptionpolicy_notsupported, policy)); } // 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); byte[] cipherList = CipherSuitesPolicyPal.GetOpenSslCipherList(sslAuthenticationOptions.CipherSuitesPolicy, protocols, policy); Debug.Assert(cipherList == null || (cipherList.Length >= 1 && cipherList[cipherList.Length - 1] == 0)); byte[] cipherSuites = CipherSuitesPolicyPal.GetOpenSslCipherSuites(sslAuthenticationOptions.CipherSuitesPolicy, protocols, policy); Debug.Assert(cipherSuites == null || (cipherSuites.Length >= 1 && cipherSuites[cipherSuites.Length - 1] == 0)); unsafe { fixed(byte *cipherListStr = cipherList) fixed(byte *cipherSuitesStr = cipherSuites) { if (!Ssl.SetCiphers(innerContext, cipherListStr, cipherSuitesStr)) { Crypto.ErrClearError(); 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 (sslAuthenticationOptions.IsServer && sslAuthenticationOptions.RemoteCertRequired) { Ssl.SslCtxSetVerify(innerContext, s_verifyClientCertificate); } GCHandle alpnHandle = default; try { if (sslAuthenticationOptions.ApplicationProtocols != null) { if (sslAuthenticationOptions.IsServer) { alpnHandle = GCHandle.Alloc(sslAuthenticationOptions.ApplicationProtocols); Interop.Ssl.SslCtxSetAlpnSelectCb(innerContext, s_alpnServerCallback, GCHandle.ToIntPtr(alpnHandle)); } else { if (Interop.Ssl.SslCtxSetAlpnProtos(innerContext, sslAuthenticationOptions.ApplicationProtocols) != 0) { throw CreateSslException(SR.net_alpn_config_failed); } } } context = SafeSslHandle.Create(innerContext, sslAuthenticationOptions.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 (!sslAuthenticationOptions.IsServer) { // The IdnMapping converts unicode input into the IDNA punycode sequence. string punyCode = s_idnMapping.GetAscii(sslAuthenticationOptions.TargetHost); // Similar to windows behavior, set SNI on openssl by default for client context, ignore errors. if (!Ssl.SslSetTlsExtHostName(context, punyCode)) { Crypto.ErrClearError(); } } if (hasCertificateAndKey) { bool hasCertReference = false; try { certHandle.DangerousAddRef(ref hasCertReference); using (X509Certificate2 cert = new X509Certificate2(certHandle.DangerousGetHandle())) { X509Chain chain = null; try { chain = TLSCertificateExtensions.BuildNewChain(cert, includeClientApplicationPolicy: false); if (chain != null && !Ssl.AddExtraChainCertificates(context, chain)) { throw CreateSslException(SR.net_ssl_use_cert_failed); } } finally { if (chain != null) { int elementsCount = chain.ChainElements.Count; for (int i = 0; i < elementsCount; i++) { chain.ChainElements[i].Certificate.Dispose(); } chain.Dispose(); } } } } finally { if (hasCertReference) { certHandle.DangerousRelease(); } } } context.AlpnHandle = alpnHandle; } catch { if (alpnHandle.IsAllocated) { alpnHandle.Free(); } throw; } } return(context); }
internal static SafeSslHandle AllocateSslContext(SslProtocols protocols, SafeX509Handle certHandle, SafeEvpPKeyHandle certKeyHandle, EncryptionPolicy policy, SslAuthenticationOptions sslAuthenticationOptions) { SafeSslHandle context = null; // Always use SSLv23_method, regardless of protocols. It supports negotiating to the highest // mutually supported version and can thus handle any of the set protocols, and we then use // SetProtocolOptions to ensure we only allow the ones requested. using (SafeSslContextHandle innerContext = Ssl.SslCtxCreate(Ssl.SslMethods.SSLv23_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 (sslAuthenticationOptions.IsServer && sslAuthenticationOptions.RemoteCertRequired) { Ssl.SslCtxSetVerify(innerContext, s_verifyClientCertificate); //update the client CA list UpdateCAListFromRootStore(innerContext); } if (sslAuthenticationOptions.ApplicationProtocols != null) { if (sslAuthenticationOptions.IsServer) { byte[] protos = Interop.Ssl.ConvertAlpnProtocolListToByteArray(sslAuthenticationOptions.ApplicationProtocols); sslAuthenticationOptions.AlpnProtocolsHandle = GCHandle.Alloc(protos); Interop.Ssl.SslCtxSetAlpnSelectCb(innerContext, s_alpnServerCallback, GCHandle.ToIntPtr(sslAuthenticationOptions.AlpnProtocolsHandle)); } else { if (Interop.Ssl.SslCtxSetAlpnProtos(innerContext, sslAuthenticationOptions.ApplicationProtocols) != 0) { throw CreateSslException(SR.net_alpn_config_failed); } } } context = SafeSslHandle.Create(innerContext, sslAuthenticationOptions.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); }