aboutsummaryrefslogtreecommitdiffstats
path: root/trio/triodef.h
diff options
context:
space:
mode:
Diffstat (limited to 'trio/triodef.h')
0 files changed, 0 insertions, 0 deletions
'n82' href='#n82'>82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
/*
 * cram.c -- CRAM-MD5 authentication (see RFC 2195)
 *
 * For license terms, see the file COPYING in this directory.
 */

#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"

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)
/* 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];
    unsigned char *respdata;

    gen_send (sock, "%s CRAM-MD5", command);

    /* 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;
    }

    /* caller may specify a response prefix we should strip if present */
    respdata = buf1;
    if (strip && strncmp(buf1, strip, strlen(strip)) == 0)
	respdata += strlen(strip);
    len = from64tobits (msg_id, respdata, sizeof(msg_id));

    if (len < 0) {
	report (stderr, GT_("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, GT_("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]);

    to64frombits (buf1, reply, strlen(reply));

    /* ship the authentication back, accept the server's responses */
    /* PMDF5.2 IMAP has a bug that requires this to be a single write */
    suppress_tags = TRUE;
    result = gen_transact(sock, buf1, sizeof(buf1));
    suppress_tags = FALSE;
    if (result)
	return(result);
    else
	return(PS_SUCCESS);
}

/* cram.c ends here */