Skip to content

imap capability tokens must be treated case-insensitively #19089

Description

@MegaManSec

I did this

Sorry, quick copy-paste because I'm in a rush but,

curl/lib/imap.c

Lines 1024 to 1104 in c37ed9a

static CURLcode imap_state_capability_resp(struct Curl_easy *data,
struct imap_conn *imapc,
int imapcode,
imapstate instate)
{
CURLcode result = CURLE_OK;
struct connectdata *conn = data->conn;
const char *line = curlx_dyn_ptr(&imapc->pp.recvbuf);
(void)instate;
/* Do we have an untagged response? */
if(imapcode == '*') {
line += 2;
/* Loop through the data line */
for(;;) {
size_t wordlen;
while(*line &&
(*line == ' ' || *line == '\t' ||
*line == '\r' || *line == '\n')) {
line++;
}
if(!*line)
break;
/* Extract the word */
for(wordlen = 0; line[wordlen] && line[wordlen] != ' ' &&
line[wordlen] != '\t' && line[wordlen] != '\r' &&
line[wordlen] != '\n';)
wordlen++;
/* Does the server support the STARTTLS capability? */
if(wordlen == 8 && !memcmp(line, "STARTTLS", 8))
imapc->tls_supported = TRUE;
/* Has the server explicitly disabled clear text authentication? */
else if(wordlen == 13 && !memcmp(line, "LOGINDISABLED", 13))
imapc->login_disabled = TRUE;
/* Does the server support the SASL-IR capability? */
else if(wordlen == 7 && !memcmp(line, "SASL-IR", 7))
imapc->ir_supported = TRUE;
/* Do we have a SASL based authentication mechanism? */
else if(wordlen > 5 && !memcmp(line, "AUTH=", 5)) {
size_t llen;
unsigned short mechbit;
line += 5;
wordlen -= 5;
/* Test the word for a matching authentication mechanism */
mechbit = Curl_sasl_decode_mech(line, wordlen, &llen);
if(mechbit && llen == wordlen)
imapc->sasl.authmechs |= mechbit;
}
line += wordlen;
}
}
else if(data->set.use_ssl && !Curl_conn_is_ssl(conn, FIRSTSOCKET)) {
/* PREAUTH is not compatible with STARTTLS. */
if(imapcode == IMAP_RESP_OK && imapc->tls_supported && !imapc->preauth) {
/* Switch to TLS connection now */
result = imap_perform_starttls(data, imapc);
}
else if(data->set.use_ssl <= CURLUSESSL_TRY)
result = imap_perform_authentication(data, imapc);
else {
failf(data, "STARTTLS not available.");
result = CURLE_USE_SSL_FAILED;
}
}
else
result = imap_perform_authentication(data, imapc);
return result;
}
..

(Chatgpt generated description):

  • IMAP keywords and atoms are case-insensitive by default. RFC 3501's formal syntax section states: "Except as noted otherwise, all alphabetic characters are case-insensitive... Implementations MUST accept these strings in a case-insensitive fashion." IETF Datatracker

    • The CAPABILITY response is a space-separated list of capability names. It must include IMAP4rev1, and it uses atoms for items like STARTTLS, LOGINDISABLED, and AUTH=<mechanism>. Clients MUST NOT issue LOGIN if LOGINDISABLED is advertised. Since these are atoms, the case-insensitive rule applies when matching them. IETF Datatracker

    • The grammar explicitly defines auth-type = atom, which again inherits the case-insensitive rule. That means AUTH=plain and AUTH=PLAIN must be treated the same by a client. IETF Datatracker

    • The STARTTLS extension for IMAP is advertised as the STARTTLS capability and invoked with the STARTTLS command. Whether a server prints STARTTLS or starttls, a conforming client has to recognize it. IETF Datatracker

    • The SASL-IR capability (initial client response) is defined by RFC 4959. Like all capability atoms, it is matched case-insensitively.

I expected the following

used a server which uses lowercase keywords in imap

curl/libcurl version

all

operating system

all

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Fields

No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions