def _verify_jws(self, payload, key): """ Verify the given JWS payload with the given key and return the payload. """ jws = JWS.from_compact(payload) try: alg = jws.signature.combined.alg.name except KeyError: msg = 'No alg value found in header' raise SuspiciousOperation(msg) if alg != self.OIDC_RP_SIGN_ALGO: msg = "The provider algorithm {!r} does not match the client's " \ "OIDC_RP_SIGN_ALGO.".format(alg) raise SuspiciousOperation(msg) if isinstance(key, six.string_types): # Use smart_bytes here since the key string comes from settings. jwk = JWK.load(smart_bytes(key)) else: # The key is a json returned from the IDP JWKS endpoint. jwk = JWK.from_json(key) if not jws.verify(jwk): msg = 'JWS token verification failed.' raise SuspiciousOperation(msg) return jws.payload
def cert_to_jwk(certificates: str, public_key: str) -> str: """ coverts a pem public key and a pem certificate chain to a jwk with a x5c element :param certificates: the certificates for the x5c as pem key list :param public_key: the pem public key as string :return: the jwk as string """ # convert public key to jwk public_key = crypto.load_publickey(crypto.FILETYPE_PEM, public_key) jwk = JWK.load(crypto.dump_publickey(crypto.FILETYPE_PEM, public_key)) # covert cert chain to base64 encoded ASN1 according to https://tools.ietf.org/html/rfc7517#section-4.7 x5c = [] for cert in pem.parse(str.encode(certificates)): cert_pem = crypto.load_certificate(crypto.FILETYPE_PEM, cert.as_bytes()) x5c.append( base64.b64encode( crypto.dump_certificate(crypto.FILETYPE_ASN1, cert_pem)).decode()) # dump jwk obj to json and add x5c cer chain jwk_j = jwk.to_json() jwk_j["x5c"] = x5c return json.dumps(jwk_j)
def verify(self, chall: 'KeyAuthorizationChallenge', account_public_key: jose.JWK) -> bool: """Verify the key authorization. :param KeyAuthorization chall: Challenge that corresponds to this response. :param JWK account_public_key: :return: ``True`` iff verification of the key authorization was successful. :rtype: bool """ parts = self.key_authorization.split('.') # pylint: disable=no-member if len(parts) != 2: logger.debug("Key authorization (%r) is not well formed", self.key_authorization) return False if parts[0] != chall.encode("token"): logger.debug( "Mismatching token in key authorization: " "%r instead of %r", parts[0], chall.encode("token")) return False thumbprint = jose.b64encode( account_public_key.thumbprint( hash_function=self.thumbprint_hash_function)).decode() if parts[1] != thumbprint: logger.debug( "Mismatching thumbprint in key authorization: " "%r instead of %r", parts[0], thumbprint) return False return True
def key_authorization(self, account_key: jose.JWK) -> str: """Generate Key Authorization. :param JWK account_key: :rtype str: """ return self.encode("token") + "." + jose.b64encode( account_key.thumbprint( hash_function=self.thumbprint_hash_function)).decode()
def from_data(cls, account_public_key: jose.JWK, kid: str, hmac_key: str, directory: Directory) -> Dict[str, Any]: """Create External Account Binding Resource from contact details, kid and hmac.""" key_json = json.dumps(account_public_key.to_partial_json()).encode() decoded_hmac_key = jose.b64.b64decode(hmac_key) url = directory["newAccount"] eab = jws.JWS.sign(key_json, jose.jwk.JWKOct(key=decoded_hmac_key), jose.jwa.HS256, None, url, kid) return eab.to_partial_json()
def decode_jws( payload: bytes, key: dict, expected_algorithm: str, verify: bool = True ) -> dict: jws = JWS.from_compact(payload) if verify: try: alg = jws.signature.combined.alg.name except KeyError as exc: raise OIDCError("No alg value found in header") from exc if alg != expected_algorithm: raise OIDCError( f"Algorithm mismatch: offered {alg} is not expected {expected_algorithm}" ) jwk = JWK.from_json(key) if not jws.verify(jwk): raise OIDCError("JWS token verification failed.") return jws.payload
def sign(cls, payload: bytes, key: josepy.JWK, alg: josepy.JWASignature, include_jwk: bool = True, protect: FrozenSet = frozenset(), **kwargs: Any) -> 'Signature': """Sign. :param bytes payload: Payload to sign. :param JWK key: Key for signature. :param JWASignature alg: Signature algorithm to use to sign. :param bool include_jwk: If True, insert the JWK inside the signature headers. :param FrozenSet protect: List of headers to protect. """ assert isinstance(key, alg.kty) header_params = kwargs header_params['alg'] = alg if include_jwk: header_params['jwk'] = key.public_key() assert set(header_params).issubset(cls.header_cls._fields) assert protect.issubset(cls.header_cls._fields) protected_params = {} for header in protect: if header in header_params: protected_params[header] = header_params.pop(header) if protected_params: protected = cls.header_cls(**protected_params).json_dumps() else: protected = '' header = cls.header_cls(**header_params) signature = alg.sign(key.key, cls._msg(protected, payload)) return cls(protected=protected, header=header, signature=signature)
def pem_to_jwk(pem): return JWK.load(pem)