1# This file is dual licensed under the terms of the Apache License, Version 2# 2.0, and the BSD License. See the LICENSE file in the root of this repository 3# for complete details. 4 5from __future__ import absolute_import, division, print_function 6 7import itertools 8import os 9import subprocess 10import sys 11import textwrap 12 13import pytest 14 15from cryptography import x509 16from cryptography.exceptions import InternalError, _Reasons 17from cryptography.hazmat.backends.interfaces import DHBackend, RSABackend 18from cryptography.hazmat.backends.openssl.backend import Backend, backend 19from cryptography.hazmat.backends.openssl.ec import _sn_to_elliptic_curve 20from cryptography.hazmat.primitives import hashes, serialization 21from cryptography.hazmat.primitives.asymmetric import dh, dsa, padding 22from cryptography.hazmat.primitives.ciphers import Cipher 23from cryptography.hazmat.primitives.ciphers.algorithms import AES 24from cryptography.hazmat.primitives.ciphers.modes import CBC 25 26from ..primitives.fixtures_rsa import RSA_KEY_2048, RSA_KEY_512 27from ...doubles import ( 28 DummyAsymmetricPadding, 29 DummyCipherAlgorithm, 30 DummyHashAlgorithm, 31 DummyMode, 32) 33from ...utils import ( 34 load_nist_vectors, 35 load_vectors_from_file, 36 raises_unsupported_algorithm, 37) 38from ...x509.test_x509 import _load_cert 39 40 41def skip_if_libre_ssl(openssl_version): 42 if u"LibreSSL" in openssl_version: 43 pytest.skip("LibreSSL hard-codes RAND_bytes to use arc4random.") 44 45 46class TestLibreSkip(object): 47 def test_skip_no(self): 48 assert skip_if_libre_ssl(u"OpenSSL 1.0.2h 3 May 2016") is None 49 50 def test_skip_yes(self): 51 with pytest.raises(pytest.skip.Exception): 52 skip_if_libre_ssl(u"LibreSSL 2.1.6") 53 54 55class DummyMGF(object): 56 _salt_length = 0 57 58 59class TestOpenSSL(object): 60 def test_backend_exists(self): 61 assert backend 62 63 def test_openssl_version_text(self): 64 """ 65 This test checks the value of OPENSSL_VERSION_TEXT. 66 67 Unfortunately, this define does not appear to have a 68 formal content definition, so for now we'll test to see 69 if it starts with OpenSSL or LibreSSL as that appears 70 to be true for every OpenSSL-alike. 71 """ 72 assert backend.openssl_version_text().startswith( 73 "OpenSSL" 74 ) or backend.openssl_version_text().startswith("LibreSSL") 75 76 def test_openssl_version_number(self): 77 assert backend.openssl_version_number() > 0 78 79 def test_supports_cipher(self): 80 assert backend.cipher_supported(None, None) is False 81 82 def test_register_duplicate_cipher_adapter(self): 83 with pytest.raises(ValueError): 84 backend.register_cipher_adapter(AES, CBC, None) 85 86 @pytest.mark.parametrize("mode", [DummyMode(), None]) 87 def test_nonexistent_cipher(self, mode): 88 b = Backend() 89 b.register_cipher_adapter( 90 DummyCipherAlgorithm, 91 type(mode), 92 lambda backend, cipher, mode: backend._ffi.NULL, 93 ) 94 cipher = Cipher( 95 DummyCipherAlgorithm(), 96 mode, 97 backend=b, 98 ) 99 with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_CIPHER): 100 cipher.encryptor() 101 102 def test_openssl_assert(self): 103 backend.openssl_assert(True) 104 with pytest.raises(InternalError): 105 backend.openssl_assert(False) 106 107 def test_consume_errors(self): 108 for i in range(10): 109 backend._lib.ERR_put_error( 110 backend._lib.ERR_LIB_EVP, 0, 0, b"test_openssl.py", -1 111 ) 112 113 assert backend._lib.ERR_peek_error() != 0 114 115 errors = backend._consume_errors() 116 117 assert backend._lib.ERR_peek_error() == 0 118 assert len(errors) == 10 119 120 def test_ssl_ciphers_registered(self): 121 meth = backend._lib.SSLv23_method() 122 ctx = backend._lib.SSL_CTX_new(meth) 123 assert ctx != backend._ffi.NULL 124 backend._lib.SSL_CTX_free(ctx) 125 126 def test_evp_ciphers_registered(self): 127 cipher = backend._lib.EVP_get_cipherbyname(b"aes-256-cbc") 128 assert cipher != backend._ffi.NULL 129 130 def test_unknown_error_in_cipher_finalize(self): 131 cipher = Cipher(AES(b"\0" * 16), CBC(b"\0" * 16), backend=backend) 132 enc = cipher.encryptor() 133 enc.update(b"\0") 134 backend._lib.ERR_put_error(0, 0, 1, b"test_openssl.py", -1) 135 with pytest.raises(InternalError): 136 enc.finalize() 137 138 def test_large_key_size_on_new_openssl(self): 139 parameters = dsa.generate_parameters(2048, backend) 140 param_num = parameters.parameter_numbers() 141 assert param_num.p.bit_length() == 2048 142 parameters = dsa.generate_parameters(3072, backend) 143 param_num = parameters.parameter_numbers() 144 assert param_num.p.bit_length() == 3072 145 146 def test_int_to_bn(self): 147 value = (2 ** 4242) - 4242 148 bn = backend._int_to_bn(value) 149 assert bn != backend._ffi.NULL 150 bn = backend._ffi.gc(bn, backend._lib.BN_clear_free) 151 152 assert bn 153 assert backend._bn_to_int(bn) == value 154 155 def test_int_to_bn_inplace(self): 156 value = (2 ** 4242) - 4242 157 bn_ptr = backend._lib.BN_new() 158 assert bn_ptr != backend._ffi.NULL 159 bn_ptr = backend._ffi.gc(bn_ptr, backend._lib.BN_free) 160 bn = backend._int_to_bn(value, bn_ptr) 161 162 assert bn == bn_ptr 163 assert backend._bn_to_int(bn_ptr) == value 164 165 def test_bn_to_int(self): 166 bn = backend._int_to_bn(0) 167 assert backend._bn_to_int(bn) == 0 168 169 170@pytest.mark.skipif( 171 not backend._lib.CRYPTOGRAPHY_NEEDS_OSRANDOM_ENGINE, 172 reason="Requires OpenSSL with ENGINE support and OpenSSL < 1.1.1d", 173) 174@pytest.mark.skip_fips(reason="osrandom engine disabled for FIPS") 175class TestOpenSSLRandomEngine(object): 176 def setup(self): 177 # The default RAND engine is global and shared between 178 # tests. We make sure that the default engine is osrandom 179 # before we start each test and restore the global state to 180 # that engine in teardown. 181 current_default = backend._lib.ENGINE_get_default_RAND() 182 name = backend._lib.ENGINE_get_name(current_default) 183 assert name == backend._lib.Cryptography_osrandom_engine_name 184 185 def teardown(self): 186 # we need to reset state to being default. backend is a shared global 187 # for all these tests. 188 backend.activate_osrandom_engine() 189 current_default = backend._lib.ENGINE_get_default_RAND() 190 name = backend._lib.ENGINE_get_name(current_default) 191 assert name == backend._lib.Cryptography_osrandom_engine_name 192 193 @pytest.mark.skipif( 194 sys.executable is None, reason="No Python interpreter available." 195 ) 196 def test_osrandom_engine_is_default(self, tmpdir): 197 engine_printer = textwrap.dedent( 198 """ 199 import sys 200 from cryptography.hazmat.backends.openssl.backend import backend 201 202 e = backend._lib.ENGINE_get_default_RAND() 203 name = backend._lib.ENGINE_get_name(e) 204 sys.stdout.write(backend._ffi.string(name).decode('ascii')) 205 res = backend._lib.ENGINE_free(e) 206 assert res == 1 207 """ 208 ) 209 engine_name = tmpdir.join("engine_name") 210 211 # If we're running tests via ``python setup.py test`` in a clean 212 # environment then all of our dependencies are going to be installed 213 # into either the current directory or the .eggs directory. However the 214 # subprocess won't know to activate these dependencies, so we'll get it 215 # to do so by passing our entire sys.path into the subprocess via the 216 # PYTHONPATH environment variable. 217 env = os.environ.copy() 218 env["PYTHONPATH"] = os.pathsep.join(sys.path) 219 220 with engine_name.open("w") as out: 221 subprocess.check_call( 222 [sys.executable, "-c", engine_printer], 223 env=env, 224 stdout=out, 225 stderr=subprocess.PIPE, 226 ) 227 228 osrandom_engine_name = backend._ffi.string( 229 backend._lib.Cryptography_osrandom_engine_name 230 ) 231 232 assert engine_name.read().encode("ascii") == osrandom_engine_name 233 234 def test_osrandom_sanity_check(self): 235 # This test serves as a check against catastrophic failure. 236 buf = backend._ffi.new("unsigned char[]", 500) 237 res = backend._lib.RAND_bytes(buf, 500) 238 assert res == 1 239 assert backend._ffi.buffer(buf)[:] != "\x00" * 500 240 241 def test_activate_osrandom_no_default(self): 242 backend.activate_builtin_random() 243 e = backend._lib.ENGINE_get_default_RAND() 244 assert e == backend._ffi.NULL 245 backend.activate_osrandom_engine() 246 e = backend._lib.ENGINE_get_default_RAND() 247 name = backend._lib.ENGINE_get_name(e) 248 assert name == backend._lib.Cryptography_osrandom_engine_name 249 res = backend._lib.ENGINE_free(e) 250 assert res == 1 251 252 def test_activate_builtin_random(self): 253 e = backend._lib.ENGINE_get_default_RAND() 254 assert e != backend._ffi.NULL 255 name = backend._lib.ENGINE_get_name(e) 256 assert name == backend._lib.Cryptography_osrandom_engine_name 257 res = backend._lib.ENGINE_free(e) 258 assert res == 1 259 backend.activate_builtin_random() 260 e = backend._lib.ENGINE_get_default_RAND() 261 assert e == backend._ffi.NULL 262 263 def test_activate_builtin_random_already_active(self): 264 backend.activate_builtin_random() 265 e = backend._lib.ENGINE_get_default_RAND() 266 assert e == backend._ffi.NULL 267 backend.activate_builtin_random() 268 e = backend._lib.ENGINE_get_default_RAND() 269 assert e == backend._ffi.NULL 270 271 def test_osrandom_engine_implementation(self): 272 name = backend.osrandom_engine_implementation() 273 assert name in [ 274 "/dev/urandom", 275 "CryptGenRandom", 276 "getentropy", 277 "getrandom", 278 ] 279 if sys.platform.startswith("linux"): 280 assert name in ["getrandom", "/dev/urandom"] 281 if sys.platform == "darwin": 282 assert name in ["getentropy", "/dev/urandom"] 283 if sys.platform == "win32": 284 assert name == "CryptGenRandom" 285 286 def test_activate_osrandom_already_default(self): 287 e = backend._lib.ENGINE_get_default_RAND() 288 name = backend._lib.ENGINE_get_name(e) 289 assert name == backend._lib.Cryptography_osrandom_engine_name 290 res = backend._lib.ENGINE_free(e) 291 assert res == 1 292 backend.activate_osrandom_engine() 293 e = backend._lib.ENGINE_get_default_RAND() 294 name = backend._lib.ENGINE_get_name(e) 295 assert name == backend._lib.Cryptography_osrandom_engine_name 296 res = backend._lib.ENGINE_free(e) 297 assert res == 1 298 299 300@pytest.mark.skipif( 301 backend._lib.CRYPTOGRAPHY_NEEDS_OSRANDOM_ENGINE, 302 reason="Requires OpenSSL without ENGINE support or OpenSSL >=1.1.1d", 303) 304class TestOpenSSLNoEngine(object): 305 def test_no_engine_support(self): 306 assert ( 307 backend._ffi.string(backend._lib.Cryptography_osrandom_engine_id) 308 == b"no-engine-support" 309 ) 310 assert ( 311 backend._ffi.string(backend._lib.Cryptography_osrandom_engine_name) 312 == b"osrandom_engine disabled" 313 ) 314 315 def test_activate_builtin_random_does_nothing(self): 316 backend.activate_builtin_random() 317 318 def test_activate_osrandom_does_nothing(self): 319 backend.activate_osrandom_engine() 320 321 322class TestOpenSSLRSA(object): 323 def test_generate_rsa_parameters_supported(self): 324 assert backend.generate_rsa_parameters_supported(1, 1024) is False 325 assert backend.generate_rsa_parameters_supported(4, 1024) is False 326 assert backend.generate_rsa_parameters_supported(3, 1024) is True 327 assert backend.generate_rsa_parameters_supported(3, 511) is False 328 329 def test_generate_bad_public_exponent(self): 330 with pytest.raises(ValueError): 331 backend.generate_rsa_private_key(public_exponent=1, key_size=2048) 332 333 with pytest.raises(ValueError): 334 backend.generate_rsa_private_key(public_exponent=4, key_size=2048) 335 336 def test_cant_generate_insecure_tiny_key(self): 337 with pytest.raises(ValueError): 338 backend.generate_rsa_private_key( 339 public_exponent=65537, key_size=511 340 ) 341 342 with pytest.raises(ValueError): 343 backend.generate_rsa_private_key( 344 public_exponent=65537, key_size=256 345 ) 346 347 def test_rsa_padding_unsupported_pss_mgf1_hash(self): 348 assert ( 349 backend.rsa_padding_supported( 350 padding.PSS( 351 mgf=padding.MGF1(DummyHashAlgorithm()), salt_length=0 352 ) 353 ) 354 is False 355 ) 356 357 def test_rsa_padding_unsupported(self): 358 assert backend.rsa_padding_supported(DummyAsymmetricPadding()) is False 359 360 def test_rsa_padding_supported_pkcs1v15(self): 361 assert backend.rsa_padding_supported(padding.PKCS1v15()) is True 362 363 def test_rsa_padding_supported_pss(self): 364 assert ( 365 backend.rsa_padding_supported( 366 padding.PSS(mgf=padding.MGF1(hashes.SHA1()), salt_length=0) 367 ) 368 is True 369 ) 370 371 def test_rsa_padding_supported_oaep(self): 372 assert ( 373 backend.rsa_padding_supported( 374 padding.OAEP( 375 mgf=padding.MGF1(algorithm=hashes.SHA1()), 376 algorithm=hashes.SHA1(), 377 label=None, 378 ), 379 ) 380 is True 381 ) 382 383 @pytest.mark.skipif( 384 backend._lib.Cryptography_HAS_RSA_OAEP_MD == 0, 385 reason="Requires OpenSSL with rsa_oaep_md (1.0.2+)", 386 ) 387 def test_rsa_padding_supported_oaep_sha2_combinations(self): 388 hashalgs = [ 389 hashes.SHA1(), 390 hashes.SHA224(), 391 hashes.SHA256(), 392 hashes.SHA384(), 393 hashes.SHA512(), 394 ] 395 for mgf1alg, oaepalg in itertools.product(hashalgs, hashalgs): 396 assert ( 397 backend.rsa_padding_supported( 398 padding.OAEP( 399 mgf=padding.MGF1(algorithm=mgf1alg), 400 algorithm=oaepalg, 401 label=None, 402 ), 403 ) 404 is True 405 ) 406 407 def test_rsa_padding_unsupported_mgf(self): 408 assert ( 409 backend.rsa_padding_supported( 410 padding.OAEP( 411 mgf=DummyMGF(), algorithm=hashes.SHA1(), label=None 412 ), 413 ) 414 is False 415 ) 416 417 assert ( 418 backend.rsa_padding_supported( 419 padding.PSS(mgf=DummyMGF(), salt_length=0) 420 ) 421 is False 422 ) 423 424 @pytest.mark.skipif( 425 backend._lib.Cryptography_HAS_RSA_OAEP_MD == 1, 426 reason="Requires OpenSSL without rsa_oaep_md (< 1.0.2)", 427 ) 428 def test_unsupported_mgf1_hash_algorithm_decrypt(self): 429 private_key = RSA_KEY_512.private_key(backend) 430 with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_PADDING): 431 private_key.decrypt( 432 b"0" * 64, 433 padding.OAEP( 434 mgf=padding.MGF1(algorithm=hashes.SHA256()), 435 algorithm=hashes.SHA1(), 436 label=None, 437 ), 438 ) 439 440 @pytest.mark.skipif( 441 backend._lib.Cryptography_HAS_RSA_OAEP_MD == 1, 442 reason="Requires OpenSSL without rsa_oaep_md (< 1.0.2)", 443 ) 444 def test_unsupported_oaep_hash_algorithm_decrypt(self): 445 private_key = RSA_KEY_512.private_key(backend) 446 with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_PADDING): 447 private_key.decrypt( 448 b"0" * 64, 449 padding.OAEP( 450 mgf=padding.MGF1(algorithm=hashes.SHA1()), 451 algorithm=hashes.SHA256(), 452 label=None, 453 ), 454 ) 455 456 def test_unsupported_mgf1_hash_algorithm_md5_decrypt(self): 457 private_key = RSA_KEY_512.private_key(backend) 458 with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_PADDING): 459 private_key.decrypt( 460 b"0" * 64, 461 padding.OAEP( 462 mgf=padding.MGF1(algorithm=hashes.MD5()), 463 algorithm=hashes.MD5(), 464 label=None, 465 ), 466 ) 467 468 469class TestOpenSSLCMAC(object): 470 def test_unsupported_cipher(self): 471 with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_CIPHER): 472 backend.create_cmac_ctx(DummyCipherAlgorithm()) 473 474 475class TestOpenSSLSignX509Certificate(object): 476 def test_requires_certificate_builder(self): 477 private_key = RSA_KEY_2048.private_key(backend) 478 479 with pytest.raises(TypeError): 480 backend.create_x509_certificate( 481 object(), private_key, DummyHashAlgorithm() 482 ) 483 484 485class TestOpenSSLSignX509CSR(object): 486 def test_requires_csr_builder(self): 487 private_key = RSA_KEY_2048.private_key(backend) 488 489 with pytest.raises(TypeError): 490 backend.create_x509_csr( 491 object(), private_key, DummyHashAlgorithm() 492 ) 493 494 495class TestOpenSSLSignX509CertificateRevocationList(object): 496 def test_invalid_builder(self): 497 private_key = RSA_KEY_2048.private_key(backend) 498 499 with pytest.raises(TypeError): 500 backend.create_x509_crl(object(), private_key, hashes.SHA256()) 501 502 503class TestOpenSSLCreateRevokedCertificate(object): 504 def test_invalid_builder(self): 505 with pytest.raises(TypeError): 506 backend.create_x509_revoked_certificate(object()) 507 508 509class TestOpenSSLSerializationWithOpenSSL(object): 510 def test_pem_password_cb(self): 511 userdata = backend._ffi.new("CRYPTOGRAPHY_PASSWORD_DATA *") 512 pw = b"abcdefg" 513 password = backend._ffi.new("char []", pw) 514 userdata.password = password 515 userdata.length = len(pw) 516 buflen = 10 517 buf = backend._ffi.new("char []", buflen) 518 res = backend._lib.Cryptography_pem_password_cb( 519 buf, buflen, 0, userdata 520 ) 521 assert res == len(pw) 522 assert userdata.called == 1 523 assert backend._ffi.buffer(buf, len(pw))[:] == pw 524 assert userdata.maxsize == buflen 525 assert userdata.error == 0 526 527 def test_pem_password_cb_no_password(self): 528 userdata = backend._ffi.new("CRYPTOGRAPHY_PASSWORD_DATA *") 529 buflen = 10 530 buf = backend._ffi.new("char []", buflen) 531 res = backend._lib.Cryptography_pem_password_cb( 532 buf, buflen, 0, userdata 533 ) 534 assert res == 0 535 assert userdata.error == -1 536 537 def test_unsupported_evp_pkey_type(self): 538 key = backend._create_evp_pkey_gc() 539 with raises_unsupported_algorithm(None): 540 backend._evp_pkey_to_private_key(key) 541 with raises_unsupported_algorithm(None): 542 backend._evp_pkey_to_public_key(key) 543 544 def test_very_long_pem_serialization_password(self): 545 password = b"x" * 1024 546 547 with pytest.raises(ValueError): 548 load_vectors_from_file( 549 os.path.join( 550 "asymmetric", 551 "Traditional_OpenSSL_Serialization", 552 "key1.pem", 553 ), 554 lambda pemfile: ( 555 backend.load_pem_private_key( 556 pemfile.read().encode(), password 557 ) 558 ), 559 ) 560 561 562class TestOpenSSLEllipticCurve(object): 563 def test_sn_to_elliptic_curve_not_supported(self): 564 with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_ELLIPTIC_CURVE): 565 _sn_to_elliptic_curve(backend, b"fake") 566 567 568@pytest.mark.requires_backend_interface(interface=RSABackend) 569class TestRSAPEMSerialization(object): 570 def test_password_length_limit(self): 571 password = b"x" * 1024 572 key = RSA_KEY_2048.private_key(backend) 573 with pytest.raises(ValueError): 574 key.private_bytes( 575 serialization.Encoding.PEM, 576 serialization.PrivateFormat.PKCS8, 577 serialization.BestAvailableEncryption(password), 578 ) 579 580 581class TestGOSTCertificate(object): 582 def test_numeric_string_x509_name_entry(self): 583 cert = _load_cert( 584 os.path.join("x509", "e-trust.ru.der"), 585 x509.load_der_x509_certificate, 586 backend, 587 ) 588 if backend._lib.CRYPTOGRAPHY_IS_LIBRESSL: 589 with pytest.raises(ValueError) as exc: 590 cert.subject 591 592 # We assert on the message in this case because if the certificate 593 # fails to load it will also raise a ValueError and this test could 594 # erroneously pass. 595 assert str(exc.value) == "Unsupported ASN1 string type. Type: 18" 596 else: 597 assert ( 598 cert.subject.get_attributes_for_oid( 599 x509.ObjectIdentifier("1.2.643.3.131.1.1") 600 )[0].value 601 == "007710474375" 602 ) 603 604 605@pytest.mark.skipif( 606 backend._lib.Cryptography_HAS_EVP_PKEY_DHX == 1, 607 reason="Requires OpenSSL without EVP_PKEY_DHX (< 1.0.2)", 608) 609@pytest.mark.requires_backend_interface(interface=DHBackend) 610class TestOpenSSLDHSerialization(object): 611 @pytest.mark.parametrize( 612 "vector", 613 load_vectors_from_file( 614 os.path.join("asymmetric", "DH", "RFC5114.txt"), load_nist_vectors 615 ), 616 ) 617 def test_dh_serialization_with_q_unsupported(self, backend, vector): 618 parameters = dh.DHParameterNumbers( 619 int(vector["p"], 16), int(vector["g"], 16), int(vector["q"], 16) 620 ) 621 public = dh.DHPublicNumbers(int(vector["ystatcavs"], 16), parameters) 622 private = dh.DHPrivateNumbers(int(vector["xstatcavs"], 16), public) 623 private_key = private.private_key(backend) 624 public_key = private_key.public_key() 625 with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_SERIALIZATION): 626 private_key.private_bytes( 627 serialization.Encoding.PEM, 628 serialization.PrivateFormat.PKCS8, 629 serialization.NoEncryption(), 630 ) 631 with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_SERIALIZATION): 632 public_key.public_bytes( 633 serialization.Encoding.PEM, 634 serialization.PublicFormat.SubjectPublicKeyInfo, 635 ) 636 with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_SERIALIZATION): 637 parameters.parameters(backend).parameter_bytes( 638 serialization.Encoding.PEM, serialization.ParameterFormat.PKCS3 639 ) 640 641 @pytest.mark.parametrize( 642 ("key_path", "loader_func"), 643 [ 644 ( 645 os.path.join("asymmetric", "DH", "dhkey_rfc5114_2.pem"), 646 serialization.load_pem_private_key, 647 ), 648 ( 649 os.path.join("asymmetric", "DH", "dhkey_rfc5114_2.der"), 650 serialization.load_der_private_key, 651 ), 652 ], 653 ) 654 def test_private_load_dhx_unsupported( 655 self, key_path, loader_func, backend 656 ): 657 key_bytes = load_vectors_from_file( 658 key_path, lambda pemfile: pemfile.read(), mode="rb" 659 ) 660 with pytest.raises(ValueError): 661 loader_func(key_bytes, None, backend) 662 663 @pytest.mark.parametrize( 664 ("key_path", "loader_func"), 665 [ 666 ( 667 os.path.join("asymmetric", "DH", "dhpub_rfc5114_2.pem"), 668 serialization.load_pem_public_key, 669 ), 670 ( 671 os.path.join("asymmetric", "DH", "dhpub_rfc5114_2.der"), 672 serialization.load_der_public_key, 673 ), 674 ], 675 ) 676 def test_public_load_dhx_unsupported(self, key_path, loader_func, backend): 677 key_bytes = load_vectors_from_file( 678 key_path, lambda pemfile: pemfile.read(), mode="rb" 679 ) 680 with pytest.raises(ValueError): 681 loader_func(key_bytes, backend) 682