mirror of
https://github.com/certbot/certbot.git
synced 2026-07-28 08:45:22 +02:00
Merge branch 'master' of github.com:research/chocolate
This commit is contained in:
@@ -0,0 +1,19 @@
|
||||
# Apache server root directory
|
||||
SERVER_ROOT = "/etc/apache2/"
|
||||
# Configuration file directory for trustify
|
||||
CONFIG_DIR = "/etc/trustify/"
|
||||
# Working directory for trustify
|
||||
WORK_DIR = "/var/lib/trustify/"
|
||||
|
||||
# Used by openssl to sign challenge certificate with trustify extension
|
||||
CHOC_CERT_CONF = CONFIG_DIR + "choc_cert_extensions.cnf"
|
||||
# Contains standard Apache SSL directives
|
||||
OPTIONS_SSL_CONF = CONFIG_DIR + "options-ssl.conf"
|
||||
# Temporary file for challenge virtual hosts
|
||||
APACHE_CHALLENGE_CONF = CONFIG_DIR + "choc_sni_cert_challenge.conf"
|
||||
# Byte size of S and Nonce
|
||||
S_SIZE = 32
|
||||
NONCE_SIZE = 32
|
||||
|
||||
# bits of hashcash to generate
|
||||
difficulty = 23
|
||||
@@ -6,7 +6,8 @@ import urllib2, os, grp, pwd, sys, time, random, sys, hashlib, subprocess
|
||||
# It is OK to use the upstream M2Crypto here instead of our modified
|
||||
# version.
|
||||
|
||||
difficulty = 23 # bits of hashcash to generate
|
||||
# bits of hashcash to generate
|
||||
from CONFIG import difficulty
|
||||
|
||||
def sha256(m):
|
||||
return hashlib.sha256(m).hexdigest()
|
||||
|
||||
@@ -5,7 +5,7 @@ import os
|
||||
import sys
|
||||
import socket
|
||||
|
||||
BASE_DIR = "/etc/apache2/"
|
||||
from CONFIG import SERVER_ROOT
|
||||
|
||||
class VH(object):
|
||||
def __init__(self, vh_path, vh_addrs):
|
||||
@@ -141,7 +141,7 @@ class Configurator(object):
|
||||
Returns list of virtual hosts found in the Apache configuration
|
||||
"""
|
||||
#Search sites-available, httpd.conf for possible virtual hosts
|
||||
paths = self.aug.match("/files" + BASE_DIR + "sites-available//VirtualHost")
|
||||
paths = self.aug.match("/files" + SERVER_ROOT + "sites-available//VirtualHost")
|
||||
vhs = []
|
||||
for p in paths:
|
||||
addrs = []
|
||||
@@ -192,13 +192,13 @@ class Configurator(object):
|
||||
Adds NameVirtualHost directive for given address
|
||||
Directive is added to ports.conf unless
|
||||
"""
|
||||
aug_file_path = "/files" + BASE_DIR + "ports.conf"
|
||||
aug_file_path = "/files" + SERVER_ROOT + "ports.conf"
|
||||
self.add_dir_to_ifmodssl(aug_file_path, "NameVirtualHost", addr)
|
||||
|
||||
if len(self.find_directive("NameVirtualHost", addr)) == 0:
|
||||
print "ports.conf is not included in your Apache config... "
|
||||
print "Adding NameVirtualHost directive to httpd.conf"
|
||||
self.add_dir_to_ifmodssl("/files" + BASE_DIR + "httpd.conf", "NameVirtualHost", addr)
|
||||
self.add_dir_to_ifmodssl("/files" + SERVER_ROOT + "httpd.conf", "NameVirtualHost", addr)
|
||||
|
||||
|
||||
def add_dir_to_ifmodssl(self, aug_conf_path, directive, val):
|
||||
@@ -232,7 +232,7 @@ class Configurator(object):
|
||||
if len(self.find_directive("Listen", "443")) == 0:
|
||||
print self.find_directive("Listen", "443")
|
||||
print "Setting the Apache Server to Listen on port 443"
|
||||
self.add_dir_to_ifmodssl("/files" + BASE_DIR + "ports.conf", "Listen", "443")
|
||||
self.add_dir_to_ifmodssl("/files" + SERVER_ROOT + "ports.conf", "Listen", "443")
|
||||
|
||||
# Check for NameVirtualHost
|
||||
# First see if any of the vhost addresses is a _default_ addr
|
||||
@@ -271,7 +271,7 @@ class Configurator(object):
|
||||
self.aug.set(aug_conf_path + "/directive[last() + 1]", directive)
|
||||
self.aug.set(aug_conf_path + "/directive[last()]/arg", arg)
|
||||
|
||||
def find_directive(self, directive, arg=None, start="/files"+BASE_DIR+"apache2.conf"):
|
||||
def find_directive(self, directive, arg=None, start="/files"+SERVER_ROOT+"apache2.conf"):
|
||||
"""
|
||||
Recursively searches through config files to find directives
|
||||
TODO: arg should probably be a list
|
||||
@@ -311,7 +311,7 @@ class Configurator(object):
|
||||
arg = cur_dir + arg
|
||||
# conf/ is a special variable for ServerRoot in Apache
|
||||
elif arg.startswith("conf/"):
|
||||
arg = BASE_DIR + arg[5:]
|
||||
arg = SERVER_ROOT + arg[5:]
|
||||
# TODO: Test if Apache allows ../ or ~/ for Includes
|
||||
|
||||
# Attempts to add a transform to the file if one does not already exist
|
||||
@@ -360,7 +360,7 @@ class Configurator(object):
|
||||
|
||||
avail_fp: string - Should be complete file path
|
||||
"""
|
||||
enabled_dir = BASE_DIR + "sites-enabled/"
|
||||
enabled_dir = SERVER_ROOT + "sites-enabled/"
|
||||
for f in os.listdir(enabled_dir):
|
||||
if os.path.realpath(enabled_dir + f) == avail_fp:
|
||||
return True
|
||||
@@ -374,7 +374,7 @@ class Configurator(object):
|
||||
"""
|
||||
if "/sites-available/" in avail_fp:
|
||||
index = avail_fp.rfind("/")
|
||||
os.symlink(avail_fp, BASE_DIR + "sites-enabled/" + avail_fp[index:])
|
||||
os.symlink(avail_fp, SERVER_ROOT + "sites-enabled/" + avail_fp[index:])
|
||||
return True
|
||||
return False
|
||||
|
||||
@@ -387,11 +387,11 @@ class Configurator(object):
|
||||
subprocess.check_output(["sudo", "a2enmod", "ssl"])
|
||||
subprocess.call(["sudo", "/etc/init.d/apache2", "reload"])
|
||||
"""
|
||||
a_conf = BASE_DIR + "mods-available/ssl.conf"
|
||||
a_load = BASE_DIR + "mods-available/ssl.load"
|
||||
a_conf = SERVER_ROOT + "mods-available/ssl.conf"
|
||||
a_load = SERVER_ROOT + "mods-available/ssl.load"
|
||||
if os.path.exists(a_conf) and os.path.exists(a_load):
|
||||
os.symlink(a_conf, BASE_DIR + "mods-enabled/ssl.conf")
|
||||
os.symlink(a_load, BASE_DIR + "mods-enabled/ssl.load")
|
||||
os.symlink(a_conf, SERVER_ROOT + "mods-enabled/ssl.conf")
|
||||
os.symlink(a_load, SERVER_ROOT + "mods-enabled/ssl.load")
|
||||
return True
|
||||
return False
|
||||
"""
|
||||
@@ -403,7 +403,7 @@ class Configurator(object):
|
||||
# Standardize the include argument based on server root
|
||||
arg = includeArg
|
||||
if not includeArg.startswith("/"):
|
||||
arg = BASE_DIR + includeArg
|
||||
arg = SERVER_ROOT + includeArg
|
||||
|
||||
# Test if augeas included file for Httpd.lens
|
||||
incTest = aug.match("/files" + arg + "/*")
|
||||
|
||||
@@ -6,18 +6,14 @@ from Crypto import Random
|
||||
import hmac
|
||||
import hashlib
|
||||
from shutil import move
|
||||
from os import remove, close
|
||||
from os import remove, close, path
|
||||
import binascii
|
||||
import augeas
|
||||
import configurator
|
||||
#import dns.resolver
|
||||
|
||||
CHOC_DIR = "/home/ubuntu/chocolate/client-webserver/"
|
||||
CHOC_CERT_CONF = "choc_cert_extensions.cnf"
|
||||
OPTIONS_SSL_CONF = CHOC_DIR + "options-ssl.conf"
|
||||
APACHE_CHALLENGE_CONF = CHOC_DIR + "choc_sni_cert_challenge.conf"
|
||||
S_SIZE = 32
|
||||
NONCE_SIZE = 32
|
||||
from CONFIG import CONFIG_DIR, WORK_DIR, SERVER_ROOT
|
||||
from CONFIG import CHOC_CERT_CONF, OPTIONS_SSL_CONF, APACHE_CHALLENGE_CONF
|
||||
from CONFIG import S_SIZE, NONCE_SIZE
|
||||
|
||||
def getChocCertFile(nonce):
|
||||
"""
|
||||
@@ -28,26 +24,20 @@ def getChocCertFile(nonce):
|
||||
result: returns certificate file name
|
||||
"""
|
||||
|
||||
return CHOC_DIR + nonce + ".crt"
|
||||
return WORK_DIR + nonce + ".crt"
|
||||
|
||||
def findApacheConfigFile():
|
||||
"""
|
||||
Locates the file path to the user's main apache config
|
||||
|
||||
TODO: This needs to be rewritten... should use true ServerRoot
|
||||
TODO: This needs to use true server_root
|
||||
|
||||
result: returns file path if present
|
||||
"""
|
||||
# This needs to be fixed to account for multiple httpd.conf files
|
||||
try:
|
||||
p = subprocess.check_output(["sudo", "find", "/etc", "-name", "httpd.conf"], stderr=open("/dev/null"))
|
||||
p = p[:len(p)-1]
|
||||
print "Apache Config: ", p
|
||||
return p
|
||||
except subprocess.CalledProcessError, e:
|
||||
print "httpd.conf not found"
|
||||
print "Please include .... in the conf file"
|
||||
return None
|
||||
if path.isfile(SERVER_ROOT + "httpd.conf"):
|
||||
return SERVER_ROOT + "httpd.conf"
|
||||
print "Unable to find httpd.conf, file does not exist in Apache ServerRoot"
|
||||
return None
|
||||
|
||||
def getConfigText(nonce, ip_addrs, key):
|
||||
"""
|
||||
@@ -70,7 +60,7 @@ Include " + OPTIONS_SSL_CONF + " \n \
|
||||
SSLCertificateFile " + getChocCertFile(nonce) + " \n \
|
||||
SSLCertificateKeyFile " + key + " \n \
|
||||
\n \
|
||||
DocumentRoot " + CHOC_DIR + "challenge_page/ \n \
|
||||
DocumentRoot " + CONFIG_DIR + "challenge_page/ \n \
|
||||
</VirtualHost> \n\n "
|
||||
|
||||
return configText
|
||||
@@ -191,6 +181,9 @@ def apache_restart():
|
||||
"""
|
||||
subprocess.call(["sudo", "/etc/init.d/apache2", "reload"])
|
||||
|
||||
# TODO: This function is insufficient as the user could edit the files
|
||||
# before the challenge is completed. It is safer to log all of the changes
|
||||
# and revert each one individually
|
||||
def cleanup(listSNITuple, configurator):
|
||||
"""
|
||||
Remove all temporary changes necessary to perform the challenge
|
||||
@@ -259,9 +252,10 @@ def perform_sni_cert_challenge(listSNITuple, csr, key, configurator):
|
||||
apache_restart()
|
||||
return True
|
||||
|
||||
# This main function is just used for testing
|
||||
def main():
|
||||
key = CHOC_DIR + "key.pem"
|
||||
csr = CHOC_DIR + "req.pem"
|
||||
key = path.abspath("key.pem")
|
||||
csr = path.abspath("req.pem")
|
||||
|
||||
testkey = M2Crypto.RSA.load_key(key)
|
||||
|
||||
@@ -287,15 +281,17 @@ def main():
|
||||
|
||||
challenges = [("example.com", y, nonce, "1.3.3.7"), ("www.example.com",y2, nonce2, "1.3.3.7")]
|
||||
#challenges = [("127.0.0.1", y, nonce, "1.3.3.7"), ("localhost", y2, nonce2, "1.3.3.7")]
|
||||
perform_sni_cert_challenge(challenges, csr, key, config)
|
||||
if perform_sni_cert_challenge(challenges, csr, key, config):
|
||||
|
||||
# Waste some time without importing time module... just for testing
|
||||
for i in range(0, 12000):
|
||||
if i % 2000 == 0:
|
||||
print "Waiting:", i
|
||||
|
||||
# Waste some time without importing time module... just for testing
|
||||
for i in range(0, 12000):
|
||||
if i % 2000 == 0:
|
||||
print "Waiting:", i
|
||||
|
||||
print "Cleaning up"
|
||||
cleanup(challenges, config)
|
||||
print "Cleaning up"
|
||||
cleanup(challenges, config)
|
||||
else:
|
||||
print "Failed SNI challenge..."
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
+21
-27
@@ -280,42 +280,36 @@ dispatch = { "makechallenge": ("pending-makechallenge", makechallenge),
|
||||
"done": ("pending-done", lambda x: None) }
|
||||
|
||||
# Main loop: act on queues notified via Redis pubsub mechanism.
|
||||
# If the queue is empty by the time we pop from it (indicated by
|
||||
# session is None), some other daemon instance has already handled
|
||||
# the request, which is fine; we then return immediately to waiting
|
||||
# for the next request.
|
||||
# Currently, we ignore the specific details of which queue was
|
||||
# notified and, upon any notification, repeatedly process a single
|
||||
# item from each queue until all queues are empty.
|
||||
|
||||
ps.subscribe(["requests"])
|
||||
for message in ps.listen():
|
||||
populated_queue = message["data"]
|
||||
if populated_queue in dispatch:
|
||||
queue, function = dispatch[populated_queue]
|
||||
for repetition in (1,2):
|
||||
# This is a potentially inappropriate hack to prevent backlogs
|
||||
# from accumulating in queues if daemons die or if spurious
|
||||
# requests arrived while no daemons were listening. The idea
|
||||
# is that every daemon process double-checks a queue that it
|
||||
# was told to look at, processing it twice per pubsub message
|
||||
# instead of once. This causes a pressure on the daemon to
|
||||
# empty the queue over time even if it isn't explicitly asked
|
||||
# to. For example, if asked 7 times to process a particular
|
||||
# queue, a daemon instance would try 14 times.
|
||||
session = r.rpop(queue)
|
||||
if session:
|
||||
if debug: print "going to %s for %s" % (populated_queue, session)
|
||||
if ancient(session, populated_queue):
|
||||
if populated_queue == "issue":
|
||||
if populated_queue == "clean-exit":
|
||||
pass # fall through to check whether this particular daemon
|
||||
# instance has its clean_shutdown flag set
|
||||
else:
|
||||
while True:
|
||||
inactive = True
|
||||
for queue in ("makechallenge", "testchallenge", "issue"):
|
||||
session = r.rpop("pending-" + queue)
|
||||
if session:
|
||||
inactive = False
|
||||
if debug: print "going to %s for %s" % (queue, session)
|
||||
if ancient(session, queue):
|
||||
if queue == "issue":
|
||||
if debug: print "not expiring issue-state", session
|
||||
else:
|
||||
if debug: print "expiring ancient session", session
|
||||
r.hset(session, "live", False)
|
||||
else:
|
||||
function(session)
|
||||
elif populated_queue == "clean-exit":
|
||||
pass # fall through to check whether this particular daemon
|
||||
# instance has its clean_shutdown flag set
|
||||
else:
|
||||
if debug: print "UNKNOWN queue %s" % populated_queue
|
||||
if queue == "makechallenge": makechallenge(session)
|
||||
elif queue == "testchallenge": testchallenge(session)
|
||||
elif queue == "issue": issue(session)
|
||||
if inactive:
|
||||
break
|
||||
|
||||
if clean_shutdown:
|
||||
print "daemon exiting cleanly"
|
||||
|
||||
Reference in New Issue
Block a user