Пример #1
0
            internal static void SetSslOptions(EasyRequest easy, ClientCertificateOption clientCertOption)
            {
                EventSourceTrace("ClientCertificateOption: {0}", clientCertOption, easy: easy);
                Debug.Assert(clientCertOption == ClientCertificateOption.Automatic || clientCertOption == ClientCertificateOption.Manual);

                // Create a client certificate provider if client certs may be used.
                X509Certificate2Collection clientCertificates = easy._handler._clientCertificates;
                ClientCertificateProvider  certProvider       =
                    clientCertOption == ClientCertificateOption.Automatic ? new ClientCertificateProvider(null) : // automatic
                    clientCertificates?.Count > 0 ? new ClientCertificateProvider(clientCertificates) :           // manual with certs
                    null;                                                                                         // manual without certs
                IntPtr userPointer = IntPtr.Zero;

                if (certProvider != null)
                {
                    EventSourceTrace("Created certificate provider", easy: easy);

                    // The client cert provider needs to be passed through to the callback, and thus
                    // we create a GCHandle to keep it rooted.  This handle needs to be cleaned up
                    // when the request has completed, and a simple and pay-for-play way to do that
                    // is by cleaning it up in a continuation off of the request.
                    userPointer = GCHandle.ToIntPtr(certProvider._gcHandle);
                    easy.Task.ContinueWith((_, state) => ((IDisposable)state).Dispose(), certProvider,
                                           CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default);
                }

                // Configure the options.  Our best support is when targeting OpenSSL/1.0.  For other backends,
                // we fall back to a minimal amount of support, and may throw a PNSE based on the options requested.
                if (CurlSslVersionDescription.IndexOf(Interop.Http.OpenSsl10Description, StringComparison.OrdinalIgnoreCase) != -1)
                {
                    // Register the callback with libcurl.  We need to register even if there's no user-provided
                    // server callback and even if there are no client certificates, because we support verifying
                    // server certificates against more than those known to OpenSSL.
                    SetSslOptionsForSupportedBackend(easy, certProvider, userPointer);
                }
                else
                {
                    // Newer versions of OpenSSL, and other non-OpenSSL backends, do not currently support callbacks.
                    // That means we'll throw a PNSE if a callback is required.
                    SetSslOptionsForUnsupportedBackend(easy, certProvider);
                }
            }
Пример #2
0
            internal static void SetSslOptions(EasyRequest easy, ClientCertificateOption clientCertOption)
            {
                Debug.Assert(
                    clientCertOption == ClientCertificateOption.Automatic ||
                    clientCertOption == ClientCertificateOption.Manual);

                // Create a client certificate provider if client certs may be used.
                X509Certificate2Collection clientCertificates = easy._handler._clientCertificates;

                if (clientCertOption != ClientCertificateOption.Manual || clientCertificates?.Count > 0)
                {
                    // libcurl does not have an option of accepting a SecIdentityRef via an input option,
                    // only via writing it to a file and letting it load the PFX.
                    // This would require that a) we write said file, and b) that it contaminate the default
                    // keychain (because their PFX loader loads to the default keychain).
                    throw new PlatformNotSupportedException(SR.net_http_libcurl_clientcerts_notsupported_os);
                }

                // Revocation checking is always on for darwinssl (SecureTransport).
                // If any other backend is used and revocation is requested, we can't guarantee
                // that assertion.
                if (easy._handler.CheckCertificateRevocationList &&
                    !CurlSslVersionDescription.Equals(Interop.Http.SecureTransportDescription))
                {
                    throw new PlatformNotSupportedException(
                              SR.Format(
                                  SR.net_http_libcurl_revocation_notsupported_sslbackend,
                                  CurlVersionDescription,
                                  CurlSslVersionDescription,
                                  Interop.Http.SecureTransportDescription));
                }

                if (easy._handler.ServerCertificateCustomValidationCallback != null)
                {
                    // libcurl (as of 7.49.1) does not have any callback which can be registered which fires
                    // between the time that a TLS/SSL handshake has offered up the server certificate and the
                    // time that the HTTP request headers are written.  Were there any callback, the option
                    // CURLINFO_TLS_SSL_PTR could be queried (and the backend identifier validated to be
                    // CURLSSLBACKEND_DARWINSSL). Then the SecTrustRef could be extracted to build the chain,
                    // a la SslStream.
                    //
                    // Without the callback the matrix looks like:
                    // * If default-trusted and callback-would-trust: No difference (except side effects, like logging).
                    // * If default-trusted and callback-would-block: Data would have been sent in violation of user trust.
                    // * If not-default-trusted and callback-would-not-trust: No difference (except side effects).
                    // * If not-default-trusted and callback-would-trust: No data sent, which doesn't match user desires.
                    //
                    // Of the two "different" cases, sending when we shouldn't is worse, so that's the direction we
                    // have to cater to. So we'll use default trust, and throw on any custom callback.
                    //
                    // The situation where system trust fails can be remedied by including the certificate into the
                    // user's keychain and setting the SSL policy trust for it to "Always Trust".
                    // Similarly, the "block this" could be attained by setting the SSL policy for a cert in the
                    // keychain to "Never Trust".
                    //
                    // However, one case we can support is when we know all certificates will pass validation.
                    // We can detect a key case of that: whether DangerousAcceptAnyServerCertificateValidator was used.
                    if (easy.ServerCertificateValidationCallbackAcceptsAll)
                    {
                        EventSourceTrace("Warning: Disabling peer verification per {0}", nameof(HttpClientHandler.DangerousAcceptAnyServerCertificateValidator), easy: easy);
                        easy.SetCurlOption(Interop.Http.CURLoption.CURLOPT_SSL_VERIFYPEER, 0); // don't verify the peer

                        // Don't set CURLOPT_SSL_VERIFHOST to 0; doing so disables SNI with SecureTransport backend.
                        if (!CurlSslVersionDescription.Equals(Interop.Http.SecureTransportDescription))
                        {
                            easy.SetCurlOption(Interop.Http.CURLoption.CURLOPT_SSL_VERIFYHOST, 0); // don't verify the hostname
                        }
                    }
                    else
                    {
                        throw new PlatformNotSupportedException(SR.net_http_libcurl_callback_notsupported_os);
                    }
                }

                SetSslVersion(easy);
            }
Пример #3
0
            internal static void SetSslOptions(EasyRequest easy, ClientCertificateOption clientCertOption)
            {
                Debug.Assert(clientCertOption == ClientCertificateOption.Automatic || clientCertOption == ClientCertificateOption.Manual);

                // Create a client certificate provider if client certs may be used.
                X509Certificate2Collection clientCertificates = easy._handler._clientCertificates;
                ClientCertificateProvider  certProvider       =
                    clientCertOption == ClientCertificateOption.Automatic ? new ClientCertificateProvider(null) : // automatic
                    clientCertificates?.Count > 0 ? new ClientCertificateProvider(clientCertificates) :           // manual with certs
                    null;                                                                                         // manual without certs
                IntPtr userPointer = IntPtr.Zero;

                if (certProvider != null)
                {
                    // The client cert provider needs to be passed through to the callback, and thus
                    // we create a GCHandle to keep it rooted.  This handle needs to be cleaned up
                    // when the request has completed, and a simple and pay-for-play way to do that
                    // is by cleaning it up in a continuation off of the request.
                    userPointer = GCHandle.ToIntPtr(certProvider._gcHandle);
                    easy.Task.ContinueWith((_, state) => ((IDisposable)state).Dispose(), certProvider,
                                           CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default);
                }

                // Register the callback with libcurl.  We need to register even if there's no user-provided
                // server callback and even if there are no client certificates, because we support verifying
                // server certificates against more than those known to OpenSSL.
                if (CurlSslVersionDescription.IndexOf("openssl/1.0", StringComparison.OrdinalIgnoreCase) != -1)
                {
                    CURLcode answer = easy.SetSslCtxCallback(s_sslCtxCallback, userPointer);
                    switch (answer)
                    {
                    case CURLcode.CURLE_OK:
                        // We successfully registered.  If we'll be invoking a user-provided callback to verify the server
                        // certificate as part of that, disable libcurl's verification of the host name.  The user's callback
                        // needs to be given the opportunity to examine the cert, and our logic will determine whether
                        // the host name matches and will inform the callback of that.
                        if (easy._handler.ServerCertificateValidationCallback != null)
                        {
                            easy.SetCurlOption(Interop.Http.CURLoption.CURLOPT_SSL_VERIFYHOST, 0);     // don't verify the peer cert's hostname
                            // We don't change the SSL_VERIFYPEER setting, as setting it to 0 will cause
                            // SSL and libcurl to ignore the result of the server callback.
                        }

                        // The allowed SSL protocols will be set in the configuration callback.
                        break;

                    case CURLcode.CURLE_UNKNOWN_OPTION:     // Curl 7.38 and prior
                    case CURLcode.CURLE_NOT_BUILT_IN:       // Curl 7.39 and later
                        // It's ok if we failed to register the callback if all of the defaults are in play
                        // with relation to handling of certificates.  But if that's not the case, failing to
                        // register the callback will result in those options not being factored in, which is
                        // a significant enough error that we need to fail.
                        EventSourceTrace("CURLOPT_SSL_CTX_FUNCTION not supported: {0}", answer, easy: easy);
                        if (certProvider != null ||
                            easy._handler.ServerCertificateValidationCallback != null ||
                            easy._handler.CheckCertificateRevocationList)
                        {
                            throw new PlatformNotSupportedException(
                                      SR.Format(SR.net_http_unix_invalid_certcallback_option, CurlVersionDescription, CurlSslVersionDescription));
                        }

                        // Since there won't be a callback to configure the allowed SSL protocols, configure them here.
                        SetSslVersion(easy);

                        break;

                    default:
                        ThrowIfCURLEError(answer);
                        break;
                    }
                }
                else
                {
                    // For newer versions of openssl throw PNSE, if default not used.
                    if (certProvider != null)
                    {
                        throw new PlatformNotSupportedException(
                                  SR.Format(
                                      SR.net_http_libcurl_clientcerts_notsupported,
                                      CurlVersionDescription, CurlSslVersionDescription));
                    }

                    if (easy._handler.ServerCertificateValidationCallback != null)
                    {
                        throw new PlatformNotSupportedException(
                                  SR.Format(
                                      SR.net_http_libcurl_callback_notsupported,
                                      CurlVersionDescription, CurlSslVersionDescription));
                    }

                    if (easy._handler.CheckCertificateRevocationList)
                    {
                        throw new PlatformNotSupportedException(
                                  SR.Format(
                                      SR.net_http_libcurl_revocation_notsupported,
                                      CurlVersionDescription, CurlSslVersionDescription));
                    }

                    // In case of defaults configure the allowed SSL protocols.
                    SetSslVersion(easy);
                }
            }