From 302e3ceb7dbd9cedb8042ec1708e2f0ac27c40ef Mon Sep 17 00:00:00 2001 From: Jakub Warmuz Date: Wed, 9 Sep 2015 20:04:28 +0000 Subject: [PATCH] Revocation: integration testable --- acme/acme/client.py | 3 ++- acme/acme/client_test.py | 2 +- letsencrypt/cli.py | 34 ++++++++++++++++++++++------------ tests/boulder-integration.sh | 7 +++++++ 4 files changed, 32 insertions(+), 14 deletions(-) diff --git a/acme/acme/client.py b/acme/acme/client.py index 9c32a81a4..ae9cde33f 100644 --- a/acme/acme/client.py +++ b/acme/acme/client.py @@ -454,7 +454,8 @@ class Client(object): # pylint: disable=too-many-instance-attributes """ response = self.net.post(self.directory[messages.Revocation], - messages.Revocation(certificate=cert)) + messages.Revocation(certificate=cert), + content_type=None) if response.status_code != http_client.OK: raise errors.ClientError( 'Successful revocation must return HTTP OK status') diff --git a/acme/acme/client_test.py b/acme/acme/client_test.py index ce03256c3..06c0a2313 100644 --- a/acme/acme/client_test.py +++ b/acme/acme/client_test.py @@ -360,7 +360,7 @@ class ClientTest(unittest.TestCase): def test_revoke(self): self.client.revoke(self.certr.body) self.net.post.assert_called_once_with( - self.directory[messages.Revocation], mock.ANY) + self.directory[messages.Revocation], mock.ANY, content_type=None) def test_revoke_bad_status_raises_error(self): self.response.status_code = http_client.METHOD_NOT_ALLOWED diff --git a/letsencrypt/cli.py b/letsencrypt/cli.py index a70db8dd2..bb04bc3d6 100644 --- a/letsencrypt/cli.py +++ b/letsencrypt/cli.py @@ -16,12 +16,16 @@ import zope.component import zope.interface.exceptions import zope.interface.verify +from acme import client as acme_client +from acme import jose + import letsencrypt from letsencrypt import account from letsencrypt import configuration from letsencrypt import constants from letsencrypt import client +from letsencrypt import crypto_util from letsencrypt import errors from letsencrypt import interfaces from letsencrypt import le_util @@ -241,16 +245,20 @@ def install(args, config, plugins): le_client.enhance_config(domains, args.redirect) -def revoke(args, unused_config, unused_plugins): +def revoke(args, config, unused_plugins): # TODO: coop with renewal config """Revoke a previously obtained certificate.""" - if args.cert_path is None and args.key_path is None: - return "At least one of --cert-path or --key-path is required" - - # This depends on the renewal config and cannot be completed yet. - zope.component.getUtility(interfaces.IDisplay).notification( - "Revocation is not available with the new Boulder server yet.") - #client.revoke(args.installer, config, plugins, args.no_confirm, - # args.cert_path, args.key_path) + if args.key_path is not None: # revocation by cert key + logger.debug("Revoking %s using cert key %s", + args.cert_path[0], args.key_path[0]) + acme = acme_client.Client( + config.server, key=jose.JWK.load(args.key_path[1])) + else: # revocation by account key + logger.debug("Revoking %s using Account Key", args.cert_path[0]) + acc, _ = _determine_account(args, config) + # pylint: disable=protected-access + acme = client._acme_from_config_key(config, acc.key) + acme.revoke(jose.ComparableX509(crypto_util.pyopenssl_load_certificate( + args.cert_path[1])[0])) def rollback(args, config, plugins): @@ -576,14 +584,16 @@ def _create_subparsers(helpful): "--cert-path", required=True, help="Path to a certificate that " "is going to be installed.") parser_install.add_argument( - "--key-path", required=True, help="Accompynying private key") + "--key-path", required=True, help="Accompanying private key") parser_install.add_argument( "--chain-path", help="Accompanying path to a certificate chain.") parser_revoke.add_argument( - "--cert-path", type=read_file, help="Revoke a specific certificate.") + "--cert-path", type=read_file, help="Revoke a specific certificate.", + required=True) parser_revoke.add_argument( "--key-path", type=read_file, - help="Revoke all certs generated by the provided authorized key.") + help="Revoke certificate using its accompanying key. Useful if " + "Account Key is lost.") parser_rollback.add_argument( "--checkpoints", type=int, metavar="N", diff --git a/tests/boulder-integration.sh b/tests/boulder-integration.sh index 23bfcf3ca..8a4f715ea 100755 --- a/tests/boulder-integration.sh +++ b/tests/boulder-integration.sh @@ -54,6 +54,13 @@ do [ "${dir}/${latest}" = "$live" ] # renewer fails this test done +# revoke by account key +common revoke --cert-path /etc/conf/live/le.wtf/cert.pem +# revoke renewed +common revoke --cert-path /etc/conf/live/le1.wtf/cert.pem +# revoke by cert key +common revoke --cert-path /etc/conf/live/le2.wtf/cert.pem \ + --key-path /etc/conf/live/le2.wtf/privkey.pem if type nginx; then