72211f
From 03ca8c6faca7de6628f9cbec3001ec6466c88d07 Mon Sep 17 00:00:00 2001
72211f
From: Patrick Monnerat <patrick@monnerat.net>
72211f
Date: Wed, 8 Sep 2021 11:56:22 +0200
72211f
Subject: [PATCH] ftp,imap,pop3: do not ignore --ssl-reqd
72211f
72211f
In imap and pop3, check if TLS is required even when capabilities
72211f
request has failed.
72211f
72211f
In ftp, ignore preauthentication (230 status of server greeting) if TLS
72211f
is required.
72211f
72211f
Bug: https://curl.se/docs/CVE-2021-22946.html
72211f
72211f
CVE-2021-22946
72211f
72211f
Upstream-commit: 364f174724ef115c63d5e5dc1d3342c8a43b1cca
72211f
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
72211f
---
72211f
 lib/ftp.c               |  9 ++++---
72211f
 lib/imap.c              | 24 ++++++++----------
72211f
 lib/pop3.c              | 33 +++++++++++-------------
72211f
 tests/data/Makefile.inc |  2 ++
72211f
 tests/data/test984      | 56 +++++++++++++++++++++++++++++++++++++++++
72211f
 tests/data/test985      | 54 +++++++++++++++++++++++++++++++++++++++
72211f
 tests/data/test986      | 53 ++++++++++++++++++++++++++++++++++++++
72211f
 7 files changed, 195 insertions(+), 36 deletions(-)
72211f
 create mode 100644 tests/data/test984
72211f
 create mode 100644 tests/data/test985
72211f
 create mode 100644 tests/data/test986
72211f
72211f
diff --git a/lib/ftp.c b/lib/ftp.c
72211f
index 71c9642..30ebeaa 100644
72211f
--- a/lib/ftp.c
72211f
+++ b/lib/ftp.c
72211f
@@ -2621,9 +2621,12 @@ static CURLcode ftp_statemach_act(struct connectdata *conn)
72211f
     /* we have now received a full FTP server response */
72211f
     switch(ftpc->state) {
72211f
     case FTP_WAIT220:
72211f
-      if(ftpcode == 230)
72211f
-        /* 230 User logged in - already! */
72211f
-        return ftp_state_user_resp(conn, ftpcode, ftpc->state);
72211f
+      if(ftpcode == 230) {
72211f
+        /* 230 User logged in - already! Take as 220 if TLS required. */
72211f
+        if(data->set.use_ssl <= CURLUSESSL_TRY ||
72211f
+           conn->ssl[FIRSTSOCKET].use)
72211f
+          return ftp_state_user_resp(conn, ftpcode, ftpc->state);
72211f
+      }
72211f
       else if(ftpcode != 220) {
72211f
         failf(data, "Got a %03d ftp-server response when 220 was expected",
72211f
               ftpcode);
72211f
diff --git a/lib/imap.c b/lib/imap.c
72211f
index bda23a5..7e159d4 100644
72211f
--- a/lib/imap.c
72211f
+++ b/lib/imap.c
72211f
@@ -910,22 +910,18 @@ static CURLcode imap_state_capability_resp(struct connectdata *conn,
72211f
       line += wordlen;
72211f
     }
72211f
   }
72211f
-  else if(imapcode == IMAP_RESP_OK) {
72211f
-    if(data->set.use_ssl && !conn->ssl[FIRSTSOCKET].use) {
72211f
-      /* We don't have a SSL/TLS connection yet, but SSL is requested */
72211f
-      if(imapc->tls_supported)
72211f
-        /* Switch to TLS connection now */
72211f
-        result = imap_perform_starttls(conn);
72211f
-      else if(data->set.use_ssl == CURLUSESSL_TRY)
72211f
-        /* Fallback and carry on with authentication */
72211f
-        result = imap_perform_authentication(conn);
72211f
-      else {
72211f
-        failf(data, "STARTTLS not supported.");
72211f
-        result = CURLE_USE_SSL_FAILED;
72211f
-      }
72211f
+  else if(data->set.use_ssl && !conn->ssl[FIRSTSOCKET].use) {
72211f
+    /* PREAUTH is not compatible with STARTTLS. */
72211f
+    if(imapcode == IMAP_RESP_OK && imapc->tls_supported && !imapc->preauth) {
72211f
+      /* Switch to TLS connection now */
72211f
+      result = imap_perform_starttls(conn);
72211f
     }
72211f
-    else
72211f
+    else if(data->set.use_ssl <= CURLUSESSL_TRY)
72211f
       result = imap_perform_authentication(conn);
72211f
+    else {
72211f
+      failf(data, "STARTTLS not available.");
72211f
+      result = CURLE_USE_SSL_FAILED;
72211f
+    }
72211f
   }
72211f
   else
72211f
     result = imap_perform_authentication(conn);
72211f
diff --git a/lib/pop3.c b/lib/pop3.c
72211f
index 04cc887..3e916ce 100644
72211f
--- a/lib/pop3.c
72211f
+++ b/lib/pop3.c
72211f
@@ -718,28 +718,23 @@ static CURLcode pop3_state_capa_resp(struct connectdata *conn, int pop3code,
72211f
       }
72211f
     }
72211f
   }
72211f
-  else if(pop3code == '+') {
72211f
-    if(data->set.use_ssl && !conn->ssl[FIRSTSOCKET].use) {
72211f
-      /* We don't have a SSL/TLS connection yet, but SSL is requested */
72211f
-      if(pop3c->tls_supported)
72211f
-        /* Switch to TLS connection now */
72211f
-        result = pop3_perform_starttls(conn);
72211f
-      else if(data->set.use_ssl == CURLUSESSL_TRY)
72211f
-        /* Fallback and carry on with authentication */
72211f
-        result = pop3_perform_authentication(conn);
72211f
-      else {
72211f
-        failf(data, "STLS not supported.");
72211f
-        result = CURLE_USE_SSL_FAILED;
72211f
-      }
72211f
-    }
72211f
-    else
72211f
-      result = pop3_perform_authentication(conn);
72211f
-  }
72211f
   else {
72211f
     /* Clear text is supported when CAPA isn't recognised */
72211f
-    pop3c->authtypes |= POP3_TYPE_CLEARTEXT;
72211f
+    if(pop3code != '+')
72211f
+      pop3c->authtypes |= POP3_TYPE_CLEARTEXT;
72211f
 
72211f
-    result = pop3_perform_authentication(conn);
72211f
+    if(!data->set.use_ssl || conn->ssl[FIRSTSOCKET].use)
72211f
+      result = pop3_perform_authentication(conn);
72211f
+    else if(pop3code == '+' && pop3c->tls_supported)
72211f
+      /* Switch to TLS connection now */
72211f
+      result = pop3_perform_starttls(conn);
72211f
+    else if(data->set.use_ssl <= CURLUSESSL_TRY)
72211f
+      /* Fallback and carry on with authentication */
72211f
+      result = pop3_perform_authentication(conn);
72211f
+    else {
72211f
+      failf(data, "STLS not supported.");
72211f
+      result = CURLE_USE_SSL_FAILED;
72211f
+    }
72211f
   }
72211f
 
72211f
   return result;
72211f
diff --git a/tests/data/Makefile.inc b/tests/data/Makefile.inc
72211f
index ef9252b..1ba482b 100644
72211f
--- a/tests/data/Makefile.inc
72211f
+++ b/tests/data/Makefile.inc
72211f
@@ -108,6 +108,8 @@ test927 test928 test929 test930 test931 test932 test933 test934 test935 \
72211f
 test936 test937 test938 test939 test940 test941 test942 test943 test944 \
72211f
 test945 test946 test947 test948 test949 test950 test951 test952 \
72211f
 \
72211f
+test984 test985 test986 \
72211f
+\
72211f
 test1000 test1001 test1002 test1003 test1004 test1005 test1006 test1007 \
72211f
 test1008 test1009 test1010 test1011 test1012 test1013 test1014 test1015 \
72211f
 test1016 test1017 test1018 test1019 test1020 test1021 test1022 test1023 \
72211f
diff --git a/tests/data/test984 b/tests/data/test984
72211f
new file mode 100644
72211f
index 0000000..e573f23
72211f
--- /dev/null
72211f
+++ b/tests/data/test984
72211f
@@ -0,0 +1,56 @@
72211f
+<testcase>
72211f
+<info>
72211f
+<keywords>
72211f
+IMAP
72211f
+STARTTLS
72211f
+</keywords>
72211f
+</info>
72211f
+
72211f
+#
72211f
+# Server-side
72211f
+<reply>
72211f
+<servercmd>
72211f
+REPLY CAPABILITY A001 BAD Not implemented
72211f
+</servercmd>
72211f
+</reply>
72211f
+
72211f
+#
72211f
+# Client-side
72211f
+<client>
72211f
+<features>
72211f
+SSL
72211f
+</features>
72211f
+<server>
72211f
+imap
72211f
+</server>
72211f
+ <name>
72211f
+IMAP require STARTTLS with failing capabilities
72211f
+ </name>
72211f
+ <command>
72211f
+imap://%HOSTIP:%IMAPPORT/%TESTNUMBER -T log/upload%TESTNUMBER -u user:secret --ssl-reqd
72211f
+</command>
72211f
+<file name="log/upload%TESTNUMBER">
72211f
+Date: Mon, 7 Feb 1994 21:52:25 -0800 (PST)
72211f
+From: Fred Foobar <foobar@example.COM>
72211f
+Subject: afternoon meeting
72211f
+To: joe@example.com
72211f
+Message-Id: <B27397-0100000@example.COM>
72211f
+MIME-Version: 1.0
72211f
+Content-Type: TEXT/PLAIN; CHARSET=US-ASCII
72211f
+
72211f
+Hello Joe, do you think we can meet at 3:30 tomorrow?
72211f
+</file>
72211f
+</client>
72211f
+
72211f
+#
72211f
+# Verify data after the test has been "shot"
72211f
+<verify>
72211f
+# 64 is CURLE_USE_SSL_FAILED
72211f
+<errorcode>
72211f
+64
72211f
+</errorcode>
72211f
+<protocol>
72211f
+A001 CAPABILITY
72211f
+</protocol>
72211f
+</verify>
72211f
+</testcase>
72211f
diff --git a/tests/data/test985 b/tests/data/test985
72211f
new file mode 100644
72211f
index 0000000..d0db4aa
72211f
--- /dev/null
72211f
+++ b/tests/data/test985
72211f
@@ -0,0 +1,54 @@
72211f
+<testcase>
72211f
+<info>
72211f
+<keywords>
72211f
+POP3
72211f
+STARTTLS
72211f
+</keywords>
72211f
+</info>
72211f
+
72211f
+#
72211f
+# Server-side
72211f
+<reply>
72211f
+<servercmd>
72211f
+REPLY CAPA -ERR Not implemented
72211f
+</servercmd>
72211f
+<data nocheck="yes">
72211f
+From: me@somewhere
72211f
+To: fake@nowhere
72211f
+
72211f
+body
72211f
+
72211f
+--
72211f
+  yours sincerely
72211f
+</data>
72211f
+</reply>
72211f
+
72211f
+#
72211f
+# Client-side
72211f
+<client>
72211f
+<features>
72211f
+SSL
72211f
+</features>
72211f
+<server>
72211f
+pop3
72211f
+</server>
72211f
+ <name>
72211f
+POP3 require STARTTLS with failing capabilities
72211f
+ </name>
72211f
+ <command>
72211f
+pop3://%HOSTIP:%POP3PORT/%TESTNUMBER -u user:secret --ssl-reqd
72211f
+ </command>
72211f
+</client>
72211f
+
72211f
+#
72211f
+# Verify data after the test has been "shot"
72211f
+<verify>
72211f
+# 64 is CURLE_USE_SSL_FAILED
72211f
+<errorcode>
72211f
+64
72211f
+</errorcode>
72211f
+<protocol>
72211f
+CAPA
72211f
+</protocol>
72211f
+</verify>
72211f
+</testcase>
72211f
diff --git a/tests/data/test986 b/tests/data/test986
72211f
new file mode 100644
72211f
index 0000000..a709437
72211f
--- /dev/null
72211f
+++ b/tests/data/test986
72211f
@@ -0,0 +1,53 @@
72211f
+<testcase>
72211f
+<info>
72211f
+<keywords>
72211f
+FTP
72211f
+STARTTLS
72211f
+</keywords>
72211f
+</info>
72211f
+
72211f
+#
72211f
+# Server-side
72211f
+<reply>
72211f
+<servercmd>
72211f
+REPLY welcome 230 Welcome
72211f
+REPLY AUTH 500 unknown command
72211f
+</servercmd>
72211f
+</reply>
72211f
+
72211f
+# Client-side
72211f
+<client>
72211f
+<features>
72211f
+SSL
72211f
+</features>
72211f
+<server>
72211f
+ftp
72211f
+</server>
72211f
+ <name>
72211f
+FTP require STARTTLS while preauthenticated
72211f
+ </name>
72211f
+<file name="log/test%TESTNUMBER.txt">
72211f
+data
72211f
+    to
72211f
+      see
72211f
+that FTPS
72211f
+works
72211f
+  so does it?
72211f
+</file>
72211f
+ <command>
72211f
+--ssl-reqd --ftp-ssl-control ftp://%HOSTIP:%FTPPORT/%TESTNUMBER -T log/test%TESTNUMBER.txt -u user:secret
72211f
+</command>
72211f
+</client>
72211f
+
72211f
+# Verify data after the test has been "shot"
72211f
+<verify>
72211f
+# 64 is CURLE_USE_SSL_FAILED
72211f
+<errorcode>
72211f
+64
72211f
+</errorcode>
72211f
+<protocol>
72211f
+AUTH SSL
72211f
+AUTH TLS
72211f
+</protocol>
72211f
+</verify>
72211f
+</testcase>
72211f
-- 
72211f
2.31.1
72211f