]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
schannel: Disable auto credentials; add an option to enable it
authorJay Satiro <raysatiro@yahoo.com>
Sat, 27 Feb 2021 21:27:31 +0000 (16:27 -0500)
committerJay Satiro <raysatiro@yahoo.com>
Thu, 22 Apr 2021 20:53:37 +0000 (16:53 -0400)
- Disable auto credentials by default. This is a breaking change
  for clients that are using it, wittingly or not.

- New libcurl ssl option value CURLSSLOPT_AUTO_CLIENT_CERT tells libcurl
  to automatically locate and use a client certificate for
  authentication, when requested by the server.

- New curl tool options --ssl-auto-client-cert and
  --proxy-ssl-auto-client-cert map to CURLSSLOPT_AUTO_CLIENT_CERT.

This option is only supported for Schannel (the native Windows SSL
library). Prior to this change Schannel would, with no notification to
the client, attempt to locate a client certificate and send it to the
server, when requested by the server. Since the server can request any
certificate that supports client authentication in the OS certificate
store it could be a privacy violation and unexpected.

Fixes https://github.com/curl/curl/issues/2262
Reported-by: Jeroen Ooms
Assisted-by: Wes Hinsley
Assisted-by: Rich FitzJohn
Ref: https://curl.se/mail/lib-2021-02/0066.html
Reported-by: Morten Minde Neergaard
Closes https://github.com/curl/curl/pull/6673

20 files changed:
docs/TODO
docs/cmdline-opts/Makefile.inc
docs/cmdline-opts/proxy-ssl-auto-client-cert.d [new file with mode: 0644]
docs/cmdline-opts/ssl-auto-client-cert.d [new file with mode: 0644]
docs/libcurl/opts/CURLOPT_PROXY_SSL_OPTIONS.3
docs/libcurl/opts/CURLOPT_SSL_OPTIONS.3
docs/libcurl/symbols-in-versions
docs/options-in-versions
include/curl/curl.h
lib/doh.c
lib/setopt.c
lib/urldata.h
lib/vtls/schannel.c
packages/OS400/curl.inc.in
src/tool_cfgable.h
src/tool_getparam.c
src/tool_help.c
src/tool_operate.c
src/tool_setopt.c
src/tool_setopt.h

index b2b0822924f1be78fa03d855872e998551aa5201..04511bb3b1c1b5d4dfc935fa6739402997692679 100644 (file)
--- a/docs/TODO
+++ b/docs/TODO
  15. Schannel
  15.1 Extend support for client certificate authentication
  15.2 Extend support for the --ciphers option
- 15.3 Add option to disable client certificate auto-send
  15.4 Add option to allow abrupt server closure
 
  16. SASL
  - Specifying Schannel Ciphers and Cipher Strengths
    https://msdn.microsoft.com/en-us/library/windows/desktop/aa380161.aspx
 
-15.3 Add option to disable client certificate auto-send
-
- Microsoft says "By default, Schannel will, with no notification to the client,
- attempt to locate a client certificate and send it to the server." That could
- be considered a privacy violation and unexpected.
-
- Some Windows users have come to expect that default behavior and to change the
- default to make it consistent with other SSL backends would be a breaking
- change. An option should be added that can be used to disable the default
- Schannel auto-send behavior.
-
- https://github.com/curl/curl/issues/2262
-
 15.4 Add option to allow abrupt server closure
 
  libcurl w/schannel will error without a known termination point from the
index 7ca0f326858f7ad8edb8ac3adab6fddeefe9cccb..6e04552e96c05d4c38c42d7095ccc39c6d2b41ab 100644 (file)
@@ -180,6 +180,7 @@ DPAGES = \
   proxy-pinnedpubkey.d \
   proxy-service-name.d \
   proxy-ssl-allow-beast.d \
+  proxy-ssl-auto-client-cert.d \
   proxy-tls13-ciphers.d \
   proxy-tlsauthtype.d \
   proxy-tlspassword.d \
@@ -223,6 +224,7 @@ DPAGES = \
   speed-limit.d \
   speed-time.d \
   ssl-allow-beast.d \
+  ssl-auto-client-cert.d \
   ssl-no-revoke.d \
   ssl-reqd.d \
   ssl-revoke-best-effort.d \
diff --git a/docs/cmdline-opts/proxy-ssl-auto-client-cert.d b/docs/cmdline-opts/proxy-ssl-auto-client-cert.d
new file mode 100644 (file)
index 0000000..0541754
--- /dev/null
@@ -0,0 +1,6 @@
+Long: proxy-ssl-auto-client-cert
+Help: Use auto client certificate for proxy (Schannel)
+Added: 7.77.0
+Category: proxy tls
+---
+Same as --ssl-auto-client-cert but used in HTTPS proxy context.
diff --git a/docs/cmdline-opts/ssl-auto-client-cert.d b/docs/cmdline-opts/ssl-auto-client-cert.d
new file mode 100644 (file)
index 0000000..16108ae
--- /dev/null
@@ -0,0 +1,12 @@
+Long: ssl-auto-client-cert
+Help: Use auto client certificate (Schannel)
+Added: 7.77.0
+See-also: proxy-ssl-auto-client-cert
+Category: tls
+---
+Tell libcurl to automatically locate and use a client certificate for
+authentication, when requested by the server. This option is only supported
+for Schannel (the native Windows SSL library). Prior to 7.77.0 this was the
+default behavior in libcurl with Schannel. Since the server can request any
+certificate that supports client authentication in the OS certificate store it
+could be a privacy violation and unexpected.
index dbc701eeb5fc768fa55fccf7ef2083bbb1c644a6..e5963dc4dcc1098e496118c2e1d42d6792e1c3c0 100644 (file)
@@ -49,13 +49,20 @@ Tells libcurl to not accept "partial" certificate chains, which it otherwise
 does by default. This option is only supported for OpenSSL and will fail the
 certificate verification if the chain ends with an intermediate certificate
 and not with a root cert. (Added in 7.68.0)
-
 .IP CURLSSLOPT_REVOKE_BEST_EFFORT
 Tells libcurl to ignore certificate revocation checks in case of missing or
 offline distribution points for those SSL backends where such behavior is
 present. This option is only supported for Schannel (the native Windows SSL
 library). If combined with \fICURLSSLOPT_NO_REVOKE\fP, the latter takes
 precedence. (Added in 7.70.0)
+.IP CURLSSLOPT_AUTO_CLIENT_CERT
+Tell libcurl to automatically locate and use a client certificate for
+authentication, when requested by the server. This option is only supported
+for Schannel (the native Windows SSL library). Prior to 7.77.0 this was the
+default behavior in libcurl with Schannel. Since the server can request any
+certificate that supports client authentication in the OS certificate store it
+could be a privacy violation and unexpected.
+(Added in 7.77.0)
 .SH DEFAULT
 0
 .SH PROTOCOLS
index 9bfe577d58936f9bedffeb9afd93d242ec1aac83..163320b59ecfcd7a3ca2b1cb22ad4fa52eff3902 100644 (file)
@@ -60,6 +60,14 @@ Tell libcurl to use the operating system's native CA store for certificate
 verification. Works only on Windows when built to use OpenSSL. This option is
 experimental and behavior is subject to change.
 (Added in 7.71.0)
+.IP CURLSSLOPT_AUTO_CLIENT_CERT
+Tell libcurl to automatically locate and use a client certificate for
+authentication, when requested by the server. This option is only supported
+for Schannel (the native Windows SSL library). Prior to 7.77.0 this was the
+default behavior in libcurl with Schannel. Since the server can request any
+certificate that supports client authentication in the OS certificate store it
+could be a privacy violation and unexpected.
+(Added in 7.77.0)
 .SH DEFAULT
 0
 .SH PROTOCOLS
index 5ff3a350332bed4b8504c9581ec55794c0dc02d2..0f5e95740c829c2387cff77d8676159eee010f3c 100644 (file)
@@ -816,6 +816,7 @@ CURLSSLBACKEND_SCHANNEL         7.34.0
 CURLSSLBACKEND_SECURETRANSPORT  7.64.1
 CURLSSLBACKEND_WOLFSSL          7.49.0
 CURLSSLOPT_ALLOW_BEAST          7.25.0
+CURLSSLOPT_AUTO_CLIENT_CERT     7.77.0
 CURLSSLOPT_NATIVE_CA            7.71.0
 CURLSSLOPT_NO_PARTIALCHAIN      7.68.0
 CURLSSLOPT_NO_REVOKE            7.44.0
index 27497b7c1979c8fd4e1ed0441c7b35a1c95ae38c..6fada9381c75415cf127769e45f77ac2b236a7c9 100644 (file)
 --proxy-pinnedpubkey                 7.59.0
 --proxy-service-name                 7.43.0
 --proxy-ssl-allow-beast              7.52.0
+--proxy-ssl-auto-client-cert         7.77.0
 --proxy-tls13-ciphers                7.61.0
 --proxy-tlsauthtype                  7.52.0
 --proxy-tlspassword                  7.52.0
 --speed-time (-y)                    4.7
 --ssl                                7.20.0
 --ssl-allow-beast                    7.25.0
+--ssl-auto-client-cert               7.77.0
 --ssl-no-revoke                      7.44.0
 --ssl-reqd                           7.20.0
 --ssl-revoke-best-effort             7.70.0
index bed8068b0b6faa49c20bcc97b8b24aac0d06cb3d..40b5ed12961f95a425ac61e5b0bfa0340399e5da 100644 (file)
@@ -888,6 +888,10 @@ typedef enum {
    operating system. Currently implemented under MS-Windows. */
 #define CURLSSLOPT_NATIVE_CA (1<<4)
 
+/* - CURLSSLOPT_AUTO_CLIENT_CERT tells libcurl to automatically locate and use
+   a client certificate for authentication. (Schannel) */
+#define CURLSSLOPT_AUTO_CLIENT_CERT (1<<5)
+
 /* The default connection attempt delay in milliseconds for happy eyeballs.
    CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS.3 and happy-eyeballs-timeout-ms.d document
    this value, keep them in sync. */
index 52388cba3eb7a1049a7f2e1d731e09455b5a5afd..8ea53ff8d1279bd2a3d2a6f79efe7c4cdf6565ac 100644 (file)
--- a/lib/doh.c
+++ b/lib/doh.c
@@ -351,7 +351,10 @@ static CURLcode dohprobe(struct Curl_easy *data,
         (data->set.ssl.revoke_best_effort ?
          CURLSSLOPT_REVOKE_BEST_EFFORT : 0) |
         (data->set.ssl.native_ca_store ?
-         CURLSSLOPT_NATIVE_CA : 0);
+         CURLSSLOPT_NATIVE_CA : 0) |
+        (data->set.ssl.auto_client_cert ?
+         CURLSSLOPT_AUTO_CLIENT_CERT : 0);
+
       curl_easy_setopt(doh, CURLOPT_SSL_OPTIONS, mask);
     }
 
index ff6cb4276c533316aff4b96c1a5a3c43f6ad867d..16b83321d18a451a168ea3ab6cbbd83d566dbcac 100644 (file)
@@ -2290,6 +2290,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
     data->set.ssl.no_partialchain = !!(arg & CURLSSLOPT_NO_PARTIALCHAIN);
     data->set.ssl.revoke_best_effort = !!(arg & CURLSSLOPT_REVOKE_BEST_EFFORT);
     data->set.ssl.native_ca_store = !!(arg & CURLSSLOPT_NATIVE_CA);
+    data->set.ssl.auto_client_cert = !!(arg & CURLSSLOPT_AUTO_CLIENT_CERT);
     /* If a setting is added here it should also be added in dohprobe()
        which sets its own CURLOPT_SSL_OPTIONS based on these settings. */
     break;
@@ -2301,9 +2302,11 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
       (bool)((arg&CURLSSLOPT_ALLOW_BEAST) ? TRUE : FALSE);
     data->set.proxy_ssl.no_revoke = !!(arg & CURLSSLOPT_NO_REVOKE);
     data->set.proxy_ssl.no_partialchain = !!(arg & CURLSSLOPT_NO_PARTIALCHAIN);
-    data->set.proxy_ssl.native_ca_store = !!(arg & CURLSSLOPT_NATIVE_CA);
     data->set.proxy_ssl.revoke_best_effort =
       !!(arg & CURLSSLOPT_REVOKE_BEST_EFFORT);
+    data->set.proxy_ssl.native_ca_store = !!(arg & CURLSSLOPT_NATIVE_CA);
+    data->set.proxy_ssl.auto_client_cert =
+      !!(arg & CURLSSLOPT_AUTO_CLIENT_CERT);
     break;
 #endif
 
index b7b17e30cd22d6d135d9af1f9a5f8c5489028204..c8797698a15dc3bfe3329d7c9922afbad9c49b4e 100644 (file)
@@ -286,6 +286,8 @@ struct ssl_config_data {
   BIT(revoke_best_effort); /* ignore SSL revocation offline/missing revocation
                               list errors */
   BIT(native_ca_store); /* use the native ca store of operating system */
+  BIT(auto_client_cert);   /* automatically locate and use a client
+                              certificate for authentication (Schannel) */
 };
 
 struct ssl_general_config {
index b944bbd493bbe538d18cfbdecfa5e21ac522c03c..7d96cf7fc391f397730af2af4ca93478af45d03f 100644 (file)
@@ -553,6 +553,20 @@ schannel_connect_step1(struct Curl_easy *data, struct connectdata *conn,
                    "names in server certificates.\n"));
     }
 
+    /* security request flags */
+    BACKEND->req_flags = ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT |
+      ISC_REQ_CONFIDENTIALITY | ISC_REQ_ALLOCATE_MEMORY |
+      ISC_REQ_STREAM;
+
+    if(!SSL_SET_OPTION(auto_client_cert)) {
+      schannel_cred.dwFlags &= ~SCH_CRED_USE_DEFAULT_CREDS;
+      schannel_cred.dwFlags |= SCH_CRED_NO_DEFAULT_CREDS;
+      BACKEND->req_flags |= ISC_REQ_USE_SUPPLIED_CREDS;
+      infof(data, "schannel: disabled automatic use of client certificate\n");
+    }
+    else
+      infof(data, "schannel: enabled automatic use of client certificate\n");
+
     switch(conn->ssl_config.version) {
     case CURL_SSLVERSION_DEFAULT:
     case CURL_SSLVERSION_TLSv1:
@@ -886,11 +900,6 @@ schannel_connect_step1(struct Curl_easy *data, struct connectdata *conn,
   InitSecBuffer(&outbuf, SECBUFFER_EMPTY, NULL, 0);
   InitSecBufferDesc(&outbuf_desc, &outbuf, 1);
 
-  /* setup request flags */
-  BACKEND->req_flags = ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT |
-    ISC_REQ_CONFIDENTIALITY | ISC_REQ_ALLOCATE_MEMORY |
-    ISC_REQ_STREAM;
-
   /* allocate memory for the security context handle */
   BACKEND->ctxt = (struct Curl_schannel_ctxt *)
     calloc(1, sizeof(struct Curl_schannel_ctxt));
index 23e3af204c6052d9701fa178b2e71eed80e6dd12..979820650d93d7224eba4815c56c742b3ecf4f37 100644 (file)
      d                 c                   X'0008'
      d CURLSSLOPT_NATIVE_CA...
      d                 c                   X'0010'
+     d CURLSSLOPT_AUTO_CLIENT_CERT...
+     d                 c                   X'0020'
       *
      d CURL_HET_DEFAULT...
      d                 c                   200
index 95c66d0817e5fb829e511cdbd61eb09d22d97e4c..c7c8dfea59511d17fadf85d715d3ff6532942699 100644 (file)
@@ -267,6 +267,9 @@ struct OperationConfig {
                                   revocation list errors */
 
   bool native_ca_store;        /* use the native os ca store */
+  bool ssl_auto_client_cert;   /* automatically locate and use a client
+                                  certificate for authentication (Schannel) */
+  bool proxy_ssl_auto_client_cert; /* proxy version of ssl_auto_client_cert */
 
   bool use_metalink;        /* process given URLs as metalink XML file */
   struct metalinkfile *metalinkfile_list; /* point to the first node */
index ad89ea312fe556d9988e5976fc51e165bbfd8db9..d616b255ce0cc3e7929fee95e329dc141a2ba445 100644 (file)
@@ -247,7 +247,8 @@ static const struct LongShort aliases[]= {
   {"El", "tlspassword",              ARG_STRING},
   {"Em", "tlsauthtype",              ARG_STRING},
   {"En", "ssl-allow-beast",          ARG_BOOL},
-  /* Eo */
+  {"Eo", "ssl-auto-client-cert",     ARG_BOOL},
+  {"EO", "proxy-ssl-auto-client-cert", ARG_BOOL},
   {"Ep", "pinnedpubkey",             ARG_STRING},
   {"EP", "proxy-pinnedpubkey",       ARG_STRING},
   {"Eq", "cert-status",              ARG_BOOL},
@@ -1651,6 +1652,16 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */
           config->ssl_allow_beast = toggle;
         break;
 
+      case 'o': /* --ssl-auto-client-cert */
+        if(curlinfo->features & CURL_VERSION_SSL)
+          config->ssl_auto_client_cert = toggle;
+        break;
+
+      case 'O': /* --proxy-ssl-auto-client-cert */
+        if(curlinfo->features & CURL_VERSION_SSL)
+          config->proxy_ssl_auto_client_cert = toggle;
+        break;
+
       case 'p': /* Pinned public key DER file */
         GetStr(&config->pinnedpubkey, nextarg);
         break;
index 32893547d8a495c605ec7294691d7b85a5bd3477..78c441e776d4ada6c92e01440409fb2ee8c1376d 100644 (file)
@@ -598,6 +598,9 @@ static const struct helptxt helptext[] = {
   {"    --proxy-ssl-allow-beast",
    "Allow security flaw for interop for HTTPS proxy",
    CURLHELP_PROXY | CURLHELP_TLS},
+  {"    --proxy-ssl-auto-client-cert",
+   "Use auto client certificate for proxy (Schannel)",
+   CURLHELP_PROXY | CURLHELP_TLS},
   {"    --proxy-tls13-ciphers <ciphersuite list>",
    "TLS 1.3 proxy cipher suites",
    CURLHELP_PROXY | CURLHELP_TLS},
@@ -727,6 +730,9 @@ static const struct helptxt helptext[] = {
   {"    --ssl-allow-beast",
    "Allow security flaw to improve interop",
    CURLHELP_TLS},
+  {"    --ssl-auto-client-cert",
+   "Use auto client certificate (Schannel)",
+   CURLHELP_TLS},
   {"    --ssl-no-revoke",
    "Disable cert revocation checks (Schannel)",
    CURLHELP_TLS},
index 5e7a9fa877c402ad3573255839e29c94573dbf78..cd6131692da4c7d973b2be9436368b0b199e77d7 100644 (file)
@@ -1720,20 +1720,31 @@ static CURLcode single_transfer(struct GlobalConfig *global,
 
           {
             long mask =
-              (config->ssl_allow_beast ? CURLSSLOPT_ALLOW_BEAST : 0) |
+              (config->ssl_allow_beast ?
+               CURLSSLOPT_ALLOW_BEAST : 0) |
+              (config->ssl_no_revoke ?
+               CURLSSLOPT_NO_REVOKE : 0) |
               (config->ssl_revoke_best_effort ?
                CURLSSLOPT_REVOKE_BEST_EFFORT : 0) |
               (config->native_ca_store ?
                CURLSSLOPT_NATIVE_CA : 0) |
-              (config->ssl_no_revoke ? CURLSSLOPT_NO_REVOKE : 0);
+              (config->ssl_auto_client_cert ?
+               CURLSSLOPT_AUTO_CLIENT_CERT : 0);
 
             if(mask)
               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);
+          {
+            long mask =
+              (config->proxy_ssl_allow_beast ?
+               CURLSSLOPT_ALLOW_BEAST : 0) |
+              (config->proxy_ssl_auto_client_cert ?
+               CURLSSLOPT_AUTO_CLIENT_CERT : 0);
+
+            if(mask)
+              my_setopt_bitmask(curl, CURLOPT_PROXY_SSL_OPTIONS, mask);
+          }
         }
 
         if(config->path_as_is)
index 196affc04244fd7b68ced25a459f6569bc99376e..673f6b35d854e6c0095e6467daf8eb38035f4c89 100644 (file)
@@ -133,6 +133,7 @@ const struct NameValueUnsigned setopt_nv_CURLSSLOPT[] = {
   NV(CURLSSLOPT_NO_PARTIALCHAIN),
   NV(CURLSSLOPT_REVOKE_BEST_EFFORT),
   NV(CURLSSLOPT_NATIVE_CA),
+  NV(CURLSSLOPT_AUTO_CLIENT_CERT),
   NVEND,
 };
 
index a54e34639c51bcbfb66385026f4a0edbc9fb08c5..a2711fb001479e5d6fafd480039a6938f8add66c 100644 (file)
@@ -76,6 +76,7 @@ extern const struct NameValueUnsigned setopt_nv_CURLHSTS[];
 #define setopt_nv_CURLOPT_FTP_SSL_CCC setopt_nv_CURLFTPSSL_CCC
 #define setopt_nv_CURLOPT_USE_SSL setopt_nv_CURLUSESSL
 #define setopt_nv_CURLOPT_SSL_OPTIONS setopt_nv_CURLSSLOPT
+#define setopt_nv_CURLOPT_PROXY_SSL_OPTIONS setopt_nv_CURLSSLOPT
 #define setopt_nv_CURLOPT_NETRC setopt_nv_CURL_NETRC
 #define setopt_nv_CURLOPT_PROTOCOLS setopt_nv_CURLPROTO
 #define setopt_nv_CURLOPT_REDIR_PROTOCOLS setopt_nv_CURLPROTO