From 6f232ed6b5343dea62abdbbd7d38b48858bee373 Mon Sep 17 00:00:00 2001 From: "Eric S. Raymond" Date: Tue, 8 Jun 1999 07:20:17 +0000 Subject: CRAM-MD5 authentication support a la RFC2195. svn path=/trunk/; revision=2485 --- NEWS | 1 + design-notes.html | 6 ++- fetchmail-features.html | 6 ++- fetchmail.man | 2 +- imap.c | 136 ++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 146 insertions(+), 5 deletions(-) diff --git a/NEWS b/NEWS index c14ae3cd..d5f0cc86 100644 --- a/NEWS +++ b/NEWS @@ -15,6 +15,7 @@ fetchmail-5.1.0 (): * There is now a documented return code 13 for termination on fetchlimit. * Added qpopper 2.53 warning to the FAQ and fetchmailconf. * Fix fetchmailconf to handle window-manager destroy notifications. +* Todd Sabin's RFC2195 support for AUTH=CRAM-MD5 under IMAP. There are 260 people on fetchmail-friends and 387 on fetchmail-announce. diff --git a/design-notes.html b/design-notes.html index cc193045..356a5b3b 100644 --- a/design-notes.html +++ b/design-notes.html @@ -10,7 +10,7 @@
Back to Fetchmail Home Page To Site Map -$Date: 1999/05/16 18:24:08 $ +$Date: 1999/06/08 07:20:17 $

Design Notes On Fetchmail

@@ -525,6 +525,8 @@ all shaped the design in one way or another.

IMAP4 Compatibility With IMAP2bis
RFC2062
Internet Message Access Protocol - Obsolete Syntax +
RFC2449 +
IMAP/POP AUTHorize Extension for Simple Challenge/Response
RFC2449
POP3 Extension Mechanism @@ -533,7 +535,7 @@ all shaped the design in one way or another.

Back to Fetchmail Home Page To Site Map -$Date: 1999/05/16 18:24:08 $ +$Date: 1999/06/08 07:20:17 $

Eric S. Raymond <esr@snark.thyrsus.com>
diff --git a/fetchmail-features.html b/fetchmail-features.html index ab778a90..b607de57 100644 --- a/fetchmail-features.html +++ b/fetchmail-features.html @@ -10,7 +10,7 @@
Back to Fetchmail Home Page To Site Map -$Date: 1999/04/18 18:32:01 $ +$Date: 1999/06/08 07:20:17 $

@@ -19,6 +19,8 @@

Since 5.0:

  • Expunge option can now be used to break POP3 retrieval into subsessions. + +
  • Support for AUTH=CRAM-MD5 under IMAP, a la RFC2195.

Since 4.0:

@@ -173,7 +175,7 @@ get-mail, gwpop, pimp-1.0, pop-perl5-1.2, popc, popmail-1.6 and upop.

Back to Fetchmail Home Page To Site Map -$Date: 1999/04/18 18:32:01 $ +$Date: 1999/06/08 07:20:17 $

Eric S. Raymond <esr@snark.thyrsus.com>
diff --git a/fetchmail.man b/fetchmail.man index 62dd8df9..3896971c 100644 --- a/fetchmail.man +++ b/fetchmail.man @@ -1851,7 +1851,7 @@ IMAP2/IMAP2BIS: RFC 1176, RFC 1732 .TP 5 IMAP4: -RFC 1730, RFC 1731, RFC 1732, RFC 2060, RFC 2061 +RFC 1730, RFC 1731, RFC 1732, RFC 2060, RFC 2061, RFC 2195 .TP 5 ETRN: RFC 1985 diff --git a/imap.c b/imap.c index 1b62f65b..94e4da30 100644 --- a/imap.c +++ b/imap.c @@ -37,6 +37,8 @@ #include #endif +#include "md5.h" + #if OPIE #include #endif /* OPIE */ @@ -588,6 +590,127 @@ static int do_gssauth(int sock, char *hostname, char *username) } #endif /* GSSAPI */ +static void hmac_md5 (unsigned char *password, size_t pass_len, + unsigned char *challenge, size_t chal_len, + unsigned char *response, size_t resp_len) +{ + int i; + unsigned char ipad[64]; + unsigned char opad[64]; + unsigned char hash_passwd[16]; + + MD5_CTX ctx; + + if (resp_len != 16) + return; + + if (pass_len > sizeof (ipad)) + { + MD5Init (&ctx); + MD5Update (&ctx, password, pass_len); + MD5Final (hash_passwd, &ctx); + password = hash_passwd; pass_len = sizeof (hash_passwd); + } + + memset (ipad, 0, sizeof (ipad)); + memset (opad, 0, sizeof (opad)); + memcpy (ipad, password, pass_len); + memcpy (opad, password, pass_len); + + for (i=0; i<64; i++) { + ipad[i] ^= 0x36; + opad[i] ^= 0x5c; + } + + MD5Init (&ctx); + MD5Update (&ctx, ipad, sizeof (ipad)); + MD5Update (&ctx, challenge, chal_len); + MD5Final (response, &ctx); + + MD5Init (&ctx); + MD5Update (&ctx, opad, sizeof (opad)); + MD5Update (&ctx, response, resp_len); + MD5Final (response, &ctx); +} + + +static int do_cram_md5 (int sock, struct query *ctl) +/* authenticate as per RFC2195 */ +{ + int result; + int len; + unsigned char buf1[1024]; + unsigned char msg_id[768]; + unsigned char response[16]; + unsigned char reply[1024]; + + gen_send (sock, "AUTHENTICATE CRAM-MD5"); + + /* From RFC2195: + * The data encoded in the first ready response contains an + * presumptively arbitrary string of random digits, a timestamp, and the + * fully-qualified primary host name of the server. The syntax of the + * unencoded form must correspond to that of an RFC 822 'msg-id' + * [RFC822] as described in [POP3]. + */ + + if (result = gen_recv (sock, buf1, sizeof (buf1))) { + return result; + } + + len = from64tobits (msg_id, buf1); + if (len < 0) { + report (stderr, _("could not decode BASE64 challenge\n")); + return PS_AUTHFAIL; + } else if (len < sizeof (msg_id)) { + msg_id[len] = 0; + } else { + msg_id[sizeof (msg_id)-1] = 0; + } + if (outlevel >= O_DEBUG) { + report (stdout, "decoded as %s\n", msg_id); + } + + /* The client makes note of the data and then responds with a string + * consisting of the user name, a space, and a 'digest'. The latter is + * computed by applying the keyed MD5 algorithm from [KEYED-MD5] where + * the key is a shared secret and the digested text is the timestamp + * (including angle-brackets). + */ + + hmac_md5 (ctl->password, strlen (ctl->password), + msg_id, strlen (msg_id), + response, sizeof (response)); + + snprintf (reply, sizeof (reply), + "%s %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", + ctl->remotename, + response[0], response[1], response[2], response[3], + response[4], response[5], response[6], response[7], + response[8], response[9], response[10], response[11], + response[12], response[13], response[14], response[15]); + + if (outlevel >= O_DEBUG) { + report (stdout, "replying with %s\n", reply); + } + + to64frombits (buf1, reply, strlen (reply)); + if (outlevel >= O_MONITOR) { + report (stdout, "IMAP> %s\n", buf1); + } + SockWrite (sock, buf1, strlen (buf1)); + SockWrite (sock, "\r\n", 2); + + if (result = gen_recv (sock, buf1, sizeof (buf1))) + return result; + + if (strstr (buf1, "OK")) { + return PS_SUCCESS; + } else { + return PS_AUTHFAIL; + } +} + int imap_canonicalize(char *result, char *passwd) /* encode an IMAP password as per RFC1730's quoting conventions */ { @@ -695,6 +818,19 @@ int imap_getauth(int sock, struct query *ctl, char *greeting) } #endif /* KERBEROS_V4 */ + if (strstr (capabilities, "AUTH=CRAM-MD5")) + { + if (outlevel >= O_DEBUG) + report (stdout, _("CRAM-MD5 authentication is supported\n")); + if ((ok = do_cram_md5 (sock, ctl))) + { + if (outlevel >= O_MONITOR) + report (stdout, "IMAP> *\n"); + SockWrite (sock, "*\r\n", 3); + } + return ok; + } + #ifdef __UNUSED__ /* The Cyrus IMAP4rev1 server chokes on this */ /* this handles either AUTH=LOGIN or AUTH-LOGIN */ if ((imap_version >= IMAP4rev1) && (!strstr(capabilities, "LOGIN"))) { -- cgit v1.2.3