123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193 |
- /*
- * This file is part of the UCB release of Plan 9. It is subject to the license
- * terms in the LICENSE file found in the top-level directory of this
- * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
- * part of the UCB release of Plan 9, including this file, may be copied,
- * modified, propagated, or distributed except according to the terms contained
- * in the LICENSE file.
- */
- /*
- * HTTPDIGEST - MD5 challenge/response authentication (RFC 2617)
- *
- * Client protocol:
- * write challenge: nonce method uri
- * read response: 2*MD5dlen hex digits
- *
- * Server protocol:
- * unimplemented
- */
- #include "dat.h"
- enum
- {
- CNeedChal,
- CHaveResp,
- Maxphase,
- };
- static char *phasenames[Maxphase] = {
- [CNeedChal] "CNeedChal",
- [CHaveResp] "CHaveResp",
- };
- struct State
- {
- char resp[MD5dlen*2+1];
- };
- static int
- hdinit(Proto *p, Fsstate *fss)
- {
- int iscli;
- State *s;
- if((iscli = isclient(_strfindattr(fss->attr, "role"))) < 0)
- return failure(fss, nil);
- if(!iscli)
- return failure(fss, "%s server not supported", p->name);
- s = emalloc(sizeof *s);
- fss->phasename = phasenames;
- fss->maxphase = Maxphase;
- fss->phase = CNeedChal;
- fss->ps = s;
- return RpcOk;
- }
- 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)
- {
- uint8_t b[MD5dlen];
- char ha1[MD5dlen*2+1];
- char ha2[MD5dlen*2+1];
- DigestState *s;
- /*
- * H(A1) = MD5(uid + ":" + realm ":" + passwd)
- */
- s = md5((uint8_t*)user, strlen(user), nil, nil);
- md5((uint8_t*)":", 1, nil, s);
- md5((uint8_t*)realm, strlen(realm), nil, s);
- md5((uint8_t*)":", 1, nil, s);
- md5((uint8_t*)passwd, strlen(passwd), b, s);
- enc16(ha1, sizeof(ha1), b, MD5dlen);
- strtolower(ha1);
- /*
- * H(A2) = MD5(method + ":" + uri)
- */
- s = md5((uint8_t*)method, strlen(method), nil, nil);
- md5((uint8_t*)":", 1, nil, s);
- md5((uint8_t*)uri, strlen(uri), b, s);
- enc16(ha2, sizeof(ha2), b, MD5dlen);
- strtolower(ha2);
- /*
- * digest = MD5(H(A1) + ":" + nonce + ":" + H(A2))
- */
- s = md5((uint8_t*)ha1, MD5dlen*2, nil, nil);
- md5((uint8_t*)":", 1, nil, s);
- md5((uint8_t*)nonce, strlen(nonce), nil, s);
- md5((uint8_t*)":", 1, nil, s);
- md5((uint8_t*)ha2, MD5dlen*2, b, s);
- enc16(dig, MD5dlen*2+1, b, MD5dlen);
- strtolower(dig);
- }
- static int
- hdwrite(Fsstate *fss, void *va, uint n)
- {
- State *s;
- int ret;
- char *a, *p, *r, *u, *t;
- char *tok[4];
- Key *k;
- Keyinfo ki;
- Attr *attr;
- s = fss->ps;
- a = va;
- if(fss->phase != CNeedChal)
- return phaseerror(fss, "write");
- attr = _delattr(_copyattr(fss->attr), "role");
- mkkeyinfo(&ki, fss, attr);
- ret = findkey(&k, &ki, "%s", fss->proto->keyprompt);
- _freeattr(attr);
- if(ret != RpcOk)
- return ret;
- p = _strfindattr(k->privattr, "!password");
- if(p == nil)
- return failure(fss, "key has no password");
- r = _strfindattr(k->attr, "realm");
- if(r == nil)
- return failure(fss, "key has no realm");
- u = _strfindattr(k->attr, "user");
- if(u == nil)
- return failure(fss, "key has no user");
- setattrs(fss->attr, k->attr);
- /* copy in case a is not null-terminated */
- t = emalloc(n+1);
- memcpy(t, a, n);
- t[n] = 0;
- /* get nonce, method, uri */
- if(tokenize(t, tok, 4) != 3)
- return failure(fss, "bad challenge");
- digest(u, r, p, tok[0], tok[1], tok[2], s->resp);
- free(t);
- closekey(k);
- fss->phase = CHaveResp;
- return RpcOk;
- }
- static int
- hdread(Fsstate *fss, void *va, uint *n)
- {
- State *s;
- s = fss->ps;
- if(fss->phase != CHaveResp)
- return phaseerror(fss, "read");
- if(*n > strlen(s->resp))
- *n = strlen(s->resp);
- memmove(va, s->resp, *n);
- fss->phase = Established;
- fss->haveai = 0;
- return RpcOk;
- }
- static void
- hdclose(Fsstate *fss)
- {
- State *s;
- s = fss->ps;
- free(s);
- }
- Proto httpdigest = {
- .name= "httpdigest",
- .init= hdinit,
- .write= hdwrite,
- .read= hdread,
- .close= hdclose,
- .addkey= replacekey,
- .keyprompt= "user? realm? !password?"
- };
|