def decode(token, key): """Decode a web token into an assertion dictionary This attempts to rectify both ecdsa and openssl generated signatures. :param token: VAPID auth token :type token: str :param key: bitarray containing the public key :type key: str :return dict of the VAPID claims :raise InvalidSignature """ try: sig_material, signature = extract_signature(token) dkey = b64urldecode(key.encode('utf8')) pkey = ec.EllipticCurvePublicNumbers.from_encoded_point( ec.SECP256R1(), dkey, ).public_key(default_backend()) pkey.verify(signature, sig_material, ec.ECDSA(hashes.SHA256())) return json.loads( b64urldecode(sig_material.split(b'.')[1]).decode('utf8')) except InvalidSignature: raise except (ValueError, TypeError, binascii.Error): raise InvalidSignature()
def decode(token, key): """Decode a web token into an assertion dictionary :param token: VAPID auth token :type token: str :param key: bitarray containing the public key :type key: str :return dict of the VAPID claims :raise InvalidSignature """ try: sig_material, signature = extract_signature(token) dkey = b64urldecode(key.encode('utf8')) pkey = ec.EllipticCurvePublicKey.from_encoded_point( ec.SECP256R1(), dkey, ) pkey.verify( signature, sig_material, ec.ECDSA(hashes.SHA256()) ) return json.loads( b64urldecode(sig_material.split(b'.')[1]).decode('utf8') ) except InvalidSignature: raise except(ValueError, TypeError, binascii.Error): raise InvalidSignature()
def from_raw_public(cls, public_raw): key = ec.EllipticCurvePublicNumbers.from_encoded_point( curve=ec.SECP256R1(), data=b64urldecode(public_raw)).public_key(default_backend()) ss = cls() ss._public_key = key return ss
def from_raw_public(cls, public_raw): key = ec.EllipticCurvePublicKey.from_encoded_point( curve=ec.SECP256R1(), data=b64urldecode(public_raw) ) ss = cls() ss._public_key = key return ss
def from_der(cls, private_key): """Initialize VAPID using a private key in DER format. :param private_key: A private key in DER format and Base64-encoded. :type private_key: bytes """ key = serialization.load_der_private_key(b64urldecode(private_key), password=None, backend=default_backend()) return cls(key)
def from_string(cls, private_key): """Initialize VAPID using a string containing the private key. This will try to determine if the key is in RAW or DER format. :param private_key: String containing the key info :type private_key: str """ pkey = private_key.encode().replace(b"\n", b"") key = b64urldecode(pkey) if len(key) == 32: return cls.from_raw(pkey) return cls.from_der(pkey)
def from_raw(cls, private_raw): """Initialize VAPID using a private key point in "raw" or "uncompressed" form. Raw keys consist of a single, 32 octet encoded integer. :param private_raw: A private key point in uncompressed form. :type private_raw: bytes """ key = ec.derive_private_key( int(binascii.hexlify(b64urldecode(private_raw)), 16), curve=ec.SECP256R1(), backend=default_backend()) return cls(key)
def verify_token(self, validation_token, verification_token): """Internally used to verify the verification token is correct. :param validation_token: Provided validation token string :type validation_token: str :param verification_token: Generated verification token :type verification_token: str :returns: Boolean indicating if verifictation token is valid. :rtype: boolean """ hsig = b64urldecode(verification_token.encode('utf8')) return self.public_key.verify( hsig, validation_token, signature_algorithm=ec.ECDSA(hashes.SHA256()) )
def extract_signature(auth): """Extracts the payload and signature from a JWT, converting from RFC7518 to RFC 3279 :param auth: A JWT Authorization Token. :type auth: str :return tuple containing the signature material and signature """ payload, asig = auth.encode('utf8').rsplit(b'.', 1) sig = b64urldecode(asig) if len(sig) != 64: raise InvalidSignature() encoded = utils.encode_dss_signature(s=int(binascii.hexlify(sig[32:]), 16), r=int(binascii.hexlify(sig[:32]), 16)) return payload, encoded
def extract_signature(auth): """Fix the JWT auth token convert a ecdsa integer pair into an OpenSSL DER pair. :param auth: A JWT Authorization Token. :type auth: str :return tuple containing the signature material and signature """ payload, asig = auth.encode('utf8').rsplit(b'.', 1) sig = b64urldecode(asig) if len(sig) != 64: return payload, sig encoded = utils.encode_dss_signature(s=int(binascii.hexlify(sig[32:]), 16), r=int(binascii.hexlify(sig[:32]), 16)) return payload, encoded
def extract_signature(auth): """Extracts the payload and signature from a JWT, converting from RFC7518 to RFC 3279 :param auth: A JWT Authorization Token. :type auth: str :return tuple containing the signature material and signature """ payload, asig = auth.encode('utf8').rsplit(b'.', 1) sig = b64urldecode(asig) if len(sig) != 64: raise InvalidSignature() encoded = utils.encode_dss_signature( s=int(binascii.hexlify(sig[32:]), 16), r=int(binascii.hexlify(sig[:32]), 16) ) return payload, encoded
def test_alt_sign(self): """ecdsa uses a raw key pair to sign, openssl uses a DER.""" v = Vapid01.from_file("/tmp/private") claims = {"aud": "https://example.com", "sub": "mailto:[email protected]", "foo": "extra value"} # Get a signed token. result = v.sign(claims) # Convert the dss into raw. auth, sig = result.get('Authorization').split(' ')[1].rsplit('.', 1) ss = utils.decode_dss_signature(b64urldecode(sig.encode('utf8'))) new_sig = binascii.b2a_base64( binascii.unhexlify("%064x%064x" % ss) ).strip().strip(b'=').decode() new_auth = auth + '.' + new_sig # phew, all that done, now check pkey = result.get("Crypto-Key").split('=')[1] items = decode(new_auth, pkey) eq_(items, claims)
def verify_token(self, validation_token, verification_token): """Internally used to verify the verification token is correct. :param validation_token: Provided validation token string :type validation_token: str :param verification_token: Generated verification token :type verification_token: str :returns: Boolean indicating if verifictation token is valid. :rtype: boolean """ hsig = b64urldecode(verification_token.encode('utf8')) r = int(binascii.hexlify(hsig[:32]), 16) s = int(binascii.hexlify(hsig[32:]), 16) try: self.public_key.verify(ecutils.encode_dss_signature(r, s), validation_token, signature_algorithm=ec.ECDSA( hashes.SHA256())) return True except InvalidSignature: return False
def verify_token(self, validation_token, verification_token): """Internally used to verify the verification token is correct. :param validation_token: Provided validation token string :type validation_token: str :param verification_token: Generated verification token :type verification_token: str :returns: Boolean indicating if verifictation token is valid. :rtype: boolean """ hsig = b64urldecode(verification_token.encode('utf8')) r = int(binascii.hexlify(hsig[:32]), 16) s = int(binascii.hexlify(hsig[32:]), 16) try: self.public_key.verify( ecutils.encode_dss_signature(r, s), validation_token, signature_algorithm=ec.ECDSA(hashes.SHA256()) ) return True except InvalidSignature: return False