aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/auth/factotum/httpdigest.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/auth/factotum/httpdigest.c')
-rw-r--r--src/cmd/auth/factotum/httpdigest.c119
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
+};