def verify_proof_chain(did, did_document, proof_chain): #--------------Verify sha-256 in the last proof---------- document_sha256 = hashlib.sha256() document_sha256.update(json.dumps(did_document).encode('utf-8')) document_sha256_b64 = base64url_encode(document_sha256.digest()) last_proof = jws.JWS() last_proof.deserialize(proof_chain[-1]) payload = json.loads(last_proof.objects['payload'].decode()) if (document_sha256_b64 != payload['sha-256']): raise Exception("The sha-256 included in the proof is not valid") return -1 #--------------Verify the chain of trust--------------- _did = did signer_jwk = did_to_jwk( did) #----The fist proof must be verified using the DID for proof in proof_chain: claimed_proof = jws.JWS() claimed_proof.deserialize(proof) payload = json.loads(claimed_proof.objects['payload'].decode()) _id = payload['id'] if (_id != _did): #----All proofs must include DID in their id field raise Exception("A proof contains an invalid id") return -1 claimed_proof.verify(signer_jwk) if ('controller' in payload): signer_jwk = jwk.JWK(**payload[ 'controller']) #----The next proof must be verified with this return True
def verifyJWS(json_JWS): def verify(jws, header): try: sign_key = jwk.JWK(**header["jwk"]) jws.verify(sign_key) return True except Exception as e: debug_log.info(repr(e)) try: json_web_signature = jws.JWS() if (isinstance(json_JWS, dict)): json_web_signature.deserialize(dumps(json_JWS)) elif (isinstance(json_JWS, str)): json_web_signature = jws.JWS(json_JWS) json_JWS = loads(json_JWS) if json_JWS.get("header", False): # Only one signature if (verify(json_web_signature, json_JWS["header"])): return True return False elif json_JWS.get("signatures", False): # Multiple signatures signatures = json_JWS["signatures"] for signature in signatures: if (verify(json_web_signature, signature["header"])): return True return False except Exception as e: debug_log.info("M:", repr(e)) return False
def test_jws_loopback(self): sign = jws.JWS(payload='message') sign.add_signature(jwk.JWK(kty='oct', k=base64url_encode(b'A' * 16)), alg="HS512") o = sign.serialize() check = jws.JWS() check.deserialize(o, jwk.JWK(kty='oct', k=base64url_encode(b'A' * 16)), alg="HS512") self.assertTrue(check.objects['valid'])
def decode_message(logger, message): """ decode jwstoken and return header, payload and signature """ logger.debug('decode_message()') jwstoken = jws.JWS() result = False error = None try: jwstoken.deserialize(message) protected = json.loads(jwstoken.objects['protected']) if bool(jwstoken.objects['payload']): payload = json.loads(jwstoken.objects['payload']) else: payload = {} signature = jwstoken.objects['signature'] result = True except BaseException as err: logger.error('decode_message() err: {0}'.format(err)) error = str(err) protected = {} payload = {} signature = None if payload: payload = dkeys_lower(payload) return (result, error, protected, payload, signature)
def generate_db_auth_code_context(client_secret=None): # --> Generate a valid authorization code client_data, user_data = test_utils.add_user_client_context_to_db() db_auth_code = models.AuthorisationCode(application_id=client_data[0]['id']) db.session.add(db_auth_code) db.session.commit() assert db_auth_code.id # --> Create an appropriate payload to be signed in now = datetime.utcnow() before = now - timedelta(seconds=10) payload = { 'client_id': client_data[0]['id'], 'redirect_uri': client_data[0]['redirect_uri'], 'expiration_date': before.strftime("%d-%m-%Y %H:%M:%S"), 'code_id': db_auth_code.id } # --> Sign the payload and generate the JWS authorization code jws_obj = jws.JWS(json.dumps(payload).encode(config.Config.AUTH_CODE_ENCODING)) private_key = jwk.JWK.from_json(config.Config.private_jwk) jws_obj.add_signature(private_key, None, json.dumps({"alg": config.Config.JWT_ALGORITHM})) post_data = { 'grand_type': 'authorization_code', 'client_secret': client_data[0]['client_secret'] if not client_secret else client_secret, 'code': jws_obj.serialize(compact=True) } return post_data, client_data, db_auth_code
def test_should_throw_exception_when_jws_signature_has_expired(self): localDir = os.path.abspath(os.path.dirname(__file__)) clientPath = os.path.join(localDir, 'resources', 'private-jwkset1') hyperwalletPath = '/public-jwkset1' encryption = Encryption(clientPath, hyperwalletPath) jwsKeySet = self.__getJwkKeySet(location=clientPath) jwkSignKey = self.__findJwkKeyByAlgorithm(jwkKeySet=jwsKeySet, algorithm='RS256') privateKeyToSign = jwk.JWK(**jwkSignKey) body = "Test message" jwsToken = cryptoJWS.JWS(body.encode('utf-8')) jwsToken.add_signature( privateKeyToSign, None, json_encode({ "alg": "RS256", "exp": int(time.time()) - 6000, "kid": jwkSignKey['kid'] })) signedBody = jwsToken.serialize(True) with self.assertRaises(HyperwalletException) as exc: encryption.checkJwsExpiration(signedBody) self.assertEqual( exc.exception.message, 'JWS signature has expired, checked by [exp] JWS header')
def encrypt(self, body=None): ''' :param body: Body message to be 1) signed and 2) encrypted. **REQUIRED** :returns: String as a result of signature and encryption of input message body ''' jwsKeySet = self.__getJwkKeySet(location = self.clientPrivateKeySetLocation) jwkSignKey = self.__findJwkKeyByAlgorithm(jwkKeySet = jwsKeySet, algorithm = self.signAlgorithm) privateKeyToSign = jwk.JWK(**jwkSignKey) jwsToken = cryptoJWS.JWS(body.encode('utf-8')) jwsToken.add_signature(privateKeyToSign, None, json_encode({ "alg": self.signAlgorithm, "kid": jwkSignKey['kid'], "exp": self.__getJwsExpirationTime() })) signedBody = jwsToken.serialize(True) jweKeySet = self.__getJwkKeySet(location = self.hyperwalletKeySetLocation) jwkEncryptKey = self.__findJwkKeyByAlgorithm(jwkKeySet = jweKeySet, algorithm = self.encryptionAlgorithm) publicKeyToEncrypt = jwk.JWK(**jwkEncryptKey) protected_header = { "alg": self.encryptionAlgorithm, "enc": self.encryptionMethod, "typ": "JWE", "kid": jwkEncryptKey['kid'], } jweToken = jwe.JWE(signedBody.encode('utf-8'), recipient=publicKeyToEncrypt, protected=protected_header) return jweToken.serialize(True)
def test_4_8_signing(self): plaintext = base64url_decode(Payload_plaintext_b64_4) S = jws.JWS(payload=plaintext) # 4_8_2 protected = \ base64url_decode(JWS_Protected_Header_4_8_2).decode('utf-8') header = json_encode(JWS_Unprotected_Header_4_8_2) pri_key = jwk.JWK(**RSA_Private_Key_3_4) S.add_signature(pri_key, None, protected, header) # 4_8_3 header = json_encode(JWS_Unprotected_Header_4_8_3) pri_key = jwk.JWK(**EC_Private_Key_3_2) S.add_signature(pri_key, None, None, header) # 4_8_4 protected = \ base64url_decode(JWS_Protected_Header_4_8_4).decode('utf-8') sym_key = jwk.JWK(**Symmetric_Key_MAC_3_5) S.add_signature(sym_key, None, protected) sig = S.serialize() # Can't compare signature with reference because ECDSA uses # random nonces every time a signature is generated. rsa_key = jwk.JWK(**RSA_Public_Key_3_3) ec_key = jwk.JWK(**EC_Public_Key_3_1) S.deserialize(sig, rsa_key) S.deserialize(sig, ec_key) S.deserialize(sig, sym_key) # Just deserialize each example form S.deserialize(json_encode(JWS_general_4_8_5), rsa_key) S.deserialize(json_encode(JWS_general_4_8_5), ec_key) S.deserialize(json_encode(JWS_general_4_8_5), sym_key)
def verify(self, jwt_raw): web_signature = jws.JWS() # pylint: disable=protected-access web_signature._allowed_algs = ALLOWED_ALGORITHMS web_signature.deserialize(jwt_raw, None, 'ES256K') key_id = web_signature.jose_header['kid'] key_raw = None try: key_raw = self.resolver.resolveKey(key_id) # pylint: disable=broad-except except: return 'Error resolving key from did' if key_raw is None: return 'Error resolving key from did' key = jwk.JWK.from_json(json.dumps(key_raw)) try: web_signature.verify(key) return web_signature.payload # pylint: disable=broad-except except: return 'invalid'
def sign(self, payload, private_key_pem_data, header_json_data): jwstoken = jws.JWS(payload.encode('utf-8')) rsa_private_key = jwk.JWK.from_pem(private_key_pem_data) jwstoken.add_signature(key=rsa_private_key, protected=header_json_data) sign = jwstoken.serialize(compact=True) print("JWS signing successful. serialized data: {}") return sign
def decrypt_and_verify(self, content): # decrypt jwetoken = jwe.JWE() jwetoken.deserialize(content, key=encryption_private_key) if json.loads(jwetoken.objects['protected'])['alg'] != 'RSA-OAEP-256' or json.loads(jwetoken.objects['protected'])['enc'] != 'A256CBC-HS512': raise Exception('Unsupported encryption') # we have to check those, otherwise other encryptions can be used as an attack vector # verify jwstoken = jws.JWS() jwstoken.deserialize(jwetoken.payload) if signature_public_key is None: jku = json.loads(jwstoken.objects['protected'])['jku'] kid = json.loads(jwstoken.objects['protected'])['kid'] #NOTE: to be certain to use a valid public key, one would have to check the # domain name and SSL certificate's Common Name against a whitelisted list keys = requests.get(jku).content keyset = jwk.JWKSet() keyset.import_keyset(keys) verification_key = keyset.get_key(kid) else: verification_key = signature_public_key if json.loads(jwstoken.objects['protected'])['alg'] != 'RS512': raise Exception('Unsupported signature algorithm') # we have to check, otherwise other algorithms can be used as an attack vector jwstoken.verify(verification_key) # if there's no exception, the signature is valid return jwstoken.payload
def _signed_request(self, url: str, payload: dict, kid: str = None) -> requests.Response: p = json.dumps(payload) account_jwk = jwk.JWK.from_pem(self._account.key_pem.encode()) protected = {'alg': 'RS256', 'url': url, 'nonce': self._nonce} if kid is None: protected['jwk'] = json.loads(account_jwk.export_public()) else: protected['kid'] = kid jws_token = jws.JWS(p.encode()) jws_token.add_signature(account_jwk, None, protected=protected, header=None) sig = jws_token.serialize() response = requests.post( url, data=sig, headers={'Content-Type': 'application/jose+json'}) reply_nonce = response.headers.get('Replay-Nonce', None) if reply_nonce is not None: self._nonce = reply_nonce return response
def message_authentication_thread(): """Get messages from decrypted queue, auth and drop to filebeat socket.""" global DECRYPTED_MESSAGES global AUTHENTICATED_MESSAGES global VALID_SENDERS global BAIL while True: if BAIL: print("Bailing out of authentication thread.") break content = DECRYPTED_MESSAGES.get() try: contents = message_is_authentic(content) if not contents: continue jwstoken = jws.JWS() jwstoken.deserialize(content) dns_uri = jwstoken.jose_header["x5u"] sender_id = Util.get_name_from_dns_uri(dns_uri) print("Message is authentic from {}".format(sender_id)) message = "{} says: {}".format(sender_id, contents.decode()) AUTHENTICATED_MESSAGES.put(json.dumps(message)) except InvalidJWSSignature as err: print("Failed to authenticate! ({})".format(err)) except InvalidJWSObject as err: print("Unable to load JWS object: {}".format(err))
def test_valid_request_correct_url_code(self, other_private_jwk): '''Ensure that the a code url parameter is passed and is valid ''' url_args = { 'grand_type': 'authorization_code', 'client_secret': 'something', 'code': 'Not a valid token' } # ---> Invalid representation of JWS Format auth_token = oauth_code.AuthorisationToken(url_args=url_args) assert not auth_token.validate_request() assert 'non-valid representation' in auth_token.errors[ 'error_description'] assert auth_token.errors['code'] == 400 # ---> JWS has not been signed by us # Create a JWS with given payload and a different private key payload = {'dummy': 'data'} jws_obj = jws.JWS( json.dumps(payload).encode(config.Config.AUTH_CODE_ENCODING)) jws_obj.add_signature(other_private_jwk, None, json.dumps({"alg": config.Config.JWT_ALGORITHM})) auth_token.code = jws_obj.serialize(compact=True) assert not auth_token.validate_request() assert 'token that has not been signed in' in auth_token.errors[ 'error_description'] assert auth_token.errors['code'] == 403
def jws_json_to_object(jws_json=None): """ Converts JWS json presentation to JWS object - http://jwcrypto.readthedocs.io/en/stable/jws.html :param jws_json: JSON presentation of JWS object :return: JWS object """ if jws_json is None: raise AttributeError("Provide jws_json as parameter") else: logger.debug("As parameter jws_json: " + repr(jws_json).replace('u\'', '\'')) try: jws_object = jws.JWS() jws_object.deserialize(raw_jws=jws_json) except Exception as exp: exp = append_description_to_exception( exp=exp, description='Could not convert JWS json to JWS object') logger.error('Could not convert JWS json to JWS object: ' + repr(exp)) raise else: logger.info('JWS json converted to JWS object') logger.debug('jws_object: ' + repr(jws_object.__dict__)) return jws_object
def decode_jwt(jwt_data: str): jws_token = jws.JWS(jwt_data) jws_token.deserialize(jwt_data) return { "header": jws_token.jose_header, "payload": json.loads(jws_token.objects.get('payload')) }
def signature_check(logger, message, pub_key): """ check JWS """ logger.debug('signature_check()') result = False error = None if pub_key: # load key try: jwkey = jwk.JWK(**pub_key) except BaseException as err: logger.error('load key failed {0}'.format(err)) jwkey = None result = False error = str(err) # verify signature if jwkey: jwstoken = jws.JWS() jwstoken.deserialize(message) try: jwstoken.verify(jwkey) result = True except BaseException as err: logger.error('verify failed {0}'.format(err)) error = str(err) else: error = 'No key specified.' # return result return (result, error)
def response(self): '''Given a valid request, craft an 'authorization code' to be sent back to the client as specified by oAuth ''' # Create a unique id in the database to be associated to this token auth_code = models.AuthorisationCode(application_id=self.client_id) db.session.add(auth_code) db.session.commit() exp_date = (datetime.utcnow() + timedelta(seconds=config.Config.AUTH_CODE_EXPIRATION_TIME)).\ strftime("%d-%m-%Y %H:%M:%S") payload = { 'client_id': self.client_id, 'redirect_uri': base64.urlsafe_b64encode(self.redirect_uri.encode()).decode(), 'expiration_date': exp_date, 'code_id': auth_code.id } # Create a JWS with given payload jws_obj = jws.JWS(json.dumps(payload).encode(config.Config.AUTH_CODE_ENCODING)) private_key = jwk.JWK.from_json(config.Config.private_jwk) jws_obj.add_signature(private_key, None, json.dumps({"alg": config.Config.JWT_ALGORITHM})) # return code and state as defined by oAuth return { 'code': jws_obj.serialize(compact=True), 'state': self.state }
def decrypt_verify_and_get_payload(private_encryption_key, public_signature_key, content): # decrypt jwetoken = jwe.JWE() jwetoken.deserialize(content, key=private_encryption_key) logging.debug(f'Payload correctly decrypted using our private key') if json.loads(jwetoken.objects['protected'] )['alg'] != 'RSA-OAEP-256' or json.loads( jwetoken.objects['protected'])['enc'] != 'A256CBC-HS512': raise Exception( 'Unsupported encryption' ) # we have to check those, otherwise other encryptions can be used as an attack vector logging.debug(f'JWE payload: {jwetoken.payload}') # verify jwstoken = jws.JWS() jwstoken.deserialize(jwetoken.payload) if json.loads(jwstoken.objects['protected'])['alg'] != 'RS512': raise Exception( 'Unsupported signature algorithm' ) # we have to check, otherwise other algorithms can be used as an attack vector jwstoken.verify(public_signature_key ) # if there's no exception, the signature is valid return jwstoken.payload
def get_payload_from_token(token, key): jws_token = jws.JWS() jws_token.deserialize(token) try: jws_token.verify(key) return Box(json.loads(jws_token.payload)) except jws.InvalidJWSSignature: return None
def verify_message(self, signature): try: verifier = jws.JWS() verifier.deserialize(signature) verifier.verify(self._key, alg='EdDSA') return verifier.payload.decode("utf-8") except jws.InvalidJWSSignature: raise OffChainInvalidSignature(signature)
def get_controller(proof): delegation_proof = jws.JWS() delegation_proof.deserialize(proof) payload = json.loads(delegation_proof.objects['payload'].decode()) if ('controller' in payload): return jwk.JWK(**payload['controller']) else: return None
def create_jwe(header, payload, sign_key, enc_key): jws_token = jws.JWS(json_encode(payload)) jws_token.add_signature(sign_key, None, json_encode({'alg': 'ES256'})) jwe_token = jwe.JWE(jws_token.serialize(compact=True), json_encode(header)) jwe_token.add_recipient(enc_key) return jwe_token.serialize(compact=True)
def make_private_key_jwt(payload): """Generate a new compact JWS to identify us to ISB""" jwstoken = jws.JWS(payload) jwstoken.add_signature(signing_key, alg="RS256", protected=json_encode( dict(alg='RS256', kid=signing_key.thumbprint()))) return jwstoken.serialize(True)
def verify(self, jws_payload, public_key_pem_data): jwstoken = jws.JWS() jwstoken.deserialize(raw_jws=jws_payload) jwk_token = jwk.JWK() jwk_token.import_from_pem(public_key_pem_data) jwstoken.verify(jwk_token) payload = jwstoken.payload print(payload) return payload
def validate_token(self, token): key = jwk.JWK(**JWK_KEY) jwstoken = jws.JWS() jwstoken.deserialize(token) try: jwstoken.verify(key) return True except: return False
async def jwsToken(self, payload: str): try: jwk = await self.privJwk() token = jws.JWS(payload.encode('utf-8')) token.add_signature(jwk, None, json_encode({"alg": "RS256"}), json_encode({"kid": jwk.thumbprint()})) return token except Exception as err: self.debug(f'Cannot create JWS token: {err}')
def sign(self): """return a signed JWT header token""" self.__pol = Policy() self.__tok = jws.JWS(json_encode(self.__pol.claims)) self.__tok.add_signature(self.__key, alg=None, protected=json_encode(self.__header)) self.__sig = self.__tok.serialize() self.__hdr = self.serialize(self.__sig) return self.__hdr
def generate_authorization_header(self): # print(dumps(self.json_structure, indent=2)) """ Generates the actual PoP token and the string for Authorization header :return: """ token = jws.JWS(dumps(self.json_structure).encode("utf-8")) token.add_signature(key=self.sign_key, alg=self.alg, header=self.header, protected=self.protected) authorization_header = "PoP {}".format(token.serialize(compact=True)) return authorization_header
def test_example_sign_verify(): from jwcrypto.common import json_encode # Generate and export keys key = jwk.JWK.generate(kty='OKP', crv='Ed25519') pub_data = key.export_to_pem(private_key=False, password=None) print('--- KEY / SIGN / VERIFY TEST ---') # Export full key: full = key.export_private() print('K.Pair:', full) # Export public pub = key.export_public() print('Public:', pub) key_pub = jwk.JWK(**json.loads(pub)) # Sign a message payload = "My Integrity protected message" print('Payload:', payload) jwstoken = jws.JWS(payload.encode('utf-8')) jwstoken.add_signature( key, alg=None, protected=json_encode({"alg": "EdDSA"}), header=json_encode({"kid": key.thumbprint()})) sig = jwstoken.serialize(compact=True) print('Signature:', sig) # Verify a message verifier = jws.JWS() verifier.deserialize(sig) verifier.verify(key) # , alg='EdDSA') payload2 = verifier.payload # Verify a message -- pub only verifier_pub = jws.JWS() verifier_pub.deserialize(sig) verifier_pub.verify(key_pub) #, alg='EdDSA') payload3 = verifier_pub.payload assert payload.encode('utf-8') == payload3