diff options
Diffstat (limited to 'src/cmd/auth/factotum/httpdigest.c')
-rw-r--r-- | src/cmd/auth/factotum/httpdigest.c | 119 |
1 files changed, 119 insertions, 0 deletions
diff --git a/src/cmd/auth/factotum/httpdigest.c b/src/cmd/auth/factotum/httpdigest.c new file mode 100644 index 00000000..70815a56 --- /dev/null +++ b/src/cmd/auth/factotum/httpdigest.c @@ -0,0 +1,119 @@ +/* + * 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(*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?", + nil, + nil +}; |