Blob


1 /*
2 * HTTPDIGEST - MD5 challenge/response authentication (RFC 2617)
3 *
4 * Client protocol:
5 * write challenge: nonce method uri
6 * read response: 2*MD5dlen hex digits
7 *
8 * Server protocol:
9 * unimplemented
10 */
11 #include "std.h"
12 #include "dat.h"
14 static void
15 digest(char *user, char *realm, char *passwd,
16 char *nonce, char *method, char *uri,
17 char *dig);
19 static int
20 hdclient(Conv *c)
21 {
22 char *realm, *passwd, *user, *f[4], *s, resp[MD5dlen*2+1];
23 int ret;
24 Key *k;
26 ret = -1;
27 s = nil;
29 c->state = "keylookup";
30 k = keyfetch(c, "%A", c->attr);
31 if(k == nil)
32 goto out;
34 user = strfindattr(k->attr, "user");
35 realm = strfindattr(k->attr, "realm");
36 passwd = strfindattr(k->attr, "!password");
38 if(convreadm(c, &s) < 0)
39 goto out;
40 if(tokenize(s, f, 4) != 3){
41 werrstr("bad challenge -- want nonce method uri");
42 goto out;
43 }
45 digest(user, realm, passwd, f[0], f[1], f[2], resp);
46 convwrite(c, resp, strlen(resp));
47 ret = 0;
49 out:
50 free(s);
51 keyclose(k);
52 return ret;
53 }
55 static void
56 strtolower(char *s)
57 {
58 while(*s){
59 *s = tolower((uchar)*s);
60 s++;
61 }
62 }
64 static void
65 digest(char *user, char *realm, char *passwd,
66 char *nonce, char *method, char *uri,
67 char *dig)
68 {
69 uchar b[MD5dlen];
70 char ha1[MD5dlen*2+1];
71 char ha2[MD5dlen*2+1];
72 DigestState *s;
74 /*
75 * H(A1) = MD5(uid + ":" + realm ":" + passwd)
76 */
77 s = md5((uchar*)user, strlen(user), nil, nil);
78 md5((uchar*)":", 1, nil, s);
79 md5((uchar*)realm, strlen(realm), nil, s);
80 md5((uchar*)":", 1, nil, s);
81 md5((uchar*)passwd, strlen(passwd), b, s);
82 enc16(ha1, sizeof(ha1), b, MD5dlen);
83 strtolower(ha1);
85 /*
86 * H(A2) = MD5(method + ":" + uri)
87 */
88 s = md5((uchar*)method, strlen(method), nil, nil);
89 md5((uchar*)":", 1, nil, s);
90 md5((uchar*)uri, strlen(uri), b, s);
91 enc16(ha2, sizeof(ha2), b, MD5dlen);
92 strtolower(ha2);
94 /*
95 * digest = MD5(H(A1) + ":" + nonce + ":" + H(A2))
96 */
97 s = md5((uchar*)ha1, MD5dlen*2, nil, nil);
98 md5((uchar*)":", 1, nil, s);
99 md5((uchar*)nonce, strlen(nonce), nil, s);
100 md5((uchar*)":", 1, nil, s);
101 md5((uchar*)ha2, MD5dlen*2, b, s);
102 enc16(dig, MD5dlen*2+1, b, MD5dlen);
103 strtolower(dig);
106 static Role hdroles[] =
108 "client", hdclient,
110 };
112 Proto httpdigest =
114 "httpdigest",
115 hdroles,
116 "user? realm? !password?",
117 0,
119 };