Added in filename support because configuration files still need to reference the correct place

This commit is contained in:
James Kasten 2014-11-29 16:05:18 -08:00
parent 9581c363b1
commit d2a1c969e4
5 changed files with 50 additions and 26 deletions

View file

@ -13,6 +13,7 @@ from Crypto import Random
from letsencrypt.client import augeas_configurator
from letsencrypt.client import CONFIG
from letsencrypt.client import crypto_util
from letsencrypt.client import errors
from letsencrypt.client import le_util
from letsencrypt.client import logger
@ -1536,7 +1537,7 @@ LogLevel warn \n\
self.add_dir("/files" + mainConfig,
"Include", CONFIG.APACHE_CHALLENGE_CONF)
def dvsni_create_chall_cert(self, name, ext, nonce, key):
def dvsni_create_chall_cert(self, name, ext, nonce, key_file):
"""Creates DVSNI challenge certifiate.
Certificate created at dvsni_get_cert_file(nonce)
@ -1544,14 +1545,20 @@ LogLevel warn \n\
:param nonce: hex form of nonce
:type nonce: str
:param key: file path to key
:param key_file: absolute path to key file
:type key: str
"""
try:
with open(key_file, 'r') as key_fd:
key_str = key_fd.read()
except IOError:
raise LetsEncryptDvsniError("Unable to load key file: %s" % key)
self.register_file_creation(True, self.dvsni_get_cert_file(nonce))
cert_pem = crypto_util.make_ss_cert(
key, [nonce + CONFIG.INVALID_EXT, name, ext])
key_str, [nonce + CONFIG.INVALID_EXT, name, ext])
with open(self.dvsni_get_cert_file(nonce), 'w') as f:
f.write(cert_pem)

View file

@ -33,7 +33,7 @@ class Client(object):
"""ACME protocol client."""
def __init__(self, ca_server, cert_signing_request=None,
private_key=None, use_curses=True):
private_key=None, private_key_file=None, use_curses=True):
"""
:param ca_server: Certificate authority server
@ -45,6 +45,9 @@ class Client(object):
:param private_key: Contents of the private key
:type private_key: str
:param private_key_file: absolute path to private_key
:type private_key_file: str
:param use_curses: Use curses UI
:type use_curses: bool
@ -61,6 +64,7 @@ class Client(object):
self.server = ca_server
self.csr = cert_signing_request
self.privkey = private_key
self.privkey_file = private_key_file
# TODO: Figure out all exceptions from this function
try:
@ -396,7 +400,6 @@ class Client(object):
else:
self.choose_certs(certs)
elif code == display.HELP:
print code, tag, cert
display.more_info_cert(cert)
self.choose_certs(certs)
else:
@ -431,7 +434,7 @@ class Client(object):
for host in vhost:
self.config.deploy_cert(host,
os.path.abspath(cert_file),
os.path.abspath(self.privkey),
os.path.abspath(self.privkey_file),
cert_chain_abspath)
# Enable any vhost that was issued to, but not enabled
if not host.enabled:
@ -542,17 +545,17 @@ class Client(object):
for row in csvreader:
idx = int(row[0]) + 1
csvwriter = csv.writer(csvfile)
csvwriter.writerow([str(idx), cert_file, self.privkey])
csvwriter.writerow([str(idx), cert_file, self.privkey_file])
else:
with open(list_file, 'wb') as csvfile:
csvwriter = csv.writer(csvfile)
csvwriter.writerow(["0", cert_file, self.privkey])
csvwriter.writerow(["0", cert_file, self.privkey_file])
shutil.copy2(self.privkey,
shutil.copy2(self.privkey_file,
os.path.join(
CONFIG.CERT_KEY_BACKUP,
os.path.basename(self.privkey) + "_" + str(idx)))
os.path.basename(self.privkey_file) + "_" + str(idx)))
shutil.copy2(cert_file,
os.path.join(
CONFIG.CERT_KEY_BACKUP,
@ -628,7 +631,7 @@ class Client(object):
challenge_objs.append({
"type": "dvsni",
"listSNITuple": sni_todo,
"dvsni_key": os.path.abspath(self.privkey),
"dvsni_key": os.path.abspath(self.privkey_file),
})
challenge_obj_indices.append(sni_satisfies)
logger.debug(sni_todo)
@ -663,7 +666,9 @@ class Client(object):
os.path.join(CONFIG.KEY_DIR, "key-letsencrypt.pem"), 0o600)
key_f.write(key_pem)
key_f.close()
logger.info("Generating key: %s" % key_filename)
self.privkey_file = key_filename
logger.info("Generating key: %s" % self.privkey_file)
else:
key_pem = self.privkey

View file

@ -22,7 +22,7 @@ def b64_cert_to_pem(b64_der_cert):
le_util.jose_b64decode(b64_der_cert)).as_pem()
def create_sig(msg, key_file, nonce=None, nonce_len=CONFIG.NONCE_SIZE):
def create_sig(msg, key_str, nonce=None, nonce_len=CONFIG.NONCE_SIZE):
"""Create signature with nonce prepended to the message.
TODO: Change this over to M2Crypto... PKey
@ -32,9 +32,9 @@ def create_sig(msg, key_file, nonce=None, nonce_len=CONFIG.NONCE_SIZE):
:param msg: Message to be signed
:type msg: Anything with __str__ method
:param key_file: Path to a file containing RSA key. Accepted formats
:param key_str: Key in string form. Accepted formats
are the same as for `Crypto.PublicKey.RSA.importKey`.
:type key_file: str
:type key_str: str
:param nonce: Nonce to be used. If None, nonce of `nonce_len` size
will be randomly genereted.
@ -48,7 +48,7 @@ def create_sig(msg, key_file, nonce=None, nonce_len=CONFIG.NONCE_SIZE):
"""
msg = str(msg)
key = Crypto.PublicKey.RSA.importKey(open(key_file).read())
key = Crypto.PublicKey.RSA.importKey(key_str)
nonce = Random.get_random_bytes(nonce_len) if nonce is None else nonce
msg_with_nonce = nonce + msg
@ -96,12 +96,12 @@ def make_key(bits=CONFIG.RSA_KEY_SIZE):
return key.exportKey(format='PEM')
def make_csr(key_file, domains):
def make_csr(key_str, domains):
"""
Returns new CSR in PEM and DER form using key_file containing all domains
"""
assert domains, "Must provide one or more hostnames for the CSR."
rsa_key = M2Crypto.RSA.load_key(key_file)
rsa_key = M2Crypto.RSA.load_key_string(key_str)
pubkey = M2Crypto.EVP.PKey()
pubkey.assign_rsa(rsa_key)
@ -128,13 +128,14 @@ def make_csr(key_file, domains):
return csr.as_pem(), csr.as_der()
def make_ss_cert(key_file, domains):
def make_ss_cert(key_str, domains):
"""Returns new self-signed cert in PEM form.
Uses key_file and contains all domains.
Uses key_str and contains all domains.
"""
assert domains, "Must provide one or more hostnames for the CSR."
rsa_key = M2Crypto.RSA.load_key(key_file)
rsa_key = M2Crypto.RSA.load_key_string(key_str)
pubkey = M2Crypto.EVP.PKey()
pubkey.assign_rsa(rsa_key)

View file

@ -3,3 +3,7 @@
class LetsEncryptClientError(Exception):
"""Generic Let's Encrypt client error."""
class LetsEncryptDvsniError(Exception):
"""Let's Encrypt DVSNI error."""

View file

@ -28,10 +28,10 @@ def main():
nargs="+")
parser.add_argument("-s", "--server", dest="server",
help="The ACME CA server address.")
parser.add_argument("-p", "--privkey", dest="privkey", type=read_file,
parser.add_argument("-p", "--privkey", dest="privkey_tup", type=read_file,
help="Path to the private key file for certificate "
"generation.")
parser.add_argument("-c", "--csr", dest="csr", type=read_file,
parser.add_argument("-c", "--csr", dest="csr_tup", type=read_file,
help="Path to the certificate signing request file "
"corresponding to the private key file. The "
"private key file argument is required if this "
@ -63,7 +63,7 @@ def main():
args = parser.parse_args()
# Enforce '--privkey' is set along with '--csr'.
if args.csr and not args.privkey:
if args.csr_tup and not args.privkey_tup:
parser.error("private key file (--privkey) must be specified along{0} "
"with the certificate signing request file (--csr)"
.format(os.linesep))
@ -83,7 +83,14 @@ def main():
server = args.server is None and CONFIG.ACME_SERVER or args.server
acme = client.Client(server, args.csr, args.privkey, args.curses)
# Prepare for init of Client
if args.privkey_tup is None:
args.privkey_tup = (None, None)
if args.csr_tup is None:
args.csr_tup = (None, None)
acme = client.Client(server, args.csr_tup[1], args.privkey_tup[1],
args.privkey_tup[0], args.curses)
if args.revoke:
acme.list_certs_keys()
else:
@ -103,7 +110,7 @@ def read_file(filename):
"""
try:
return file(filename, 'rU').read()
return filename, file(filename, 'rU').read()
except IOError as exc:
raise argparse.ArgumentTypeError(exc.strerror)