Clean up imports

This commit is contained in:
Jakub Warmuz 2014-11-21 21:06:13 +01:00
parent aafcaa4ef8
commit de53f8e940
14 changed files with 203 additions and 197 deletions

View file

@ -1,11 +1,10 @@
#!/usr/bin/env python
# acme.py
# validate JSON objects as ACME protocol messages
import json, jsonschema
"""Validate JSON objects as ACME protocol messages."""
import json
import pkg_resources
import jsonschema
schemata = {schema: json.load(open(pkg_resources.resource_filename(
__name__, "schemata/%s.json" % schema))) for schema in [
"authorization", "authorizationRequest", "certificate", "certificateRequest",

View file

@ -1,30 +1,23 @@
import augeas
import subprocess
import re
import hashlib
import os
import sys
import socket
import time
import pkg_resources
import re
import shutil
from pkg_resources import Requirement, resource_filename
import socket
import subprocess
import sys
import time
from letsencrypt.client.CONFIG import SERVER_ROOT, BACKUP_DIR
from letsencrypt.client.CONFIG import REWRITE_HTTPS_ARGS, CONFIG_DIR, WORK_DIR
from letsencrypt.client.CONFIG import TEMP_CHECKPOINT_DIR, IN_PROGRESS_DIR
from letsencrypt.client.CONFIG import OPTIONS_SSL_CONF, LE_VHOST_EXT
from letsencrypt.client import logger, le_util, augeas_configurator
from letsencrypt.client import crypto_util
# Challenge specific imports
import binascii, hashlib
from Crypto import Random
from letsencrypt.client.CONFIG import S_SIZE, APACHE_CHALLENGE_CONF, INVALID_EXT
options_ssl_conf = resource_filename(__name__, os.path.basename(OPTIONS_SSL_CONF))
from letsencrypt.client import augeas_configurator
from letsencrypt.client import CONFIG
from letsencrypt.client import crypto_util
from letsencrypt.client import le_util
from letsencrypt.client import logger
#from CONFIG import SERVER_ROOT, BACKUP_DIR, REWRITE_HTTPS_ARGS, CONFIG_DIR,
#from CONFIG import WORK_DIR, TEMP_CHECKPOINT_DIR, IN_PROGRESS_DIR, OPTIONS_SSL_CONF, LE_VHOST_EXT
#import logger, le_util
options_ssl_conf = pkg_resources.resource_filename(__name__, os.path.basename(CONFIG.OPTIONS_SSL_CONF))
# Configurator should be turned into a Singleton
@ -92,7 +85,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
so that other Configurators (like Nginx) can be developed and interoperate
with the client.
"""
def __init__(self, server_root=SERVER_ROOT):
def __init__(self, server_root=CONFIG.SERVER_ROOT):
super(ApacheConfigurator, self).__init__()
self.server_root = server_root
@ -566,14 +559,14 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
def make_vhost_ssl(self, nonssl_vhost):
"""
Duplicates vhost and adds default ssl options
New vhost will reside as (nonssl_vhost.path) + LE_VHOST_EXT
New vhost will reside as (nonssl_vhost.path) + CONFIG.LE_VHOST_EXT
"""
avail_fp = nonssl_vhost.file
# Copy file
if avail_fp.endswith(".conf"):
ssl_fp = avail_fp[:-(len(".conf"))] + LE_VHOST_EXT
ssl_fp = avail_fp[:-(len(".conf"))] + CONFIG.LE_VHOST_EXT
else:
ssl_fp = avail_fp + LE_VHOST_EXT
ssl_fp = avail_fp + CONFIG.LE_VHOST_EXT
# First register the creation so that it is properly removed if
# configuration is rolled back
@ -678,7 +671,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
return False, general_v
#Add directives to server
self.add_dir(general_v.path, "RewriteEngine", "On")
self.add_dir(general_v.path, "RewriteRule", REWRITE_HTTPS_ARGS)
self.add_dir(general_v.path, "RewriteRule", CONFIG.REWRITE_HTTPS_ARGS)
self.save_notes += 'Redirecting host in %s to ssl vhost in %s\n' % (general_v.file, ssl_vhost.file)
self.save()
return True, general_v
@ -704,9 +697,9 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
if not rewrite_path:
# "No existing redirection for virtualhost"
return False, -1
if len(rewrite_path) == len(REWRITE_HTTPS_ARGS):
if len(rewrite_path) == len(CONFIG.REWRITE_HTTPS_ARGS):
for idx, m in enumerate(rewrite_path):
if self.aug.get(m) != REWRITE_HTTPS_ARGS[idx]:
if self.aug.get(m) != CONFIG.REWRITE_HTTPS_ARGS[idx]:
# Not a letsencrypt https rewrite
return True, 2
# Existing letsencrypt https rewrite rule is in place
@ -979,7 +972,7 @@ LogLevel warn \n\
def save_apache_config(self):
# Not currently used
# Should be safe because it is a protected directory
shutil.copytree(self.server_root, BACKUP_DIR + "apache2-" + str(time.time()))
shutil.copytree(self.server_root, CONFIG.BACKUP_DIR + "apache2-" + str(time.time()))
def verify_setup(self):
@ -988,9 +981,9 @@ LogLevel warn \n\
Aim for defensive coding... make sure all input files
have permissions of root
'''
le_util.make_or_verify_dir(CONFIG_DIR, 0755)
le_util.make_or_verify_dir(WORK_DIR, 0755)
le_util.make_or_verify_dir(BACKUP_DIR, 0755)
le_util.make_or_verify_dir(CONFIG.CONFIG_DIR, 0755)
le_util.make_or_verify_dir(CONFIG.WORK_DIR, 0755)
le_util.make_or_verify_dir(CONFIG.BACKUP_DIR, 0755)
def standardize_excl(self):
"""
@ -1112,7 +1105,7 @@ LogLevel warn \n\
addresses.append(vhost.addrs)
# Generate S
s = Random.get_random_bytes(S_SIZE)
s = Random.get_random_bytes(CONFIG.S_SIZE)
# Create all of the challenge certs
for t in chall_dict["listSNITuple"]:
# Need to decode from base64
@ -1140,7 +1133,7 @@ LogLevel warn \n\
nonce: string - hex
result: returns certificate file name
"""
return WORK_DIR + nonce + ".crt"
return CONFIG.WORK_DIR + nonce + ".crt"
def __getConfigText(self, nonce, ip_addrs, key):
"""
@ -1153,7 +1146,7 @@ LogLevel warn \n\
result: returns virtual host configuration text
"""
configText = "<VirtualHost " + " ".join(ip_addrs) + "> \n \
ServerName " + nonce + INVALID_EXT + " \n \
ServerName " + nonce + CONFIG.INVALID_EXT + " \n \
UseCanonicalName on \n \
SSLStrictSNIVHostCheck on \n \
\n \
@ -1163,7 +1156,7 @@ Include " + options_ssl_conf + " \n \
SSLCertificateFile " + self.dvsni_get_cert_file(nonce) + " \n \
SSLCertificateKeyFile " + key + " \n \
\n \
DocumentRoot " + CONFIG_DIR + "challenge_page/ \n \
DocumentRoot " + CONFIG.CONFIG_DIR + "challenge_page/ \n \
</VirtualHost> \n\n "
return configText
@ -1187,8 +1180,8 @@ DocumentRoot " + CONFIG_DIR + "challenge_page/ \n \
configText += "</IfModule> \n"
self.dvsni_conf_include_check(mainConfig)
self.register_file_creation(True, APACHE_CHALLENGE_CONF)
newConf = open(APACHE_CHALLENGE_CONF, 'w')
self.register_file_creation(True, CONFIG.APACHE_CHALLENGE_CONF)
newConf = open(CONFIG.APACHE_CHALLENGE_CONF, 'w')
newConf.write(configText)
newConf.close()
@ -1203,9 +1196,9 @@ DocumentRoot " + CONFIG_DIR + "challenge_page/ \n \
result: User Apache configuration includes chocolate sni challenge file
"""
if len(self.find_directive(self.case_i("Include"), APACHE_CHALLENGE_CONF)) == 0:
if len(self.find_directive(self.case_i("Include"), CONFIG.APACHE_CHALLENGE_CONF)) == 0:
#print "Including challenge virtual host(s)"
self.add_dir("/files" + mainConfig, "Include", APACHE_CHALLENGE_CONF)
self.add_dir("/files" + mainConfig, "Include", CONFIG.APACHE_CHALLENGE_CONF)
def dvsni_create_chall_cert(self, name, ext, nonce, key):
"""
@ -1219,7 +1212,7 @@ DocumentRoot " + CONFIG_DIR + "challenge_page/ \n \
"""
self.register_file_creation(True, self.dvsni_get_cert_file(nonce))
cert_pem = crypto_util.make_ss_cert(key, [nonce + INVALID_EXT, name, ext])
cert_pem = crypto_util.make_ss_cert(key, [nonce + CONFIG.INVALID_EXT, name, ext])
with open(self.dvsni_get_cert_file(nonce), 'w') as f:
f.write(cert_pem)
@ -1230,16 +1223,16 @@ DocumentRoot " + CONFIG_DIR + "challenge_page/ \n \
r: byte array
s: byte array
result: returns z + INVALID_EXT
result: returns z + CONFIG.INVALID_EXT
"""
h = hashlib.new('sha256')
h.update(r)
h.update(s)
return h.hexdigest() + INVALID_EXT
return h.hexdigest() + CONFIG.INVALID_EXT
def main():
config = Configurator()
config = ApacheConfigurator()
logger.setLogger(logger.FileLogger(sys.stdout))
logger.setLogLevel(logger.DEBUG)
"""

View file

@ -1,12 +1,17 @@
import os, sys, shutil, time
from letsencrypt.client.configurator import Configurator
import os
import sys
import shutil
import time
import augeas
from letsencrypt.client import le_util, logger
from letsencrypt.client.CONFIG import TEMP_CHECKPOINT_DIR, IN_PROGRESS_DIR
from letsencrypt.client.CONFIG import BACKUP_DIR
class AugeasConfigurator(Configurator):
from letsencrypt.client import CONFIG
from letsencrypt.client import configurator
from letsencrypt.client import le_util
from letsencrypt.client import logger
class AugeasConfigurator(configurator.Configurator):
def __init__(self):
super(AugeasConfigurator, self).__init__()
@ -90,13 +95,13 @@ class AugeasConfigurator(Configurator):
# Create Checkpoint
if temporary:
self.add_to_checkpoint(TEMP_CHECKPOINT_DIR, save_files)
self.add_to_checkpoint(CONFIG.TEMP_CHECKPOINT_DIR, save_files)
else:
self.add_to_checkpoint(IN_PROGRESS_DIR, save_files)
self.add_to_checkpoint(CONFIG.IN_PROGRESS_DIR, save_files)
if title and not temporary and os.path.isdir(IN_PROGRESS_DIR):
success = self.__finalize_checkpoint(IN_PROGRESS_DIR, title)
if title and not temporary and os.path.isdir(CONFIG.IN_PROGRESS_DIR):
success = self.__finalize_checkpoint(CONFIG.IN_PROGRESS_DIR, title)
if not success:
# This should never happen
# This will be hopefully be cleaned up on the recovery
@ -115,12 +120,12 @@ class AugeasConfigurator(Configurator):
This function should reload the users original configuration files
for all saves with reversible=True
"""
if os.path.isdir(TEMP_CHECKPOINT_DIR):
result = self.__recover_checkpoint(TEMP_CHECKPOINT_DIR)
if os.path.isdir(CONFIG.TEMP_CHECKPOINT_DIR):
result = self.__recover_checkpoint(CONFIG.TEMP_CHECKPOINT_DIR)
changes = True
if result != 0:
# We have a partial or incomplete recovery
logger.fatal("Incomplete or failed recovery for %s" % TEMP_CHECKPOINT_DIR)
logger.fatal("Incomplete or failed recovery for %s" % CONFIG.TEMP_CHECKPOINT_DIR)
sys.exit(67)
# Remember to reload Augeas
self.aug.load()
@ -137,14 +142,14 @@ class AugeasConfigurator(Configurator):
logger.error("Rollback argument must be a positive integer")
return
backups = os.listdir(BACKUP_DIR)
backups = os.listdir(CONFIG.BACKUP_DIR)
backups.sort()
if len(backups) < rollback:
logger.error("Unable to rollback %d checkpoints, only %d exist" % (rollback, len(backups)))
while rollback > 0 and backups:
cp_dir = BACKUP_DIR + backups.pop()
cp_dir = CONFIG.BACKUP_DIR + backups.pop()
result = self.__recover_checkpoint(cp_dir)
if result != 0:
logger.fatal("Failed to load checkpoint during rollback")
@ -160,7 +165,7 @@ class AugeasConfigurator(Configurator):
script found in the constructor, before this function would ever be
called
"""
backups = os.listdir(BACKUP_DIR)
backups = os.listdir(CONFIG.BACKUP_DIR)
backups.sort(reverse=True)
if not backups:
@ -171,21 +176,21 @@ class AugeasConfigurator(Configurator):
for bu in backups:
float(bu)
except:
assert False, "Invalid files in %s" % BACKUP_DIR
assert False, "Invalid files in %s" % CONFIG.BACKUP_DIR
for bu in backups:
print time.ctime(float(bu))
with open(BACKUP_DIR + bu + "/CHANGES_SINCE") as f:
with open(CONFIG.BACKUP_DIR + bu + "/CHANGES_SINCE") as f:
print f.read()
print "Affected files:"
with open(BACKUP_DIR + bu + "/FILEPATHS") as f:
with open(CONFIG.BACKUP_DIR + bu + "/FILEPATHS") as f:
filepaths = f.read().splitlines()
for fp in filepaths:
print " %s" % fp
try:
with open(BACKUP_DIR + bu + "/NEW_FILES") as f:
with open(CONFIG.BACKUP_DIR + bu + "/NEW_FILES") as f:
print "New Configuration Files:"
filepaths = f.read().splitlines()
for fp in filepaths:
@ -199,7 +204,7 @@ class AugeasConfigurator(Configurator):
Add title to cp_dir CHANGES_SINCE
Move cp_dir to Backups directory and rename with timestamp
"""
final_dir = BACKUP_DIR + str(time.time())
final_dir = CONFIG.BACKUP_DIR + str(time.time())
try:
with open(cp_dir + "CHANGES_SINCE.tmp", 'w') as ft:
ft.write("-- %s --\n" % title)
@ -275,7 +280,7 @@ class AugeasConfigurator(Configurator):
return 0
def check_tempfile_saves(self, save_files, temporary):
temp_path = "%sFILEPATHS" % TEMP_CHECKPOINT_DIR
temp_path = "%sFILEPATHS" % CONFIG.TEMP_CHECKPOINT_DIR
if os.path.isfile(temp_path):
with open(temp_path, 'r') as protected_fd:
protected_files = protected_fd.read().splitlines()
@ -294,9 +299,9 @@ class AugeasConfigurator(Configurator):
(Before a save occurs)
"""
if temporary:
cp_dir = TEMP_CHECKPOINT_DIR
cp_dir = CONFIG.TEMP_CHECKPOINT_DIR
else:
cp_dir = IN_PROGRESS_DIR
cp_dir = CONFIG.IN_PROGRESS_DIR
le_util.make_or_verify_dir(cp_dir)
try:
@ -310,19 +315,19 @@ class AugeasConfigurator(Configurator):
def recovery_routine(self):
"""
Revert all previously modified files. First, any changes found in
TEMP_CHECKPOINT_DIR are removed, then IN_PROGRESS changes are removed
CONFIG.TEMP_CHECKPOINT_DIR are removed, then IN_PROGRESS changes are removed
The order is important. IN_PROGRESS is unable to add files that are
already added by a TEMP change. Thus TEMP must be rolled back first
because that will be the 'latest' occurrence of the file.
"""
self.revert_challenge_config()
if os.path.isdir(IN_PROGRESS_DIR):
result = self.__recover_checkpoint(IN_PROGRESS_DIR)
if os.path.isdir(CONFIG.IN_PROGRESS_DIR):
result = self.__recover_checkpoint(CONFIG.IN_PROGRESS_DIR)
if result != 0:
# We have a partial or incomplete recovery
# Not as egregious
# TODO: Additional tests? recovery
logger.fatal("Incomplete or failed recovery for %s" % IN_PROGRESS_DIR)
logger.fatal("Incomplete or failed recovery for %s" % CONFIG.IN_PROGRESS_DIR)
sys.exit(68)
# Need to reload configuration after these changes take effect

View file

@ -1,5 +1,5 @@
from letsencrypt.client import logger
#import logger
class Challenge(object):
def __init__(self, configurator):

View file

@ -1,21 +1,25 @@
#!/usr/bin/env python
import csv
import datetime
import json
import os
import shutil
import socket
import string
import sys
import time
import M2Crypto
import json
import os, time, sys, shutil
import csv
import requests
from letsencrypt.client.acme import acme_object_validate
from letsencrypt.client import configurator, apache_configurator
from letsencrypt.client import logger, display
from letsencrypt.client import le_util, crypto_util
from letsencrypt.client.CONFIG import RSA_KEY_SIZE, CERT_PATH
from letsencrypt.client.CONFIG import CHAIN_PATH, SERVER_ROOT, KEY_DIR, CERT_DIR
from letsencrypt.client.CONFIG import CERT_KEY_BACKUP, EXCLUSIVE_CHALLENGES
from letsencrypt.client.CONFIG import CHALLENGE_PREFERENCES, CONFIG_CHALLENGES
from letsencrypt.client import acme
from letsencrypt.client import apache_configurator
from letsencrypt.client import CONFIG
from letsencrypt.client import crypto_util
from letsencrypt.client import display
from letsencrypt.client import le_util
from letsencrypt.client import logger
# it's weird to point to chocolate servers via raw IPv6 addresses, and such
# addresses can be %SCARY in some contexts, so out of paranoia let's disable
# them by default
@ -35,7 +39,7 @@ class Client(object):
# TODO: Can probably figure out which configurator to use without
# special packaging based on system info
# Command line arg or client function to discover
self.config = apache_configurator.ApacheConfigurator(SERVER_ROOT)
self.config = apache_configurator.ApacheConfigurator(CONFIG.SERVER_ROOT)
self.server = ca_server
@ -168,8 +172,8 @@ class Client(object):
self.list_certs_keys()
def remove_cert_key(self, c):
list_file = CERT_KEY_BACKUP + "LIST"
list_file2 = CERT_KEY_BACKUP + "LIST.tmp"
list_file = CONFIG.CERT_KEY_BACKUP + "LIST"
list_file2 = CONFIG.CERT_KEY_BACKUP + "LIST.tmp"
with open(list_file, 'rb') as orgfile:
csvreader = csv.reader(orgfile)
with open(list_file2, 'wb') as newfile:
@ -187,10 +191,10 @@ class Client(object):
def list_certs_keys(self):
list_file = CERT_KEY_BACKUP + "LIST"
list_file = CONFIG.CERT_KEY_BACKUP + "LIST"
certs = []
if not os.path.isfile(CERT_KEY_BACKUP + "LIST"):
if not os.path.isfile(CONFIG.CERT_KEY_BACKUP + "LIST"):
logger.info("You don't have any certificates saved from letsencrypt")
return
@ -206,8 +210,8 @@ class Client(object):
for row in csvreader:
c = crypto_util.get_cert_info(row[1])
b_k = CERT_KEY_BACKUP + os.path.basename(row[2]) + "_" + row[0]
b_c = CERT_KEY_BACKUP + os.path.basename(row[1]) + "_" + row[0]
b_k = CONFIG.CERT_KEY_BACKUP + os.path.basename(row[2]) + "_" + row[0]
b_c = CONFIG.CERT_KEY_BACKUP + os.path.basename(row[1]) + "_" + row[0]
c["orig_key_file"] = row[2]
c["orig_cert_file"] = row[1]
@ -246,7 +250,7 @@ class Client(object):
def install_certificate(self, certificate_dict, vhost):
cert_chain_abspath = None
cert_fd, self.cert_file = le_util.unique_file(CERT_PATH, 644)
cert_fd, self.cert_file = le_util.unique_file(CONFIG.CERT_PATH, 644)
cert_fd.write(
crypto_util.b64_cert_to_pem(certificate_dict["certificate"]))
cert_fd.close()
@ -254,7 +258,7 @@ class Client(object):
self.cert_file)
if certificate_dict.get("chain", None):
chain_fd, chain_fn = le_util.unique_file(CHAIN_PATH, 644)
chain_fd, chain_fn = le_util.unique_file(CONFIG.CHAIN_PATH, 644)
for c in certificate_dict.get("chain", []):
chain_fd.write(crypto_util.b64_cert_to_pem(c))
chain_fd.close()
@ -308,7 +312,7 @@ class Client(object):
def cleanup_challenges(self, challenge_objs):
logger.info("Cleaning up challenges...")
for c in challenge_objs:
if c["type"] in CONFIG_CHALLENGES:
if c["type"] in CONFIG.CONFIG_CHALLENGES:
self.config.cleanup()
else:
#Handle other cleanup if needed
@ -377,7 +381,7 @@ class Client(object):
# Perform challenges
for i, c_obj in enumerate(challenge_objs):
response = "null"
if c_obj["type"] in CONFIG_CHALLENGES:
if c_obj["type"] in CONFIG.CONFIG_CHALLENGES:
response = self.config.perform(c_obj)
else:
# Handle RecoveryToken type challenges
@ -411,7 +415,7 @@ class Client(object):
"""
chall_cost = {}
max_cost = 0
for i, chall in enumerate(CHALLENGE_PREFERENCES):
for i, chall in enumerate(CONFIG.CHALLENGE_PREFERENCES):
chall_cost[chall] = i
max_cost += i
@ -443,7 +447,7 @@ class Client(object):
# Add logic for a crappy server
# Choose a DV
path = []
for pref_c in CHALLENGE_PREFERENCES:
for pref_c in CONFIG.CHALLENGE_PREFERENCES:
for i, offered_c in enumerate(challenges):
if (pref_c == offered_c["type"] and
self.is_preferred(offered_c["type"], path)):
@ -454,7 +458,7 @@ class Client(object):
def is_preferred(self, offered_c_type, path):
for tup in path:
for s in EXCLUSIVE_CHALLENGES:
for s in CONFIG.EXCLUSIVE_CHALLENGES:
# Second part is in case we eventually allow multiple names
# to be challenges at the same time
if (tup[1] in s and offered_c_type in s and
@ -466,14 +470,14 @@ class Client(object):
def send(self, json_obj):
try:
json_encoded = json.dumps(json_obj)
acme_object_validate(json_encoded)
acme.acme_object_validate(json_encoded)
response = requests.post(
self.server_url,
data=json_encoded,
headers={"Content-Type": "application/json"},
)
body = response.content
acme_object_validate(body)
acme.acme_object_validate(body)
return response.json()
except Exception as e:
logger.fatal("Send() failed... may have lost connection to server")
@ -488,8 +492,8 @@ class Client(object):
def store_cert_key(self, encrypt = False):
list_file = CERT_KEY_BACKUP + "LIST"
le_util.make_or_verify_dir(CERT_KEY_BACKUP, 0700)
list_file = CONFIG.CERT_KEY_BACKUP + "LIST"
le_util.make_or_verify_dir(CONFIG.CERT_KEY_BACKUP, 0700)
idx = 0
if encrypt:
@ -511,10 +515,10 @@ class Client(object):
csvwriter.writerow(["0", self.cert_file, self.key_file])
shutil.copy2(self.key_file,
CERT_KEY_BACKUP + os.path.basename(self.key_file) +
CONFIG.CERT_KEY_BACKUP + os.path.basename(self.key_file) +
"_" + str(idx))
shutil.copy2(self.cert_file,
CERT_KEY_BACKUP + os.path.basename(self.cert_file) +
CONFIG.CERT_KEY_BACKUP + os.path.basename(self.cert_file) +
"_" + str(idx))
@ -581,11 +585,11 @@ class Client(object):
key_pem = None
csr_pem = None
if not self.key_file:
key_pem = crypto_util.make_key(RSA_KEY_SIZE)
key_pem = crypto_util.make_key(CONFIG.RSA_KEY_SIZE)
# Save file
le_util.make_or_verify_dir(KEY_DIR, 0700)
le_util.make_or_verify_dir(CONFIG.KEY_DIR, 0700)
key_f, self.key_file = le_util.unique_file(
KEY_DIR + "key-letsencrypt.pem", 0600)
CONFIG.KEY_DIR + "key-letsencrypt.pem", 0600)
key_f.write(key_pem)
key_f.close()
logger.info("Generating key: %s" % self.key_file)
@ -599,9 +603,9 @@ class Client(object):
if not self.csr_file:
csr_pem, csr_der = crypto_util.make_csr(self.key_file, self.names)
# Save CSR
le_util.make_or_verify_dir(CERT_DIR, 0755)
le_util.make_or_verify_dir(CONFIG.CERT_DIR, 0755)
csr_f, self.csr_file = le_util.unique_file(
CERT_DIR + "csr-letsencrypt.pem", 0644)
CONFIG.CERT_DIR + "csr-letsencrypt.pem", 0644)
csr_f.write(csr_pem)
csr_f.close()
logger.info("Creating CSR: %s" % self.csr_file)
@ -695,15 +699,13 @@ class Client(object):
Do enough to avoid shellcode from the environment. There's
no need to do more.
"""
import string as s
allowed = s.ascii_letters + s.digits + "-." # hostnames & IPv4
allowed = string.ascii_letters + string.digits + "-." # hostnames & IPv4
if all([c in allowed for c in hostname]):
return True
if not allow_raw_ipv6_server: return False
# ipv6 is messy and complicated, can contain %zoneindex etc.
import socket
try:
# is this a valid IPv6 address?
socket.getaddrinfo(hostname,443,socket.AF_INET6)

View file

@ -1,29 +1,32 @@
import M2Crypto
import time, binascii
import binascii
import hashlib
from Crypto.Random import get_random_bytes
from Crypto.PublicKey import RSA
from Crypto.Signature import PKCS1_v1_5
from Crypto.Hash import SHA256
from M2Crypto import EVP, X509, ASN1
import time
from letsencrypt.client.CONFIG import NONCE_SIZE, RSA_KEY_SIZE
from Crypto import Random
import Crypto.Hash.SHA256
import Crypto.PublicKey.RSA
import Crypto.Signature.PKCS1_v1_5
import M2Crypto
from letsencrypt.client import CONFIG
from letsencrypt.client import le_util
def b64_cert_to_pem(b64_der_cert):
x = M2Crypto.X509.load_cert_der_string(le_util.b64_url_dec(b64_der_cert))
return x.as_pem()
def create_sig(msg, key_file, signer_nonce = None, signer_nonce_len = NONCE_SIZE):
def create_sig(msg, key_file, signer_nonce = None, signer_nonce_len = CONFIG.NONCE_SIZE):
# DOES prepend signer_nonce to message
# TODO: Change this over to M2Crypto... PKey
# Protect against crypto unicode errors... is this sufficient? Do I need to escape?
msg = str(msg)
key = RSA.importKey(open(key_file).read())
key = Crypto.PublicKey.RSA.importKey(open(key_file).read())
if signer_nonce is None:
signer_nonce = get_random_bytes(signer_nonce_len)
h = SHA256.new(signer_nonce + msg)
signer = PKCS1_v1_5.new(key)
signer_nonce = Random.get_random_bytes(signer_nonce_len)
h = Crypto.Hash.SHA256.new(signer_nonce + msg)
signer = Crypto.Signature.PKCS1_v1_5.new(key)
signature = signer.sign(h)
#print "signing:", signer_nonce + msg
#print "signature:", signature
@ -48,12 +51,12 @@ def sha256(m):
return hashlib.sha256(m).hexdigest()
# based on M2Crypto unit test written by Toby Allsopp
def make_key(bits=RSA_KEY_SIZE):
def make_key(bits=CONFIG.RSA_KEY_SIZE):
"""
Returns new RSA key in PEM form with specified bits
"""
#Python Crypto module doesn't produce any stdout
key = RSA.generate(bits)
key = Crypto.PublicKey.RSA.generate(bits)
#rsa = M2Crypto.RSA.gen_key(bits, 65537)
#key_pem = rsa.as_pem(cipher=None)
#rsa = None # should not be freed here
@ -67,10 +70,10 @@ def make_csr(key_file, domains):
"""
assert domains, "Must provide one or more hostnames for the CSR."
rsa_key = M2Crypto.RSA.load_key(key_file)
pk = EVP.PKey()
pk = M2Crypto.EVP.PKey()
pk.assign_rsa(rsa_key)
x = X509.Request()
x = M2Crypto.X509.Request()
x.set_pubkey(pk)
name = x.get_subject()
name.C = "US"
@ -80,8 +83,8 @@ def make_csr(key_file, domains):
name.OU = "University of Michigan"
name.CN = domains[0]
extstack = X509.X509_Extension_Stack()
ext = X509.new_extension('subjectAltName', ", ".join(["DNS:%s" % d for d in domains]))
extstack = M2Crypto.X509.X509_Extension_Stack()
ext = M2Crypto.X509.new_extension('subjectAltName', ", ".join(["DNS:%s" % d for d in domains]))
extstack.push(ext)
x.add_extensions(extstack)
@ -97,18 +100,18 @@ def make_ss_cert(key_file, domains):
"""
assert domains, "Must provide one or more hostnames for the CSR."
rsa_key = M2Crypto.RSA.load_key(key_file)
pk = EVP.PKey()
pk = M2Crypto.EVP.PKey()
pk.assign_rsa(rsa_key)
x = X509.X509()
x = M2Crypto.X509.X509()
x.set_pubkey(pk)
x.set_serial_number(1337)
x.set_version(2)
t = long(time.time())
current = ASN1.ASN1_UTCTIME()
current = M2Crypto.ASN1.ASN1_UTCTIME()
current.set_time(t)
expire = ASN1.ASN1_UTCTIME()
expire = M2Crypto.ASN1.ASN1_UTCTIME()
expire.set_time((7 * 24 * 60 * 60) + t)
x.set_not_before(current)
x.set_not_after(expire)
@ -121,9 +124,9 @@ def make_ss_cert(key_file, domains):
name.CN = domains[0]
x.set_issuer(x.get_subject())
x.add_ext(X509.new_extension('basicConstraints', 'CA:FALSE'))
#x.add_ext(X509.new_extension('extendedKeyUsage', 'TLS Web Server Authentication'))
x.add_ext(X509.new_extension('subjectAltName', ", ".join(["DNS:%s" % d for d in domains])))
x.add_ext(M2Crypto.X509.new_extension('basicConstraints', 'CA:FALSE'))
#x.add_ext(M2Crypto.X509.new_extension('extendedKeyUsage', 'TLS Web Server Authentication'))
x.add_ext(M2Crypto.X509.new_extension('subjectAltName', ", ".join(["DNS:%s" % d for d in domains])))
x.sign(pk, 'sha256')
assert x.verify(pk)

View file

@ -1,3 +1,5 @@
import textwrap
import dialog
@ -80,7 +82,6 @@ class Display(SingletonD):
class NcursesDisplay(Display):
import dialog
def __init__(self):
self.d = dialog.Dialog()
@ -153,11 +154,8 @@ class NcursesDisplay(Display):
print text
self.d.msgbox(text, width=WIDTH, height=HEIGHT)
textwrap = None
class FileDisplay(Display):
global textwrap
import textwrap
def __init__(self, outfile):
self.outfile = outfile

View file

@ -1,6 +1,10 @@
from letsencrypt.client.challenge import Challenge
import textwrap
import dialog
from letsencrypt.client import challenge
###########################################################
# Interactive challenge displays the string sent by the CA
# formatted to fit on the screen of the client
@ -8,7 +12,7 @@ import textwrap
# client should continue the letsencrypt process
###########################################################
class Interactive_Challenge(Challenge):
class Interactive_Challenge(challenge.Challenge):
BOX_SIZE = 70
def __init__(self, string):

View file

@ -1,12 +1,13 @@
# This file will contain functions useful for all Letsencrypt Classes
import errno
import stat
import os, pwd, grp
import time
"""Utilities for all Let's Encrypt."""
import base64
from letsencrypt.client import logger
#import logger
import grp
import errno
import os
import pwd
import stat
import sys
from letsencrypt.client import logger
def make_or_verify_dir(directory, permissions=0755, uid=0):

View file

@ -1,6 +1,12 @@
import logger
import textwrap
import time
import dialog
from letsencrypt.client import display
class Singleton(object):
_instance = None
def __new__(cls, *args, **kwargs):
@ -36,11 +42,8 @@ class Logger(Singleton):
t = time.time()
return time.strftime("%b %d %Y %H:%M:%S", time.localtime(t)) + ('%.03f' % (t - int(t)))[1:]
textwrap = None
class FileLogger(Logger):
global textwrap
import textwrap
def __init__(self, outfile):
self.outfile = outfile
@ -51,7 +54,7 @@ class FileLogger(Logger):
wm = textwrap.fill(msg, 80)
self.outfile.write("%s\n" % wm)
import dialog
class NcursesLogger(Logger):
def __init__(self,
@ -143,28 +146,27 @@ def none(data):
if __name__ == "__main__":
# Unit test/example usage:
import logger
# Set the logging type you want to use (stdout logging):
#logger.setLogger(FileLogger(sys.stdout))
logger.setLogger(NcursesLogger())
setLogger(NcursesLogger())
# Set the most verbose you want to log (TRACE, DEBUG, INFO, WARN, ERROR, FATAL, NONE)
logger.setLogLevel(logger.TRACE)
setLogLevel(logger.TRACE)
# Log a message:
#logger.log(logger.INFO, "logger!")
time.sleep(0.01)
logger.info("This is a long line, it's pretty long, butitalso hasbig wordsthat areprobably hardtobreak oninan easywayforthe ncurseslib, sowhatdoes itdo then?")
logger.info("aa " + "a"*70 + "B")
info("This is a long line, it's pretty long, butitalso hasbig wordsthat areprobably hardtobreak oninan easywayforthe ncurseslib, sowhatdoes itdo then?")
info("aa " + "a"*70 + "B")
for i in range(20):
logger.info("iteration #%d/20" % i)
info("iteration #%d/20" % i)
time.sleep(0.3)
# Alternatively, use
logger.error("errrrr")
error("errrrr")
logger.trace("some trace data: %d - %f - %s" % (5, 8.3, 'cows'))
trace("some trace data: %d - %f - %s" % (5, 8.3, 'cows'))

View file

@ -1,8 +1,5 @@
from letsencrypt.client.CONFIG import SERVER_ROOT, BACKUP_DIR
from letsencrypt.client.CONFIG import REWRITE_HTTPS_ARGS, CONFIG_DIR, WORK_DIR
from letsencrypt.client.CONFIG import TEMP_CHECKPOINT_DIR, IN_PROGRESS_DIR
from letsencrypt.client.CONFIG import OPTIONS_SSL_CONF, LE_VHOST_EXT
from letsencrypt.client import logger, le_util, configurator
from letsencrypt.client import CONFIG
from letsencrypt.client import augeas_configurator
# This might be helpful... but feel free to use whatever you want
@ -21,9 +18,9 @@ from letsencrypt.client import logger, le_util, configurator
# def add_name(self, name):
# self.names.append(name)
class NginxConfigurator(AugeasConfigurator):
class NginxConfigurator(augeas_configurator.AugeasConfigurator):
def __init__(self, server_root=SERVER_ROOT):
def __init__(self, server_root=CONFIG.SERVER_ROOT):
self.server_root = server_root
# See if any temporary changes need to be recovered
@ -188,9 +185,9 @@ class NginxConfigurator(AugeasConfigurator):
# Aim for defensive coding... make sure all input files
# have permissions of root
# '''
# le_util.make_or_verify_dir(CONFIG_DIR, 0755)
# le_util.make_or_verify_dir(WORK_DIR, 0755)
# le_util.make_or_verify_dir(BACKUP_DIR, 0755)
# le_util.make_or_verify_dir(CONFIG.CONFIG_DIR, 0755)
# le_util.make_or_verify_dir(CONFIG.WORK_DIR, 0755)
# le_util.make_or_verify_dir(CONFIG.BACKUP_DIR, 0755)
def restart(self, quiet=False):
"""

View file

@ -1,11 +1,11 @@
import requests
from letsencrypt.client.challenge import Challenge
from letsencrypt.client import logger
from letsencrypt.client.CONFIG import RECOVERY_TOKEN_EXT
import dialog
import requests
import time
class RecoveryContact(Challenge):
from letsencrypt.client import challenge
class RecoveryContact(challenge.Challenge):
def __init__(self, activationURL = "", successURL = "", contact = "", poll_delay = 3):
self.token = ""

View file

@ -1,6 +1,9 @@
from letsencrypt.client.challenge import Challenge
import dialog
class RecoveryToken(Challenge):
from letsencrypt.client import challenge
class RecoveryToken(challenge.Challenge):
def __init__(self):
self.token = ""

View file

@ -1,14 +1,15 @@
#!/usr/bin/env python
# This file parses the command line and calls the appropriate functions
"""Parse command line and call the appropriate functions."""
import getopt
import os
import sys
from letsencrypt.client import apache_configurator
from letsencrypt.client import CONFIG
from letsencrypt.client import client
from letsencrypt.client import display
from letsencrypt.client.CONFIG import ACME_SERVER
from letsencrypt.client import logger
def main():
# Check to make sure user is root
@ -49,7 +50,6 @@ def main():
elif o == "--server":
server = a
elif o == "--rollback":
from letsencrypt.client import apache_configurator, logger
logger.setLogger(logger.FileLogger(sys.stdout))
logger.setLogLevel(logger.INFO)
config = apache_configurator.ApacheConfigurator()
@ -57,7 +57,6 @@ def main():
config.restart()
sys.exit(0)
elif o == "--view-checkpoints":
from letsencrypt.client import apache_configurator, logger
logger.setLogger(logger.FileLogger(sys.stdout))
logger.setLogLevel(logger.INFO)
config = apache_configurator.ApacheConfigurator()
@ -84,7 +83,7 @@ def main():
display.setDisplay(display.FileDisplay(sys.stdout))
if not server:
server = ACME_SERVER
server = CONFIG.ACME_SERVER
c = client.Client(server, csr, privkey, curses)
if flag_revoke: