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 9 10import pytest 11 12from cryptography.exceptions import AlreadyFinalized, InvalidSignature 13from cryptography.hazmat.backends.interfaces import ( 14 DSABackend, 15 PEMSerializationBackend, 16) 17from cryptography.hazmat.primitives import hashes, serialization 18from cryptography.hazmat.primitives.asymmetric import dsa 19from cryptography.hazmat.primitives.asymmetric.utils import ( 20 Prehashed, 21 encode_dss_signature, 22) 23from cryptography.utils import CryptographyDeprecationWarning 24 25from .fixtures_dsa import DSA_KEY_1024, DSA_KEY_2048, DSA_KEY_3072 26from .utils import skip_fips_traditional_openssl 27from ...doubles import DummyHashAlgorithm, DummyKeySerializationEncryption 28from ...utils import ( 29 load_fips_dsa_key_pair_vectors, 30 load_fips_dsa_sig_vectors, 31 load_vectors_from_file, 32) 33 34 35def _skip_if_dsa_not_supported(backend, algorithm, p, q, g): 36 if not backend.dsa_parameters_supported( 37 p, q, g 38 ) or not backend.dsa_hash_supported(algorithm): 39 pytest.skip( 40 "{} does not support the provided parameters".format(backend) 41 ) 42 43 44@pytest.mark.requires_backend_interface(interface=DSABackend) 45def test_skip_if_dsa_not_supported(backend): 46 with pytest.raises(pytest.skip.Exception): 47 _skip_if_dsa_not_supported(backend, DummyHashAlgorithm(), 1, 1, 1) 48 49 50@pytest.mark.requires_backend_interface(interface=DSABackend) 51class TestDSA(object): 52 def test_generate_dsa_parameters(self, backend): 53 parameters = dsa.generate_parameters(2048, backend) 54 assert isinstance(parameters, dsa.DSAParameters) 55 56 def test_generate_invalid_dsa_parameters(self, backend): 57 with pytest.raises(ValueError): 58 dsa.generate_parameters(1, backend) 59 60 @pytest.mark.parametrize( 61 "vector", 62 load_vectors_from_file( 63 os.path.join("asymmetric", "DSA", "FIPS_186-3", "KeyPair.rsp"), 64 load_fips_dsa_key_pair_vectors, 65 ), 66 ) 67 def test_generate_dsa_keys(self, vector, backend): 68 if ( 69 backend._fips_enabled 70 and vector["p"] < backend._fips_dsa_min_modulus 71 ): 72 pytest.skip("Small modulus blocked in FIPS mode") 73 parameters = dsa.DSAParameterNumbers( 74 p=vector["p"], q=vector["q"], g=vector["g"] 75 ).parameters(backend) 76 skey = parameters.generate_private_key() 77 numbers = skey.private_numbers() 78 skey_parameters = numbers.public_numbers.parameter_numbers 79 pkey = skey.public_key() 80 parameters = pkey.parameters() 81 parameter_numbers = parameters.parameter_numbers() 82 assert parameter_numbers.p == skey_parameters.p 83 assert parameter_numbers.q == skey_parameters.q 84 assert parameter_numbers.g == skey_parameters.g 85 assert skey_parameters.p == vector["p"] 86 assert skey_parameters.q == vector["q"] 87 assert skey_parameters.g == vector["g"] 88 assert skey.key_size == vector["p"].bit_length() 89 assert pkey.key_size == skey.key_size 90 public_numbers = pkey.public_numbers() 91 assert numbers.public_numbers.y == public_numbers.y 92 assert numbers.public_numbers.y == pow( 93 skey_parameters.g, numbers.x, skey_parameters.p 94 ) 95 96 def test_generate_dsa_private_key_and_parameters(self, backend): 97 skey = dsa.generate_private_key(2048, backend) 98 assert skey 99 numbers = skey.private_numbers() 100 skey_parameters = numbers.public_numbers.parameter_numbers 101 assert numbers.public_numbers.y == pow( 102 skey_parameters.g, numbers.x, skey_parameters.p 103 ) 104 105 @pytest.mark.parametrize( 106 ("p", "q", "g"), 107 [ 108 ( 109 2 ** 1000, 110 DSA_KEY_1024.public_numbers.parameter_numbers.q, 111 DSA_KEY_1024.public_numbers.parameter_numbers.g, 112 ), 113 ( 114 2 ** 2000, 115 DSA_KEY_2048.public_numbers.parameter_numbers.q, 116 DSA_KEY_2048.public_numbers.parameter_numbers.g, 117 ), 118 ( 119 2 ** 3000, 120 DSA_KEY_3072.public_numbers.parameter_numbers.q, 121 DSA_KEY_3072.public_numbers.parameter_numbers.g, 122 ), 123 ( 124 2 ** 3100, 125 DSA_KEY_3072.public_numbers.parameter_numbers.q, 126 DSA_KEY_3072.public_numbers.parameter_numbers.g, 127 ), 128 ( 129 DSA_KEY_1024.public_numbers.parameter_numbers.p, 130 2 ** 150, 131 DSA_KEY_1024.public_numbers.parameter_numbers.g, 132 ), 133 ( 134 DSA_KEY_2048.public_numbers.parameter_numbers.p, 135 2 ** 250, 136 DSA_KEY_2048.public_numbers.parameter_numbers.g, 137 ), 138 ( 139 DSA_KEY_3072.public_numbers.parameter_numbers.p, 140 2 ** 260, 141 DSA_KEY_3072.public_numbers.parameter_numbers.g, 142 ), 143 ( 144 DSA_KEY_1024.public_numbers.parameter_numbers.p, 145 DSA_KEY_1024.public_numbers.parameter_numbers.q, 146 0, 147 ), 148 ( 149 DSA_KEY_1024.public_numbers.parameter_numbers.p, 150 DSA_KEY_1024.public_numbers.parameter_numbers.q, 151 1, 152 ), 153 ( 154 DSA_KEY_1024.public_numbers.parameter_numbers.p, 155 DSA_KEY_1024.public_numbers.parameter_numbers.q, 156 2 ** 1200, 157 ), 158 ], 159 ) 160 def test_invalid_parameters_values(self, p, q, g, backend): 161 with pytest.raises(ValueError): 162 dsa.DSAParameterNumbers(p, q, g).parameters(backend) 163 164 @pytest.mark.parametrize( 165 ("p", "q", "g", "y", "x"), 166 [ 167 ( 168 2 ** 1000, 169 DSA_KEY_1024.public_numbers.parameter_numbers.q, 170 DSA_KEY_1024.public_numbers.parameter_numbers.g, 171 DSA_KEY_1024.public_numbers.y, 172 DSA_KEY_1024.x, 173 ), 174 ( 175 2 ** 2000, 176 DSA_KEY_2048.public_numbers.parameter_numbers.q, 177 DSA_KEY_2048.public_numbers.parameter_numbers.g, 178 DSA_KEY_2048.public_numbers.y, 179 DSA_KEY_2048.x, 180 ), 181 ( 182 2 ** 3000, 183 DSA_KEY_3072.public_numbers.parameter_numbers.q, 184 DSA_KEY_3072.public_numbers.parameter_numbers.g, 185 DSA_KEY_3072.public_numbers.y, 186 DSA_KEY_3072.x, 187 ), 188 ( 189 2 ** 3100, 190 DSA_KEY_3072.public_numbers.parameter_numbers.q, 191 DSA_KEY_3072.public_numbers.parameter_numbers.g, 192 DSA_KEY_3072.public_numbers.y, 193 DSA_KEY_3072.x, 194 ), 195 ( 196 DSA_KEY_1024.public_numbers.parameter_numbers.p, 197 2 ** 150, 198 DSA_KEY_1024.public_numbers.parameter_numbers.g, 199 DSA_KEY_1024.public_numbers.y, 200 DSA_KEY_1024.x, 201 ), 202 ( 203 DSA_KEY_2048.public_numbers.parameter_numbers.p, 204 2 ** 250, 205 DSA_KEY_2048.public_numbers.parameter_numbers.g, 206 DSA_KEY_2048.public_numbers.y, 207 DSA_KEY_2048.x, 208 ), 209 ( 210 DSA_KEY_3072.public_numbers.parameter_numbers.p, 211 2 ** 260, 212 DSA_KEY_3072.public_numbers.parameter_numbers.g, 213 DSA_KEY_3072.public_numbers.y, 214 DSA_KEY_3072.x, 215 ), 216 ( 217 DSA_KEY_1024.public_numbers.parameter_numbers.p, 218 DSA_KEY_1024.public_numbers.parameter_numbers.q, 219 0, 220 DSA_KEY_1024.public_numbers.y, 221 DSA_KEY_1024.x, 222 ), 223 ( 224 DSA_KEY_1024.public_numbers.parameter_numbers.p, 225 DSA_KEY_1024.public_numbers.parameter_numbers.q, 226 1, 227 DSA_KEY_1024.public_numbers.y, 228 DSA_KEY_1024.x, 229 ), 230 ( 231 DSA_KEY_1024.public_numbers.parameter_numbers.p, 232 DSA_KEY_1024.public_numbers.parameter_numbers.q, 233 2 ** 1200, 234 DSA_KEY_1024.public_numbers.y, 235 DSA_KEY_1024.x, 236 ), 237 ( 238 DSA_KEY_1024.public_numbers.parameter_numbers.p, 239 DSA_KEY_1024.public_numbers.parameter_numbers.q, 240 DSA_KEY_1024.public_numbers.parameter_numbers.g, 241 DSA_KEY_1024.public_numbers.y, 242 0, 243 ), 244 ( 245 DSA_KEY_1024.public_numbers.parameter_numbers.p, 246 DSA_KEY_1024.public_numbers.parameter_numbers.q, 247 DSA_KEY_1024.public_numbers.parameter_numbers.g, 248 DSA_KEY_1024.public_numbers.y, 249 -2, 250 ), 251 ( 252 DSA_KEY_1024.public_numbers.parameter_numbers.p, 253 DSA_KEY_1024.public_numbers.parameter_numbers.q, 254 DSA_KEY_1024.public_numbers.parameter_numbers.g, 255 DSA_KEY_1024.public_numbers.y, 256 2 ** 159, 257 ), 258 ( 259 DSA_KEY_1024.public_numbers.parameter_numbers.p, 260 DSA_KEY_1024.public_numbers.parameter_numbers.q, 261 DSA_KEY_1024.public_numbers.parameter_numbers.g, 262 DSA_KEY_1024.public_numbers.y, 263 2 ** 200, 264 ), 265 ( 266 DSA_KEY_1024.public_numbers.parameter_numbers.p, 267 DSA_KEY_1024.public_numbers.parameter_numbers.q, 268 DSA_KEY_1024.public_numbers.parameter_numbers.g, 269 2 ** 100, 270 DSA_KEY_1024.x, 271 ), 272 ], 273 ) 274 def test_invalid_dsa_private_key_arguments(self, p, q, g, y, x, backend): 275 with pytest.raises(ValueError): 276 dsa.DSAPrivateNumbers( 277 public_numbers=dsa.DSAPublicNumbers( 278 parameter_numbers=dsa.DSAParameterNumbers(p=p, q=q, g=g), 279 y=y, 280 ), 281 x=x, 282 ).private_key(backend) 283 284 @pytest.mark.parametrize( 285 ("p", "q", "g", "y"), 286 [ 287 ( 288 2 ** 1000, 289 DSA_KEY_1024.public_numbers.parameter_numbers.q, 290 DSA_KEY_1024.public_numbers.parameter_numbers.g, 291 DSA_KEY_1024.public_numbers.y, 292 ), 293 ( 294 2 ** 2000, 295 DSA_KEY_2048.public_numbers.parameter_numbers.q, 296 DSA_KEY_2048.public_numbers.parameter_numbers.g, 297 DSA_KEY_2048.public_numbers.y, 298 ), 299 ( 300 2 ** 3000, 301 DSA_KEY_3072.public_numbers.parameter_numbers.q, 302 DSA_KEY_3072.public_numbers.parameter_numbers.g, 303 DSA_KEY_3072.public_numbers.y, 304 ), 305 ( 306 2 ** 3100, 307 DSA_KEY_3072.public_numbers.parameter_numbers.q, 308 DSA_KEY_3072.public_numbers.parameter_numbers.g, 309 DSA_KEY_3072.public_numbers.y, 310 ), 311 ( 312 DSA_KEY_1024.public_numbers.parameter_numbers.p, 313 2 ** 150, 314 DSA_KEY_1024.public_numbers.parameter_numbers.g, 315 DSA_KEY_1024.public_numbers.y, 316 ), 317 ( 318 DSA_KEY_2048.public_numbers.parameter_numbers.p, 319 2 ** 250, 320 DSA_KEY_2048.public_numbers.parameter_numbers.g, 321 DSA_KEY_2048.public_numbers.y, 322 ), 323 ( 324 DSA_KEY_3072.public_numbers.parameter_numbers.p, 325 2 ** 260, 326 DSA_KEY_3072.public_numbers.parameter_numbers.g, 327 DSA_KEY_3072.public_numbers.y, 328 ), 329 ( 330 DSA_KEY_1024.public_numbers.parameter_numbers.p, 331 DSA_KEY_1024.public_numbers.parameter_numbers.q, 332 0, 333 DSA_KEY_1024.public_numbers.y, 334 ), 335 ( 336 DSA_KEY_1024.public_numbers.parameter_numbers.p, 337 DSA_KEY_1024.public_numbers.parameter_numbers.q, 338 1, 339 DSA_KEY_1024.public_numbers.y, 340 ), 341 ( 342 DSA_KEY_1024.public_numbers.parameter_numbers.p, 343 DSA_KEY_1024.public_numbers.parameter_numbers.q, 344 2 ** 1200, 345 DSA_KEY_1024.public_numbers.y, 346 ), 347 ], 348 ) 349 def test_invalid_dsa_public_key_arguments(self, p, q, g, y, backend): 350 with pytest.raises(ValueError): 351 dsa.DSAPublicNumbers( 352 parameter_numbers=dsa.DSAParameterNumbers(p=p, q=q, g=g), y=y 353 ).public_key(backend) 354 355 def test_large_p(self, backend): 356 key = load_vectors_from_file( 357 os.path.join("asymmetric", "PEM_Serialization", "dsa_4096.pem"), 358 lambda pemfile: serialization.load_pem_private_key( 359 pemfile.read(), None, backend 360 ), 361 mode="rb", 362 ) 363 pn = key.private_numbers() 364 assert pn.public_numbers.parameter_numbers.p.bit_length() == 4096 365 # Turn it back into a key to confirm that values this large pass 366 # verification 367 dsa.DSAPrivateNumbers( 368 public_numbers=dsa.DSAPublicNumbers( 369 parameter_numbers=dsa.DSAParameterNumbers( 370 p=pn.public_numbers.parameter_numbers.p, 371 q=pn.public_numbers.parameter_numbers.q, 372 g=pn.public_numbers.parameter_numbers.g, 373 ), 374 y=pn.public_numbers.y, 375 ), 376 x=pn.x, 377 ).private_key(backend) 378 379 380@pytest.mark.requires_backend_interface(interface=DSABackend) 381class TestDSAVerification(object): 382 _algorithms_dict = { 383 "SHA1": hashes.SHA1, 384 "SHA224": hashes.SHA224, 385 "SHA256": hashes.SHA256, 386 "SHA384": hashes.SHA384, 387 "SHA512": hashes.SHA512, 388 } 389 390 @pytest.mark.parametrize( 391 "vector", 392 load_vectors_from_file( 393 os.path.join("asymmetric", "DSA", "FIPS_186-3", "SigVer.rsp"), 394 load_fips_dsa_sig_vectors, 395 ), 396 ) 397 def test_dsa_verification(self, vector, backend): 398 digest_algorithm = vector["digest_algorithm"].replace("-", "") 399 algorithm = self._algorithms_dict[digest_algorithm] 400 401 _skip_if_dsa_not_supported( 402 backend, algorithm, vector["p"], vector["q"], vector["g"] 403 ) 404 405 public_key = dsa.DSAPublicNumbers( 406 parameter_numbers=dsa.DSAParameterNumbers( 407 vector["p"], vector["q"], vector["g"] 408 ), 409 y=vector["y"], 410 ).public_key(backend) 411 sig = encode_dss_signature(vector["r"], vector["s"]) 412 413 if vector["result"] == "F": 414 with pytest.raises(InvalidSignature): 415 public_key.verify(sig, vector["msg"], algorithm()) 416 else: 417 public_key.verify(sig, vector["msg"], algorithm()) 418 419 def test_dsa_verify_invalid_asn1(self, backend): 420 public_key = DSA_KEY_1024.public_numbers.public_key(backend) 421 with pytest.raises(InvalidSignature): 422 public_key.verify(b"fakesig", b"fakemsg", hashes.SHA1()) 423 424 def test_signature_not_bytes(self, backend): 425 public_key = DSA_KEY_1024.public_numbers.public_key(backend) 426 with pytest.raises(TypeError), pytest.warns( 427 CryptographyDeprecationWarning 428 ): 429 public_key.verifier(1234, hashes.SHA1()) 430 431 def test_use_after_finalize(self, backend): 432 public_key = DSA_KEY_1024.public_numbers.public_key(backend) 433 with pytest.warns(CryptographyDeprecationWarning): 434 verifier = public_key.verifier(b"fakesig", hashes.SHA1()) 435 verifier.update(b"irrelevant") 436 with pytest.raises(InvalidSignature): 437 verifier.verify() 438 with pytest.raises(AlreadyFinalized): 439 verifier.verify() 440 with pytest.raises(AlreadyFinalized): 441 verifier.update(b"more data") 442 443 def test_verify(self, backend): 444 message = b"one little message" 445 algorithm = hashes.SHA1() 446 private_key = DSA_KEY_1024.private_key(backend) 447 signature = private_key.sign(message, algorithm) 448 public_key = private_key.public_key() 449 public_key.verify(signature, message, algorithm) 450 451 def test_prehashed_verify(self, backend): 452 private_key = DSA_KEY_1024.private_key(backend) 453 message = b"one little message" 454 h = hashes.Hash(hashes.SHA1(), backend) 455 h.update(message) 456 digest = h.finalize() 457 prehashed_alg = Prehashed(hashes.SHA1()) 458 signature = private_key.sign(message, hashes.SHA1()) 459 public_key = private_key.public_key() 460 public_key.verify(signature, digest, prehashed_alg) 461 462 def test_prehashed_digest_mismatch(self, backend): 463 private_key = DSA_KEY_1024.private_key(backend) 464 public_key = private_key.public_key() 465 message = b"one little message" 466 h = hashes.Hash(hashes.SHA1(), backend) 467 h.update(message) 468 digest = h.finalize() 469 prehashed_alg = Prehashed(hashes.SHA224()) 470 with pytest.raises(ValueError): 471 public_key.verify(b"\x00" * 128, digest, prehashed_alg) 472 473 def test_prehashed_unsupported_in_signer_ctx(self, backend): 474 private_key = DSA_KEY_1024.private_key(backend) 475 with pytest.raises(TypeError), pytest.warns( 476 CryptographyDeprecationWarning 477 ): 478 private_key.signer(Prehashed(hashes.SHA1())) 479 480 def test_prehashed_unsupported_in_verifier_ctx(self, backend): 481 public_key = DSA_KEY_1024.private_key(backend).public_key() 482 with pytest.raises(TypeError), pytest.warns( 483 CryptographyDeprecationWarning 484 ): 485 public_key.verifier(b"0" * 64, Prehashed(hashes.SHA1())) 486 487 488@pytest.mark.requires_backend_interface(interface=DSABackend) 489class TestDSASignature(object): 490 _algorithms_dict = { 491 "SHA1": hashes.SHA1, 492 "SHA224": hashes.SHA224, 493 "SHA256": hashes.SHA256, 494 "SHA384": hashes.SHA384, 495 "SHA512": hashes.SHA512, 496 } 497 498 @pytest.mark.parametrize( 499 "vector", 500 load_vectors_from_file( 501 os.path.join("asymmetric", "DSA", "FIPS_186-3", "SigGen.txt"), 502 load_fips_dsa_sig_vectors, 503 ), 504 ) 505 def test_dsa_signing(self, vector, backend): 506 digest_algorithm = vector["digest_algorithm"].replace("-", "") 507 algorithm = self._algorithms_dict[digest_algorithm] 508 509 _skip_if_dsa_not_supported( 510 backend, algorithm, vector["p"], vector["q"], vector["g"] 511 ) 512 513 private_key = dsa.DSAPrivateNumbers( 514 public_numbers=dsa.DSAPublicNumbers( 515 parameter_numbers=dsa.DSAParameterNumbers( 516 vector["p"], vector["q"], vector["g"] 517 ), 518 y=vector["y"], 519 ), 520 x=vector["x"], 521 ).private_key(backend) 522 signature = private_key.sign(vector["msg"], algorithm()) 523 assert signature 524 525 private_key.public_key().verify(signature, vector["msg"], algorithm()) 526 527 def test_use_after_finalize(self, backend): 528 private_key = DSA_KEY_1024.private_key(backend) 529 with pytest.warns(CryptographyDeprecationWarning): 530 signer = private_key.signer(hashes.SHA1()) 531 signer.update(b"data") 532 signer.finalize() 533 with pytest.raises(AlreadyFinalized): 534 signer.finalize() 535 with pytest.raises(AlreadyFinalized): 536 signer.update(b"more data") 537 538 def test_sign(self, backend): 539 private_key = DSA_KEY_1024.private_key(backend) 540 message = b"one little message" 541 algorithm = hashes.SHA1() 542 signature = private_key.sign(message, algorithm) 543 public_key = private_key.public_key() 544 public_key.verify(signature, message, algorithm) 545 546 def test_prehashed_sign(self, backend): 547 private_key = DSA_KEY_1024.private_key(backend) 548 message = b"one little message" 549 h = hashes.Hash(hashes.SHA1(), backend) 550 h.update(message) 551 digest = h.finalize() 552 prehashed_alg = Prehashed(hashes.SHA1()) 553 signature = private_key.sign(digest, prehashed_alg) 554 public_key = private_key.public_key() 555 public_key.verify(signature, message, hashes.SHA1()) 556 557 def test_prehashed_digest_mismatch(self, backend): 558 private_key = DSA_KEY_1024.private_key(backend) 559 message = b"one little message" 560 h = hashes.Hash(hashes.SHA1(), backend) 561 h.update(message) 562 digest = h.finalize() 563 prehashed_alg = Prehashed(hashes.SHA224()) 564 with pytest.raises(ValueError): 565 private_key.sign(digest, prehashed_alg) 566 567 568class TestDSANumbers(object): 569 def test_dsa_parameter_numbers(self): 570 parameter_numbers = dsa.DSAParameterNumbers(p=1, q=2, g=3) 571 assert parameter_numbers.p == 1 572 assert parameter_numbers.q == 2 573 assert parameter_numbers.g == 3 574 575 def test_dsa_parameter_numbers_invalid_types(self): 576 with pytest.raises(TypeError): 577 dsa.DSAParameterNumbers(p=None, q=2, g=3) 578 579 with pytest.raises(TypeError): 580 dsa.DSAParameterNumbers(p=1, q=None, g=3) 581 582 with pytest.raises(TypeError): 583 dsa.DSAParameterNumbers(p=1, q=2, g=None) 584 585 def test_dsa_public_numbers(self): 586 parameter_numbers = dsa.DSAParameterNumbers(p=1, q=2, g=3) 587 public_numbers = dsa.DSAPublicNumbers( 588 y=4, parameter_numbers=parameter_numbers 589 ) 590 assert public_numbers.y == 4 591 assert public_numbers.parameter_numbers == parameter_numbers 592 593 def test_dsa_public_numbers_invalid_types(self): 594 with pytest.raises(TypeError): 595 dsa.DSAPublicNumbers(y=4, parameter_numbers=None) 596 597 with pytest.raises(TypeError): 598 parameter_numbers = dsa.DSAParameterNumbers(p=1, q=2, g=3) 599 dsa.DSAPublicNumbers(y=None, parameter_numbers=parameter_numbers) 600 601 def test_dsa_private_numbers(self): 602 parameter_numbers = dsa.DSAParameterNumbers(p=1, q=2, g=3) 603 public_numbers = dsa.DSAPublicNumbers( 604 y=4, parameter_numbers=parameter_numbers 605 ) 606 private_numbers = dsa.DSAPrivateNumbers( 607 x=5, public_numbers=public_numbers 608 ) 609 assert private_numbers.x == 5 610 assert private_numbers.public_numbers == public_numbers 611 612 def test_dsa_private_numbers_invalid_types(self): 613 parameter_numbers = dsa.DSAParameterNumbers(p=1, q=2, g=3) 614 public_numbers = dsa.DSAPublicNumbers( 615 y=4, parameter_numbers=parameter_numbers 616 ) 617 with pytest.raises(TypeError): 618 dsa.DSAPrivateNumbers(x=4, public_numbers=None) 619 620 with pytest.raises(TypeError): 621 dsa.DSAPrivateNumbers(x=None, public_numbers=public_numbers) 622 623 def test_repr(self): 624 parameter_numbers = dsa.DSAParameterNumbers(p=1, q=2, g=3) 625 assert ( 626 repr(parameter_numbers) == "<DSAParameterNumbers(p=1, q=2, g=3)>" 627 ) 628 629 public_numbers = dsa.DSAPublicNumbers( 630 y=4, parameter_numbers=parameter_numbers 631 ) 632 assert repr(public_numbers) == ( 633 "<DSAPublicNumbers(y=4, parameter_numbers=<DSAParameterNumbers(p=1" 634 ", q=2, g=3)>)>" 635 ) 636 637 638class TestDSANumberEquality(object): 639 def test_parameter_numbers_eq(self): 640 param = dsa.DSAParameterNumbers(1, 2, 3) 641 assert param == dsa.DSAParameterNumbers(1, 2, 3) 642 643 def test_parameter_numbers_ne(self): 644 param = dsa.DSAParameterNumbers(1, 2, 3) 645 assert param != dsa.DSAParameterNumbers(1, 2, 4) 646 assert param != dsa.DSAParameterNumbers(1, 1, 3) 647 assert param != dsa.DSAParameterNumbers(2, 2, 3) 648 assert param != object() 649 650 def test_public_numbers_eq(self): 651 pub = dsa.DSAPublicNumbers(1, dsa.DSAParameterNumbers(1, 2, 3)) 652 assert pub == dsa.DSAPublicNumbers(1, dsa.DSAParameterNumbers(1, 2, 3)) 653 654 def test_public_numbers_ne(self): 655 pub = dsa.DSAPublicNumbers(1, dsa.DSAParameterNumbers(1, 2, 3)) 656 assert pub != dsa.DSAPublicNumbers(2, dsa.DSAParameterNumbers(1, 2, 3)) 657 assert pub != dsa.DSAPublicNumbers(1, dsa.DSAParameterNumbers(2, 2, 3)) 658 assert pub != dsa.DSAPublicNumbers(1, dsa.DSAParameterNumbers(1, 3, 3)) 659 assert pub != dsa.DSAPublicNumbers(1, dsa.DSAParameterNumbers(1, 2, 4)) 660 assert pub != object() 661 662 def test_private_numbers_eq(self): 663 pub = dsa.DSAPublicNumbers(1, dsa.DSAParameterNumbers(1, 2, 3)) 664 priv = dsa.DSAPrivateNumbers(1, pub) 665 assert priv == dsa.DSAPrivateNumbers( 666 1, dsa.DSAPublicNumbers(1, dsa.DSAParameterNumbers(1, 2, 3)) 667 ) 668 669 def test_private_numbers_ne(self): 670 pub = dsa.DSAPublicNumbers(1, dsa.DSAParameterNumbers(1, 2, 3)) 671 priv = dsa.DSAPrivateNumbers(1, pub) 672 assert priv != dsa.DSAPrivateNumbers( 673 2, dsa.DSAPublicNumbers(1, dsa.DSAParameterNumbers(1, 2, 3)) 674 ) 675 assert priv != dsa.DSAPrivateNumbers( 676 1, dsa.DSAPublicNumbers(2, dsa.DSAParameterNumbers(1, 2, 3)) 677 ) 678 assert priv != dsa.DSAPrivateNumbers( 679 1, dsa.DSAPublicNumbers(1, dsa.DSAParameterNumbers(2, 2, 3)) 680 ) 681 assert priv != dsa.DSAPrivateNumbers( 682 1, dsa.DSAPublicNumbers(1, dsa.DSAParameterNumbers(1, 3, 3)) 683 ) 684 assert priv != dsa.DSAPrivateNumbers( 685 1, dsa.DSAPublicNumbers(1, dsa.DSAParameterNumbers(1, 2, 4)) 686 ) 687 assert priv != object() 688 689 690@pytest.mark.requires_backend_interface(interface=DSABackend) 691@pytest.mark.requires_backend_interface(interface=PEMSerializationBackend) 692class TestDSASerialization(object): 693 @pytest.mark.parametrize( 694 ("fmt", "password"), 695 itertools.product( 696 [ 697 serialization.PrivateFormat.TraditionalOpenSSL, 698 serialization.PrivateFormat.PKCS8, 699 ], 700 [ 701 b"s", 702 b"longerpassword", 703 b"!*$&(@#$*&($T@%_somesymbols", 704 b"\x01" * 1000, 705 ], 706 ), 707 ) 708 def test_private_bytes_encrypted_pem(self, backend, fmt, password): 709 skip_fips_traditional_openssl(backend, fmt) 710 key_bytes = load_vectors_from_file( 711 os.path.join("asymmetric", "PKCS8", "unenc-dsa-pkcs8.pem"), 712 lambda pemfile: pemfile.read().encode(), 713 ) 714 key = serialization.load_pem_private_key(key_bytes, None, backend) 715 serialized = key.private_bytes( 716 serialization.Encoding.PEM, 717 fmt, 718 serialization.BestAvailableEncryption(password), 719 ) 720 loaded_key = serialization.load_pem_private_key( 721 serialized, password, backend 722 ) 723 loaded_priv_num = loaded_key.private_numbers() 724 priv_num = key.private_numbers() 725 assert loaded_priv_num == priv_num 726 727 @pytest.mark.parametrize( 728 ("encoding", "fmt"), 729 [ 730 (serialization.Encoding.Raw, serialization.PrivateFormat.PKCS8), 731 (serialization.Encoding.DER, serialization.PrivateFormat.Raw), 732 (serialization.Encoding.Raw, serialization.PrivateFormat.Raw), 733 (serialization.Encoding.X962, serialization.PrivateFormat.PKCS8), 734 ], 735 ) 736 def test_private_bytes_rejects_invalid(self, encoding, fmt, backend): 737 key = DSA_KEY_1024.private_key(backend) 738 with pytest.raises(ValueError): 739 key.private_bytes(encoding, fmt, serialization.NoEncryption()) 740 741 @pytest.mark.parametrize( 742 ("fmt", "password"), 743 [ 744 [serialization.PrivateFormat.PKCS8, b"s"], 745 [serialization.PrivateFormat.PKCS8, b"longerpassword"], 746 [serialization.PrivateFormat.PKCS8, b"!*$&(@#$*&($T@%_somesymbol"], 747 [serialization.PrivateFormat.PKCS8, b"\x01" * 1000], 748 ], 749 ) 750 def test_private_bytes_encrypted_der(self, backend, fmt, password): 751 key_bytes = load_vectors_from_file( 752 os.path.join("asymmetric", "PKCS8", "unenc-dsa-pkcs8.pem"), 753 lambda pemfile: pemfile.read().encode(), 754 ) 755 key = serialization.load_pem_private_key(key_bytes, None, backend) 756 serialized = key.private_bytes( 757 serialization.Encoding.DER, 758 fmt, 759 serialization.BestAvailableEncryption(password), 760 ) 761 loaded_key = serialization.load_der_private_key( 762 serialized, password, backend 763 ) 764 loaded_priv_num = loaded_key.private_numbers() 765 priv_num = key.private_numbers() 766 assert loaded_priv_num == priv_num 767 768 @pytest.mark.parametrize( 769 ("encoding", "fmt", "loader_func"), 770 [ 771 [ 772 serialization.Encoding.PEM, 773 serialization.PrivateFormat.TraditionalOpenSSL, 774 serialization.load_pem_private_key, 775 ], 776 [ 777 serialization.Encoding.DER, 778 serialization.PrivateFormat.TraditionalOpenSSL, 779 serialization.load_der_private_key, 780 ], 781 [ 782 serialization.Encoding.PEM, 783 serialization.PrivateFormat.PKCS8, 784 serialization.load_pem_private_key, 785 ], 786 [ 787 serialization.Encoding.DER, 788 serialization.PrivateFormat.PKCS8, 789 serialization.load_der_private_key, 790 ], 791 ], 792 ) 793 def test_private_bytes_unencrypted( 794 self, backend, encoding, fmt, loader_func 795 ): 796 key = DSA_KEY_1024.private_key(backend) 797 serialized = key.private_bytes( 798 encoding, fmt, serialization.NoEncryption() 799 ) 800 loaded_key = loader_func(serialized, None, backend) 801 loaded_priv_num = loaded_key.private_numbers() 802 priv_num = key.private_numbers() 803 assert loaded_priv_num == priv_num 804 805 @pytest.mark.skip_fips( 806 reason="Traditional OpenSSL key format is not supported in FIPS mode." 807 ) 808 @pytest.mark.parametrize( 809 ("key_path", "encoding", "loader_func"), 810 [ 811 [ 812 os.path.join( 813 "asymmetric", 814 "Traditional_OpenSSL_Serialization", 815 "dsa.1024.pem", 816 ), 817 serialization.Encoding.PEM, 818 serialization.load_pem_private_key, 819 ], 820 [ 821 os.path.join( 822 "asymmetric", "DER_Serialization", "dsa.1024.der" 823 ), 824 serialization.Encoding.DER, 825 serialization.load_der_private_key, 826 ], 827 ], 828 ) 829 def test_private_bytes_traditional_openssl_unencrypted( 830 self, backend, key_path, encoding, loader_func 831 ): 832 key_bytes = load_vectors_from_file( 833 key_path, lambda pemfile: pemfile.read(), mode="rb" 834 ) 835 key = loader_func(key_bytes, None, backend) 836 serialized = key.private_bytes( 837 encoding, 838 serialization.PrivateFormat.TraditionalOpenSSL, 839 serialization.NoEncryption(), 840 ) 841 assert serialized == key_bytes 842 843 def test_private_bytes_traditional_der_encrypted_invalid(self, backend): 844 key = DSA_KEY_1024.private_key(backend) 845 with pytest.raises(ValueError): 846 key.private_bytes( 847 serialization.Encoding.DER, 848 serialization.PrivateFormat.TraditionalOpenSSL, 849 serialization.BestAvailableEncryption(b"password"), 850 ) 851 852 def test_private_bytes_invalid_encoding(self, backend): 853 key = load_vectors_from_file( 854 os.path.join("asymmetric", "PKCS8", "unenc-dsa-pkcs8.pem"), 855 lambda pemfile: serialization.load_pem_private_key( 856 pemfile.read().encode(), None, backend 857 ), 858 ) 859 with pytest.raises(TypeError): 860 key.private_bytes( 861 "notencoding", 862 serialization.PrivateFormat.PKCS8, 863 serialization.NoEncryption(), 864 ) 865 866 def test_private_bytes_invalid_format(self, backend): 867 key = load_vectors_from_file( 868 os.path.join("asymmetric", "PKCS8", "unenc-dsa-pkcs8.pem"), 869 lambda pemfile: serialization.load_pem_private_key( 870 pemfile.read().encode(), None, backend 871 ), 872 ) 873 with pytest.raises(TypeError): 874 key.private_bytes( 875 serialization.Encoding.PEM, 876 "invalidformat", 877 serialization.NoEncryption(), 878 ) 879 880 def test_private_bytes_invalid_encryption_algorithm(self, backend): 881 key = load_vectors_from_file( 882 os.path.join("asymmetric", "PKCS8", "unenc-dsa-pkcs8.pem"), 883 lambda pemfile: serialization.load_pem_private_key( 884 pemfile.read().encode(), None, backend 885 ), 886 ) 887 with pytest.raises(TypeError): 888 key.private_bytes( 889 serialization.Encoding.PEM, 890 serialization.PrivateFormat.TraditionalOpenSSL, 891 "notanencalg", 892 ) 893 894 def test_private_bytes_unsupported_encryption_type(self, backend): 895 key = load_vectors_from_file( 896 os.path.join("asymmetric", "PKCS8", "unenc-dsa-pkcs8.pem"), 897 lambda pemfile: serialization.load_pem_private_key( 898 pemfile.read().encode(), None, backend 899 ), 900 ) 901 with pytest.raises(ValueError): 902 key.private_bytes( 903 serialization.Encoding.PEM, 904 serialization.PrivateFormat.TraditionalOpenSSL, 905 DummyKeySerializationEncryption(), 906 ) 907 908 909@pytest.mark.requires_backend_interface(interface=DSABackend) 910@pytest.mark.requires_backend_interface(interface=PEMSerializationBackend) 911class TestDSAPEMPublicKeySerialization(object): 912 @pytest.mark.parametrize( 913 ("key_path", "loader_func", "encoding"), 914 [ 915 ( 916 os.path.join("asymmetric", "PKCS8", "unenc-dsa-pkcs8.pub.pem"), 917 serialization.load_pem_public_key, 918 serialization.Encoding.PEM, 919 ), 920 ( 921 os.path.join( 922 "asymmetric", 923 "DER_Serialization", 924 "unenc-dsa-pkcs8.pub.der", 925 ), 926 serialization.load_der_public_key, 927 serialization.Encoding.DER, 928 ), 929 ], 930 ) 931 def test_public_bytes_match( 932 self, key_path, loader_func, encoding, backend 933 ): 934 key_bytes = load_vectors_from_file( 935 key_path, lambda pemfile: pemfile.read(), mode="rb" 936 ) 937 key = loader_func(key_bytes, backend) 938 serialized = key.public_bytes( 939 encoding, 940 serialization.PublicFormat.SubjectPublicKeyInfo, 941 ) 942 assert serialized == key_bytes 943 944 def test_public_bytes_openssh(self, backend): 945 key_bytes = load_vectors_from_file( 946 os.path.join("asymmetric", "PKCS8", "unenc-dsa-pkcs8.pub.pem"), 947 lambda pemfile: pemfile.read(), 948 mode="rb", 949 ) 950 key = serialization.load_pem_public_key(key_bytes, backend) 951 952 ssh_bytes = key.public_bytes( 953 serialization.Encoding.OpenSSH, serialization.PublicFormat.OpenSSH 954 ) 955 assert ssh_bytes == ( 956 b"ssh-dss AAAAB3NzaC1kc3MAAACBAKoJMMwUWCUiHK/6KKwolBlqJ4M95ewhJweR" 957 b"aJQgd3Si57I4sNNvGySZosJYUIPrAUMpJEGNhn+qIS3RBx1NzrJ4J5StOTzAik1K" 958 b"2n9o1ug5pfzTS05ALYLLioy0D+wxkRv5vTYLA0yqy0xelHmSVzyekAmcGw8FlAyr" 959 b"5dLeSaFnAAAAFQCtwOhps28KwBOmgf301ImdaYIEUQAAAIEAjGtFia+lOk0QSL/D" 960 b"RtHzhsp1UhzPct2qJRKGiA7hMgH/SIkLv8M9ebrK7HHnp3hQe9XxpmQi45QVvgPn" 961 b"EUG6Mk9bkxMZKRgsiKn6QGKDYGbOvnS1xmkMfRARBsJAq369VOTjMB/Qhs5q2ski" 962 b"+ycTorCIfLoTubxozlz/8kHNMkYAAACAKyYOqX3GoSrpMsZA5989j/BKigWgMk+N" 963 b"Xxsj8V+hcP8/QgYRJO/yWGyxG0moLc3BuQ/GqE+xAQnLZ9tdLalxrq8Xvl43KEVj" 964 b"5MZNnl/ISAJYsxnw3inVTYNQcNnih5FNd9+BSR9EI7YtqYTrP0XrKin86l2uUlrG" 965 b"q2vM4Ev99bY=" 966 ) 967 968 def test_public_bytes_invalid_encoding(self, backend): 969 key = DSA_KEY_2048.private_key(backend).public_key() 970 with pytest.raises(TypeError): 971 key.public_bytes( 972 "notencoding", serialization.PublicFormat.SubjectPublicKeyInfo 973 ) 974 975 def test_public_bytes_invalid_format(self, backend): 976 key = DSA_KEY_2048.private_key(backend).public_key() 977 with pytest.raises(TypeError): 978 key.public_bytes(serialization.Encoding.PEM, "invalidformat") 979 980 def test_public_bytes_pkcs1_unsupported(self, backend): 981 key = DSA_KEY_2048.private_key(backend).public_key() 982 with pytest.raises(ValueError): 983 key.public_bytes( 984 serialization.Encoding.PEM, serialization.PublicFormat.PKCS1 985 ) 986 987 @pytest.mark.parametrize( 988 ("encoding", "fmt"), 989 [ 990 ( 991 serialization.Encoding.Raw, 992 serialization.PublicFormat.SubjectPublicKeyInfo, 993 ), 994 (serialization.Encoding.Raw, serialization.PublicFormat.PKCS1), 995 ] 996 + list( 997 itertools.product( 998 [ 999 serialization.Encoding.Raw, 1000 serialization.Encoding.X962, 1001 serialization.Encoding.PEM, 1002 serialization.Encoding.DER, 1003 ], 1004 [ 1005 serialization.PublicFormat.Raw, 1006 serialization.PublicFormat.UncompressedPoint, 1007 serialization.PublicFormat.CompressedPoint, 1008 ], 1009 ) 1010 ), 1011 ) 1012 def test_public_bytes_rejects_invalid(self, encoding, fmt, backend): 1013 key = DSA_KEY_2048.private_key(backend).public_key() 1014 with pytest.raises(ValueError): 1015 key.public_bytes(encoding, fmt) 1016