#include "config.h"
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#if defined(STDC_HEADERS)
#include <stdlib.h>
#endif
#include "fetchmail.h"
#include "socket.h"
#include "i18n.h"
#include "md5.h"
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);
}
int do_cram_md5 (int sock, char *command, struct query *ctl, char *strip)
{
int result;
int len;
unsigned char buf1[1024];
unsigned char msg_id[768];
unsigned char response[16];
unsigned char reply[1024];
unsigned char *respdata;
gen_send (sock, "%s CRAM-MD5", command);
if ((result = gen_recv (sock, buf1, sizeof (buf1)))) {
return result;
}
respdata = buf1;
if (strip && strncmp(buf1, strip, strlen(strip)) == 0)
respdata += strlen(strip);
len = from64tobits (msg_id, respdata);
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);
}
hmac_md5(ctl->password, strlen(ctl->password),
msg_id, strlen (msg_id),
response, sizeof (response));
#ifdef HAVE_SNPRINTF
snprintf (reply, sizeof(reply),
#else
sprintf(reply,
#endif
"%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]);
to64frombits (buf1, reply, strlen(reply));
suppress_tags = TRUE;
result = gen_transact(sock, buf1, sizeof(buf1));
suppress_tags = FALSE;
if (result)
return(result);
else
return(PS_SUCCESS);
}