httpdigest.c (2239B)
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" 13 14 static void 15 digest(char *user, char *realm, char *passwd, 16 char *nonce, char *method, char *uri, 17 char *dig); 18 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; 25 26 ret = -1; 27 s = nil; 28 29 c->state = "keylookup"; 30 k = keyfetch(c, "%A", c->attr); 31 if(k == nil) 32 goto out; 33 34 user = strfindattr(k->attr, "user"); 35 realm = strfindattr(k->attr, "realm"); 36 passwd = strfindattr(k->attr, "!password"); 37 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 } 44 45 digest(user, realm, passwd, f[0], f[1], f[2], resp); 46 convwrite(c, resp, strlen(resp)); 47 ret = 0; 48 49 out: 50 free(s); 51 keyclose(k); 52 return ret; 53 } 54 55 static void 56 strtolower(char *s) 57 { 58 while(*s){ 59 *s = tolower((uchar)*s); 60 s++; 61 } 62 } 63 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; 73 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); 84 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); 93 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); 104 } 105 106 static Role hdroles[] = 107 { 108 "client", hdclient, 109 0 110 }; 111 112 Proto httpdigest = 113 { 114 "httpdigest", 115 hdroles, 116 "user? realm? !password?", 117 0, 118 0 119 };