From 7aceaba6f0fdd430101937b14a6da0e05b8e39b3 Mon Sep 17 00:00:00 2001 From: Seth Schoen Date: Thu, 31 May 2012 13:22:33 -0700 Subject: [PATCH] some reorganization and a start toward processing requests --- webserver/chocolate.py | 103 +++++++++++++++++++++++++++++++++++------ 1 file changed, 88 insertions(+), 15 deletions(-) diff --git a/webserver/chocolate.py b/webserver/chocolate.py index 73c5c68d6..143d5a3a5 100755 --- a/webserver/chocolate.py +++ b/webserver/chocolate.py @@ -1,6 +1,7 @@ #!/usr/bin/env python import web, shelve, time +import CSR from Crypto.Hash import SHA256, HMAC from Crypto import Random from chocolate_protocol_pb2 import chocolatemessage @@ -42,11 +43,91 @@ class sessionstore(object): def age(self, session): return int(time.time()) - self.f[session]["created"] + def make_request(self, session, request): + self.f["request"] = request + + def get_request(self, session): + return self.f["request"] + + def request_made(self, session): + return "request" in self.f[session] + class index: def GET(self): web.header("Content-type", "text/html") return "Hello, world! This server only accepts POST requests." + def killsession(self): + self.sessions.kill(self.session) + + def handlesession(self, m, r): + if m.session == "": + # New session + r.session = SHA256.new(Random.get_random_bytes(32)).hexdigest() + self.session = r.session.encode("UTF8") + self.sessions.create(self.session, int(time.time())) + elif m.session and not r.failure.IsInitialized(): + self.session = m.session.encode("UTF8") + r.session = self.session + if not self.sessions.exists(self.session): + r.failure.cause = r.StaleRequest + elif not self.sessions.live(self.session): + r.failure.cause = r.StaleRequest + elif self.sessions.age(self.session) > MaximumSessionAge: + self.killsession() + r.failure.cause = r.StaleRequest + + def handleclientfailure(self, m, r): + if r.failure.IsInitialized(): return + if m.failure.IsInitialized(): + # Received failure message from client! + self.killsession() + r.failure.cause = r.AbandonedRequest + + def handlesigningrequest(self, m, r): + if r.failure.IsInitialized(): return + if not m.request: return + if self.sessions.request_made(self.session): + self.killsession() + r.failure.cause = r.BadRequest + r.failure.uri = "https://ca.example.com/failures/request" + return + # TODO: currently only examine the first request + # TODO: check client puzzle + timestamp = m.request[0].timestamp + recipient = m.request[0].recipient + nonce = m.request[0].nonce + csr = m.request[0].csr + sig = m.request[0].sig + if timestamp > time.time() or time.time() - timestamp > 100: + self.killsession() + r.failure.cause = r.BadRequest + r.failure.affectedrequest = nonce + r.failure.uri = "https://ca.example.com/failures/time" + return + if recipient != "ca.example.com": + self.killsession() + r.failure.cause = r.BadRequest + r.failure.affectedrequest = nonce + r.failure.uri = "https://ca.example.com/failures/recipient" + return + if not CSR.parse(csr): + self.killsession() + r.failure.cause = r.BadCSR + r.failure.affectedrequest = nonce + return + # if CSR.verify(pubkey(csr), sig) != hmac("chocolate-request-ca-example.com", /%s/%s/%s/%s" % (timestamp, recipient, nonce, csr))): + # self.killsession() + # r.failure.cause = BadSignature + # r.failure.affectedrequest = nonce + # self.killsession() + # return + if not CSR.goodkey(csr): + self.killsession() + r.failure.cause = r.UnsafeKey + r.failure.affectedrequest = nonce + return + def POST(self): web.header("Content-type", "application/x-protobuf") # web.setcookie("chocolate", hmac("foo", "bar"), @@ -62,21 +143,13 @@ class index: else: if m.chocolateversion != 1: r.failure.cause = r.UnsupportedVersion - if m.session == "": - # New session - r.session = SHA256.new(Random.get_random_bytes(32)).hexdigest() - session = r.session.encode("UTF8") - self.sessions.create(session, int(time.time())) - elif m.session and not r.failure.IsInitialized(): - session = m.session.encode("UTF8") - r.session = session - if not self.sessions.exists(session): - r.failure.cause = r.StaleRequest - elif not self.sessions.live(session): - r.failure.cause = r.StaleRequest - elif self.sessions.age(session) > MaximumSessionAge: - self.sessions.kill(session) - r.failure.cause = r.StaleRequest + self.handlesession(m, r) + + self.handleclientfailure(m, r) + + self.handlesigningrequest(m, r) + + # Send reply if m.debug: web.header("Content-type", "text/plain") return "SAW MESSAGE: %s\n" % str(r)