1
0
mirror of https://github.com/certbot/certbot.git synced 2026-01-26 07:41:33 +03:00

correctly emit subject alternative names and remove most user-supplied data from cert

This commit is contained in:
Seth Schoen
2012-07-13 22:50:58 -07:00
parent 34e3663399
commit 32c2ba8e71
4 changed files with 86 additions and 17 deletions

View File

@@ -77,6 +77,7 @@ if [ -z "$CATOP" ] ; then CATOP=./demoCA ; fi
CAKEY=./cakey.pem
CAREQ=./careq.pem
CACERT=./cacert.pem
CACFG=./ca.cfg
RET=0
@@ -168,6 +169,14 @@ case $1 in
RET=$?
exit $RET
;;
-complete)
# TODO: for deployed system, add -notext to avoid getting human-readable
# text output.
/bin/echo -e "y\ny\n" | $CA -passin env:PASSWORD -config ${CATOP}/${CACFG} -extfile "$3" -subj "$2" -out "$5" -infiles "$4"
RET=$?
exit $RET
;;
-signCA)
$CA -policy policy_anything -out newcert.pem -extensions v3_ca -infiles newreq.pem
RET=$?

View File

@@ -5,13 +5,13 @@
import site, os
assert os.path.exists("../m3/lib/python"), "\nPlease install m3crypto into ../m3/lib/python by running\nmkdir -p ../m3/lib/python; PYTHONPATH=../m3/lib/python python setup.py install --home=../m3\nfrom inside the m3crypto directory."
site.addsitedir("../m3/lib/python")
import subprocess, tempfile, re
import subprocess, re
from tempfile import NamedTemporaryFile as temp
import M2Crypto
from distutils.version import LooseVersion
assert LooseVersion(M2Crypto.version) >= LooseVersion("0.22")
import hashlib
# we can use tempfile.NamedTemporaryFile() to get tempfiles
# to pass to OpenSSL subprocesses.
# we can use temp() to get tempfiles to pass to OpenSSL subprocesses.
def parse(csr):
"""
@@ -205,21 +205,42 @@ def encrypt(key, data):
pubkey = M2Crypto.RSA.load_pub_key_bio(bio)
return pubkey.public_encrypt(data, M2Crypto.RSA.pkcs1_oaep_padding)
def issue(csr):
"""Issue the certificate requested by this CSR and return it!"""
# TODO: a real CA should severely restrict the content of the cert, not
# just grant what's asked for. (For example, the CA shouldn't trust
# all the data in the subject field if it hasn't been validated.)
# Therefore, we should construct a new CSR from scratch using the
# parsed-out data from the input CSR, and then pass that to OpenSSL.
def issue(csr, subjects):
"""Issue a certificate requested by CSR, specifying the subject names
indicated in subjects, and return the certificate."""
if not subjects:
return None
csr = str(csr)
subjects = [str(s) for s in subjects]
for s in subjects:
if ":" in s or "," in s or " " in s or "\n" in s or "\r" in s:
# We should already have validated the names to be issued a
# long time ago, but this is an extra sanity check to make
# sure that the cert issuing process can't be corrupted by
# attempting to issue certs for names with special characters.
return None
cert = None
with tempfile.NamedTemporaryFile() as csr_tmp:
# We need three temporary files: for the CSR, for the extension config
# file, and for the resulting certificate.
with temp() as csr_tmp, temp() as ext_tmp, temp() as cert_tmp:
csr_tmp.write(csr)
csr_tmp.flush()
with tempfile.NamedTemporaryFile() as cert_tmp:
ret = subprocess.Popen(["./CA.sh", "-chocolate", csr_tmp.name, cert_tmp.name],shell=False,stdin=subprocess.PIPE,stdout=subprocess.PIPE,stderr=subprocess.PIPE).wait()
if ret == 0:
cert = cert_tmp.read()
dn = "/CN=%s" % subjects[0]
ext_tmp.write("""
basicConstraints=CA:FALSE
keyUsage=digitalSignature, keyEncipherment, keyAgreement
extendedKeyUsage=serverAuth
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid,issuer
nsComment = "Chocolatey"
""")
if subjects[1:]:
san_line = "subjectAltName="
san_line += ",".join("DNS:%s" % n for n in subjects[1:]) + "\n"
ext_tmp.write(san_line)
ext_tmp.flush()
print ["./CA.sh", "-complete", dn, ext_tmp.name, csr_tmp.name, cert_tmp.name]
ret = subprocess.Popen(["./CA.sh", "-complete", dn, ext_tmp.name, csr_tmp.name, cert_tmp.name],shell=False,stdin=subprocess.PIPE,stdout=subprocess.PIPE,stderr=subprocess.PIPE).wait()
if ret == 0:
cert = cert_tmp.read()
return cert

View File

@@ -223,7 +223,8 @@ def issue(session):
r.lrem("pending-requests", session)
return
csr = r.hget(session, "csr")
cert = CSR.issue(csr)
names = r.lrange("%s:names" % session, 0, -1)
cert = CSR.issue(csr, names)
r.hset(session, "cert", cert)
if cert: # once issuing cert succeeded
if debug: print "issued for", session

38
server-ca/demoCA/ca.cfg Normal file
View File

@@ -0,0 +1,38 @@
[ ca ]
default_ca = CA_default # The default ca section
[ CA_default ]
policy = policy_blank
email_in_dn = no
name_opt = ca_default
cert_opt = ca_default
copy_extensions = none
dir = ./demoCA # Where everything is kept
certs = $dir/certs # Where the issued certs are kept
crl_dir = $dir/crl # Where the issued crl are kept
database = $dir/index.txt # database index file.
unique_subject = no # Set to 'no' to allow creation of
# several ctificates with same subject.
new_certs_dir = $dir/newcerts # default place for new certs.
certificate = $dir/cacert.pem # The CA certificate
serial = $dir/serial # The current serial number
crlnumber = $dir/crlnumber # the current crl number
# must be commented out to leave a V1 CRL
crl = $dir/crl.pem # The current CRL
private_key = $dir/private/cakey.pem# The private key
RANDFILE = $dir/private/.rand # private random number file
# Extensions to add to a CRL. Note: Netscape communicator chokes on V2 CRLs
# so this is commented out by default to leave a V1 CRL.
# crlnumber must also be commented out to leave a V1 CRL.
# crl_extensions = crl_ext
default_days = 365 # how long to certify for
default_crl_days= 30 # how long before next CRL
default_md = default # use public key default MD
preserve = no # keep passed DN ordering
[ policy_blank ]
commonName = supplied