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