def __init__(self, hmac_key, algorithm): """Constructor for Hmac. Args: hmac_key: bytes, the symmetric hmac key. algorithm: string, HMAC algorithm as defined at https://tools.ietf.org/html/rfc7518#section-3.1. Raises: TypeError: if the hmac key is not bytes. UnsupportedAlgorithm: if the algorithm is not supported or key is too short. """ if algorithm == "HS256": self._hash = hashes.SHA256() elif algorithm == "HS384": self._hash = hashes.SHA384() elif algorithm == "HS512": self._hash = hashes.SHA512() else: raise exceptions.UnsupportedAlgorithm("Unknown algorithm: %s " % (algorithm)) if not isinstance(hmac_key, six.binary_type): raise TypeError("hmac key must be bytes") if len(hmac_key) < 16: raise exceptions.UnsupportedAlgorithm("key too short") self._hmac_key = hmac_key self.algorithm = algorithm
def __init__(self, jwk_set): """Constructor for JwsPublicKeySign. Args: jwk_set: a JwkSet. Raises: UnsupportedAlgorithm: if the algorihtm is not defined at https://tools.ietf.org/html/rfc7518#section-3.1 or if jwk is not Rsa or Ecdsa key. """ if len(jwk_set.keys) != 1: raise exceptions.UnsupportedAlgorithm( "Do not support multiple keys in signer") key = jwk_set.keys[0] if key.key_type == "RSA": self.signer = RsaSign(key.priv_key, key.algorithm) elif key.key_type == "EC": self.signer = EcdsaSign(key.priv_key, key.algorithm) else: raise exceptions.UnsupportedAlgorithm( "Unknown key type: %s or algorithm: %s" % (key.key_type, key.algorithm)) if hasattr(key, "kid"): self.kid = key.kid self.algorithm = key.algorithm
def from_pem(cls, pem_key, algorithm, kid=""): """Parses PEM key and transformat it to Jwk key. As PEM key doesn't specify the full algorithm to use (e.g. a RSA key doesn't specify which hash function should be used), the caller has to specify what algorithm that it would use the key for. Args: pem_key: bytes, RSA or ECDSA key in PEM format. algorithm: string, RSA or ECDSA algorithm as defined at https://tools.ietf.org/html/rfc7518#section-3.1. kid: string, Key ID as defined at https://tools.ietf.org/html/rfc7515#section-4.1.4. Raises: UnsupportedAlgorithm: if the algorithm is not supported or pem_key is error. """ if algorithm not in [ "RS256", "RS384", "RS512", "ES256", "ES384", "ES512", "PS256", "PS384", "PS512" ]: raise exceptions.UnsupportedAlgorithm("Unknown algorithm: %s" % (algorithm)) key_type = "" key = "" # Try to parse it as private key. try: key = load_pem_private_key(pem_key, None, backend=backends.default_backend()) except (ValueError, TypeError, exceptions.UnsupportedAlgorithm) as ignored: # If not succeeded, try to parse it as public key. try: key = load_pem_public_key(pem_key, backend=backends.default_backend()) except (ValueError, TypeError, exceptions.UnsupportedAlgorithm) as e: raise exceptions.UnsupportedAlgorithm( "Pem key parsing error: %s" % (e)) if isinstance(key, rsa.RSAPrivateKey): return JwkSet( [Jwk("RSA", kid, algorithm, None, key, key.public_key())]) elif isinstance(key, rsa.RSAPublicKey): return JwkSet([Jwk("RSA", kid, algorithm, None, None, key)]) elif isinstance(key, ec.EllipticCurvePrivateKey): return JwkSet( [Jwk("EC", kid, algorithm, None, key, key.public_key())]) elif isinstance(key, ec.EllipticCurvePublicKey): return JwkSet([Jwk("EC", kid, algorithm, None, None, key)]) else: raise exceptions.UnsupportedAlgorithm( "Unknown supported key pem: %s" % (e))
def from_cryptography_key(cls, key, algorithm, kid=""): """Transform cryptography's key to Jwk key. As cryptography's key doesn't specify the full algorithm to use (e.g. a RSA key doesn't specify which hash function should be used), the caller has to specify what algorithm that it would use the key for. Args: key: rsa.RSAPrivateKey, rsa.RSAPublicKey, ec.EllipticCurvePrivateKey or ec.EllipticCurvePublicKey algorithm: string, RSA or ECDSA algorithm as defined at https://tools.ietf.org/html/rfc7518#section-3.1. kid: string, Key ID as defined at https://tools.ietf.org/html/rfc7515#section-4.1.4. Raises: UnsupportedAlgorithm: if the algorithm is not supported or cryptography key has error. Returns: A JwkSet. """ rsa_algorithms = ["RS256", "RS384", "RS512", "PS256", "PS384", "PS512"] ecdsa_algorithms = ["ES256", "ES384", "ES512"] if algorithm in rsa_algorithms: if isinstance(key, rsa.RSAPrivateKey): return JwkSet( [Jwk("RSA", kid, algorithm, None, key, key.public_key())]) elif isinstance(key, rsa.RSAPublicKey): return JwkSet([Jwk("RSA", kid, algorithm, None, None, key)]) else: raise exceptions.UnsupportedAlgorithm( "Unsupported mismatch between algorithm: %s and cryptography key:%s" % (algorithm, key)) elif algorithm in ecdsa_algorithms: if isinstance(key, ec.EllipticCurvePrivateKey): return JwkSet( [Jwk("EC", kid, algorithm, None, key, key.public_key())]) elif isinstance(key, ec.EllipticCurvePublicKey): return JwkSet([Jwk("EC", kid, algorithm, None, None, key)]) else: raise exceptions.UnsupportedAlgorithm( "Unsupported mismatch between algorithm: %s and cryptography key:%s" % (algorithm, key)) else: raise exceptions.UnsupportedAlgorithm("Unknown algorithm: %s" % (algorithm))
def ecdsa_algorithm_to_curve_length(algorithm): """Computes curve length based on ecdsa's algorithm. Args: algorithm: string, Ecdsa algorithm as defined at https://tools.ietf.org/html/rfc7518#section-3.1. Raises: UnsupportedAlgorithm: if the algorithm is not supported. Returns: The curve length in bytes. """ _NIST_P256_CURVE_LENGTH_IN_BITS = 256 _NIST_P384_CURVE_LENGTH_IN_BITS = 384 _NIST_P521_CURVE_LENGTH_IN_BITS = 521 if algorithm == "ES256": return int(_NIST_P256_CURVE_LENGTH_IN_BITS // 8) elif algorithm == "ES384": return int(_NIST_P384_CURVE_LENGTH_IN_BITS // 8) elif algorithm == "ES512": return int((_NIST_P521_CURVE_LENGTH_IN_BITS + 7) // 8) else: raise exceptions.UnsupportedAlgorithm("Unknown algorithm: %s" % (algorithm))
def parse_rsa_algorithm(algorithm): """Parses Rsa's algorithm and returns tuple (hash, padding). Args: algorithm: string, RSA algorithm as defined at https://tools.ietf.org/html/rfc7518#section-3.1. Raises: UnsupportedAlgorithm: if the algorithm is not supported. Returns: (hash, padding) tuple. """ if algorithm == "RS256": return (hashes.SHA256(), padding.PKCS1v15()) elif algorithm == "RS384": return (hashes.SHA384(), padding.PKCS1v15()) elif algorithm == "RS512": return (hashes.SHA512(), padding.PKCS1v15()) elif algorithm == "PS256": return (hashes.SHA256(), padding.PSS(mgf=padding.MGF1(hashes.SHA256()), salt_length=padding.PSS.MAX_LENGTH)) elif algorithm == "PS384": return (hashes.SHA384(), padding.PSS(mgf=padding.MGF1(hashes.SHA384()), salt_length=padding.PSS.MAX_LENGTH)) elif algorithm == "PS512": return (hashes.SHA512(), padding.PSS(mgf=padding.MGF1(hashes.SHA512()), salt_length=padding.PSS.MAX_LENGTH)) else: raise exceptions.UnsupportedAlgorithm("Unknown algorithm: %s" % (algorithm))
def __init__(self, key): if not backend.aead_cipher_supported(self): raise exceptions.UnsupportedAlgorithm( "ChaCha20Poly1305 is not supported by this version of OpenSSL", exceptions._Reasons.UNSUPPORTED_CIPHER) utils._check_byteslike("key", key) if len(key) != 32: raise ValueError("ChaCha20Poly1305 key must be 32 bytes.") self._key = key
def __init__(self, key: bytes): utils._check_byteslike("key", key) if len(key) not in (16, 24, 32): raise ValueError("AESOCB3 key must be 128, 192, or 256 bits.") self._key = key if not backend.aead_cipher_supported(self): raise exceptions.UnsupportedAlgorithm( "OCB3 is not supported by this version of OpenSSL", exceptions._Reasons.UNSUPPORTED_CIPHER, )
def __init__(self, key: bytes): utils._check_byteslike("key", key) if len(key) not in (32, 48, 64): raise ValueError("AESSIV key must be 256, 384, or 512 bits.") self._key = key if not backend.aead_cipher_supported(self): raise exceptions.UnsupportedAlgorithm( "AES-SIV is not supported by this version of OpenSSL", exceptions._Reasons.UNSUPPORTED_CIPHER, )
def __init__(self, pub_key, algorithm): """Constructor for EcdsaVerify. Args: pub_key: ec.EllipticCurvePublicKey, the Ecdsa public key. algorithm: string, Ecdsa algorithm as defined at https://tools.ietf.org/html/rfc7518#section-3.1. Raises: TypeError: if the public key is not an instance of ec.EllipticCurvePublicKey. UnsupportedAlgorithm: if the algorithm is not supported. """ if not isinstance(pub_key, ec.EllipticCurvePublicKey): raise TypeError( "The public key must be an instance of ec.EllipticCurvePublicKey" ) self.pub_key = pub_key curve_name = "" if algorithm == "ES256": self.hash = hashes.SHA256() curve_name = "secp256r1" elif algorithm == "ES384": self.hash = hashes.SHA384() curve_name = "secp384r1" elif algorithm == "ES521": self.hash = hashes.SHA512() curve_name = "secp521r1" else: raise exceptions.UnsupportedAlgorithm("Unknown algorithm : %s" % (algorithm)) # In Ecdsa, both the key and the algorithm define the curve. Therefore, we # must cross check them to make sure they're the same. if curve_name != pub_key.curve.name: raise exceptions.UnsupportedAlgorithm( "The curve in public key %s and in algorithm % don't match" % (pub_key.curve.name, curve_name)) self.algorithm = algorithm
def __init__(self, jwk_set): """Constructor for JwsMacAuthenticator. Args: jwk_set: a JwkSet. Raises: UnsupportedAlgorithm: if the key.algorihtm is not defined at https://tools.ietf.org/html/rfc7518#section-3.1 or if jwk is not symmetric Hmac key. """ if len(jwk_set.keys) != 1: raise exceptions.UnsupportedAlgorithm( "Do not support multiple keys in authenticator") key = jwk_set.keys[0] if key.key_type == "oct": self.mac = Hmac(key.sym_key, key.algorithm) else: raise exceptions.UnsupportedAlgorithm( "Unknown key type: %s or algorithm: %s" % (key.key_type, key.algorithm)) if hasattr(key, "kid"): self.kid = key.kid self.algorithm = key.algorithm
def __init__(self, key, tag_length=16): utils._check_byteslike("key", key) if len(key) not in (16, 24, 32): raise ValueError("AESCCM key must be 128, 192, or 256 bits.") self._key = key if not isinstance(tag_length, int): raise TypeError("tag_length must be an integer") if tag_length not in (4, 6, 8, 10, 12, 14, 16): raise ValueError("Invalid tag_length") self._tag_length = tag_length if not backend.aead_cipher_supported(self): raise exceptions.UnsupportedAlgorithm( "AESCCM is not supported by this version of OpenSSL", exceptions._Reasons.UNSUPPORTED_CIPHER)
def test_verify_signature_unsupported_algorithm(self, mock_get_pub_key): public_key = TEST_RSA_PRIVATE_KEY.public_key() public_key.verifier = mock.MagicMock( side_effect=crypto_exception.UnsupportedAlgorithm( "When OpenSSL is older than 1.0.1 then only SHA1 is " "supported with MGF1.", crypto_exception._Reasons.UNSUPPORTED_HASH)) mock_get_pub_key.return_value = public_key image_properties = { CERT_UUID: 'fea14bc2-d75f-4ba5-bccc-b5c924ad0693', HASH_METHOD: 'SHA-256', KEY_TYPE: 'RSA-PSS', SIGNATURE: 'BLAH' } self.assertRaisesRegexp( exception.SignatureVerificationError, 'Unable to verify signature since the ' 'algorithm is unsupported on this system', signature_utils.get_verifier, None, image_properties)
def __init__(self, jwk_set): """Constructor for JwsMacVerify. Args: jwk_set: a JwkSet. Raises: UnsupportedAlgorithm: if the algorihtm is not defined at https://tools.ietf.org/html/rfc7518#section-3.1 or if jwk is symmetric Hmac key. """ self.verifiers = [] for key in jwk_set.keys: if key.key_type == "oct": self.verifiers.append((Hmac(key.sym_key, key.algorithm), key.kid)) else: raise exceptions.UnsupportedAlgorithm( "Unsupported key type: %s or unrecognized algorithm: %s" % (key.key_type, key.algorithm))
def __init__(self, jwk_set): """Constructor for JwsPublicKeyVerify. Args: jwk_set: a JwkSet. Raises: UnsupportedAlgorithm: if the algorihtm is not defined at https://tools.ietf.org/html/rfc7518#section-3.1 or if jwk is not Rsa or Ecdsa key. """ self.verifiers = [] for key in jwk_set.keys: if key.key_type == "RSA": self.verifiers.append((RsaVerify(key.pub_key, key.algorithm), key.kid)) elif key.key_type == "EC": self.verifiers.append((EcdsaVerify(key.pub_key, key.algorithm), key.kid)) else: raise exceptions.UnsupportedAlgorithm( "Unsupported key type: %s" % (key.key_type))
def _read_single_json_key(cls, parsed_key): """Reads a parsed json key and transform it to Jwk key. Args: parsed_key: a Python reprenstation of Json object. Raises: UnsupportedAlgorithm: if the key type is not supported. Returns: A Jwk key. """ key_type = parsed_key["kty"] algorithm = parsed_key.get("alg", "") if not algorithm: raise exceptions.UnsupportedAlgorithm("Alg field is missing") if algorithm not in [ "HS256", "HS384", "HS512", "RS256", "RS384", "RS512", "ES256", "ES384", "ES512", "PS256", "PS384", "PS512" ]: raise exceptions.UnsupportedAlgorithm("Unknown algorithm: %s" % (algorithm)) if key_type == "RSA": rsa_pub_numbers = rsa.RSAPublicNumbers( jwsutil.b64_to_int(parsed_key["e"]), jwsutil.b64_to_int(parsed_key["n"])) if parsed_key.get("p", None) is not None: # Rsa private key. rsa_priv_numbers = rsa.RSAPrivateNumbers( jwsutil.b64_to_int(parsed_key["p"]), jwsutil.b64_to_int(parsed_key["q"]), jwsutil.b64_to_int(parsed_key["d"]), jwsutil.b64_to_int(parsed_key["dp"]), jwsutil.b64_to_int(parsed_key["dq"]), jwsutil.b64_to_int(parsed_key["qi"]), rsa_pub_numbers) priv_key = rsa_priv_numbers.private_key( backends.default_backend()) return Jwk(key_type, parsed_key.get("kid", ""), algorithm, None, priv_key, priv_key.public_key()) else: # Rsa public key. return Jwk( key_type, parsed_key.get("kid", ""), algorithm, None, None, rsa_pub_numbers.public_key(backends.default_backend())) elif key_type == "EC": if parsed_key["crv"] == "P-256": curve = ec.SECP256R1() elif parsed_key["crv"] == "P-384": curve = ec.SECP384R1() elif parsed_key["crv"] == "P-521": curve = ec.SECP521R1() else: raise exceptions.UnsupportedAlgorithm("Unknown curve: %s" % (parsed_key["crv"])) if parsed_key.get("d", None) is not None: # Ecdsa private key. priv_key = ec.derive_private_key( jwsutil.b64_to_int(parsed_key["d"]), curve, backends.default_backend()) return Jwk(key_type, parsed_key.get("kid", ""), algorithm, None, priv_key, priv_key.public_key()) else: # Ecdsa public key. ec_pub_numbers = ec.EllipticCurvePublicNumbers( jwsutil.b64_to_int(parsed_key["x"]), jwsutil.b64_to_int(parsed_key["y"]), curve) pub_key = ec_pub_numbers.public_key(backends.default_backend()) return Jwk(key_type, parsed_key.get("kid", ""), algorithm, None, None, pub_key) elif key_type == "oct": sym_key = jwsutil.urlsafe_b64decode(parsed_key["k"]) return Jwk(key_type, parsed_key.get("kid", ""), algorithm, sym_key) else: raise exceptions.UnsupportedAlgorithm("Unsupported key type: %s" % (key_type))
def sign_cert(cls, csr, validity, ca_cert=None, ca_key=None, ca_key_pass=None, ca_digest=None): """Signs a certificate using our private CA based on the specified CSR The signed certificate will be valid from now until <validity> seconds from now. :param csr: A Certificate Signing Request :param validity: Valid for <validity> seconds from the current time :param ca_cert: Signing Certificate (default: config) :param ca_key: Signing Certificate Key (default: config) :param ca_key_pass: Signing Certificate Key Pass (default: config) :param ca_digest: Digest method to use for signing (default: config) :return: Signed certificate :raises Exception: if certificate signing fails """ LOG.info("Signing a certificate request using OpenSSL locally.") cls._validate_cert(ca_cert, ca_key, ca_key_pass) if not ca_digest: ca_digest = CONF.certificates.signing_digest try: algorithm = getattr(hashes, ca_digest.upper())() except AttributeError: raise crypto_exceptions.UnsupportedAlgorithm( "Supplied digest method not found: %s" % ca_digest ) if not ca_cert: with open(CONF.certificates.ca_certificate, 'rb') as f: ca_cert = f.read() if not ca_key: with open(CONF.certificates.ca_private_key, 'rb') as f: ca_key = f.read() if not ca_key_pass: ca_key_pass = CONF.certificates.ca_private_key_passphrase if ca_key_pass is not None: ca_key_pass = ca_key_pass.encode('utf-8') try: lo_cert = x509.load_pem_x509_certificate( data=ca_cert, backend=backends.default_backend()) lo_key = serialization.load_pem_private_key( data=ca_key, password=ca_key_pass, backend=backends.default_backend()) lo_req = x509.load_pem_x509_csr(data=csr, backend=backends.default_backend()) new_cert = x509.CertificateBuilder() new_cert = new_cert.serial_number(cls._new_serial()) valid_from_datetime = datetime.datetime.utcnow() valid_to_datetime = (datetime.datetime.utcnow() + datetime.timedelta(seconds=validity)) new_cert = new_cert.not_valid_before(valid_from_datetime) new_cert = new_cert.not_valid_after(valid_to_datetime) new_cert = new_cert.issuer_name(lo_cert.subject) new_cert = new_cert.subject_name(lo_req.subject) new_cert = new_cert.public_key(lo_req.public_key()) new_cert = new_cert.add_extension( x509.BasicConstraints(ca=False, path_length=None), critical=True ) cn_str = lo_req.subject.get_attributes_for_oid( x509.oid.NameOID.COMMON_NAME)[0].value new_cert = new_cert.add_extension( x509.SubjectAlternativeName([x509.DNSName(cn_str)]), critical=False ) new_cert = new_cert.add_extension( x509.KeyUsage( digital_signature=True, key_encipherment=True, data_encipherment=True, key_agreement=True, content_commitment=False, key_cert_sign=False, crl_sign=False, encipher_only=False, decipher_only=False ), critical=True ) new_cert = new_cert.add_extension( x509.ExtendedKeyUsage([ x509.oid.ExtendedKeyUsageOID.SERVER_AUTH, x509.oid.ExtendedKeyUsageOID.CLIENT_AUTH ]), critical=True ) signed_cert = new_cert.sign(private_key=lo_key, algorithm=algorithm, backend=backends.default_backend()) return signed_cert.public_bytes( encoding=serialization.Encoding.PEM) except Exception as e: LOG.error("Unable to sign certificate.") raise exceptions.CertificateGenerationException(msg=e)