class ChallengeBody(ResourceBody):
    """Challenge Resource Body.

    .. todo::
       Confusingly, this has a similar name to `.challenges.Challenge`,
       as well as `.achallenges.AnnotatedChallenge`. Please use names
       such as ``challb`` to distinguish instances of this class from
       ``achall``.

    :ivar letsencrypt.acme.challenges.Challenge: Wrapped challenge.
        Conveniently, all challenge fields are proxied, i.e. you can
        call ``challb.x`` to get ``challb.chall.x`` contents.
    :ivar letsencrypt.acme.messages2.Status status:
    :ivar datetime.datetime validated:

    """
    __slots__ = ('chall',)
    uri = jose.Field('uri')
    status = jose.Field('status', decoder=Status.from_json)
    validated = fields.RFC3339Field('validated', omitempty=True)

    def to_partial_json(self):
        jobj = super(ChallengeBody, self).to_partial_json()
        jobj.update(self.chall.to_partial_json())
        return jobj

    @classmethod
    def fields_from_json(cls, jobj):
        jobj_fields = super(ChallengeBody, cls).fields_from_json(jobj)
        jobj_fields['chall'] = challenges.Challenge.from_json(jobj)
        return jobj_fields

    def __getattr__(self, name):
        return getattr(self.chall, name)
Esempio n. 2
0
class ChallengeBody(ResourceBody):
    """Challenge Resource Body.

    .. todo::
       Confusingly, this has a similar name to `.challenges.Challenge`,
       as well as `.achallenges.AnnotatedChallenge` or
       `.achallenges.Indexed`... Once `messages2` and `network2` is
       integrated with the rest of the client, this class functionality
       will be merged with `.challenges.Challenge`. Meanwhile,
       separation allows the ``master`` to be still interoperable with
       Node.js server (protocol v00). For the time being use names such
       as ``challb`` to distinguish instances of this class from
       ``achall`` or ``ichall``.

    :ivar letsencrypt.acme.messages2.Status status:
    :ivar datetime.datetime validated:

    """

    __slots__ = ('chall', )
    uri = jose.Field('uri')
    status = jose.Field('status', decoder=Status.from_json)
    validated = fields.RFC3339Field('validated', omitempty=True)

    def to_partial_json(self):
        jobj = super(ChallengeBody, self).to_partial_json()
        jobj.update(self.chall.to_partial_json())
        return jobj

    @classmethod
    def fields_from_json(cls, jobj):
        jobj_fields = super(ChallengeBody, cls).fields_from_json(jobj)
        jobj_fields['chall'] = challenges.Challenge.from_json(jobj)
        return jobj_fields
Esempio n. 3
0
class RecoveryContact(ContinuityChallenge):
    """ACME "recoveryContact" challenge."""
    typ = "recoveryContact"

    activation_url = jose.Field("activationURL", omitempty=True)
    success_url = jose.Field("successURL", omitempty=True)
    contact = jose.Field("contact", omitempty=True)
Esempio n. 4
0
class Certificate(Message):
    """ACME "certificate" message.

    :ivar certificate: The certificate (:class:`M2Crypto.X509.X509`
        wrapped in :class:`letsencrypt.acme.util.ComparableX509`).

    :ivar list chain: Chain of certificates (:class:`M2Crypto.X509.X509`
        wrapped in :class:`letsencrypt.acme.util.ComparableX509` ).

    """
    typ = "certificate"
    schema = util.load_schema(typ)

    certificate = jose.Field("certificate",
                             encoder=jose.encode_cert,
                             decoder=jose.decode_cert)
    chain = jose.Field("chain", omitempty=True, default=())
    refresh = jose.Field("refresh", omitempty=True)

    @chain.decoder
    def chain(value):  # pylint: disable=missing-docstring,no-self-argument
        return tuple(jose.decode_cert(cert) for cert in value)

    @chain.encoder
    def chain(value):  # pylint: disable=missing-docstring,no-self-argument
        return tuple(jose.encode_cert(cert) for cert in value)
Esempio n. 5
0
class Challenge(Message):
    """ACME "challenge" message.

    :ivar str nonce: Random data, **not** base64-encoded.
    :ivar list challenges: List of
        :class:`~letsencrypt.acme.challenges.Challenge` objects.

    .. todo::
        1. can challenges contain two challenges of the same type?
        2. can challenges contain duplicates?
        3. check "combinations" indices are in valid range
        4. turn "combinations" elements into sets?
        5. turn "combinations" into set?

    """
    typ = "challenge"
    schema = util.load_schema(typ)

    session_id = jose.Field("sessionID")
    nonce = jose.Field("nonce",
                       encoder=jose.b64encode,
                       decoder=jose.decode_b64jose)
    challenges = jose.Field("challenges")
    combinations = jose.Field("combinations", omitempty=True, default=())

    @challenges.decoder
    def challenges(value):  # pylint: disable=missing-docstring,no-self-argument
        return tuple(challenges.Challenge.from_json(chall) for chall in value)

    @property
    def resolved_combinations(self):
        """Combinations with challenges instead of indices."""
        return tuple(
            tuple(self.challenges[idx] for idx in combo)
            for combo in self.combinations)
Esempio n. 6
0
class DVSNI(DVChallenge):
    """ACME "dvsni" challenge.

    :ivar str r: Random data, **not** base64-encoded.
    :ivar str nonce: Random data, **not** hex-encoded.

    """
    typ = "dvsni"

    DOMAIN_SUFFIX = ".acme.invalid"
    """Domain name suffix."""

    R_SIZE = 32
    """Required size of the :attr:`r` in bytes."""

    NONCE_SIZE = 16
    """Required size of the :attr:`nonce` in bytes."""

    r = jose.Field(
        "r",
        encoder=jose.b64encode,  # pylint: disable=invalid-name
        decoder=functools.partial(jose.decode_b64jose, size=R_SIZE))
    nonce = jose.Field("nonce",
                       encoder=binascii.hexlify,
                       decoder=functools.partial(
                           functools.partial(jose.decode_hex16,
                                             size=NONCE_SIZE)))

    @property
    def nonce_domain(self):
        """Domain name used in SNI."""
        return binascii.hexlify(self.nonce) + self.DOMAIN_SUFFIX
Esempio n. 7
0
class Defer(Message):
    """ACME "defer" message."""
    typ = "defer"
    schema = util.load_schema(typ)

    token = jose.Field("token")
    interval = jose.Field("interval", omitempty=True)
    message = jose.Field("message", omitempty=True)
Esempio n. 8
0
class Identifier(jose.JSONObjectWithFields):
    """ACME identifier.

    :ivar letsencrypt.acme.messages2.IdentifierType typ:

    """
    typ = jose.Field('type', decoder=IdentifierType.from_json)
    value = jose.Field('value')
Esempio n. 9
0
class CertificateRequest(jose.JSONObjectWithFields):
    """ACME new-cert request.

    :ivar letsencrypt.acme.jose.util.ComparableX509 csr:
        `M2Crypto.X509.Request` wrapped in `.ComparableX509`
    :ivar tuple authorizations: `tuple` of URIs (`str`)

    """
    csr = jose.Field('csr', decoder=jose.decode_csr, encoder=jose.encode_csr)
    authorizations = jose.Field('authorizations', decoder=tuple)
 class MockMessage(MockParentMessage):
     typ = 'test'
     schema = {
         'type': 'object',
         'properties': {
             'price': {'type': 'number'},
             'name': {'type': 'string'},
         },
     }
     price = jose.Field('price')
     name = jose.Field('name')
Esempio n. 11
0
class Authorization(Message):
    """ACME "authorization" message.

    :ivar jwk: :class:`letsencrypt.acme.jose.JWK`

    """
    typ = "authorization"
    schema = util.load_schema(typ)

    recovery_token = jose.Field("recoveryToken", omitempty=True)
    identifier = jose.Field("identifier", omitempty=True)
    jwk = jose.Field("jwk", decoder=jose.JWK.from_json, omitempty=True)
Esempio n. 12
0
class Registration(ResourceBody):
    """Registration Resource Body.

    :ivar letsencrypt.acme.jose.jwk.JWK key: Public key.
    :ivar tuple contact: Contact information following ACME spec

    """
    # on new-reg key server ignores 'key' and populates it based on
    # JWS.signature.combined.jwk
    key = jose.Field('key', omitempty=True, decoder=jose.JWK.from_json)
    contact = jose.Field('contact', omitempty=True, default=())
    recovery_token = jose.Field('recoveryToken', omitempty=True)
    agreement = jose.Field('agreement', omitempty=True)
Esempio n. 13
0
class ProofOfPossession(ContinuityChallenge):
    """ACME "proofOfPossession" challenge.

    :ivar str nonce: Random data, **not** base64-encoded.
    :ivar hints: Various clues for the client (:class:`Hints`).

    """
    typ = "proofOfPossession"

    NONCE_SIZE = 16

    class Hints(jose.JSONObjectWithFields):
        """Hints for "proofOfPossession" challenge.

        :ivar jwk: JSON Web Key (:class:`letsencrypt.acme.jose.JWK`)
        :ivar list certs: List of :class:`letsencrypt.acme.jose.ComparableX509`
            certificates.

        """
        jwk = jose.Field("jwk", decoder=jose.JWK.from_json)
        cert_fingerprints = jose.Field("certFingerprints",
                                       omitempty=True,
                                       default=())
        certs = jose.Field("certs", omitempty=True, default=())
        subject_key_identifiers = jose.Field("subjectKeyIdentifiers",
                                             omitempty=True,
                                             default=())
        serial_numbers = jose.Field("serialNumbers",
                                    omitempty=True,
                                    default=())
        issuers = jose.Field("issuers", omitempty=True, default=())
        authorized_for = jose.Field("authorizedFor",
                                    omitempty=True,
                                    default=())

        @certs.encoder
        def certs(value):  # pylint: disable=missing-docstring,no-self-argument
            return tuple(jose.encode_cert(cert) for cert in value)

        @certs.decoder
        def certs(value):  # pylint: disable=missing-docstring,no-self-argument
            return tuple(jose.decode_cert(cert) for cert in value)

    alg = jose.Field("alg", decoder=jose.JWASignature.from_json)
    nonce = jose.Field("nonce",
                       encoder=jose.b64encode,
                       decoder=functools.partial(jose.decode_b64jose,
                                                 size=NONCE_SIZE))
    hints = jose.Field("hints", decoder=Hints.from_json)
Esempio n. 14
0
class Revocation(jose.JSONObjectWithFields):
    """Revocation message.

    :ivar revoke: Either a `datetime.datetime` or `Revocation.NOW`.
    :ivar tuple authorizations: Same as `CertificateRequest.authorizations`

    """

    NOW = 'now'
    """A possible value for `revoke`, denoting that certificate should
    be revoked now."""

    revoke = jose.Field('revoke')
    authorizations = CertificateRequest._fields['authorizations']

    @revoke.decoder
    def revoke(value):  # pylint: disable=missing-docstring,no-self-argument
        if value == Revocation.NOW:
            return value
        else:
            return fields.RFC3339Field.default_decoder(value)

    @revoke.encoder
    def revoke(value):  # pylint: disable=missing-docstring,no-self-argument
        if value == Revocation.NOW:
            return value
        else:
            return fields.RFC3339Field.default_encoder(value)
Esempio n. 15
0
class RevocationRequest(Message):
    """ACME "revocationRequest" message.

    :ivar certificate: Certificate (:class:`M2Crypto.X509.X509`
        wrapped in :class:`letsencrypt.acme.util.ComparableX509`).
    :ivar signature: Signature (:class:`letsencrypt.acme.other.Signature`).

    """
    typ = "revocationRequest"
    schema = util.load_schema(typ)

    certificate = jose.Field("certificate",
                             decoder=jose.decode_cert,
                             encoder=jose.encode_cert)
    signature = jose.Field("signature", decoder=other.Signature.from_json)

    @classmethod
    def create(cls, key, sig_nonce=None, **kwargs):
        """Create signed "revocationRequest".

        :param key: Key used for signing.
        :type key: :class:`Crypto.PublicKey.RSA`

        :param str sig_nonce: Nonce used for signature. Useful for testing.
        :kwargs: Any other arguments accepted by the class constructor.

        :returns: Signed "revocationRequest" ACME message.
        :rtype: :class:`RevocationRequest`

        """
        return cls(signature=other.Signature.from_msg(
            kwargs["certificate"].as_der(), key, sig_nonce),
                   **kwargs)

    def verify(self):
        """Verify signature.

        .. warning:: Caller must check that the public key encoded in the
            :attr:`signature`'s :class:`letsencrypt.acme.jose.JWK` object
            is the correct key for a given context.

        :returns: True iff ``signature`` can be verified, False otherwise.
        :rtype: bool

        """
        # self.signature is not Field | pylint: disable=no-member
        return self.signature.verify(self.certificate.as_der())
Esempio n. 16
0
class Error(jose.JSONObjectWithFields, Exception):
    """ACME error.

    https://tools.ietf.org/html/draft-ietf-appsawg-http-problem-00

    """
    ERROR_TYPE_NAMESPACE = 'urn:acme:error:'
    ERROR_TYPE_DESCRIPTIONS = {
        'malformed': 'The request message was malformed',
        'unauthorized': 'The client lacks sufficient authorization',
        'serverInternal': 'The server experienced an internal error',
        'badCSR': 'The CSR is unacceptable (e.g., due to a short key)',
    }

    # TODO: Boulder omits 'type' and 'instance', spec requires, boulder#128
    typ = jose.Field('type', omitempty=True)
    title = jose.Field('title', omitempty=True)
    detail = jose.Field('detail')
    instance = jose.Field('instance', omitempty=True)

    @typ.encoder
    def typ(value):  # pylint: disable=missing-docstring,no-self-argument
        return Error.ERROR_TYPE_NAMESPACE + value

    @typ.decoder
    def typ(value):  # pylint: disable=missing-docstring,no-self-argument
        # pylint thinks isinstance(value, Error), so startswith is not found
        # pylint: disable=no-member
        if not value.startswith(Error.ERROR_TYPE_NAMESPACE):
            raise jose.DeserializationError('Missing error type prefix')

        without_prefix = value[len(Error.ERROR_TYPE_NAMESPACE):]
        if without_prefix not in Error.ERROR_TYPE_DESCRIPTIONS:
            raise jose.DeserializationError('Error type not recognized')

        return without_prefix

    @property
    def description(self):
        """Hardcoded error description based on its type."""
        return self.ERROR_TYPE_DESCRIPTIONS[self.typ]

    def __str__(self):
        if self.typ is not None:
            return ' :: '.join([self.typ, self.description, self.detail])
        else:
            return str(self.detail)
Esempio n. 17
0
class Error(Message):
    """ACME "error" message."""
    typ = "error"
    schema = util.load_schema(typ)

    error = jose.Field("error")
    message = jose.Field("message", omitempty=True)
    more_info = jose.Field("moreInfo", omitempty=True)

    MESSAGE_CODES = {
        "malformed": "The request message was malformed",
        "unauthorized": "The client lacks sufficient authorization",
        "serverInternal": "The server experienced an internal error",
        "notSupported": "The request type is not supported",
        "unknown": "The server does not recognize an ID/token in the request",
        "badCSR": "The CSR is unacceptable (e.g., due to a short key)",
    }
Esempio n. 18
0
    class Hints(jose.JSONObjectWithFields):
        """Hints for "proofOfPossession" challenge.

        :ivar jwk: JSON Web Key (:class:`letsencrypt.acme.jose.JWK`)
        :ivar list certs: List of :class:`letsencrypt.acme.jose.ComparableX509`
            certificates.

        """
        jwk = jose.Field("jwk", decoder=jose.JWK.from_json)
        cert_fingerprints = jose.Field("certFingerprints",
                                       omitempty=True,
                                       default=())
        certs = jose.Field("certs", omitempty=True, default=())
        subject_key_identifiers = jose.Field("subjectKeyIdentifiers",
                                             omitempty=True,
                                             default=())
        serial_numbers = jose.Field("serialNumbers",
                                    omitempty=True,
                                    default=())
        issuers = jose.Field("issuers", omitempty=True, default=())
        authorized_for = jose.Field("authorizedFor",
                                    omitempty=True,
                                    default=())

        @certs.encoder
        def certs(value):  # pylint: disable=missing-docstring,no-self-argument
            return tuple(jose.encode_cert(cert) for cert in value)

        @certs.decoder
        def certs(value):  # pylint: disable=missing-docstring,no-self-argument
            return tuple(jose.decode_cert(cert) for cert in value)
Esempio n. 19
0
class ProofOfPossessionResponse(ChallengeResponse):
    """ACME "proofOfPossession" challenge response.

    :ivar str nonce: Random data, **not** base64-encoded.
    :ivar signature: :class:`~letsencrypt.acme.other.Signature` of this message.

    """
    typ = "proofOfPossession"

    NONCE_SIZE = ProofOfPossession.NONCE_SIZE

    nonce = jose.Field(
        "nonce", encoder=jose.b64encode, decoder=functools.partial(
            jose.decode_b64jose, size=NONCE_SIZE))
    signature = jose.Field("signature", decoder=other.Signature.from_json)

    def verify(self):
        """Verify the challenge."""
        # self.signature is not Field | pylint: disable=no-member
        return self.signature.verify(self.nonce)
Esempio n. 20
0
class Authorization(ResourceBody):
    """Authorization Resource Body.

    :ivar letsencrypt.acme.messages2.Identifier identifier:
    :ivar list challenges: `list` of `Challenge`
    :ivar tuple combinations: Challenge combinations (`tuple` of `tuple`
        of `int`, as opposed to `list` of `list` from the spec).
    :ivar letsencrypt.acme.jose.jwk.JWK key: Public key.
    :ivar tuple contact:
    :ivar letsencrypt.acme.messages2.Status status:
    :ivar datetime.datetime expires:

    """

    identifier = jose.Field('identifier', decoder=Identifier.from_json)
    challenges = jose.Field('challenges', omitempty=True)
    combinations = jose.Field('combinations', omitempty=True)

    # TODO: acme-spec #92, #98
    key = Registration._fields['key']
    contact = Registration._fields['contact']

    status = jose.Field('status', omitempty=True, decoder=Status.from_json)
    # TODO: 'expires' is allowed for Authorization Resources in
    # general, but for Key Authorization '[t]he "expires" field MUST
    # be absent'... then acme-spec gives example with 'expires'
    # present... That's confusing!
    expires = fields.RFC3339Field('expires', omitempty=True)

    @challenges.decoder
    def challenges(value):  # pylint: disable=missing-docstring,no-self-argument
        return tuple(ChallengeBody.from_json(chall) for chall in value)

    @property
    def resolved_combinations(self):
        """Combinations with challenges instead of indices."""
        return tuple(
            tuple(self.challenges[idx] for idx in combo)
            for combo in self.combinations)
Esempio n. 21
0
class SimpleHTTPSResponse(ChallengeResponse):
    """ACME "simpleHttps" challenge response."""
    typ = "simpleHttps"
    path = jose.Field("path")

    URI_TEMPLATE = "https://{domain}/.well-known/acme-challenge/{path}"
    """URI template for HTTPS server provisioned resource."""
    def uri(self, domain):
        """Create an URI to the provisioned resource.

        Forms an URI to the HTTPS server provisioned resource (containing
        :attr:`~SimpleHTTPS.token`) by populating the :attr:`URI_TEMPLATE`.

        :param str domain: Domain name being verified.

        """
        return self.URI_TEMPLATE.format(domain=domain, path=self.path)
Esempio n. 22
0
class DVSNIResponse(ChallengeResponse):
    """ACME "dvsni" challenge response.

    :param str s: Random data, **not** base64-encoded.

    """
    typ = "dvsni"

    DOMAIN_SUFFIX = DVSNI.DOMAIN_SUFFIX
    """Domain name suffix."""

    S_SIZE = 32
    """Required size of the :attr:`s` in bytes."""

    s = jose.Field(
        "s",
        encoder=jose.b64encode,  # pylint: disable=invalid-name
        decoder=functools.partial(jose.decode_b64jose, size=S_SIZE))

    def __init__(self, s=None, *args, **kwargs):
        s = Crypto.Random.get_random_bytes(self.S_SIZE) if s is None else s
        super(DVSNIResponse, self).__init__(s=s, *args, **kwargs)

    def z(self, chall):  # pylint: disable=invalid-name
        """Compute the parameter ``z``.

        :param challenge: Corresponding challenge.
        :type challenge: :class:`DVSNI`

        """
        z = hashlib.new("sha256")  # pylint: disable=invalid-name
        z.update(chall.r)
        z.update(self.s)
        return z.hexdigest()

    def z_domain(self, chall):
        """Domain name for certificate subjectAltName."""
        return self.z(chall) + self.DOMAIN_SUFFIX
Esempio n. 23
0
class AuthorizationRequest(Message):
    """ACME "authorizationRequest" message.

    :ivar str nonce: Random data from the corresponding
        :attr:`Challenge.nonce`, **not** base64-encoded.
    :ivar list responses: List of completed challenges (
        :class:`letsencrypt.acme.challenges.ChallengeResponse`).
    :ivar signature: Signature (:class:`letsencrypt.acme.other.Signature`).

    """
    typ = "authorizationRequest"
    schema = util.load_schema(typ)

    session_id = jose.Field("sessionID")
    nonce = jose.Field("nonce",
                       encoder=jose.b64encode,
                       decoder=jose.decode_b64jose)
    responses = jose.Field("responses")
    signature = jose.Field("signature", decoder=other.Signature.from_json)
    contact = jose.Field("contact", omitempty=True, default=())

    @responses.decoder
    def responses(value):  # pylint: disable=missing-docstring,no-self-argument
        return tuple(
            challenges.ChallengeResponse.from_json(chall) for chall in value)

    @classmethod
    def create(cls, name, key, sig_nonce=None, **kwargs):
        """Create signed "authorizationRequest".

        :param str name: Hostname

        :param key: Key used for signing.
        :type key: :class:`Crypto.PublicKey.RSA`

        :param str sig_nonce: Nonce used for signature. Useful for testing.
        :kwargs: Any other arguments accepted by the class constructor.

        :returns: Signed "authorizationRequest" ACME message.
        :rtype: :class:`AuthorizationRequest`

        """
        # pylint: disable=too-many-arguments
        signature = other.Signature.from_msg(name + kwargs["nonce"], key,
                                             sig_nonce)
        return cls(signature=signature,
                   contact=kwargs.pop("contact", ()),
                   **kwargs)

    def verify(self, name):
        """Verify signature.

        .. warning:: Caller must check that the public key encoded in the
            :attr:`signature`'s :class:`letsencrypt.acme.jose.JWK` object
            is the correct key for a given context.

        :param str name: Hostname

        :returns: True iff ``signature`` can be verified, False otherwise.
        :rtype: bool

        """
        # self.signature is not Field | pylint: disable=no-member
        return self.signature.verify(name + self.nonce)
Esempio n. 24
0
class ChallengeRequest(Message):
    """ACME "challengeRequest" message."""
    typ = "challengeRequest"
    schema = util.load_schema(typ)
    identifier = jose.Field("identifier")
Esempio n. 25
0
class SimpleHTTPS(DVChallenge):
    """ACME "simpleHttps" challenge."""
    typ = "simpleHttps"
    token = jose.Field("token")
Esempio n. 26
0
class DNS(DVChallenge):
    """ACME "dns" challenge."""
    typ = "dns"
    token = jose.Field("token")
Esempio n. 27
0
class Signature(jose.JSONObjectWithFields):
    """ACME signature.

    :ivar str alg: Signature algorithm.
    :ivar str sig: Signature.
    :ivar str nonce: Nonce.

    :ivar jwk: JWK.
    :type jwk: :class:`JWK`

    """
    NONCE_SIZE = 16
    """Minimum size of nonce in bytes."""

    alg = jose.Field('alg', decoder=jose.JWASignature.from_json)
    sig = jose.Field('sig',
                     encoder=jose.b64encode,
                     decoder=jose.decode_b64jose)
    nonce = jose.Field('nonce',
                       encoder=jose.b64encode,
                       decoder=functools.partial(jose.decode_b64jose,
                                                 size=NONCE_SIZE,
                                                 minimum=True))
    jwk = jose.Field('jwk', decoder=jose.JWK.from_json)

    @classmethod
    def from_msg(cls, msg, key, nonce=None, nonce_size=None, alg=jose.RS256):
        """Create signature with nonce prepended to the message.

        .. todo:: Protect against crypto unicode errors... is this sufficient?
            Do I need to escape?

        :param str msg: Message to be signed.

        :param key: Key used for signing.
        :type key: :class:`Crypto.PublicKey.RSA`

        :param str nonce: Nonce to be used. If None, nonce of
            ``nonce_size`` will be randomly generated.
        :param int nonce_size: Size of the automatically generated nonce.
            Defaults to :const:`NONCE_SIZE`.

        """
        nonce_size = cls.NONCE_SIZE if nonce_size is None else nonce_size
        if nonce is None:
            nonce = Crypto.Random.get_random_bytes(nonce_size)

        msg_with_nonce = nonce + msg
        sig = alg.sign(key, nonce + msg)
        logging.debug('%s signed as %s', msg_with_nonce, sig)

        return cls(alg=alg,
                   sig=sig,
                   nonce=nonce,
                   jwk=alg.kty(key=key.publickey()))

    def verify(self, msg):
        """Verify the signature.

        :param str msg: Message that was used in signing.

        """
        # self.alg is not Field, but JWA | pylint: disable=no-member
        return self.alg.verify(self.jwk.key, self.nonce + msg, self.sig)
Esempio n. 28
0
class StatusRequest(Message):
    """ACME "statusRequest" message."""
    typ = "statusRequest"
    schema = util.load_schema(typ)
    token = jose.Field("token")
Esempio n. 29
0
class RecoveryTokenResponse(ChallengeResponse):
    """ACME "recoveryToken" challenge response."""
    typ = "recoveryToken"
    token = jose.Field("token", omitempty=True)