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