mirror of
https://github.com/certbot/certbot.git
synced 2026-01-26 07:41:33 +03:00
Merge branch 'master' of github.com:research/chocolate
This commit is contained in:
@@ -233,6 +233,7 @@ class session(object):
|
||||
recipient = m.request.recipient
|
||||
csr = m.request.csr
|
||||
sig = m.request.sig
|
||||
self.log("new session from %s" % web.ctx.ip)
|
||||
# Check whether we are the intended recipient of the request. Doing this
|
||||
# before the hashcash check is more work for the server but gives a more
|
||||
# helpful error message (because the hashcash will be wrong automatically
|
||||
@@ -314,6 +315,7 @@ class session(object):
|
||||
r.proceed.polldelay = polldelay
|
||||
|
||||
def handleexistingsession(self, m, r):
|
||||
self.log("received message from %s" % web.ctx.ip)
|
||||
if m.request.IsInitialized():
|
||||
self.die(r, r.BadRequest, uri="https://ca.example.com/failures/requestinexistingsession")
|
||||
return
|
||||
|
||||
@@ -5,6 +5,9 @@
|
||||
import time, binascii
|
||||
from Crypto import Random
|
||||
|
||||
import redis
|
||||
log_redis = redis.Redis()
|
||||
|
||||
def signal_handler(a, b):
|
||||
global clean_shutdown
|
||||
clean_shutdown = True
|
||||
@@ -27,6 +30,6 @@ def random_raw():
|
||||
|
||||
def log(msg, session = None):
|
||||
if session:
|
||||
r.publish("logs", "%s: %s" % (short(session), msg))
|
||||
log_redis.publish("logs", "%s: %s" % (short(session), msg))
|
||||
else:
|
||||
r.publish("logs", "%s" % session)
|
||||
log_redis.publish("logs", "%s" % session)
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
# the database that are waiting for a cert to be issued.
|
||||
|
||||
import redis, redis_lock, CSR, sys, signal
|
||||
from sni_challenge.verify import verify_challenge
|
||||
from Crypto import Random
|
||||
|
||||
r = redis.Redis()
|
||||
@@ -49,12 +48,12 @@ def issue(session):
|
||||
return
|
||||
csr = r.hget(session, "csr")
|
||||
names = r.lrange("%s:names" % session, 0, -1)
|
||||
log("attempting to issue certificate for names: %s" % join(names), session)
|
||||
log("attempting to issue certificate for names: %s" % ", ".join(names), session)
|
||||
with issue_lock:
|
||||
cert = CSR.issue(csr, names)
|
||||
r.hset(session, "cert", cert)
|
||||
if cert: # once issuing cert succeeded
|
||||
log("issued certificate for names: %s" % join(names), session)
|
||||
log("issued certificate for names: %s" % ", ".join(names), session)
|
||||
r.hset(session, "state", "done")
|
||||
# r.lpush("pending-done", session)
|
||||
else: # should not be reached in deployed version
|
||||
|
||||
@@ -26,5 +26,6 @@ for message in ps.listen():
|
||||
if message["channel"] == "exit":
|
||||
break
|
||||
if clean_shutdown:
|
||||
print "logging daemon exiting cleanly"
|
||||
sys.stdout.write("logging daemon exiting cleanly\n")
|
||||
sys.stdout.flush()
|
||||
break
|
||||
|
||||
@@ -25,7 +25,7 @@ def makechallenge(session):
|
||||
# pending-requests queue and not pushed into any other queue.
|
||||
# We don't have to remove it from pending-makechallenge
|
||||
# because the caller has already done so.
|
||||
if debug: print "removing expired session", short(session)
|
||||
log("removing expired session", session)
|
||||
r.lrem("pending-requests", session)
|
||||
return
|
||||
# Currently only makes challenges of type 0 (DomainValidateSNI)
|
||||
@@ -37,9 +37,8 @@ def makechallenge(session):
|
||||
# Make one challenge for each name. (This one-to-one relationship
|
||||
# is not an inherent protocol requirement!)
|
||||
names = r.lrange("%s:names" % session, 0, -1)
|
||||
if debug: print "%s: new valid request" % session
|
||||
if debug: print "%s: from requesting client at %s" % (short(session), r.hget(session, "client-addr"))
|
||||
if debug: print "%s: for %d names: %s" % (short(session), len(names), ", ".join(names))
|
||||
log("new valid request from requesting client at %s" % r.hget(session, "client-addr"), session)
|
||||
log("for %d names: %s" % (len(names), ", ".join(names)), session)
|
||||
for i, name in enumerate(names):
|
||||
challenge = "%s:%d" % (session, i)
|
||||
r.hset(challenge, "challtime", int(time.time()))
|
||||
@@ -52,7 +51,7 @@ def makechallenge(session):
|
||||
r.hset(challenge, "dvsni:ext", "1.3.3.7")
|
||||
# Keep accurate count of how many challenges exist in this session.
|
||||
r.hincrby(session, "challenges", 1)
|
||||
if debug: print "created new challenge", short(challenge)
|
||||
log("created new challenge %s" % challenge, session)
|
||||
if True: # challenges have been created
|
||||
r.hset(session, "state", "testchallenge")
|
||||
else:
|
||||
|
||||
@@ -47,7 +47,7 @@ for message in ps.listen():
|
||||
if len(session) != 64: continue
|
||||
if session not in r or r.hget(session, "live") != "True": continue
|
||||
if r.hget(session, "state") != "payment": continue
|
||||
if debug: print "\t** All challenges satisfied; payment received; request %s GRANTED" % short(session)
|
||||
log("\t** All challenges satisfied; payment received; request GRANTED", session)
|
||||
r.hset(session, "state", "issue")
|
||||
r.lpush("pending-issue", session)
|
||||
continue
|
||||
|
||||
@@ -30,11 +30,11 @@ class payment(object):
|
||||
def GET(self, session):
|
||||
web.header("Content-type", "text/html")
|
||||
if len(session) != 64 or not all(hexdigit(s) for s in session):
|
||||
return "Attempt to process payment for invalid session."
|
||||
return "<html><h1>Oops!</h1>Attempt to process payment for invalid session.</html>"
|
||||
if session not in r or r.hget(session, "live") != "True":
|
||||
return "Attempt to process payment for invalid session."
|
||||
return "<html><h1>Oops!</h1>Attempt to process payment for invalid session.</html>"
|
||||
if r.hget(session, "state") != "payment":
|
||||
return "Attempt to process payment for session not expecting it."
|
||||
return "<html><h1>Oops!</h1>Attempt to process payment for session that was not expecting it.</html>"
|
||||
r.publish("payments", session)
|
||||
names = r.lrange("%s:names" % session, 0, -1)
|
||||
names_list = '<ul style="font-family:monospace">' + "\n".join("<li>%s</li>" % n for n in names) + '</ul>'
|
||||
|
||||
@@ -68,16 +68,17 @@ def verify_challenge(address, r, nonce, socksify=False):
|
||||
sni_support.set_sni_ext(conn.ssl, sni_name)
|
||||
try:
|
||||
conn.connect((address, 443))
|
||||
peername = str(conn.socket.getpeername())
|
||||
except Exception, e:
|
||||
return False, "Connection to SSL Server failed (%s)" % str(e)
|
||||
return False, "Connection to SSL Server failed (%s)" % str(e), peername
|
||||
|
||||
cert_chain = conn.get_peer_cert_chain()
|
||||
|
||||
#Ensure certificate chain form is correct
|
||||
if cert_chain is None:
|
||||
return False, "Client did not provide a certificate"
|
||||
return False, "Client did not provide a certificate", peername
|
||||
if len(cert_chain) != 1:
|
||||
return False, "Chocolate client should only include 1 cert"
|
||||
return False, "Chocolate client should only include 1 cert", peername
|
||||
|
||||
for i in range(0,cert_chain[0].get_ext_count()):
|
||||
ext = cert_chain[0].get_ext_at(i)
|
||||
@@ -87,11 +88,11 @@ def verify_challenge(address, r, nonce, socksify=False):
|
||||
|
||||
valid = check_challenge_value(sni_support.get_unknown_value(ext.x509_ext), r)
|
||||
if valid:
|
||||
return True, "Challenge completed successfully"
|
||||
return True, "Challenge completed successfully", peername
|
||||
else:
|
||||
return False, "Certificate extension does not check out"
|
||||
return False, "Certificate extension does not check out", peername
|
||||
|
||||
return False, "Chocolate extension not included in certificate"
|
||||
return False, "Chocolate extension not included in certificate", peername
|
||||
|
||||
def main():
|
||||
#Testing the example sni_challenge
|
||||
@@ -108,10 +109,10 @@ def main():
|
||||
nonce = binascii.hexlify(nonce)
|
||||
nonce2 = binascii.hexlify(nonce2)
|
||||
|
||||
valid, response = verify_challenge("example.com", r, nonce)
|
||||
valid, response, peername = verify_challenge("example.com", r, nonce)
|
||||
#valid, response = verify_challenge("127.0.0.1", r, nonce)
|
||||
print response
|
||||
valid, response = verify_challenge("www.example.com", r2, nonce2)
|
||||
valid, response, peername = verify_challenge("www.example.com", r2, nonce2)
|
||||
#valid, response = verify_challenge("localhost", r2, nonce2)
|
||||
print response
|
||||
if __name__ == "__main__":
|
||||
|
||||
@@ -34,7 +34,7 @@ def testchallenge(session):
|
||||
# pending-requests queue and not pushed into any other queue.
|
||||
# We don't have to remove it from pending-testchallenge
|
||||
# because the caller has already done so.
|
||||
if debug: print "removing expired session", short(session)
|
||||
log("removing expired session", session)
|
||||
r.lrem("pending-requests", session)
|
||||
return
|
||||
if r.hget(session, "state") != "testchallenge":
|
||||
@@ -49,7 +49,7 @@ def testchallenge(session):
|
||||
all_satisfied = True
|
||||
for i, name in enumerate(r.lrange("%s:names" % session, 0, -1)):
|
||||
challenge = "%s:%d" % (session, i)
|
||||
if debug: print "testing challenge", short(challenge)
|
||||
log("testing challenge %s" % challenge, session)
|
||||
challtime = int(r.hget(challenge, "challtime"))
|
||||
challtype = int(r.hget(challenge, "type"))
|
||||
name = r.hget(challenge, "name")
|
||||
@@ -59,15 +59,14 @@ def testchallenge(session):
|
||||
if not satisfied and not failed:
|
||||
# if debug: print "challenge", short(challenge), "being tested"
|
||||
if challtype == 0: # DomainValidateSNI
|
||||
if debug: print "\tbeginning dvsni test to %s" % name
|
||||
log("\tbeginning dvsni test to %s" % name, session)
|
||||
dvsni_nonce = r.hget(challenge, "dvsni:nonce")
|
||||
dvsni_r = r.hget(challenge, "dvsni:r")
|
||||
dvsni_ext = r.hget(challenge, "dvsni:ext")
|
||||
direct_result, direct_reason = verify_challenge(name, dvsni_r, dvsni_nonce, False)
|
||||
proxy_result, proxy_reason = verify_challenge(name, dvsni_r, dvsni_nonce, True)
|
||||
if debug:
|
||||
print "\t...direct probe: %s (%s)" % (direct_result, direct_reason)
|
||||
print "\tTor proxy probe: %s (%s)" % (proxy_result, proxy_reason)
|
||||
direct_result, direct_reason, direct_peername = verify_challenge(name, dvsni_r, dvsni_nonce, False)
|
||||
proxy_result, proxy_reason, proxy_peername = verify_challenge(name, dvsni_r, dvsni_nonce, True)
|
||||
log("\t...direct probe: %s (%s) to %s" % (direct_result, direct_reason, direct_peername), session)
|
||||
log("\tTor proxy probe: %s (%s)" % (proxy_result, proxy_reason), session)
|
||||
if direct_result and proxy_result:
|
||||
r.hset(challenge, "satisfied", True)
|
||||
else:
|
||||
@@ -80,7 +79,7 @@ def testchallenge(session):
|
||||
# Don't know how to handle this challenge type
|
||||
all_satisfied = False
|
||||
elif not satisfied:
|
||||
if debug: print "\tchallenge was not attempted"
|
||||
log("\tchallenge was not attempted", session)
|
||||
all_satisfied = False
|
||||
if all_satisfied:
|
||||
# Challenges all succeeded, so we should prepare to issue
|
||||
@@ -91,7 +90,7 @@ def testchallenge(session):
|
||||
# the daemon that put this session on the queue should
|
||||
# also have implicitly guaranteed this).
|
||||
if policy.payment_required(session):
|
||||
if debug: print "\t** All challenges satisfied; request %s NEEDS PAYMENT" % short(session)
|
||||
log("\t** All challenges satisfied; request NEEDS PAYMENT", session)
|
||||
# Try to get a unique abbreviated ID (10 hex digits)
|
||||
for i in xrange(20):
|
||||
abbreviation = random()[:10]
|
||||
@@ -110,7 +109,7 @@ def testchallenge(session):
|
||||
# instantaneously as soon as the payment system sends a "payments"
|
||||
# pubsub message to the payments daemon.
|
||||
else:
|
||||
if debug: print "\t** All challenges satisfied; request %s GRANTED" % short(session)
|
||||
log("\t** All challenges satisfied; request GRANTED", session)
|
||||
r.hset(session, "state", "issue")
|
||||
r.lpush("pending-issue", session)
|
||||
else:
|
||||
|
||||
Reference in New Issue
Block a user