diff --git a/letsencrypt_auto/Dockerfile b/letsencrypt_auto/Dockerfile new file mode 100644 index 000000000..4bdb1426f --- /dev/null +++ b/letsencrypt_auto/Dockerfile @@ -0,0 +1,33 @@ +# For running tests, build a docker image with a passwordless sudo and a trust +# store we can manipulate. + +FROM ubuntu:trusty + +# Add an unprivileged user: +RUN useradd --create-home --home-dir /home/lea --shell /bin/bash --groups sudo --uid 1000 lea + +# Let that user sudo: +RUN adduser lea sudo +RUN sed -i.bkp -e \ + 's/%sudo\s\+ALL=(ALL\(:ALL\)\?)\s\+ALL/%sudo ALL=NOPASSWD:ALL/g' \ + /etc/sudoers + +# Install pip and nose: +RUN apt-get update && \ + apt-get -q -y install python-pip && \ + apt-get clean +RUN pip install nose + +RUN mkdir -p /home/lea/letsencrypt/letsencrypt + +# Install fake testing CA: +COPY ./tests/certs/ca/my-root-ca.crt.pem /usr/local/share/ca-certificates/ +RUN update-ca-certificates + +# Copy code: +COPY . /home/lea/letsencrypt/letsencrypt_auto + +USER lea +WORKDIR /home/lea + +CMD ["nosetests", "-s", "letsencrypt/letsencrypt_auto/tests"] diff --git a/letsencrypt_auto/__init__.py b/letsencrypt_auto/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/letsencrypt_auto/build.py b/letsencrypt_auto/build.py index d89c81470..9a5fc46a7 100755 --- a/letsencrypt_auto/build.py +++ b/letsencrypt_auto/build.py @@ -6,11 +6,14 @@ contents of the file at ./pieces/some/file except for certain tokens which have other, special definitions. """ -from os.path import dirname, join +from os.path import abspath, dirname, join import re from sys import argv +DIR = dirname(abspath(__file__)) + + def le_version(build_script_dir): """Return the version number stamped in letsencrypt/__init__.py.""" return re.search('''^__version__ = ['"](.+)['"].*''', @@ -25,25 +28,36 @@ def file_contents(path): return file.read() -def main(): - dir = dirname(argv[0]) +def build(version=None, requirements=None): + """Return the built contents of the letsencrypt-auto script. + :arg version: The version to attach to the script. Default: the version of + the letsencrypt package + :arg requirements: The contents of the requirements file to embed. Default: + contents of letsencrypt-auto-requirements.txt + + """ special_replacements = { - 'LE_AUTO_VERSION': le_version(dir) + 'LE_AUTO_VERSION': version or le_version(DIR) } + if requirements: + special_replacements['letsencrypt-auto-requirements.txt'] = requirements def replacer(match): token = match.group(1) if token in special_replacements: return special_replacements[token] else: - return file_contents(join(dir, 'pieces', token)) + return file_contents(join(DIR, 'pieces', token)) - result = re.sub(r'{{\s*([A-Za-z0-9_./-]+)\s*}}', - replacer, - file_contents(join(dir, 'letsencrypt-auto.template'))) - with open(join(dir, 'letsencrypt-auto'), 'w') as out: - out.write(result) + return re.sub(r'{{\s*([A-Za-z0-9_./-]+)\s*}}', + replacer, + file_contents(join(DIR, 'letsencrypt-auto.template'))) + + +def main(): + with open(join(DIR, 'letsencrypt-auto'), 'w') as out: + out.write(build()) if __name__ == '__main__': diff --git a/letsencrypt_auto/letsencrypt-auto.template b/letsencrypt_auto/letsencrypt-auto.template index 07adef413..ee18e8366 100755 --- a/letsencrypt_auto/letsencrypt-auto.template +++ b/letsencrypt_auto/letsencrypt-auto.template @@ -155,13 +155,7 @@ else SUDO= fi -if [ ! -f "$VENV_BIN/letsencrypt" ]; then - # If it looks like we've never bootstrapped before, bootstrap: - Bootstrap -fi -if [ "$1" = "--os-packages-only" ]; then - echo "OS packages installed." -elif [ "$1" = "--no-self-upgrade" ]; then +if [ "$1" = "--no-self-upgrade" ]; then # Phase 2: Create venv, install LE, and run. shift 1 # the --no-self-upgrade arg @@ -184,7 +178,7 @@ elif [ "$1" = "--no-self-upgrade" ]; then echo "Installing Python packages..." TEMP_DIR=$(TempDir) - # There is no $ interpolation due to quotes on heredoc delimiters. + # There is no $ interpolation due to quotes on starting heredoc delimiter. # ------------------------------------------------------------------------- cat << "UNLIKELY_EOF" > "$TEMP_DIR/letsencrypt-auto-requirements.txt" {{ letsencrypt-auto-requirements.txt }} @@ -216,7 +210,16 @@ else # upgrading. Phase 1 checks the version of the latest release of # letsencrypt-auto (which is always the same as that of the letsencrypt # package). Phase 2 checks the version of the locally installed letsencrypt. - + + if [ ! -f "$VENV_BIN/letsencrypt" ]; then + # If it looks like we've never bootstrapped before, bootstrap: + Bootstrap + fi + if [ "$1" = "--os-packages-only" ]; then + echo "OS packages installed." + exit 0 + fi + echo "Checking for new version..." TEMP_DIR=$(TempDir) # --------------------------------------------------------------------------- diff --git a/letsencrypt_auto/pieces/fetch.py b/letsencrypt_auto/pieces/fetch.py index 9625c224a..d094e6347 100644 --- a/letsencrypt_auto/pieces/fetch.py +++ b/letsencrypt_auto/pieces/fetch.py @@ -93,7 +93,7 @@ def verified_new_le_auto(get, tag, temp_dir): """ le_auto_dir = environ.get( - 'LE_AUTO_DOWNLOAD_TEMPLATE', + 'LE_AUTO_DIR_TEMPLATE', 'https://raw.githubusercontent.com/letsencrypt/letsencrypt/%s/' 'letsencrypt-auto/') % tag write(get(le_auto_dir + 'letsencrypt-auto'), temp_dir, 'letsencrypt-auto') @@ -129,4 +129,5 @@ def main(): return 0 -exit(main()) +if __name__ == '__main__': + exit(main()) diff --git a/letsencrypt_auto/pieces/letsencrypt-auto-requirements.txt b/letsencrypt_auto/pieces/letsencrypt-auto-requirements.txt index 820b44396..70b005d2d 100644 --- a/letsencrypt_auto/pieces/letsencrypt-auto-requirements.txt +++ b/letsencrypt_auto/pieces/letsencrypt-auto-requirements.txt @@ -20,8 +20,8 @@ # sha256: 1F3TmncLSvtZHIJVX2qLvBrH6wGe2ptiHu4aCnIgEiA cffi==1.3.1 -# sha256: 0ayQAF3qd2CBys5QjLnHMi4EONHA82AN8auXEZEBJME -https://github.com/kuba/ConfigArgParse/archive/a58b35d75a10e8b8fbee7f3c69163b63bb506325.zip#egg=ConfigArgParse +# sha256: O1CoPdWBSd_O6Yy2VlJl0QtT6cCivKfu73-19VJIkKc +ConfigArgParse == 0.10.0 # sha256: ovVlB3DhyH-zNa8Zqbfrc_wFzPIhROto230AzSvLCQI configobj==5.0.6 diff --git a/letsencrypt_auto/tests/__init__.py b/letsencrypt_auto/tests/__init__.py new file mode 100644 index 000000000..13180b5f5 --- /dev/null +++ b/letsencrypt_auto/tests/__init__.py @@ -0,0 +1,7 @@ +"""Tests for letsencrypt-auto + +For now, run these by saying... :: + + ./build.py && docker build -t lea . && docker run --rm -t -i lea + +""" diff --git a/letsencrypt_auto/tests/auto_test.py b/letsencrypt_auto/tests/auto_test.py new file mode 100644 index 000000000..c2b9fc378 --- /dev/null +++ b/letsencrypt_auto/tests/auto_test.py @@ -0,0 +1,247 @@ +"""Tests for letsencrypt-auto""" + +from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler +from contextlib import contextmanager +from functools import partial +from json import dumps +from os import environ +from os.path import abspath, dirname, join +import re +from shutil import rmtree +import socket +import ssl +from subprocess import CalledProcessError, check_output, Popen, PIPE +from tempfile import mkdtemp +from threading import Thread +from unittest import TestCase + +from nose.tools import eq_, nottest, ok_ + +from ..build import build as build_le_auto + + +class RequestHandler(BaseHTTPRequestHandler): + """An HTTPS request handler which is quiet and serves a specific folder.""" + + def __init__(self, resources, *args, **kwargs): + """ + :arg resources: A dict of resource paths pointing to content bytes + + """ + self.resources = resources + BaseHTTPRequestHandler.__init__(self, *args, **kwargs) + + def log_message(self, format, *args): + """Don't log each request to the terminal.""" + + def do_GET(self): + """Serve a GET request.""" + content = self.send_head() + if content is not None: + self.wfile.write(content) + + def send_head(self): + """Common code for GET and HEAD commands + + This sends the response code and MIME headers and returns either a + bytestring of content or, if none is found, None. + + """ + path = self.path[1:] # Strip leading slash. + content = self.resources.get(path) + if content is None: + self.send_error(404, 'Path "%s" not found in self.resources' % path) + else: + self.send_response(200) + self.send_header('Content-type', 'text/plain') + self.send_header('Content-Length', str(len(content))) + self.end_headers() + return content + + +def server_and_port(resources): + """Return an unstarted HTTPS server and the port it will use.""" + # Find a port, and bind to it. I can't get the OS to close the socket + # promptly after we shut down the server, so we typically need to try + # a couple ports after the first test case. Setting + # TCPServer.allow_reuse_address = True seems to have nothing to do + # with this behavior. + worked = False + for port in xrange(4443, 4543): + try: + server = HTTPServer(('localhost', port), + partial(RequestHandler, resources)) + except socket.error: + pass + else: + worked = True + server.socket = ssl.wrap_socket( + server.socket, + certfile=join(tests_dir(), 'certs', 'localhost', 'server.pem'), + server_side=True) + break + if not worked: + raise RuntimeError("Couldn't find an unused socket for the testing HTTPS server.") + return server, port + + +@contextmanager +def serving(resources): + """Spin up a local HTTPS server, and yield its base URL. + + Use a self-signed cert generated as outlined by + https://coolaj86.com/articles/create-your-own-certificate-authority-for- + testing/. + + """ + server, port = server_and_port(resources) + thread = Thread(target=server.serve_forever) + try: + thread.start() + yield 'https://localhost:{port}/'.format(port=port) + finally: + server.shutdown() + thread.join() + + +@nottest +def tests_dir(): + """Return a path to the "tests" directory.""" + return dirname(abspath(__file__)) + + +@contextmanager +def ephemeral_dir(): + dir = mkdtemp(prefix='le-test-') + try: + yield dir + finally: + rmtree(dir) + + +def out_and_err(command, input=None, shell=False, env=None): + """Run a shell command, and return stderr and stdout as string. + + If the command returns nonzero, raise CalledProcessError. + + :arg command: A list of commandline args + :arg input: Data to pipe to stdin. Omit for none. + + Remaining args have the same meaning as for Popen. + + """ + process = Popen(command, + stdout=PIPE, + stdin=PIPE, + stderr=PIPE, + shell=shell, + env=env) + out, err = process.communicate(input=input) + status = process.poll() # same as in check_output(), though wait() sounds better + if status: + raise CalledProcessError(status, command, output=out) + return out, err + + +def signed(content, private_key_name='signing.key'): + """Return the signed SHA-256 hash of ``content``, using the given key file.""" + command = ['openssl', 'dgst', '-sha256', '-sign', + join(tests_dir(), private_key_name)] + out, err = out_and_err(command, input=content) + return out + + +def run_le_auto(venv_dir, base_url): + """Run the prebuilt version of letsencrypt-auto, returning stdout and + stderr strings. + + If the command returns other than 0, raise CalledProcessError. + + """ + env = environ.copy() + d = dict(XDG_DATA_HOME=venv_dir, + LE_AUTO_JSON_URL=base_url + 'letsencrypt/json', + LE_AUTO_DIR_TEMPLATE=base_url + '%s/', + # The public key corresponding to signing_keys/test.key: + LE_AUTO_PUBLIC_KEY="""-----BEGIN PUBLIC KEY----- +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsMoSzLYQ7E1sdSOkwelg +tzKIh2qi3bpXuYtcfFC0XrvWig071NwIj+dZiT0OLZ2hPispEH0B7ISuuWg1ll7G +hFW0VdbxL6JdGzS2ShNWkX9hE9z+j8VqwDPOBn3ZHm03qwpYkBDwQib3KqOdYbTT +uUtJmmGcuk3a9Aq/sCT6DdfmTSdP5asdQYwIcaQreDrOosaS84DTWI3IU+UYJVgl +LsIVPBuy9IcgHidUQ96hJnoPsDCWsHwX62495QKEarauyKQrJzFes0EY95orDM47 +Z5o/NDiQB11m91yNB0MmPYY9QSbnOA9j7IaaC97AwRLuwXY+/R2ablTcxurWou68 +iQIDAQAB +-----END PUBLIC KEY-----""") + env.update(d) + return out_and_err( + join(dirname(tests_dir()), 'letsencrypt-auto') + ' --version', + shell=True, + env=env) + + +class AutoTests(TestCase): + def test_all(self): + """Exercise most branches of letsencrypt-auto. + + The branches: + + * An le-auto upgrade is needed. + * An le-auto upgrade is not needed. + * There was an out-of-date LE script installed. + * There was a current LE script installed. + * There was no LE script installed. (not that important) + * Peep verification passes. + * Peep has a hash mismatch. + * The OpenSSL sig mismatches. + + I violate my usual rule of having small, decoupled tests, because... + + 1. We shouldn't need to run a Cartesian product of the branches: the + phases run in separate shell processes, containing state leakage + pretty effectively. The only shared state is FS state, and it's + limited to a temp dir, assuming (if we dare) all functions properly. + 2. One combination of branches happens to set us up nicely for testing + the next, saving code. + + At the moment, we let bootstrapping run. We probably wanted those + packages installed anyway for local development. + + For tests which get this far, we run merely ``letsencrypt --version``. + The functioning of the rest of the letsencrypt script is covered by + other test suites. + + """ + NEW_LE_AUTO = build_le_auto(version='99.9.9') + NEW_LE_AUTO_SIG = signed(NEW_LE_AUTO) + + with ephemeral_dir() as venv_dir: + # This serves a PyPI page with a higher version, a GitHub-alike + # with a corresponding le-auto script, and a matching signature. + resources = {'': """ + Directory listing for / + +

Directory listing for /

+
+ +
+ + """, # TODO: Cut this down. + 'letsencrypt/json': dumps({'releases': {'99.9.9': None}}), + 'v99.9.9/letsencrypt-auto': NEW_LE_AUTO, + 'v99.9.9/letsencrypt-auto.sig': NEW_LE_AUTO_SIG} + with serving(resources) as base_url: + # Test when a phase-1 upgrade is needed, there's no LE binary + # installed, and peep verifies: + out, err = run_le_auto(venv_dir, base_url) + ok_(re.match(r'letsencrypt \d+\.\d+\.\d+', + err.strip().splitlines()[-1])) + + + # This conveniently sets us up to test the next 2 cases: + # Test when no phase-1 upgrade is needed and no LE upgrade is needed (probably a common case). + + # Test (when no phase-1 upgrade is needed), there's an out-of-date LE script installed, (and peep works). + # Test when peep has a hash mismatch. + # Test when the OpenSSL sig mismatches. diff --git a/letsencrypt_auto/tests/certs/ca/my-root-ca.crt.pem b/letsencrypt_auto/tests/certs/ca/my-root-ca.crt.pem new file mode 100644 index 000000000..4e4d29bd2 --- /dev/null +++ b/letsencrypt_auto/tests/certs/ca/my-root-ca.crt.pem @@ -0,0 +1,23 @@ +-----BEGIN CERTIFICATE----- +MIID5jCCAs6gAwIBAgIJAI1Qkfyw88REMA0GCSqGSIb3DQEBBQUAMFUxCzAJBgNV +BAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMRswGQYDVQQKExJNeSBCb2d1cyBS +b290IENlcnQxFDASBgNVBAMTC2V4YW1wbGUuY29tMB4XDTE1MTIwNDIwNTIxNVoX +DTQwMTIwMzIwNTIxNVowVTELMAkGA1UEBhMCQVUxEzARBgNVBAgTClNvbWUtU3Rh +dGUxGzAZBgNVBAoTEk15IEJvZ3VzIFJvb3QgQ2VydDEUMBIGA1UEAxMLZXhhbXBs +ZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDQVQpQ2EH4gTJB +NJP6+ocT3xJwT8mSXYUnvzjj6iv+JxZiXRGzAPziNzrrSRKY0yDHF+UiJwuOerLa +n8laZkLb1Ogqzs2u64rKeb0xWv90Qp+eXG0J/1xb4dw+GExqe5QFo1JUJzO/eK7m +1S04SeFkN1qV9mD5yJUy7DGiTUzDHgCxM2tXMLusXYqkxsQQ9+2EJ7BEOK4YJGEx +Sign5FuSxb64PiNow6OA97CaLl7tV4INP4w195ueDRIaS4poeOep4s8U7IAdMjIZ +EryJgKNCij50xK92vPBBJSj0NOitltBlwoEqkOZpQCOZamFd6nvt78LQ6W8Am+l6 +y6oCON5JAgMBAAGjgbgwgbUwHQYDVR0OBBYEFAlrdStDhaayLLj89Whe3Gc+HE8y +MIGFBgNVHSMEfjB8gBQJa3UrQ4Wmsiy4/PVoXtxnPhxPMqFZpFcwVTELMAkGA1UE +BhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUxGzAZBgNVBAoTEk15IEJvZ3VzIFJv +b3QgQ2VydDEUMBIGA1UEAxMLZXhhbXBsZS5jb22CCQCNUJH8sPPERDAMBgNVHRME +BTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQC7KAQfDTiNM3QO8Ic3x21CAPJUavkH +zshifN+Ei0+nmseHDTCTgsGfGDOToLUpUEZ4PuiHnz08UwRfd9wotc3SgY9ZaXMe +vRs8KUAF9EoyTvESzPyv2b6cS9NNMpj5y7KyXSyP17VoGbNavtiGQ4dwgEH6VgNl +0RtBvcSBv/tqxIIx1tWzL74tVEm0Kbd9BAZsYpQNKL8e6WXP35/j0PvCCvtofGrA +E8LTqMz4kCwnX+QaJIMJhBophRCsjXdAkvFbFxX0DGPztQtzIwBPcdMjsft7AFeE +0XchhDDXxw8YsbpvPfCvrD8XiiVuBycbnB1zt0LLVwB/QsCzUW9ImpLC +-----END CERTIFICATE----- diff --git a/letsencrypt_auto/tests/certs/ca/my-root-ca.key.pem b/letsencrypt_auto/tests/certs/ca/my-root-ca.key.pem new file mode 100644 index 000000000..9caa7ddaa --- /dev/null +++ b/letsencrypt_auto/tests/certs/ca/my-root-ca.key.pem @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEA0FUKUNhB+IEyQTST+vqHE98ScE/Jkl2FJ7844+or/icWYl0R +swD84jc660kSmNMgxxflIicLjnqy2p/JWmZC29ToKs7NruuKynm9MVr/dEKfnlxt +Cf9cW+HcPhhManuUBaNSVCczv3iu5tUtOEnhZDdalfZg+ciVMuwxok1Mwx4AsTNr +VzC7rF2KpMbEEPfthCewRDiuGCRhMUooJ+RbksW+uD4jaMOjgPewmi5e7VeCDT+M +Nfebng0SGkuKaHjnqeLPFOyAHTIyGRK8iYCjQoo+dMSvdrzwQSUo9DTorZbQZcKB +KpDmaUAjmWphXep77e/C0OlvAJvpesuqAjjeSQIDAQABAoIBAH+qbVzneV3wxjwh +HUHi/p3VyHXc3xh7iNq3mwRH/1eK2nPCttLsGwwBbnC64dOXJfH7maWZKcLRPAMv +gfOM0RHn4bJB8tdrbizv91lke0DihvBDkWpb+1wvB4lh2Io0Wpwt3ojFUTfXm87G ++iQRWjbQmQlm5zyKh6uiBDSCjDTQdb9omZEBMAwlGPTZwt8TRUEtWd8QgW8FCHoB +iLER2WBwXdvn3PBtocI3VE6IYDSeZ81Xv+d7925RtVintT8Suk4toYwX+jfSz+wZ +sgHd5V6PSv9a7GUlWoUihD99D9wqDZE8IvMDZ5ofSAUd1KfICDtmsEyugY7u2yYZ +tYt49AECgYEA73f7ITMHg8JsUipqb6eG10gCRtRhkqrrO1g/TNeTBh3CTrQGb56e +y6kmUivn5gK46t3T2N4Ht4IR8fpLcJcbPYPQNulSjmWm5y6WduafXW/VCW1NA9Lc +FyGPkMxFCIVJTLFxfLFepBVvtUzLLDKGGtQxru/GNbBzjdtmVfDPIoECgYEA3rbM +cTfvj+jWrV1YsRbphyjy+k3OJEIVx6KA4s5d7Tp12UfYQp/B3HPhXXm5wqeo1Nos +UAEWZIMi1VoE8iu6jjeJ6uERtbKKQVed25Us/ff0jUPbxlXgiBOtRcllq9d9Srjm +ybHUgfjLsZ2/xpIcOl+oI5pDM9JvD8Sq4ZCFR8kCgYBK/H0tFjeiML2OtS2DLShy +PWBJIbQ0I0Vp3eZkf5TQc30m/ASP61G6YItZa9pAElYpZbEy1cQA2MAZz9DTvt2O +07ndmA57/KTY+6OuM+Vvctd5DjrxmZPFwoKcSvrLAkHDvETXUQtbwkKquRNeEawg +tpWgPAELSufEYhGXk8KpAQKBgBDCqPgMQZcO6rj5QWdyVfi5+C8mE9Fet8ziSdjH +twHXWG8VnQzGgQxaHCewtW4Ut/vsv1D2A/1kcQalU6H18IArZdGrRm3qFcV9FoAj +5dLnChxncu6mH9Odx3htA52/BcrNx3B+VYPCeXHQcVI8RKuP71NelJgdygXhwwpe +mekhAoGBAOUovnqylciYa9HRqo+xZk59eyX+ehhnlV8SeJ2K0PwaQkzQ0KYtCmE7 +kdSdhcv8h/IQKGaFfc/LyFMM/a26PfAeY5bj41UjkT0K5hQrYuL/52xaT401YLcb +Xo+bZz9K0hrdP7TdZFuTY/WxojXgjsVAuAN1NwnJumqxhzPh+hfl +-----END RSA PRIVATE KEY----- diff --git a/letsencrypt_auto/tests/certs/ca/my-root-ca.srl b/letsencrypt_auto/tests/certs/ca/my-root-ca.srl new file mode 100644 index 000000000..ad6d262b4 --- /dev/null +++ b/letsencrypt_auto/tests/certs/ca/my-root-ca.srl @@ -0,0 +1 @@ +D613482D0EF95DD0 diff --git a/letsencrypt_auto/tests/certs/localhost/cert.pem b/letsencrypt_auto/tests/certs/localhost/cert.pem new file mode 100644 index 000000000..ac83535ce --- /dev/null +++ b/letsencrypt_auto/tests/certs/localhost/cert.pem @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDKjCCAhICCQDWE0gtDvld0DANBgkqhkiG9w0BAQUFADBVMQswCQYDVQQGEwJB +VTETMBEGA1UECBMKU29tZS1TdGF0ZTEbMBkGA1UEChMSTXkgQm9ndXMgUm9vdCBD +ZXJ0MRQwEgYDVQQDEwtleGFtcGxlLmNvbTAeFw0xNTEyMDQyMDU0MzFaFw00MDEy +MDMyMDU0MzFaMFkxCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEw +HwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxEjAQBgNVBAMTCWxvY2Fs +aG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK2WIIi86Mis4UQH +a5PrFbX2PBtQHbI3t3ekN1CewRsgQ/2X3lCeWhKmr3CJYXVgA7q/23PORQAiuV6y +DG2dQIrjeahWCXaCptTi49ljfVRTW2IxrHke/iA8TkDuZbWGzVLb8TB83ipBOD41 +SjuomoN4A/ktnIfbNqRqgjjHs2wwJHDfxPiCQlwyOayjHmdlh8cqfVE8rWEm5/3T +Iu0X1J53SammR1SbUmsLJNofxFYMK1ogHb0CaFEG9QuuUDPJl5K74Rr6InMQZKPn +ne4W3cGoALxPHAca7yicpSMSmdsmd6pqylc2Fdua7o/wf0SwShxS4A1DqA/HWLEM +V6MSEF8CAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAz5sMAFG6W/ZEULZITkBTCU6P +NttpGiKufnqyBW5HyNylaczfnHnClvQjr8f/84xvKVcfC3xP0lz+92aIQqo+5L/n +v7gLhBFR4Vr2XwMt2qz2FpkaxmVwnhVAHaaC05WIKQ6W2gDwWT0u1K8YdTh+7mvN +AT9FW4vDgtNZWq4W/PePh9QCiOOQhGOuBYj/7zqLtz4XPifhi66ILIRDHiu0kond +3YMFcECIAf4MPT9vT0iNcWX+c8CfAixPt8nMD6bzOo3oTcfuZh/2enfgLbMqOlOi +uk72FM5VVPXTWAckJvL/vVjqsvDuJQKqbr0oUc3bdWbS36xtWZUycp4IQLguAQ== +-----END CERTIFICATE----- diff --git a/letsencrypt_auto/tests/certs/localhost/localhost.csr.pem b/letsencrypt_auto/tests/certs/localhost/localhost.csr.pem new file mode 100644 index 000000000..8a6189f88 --- /dev/null +++ b/letsencrypt_auto/tests/certs/localhost/localhost.csr.pem @@ -0,0 +1,17 @@ +-----BEGIN CERTIFICATE REQUEST----- +MIICnjCCAYYCAQAwWTELMAkGA1UEBhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUx +ITAfBgNVBAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDESMBAGA1UEAxMJbG9j +YWxob3N0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArZYgiLzoyKzh +RAdrk+sVtfY8G1Adsje3d6Q3UJ7BGyBD/ZfeUJ5aEqavcIlhdWADur/bc85FACK5 +XrIMbZ1AiuN5qFYJdoKm1OLj2WN9VFNbYjGseR7+IDxOQO5ltYbNUtvxMHzeKkE4 +PjVKO6iag3gD+S2ch9s2pGqCOMezbDAkcN/E+IJCXDI5rKMeZ2WHxyp9UTytYSbn +/dMi7RfUnndJqaZHVJtSawsk2h/EVgwrWiAdvQJoUQb1C65QM8mXkrvhGvoicxBk +o+ed7hbdwagAvE8cBxrvKJylIxKZ2yZ3qmrKVzYV25ruj/B/RLBKHFLgDUOoD8dY +sQxXoxIQXwIDAQABoAAwDQYJKoZIhvcNAQEFBQADggEBAFbg3WrAokoPx7iAYG6z +PqeDd4/XanXjeL4Ryxv6LoGhu69mmBAd3N5ILPyQJjnkWpIjEmJDzEcPMzhQjRh5 +GlWTyvKWO4zClYU840KZk7crVkpzNZ+HP0YeM/Agz6sab00ffRcq5m1wEF9MCvDE +8FUXk1HBHRAb/6t9QV/7axsPOkGT8SjQ1v2SCaiB0HQL3sYChYLi5zu4dfmQNPGq +ar9Xm5a0YqOQIFfmy8RSwxk0Q/ipNFTGN1uvlIRkgbT9zPnodxjWZsSI9BF+q5Af +uiE/oAk7MxfJ0LyLfhOWB+T98bKIOVtFT3wMLS1IIgMogwqCEXFf30Q9p2iTEzqT +6UE= +-----END CERTIFICATE REQUEST----- diff --git a/letsencrypt_auto/tests/certs/localhost/privkey.pem b/letsencrypt_auto/tests/certs/localhost/privkey.pem new file mode 100644 index 000000000..18feba403 --- /dev/null +++ b/letsencrypt_auto/tests/certs/localhost/privkey.pem @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEArZYgiLzoyKzhRAdrk+sVtfY8G1Adsje3d6Q3UJ7BGyBD/Zfe +UJ5aEqavcIlhdWADur/bc85FACK5XrIMbZ1AiuN5qFYJdoKm1OLj2WN9VFNbYjGs +eR7+IDxOQO5ltYbNUtvxMHzeKkE4PjVKO6iag3gD+S2ch9s2pGqCOMezbDAkcN/E ++IJCXDI5rKMeZ2WHxyp9UTytYSbn/dMi7RfUnndJqaZHVJtSawsk2h/EVgwrWiAd +vQJoUQb1C65QM8mXkrvhGvoicxBko+ed7hbdwagAvE8cBxrvKJylIxKZ2yZ3qmrK +VzYV25ruj/B/RLBKHFLgDUOoD8dYsQxXoxIQXwIDAQABAoIBAG8bVJ+xKt6nqVg9 +16HKKw9ZGIfy888K0qgFuFImCzwtntdGycmYUdb2Uf0aMgNK/ZgfDXxGXuwDTdtK +46GVsaY0i74vs8bjQZ2pzGVsxN+gqzFi0h6Es+w2LXBqJzfVnL6YgPykMB+jtzg6 +K9Wbyaq0uvZXN4XNzl/WvJtTV4i7Cff1MOd5EhKFdqxrZvB/SRBCr/SMMafRtB9P +EvMneNKzhmlrutHAxuyxEKZR32Kkx7ydAdTjGgn+rE+NL5BweXfeWhLU4Bv14bn9 +Mkneu3w5o1ryJfE2YnVajUP//jeopUT0nTQ3MpEusBQCLBlvFXjjM9uCaFX+5+MP +0H4xVcECgYEA1Q+wR3GHbk37vIGSlbENyUsri5WlMt8IVAHsDsTOpxAjYB0yyo+x +h9RS+RJZQECJlA6H72peUl3GM7RgdWIcKOT3nZ12XqYKG57rr/N5zlUuxbdS8KBk +JhyZeJdYjq/Jrno1ZP+OSmc7VvBLcM7irY7LHlvK0o8W1W0TNJ8jrZkCgYEA0JHX +lJd+fiezcUS7g4moHtzJp0JKquQiXLX+c2urmpyhb3ZrTuQ8OUjSy6DlwHlgDx8K +Hg2sdx/ZCuDaGjR4IY/Qs5RFt9WUqlK9gi9V3nYVrzBOQkdFOf/Ad3j4pQ8/aeCX +nP6snHXz1WqPpbCXG6l6GzFGbQU473GfuKsDuLcCgYAWQaNKc0OQdDj9whNL68ji +5CVSWXl+TOoTzHeaO1jS/s6TNbmei1AiPj3EovQL0DIO802j5tqfhAg2UntZB7yl +UPXE0zQQQwv/QqSgJrDsqt1N7g6N8FNF3+rwO+8WSKqqvT1ipYd5ojsCo+tdh18K +fkYdj70qLaRW+yPsdUtG0QKBgEYc8NqbvsML94+ZKmwCh4iwcf2PFGi0PjTqXTpR +tKNKCh7dMR+ZLAGZ0HrxgKqeYsNSjOUjdZmqFB1LDyaGAuhNXzwvGOy+mLZVEC3G +Wdhp28pDs9sl+EiSCBJhkTxzjr656F23YzFJmYlhxB5P6cw7wbeIbgNSIRylFqtO +mfarAoGBAICsAEWypOctxtmtOcjxgJ7jMbOA7rrsGlXpiy1/WlwIwRGF5LMvIIFX +qFAfiPcZn05ZgdAGzaFYowdjmQB10FW0jZbDf+nIHfOF5YmfmfWjsaweEGALJmqB +okGu/lGNGf3XoYzy0/hC3WAqk3znSZtQLUq8jEWF7dLNUizUeUow +-----END RSA PRIVATE KEY----- diff --git a/letsencrypt_auto/tests/certs/localhost/server.pem b/letsencrypt_auto/tests/certs/localhost/server.pem new file mode 100644 index 000000000..c5765dd89 --- /dev/null +++ b/letsencrypt_auto/tests/certs/localhost/server.pem @@ -0,0 +1,46 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEArZYgiLzoyKzhRAdrk+sVtfY8G1Adsje3d6Q3UJ7BGyBD/Zfe +UJ5aEqavcIlhdWADur/bc85FACK5XrIMbZ1AiuN5qFYJdoKm1OLj2WN9VFNbYjGs +eR7+IDxOQO5ltYbNUtvxMHzeKkE4PjVKO6iag3gD+S2ch9s2pGqCOMezbDAkcN/E ++IJCXDI5rKMeZ2WHxyp9UTytYSbn/dMi7RfUnndJqaZHVJtSawsk2h/EVgwrWiAd +vQJoUQb1C65QM8mXkrvhGvoicxBko+ed7hbdwagAvE8cBxrvKJylIxKZ2yZ3qmrK +VzYV25ruj/B/RLBKHFLgDUOoD8dYsQxXoxIQXwIDAQABAoIBAG8bVJ+xKt6nqVg9 +16HKKw9ZGIfy888K0qgFuFImCzwtntdGycmYUdb2Uf0aMgNK/ZgfDXxGXuwDTdtK +46GVsaY0i74vs8bjQZ2pzGVsxN+gqzFi0h6Es+w2LXBqJzfVnL6YgPykMB+jtzg6 +K9Wbyaq0uvZXN4XNzl/WvJtTV4i7Cff1MOd5EhKFdqxrZvB/SRBCr/SMMafRtB9P +EvMneNKzhmlrutHAxuyxEKZR32Kkx7ydAdTjGgn+rE+NL5BweXfeWhLU4Bv14bn9 +Mkneu3w5o1ryJfE2YnVajUP//jeopUT0nTQ3MpEusBQCLBlvFXjjM9uCaFX+5+MP +0H4xVcECgYEA1Q+wR3GHbk37vIGSlbENyUsri5WlMt8IVAHsDsTOpxAjYB0yyo+x +h9RS+RJZQECJlA6H72peUl3GM7RgdWIcKOT3nZ12XqYKG57rr/N5zlUuxbdS8KBk +JhyZeJdYjq/Jrno1ZP+OSmc7VvBLcM7irY7LHlvK0o8W1W0TNJ8jrZkCgYEA0JHX +lJd+fiezcUS7g4moHtzJp0JKquQiXLX+c2urmpyhb3ZrTuQ8OUjSy6DlwHlgDx8K +Hg2sdx/ZCuDaGjR4IY/Qs5RFt9WUqlK9gi9V3nYVrzBOQkdFOf/Ad3j4pQ8/aeCX +nP6snHXz1WqPpbCXG6l6GzFGbQU473GfuKsDuLcCgYAWQaNKc0OQdDj9whNL68ji +5CVSWXl+TOoTzHeaO1jS/s6TNbmei1AiPj3EovQL0DIO802j5tqfhAg2UntZB7yl +UPXE0zQQQwv/QqSgJrDsqt1N7g6N8FNF3+rwO+8WSKqqvT1ipYd5ojsCo+tdh18K +fkYdj70qLaRW+yPsdUtG0QKBgEYc8NqbvsML94+ZKmwCh4iwcf2PFGi0PjTqXTpR +tKNKCh7dMR+ZLAGZ0HrxgKqeYsNSjOUjdZmqFB1LDyaGAuhNXzwvGOy+mLZVEC3G +Wdhp28pDs9sl+EiSCBJhkTxzjr656F23YzFJmYlhxB5P6cw7wbeIbgNSIRylFqtO +mfarAoGBAICsAEWypOctxtmtOcjxgJ7jMbOA7rrsGlXpiy1/WlwIwRGF5LMvIIFX +qFAfiPcZn05ZgdAGzaFYowdjmQB10FW0jZbDf+nIHfOF5YmfmfWjsaweEGALJmqB +okGu/lGNGf3XoYzy0/hC3WAqk3znSZtQLUq8jEWF7dLNUizUeUow +-----END RSA PRIVATE KEY----- +-----BEGIN CERTIFICATE----- +MIIDKjCCAhICCQDWE0gtDvld0DANBgkqhkiG9w0BAQUFADBVMQswCQYDVQQGEwJB +VTETMBEGA1UECBMKU29tZS1TdGF0ZTEbMBkGA1UEChMSTXkgQm9ndXMgUm9vdCBD +ZXJ0MRQwEgYDVQQDEwtleGFtcGxlLmNvbTAeFw0xNTEyMDQyMDU0MzFaFw00MDEy +MDMyMDU0MzFaMFkxCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEw +HwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxEjAQBgNVBAMTCWxvY2Fs +aG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK2WIIi86Mis4UQH +a5PrFbX2PBtQHbI3t3ekN1CewRsgQ/2X3lCeWhKmr3CJYXVgA7q/23PORQAiuV6y +DG2dQIrjeahWCXaCptTi49ljfVRTW2IxrHke/iA8TkDuZbWGzVLb8TB83ipBOD41 +SjuomoN4A/ktnIfbNqRqgjjHs2wwJHDfxPiCQlwyOayjHmdlh8cqfVE8rWEm5/3T +Iu0X1J53SammR1SbUmsLJNofxFYMK1ogHb0CaFEG9QuuUDPJl5K74Rr6InMQZKPn +ne4W3cGoALxPHAca7yicpSMSmdsmd6pqylc2Fdua7o/wf0SwShxS4A1DqA/HWLEM +V6MSEF8CAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAz5sMAFG6W/ZEULZITkBTCU6P +NttpGiKufnqyBW5HyNylaczfnHnClvQjr8f/84xvKVcfC3xP0lz+92aIQqo+5L/n +v7gLhBFR4Vr2XwMt2qz2FpkaxmVwnhVAHaaC05WIKQ6W2gDwWT0u1K8YdTh+7mvN +AT9FW4vDgtNZWq4W/PePh9QCiOOQhGOuBYj/7zqLtz4XPifhi66ILIRDHiu0kond +3YMFcECIAf4MPT9vT0iNcWX+c8CfAixPt8nMD6bzOo3oTcfuZh/2enfgLbMqOlOi +uk72FM5VVPXTWAckJvL/vVjqsvDuJQKqbr0oUc3bdWbS36xtWZUycp4IQLguAQ== +-----END CERTIFICATE----- diff --git a/letsencrypt_auto/tests/signing.key b/letsencrypt_auto/tests/signing.key new file mode 100644 index 000000000..b9964d00c --- /dev/null +++ b/letsencrypt_auto/tests/signing.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpQIBAAKCAQEAsMoSzLYQ7E1sdSOkwelgtzKIh2qi3bpXuYtcfFC0XrvWig07 +1NwIj+dZiT0OLZ2hPispEH0B7ISuuWg1ll7GhFW0VdbxL6JdGzS2ShNWkX9hE9z+ +j8VqwDPOBn3ZHm03qwpYkBDwQib3KqOdYbTTuUtJmmGcuk3a9Aq/sCT6DdfmTSdP +5asdQYwIcaQreDrOosaS84DTWI3IU+UYJVglLsIVPBuy9IcgHidUQ96hJnoPsDCW +sHwX62495QKEarauyKQrJzFes0EY95orDM47Z5o/NDiQB11m91yNB0MmPYY9QSbn +OA9j7IaaC97AwRLuwXY+/R2ablTcxurWou68iQIDAQABAoIBAQCJE3W2Mqk2f+XL +geKa1BjAkzcXQJCduYGRhUQlw/HGzoBPtGki56Tf53MeHTAkIGfIq3CAr1zRhiNv +8SQzvrLQIx/buvhxhcQJdzqsfwgNcqXT3/OliF34P3LMx8GUfPy/6xq2Qdv4fvwA +nLJH8wyDTKP6RxtdvUY7GSZ+Ln2QQv/3Nco7tax4GHNGom8iSgeH/YKTDnvitdqh +a0fr930QzU39TfOftLmasdmKUOIg8G2wr4Sy6Kn060+OUoQr1fZF5mnLvvQeILCK +uav91JkIeMLggzk+t88IJUFWdOoxv5hWTnNzHyt+/GYfovyRz2fKQMwzdh1F8iM5 ++867rEb9AoGBANn1ncemJBedDshStdCBUH0+2ExPrawveaXOZKnx8/VGFXNi0hAf +KzkntMWd5g5kB077FtKO9CYTBvK4pZBWIFLcJEqAz88JeXME6dfUbRucDr72ko+l +rcLHXj7F0IDVzj/9CphMGAhC9J/4YW9SPcSbMw6dQ6xOk73f1Vowve0DAoGBAM+k +/F+hVqCS3f22Bg9KuDtx+zCydaZxC842DgIkV1SO2iFhNHjnpQ5EIR0WrSYeV2n+ +rD7kVs5OH1HvnGScHaQKtAVqZClSwF14jzE+Aj8XDwxiHLSOhJgKlzfVX7h1ymMh +7fsslDl6xNGQ+40gubhkCLT5qABFKy1mrZ8b+3yDAoGAGLGUI6d2FVrM7vM3+Bx+ +gwIYvWSVl5l1XcypaPupmRNMoNsEU6FEY2BVQcJm6yB4F4GpD0f0709ejSdQUq7/ +UIPydKJtaNZ49QgMelBt4B/pJ8eFyVKLAjNWQSRmQAJ5MJS5m5Gbc2wqjOk2GMen +idvPiAtXPHFWmb9/S42UJwMCgYEAjymAe2qgcGtyNNfIC8kHhqzKdEPGi/ALJKzu +MZnewEURrcv4QpfrnA9rCUQ2Mz7eJA1bsqz6EJmaTIK4wEFGynA6uDUnQ7pzOL7D +cz7+i4MZc/89LVvJnY5Hvk4WBfboiDq/etq8g3jatGaSmTYD9la6DhTHORB3eYD+ +meHQHYMCgYEA18y9hnx2k4vNeBei4YXF4pAvKdwKLQD+CcP9ljb3VT+kXktjRA1C +aWj3HhMwvcxtttfkQzEnwwGRAkTEtNewJ8KFxhmc9nYElZTNZ+SuHD5Dkv8xqoj8 +NvG8rU1eiEyPwE2wQxpM5JLqbo7IWtR0dmptjKoF1gRxn6Wh4TwEiHA= +-----END RSA PRIVATE KEY-----