Source code for letsencrypt.proof_of_possession

"""Proof of Possession Identifier Validation Challenge."""
import logging
import os

from cryptography import x509
from cryptography.hazmat.backends import default_backend
import zope.component

from acme import challenges
from acme import jose
from acme import other

from letsencrypt import interfaces
from letsencrypt.display import util as display_util


logger = logging.getLogger(__name__)


[docs]class ProofOfPossession(object): # pylint: disable=too-few-public-methods """Proof of Possession Identifier Validation Challenge. Based on draft-barnes-acme, section 6.5. :ivar installer: Installer object :type installer: :class:`~letsencrypt.interfaces.IInstaller` """ def __init__(self, installer): self.installer = installer
[docs] def perform(self, achall): """Perform the Proof of Possession Challenge. :param achall: Proof of Possession Challenge :type achall: :class:`letsencrypt.achallenges.ProofOfPossession` :returns: Response or None/False if the challenge cannot be completed :rtype: :class:`acme.challenges.ProofOfPossessionResponse` or False """ if (achall.alg in [jose.HS256, jose.HS384, jose.HS512] or not isinstance(achall.hints.jwk, achall.alg.kty)): return None for cert, key, _ in self.installer.get_all_certs_keys(): with open(cert) as cert_file: cert_data = cert_file.read() try: cert_obj = x509.load_pem_x509_certificate( cert_data, default_backend()) except ValueError: try: cert_obj = x509.load_der_x509_certificate( cert_data, default_backend()) except ValueError: logger.warn("Certificate is neither PER nor DER: %s", cert) cert_key = achall.alg.kty(key=cert_obj.public_key()) if cert_key == achall.hints.jwk: return self._gen_response(achall, key) # Is there are different prompt we should give the user? code, key = zope.component.getUtility( interfaces.IDisplay).input( "Path to private key for identifier: %s " % achall.domain) if code != display_util.CANCEL: return self._gen_response(achall, key) # If we get here, the key wasn't found return False
[docs] def _gen_response(self, achall, key_path): # pylint: disable=no-self-use """Create the response to the Proof of Possession Challenge. :param achall: Proof of Possession Challenge :type achall: :class:`letsencrypt.achallenges.ProofOfPossession` :param str key_path: Path to the key corresponding to the hinted to public key. :returns: Response or False if the challenge cannot be completed :rtype: :class:`acme.challenges.ProofOfPossessionResponse` or False """ if os.path.isfile(key_path): with open(key_path, 'rb') as key: try: # Needs to be changed if JWKES doesn't have a key attribute jwk = achall.alg.kty.load(key.read()) sig = other.Signature.from_msg(achall.nonce, jwk.key, alg=achall.alg) except (IndexError, ValueError, TypeError, jose.errors.Error): return False return challenges.ProofOfPossessionResponse(nonce=achall.nonce, signature=sig) return False