CVE-2021-22897: Exposure of Resource to Wrong Sphere (CWE-668)
value: curl 7.61.0 through 7.76.1 suffers from exposure of data element to wrong session due to a mistake in the code for CURLOPT_SSL_CIPHER_LIST when libcurl is built to use the Schannel TLS library. The selected cipher set was stored in a single "static" variable in the library, which has the surprising side-effect that if an application sets up multiple concurrent transfers, the last one that sets the ciphers will accidentally control the set used by all transfers. In a worst-case scenario, this weakens transport security significantly.
CWE description: The product exposes a resource to the wrong control sphere, providing unintended actors with inappropriate access to the resource.
CVSS v3 base score: 5.3
Published: 2021-06-11T16:15Z
Repository: https://github.com/curl/curl
Language: C
Files changed: lib/vtls/schannel.c, lib/vtls/schannel.h
Commit date: 2021-05-24 07:56:05 +0200
Commit message: schannel: don't use static to store selected ciphers

CVE-2021-22897

Bug: https://curl.se/docs/CVE-2021-22897.html

Diff: diff --git a/lib/vtls/schannel.c b/lib/vtls/schannel.c
index 8c25ac5dd5..dba7072273 100644
--- a/lib/vtls/schannel.c
+++ b/lib/vtls/schannel.c
@@ -326,16 +326,16 @@ get_alg_id_by_name(char *name)
 #endif
   return 0;
 }
 
 static CURLcode
-set_ssl_ciphers(SCHANNEL_CRED *schannel_cred, char *ciphers)
+set_ssl_ciphers(SCHANNEL_CRED *schannel_cred, char *ciphers,
+                int *algIds)
 {
   char *startCur = ciphers;
   int algCount = 0;
-  static ALG_ID algIds[45]; /*There are 45 listed in the MS headers*/
-  while(startCur && (0 != *startCur) && (algCount < 45)) {
+  while(startCur && (0 != *startCur) && (algCount < NUMOF_CIPHERS)) {
     long alg = strtol(startCur, 0, 0);
     if(!alg)
       alg = get_alg_id_by_name(startCur);
     if(alg)
       algIds[algCount++] = alg;
@@ -591,11 +591,12 @@ schannel_connect_step1(struct Curl_easy *data, struct connectdata *conn,
       failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
       return CURLE_SSL_CONNECT_ERROR;
     }
 
     if(SSL_CONN_CONFIG(cipher_list)) {
-      result = set_ssl_ciphers(&schannel_cred, SSL_CONN_CONFIG(cipher_list));
+      result = set_ssl_ciphers(&schannel_cred, SSL_CONN_CONFIG(cipher_list),
+                               BACKEND->algIds);
       if(CURLE_OK != result) {
         failf(data, "Unable to set ciphers to passed via SSL_CONN_CONFIG");
         return result;
       }
     }
diff --git a/lib/vtls/schannel.h b/lib/vtls/schannel.h
index 2952caa1a5..77853aa30f 100644
--- a/lib/vtls/schannel.h
+++ b/lib/vtls/schannel.h
@@ -69,10 +69,12 @@ CURLcode Curl_verify_certificate(struct Curl_easy *data,
 #ifdef CERT_CHAIN_REVOCATION_CHECK_CHAIN
 #define HAS_MANUAL_VERIFY_API
 #endif
 #endif
 
+#define NUMOF_CIPHERS 45 /* There are 45 listed in the MS headers */
+
 struct Curl_schannel_cred {
   CredHandle cred_handle;
   TimeStamp time_stamp;
   int refcount;
 };
@@ -100,10 +102,11 @@ struct ssl_backend_data {
   bool recv_connection_closed; /* true if connection closed, regardless how */
   bool use_alpn; /* true if ALPN is used for this connection */
 #ifdef HAS_MANUAL_VERIFY_API
   bool use_manual_cred_validation; /* true if manual cred validation is used */
 #endif
+  ALG_ID algIds[NUMOF_CIPHERS];
 };
 #endif /* EXPOSE_SCHANNEL_INTERNAL_STRUCTS */
 
 #endif /* USE_SCHANNEL */
 #endif /* HEADER_CURL_SCHANNEL_H */

Vulnerable code: set_ssl_ciphers(SCHANNEL_CRED *schannel_cred, char *ciphers)
  static ALG_ID algIds[45]; /*There are 45 listed in the MS headers*/
  while(startCur && (0 != *startCur) && (algCount < 45)) {
      result = set_ssl_ciphers(&schannel_cred, SSL_CONN_CONFIG(cipher_list));
Fixed code: set_ssl_ciphers(SCHANNEL_CRED *schannel_cred, char *ciphers,
                int *algIds)
  while(startCur && (0 != *startCur) && (algCount < NUMOF_CIPHERS)) {
      result = set_ssl_ciphers(&schannel_cred, SSL_CONN_CONFIG(cipher_list),
                               BACKEND->algIds);
#define NUMOF_CIPHERS 45 /* There are 45 listed in the MS headers */

  ALG_ID algIds[NUMOF_CIPHERS];