plan9port

fork of plan9port with libvec, libstr and libsdb
Log | Files | Refs | README | LICENSE

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