|  | /* | 
|  | * HTTPDIGEST - MD5 challenge/response authentication (RFC 2617) | 
|  | * | 
|  | * Client protocol: | 
|  | *	write challenge: nonce method uri | 
|  | *	read response: 2*MD5dlen hex digits | 
|  | * | 
|  | * Server protocol: | 
|  | *	unimplemented | 
|  | */ | 
|  | #include "std.h" | 
|  | #include "dat.h" | 
|  |  | 
|  | static void | 
|  | digest(char *user, char *realm, char *passwd, | 
|  | char *nonce, char *method, char *uri, | 
|  | char *dig); | 
|  |  | 
|  | static int | 
|  | hdclient(Conv *c) | 
|  | { | 
|  | char *realm, *passwd, *user, *f[4], *s, resp[MD5dlen*2+1]; | 
|  | int ret; | 
|  | Key *k; | 
|  |  | 
|  | ret = -1; | 
|  | s = nil; | 
|  |  | 
|  | c->state = "keylookup"; | 
|  | k = keyfetch(c, "%A", c->attr); | 
|  | if(k == nil) | 
|  | goto out; | 
|  |  | 
|  | user = strfindattr(k->attr, "user"); | 
|  | realm = strfindattr(k->attr, "realm"); | 
|  | passwd = strfindattr(k->attr, "!password"); | 
|  |  | 
|  | if(convreadm(c, &s) < 0) | 
|  | goto out; | 
|  | if(tokenize(s, f, 4) != 3){ | 
|  | werrstr("bad challenge -- want nonce method uri"); | 
|  | goto out; | 
|  | } | 
|  |  | 
|  | digest(user, realm, passwd, f[0], f[1], f[2], resp); | 
|  | convwrite(c, resp, strlen(resp)); | 
|  | ret = 0; | 
|  |  | 
|  | out: | 
|  | free(s); | 
|  | keyclose(k); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static void | 
|  | strtolower(char *s) | 
|  | { | 
|  | while(*s){ | 
|  | *s = tolower((uchar)*s); | 
|  | s++; | 
|  | } | 
|  | } | 
|  |  | 
|  | static void | 
|  | digest(char *user, char *realm, char *passwd, | 
|  | char *nonce, char *method, char *uri, | 
|  | char *dig) | 
|  | { | 
|  | uchar b[MD5dlen]; | 
|  | char ha1[MD5dlen*2+1]; | 
|  | char ha2[MD5dlen*2+1]; | 
|  | DigestState *s; | 
|  |  | 
|  | /* | 
|  | *  H(A1) = MD5(uid + ":" + realm ":" + passwd) | 
|  | */ | 
|  | s = md5((uchar*)user, strlen(user), nil, nil); | 
|  | md5((uchar*)":", 1, nil, s); | 
|  | md5((uchar*)realm, strlen(realm), nil, s); | 
|  | md5((uchar*)":", 1, nil, s); | 
|  | md5((uchar*)passwd, strlen(passwd), b, s); | 
|  | enc16(ha1, sizeof(ha1), b, MD5dlen); | 
|  | strtolower(ha1); | 
|  |  | 
|  | /* | 
|  | *  H(A2) = MD5(method + ":" + uri) | 
|  | */ | 
|  | s = md5((uchar*)method, strlen(method), nil, nil); | 
|  | md5((uchar*)":", 1, nil, s); | 
|  | md5((uchar*)uri, strlen(uri), b, s); | 
|  | enc16(ha2, sizeof(ha2), b, MD5dlen); | 
|  | strtolower(ha2); | 
|  |  | 
|  | /* | 
|  | *  digest = MD5(H(A1) + ":" + nonce + ":" + H(A2)) | 
|  | */ | 
|  | s = md5((uchar*)ha1, MD5dlen*2, nil, nil); | 
|  | md5((uchar*)":", 1, nil, s); | 
|  | md5((uchar*)nonce, strlen(nonce), nil, s); | 
|  | md5((uchar*)":", 1, nil, s); | 
|  | md5((uchar*)ha2, MD5dlen*2, b, s); | 
|  | enc16(dig, MD5dlen*2+1, b, MD5dlen); | 
|  | strtolower(dig); | 
|  | } | 
|  |  | 
|  | static Role hdroles[] = | 
|  | { | 
|  | "client",	hdclient, | 
|  | 0 | 
|  | }; | 
|  |  | 
|  | Proto httpdigest = | 
|  | { | 
|  | "httpdigest", | 
|  | hdroles, | 
|  | "user? realm? !password?", | 
|  | 0, | 
|  | 0 | 
|  | }; |