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 --- imap.c | 136 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 136 insertions(+) (limited to 'imap.c') 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