mirror of
https://github.com/certbot/certbot.git
synced 2026-08-02 00:22:28 +02:00
Merge branch 'master' of github.com:research/chocolate
This commit is contained in:
+1
-18
@@ -2,23 +2,6 @@ In this directory are tools that will run on webservers for sysadmins to
|
|||||||
automatically obtain their certs
|
automatically obtain their certs
|
||||||
|
|
||||||
|
|
||||||
Set CHOCOLATESERVER environment variable for "make deploy" and client.py!
|
Set CHOCOLATESERVER environment variable for client.py!
|
||||||
|
|
||||||
|
|
||||||
chocolate.py - server-side, requires web.py (python-webpy),
|
|
||||||
PyCrypto (python-crypto), redis, python-redis, python-protobuf,
|
|
||||||
python-nss
|
|
||||||
probably wants to run under a web server like lighttpd with fastcgi
|
|
||||||
|
|
||||||
client.py - experimental tool for making requests and parsing replies
|
client.py - experimental tool for making requests and parsing replies
|
||||||
|
|
||||||
chocolate_protocol.proto - protocol definition; needs protobuf-compiler
|
|
||||||
|
|
||||||
sni_challenge -
|
|
||||||
Assumes Apache server with name based virtual hosts is running
|
|
||||||
(for intended address).
|
|
||||||
Call perform_sni_cert_challenge(address, r, nonce) to do the whole
|
|
||||||
challenge.
|
|
||||||
Example code is given in main method
|
|
||||||
Right now requires full path specification of CSR/KEY in the Global
|
|
||||||
Variables (how should this be specified?)
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ deploy: chocolate_protocol_pb2.py chocolate.py CSR.py pkcs10.py daemon.py
|
|||||||
|
|
||||||
chocolate_protocol_pb2.py: chocolate_protocol.proto
|
chocolate_protocol_pb2.py: chocolate_protocol.proto
|
||||||
protoc chocolate_protocol.proto --python_out=.
|
protoc chocolate_protocol.proto --python_out=.
|
||||||
|
cp -p chocolate_protocol_pb2.py ../client-webserver/
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f *.pyc
|
rm -f *.pyc
|
||||||
@@ -1,2 +1,22 @@
|
|||||||
In this directory is a reference CA implementation of the Chocolate protocol,
|
In this directory is a reference CA implementation of the Chocolate protocol,
|
||||||
DV and signing mechanism.
|
DV and signing mechanism.
|
||||||
|
|
||||||
|
Set CHOCOLATESERVER environment variable for "make deploy"!
|
||||||
|
|
||||||
|
|
||||||
|
chocolate.py - server-side, requires web.py (python-webpy),
|
||||||
|
PyCrypto (python-crypto) 2.3 (not 2.1!!), redis, python-redis,
|
||||||
|
python-protobuf, python-nss
|
||||||
|
probably wants to run under a web server like lighttpd with fastcgi
|
||||||
|
|
||||||
|
|
||||||
|
chocolate_protocol.proto - protocol definition; needs protobuf-compiler
|
||||||
|
|
||||||
|
sni_challenge -
|
||||||
|
Assumes Apache server with name based virtual hosts is running
|
||||||
|
(for intended address).
|
||||||
|
Call perform_sni_cert_challenge(address, r, nonce) to do the whole
|
||||||
|
challenge.
|
||||||
|
Example code is given in main method
|
||||||
|
Right now requires full path specification of CSR/KEY in the Global
|
||||||
|
Variables (how should this be specified?)
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
import web, redis, time
|
import web, redis, time
|
||||||
import CSR
|
import CSR
|
||||||
from Crypto.Hash import SHA256, HMAC
|
from Crypto.Hash import SHA256, HMAC
|
||||||
|
from Crypto.PublicKey import RSA
|
||||||
from Crypto import Random
|
from Crypto import Random
|
||||||
from chocolate_protocol_pb2 import chocolatemessage
|
from chocolate_protocol_pb2 import chocolatemessage
|
||||||
from google.protobuf.message import DecodeError
|
from google.protobuf.message import DecodeError
|
||||||
@@ -102,6 +103,10 @@ class session(object):
|
|||||||
"""Has there already been a signing request made in this session?"""
|
"""Has there already been a signing request made in this session?"""
|
||||||
return sessions.hget(self.id, "state") is not None
|
return sessions.hget(self.id, "state") is not None
|
||||||
|
|
||||||
|
def pubkey(self):
|
||||||
|
"""Return the PEM-formatted subject public key from the CSR."""
|
||||||
|
return CSR.pubkey(sessions.hget(self.id, "csr"))
|
||||||
|
|
||||||
def cert(self):
|
def cert(self):
|
||||||
"""Return the issued certificate."""
|
"""Return the issued certificate."""
|
||||||
return sessions.hget(self.id, "cert")
|
return sessions.hget(self.id, "cert")
|
||||||
@@ -276,8 +281,12 @@ class session(object):
|
|||||||
chall.type = int(c["type"])
|
chall.type = int(c["type"])
|
||||||
chall.name = c["name"]
|
chall.name = c["name"]
|
||||||
chall.succeeded = (c["satisfied"] == "True") # TODO: this contradicts comment in protocol about meaning of "succeeded"
|
chall.succeeded = (c["satisfied"] == "True") # TODO: this contradicts comment in protocol about meaning of "succeeded"
|
||||||
chall.data.append(c["dvsni:r"])
|
# Calculate y
|
||||||
|
dvsni_r = c["dvsni:r"]
|
||||||
|
y = RSA.importKey(self.pubkey()).encrypt(dvsni_r, None)[0]
|
||||||
|
# In dvsni, we send nonce, y, ext
|
||||||
chall.data.append(c["dvsni:nonce"])
|
chall.data.append(c["dvsni:nonce"])
|
||||||
|
chall.data.append(y)
|
||||||
chall.data.append(c["dvsni:ext"])
|
chall.data.append(c["dvsni:ext"])
|
||||||
|
|
||||||
def POST(self):
|
def POST(self):
|
||||||
@@ -26,7 +26,7 @@
|
|||||||
# If the client never checks in, the daemon can keep advancing
|
# If the client never checks in, the daemon can keep advancing
|
||||||
# the request's state, which may not be the right behavior.
|
# the request's state, which may not be the right behavior.
|
||||||
|
|
||||||
import redis, time
|
import redis, time, CSR
|
||||||
r = redis.Redis()
|
r = redis.Redis()
|
||||||
|
|
||||||
from Crypto.Hash import SHA256, HMAC
|
from Crypto.Hash import SHA256, HMAC
|
||||||
@@ -132,8 +132,10 @@ def issue(session):
|
|||||||
return
|
return
|
||||||
# Note that we can push this back into the original queue.
|
# Note that we can push this back into the original queue.
|
||||||
# TODO: need to add a way to make sure we don't test the same
|
# TODO: need to add a way to make sure we don't test the same
|
||||||
# TODO: actually issue the cert
|
# TODO: actually make this call issue the cert
|
||||||
r.hset(session, "cert", "----ISSUED CERT GOES HERE----")
|
csr = r.hget(session, "csr")
|
||||||
|
cert = CSR.issue(csr)
|
||||||
|
r.hset(session, "cert", cert)
|
||||||
if False: # once issuing cert succeeded
|
if False: # once issuing cert succeeded
|
||||||
r.hset(session, "state", "done")
|
r.hset(session, "state", "done")
|
||||||
r.lpush("pending-done", session)
|
r.lpush("pending-done", session)
|
||||||
@@ -3,6 +3,7 @@ from Crypto import Random
|
|||||||
import sni_support
|
import sni_support
|
||||||
import hmac
|
import hmac
|
||||||
import hashlib
|
import hashlib
|
||||||
|
import binascii
|
||||||
|
|
||||||
S_SIZE = 32
|
S_SIZE = 32
|
||||||
NONCE_SIZE = 32
|
NONCE_SIZE = 32
|
||||||
@@ -15,6 +16,13 @@ def byteToHex(byteStr):
|
|||||||
return ''.join(["%02X" % ord(x) for x in byteStr]).strip()
|
return ''.join(["%02X" % ord(x) for x in byteStr]).strip()
|
||||||
|
|
||||||
def check_challenge_value(ext_value, r):
|
def check_challenge_value(ext_value, r):
|
||||||
|
"""
|
||||||
|
Checks that a challenge response actually passes the challenge
|
||||||
|
|
||||||
|
ext_value: string returned by client-webserver's X.509 cert
|
||||||
|
chocolate extension
|
||||||
|
r: secret random key (binary string) chosen by server-CA
|
||||||
|
"""
|
||||||
s = ext_value[0:S_SIZE]
|
s = ext_value[0:S_SIZE]
|
||||||
mac = ext_value[S_SIZE:]
|
mac = ext_value[S_SIZE:]
|
||||||
expected_mac = hmac.new(r, str(s), hashlib.sha256).digest()
|
expected_mac = hmac.new(r, str(s), hashlib.sha256).digest()
|
||||||
@@ -30,6 +38,17 @@ def check_challenge_value(ext_value, r):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
def verify_challenge(address, r, nonce):
|
def verify_challenge(address, r, nonce):
|
||||||
|
"""
|
||||||
|
Verifies an SNI challenge at address (assumes port 443)
|
||||||
|
|
||||||
|
address: string host (e.g. "127.0.0.1")
|
||||||
|
r: secret random key (binary string)
|
||||||
|
nonce: ascii string of nonce (e.g. "66f58cfb...")
|
||||||
|
|
||||||
|
returns (result, reason)
|
||||||
|
result: True/False for passed/failed verification
|
||||||
|
reason: Human-readable string describing reason for result
|
||||||
|
"""
|
||||||
sni_name = nonce + ".chocolate"
|
sni_name = nonce + ".chocolate"
|
||||||
|
|
||||||
context = M2Crypto.SSL.Context()
|
context = M2Crypto.SSL.Context()
|
||||||
@@ -72,7 +91,7 @@ def main():
|
|||||||
r = Random.get_random_bytes(NONCE_SIZE)
|
r = Random.get_random_bytes(NONCE_SIZE)
|
||||||
r = "testValueForR"
|
r = "testValueForR"
|
||||||
encryptedValue = testkey.encrypt(r, 0)
|
encryptedValue = testkey.encrypt(r, 0)
|
||||||
valid, response = verify_challenge("127.0.0.1", r, nonce)
|
valid, response = verify_challenge("127.0.0.1", r, binascii.hexlify(nonce))
|
||||||
print response
|
print response
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|||||||
Reference in New Issue
Block a user