initial checkin of client and server that can talk to each other!

This commit is contained in:
Seth Schoen 2012-05-27 23:14:55 -07:00
parent 6dcfdcecda
commit b70d4c8215
5 changed files with 158 additions and 0 deletions

8
webserver/Makefile Normal file
View file

@ -0,0 +1,8 @@
deploy: chocolate_protocol_pb2.py chocolate.py
scp chocolate_protocol.proto chocolate.py ${CHOCOLATESERVER}: && ssh ${CHOCOLATESERVER} protoc chocolate_protocol.proto --python_out=.
chocolate_protocol_pb2.py: chocolate_protocol.proto
protoc chocolate_protocol.proto --python_out=.
clean:
rm -f chocolate_protocol_pb2.pyc

View file

@ -1,2 +1,13 @@
In this directory are tools that will run on webservers for sysadmins to
automatically obtain their certs
Set CHOCOLATESERVER environment variable for "make deploy" and client.py!
chocolate.py - server-side, requires web.py (python-webpy), PyCrypto (python-crypto)
probably wants to run under a web server like lighttpd with fastcgi
client.py - experimental tool for making requests and parsing replies
chocolate_protocol.proto - protocol definition; needs protobuf-compiler

39
webserver/chocolate.py Executable file
View file

@ -0,0 +1,39 @@
#!/usr/bin/env python
import web
from Crypto.Hash import SHA256, HMAC
from chocolate_protocol_pb2 import chocolatemessage
from google.protobuf.message import DecodeError
def hmac(k, m):
return HMAC.new(k, m, SHA256).hexdigest()
urls = (
'.*', 'index'
)
class index:
def GET(self):
web.header("Content-type", "text/html")
return "Hello, world! This server only accepts POST requests."
def POST(self):
web.header("Content-type", "text/html")
web.setcookie("chocolate", hmac("foo", "bar"),
secure=True) # , httponly=True)
m = chocolatemessage()
r = chocolatemessage()
r.chocolateversion = 1
try:
m.ParseFromString(web.data())
except DecodeError:
r.failure.cause = r.BadRequest
else:
if m.chocolateversion != 1:
r.failure.cause = r.UnsupportedVersion
if m.debug: return "SAW MESSAGE: %s\n" % str(r)
else: return r.SerializeToString()
if __name__ == "__main__":
app = web.application(urls, globals())
app.run()

View file

@ -0,0 +1,80 @@
message chocolatemessage {
required int32 chocolateversion = 1;
/* required string session? */
message SigningRequest {
required int64 timestamp = 2;
required string nonce = 3;
required string csr = 4;
required string sig = 5;
optional string clientpuzzle = 6;
/* server can specify difficulty? */
}
enum FailureReason {
UnsupportedVersion = 0;
AbandonedRequest = 1;
ServerOutage = 2;
ServerGone = 3;
StaleRequest = 4;
BadSignature = 5;
BadCSR = 6;
BadRequest = 7;
/* Unauthenticated = ?; */
NeedClientPuzzle = 8;
CannotIssueThatName = 9;
UnsafeKey = 10;
ChallengeFailed = 11;
ChallengeTimeout = 12;
}
message Failure {
required FailureReason cause = 1;
optional string URI = 2;
/* reference to which SigningRequest this relates to? */
}
message Proceed {
/* possibly URI should be replaced with session ID? */
required string timestamp = 1;
required string URI = 2;
optional int32 polldelay = 3;
}
enum ChallengeType {
DomainValidate = 0;
EmailValidate = 1;
Payment = 2;
}
message Challenge {
required ChallengeType type = 1;
required int32 challengeid = 2;
optional string name = 3;
optional string data = 4;
optional string URI = 5;
optional bool succeeded = 6;
/* from server: true if server ACK success,
false if server NAK success,
omit if server doesn't know if client
has attempted yet.
from client: true if claiming to be done,
false if unable,
omit if client hasn't attempted yet. */
}
message Success {
required string certificate = 1; /* Repeated string certificate? */
}
optional SigningRequest request = 2;
optional Failure failure = 3;
optional Proceed proceed = 4;
repeated Challenge challenge = 5;
repeated Challenge completedchallenge = 6;
optional Success success = 7;
optional bool debug = 8; /* Causes server to return text instead of
message! */
}

20
webserver/client.py Normal file
View file

@ -0,0 +1,20 @@
#!/usr/bin/env python
from chocolate_protocol_pb2 import chocolatemessage
import urllib2, os, sys
try:
upstream = "https://%s/chocolate.py" % os.environ["CHOCOLATESERVER"]
except KeyError:
print "Please set the environment variable CHOCOLATESERVER to the hostname"
print "of a server that speaks this protocol."
sys.exit(1)
def do(m):
u = urllib2.urlopen(upstream, m.SerializeToString())
return u.read()
def decode(m):
return str(chocolatemessage.FromString(m))
m = chocolatemessage()