diff --git a/docs/curl.1 b/docs/curl.1 index cfa17aed3..04346867e 100644 --- a/docs/curl.1 +++ b/docs/curl.1 @@ -1468,6 +1468,33 @@ the default authentication method curl uses with proxies. .IP "--proxy-digest" Tells curl to use HTTP Digest authentication when communicating with the given proxy. Use \fI--digest\fP for enabling HTTP Digest with a remote host. +.IP "--proxy-cacert " +(SSL) Same as --cacert but used in HTTPS proxy context. +(Added in 7.XXX) +.IP "--proxy-capath " +(SSL) Same as --capath but used in HTTPS proxy context. +(Added in 7.XXX) +.IP "--proxy-cert " +(SSL) Same as \fI--cert\fP but used in HTTPS proxy context. +(Added in 7.XXX) +.IP "--proxy-cert-type " +(SSL) Same as \fI--cert-type\fP but used in HTTPS proxy context. +(Added in 7.XXX) +.IP "--proxy-ciphers " +(SSL) Same as \fI--ciphers\fP but used in HTTPS proxy context. +(Added in 7.XXX) +.IP "--proxy-crlfile " +(HTTPS) Same as \fI--crlfile\fP but used in HTTPS proxy context. +(Added in 7.XXX) +.IP "--proxy-insecure" +(SSL) Same as \fI--insecure\fP but used in HTTPS proxy context. +(Added in 7.XXX) +.IP "--proxy-key " +(SSL) Same as \fI--key\fP but used in HTTPS proxy context. +(Added in 7.XXX) +.IP "--proxy-key-type " +(SSL) Same as \fI--key-type\fP but used in HTTPS proxy context. +(Added in 7.XXX) .IP "--proxy-negotiate" Tells curl to use HTTP Negotiate (SPNEGO) authentication when communicating with the given proxy. Use \fI--negotiate\fP for enabling HTTP Negotiate (SPNEGO) @@ -1475,11 +1502,35 @@ with a remote host. (Added in 7.17.1) .IP "--proxy-ntlm" Tells curl to use HTTP NTLM authentication when communicating with the given proxy. Use \fI--ntlm\fP for enabling NTLM with a remote host. +.IP "--proxy-pass " +(SSL) Same as \fI--pass\fP but used in HTTPS proxy context. +(Added in 7.XXX) .IP "--proxy-service-name " This option allows you to change the service name for proxy negotiation. Examples: --proxy-negotiate proxy-name \fI--proxy-service-name\fP sockd would use sockd/proxy-name. (Added in 7.43.0). +.IP "--proxy-ssl-allow-beast" +(SSL) Same as \fI--ssl-allow-beast\fP but used in HTTPS proxy context. +(Added in 7.XXX) +.IP "--proxy-sslv2" +(SSL) Same as \fI--sslv2\fP but used in HTTPS proxy context. +(Added in 7.XXX) +.IP "--proxy-sslv3" +(SSL) Same as \fI--sslv3\fP but used in HTTPS proxy context. +(Added in 7.XXX) +.IP "--proxy-tlsauthtype " +Same as \fI--tlsauthtype\fP but used in HTTPS proxy context. +(Added in 7.XXX) +.IP "--proxy-tlspassword " +Same as \fI--tlspassword\fP but used in HTTPS proxy context. +(Added in 7.XXX) +.IP "--proxy-tlsuser " +Same as \fI--tlsuser\fP but used in HTTPS proxy context. +(Added in 7.XXX) +.IP "--proxy-tlsv1" +(SSL) Same as \fI--tlsv1\fP but used in HTTPS proxy context. +(Added in 7.XXX) .IP "--proxy1.0 " Use the specified HTTP 1.0 proxy. If the port number is not specified, it is assumed at port 1080. diff --git a/docs/libcurl/curl_easy_getinfo.3 b/docs/libcurl/curl_easy_getinfo.3 index 9ffcd14af..4f36561ac 100644 --- a/docs/libcurl/curl_easy_getinfo.3 +++ b/docs/libcurl/curl_easy_getinfo.3 @@ -104,6 +104,9 @@ See \fICURLINFO_REQUEST_SIZE(3)\fP .IP CURLINFO_SSL_VERIFYRESULT Certificate verification result. See \fICURLINFO_SSL_VERIFYRESULT(3)\fP +.IP CURLINFO_PROXY_SSL_VERIFYRESULT +Proxy certificate verification result. +See \fICURLINFO_PROXY_SSL_VERIFYRESULT(3)\fP .IP CURLINFO_SSL_ENGINES A list of OpenSSL crypto engines. See \fICURLINFO_SSL_ENGINES(3)\fP diff --git a/docs/libcurl/curl_easy_setopt.3 b/docs/libcurl/curl_easy_setopt.3 index b32e1c03b..590a47f8c 100644 --- a/docs/libcurl/curl_easy_setopt.3 +++ b/docs/libcurl/curl_easy_setopt.3 @@ -159,10 +159,14 @@ Protocols to allow redirects to. See \fICURLOPT_REDIR_PROTOCOLS(3)\fP Default protocol. See \fICURLOPT_DEFAULT_PROTOCOL(3)\fP .IP CURLOPT_PROXY Proxy to use. See \fICURLOPT_PROXY(3)\fP +.IP CURLOPT_SOCKS_PROXY +Socks proxy to use. See \fICURLOPT_SOCKS_PROXY(3)\fP .IP CURLOPT_PROXYPORT Proxy port to use. See \fICURLOPT_PROXYPORT(3)\fP .IP CURLOPT_PROXYTYPE Proxy type. See \fICURLOPT_PROXYTYPE(3)\fP +.IP CURLOPT_SOCKS_PROXYTYPE +Socks proxy type. See \fICURLOPT_SOCKS_PROXYTYPE(3)\fP .IP CURLOPT_NOPROXY Filter out hosts from proxy use. \fICURLOPT_NOPROXY(3)\fP .IP CURLOPT_HTTPPROXYTUNNEL @@ -228,10 +232,16 @@ Proxy password. See \fICURLOPT_PROXYPASSWORD(3)\fP HTTP server authentication methods. See \fICURLOPT_HTTPAUTH(3)\fP .IP CURLOPT_TLSAUTH_USERNAME TLS authentication user name. See \fICURLOPT_TLSAUTH_USERNAME(3)\fP +.IP CURLOPT_PROXY_TLSAUTH_USERNAME +Proxy TLS authentication user name. See \fICURLOPT_PROXY_TLSAUTH_USERNAME(3)\fP .IP CURLOPT_TLSAUTH_PASSWORD TLS authentication password. See \fICURLOPT_TLSAUTH_PASSWORD(3)\fP +.IP CURLOPT_PROXY_TLSAUTH_PASSWORD +Proxy TLS authentication password. See \fICURLOPT_PROXY_TLSAUTH_PASSWORD(3)\fP .IP CURLOPT_TLSAUTH_TYPE TLS authentication methods. See \fICURLOPT_TLSAUTH_TYPE(3)\fP +.IP CURLOPT_PROXY_TLSAUTH_TYPE +Proxy TLS authentication methods. See \fICURLOPT_PROXY_TLSAUTH_TYPE(3)\fP .IP CURLOPT_PROXYAUTH HTTP proxy authentication methods. See \fICURLOPT_PROXYAUTH(3)\fP .IP CURLOPT_SASL_IR @@ -447,14 +457,24 @@ Timeout for waiting for the server's connect back to be accepted. See \fICURLOPT .SH SSL and SECURITY OPTIONS .IP CURLOPT_SSLCERT Client cert. See \fICURLOPT_SSLCERT(3)\fP +.IP CURLOPT_PROXY_SSLCERT +Proxy client cert. See \fICURLOPT_PROXY_SSLCERT(3)\fP .IP CURLOPT_SSLCERTTYPE Client cert type. See \fICURLOPT_SSLCERTTYPE(3)\fP +.IP CURLOPT_PROXY_SSLCERTTYPE +Proxy client cert type. See \fICURLOPT_PROXY_SSLCERTTYPE(3)\fP .IP CURLOPT_SSLKEY Client key. See \fICURLOPT_SSLKEY(3)\fP +.IP CURLOPT_PROXY_SSLKEY +Proxy client key. See \fICURLOPT_PROXY_SSLKEY(3)\fP .IP CURLOPT_SSLKEYTYPE Client key type. See \fICURLOPT_SSLKEYTYPE(3)\fP +.IP CURLOPT_PROXY_SSLKEYTYPE +Proxy client key type. See \fICURLOPT_PROXY_SSLKEYTYPE(3)\fP .IP CURLOPT_KEYPASSWD Client key password. See \fICURLOPT_KEYPASSWD(3)\fP +.IP CURLOPT_PROXY_KEYPASSWD +Proxy client key password. See \fICURLOPT_PROXY_KEYPASSWD(3)\fP .IP CURLOPT_SSL_ENABLE_ALPN Enable use of ALPN. See \fICURLOPT_SSL_ENABLE_ALPN(3)\fP .IP CURLOPT_SSL_ENABLE_NPN @@ -467,20 +487,32 @@ Default SSL engine. See \fICURLOPT_SSLENGINE_DEFAULT(3)\fP Enable TLS False Start. See \fICURLOPT_SSL_FALSESTART(3)\fP .IP CURLOPT_SSLVERSION SSL version to use. See \fICURLOPT_SSLVERSION(3)\fP +.IP CURLOPT_PROXY_SSLVERSION +Proxy SSL version to use. See \fICURLOPT_PROXY_SSLVERSION(3)\fP .IP CURLOPT_SSL_VERIFYHOST Verify the host name in the SSL certificate. See \fICURLOPT_SSL_VERIFYHOST(3)\fP +.IP CURLOPT_PROXY_SSL_VERIFYHOST +Verify the host name in the proxy SSL certificate. See \fICURLOPT_PROXY_SSL_VERIFYHOST(3)\fP .IP CURLOPT_SSL_VERIFYPEER Verify the SSL certificate. See \fICURLOPT_SSL_VERIFYPEER(3)\fP +.IP CURLOPT_PROXY_SSL_VERIFYPEER +Verify the proxy SSL certificate. See \fICURLOPT_PROXY_SSL_VERIFYPEER(3)\fP .IP CURLOPT_SSL_VERIFYSTATUS Verify the SSL certificate's status. See \fICURLOPT_SSL_VERIFYSTATUS(3)\fP .IP CURLOPT_CAINFO CA cert bundle. See \fICURLOPT_CAINFO(3)\fP +.IP CURLOPT_PROXY_CAINFO +Proxy CA cert bundle. See \fICURLOPT_PROXY_CAINFO(3)\fP .IP CURLOPT_ISSUERCERT Issuer certificate. See \fICURLOPT_ISSUERCERT(3)\fP .IP CURLOPT_CAPATH Path to CA cert bundle. See \fICURLOPT_CAPATH(3)\fP +.IP CURLOPT_PROXY_CAPATH +Path to proxy CA cert bundle. See \fICURLOPT_PROXY_CAPATH(3)\fP .IP CURLOPT_CRLFILE Certificate Revocation List. See \fICURLOPT_CRLFILE(3)\fP +.IP CURLOPT_PROXY_CRLFILE +Proxy Certificate Revocation List. See \fICURLOPT_PROXY_CRLFILE(3)\fP .IP CURLOPT_CERTINFO Extract certificate info. See \fICURLOPT_CERTINFO(3)\fP .IP CURLOPT_PINNEDPUBLICKEY @@ -491,10 +523,14 @@ Provide source for entropy random data. See \fICURLOPT_RANDOM_FILE(3)\fP Identify EGD socket for entropy. See \fICURLOPT_EGDSOCKET(3)\fP .IP CURLOPT_SSL_CIPHER_LIST Ciphers to use. See \fICURLOPT_SSL_CIPHER_LIST(3)\fP +.IP CURLOPT_PROXY_SSL_CIPHER_LIST +Proxy ciphers to use. See \fICURLOPT_PROXY_SSL_CIPHER_LIST(3)\fP .IP CURLOPT_SSL_SESSIONID_CACHE Disable SSL session-id cache. See \fICURLOPT_SSL_SESSIONID_CACHE(3)\fP .IP CURLOPT_SSL_OPTIONS Control SSL behavior. See \fICURLOPT_SSL_OPTIONS(3)\fP +.IP CURLOPT_PROXY_SSL_OPTIONS +Control proxy SSL behavior. See \fICURLOPT_PROXY_SSL_OPTIONS(3)\fP .IP CURLOPT_KRBLEVEL Kerberos security level. See \fICURLOPT_KRBLEVEL(3)\fP .IP CURLOPT_GSSAPI_DELEGATION diff --git a/docs/libcurl/opts/CURLINFO_PROXY_SSL_VERIFYRESULT.3 b/docs/libcurl/opts/CURLINFO_PROXY_SSL_VERIFYRESULT.3 new file mode 100644 index 000000000..8f09df5c4 --- /dev/null +++ b/docs/libcurl/opts/CURLINFO_PROXY_SSL_VERIFYRESULT.3 @@ -0,0 +1,44 @@ +.\" ************************************************************************** +.\" * _ _ ____ _ +.\" * Project ___| | | | _ \| | +.\" * / __| | | | |_) | | +.\" * | (__| |_| | _ <| |___ +.\" * \___|\___/|_| \_\_____| +.\" * +.\" * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. +.\" * +.\" * This software is licensed as described in the file COPYING, which +.\" * you should have received as part of this distribution. The terms +.\" * are also available at https://curl.haxx.se/docs/copyright.html. +.\" * +.\" * You may opt to use, copy, modify, merge, publish, distribute and/or sell +.\" * copies of the Software, and permit persons to whom the Software is +.\" * furnished to do so, under the terms of the COPYING file. +.\" * +.\" * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +.\" * KIND, either express or implied. +.\" * +.\" ************************************************************************** +.\" +.TH CURLINFO_PROXY_SSL_VERIFYRESULT 3 "16 Nov 2016" "libcurl 7.51.1" "curl_easy_getinfo options" +.SH NAME +CURLINFO_PROXY_SSL_VERIFYRESULT \- get the result of the proxy certification verification +.SH SYNOPSIS +#include + +CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_PROXY_SSL_VERIFYRESULT, long *result); +.SH DESCRIPTION +TODO: Make this text specific to HTTPS proxy. (Added in 7.XXX) +Pass a pointer to a long to receive the result of the certification +verification that was requested (using the \fICURLOPT_SSL_VERIFYPEER(3)\fP +option. +.SH PROTOCOLS +All using TLS +.SH EXAMPLE +TODO +.SH AVAILABILITY +Added in 7.5 +.SH RETURN VALUE +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. +.SH "SEE ALSO" +.BR curl_easy_getinfo "(3), " curl_easy_setopt "(3), " diff --git a/docs/libcurl/opts/CURLOPT_PROXY_CAINFO.3 b/docs/libcurl/opts/CURLOPT_PROXY_CAINFO.3 new file mode 100644 index 000000000..31fc562e8 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_PROXY_CAINFO.3 @@ -0,0 +1,64 @@ +.\" ************************************************************************** +.\" * _ _ ____ _ +.\" * Project ___| | | | _ \| | +.\" * / __| | | | |_) | | +.\" * | (__| |_| | _ <| |___ +.\" * \___|\___/|_| \_\_____| +.\" * +.\" * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. +.\" * +.\" * This software is licensed as described in the file COPYING, which +.\" * you should have received as part of this distribution. The terms +.\" * are also available at https://curl.haxx.se/docs/copyright.html. +.\" * +.\" * You may opt to use, copy, modify, merge, publish, distribute and/or sell +.\" * copies of the Software, and permit persons to whom the Software is +.\" * furnished to do so, under the terms of the COPYING file. +.\" * +.\" * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +.\" * KIND, either express or implied. +.\" * +.\" ************************************************************************** +.\" +.TH CURLOPT_PROXY_CAINFO 3 "16 Nov 2016" "libcurl 7.51.1" "curl_easy_setopt options" +.SH NAME +CURLOPT_PROXY_CAINFO \- path to proxy Certificate Authority (CA) bundle +.SH SYNOPSIS +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_PROXY_CAINFO, char *path); +.SH DESCRIPTION +TODO: Make this text specific to HTTPS proxy. (Added in 7.XXX) +Pass a char * to a zero terminated string naming a file holding one or more +certificates to verify the peer with. + +If \fICURLOPT_SSL_VERIFYPEER(3)\fP is zero and you avoid verifying the +server's certificate, \fICURLOPT_CAINFO(3)\fP need not even indicate an +accessible file. + +This option is by default set to the system path where libcurl's cacert bundle +is assumed to be stored, as established at build time. + +If curl is built against the NSS SSL library, the NSS PEM PKCS#11 module +(libnsspem.so) needs to be available for this option to work properly. + +(iOS and macOS only) If curl is built against Secure Transport, then this +option is supported for backward compatibility with other SSL engines, but it +should not be set. If the option is not set, then curl will use the +certificates in the system and user Keychain to verify the peer, which is the +preferred method of verifying the peer's certificate chain. +.SH DEFAULT +Built-in system specific +.SH PROTOCOLS +All TLS based protocols: HTTPS, FTPS, IMAPS, POP3S, SMTPS etc. +.SH EXAMPLE +TODO +.SH AVAILABILITY +For SSL engines that don't support certificate files the CURLOPT_PROXY_CAINFO option +is ignored. Refer to https://curl.haxx.se/docs/ssl-compared.html +.SH RETURN VALUE +Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or +CURLE_OUT_OF_MEMORY if there was insufficient heap space. +.SH "SEE ALSO" +.BR CURLOPT_CAPATH "(3), " +.BR CURLOPT_SSL_VERIFYPEER "(3), " CURLOPT_SSL_VERIFYHOST "(3), " diff --git a/docs/libcurl/opts/CURLOPT_PROXY_CAPATH.3 b/docs/libcurl/opts/CURLOPT_PROXY_CAPATH.3 new file mode 100644 index 000000000..7c984538a --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_PROXY_CAPATH.3 @@ -0,0 +1,54 @@ +.\" ************************************************************************** +.\" * _ _ ____ _ +.\" * Project ___| | | | _ \| | +.\" * / __| | | | |_) | | +.\" * | (__| |_| | _ <| |___ +.\" * \___|\___/|_| \_\_____| +.\" * +.\" * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. +.\" * +.\" * This software is licensed as described in the file COPYING, which +.\" * you should have received as part of this distribution. The terms +.\" * are also available at https://curl.haxx.se/docs/copyright.html. +.\" * +.\" * You may opt to use, copy, modify, merge, publish, distribute and/or sell +.\" * copies of the Software, and permit persons to whom the Software is +.\" * furnished to do so, under the terms of the COPYING file. +.\" * +.\" * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +.\" * KIND, either express or implied. +.\" * +.\" ************************************************************************** +.\" +.TH CURLOPT_PROXY_CAPATH 3 "16 Nov 2016" "libcurl 7.51.1" "curl_easy_setopt options" +.SH NAME +CURLOPT_PROXY_CAPATH \- specify directory holding proxy CA certificates +.SH SYNOPSIS +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_PROXY_CAPATH, char *capath); +.SH DESCRIPTION +TODO: Make this text specific to HTTPS proxy. (Added in 7.XXX) +Pass a char * to a zero terminated string naming a directory holding multiple +CA certificates to verify the peer with. If libcurl is built against OpenSSL, +the certificate directory must be prepared using the openssl c_rehash utility. +This makes sense only when used in combination with the +\fICURLOPT_SSL_VERIFYPEER(3)\fP option. + +The \fICURLOPT_CAPATH(3)\fP function apparently does not work in Windows due +to some limitation in openssl. +.SH DEFAULT +NULL +.SH PROTOCOLS +All TLS based protocols: HTTPS, FTPS, IMAPS, POP3S, SMTPS etc. +.SH EXAMPLE +TODO +.SH AVAILABILITY +This option is supported by the OpenSSL, GnuTLS and PolarSSL backends. The NSS +backend provides the option only for backward compatibility. +.SH RETURN VALUE +Returns CURLE_OK if TLS enabled, and CURLE_UNKNOWN_OPTION if not, or +CURLE_OUT_OF_MEMORY if there was insufficient heap space. +.SH "SEE ALSO" +.BR CURLOPT_CAINFO "(3), " +.BR CURLOPT_STDERR "(3), " CURLOPT_DEBUGFUNCTION "(3), " diff --git a/docs/libcurl/opts/CURLOPT_PROXY_CRLFILE.3 b/docs/libcurl/opts/CURLOPT_PROXY_CRLFILE.3 new file mode 100644 index 000000000..956cc5691 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_PROXY_CRLFILE.3 @@ -0,0 +1,61 @@ +.\" ************************************************************************** +.\" * _ _ ____ _ +.\" * Project ___| | | | _ \| | +.\" * / __| | | | |_) | | +.\" * | (__| |_| | _ <| |___ +.\" * \___|\___/|_| \_\_____| +.\" * +.\" * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. +.\" * +.\" * This software is licensed as described in the file COPYING, which +.\" * you should have received as part of this distribution. The terms +.\" * are also available at https://curl.haxx.se/docs/copyright.html. +.\" * +.\" * You may opt to use, copy, modify, merge, publish, distribute and/or sell +.\" * copies of the Software, and permit persons to whom the Software is +.\" * furnished to do so, under the terms of the COPYING file. +.\" * +.\" * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +.\" * KIND, either express or implied. +.\" * +.\" ************************************************************************** +.\" +.TH CURLOPT_PROXY_CRLFILE 3 "16 Nov 2016" "libcurl 7.51.1" "curl_easy_setopt options" +.SH NAME +CURLOPT_PROXY_CRLFILE \- specify a proxy Certificate Revocation List file +.SH SYNOPSIS +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_PROXY_CRLFILE, char *file); +.SH DESCRIPTION +TODO: Make this text specific to HTTPS proxy. (Added in 7.XXX) +Pass a char * to a zero terminated string naming a \fIfile\fP with the +concatenation of CRL (in PEM format) to use in the certificate validation that +occurs during the SSL exchange. + +When curl is built to use NSS or GnuTLS, there is no way to influence the use +of CRL passed to help in the verification process. When libcurl is built with +OpenSSL support, X509_V_FLAG_CRL_CHECK and X509_V_FLAG_CRL_CHECK_ALL are both +set, requiring CRL check against all the elements of the certificate chain if +a CRL file is passed. + +This option makes sense only when used in combination with the +\fICURLOPT_SSL_VERIFYPEER(3)\fP option. + +A specific error code (\fICURLE_SSL_CRL_BADFILE\fP) is defined with the +option. It is returned when the SSL exchange fails because the CRL file cannot +be loaded. A failure in certificate verification due to a revocation +information found in the CRL does not trigger this specific error. +.SH DEFAULT +NULL +.SH PROTOCOLS +All TLS-based protocols +.SH EXAMPLE +TODO +.SH AVAILABILITY +Added in 7.51.1 +.SH RETURN VALUE +Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or +CURLE_OUT_OF_MEMORY if there was insufficient heap space. +.SH "SEE ALSO" +.BR CURLOPT_SSL_VERIFYPEER "(3), " CURLOPT_SSL_VERIFYHOST "(3), " diff --git a/docs/libcurl/opts/CURLOPT_PROXY_KEYPASSWD.3 b/docs/libcurl/opts/CURLOPT_PROXY_KEYPASSWD.3 new file mode 100644 index 000000000..5f328020e --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_PROXY_KEYPASSWD.3 @@ -0,0 +1,46 @@ +.\" ************************************************************************** +.\" * _ _ ____ _ +.\" * Project ___| | | | _ \| | +.\" * / __| | | | |_) | | +.\" * | (__| |_| | _ <| |___ +.\" * \___|\___/|_| \_\_____| +.\" * +.\" * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. +.\" * +.\" * This software is licensed as described in the file COPYING, which +.\" * you should have received as part of this distribution. The terms +.\" * are also available at https://curl.haxx.se/docs/copyright.html. +.\" * +.\" * You may opt to use, copy, modify, merge, publish, distribute and/or sell +.\" * copies of the Software, and permit persons to whom the Software is +.\" * furnished to do so, under the terms of the COPYING file. +.\" * +.\" * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +.\" * KIND, either express or implied. +.\" * +.\" ************************************************************************** +.\" +.TH CURLOPT_PROXY_KEYPASSWD 3 "16 Nov 2016" "libcurl 7.51.1" "curl_easy_setopt options" +.SH NAME +CURLOPT_PROXY_KEYPASSWD \- set passphrase to proxy private key +.SH SYNOPSIS +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_PROXY_KEYPASSWD, char *pwd); +.SH DESCRIPTION +TODO: Make this text specific to HTTPS proxy. (Added in 7.XXX) +Pass a pointer to a zero terminated string as parameter. It will be used as +the password required to use the \fICURLOPT_SSLKEY(3)\fP or +\fICURLOPT_SSH_PRIVATE_KEYFILE(3)\fP private key. You never needed a pass +phrase to load a certificate but you need one to load your private key. +.SH DEFAULT +NULL +.SH PROTOCOLS +All TLS based protocols: HTTPS, FTPS, IMAPS, POP3S, SMTPS etc. +.SH EXAMPLE +TODO +.SH RETURN VALUE +Returns CURLE_OK if TLS enabled, CURLE_UNKNOWN_OPTION if not, or +CURLE_OUT_OF_MEMORY if there was insufficient heap space. +.SH "SEE ALSO" +.BR CURLOPT_SSLKEY "(3), " CURLOPT_SSH_PRIVATE_KEYFILE "(3), " diff --git a/docs/libcurl/opts/CURLOPT_PROXY_SSLCERT.3 b/docs/libcurl/opts/CURLOPT_PROXY_SSLCERT.3 new file mode 100644 index 000000000..8ce38592d --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_PROXY_SSLCERT.3 @@ -0,0 +1,56 @@ +.\" ************************************************************************** +.\" * _ _ ____ _ +.\" * Project ___| | | | _ \| | +.\" * / __| | | | |_) | | +.\" * | (__| |_| | _ <| |___ +.\" * \___|\___/|_| \_\_____| +.\" * +.\" * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. +.\" * +.\" * This software is licensed as described in the file COPYING, which +.\" * you should have received as part of this distribution. The terms +.\" * are also available at https://curl.haxx.se/docs/copyright.html. +.\" * +.\" * You may opt to use, copy, modify, merge, publish, distribute and/or sell +.\" * copies of the Software, and permit persons to whom the Software is +.\" * furnished to do so, under the terms of the COPYING file. +.\" * +.\" * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +.\" * KIND, either express or implied. +.\" * +.\" ************************************************************************** +.\" +.TH CURLOPT_PROXY_SSLCERT 3 "16 Nov 2016" "libcurl 7.51.1" "curl_easy_setopt options" +.SH NAME +CURLOPT_PROXY_SSLCERT \- set SSL proxy client certificate +.SH SYNOPSIS +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_PROXY_SSLCERT, char *cert); +.SH DESCRIPTION +TODO: Make this text specific to HTTPS proxy. (Added in 7.XXX) +Pass a pointer to a zero terminated string as parameter. The string should be +the file name of your client certificate. The default format is "P12" on +Secure Transport and "PEM" on other engines, and can be changed with +\fICURLOPT_SSLCERTTYPE(3)\fP. + +With NSS or Secure Transport, this can also be the nickname of the certificate +you wish to authenticate with as it is named in the security database. If you +want to use a file from the current directory, please precede it with "./" +prefix, in order to avoid confusion with a nickname. + +When using a client certificate, you most likely also need to provide a +private key with \fICURLOPT_SSLKEY(3)\fP. +.SH DEFAULT +NULL +.SH PROTOCOLS +All TLS based protocols: HTTPS, FTPS, IMAPS, POP3S, SMTPS etc. +.SH EXAMPLE +TODO +.SH AVAILABILITY +If built TLS enabled. +.SH RETURN VALUE +Returns CURLE_OK if TLS enabled, CURLE_UNKNOWN_OPTION if not, or +CURLE_OUT_OF_MEMORY if there was insufficient heap space. +.SH "SEE ALSO" +.BR CURLOPT_SSLCERTTYPE "(3), " CURLOPT_SSLKEY "(3), " diff --git a/docs/libcurl/opts/CURLOPT_PROXY_SSLCERTTYPE.3 b/docs/libcurl/opts/CURLOPT_PROXY_SSLCERTTYPE.3 new file mode 100644 index 000000000..297cc0c30 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_PROXY_SSLCERTTYPE.3 @@ -0,0 +1,49 @@ +.\" ************************************************************************** +.\" * _ _ ____ _ +.\" * Project ___| | | | _ \| | +.\" * / __| | | | |_) | | +.\" * | (__| |_| | _ <| |___ +.\" * \___|\___/|_| \_\_____| +.\" * +.\" * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. +.\" * +.\" * This software is licensed as described in the file COPYING, which +.\" * you should have received as part of this distribution. The terms +.\" * are also available at https://curl.haxx.se/docs/copyright.html. +.\" * +.\" * You may opt to use, copy, modify, merge, publish, distribute and/or sell +.\" * copies of the Software, and permit persons to whom the Software is +.\" * furnished to do so, under the terms of the COPYING file. +.\" * +.\" * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +.\" * KIND, either express or implied. +.\" * +.\" ************************************************************************** +.\" +.TH CURLOPT_PROXY_SSLCERTTYPE 3 "16 Nov 2016" "libcurl 7.51.1" "curl_easy_setopt options" +.SH NAME +CURLOPT_PROXY_SSLCERTTYPE \- specify type of the proxy client SSL certificate +.SH SYNOPSIS +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_PROXY_SSLCERTTYPE, char *type); +.SH DESCRIPTION +TODO: Make this text specific to HTTPS proxy. (Added in 7.XXX) +Pass a pointer to a zero terminated string as parameter. The string should be +the format of your certificate. Supported formats are "PEM" and "DER", except +with Secure Transport. OpenSSL (versions 0.9.3 and later) and Secure Transport +(on iOS 5 or later, or OS X 10.7 or later) also support "P12" for +PKCS#12-encoded files. +.SH DEFAULT +"PEM" +.SH PROTOCOLS +All TLS based protocols: HTTPS, FTPS, IMAPS, POP3S, SMTPS etc. +.SH EXAMPLE +TODO +.SH AVAILABILITY +If built TLS enabled. +.SH RETURN VALUE +Returns CURLE_OK if TLS is supported, CURLE_UNKNOWN_OPTION if not, or +CURLE_OUT_OF_MEMORY if there was insufficient heap space. +.SH "SEE ALSO" +.BR CURLOPT_SSLCERT "(3), " CURLOPT_SSLKEY "(3), " diff --git a/docs/libcurl/opts/CURLOPT_PROXY_SSLKEY.3 b/docs/libcurl/opts/CURLOPT_PROXY_SSLKEY.3 new file mode 100644 index 000000000..6301ae8f4 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_PROXY_SSLKEY.3 @@ -0,0 +1,51 @@ +.\" ************************************************************************** +.\" * _ _ ____ _ +.\" * Project ___| | | | _ \| | +.\" * / __| | | | |_) | | +.\" * | (__| |_| | _ <| |___ +.\" * \___|\___/|_| \_\_____| +.\" * +.\" * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. +.\" * +.\" * This software is licensed as described in the file COPYING, which +.\" * you should have received as part of this distribution. The terms +.\" * are also available at https://curl.haxx.se/docs/copyright.html. +.\" * +.\" * You may opt to use, copy, modify, merge, publish, distribute and/or sell +.\" * copies of the Software, and permit persons to whom the Software is +.\" * furnished to do so, under the terms of the COPYING file. +.\" * +.\" * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +.\" * KIND, either express or implied. +.\" * +.\" ************************************************************************** +.\" +.TH CURLOPT_PROXY_SSLKEY 3 "16 Nov 2016" "libcurl 7.51.1" "curl_easy_setopt options" +.SH NAME +CURLOPT_PROXY_SSLKEY \- specify private keyfile for TLS and SSL proxy client cert +.SH SYNOPSIS +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_PROXY_SSLKEY, char *keyfile); +.SH DESCRIPTION +TODO: Make this text specific to HTTPS proxy. (Added in 7.XXX) +Pass a pointer to a zero terminated string as parameter. The string should be +the file name of your private key. The default format is "PEM" and can be +changed with \fICURLOPT_SSLKEYTYPE(3)\fP. + +(iOS and Mac OS X only) This option is ignored if curl was built against +Secure Transport. Secure Transport expects the private key to be already +present in the keychain or PKCS#12 file containing the certificate. +.SH DEFAULT +NULL +.SH PROTOCOLS +All TLS based protocols: HTTPS, FTPS, IMAPS, POP3S, SMTPS etc. +.SH EXAMPLE +TODO +.SH AVAILABILITY +If built TLS enabled. +.SH RETURN VALUE +Returns CURLE_OK if TLS is supported, CURLE_UNKNOWN_OPTION if not, or +CURLE_OUT_OF_MEMORY if there was insufficient heap space. +.SH "SEE ALSO" +.BR CURLOPT_SSLKEYTYPE "(3), " CURLOPT_SSLCERT "(3), " diff --git a/docs/libcurl/opts/CURLOPT_PROXY_SSLKEYTYPE.3 b/docs/libcurl/opts/CURLOPT_PROXY_SSLKEYTYPE.3 new file mode 100644 index 000000000..8c81b49f0 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_PROXY_SSLKEYTYPE.3 @@ -0,0 +1,51 @@ +.\" ************************************************************************** +.\" * _ _ ____ _ +.\" * Project ___| | | | _ \| | +.\" * / __| | | | |_) | | +.\" * | (__| |_| | _ <| |___ +.\" * \___|\___/|_| \_\_____| +.\" * +.\" * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. +.\" * +.\" * This software is licensed as described in the file COPYING, which +.\" * you should have received as part of this distribution. The terms +.\" * are also available at https://curl.haxx.se/docs/copyright.html. +.\" * +.\" * You may opt to use, copy, modify, merge, publish, distribute and/or sell +.\" * copies of the Software, and permit persons to whom the Software is +.\" * furnished to do so, under the terms of the COPYING file. +.\" * +.\" * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +.\" * KIND, either express or implied. +.\" * +.\" ************************************************************************** +.\" +.TH CURLOPT_PROXY_SSLKEYTYPE 3 "16 Nov 2016" "libcurl 7.51.1" "curl_easy_setopt options" +.SH NAME +CURLOPT_PROXY_SSLKEYTYPE \- set type of the proxy private key file +.SH SYNOPSIS +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_PROXY_SSLKEYTYPE, char *type); +.SH DESCRIPTION +TODO: Make this text specific to HTTPS proxy. (Added in 7.XXX) +Pass a pointer to a zero terminated string as parameter. The string should be +the format of your private key. Supported formats are "PEM", "DER" and "ENG". + +The format "ENG" enables you to load the private key from a crypto engine. In +this case \fICURLOPT_SSLKEY(3)\fP is used as an identifier passed to the +engine. You have to set the crypto engine with \fICURLOPT_SSLENGINE(3)\fP. +\&"DER" format key file currently does not work because of a bug in OpenSSL. +.SH DEFAULT +"PEM" +.SH PROTOCOLS +All TLS based protocols: HTTPS, FTPS, IMAPS, POP3S, SMTPS etc. +.SH EXAMPLE +TODO +.SH AVAILABILITY +If built TLS enabled. +.SH RETURN VALUE +Returns CURLE_OK if TLS is supported, CURLE_UNKNOWN_OPTION if not, or +CURLE_OUT_OF_MEMORY if there was insufficient heap space. +.SH "SEE ALSO" +.BR CURLOPT_SSLKEY "(3), " CURLOPT_SSLCERT "(3), " diff --git a/docs/libcurl/opts/CURLOPT_PROXY_SSLVERSION.3 b/docs/libcurl/opts/CURLOPT_PROXY_SSLVERSION.3 new file mode 100644 index 000000000..ef65b169c --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_PROXY_SSLVERSION.3 @@ -0,0 +1,81 @@ +.\" ************************************************************************** +.\" * _ _ ____ _ +.\" * Project ___| | | | _ \| | +.\" * / __| | | | |_) | | +.\" * | (__| |_| | _ <| |___ +.\" * \___|\___/|_| \_\_____| +.\" * +.\" * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. +.\" * +.\" * This software is licensed as described in the file COPYING, which +.\" * you should have received as part of this distribution. The terms +.\" * are also available at https://curl.haxx.se/docs/copyright.html. +.\" * +.\" * You may opt to use, copy, modify, merge, publish, distribute and/or sell +.\" * copies of the Software, and permit persons to whom the Software is +.\" * furnished to do so, under the terms of the COPYING file. +.\" * +.\" * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +.\" * KIND, either express or implied. +.\" * +.\" ************************************************************************** +.\" +.TH CURLOPT_PROXY_SSLVERSION 3 "16 Nov 2016" "libcurl 7.51.1" "curl_easy_setopt options" +.SH NAME +CURLOPT_PROXY_SSLVERSION \- set proxy preferred TLS/SSL version +.SH SYNOPSIS +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_PROXY_SSLVERSION, long version); +.SH DESCRIPTION +TODO: Make this text specific to HTTPS proxy. (Added in 7.XXX) +Pass a long as parameter to control which version of SSL/TLS to attempt to +use. + +Use one of the available defines for this purpose. The available options are: +.RS +.IP CURL_SSLVERSION_DEFAULT +The default action. This will attempt to figure out the remote SSL protocol +version. +.IP CURL_SSLVERSION_TLSv1 +TLSv1.x +.IP CURL_SSLVERSION_SSLv2 +SSLv2 +.IP CURL_SSLVERSION_SSLv3 +SSLv3 +.IP CURL_SSLVERSION_TLSv1_0 +TLSv1.0 (Added in 7.34.0) +.IP CURL_SSLVERSION_TLSv1_1 +TLSv1.1 (Added in 7.34.0) +.IP CURL_SSLVERSION_TLSv1_2 +TLSv1.2 (Added in 7.34.0) +.IP CURL_SSLVERSION_TLSv1_3 +TLSv1.3 (Added in 7.51.1) +.RE +.SH DEFAULT +CURL_SSLVERSION_DEFAULT +.SH PROTOCOLS +All TLS based protocols: HTTPS, FTPS, IMAPS, POP3S, SMTPS etc. +.SH EXAMPLE +.nf +CURL *curl = curl_easy_init(); +if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + + /* ask libcurl to use TLS version 1.0 or later */ + curl_easy_setopt(curl, CURLOPT_PROXY_SSLVERSION, CURL_SSLVERSION_TLSv1); + + /* Perform the request */ + curl_easy_perform(curl); +} +.fi +.SH AVAILABILITY +SSLv2 is disabled by default since 7.18.1. Other SSL versions availability may +vary depending on which backend libcurl has been built to use. + +SSLv3 is disabled by default since 7.39.0. +.SH RETURN VALUE +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. +.SH "SEE ALSO" +.BR CURLOPT_USE_SSL "(3), " CURLOPT_HTTP_VERSION "(3), " +.BR CURLOPT_IPRESOLVE "(3) " diff --git a/docs/libcurl/opts/CURLOPT_PROXY_SSL_CIPHER_LIST.3 b/docs/libcurl/opts/CURLOPT_PROXY_SSL_CIPHER_LIST.3 new file mode 100644 index 000000000..a7cbc6af7 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_PROXY_SSL_CIPHER_LIST.3 @@ -0,0 +1,66 @@ +.\" ************************************************************************** +.\" * _ _ ____ _ +.\" * Project ___| | | | _ \| | +.\" * / __| | | | |_) | | +.\" * | (__| |_| | _ <| |___ +.\" * \___|\___/|_| \_\_____| +.\" * +.\" * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. +.\" * +.\" * This software is licensed as described in the file COPYING, which +.\" * you should have received as part of this distribution. The terms +.\" * are also available at https://curl.haxx.se/docs/copyright.html. +.\" * +.\" * You may opt to use, copy, modify, merge, publish, distribute and/or sell +.\" * copies of the Software, and permit persons to whom the Software is +.\" * furnished to do so, under the terms of the COPYING file. +.\" * +.\" * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +.\" * KIND, either express or implied. +.\" * +.\" ************************************************************************** +.\" +.TH CURLOPT_PROXY_SSL_CIPHER_LIST 3 "16 Nov 2016" "libcurl 7.51.1" "curl_easy_setopt options" +.SH NAME +CURLOPT_PROXY_SSL_CIPHER_LIST \- specify ciphers to use for proxy TLS +.SH SYNOPSIS +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_PROXY_SSL_CIPHER_LIST, char *list); +.SH DESCRIPTION +TODO: Make this text specific to HTTPS proxy. (Added in 7.XXX) +Pass a char *, pointing to a zero terminated string holding the list of +ciphers to use for the SSL connection. The list must be syntactically correct, +it consists of one or more cipher strings separated by colons. Commas or +spaces are also acceptable separators but colons are normally used, \&!, \&- +and \&+ can be used as operators. + +For OpenSSL and GnuTLS valid examples of cipher lists include 'RC4-SHA', +\'SHA1+DES\', 'TLSv1' and 'DEFAULT'. The default list is normally set when you +compile OpenSSL. + +You'll find more details about cipher lists on this URL: + + https://www.openssl.org/docs/apps/ciphers.html + +For NSS, valid examples of cipher lists include 'rsa_rc4_128_md5', +\'rsa_aes_128_sha\', etc. With NSS you don't add/remove ciphers. If one uses +this option then all known ciphers are disabled and only those passed in are +enabled. + +You'll find more details about the NSS cipher lists on this URL: + + http://git.fedorahosted.org/cgit/mod_nss.git/plain/docs/mod_nss.html#Directives +.SH DEFAULT +NULL, use internal default +.SH PROTOCOLS +All TLS based protocols: HTTPS, FTPS, IMAPS, POP3S, SMTPS etc. +.SH EXAMPLE +TODO +.SH AVAILABILITY +If built TLS enabled. +.SH RETURN VALUE +Returns CURLE_OK if TLS is supported, CURLE_UNKNOWN_OPTION if not, or +CURLE_OUT_OF_MEMORY if there was insufficient heap space. +.SH "SEE ALSO" +.BR CURLOPT_SSLVERSION "(3), " CURLOPT_USE_SSL "(3), " diff --git a/docs/libcurl/opts/CURLOPT_PROXY_SSL_OPTIONS.3 b/docs/libcurl/opts/CURLOPT_PROXY_SSL_OPTIONS.3 new file mode 100644 index 000000000..6b4cbaeb4 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_PROXY_SSL_OPTIONS.3 @@ -0,0 +1,62 @@ +.\" ************************************************************************** +.\" * _ _ ____ _ +.\" * Project ___| | | | _ \| | +.\" * / __| | | | |_) | | +.\" * | (__| |_| | _ <| |___ +.\" * \___|\___/|_| \_\_____| +.\" * +.\" * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. +.\" * +.\" * This software is licensed as described in the file COPYING, which +.\" * you should have received as part of this distribution. The terms +.\" * are also available at https://curl.haxx.se/docs/copyright.html. +.\" * +.\" * You may opt to use, copy, modify, merge, publish, distribute and/or sell +.\" * copies of the Software, and permit persons to whom the Software is +.\" * furnished to do so, under the terms of the COPYING file. +.\" * +.\" * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +.\" * KIND, either express or implied. +.\" * +.\" ************************************************************************** +.\" +.TH CURLOPT_PROXY_SSL_OPTIONS 3 "16 Nov 2016" "libcurl 7.51.1" "curl_easy_setopt options" +.SH NAME +CURLOPT_PROXY_SSL_OPTIONS \- set proxy SSL behavior options +.SH SYNOPSIS +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_PROXY_SSL_OPTIONS, long bitmask); +.SH DESCRIPTION +TODO: Make this text specific to HTTPS proxy. (Added in 7.XXX) +Pass a long with a bitmask to tell libcurl about specific SSL behaviors. + +\fICURLSSLOPT_ALLOW_BEAST\fP tells libcurl to not attempt to use any +workarounds for a security flaw in the SSL3 and TLS1.0 protocols. If this +option isn't used or this bit is set to 0, the SSL layer libcurl uses may use a +work-around for this flaw although it might cause interoperability problems +with some (older) SSL implementations. WARNING: avoiding this work-around +lessens the security, and by setting this option to 1 you ask for exactly that. +This option is only supported for DarwinSSL, NSS and OpenSSL. + +Added in 7.44.0: + +\fICURLSSLOPT_NO_REVOKE\fP tells libcurl to disable certificate revocation +checks for those SSL backends where such behavior is present. \fBCurrently this +option is only supported for WinSSL (the native Windows SSL library), with an +exception in the case of Windows' Untrusted Publishers blacklist which it seems +can't be bypassed.\fP This option may have broader support to accommodate other +SSL backends in the future. +https://curl.haxx.se/docs/ssl-compared.html + + +.SH DEFAULT +0 +.SH PROTOCOLS +All TLS-based protocols +.SH EXAMPLE +TODO +.SH RETURN VALUE +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. +.SH "SEE ALSO" +.BR CURLOPT_SSLVERSION "(3), " CURLOPT_SSL_CIPHER_LIST "(3), " diff --git a/docs/libcurl/opts/CURLOPT_PROXY_SSL_VERIFYHOST.3 b/docs/libcurl/opts/CURLOPT_PROXY_SSL_VERIFYHOST.3 new file mode 100644 index 000000000..9a0d69ab6 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_PROXY_SSL_VERIFYHOST.3 @@ -0,0 +1,88 @@ +.\" ************************************************************************** +.\" * _ _ ____ _ +.\" * Project ___| | | | _ \| | +.\" * / __| | | | |_) | | +.\" * | (__| |_| | _ <| |___ +.\" * \___|\___/|_| \_\_____| +.\" * +.\" * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. +.\" * +.\" * This software is licensed as described in the file COPYING, which +.\" * you should have received as part of this distribution. The terms +.\" * are also available at https://curl.haxx.se/docs/copyright.html. +.\" * +.\" * You may opt to use, copy, modify, merge, publish, distribute and/or sell +.\" * copies of the Software, and permit persons to whom the Software is +.\" * furnished to do so, under the terms of the COPYING file. +.\" * +.\" * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +.\" * KIND, either express or implied. +.\" * +.\" ************************************************************************** +.\" +.TH CURLOPT_PROXY_SSL_VERIFYHOST 3 "16 Nov 2016" "libcurl 7.51.1" "curl_easy_setopt options" +.SH NAME +CURLOPT_PROXY_SSL_VERIFYHOST \- verify the proxy certificate's name against host +.SH SYNOPSIS +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_PROXY_SSL_VERIFYHOST, long verify); +.SH DESCRIPTION +TODO: Make this text specific to HTTPS proxy. (Added in 7.XXX) +Pass a long as parameter specifying what to \fIverify\fP. + +This option determines whether libcurl verifies that the server cert is for +the server it is known as. + +When negotiating TLS and SSL connections, the server sends a certificate +indicating its identity. + +When \fICURLOPT_SSL_VERIFYHOST(3)\fP is 2, that certificate must indicate that +the server is the server to which you meant to connect, or the connection +fails. Simply put, it means it has to have the same name in the certificate as +is in the URL you operate against. + +Curl considers the server the intended one when the Common Name field or a +Subject Alternate Name field in the certificate matches the host name in the +URL to which you told Curl to connect. + +When the \fIverify\fP value is 1, \fIcurl_easy_setopt\fP will return an error +and the option value will not be changed. It was previously (in 7.28.0 and +earlier) a debug option of some sorts, but it is no longer supported due to +frequently leading to programmer mistakes. Future versions will stop returning +an error for 1 and just treat 1 and 2 the same. + +When the \fIverify\fP value is 0, the connection succeeds regardless of the +names in the certificate. Use that ability with caution! + +The default value for this option is 2. + +This option controls checking the server's certificate's claimed identity. +The server could be lying. To control lying, see +\fICURLOPT_SSL_VERIFYPEER(3)\fP. If libcurl is built against NSS and +\fICURLOPT_SSL_VERIFYPEER(3)\fP is zero, \fICURLOPT_SSL_VERIFYHOST(3)\fP is +also set to zero and cannot be overridden. +.SH DEFAULT +2 +.SH PROTOCOLS +All TLS based protocols: HTTPS, FTPS, IMAPS, POP3S, SMTPS etc. +.SH EXAMPLE +.nf +CURL *curl = curl_easy_init(); +if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + + /* Set the default value: strict name check please */ + curl_easy_setopt(curl, CURLOPT_PROXY_SSL_VERIFYHOST, 2L); + + curl_easy_perform(curl); +} +.fi +.SH AVAILABILITY +If built TLS enabled. +.SH RETURN VALUE +Returns CURLE_OK if TLS is supported, and CURLE_UNKNOWN_OPTION if not. + +If 1 is set as argument, \fICURLE_BAD_FUNCTION_ARGUMENT\fP is returned. +.SH "SEE ALSO" +.BR CURLOPT_SSL_VERIFYPEER "(3), " CURLOPT_CAINFO "(3), " diff --git a/docs/libcurl/opts/CURLOPT_PROXY_SSL_VERIFYPEER.3 b/docs/libcurl/opts/CURLOPT_PROXY_SSL_VERIFYPEER.3 new file mode 100644 index 000000000..294c77b37 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_PROXY_SSL_VERIFYPEER.3 @@ -0,0 +1,82 @@ +.\" ************************************************************************** +.\" * _ _ ____ _ +.\" * Project ___| | | | _ \| | +.\" * / __| | | | |_) | | +.\" * | (__| |_| | _ <| |___ +.\" * \___|\___/|_| \_\_____| +.\" * +.\" * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. +.\" * +.\" * This software is licensed as described in the file COPYING, which +.\" * you should have received as part of this distribution. The terms +.\" * are also available at https://curl.haxx.se/docs/copyright.html. +.\" * +.\" * You may opt to use, copy, modify, merge, publish, distribute and/or sell +.\" * copies of the Software, and permit persons to whom the Software is +.\" * furnished to do so, under the terms of the COPYING file. +.\" * +.\" * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +.\" * KIND, either express or implied. +.\" * +.\" ************************************************************************** +.\" +.TH CURLOPT_PROXY_SSL_VERIFYPEER 3 "16 Nov 2016" "libcurl 7.51.1" "curl_easy_setopt options" +.SH NAME +CURLOPT_PROXY_SSL_VERIFYPEER \- verify the proxy peer's SSL certificate +.SH SYNOPSIS +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_PROXY_SSL_VERIFYPEER, long verify); +.SH DESCRIPTION +TODO: Make this text specific to HTTPS proxy. (Added in 7.XXX) +Pass a long as parameter to enable or disable. + +This option determines whether curl verifies the authenticity of the peer's +certificate. A value of 1 means curl verifies; 0 (zero) means it doesn't. + +When negotiating a TLS or SSL connection, the server sends a certificate +indicating its identity. Curl verifies whether the certificate is authentic, +i.e. that you can trust that the server is who the certificate says it is. +This trust is based on a chain of digital signatures, rooted in certification +authority (CA) certificates you supply. curl uses a default bundle of CA +certificates (the path for that is determined at build time) and you can +specify alternate certificates with the \fICURLOPT_CAINFO(3)\fP option or the +\fICURLOPT_CAPATH(3)\fP option. + +When \fICURLOPT_SSL_VERIFYPEER(3)\fP is enabled, and the verification fails to +prove that the certificate is authentic, the connection fails. When the +option is zero, the peer certificate verification succeeds regardless. + +Authenticating the certificate is not enough to be sure about the server. You +typically also want to ensure that the server is the server you mean to be +talking to. Use \fICURLOPT_SSL_VERIFYHOST(3)\fP for that. The check that the +host name in the certificate is valid for the host name you're connecting to +is done independently of the \fICURLOPT_SSL_VERIFYPEER(3)\fP option. + +WARNING: disabling verification of the certificate allows bad guys to +man-in-the-middle the communication without you knowing it. Disabling +verification makes the communication insecure. Just having encryption on a +transfer is not enough as you cannot be sure that you are communicating with +the correct end-point. +.SH DEFAULT +By default, curl assumes a value of 1. +.SH PROTOCOLS +All TLS based protocols: HTTPS, FTPS, IMAPS, POP3S, SMTPS etc. +.SH EXAMPLE +.nf +CURL *curl = curl_easy_init(); +if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + + /* Set the default value: strict certificate check please */ + curl_easy_setopt(curl, CURLOPT_PROXY_SSL_VERIFYPEER, 1L); + + curl_easy_perform(curl); +} +.fi +.SH AVAILABILITY +If built TLS enabled. +.SH RETURN VALUE +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. +.SH "SEE ALSO" +.BR CURLOPT_SSL_VERIFYHOST "(3), " diff --git a/docs/libcurl/opts/CURLOPT_PROXY_TLSAUTH_PASSWORD.3 b/docs/libcurl/opts/CURLOPT_PROXY_TLSAUTH_PASSWORD.3 new file mode 100644 index 000000000..ed2544bd1 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_PROXY_TLSAUTH_PASSWORD.3 @@ -0,0 +1,48 @@ +.\" ************************************************************************** +.\" * _ _ ____ _ +.\" * Project ___| | | | _ \| | +.\" * / __| | | | |_) | | +.\" * | (__| |_| | _ <| |___ +.\" * \___|\___/|_| \_\_____| +.\" * +.\" * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. +.\" * +.\" * This software is licensed as described in the file COPYING, which +.\" * you should have received as part of this distribution. The terms +.\" * are also available at https://curl.haxx.se/docs/copyright.html. +.\" * +.\" * You may opt to use, copy, modify, merge, publish, distribute and/or sell +.\" * copies of the Software, and permit persons to whom the Software is +.\" * furnished to do so, under the terms of the COPYING file. +.\" * +.\" * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +.\" * KIND, either express or implied. +.\" * +.\" ************************************************************************** +.\" +.TH CURLOPT_PROXY_TLSAUTH_PASSWORD 3 "16 Nov 2016" "libcurl 7.51.1" "curl_easy_setopt options" +.SH NAME +CURLOPT_PROXY_TLSAUTH_PASSWORD \- password to use for proxy TLS authentication +.SH SYNOPSIS +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_PROXY_TLSAUTH_PASSWORD, char *pwd); +.SH DESCRIPTION +TODO: Make this text specific to HTTPS proxy. (Added in 7.XXX) +Pass a char * as parameter, which should point to the zero terminated password +to use for the TLS authentication method specified with the +\fICURLOPT_TLSAUTH_TYPE(3)\fP option. Requires that the +\fICURLOPT_TLSAUTH_USERNAME(3)\fP option also be set. +.SH DEFAULT +NULL +.SH PROTOCOLS +All TLS-based protocols +.SH EXAMPLE +TODO +.SH AVAILABILITY +Added in 7.21.4 +.SH RETURN VALUE +Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or +CURLE_OUT_OF_MEMORY if there was insufficient heap space. +.SH "SEE ALSO" +.BR CURLOPT_TLSAUTH_TYPE "(3), " CURLOPT_TLSAUTH_USERNAME "(3), " diff --git a/docs/libcurl/opts/CURLOPT_PROXY_TLSAUTH_TYPE.3 b/docs/libcurl/opts/CURLOPT_PROXY_TLSAUTH_TYPE.3 new file mode 100644 index 000000000..f30256ab7 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_PROXY_TLSAUTH_TYPE.3 @@ -0,0 +1,53 @@ +.\" ************************************************************************** +.\" * _ _ ____ _ +.\" * Project ___| | | | _ \| | +.\" * / __| | | | |_) | | +.\" * | (__| |_| | _ <| |___ +.\" * \___|\___/|_| \_\_____| +.\" * +.\" * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. +.\" * +.\" * This software is licensed as described in the file COPYING, which +.\" * you should have received as part of this distribution. The terms +.\" * are also available at https://curl.haxx.se/docs/copyright.html. +.\" * +.\" * You may opt to use, copy, modify, merge, publish, distribute and/or sell +.\" * copies of the Software, and permit persons to whom the Software is +.\" * furnished to do so, under the terms of the COPYING file. +.\" * +.\" * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +.\" * KIND, either express or implied. +.\" * +.\" ************************************************************************** +.\" +.TH CURLOPT_PROXY_TLSAUTH_TYPE 3 "16 Nov 2016" "libcurl 7.51.1" "curl_easy_setopt options" +.SH NAME +CURLOPT_PROXY_TLSAUTH_TYPE \- set proxy TLS authentication methods +.SH SYNOPSIS +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_PROXY_TLSAUTH_TYPE, char *type); +.SH DESCRIPTION +TODO: Make this text specific to HTTPS proxy. (Added in 7.XXX) +Pass a pointer to a zero terminated string as parameter. The string +should be the method of the TLS authentication. Supported method is "SRP". + +.IP SRP +TLS-SRP authentication. Secure Remote Password authentication for TLS is +defined in RFC5054 and provides mutual authentication if both sides have a +shared secret. To use TLS-SRP, you must also set the +\fICURLOPT_TLSAUTH_USERNAME(3)\fP and \fICURLOPT_TLSAUTH_PASSWORD(3)\fP +options. +.SH DEFAULT +blank +.SH PROTOCOLS +All TLS-based protocols +.SH EXAMPLE +TODO +.SH AVAILABILITY +You need to build libcurl with GnuTLS or OpenSSL with TLS-SRP support for this +to work. +.SH RETURN VALUE +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. +.SH "SEE ALSO" +.BR CURLOPT_TLSAUTH_USERNAME "(3), " CURLOPT_TLSAUTH_PASSWORD "(3), " diff --git a/docs/libcurl/opts/CURLOPT_PROXY_TLSAUTH_USERNAME.3 b/docs/libcurl/opts/CURLOPT_PROXY_TLSAUTH_USERNAME.3 new file mode 100644 index 000000000..53c8378a4 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_PROXY_TLSAUTH_USERNAME.3 @@ -0,0 +1,46 @@ +.\" ************************************************************************** +.\" * _ _ ____ _ +.\" * Project ___| | | | _ \| | +.\" * / __| | | | |_) | | +.\" * | (__| |_| | _ <| |___ +.\" * \___|\___/|_| \_\_____| +.\" * +.\" * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. +.\" * +.\" * This software is licensed as described in the file COPYING, which +.\" * you should have received as part of this distribution. The terms +.\" * are also available at https://curl.haxx.se/docs/copyright.html. +.\" * +.\" * You may opt to use, copy, modify, merge, publish, distribute and/or sell +.\" * copies of the Software, and permit persons to whom the Software is +.\" * furnished to do so, under the terms of the COPYING file. +.\" * +.\" * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +.\" * KIND, either express or implied. +.\" * +.\" ************************************************************************** +.\" +.TH CURLOPT_PROXY_TLSAUTH_USERNAME 3 "16 Nov 2016" "libcurl 7.51.1" "curl_easy_setopt options" +.SH NAME +CURLOPT_PROXY_TLSAUTH_USERNAME \- user name to use for proxy TLS authentication +.SH SYNOPSIS +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_PROXY_TLSAUTH_USERNAME, char *user); +.SH DESCRIPTION +TODO: Make this text specific to HTTPS proxy. (Added in 7.XXX) +Pass a char * as parameter, which should point to the zero terminated username +to use for the TLS authentication method specified with the +\fICURLOPT_TLSAUTH_TYPE(3)\fP option. Requires that the +\fICURLOPT_TLSAUTH_PASSWORD(3)\fP option also be set. +.SH DEFAULT +NULL +.SH PROTOCOLS +All TLS-based protocols +.SH EXAMPLE +TODO +.SH RETURN VALUE +Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or +CURLE_OUT_OF_MEMORY if there was insufficient heap space. +.SH "SEE ALSO" +.BR CURLOPT_TLSAUTH_TYPE "(3), " CURLOPT_TLSAUTH_PASSWORD "(3), " diff --git a/docs/libcurl/opts/CURLOPT_SOCKS_PROXY.3 b/docs/libcurl/opts/CURLOPT_SOCKS_PROXY.3 new file mode 100644 index 000000000..bddb40a18 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_SOCKS_PROXY.3 @@ -0,0 +1,88 @@ +.\" ************************************************************************** +.\" * _ _ ____ _ +.\" * Project ___| | | | _ \| | +.\" * / __| | | | |_) | | +.\" * | (__| |_| | _ <| |___ +.\" * \___|\___/|_| \_\_____| +.\" * +.\" * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. +.\" * +.\" * This software is licensed as described in the file COPYING, which +.\" * you should have received as part of this distribution. The terms +.\" * are also available at https://curl.haxx.se/docs/copyright.html. +.\" * +.\" * You may opt to use, copy, modify, merge, publish, distribute and/or sell +.\" * copies of the Software, and permit persons to whom the Software is +.\" * furnished to do so, under the terms of the COPYING file. +.\" * +.\" * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +.\" * KIND, either express or implied. +.\" * +.\" ************************************************************************** +.\" +.TH CURLOPT_SOCKS_PROXY 3 "16 Nov 2016" "libcurl 7.51.1" "curl_easy_setopt options" +.SH NAME +CURLOPT_SOCKS_PROXY \- set socks proxy to use +.SH SYNOPSIS +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_SOCKS_PROXY, char *proxy); +.SH DESCRIPTION +TODO: Make this text specific to HTTPS proxy. (Added in 7.XXX) +Set the \fIproxy\fP to use for the upcoming request. The parameter should be a +char * to a zero terminated string holding the host name or dotted numerical +IP address. A numerical IPv6 address must be written within [brackets]. + +To specify port number in this string, append :[port] to the end of the host +name. The proxy's port number may optionally be specified with the separate +option \fICURLOPT_PROXYPORT(3)\fP. If not specified, libcurl will default to +using port 1080 for proxies. + +The proxy string may be prefixed with [scheme]:// to specify which kind of +proxy is used. Use socks4://, socks4a://, socks5:// or socks5h:// (the last +one to enable socks5 and asking the proxy to do the resolving, also known as +\fICURLPROXY_SOCKS5_HOSTNAME\fP type) to request the specific SOCKS version to +be used. No scheme specified or http://, will be treated as HTTP proxies. + +Without a scheme prefix, \fICURLOPT_PROXYTYPE(3)\fP can be used to specify +which kind of proxy the string identifies. + +When you tell the library to use a HTTP proxy, libcurl will transparently +convert operations to HTTP even if you specify an FTP URL etc. This may have +an impact on what other features of the library you can use, such as +\fICURLOPT_QUOTE(3)\fP and similar FTP specifics that don't work unless you +tunnel through the HTTP proxy. Such tunneling is activated with +\fICURLOPT_HTTPPROXYTUNNEL(3)\fP. + +libcurl respects the environment variables \fBhttp_proxy\fP, \fBftp_proxy\fP, +\fBall_proxy\fP etc, if any of those are set. The \fICURLOPT_PROXY(3)\fP +option does however override any possibly set environment variables. + +Setting the proxy string to "" (an empty string) will explicitly disable the +use of a proxy, even if there is an environment variable set for it. + +A proxy host string can also include protocol scheme (http://) and embedded +user + password. +.SH DEFAULT +Default is NULL, meaning no proxy is used. + +When you set a host name to use, do not assume that there's any particular +single port number used widely for proxies. Specify it! +.SH PROTOCOLS +All except file://. Note that some protocols don't do very well over proxy. +.SH EXAMPLE +TODO +.SH AVAILABILITY +Since 7.14.1 the proxy environment variable names can include the protocol +scheme. + +Since 7.21.7 the proxy string supports the socks protocols as "schemes". + +Since 7.50.2, unsupported schemes in proxy strings cause libcurl to return +error. +.SH RETURN VALUE +Returns CURLE_OK if proxies are supported, CURLE_UNKNOWN_OPTION if not, or +CURLE_OUT_OF_MEMORY if there was insufficient heap space. +.SH "SEE ALSO" +.BR CURLOPT_PROXYPORT "(3), " CURLOPT_HTTPPROXYTUNNEL "(3), " +.BR CURLOPT_PROXYTYPE "(3)" diff --git a/docs/libcurl/opts/CURLOPT_SOCKS_PROXYTYPE.3 b/docs/libcurl/opts/CURLOPT_SOCKS_PROXYTYPE.3 new file mode 100644 index 000000000..789bfb877 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_SOCKS_PROXYTYPE.3 @@ -0,0 +1,55 @@ +.\" ************************************************************************** +.\" * _ _ ____ _ +.\" * Project ___| | | | _ \| | +.\" * / __| | | | |_) | | +.\" * | (__| |_| | _ <| |___ +.\" * \___|\___/|_| \_\_____| +.\" * +.\" * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. +.\" * +.\" * This software is licensed as described in the file COPYING, which +.\" * you should have received as part of this distribution. The terms +.\" * are also available at https://curl.haxx.se/docs/copyright.html. +.\" * +.\" * You may opt to use, copy, modify, merge, publish, distribute and/or sell +.\" * copies of the Software, and permit persons to whom the Software is +.\" * furnished to do so, under the terms of the COPYING file. +.\" * +.\" * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +.\" * KIND, either express or implied. +.\" * +.\" ************************************************************************** +.\" +.TH CURLOPT_SOCKS_PROXYTYPE 3 "16 Nov 2016" "libcurl 7.51.1" "curl_easy_setopt options" +.SH NAME +CURLOPT_SOCKS_PROXYTYPE \- socks proxy protocol type +.SH SYNOPSIS +#include + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_SOCKS_PROXYTYPE, long type); +.SH DESCRIPTION +TODO: Make this text specific to HTTPS proxy. (Added in 7.XXX) +Pass a long with this option to set type of the proxy. Available options for +this are \fICURLPROXY_HTTP\fP, \fICURLPROXY_HTTP_1_0\fP +\fICURLPROXY_SOCKS4\fP, \fICURLPROXY_SOCKS5\fP, \fICURLPROXY_SOCKS4A\fP and +\fICURLPROXY_SOCKS5_HOSTNAME\fP. The HTTP type is default. + +If you set \fICURLOPT_PROXYTYPE(3)\fP to \fICURLPROXY_HTTP_1_0\fP, it will +only affect how libcurl speaks to a proxy when CONNECT is used. The HTTP +version used for "regular" HTTP requests is instead controlled with +\fICURLOPT_HTTP_VERSION(3)\fP. + +Often it is more convenient to specify the proxy type with the scheme part of +the \fICURLOPT_PROXY(3)\fP string. +.SH DEFAULT +CURLPROXY_HTTP +.SH PROTOCOLS +Most +.SH EXAMPLE +TODO +.SH AVAILABILITY +Always +.SH RETURN VALUE +Returns CURLE_OK +.SH "SEE ALSO" +.BR CURLOPT_PROXY "(3), " CURLOPT_PROXYPORT "(3), " diff --git a/docs/libcurl/opts/Makefile.am b/docs/libcurl/opts/Makefile.am index 8cb1b52b8..1ef4f2bc1 100644 --- a/docs/libcurl/opts/Makefile.am +++ b/docs/libcurl/opts/Makefile.am @@ -49,6 +49,7 @@ man_MANS = \ CURLINFO_PRIMARY_IP.3 \ CURLINFO_PRIMARY_PORT.3 \ CURLINFO_PRIVATE.3 \ + CURLINFO_PROXY_SSL_VERIFYRESULT.3 \ CURLINFO_PROXYAUTH_AVAIL.3 \ CURLINFO_REDIRECT_COUNT.3 \ CURLINFO_REDIRECT_TIME.3 \ @@ -223,6 +224,24 @@ man_MANS = \ CURLOPT_PROXYUSERPWD.3 \ CURLOPT_PROXY_SERVICE_NAME.3 \ CURLOPT_PROXY_TRANSFER_MODE.3 \ + CURLOPT_PROXY_CAINFO.3 \ + CURLOPT_PROXY_CAPATH.3 \ + CURLOPT_PROXY_CRLFILE.3 \ + CURLOPT_PROXY_KEYPASSWD.3 \ + CURLOPT_PROXY_SSLCERT.3 \ + CURLOPT_PROXY_SSLCERTTYPE.3 \ + CURLOPT_PROXY_SSLKEY.3 \ + CURLOPT_PROXY_SSLKEYTYPE.3 \ + CURLOPT_PROXY_SSLVERSION.3 \ + CURLOPT_PROXY_SSL_CIPHER_LIST.3 \ + CURLOPT_PROXY_SSL_OPTIONS.3 \ + CURLOPT_PROXY_SSL_VERIFYHOST.3 \ + CURLOPT_PROXY_SSL_VERIFYPEER.3 \ + CURLOPT_PROXY_TLSAUTH_PASSWORD.3 \ + CURLOPT_PROXY_TLSAUTH_TYPE.3 \ + CURLOPT_PROXY_TLSAUTH_USERNAME.3 \ + CURLOPT_SOCKS_PROXY.3 \ + CURLOPT_SOCKS_PROXYTYPE.3 \ CURLOPT_PUT.3 \ CURLOPT_QUOTE.3 \ CURLOPT_RANDOM_FILE.3 \ diff --git a/docs/libcurl/symbols-in-versions b/docs/libcurl/symbols-in-versions index ef730c8a9..fb3330f14 100644 --- a/docs/libcurl/symbols-in-versions +++ b/docs/libcurl/symbols-in-versions @@ -240,6 +240,7 @@ CURLINFO_PRIMARY_IP 7.19.0 CURLINFO_PRIMARY_PORT 7.21.0 CURLINFO_PRIVATE 7.10.3 CURLINFO_PROXYAUTH_AVAIL 7.10.8 +CURLINFO_PROXY_SSL_VERIFYRESULT 7.51.1 CURLINFO_REDIRECT_COUNT 7.9.7 CURLINFO_REDIRECT_TIME 7.9.7 CURLINFO_REDIRECT_URL 7.18.2 @@ -468,7 +469,23 @@ CURLOPT_PROXYPORT 7.1 CURLOPT_PROXYTYPE 7.10 CURLOPT_PROXYUSERNAME 7.19.1 CURLOPT_PROXYUSERPWD 7.1 +CURLOPT_PROXY_CAINFO 7.51.1 +CURLOPT_PROXY_CAPATH 7.51.1 +CURLOPT_PROXY_CRLFILE 7.51.1 +CURLOPT_PROXY_KEYPASSWD 7.51.1 CURLOPT_PROXY_SERVICE_NAME 7.43.0 +CURLOPT_PROXY_SSLCERT 7.51.1 +CURLOPT_PROXY_SSLCERTTYPE 7.51.1 +CURLOPT_PROXY_SSLKEY 7.51.1 +CURLOPT_PROXY_SSLKEYTYPE 7.51.1 +CURLOPT_PROXY_SSLVERSION 7.51.1 +CURLOPT_PROXY_SSL_CIPHER_LIST 7.51.1 +CURLOPT_PROXY_SSL_OPTIONS 7.51.1 +CURLOPT_PROXY_SSL_VERIFYHOST 7.51.1 +CURLOPT_PROXY_SSL_VERIFYPEER 7.51.1 +CURLOPT_PROXY_TLSAUTH_PASSWORD 7.51.1 +CURLOPT_PROXY_TLSAUTH_TYPE 7.51.1 +CURLOPT_PROXY_TLSAUTH_USERNAME 7.51.1 CURLOPT_PROXY_TRANSFER_MODE 7.18.0 CURLOPT_PUT 7.1 CURLOPT_QUOTE 7.1 @@ -498,6 +515,8 @@ CURLOPT_SOCKOPTDATA 7.16.0 CURLOPT_SOCKOPTFUNCTION 7.16.0 CURLOPT_SOCKS5_GSSAPI_NEC 7.19.4 CURLOPT_SOCKS5_GSSAPI_SERVICE 7.19.4 7.49.0 +CURLOPT_SOCKS_PROXY 7.51.1 +CURLOPT_SOCKS_PROXYTYPE 7.51.1 CURLOPT_SOURCE_HOST 7.12.1 - 7.15.5 CURLOPT_SOURCE_PATH 7.12.1 - 7.15.5 CURLOPT_SOURCE_PORT 7.12.1 - 7.15.5 @@ -611,6 +630,7 @@ CURLPROTO_TELNET 7.19.4 CURLPROTO_TFTP 7.19.4 CURLPROXY_HTTP 7.10 CURLPROXY_HTTP_1_0 7.19.4 +CURLPROXY_HTTPS 7.51.1 CURLPROXY_SOCKS4 7.10 CURLPROXY_SOCKS4A 7.18.0 CURLPROXY_SOCKS5 7.10 diff --git a/include/curl/curl.h b/include/curl/curl.h index 03fcfebc3..24762c7d8 100644 --- a/include/curl/curl.h +++ b/include/curl/curl.h @@ -640,6 +640,7 @@ typedef enum { CONNECT HTTP/1.1 */ CURLPROXY_HTTP_1_0 = 1, /* added in 7.19.4, force to use CONNECT HTTP/1.0 */ + CURLPROXY_HTTPS = 2, /* added in TBD */ CURLPROXY_SOCKS4 = 4, /* support added in 7.15.2, enum existed already in 7.10 */ CURLPROXY_SOCKS5 = 5, /* added in 7.10 */ @@ -1206,7 +1207,8 @@ typedef enum { CINIT(SHARE, OBJECTPOINT, 100), /* indicates type of proxy. accepted values are CURLPROXY_HTTP (default), - CURLPROXY_SOCKS4, CURLPROXY_SOCKS4A and CURLPROXY_SOCKS5. */ + CURLPROXY_HTTPS, CURLPROXY_SOCKS4, CURLPROXY_SOCKS4A and + CURLPROXY_SOCKS5. */ CINIT(PROXYTYPE, LONG, 101), /* Set the Accept-Encoding string. Use this to tell a server you would like @@ -1704,6 +1706,70 @@ typedef enum { * HTTP status code >= 300 */ CINIT(KEEP_SENDING_ON_ERROR, LONG, 245), + /* The CApath or CAfile used to validate the proxy certificate + this option is used only if PROXY_SSL_VERIFYPEER is true */ + CINIT(PROXY_CAINFO, STRINGPOINT, 246), + + /* The CApath directory used to validate the proxy certificate + this option is used only if PROXY_SSL_VERIFYPEER is true */ + CINIT(PROXY_CAPATH, STRINGPOINT, 247), + + /* Set if we should verify the proxy in ssl handshake, + set 1 to verify. */ + CINIT(PROXY_SSL_VERIFYPEER, LONG, 248), + + /* Set if we should verify the Common name from the proxy certificate in ssl + * handshake, set 1 to check existence, 2 to ensure that it matches + * the provided hostname. */ + CINIT(PROXY_SSL_VERIFYHOST, LONG, 249), + + /* What version to specifically try to use for proxy. + See CURL_SSLVERSION defines below. */ + CINIT(PROXY_SSLVERSION, LONG, 250), + + /* Set a username for authenticated TLS for proxy */ + CINIT(PROXY_TLSAUTH_USERNAME, STRINGPOINT, 251), + + /* Set a password for authenticated TLS for proxy */ + CINIT(PROXY_TLSAUTH_PASSWORD, STRINGPOINT, 252), + + /* Set authentication type for authenticated TLS for proxy */ + CINIT(PROXY_TLSAUTH_TYPE, STRINGPOINT, 253), + + /* name of the file keeping your private SSL-certificate for proxy */ + CINIT(PROXY_SSLCERT, STRINGPOINT, 254), + + /* type of the file keeping your SSL-certificate ("DER", "PEM", "ENG") for + proxy */ + CINIT(PROXY_SSLCERTTYPE, STRINGPOINT, 255), + + /* name of the file keeping your private SSL-key for proxy */ + CINIT(PROXY_SSLKEY, STRINGPOINT, 256), + + /* type of the file keeping your private SSL-key ("DER", "PEM", "ENG") for + proxy */ + CINIT(PROXY_SSLKEYTYPE, STRINGPOINT, 257), + + /* password for the SSL private key for proxy */ + CINIT(PROXY_KEYPASSWD, STRINGPOINT, 258), + + /* Specify which SSL ciphers to use for proxy */ + CINIT(PROXY_SSL_CIPHER_LIST, STRINGPOINT, 259), + + /* CRL file for proxy */ + CINIT(PROXY_CRLFILE, STRINGPOINT, 260), + + /* Enable/disable specific SSL features with a bitmask for proxy, see + CURLSSLOPT_* */ + CINIT(PROXY_SSL_OPTIONS, LONG, 261), + + /* Name of socks proxy to use. */ + CINIT(SOCKS_PROXY, STRINGPOINT, 262), + + /* indicates type of proxy. accepted values are CURLPROXY_SOCKS4, + CURLPROXY_SOCKS4A and CURLPROXY_SOCKS5. */ + CINIT(SOCKS_PROXYTYPE, LONG, 263), + CURLOPT_LASTENTRY /* the last unused */ } CURLoption; @@ -2210,9 +2276,10 @@ typedef enum { CURLINFO_ACTIVESOCKET = CURLINFO_SOCKET + 44, CURLINFO_TLS_SSL_PTR = CURLINFO_SLIST + 45, CURLINFO_HTTP_VERSION = CURLINFO_LONG + 46, + CURLINFO_PROXY_SSL_VERIFYRESULT = CURLINFO_LONG + 47, /* Fill in new entries below here! */ - CURLINFO_LASTONE = 46 + CURLINFO_LASTONE = 47 } CURLINFO; /* CURLINFO_RESPONSE_CODE is the new name for the option previously known as diff --git a/lib/conncache.c b/lib/conncache.c index 01b1b449d..d8ef9a54c 100644 --- a/lib/conncache.c +++ b/lib/conncache.c @@ -132,8 +132,10 @@ static char *hashkey(struct connectdata *conn) { const char *hostname; - if(conn->bits.proxy) - hostname = conn->proxy.name; + if(conn->bits.socksproxy) + hostname = conn->socks_proxy.host.name; + else if(conn->bits.httpproxy) + hostname = conn->http_proxy.host.name; else if(conn->bits.conn_to_host) hostname = conn->conn_to_host.name; else diff --git a/lib/connect.c b/lib/connect.c index d87951c88..6329434af 100644 --- a/lib/connect.c +++ b/lib/connect.c @@ -853,8 +853,10 @@ CURLcode Curl_is_connected(struct connectdata *conn, return result; } - if(conn->bits.proxy) - hostname = conn->proxy.name; + if(conn->bits.socksproxy) + hostname = conn->socks_proxy.host.name; + else if(conn->bits.httpproxy) + hostname = conn->http_proxy.host.name; else if(conn->bits.conn_to_host) hostname = conn->conn_to_host.name; else diff --git a/lib/curl_ntlm_wb.c b/lib/curl_ntlm_wb.c index 1d1b3a3f2..4699d8f42 100644 --- a/lib/curl_ntlm_wb.c +++ b/lib/curl_ntlm_wb.c @@ -349,7 +349,7 @@ CURLcode Curl_output_ntlm_wb(struct connectdata *conn, if(proxy) { allocuserpwd = &conn->allocptr.proxyuserpwd; - userp = conn->proxyuser; + userp = conn->http_proxy.user; ntlm = &conn->proxyntlm; authp = &conn->data->state.authproxy; } diff --git a/lib/ftp.c b/lib/ftp.c index 04670b625..1e61fc551 100644 --- a/lib/ftp.c +++ b/lib/ftp.c @@ -499,7 +499,7 @@ static CURLcode InitiateTransfer(struct connectdata *conn) struct FTP *ftp = data->req.protop; CURLcode result = CURLE_OK; - if(conn->ssl[SECONDARYSOCKET].use) { + if(conn->bits.ftp_use_data_ssl) { /* since we only have a plaintext TCP connection here, we must now * do the TLS stuff */ infof(data, "Doing the SSL/TLS handshake on the data stream\n"); @@ -740,7 +740,7 @@ CURLcode Curl_GetFTPResponse(ssize_t *nreadp, /* return number of bytes read */ * wait for more data anyway. */ } - else { + else if(!Curl_ssl_data_pending(conn, FIRSTSOCKET)) { switch (SOCKET_READABLE(sockfd, interval_ms)) { case -1: /* select() error, stop reading */ failf(data, "FTP response aborted due to select/poll error: %d", @@ -1850,84 +1850,6 @@ static CURLcode ftp_epsv_disable(struct connectdata *conn) return result; } -/* - * Perform the necessary magic that needs to be done once the TCP connection - * to the proxy has completed. - */ -static CURLcode proxy_magic(struct connectdata *conn, - char *newhost, unsigned short newport, - bool *magicdone) -{ - CURLcode result = CURLE_OK; - struct Curl_easy *data = conn->data; - -#if defined(CURL_DISABLE_PROXY) - (void) newhost; - (void) newport; -#endif - - *magicdone = FALSE; - - switch(conn->proxytype) { - case CURLPROXY_SOCKS5: - case CURLPROXY_SOCKS5_HOSTNAME: - result = Curl_SOCKS5(conn->proxyuser, conn->proxypasswd, newhost, - newport, SECONDARYSOCKET, conn); - *magicdone = TRUE; - break; - case CURLPROXY_SOCKS4: - result = Curl_SOCKS4(conn->proxyuser, newhost, newport, - SECONDARYSOCKET, conn, FALSE); - *magicdone = TRUE; - break; - case CURLPROXY_SOCKS4A: - result = Curl_SOCKS4(conn->proxyuser, newhost, newport, - SECONDARYSOCKET, conn, TRUE); - *magicdone = TRUE; - break; - case CURLPROXY_HTTP: - case CURLPROXY_HTTP_1_0: - /* do nothing here. handled later. */ - break; - default: - failf(data, "unknown proxytype option given"); - result = CURLE_COULDNT_CONNECT; - break; - } - - if(conn->bits.tunnel_proxy && conn->bits.httpproxy) { - /* BLOCKING */ - /* We want "seamless" FTP operations through HTTP proxy tunnel */ - - /* Curl_proxyCONNECT is based on a pointer to a struct HTTP at the - * member conn->proto.http; we want FTP through HTTP and we have to - * change the member temporarily for connecting to the HTTP proxy. After - * Curl_proxyCONNECT we have to set back the member to the original - * struct FTP pointer - */ - struct HTTP http_proxy; - struct FTP *ftp_save = data->req.protop; - memset(&http_proxy, 0, sizeof(http_proxy)); - data->req.protop = &http_proxy; - - result = Curl_proxyCONNECT(conn, SECONDARYSOCKET, newhost, newport, TRUE); - - data->req.protop = ftp_save; - - if(result) - return result; - - if(conn->tunnel_state[SECONDARYSOCKET] != TUNNEL_COMPLETE) { - /* the CONNECT procedure is not complete, the tunnel is not yet up */ - state(conn, FTP_STOP); /* this phase is completed */ - return result; - } - else - *magicdone = TRUE; - } - - return result; -} static char *control_address(struct connectdata *conn) { @@ -1935,11 +1857,7 @@ static char *control_address(struct connectdata *conn) If a proxy tunnel is used, returns the original host name instead, because the effective control connection address is the proxy address, not the ftp host. */ - if(conn->bits.tunnel_proxy || - conn->proxytype == CURLPROXY_SOCKS5 || - conn->proxytype == CURLPROXY_SOCKS5_HOSTNAME || - conn->proxytype == CURLPROXY_SOCKS4 || - conn->proxytype == CURLPROXY_SOCKS4A) + if(conn->bits.tunnel_proxy || conn->bits.socksproxy) return conn->host.name; return conn->ip_addr_str; @@ -2063,7 +1981,9 @@ static CURLcode ftp_state_pasv_resp(struct connectdata *conn, * here. We don't want to rely on a former host lookup that might've * expired now, instead we remake the lookup here and now! */ - rc = Curl_resolv(conn, conn->proxy.name, (int)conn->port, &addr); + const char * const host_name = conn->bits.socksproxy ? + conn->socks_proxy.host.name : conn->http_proxy.host.name; + rc = Curl_resolv(conn, host_name, (int)conn->port, &addr); if(rc == CURLRESOLV_PENDING) /* BLOCKING, ignores the return code but 'addr' will be NULL in case of failure */ @@ -2073,8 +1993,7 @@ static CURLcode ftp_state_pasv_resp(struct connectdata *conn, (unsigned short)conn->port; /* we connect to the proxy's port */ if(!addr) { - failf(data, "Can't resolve proxy host %s:%hu", - conn->proxy.name, connectport); + failf(data, "Can't resolve proxy host %s:%hu", host_name, connectport); return CURLE_FTP_CANT_GET_HOST; } } @@ -2115,6 +2034,10 @@ static CURLcode ftp_state_pasv_resp(struct connectdata *conn, /* this just dumps information about this second connection */ ftp_pasv_verbose(conn, addr->addr, ftpc->newhost, connectport); + Curl_safefree(conn->secondaryhostname); + conn->secondaryhostname = strdup(ftpc->newhost); + conn->secondary_port = ftpc->newport; + Curl_resolv_unlock(data, addr); /* we're done using this address */ conn->bits.do_more = TRUE; state(conn, FTP_STOP); /* this phase is completed */ @@ -2763,7 +2686,10 @@ static CURLcode ftp_statemach_act(struct connectdata *conn) } #endif - if(data->set.use_ssl && !conn->ssl[FIRSTSOCKET].use) { + if(data->set.use_ssl && + (!conn->ssl[FIRSTSOCKET].use || + (conn->bits.proxy_ssl_connected[FIRSTSOCKET] && + !conn->proxy_ssl[FIRSTSOCKET].use))) { /* We don't have a SSL/TLS connection yet, but FTPS is requested. Try a FTPS connection now */ @@ -2808,7 +2734,7 @@ static CURLcode ftp_statemach_act(struct connectdata *conn) /* Curl_ssl_connect is BLOCKING */ result = Curl_ssl_connect(conn, FIRSTSOCKET); if(!result) { - conn->ssl[SECONDARYSOCKET].use = FALSE; /* clear-text data */ + conn->bits.ftp_use_data_ssl = FALSE; /* clear-text data */ result = ftp_state_user(conn); } } @@ -2850,7 +2776,7 @@ static CURLcode ftp_statemach_act(struct connectdata *conn) case FTP_PROT: if(ftpcode/100 == 2) /* We have enabled SSL for the data connection! */ - conn->ssl[SECONDARYSOCKET].use = + conn->bits.ftp_use_data_ssl = (data->set.use_ssl != CURLUSESSL_CONTROL) ? TRUE : FALSE; /* FTP servers typically responds with 500 if they decide to reject our 'P' request */ @@ -3666,10 +3592,6 @@ static CURLcode ftp_do_more(struct connectdata *conn, int *completep) /* Ready to do more? */ if(connected) { DEBUGF(infof(data, "DO-MORE connected phase starts\n")); - if(conn->bits.proxy) { - infof(data, "Connection to proxy confirmed\n"); - result = proxy_magic(conn, ftpc->newhost, ftpc->newport, &connected); - } } else { if(result && (ftpc->count1 == 0)) { @@ -3681,6 +3603,18 @@ static CURLcode ftp_do_more(struct connectdata *conn, int *completep) } } + result = Curl_proxy_connect(conn, SECONDARYSOCKET); + if(result) + return result; + + if(CONNECT_SECONDARYSOCKET_PROXY_SSL()) + return result; + + if(conn->bits.tunnel_proxy && conn->bits.httpproxy && + conn->tunnel_state[SECONDARYSOCKET] != TUNNEL_COMPLETE) + return result; + + if(ftpc->state) { /* already in a state so skip the intial commands. They are only done to kickstart the do_more state */ @@ -4246,8 +4180,8 @@ CURLcode ftp_parse_url_path(struct connectdata *conn) const char *cur_pos; const char *filename = NULL; - cur_pos = path_to_use; /* current position in path. point at the begin - of next path component */ + cur_pos = path_to_use; /* current position in path. point at the begin of + next path component */ ftpc->ctl_valid = FALSE; ftpc->cwdfail = FALSE; diff --git a/lib/getinfo.c b/lib/getinfo.c index 3186d8ac5..7dcc71d33 100644 --- a/lib/getinfo.c +++ b/lib/getinfo.c @@ -160,6 +160,9 @@ static CURLcode getinfo_long(struct Curl_easy *data, CURLINFO info, case CURLINFO_SSL_VERIFYRESULT: *param_longp = data->set.ssl.certverifyresult; break; + case CURLINFO_PROXY_SSL_VERIFYRESULT: + *param_longp = data->set.proxy_ssl.certverifyresult; + break; case CURLINFO_REDIRECT_COUNT: *param_longp = data->set.followlocation; break; diff --git a/lib/http.c b/lib/http.c index 999d6da87..36317f563 100644 --- a/lib/http.c +++ b/lib/http.c @@ -288,8 +288,8 @@ static CURLcode http_output_basic(struct connectdata *conn, bool proxy) if(proxy) { userp = &conn->allocptr.proxyuserpwd; - user = conn->proxyuser; - pwd = conn->proxypasswd; + user = conn->http_proxy.user; + pwd = conn->http_proxy.passwd; } else { userp = &conn->allocptr.userpwd; @@ -642,7 +642,7 @@ output_auth_headers(struct connectdata *conn, if(auth) { infof(data, "%s auth using %s with user '%s'\n", proxy ? "Proxy" : "Server", auth, - proxy ? (conn->proxyuser ? conn->proxyuser : "") : + proxy ? (conn->http_proxy.user ? conn->http_proxy.user : "") : (conn->user ? conn->user : "")); authstatus->multi = (!authstatus->done) ? TRUE : FALSE; } @@ -1099,7 +1099,9 @@ CURLcode Curl_add_buffer_send(Curl_send_buffer *in, return result; } - if((conn->handler->flags & PROTOPT_SSL) && conn->httpversion != 20) { + if((conn->handler->flags & PROTOPT_SSL || + conn->http_proxy.proxytype == CURLPROXY_HTTPS) + && conn->httpversion != 20) { /* We never send more than CURL_MAX_WRITE_SIZE bytes in one single chunk when we speak HTTPS, as if only a fraction of it is sent now, this data needs to fit into the normal read-callback buffer later on and that @@ -1350,10 +1352,13 @@ CURLcode Curl_http_connect(struct connectdata *conn, bool *done) connkeep(conn, "HTTP default"); /* the CONNECT procedure might not have been completed */ - result = Curl_proxy_connect(conn); + result = Curl_proxy_connect(conn, FIRSTSOCKET); if(result) return result; + if(CONNECT_FIRSTSOCKET_PROXY_SSL()) + return CURLE_OK; /* wait for HTTPS proxy SSL initialization to complete */ + if(conn->tunnel_state[FIRSTSOCKET] == TUNNEL_CONNECT) /* nothing else to do except wait right now - we're not done here. */ return CURLE_OK; @@ -1396,50 +1401,16 @@ static CURLcode https_connecting(struct connectdata *conn, bool *done) return result; } -#endif -#if defined(USE_OPENSSL) || defined(USE_GNUTLS) || defined(USE_SCHANNEL) || \ - defined(USE_DARWINSSL) || defined(USE_POLARSSL) || defined(USE_NSS) || \ - defined(USE_MBEDTLS) -/* This function is for OpenSSL, GnuTLS, darwinssl, schannel and polarssl only. - It should be made to query the generic SSL layer instead. */ static int https_getsock(struct connectdata *conn, curl_socket_t *socks, int numsocks) { - if(conn->handler->flags & PROTOPT_SSL) { - struct ssl_connect_data *connssl = &conn->ssl[FIRSTSOCKET]; - - if(!numsocks) - return GETSOCK_BLANK; - - if(connssl->connecting_state == ssl_connect_2_writing) { - /* write mode */ - socks[0] = conn->sock[FIRSTSOCKET]; - return GETSOCK_WRITESOCK(0); - } - else if(connssl->connecting_state == ssl_connect_2_reading) { - /* read mode */ - socks[0] = conn->sock[FIRSTSOCKET]; - return GETSOCK_READSOCK(0); - } - } - - return CURLE_OK; -} -#else -#ifdef USE_SSL -static int https_getsock(struct connectdata *conn, - curl_socket_t *socks, - int numsocks) -{ - (void)conn; - (void)socks; - (void)numsocks; + if(conn->handler->flags & PROTOPT_SSL) + return Curl_ssl_getsock(conn, socks, numsocks); return GETSOCK_BLANK; } #endif /* USE_SSL */ -#endif /* USE_OPENSSL || USE_GNUTLS || USE_SCHANNEL */ /* * Curl_http_done() gets called after a single HTTP request has been diff --git a/lib/http_digest.c b/lib/http_digest.c index 184d00b28..91b88a383 100644 --- a/lib/http_digest.c +++ b/lib/http_digest.c @@ -95,8 +95,8 @@ CURLcode Curl_output_digest(struct connectdata *conn, if(proxy) { digest = &data->state.proxydigest; allocuserpwd = &conn->allocptr.proxyuserpwd; - userp = conn->proxyuser; - passwdp = conn->proxypasswd; + userp = conn->http_proxy.user; + passwdp = conn->http_proxy.passwd; authp = &data->state.authproxy; } else { diff --git a/lib/http_negotiate.c b/lib/http_negotiate.c index 5ea9f3401..51375e81d 100644 --- a/lib/http_negotiate.c +++ b/lib/http_negotiate.c @@ -51,11 +51,11 @@ CURLcode Curl_input_negotiate(struct connectdata *conn, bool proxy, struct negotiatedata *neg_ctx; if(proxy) { - userp = conn->proxyuser; - passwdp = conn->proxypasswd; + userp = conn->http_proxy.user; + passwdp = conn->http_proxy.passwd; service = data->set.str[STRING_PROXY_SERVICE_NAME] ? data->set.str[STRING_PROXY_SERVICE_NAME] : "HTTP"; - host = conn->proxy.name; + host = conn->http_proxy.host.name; neg_ctx = &data->state.proxyneg; } else { diff --git a/lib/http_ntlm.c b/lib/http_ntlm.c index e424040d9..21c77cd68 100644 --- a/lib/http_ntlm.c +++ b/lib/http_ntlm.c @@ -136,8 +136,8 @@ CURLcode Curl_output_ntlm(struct connectdata *conn, bool proxy) if(proxy) { allocuserpwd = &conn->allocptr.proxyuserpwd; - userp = conn->proxyuser; - passwdp = conn->proxypasswd; + userp = conn->http_proxy.user; + passwdp = conn->http_proxy.passwd; ntlm = &conn->proxyntlm; authp = &conn->data->state.authproxy; } diff --git a/lib/http_proxy.c b/lib/http_proxy.c index 9ffd1cd46..cd4cac06d 100644 --- a/lib/http_proxy.c +++ b/lib/http_proxy.c @@ -35,14 +35,48 @@ #include "non-ascii.h" #include "connect.h" #include "curlx.h" +#include "vtls/vtls.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" #include "memdebug.h" -CURLcode Curl_proxy_connect(struct connectdata *conn) +/* + * Perform SSL initialization for HTTPS proxy. Sets + * proxy_ssl_connected connection bit when complete. Can be + * called multiple times. + */ +static CURLcode https_proxy_connect(struct connectdata *conn, int sockindex) { +#ifdef USE_SSL + CURLcode result = CURLE_OK; + DEBUGASSERT(conn->http_proxy.proxytype == CURLPROXY_HTTPS); + if(!conn->bits.proxy_ssl_connected[sockindex]) { + /* perform SSL initialization for this socket */ + result = + Curl_ssl_connect_nonblocking(conn, sockindex, + &conn->bits.proxy_ssl_connected[sockindex]); + if(result) + conn->bits.close = TRUE; /* a failed connection is marked for closure to + prevent (bad) re-use or similar */ + } + return result; +#else + return CURLE_NOT_BUILT_IN; +#endif +} + +CURLcode Curl_proxy_connect(struct connectdata *conn, int sockindex) +{ + if(conn->http_proxy.proxytype == CURLPROXY_HTTPS) { + const CURLcode result = https_proxy_connect(conn, sockindex); + if(result) + return result; + if(!conn->bits.proxy_ssl_connected[sockindex]) + return result; /* wait for HTTPS proxy SSL initialization to complete */ + } + if(conn->bits.tunnel_proxy && conn->bits.httpproxy) { #ifndef CURL_DISABLE_PROXY /* for [protocol] tunneled through HTTP proxy */ @@ -68,15 +102,20 @@ CURLcode Curl_proxy_connect(struct connectdata *conn) memset(&http_proxy, 0, sizeof(http_proxy)); conn->data->req.protop = &http_proxy; connkeep(conn, "HTTP proxy CONNECT"); - if(conn->bits.conn_to_host) + if(sockindex == SECONDARYSOCKET) + hostname = conn->secondaryhostname; + else if(conn->bits.conn_to_host) hostname = conn->conn_to_host.name; else hostname = conn->host.name; - if(conn->bits.conn_to_port) + + if(sockindex == SECONDARYSOCKET) + remote_port = conn->secondary_port; + else if(conn->bits.conn_to_port) remote_port = conn->conn_to_port; else remote_port = conn->remote_port; - result = Curl_proxyCONNECT(conn, FIRSTSOCKET, hostname, + result = Curl_proxyCONNECT(conn, sockindex, hostname, remote_port, FALSE); conn->data->req.protop = prot_save; if(CURLE_OK != result) @@ -161,7 +200,7 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn, char *host=(char *)""; const char *proxyconn=""; const char *useragent=""; - const char *http = (conn->proxytype == CURLPROXY_HTTP_1_0) ? + const char *http = (conn->http_proxy.proxytype == CURLPROXY_HTTP_1_0) ? "1.0" : "1.1"; bool ipv6_ip = conn->bits.ipv6_ip; char *hostheader; diff --git a/lib/http_proxy.h b/lib/http_proxy.h index fd0433033..d1f5a7c83 100644 --- a/lib/http_proxy.h +++ b/lib/http_proxy.h @@ -32,11 +32,11 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn, /* Default proxy timeout in milliseconds */ #define PROXY_TIMEOUT (3600*1000) -CURLcode Curl_proxy_connect(struct connectdata *conn); +CURLcode Curl_proxy_connect(struct connectdata *conn, int sockindex); #else #define Curl_proxyCONNECT(x,y,z,w,v) CURLE_NOT_BUILT_IN -#define Curl_proxy_connect(x) CURLE_OK +#define Curl_proxy_connect(x,y) CURLE_OK #endif #endif /* HEADER_CURL_HTTP_PROXY_H */ diff --git a/lib/ldap.c b/lib/ldap.c index 7dbc1b0e6..f4d57a299 100644 --- a/lib/ldap.c +++ b/lib/ldap.c @@ -271,7 +271,7 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done) ldap_set_option(server, LDAP_OPT_SSL, LDAP_OPT_ON); #else int ldap_option; - char* ldap_ca = data->set.str[STRING_SSL_CAFILE]; + char* ldap_ca = conn->ssl_config.CAfile; #if defined(CURL_HAS_NOVELL_LDAPSDK) rc = ldapssl_client_init(NULL, NULL); if(rc != LDAP_SUCCESS) { @@ -279,11 +279,11 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done) result = CURLE_SSL_CERTPROBLEM; goto quit; } - if(data->set.ssl.verifypeer) { + if(conn->ssl_config.verifypeer) { /* Novell SDK supports DER or BASE64 files. */ int cert_type = LDAPSSL_CERT_FILETYPE_B64; - if((data->set.str[STRING_CERT_TYPE]) && - (strcasecompare(data->set.str[STRING_CERT_TYPE], "DER"))) + if((data->set.ssl.cert_type) && + (strcasecompare(data->set.ssl.cert_type, "DER"))) cert_type = LDAPSSL_CERT_FILETYPE_DER; if(!ldap_ca) { failf(data, "LDAP local: ERROR %s CA cert not set!", @@ -321,10 +321,10 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done) goto quit; } #elif defined(LDAP_OPT_X_TLS) - if(data->set.ssl.verifypeer) { + if(conn->ssl_config.verifypeer) { /* OpenLDAP SDK supports BASE64 files. */ - if((data->set.str[STRING_CERT_TYPE]) && - (!strcasecompare(data->set.str[STRING_CERT_TYPE], "PEM"))) { + if((data->set.ssl.cert_type) && + (!strcasecompare(data->set.ssl.cert_type, "PEM"))) { failf(data, "LDAP local: ERROR OpenLDAP only supports PEM cert-type!"); result = CURLE_SSL_CERTPROBLEM; goto quit; diff --git a/lib/multi.c b/lib/multi.c index ca97aba84..07a903da5 100644 --- a/lib/multi.c +++ b/lib/multi.c @@ -42,6 +42,7 @@ #include "multihandle.h" #include "pipeline.h" #include "sigpipe.h" +#include "vtls/vtls.h" #include "connect.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" @@ -812,6 +813,9 @@ static int waitconnect_getsock(struct connectdata *conn, if(!numsocks) return GETSOCK_BLANK; + if(CONNECT_FIRSTSOCKET_PROXY_SSL()) + return Curl_ssl_getsock(conn, sock, numsocks); + for(i=0; i<2; i++) { if(conn->tempsock[i] != CURL_SOCKET_BAD) { sock[s] = conn->tempsock[i]; @@ -1548,7 +1552,9 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, multistate(data, CURLM_STATE_CONNECT); } else if(!result) { - if(data->easy_conn->tunnel_state[FIRSTSOCKET] == TUNNEL_COMPLETE) { + if((data->easy_conn->http_proxy.proxytype != CURLPROXY_HTTPS || + data->easy_conn->bits.proxy_ssl_connected[FIRSTSOCKET]) && + (data->easy_conn->tunnel_state[FIRSTSOCKET] != TUNNEL_CONNECT)) { rc = CURLM_CALL_MULTI_PERFORM; /* initiate protocol connect phase */ multistate(data, CURLM_STATE_SENDPROTOCONNECT); @@ -1561,6 +1567,14 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, /* awaiting a completion of an asynch TCP connect */ result = Curl_is_connected(data->easy_conn, FIRSTSOCKET, &connected); if(connected && !result) { +#ifndef CURL_DISABLE_HTTP + if((data->easy_conn->http_proxy.proxytype == CURLPROXY_HTTPS && + !data->easy_conn->bits.proxy_ssl_connected[FIRSTSOCKET]) || + (data->easy_conn->tunnel_state[FIRSTSOCKET] == TUNNEL_CONNECT)) { + multistate(data, CURLM_STATE_WAITPROXYCONNECT); + break; + } +#endif rc = CURLM_CALL_MULTI_PERFORM; multistate(data, data->easy_conn->bits.tunnel_proxy? CURLM_STATE_WAITPROXYCONNECT: diff --git a/lib/multihandle.h b/lib/multihandle.h index c56b6aec1..0b78de943 100644 --- a/lib/multihandle.h +++ b/lib/multihandle.h @@ -38,7 +38,9 @@ typedef enum { CURLM_STATE_CONNECT, /* 2 - resolve/connect has been sent off */ CURLM_STATE_WAITRESOLVE, /* 3 - awaiting the resolve to finalize */ CURLM_STATE_WAITCONNECT, /* 4 - awaiting the TCP connect to finalize */ - CURLM_STATE_WAITPROXYCONNECT, /* 5 - awaiting proxy CONNECT to finalize */ + CURLM_STATE_WAITPROXYCONNECT, /* 5 - awaiting HTTPS proxy SSL initialization + to complete and/or proxy CONNECT to + finalize */ CURLM_STATE_SENDPROTOCONNECT, /* 6 - initiate protocol connect procedure */ CURLM_STATE_PROTOCONNECT, /* 7 - completing the protocol-specific connect phase */ diff --git a/lib/pingpong.c b/lib/pingpong.c index ded17ef40..7a9935727 100644 --- a/lib/pingpong.c +++ b/lib/pingpong.c @@ -101,7 +101,9 @@ CURLcode Curl_pp_statemach(struct pingpong *pp, bool block) else interval_ms = 0; /* immediate */ - if(Curl_pp_moredata(pp)) + if(Curl_ssl_data_pending(conn, FIRSTSOCKET)) + rc = 1; + else if(Curl_pp_moredata(pp)) /* We are receiving and there is data in the cache so just read it */ rc = 1; else if(!pp->sendleft && Curl_ssl_data_pending(conn, FIRSTSOCKET)) diff --git a/lib/socks.c b/lib/socks.c index 3b28798e5..c10543734 100644 --- a/lib/socks.c +++ b/lib/socks.c @@ -109,9 +109,10 @@ CURLcode Curl_SOCKS4(const char *proxy_name, const char *hostname, int remote_port, int sockindex, - struct connectdata *conn, - bool protocol4a) + struct connectdata *conn) { + const bool protocol4a = + (conn->socks_proxy.proxytype == CURLPROXY_SOCKS4A) ? TRUE : FALSE; #define SOCKS4REQLEN 262 unsigned char socksreq[SOCKS4REQLEN]; /* room for SOCKS4 request incl. user id */ @@ -126,6 +127,10 @@ CURLcode Curl_SOCKS4(const char *proxy_name, return CURLE_OPERATION_TIMEDOUT; } + if(conn->bits.httpproxy) + infof(conn->data, "SOCKS4%s: connecting to HTTP proxy %s port %d\n", + protocol4a ? "a" : "", hostname, remote_port); + (void)curlx_nonblock(sock, FALSE); infof(data, "SOCKS4 communication to %s:%d\n", hostname, remote_port); @@ -377,10 +382,15 @@ CURLcode Curl_SOCKS5(const char *proxy_name, curl_socket_t sock = conn->sock[sockindex]; struct Curl_easy *data = conn->data; time_t timeout; - bool socks5_resolve_local = (conn->proxytype == CURLPROXY_SOCKS5)?TRUE:FALSE; + bool socks5_resolve_local = + (conn->socks_proxy.proxytype == CURLPROXY_SOCKS5) ? TRUE : FALSE; const size_t hostname_len = strlen(hostname); ssize_t len = 0; + if(conn->bits.httpproxy) + infof(conn->data, "SOCKS5: connecting to HTTP proxy %s port %d\n", + hostname, remote_port); + /* RFC1928 chapter 5 specifies max 255 chars for domain name in packet */ if(!socks5_resolve_local && hostname_len > 255) { infof(conn->data, "SOCKS5: server resolving disabled for hostnames of " diff --git a/lib/socks.h b/lib/socks.h index a44ada6be..348707e74 100644 --- a/lib/socks.h +++ b/lib/socks.h @@ -25,7 +25,7 @@ #include "curl_setup.h" #ifdef CURL_DISABLE_PROXY -#define Curl_SOCKS4(a,b,c,d,e,f) CURLE_NOT_BUILT_IN +#define Curl_SOCKS4(a,b,c,d,e) CURLE_NOT_BUILT_IN #define Curl_SOCKS5(a,b,c,d,e,f) CURLE_NOT_BUILT_IN #else /* @@ -49,8 +49,7 @@ CURLcode Curl_SOCKS4(const char *proxy_name, const char *hostname, int remote_port, int sockindex, - struct connectdata *conn, - bool protocol4a); + struct connectdata *conn); /* * This function logs in to a SOCKS5 proxy and sends the specifics to the diff --git a/lib/socks_gssapi.c b/lib/socks_gssapi.c index 369245a61..ec9ab4f1c 100644 --- a/lib/socks_gssapi.c +++ b/lib/socks_gssapi.c @@ -123,6 +123,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, unsigned char socksreq[4]; /* room for GSS-API exchange header only */ const char *serviceptr = data->set.str[STRING_PROXY_SERVICE_NAME] ? data->set.str[STRING_PROXY_SERVICE_NAME] : "rcmd"; + const size_t serviceptr_length = strlen(serviceptr); /* GSS-API request looks like * +----+------+-----+----------------+ @@ -134,22 +135,23 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, /* prepare service name */ if(strchr(serviceptr, '/')) { - service.value = malloc(strlen(serviceptr)); + service.length = serviceptr_length; + service.value = malloc(service.length); if(!service.value) return CURLE_OUT_OF_MEMORY; - service.length = strlen(serviceptr); memcpy(service.value, serviceptr, service.length); gss_major_status = gss_import_name(&gss_minor_status, &service, (gss_OID) GSS_C_NULL_OID, &server); } else { - service.value = malloc(strlen(serviceptr) +strlen(conn->proxy.name)+2); + service.value = malloc(serviceptr_length + + strlen(conn->socks_proxy.host.name)+2); if(!service.value) return CURLE_OUT_OF_MEMORY; - service.length = strlen(serviceptr) +strlen(conn->proxy.name)+1; + service.length = serviceptr_length + strlen(conn->socks_proxy.host.name)+1; snprintf(service.value, service.length+1, "%s@%s", - serviceptr, conn->proxy.name); + serviceptr, conn->socks_proxy.host.name); gss_major_status = gss_import_name(&gss_minor_status, &service, GSS_C_NT_HOSTBASED_SERVICE, &server); diff --git a/lib/socks_sspi.c b/lib/socks_sspi.c index 605349038..c671fff3b 100644 --- a/lib/socks_sspi.c +++ b/lib/socks_sspi.c @@ -86,6 +86,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, unsigned char socksreq[4]; /* room for GSS-API exchange header only */ const char *service = data->set.str[STRING_PROXY_SERVICE_NAME] ? data->set.str[STRING_PROXY_SERVICE_NAME] : "rcmd"; + const size_t service_length = strlen(service); /* GSS-API request looks like * +----+------+-----+----------------+ @@ -102,11 +103,13 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, return CURLE_OUT_OF_MEMORY; } else { - service_name = malloc(strlen(service) + strlen(conn->proxy.name) + 2); + service_name = malloc(service_length + + strlen(conn->socks_proxy.host.name) + 2); if(!service_name) return CURLE_OUT_OF_MEMORY; - snprintf(service_name, strlen(service) +strlen(conn->proxy.name)+2, - "%s/%s", service, conn->proxy.name); + snprintf(service_name, service_length + + strlen(conn->socks_proxy.host.name)+2, "%s/%s", + service, conn->socks_proxy.host.name); } input_desc.cBuffers = 1; diff --git a/lib/ssh.c b/lib/ssh.c index 420beb27e..04ca39cef 100644 --- a/lib/ssh.c +++ b/lib/ssh.c @@ -874,7 +874,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) break; } - sshc->passphrase = data->set.str[STRING_KEY_PASSWD]; + sshc->passphrase = data->set.ssl.key_passwd; if(!sshc->passphrase) sshc->passphrase = ""; diff --git a/lib/strcase.c b/lib/strcase.c index 807689ef8..ccbaac176 100644 --- a/lib/strcase.c +++ b/lib/strcase.c @@ -120,6 +120,16 @@ int Curl_strcasecompare(const char *first, const char *second) return (Curl_raw_toupper(*first) == Curl_raw_toupper(*second)); } +int Curl_safe_strcasecompare(const char *first, const char *second) +{ + if(first && second) + /* both pointers point to something then compare them */ + return Curl_strcasecompare(first, second); + else + /* if both pointers are NULL then treat them as equal */ + return (NULL == first && NULL == second); +} + /* * @unittest: 1301 */ diff --git a/lib/strcase.h b/lib/strcase.h index bf057b1ff..ea2abc8b6 100644 --- a/lib/strcase.h +++ b/lib/strcase.h @@ -36,6 +36,7 @@ #define strncasecompare(a,b,c) Curl_strncasecompare(a,b,c) int Curl_strcasecompare(const char *first, const char *second); +int Curl_safe_strcasecompare(const char *first, const char *second); int Curl_strncasecompare(const char *first, const char *second, size_t max); char Curl_raw_toupper(char in); diff --git a/lib/transfer.c b/lib/transfer.c index a2882c5c8..052ecc182 100644 --- a/lib/transfer.c +++ b/lib/transfer.c @@ -1296,7 +1296,7 @@ CURLcode Curl_pretransfer(struct Curl_easy *data) /* Init the SSL session ID cache here. We do it here since we want to do it after the *_setopt() calls (that could specify the size of the cache) but before any transfer takes place. */ - result = Curl_ssl_initsessions(data, data->set.ssl.max_ssl_sessions); + result = Curl_ssl_initsessions(data, data->set.general_ssl.max_ssl_sessions); if(result) return result; diff --git a/lib/url.c b/lib/url.c index 552be9468..15ba92cae 100644 --- a/lib/url.c +++ b/lib/url.c @@ -526,7 +526,7 @@ CURLcode Curl_init_userdefined(struct UserDefined *set) set->dns_cache_timeout = 60; /* Timeout every 60 seconds by default */ /* Set the default size of the SSL session ID cache */ - set->ssl.max_ssl_sessions = 5; + set->general_ssl.max_ssl_sessions = 5; set->proxyport = CURL_DEFAULT_PROXY_PORT; /* from url.h */ set->proxytype = CURLPROXY_HTTP; /* defaults to HTTP proxy */ @@ -540,14 +540,16 @@ CURLcode Curl_init_userdefined(struct UserDefined *set) * libcurl 7.10 introduced SSL verification *by default*! This needs to be * switched off unless wanted. */ - set->ssl.verifypeer = TRUE; - set->ssl.verifyhost = TRUE; + set->ssl.primary.verifypeer = TRUE; + set->ssl.primary.verifyhost = TRUE; #ifdef USE_TLS_SRP set->ssl.authtype = CURL_TLSAUTH_NONE; #endif set->ssh_auth_types = CURLSSH_AUTH_DEFAULT; /* defaults to any auth type */ - set->ssl.sessionid = TRUE; /* session ID caching enabled by default */ + set->general_ssl.sessionid = TRUE; /* session ID caching enabled by + default */ + set->proxy_ssl = set->ssl; set->new_file_perms = 0644; /* Default permissions */ set->new_directory_perms = 0755; /* Default permissions */ @@ -570,14 +572,17 @@ CURLcode Curl_init_userdefined(struct UserDefined *set) /* This is our preferred CA cert bundle/path since install time */ #if defined(CURL_CA_BUNDLE) - result = setstropt(&set->str[STRING_SSL_CAFILE], CURL_CA_BUNDLE); + result = setstropt(&set->str[STRING_SSL_CAFILE_ORIG], CURL_CA_BUNDLE); if(result) return result; #endif #if defined(CURL_CA_PATH) - result = setstropt(&set->str[STRING_SSL_CAPATH], CURL_CA_PATH); + result = setstropt(&set->str[STRING_SSL_CAPATH_ORIG], CURL_CA_PATH); if(result) return result; + + result = setstropt(&set->str[STRING_SSL_CAPATH_PROXY], + (char *) CURL_CA_PATH); #endif set->wildcardmatch = FALSE; @@ -697,7 +702,12 @@ CURLcode Curl_setopt(struct Curl_easy *data, CURLoption option, break; case CURLOPT_SSL_CIPHER_LIST: /* set a list of cipher we want to use in the SSL connection */ - result = setstropt(&data->set.str[STRING_SSL_CIPHER_LIST], + result = setstropt(&data->set.str[STRING_SSL_CIPHER_LIST_ORIG], + va_arg(param, char *)); + break; + case CURLOPT_PROXY_SSL_CIPHER_LIST: + /* set a list of cipher we want to use in the SSL connection for proxy */ + result = setstropt(&data->set.str[STRING_SSL_CIPHER_LIST_PROXY], va_arg(param, char *)); break; @@ -903,7 +913,18 @@ CURLcode Curl_setopt(struct Curl_easy *data, CURLoption option, * implementations are lame. */ #ifdef USE_SSL - data->set.ssl.version = va_arg(param, long); + data->set.ssl.primary.version = va_arg(param, long); +#else + result = CURLE_UNKNOWN_OPTION; +#endif + break; + case CURLOPT_PROXY_SSLVERSION: + /* + * Set explicit SSL version to try to connect with for proxy, as some SSL + * implementations are lame. + */ +#ifdef USE_SSL + data->set.proxy_ssl.primary.version = va_arg(param, long); #else result = CURLE_UNKNOWN_OPTION; #endif @@ -1437,18 +1458,30 @@ CURLcode Curl_setopt(struct Curl_easy *data, CURLoption option, case CURLOPT_PROXY: /* - * Set proxy server:port to use as HTTP proxy. + * Set proxy server:port to use as proxy. * - * If the proxy is set to "" we explicitly say that we don't want to use a - * proxy (even though there might be environment variables saying so). + * If the proxy is set to "" (and CURLOPT_SOCKS_PROXY is set to "" or NULL) + * we explicitly say that we don't want to use a proxy + * (even though there might be environment variables saying so). * * Setting it to NULL, means no proxy but allows the environment variables - * to decide for us. + * to decide for us (if CURLOPT_SOCKS_PROXY setting it to NULL). */ result = setstropt(&data->set.str[STRING_PROXY], va_arg(param, char *)); break; + case CURLOPT_SOCKS_PROXY: + /* + * Set proxy server:port to use as SOCKS proxy. + * + * If the proxy is set to "" or NULL we explicitly say that we don't want + * to use the socks proxy. + */ + result = setstropt(&data->set.str[STRING_SOCKS_PROXY], + va_arg(param, char *)); + break; + case CURLOPT_PROXYTYPE: /* * Set proxy type. HTTP/HTTP_1_0/SOCKS4/SOCKS4a/SOCKS5/SOCKS5_HOSTNAME @@ -1456,6 +1489,13 @@ CURLcode Curl_setopt(struct Curl_easy *data, CURLoption option, data->set.proxytype = (curl_proxytype)va_arg(param, long); break; + case CURLOPT_SOCKS_PROXYTYPE: + /* + * Set proxy type. SOCKS4/SOCKS4a/SOCKS5/SOCKS5_HOSTNAME + */ + data->set.socks_proxytype = (curl_proxytype)va_arg(param, long); + break; + case CURLOPT_PROXY_TRANSFER_MODE: /* * set transfer mode (;type=) when doing FTP via an HTTP proxy @@ -1913,35 +1953,70 @@ CURLcode Curl_setopt(struct Curl_easy *data, CURLoption option, /* * String that holds file name of the SSL certificate to use */ - result = setstropt(&data->set.str[STRING_CERT], + result = setstropt(&data->set.str[STRING_CERT_ORIG], + va_arg(param, char *)); + break; + case CURLOPT_PROXY_SSLCERT: + /* + * String that holds file name of the SSL certificate to use for proxy + */ + result = setstropt(&data->set.str[STRING_CERT_PROXY], va_arg(param, char *)); break; case CURLOPT_SSLCERTTYPE: /* * String that holds file type of the SSL certificate to use */ - result = setstropt(&data->set.str[STRING_CERT_TYPE], + result = setstropt(&data->set.str[STRING_CERT_TYPE_ORIG], + va_arg(param, char *)); + break; + case CURLOPT_PROXY_SSLCERTTYPE: + /* + * String that holds file type of the SSL certificate to use for proxy + */ + result = setstropt(&data->set.str[STRING_CERT_TYPE_PROXY], va_arg(param, char *)); break; case CURLOPT_SSLKEY: /* * String that holds file name of the SSL key to use */ - result = setstropt(&data->set.str[STRING_KEY], + result = setstropt(&data->set.str[STRING_KEY_ORIG], + va_arg(param, char *)); + break; + case CURLOPT_PROXY_SSLKEY: + /* + * String that holds file name of the SSL key to use for proxy + */ + result = setstropt(&data->set.str[STRING_KEY_PROXY], va_arg(param, char *)); break; case CURLOPT_SSLKEYTYPE: /* * String that holds file type of the SSL key to use */ - result = setstropt(&data->set.str[STRING_KEY_TYPE], + result = setstropt(&data->set.str[STRING_KEY_TYPE_ORIG], + va_arg(param, char *)); + break; + case CURLOPT_PROXY_SSLKEYTYPE: + /* + * String that holds file type of the SSL key to use for proxy + */ + result = setstropt(&data->set.str[STRING_KEY_TYPE_PROXY], va_arg(param, char *)); break; case CURLOPT_KEYPASSWD: /* * String that holds the SSL or SSH private key password. */ - result = setstropt(&data->set.str[STRING_KEY_PASSWD], + result = setstropt(&data->set.str[STRING_KEY_PASSWD_ORIG], + va_arg(param, char *)); + break; + case CURLOPT_PROXY_KEYPASSWD: + /* + * String that holds the SSL private key password for proxy. + */ + result = setstropt(&data->set.str[STRING_KEY_PASSWD_PROXY], va_arg(param, char *)); break; case CURLOPT_SSLENGINE: @@ -2004,7 +2079,15 @@ CURLcode Curl_setopt(struct Curl_easy *data, CURLoption option, /* * Enable peer SSL verifying. */ - data->set.ssl.verifypeer = (0 != va_arg(param, long)) ? TRUE : FALSE; + data->set.ssl.primary.verifypeer = (0 != va_arg(param, long)) ? + TRUE : FALSE; + break; + case CURLOPT_PROXY_SSL_VERIFYPEER: + /* + * Enable peer SSL verifying for proxy. + */ + data->set.proxy_ssl.primary.verifypeer = + (0 != va_arg(param, long))?TRUE:FALSE; break; case CURLOPT_SSL_VERIFYHOST: /* @@ -2022,7 +2105,25 @@ CURLcode Curl_setopt(struct Curl_easy *data, CURLoption option, return CURLE_BAD_FUNCTION_ARGUMENT; } - data->set.ssl.verifyhost = (0 != arg) ? TRUE : FALSE; + data->set.ssl.primary.verifyhost = (0 != arg) ? TRUE : FALSE; + break; + case CURLOPT_PROXY_SSL_VERIFYHOST: + /* + * Enable verification of the host name in the peer certificate for proxy + */ + arg = va_arg(param, long); + + /* Obviously people are not reading documentation and too many thought + this argument took a boolean when it wasn't and misused it. We thus ban + 1 as a sensible input and we warn about its use. Then we only have the + 2 action internally stored as TRUE. */ + + if(1 == arg) { + failf(data, "CURLOPT_SSL_VERIFYHOST no longer supports 1 as value!"); + return CURLE_BAD_FUNCTION_ARGUMENT; + } + + data->set.proxy_ssl.primary.verifyhost = (0 != arg)?TRUE:FALSE; break; case CURLOPT_SSL_VERIFYSTATUS: /* @@ -2033,7 +2134,8 @@ CURLcode Curl_setopt(struct Curl_easy *data, CURLoption option, break; } - data->set.ssl.verifystatus = (0 != va_arg(param, long)) ? TRUE : FALSE; + data->set.ssl.primary.verifystatus = (0 != va_arg(param, long)) ? + TRUE : FALSE; break; case CURLOPT_SSL_CTX_FUNCTION: #ifdef have_curlssl_ssl_ctx @@ -2089,7 +2191,15 @@ CURLcode Curl_setopt(struct Curl_easy *data, CURLoption option, /* * Set CA info for SSL connection. Specify file name of the CA certificate */ - result = setstropt(&data->set.str[STRING_SSL_CAFILE], + result = setstropt(&data->set.str[STRING_SSL_CAFILE_ORIG], + va_arg(param, char *)); + break; + case CURLOPT_PROXY_CAINFO: + /* + * Set CA info SSL connection for proxy. Specify file name of the + * CA certificate + */ + result = setstropt(&data->set.str[STRING_SSL_CAFILE_PROXY], va_arg(param, char *)); break; case CURLOPT_CAPATH: @@ -2099,7 +2209,16 @@ CURLcode Curl_setopt(struct Curl_easy *data, CURLoption option, * certificates which have been prepared using openssl c_rehash utility. */ /* This does not work on windows. */ - result = setstropt(&data->set.str[STRING_SSL_CAPATH], + result = setstropt(&data->set.str[STRING_SSL_CAPATH_ORIG], + va_arg(param, char *)); + break; + case CURLOPT_PROXY_CAPATH: + /* + * Set CA path info for SSL connection proxy. Specify directory name of the + * CA certificates which have been prepared using openssl c_rehash utility. + */ + /* This does not work on windows. */ + result = setstropt(&data->set.str[STRING_SSL_CAPATH_PROXY], va_arg(param, char *)); #else result = CURLE_NOT_BUILT_IN; @@ -2110,7 +2229,15 @@ CURLcode Curl_setopt(struct Curl_easy *data, CURLoption option, * Set CRL file info for SSL connection. Specify file name of the CRL * to check certificates revocation */ - result = setstropt(&data->set.str[STRING_SSL_CRLFILE], + result = setstropt(&data->set.str[STRING_SSL_CRLFILE_ORIG], + va_arg(param, char *)); + break; + case CURLOPT_PROXY_CRLFILE: + /* + * Set CRL file info for SSL connection for proxy. Specify file name of the + * CRL to check certificates revocation + */ + result = setstropt(&data->set.str[STRING_SSL_CRLFILE_PROXY], va_arg(param, char *)); break; case CURLOPT_ISSUERCERT: @@ -2118,7 +2245,7 @@ CURLcode Curl_setopt(struct Curl_easy *data, CURLoption option, * Set Issuer certificate file * to check certificates issuer */ - result = setstropt(&data->set.str[STRING_SSL_ISSUERCERT], + result = setstropt(&data->set.str[STRING_SSL_ISSUERCERT_ORIG], va_arg(param, char *)); break; case CURLOPT_TELNETOPTIONS: @@ -2199,7 +2326,7 @@ CURLcode Curl_setopt(struct Curl_easy *data, CURLoption option, } #endif /* CURL_DISABLE_HTTP */ if(data->share->sslsession) { - data->set.ssl.max_ssl_sessions = data->share->max_ssl_sessions; + data->set.general_ssl.max_ssl_sessions = data->share->max_ssl_sessions; data->state.session = data->share->sslsession; } Curl_share_unlock(data, CURL_LOCK_DATA_SHARE); @@ -2234,8 +2361,14 @@ CURLcode Curl_setopt(struct Curl_easy *data, CURLoption option, case CURLOPT_SSL_OPTIONS: arg = va_arg(param, long); - data->set.ssl_enable_beast = !!(arg & CURLSSLOPT_ALLOW_BEAST); - data->set.ssl_no_revoke = !!(arg & CURLSSLOPT_NO_REVOKE); + data->set.ssl.enable_beast = arg&CURLSSLOPT_ALLOW_BEAST?TRUE:FALSE; + data->set.ssl.no_revoke = !!(arg & CURLSSLOPT_NO_REVOKE); + break; + + case CURLOPT_PROXY_SSL_OPTIONS: + arg = va_arg(param, long); + data->set.proxy_ssl.enable_beast = arg&CURLSSLOPT_ALLOW_BEAST?TRUE:FALSE; + data->set.proxy_ssl.no_revoke = !!(arg & CURLSSLOPT_NO_REVOKE); break; #endif @@ -2331,7 +2464,8 @@ CURLcode Curl_setopt(struct Curl_easy *data, CURLoption option, break; case CURLOPT_SSL_SESSIONID_CACHE: - data->set.ssl.sessionid = (0 != va_arg(param, long)) ? TRUE : FALSE; + data->set.general_ssl.sessionid = (0 != va_arg(param, long)) ? + TRUE : FALSE; break; #ifdef USE_LIBSSH2 @@ -2598,23 +2732,43 @@ CURLcode Curl_setopt(struct Curl_easy *data, CURLoption option, break; #ifdef USE_TLS_SRP case CURLOPT_TLSAUTH_USERNAME: - result = setstropt(&data->set.str[STRING_TLSAUTH_USERNAME], + result = setstropt(&data->set.str[STRING_TLSAUTH_USERNAME_ORIG], va_arg(param, char *)); - if(data->set.str[STRING_TLSAUTH_USERNAME] && !data->set.ssl.authtype) + if(data->set.str[STRING_TLSAUTH_USERNAME_ORIG] && !data->set.ssl.authtype) data->set.ssl.authtype = CURL_TLSAUTH_SRP; /* default to SRP */ break; - case CURLOPT_TLSAUTH_PASSWORD: - result = setstropt(&data->set.str[STRING_TLSAUTH_PASSWORD], + case CURLOPT_PROXY_TLSAUTH_USERNAME: + result = setstropt(&data->set.str[STRING_TLSAUTH_USERNAME_PROXY], va_arg(param, char *)); - if(data->set.str[STRING_TLSAUTH_USERNAME] && !data->set.ssl.authtype) + if(data->set.str[STRING_TLSAUTH_USERNAME_PROXY] && + !data->set.proxy_ssl.authtype) + data->set.proxy_ssl.authtype = CURL_TLSAUTH_SRP; /* default to SRP */ + break; + case CURLOPT_TLSAUTH_PASSWORD: + result = setstropt(&data->set.str[STRING_TLSAUTH_PASSWORD_ORIG], + va_arg(param, char *)); + if(data->set.str[STRING_TLSAUTH_USERNAME_ORIG] && !data->set.ssl.authtype) data->set.ssl.authtype = CURL_TLSAUTH_SRP; /* default to SRP */ break; + case CURLOPT_PROXY_TLSAUTH_PASSWORD: + result = setstropt(&data->set.str[STRING_TLSAUTH_PASSWORD_PROXY], + va_arg(param, char *)); + if(data->set.str[STRING_TLSAUTH_USERNAME_PROXY] && + !data->set.proxy_ssl.authtype) + data->set.proxy_ssl.authtype = CURL_TLSAUTH_SRP; /* default to SRP */ + break; case CURLOPT_TLSAUTH_TYPE: if(strncasecompare((char *)va_arg(param, char *), "SRP", strlen("SRP"))) data->set.ssl.authtype = CURL_TLSAUTH_SRP; else data->set.ssl.authtype = CURL_TLSAUTH_NONE; break; + case CURLOPT_PROXY_TLSAUTH_TYPE: + if(strncasecompare((char *)va_arg(param, char *), "SRP", strlen("SRP"))) + data->set.proxy_ssl.authtype = CURL_TLSAUTH_SRP; + else + data->set.proxy_ssl.authtype = CURL_TLSAUTH_NONE; + break; #endif case CURLOPT_DNS_SERVERS: result = Curl_set_dns_servers(data, va_arg(param, char *)); @@ -2771,8 +2925,10 @@ static void conn_free(struct connectdata *conn) Curl_safefree(conn->passwd); Curl_safefree(conn->oauth_bearer); Curl_safefree(conn->options); - Curl_safefree(conn->proxyuser); - Curl_safefree(conn->proxypasswd); + Curl_safefree(conn->http_proxy.user); + Curl_safefree(conn->socks_proxy.user); + Curl_safefree(conn->http_proxy.passwd); + Curl_safefree(conn->socks_proxy.passwd); Curl_safefree(conn->allocptr.proxyuserpwd); Curl_safefree(conn->allocptr.uagent); Curl_safefree(conn->allocptr.userpwd); @@ -2786,7 +2942,9 @@ static void conn_free(struct connectdata *conn) Curl_safefree(conn->trailer); Curl_safefree(conn->host.rawalloc); /* host name buffer */ Curl_safefree(conn->conn_to_host.rawalloc); /* host name buffer */ - Curl_safefree(conn->proxy.rawalloc); /* proxy name buffer */ + Curl_safefree(conn->secondaryhostname); + Curl_safefree(conn->http_proxy.host.rawalloc); /* http proxy name buffer */ + Curl_safefree(conn->socks_proxy.host.rawalloc); /* socks proxy name buffer */ Curl_safefree(conn->master_buffer); conn_reset_all_postponed_data(conn); @@ -2798,7 +2956,8 @@ static void conn_free(struct connectdata *conn) conn->recv_pipe = NULL; Curl_safefree(conn->localdev); - Curl_free_ssl_config(&conn->ssl_config); + Curl_free_primary_ssl_config(&conn->ssl_config); + Curl_free_primary_ssl_config(&conn->proxy_ssl_config); #ifdef USE_UNIX_SOCKETS Curl_safefree(conn->unix_domain_socket); @@ -2863,6 +3022,8 @@ CURLcode Curl_disconnect(struct connectdata *conn, bool dead_connection) free_fixed_hostname(&conn->host); free_fixed_hostname(&conn->conn_to_host); free_fixed_hostname(&conn->proxy); + free_fixed_hostname(&conn->http_proxy.host); + free_fixed_hostname(&conn->socks_proxy.host); Curl_ssl_close(conn, FIRSTSOCKET); @@ -3059,6 +3220,21 @@ Curl_oldest_idle_connection(struct Curl_easy *data) return conn_candidate; } +static bool +proxy_info_matches(const struct proxy_info* data, + const struct proxy_info* needle) +{ + if((data->proxytype == needle->proxytype) && + (data->port == needle->port) && + Curl_safe_strcasecompare(data->host.name, needle->host.name) && + Curl_safe_strcasecompare(data->user, needle->user) && + Curl_safe_strcasecompare(data->passwd, needle->passwd)) + return TRUE; + + return FALSE; +} + + /* * This function finds the connection in the connection * bundle that has been unused for the longest time. @@ -3352,23 +3528,12 @@ ConnectionExists(struct Curl_easy *data, /* except protocols that have been upgraded via TLS */ continue; - if(needle->handler->flags&PROTOPT_SSL) { - if((data->set.ssl.verifypeer != check->verifypeer) || - (data->set.ssl.verifyhost != check->verifyhost)) - continue; - } - - if(needle->bits.proxy != check->bits.proxy) - /* don't do mixed proxy and non-proxy connections */ + if(needle->bits.httpproxy != check->bits.httpproxy || + needle->bits.socksproxy != check->bits.socksproxy) continue; - if(needle->bits.proxy && - (needle->proxytype != check->proxytype || - needle->bits.httpproxy != check->bits.httpproxy || - needle->bits.tunnel_proxy != check->bits.tunnel_proxy || - !strcasecompare(needle->proxy.name, check->proxy.name) || - needle->port != check->port)) - /* don't mix connections that use different proxies */ + if(needle->bits.socksproxy && !proxy_info_matches(&needle->socks_proxy, + &check->socks_proxy)) continue; if(needle->bits.conn_to_host != check->bits.conn_to_host) @@ -3381,6 +3546,33 @@ ConnectionExists(struct Curl_easy *data, * connections that don't use this feature */ continue; + if(needle->bits.httpproxy) { + if(!proxy_info_matches(&needle->http_proxy, &check->http_proxy)) + continue; + + if(needle->bits.tunnel_proxy != check->bits.tunnel_proxy) + continue; + + if(needle->http_proxy.proxytype == CURLPROXY_HTTPS) { + /* use https proxy */ + if(needle->handler->flags&PROTOPT_SSL) { + /* use double layer ssl */ + if(!Curl_ssl_config_matches(&needle->proxy_ssl_config, + &check->proxy_ssl_config)) + continue; + if(check->proxy_ssl[FIRSTSOCKET].state != ssl_connection_complete) + continue; + } + else { + if(!Curl_ssl_config_matches(&needle->ssl_config, + &check->ssl_config)) + continue; + if(check->ssl[FIRSTSOCKET].state != ssl_connection_complete) + continue; + } + } + } + if(!canPipeline && check->inuse) /* this request can't be pipelined but the checked connection is already in use so we skip it */ @@ -3416,10 +3608,11 @@ ConnectionExists(struct Curl_easy *data, } if(!needle->bits.httpproxy || (needle->handler->flags&PROTOPT_SSL) || - (needle->bits.httpproxy && needle->bits.tunnel_proxy)) { + needle->bits.tunnel_proxy) { /* The requested connection does not use a HTTP proxy or it uses SSL or - it is a non-SSL protocol tunneled over the same HTTP proxy name and - port number */ + it is a non-SSL protocol tunneled or it is a non-SSL protocol which + is allowed to be upgraded via TLS */ + if((strcasecompare(needle->handler->scheme, check->handler->scheme) || (get_protocol_family(check->handler->protocol) == needle->handler->protocol && check->tls_upgraded)) && @@ -3480,12 +3673,13 @@ ConnectionExists(struct Curl_easy *data, /* Same for Proxy NTLM authentication */ if(wantProxyNTLMhttp) { - /* Both check->proxyuser and check->proxypasswd can be NULL */ - if(!check->proxyuser || !check->proxypasswd) + /* Both check->http_proxy.user and check->http_proxy.passwd can be + * NULL */ + if(!check->http_proxy.user || !check->http_proxy.passwd) continue; - if(strcmp(needle->proxyuser, check->proxyuser) || - strcmp(needle->proxypasswd, check->proxypasswd)) + if(strcmp(needle->http_proxy.user, check->http_proxy.user) || + strcmp(needle->http_proxy.passwd, check->http_proxy.passwd)) continue; } else if(check->proxyntlm.state != NTLMSTATE_NONE) { @@ -3589,51 +3783,50 @@ ConnectionExists(struct Curl_easy *data, Note: this function's sub-functions call failf() */ -CURLcode Curl_connected_proxy(struct connectdata *conn, - int sockindex) +CURLcode Curl_connected_proxy(struct connectdata *conn, int sockindex) { - if(!conn->bits.proxy || sockindex) + CURLcode result = CURLE_OK; + /* if(!conn->bits.proxy || sockindex) */ /* this magic only works for the primary socket as the secondary is used for FTP only and it has FTP specific magic in ftp.c */ - return CURLE_OK; + /* return CURLE_OK; */ - switch(conn->proxytype) { + if(conn->bits.socksproxy) { #ifndef CURL_DISABLE_PROXY - case CURLPROXY_SOCKS5: - case CURLPROXY_SOCKS5_HOSTNAME: - return Curl_SOCKS5(conn->proxyuser, conn->proxypasswd, - conn->bits.conn_to_host ? conn->conn_to_host.name : - conn->host.name, - conn->bits.conn_to_port ? conn->conn_to_port : - conn->remote_port, - FIRSTSOCKET, conn); + const char * const host = conn->bits.conn_to_host ? + conn->conn_to_host.name : + conn->bits.httpproxy ? + conn->http_proxy.host.name : + sockindex == SECONDARYSOCKET ? + conn->secondaryhostname : conn->host.name; + const int port = conn->bits.conn_to_port ? conn->conn_to_port : + conn->bits.httpproxy ? + (int)conn->http_proxy.port : + sockindex == SECONDARYSOCKET ? + conn->secondary_port : conn->remote_port; + conn->bits.socksproxy_connecting = TRUE; + switch(conn->socks_proxy.proxytype) { + case CURLPROXY_SOCKS5: + case CURLPROXY_SOCKS5_HOSTNAME: + result = Curl_SOCKS5(conn->socks_proxy.user, conn->socks_proxy.passwd, + host, port, sockindex, conn); + break; - case CURLPROXY_SOCKS4: - return Curl_SOCKS4(conn->proxyuser, - conn->bits.conn_to_host ? conn->conn_to_host.name : - conn->host.name, - conn->bits.conn_to_port ? conn->conn_to_port : - conn->remote_port, - FIRSTSOCKET, conn, FALSE); - - case CURLPROXY_SOCKS4A: - return Curl_SOCKS4(conn->proxyuser, - conn->bits.conn_to_host ? conn->conn_to_host.name : - conn->host.name, - conn->bits.conn_to_port ? conn->conn_to_port : - conn->remote_port, - FIRSTSOCKET, conn, TRUE); + case CURLPROXY_SOCKS4: + case CURLPROXY_SOCKS4A: + result = Curl_SOCKS4(conn->socks_proxy.user, host, port, sockindex, + conn); + break; + default: + failf(conn->data, "unknown proxytype option given"); + result = CURLE_COULDNT_CONNECT; + } /* switch proxytype */ + conn->bits.socksproxy_connecting = FALSE; #endif /* CURL_DISABLE_PROXY */ - case CURLPROXY_HTTP: - case CURLPROXY_HTTP_1_0: - /* do nothing here. handled later. */ - break; - default: - break; - } /* switch proxytype */ + } - return CURLE_OK; + return result; } /* @@ -3644,7 +3837,9 @@ void Curl_verboseconnect(struct connectdata *conn) { if(conn->data->set.verbose) infof(conn->data, "Connected to %s (%s) port %ld (#%ld)\n", - conn->bits.proxy ? conn->proxy.dispname : conn->host.dispname, + conn->bits.socksproxy ? conn->socks_proxy.host.dispname : + conn->bits.httpproxy ? conn->http_proxy.host.dispname : + conn->host.dispname, conn->ip_addr_str, conn->port, conn->connection_id); } #endif @@ -3734,10 +3929,14 @@ CURLcode Curl_protocol_connect(struct connectdata *conn, if(!conn->bits.protoconnstart) { - result = Curl_proxy_connect(conn); + result = Curl_proxy_connect(conn, FIRSTSOCKET); if(result) return result; + if(CONNECT_FIRSTSOCKET_PROXY_SSL()) + /* wait for HTTPS proxy SSL initialization to complete */ + return CURLE_OK; + if(conn->bits.tunnel_proxy && conn->bits.httpproxy && (conn->tunnel_state[FIRSTSOCKET] != TUNNEL_COMPLETE)) /* when using an HTTP tunnel proxy, await complete tunnel establishment @@ -3896,12 +4095,14 @@ static struct connectdata *allocate_conn(struct Curl_easy *data) conn->data = data; /* Setup the association between this connection and the Curl_easy */ - conn->proxytype = data->set.proxytype; /* type */ + conn->http_proxy.proxytype = data->set.proxytype; + conn->socks_proxy.proxytype = data->set.socks_proxytype; #ifdef CURL_DISABLE_PROXY conn->bits.proxy = FALSE; conn->bits.httpproxy = FALSE; + conn->bits.socksproxy = FALSE; conn->bits.proxy_user_passwd = FALSE; conn->bits.tunnel_proxy = FALSE; @@ -3912,11 +4113,20 @@ static struct connectdata *allocate_conn(struct Curl_easy *data) conn->bits.proxy = (data->set.str[STRING_PROXY] && *data->set.str[STRING_PROXY]) ? TRUE : FALSE; conn->bits.httpproxy = (conn->bits.proxy && - (conn->proxytype == CURLPROXY_HTTP || - conn->proxytype == CURLPROXY_HTTP_1_0)) ? - TRUE : FALSE; - conn->bits.proxy_user_passwd = (data->set.str[STRING_PROXYUSERNAME]) ? - TRUE : FALSE; + (conn->http_proxy.proxytype == CURLPROXY_HTTP || + conn->http_proxy.proxytype == CURLPROXY_HTTP_1_0 || + conn->http_proxy.proxytype == CURLPROXY_HTTPS)) ? + TRUE : FALSE; + conn->bits.socksproxy = (conn->bits.proxy && + !conn->bits.httpproxy) ? TRUE : FALSE; + + if(data->set.str[STRING_SOCKS_PROXY] && *data->set.str[STRING_SOCKS_PROXY]) { + conn->bits.proxy = TRUE; + conn->bits.socksproxy = TRUE; + } + + conn->bits.proxy_user_passwd = + (data->set.str[STRING_PROXYUSERNAME]) ? TRUE : FALSE; conn->bits.tunnel_proxy = data->set.tunnel_thru_httpproxy; #endif /* CURL_DISABLE_PROXY */ @@ -3925,8 +4135,10 @@ static struct connectdata *allocate_conn(struct Curl_easy *data) conn->bits.ftp_use_epsv = data->set.ftp_use_epsv; conn->bits.ftp_use_eprt = data->set.ftp_use_eprt; - conn->verifypeer = data->set.ssl.verifypeer; - conn->verifyhost = data->set.ssl.verifyhost; + conn->ssl_config.verifypeer = data->set.ssl.primary.verifypeer; + conn->ssl_config.verifyhost = data->set.ssl.primary.verifyhost; + conn->proxy_ssl_config.verifypeer = data->set.proxy_ssl.primary.verifypeer; + conn->proxy_ssl_config.verifyhost = data->set.proxy_ssl.primary.verifyhost; conn->ip_version = data->set.ipver; @@ -4658,7 +4870,8 @@ static char *detect_proxy(struct connectdata *conn) * that may exist registered to the same proxy host. */ static CURLcode parse_proxy(struct Curl_easy *data, - struct connectdata *conn, char *proxy) + struct connectdata *conn, char *proxy, + curl_proxytype proxytype) { char *prox_portno; char *endofprot; @@ -4667,6 +4880,10 @@ static CURLcode parse_proxy(struct Curl_easy *data, char *proxyptr; char *portptr; char *atsign; + long port = -1; + char *proxyuser = NULL; + char *proxypasswd = NULL; + bool sockstype; /* We do the proxy host string parsing here. We want the host name and the * port name. Accept a protocol:// prefix @@ -4676,14 +4893,16 @@ static CURLcode parse_proxy(struct Curl_easy *data, endofprot = strstr(proxy, "://"); if(endofprot) { proxyptr = endofprot+3; - if(checkprefix("socks5h", proxy)) - conn->proxytype = CURLPROXY_SOCKS5_HOSTNAME; + if(checkprefix("https", proxy)) + proxytype = CURLPROXY_HTTPS; + else if(checkprefix("socks5h", proxy)) + proxytype = CURLPROXY_SOCKS5_HOSTNAME; else if(checkprefix("socks5", proxy)) - conn->proxytype = CURLPROXY_SOCKS5; + proxytype = CURLPROXY_SOCKS5; else if(checkprefix("socks4a", proxy)) - conn->proxytype = CURLPROXY_SOCKS4A; + proxytype = CURLPROXY_SOCKS4A; else if(checkprefix("socks4", proxy) || checkprefix("socks", proxy)) - conn->proxytype = CURLPROXY_SOCKS4; + proxytype = CURLPROXY_SOCKS4; else if(checkprefix("http:", proxy)) ; /* leave it as HTTP or HTTP/1.0 */ else { @@ -4695,54 +4914,20 @@ static CURLcode parse_proxy(struct Curl_easy *data, else proxyptr = proxy; /* No xxx:// head: It's a HTTP proxy */ + sockstype = proxytype == CURLPROXY_SOCKS5_HOSTNAME || + proxytype == CURLPROXY_SOCKS5 || + proxytype == CURLPROXY_SOCKS4A || + proxytype == CURLPROXY_SOCKS4; + /* Is there a username and password given in this proxy url? */ atsign = strchr(proxyptr, '@'); if(atsign) { - char *proxyuser = NULL; - char *proxypasswd = NULL; CURLcode result = parse_login_details(proxyptr, atsign - proxyptr, - &proxyuser, &proxypasswd, NULL); - if(!result) { - /* found user and password, rip them out. note that we are - unescaping them, as there is otherwise no way to have a - username or password with reserved characters like ':' in - them. */ - Curl_safefree(conn->proxyuser); - if(proxyuser && strlen(proxyuser) < MAX_CURL_USER_LENGTH) - result = Curl_urldecode(data, proxyuser, 0, &conn->proxyuser, NULL, - FALSE); - else { - conn->proxyuser = strdup(""); - if(!conn->proxyuser) - result = CURLE_OUT_OF_MEMORY; - } - - if(!result) { - Curl_safefree(conn->proxypasswd); - if(proxypasswd && strlen(proxypasswd) < MAX_CURL_PASSWORD_LENGTH) - result = Curl_urldecode(data, proxypasswd, 0, - &conn->proxypasswd, NULL, FALSE); - else { - conn->proxypasswd = strdup(""); - if(!conn->proxypasswd) - result = CURLE_OUT_OF_MEMORY; - } - } - - if(!result) { - conn->bits.proxy_user_passwd = TRUE; /* enable it */ - atsign++; /* the right side of the @-letter */ - - proxyptr = atsign; /* now use this instead */ - } - } - - free(proxyuser); - free(proxypasswd); - + &proxyuser, &proxypasswd, NULL); if(result) return result; + proxyptr = atsign + 1; } /* start scanning for port number at this point */ @@ -4779,7 +4964,7 @@ static CURLcode parse_proxy(struct Curl_easy *data, prox_portno = strchr(portptr, ':'); if(prox_portno) { char *endp = NULL; - long port = 0; + *prox_portno = 0x0; /* cut off number from host name */ prox_portno ++; /* now set the local port number */ @@ -4813,15 +4998,53 @@ static CURLcode parse_proxy(struct Curl_easy *data, if(data->set.proxyport) /* None given in the proxy string, then get the default one if it is given */ - conn->port = data->set.proxyport; + port = data->set.proxyport; } - /* now, clone the cleaned proxy host name */ - conn->proxy.rawalloc = strdup(proxyptr); - conn->proxy.name = conn->proxy.rawalloc; + if(*proxyptr) { + struct proxy_info *proxyinfo = + sockstype ? &conn->socks_proxy : &conn->http_proxy; + proxyinfo->proxytype = proxytype; - if(!conn->proxy.rawalloc) - return CURLE_OUT_OF_MEMORY; + if(proxyuser) { + /* found user and password, rip them out. note that we are unescaping + them, as there is otherwise no way to have a username or password + with reserved characters like ':' in them. */ + Curl_safefree(proxyinfo->user); + proxyinfo->user = curl_easy_unescape(data, proxyuser, 0, NULL); + + if(!proxyinfo->user) + return CURLE_OUT_OF_MEMORY; + + Curl_safefree(proxyinfo->passwd); + if(proxypasswd && strlen(proxypasswd) < MAX_CURL_PASSWORD_LENGTH) + proxyinfo->passwd = curl_easy_unescape(data, proxypasswd, 0, NULL); + else + proxyinfo->passwd = strdup(""); + + if(!proxyinfo->passwd) + return CURLE_OUT_OF_MEMORY; + + conn->bits.proxy_user_passwd = TRUE; /* enable it */ + } + + if(port >= 0) { + proxyinfo->port = port; + if(conn->port < 0 || sockstype || !conn->socks_proxy.host.rawalloc) + conn->port = port; + } + + /* now, clone the cleaned proxy host name */ + Curl_safefree(proxyinfo->host.rawalloc); + proxyinfo->host.rawalloc = strdup(proxyptr); + proxyinfo->host.name = proxyinfo->host.rawalloc; + + if(!proxyinfo->host.rawalloc) + return CURLE_OUT_OF_MEMORY; + } + + Curl_safefree(proxyuser); + Curl_safefree(proxypasswd); return CURLE_OK; } @@ -4847,10 +5070,11 @@ static CURLcode parse_proxy_auth(struct Curl_easy *data, proxypasswd[MAX_CURL_PASSWORD_LENGTH-1] = '\0'; /*To be on safe side*/ } - result = Curl_urldecode(data, proxyuser, 0, &conn->proxyuser, NULL, FALSE); + result = Curl_urldecode(data, proxyuser, 0, &conn->http_proxy.user, NULL, + FALSE); if(!result) - result = Curl_urldecode(data, proxypasswd, 0, &conn->proxypasswd, NULL, - FALSE); + result = Curl_urldecode(data, proxypasswd, 0, &conn->http_proxy.passwd, + NULL, FALSE); return result; } #endif /* CURL_DISABLE_PROXY */ @@ -5578,7 +5802,7 @@ static CURLcode resolve_server(struct Curl_easy *data, } else #endif - if(!conn->proxy.name || !*conn->proxy.name) { + if(!conn->bits.proxy) { struct hostname *connhost; if(conn->bits.conn_to_host) connhost = &conn->conn_to_host; @@ -5610,8 +5834,11 @@ static CURLcode resolve_server(struct Curl_easy *data, else { /* This is a proxy that hasn't been resolved yet. */ + struct hostname * const host = conn->bits.socksproxy ? + &conn->socks_proxy.host : &conn->http_proxy.host; + /* resolve proxy */ - rc = Curl_resolv_timeout(conn, conn->proxy.name, (int)conn->port, + rc = Curl_resolv_timeout(conn, host->name, (int)conn->port, &hostaddr, timeout_ms); if(rc == CURLRESOLV_PENDING) @@ -5621,7 +5848,7 @@ static CURLcode resolve_server(struct Curl_easy *data, result = CURLE_OPERATION_TIMEDOUT; else if(!hostaddr) { - failf(data, "Couldn't resolve proxy '%s'", conn->proxy.dispname); + failf(data, "Couldn't resolve proxy '%s'", host->dispname); result = CURLE_COULDNT_RESOLVE_PROXY; /* don't return yet, we need to clean up the timeout first */ } @@ -5641,12 +5868,18 @@ static CURLcode resolve_server(struct Curl_easy *data, static void reuse_conn(struct connectdata *old_conn, struct connectdata *conn) { + free_fixed_hostname(&old_conn->http_proxy.host); + free_fixed_hostname(&old_conn->socks_proxy.host); free_fixed_hostname(&old_conn->proxy); + + free(old_conn->http_proxy.host.rawalloc); + free(old_conn->socks_proxy.host.rawalloc); free(old_conn->proxy.rawalloc); /* free the SSL config struct from this connection struct as this was allocated in vain and is targeted for destruction */ - Curl_free_ssl_config(&old_conn->ssl_config); + Curl_free_primary_ssl_config(&old_conn->ssl_config); + Curl_free_primary_ssl_config(&old_conn->proxy_ssl_config); conn->data = old_conn->data; @@ -5666,12 +5899,18 @@ static void reuse_conn(struct connectdata *old_conn, conn->bits.proxy_user_passwd = old_conn->bits.proxy_user_passwd; if(conn->bits.proxy_user_passwd) { /* use the new proxy user name and proxy password though */ - Curl_safefree(conn->proxyuser); - Curl_safefree(conn->proxypasswd); - conn->proxyuser = old_conn->proxyuser; - conn->proxypasswd = old_conn->proxypasswd; - old_conn->proxyuser = NULL; - old_conn->proxypasswd = NULL; + Curl_safefree(conn->http_proxy.user); + Curl_safefree(conn->socks_proxy.user); + Curl_safefree(conn->http_proxy.passwd); + Curl_safefree(conn->socks_proxy.passwd); + conn->http_proxy.user = old_conn->http_proxy.user; + conn->socks_proxy.user = old_conn->socks_proxy.user; + conn->http_proxy.passwd = old_conn->http_proxy.passwd; + conn->socks_proxy.passwd = old_conn->socks_proxy.passwd; + old_conn->http_proxy.user = NULL; + old_conn->socks_proxy.user = NULL; + old_conn->http_proxy.passwd = NULL; + old_conn->socks_proxy.passwd = NULL; } /* host can change, when doing keepalive with a proxy or if the case is @@ -5697,8 +5936,10 @@ static void reuse_conn(struct connectdata *old_conn, Curl_safefree(old_conn->user); Curl_safefree(old_conn->passwd); - Curl_safefree(old_conn->proxyuser); - Curl_safefree(old_conn->proxypasswd); + Curl_safefree(old_conn->http_proxy.user); + Curl_safefree(old_conn->socks_proxy.user); + Curl_safefree(old_conn->http_proxy.passwd); + Curl_safefree(old_conn->socks_proxy.passwd); Curl_safefree(old_conn->localdev); Curl_llist_destroy(old_conn->send_pipe, NULL); @@ -5743,6 +5984,7 @@ static CURLcode create_conn(struct Curl_easy *data, char *options = NULL; bool reuse; char *proxy = NULL; + char *socksproxy = NULL; bool prot_missing = FALSE; bool connections_available = TRUE; bool force_reuse = FALSE; @@ -5909,12 +6151,22 @@ static CURLcode create_conn(struct Curl_easy *data, } } + if(data->set.str[STRING_SOCKS_PROXY]) { + socksproxy = strdup(data->set.str[STRING_SOCKS_PROXY]); + /* if global socks proxy is set, this is it */ + if(NULL == socksproxy) { + failf(data, "memory shortage"); + result = CURLE_OUT_OF_MEMORY; + goto out; + } + } + if(data->set.str[STRING_NOPROXY] && check_noproxy(conn->host.name, data->set.str[STRING_NOPROXY])) { - free(proxy); /* proxy is in exception list */ - proxy = NULL; + Curl_safefree(proxy); + Curl_safefree(socksproxy); } - else if(!proxy) + else if(!proxy && !socksproxy) proxy = detect_proxy(conn); #ifdef USE_UNIX_SOCKETS @@ -5936,23 +6188,36 @@ static CURLcode create_conn(struct Curl_easy *data, protocol doesn't work with network */ proxy = NULL; } + if(socksproxy && (!*socksproxy || + (conn->handler->flags & PROTOPT_NONETWORK))) { + free(socksproxy); /* Don't bother with an empty socks proxy string or if + the protocol doesn't work with network */ + socksproxy = NULL; + } /*********************************************************************** * If this is supposed to use a proxy, we need to figure out the proxy host * name, proxy type and port number, so that we can re-use an existing * connection that may exist registered to the same proxy host. ***********************************************************************/ - if(proxy) { - result = parse_proxy(data, conn, proxy); + if(proxy || socksproxy) { + if(proxy) { + result = parse_proxy(data, conn, proxy, conn->http_proxy.proxytype); + Curl_safefree(proxy); /* parse_proxy copies the proxy string */ + if(result) + goto out; + } - free(proxy); /* parse_proxy copies the proxy string */ - proxy = NULL; + if(socksproxy) { + result = parse_proxy(data, conn, socksproxy, + conn->socks_proxy.proxytype); + /* parse_proxy copies the socks proxy string */ + Curl_safefree(socksproxy); + if(result) + goto out; + } - if(result) - goto out; - - if((conn->proxytype == CURLPROXY_HTTP) || - (conn->proxytype == CURLPROXY_HTTP_1_0)) { + if(conn->http_proxy.host.rawalloc) { #ifdef CURL_DISABLE_HTTP /* asking for a HTTP proxy is a bit funny when HTTP is disabled... */ result = CURLE_UNSUPPORTED_PROTOCOL; @@ -5971,12 +6236,34 @@ static CURLcode create_conn(struct Curl_easy *data, conn->bits.httpproxy = FALSE; /* not a HTTP proxy */ conn->bits.tunnel_proxy = FALSE; /* no tunneling if not HTTP */ } - conn->bits.proxy = TRUE; + + if(conn->socks_proxy.host.rawalloc) { + if(!conn->http_proxy.host.rawalloc) { + /* once a socks proxy */ + if(!conn->socks_proxy.user) { + conn->socks_proxy.user = conn->http_proxy.user; + conn->http_proxy.user = NULL; + Curl_safefree(conn->socks_proxy.passwd); + conn->socks_proxy.passwd = conn->http_proxy.passwd; + conn->http_proxy.passwd = NULL; + } + } + conn->bits.socksproxy = TRUE; + } + else + conn->bits.socksproxy = FALSE; /* not a socks proxy */ } else { + conn->bits.socksproxy = FALSE; + conn->bits.httpproxy = FALSE; + } + conn->bits.proxy = conn->bits.httpproxy || conn->bits.socksproxy; + + if(!conn->bits.proxy) { /* we aren't using the proxy after all... */ conn->bits.proxy = FALSE; conn->bits.httpproxy = FALSE; + conn->bits.socksproxy = FALSE; conn->bits.proxy_user_passwd = FALSE; conn->bits.tunnel_proxy = FALSE; } @@ -6112,20 +6399,51 @@ static CURLcode create_conn(struct Curl_easy *data, that will be freed as part of the Curl_easy struct, but all cloned copies will be separately allocated. */ - data->set.ssl.CApath = data->set.str[STRING_SSL_CAPATH]; - data->set.ssl.CAfile = data->set.str[STRING_SSL_CAFILE]; - data->set.ssl.CRLfile = data->set.str[STRING_SSL_CRLFILE]; - data->set.ssl.issuercert = data->set.str[STRING_SSL_ISSUERCERT]; - data->set.ssl.random_file = data->set.str[STRING_SSL_RANDOM_FILE]; - data->set.ssl.egdsocket = data->set.str[STRING_SSL_EGDSOCKET]; - data->set.ssl.cipher_list = data->set.str[STRING_SSL_CIPHER_LIST]; - data->set.ssl.clientcert = data->set.str[STRING_CERT]; + data->set.ssl.primary.CApath = data->set.str[STRING_SSL_CAPATH_ORIG]; + data->set.proxy_ssl.primary.CApath = data->set.str[STRING_SSL_CAPATH_PROXY]; + data->set.ssl.primary.CAfile = data->set.str[STRING_SSL_CAFILE_ORIG]; + data->set.proxy_ssl.primary.CAfile = data->set.str[STRING_SSL_CAFILE_PROXY]; + data->set.ssl.primary.random_file = data->set.str[STRING_SSL_RANDOM_FILE]; + data->set.proxy_ssl.primary.random_file = + data->set.str[STRING_SSL_RANDOM_FILE]; + data->set.ssl.primary.egdsocket = data->set.str[STRING_SSL_EGDSOCKET]; + data->set.proxy_ssl.primary.egdsocket = data->set.str[STRING_SSL_EGDSOCKET]; + data->set.ssl.primary.cipher_list = + data->set.str[STRING_SSL_CIPHER_LIST_ORIG]; + data->set.proxy_ssl.primary.cipher_list = + data->set.str[STRING_SSL_CIPHER_LIST_PROXY]; + + data->set.ssl.CRLfile = data->set.str[STRING_SSL_CRLFILE_ORIG]; + data->set.proxy_ssl.CRLfile = data->set.str[STRING_SSL_CRLFILE_PROXY]; + data->set.ssl.issuercert = data->set.str[STRING_SSL_ISSUERCERT_ORIG]; + data->set.proxy_ssl.issuercert = data->set.str[STRING_SSL_ISSUERCERT_PROXY]; + data->set.ssl.cert = data->set.str[STRING_CERT_ORIG]; + data->set.proxy_ssl.cert = data->set.str[STRING_CERT_PROXY]; + data->set.ssl.cert_type = data->set.str[STRING_CERT_TYPE_ORIG]; + data->set.proxy_ssl.cert_type = data->set.str[STRING_CERT_TYPE_PROXY]; + data->set.ssl.key = data->set.str[STRING_KEY_ORIG]; + data->set.proxy_ssl.key = data->set.str[STRING_KEY_PROXY]; + data->set.ssl.key_type = data->set.str[STRING_KEY_TYPE_ORIG]; + data->set.proxy_ssl.key_type = data->set.str[STRING_KEY_TYPE_PROXY]; + data->set.ssl.key_passwd = data->set.str[STRING_KEY_PASSWD_ORIG]; + data->set.proxy_ssl.key_passwd = data->set.str[STRING_KEY_PASSWD_PROXY]; + data->set.ssl.primary.clientcert = data->set.str[STRING_CERT_ORIG]; + data->set.proxy_ssl.primary.clientcert = data->set.str[STRING_CERT_PROXY]; #ifdef USE_TLS_SRP - data->set.ssl.username = data->set.str[STRING_TLSAUTH_USERNAME]; - data->set.ssl.password = data->set.str[STRING_TLSAUTH_PASSWORD]; + data->set.ssl.username = data->set.str[STRING_TLSAUTH_USERNAME_ORIG]; + data->set.proxy_ssl.username = data->set.str[STRING_TLSAUTH_USERNAME_PROXY]; + data->set.ssl.password = data->set.str[STRING_TLSAUTH_PASSWORD_ORIG]; + data->set.proxy_ssl.password = data->set.str[STRING_TLSAUTH_PASSWORD_PROXY]; #endif - if(!Curl_clone_ssl_config(&data->set.ssl, &conn->ssl_config)) { + if(!Curl_clone_primary_ssl_config(&data->set.ssl.primary, + &conn->ssl_config)) { + result = CURLE_OUT_OF_MEMORY; + goto out; + } + + if(!Curl_clone_primary_ssl_config(&data->set.proxy_ssl.primary, + &conn->proxy_ssl_config)) { result = CURLE_OUT_OF_MEMORY; goto out; } @@ -6182,7 +6500,9 @@ static CURLcode create_conn(struct Curl_easy *data, infof(data, "Re-using existing connection! (#%ld) with %s %s\n", conn->connection_id, conn->bits.proxy?"proxy":"host", - conn->proxy.name?conn->proxy.dispname:conn->host.dispname); + conn->socks_proxy.host.name ? conn->socks_proxy.host.dispname : + conn->http_proxy.host.name ? conn->http_proxy.host.dispname : + conn->host.dispname); } else { /* We have decided that we want a new connection. However, we may not @@ -6313,6 +6633,7 @@ static CURLcode create_conn(struct Curl_easy *data, free(options); free(passwd); free(user); + free(socksproxy); free(proxy); return result; } diff --git a/lib/url.h b/lib/url.h index 90d9db3c3..c1254f5dc 100644 --- a/lib/url.h +++ b/lib/url.h @@ -76,5 +76,16 @@ CURLcode Curl_connected_proxy(struct connectdata *conn, int sockindex); void Curl_verboseconnect(struct connectdata *conn); #endif +#define CONNECT_PROXY_SSL()\ + (conn->http_proxy.proxytype == CURLPROXY_HTTPS &&\ + !conn->bits.proxy_ssl_connected[sockindex]) + +#define CONNECT_FIRSTSOCKET_PROXY_SSL()\ + (conn->http_proxy.proxytype == CURLPROXY_HTTPS &&\ + !conn->bits.proxy_ssl_connected[FIRSTSOCKET]) + +#define CONNECT_SECONDARYSOCKET_PROXY_SSL()\ + (conn->http_proxy.proxytype == CURLPROXY_HTTPS &&\ + !conn->bits.proxy_ssl_connected[SECONDARYSOCKET]) #endif /* HEADER_CURL_URL_H */ diff --git a/lib/urldata.h b/lib/urldata.h index badd765b9..7fed5c5cc 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -316,6 +316,8 @@ struct ssl_connect_data { #elif defined(USE_GSKIT) gsk_handle handle; int iocport; + int localfd; + int remotefd; #elif defined(USE_AXTLS) SSL_CTX* ssl_ctx; SSL* ssl; @@ -341,28 +343,38 @@ struct ssl_connect_data { #endif }; -struct ssl_config_data { +struct ssl_primary_config { long version; /* what version the client wants to use */ - long certverifyresult; /* result from the certificate verification */ - bool verifypeer; /* set TRUE if this is desired */ bool verifyhost; /* set TRUE if CN/SAN must match hostname */ bool verifystatus; /* set TRUE if certificate status must be checked */ char *CApath; /* certificate dir (doesn't work on windows) */ char *CAfile; /* certificate to verify peer against */ - const char *CRLfile; /* CRL to check certificate revocation */ - const char *issuercert;/* optional issuer certificate filename */ char *clientcert; char *random_file; /* path to file containing "random" data */ char *egdsocket; /* path to file containing the EGD daemon socket */ char *cipher_list; /* list of ciphers to use */ - size_t max_ssl_sessions; /* SSL session id cache size */ +}; + +struct ssl_config_data { + struct ssl_primary_config primary; + bool enable_beast; /* especially allow this flaw for interoperability's + sake*/ + bool no_revoke; /* disable SSL certificate revocation checks */ + long certverifyresult; /* result from the certificate verification */ + char *CRLfile; /* CRL to check certificate revocation */ + char *issuercert;/* optional issuer certificate filename */ curl_ssl_ctx_callback fsslctx; /* function to initialize ssl ctx */ void *fsslctxp; /* parameter for call back */ - bool sessionid; /* cache session IDs or not */ bool certinfo; /* gather lots of certificate info */ bool falsestart; + char *cert; /* client certificate file name */ + char *cert_type; /* format for certificate (default: PEM)*/ + char *key; /* private key file name */ + char *key_type; /* format for private key (default: PEM) */ + char *key_passwd; /* plain text private key password */ + #ifdef USE_TLS_SRP char *username; /* TLS username (for, e.g., SRP) */ char *password; /* TLS password (for, e.g., SRP) */ @@ -370,6 +382,11 @@ struct ssl_config_data { #endif }; +struct ssl_general_config { + bool sessionid; /* cache session IDs or not */ + size_t max_ssl_sessions; /* SSL session id cache size */ +}; + /* information stored about one single SSL session */ struct curl_ssl_session { char *name; /* host name for which this ID was used */ @@ -380,7 +397,7 @@ struct curl_ssl_session { long age; /* just a number, the higher the more recent */ int remote_port; /* remote port */ int conn_to_port; /* remote port for the connection (may be -1) */ - struct ssl_config_data ssl_config; /* setup for this session */ + struct ssl_primary_config ssl_config; /* setup for this session */ }; /* Struct used for Digest challenge-response authentication */ @@ -497,6 +514,7 @@ struct ConnectBits { that overrides the port in the URL (remote port) */ bool proxy; /* if set, this transfer is done through a proxy - any type */ bool httpproxy; /* if set, this transfer is done through a http proxy */ + bool socksproxy; /* if set, this transfer is done through a socks proxy */ bool user_passwd; /* do we use user+password for this connection? */ bool proxy_user_passwd; /* user+password for the proxy? */ bool ipv6_ip; /* we communicate with a remote site specified with pure IPv6 @@ -531,6 +549,7 @@ struct ConnectBits { bool ftp_use_eprt; /* As set with CURLOPT_FTP_USE_EPRT, but if we find out EPRT doesn't work we disable it for the forthcoming requests */ + bool ftp_use_data_ssl; /* Enabled SSL for the data connection */ bool netrc; /* name+password provided by netrc */ bool userpwd_in_url; /* name+password found in url */ bool stream_was_rewound; /* Indicates that the stream was rewound after a @@ -547,6 +566,9 @@ struct ConnectBits { bool tcp_fastopen; /* use TCP Fast Open */ bool tls_enable_npn; /* TLS NPN extension? */ bool tls_enable_alpn; /* TLS ALPN extension? */ + bool proxy_ssl_connected[2]; /* TRUE when SSL initialization for HTTPS proxy + is complete */ + bool socksproxy_connecting; /* connecting through a socks proxy */ }; struct hostname { @@ -849,6 +871,14 @@ struct postponed_data { }; #endif /* USE_RECV_BEFORE_SEND_WORKAROUND */ +struct proxy_info { + struct hostname host; + long port; + curl_proxytype proxytype; /* what kind of proxy that is in use */ + char *user; /* proxy user name string, allocated */ + char *passwd; /* proxy password string, allocated */ +}; + /* * The connectdata struct contains all fields and variables that should be * unique for an entire connection. @@ -898,14 +928,20 @@ struct connectdata { int socktype; /* SOCK_STREAM or SOCK_DGRAM */ struct hostname host; + char *secondaryhostname; /* secondary socket host name (ftp) */ struct hostname conn_to_host; /* the host to connect to. valid only if bits.conn_to_host is set */ struct hostname proxy; + struct proxy_info socks_proxy; + struct proxy_info http_proxy; + long port; /* which port to use locally */ int remote_port; /* the remote port, not the proxy port! */ int conn_to_port; /* the remote port to connect to. valid only if bits.conn_to_port is set */ + unsigned short secondary_port; /* secondary socket remote port to connect to + (ftp) */ /* 'primary_ip' and 'primary_port' get filled with peer's numerical ip address and port number whenever an outgoing connection is @@ -930,10 +966,6 @@ struct connectdata { char *oauth_bearer; /* bearer token for OAuth 2.0, allocated */ - char *proxyuser; /* proxy user name string, allocated */ - char *proxypasswd; /* proxy password string, allocated */ - curl_proxytype proxytype; /* what kind of proxy that is in use */ - int httpversion; /* the HTTP version*10 reported by the server */ int rtspversion; /* the RTSP version*10 reported by the server */ @@ -951,7 +983,9 @@ struct connectdata { struct postponed_data postponed[2]; /* two buffers for two sockets */ #endif /* USE_RECV_BEFORE_SEND_WORKAROUND */ struct ssl_connect_data ssl[2]; /* this is for ssl-stuff */ - struct ssl_config_data ssl_config; + struct ssl_connect_data proxy_ssl[2]; /* this is for proxy ssl-stuff */ + struct ssl_primary_config ssl_config; + struct ssl_primary_config proxy_ssl_config; bool tls_upgraded; struct ConnectBits bits; /* various state-flags for this connection */ @@ -1078,9 +1112,6 @@ struct connectdata { int socks5_gssapi_enctype; #endif - bool verifypeer; - bool verifyhost; - /* When this connection is created, store the conditions for the local end bind. This is stored before the actual bind and before any connection is made and will serve the purpose of being used for comparison reasons so @@ -1406,8 +1437,10 @@ struct DynamicStatic { struct Curl_multi; /* declared and used only in multi.c */ enum dupstring { - STRING_CERT, /* client certificate file name */ - STRING_CERT_TYPE, /* format for certificate (default: PEM)*/ + STRING_CERT_ORIG, /* client certificate file name */ + STRING_CERT_PROXY, /* client certificate file name */ + STRING_CERT_TYPE_ORIG, /* format for certificate (default: PEM)*/ + STRING_CERT_TYPE_PROXY, /* format for certificate (default: PEM)*/ STRING_COOKIE, /* HTTP cookie string to send */ STRING_COOKIEJAR, /* dump all cookies to this file */ STRING_CUSTOMREQUEST, /* HTTP/FTP/RTSP request/method to use */ @@ -1417,25 +1450,34 @@ enum dupstring { STRING_FTP_ACCOUNT, /* ftp account data */ STRING_FTP_ALTERNATIVE_TO_USER, /* command to send if USER/PASS fails */ STRING_FTPPORT, /* port to send with the FTP PORT command */ - STRING_KEY, /* private key file name */ - STRING_KEY_PASSWD, /* plain text private key password */ - STRING_KEY_TYPE, /* format for private key (default: PEM) */ + STRING_KEY_ORIG, /* private key file name */ + STRING_KEY_PROXY, /* private key file name */ + STRING_KEY_PASSWD_ORIG, /* plain text private key password */ + STRING_KEY_PASSWD_PROXY, /* plain text private key password */ + STRING_KEY_TYPE_ORIG, /* format for private key (default: PEM) */ + STRING_KEY_TYPE_PROXY, /* format for private key (default: PEM) */ STRING_KRB_LEVEL, /* krb security level */ STRING_NETRC_FILE, /* if not NULL, use this instead of trying to find $HOME/.netrc */ STRING_PROXY, /* proxy to use */ + STRING_SOCKS_PROXY, /* socks proxy to use */ STRING_SET_RANGE, /* range, if used */ STRING_SET_REFERER, /* custom string for the HTTP referer field */ STRING_SET_URL, /* what original URL to work on */ - STRING_SSL_CAPATH, /* CA directory name (doesn't work on windows) */ - STRING_SSL_CAFILE, /* certificate file to verify peer against */ + STRING_SSL_CAPATH_ORIG, /* CA directory name (doesn't work on windows) */ + STRING_SSL_CAPATH_PROXY, /* CA directory name (doesn't work on windows) */ + STRING_SSL_CAFILE_ORIG, /* certificate file to verify peer against */ + STRING_SSL_CAFILE_PROXY, /* certificate file to verify peer against */ STRING_SSL_PINNEDPUBLICKEY, /* public key file to verify peer against */ - STRING_SSL_CIPHER_LIST, /* list of ciphers to use */ + STRING_SSL_CIPHER_LIST_ORIG, /* list of ciphers to use */ + STRING_SSL_CIPHER_LIST_PROXY, /* list of ciphers to use */ STRING_SSL_EGDSOCKET, /* path to file containing the EGD daemon socket */ STRING_SSL_RANDOM_FILE, /* path to file containing "random" data */ STRING_USERAGENT, /* User-Agent string */ - STRING_SSL_CRLFILE, /* crl file to check certificate */ - STRING_SSL_ISSUERCERT, /* issuer cert file to check certificate */ + STRING_SSL_CRLFILE_ORIG, /* crl file to check certificate */ + STRING_SSL_CRLFILE_PROXY, /* crl file to check certificate */ + STRING_SSL_ISSUERCERT_ORIG, /* issuer cert file to check certificate */ + STRING_SSL_ISSUERCERT_PROXY, /* issuer cert file to check certificate */ STRING_USERNAME, /* , if used */ STRING_PASSWORD, /* , if used */ STRING_OPTIONS, /* , if used */ @@ -1463,8 +1505,10 @@ enum dupstring { STRING_MAIL_AUTH, #ifdef USE_TLS_SRP - STRING_TLSAUTH_USERNAME, /* TLS auth */ - STRING_TLSAUTH_PASSWORD, /* TLS auth */ + STRING_TLSAUTH_USERNAME_ORIG, /* TLS auth */ + STRING_TLSAUTH_USERNAME_PROXY, /* TLS auth */ + STRING_TLSAUTH_PASSWORD_ORIG, /* TLS auth */ + STRING_TLSAUTH_PASSWORD_PROXY, /* TLS auth */ #endif STRING_BEARER, /* , if used */ #ifdef USE_UNIX_SOCKETS @@ -1582,7 +1626,10 @@ struct UserDefined { long httpversion; /* when non-zero, a specific HTTP version requested to be used in the library's request(s) */ struct ssl_config_data ssl; /* user defined SSL stuff */ + struct ssl_config_data proxy_ssl; /* user defined SSL stuff for proxy */ + struct ssl_general_config general_ssl; /* general user defined SSL stuff */ curl_proxytype proxytype; /* what kind of proxy that is in use */ + curl_proxytype socks_proxytype; /* what kind of socks proxy that is in use */ long dns_cache_timeout; /* DNS cache timeout */ long buffer_size; /* size of receive buffer to use */ void *private_data; /* application-private data */ @@ -1646,9 +1693,6 @@ struct UserDefined { bool ftp_skip_ip; /* skip the IP address the FTP server passes on to us */ bool connect_only; /* make connection, let application use the socket */ - bool ssl_enable_beast; /* especially allow this flaw for interoperability's - sake*/ - bool ssl_no_revoke; /* disable SSL certificate revocation checks */ long ssh_auth_types; /* allowed SSH auth types */ bool http_te_skip; /* pass the raw body data to the user, even when transfer-encoded (chunked, compressed) */ diff --git a/lib/vtls/axtls.c b/lib/vtls/axtls.c index 85b8bc4f6..8a5029f78 100644 --- a/lib/vtls/axtls.c +++ b/lib/vtls/axtls.c @@ -158,7 +158,7 @@ static CURLcode connect_prep(struct connectdata *conn, int sockindex) /* axTLS only supports TLSv1 */ /* check to see if we've been told to use an explicit SSL/TLS version */ - switch(data->set.ssl.version) { + switch(SSL_CONN_CONFIG(version)) { case CURL_SSLVERSION_DEFAULT: case CURL_SSLVERSION_TLSv1: break; @@ -183,17 +183,17 @@ static CURLcode connect_prep(struct connectdata *conn, int sockindex) conn->ssl[sockindex].ssl = NULL; /* Load the trusted CA cert bundle file */ - if(data->set.ssl.CAfile) { - if(ssl_obj_load(ssl_ctx, SSL_OBJ_X509_CACERT, data->set.ssl.CAfile, NULL) - != SSL_OK) { + if(SSL_CONN_CONFIG(CAfile)) { + if(ssl_obj_load(ssl_ctx, SSL_OBJ_X509_CACERT, + SSL_CONN_CONFIG(CAfile), NULL) != SSL_OK) { infof(data, "error reading ca cert file %s \n", - data->set.ssl.CAfile); - if(data->set.ssl.verifypeer) { + SSL_CONN_CONFIG(CAfile)); + if(SSL_CONN_CONFIG(verifypeer)) { return CURLE_SSL_CACERT_BADFILE; } } else - infof(data, "found certificates in %s\n", data->set.ssl.CAfile); + infof(data, "found certificates in %s\n", SSL_CONN_CONFIG(CAfile)); } /* gtls.c tasks we're skipping for now: @@ -205,15 +205,15 @@ static CURLcode connect_prep(struct connectdata *conn, int sockindex) */ /* Load client certificate */ - if(data->set.str[STRING_CERT]) { + if(SSL_SET_OPTION(cert)) { i=0; /* Instead of trying to analyze cert type here, let axTLS try them all. */ while(cert_types[i] != 0) { ssl_fcn_return = ssl_obj_load(ssl_ctx, cert_types[i], - data->set.str[STRING_CERT], NULL); + SSL_SET_OPTION(cert), NULL); if(ssl_fcn_return == SSL_OK) { infof(data, "successfully read cert file %s \n", - data->set.str[STRING_CERT]); + SSL_SET_OPTION(cert)); break; } i++; @@ -221,7 +221,7 @@ static CURLcode connect_prep(struct connectdata *conn, int sockindex) /* Tried all cert types, none worked. */ if(cert_types[i] == 0) { failf(data, "%s is not x509 or pkcs12 format", - data->set.str[STRING_CERT]); + SSL_SET_OPTION(cert)); return CURLE_SSL_CERTPROBLEM; } } @@ -229,15 +229,15 @@ static CURLcode connect_prep(struct connectdata *conn, int sockindex) /* Load client key. If a pkcs12 file successfully loaded a cert, then there's nothing to do because the key has already been loaded. */ - if(data->set.str[STRING_KEY] && cert_types[i] != SSL_OBJ_PKCS12) { + if(SSL_SET_OPTION(key) && cert_types[i] != SSL_OBJ_PKCS12) { i=0; /* Instead of trying to analyze key type here, let axTLS try them all. */ while(key_types[i] != 0) { ssl_fcn_return = ssl_obj_load(ssl_ctx, key_types[i], - data->set.str[STRING_KEY], NULL); + SSL_SET_OPTION(key), NULL); if(ssl_fcn_return == SSL_OK) { infof(data, "successfully read key file %s \n", - data->set.str[STRING_KEY]); + SSL_SET_OPTION(key)); break; } i++; @@ -245,7 +245,7 @@ static CURLcode connect_prep(struct connectdata *conn, int sockindex) /* Tried all key types, none worked. */ if(key_types[i] == 0) { failf(data, "Failure: %s is not a supported key file", - data->set.str[STRING_KEY]); + SSL_SET_OPTION(key)); return CURLE_SSL_CONNECT_ERROR; } } @@ -256,13 +256,14 @@ static CURLcode connect_prep(struct connectdata *conn, int sockindex) * 2) setting up callbacks. these seem gnutls specific */ - if(conn->ssl_config.sessionid) { + if(data->set.general_ssl.sessionid) { const uint8_t *ssl_sessionid; size_t ssl_idsize; /* In axTLS, handshaking happens inside ssl_client_new. */ Curl_ssl_sessionid_lock(conn); - if(!Curl_ssl_getsessionid(conn, (void **) &ssl_sessionid, &ssl_idsize)) { + if(!Curl_ssl_getsessionid(conn, (void **) &ssl_sessionid, &ssl_idsize, + sockindex)) { /* we got a session id, use it! */ infof (data, "SSL re-using session ID\n"); ssl = ssl_client_new(ssl_ctx, conn->sock[sockindex], @@ -291,13 +292,17 @@ static CURLcode connect_finish(struct connectdata *conn, int sockindex) const char *dns_altname; int8_t found_subject_alt_names = 0; int8_t found_subject_alt_name_matching_conn = 0; + const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : + conn->host.name; + const char * const dispname = SSL_IS_PROXY() ? + conn->http_proxy.host.dispname : conn->host.dispname; /* Here, gtls.c gets the peer certificates and fails out depending on * settings in "data." axTLS api doesn't have get cert chain fcn, so omit? */ /* Verify server's certificate */ - if(data->set.ssl.verifypeer) { + if(SSL_CONN_CONFIG(verifypeer)) { if(ssl_verify_cert(ssl) != SSL_OK) { Curl_axtls_close(conn, sockindex); failf(data, "server cert verify failed"); @@ -328,8 +333,8 @@ static CURLcode connect_finish(struct connectdata *conn, int sockindex) found_subject_alt_names = 1; infof(data, "\tComparing subject alt name DNS with hostname: %s <-> %s\n", - dns_altname, conn->host.name); - if(Curl_cert_hostcheck(dns_altname, conn->host.name)) { + dns_altname, hostname); + if(Curl_cert_hostcheck(dns_altname, hostname)) { found_subject_alt_name_matching_conn = 1; break; } @@ -337,23 +342,21 @@ static CURLcode connect_finish(struct connectdata *conn, int sockindex) /* RFC2818 checks */ if(found_subject_alt_names && !found_subject_alt_name_matching_conn) { - if(data->set.ssl.verifyhost) { + if(SSL_CONN_CONFIG(verifyhost)) { /* Break connection ! */ Curl_axtls_close(conn, sockindex); - failf(data, "\tsubjectAltName(s) do not match %s\n", - conn->host.dispname); + failf(data, "\tsubjectAltName(s) do not match %s\n", dispname); return CURLE_PEER_FAILED_VERIFICATION; } else - infof(data, "\tsubjectAltName(s) do not match %s\n", - conn->host.dispname); + infof(data, "\tsubjectAltName(s) do not match %s\n", dispname); } else if(found_subject_alt_names == 0) { /* Per RFC2818, when no Subject Alt Names were available, examine the peer CN as a legacy fallback */ peer_CN = ssl_get_cert_dn(ssl, SSL_X509_CERT_COMMON_NAME); if(peer_CN == NULL) { - if(data->set.ssl.verifyhost) { + if(SSL_CONN_CONFIG(verifyhost)) { Curl_axtls_close(conn, sockindex); failf(data, "unable to obtain common name from peer certificate"); return CURLE_PEER_FAILED_VERIFICATION; @@ -362,17 +365,17 @@ static CURLcode connect_finish(struct connectdata *conn, int sockindex) infof(data, "unable to obtain common name from peer certificate"); } else { - if(!Curl_cert_hostcheck((const char *)peer_CN, conn->host.name)) { - if(data->set.ssl.verifyhost) { + if(!Curl_cert_hostcheck((const char *)peer_CN, hostname)) { + if(SSL_CONN_CONFIG(verifyhost)) { /* Break connection ! */ Curl_axtls_close(conn, sockindex); failf(data, "\tcommon name \"%s\" does not match \"%s\"\n", - peer_CN, conn->host.dispname); + peer_CN, dispname); return CURLE_PEER_FAILED_VERIFICATION; } else infof(data, "\tcommon name \"%s\" does not match \"%s\"\n", - peer_CN, conn->host.dispname); + peer_CN, dispname); } } } @@ -383,12 +386,12 @@ static CURLcode connect_finish(struct connectdata *conn, int sockindex) conn->send[sockindex] = axtls_send; /* Put our freshly minted SSL session in cache */ - if(conn->ssl_config.sessionid) { + if(data->set.general_ssl.sessionid) { const uint8_t *ssl_sessionid = ssl_get_session_id_size(ssl); size_t ssl_idsize = ssl_get_session_id(ssl); Curl_ssl_sessionid_lock(conn); - if(Curl_ssl_addsessionid(conn, (void *) ssl_sessionid, ssl_idsize) - != CURLE_OK) + if(Curl_ssl_addsessionid(conn, (void *) ssl_sessionid, ssl_idsize, + sockindex) != CURLE_OK) infof (data, "failed to add session to cache\n"); Curl_ssl_sessionid_unlock(conn); } diff --git a/lib/vtls/cyassl.c b/lib/vtls/cyassl.c index f0c0f4a07..5570760d4 100644 --- a/lib/vtls/cyassl.c +++ b/lib/vtls/cyassl.c @@ -149,7 +149,7 @@ cyassl_connect_step1(struct connectdata *conn, return CURLE_OK; /* check to see if we've been told to use an explicit SSL/TLS version */ - switch(data->set.ssl.version) { + switch(SSL_CONN_CONFIG(version)) { case CURL_SSLVERSION_DEFAULT: case CURL_SSLVERSION_TLSv1: #if LIBCYASSL_VERSION_HEX >= 0x03003000 /* >= 3.3.0 */ @@ -208,7 +208,7 @@ cyassl_connect_step1(struct connectdata *conn, return CURLE_OUT_OF_MEMORY; } - switch(data->set.ssl.version) { + switch(SSL_CONN_CONFIG(version)) { case CURL_SSLVERSION_DEFAULT: case CURL_SSLVERSION_TLSv1: #if LIBCYASSL_VERSION_HEX > 0x03004006 /* > 3.4.6 */ @@ -231,18 +231,18 @@ cyassl_connect_step1(struct connectdata *conn, #ifndef NO_FILESYSTEM /* load trusted cacert */ - if(data->set.str[STRING_SSL_CAFILE]) { + if(SSL_CONN_CONFIG(CAfile)) { if(1 != SSL_CTX_load_verify_locations(conssl->ctx, - data->set.str[STRING_SSL_CAFILE], - data->set.str[STRING_SSL_CAPATH])) { - if(data->set.ssl.verifypeer) { + SSL_CONN_CONFIG(CAfile), + SSL_CONN_CONFIG(CApath))) { + if(SSL_CONN_CONFIG(verifypeer)) { /* Fail if we insist on successfully verifying the server. */ failf(data, "error setting certificate verify locations:\n" " CAfile: %s\n CApath: %s", - data->set.str[STRING_SSL_CAFILE]? - data->set.str[STRING_SSL_CAFILE]: "none", - data->set.str[STRING_SSL_CAPATH]? - data->set.str[STRING_SSL_CAPATH] : "none"); + SSL_CONN_CONFIG(CAfile)? + SSL_CONN_CONFIG(CAfile): "none", + SSL_CONN_CONFIG(CApath)? + SSL_CONN_CONFIG(CApath) : "none"); return CURLE_SSL_CACERT_BADFILE; } else { @@ -259,25 +259,25 @@ cyassl_connect_step1(struct connectdata *conn, infof(data, " CAfile: %s\n" " CApath: %s\n", - data->set.str[STRING_SSL_CAFILE] ? data->set.str[STRING_SSL_CAFILE]: + SSL_CONN_CONFIG(CAfile) ? SSL_CONN_CONFIG(CAfile): "none", - data->set.str[STRING_SSL_CAPATH] ? data->set.str[STRING_SSL_CAPATH]: + SSL_CONN_CONFIG(CApath) ? SSL_CONN_CONFIG(CApath): "none"); } /* Load the client certificate, and private key */ - if(data->set.str[STRING_CERT] && data->set.str[STRING_KEY]) { - int file_type = do_file_type(data->set.str[STRING_CERT_TYPE]); + if(SSL_SET_OPTION(cert) && SSL_SET_OPTION(key)) { + int file_type = do_file_type(SSL_SET_OPTION(cert_type)); - if(SSL_CTX_use_certificate_file(conssl->ctx, data->set.str[STRING_CERT], + if(SSL_CTX_use_certificate_file(conssl->ctx, SSL_SET_OPTION(cert), file_type) != 1) { failf(data, "unable to use client certificate (no key or wrong pass" " phrase?)"); return CURLE_SSL_CONNECT_ERROR; } - file_type = do_file_type(data->set.str[STRING_KEY_TYPE]); - if(SSL_CTX_use_PrivateKey_file(conssl->ctx, data->set.str[STRING_KEY], + file_type = do_file_type(SSL_SET_OPTION(key_type)); + if(SSL_CTX_use_PrivateKey_file(conssl->ctx, SSL_SET_OPTION(key), file_type) != 1) { failf(data, "unable to set private key"); return CURLE_SSL_CONNECT_ERROR; @@ -290,7 +290,8 @@ cyassl_connect_step1(struct connectdata *conn, * anyway. In the latter case the result of the verification is checked with * SSL_get_verify_result() below. */ SSL_CTX_set_verify(conssl->ctx, - data->set.ssl.verifypeer?SSL_VERIFY_PEER:SSL_VERIFY_NONE, + SSL_CONN_CONFIG(verifypeer)?SSL_VERIFY_PEER: + SSL_VERIFY_NONE, NULL); #ifdef HAVE_SNI @@ -299,13 +300,15 @@ cyassl_connect_step1(struct connectdata *conn, #ifdef ENABLE_IPV6 struct in6_addr addr6; #endif - size_t hostname_len = strlen(conn->host.name); + const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : + conn->host.name; + size_t hostname_len = strlen(hostname); if((hostname_len < USHRT_MAX) && - (0 == Curl_inet_pton(AF_INET, conn->host.name, &addr4)) && + (0 == Curl_inet_pton(AF_INET, hostname, &addr4)) && #ifdef ENABLE_IPV6 - (0 == Curl_inet_pton(AF_INET6, conn->host.name, &addr6)) && + (0 == Curl_inet_pton(AF_INET6, hostname, &addr6)) && #endif - (CyaSSL_CTX_UseSNI(conssl->ctx, CYASSL_SNI_HOST_NAME, conn->host.name, + (CyaSSL_CTX_UseSNI(conssl->ctx, CYASSL_SNI_HOST_NAME, hostname, (unsigned short)hostname_len) != 1)) { infof(data, "WARNING: failed to configure server name indication (SNI) " "TLS extension\n"); @@ -334,7 +337,7 @@ cyassl_connect_step1(struct connectdata *conn, } } #ifdef NO_FILESYSTEM - else if(data->set.ssl.verifypeer) { + else if(SSL_CONN_CONFIG(verifypeer)) { failf(data, "SSL: Certificates couldn't be loaded because CyaSSL was built" " with \"no filesystem\". Either disable peer verification" " (insecure) or if you are building an application with libcurl you" @@ -380,11 +383,11 @@ cyassl_connect_step1(struct connectdata *conn, #endif /* HAVE_ALPN */ /* Check if there's a cached ID we can/should use here! */ - if(conn->ssl_config.sessionid) { + if(data->set.general_ssl.sessionid) { void *ssl_sessionid = NULL; Curl_ssl_sessionid_lock(conn); - if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL)) { + if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL, sockindex)) { /* we got a session id, use it! */ if(!SSL_set_session(conssl->handle, ssl_sessionid)) { Curl_ssl_sessionid_unlock(conn); @@ -417,13 +420,17 @@ cyassl_connect_step2(struct connectdata *conn, int ret = -1; struct Curl_easy *data = conn->data; struct ssl_connect_data* conssl = &conn->ssl[sockindex]; + const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : + conn->host.name; + const char * const dispname = SSL_IS_PROXY() ? + conn->http_proxy.host.dispname : conn->host.dispname; conn->recv[sockindex] = cyassl_recv; conn->send[sockindex] = cyassl_send; /* Enable RFC2818 checks */ - if(data->set.ssl.verifyhost) { - ret = CyaSSL_check_domain_name(conssl->handle, conn->host.name); + if(SSL_CONN_CONFIG(verifyhost)) { + ret = CyaSSL_check_domain_name(conssl->handle, hostname); if(ret == SSL_FAILURE) return CURLE_OUT_OF_MEMORY; } @@ -447,31 +454,31 @@ cyassl_connect_step2(struct connectdata *conn, else if(DOMAIN_NAME_MISMATCH == detail) { #if 1 failf(data, "\tsubject alt name(s) or common name do not match \"%s\"\n", - conn->host.dispname); + dispname); return CURLE_PEER_FAILED_VERIFICATION; #else /* When the CyaSSL_check_domain_name() is used and you desire to continue - * on a DOMAIN_NAME_MISMATCH, i.e. 'data->set.ssl.verifyhost == 0', + * on a DOMAIN_NAME_MISMATCH, i.e. 'conn->ssl_config.verifyhost == 0', * CyaSSL version 2.4.0 will fail with an INCOMPLETE_DATA error. The only * way to do this is currently to switch the CyaSSL_check_domain_name() - * in and out based on the 'data->set.ssl.verifyhost' value. */ - if(data->set.ssl.verifyhost) { + * in and out based on the 'conn->ssl_config.verifyhost' value. */ + if(SSL_CONN_CONFIG(verifyhost)) { failf(data, "\tsubject alt name(s) or common name do not match \"%s\"\n", - conn->host.dispname); + dispname); return CURLE_PEER_FAILED_VERIFICATION; } else { infof(data, "\tsubject alt name(s) and/or common name do not match \"%s\"\n", - conn->host.dispname); + dispname); return CURLE_OK; } #endif } #if LIBCYASSL_VERSION_HEX >= 0x02007000 /* 2.7.0 */ else if(ASN_NO_SIGNER_E == detail) { - if(data->set.ssl.verifypeer) { + if(SSL_CONN_CONFIG(verifypeer)) { failf(data, "\tCA signer not available for verification\n"); return CURLE_SSL_CACERT_BADFILE; } @@ -587,7 +594,7 @@ cyassl_connect_step3(struct connectdata *conn, DEBUGASSERT(ssl_connect_3 == connssl->connecting_state); - if(conn->ssl_config.sessionid) { + if(data->set.general_ssl.sessionid) { bool incache; SSL_SESSION *our_ssl_sessionid; void *old_ssl_sessionid = NULL; @@ -595,7 +602,8 @@ cyassl_connect_step3(struct connectdata *conn, our_ssl_sessionid = SSL_get_session(connssl->handle); Curl_ssl_sessionid_lock(conn); - incache = !(Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL)); + incache = !(Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL, + sockindex)); if(incache) { if(old_ssl_sessionid != our_ssl_sessionid) { infof(data, "old SSL session ID is stale, removing\n"); @@ -606,7 +614,7 @@ cyassl_connect_step3(struct connectdata *conn, if(!incache) { result = Curl_ssl_addsessionid(conn, our_ssl_sessionid, - 0 /* unknown size */); + 0 /* unknown size */, sockindex); if(result) { Curl_ssl_sessionid_unlock(conn); failf(data, "failed to store ssl session"); diff --git a/lib/vtls/darwinssl.c b/lib/vtls/darwinssl.c index 134a28211..28856365a 100644 --- a/lib/vtls/darwinssl.c +++ b/lib/vtls/darwinssl.c @@ -1088,7 +1088,7 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn, /* check to see if we've been told to use an explicit SSL/TLS version */ #if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS if(SSLSetProtocolVersionMax != NULL) { - switch(data->set.ssl.version) { + switch(conn->ssl_config.version) { case CURL_SSLVERSION_DEFAULT: case CURL_SSLVERSION_TLSv1: (void)SSLSetProtocolVersionMin(connssl->ssl_ctx, kTLSProtocol1); @@ -1135,7 +1135,7 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn, (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx, kSSLProtocolAll, false); - switch (data->set.ssl.version) { + switch (conn->ssl_config.version) { case CURL_SSLVERSION_DEFAULT: case CURL_SSLVERSION_TLSv1: (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx, @@ -1192,7 +1192,7 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn, } #else (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx, kSSLProtocolAll, false); - switch(data->set.ssl.version) { + switch(conn->ssl_config.version) { case CURL_SSLVERSION_DEFAULT: case CURL_SSLVERSION_TLSv1: case CURL_SSLVERSION_TLSv1_0: @@ -1349,7 +1349,7 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn, #else if(SSLSetSessionOption != NULL) { #endif /* CURL_BUILD_MAC */ - bool break_on_auth = !data->set.ssl.verifypeer || + bool break_on_auth = !conn->ssl_config.verifypeer || data->set.str[STRING_SSL_CAFILE]; err = SSLSetSessionOption(connssl->ssl_ctx, kSSLSessionOptionBreakOnServerAuth, @@ -1362,7 +1362,7 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn, else { #if CURL_SUPPORT_MAC_10_8 err = SSLSetEnableCertVerify(connssl->ssl_ctx, - data->set.ssl.verifypeer?true:false); + conn->ssl_config.verifypeer?true:false); if(err != noErr) { failf(data, "SSL: SSLSetEnableCertVerify() failed: OSStatus %d", err); return CURLE_SSL_CONNECT_ERROR; @@ -1371,7 +1371,7 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn, } #else err = SSLSetEnableCertVerify(connssl->ssl_ctx, - data->set.ssl.verifypeer?true:false); + conn->ssl_config.verifypeer?true:false); if(err != noErr) { failf(data, "SSL: SSLSetEnableCertVerify() failed: OSStatus %d", err); return CURLE_SSL_CONNECT_ERROR; @@ -1396,7 +1396,7 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn, /* Configure hostname check. SNI is used if available. * Both hostname check and SNI require SSLSetPeerDomainName(). * Also: the verifyhost setting influences SNI usage */ - if(data->set.ssl.verifyhost) { + if(conn->ssl_config.verifyhost) { err = SSLSetPeerDomainName(connssl->ssl_ctx, conn->host.name, strlen(conn->host.name)); @@ -1526,21 +1526,22 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn, /* We want to enable 1/n-1 when using a CBC cipher unless the user specifically doesn't want us doing that: */ if(SSLSetSessionOption != NULL) { + /* TODO s/data->set.ssl.enable_beast/SSL_SET_OPTION(enable_beast)/g */ SSLSetSessionOption(connssl->ssl_ctx, kSSLSessionOptionSendOneByteRecord, - !data->set.ssl_enable_beast); + !data->set.ssl.enable_beast); SSLSetSessionOption(connssl->ssl_ctx, kSSLSessionOptionFalseStart, data->set.ssl.falsestart); /* false start support */ } #endif /* CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7 */ /* Check if there's a cached ID we can/should use here! */ - if(conn->ssl_config.sessionid) { + if(data->set.general_ssl.sessionid) { char *ssl_sessionid; size_t ssl_sessionid_len; Curl_ssl_sessionid_lock(conn); if(!Curl_ssl_getsessionid(conn, (void **)&ssl_sessionid, - &ssl_sessionid_len)) { + &ssl_sessionid_len, sockindex)) { /* we got a session id, use it! */ err = SSLSetPeerID(connssl->ssl_ctx, ssl_sessionid, ssl_sessionid_len); Curl_ssl_sessionid_unlock(conn); @@ -1568,7 +1569,8 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn, return CURLE_SSL_CONNECT_ERROR; } - result = Curl_ssl_addsessionid(conn, ssl_sessionid, ssl_sessionid_len); + result = Curl_ssl_addsessionid(conn, ssl_sessionid, ssl_sessionid_len, + sockindex); Curl_ssl_sessionid_unlock(conn); if(result) { failf(data, "failed to store ssl session"); diff --git a/lib/vtls/gskit.c b/lib/vtls/gskit.c index 2ccb9e47b..a91d09cb7 100644 --- a/lib/vtls/gskit.c +++ b/lib/vtls/gskit.c @@ -81,6 +81,10 @@ #include "memdebug.h" +/* Directions. */ +#define SOS_READ 0x01 +#define SOS_WRITE 0x02 + /* SSL version flags. */ #define CURL_GSKPROTO_SSLV2 0 #define CURL_GSKPROTO_SSLV2_MASK (1 << CURL_GSKPROTO_SSLV2) @@ -289,10 +293,11 @@ static CURLcode set_callback(struct Curl_easy *data, } -static CURLcode set_ciphers(struct Curl_easy *data, +static CURLcode set_ciphers(struct connectdata *conn, gsk_handle h, unsigned int *protoflags) { - const char *cipherlist = data->set.str[STRING_SSL_CIPHER_LIST]; + struct Curl_easy *data = conn->data; + const char *cipherlist = SSL_CONN_CONFIG(cipher_list); const char *clp; const gskit_cipher *ctp; int i; @@ -340,7 +345,7 @@ static CURLcode set_ciphers(struct Curl_easy *data, break; /* Search the cipher in our table. */ for(ctp = ciphertable; ctp->name; ctp++) - if(strnequal(ctp->name, clp, l) && !ctp->name[l]) + if(strncasecompare(ctp->name, clp, l) && !ctp->name[l]) break; if(!ctp->name) { failf(data, "Unknown cipher %.*s", l, clp); @@ -500,17 +505,195 @@ static void close_async_handshake(struct ssl_connect_data *connssl) connssl->iocport = -1; } +/* SSL over SSL + * Problems: + * 1) GSKit can only perform SSL on an AF_INET or AF_INET6 stream socket. To + * pipe an SSL stream into another, it is therefore needed to have a pair + * of such communicating sockets and handle the pipelining explicitly. + * 2) OS/400 socketpair() is only implemented for domain AF_UNIX, thus cannot + * be used to produce the pipeline. + * The solution is to simulate socketpair() for AF_INET with low-level API + * listen(), bind() and connect(). + */ -static void close_one(struct ssl_connect_data *conn, - struct Curl_easy *data) +static int +inetsocketpair(int sv[2]) { - if(conn->handle) { - gskit_status(data, gsk_secure_soc_close(&conn->handle), - "gsk_secure_soc_close()", 0); - conn->handle = (gsk_handle) NULL; + int lfd; /* Listening socket. */ + int sfd; /* Server socket. */ + int cfd; /* Client socket. */ + int len; + struct sockaddr_in addr1; + struct sockaddr_in addr2; + + /* Create listening socket on a local dynamic port. */ + lfd = socket(AF_INET, SOCK_STREAM, 0); + if(lfd < 0) + return -1; + memset((char *) &addr1, 0, sizeof addr1); + addr1.sin_family = AF_INET; + addr1.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + addr1.sin_port = 0; + if(bind(lfd, (struct sockaddr *) &addr1, sizeof addr1) || + listen(lfd, 2) < 0) { + close(lfd); + return -1; } - if(conn->iocport >= 0) - close_async_handshake(conn); + + /* Get the allocated port. */ + len = sizeof addr1; + if(getsockname(lfd, (struct sockaddr *) &addr1, &len) < 0) { + close(lfd); + return -1; + } + + /* Create the client socket. */ + cfd = socket(AF_INET, SOCK_STREAM, 0); + if(cfd < 0) { + close(lfd); + return -1; + } + + /* Request unblocking connection to the listening socket. */ + curlx_nonblock(cfd, TRUE); + if(connect(cfd, (struct sockaddr *) &addr1, sizeof addr1) < 0 && + errno != EINPROGRESS) { + close(lfd); + close(cfd); + return -1; + } + + /* Get the client dynamic port for intrusion check below. */ + len = sizeof addr2; + if(getsockname(cfd, (struct sockaddr *) &addr2, &len) < 0) { + close(lfd); + close(cfd); + return -1; + } + + /* Accept the incoming connection and get the server socket. */ + curlx_nonblock(lfd, TRUE); + for(;;) { + len = sizeof addr1; + sfd = accept(lfd, (struct sockaddr *) &addr1, &len); + if(sfd < 0) { + close(lfd); + close(cfd); + return -1; + } + + /* Check for possible intrusion from an external process. */ + if(addr1.sin_addr.s_addr == addr2.sin_addr.s_addr && + addr1.sin_port == addr2.sin_port) + break; + + /* Intrusion: reject incoming connection. */ + close(sfd); + } + + /* Done, return sockets and succeed. */ + close(lfd); + curlx_nonblock(cfd, FALSE); + sv[0] = cfd; + sv[1] = sfd; + return 0; +} + +static int pipe_ssloverssl(struct connectdata *conn, int sockindex, + int directions) +{ + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + struct ssl_connect_data *connproxyssl = &conn->proxy_ssl[sockindex]; + fd_set fds_read; + fd_set fds_write; + int n; + int m; + int i; + int ret = 0; + struct timeval tv = {0, 0}; + char buf[CURL_MAX_WRITE_SIZE]; + + if(!connssl->use || !connproxyssl->use) + return 0; /* No SSL over SSL: OK. */ + + FD_ZERO(&fds_read); + FD_ZERO(&fds_write); + n = -1; + if(directions & SOS_READ) { + FD_SET(connssl->remotefd, &fds_write); + n = connssl->remotefd; + } + if(directions & SOS_WRITE) { + FD_SET(connssl->remotefd, &fds_read); + n = connssl->remotefd; + FD_SET(conn->sock[sockindex], &fds_write); + if(n < conn->sock[sockindex]) + n = conn->sock[sockindex]; + } + i = select(n + 1, &fds_read, &fds_write, NULL, &tv); + if(i < 0) + return -1; /* Select error. */ + + if(FD_ISSET(connssl->remotefd, &fds_write)) { + /* Try getting data from HTTPS proxy and pipe it upstream. */ + n = 0; + i = gsk_secure_soc_read(connproxyssl->handle, buf, sizeof buf, &n); + switch(i) { + case GSK_OK: + if(n) { + i = write(connssl->remotefd, buf, n); + if(i < 0) + return -1; + ret = 1; + } + break; + case GSK_OS400_ERROR_TIMED_OUT: + case GSK_WOULD_BLOCK: + break; + default: + return -1; + } + } + + if(FD_ISSET(connssl->remotefd, &fds_read) && + FD_ISSET(conn->sock[sockindex], &fds_write)) { + /* Pipe data to HTTPS proxy. */ + n = read(connssl->remotefd, buf, sizeof buf); + if(n < 0) + return -1; + if(n) { + i = gsk_secure_soc_write(connproxyssl->handle, buf, n, &m); + if(i != GSK_OK || n != m) + return -1; + ret = 1; + } + } + + return ret; /* OK */ +} + + +static void close_one(struct ssl_connect_data *connssl, + struct connectdata *conn, int sockindex) +{ + if(connssl->handle) { + gskit_status(conn->data, gsk_secure_soc_close(&connssl->handle), + "gsk_secure_soc_close()", 0); + /* Last chance to drain output. */ + while(pipe_ssloverssl(conn, sockindex, SOS_WRITE) > 0) + ; + connssl->handle = (gsk_handle) NULL; + if(connssl->localfd >= 0) { + close(connssl->localfd); + connssl->localfd = -1; + } + if(connssl->remotefd >= 0) { + close(connssl->remotefd); + connssl->remotefd = -1; + } + } + if(connssl->iocport >= 0) + close_async_handshake(connssl); } @@ -518,13 +701,18 @@ static ssize_t gskit_send(struct connectdata *conn, int sockindex, const void *mem, size_t len, CURLcode *curlcode) { struct Curl_easy *data = conn->data; - CURLcode cc; + CURLcode cc = CURLE_SEND_ERROR; int written; - cc = gskit_status(data, - gsk_secure_soc_write(conn->ssl[sockindex].handle, - (char *) mem, (int) len, &written), - "gsk_secure_soc_write()", CURLE_SEND_ERROR); + if(pipe_ssloverssl(conn, sockindex, SOS_WRITE) >= 0) { + cc = gskit_status(data, + gsk_secure_soc_write(conn->ssl[sockindex].handle, + (char *) mem, (int) len, &written), + "gsk_secure_soc_write()", CURLE_SEND_ERROR); + if(cc == CURLE_OK) + if(pipe_ssloverssl(conn, sockindex, SOS_WRITE) < 0) + cc = CURLE_SEND_ERROR; + } if(cc != CURLE_OK) { *curlcode = cc; written = -1; @@ -539,15 +727,23 @@ static ssize_t gskit_recv(struct connectdata *conn, int num, char *buf, struct Curl_easy *data = conn->data; int buffsize; int nread; - CURLcode cc; + CURLcode cc = CURLE_RECV_ERROR; - buffsize = buffersize > (size_t) INT_MAX? INT_MAX: (int) buffersize; - cc = gskit_status(data, gsk_secure_soc_read(conn->ssl[num].handle, - buf, buffsize, &nread), - "gsk_secure_soc_read()", CURLE_RECV_ERROR); - if(cc != CURLE_OK) { + if(pipe_ssloverssl(conn, num, SOS_READ) >= 0) { + buffsize = buffersize > (size_t) INT_MAX? INT_MAX: (int) buffersize; + cc = gskit_status(data, gsk_secure_soc_read(conn->ssl[num].handle, + buf, buffsize, &nread), + "gsk_secure_soc_read()", CURLE_RECV_ERROR); + } + switch(cc) { + case CURLE_OK: + break; + case CURLE_OPERATION_TIMEDOUT: + cc = CURLE_AGAIN; + default: *curlcode = cc; nread = -1; + break; } return (ssize_t) nread; } @@ -560,18 +756,26 @@ static CURLcode gskit_connect_step1(struct connectdata *conn, int sockindex) gsk_handle envir; CURLcode result; int rc; - char *keyringfile; - char *keyringpwd; - char *keyringlabel; - char *sni; + const char * const keyringfile = SSL_CONN_CONFIG(CAfile); + const char * const keyringpwd = SSL_SET_OPTION(key_passwd); + const char * const keyringlabel = SSL_SET_OPTION(cert); + const long int ssl_version = SSL_CONN_CONFIG(version); + const bool verifypeer = SSL_CONN_CONFIG(verifypeer); + const char * const hostname = SSL_IS_PROXY()? conn->http_proxy.host.name: + conn->host.name; + const char *sni; unsigned int protoflags; long timeout; Qso_OverlappedIO_t commarea; + int sockpair[2]; + static const int sobufsize = CURL_MAX_WRITE_SIZE; /* Create SSL environment, start (preferably asynchronous) handshake. */ connssl->handle = (gsk_handle) NULL; connssl->iocport = -1; + connssl->localfd = -1; + connssl->remotefd = -1; /* GSKit supports two ways of specifying an SSL context: either by * application identifier (that should have been defined at the system @@ -586,9 +790,6 @@ static CURLcode gskit_connect_step1(struct connectdata *conn, int sockindex) * application identifier mode is tried first, as recommended in IBM doc. */ - keyringfile = data->set.str[STRING_SSL_CAFILE]; - keyringpwd = data->set.str[STRING_KEY_PASSWD]; - keyringlabel = data->set.str[STRING_CERT]; envir = (gsk_handle) NULL; if(keyringlabel && *keyringlabel && !keyringpwd && @@ -613,16 +814,34 @@ static CURLcode gskit_connect_step1(struct connectdata *conn, int sockindex) if(result) return result; + /* Establish a pipelining socket pair for SSL over SSL. */ + if(conn->proxy_ssl[sockindex].use) { + if(inetsocketpair(sockpair)) + return CURLE_SSL_CONNECT_ERROR; + connssl->localfd = sockpair[0]; + connssl->remotefd = sockpair[1]; + setsockopt(connssl->localfd, SOL_SOCKET, SO_RCVBUF, + (void *) sobufsize, sizeof sobufsize); + setsockopt(connssl->remotefd, SOL_SOCKET, SO_RCVBUF, + (void *) sobufsize, sizeof sobufsize); + setsockopt(connssl->localfd, SOL_SOCKET, SO_SNDBUF, + (void *) sobufsize, sizeof sobufsize); + setsockopt(connssl->remotefd, SOL_SOCKET, SO_SNDBUF, + (void *) sobufsize, sizeof sobufsize); + curlx_nonblock(connssl->localfd, TRUE); + curlx_nonblock(connssl->remotefd, TRUE); + } + /* Determine which SSL/TLS version should be enabled. */ sni = conn->host.name; - switch (data->set.ssl.version) { + switch (ssl_version) { case CURL_SSLVERSION_SSLv2: protoflags = CURL_GSKPROTO_SSLV2_MASK; - sni = (char *) NULL; + sni = NULL; break; case CURL_SSLVERSION_SSLv3: protoflags = CURL_GSKPROTO_SSLV3_MASK; - sni = (char *) NULL; + sni = NULL; break; case CURL_SSLVERSION_DEFAULT: case CURL_SSLVERSION_TLSv1: @@ -666,9 +885,12 @@ static CURLcode gskit_connect_step1(struct connectdata *conn, int sockindex) (timeout + 999) / 1000); } if(!result) - result = set_numeric(data, connssl->handle, GSK_FD, conn->sock[sockindex]); + result = set_numeric(data, connssl->handle, GSK_OS400_READ_TIMEOUT, 1); if(!result) - result = set_ciphers(data, connssl->handle, &protoflags); + result = set_numeric(data, connssl->handle, GSK_FD, connssl->localfd >= 0? + connssl->localfd: conn->sock[sockindex]); + if(!result) + result = set_ciphers(conn, connssl->handle, &protoflags); if(!protoflags) { failf(data, "No SSL protocol/cipher combination enabled"); result = CURLE_SSL_CIPHER; @@ -711,7 +933,7 @@ static CURLcode gskit_connect_step1(struct connectdata *conn, int sockindex) } if(!result) result = set_enum(data, connssl->handle, GSK_SERVER_AUTH_TYPE, - data->set.ssl.verifypeer? GSK_SERVER_AUTH_FULL: + verifypeer? GSK_SERVER_AUTH_FULL: GSK_SERVER_AUTH_PASSTHRU, FALSE); if(!result) { @@ -735,6 +957,10 @@ static CURLcode gskit_connect_step1(struct connectdata *conn, int sockindex) else if(errno != ENOBUFS) result = gskit_status(data, GSK_ERROR_IO, "QsoCreateIOCompletionPort()", 0); + else if(conn->proxy_ssl[sockindex].use) { + /* Cannot pipeline while handshaking synchronously. */ + result = CURLE_SSL_CONNECT_ERROR; + } else { /* No more completion port available. Use synchronous IO. */ result = gskit_status(data, gsk_secure_soc_init(connssl->handle), @@ -747,7 +973,7 @@ static CURLcode gskit_connect_step1(struct connectdata *conn, int sockindex) } /* Error: rollback. */ - close_one(connssl, data); + close_one(connssl, conn, sockindex); return result; } @@ -917,6 +1143,11 @@ static CURLcode gskit_connect_common(struct connectdata *conn, int sockindex, result = gskit_connect_step1(conn, sockindex); } + /* Handle handshake pipelining. */ + if(!result) + if(pipe_ssloverssl(conn, sockindex, SOS_READ | SOS_WRITE) < 0) + result = CURLE_SSL_CONNECT_ERROR; + /* Step 2: check if handshake is over. */ if(!result && connssl->connecting_state == ssl_connect_2) { /* check allowed time left */ @@ -931,12 +1162,17 @@ static CURLcode gskit_connect_common(struct connectdata *conn, int sockindex, result = gskit_connect_step2(conn, sockindex, nonblocking); } + /* Handle handshake pipelining. */ + if(!result) + if(pipe_ssloverssl(conn, sockindex, SOS_READ | SOS_WRITE) < 0) + result = CURLE_SSL_CONNECT_ERROR; + /* Step 3: gather certificate info, verify host. */ if(!result && connssl->connecting_state == ssl_connect_3) result = gskit_connect_step3(conn, sockindex); if(result) - close_one(connssl, data); + close_one(connssl, conn, sockindex); else if(connssl->connecting_state == ssl_connect_done) { connssl->state = ssl_connection_complete; connssl->connecting_state = ssl_connect_1; @@ -980,11 +1216,8 @@ CURLcode Curl_gskit_connect(struct connectdata *conn, int sockindex) void Curl_gskit_close(struct connectdata *conn, int sockindex) { - struct Curl_easy *data = conn->data; - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - - if(connssl->use) - close_one(connssl, data); + close_one(&conn->ssl[sockindex], conn, sockindex); + close_one(&conn->proxy_ssl[sockindex], conn, sockindex); } @@ -1003,7 +1236,7 @@ int Curl_gskit_shutdown(struct connectdata *conn, int sockindex) if(data->set.ftp_ccc != CURLFTPSSL_CCC_ACTIVE) return 0; - close_one(connssl, data); + close_one(connssl, conn, sockindex); rc = 0; what = SOCKET_READABLE(conn->sock[sockindex], SSL_SHUTDOWN_TIMEOUT); diff --git a/lib/vtls/gtls.c b/lib/vtls/gtls.c index 6eb3a9992..ba07faac6 100644 --- a/lib/vtls/gtls.c +++ b/lib/vtls/gtls.c @@ -171,6 +171,16 @@ static ssize_t Curl_gtls_pull(void *s, void *buf, size_t len) return ret; } +static ssize_t Curl_gtls_push_ssl(void *s, const void *buf, size_t len) +{ + return gnutls_record_send((gnutls_session_t) s, buf, len); +} + +static ssize_t Curl_gtls_pull_ssl(void *s, void *buf, size_t len) +{ + return gnutls_record_recv((gnutls_session_t) s, buf, len); +} + /* Curl_gtls_init() * * Global GnuTLS init, called from Curl_ssl_init(). This calls functions that @@ -371,6 +381,9 @@ gtls_connect_step1(struct connectdata *conn, gnutls_session_t session; int rc; bool sni = TRUE; /* default is SNI enabled */ + void *transport_ptr = NULL; + gnutls_push_func gnutls_transport_push = NULL; + gnutls_pull_func gnutls_transport_pull = NULL; #ifdef ENABLE_IPV6 struct in6_addr addr; #else @@ -401,6 +414,9 @@ gtls_connect_step1(struct connectdata *conn, const char *err = NULL; #endif + const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : + conn->host.name; + if(conn->ssl[sockindex].state == ssl_connection_complete) /* to make us tolerant against being called more than once for the same connection */ @@ -409,11 +425,11 @@ gtls_connect_step1(struct connectdata *conn, if(!gtls_inited) Curl_gtls_init(); - if(data->set.ssl.version == CURL_SSLVERSION_SSLv2) { + if(SSL_CONN_CONFIG(version) == CURL_SSLVERSION_SSLv2) { failf(data, "GnuTLS does not support SSLv2"); return CURLE_SSL_CONNECT_ERROR; } - else if(data->set.ssl.version == CURL_SSLVERSION_SSLv3) + else if(SSL_CONN_CONFIG(version) == CURL_SSLVERSION_SSLv3) sni = FALSE; /* SSLv3 has no SNI */ /* allocate a cred struct */ @@ -424,8 +440,8 @@ gtls_connect_step1(struct connectdata *conn, } #ifdef USE_TLS_SRP - if(data->set.ssl.authtype == CURL_TLSAUTH_SRP) { - infof(data, "Using TLS-SRP username: %s\n", data->set.ssl.username); + if(SSL_SET_OPTION(authtype) == CURL_TLSAUTH_SRP) { + infof(data, "Using TLS-SRP username: %s\n", SSL_SET_OPTION(username)); rc = gnutls_srp_allocate_client_credentials( &conn->ssl[sockindex].srp_client_cred); @@ -437,8 +453,8 @@ gtls_connect_step1(struct connectdata *conn, rc = gnutls_srp_set_client_credentials(conn->ssl[sockindex]. srp_client_cred, - data->set.ssl.username, - data->set.ssl.password); + SSL_SET_OPTION(username), + SSL_SET_OPTION(password)); if(rc != GNUTLS_E_SUCCESS) { failf(data, "gnutls_srp_set_client_cred() failed: %s", gnutls_strerror(rc)); @@ -447,40 +463,40 @@ gtls_connect_step1(struct connectdata *conn, } #endif - if(data->set.ssl.CAfile) { + if(SSL_CONN_CONFIG(CAfile)) { /* set the trusted CA cert bundle file */ gnutls_certificate_set_verify_flags(conn->ssl[sockindex].cred, GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT); rc = gnutls_certificate_set_x509_trust_file(conn->ssl[sockindex].cred, - data->set.ssl.CAfile, + SSL_CONN_CONFIG(CAfile), GNUTLS_X509_FMT_PEM); if(rc < 0) { infof(data, "error reading ca cert file %s (%s)\n", - data->set.ssl.CAfile, gnutls_strerror(rc)); - if(data->set.ssl.verifypeer) + SSL_CONN_CONFIG(CAfile), gnutls_strerror(rc)); + if(SSL_CONN_CONFIG(verifypeer)) return CURLE_SSL_CACERT_BADFILE; } else - infof(data, "found %d certificates in %s\n", - rc, data->set.ssl.CAfile); + infof(data, "found %d certificates in %s\n", rc, + SSL_CONN_CONFIG(CAfile)); } #ifdef HAS_CAPATH - if(data->set.ssl.CApath) { + if(SSL_CONN_CONFIG(CApath)) { /* set the trusted CA cert directory */ rc = gnutls_certificate_set_x509_trust_dir(conn->ssl[sockindex].cred, - data->set.ssl.CApath, - GNUTLS_X509_FMT_PEM); + SSL_CONN_CONFIG(CApath), + GNUTLS_X509_FMT_PEM); if(rc < 0) { infof(data, "error reading ca cert file %s (%s)\n", - data->set.ssl.CAfile, gnutls_strerror(rc)); - if(data->set.ssl.verifypeer) + SSL_CONN_CONFIG(CApath), gnutls_strerror(rc)); + if(SSL_CONN_CONFIG(verifypeer)) return CURLE_SSL_CACERT_BADFILE; } else infof(data, "found %d certificates in %s\n", - rc, data->set.ssl.CApath); + rc, SSL_CONN_CONFIG(CApath)); } #endif @@ -492,19 +508,19 @@ gtls_connect_step1(struct connectdata *conn, } #endif - if(data->set.ssl.CRLfile) { + if(SSL_SET_OPTION(CRLfile)) { /* set the CRL list file */ rc = gnutls_certificate_set_x509_crl_file(conn->ssl[sockindex].cred, - data->set.ssl.CRLfile, + SSL_SET_OPTION(CRLfile), GNUTLS_X509_FMT_PEM); if(rc < 0) { failf(data, "error reading crl file %s (%s)", - data->set.ssl.CRLfile, gnutls_strerror(rc)); + SSL_SET_OPTION(CRLfile), gnutls_strerror(rc)); return CURLE_SSL_CRL_BADFILE; } else infof(data, "found %d CRL in %s\n", - rc, data->set.ssl.CRLfile); + rc, SSL_SET_OPTION(CRLfile)); } /* Initialize TLS session as a client */ @@ -517,13 +533,13 @@ gtls_connect_step1(struct connectdata *conn, /* convenient assign */ session = conn->ssl[sockindex].session; - if((0 == Curl_inet_pton(AF_INET, conn->host.name, &addr)) && + if((0 == Curl_inet_pton(AF_INET, hostname, &addr)) && #ifdef ENABLE_IPV6 - (0 == Curl_inet_pton(AF_INET6, conn->host.name, &addr)) && + (0 == Curl_inet_pton(AF_INET6, hostname, &addr)) && #endif sni && - (gnutls_server_name_set(session, GNUTLS_NAME_DNS, conn->host.name, - strlen(conn->host.name)) < 0)) + (gnutls_server_name_set(session, GNUTLS_NAME_DNS, hostname, + strlen(hostname)) < 0)) infof(data, "WARNING: failed to configure server name indication (SNI) " "TLS extension\n"); @@ -544,13 +560,13 @@ gtls_connect_step1(struct connectdata *conn, if(rc != GNUTLS_E_SUCCESS) return CURLE_SSL_CONNECT_ERROR; - if(data->set.ssl.cipher_list != NULL) { + if(SSL_CONN_CONFIG(cipher_list) != NULL) { failf(data, "can't pass a custom cipher list to older GnuTLS" " versions"); return CURLE_SSL_CONNECT_ERROR; } - switch (data->set.ssl.version) { + switch (SSL_CONN_CONFIG(version) { case CURL_SSLVERSION_SSLv3: protocol_priority[0] = GNUTLS_SSL3; break; @@ -589,7 +605,7 @@ gtls_connect_step1(struct connectdata *conn, /* Ensure +SRP comes at the *end* of all relevant strings so that it can be * removed if a run-time error indicates that SRP is not supported by this * GnuTLS version */ - switch (data->set.ssl.version) { + switch (SSL_CONN_CONFIG(version)) { case CURL_SSLVERSION_SSLv3: prioritylist = GNUTLS_CIPHERS ":-VERS-TLS-ALL:+VERS-SSL3.0"; sni = false; @@ -668,8 +684,8 @@ gtls_connect_step1(struct connectdata *conn, } #endif - if(data->set.str[STRING_CERT]) { - if(data->set.str[STRING_KEY_PASSWD]) { + if(SSL_SET_OPTION(cert)) { + if(SSL_SET_OPTION(key_passwd)) { #if HAVE_GNUTLS_CERTIFICATE_SET_X509_KEY_FILE2 const unsigned int supported_key_encryption_algorithms = GNUTLS_PKCS_USE_PKCS12_3DES | GNUTLS_PKCS_USE_PKCS12_ARCFOUR | @@ -678,11 +694,11 @@ gtls_connect_step1(struct connectdata *conn, GNUTLS_PKCS_USE_PBES2_AES_256; rc = gnutls_certificate_set_x509_key_file2( conn->ssl[sockindex].cred, - data->set.str[STRING_CERT], - data->set.str[STRING_KEY] ? - data->set.str[STRING_KEY] : data->set.str[STRING_CERT], - do_file_type(data->set.str[STRING_CERT_TYPE]), - data->set.str[STRING_KEY_PASSWD], + SSL_SET_OPTION(cert), + SSL_SET_OPTION(key) ? + SSL_SET_OPTION(key) : SSL_SET_OPTION(cert), + do_file_type(SSL_SET_OPTION(cert_type)), + SSL_SET_OPTION(key_passwd), supported_key_encryption_algorithms); if(rc != GNUTLS_E_SUCCESS) { failf(data, @@ -696,15 +712,14 @@ gtls_connect_step1(struct connectdata *conn, #endif } else { - rc = gnutls_certificate_set_x509_key_file( + if(gnutls_certificate_set_x509_key_file( conn->ssl[sockindex].cred, - data->set.str[STRING_CERT], - data->set.str[STRING_KEY] ? - data->set.str[STRING_KEY] : data->set.str[STRING_CERT], - do_file_type(data->set.str[STRING_CERT_TYPE]) ); - if(rc != GNUTLS_E_SUCCESS) { - failf(data, "error reading X.509 key or certificate file: %s", - gnutls_strerror(rc)); + SSL_SET_OPTION(cert), + SSL_SET_OPTION(key) ? + SSL_SET_OPTION(key) : SSL_SET_OPTION(cert), + do_file_type(SSL_SET_OPTION(cert_type)) ) != + GNUTLS_E_SUCCESS) { + failf(data, "error reading X.509 key or certificate file"); return CURLE_SSL_CONNECT_ERROR; } } @@ -712,7 +727,7 @@ gtls_connect_step1(struct connectdata *conn, #ifdef USE_TLS_SRP /* put the credentials to the current session */ - if(data->set.ssl.authtype == CURL_TLSAUTH_SRP) { + if(SSL_SET_OPTION(authtype) == CURL_TLSAUTH_SRP) { rc = gnutls_credentials_set(session, GNUTLS_CRD_SRP, conn->ssl[sockindex].srp_client_cred); if(rc != GNUTLS_E_SUCCESS) { @@ -731,19 +746,30 @@ gtls_connect_step1(struct connectdata *conn, } } - /* set the connection handle (file descriptor for the socket) */ - gnutls_transport_set_ptr(session, - GNUTLS_INT_TO_POINTER_CAST(conn->sock[sockindex])); + if(conn->proxy_ssl[sockindex].use) { + transport_ptr = conn->proxy_ssl[sockindex].session; + gnutls_transport_push = Curl_gtls_push_ssl; + gnutls_transport_pull = Curl_gtls_pull_ssl; + } + else { + /* file descriptor for the socket */ + transport_ptr = GNUTLS_INT_TO_POINTER_CAST(conn->sock[sockindex]); + gnutls_transport_push = Curl_gtls_push; + gnutls_transport_pull = Curl_gtls_pull; + } + + /* set the connection handle */ + gnutls_transport_set_ptr(session, transport_ptr); /* register callback functions to send and receive data. */ - gnutls_transport_set_push_function(session, Curl_gtls_push); - gnutls_transport_set_pull_function(session, Curl_gtls_pull); + gnutls_transport_set_push_function(session, gnutls_transport_push); + gnutls_transport_set_pull_function(session, gnutls_transport_pull); /* lowat must be set to zero when using custom push and pull functions. */ gnutls_transport_set_lowat(session, 0); #ifdef HAS_OCSP - if(data->set.ssl.verifystatus) { + if(SSL_CONN_CONFIG(verifystatus)) { rc = gnutls_ocsp_status_request_enable_client(session, NULL, 0, NULL); if(rc != GNUTLS_E_SUCCESS) { failf(data, "gnutls_ocsp_status_request_enable_client() failed: %d", rc); @@ -754,12 +780,12 @@ gtls_connect_step1(struct connectdata *conn, /* This might be a reconnect, so we check for a session ID in the cache to speed up things */ - if(conn->ssl_config.sessionid) { + if(data->set.general_ssl.sessionid) { void *ssl_sessionid; size_t ssl_idsize; Curl_ssl_sessionid_lock(conn); - if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, &ssl_idsize)) { + if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, &ssl_idsize, sockindex)) { /* we got a session id, use it! */ gnutls_session_set_data(session, ssl_sessionid, ssl_idsize); @@ -854,8 +880,9 @@ gtls_connect_step3(struct connectdata *conn, gnutls_datum_t proto; #endif CURLcode result = CURLE_OK; - gnutls_protocol_t version = gnutls_protocol_get_version(session); + const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : + conn->host.name; /* the name of the cipher suite used, e.g. ECDHE_RSA_AES_256_GCM_SHA384. */ ptr = gnutls_cipher_suite_get_name(gnutls_kx_get(session), @@ -873,13 +900,13 @@ gtls_connect_step3(struct connectdata *conn, chainp = gnutls_certificate_get_peers(session, &cert_list_size); if(!chainp) { - if(data->set.ssl.verifypeer || - data->set.ssl.verifyhost || - data->set.ssl.issuercert) { + if(SSL_CONN_CONFIG(verifypeer) || + SSL_CONN_CONFIG(verifyhost) || + SSL_SET_OPTION(issuercert)) { #ifdef USE_TLS_SRP - if(data->set.ssl.authtype == CURL_TLSAUTH_SRP - && data->set.ssl.username != NULL - && !data->set.ssl.verifypeer + if(SSL_SET_OPTION(authtype) == CURL_TLSAUTH_SRP + && SSL_SET_OPTION(username) != NULL + && !SSL_CONN_CONFIG(verifypeer) && gnutls_cipher_get(session)) { /* no peer cert, but auth is ok if we have SRP user and cipher and no peer verify */ @@ -912,7 +939,7 @@ gtls_connect_step3(struct connectdata *conn, } } - if(data->set.ssl.verifypeer) { + if(SSL_CONN_CONFIG(verifypeer)) { /* This function will try to verify the peer's certificate and return its status (trusted, invalid etc.). The value of status should be one or more of the gnutls_certificate_status_t enumerated elements bitwise @@ -928,10 +955,11 @@ gtls_connect_step3(struct connectdata *conn, /* verify_status is a bitmask of gnutls_certificate_status bits */ if(verify_status & GNUTLS_CERT_INVALID) { - if(data->set.ssl.verifypeer) { + if(SSL_CONN_CONFIG(verifypeer)) { failf(data, "server certificate verification failed. CAfile: %s " - "CRLfile: %s", data->set.ssl.CAfile?data->set.ssl.CAfile:"none", - data->set.ssl.CRLfile?data->set.ssl.CRLfile:"none"); + "CRLfile: %s", SSL_CONN_CONFIG(CAfile) ? SSL_CONN_CONFIG(CAfile): + "none", + SSL_SET_OPTION(CRLfile)?SSL_SET_OPTION(CRLfile):"none"); return CURLE_SSL_CACERT; } else @@ -944,7 +972,7 @@ gtls_connect_step3(struct connectdata *conn, infof(data, "\t server certificate verification SKIPPED\n"); #ifdef HAS_OCSP - if(data->set.ssl.verifystatus) { + if(SSL_CONN_CONFIG(verifystatus)) { if(gnutls_ocsp_status_request_is_checked(session, 0) == 0) { gnutls_datum_t status_request; gnutls_ocsp_resp_t ocsp_resp; @@ -1056,21 +1084,21 @@ gtls_connect_step3(struct connectdata *conn, gnutls_x509_crt_t format */ gnutls_x509_crt_import(x509_cert, chainp, GNUTLS_X509_FMT_DER); - if(data->set.ssl.issuercert) { + if(SSL_SET_OPTION(issuercert)) { gnutls_x509_crt_init(&x509_issuer); - issuerp = load_file(data->set.ssl.issuercert); + issuerp = load_file(SSL_SET_OPTION(issuercert)); gnutls_x509_crt_import(x509_issuer, &issuerp, GNUTLS_X509_FMT_PEM); rc = gnutls_x509_crt_check_issuer(x509_cert, x509_issuer); gnutls_x509_crt_deinit(x509_issuer); unload_file(issuerp); if(rc <= 0) { failf(data, "server certificate issuer check failed (IssuerCert: %s)", - data->set.ssl.issuercert?data->set.ssl.issuercert:"none"); + SSL_SET_OPTION(issuercert)?SSL_SET_OPTION(issuercert):"none"); gnutls_x509_crt_deinit(x509_cert); return CURLE_SSL_ISSUER_ERROR; } infof(data, "\t server certificate issuer check OK (Issuer Cert: %s)\n", - data->set.ssl.issuercert?data->set.ssl.issuercert:"none"); + SSL_SET_OPTION(issuercert)?SSL_SET_OPTION(issuercert):"none"); } size=sizeof(certbuf); @@ -1089,7 +1117,7 @@ gtls_connect_step3(struct connectdata *conn, in RFC2818 (HTTPS), which takes into account wildcards, and the subject alternative name PKIX extension. Returns non zero on success, and zero on failure. */ - rc = gnutls_x509_crt_check_hostname(x509_cert, conn->host.name); + rc = gnutls_x509_crt_check_hostname(x509_cert, hostname); #if GNUTLS_VERSION_NUMBER < 0x030306 /* Before 3.3.6, gnutls_x509_crt_check_hostname() didn't check IP addresses. */ @@ -1105,10 +1133,10 @@ gtls_connect_step3(struct connectdata *conn, int i; int ret = 0; - if(Curl_inet_pton(AF_INET, conn->host.name, addrbuf) > 0) + if(Curl_inet_pton(AF_INET, hostname, addrbuf) > 0) addrlen = 4; #ifdef ENABLE_IPV6 - else if(Curl_inet_pton(AF_INET6, conn->host.name, addrbuf) > 0) + else if(Curl_inet_pton(AF_INET6, hostname, addrbuf) > 0) addrlen = 16; #endif @@ -1133,15 +1161,18 @@ gtls_connect_step3(struct connectdata *conn, } #endif if(!rc) { - if(data->set.ssl.verifyhost) { + const char * const dispname = SSL_IS_PROXY() ? + conn->http_proxy.host.dispname : conn->host.dispname; + + if(SSL_CONN_CONFIG(verifyhost)) { failf(data, "SSL: certificate subject name (%s) does not match " - "target host name '%s'", certbuf, conn->host.dispname); + "target host name '%s'", certbuf, dispname); gnutls_x509_crt_deinit(x509_cert); return CURLE_PEER_FAILED_VERIFICATION; } else infof(data, "\t common name: %s (does not match '%s')\n", - certbuf, conn->host.dispname); + certbuf, dispname); } else infof(data, "\t common name: %s (matched)\n", certbuf); @@ -1150,7 +1181,7 @@ gtls_connect_step3(struct connectdata *conn, certclock = gnutls_x509_crt_get_expiration_time(x509_cert); if(certclock == (time_t)-1) { - if(data->set.ssl.verifypeer) { + if(SSL_CONN_CONFIG(verifypeer)) { failf(data, "server cert expiration date verify failed"); gnutls_x509_crt_deinit(x509_cert); return CURLE_SSL_CONNECT_ERROR; @@ -1160,7 +1191,7 @@ gtls_connect_step3(struct connectdata *conn, } else { if(certclock < time(NULL)) { - if(data->set.ssl.verifypeer) { + if(SSL_CONN_CONFIG(verifypeer)) { failf(data, "server certificate expiration date has passed."); gnutls_x509_crt_deinit(x509_cert); return CURLE_PEER_FAILED_VERIFICATION; @@ -1175,7 +1206,7 @@ gtls_connect_step3(struct connectdata *conn, certclock = gnutls_x509_crt_get_activation_time(x509_cert); if(certclock == (time_t)-1) { - if(data->set.ssl.verifypeer) { + if(SSL_CONN_CONFIG(verifypeer)) { failf(data, "server cert activation date verify failed"); gnutls_x509_crt_deinit(x509_cert); return CURLE_SSL_CONNECT_ERROR; @@ -1185,7 +1216,7 @@ gtls_connect_step3(struct connectdata *conn, } else { if(certclock > time(NULL)) { - if(data->set.ssl.verifypeer) { + if(SSL_CONN_CONFIG(verifypeer)) { failf(data, "server certificate not activated yet."); gnutls_x509_crt_deinit(x509_cert); return CURLE_PEER_FAILED_VERIFICATION; @@ -1277,7 +1308,7 @@ gtls_connect_step3(struct connectdata *conn, conn->recv[sockindex] = gtls_recv; conn->send[sockindex] = gtls_send; - if(conn->ssl_config.sessionid) { + if(data->set.general_ssl.sessionid) { /* we always unconditionally get the session id here, as even if we already got it from the cache and asked to use it in the connection, it might've been rejected and then a new one is in use now and we need to @@ -1296,7 +1327,8 @@ gtls_connect_step3(struct connectdata *conn, gnutls_session_get_data(session, connect_sessionid, &connect_idsize); Curl_ssl_sessionid_lock(conn); - incache = !(Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL)); + incache = !(Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL, + sockindex)); if(incache) { /* there was one before in the cache, so instead of risking that the previous one was rejected, we just kill that and store the new */ @@ -1304,7 +1336,8 @@ gtls_connect_step3(struct connectdata *conn, } /* store this session id */ - result = Curl_ssl_addsessionid(conn, connect_sessionid, connect_idsize); + result = Curl_ssl_addsessionid(conn, connect_sessionid, connect_idsize, + sockindex); Curl_ssl_sessionid_unlock(conn); if(result) { free(connect_sessionid); @@ -1386,6 +1419,20 @@ Curl_gtls_connect(struct connectdata *conn, return CURLE_OK; } +bool Curl_gtls_data_pending(const struct connectdata *conn, int connindex) +{ + bool res = FALSE; + if(conn->ssl[connindex].session && + 0 != gnutls_record_check_pending(conn->ssl[connindex].session)) + res = TRUE; + + if(conn->proxy_ssl[connindex].session && + 0 != gnutls_record_check_pending(conn->proxy_ssl[connindex].session)) + res = TRUE; + + return res; +} + static ssize_t gtls_send(struct connectdata *conn, int sockindex, const void *mem, @@ -1405,29 +1452,29 @@ static ssize_t gtls_send(struct connectdata *conn, return rc; } -static void close_one(struct connectdata *conn, - int idx) +static void close_one(struct ssl_connect_data *ssl) { - if(conn->ssl[idx].session) { - gnutls_bye(conn->ssl[idx].session, GNUTLS_SHUT_RDWR); - gnutls_deinit(conn->ssl[idx].session); - conn->ssl[idx].session = NULL; + if(ssl->session) { + gnutls_bye(ssl->session, GNUTLS_SHUT_RDWR); + gnutls_deinit(ssl->session); + ssl->session = NULL; } - if(conn->ssl[idx].cred) { - gnutls_certificate_free_credentials(conn->ssl[idx].cred); - conn->ssl[idx].cred = NULL; + if(ssl->cred) { + gnutls_certificate_free_credentials(ssl->cred); + ssl->cred = NULL; } #ifdef USE_TLS_SRP - if(conn->ssl[idx].srp_client_cred) { - gnutls_srp_free_client_credentials(conn->ssl[idx].srp_client_cred); - conn->ssl[idx].srp_client_cred = NULL; + if(ssl->srp_client_cred) { + gnutls_srp_free_client_credentials(ssl->srp_client_cred); + ssl->srp_client_cred = NULL; } #endif } void Curl_gtls_close(struct connectdata *conn, int sockindex) { - close_one(conn, sockindex); + close_one(&conn->ssl[sockindex]); + close_one(&conn->proxy_ssl[sockindex]); } /* @@ -1493,8 +1540,8 @@ int Curl_gtls_shutdown(struct connectdata *conn, int sockindex) gnutls_certificate_free_credentials(conn->ssl[sockindex].cred); #ifdef USE_TLS_SRP - if(data->set.ssl.authtype == CURL_TLSAUTH_SRP - && data->set.ssl.username != NULL) + if(SSL_SET_OPTION(authtype) == CURL_TLSAUTH_SRP + && SSL_SET_OPTION(username) != NULL) gnutls_srp_free_client_credentials(conn->ssl[sockindex].srp_client_cred); #endif diff --git a/lib/vtls/gtls.h b/lib/vtls/gtls.h index e0a95a7cc..e3d58531f 100644 --- a/lib/vtls/gtls.h +++ b/lib/vtls/gtls.h @@ -34,6 +34,8 @@ CURLcode Curl_gtls_connect(struct connectdata *conn, int sockindex); CURLcode Curl_gtls_connect_nonblocking(struct connectdata *conn, int sockindex, bool *done); +bool Curl_gtls_data_pending(const struct connectdata *conn, + int connindex); /* close a SSL connection */ void Curl_gtls_close(struct connectdata *conn, int sockindex); @@ -81,7 +83,7 @@ bool Curl_gtls_cert_status_request(void); #define curlssl_engines_list(x) ((void)x, (struct curl_slist *)NULL) #define curlssl_version Curl_gtls_version #define curlssl_check_cxn(x) ((void)x, -1) -#define curlssl_data_pending(x,y) ((void)x, (void)y, 0) +#define curlssl_data_pending(x,y) Curl_gtls_data_pending(x,y) #define curlssl_random(x,y,z) Curl_gtls_random(x,y,z) #define curlssl_md5sum(a,b,c,d) Curl_gtls_md5sum(a,b,c,d) #define curlssl_sha256sum(a,b,c,d) Curl_gtls_sha256sum(a,b,c,d) diff --git a/lib/vtls/mbedtls.c b/lib/vtls/mbedtls.c index 7797c3e40..797ba167c 100644 --- a/lib/vtls/mbedtls.c +++ b/lib/vtls/mbedtls.c @@ -372,11 +372,11 @@ mbed_connect_step1(struct connectdata *conn, mbedtls_ssl_list_ciphersuites()); /* Check if there's a cached ID we can/should use here! */ - if(conn->ssl_config.sessionid) { + if(data->set.general_ssl.sessionid) { void *old_session = NULL; Curl_ssl_sessionid_lock(conn); - if(!Curl_ssl_getsessionid(conn, &old_session, NULL)) { + if(!Curl_ssl_getsessionid(conn, &old_session, NULL, sockindex)) { ret = mbedtls_ssl_set_session(&connssl->ssl, old_session); if(ret) { Curl_ssl_sessionid_unlock(conn); @@ -613,7 +613,7 @@ mbed_connect_step3(struct connectdata *conn, DEBUGASSERT(ssl_connect_3 == connssl->connecting_state); - if(conn->ssl_config.sessionid) { + if(data->set.general_ssl.sessionid) { int ret; mbedtls_ssl_session *our_ssl_sessionid; void *old_ssl_sessionid = NULL; @@ -632,10 +632,10 @@ mbed_connect_step3(struct connectdata *conn, /* If there's already a matching session in the cache, delete it */ Curl_ssl_sessionid_lock(conn); - if(!Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL)) + if(!Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL, sockindex)) Curl_ssl_delsessionid(conn, old_ssl_sessionid); - retcode = Curl_ssl_addsessionid(conn, our_ssl_sessionid, 0); + retcode = Curl_ssl_addsessionid(conn, our_ssl_sessionid, 0, sockindex); Curl_ssl_sessionid_unlock(conn); if(retcode) { free(our_ssl_sessionid); diff --git a/lib/vtls/nss.c b/lib/vtls/nss.c index 6e0dc5b29..2d8439934 100644 --- a/lib/vtls/nss.c +++ b/lib/vtls/nss.c @@ -337,9 +337,8 @@ static int is_file(const char *filename) * should be later deallocated using free(). If the OOM failure occurs, we * return NULL, too. */ -static char* dup_nickname(struct Curl_easy *data, enum dupstring cert_kind) +static char* dup_nickname(struct Curl_easy *data, const char *str) { - const char *str = data->set.str[cert_kind]; const char *n; if(!is_file(str)) @@ -585,6 +584,7 @@ static CURLcode nss_load_key(struct connectdata *conn, int sockindex, SECStatus status; CURLcode result; struct ssl_connect_data *ssl = conn->ssl; + struct Curl_easy *data = conn->data; (void)sockindex; /* unused */ @@ -602,8 +602,7 @@ static CURLcode nss_load_key(struct connectdata *conn, int sockindex, SECMOD_WaitForAnyTokenEvent(mod, 0, 0); PK11_IsPresent(slot); - status = PK11_Authenticate(slot, PR_TRUE, - conn->data->set.str[STRING_KEY_PASSWD]); + status = PK11_Authenticate(slot, PR_TRUE, SSL_SET_OPTION(key_passwd)); PK11_FreeSlot(slot); return (SECSuccess == status) ? CURLE_OK : CURLE_SSL_CERTPROBLEM; @@ -682,7 +681,7 @@ static SECStatus nss_auth_cert_hook(void *arg, PRFileDesc *fd, PRBool checksig, struct connectdata *conn = (struct connectdata *)arg; #ifdef SSL_ENABLE_OCSP_STAPLING - if(conn->data->set.ssl.verifystatus) { + if(SSL_CONN_CONFIG(verifystatus)) { SECStatus cacheResult; const SECItemArray *csa = SSL_PeerStapledOCSPResponses(fd); @@ -708,7 +707,7 @@ static SECStatus nss_auth_cert_hook(void *arg, PRFileDesc *fd, PRBool checksig, } #endif - if(!conn->data->set.ssl.verifypeer) { + if(!SSL_CONN_CONFIG(verifypeer)) { infof(conn->data, "skipping SSL peer certificate verification\n"); return SECSuccess; } @@ -933,9 +932,12 @@ static SECStatus BadCertHandler(void *arg, PRFileDesc *sock) CERTCertificate *cert; /* remember the cert verification result */ - data->set.ssl.certverifyresult = err; + if(SSL_IS_PROXY()) + data->set.proxy_ssl.certverifyresult = err; + else + data->set.ssl.certverifyresult = err; - if(err == SSL_ERROR_BAD_CERT_DOMAIN && !data->set.ssl.verifyhost) + if(err == SSL_ERROR_BAD_CERT_DOMAIN && !SSL_CONN_CONFIG(verifyhost)) /* we are asked not to verify the host name */ return SECSuccess; @@ -1372,38 +1374,57 @@ Curl_nss_check_cxn(struct connectdata *conn) return -1; /* connection status unknown */ } -/* - * This function is called when an SSL connection is closed. - */ -void Curl_nss_close(struct connectdata *conn, int sockindex) +static void nss_close(struct ssl_connect_data *connssl) { - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + /* before the cleanup, check whether we are using a client certificate */ + const bool client_cert = (connssl->client_nickname != NULL) + || (connssl->obj_clicert != NULL); + + free(connssl->client_nickname); + connssl->client_nickname = NULL; + + /* destroy all NSS objects in order to avoid failure of NSS shutdown */ + Curl_llist_destroy(connssl->obj_list, NULL); + connssl->obj_list = NULL; + connssl->obj_clicert = NULL; if(connssl->handle) { - /* NSS closes the socket we previously handed to it, so we must mark it - as closed to avoid double close */ - fake_sclose(conn->sock[sockindex]); - conn->sock[sockindex] = CURL_SOCKET_BAD; - - if((connssl->client_nickname != NULL) || (connssl->obj_clicert != NULL)) + if(client_cert) /* A server might require different authentication based on the * particular path being requested by the client. To support this * scenario, we must ensure that a connection will never reuse the * authentication data from a previous connection. */ SSL_InvalidateSession(connssl->handle); - free(connssl->client_nickname); - connssl->client_nickname = NULL; - /* destroy all NSS objects in order to avoid failure of NSS shutdown */ - Curl_llist_destroy(connssl->obj_list, NULL); - connssl->obj_list = NULL; - connssl->obj_clicert = NULL; - PR_Close(connssl->handle); connssl->handle = NULL; } } +/* + * This function is called when an SSL connection is closed. + */ +void Curl_nss_close(struct connectdata *conn, int sockindex) +{ + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + struct ssl_connect_data *connssl_proxy = &conn->proxy_ssl[sockindex]; + + if(connssl->handle || connssl_proxy->handle) { + /* NSS closes the socket we previously handed to it, so we must mark it + as closed to avoid double close */ + fake_sclose(conn->sock[sockindex]); + conn->sock[sockindex] = CURL_SOCKET_BAD; + } + + if(connssl->handle) + /* nss_close(connssl) will transitively close also connssl_proxy->handle + if both are used. Clear it to avoid a double close leading to crash. */ + connssl_proxy->handle = NULL; + + nss_close(connssl); + nss_close(connssl_proxy); +} + /* return true if NSS can provide error code (and possibly msg) for the error */ static bool is_nss_error(CURLcode err) @@ -1442,8 +1463,8 @@ static CURLcode nss_load_ca_certificates(struct connectdata *conn, int sockindex) { struct Curl_easy *data = conn->data; - const char *cafile = data->set.ssl.CAfile; - const char *capath = data->set.ssl.CApath; + const char *cafile = SSL_CONN_CONFIG(CAfile); + const char *capath = SSL_CONN_CONFIG(CApath); if(cafile) { CURLcode result = nss_load_cert(&conn->ssl[sockindex], cafile, PR_TRUE); @@ -1491,9 +1512,10 @@ static CURLcode nss_load_ca_certificates(struct connectdata *conn, } static CURLcode nss_init_sslver(SSLVersionRange *sslver, - struct Curl_easy *data) + struct Curl_easy *data, + struct connectdata *conn) { - switch(data->set.ssl.version) { + switch (SSL_CONN_CONFIG(version)) { case CURL_SSLVERSION_DEFAULT: /* map CURL_SSLVERSION_DEFAULT to NSS default */ if(SSL_VersionRangeGetDefault(ssl_variant_stream, sslver) != SECSuccess) @@ -1614,6 +1636,7 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex) curl_socket_t sockfd = conn->sock[sockindex]; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; CURLcode result; + bool second_layer = FALSE; SSLVersionRange sslver = { SSL_LIBRARY_VERSION_TLS_1_0, /* min */ @@ -1672,18 +1695,18 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex) goto error; /* do not use SSL cache if disabled or we are not going to verify peer */ - ssl_no_cache = (conn->ssl_config.sessionid && data->set.ssl.verifypeer) ? - PR_FALSE : PR_TRUE; + ssl_no_cache = (data->set.general_ssl.sessionid + && SSL_CONN_CONFIG(verifypeer)) ? PR_FALSE : PR_TRUE; if(SSL_OptionSet(model, SSL_NO_CACHE, ssl_no_cache) != SECSuccess) goto error; /* enable/disable the requested SSL version(s) */ - if(nss_init_sslver(&sslver, data) != CURLE_OK) + if(nss_init_sslver(&sslver, data, conn) != CURLE_OK) goto error; if(SSL_VersionRangeSet(model, &sslver) != SECSuccess) goto error; - ssl_cbc_random_iv = !data->set.ssl_enable_beast; + ssl_cbc_random_iv = !SSL_SET_OPTION(enable_beast); #ifdef SSL_CBC_RANDOM_IV /* unless the user explicitly asks to allow the protocol vulnerability, we use the work-around */ @@ -1695,14 +1718,14 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex) infof(data, "warning: support for SSL_CBC_RANDOM_IV not compiled in\n"); #endif - if(data->set.ssl.cipher_list) { - if(set_ciphers(data, model, data->set.ssl.cipher_list) != SECSuccess) { + if(SSL_CONN_CONFIG(cipher_list)) { + if(set_ciphers(data, model, SSL_CONN_CONFIG(cipher_list)) != SECSuccess) { result = CURLE_SSL_CIPHER; goto error; } } - if(!data->set.ssl.verifypeer && data->set.ssl.verifyhost) + if(!SSL_CONN_CONFIG(verifypeer) && SSL_CONN_CONFIG(verifyhost)) infof(data, "warning: ignoring value of ssl.verifyhost\n"); /* bypass the default SSL_AuthCertificate() hook in case we do not want to @@ -1710,14 +1733,19 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex) if(SSL_AuthCertificateHook(model, nss_auth_cert_hook, conn) != SECSuccess) goto error; - data->set.ssl.certverifyresult=0; /* not checked yet */ + /* not checked yet */ + if(SSL_IS_PROXY()) + data->set.proxy_ssl.certverifyresult = 0; + else + data->set.ssl.certverifyresult = 0; + if(SSL_BadCertHook(model, BadCertHandler, conn) != SECSuccess) goto error; if(SSL_HandshakeCallback(model, HandshakeCallback, conn) != SECSuccess) goto error; - if(data->set.ssl.verifypeer) { + if(SSL_CONN_CONFIG(verifypeer)) { const CURLcode rv = nss_load_ca_certificates(conn, sockindex); if(rv) { result = rv; @@ -1725,24 +1753,24 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex) } } - if(data->set.ssl.CRLfile) { - const CURLcode rv = nss_load_crl(data->set.ssl.CRLfile); + if(SSL_SET_OPTION(CRLfile)) { + const CURLcode rv = nss_load_crl(SSL_SET_OPTION(CRLfile)); if(rv) { result = rv; goto error; } - infof(data, " CRLfile: %s\n", data->set.ssl.CRLfile); + infof(data, " CRLfile: %s\n", SSL_SET_OPTION(CRLfile)); } - if(data->set.str[STRING_CERT]) { - char *nickname = dup_nickname(data, STRING_CERT); + if(SSL_SET_OPTION(cert)) { + char *nickname = dup_nickname(data, SSL_SET_OPTION(cert)); if(nickname) { /* we are not going to use libnsspem.so to read the client cert */ connssl->obj_clicert = NULL; } else { - CURLcode rv = cert_stuff(conn, sockindex, data->set.str[STRING_CERT], - data->set.str[STRING_KEY]); + CURLcode rv = cert_stuff(conn, sockindex, SSL_SET_OPTION(cert), + SSL_SET_OPTION(key)); if(rv) { /* failf() is already done in cert_stuff() */ result = rv; @@ -1762,15 +1790,24 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex) goto error; } - /* wrap OS file descriptor by NSPR's file descriptor abstraction */ - nspr_io = PR_ImportTCPSocket(sockfd); - if(!nspr_io) - goto error; + if(conn->proxy_ssl[sockindex].use) { + DEBUGASSERT(ssl_connection_complete == conn->proxy_ssl[sockindex].state); + DEBUGASSERT(conn->proxy_ssl[sockindex].handle != NULL); + nspr_io = conn->proxy_ssl[sockindex].handle; + second_layer = TRUE; + } + else { + /* wrap OS file descriptor by NSPR's file descriptor abstraction */ + nspr_io = PR_ImportTCPSocket(sockfd); + if(!nspr_io) + goto error; + } /* create our own NSPR I/O layer */ nspr_io_stub = PR_CreateIOLayerStub(nspr_io_identity, &nspr_io_methods); if(!nspr_io_stub) { - PR_Close(nspr_io); + if(!second_layer) + PR_Close(nspr_io); goto error; } @@ -1779,7 +1816,8 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex) /* push our new layer to the NSPR I/O stack */ if(PR_PushIOLayer(nspr_io, PR_TOP_IO_LAYER, nspr_io_stub) != PR_SUCCESS) { - PR_Close(nspr_io); + if(!second_layer) + PR_Close(nspr_io); PR_Close(nspr_io_stub); goto error; } @@ -1787,7 +1825,8 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex) /* import our model socket onto the current I/O stack */ connssl->handle = SSL_ImportFD(model, nspr_io); if(!connssl->handle) { - PR_Close(nspr_io); + if(!second_layer) + PR_Close(nspr_io); goto error; } @@ -1795,12 +1834,12 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex) model = NULL; /* This is the password associated with the cert that we're using */ - if(data->set.str[STRING_KEY_PASSWD]) { - SSL_SetPKCS11PinArg(connssl->handle, data->set.str[STRING_KEY_PASSWD]); + if(SSL_SET_OPTION(key_passwd)) { + SSL_SetPKCS11PinArg(connssl->handle, SSL_SET_OPTION(key_passwd)); } #ifdef SSL_ENABLE_OCSP_STAPLING - if(data->set.ssl.verifystatus) { + if(SSL_CONN_CONFIG(verifystatus)) { if(SSL_OptionSet(connssl->handle, SSL_ENABLE_OCSP_STAPLING, PR_TRUE) != SECSuccess) goto error; @@ -1860,11 +1899,14 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex) goto error; /* propagate hostname to the TLS layer */ - if(SSL_SetURL(connssl->handle, conn->host.name) != SECSuccess) + if(SSL_SetURL(connssl->handle, SSL_IS_PROXY() ? conn->http_proxy.host.name : + conn->host.name) != SECSuccess) goto error; /* prevent NSS from re-using the session for a different hostname */ - if(SSL_SetSockPeerID(connssl->handle, conn->host.name) != SECSuccess) + if(SSL_SetSockPeerID(connssl->handle, SSL_IS_PROXY() ? + conn->http_proxy.host.name : conn->host.name) + != SECSuccess) goto error; return CURLE_OK; @@ -1882,6 +1924,8 @@ static CURLcode nss_do_connect(struct connectdata *conn, int sockindex) struct Curl_easy *data = conn->data; CURLcode result = CURLE_SSL_CONNECT_ERROR; PRUint32 timeout; + long * const certverifyresult = SSL_IS_PROXY() ? + &data->set.proxy_ssl.certverifyresult : &data->set.ssl.certverifyresult; /* check timeout situation */ const long time_left = Curl_timeleft(data, NULL, TRUE); @@ -1897,9 +1941,9 @@ static CURLcode nss_do_connect(struct connectdata *conn, int sockindex) if(PR_GetError() == PR_WOULD_BLOCK_ERROR) /* blocking direction is updated by nss_update_connecting_state() */ return CURLE_AGAIN; - else if(conn->data->set.ssl.certverifyresult == SSL_ERROR_BAD_CERT_DOMAIN) + else if(*certverifyresult == SSL_ERROR_BAD_CERT_DOMAIN) result = CURLE_PEER_FAILED_VERIFICATION; - else if(conn->data->set.ssl.certverifyresult!=0) + else if(*certverifyresult != 0) result = CURLE_SSL_CACERT; goto error; } @@ -1908,11 +1952,11 @@ static CURLcode nss_do_connect(struct connectdata *conn, int sockindex) if(result) goto error; - if(data->set.str[STRING_SSL_ISSUERCERT]) { + if(SSL_SET_OPTION(issuercert)) { SECStatus ret = SECFailure; - char *nickname = dup_nickname(data, STRING_SSL_ISSUERCERT); + char *nickname = dup_nickname(data, SSL_SET_OPTION(issuercert)); if(nickname) { - /* we support only nicknames in case of STRING_SSL_ISSUERCERT for now */ + /* we support only nicknames in case of issuercert for now */ ret = check_issuer_cert(connssl->handle, nickname); free(nickname); } diff --git a/lib/vtls/openssl.c b/lib/vtls/openssl.c index ae1a54f05..b8bc6c117 100644 --- a/lib/vtls/openssl.c +++ b/lib/vtls/openssl.c @@ -203,7 +203,7 @@ static CURLcode Curl_ossl_seed(struct Curl_easy *data) #ifndef RANDOM_FILE /* if RANDOM_FILE isn't defined, we only perform this if an option tells us to! */ - if(data->set.ssl.random_file) + if(data->set.str[STRING_SSL_RANDOM_FILE]) #define RANDOM_FILE "" /* doesn't matter won't be used */ #endif { @@ -331,7 +331,8 @@ int cert_stuff(struct connectdata *conn, char *cert_file, const char *cert_type, char *key_file, - const char *key_type) + const char *key_type, + char *key_passwd) { struct Curl_easy *data = conn->data; @@ -342,10 +343,9 @@ int cert_stuff(struct connectdata *conn, X509 *x509; int cert_done = 0; - if(data->set.str[STRING_KEY_PASSWD]) { + if(key_passwd) { /* set the password in the callback userdata */ - SSL_CTX_set_default_passwd_cb_userdata(ctx, - data->set.str[STRING_KEY_PASSWD]); + SSL_CTX_set_default_passwd_cb_userdata(ctx, key_passwd); /* Set passwd callback: */ SSL_CTX_set_default_passwd_cb(ctx, passwd_callback); } @@ -456,7 +456,7 @@ int cert_stuff(struct connectdata *conn, PKCS12_PBE_add(); - if(!PKCS12_parse(p12, data->set.str[STRING_KEY_PASSWD], &pri, &x509, + if(!PKCS12_parse(p12, key_passwd, &pri, &x509, &ca)) { failf(data, "could not parse PKCS12 file, check password, " OSSL_PACKAGE @@ -568,7 +568,7 @@ int cert_stuff(struct connectdata *conn, priv_key = (EVP_PKEY *) ENGINE_load_private_key(data->state.engine, key_file, ui_method, - data->set.str[STRING_KEY_PASSWD]); + key_passwd); UI_destroy_method(ui_method); if(!priv_key) { failf(data, "failed to load private key from crypto engine"); @@ -899,13 +899,8 @@ struct curl_slist *Curl_ossl_engines_list(struct Curl_easy *data) } -/* - * This function is called when an SSL connection is closed. - */ -void Curl_ossl_close(struct connectdata *conn, int sockindex) +static void ossl_close(struct ssl_connect_data *connssl) { - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - if(connssl->handle) { (void)SSL_shutdown(connssl->handle); SSL_set_connect_state(connssl->handle); @@ -919,6 +914,15 @@ void Curl_ossl_close(struct connectdata *conn, int sockindex) } } +/* + * This function is called when an SSL connection is closed. + */ +void Curl_ossl_close(struct connectdata *conn, int sockindex) +{ + ossl_close(&conn->ssl[sockindex]); + ossl_close(&conn->proxy_ssl[sockindex]); +} + /* * This function is called to shut down the SSL layer but keep the * socket open (CCC - Clear Command Channel) @@ -1090,16 +1094,20 @@ static CURLcode verifyhost(struct connectdata *conn, X509 *server_cert) CURLcode result = CURLE_OK; bool dNSName = FALSE; /* if a dNSName field exists in the cert */ bool iPAddress = FALSE; /* if a iPAddress field exists in the cert */ + const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : + conn->host.name; + const char * const dispname = SSL_IS_PROXY() ? + conn->http_proxy.host.dispname : conn->host.dispname; #ifdef ENABLE_IPV6 if(conn->bits.ipv6_ip && - Curl_inet_pton(AF_INET6, conn->host.name, &addr)) { + Curl_inet_pton(AF_INET6, hostname, &addr)) { target = GEN_IPADD; addrlen = sizeof(struct in6_addr); } else #endif - if(Curl_inet_pton(AF_INET, conn->host.name, &addr)) { + if(Curl_inet_pton(AF_INET, hostname, &addr)) { target = GEN_IPADD; addrlen = sizeof(struct in_addr); } @@ -1148,11 +1156,11 @@ static CURLcode verifyhost(struct connectdata *conn, X509 *server_cert) if((altlen == strlen(altptr)) && /* if this isn't true, there was an embedded zero in the name string and we cannot match it. */ - Curl_cert_hostcheck(altptr, conn->host.name)) { + Curl_cert_hostcheck(altptr, hostname)) { dnsmatched = TRUE; infof(data, " subjectAltName: host \"%s\" matched cert's \"%s\"\n", - conn->host.dispname, altptr); + dispname, altptr); } break; @@ -1163,7 +1171,7 @@ static CURLcode verifyhost(struct connectdata *conn, X509 *server_cert) ipmatched = TRUE; infof(data, " subjectAltName: host \"%s\" matched cert's IP address!\n", - conn->host.dispname); + dispname); } break; } @@ -1179,9 +1187,9 @@ static CURLcode verifyhost(struct connectdata *conn, X509 *server_cert) /* an alternative name matched */ ; else if(dNSName || iPAddress) { - infof(data, " subjectAltName does not match %s\n", conn->host.dispname); + infof(data, " subjectAltName does not match %s\n", dispname); failf(data, "SSL: no alternative certificate subject name matches " - "target host name '%s'", conn->host.dispname); + "target host name '%s'", dispname); result = CURLE_PEER_FAILED_VERIFICATION; } else { @@ -1255,9 +1263,9 @@ static CURLcode verifyhost(struct connectdata *conn, X509 *server_cert) "SSL: unable to obtain common name from peer certificate"); result = CURLE_PEER_FAILED_VERIFICATION; } - else if(!Curl_cert_hostcheck((const char *)peer_CN, conn->host.name)) { + else if(!Curl_cert_hostcheck((const char *)peer_CN, hostname)) { failf(data, "SSL: certificate subject name '%s' does not match " - "target host name '%s'", peer_CN, conn->host.dispname); + "target host name '%s'", peer_CN, dispname); result = CURLE_PEER_FAILED_VERIFICATION; } else { @@ -1703,6 +1711,20 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) struct in_addr addr; #endif #endif + long * const certverifyresult = SSL_IS_PROXY() ? + &data->set.proxy_ssl.certverifyresult : &data->set.ssl.certverifyresult; + const long int ssl_version = SSL_CONN_CONFIG(version); +#ifdef USE_TLS_SRP + const enum CURL_TLSAUTH ssl_authtype = SSL_SET_OPTION(authtype); +#endif + char * const ssl_cert = SSL_SET_OPTION(cert); + const char * const ssl_cert_type = SSL_SET_OPTION(cert_type); + const char * const ssl_cafile = SSL_CONN_CONFIG(CAfile); + const char * const ssl_capath = SSL_CONN_CONFIG(CApath); + const bool verifypeer = SSL_CONN_CONFIG(verifypeer); + const char * const ssl_crlfile = SSL_SET_OPTION(CRLfile); + const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : + conn->host.name; DEBUGASSERT(ssl_connect_1 == connssl->connecting_state); @@ -1711,11 +1733,11 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) if(result) return result; - data->set.ssl.certverifyresult = !X509_V_OK; + *certverifyresult = !X509_V_OK; /* check to see if we've been told to use an explicit SSL/TLS version */ - switch(data->set.ssl.version) { + switch(ssl_version) { case CURL_SSLVERSION_DEFAULT: case CURL_SSLVERSION_TLSv1: case CURL_SSLVERSION_TLSv1_0: @@ -1737,7 +1759,7 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) return CURLE_NOT_BUILT_IN; #else #ifdef USE_TLS_SRP - if(data->set.ssl.authtype == CURL_TLSAUTH_SRP) + if(ssl_authtype == CURL_TLSAUTH_SRP) return CURLE_SSL_CONNECT_ERROR; #endif req_method = SSLv2_client_method(); @@ -1750,7 +1772,7 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) return CURLE_NOT_BUILT_IN; #else #ifdef USE_TLS_SRP - if(data->set.ssl.authtype == CURL_TLSAUTH_SRP) + if(ssl_authtype == CURL_TLSAUTH_SRP) return CURLE_SSL_CONNECT_ERROR; #endif req_method = SSLv3_client_method(); @@ -1838,14 +1860,14 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) #ifdef SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS /* unless the user explicitly ask to allow the protocol vulnerability we use the work-around */ - if(!conn->data->set.ssl_enable_beast) + if(!SSL_SET_OPTION(enable_beast)) ctx_options &= ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS; #endif - switch(data->set.ssl.version) { + switch(ssl_version) { case CURL_SSLVERSION_SSLv3: #ifdef USE_TLS_SRP - if(data->set.ssl.authtype == CURL_TLSAUTH_SRP) { + if(ssl_authtype == CURL_TLSAUTH_SRP) { infof(data, "Set version TLSv1.x for SRP authorisation\n"); } #endif @@ -1979,19 +2001,16 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) } #endif - if(data->set.str[STRING_CERT] || data->set.str[STRING_CERT_TYPE]) { - if(!cert_stuff(conn, - connssl->ctx, - data->set.str[STRING_CERT], - data->set.str[STRING_CERT_TYPE], - data->set.str[STRING_KEY], - data->set.str[STRING_KEY_TYPE])) { + if(ssl_cert || ssl_cert_type) { + if(!cert_stuff(conn, connssl->ctx, ssl_cert, ssl_cert_type, + SSL_SET_OPTION(key), SSL_SET_OPTION(key_type), + SSL_SET_OPTION(key_passwd))) { /* failf() is already done in cert_stuff() */ return CURLE_SSL_CERTPROBLEM; } } - ciphers = data->set.str[STRING_SSL_CIPHER_LIST]; + ciphers = SSL_CONN_CONFIG(cipher_list); if(!ciphers) ciphers = (char *)DEFAULT_CIPHER_SELECTION; if(!SSL_CTX_set_cipher_list(connssl->ctx, ciphers)) { @@ -2001,18 +2020,20 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) infof(data, "Cipher selection: %s\n", ciphers); #ifdef USE_TLS_SRP - if(data->set.ssl.authtype == CURL_TLSAUTH_SRP) { - infof(data, "Using TLS-SRP username: %s\n", data->set.ssl.username); + if(ssl_authtype == CURL_TLSAUTH_SRP) { + char * const ssl_username = SSL_SET_OPTION(username); - if(!SSL_CTX_set_srp_username(connssl->ctx, data->set.ssl.username)) { + infof(data, "Using TLS-SRP username: %s\n", ssl_username); + + if(!SSL_CTX_set_srp_username(connssl->ctx, ssl_username)) { failf(data, "Unable to set SRP user name"); return CURLE_BAD_FUNCTION_ARGUMENT; } - if(!SSL_CTX_set_srp_password(connssl->ctx, data->set.ssl.password)) { + if(!SSL_CTX_set_srp_password(connssl->ctx, SSL_SET_OPTION(password))) { failf(data, "failed setting SRP password"); return CURLE_BAD_FUNCTION_ARGUMENT; } - if(!data->set.str[STRING_SSL_CIPHER_LIST]) { + if(!SSL_CONN_CONFIG(cipher_list)) { infof(data, "Setting cipher list SRP\n"); if(!SSL_CTX_set_cipher_list(connssl->ctx, "SRP")) { @@ -2022,20 +2043,17 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) } } #endif - if(data->set.str[STRING_SSL_CAFILE] || data->set.str[STRING_SSL_CAPATH]) { + + if(ssl_cafile || ssl_capath) { /* tell SSL where to find CA certificates that are used to verify the servers certificate. */ - if(!SSL_CTX_load_verify_locations(connssl->ctx, - data->set.str[STRING_SSL_CAFILE], - data->set.str[STRING_SSL_CAPATH])) { - if(data->set.ssl.verifypeer) { + if(!SSL_CTX_load_verify_locations(connssl->ctx, ssl_cafile, ssl_capath)) { + if(verifypeer) { /* Fail if we insist on successfully verifying the server. */ failf(data, "error setting certificate verify locations:\n" " CAfile: %s\n CApath: %s", - data->set.str[STRING_SSL_CAFILE]? - data->set.str[STRING_SSL_CAFILE]: "none", - data->set.str[STRING_SSL_CAPATH]? - data->set.str[STRING_SSL_CAPATH] : "none"); + ssl_cafile ? ssl_cafile : "none", + ssl_capath ? ssl_capath : "none"); return CURLE_SSL_CACERT_BADFILE; } else { @@ -2052,10 +2070,8 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) infof(data, " CAfile: %s\n" " CApath: %s\n", - data->set.str[STRING_SSL_CAFILE] ? data->set.str[STRING_SSL_CAFILE]: - "none", - data->set.str[STRING_SSL_CAPATH] ? data->set.str[STRING_SSL_CAPATH]: - "none"); + ssl_cafile ? ssl_cafile : "none", + ssl_capath ? ssl_capath : "none"); } #ifdef CURL_CA_FALLBACK else if(data->set.ssl.verifypeer) { @@ -2065,16 +2081,14 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) } #endif - if(data->set.str[STRING_SSL_CRLFILE]) { + if(ssl_crlfile) { /* tell SSL where to find CRL file that is used to check certificate * revocation */ lookup=X509_STORE_add_lookup(SSL_CTX_get_cert_store(connssl->ctx), X509_LOOKUP_file()); if(!lookup || - (!X509_load_crl_file(lookup, data->set.str[STRING_SSL_CRLFILE], - X509_FILETYPE_PEM)) ) { - failf(data, "error loading CRL file: %s", - data->set.str[STRING_SSL_CRLFILE]); + (!X509_load_crl_file(lookup, ssl_crlfile, X509_FILETYPE_PEM)) ) { + failf(data, "error loading CRL file: %s", ssl_crlfile); return CURLE_SSL_CRL_BADFILE; } else { @@ -2083,9 +2097,7 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) X509_STORE_set_flags(SSL_CTX_get_cert_store(connssl->ctx), X509_V_FLAG_CRL_CHECK|X509_V_FLAG_CRL_CHECK_ALL); } - infof(data, - " CRLfile: %s\n", data->set.str[STRING_SSL_CRLFILE] ? - data->set.str[STRING_SSL_CRLFILE]: "none"); + infof(data, " CRLfile: %s\n", ssl_crlfile ? ssl_crlfile: "none"); } /* Try building a chain using issuers in the trusted store first to avoid @@ -2107,8 +2119,7 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) * anyway. In the latter case the result of the verification is checked with * SSL_get_verify_result() below. */ SSL_CTX_set_verify(connssl->ctx, - data->set.ssl.verifypeer?SSL_VERIFY_PEER:SSL_VERIFY_NONE, - NULL); + verifypeer ? SSL_VERIFY_PEER : SSL_VERIFY_NONE, NULL); /* give application a chance to interfere with SSL set up. */ if(data->set.ssl.fsslctx) { @@ -2131,31 +2142,30 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) #if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \ !defined(OPENSSL_NO_OCSP) - if(data->set.ssl.verifystatus) + if(SSL_CONN_CONFIG(verifystatus)) SSL_set_tlsext_status_type(connssl->handle, TLSEXT_STATUSTYPE_ocsp); #endif SSL_set_connect_state(connssl->handle); connssl->server_cert = 0x0; - #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME - if((0 == Curl_inet_pton(AF_INET, conn->host.name, &addr)) && + if((0 == Curl_inet_pton(AF_INET, hostname, &addr)) && #ifdef ENABLE_IPV6 - (0 == Curl_inet_pton(AF_INET6, conn->host.name, &addr)) && + (0 == Curl_inet_pton(AF_INET6, hostname, &addr)) && #endif sni && - !SSL_set_tlsext_host_name(connssl->handle, conn->host.name)) + !SSL_set_tlsext_host_name(connssl->handle, hostname)) infof(data, "WARNING: failed to configure server name indication (SNI) " "TLS extension\n"); #endif /* Check if there's a cached ID we can/should use here! */ - if(conn->ssl_config.sessionid) { + if(data->set.general_ssl.sessionid) { void *ssl_sessionid = NULL; Curl_ssl_sessionid_lock(conn); - if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL)) { + if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL, sockindex)) { /* we got a session id, use it! */ if(!SSL_set_session(connssl->handle, ssl_sessionid)) { Curl_ssl_sessionid_unlock(conn); @@ -2169,8 +2179,16 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) Curl_ssl_sessionid_unlock(conn); } - /* pass the raw socket into the SSL layers */ - if(!SSL_set_fd(connssl->handle, (int)sockfd)) { + if(conn->proxy_ssl[sockindex].use) { + BIO *const bio = BIO_new(BIO_f_ssl()); + DEBUGASSERT(ssl_connection_complete == conn->proxy_ssl[sockindex].state); + DEBUGASSERT(conn->proxy_ssl[sockindex].handle != NULL); + DEBUGASSERT(bio != NULL); + BIO_set_ssl(bio, conn->proxy_ssl[sockindex].handle, FALSE); + SSL_set_bio(connssl->handle, bio, bio); + } + else if(!SSL_set_fd(connssl->handle, (int)sockfd)) { + /* pass the raw socket into the SSL layers */ failf(data, "SSL: SSL_set_fd failed: %s", ERR_error_string(ERR_get_error(), NULL)); return CURLE_SSL_CONNECT_ERROR; @@ -2187,8 +2205,8 @@ static CURLcode ossl_connect_step2(struct connectdata *conn, int sockindex) int err; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; DEBUGASSERT(ssl_connect_2 == connssl->connecting_state - || ssl_connect_2_reading == connssl->connecting_state - || ssl_connect_2_writing == connssl->connecting_state); + || ssl_connect_2_reading == connssl->connecting_state + || ssl_connect_2_writing == connssl->connecting_state); ERR_clear_error(); @@ -2257,8 +2275,11 @@ static CURLcode ossl_connect_step2(struct connectdata *conn, int sockindex) * the SO_ERROR is also lost. */ if(CURLE_SSL_CONNECT_ERROR == result && errdetail == 0) { + const char * const hostname = SSL_IS_PROXY() ? + conn->http_proxy.host.name : conn->host.name; + const long int port = SSL_IS_PROXY() ? conn->port : conn->remote_port; failf(data, "Unknown SSL protocol error in connection to %s:%ld ", - conn->host.name, conn->remote_port); + hostname, port); return result; } @@ -2735,6 +2756,8 @@ static CURLcode servercert(struct connectdata *conn, FILE *fp; char *buffer = data->state.buffer; const char *ptr; + long * const certverifyresult = SSL_IS_PROXY() ? + &data->set.proxy_ssl.certverifyresult : &data->set.ssl.certverifyresult; BIO *mem = BIO_new(BIO_s_mem()); if(data->set.ssl.certinfo) @@ -2750,7 +2773,7 @@ static CURLcode servercert(struct connectdata *conn, return CURLE_PEER_FAILED_VERIFICATION; } - infof(data, "Server certificate:\n"); + infof(data, "%s certificate:\n", SSL_IS_PROXY() ? "Proxy" : "Server"); rc = x509_name_oneline(X509_get_subject_name(connssl->server_cert), buffer, BUFSIZE); @@ -2768,7 +2791,7 @@ static CURLcode servercert(struct connectdata *conn, BIO_free(mem); - if(data->set.ssl.verifyhost) { + if(SSL_CONN_CONFIG(verifyhost)) { result = verifyhost(conn, connssl->server_cert); if(result) { X509_free(connssl->server_cert); @@ -2791,12 +2814,12 @@ static CURLcode servercert(struct connectdata *conn, deallocating the certificate. */ /* e.g. match issuer name with provided issuer certificate */ - if(data->set.str[STRING_SSL_ISSUERCERT]) { - fp = fopen(data->set.str[STRING_SSL_ISSUERCERT], FOPEN_READTEXT); + if(SSL_SET_OPTION(issuercert)) { + fp = fopen(SSL_SET_OPTION(issuercert), FOPEN_READTEXT); if(!fp) { if(strict) failf(data, "SSL: Unable to open issuer cert (%s)", - data->set.str[STRING_SSL_ISSUERCERT]); + SSL_SET_OPTION(issuercert)); X509_free(connssl->server_cert); connssl->server_cert = NULL; return CURLE_SSL_ISSUER_ERROR; @@ -2806,7 +2829,7 @@ static CURLcode servercert(struct connectdata *conn, if(!issuer) { if(strict) failf(data, "SSL: Unable to read issuer cert (%s)", - data->set.str[STRING_SSL_ISSUERCERT]); + SSL_SET_OPTION(issuercert)); X509_free(connssl->server_cert); X509_free(issuer); fclose(fp); @@ -2818,7 +2841,7 @@ static CURLcode servercert(struct connectdata *conn, if(X509_check_issued(issuer, connssl->server_cert) != X509_V_OK) { if(strict) failf(data, "SSL: Certificate issuer check failed (%s)", - data->set.str[STRING_SSL_ISSUERCERT]); + SSL_SET_OPTION(issuercert)); X509_free(connssl->server_cert); X509_free(issuer); connssl->server_cert = NULL; @@ -2826,15 +2849,14 @@ static CURLcode servercert(struct connectdata *conn, } infof(data, " SSL certificate issuer check ok (%s)\n", - data->set.str[STRING_SSL_ISSUERCERT]); + SSL_SET_OPTION(issuercert)); X509_free(issuer); } - lerr = data->set.ssl.certverifyresult = - SSL_get_verify_result(connssl->handle); + lerr = *certverifyresult = SSL_get_verify_result(connssl->handle); - if(data->set.ssl.certverifyresult != X509_V_OK) { - if(data->set.ssl.verifypeer) { + if(*certverifyresult != X509_V_OK) { + if(SSL_CONN_CONFIG(verifypeer)) { /* We probably never reach this, because SSL_connect() will fail and we return earlier if verifypeer is set? */ if(strict) @@ -2853,7 +2875,7 @@ static CURLcode servercert(struct connectdata *conn, #if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \ !defined(OPENSSL_NO_OCSP) - if(data->set.ssl.verifystatus) { + if(SSL_CONN_CONFIG(verifystatus)) { result = verifystatus(conn, connssl); if(result) { X509_free(connssl->server_cert); @@ -2889,7 +2911,7 @@ static CURLcode ossl_connect_step3(struct connectdata *conn, int sockindex) DEBUGASSERT(ssl_connect_3 == connssl->connecting_state); - if(conn->ssl_config.sessionid) { + if(data->set.general_ssl.sessionid) { bool incache; SSL_SESSION *our_ssl_sessionid; void *old_ssl_sessionid = NULL; @@ -2901,7 +2923,8 @@ static CURLcode ossl_connect_step3(struct connectdata *conn, int sockindex) regardless of its state. */ Curl_ssl_sessionid_lock(conn); - incache = !(Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL)); + incache = !(Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL, + sockindex)); if(incache) { if(old_ssl_sessionid != our_ssl_sessionid) { infof(data, "old SSL session ID is stale, removing\n"); @@ -2912,7 +2935,7 @@ static CURLcode ossl_connect_step3(struct connectdata *conn, int sockindex) if(!incache) { result = Curl_ssl_addsessionid(conn, our_ssl_sessionid, - 0 /* unknown size */); + 0 /* unknown size */, sockindex); if(result) { Curl_ssl_sessionid_unlock(conn); failf(data, "failed to store ssl session"); @@ -2936,8 +2959,8 @@ static CURLcode ossl_connect_step3(struct connectdata *conn, int sockindex) * operations. */ - result = servercert(conn, connssl, - (data->set.ssl.verifypeer || data->set.ssl.verifyhost)); + result = servercert(conn, connssl, (SSL_CONN_CONFIG(verifypeer) || + SSL_CONN_CONFIG(verifyhost))); if(!result) connssl->connecting_state = ssl_connect_done; @@ -3085,7 +3108,10 @@ bool Curl_ossl_data_pending(const struct connectdata *conn, int connindex) { if(conn->ssl[connindex].handle) /* SSL is in use */ - return (0 != SSL_pending(conn->ssl[connindex].handle)) ? TRUE : FALSE; + return (0 != SSL_pending(conn->ssl[connindex].handle) || + (conn->proxy_ssl[connindex].handle && + 0 != SSL_pending(conn->proxy_ssl[connindex].handle))) ? + TRUE : FALSE; else return FALSE; } @@ -3130,8 +3156,18 @@ static ssize_t ossl_send(struct connectdata *conn, /* A failure in the SSL library occurred, usually a protocol error. The OpenSSL error queue contains more information on the error. */ sslerror = ERR_get_error(); - failf(conn->data, "SSL_write() error: %s", - ossl_strerror(sslerror, error_buffer, sizeof(error_buffer))); + if(sslerror == + ERR_PACK(ERR_LIB_SSL, SSL_F_SSL3_WRITE_PENDING, SSL_R_BIO_NOT_SET) && + conn->ssl[sockindex].state == ssl_connection_complete && + conn->proxy_ssl[sockindex].state == ssl_connection_complete) { + char ver[120]; + Curl_ossl_version(ver, 120); + failf(conn->data, "Error: %s does not support double SSL tunneling.", + ver); + } + else + failf(conn->data, "SSL_write() error: %s", + ossl_strerror(sslerror, error_buffer, sizeof(error_buffer))); *curlcode = CURLE_SEND_ERROR; return -1; } diff --git a/lib/vtls/polarssl.c b/lib/vtls/polarssl.c index a6a769091..d6b0f238e 100644 --- a/lib/vtls/polarssl.c +++ b/lib/vtls/polarssl.c @@ -147,12 +147,16 @@ polarssl_connect_step1(struct connectdata *conn, { struct Curl_easy *data = conn->data; struct ssl_connect_data* connssl = &conn->ssl[sockindex]; + const char *capath = SSL_CONN_CONFIG(CApath); + const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : + conn->host.name; + const long int port = SSL_IS_PROXY() ? conn->port : conn->remote_port; int ret = -1; char errorbuf[128]; errorbuf[0]=0; /* PolarSSL only supports SSLv3 and TLSv1 */ - if(data->set.ssl.version == CURL_SSLVERSION_SSLv2) { + if(SSL_CONN_CONFIG(version) == CURL_SSLVERSION_SSLv2) { failf(data, "PolarSSL does not support SSLv2"); return CURLE_SSL_CONNECT_ERROR; } @@ -180,30 +184,29 @@ polarssl_connect_step1(struct connectdata *conn, /* Load the trusted CA */ memset(&connssl->cacert, 0, sizeof(x509_crt)); - if(data->set.str[STRING_SSL_CAFILE]) { + if(SSL_CONN_CONFIG(CAfile)) { ret = x509_crt_parse_file(&connssl->cacert, - data->set.str[STRING_SSL_CAFILE]); + SSL_CONN_CONFIG(CAfile)); if(ret<0) { error_strerror(ret, errorbuf, sizeof(errorbuf)); failf(data, "Error reading ca cert file %s - PolarSSL: (-0x%04X) %s", - data->set.str[STRING_SSL_CAFILE], -ret, errorbuf); + SSL_CONN_CONFIG(CAfile), -ret, errorbuf); - if(data->set.ssl.verifypeer) + if(SSL_CONN_CONFIG(verifypeer)) return CURLE_SSL_CACERT_BADFILE; } } - if(data->set.str[STRING_SSL_CAPATH]) { - ret = x509_crt_parse_path(&connssl->cacert, - data->set.str[STRING_SSL_CAPATH]); + if(capath) { + ret = x509_crt_parse_path(&connssl->cacert, capath); if(ret<0) { error_strerror(ret, errorbuf, sizeof(errorbuf)); failf(data, "Error reading ca cert path %s - PolarSSL: (-0x%04X) %s", - data->set.str[STRING_SSL_CAPATH], -ret, errorbuf); + capath, -ret, errorbuf); - if(data->set.ssl.verifypeer) + if(SSL_CONN_CONFIG(verifypeer)) return CURLE_SSL_CACERT_BADFILE; } } @@ -211,25 +214,25 @@ polarssl_connect_step1(struct connectdata *conn, /* Load the client certificate */ memset(&connssl->clicert, 0, sizeof(x509_crt)); - if(data->set.str[STRING_CERT]) { + if(SSL_SET_OPTION(cert)) { ret = x509_crt_parse_file(&connssl->clicert, - data->set.str[STRING_CERT]); + SSL_SET_OPTION(cert)); if(ret) { error_strerror(ret, errorbuf, sizeof(errorbuf)); failf(data, "Error reading client cert file %s - PolarSSL: (-0x%04X) %s", - data->set.str[STRING_CERT], -ret, errorbuf); + SSL_SET_OPTION(cert), -ret, errorbuf); return CURLE_SSL_CERTPROBLEM; } } /* Load the client private key */ - if(data->set.str[STRING_KEY]) { + if(SSL_SET_OPTION(key)) { pk_context pk; pk_init(&pk); - ret = pk_parse_keyfile(&pk, data->set.str[STRING_KEY], - data->set.str[STRING_KEY_PASSWD]); + ret = pk_parse_keyfile(&pk, SSL_SET_OPTION(key), + SSL_SET_OPTION(key_passwd)); if(ret == 0 && !pk_can_do(&pk, POLARSSL_PK_RSA)) ret = POLARSSL_ERR_PK_TYPE_MISMATCH; if(ret == 0) @@ -241,7 +244,7 @@ polarssl_connect_step1(struct connectdata *conn, if(ret) { error_strerror(ret, errorbuf, sizeof(errorbuf)); failf(data, "Error reading private key %s - PolarSSL: (-0x%04X) %s", - data->set.str[STRING_KEY], -ret, errorbuf); + SSL_SET_OPTION(key), -ret, errorbuf); return CURLE_SSL_CERTPROBLEM; } @@ -250,28 +253,27 @@ polarssl_connect_step1(struct connectdata *conn, /* Load the CRL */ memset(&connssl->crl, 0, sizeof(x509_crl)); - if(data->set.str[STRING_SSL_CRLFILE]) { + if(SSL_SET_OPTION(CRLfile)) { ret = x509_crl_parse_file(&connssl->crl, - data->set.str[STRING_SSL_CRLFILE]); + SSL_SET_OPTION(CRLfile)); if(ret) { error_strerror(ret, errorbuf, sizeof(errorbuf)); failf(data, "Error reading CRL file %s - PolarSSL: (-0x%04X) %s", - data->set.str[STRING_SSL_CRLFILE], -ret, errorbuf); + SSL_SET_OPTION(CRLfile), -ret, errorbuf); return CURLE_SSL_CRL_BADFILE; } } - infof(data, "PolarSSL: Connecting to %s:%d\n", - conn->host.name, conn->remote_port); + infof(data, "PolarSSL: Connecting to %s:%d\n", hostname, port); if(ssl_init(&connssl->ssl)) { failf(data, "PolarSSL: ssl_init failed"); return CURLE_SSL_CONNECT_ERROR; } - switch(data->set.ssl.version) { + switch(SSL_CONN_CONFIG(version)) { case CURL_SSLVERSION_DEFAULT: case CURL_SSLVERSION_TLSv1: ssl_set_min_version(&connssl->ssl, SSL_MAJOR_VERSION_3, @@ -325,11 +327,11 @@ polarssl_connect_step1(struct connectdata *conn, ssl_set_ciphersuites(&connssl->ssl, ssl_list_ciphersuites()); /* Check if there's a cached ID we can/should use here! */ - if(conn->ssl_config.sessionid) { + if(data->set.general_ssl.sessionid) { void *old_session = NULL; Curl_ssl_sessionid_lock(conn); - if(!Curl_ssl_getsessionid(conn, &old_session, NULL)) { + if(!Curl_ssl_getsessionid(conn, &old_session, NULL, sockindex)) { ret = ssl_set_session(&connssl->ssl, old_session); if(ret) { Curl_ssl_sessionid_unlock(conn); @@ -344,12 +346,12 @@ polarssl_connect_step1(struct connectdata *conn, ssl_set_ca_chain(&connssl->ssl, &connssl->cacert, &connssl->crl, - conn->host.name); + hostname); ssl_set_own_cert_rsa(&connssl->ssl, &connssl->clicert, &connssl->rsa); - if(ssl_set_hostname(&connssl->ssl, conn->host.name)) { + if(ssl_set_hostname(&connssl->ssl, hostname)) { /* ssl_set_hostname() sets the name to use in CN/SAN checks *and* the name to set in the SNI extension. So even if curl connects to a host specified as an IP address, this function must be used. */ @@ -428,7 +430,7 @@ polarssl_connect_step2(struct connectdata *conn, ret = ssl_get_verify_result(&conn->ssl[sockindex].ssl); - if(ret && data->set.ssl.verifypeer) { + if(ret && SSL_CONN_CONFIG(verifypeer)) { if(ret & BADCERT_EXPIRED) failf(data, "Cert verify failed: BADCERT_EXPIRED"); @@ -549,7 +551,7 @@ polarssl_connect_step3(struct connectdata *conn, DEBUGASSERT(ssl_connect_3 == connssl->connecting_state); - if(conn->ssl_config.sessionid) { + if(data->set.general_ssl.sessionid) { int ret; ssl_session *our_ssl_sessionid; void *old_ssl_sessionid = NULL; @@ -568,10 +570,10 @@ polarssl_connect_step3(struct connectdata *conn, /* If there's already a matching session in the cache, delete it */ Curl_ssl_sessionid_lock(conn); - if(!Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL)) + if(!Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL, sockindex)) Curl_ssl_delsessionid(conn, old_ssl_sessionid); - retcode = Curl_ssl_addsessionid(conn, our_ssl_sessionid, 0); + retcode = Curl_ssl_addsessionid(conn, our_ssl_sessionid, 0, sockindex); Curl_ssl_sessionid_unlock(conn); if(retcode) { free(our_ssl_sessionid); diff --git a/lib/vtls/schannel.c b/lib/vtls/schannel.c index 6044bf1b0..7b20c2656 100644 --- a/lib/vtls/schannel.c +++ b/lib/vtls/schannel.c @@ -142,9 +142,9 @@ schannel_connect_step1(struct connectdata *conn, int sockindex) connssl->cred = NULL; /* check for an existing re-usable credential handle */ - if(conn->ssl_config.sessionid) { + if(data->set.general_ssl.sessionid) { Curl_ssl_sessionid_lock(conn); - if(!Curl_ssl_getsessionid(conn, (void **)&old_cred, NULL)) { + if(!Curl_ssl_getsessionid(conn, (void **)&old_cred, NULL, sockindex)) { connssl->cred = old_cred; infof(data, "schannel: re-using existing credential handle\n"); @@ -161,7 +161,7 @@ schannel_connect_step1(struct connectdata *conn, int sockindex) memset(&schannel_cred, 0, sizeof(schannel_cred)); schannel_cred.dwVersion = SCHANNEL_CRED_VERSION; - if(data->set.ssl.verifypeer) { + if(conn->ssl_config.verifypeer) { #ifdef _WIN32_WCE /* certificate validation on CE doesn't seem to work right; we'll do it following a more manual process. */ @@ -170,13 +170,14 @@ schannel_connect_step1(struct connectdata *conn, int sockindex) SCH_CRED_IGNORE_REVOCATION_OFFLINE; #else schannel_cred.dwFlags = SCH_CRED_AUTO_CRED_VALIDATION; - if(data->set.ssl_no_revoke) + /* TODO s/data->set.ssl.no_revoke/SSL_SET_OPTION(no_revoke)/g */ + if(data->set.ssl.no_revoke) schannel_cred.dwFlags |= SCH_CRED_IGNORE_NO_REVOCATION_CHECK | SCH_CRED_IGNORE_REVOCATION_OFFLINE; else schannel_cred.dwFlags |= SCH_CRED_REVOCATION_CHECK_CHAIN; #endif - if(data->set.ssl_no_revoke) + if(data->set.ssl.no_revoke) infof(data, "schannel: disabled server certificate revocation " "checks\n"); else @@ -189,14 +190,14 @@ schannel_connect_step1(struct connectdata *conn, int sockindex) infof(data, "schannel: disabled server certificate revocation checks\n"); } - if(!data->set.ssl.verifyhost) { + if(!conn->ssl_config.verifyhost) { schannel_cred.dwFlags |= SCH_CRED_NO_SERVERNAME_CHECK; infof(data, "schannel: verifyhost setting prevents Schannel from " "comparing the supplied target name with the subject " "names in server certificates. Also disables SNI.\n"); } - switch(data->set.ssl.version) { + switch(conn->ssl_config.version) { case CURL_SSLVERSION_DEFAULT: case CURL_SSLVERSION_TLSv1: schannel_cred.grbitEnabledProtocols = SP_PROT_TLS1_0_CLIENT | @@ -628,7 +629,7 @@ schannel_connect_step2(struct connectdata *conn, int sockindex) #ifdef _WIN32_WCE /* Windows CE doesn't do any server certificate validation. We have to do it manually. */ - if(data->set.ssl.verifypeer) + if(conn->ssl_config.verifypeer) return verify_certificate(conn, sockindex); #endif @@ -706,12 +707,13 @@ schannel_connect_step3(struct connectdata *conn, int sockindex) #endif /* save the current session data for possible re-use */ - if(conn->ssl_config.sessionid) { + if(data->set.general_ssl.sessionid) { bool incache; struct curl_schannel_cred *old_cred = NULL; Curl_ssl_sessionid_lock(conn); - incache = !(Curl_ssl_getsessionid(conn, (void **)&old_cred, NULL)); + incache = !(Curl_ssl_getsessionid(conn, (void **)&old_cred, NULL, + sockindex)); if(incache) { if(old_cred != connssl->cred) { infof(data, "schannel: old credential handle is stale, removing\n"); @@ -722,7 +724,8 @@ schannel_connect_step3(struct connectdata *conn, int sockindex) } if(!incache) { result = Curl_ssl_addsessionid(conn, (void *)connssl->cred, - sizeof(struct curl_schannel_cred)); + sizeof(struct curl_schannel_cred), + sockindex); if(result) { Curl_ssl_sessionid_unlock(conn); failf(data, "schannel: failed to store credential handle"); @@ -1551,7 +1554,7 @@ static CURLcode verify_certificate(struct connectdata *conn, int sockindex) NULL, pCertContextServer->hCertStore, &ChainPara, - (data->set.ssl_no_revoke ? 0 : + (data->set.ssl.no_revoke ? 0 : CERT_CHAIN_REVOCATION_CHECK_CHAIN), NULL, &pChainContext)) { @@ -1587,7 +1590,7 @@ static CURLcode verify_certificate(struct connectdata *conn, int sockindex) } if(result == CURLE_OK) { - if(data->set.ssl.verifyhost) { + if(conn->ssl_config.verifyhost) { TCHAR cert_hostname_buff[128]; xcharp_u hostname; xcharp_u cert_hostname; diff --git a/lib/vtls/vtls.c b/lib/vtls/vtls.c index ed65b46b9..07d64ab9d 100644 --- a/lib/vtls/vtls.c +++ b/lib/vtls/vtls.c @@ -65,6 +65,7 @@ #include "url.h" #include "progress.h" #include "share.h" +#include "multiif.h" #include "timeval.h" #include "curl_md5.h" #include "warnless.h" @@ -80,94 +81,48 @@ (data->share->specifier & \ (1<var) { \ + dest->var = strdup(source->var); \ + if(!dest->var) \ + return FALSE; \ + } \ + else \ + dest->var = NULL; bool -Curl_ssl_config_matches(struct ssl_config_data* data, - struct ssl_config_data* needle) +Curl_ssl_config_matches(struct ssl_primary_config* data, + struct ssl_primary_config* needle) { if((data->version == needle->version) && (data->verifypeer == needle->verifypeer) && (data->verifyhost == needle->verifyhost) && - safe_strequal(data->CApath, needle->CApath) && - safe_strequal(data->CAfile, needle->CAfile) && - safe_strequal(data->clientcert, needle->clientcert) && - safe_strequal(data->cipher_list, needle->cipher_list)) + Curl_safe_strcasecompare(data->CApath, needle->CApath) && + Curl_safe_strcasecompare(data->CAfile, needle->CAfile) && + Curl_safe_strcasecompare(data->clientcert, needle->clientcert) && + Curl_safe_strcasecompare(data->cipher_list, needle->cipher_list)) return TRUE; return FALSE; } bool -Curl_clone_ssl_config(struct ssl_config_data *source, - struct ssl_config_data *dest) +Curl_clone_primary_ssl_config(struct ssl_primary_config *source, + struct ssl_primary_config *dest) { - dest->sessionid = source->sessionid; dest->verifyhost = source->verifyhost; dest->verifypeer = source->verifypeer; dest->version = source->version; - if(source->CAfile) { - dest->CAfile = strdup(source->CAfile); - if(!dest->CAfile) - return FALSE; - } - else - dest->CAfile = NULL; - - if(source->CApath) { - dest->CApath = strdup(source->CApath); - if(!dest->CApath) - return FALSE; - } - else - dest->CApath = NULL; - - if(source->cipher_list) { - dest->cipher_list = strdup(source->cipher_list); - if(!dest->cipher_list) - return FALSE; - } - else - dest->cipher_list = NULL; - - if(source->egdsocket) { - dest->egdsocket = strdup(source->egdsocket); - if(!dest->egdsocket) - return FALSE; - } - else - dest->egdsocket = NULL; - - if(source->random_file) { - dest->random_file = strdup(source->random_file); - if(!dest->random_file) - return FALSE; - } - else - dest->random_file = NULL; - - if(source->clientcert) { - dest->clientcert = strdup(source->clientcert); - if(!dest->clientcert) - return FALSE; - dest->sessionid = FALSE; - } - else - dest->clientcert = NULL; - + CLONE_STRING(CAfile); + CLONE_STRING(CApath); + CLONE_STRING(cipher_list); + CLONE_STRING(egdsocket); + CLONE_STRING(random_file); + CLONE_STRING(clientcert); return TRUE; } -void Curl_free_ssl_config(struct ssl_config_data* sslc) +void Curl_free_primary_ssl_config(struct ssl_primary_config* sslc) { Curl_safefree(sslc->CAfile); Curl_safefree(sslc->CApath); @@ -217,19 +172,41 @@ void Curl_ssl_cleanup(void) static bool ssl_prefs_check(struct Curl_easy *data) { /* check for CURLOPT_SSLVERSION invalid parameter value */ - if((data->set.ssl.version < 0) - || (data->set.ssl.version >= CURL_SSLVERSION_LAST)) { + if((data->set.ssl.primary.version < 0) + || (data->set.ssl.primary.version >= CURL_SSLVERSION_LAST)) { failf(data, "Unrecognized parameter value passed via CURLOPT_SSLVERSION"); return FALSE; } return TRUE; } +static CURLcode +ssl_connect_init_proxy(struct connectdata *conn, int sockindex) { + DEBUGASSERT(conn->bits.proxy_ssl_connected[sockindex]); + if(ssl_connection_complete == conn->ssl[sockindex].state && + !conn->proxy_ssl[sockindex].use) { +#if defined(USE_OPENSSL) || defined(USE_GNUTLS) || defined(USE_NSS) || \ + defined(USE_GSKIT) + conn->proxy_ssl[sockindex] = conn->ssl[sockindex]; + memset(&conn->ssl[sockindex], 0, sizeof(conn->ssl[sockindex])); +#else + return CURLE_NOT_BUILT_IN; +#endif + } + return CURLE_OK; +} + CURLcode Curl_ssl_connect(struct connectdata *conn, int sockindex) { CURLcode result; + if(conn->bits.proxy_ssl_connected[sockindex]) { + result = ssl_connect_init_proxy(conn, sockindex); + if(result) + return result; + } + if(!ssl_prefs_check(conn->data)) return CURLE_SSL_CONNECT_ERROR; @@ -250,6 +227,11 @@ Curl_ssl_connect_nonblocking(struct connectdata *conn, int sockindex, bool *done) { CURLcode result; + if(conn->bits.proxy_ssl_connected[sockindex]) { + result = ssl_connect_init_proxy(conn, sockindex); + if(result) + return result; + } if(!ssl_prefs_check(conn->data)) return CURLE_SSL_CONNECT_ERROR; @@ -292,7 +274,8 @@ void Curl_ssl_sessionid_unlock(struct connectdata *conn) */ bool Curl_ssl_getsessionid(struct connectdata *conn, void **ssl_sessionid, - size_t *idsize) /* set 0 if unknown */ + size_t *idsize, /* set 0 if unknown */ + int sockindex) { struct curl_ssl_session *check; struct Curl_easy *data = conn->data; @@ -300,11 +283,18 @@ bool Curl_ssl_getsessionid(struct connectdata *conn, long *general_age; bool no_match = TRUE; + const bool isProxy = CONNECT_PROXY_SSL(); + struct ssl_primary_config * const ssl_config = isProxy ? + &conn->proxy_ssl_config : + &conn->ssl_config; + const char * const name = isProxy ? conn->http_proxy.host.name : + conn->host.name; + int port = isProxy ? (int)conn->port : conn->remote_port; *ssl_sessionid = NULL; - DEBUGASSERT(conn->ssl_config.sessionid); + DEBUGASSERT(data->set.general_ssl.sessionid); - if(!conn->ssl_config.sessionid) + if(!data->set.general_ssl.sessionid) /* session ID re-use is disabled */ return TRUE; @@ -314,21 +304,21 @@ bool Curl_ssl_getsessionid(struct connectdata *conn, else general_age = &data->state.sessionage; - for(i = 0; i < data->set.ssl.max_ssl_sessions; i++) { + for(i = 0; i < data->set.general_ssl.max_ssl_sessions; i++) { check = &data->state.session[i]; if(!check->sessionid) /* not session ID means blank entry */ continue; - if(strcasecompare(conn->host.name, check->name) && + if(strcasecompare(name, check->name) && ((!conn->bits.conn_to_host && !check->conn_to_host) || (conn->bits.conn_to_host && check->conn_to_host && strcasecompare(conn->conn_to_host.name, check->conn_to_host))) && ((!conn->bits.conn_to_port && check->conn_to_port == -1) || (conn->bits.conn_to_port && check->conn_to_port != -1 && conn->conn_to_port == check->conn_to_port)) && - (conn->remote_port == check->remote_port) && + (port == check->remote_port) && strcasecompare(conn->handler->scheme, check->scheme) && - Curl_ssl_config_matches(&conn->ssl_config, &check->ssl_config)) { + Curl_ssl_config_matches(ssl_config, &check->ssl_config)) { /* yes, we have a session ID! */ (*general_age)++; /* increase general age */ check->age = *general_age; /* set this as used in this age */ @@ -357,7 +347,7 @@ void Curl_ssl_kill_session(struct curl_ssl_session *session) session->sessionid = NULL; session->age = 0; /* fresh */ - Curl_free_ssl_config(&session->ssl_config); + Curl_free_primary_ssl_config(&session->ssl_config); Curl_safefree(session->name); Curl_safefree(session->conn_to_host); @@ -372,7 +362,7 @@ void Curl_ssl_delsessionid(struct connectdata *conn, void *ssl_sessionid) size_t i; struct Curl_easy *data=conn->data; - for(i = 0; i < data->set.ssl.max_ssl_sessions; i++) { + for(i = 0; i < data->set.general_ssl.max_ssl_sessions; i++) { struct curl_ssl_session *check = &data->state.session[i]; if(check->sessionid == ssl_sessionid) { @@ -390,7 +380,8 @@ void Curl_ssl_delsessionid(struct connectdata *conn, void *ssl_sessionid) */ CURLcode Curl_ssl_addsessionid(struct connectdata *conn, void *ssl_sessionid, - size_t idsize) + size_t idsize, + int sockindex) { size_t i; struct Curl_easy *data=conn->data; /* the mother of all structs */ @@ -400,10 +391,14 @@ CURLcode Curl_ssl_addsessionid(struct connectdata *conn, char *clone_conn_to_host; int conn_to_port; long *general_age; + const bool isProxy = CONNECT_PROXY_SSL(); + struct ssl_primary_config * const ssl_config = isProxy ? + &conn->proxy_ssl_config : + &conn->ssl_config; - DEBUGASSERT(conn->ssl_config.sessionid); + DEBUGASSERT(data->set.general_ssl.sessionid); - clone_host = strdup(conn->host.name); + clone_host = strdup(isProxy ? conn->http_proxy.host.name : conn->host.name); if(!clone_host) return CURLE_OUT_OF_MEMORY; /* bail out */ @@ -434,14 +429,14 @@ CURLcode Curl_ssl_addsessionid(struct connectdata *conn, } /* find an empty slot for us, or find the oldest */ - for(i = 1; (i < data->set.ssl.max_ssl_sessions) && + for(i = 1; (i < data->set.general_ssl.max_ssl_sessions) && data->state.session[i].sessionid; i++) { if(data->state.session[i].age < oldest_age) { oldest_age = data->state.session[i].age; store = &data->state.session[i]; } } - if(i == data->set.ssl.max_ssl_sessions) + if(i == data->set.general_ssl.max_ssl_sessions) /* cache is full, we must "kill" the oldest entry! */ Curl_ssl_kill_session(store); else @@ -457,10 +452,11 @@ CURLcode Curl_ssl_addsessionid(struct connectdata *conn, store->name = clone_host; /* clone host name */ store->conn_to_host = clone_conn_to_host; /* clone connect to host name */ store->conn_to_port = conn_to_port; /* connect to port number */ - store->remote_port = conn->remote_port; /* port number */ + /* port number */ + store->remote_port = isProxy ? (int)conn->port : conn->remote_port; store->scheme = conn->handler->scheme; - if(!Curl_clone_ssl_config(&conn->ssl_config, &store->ssl_config)) { + if(!Curl_clone_primary_ssl_config(ssl_config, &store->ssl_config)) { store->sessionid = NULL; /* let caller free sessionid */ free(clone_host); free(clone_conn_to_host); @@ -476,7 +472,7 @@ void Curl_ssl_close_all(struct Curl_easy *data) size_t i; /* kill the session ID cache if not shared */ if(data->state.session && !SSLSESSION_SHARED(data)) { - for(i = 0; i < data->set.ssl.max_ssl_sessions; i++) + for(i = 0; i < data->set.general_ssl.max_ssl_sessions; i++) /* the single-killer function handles empty table slots */ Curl_ssl_kill_session(&data->state.session[i]); @@ -487,6 +483,43 @@ void Curl_ssl_close_all(struct Curl_easy *data) curlssl_close_all(data); } +#if defined(USE_SSLEAY) || defined(USE_GNUTLS) || defined(USE_SCHANNEL) || \ + defined(USE_DARWINSSL) || defined(USE_NSS) +/* This function is for OpenSSL, GnuTLS, darwinssl, and schannel only. */ +int Curl_ssl_getsock(struct connectdata *conn, curl_socket_t *socks, + int numsocks) +{ + struct ssl_connect_data *connssl = &conn->ssl[FIRSTSOCKET]; + + if(!numsocks) + return GETSOCK_BLANK; + + if(connssl->connecting_state == ssl_connect_2_writing) { + /* write mode */ + socks[0] = conn->sock[FIRSTSOCKET]; + return GETSOCK_WRITESOCK(0); + } + else if(connssl->connecting_state == ssl_connect_2_reading) { + /* read mode */ + socks[0] = conn->sock[FIRSTSOCKET]; + return GETSOCK_READSOCK(0); + } + + return GETSOCK_BLANK; +} +#else +int Curl_ssl_getsock(struct connectdata *conn, + curl_socket_t *socks, + int numsocks) +{ + (void)conn; + (void)socks; + (void)numsocks; + return GETSOCK_BLANK; +} +/* USE_SSLEAY || USE_GNUTLS || USE_SCHANNEL || USE_DARWINSSL || USE_NSS */ +#endif + void Curl_ssl_close(struct connectdata *conn, int sockindex) { DEBUGASSERT((sockindex <= 1) && (sockindex >= -1)); @@ -544,7 +577,7 @@ CURLcode Curl_ssl_initsessions(struct Curl_easy *data, size_t amount) return CURLE_OUT_OF_MEMORY; /* store the info in the SSL section */ - data->set.ssl.max_ssl_sessions = amount; + data->set.general_ssl.max_ssl_sessions = amount; data->state.session = session; data->state.sessionage = 1; /* this is brand new */ return CURLE_OK; diff --git a/lib/vtls/vtls.h b/lib/vtls/vtls.h index 69d206f52..88fdb9ab2 100644 --- a/lib/vtls/vtls.h +++ b/lib/vtls/vtls.h @@ -50,11 +50,24 @@ #define ALPN_HTTP_1_1_LENGTH 8 #define ALPN_HTTP_1_1 "http/1.1" -bool Curl_ssl_config_matches(struct ssl_config_data* data, - struct ssl_config_data* needle); -bool Curl_clone_ssl_config(struct ssl_config_data* source, - struct ssl_config_data* dest); -void Curl_free_ssl_config(struct ssl_config_data* sslc); +/* set of helper macros for the backends to access the correct fields. For the + proxy or for the remote host - to properly support HTTPS proxy */ + +#define SSL_IS_PROXY() (CURLPROXY_HTTPS == conn->http_proxy.proxytype && \ + ssl_connection_complete != conn->proxy_ssl[conn->sock[SECONDARYSOCKET] == \ + CURL_SOCKET_BAD ? FIRSTSOCKET : SECONDARYSOCKET].state) +#define SSL_SET_OPTION(var) (SSL_IS_PROXY() ? data->set.proxy_ssl.var : \ + data->set.ssl.var) +#define SSL_CONN_CONFIG(var) (SSL_IS_PROXY() ? \ + conn->proxy_ssl_config.var : conn->ssl_config.var) + +bool Curl_ssl_config_matches(struct ssl_primary_config* data, + struct ssl_primary_config* needle); +bool Curl_clone_primary_ssl_config(struct ssl_primary_config *source, + struct ssl_primary_config *dest); +void Curl_free_primary_ssl_config(struct ssl_primary_config* sslc); +int Curl_ssl_getsock(struct connectdata *conn, curl_socket_t *socks, + int numsocks); int Curl_ssl_backend(void); @@ -114,7 +127,8 @@ void Curl_ssl_sessionid_unlock(struct connectdata *conn); */ bool Curl_ssl_getsessionid(struct connectdata *conn, void **ssl_sessionid, - size_t *idsize); /* set 0 if unknown */ + size_t *idsize, /* set 0 if unknown */ + int sockindex); /* add a new session ID * Sessionid mutex must be locked (see Curl_ssl_sessionid_lock). * Caller must ensure that it has properly shared ownership of this sessionid @@ -122,7 +136,8 @@ bool Curl_ssl_getsessionid(struct connectdata *conn, */ CURLcode Curl_ssl_addsessionid(struct connectdata *conn, void *ssl_sessionid, - size_t idsize); + size_t idsize, + int sockindex); /* Kill a single session ID entry in the cache * Sessionid mutex must be locked (see Curl_ssl_sessionid_lock). * This will call engine-specific curlssl_session_free function, which must diff --git a/lib/x509asn1.c b/lib/x509asn1.c index dc8aa81f3..5540406a0 100644 --- a/lib/x509asn1.c +++ b/lib/x509asn1.c @@ -1078,6 +1078,11 @@ CURLcode Curl_verifyhost(struct connectdata * conn, int matched = -1; size_t addrlen = (size_t) -1; ssize_t len; + const char * const hostname = SSL_IS_PROXY()? conn->http_proxy.host.name: + conn->host.name; + const char * const dispname = SSL_IS_PROXY()? + conn->http_proxy.host.dispname: + conn->host.dispname; #ifdef ENABLE_IPV6 struct in6_addr addr; #else @@ -1087,7 +1092,7 @@ CURLcode Curl_verifyhost(struct connectdata * conn, /* Verify that connection server matches info in X509 certificate at `beg'..`end'. */ - if(!data->set.ssl.verifyhost) + if(!SSL_CONN_CONFIG(verifyhost)) return CURLE_OK; if(Curl_parseX509(&cert, beg, end)) @@ -1095,11 +1100,11 @@ CURLcode Curl_verifyhost(struct connectdata * conn, /* Get the server IP address. */ #ifdef ENABLE_IPV6 - if(conn->bits.ipv6_ip && Curl_inet_pton(AF_INET6, conn->host.name, &addr)) + if(conn->bits.ipv6_ip && Curl_inet_pton(AF_INET6, hostname, &addr)) addrlen = sizeof(struct in6_addr); else #endif - if(Curl_inet_pton(AF_INET, conn->host.name, &addr)) + if(Curl_inet_pton(AF_INET, hostname, &addr)) addrlen = sizeof(struct in_addr); /* Process extensions. */ @@ -1122,7 +1127,7 @@ CURLcode Curl_verifyhost(struct connectdata * conn, len = utf8asn1str(&dnsname, CURL_ASN1_IA5_STRING, name.beg, name.end); if(len > 0 && (size_t)len == strlen(dnsname)) - matched = Curl_cert_hostcheck(dnsname, conn->host.name); + matched = Curl_cert_hostcheck(dnsname, hostname); else matched = 0; free(dnsname); @@ -1140,12 +1145,12 @@ CURLcode Curl_verifyhost(struct connectdata * conn, switch (matched) { case 1: /* an alternative name matched the server hostname */ - infof(data, "\t subjectAltName: %s matched\n", conn->host.dispname); + infof(data, "\t subjectAltName: %s matched\n", dispname); return CURLE_OK; case 0: /* an alternative name field existed, but didn't match and then we MUST fail */ - infof(data, "\t subjectAltName does not match %s\n", conn->host.dispname); + infof(data, "\t subjectAltName does not match %s\n", dispname); return CURLE_PEER_FAILED_VERIFICATION; } @@ -1177,14 +1182,14 @@ CURLcode Curl_verifyhost(struct connectdata * conn, } if(strlen(dnsname) != (size_t) len) /* Nul byte in string ? */ failf(data, "SSL: illegal cert name field"); - else if(Curl_cert_hostcheck((const char *) dnsname, conn->host.name)) { + else if(Curl_cert_hostcheck((const char *) dnsname, hostname)) { infof(data, "\t common name: %s (matched)\n", dnsname); free(dnsname); return CURLE_OK; } else failf(data, "SSL: certificate subject name '%s' does not match " - "target host name '%s'", dnsname, conn->host.dispname); + "target host name '%s'", dnsname, dispname); free(dnsname); } diff --git a/packages/OS400/README.OS400 b/packages/OS400/README.OS400 index 24cf39e64..23924e36c 100644 --- a/packages/OS400/README.OS400 +++ b/packages/OS400/README.OS400 @@ -94,7 +94,19 @@ options: CURLOPT_PROXYPASSWORD CURLOPT_PROXYUSERNAME CURLOPT_PROXYUSERPWD + CURLOPT_PROXY_CAINFO + CURLOPT_PROXY_CAPATH + CURLOPT_PROXY_CRLFILE + CURLOPT_PROXY_KEYPASSWD CURLOPT_PROXY_SERVICE_NAME + CURLOPT_PROXY_SSLCERT + CURLOPT_PROXY_SSLCERTTYPE + CURLOPT_PROXY_SSL_CIPHER_LIST + CURLOPT_PROXY_SSLKEY + CURLOPT_PROXY_SSLKEYTYPE + CURLOPT_PROXY_TLSAUTH_PASSWORD + CURLOPT_PROXY_TLSAUTH_TYPE + CURLOPT_PROXY_TLSAUTH_USERNAME CURLOPT_RANDOM_FILE CURLOPT_RANGE CURLOPT_REFERER @@ -103,6 +115,7 @@ options: CURLOPT_RTSP_TRANSPORT CURLOPT_SERVICE_NAME CURLOPT_SOCKS5_GSSAPI_SERVICE + CURLOPT_SOCKS_PROXY CURLOPT_SSH_HOST_PUBLIC_KEY_MD5 CURLOPT_SSH_KNOWNHOSTS CURLOPT_SSH_PRIVATE_KEYFILE diff --git a/packages/OS400/ccsidcurl.c b/packages/OS400/ccsidcurl.c index 3b08bef7d..d9f710029 100644 --- a/packages/OS400/ccsidcurl.c +++ b/packages/OS400/ccsidcurl.c @@ -1165,7 +1165,19 @@ curl_easy_setopt_ccsid(CURL * curl, CURLoption tag, ...) case CURLOPT_PROXYPASSWORD: case CURLOPT_PROXYUSERNAME: case CURLOPT_PROXYUSERPWD: + case CURLOPT_PROXY_CAINFO: + case CURLOPT_PROXY_CAPATH: + case CURLOPT_PROXY_CRLFILE: + case CURLOPT_PROXY_KEYPASSWD: case CURLOPT_PROXY_SERVICE_NAME: + case CURLOPT_PROXY_SSLCERT: + case CURLOPT_PROXY_SSLCERTTYPE: + case CURLOPT_PROXY_SSL_CIPHER_LIST: + case CURLOPT_PROXY_SSLKEY: + case CURLOPT_PROXY_SSLKEYTYPE: + case CURLOPT_PROXY_TLSAUTH_PASSWORD: + case CURLOPT_PROXY_TLSAUTH_TYPE: + case CURLOPT_PROXY_TLSAUTH_USERNAME: case CURLOPT_RANDOM_FILE: case CURLOPT_RANGE: case CURLOPT_REFERER: @@ -1174,6 +1186,7 @@ curl_easy_setopt_ccsid(CURL * curl, CURLoption tag, ...) case CURLOPT_RTSP_TRANSPORT: case CURLOPT_SERVICE_NAME: case CURLOPT_SOCKS5_GSSAPI_SERVICE: + case CURLOPT_SOCKS_PROXY: case CURLOPT_SSH_HOST_PUBLIC_KEY_MD5: case CURLOPT_SSH_KNOWNHOSTS: case CURLOPT_SSH_PRIVATE_KEYFILE: diff --git a/packages/OS400/curl.inc.in b/packages/OS400/curl.inc.in index 4028795ef..9fa959a17 100644 --- a/packages/OS400/curl.inc.in +++ b/packages/OS400/curl.inc.in @@ -657,6 +657,8 @@ d c 0 d CURLPROXY_HTTP_1_0... d c 1 + d CURLPROXY_HTTPS... + d c 2 d CURLPROXY_SOCKS4... d c 4 d CURLPROXY_SOCKS5... @@ -1258,6 +1260,42 @@ d c 00244 d CURLOPT_KEEP_SENDING_ON_ERROR... d c 00245 + d CURLOPT_PROXY_CAINFO... + d c 10246 + d CURLOPT_PROXY_CAPATH... + d c 10247 + d CURLOPT_PROXY_SSL_VERIFYPEER... + d c 00248 + d CURLOPT_PROXY_SSL_VERIFYHOST... + d c 00249 + d CURLOPT_PROXY_SSLVERSION... + d c 00250 + d CURLOPT_PROXY_TLSAUTH_USERNAME... + d c 10251 + d CURLOPT_PROXY_TLSAUTH_PASSWORD... + d c 10252 + d CURLOPT_PROXY_TLSAUTH_TYPE... + d c 10253 + d CURLOPT_PROXY_SSLCERT... + d c 10254 + d CURLOPT_PROXY_SSLCERTTYPE... + d c 10255 + d CURLOPT_PROXY_SSLKEY... + d c 10256 + d CURLOPT_PROXY_SSLKEYTYPE... + d c 10257 + d CURLOPT_PROXY_KEYPASSWD... + d c 10258 + d CURLOPT_PROXY_SSL_CIPHER_LIST... + d c 10259 + d CURLOPT_PROXY_CRLFILE... + d c 10260 + d CURLOPT_PROXY_SSL_OPTIONS... + d c 00261 + d CURLOPT_SOCKS_PROXY... + d c 10262 + d CURLOPT_SOCKS_PROXYTYPE... + d c 00263 * /if not defined(CURL_NO_OLDIES) d CURLOPT_FILE c 10001 @@ -1444,6 +1482,8 @@ d c X'0040002D' d CURLINFO_HTTP_VERSION... CURLINFO_LONG + 46 d c X'0020002E' + d CURLINFO_PROXY_SSL_VERIFYRESULT... CURLINFO_LONG + 45 + d c X'0020002F' * d CURLINFO_HTTP_CODE... Old ...RESPONSE_CODE d c X'00200002' diff --git a/src/tool_cfgable.c b/src/tool_cfgable.c index 567123b82..5d38fb338 100644 --- a/src/tool_cfgable.c +++ b/src/tool_cfgable.c @@ -68,6 +68,9 @@ static void free_config_fields(struct OperationConfig *config) Curl_safefree(config->tls_username); Curl_safefree(config->tls_password); Curl_safefree(config->tls_authtype); + Curl_safefree(config->proxy_tls_username); + Curl_safefree(config->proxy_tls_password); + Curl_safefree(config->proxy_tls_authtype); Curl_safefree(config->proxyuserpwd); Curl_safefree(config->proxy); @@ -99,15 +102,24 @@ static void free_config_fields(struct OperationConfig *config) config->url_out = NULL; Curl_safefree(config->cipher_list); + Curl_safefree(config->proxy_cipher_list); Curl_safefree(config->cert); + Curl_safefree(config->proxy_cert); Curl_safefree(config->cert_type); + Curl_safefree(config->proxy_cert_type); Curl_safefree(config->cacert); + Curl_safefree(config->proxy_cacert); Curl_safefree(config->capath); + Curl_safefree(config->proxy_capath); Curl_safefree(config->crlfile); Curl_safefree(config->pinnedpubkey); + Curl_safefree(config->proxy_crlfile); Curl_safefree(config->key); + Curl_safefree(config->proxy_key); Curl_safefree(config->key_type); + Curl_safefree(config->proxy_key_type); Curl_safefree(config->key_passwd); + Curl_safefree(config->proxy_key_passwd); Curl_safefree(config->pubkey); Curl_safefree(config->hostpubmd5); Curl_safefree(config->engine); diff --git a/src/tool_cfgable.h b/src/tool_cfgable.h index e72fab11b..6589d8824 100644 --- a/src/tool_cfgable.h +++ b/src/tool_cfgable.h @@ -78,6 +78,9 @@ struct OperationConfig { char *tls_username; char *tls_password; char *tls_authtype; + char *proxy_tls_username; + char *proxy_tls_password; + char *proxy_tls_authtype; char *proxyuserpwd; char *proxy; int proxyver; /* set to CURLPROXY_HTTP* define */ @@ -106,15 +109,24 @@ struct OperationConfig { struct getout *url_get; /* point to the node to fill in URL */ struct getout *url_out; /* point to the node to fill in outfile */ char *cipher_list; + char *proxy_cipher_list; char *cert; + char *proxy_cert; char *cert_type; + char *proxy_cert_type; char *cacert; + char *proxy_cacert; char *capath; + char *proxy_capath; char *crlfile; + char *proxy_crlfile; char *pinnedpubkey; char *key; + char *proxy_key; char *key_type; + char *proxy_key_type; char *key_passwd; + char *proxy_key_passwd; char *pubkey; char *hostpubmd5; char *engine; @@ -127,6 +139,8 @@ struct OperationConfig { bool globoff; bool use_httpget; bool insecure_ok; /* set TRUE to allow insecure SSL connects */ + bool proxy_insecure_ok; /* set TRUE to allow insecure SSL connects + for proxy */ bool verifystatus; bool create_dirs; bool ftp_create_dirs; @@ -142,6 +156,7 @@ struct OperationConfig { struct curl_slist *postquote; struct curl_slist *prequote; long ssl_version; + long proxy_ssl_version; long ip_version; curl_TimeCond timecond; time_t condtime; @@ -202,7 +217,10 @@ struct OperationConfig { bool xattr; /* store metadata in extended attributes */ long gssapi_delegation; bool ssl_allow_beast; /* allow this SSL vulnerability */ + bool proxy_ssl_allow_beast; /* allow this SSL vulnerability for proxy*/ + bool ssl_no_revoke; /* disable SSL certificate revocation checks */ + /*bool proxy_ssl_no_revoke; */ bool use_metalink; /* process given URLs as metalink XML file */ metalinkfile *metalinkfile_list; /* point to the first node */ diff --git a/src/tool_getparam.c b/src/tool_getparam.c index 1f89fbc00..3d254e1b5 100644 --- a/src/tool_getparam.c +++ b/src/tool_getparam.c @@ -230,6 +230,24 @@ static const struct LongShort aliases[]= { {"Er", "false-start", FALSE}, {"Es", "ssl-no-revoke", FALSE}, {"Et", "tcp-fastopen", FALSE}, + {"Eu", "proxy-tlsuser", TRUE}, + {"Ev", "proxy-tlspassword", TRUE}, + {"Ew", "proxy-tlsauthtype", TRUE}, + {"Ex", "proxy-cert", TRUE}, + {"Ey", "proxy-cert-type", TRUE}, + {"Ez", "proxy-key", TRUE}, + {"E0", "proxy-key-type", TRUE}, + {"E1", "proxy-pass", TRUE}, + {"E2", "proxy-ciphers", TRUE}, + {"E3", "proxy-crlfile", TRUE}, + {"E4", "proxy-ssl-allow-beast", FALSE}, + {"E5", "login-options", TRUE}, + {"E6", "proxy-cacert", TRUE}, + {"E7", "proxy-capath", TRUE}, + {"E8", "proxy-insecure", FALSE}, + {"E9", "proxy-tlsv1", FALSE}, + {"EA", "proxy-sslv2", FALSE}, + {"EB", "proxy-sslv3", FALSE}, {"f", "fail", FALSE}, {"fa", "fail-early", FALSE}, {"F", "form", TRUE}, @@ -384,6 +402,20 @@ done: *certname_place = '\0'; } +static void +GetFileAndPassword(char *nextarg, char **file, char **password) +{ + char *certname, *passphrase; + parse_cert_parameter(nextarg, &certname, &passphrase); + Curl_safefree(*file); + *file = certname; + if(passphrase) { + Curl_safefree(*password); + *password = passphrase; + } + cleanarg(nextarg); +} + ParameterError getparameter(char *flag, /* f or -long-flag */ char *nextarg, /* NULL if unset */ bool *usedarg, /* set to TRUE if the arg @@ -1334,6 +1366,9 @@ ParameterError getparameter(char *flag, /* f or -long-flag */ break; case 'E': switch(subletter) { + case '\0': /* certificate file */ + GetFileAndPassword(nextarg, &config->cert, &config->key_passwd); + break; case 'a': /* CA info PEM file */ /* CA info PEM file */ GetStr(&config->cacert, nextarg); @@ -1424,18 +1459,101 @@ ParameterError getparameter(char *flag, /* f or -long-flag */ config->tcp_fastopen = TRUE; break; - default: /* certificate file */ - { - char *certname, *passphrase; - parse_cert_parameter(nextarg, &certname, &passphrase); - Curl_safefree(config->cert); - config->cert = certname; - if(passphrase) { - Curl_safefree(config->key_passwd); - config->key_passwd = passphrase; + case 'u': /* TLS username for proxy */ + if(curlinfo->features & CURL_VERSION_TLSAUTH_SRP) + GetStr(&config->proxy_tls_username, nextarg); + else + return PARAM_LIBCURL_DOESNT_SUPPORT; + break; + + case 'v': /* TLS password for proxy */ + if(curlinfo->features & CURL_VERSION_TLSAUTH_SRP) + GetStr(&config->proxy_tls_password, nextarg); + else + return PARAM_LIBCURL_DOESNT_SUPPORT; + break; + + case 'w': /* TLS authentication type for proxy */ + if(curlinfo->features & CURL_VERSION_TLSAUTH_SRP) { + GetStr(&config->proxy_tls_authtype, nextarg); + if(!curl_strequal(config->proxy_tls_authtype, "SRP")) + return PARAM_LIBCURL_DOESNT_SUPPORT; /* only support TLS-SRP */ } + else + return PARAM_LIBCURL_DOESNT_SUPPORT; + break; + + case 'x': /* certificate file for proxy */ + GetFileAndPassword(nextarg, &config->proxy_cert, + &config->proxy_key_passwd); + break; + + case 'y': /* cert file type for proxy */ + GetStr(&config->proxy_cert_type, nextarg); + break; + + case 'z': /* private key file for proxy */ + GetStr(&config->proxy_key, nextarg); + break; + + case '0': /* private key file type for proxy */ + GetStr(&config->proxy_key_type, nextarg); + break; + + case '1': /* private key passphrase for proxy */ + GetStr(&config->proxy_key_passwd, nextarg); cleanarg(nextarg); - } + break; + + case '2': /* ciphers for proxy */ + GetStr(&config->proxy_cipher_list, nextarg); + break; + + case '3': /* CRL info PEM file for proxy */ + /* CRL file */ + GetStr(&config->proxy_crlfile, nextarg); + break; + + case '4': /* no empty SSL fragments for proxy */ + if(curlinfo->features & CURL_VERSION_SSL) + config->proxy_ssl_allow_beast = toggle; + break; + + case '5': /* --login-options */ + GetStr(&config->login_options, nextarg); + break; + + case '6': /* CA info PEM file for proxy */ + /* CA info PEM file */ + GetStr(&config->proxy_cacert, nextarg); + break; + + case '7': /* CA info PEM file for proxy */ + /* CA cert directory */ + GetStr(&config->proxy_capath, nextarg); + break; + + case '8': /* allow insecure SSL connects for proxy */ + config->proxy_insecure_ok = toggle; + break; + + case '9': + /* TLS version 1 for proxy */ + config->proxy_ssl_version = CURL_SSLVERSION_TLSv1; + break; + + case 'A': + /* SSL version 2 for proxy */ + config->proxy_ssl_version = CURL_SSLVERSION_SSLv2; + break; + + case 'B': + /* SSL version 3 for proxy */ + config->proxy_ssl_version = CURL_SSLVERSION_SSLv3; + break; + + default: /* unknown flag */ + return PARAM_OPTION_UNKNOWN; } break; case 'f': diff --git a/src/tool_help.c b/src/tool_help.c index 02794ebc1..b55410f68 100644 --- a/src/tool_help.c +++ b/src/tool_help.c @@ -176,10 +176,36 @@ static const char *const helptext[] = { " --proxy-anyauth Pick \"any\" proxy authentication method (H)", " --proxy-basic Use Basic authentication on the proxy (H)", " --proxy-digest Use Digest authentication on the proxy (H)", + " --proxy-cacert FILE " + "CA certificate to verify peer against for proxy (SSL)", + " --proxy-capath DIR " + "CA directory to verify peer against for proxy (SSL)", + " --proxy-cert CERT[:PASSWD] " + "Client certificate file and password for proxy (SSL)", + " --proxy-cert-type TYPE " + "Certificate file type (DER/PEM/ENG) for proxy (SSL)", + " --proxy-ciphers LIST SSL ciphers to use for proxy (SSL)", + " --proxy-crlfile FILE " + "Get a CRL list in PEM format from the given file for proxy", + " --proxy-insecure " + "Allow connections to SSL sites without certs for proxy (H)", + " --proxy-key KEY Private key file name for proxy (SSL)", + " --proxy-key-type TYPE " + "Private key file type for proxy (DER/PEM/ENG) (SSL)", " --proxy-negotiate " "Use HTTP Negotiate (SPNEGO) authentication on the proxy (H)", " --proxy-ntlm Use NTLM authentication on the proxy (H)", " --proxy-header LINE Pass custom header LINE to proxy (H)", + " --proxy-pass PASS Pass phrase for the private key for proxy (SSL)", + " --proxy-ssl-allow-beast " + "Allow security flaw to improve interop for proxy (SSL)", + " --proxy-sslv2 Use SSLv2 for proxy (SSL)", + " --proxy-sslv3 Use SSLv3 for proxy (SSL)", + " --proxy-tlsv1 Use TLSv1 for proxy (SSL)", + " --proxy-tlsuser USER TLS username for proxy", + " --proxy-tlspassword STRING TLS password for proxy", + " --proxy-tlsauthtype STRING " + "TLS authentication type for proxy (default SRP)", " --proxy-service-name NAME SPNEGO proxy service name", " --service-name NAME SPNEGO service name", " -U, --proxy-user USER[:PASSWORD] Proxy user and password", diff --git a/src/tool_operate.c b/src/tool_operate.c index c44f2141c..b115ad94e 100644 --- a/src/tool_operate.c +++ b/src/tool_operate.c @@ -869,8 +869,9 @@ static CURLcode operate_do(struct GlobalConfig *global, /* new in libcurl 7.10 */ if(config->socksproxy) { - my_setopt_str(curl, CURLOPT_PROXY, config->socksproxy); - my_setopt_enum(curl, CURLOPT_PROXYTYPE, (long)config->socksver); + my_setopt_str(curl, CURLOPT_SOCKS_PROXY, config->socksproxy); + my_setopt_enum(curl, CURLOPT_SOCKS_PROXYTYPE, + (long)config->socksver); } /* new in libcurl 7.10.6 */ @@ -1000,6 +1001,7 @@ static CURLcode operate_do(struct GlobalConfig *global, my_setopt(curl, CURLOPT_RESUME_FROM_LARGE, CURL_OFF_T_C(0)); my_setopt_str(curl, CURLOPT_KEYPASSWD, config->key_passwd); + my_setopt_str(curl, CURLOPT_PROXY_KEYPASSWD, config->proxy_key_passwd); if(built_in_protos & (CURLPROTO_SCP|CURLPROTO_SFTP)) { @@ -1017,6 +1019,8 @@ static CURLcode operate_do(struct GlobalConfig *global, if(config->cacert) my_setopt_str(curl, CURLOPT_CAINFO, config->cacert); + if(config->proxy_cacert) + my_setopt_str(curl, CURLOPT_PROXY_CAINFO, config->proxy_cacert); if(config->capath) { result = res_setopt_str(curl, CURLOPT_CAPATH, config->capath); if(result == CURLE_NOT_BUILT_IN) { @@ -1027,17 +1031,32 @@ static CURLcode operate_do(struct GlobalConfig *global, else if(result) goto show_error; } + if(config->proxy_capath) + my_setopt_str(curl, CURLOPT_PROXY_CAPATH, config->proxy_capath); + else if(config->capath) /* CURLOPT_PROXY_CAPATH default is capath */ + my_setopt_str(curl, CURLOPT_PROXY_CAPATH, config->capath); + if(config->crlfile) my_setopt_str(curl, CURLOPT_CRLFILE, config->crlfile); + if(config->proxy_crlfile) + my_setopt_str(curl, CURLOPT_PROXY_CRLFILE, config->proxy_crlfile); + else if(config->crlfile) /* CURLOPT_PROXY_CRLFILE default is crlfile */ + my_setopt_str(curl, CURLOPT_PROXY_CRLFILE, config->crlfile); if(config->pinnedpubkey) my_setopt_str(curl, CURLOPT_PINNEDPUBLICKEY, config->pinnedpubkey); if(curlinfo->features & CURL_VERSION_SSL) { my_setopt_str(curl, CURLOPT_SSLCERT, config->cert); + my_setopt_str(curl, CURLOPT_PROXY_SSLCERT, config->proxy_cert); my_setopt_str(curl, CURLOPT_SSLCERTTYPE, config->cert_type); + my_setopt_str(curl, CURLOPT_PROXY_SSLCERTTYPE, + config->proxy_cert_type); my_setopt_str(curl, CURLOPT_SSLKEY, config->key); + my_setopt_str(curl, CURLOPT_PROXY_SSLKEY, config->proxy_key); my_setopt_str(curl, CURLOPT_SSLKEYTYPE, config->key_type); + my_setopt_str(curl, CURLOPT_PROXY_SSLKEYTYPE, + config->proxy_key_type); if(config->insecure_ok) { my_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); @@ -1048,6 +1067,13 @@ static CURLcode operate_do(struct GlobalConfig *global, /* libcurl default is strict verifyhost -> 2L */ /* my_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2L); */ } + if(config->proxy_insecure_ok) { + my_setopt(curl, CURLOPT_PROXY_SSL_VERIFYPEER, 0L); + my_setopt(curl, CURLOPT_PROXY_SSL_VERIFYHOST, 0L); + } + else { + my_setopt(curl, CURLOPT_PROXY_SSL_VERIFYPEER, 1L); + } if(config->verifystatus) my_setopt(curl, CURLOPT_SSL_VERIFYSTATUS, 1L); @@ -1056,6 +1082,8 @@ static CURLcode operate_do(struct GlobalConfig *global, my_setopt(curl, CURLOPT_SSL_FALSESTART, 1L); my_setopt_enum(curl, CURLOPT_SSLVERSION, config->ssl_version); + my_setopt_enum(curl, CURLOPT_PROXY_SSLVERSION, + config->proxy_ssl_version); } if(config->path_as_is) my_setopt(curl, CURLOPT_PATH_AS_IS, 1L); @@ -1157,6 +1185,10 @@ static CURLcode operate_do(struct GlobalConfig *global, if(config->cipher_list) my_setopt_str(curl, CURLOPT_SSL_CIPHER_LIST, config->cipher_list); + if(config->proxy_cipher_list) + my_setopt_str(curl, CURLOPT_PROXY_SSL_CIPHER_LIST, + config->proxy_cipher_list); + /* new in libcurl 7.9.2: */ if(config->disable_epsv) /* disable it */ @@ -1325,6 +1357,15 @@ static CURLcode operate_do(struct GlobalConfig *global, if(config->tls_authtype) my_setopt_str(curl, CURLOPT_TLSAUTH_TYPE, config->tls_authtype); + if(config->proxy_tls_username) + my_setopt_str(curl, CURLOPT_PROXY_TLSAUTH_USERNAME, + config->proxy_tls_username); + if(config->proxy_tls_password) + my_setopt_str(curl, CURLOPT_PROXY_TLSAUTH_PASSWORD, + config->proxy_tls_password); + if(config->proxy_tls_authtype) + my_setopt_str(curl, CURLOPT_PROXY_TLSAUTH_TYPE, + config->proxy_tls_authtype); } /* new in 7.22.0 */ @@ -1340,6 +1381,10 @@ static CURLcode operate_do(struct GlobalConfig *global, my_setopt_bitmask(curl, CURLOPT_SSL_OPTIONS, mask); } + if(config->proxy_ssl_allow_beast) + my_setopt(curl, CURLOPT_PROXY_SSL_OPTIONS, + (long)CURLSSLOPT_ALLOW_BEAST); + if(config->mail_auth) my_setopt_str(curl, CURLOPT_MAIL_AUTH, config->mail_auth); diff --git a/src/tool_setopt.c b/src/tool_setopt.c index f3de09dee..ad3d30739 100644 --- a/src/tool_setopt.c +++ b/src/tool_setopt.c @@ -45,6 +45,15 @@ const NameValue setopt_nv_CURLPROXY[] = { NV(CURLPROXY_HTTP), NV(CURLPROXY_HTTP_1_0), + NV(CURLPROXY_HTTPS), + NV(CURLPROXY_SOCKS4), + NV(CURLPROXY_SOCKS5), + NV(CURLPROXY_SOCKS4A), + NV(CURLPROXY_SOCKS5_HOSTNAME), + NVEND, +}; + +const NameValue setopt_nv_CURL_SOCKS_PROXY[] = { NV(CURLPROXY_SOCKS4), NV(CURLPROXY_SOCKS5), NV(CURLPROXY_SOCKS4A), @@ -159,6 +168,8 @@ static const NameValue setopt_nv_CURLNONZERODEFAULTS[] = { NV1(CURLOPT_SSL_ENABLE_NPN, 1), NV1(CURLOPT_SSL_ENABLE_ALPN, 1), NV1(CURLOPT_TCP_NODELAY, 1), + NV1(CURLOPT_PROXY_SSL_VERIFYPEER, 1), + NV1(CURLOPT_PROXY_SSL_VERIFYHOST, 1), NVEND }; diff --git a/src/tool_setopt.h b/src/tool_setopt.h index 7cd38751c..fecf24fa3 100644 --- a/src/tool_setopt.h +++ b/src/tool_setopt.h @@ -47,6 +47,7 @@ typedef struct { } NameValueUnsigned; extern const NameValue setopt_nv_CURLPROXY[]; +extern const NameValue setopt_nv_CURL_SOCKS_PROXY[]; extern const NameValue setopt_nv_CURL_HTTP_VERSION[]; extern const NameValue setopt_nv_CURL_SSLVERSION[]; extern const NameValue setopt_nv_CURL_TIMECOND[]; @@ -61,6 +62,7 @@ extern const NameValueUnsigned setopt_nv_CURLAUTH[]; #define setopt_nv_CURLOPT_HTTP_VERSION setopt_nv_CURL_HTTP_VERSION #define setopt_nv_CURLOPT_HTTPAUTH setopt_nv_CURLAUTH #define setopt_nv_CURLOPT_SSLVERSION setopt_nv_CURL_SSLVERSION +#define setopt_nv_CURLOPT_PROXY_SSLVERSION setopt_nv_CURL_SSLVERSION #define setopt_nv_CURLOPT_TIMECONDITION setopt_nv_CURL_TIMECOND #define setopt_nv_CURLOPT_FTP_SSL_CCC setopt_nv_CURLFTPSSL_CCC #define setopt_nv_CURLOPT_USE_SSL setopt_nv_CURLUSESSL @@ -69,6 +71,7 @@ extern const NameValueUnsigned setopt_nv_CURLAUTH[]; #define setopt_nv_CURLOPT_PROTOCOLS setopt_nv_CURLPROTO #define setopt_nv_CURLOPT_REDIR_PROTOCOLS setopt_nv_CURLPROTO #define setopt_nv_CURLOPT_PROXYTYPE setopt_nv_CURLPROXY +#define setopt_nv_CURLOPT_SOCKS_PROXYTYPE setopt_nv_CURL_SOCKS_PROXY #define setopt_nv_CURLOPT_PROXYAUTH setopt_nv_CURLAUTH /* Intercept setopt calls for --libcurl */ diff --git a/src/tool_writeout.c b/src/tool_writeout.c index 60221d09b..dfe86471e 100644 --- a/src/tool_writeout.c +++ b/src/tool_writeout.c @@ -52,6 +52,7 @@ typedef enum { VAR_FTP_ENTRY_PATH, VAR_REDIRECT_URL, VAR_SSL_VERIFY_RESULT, + VAR_PROXY_SSL_VERIFY_RESULT, VAR_EFFECTIVE_FILENAME, VAR_PRIMARY_IP, VAR_PRIMARY_PORT, @@ -91,6 +92,7 @@ static const struct variable replacements[]={ {"ftp_entry_path", VAR_FTP_ENTRY_PATH}, {"redirect_url", VAR_REDIRECT_URL}, {"ssl_verify_result", VAR_SSL_VERIFY_RESULT}, + {"proxy_ssl_verify_result", VAR_PROXY_SSL_VERIFY_RESULT}, {"filename_effective", VAR_EFFECTIVE_FILENAME}, {"remote_ip", VAR_PRIMARY_IP}, {"remote_port", VAR_PRIMARY_PORT}, @@ -252,6 +254,12 @@ void ourWriteOut(CURL *curl, struct OutStruct *outs, const char *writeinfo) &longinfo)) fprintf(stream, "%ld", longinfo); break; + case VAR_PROXY_SSL_VERIFY_RESULT: + if(CURLE_OK == + curl_easy_getinfo(curl, CURLINFO_PROXY_SSL_VERIFYRESULT, + &longinfo)) + fprintf(stream, "%ld", longinfo); + break; case VAR_EFFECTIVE_FILENAME: if(outs->filename) fprintf(stream, "%s", outs->filename);