1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
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 (char *password, size_t pass_len,
char *challenge, size_t chal_len,
unsigned char *response, size_t resp_len)
{
int i;
unsigned char ipad[64];
unsigned char opad[64];
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;
char buf1[1024];
char msg_id[768];
unsigned char response[16];
char reply[1024];
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 ((size_t)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 */
|