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 base64 8import itertools 9import os 10import textwrap 11 12import pytest 13 14import six 15 16from cryptography.exceptions import UnsupportedAlgorithm 17from cryptography.hazmat.backends.interfaces import ( 18 DERSerializationBackend, 19 DSABackend, 20 EllipticCurveBackend, 21 PEMSerializationBackend, 22 RSABackend, 23) 24from cryptography.hazmat.primitives.asymmetric import ( 25 dsa, 26 ec, 27 ed25519, 28 ed448, 29 rsa, 30 x25519, 31 x448, 32) 33from cryptography.hazmat.primitives.serialization import ( 34 BestAvailableEncryption, 35 Encoding, 36 NoEncryption, 37 PrivateFormat, 38 PublicFormat, 39 load_der_parameters, 40 load_der_private_key, 41 load_der_public_key, 42 load_pem_parameters, 43 load_pem_private_key, 44 load_pem_public_key, 45 load_ssh_private_key, 46 load_ssh_public_key, 47 ssh, 48) 49 50 51from .test_ec import _skip_curve_unsupported 52from .utils import ( 53 _check_dsa_private_numbers, 54 _check_rsa_private_numbers, 55 load_vectors_from_file, 56) 57from ...doubles import DummyKeySerializationEncryption 58 59 60def _skip_fips_format(key_path, password, backend): 61 if backend._fips_enabled: 62 if key_path[0] == "Traditional_OpenSSL_Serialization": 63 pytest.skip("Traditional OpenSSL format blocked in FIPS mode") 64 if key_path[0] == "PEM_Serialization" and password is not None: 65 pytest.skip("Encrypted PEM_Serialization blocked in FIPS mode") 66 67 68class TestBufferProtocolSerialization(object): 69 @pytest.mark.requires_backend_interface(interface=RSABackend) 70 @pytest.mark.parametrize( 71 ("key_path", "password"), 72 [ 73 (["DER_Serialization", "enc-rsa-pkcs8.der"], bytearray(b"foobar")), 74 (["DER_Serialization", "enc2-rsa-pkcs8.der"], bytearray(b"baz")), 75 (["DER_Serialization", "unenc-rsa-pkcs8.der"], None), 76 (["DER_Serialization", "testrsa.der"], None), 77 ], 78 ) 79 def test_load_der_rsa_private_key(self, key_path, password, backend): 80 data = load_vectors_from_file( 81 os.path.join("asymmetric", *key_path), 82 lambda derfile: derfile.read(), 83 mode="rb", 84 ) 85 key = load_der_private_key(bytearray(data), password, backend) 86 assert key 87 assert isinstance(key, rsa.RSAPrivateKey) 88 _check_rsa_private_numbers(key.private_numbers()) 89 90 @pytest.mark.requires_backend_interface(interface=RSABackend) 91 @pytest.mark.parametrize( 92 ("key_path", "password"), 93 [ 94 ( 95 ["PEM_Serialization", "rsa_private_key.pem"], 96 bytearray(b"123456"), 97 ), 98 (["PKCS8", "unenc-rsa-pkcs8.pem"], None), 99 (["PKCS8", "enc-rsa-pkcs8.pem"], bytearray(b"foobar")), 100 (["PKCS8", "enc2-rsa-pkcs8.pem"], bytearray(b"baz")), 101 ( 102 ["Traditional_OpenSSL_Serialization", "key1.pem"], 103 bytearray(b"123456"), 104 ), 105 ], 106 ) 107 def test_load_pem_rsa_private_key(self, key_path, password, backend): 108 _skip_fips_format(key_path, password, backend) 109 data = load_vectors_from_file( 110 os.path.join("asymmetric", *key_path), 111 lambda pemfile: pemfile.read(), 112 mode="rb", 113 ) 114 key = load_pem_private_key(bytearray(data), password, backend) 115 assert key 116 assert isinstance(key, rsa.RSAPrivateKey) 117 _check_rsa_private_numbers(key.private_numbers()) 118 119 120@pytest.mark.requires_backend_interface(interface=DERSerializationBackend) 121class TestDERSerialization(object): 122 @pytest.mark.requires_backend_interface(interface=RSABackend) 123 @pytest.mark.parametrize( 124 ("key_path", "password"), 125 [ 126 (["DER_Serialization", "enc-rsa-pkcs8.der"], b"foobar"), 127 (["DER_Serialization", "enc2-rsa-pkcs8.der"], b"baz"), 128 (["DER_Serialization", "unenc-rsa-pkcs8.der"], None), 129 (["DER_Serialization", "testrsa.der"], None), 130 ], 131 ) 132 def test_load_der_rsa_private_key(self, key_path, password, backend): 133 key = load_vectors_from_file( 134 os.path.join("asymmetric", *key_path), 135 lambda derfile: load_der_private_key( 136 derfile.read(), password, backend 137 ), 138 mode="rb", 139 ) 140 assert key 141 assert isinstance(key, rsa.RSAPrivateKey) 142 _check_rsa_private_numbers(key.private_numbers()) 143 144 @pytest.mark.requires_backend_interface(interface=DSABackend) 145 @pytest.mark.parametrize( 146 ("key_path", "password"), 147 [ 148 (["DER_Serialization", "unenc-dsa-pkcs8.der"], None), 149 (["DER_Serialization", "dsa.1024.der"], None), 150 (["DER_Serialization", "dsa.2048.der"], None), 151 (["DER_Serialization", "dsa.3072.der"], None), 152 ], 153 ) 154 def test_load_der_dsa_private_key(self, key_path, password, backend): 155 key = load_vectors_from_file( 156 os.path.join("asymmetric", *key_path), 157 lambda derfile: load_der_private_key( 158 derfile.read(), password, backend 159 ), 160 mode="rb", 161 ) 162 assert key 163 assert isinstance(key, dsa.DSAPrivateKey) 164 _check_dsa_private_numbers(key.private_numbers()) 165 166 @pytest.mark.parametrize( 167 "key_path", [["DER_Serialization", "enc-rsa-pkcs8.der"]] 168 ) 169 @pytest.mark.requires_backend_interface(interface=RSABackend) 170 def test_password_not_bytes(self, key_path, backend): 171 key_file = os.path.join("asymmetric", *key_path) 172 password = u"this password is not bytes" 173 174 with pytest.raises(TypeError): 175 load_vectors_from_file( 176 key_file, 177 lambda derfile: load_der_private_key( 178 derfile.read(), password, backend 179 ), 180 mode="rb", 181 ) 182 183 @pytest.mark.parametrize( 184 ("key_path", "password"), 185 [ 186 (["DER_Serialization", "ec_private_key.der"], None), 187 (["DER_Serialization", "ec_private_key_encrypted.der"], b"123456"), 188 ], 189 ) 190 @pytest.mark.requires_backend_interface(interface=EllipticCurveBackend) 191 def test_load_der_ec_private_key(self, key_path, password, backend): 192 _skip_curve_unsupported(backend, ec.SECP256R1()) 193 key = load_vectors_from_file( 194 os.path.join("asymmetric", *key_path), 195 lambda derfile: load_der_private_key( 196 derfile.read(), password, backend 197 ), 198 mode="rb", 199 ) 200 201 assert key 202 assert isinstance(key, ec.EllipticCurvePrivateKey) 203 assert key.curve.name == "secp256r1" 204 assert key.curve.key_size == 256 205 206 @pytest.mark.parametrize( 207 "key_path", [["DER_Serialization", "enc-rsa-pkcs8.der"]] 208 ) 209 @pytest.mark.requires_backend_interface(interface=RSABackend) 210 def test_wrong_password(self, key_path, backend): 211 key_file = os.path.join("asymmetric", *key_path) 212 password = b"this password is wrong" 213 214 with pytest.raises(ValueError): 215 load_vectors_from_file( 216 key_file, 217 lambda derfile: load_der_private_key( 218 derfile.read(), password, backend 219 ), 220 mode="rb", 221 ) 222 223 @pytest.mark.parametrize( 224 "key_path", [["DER_Serialization", "unenc-rsa-pkcs8.der"]] 225 ) 226 @pytest.mark.requires_backend_interface(interface=RSABackend) 227 def test_unused_password(self, key_path, backend): 228 key_file = os.path.join("asymmetric", *key_path) 229 password = b"this password will not be used" 230 231 with pytest.raises(TypeError): 232 load_vectors_from_file( 233 key_file, 234 lambda derfile: load_der_private_key( 235 derfile.read(), password, backend 236 ), 237 mode="rb", 238 ) 239 240 @pytest.mark.parametrize( 241 ("key_path", "password"), 242 itertools.product( 243 [["DER_Serialization", "enc-rsa-pkcs8.der"]], [b"", None] 244 ), 245 ) 246 @pytest.mark.requires_backend_interface(interface=RSABackend) 247 def test_missing_password(self, key_path, password, backend): 248 key_file = os.path.join("asymmetric", *key_path) 249 250 with pytest.raises(TypeError): 251 load_vectors_from_file( 252 key_file, 253 lambda derfile: load_der_private_key( 254 derfile.read(), password, backend 255 ), 256 mode="rb", 257 ) 258 259 def test_wrong_format(self, backend): 260 key_data = b"---- NOT A KEY ----\n" 261 262 with pytest.raises(ValueError): 263 load_der_private_key(key_data, None, backend) 264 265 with pytest.raises(ValueError): 266 load_der_private_key( 267 key_data, b"this password will not be used", backend 268 ) 269 270 def test_corrupt_der_pkcs8(self, backend): 271 # unenc-rsa-pkcs8 with a bunch of data missing. 272 key_data = textwrap.dedent( 273 """\ 274 MIICdQIBADALBgkqhkiG9w0BAQEEggJhMIICXQIBAAKBgQC7JHoJfg6yNzLMOWet 275 8Z49a4KD0dCspMAYvo2YAMB7/wdEycocujbhJ2n/seONi+5XqTqqFkM5VBl8rmkk 276 FPZk/7x0xmdsTPECSWnHK+HhoaNDFPR3j8jQhVo1laxiqcEhAHegi5cwtFosuJAv 277 FiRC0Cgz+frQPFQEBsAV9RuasyQxqzxrR0Ow0qncBeGBWbYE6WZhqtcLAI895b+i 278 +F4lbB4iD7T9QeIDMU/aIMXA81UO4cns1z4qDAHKeyLLrPQrJ/B4X7XC+egUWm5+ 279 hr1qmyAMusyXIBECQQDJWZ8piluf4yrYfsJAn6hF5T4RjTztbqvO0GVG2McHY7Uj 280 NPSffhzHx/ll0fQEQji+OgydCCX8o3HZrgw5YfSJAkEA7e+rqdU5nO5ZG//PSEQb 281 tjLnRiTzBH/elQhtdZ5nF7pcpNTi4k13zutmKcWW4GK75azcRGJUhu1kDM7QYAOd 282 SQJAVNkYcifkvna7GmooL5VYEsQsqLbM4v0NF2TIGNfG3z1MGp75KrC5LhL97MNR 283 we2p/bd2k0HYyCKUGnf2nMPDiQJBAI75pwittSoE240EobUGIDTSz8CJsXIxuDmL 284 z+KOpdpPRR5TQmbEMEspjsFpFymMiuYPgmihQbO2cJl1qScY5OkCQQCJ6m5tcN8l 285 Xxg/SNpjEIv+qAyUD96XVlOJlOIeLHQ8kYE0C6ZA+MsqYIzgAreJk88Yn0lU/X0/ 286 mu/UpE/BRZmR 287 """ 288 ).encode() 289 bad_der = base64.b64decode(b"".join(key_data.splitlines())) 290 291 with pytest.raises(ValueError): 292 load_der_private_key(bad_der, None, backend) 293 294 with pytest.raises(ValueError): 295 load_der_private_key( 296 bad_der, b"this password will not be used", backend 297 ) 298 299 def test_corrupt_traditional_format_der(self, backend): 300 # privkey with a bunch of data missing. 301 key_data = textwrap.dedent( 302 """\ 303 MIIBPAIBAAJBAKrbeqkuRk8VcRmWFmtP+LviMB3+6dizWW3DwaffznyHGAFwUJ/I 304 Tv0XtbsCyl3QoyKGhrOAy3RvPK5M38iuXT0CAwEAAQJAZ3cnzaHXM/bxGaR5CR1R 305 rD1qFBAVfoQFiOH9uPJgMaoAuoQEisPHVcZDKcOv4wEg6/TInAIXBnEigtqvRzuy 306 mvcpHZwQJdmdHHkGKAs37Dfxi67HbkUCIQCeZGliHXFa071Fp06ZeWlR2ADonTZz 307 rJBhdTe0v5pCeQIhAIZfkiGgGBX4cIuuckzEm43g9WMUjxP/0GlK39vIyihxAiEA 308 mymehFRT0MvqW5xAKAx7Pgkt8HVKwVhc2LwGKHE0DZM= 309 """ 310 ).encode() 311 bad_der = base64.b64decode(b"".join(key_data.splitlines())) 312 313 with pytest.raises(ValueError): 314 load_pem_private_key(bad_der, None, backend) 315 316 with pytest.raises(ValueError): 317 load_pem_private_key( 318 bad_der, b"this password will not be used", backend 319 ) 320 321 @pytest.mark.parametrize( 322 "key_file", 323 [ 324 os.path.join( 325 "asymmetric", "DER_Serialization", "unenc-rsa-pkcs8.pub.der" 326 ), 327 os.path.join( 328 "asymmetric", "DER_Serialization", "rsa_public_key.der" 329 ), 330 os.path.join("asymmetric", "public", "PKCS1", "rsa.pub.der"), 331 ], 332 ) 333 @pytest.mark.requires_backend_interface(interface=RSABackend) 334 def test_load_der_rsa_public_key(self, key_file, backend): 335 key = load_vectors_from_file( 336 key_file, 337 lambda derfile: load_der_public_key(derfile.read(), backend), 338 mode="rb", 339 ) 340 assert key 341 assert isinstance(key, rsa.RSAPublicKey) 342 numbers = key.public_numbers() 343 assert numbers.e == 65537 344 345 def test_load_der_invalid_public_key(self, backend): 346 with pytest.raises(ValueError): 347 load_der_public_key(b"invalid data", backend) 348 349 @pytest.mark.parametrize( 350 "key_file", 351 [ 352 os.path.join( 353 "asymmetric", "DER_Serialization", "unenc-dsa-pkcs8.pub.der" 354 ), 355 os.path.join( 356 "asymmetric", "DER_Serialization", "dsa_public_key.der" 357 ), 358 ], 359 ) 360 @pytest.mark.requires_backend_interface(interface=DSABackend) 361 def test_load_der_dsa_public_key(self, key_file, backend): 362 key = load_vectors_from_file( 363 key_file, 364 lambda derfile: load_der_public_key(derfile.read(), backend), 365 mode="rb", 366 ) 367 assert key 368 assert isinstance(key, dsa.DSAPublicKey) 369 370 @pytest.mark.requires_backend_interface(interface=EllipticCurveBackend) 371 def test_load_ec_public_key(self, backend): 372 _skip_curve_unsupported(backend, ec.SECP256R1()) 373 key = load_vectors_from_file( 374 os.path.join( 375 "asymmetric", "DER_Serialization", "ec_public_key.der" 376 ), 377 lambda derfile: load_der_public_key(derfile.read(), backend), 378 mode="rb", 379 ) 380 assert key 381 assert isinstance(key, ec.EllipticCurvePublicKey) 382 assert key.curve.name == "secp256r1" 383 assert key.curve.key_size == 256 384 385 def test_wrong_parameters_format(self, backend): 386 param_data = b"---- NOT A KEY ----\n" 387 388 with pytest.raises(ValueError): 389 load_der_parameters(param_data, backend) 390 391 392@pytest.mark.requires_backend_interface(interface=PEMSerializationBackend) 393class TestPEMSerialization(object): 394 @pytest.mark.parametrize( 395 ("key_file", "password"), 396 [ 397 (["PEM_Serialization", "rsa_private_key.pem"], b"123456"), 398 (["PKCS8", "unenc-rsa-pkcs8.pem"], None), 399 (["PKCS8", "enc-rsa-pkcs8.pem"], b"foobar"), 400 (["PKCS8", "enc2-rsa-pkcs8.pem"], b"baz"), 401 (["PKCS8", "pkcs12_s2k_pem-X_9607.pem"], b"123456"), 402 (["PKCS8", "pkcs12_s2k_pem-X_9671.pem"], b"123456"), 403 (["PKCS8", "pkcs12_s2k_pem-X_9925.pem"], b"123456"), 404 (["PKCS8", "pkcs12_s2k_pem-X_9926.pem"], b"123456"), 405 (["PKCS8", "pkcs12_s2k_pem-X_9927.pem"], b"123456"), 406 (["PKCS8", "pkcs12_s2k_pem-X_9928.pem"], b"123456"), 407 (["PKCS8", "pkcs12_s2k_pem-X_9929.pem"], b"123456"), 408 (["PKCS8", "pkcs12_s2k_pem-X_9930.pem"], b"123456"), 409 (["PKCS8", "pkcs12_s2k_pem-X_9931.pem"], b"123456"), 410 (["PKCS8", "pkcs12_s2k_pem-X_9932.pem"], b"123456"), 411 (["Traditional_OpenSSL_Serialization", "key1.pem"], b"123456"), 412 (["Traditional_OpenSSL_Serialization", "key2.pem"], b"a123456"), 413 (["Traditional_OpenSSL_Serialization", "testrsa.pem"], None), 414 ( 415 ["Traditional_OpenSSL_Serialization", "testrsa-encrypted.pem"], 416 b"password", 417 ), 418 ], 419 ) 420 def test_load_pem_rsa_private_key(self, key_file, password, backend): 421 _skip_fips_format(key_file, password, backend) 422 key = load_vectors_from_file( 423 os.path.join("asymmetric", *key_file), 424 lambda pemfile: load_pem_private_key( 425 pemfile.read().encode(), password, backend 426 ), 427 ) 428 429 assert key 430 assert isinstance(key, rsa.RSAPrivateKey) 431 _check_rsa_private_numbers(key.private_numbers()) 432 433 @pytest.mark.parametrize( 434 ("key_path", "password"), 435 [ 436 (["Traditional_OpenSSL_Serialization", "dsa.1024.pem"], None), 437 (["Traditional_OpenSSL_Serialization", "dsa.2048.pem"], None), 438 (["Traditional_OpenSSL_Serialization", "dsa.3072.pem"], None), 439 (["PKCS8", "unenc-dsa-pkcs8.pem"], None), 440 (["PEM_Serialization", "dsa_private_key.pem"], b"123456"), 441 ], 442 ) 443 def test_load_dsa_private_key(self, key_path, password, backend): 444 _skip_fips_format(key_path, password, backend) 445 key = load_vectors_from_file( 446 os.path.join("asymmetric", *key_path), 447 lambda pemfile: load_pem_private_key( 448 pemfile.read().encode(), password, backend 449 ), 450 ) 451 assert key 452 assert isinstance(key, dsa.DSAPrivateKey) 453 _check_dsa_private_numbers(key.private_numbers()) 454 455 @pytest.mark.parametrize( 456 ("key_path", "password"), 457 [ 458 (["PKCS8", "ec_private_key.pem"], None), 459 (["PKCS8", "ec_private_key_encrypted.pem"], b"123456"), 460 (["PEM_Serialization", "ec_private_key.pem"], None), 461 (["PEM_Serialization", "ec_private_key_encrypted.pem"], b"123456"), 462 ], 463 ) 464 @pytest.mark.requires_backend_interface(interface=EllipticCurveBackend) 465 def test_load_pem_ec_private_key(self, key_path, password, backend): 466 _skip_curve_unsupported(backend, ec.SECP256R1()) 467 _skip_fips_format(key_path, password, backend) 468 key = load_vectors_from_file( 469 os.path.join("asymmetric", *key_path), 470 lambda pemfile: load_pem_private_key( 471 pemfile.read().encode(), password, backend 472 ), 473 ) 474 475 assert key 476 assert isinstance(key, ec.EllipticCurvePrivateKey) 477 assert key.curve.name == "secp256r1" 478 assert key.curve.key_size == 256 479 480 @pytest.mark.parametrize( 481 ("key_file"), 482 [ 483 os.path.join("asymmetric", "PKCS8", "unenc-rsa-pkcs8.pub.pem"), 484 os.path.join( 485 "asymmetric", "PEM_Serialization", "rsa_public_key.pem" 486 ), 487 os.path.join("asymmetric", "public", "PKCS1", "rsa.pub.pem"), 488 ], 489 ) 490 def test_load_pem_rsa_public_key(self, key_file, backend): 491 key = load_vectors_from_file( 492 key_file, 493 lambda pemfile: load_pem_public_key( 494 pemfile.read().encode(), backend 495 ), 496 ) 497 assert key 498 assert isinstance(key, rsa.RSAPublicKey) 499 numbers = key.public_numbers() 500 assert numbers.e == 65537 501 502 @pytest.mark.parametrize( 503 ("key_file"), 504 [ 505 os.path.join("asymmetric", "PKCS8", "unenc-dsa-pkcs8.pub.pem"), 506 os.path.join( 507 "asymmetric", "PEM_Serialization", "dsa_public_key.pem" 508 ), 509 ], 510 ) 511 def test_load_pem_dsa_public_key(self, key_file, backend): 512 key = load_vectors_from_file( 513 key_file, 514 lambda pemfile: load_pem_public_key( 515 pemfile.read().encode(), backend 516 ), 517 ) 518 assert key 519 assert isinstance(key, dsa.DSAPublicKey) 520 521 @pytest.mark.requires_backend_interface(interface=EllipticCurveBackend) 522 def test_load_ec_public_key(self, backend): 523 _skip_curve_unsupported(backend, ec.SECP256R1()) 524 key = load_vectors_from_file( 525 os.path.join( 526 "asymmetric", "PEM_Serialization", "ec_public_key.pem" 527 ), 528 lambda pemfile: load_pem_public_key( 529 pemfile.read().encode(), backend 530 ), 531 ) 532 assert key 533 assert isinstance(key, ec.EllipticCurvePublicKey) 534 assert key.curve.name == "secp256r1" 535 assert key.curve.key_size == 256 536 537 @pytest.mark.skip_fips( 538 reason="Traditional OpenSSL format blocked in FIPS mode" 539 ) 540 def test_rsa_traditional_encrypted_values(self, backend): 541 pkey = load_vectors_from_file( 542 os.path.join( 543 "asymmetric", "Traditional_OpenSSL_Serialization", "key1.pem" 544 ), 545 lambda pemfile: load_pem_private_key( 546 pemfile.read().encode(), b"123456", backend 547 ), 548 ) 549 assert pkey 550 551 numbers = pkey.private_numbers() 552 assert numbers.p == int( 553 "fb7d316fc51531b36d93adaefaf52db6ad5beb793d37c4cf9dfc1ddd17cfbafb", 554 16, 555 ) 556 assert numbers.q == int( 557 "df98264e646de9a0fbeab094e31caad5bc7adceaaae3c800ca0275dd4bb307f5", 558 16, 559 ) 560 assert numbers.d == int( 561 "db4848c36f478dd5d38f35ae519643b6b810d404bcb76c00e44015e56ca1cab0" 562 "7bb7ae91f6b4b43fcfc82a47d7ed55b8c575152116994c2ce5325ec24313b911", 563 16, 564 ) 565 assert numbers.dmp1 == int( 566 "ce997f967192c2bcc3853186f1559fd355c190c58ddc15cbf5de9b6df954c727", 567 16, 568 ) 569 assert numbers.dmq1 == int( 570 "b018a57ab20ffaa3862435445d863369b852cf70a67c55058213e3fe10e3848d", 571 16, 572 ) 573 assert numbers.iqmp == int( 574 "6a8d830616924f5cf2d1bc1973f97fde6b63e052222ac7be06aa2532d10bac76", 575 16, 576 ) 577 assert numbers.public_numbers.e == 65537 578 assert numbers.public_numbers.n == int( 579 "dba786074f2f0350ce1d99f5aed5b520cfe0deb5429ec8f2a88563763f566e77" 580 "9814b7c310e5326edae31198eed439b845dd2db99eaa60f5c16a43f4be6bcf37", 581 16, 582 ) 583 584 @pytest.mark.parametrize( 585 "key_path", 586 [ 587 ["Traditional_OpenSSL_Serialization", "testrsa.pem"], 588 ["PKCS8", "unenc-rsa-pkcs8.pem"], 589 ], 590 ) 591 def test_unused_password(self, key_path, backend): 592 key_file = os.path.join("asymmetric", *key_path) 593 password = b"this password will not be used" 594 595 with pytest.raises(TypeError): 596 load_vectors_from_file( 597 key_file, 598 lambda pemfile: load_pem_private_key( 599 pemfile.read().encode(), password, backend 600 ), 601 ) 602 603 def test_invalid_encoding_with_traditional(self, backend): 604 key_file = os.path.join( 605 "asymmetric", "Traditional_OpenSSL_Serialization", "testrsa.pem" 606 ) 607 key = load_vectors_from_file( 608 key_file, 609 lambda pemfile: load_pem_private_key( 610 pemfile.read(), None, backend 611 ), 612 mode="rb", 613 ) 614 615 for enc in (Encoding.OpenSSH, Encoding.Raw, Encoding.X962): 616 with pytest.raises(ValueError): 617 key.private_bytes( 618 enc, PrivateFormat.TraditionalOpenSSL, NoEncryption() 619 ) 620 621 @pytest.mark.parametrize( 622 "key_path", 623 [ 624 ["Traditional_OpenSSL_Serialization", "testrsa-encrypted.pem"], 625 ["PKCS8", "enc-rsa-pkcs8.pem"], 626 ], 627 ) 628 def test_password_not_bytes(self, key_path, backend): 629 key_file = os.path.join("asymmetric", *key_path) 630 password = u"this password is not bytes" 631 632 with pytest.raises(TypeError): 633 load_vectors_from_file( 634 key_file, 635 lambda pemfile: load_pem_private_key( 636 pemfile.read().encode(), password, backend 637 ), 638 ) 639 640 @pytest.mark.parametrize( 641 "key_path", 642 [ 643 ["Traditional_OpenSSL_Serialization", "testrsa-encrypted.pem"], 644 ["PKCS8", "enc-rsa-pkcs8.pem"], 645 ], 646 ) 647 def test_wrong_password(self, key_path, backend): 648 key_file = os.path.join("asymmetric", *key_path) 649 password = b"this password is wrong" 650 651 with pytest.raises(ValueError): 652 load_vectors_from_file( 653 key_file, 654 lambda pemfile: load_pem_private_key( 655 pemfile.read().encode(), password, backend 656 ), 657 ) 658 659 @pytest.mark.parametrize( 660 ("key_path", "password"), 661 itertools.product( 662 [ 663 ["Traditional_OpenSSL_Serialization", "testrsa-encrypted.pem"], 664 ["PKCS8", "enc-rsa-pkcs8.pem"], 665 ], 666 [b"", None], 667 ), 668 ) 669 def test_missing_password(self, key_path, password, backend): 670 key_file = os.path.join("asymmetric", *key_path) 671 672 with pytest.raises(TypeError): 673 load_vectors_from_file( 674 key_file, 675 lambda pemfile: load_pem_private_key( 676 pemfile.read().encode(), password, backend 677 ), 678 ) 679 680 def test_wrong_private_format(self, backend): 681 key_data = b"---- NOT A KEY ----\n" 682 683 with pytest.raises(ValueError): 684 load_pem_private_key(key_data, None, backend) 685 686 with pytest.raises(ValueError): 687 load_pem_private_key( 688 key_data, b"this password will not be used", backend 689 ) 690 691 def test_wrong_public_format(self, backend): 692 key_data = b"---- NOT A KEY ----\n" 693 694 with pytest.raises(ValueError): 695 load_pem_public_key(key_data, backend) 696 697 def test_wrong_parameters_format(self, backend): 698 param_data = b"---- NOT A KEY ----\n" 699 700 with pytest.raises(ValueError): 701 load_pem_parameters(param_data, backend) 702 703 def test_corrupt_traditional_format(self, backend): 704 # privkey.pem with a bunch of data missing. 705 key_data = textwrap.dedent( 706 """\ 707 -----BEGIN RSA PRIVATE KEY----- 708 MIIBPAIBAAJBAKrbeqkuRk8VcRmWFmtP+LviMB3+6dizWW3DwaffznyHGAFwUJ/I 709 Tv0XtbsCyl3QoyKGhrOAy3RvPK5M38iuXT0CAwEAAQJAZ3cnzaHXM/bxGaR5CR1R 710 rD1qFBAVfoQFiOH9uPJgMaoAuoQEisPHVcZDKcOv4wEg6/TInAIXBnEigtqvRzuy 711 mvcpHZwQJdmdHHkGKAs37Dfxi67HbkUCIQCeZGliHXFa071Fp06ZeWlR2ADonTZz 712 rJBhdTe0v5pCeQIhAIZfkiGgGBX4cIuuckzEm43g9WMUjxP/0GlK39vIyihxAiEA 713 mymehFRT0MvqW5xAKAx7Pgkt8HVKwVhc2LwGKHE0DZM= 714 -----END RSA PRIVATE KEY----- 715 """ 716 ).encode() 717 718 with pytest.raises(ValueError): 719 load_pem_private_key(key_data, None, backend) 720 721 with pytest.raises(ValueError): 722 load_pem_private_key( 723 key_data, b"this password will not be used", backend 724 ) 725 726 def test_traditional_encrypted_corrupt_format(self, backend): 727 # privkey.pem with a single bit flipped 728 key_data = textwrap.dedent( 729 """\ 730 -----BEGIN RSA PRIVATE KEY----- 731 Proc-Type: <,ENCRYPTED 732 DEK-Info: AES-128-CBC,5E22A2BD85A653FB7A3ED20DE84F54CD 733 734 hAqtb5ZkTMGcs4BBDQ1SKZzdQThWRDzEDxM3qBfjvYa35KxZ54aic013mW/lwj2I 735 v5bbpOjrHYHNAiZYZ7RNb+ztbF6F/g5PA5g7mFwEq+LFBY0InIplYBSv9QtE+lot 736 Dy4AlZa/+NzJwgdKDb+JVfk5SddyD4ywnyeORnMPy4xXKvjXwmW+iLibZVKsjIgw 737 H8hSxcD+FhWyJm9h9uLtmpuqhQo0jTUYpnTezZx2xeVPB53Ev7YCxR9Nsgj5GsVf 738 9Z/hqLB7IFgM3pa0z3PQeUIZF/cEf72fISWIOBwwkzVrPUkXWfbuWeJXQXSs3amE 739 5A295jD9BQp9CY0nNFSsy+qiXWToq2xT3y5zVNEStmN0SCGNaIlUnJzL9IHW+oMI 740 kPmXZMnAYBWeeCF1gf3J3aE5lZInegHNfEI0+J0LazC2aNU5Dg/BNqrmRqKWEIo/ 741 -----END RSA PRIVATE KEY----- 742 """ 743 ).encode() 744 745 password = b"this password is wrong" 746 747 with pytest.raises(ValueError): 748 load_pem_private_key(key_data, None, backend) 749 750 with pytest.raises(ValueError): 751 load_pem_private_key(key_data, password, backend) 752 753 def test_unsupported_key_encryption(self, backend): 754 key_data = textwrap.dedent( 755 """\ 756 -----BEGIN RSA PRIVATE KEY----- 757 Proc-Type: 4,ENCRYPTED 758 DEK-Info: FAKE-123,5E22A2BD85A653FB7A3ED20DE84F54CD 759 760 hAqtb5ZkTMGcs4BBDQ1SKZzdQThWRDzEDxM3qBfjvYa35KxZ54aic013mW/lwj2I 761 v5bbpOjrHYHNAiZYZ7RNb+ztbF6F/g5PA5g7mFwEq+LFBY0InIplYBSv9QtE+lot 762 Dy4AlZa/+NzJwgdKDb+JVfk5SddyD4ywnyeORnMPy4xXKvjXwmW+iLibZVKsjIgw 763 H8hSxcD+FhWyJm9h9uLtmpuqhQo0jTUYpnTezZx2xeVPB53Ev7YCxR9Nsgj5GsVf 764 9Z/hqLB7IFgM3pa0z3PQeUIZF/cEf72fISWIOBwwkzVrPUkXWfbuWeJXQXSs3amE 765 5A295jD9BQp9CY0nNFSsy+qiXWToq2xT3y5zVNEStmN0SCGNaIlUnJzL9IHW+oMI 766 kPmXZMnAYBWeeCF1gf3J3aE5lZInegHNfEI0+J0LazC2aNU5Dg/BNqrmRqKWEIo/ 767 -----END RSA PRIVATE KEY----- 768 """ 769 ).encode() 770 771 password = b"password" 772 773 with pytest.raises(ValueError): 774 load_pem_private_key(key_data, password, backend) 775 776 def test_corrupt_pkcs8_format(self, backend): 777 # unenc-rsa-pkcs8.pem with a bunch of data missing. 778 key_data = textwrap.dedent( 779 """\ 780 -----BEGIN PRIVATE KEY----- 781 MIICdQIBADALBgkqhkiG9w0BAQEEggJhMIICXQIBAAKBgQC7JHoJfg6yNzLMOWet 782 8Z49a4KD0dCspMAYvo2YAMB7/wdEycocujbhJ2n/seONi+5XqTqqFkM5VBl8rmkk 783 FPZk/7x0xmdsTPECSWnHK+HhoaNDFPR3j8jQhVo1laxiqcEhAHegi5cwtFosuJAv 784 FiRC0Cgz+frQPFQEBsAV9RuasyQxqzxrR0Ow0qncBeGBWbYE6WZhqtcLAI895b+i 785 +F4lbB4iD7T9QeIDMU/aIMXA81UO4cns1z4qDAHKeyLLrPQrJ/B4X7XC+egUWm5+ 786 hr1qmyAMusyXIBECQQDJWZ8piluf4yrYfsJAn6hF5T4RjTztbqvO0GVG2McHY7Uj 787 NPSffhzHx/ll0fQEQji+OgydCCX8o3HZrgw5YfSJAkEA7e+rqdU5nO5ZG//PSEQb 788 tjLnRiTzBH/elQhtdZ5nF7pcpNTi4k13zutmKcWW4GK75azcRGJUhu1kDM7QYAOd 789 SQJAVNkYcifkvna7GmooL5VYEsQsqLbM4v0NF2TIGNfG3z1MGp75KrC5LhL97MNR 790 we2p/bd2k0HYyCKUGnf2nMPDiQJBAI75pwittSoE240EobUGIDTSz8CJsXIxuDmL 791 z+KOpdpPRR5TQmbEMEspjsFpFymMiuYPgmihQbO2cJl1qScY5OkCQQCJ6m5tcN8l 792 Xxg/SNpjEIv+qAyUD96XVlOJlOIeLHQ8kYE0C6ZA+MsqYIzgAreJk88Yn0lU/X0/ 793 mu/UpE/BRZmR 794 -----END PRIVATE KEY----- 795 """ 796 ).encode() 797 798 with pytest.raises(ValueError): 799 load_pem_private_key(key_data, None, backend) 800 801 with pytest.raises(ValueError): 802 load_pem_private_key( 803 key_data, b"this password will not be used", backend 804 ) 805 806 def test_pks8_encrypted_corrupt_format(self, backend): 807 # enc-rsa-pkcs8.pem with some bits flipped. 808 key_data = textwrap.dedent( 809 """\ 810 -----BEGIN ENCRYPTED PRIVATE KEY----- 811 MIICojAcBgoqhkiG9w0BDAEDMA4ECHK0M0+QuEL9AgIBIcSCAoDRq+KRY+0XP0tO 812 lwBTzViiXSXoyNnKAZKt5r5K/fGNntv22g/1s/ZNCetrqsJDC5eMUPPacz06jFq/ 813 Ipsep4/OgjQ9UAOzXNrWEoNyrHnWDo7usgD3CW0mKyqER4+wG0adVMbt3N+CJHGB 814 85jzRmQTfkdx1rSWeSx+XyswHn8ER4+hQ+omKWMVm7AFkjjmP/KnhUnLT98J8rhU 815 ArQoFPHz/6HVkypFccNaPPNg6IA4aS2A+TU9vJYOaXSVfFB2yf99hfYYzC+ukmuU 816 5Lun0cysK5s/5uSwDueUmDQKspnaNyiaMGDxvw8hilJc7vg0fGObfnbIpizhxJwq 817 gKBfR7Zt0Hv8OYi1He4MehfMGdbHskztF+yQ40LplBGXQrvAqpU4zShga1BoQ98T 818 0ekbBmqj7hg47VFsppXR7DKhx7G7rpMmdKbFhAZVCjae7rRGpUtD52cpFdPhMyAX 819 huhMkoczwUW8B/rM4272lkHo6Br0yk/TQfTEGkvryflNVu6lniPTV151WV5U1M3o 820 3G3a44eDyt7Ln+WSOpWtbPQMTrpKhur6WXgJvrpa/m02oOGdvOlDsoOCgavgQMWg 821 7xKKL7620pHl7p7f/8tlE8q6vLXVvyNtAOgt/JAr2rgvrHaZSzDE0DwgCjBXEm+7 822 cVMVNkHod7bLQefVanVtWqPzbmr8f7gKeuGwWSG9oew/lN2hxcLEPJHAQlnLgx3P 823 0GdGjK9NvwA0EP2gYIeE4+UtSder7xQ7bVh25VB20R4TTIIs4aXXCVOoQPagnzaT 824 6JLgl8FrvdfjHwIvmSOO1YMNmILBq000Q8WDqyErBDs4hsvtO6VQ4LeqJj6gClX3 825 qeJNaJFu 826 -----END ENCRYPTED PRIVATE KEY----- 827 """ 828 ).encode() 829 830 password = b"this password is wrong" 831 832 with pytest.raises(ValueError): 833 load_pem_private_key(key_data, None, backend) 834 835 with pytest.raises(ValueError): 836 load_pem_private_key(key_data, password, backend) 837 838 def test_rsa_pkcs8_encrypted_values(self, backend): 839 pkey = load_vectors_from_file( 840 os.path.join("asymmetric", "PKCS8", "enc-rsa-pkcs8.pem"), 841 lambda pemfile: load_pem_private_key( 842 pemfile.read().encode(), b"foobar", backend 843 ), 844 ) 845 assert pkey 846 847 numbers = pkey.private_numbers() 848 849 assert numbers.public_numbers.n == int( 850 "00beec64d6db5760ac2fd4c971145641b9bd7f5c56558ece608795c79807" 851 "376a7fe5b19f95b35ca358ea5c8abd7ae051d49cd2f1e45969a1ae945460" 852 "3c14b278664a0e414ebc8913acb6203626985525e17a600611b028542dd0" 853 "562aad787fb4f1650aa318cdcff751e1b187cbf6785fbe164e9809491b95" 854 "dd68480567c99b1a57", 855 16, 856 ) 857 858 assert numbers.public_numbers.e == 65537 859 860 assert numbers.d == int( 861 "0cfe316e9dc6b8817f4fcfd5ae38a0886f68f773b8a6db4c9e6d8703c599" 862 "f3d9785c3a2c09e4c8090909fb3721e19a3009ec21221523a729265707a5" 863 "8f13063671c42a4096cad378ef2510cb59e23071489d8893ac4934dd149f" 864 "34f2d094bea57f1c8027c3a77248ac9b91218737d0c3c3dfa7d7829e6977" 865 "cf7d995688c86c81", 866 16, 867 ) 868 869 assert numbers.p == int( 870 "00db122ac857b2c0437d7616daa98e597bb75ca9ad3a47a70bec10c10036" 871 "03328794b225c8e3eee6ffd3fd6d2253d28e071fe27d629ab072faa14377" 872 "ce6118cb67", 873 16, 874 ) 875 876 assert numbers.q == int( 877 "00df1b8aa8506fcbbbb9d00257f2975e38b33d2698fd0f37e82d7ef38c56" 878 "f21b6ced63c825383782a7115cfcc093300987dbd2853b518d1c8f26382a" 879 "2d2586d391", 880 16, 881 ) 882 883 assert numbers.dmp1 == int( 884 "00be18aca13e60712fdf5daa85421eb10d86d654b269e1255656194fb0c4" 885 "2dd01a1070ea12c19f5c39e09587af02f7b1a1030d016a9ffabf3b36d699" 886 "ceaf38d9bf", 887 16, 888 ) 889 890 assert numbers.dmq1 == int( 891 "71aa8978f90a0c050744b77cf1263725b203ac9f730606d8ae1d289dce4a" 892 "28b8d534e9ea347aeb808c73107e583eb80c546d2bddadcdb3c82693a4c1" 893 "3d863451", 894 16, 895 ) 896 897 assert numbers.iqmp == int( 898 "136b7b1afac6e6279f71b24217b7083485a5e827d156024609dae39d48a6" 899 "bdb55af2f062cc4a3b077434e6fffad5faa29a2b5dba2bed3e4621e478c0" 900 "97ccfe7f", 901 16, 902 ) 903 904 def test_load_pem_dsa_private_key(self, backend): 905 key = load_vectors_from_file( 906 os.path.join("asymmetric", "PKCS8", "unenc-dsa-pkcs8.pem"), 907 lambda pemfile: load_pem_private_key( 908 pemfile.read().encode(), None, backend 909 ), 910 ) 911 assert key 912 assert isinstance(key, dsa.DSAPrivateKey) 913 914 params = key.parameters() 915 assert isinstance(params, dsa.DSAParameters) 916 917 num = key.private_numbers() 918 pub = num.public_numbers 919 parameter_numbers = pub.parameter_numbers 920 assert num.x == int("00a535a8e1d0d91beafc8bee1d9b2a3a8de3311203", 16) 921 assert pub.y == int( 922 "2b260ea97dc6a12ae932c640e7df3d8ff04a8a05a0324f8d5f1b23f15fa1" 923 "70ff3f42061124eff2586cb11b49a82dcdc1b90fc6a84fb10109cb67db5d" 924 "2da971aeaf17be5e37284563e4c64d9e5fc8480258b319f0de29d54d8350" 925 "70d9e287914d77df81491f4423b62da984eb3f45eb2a29fcea5dae525ac6" 926 "ab6bcce04bfdf5b6", 927 16, 928 ) 929 930 assert parameter_numbers.p == int( 931 "00aa0930cc145825221caffa28ac2894196a27833de5ec21270791689420" 932 "7774a2e7b238b0d36f1b2499a2c2585083eb01432924418d867faa212dd1" 933 "071d4dceb2782794ad393cc08a4d4ada7f68d6e839a5fcd34b4e402d82cb" 934 "8a8cb40fec31911bf9bd360b034caacb4c5e947992573c9e90099c1b0f05" 935 "940cabe5d2de49a167", 936 16, 937 ) 938 939 assert parameter_numbers.q == int( 940 "00adc0e869b36f0ac013a681fdf4d4899d69820451", 16 941 ) 942 943 assert parameter_numbers.g == int( 944 "008c6b4589afa53a4d1048bfc346d1f386ca75521ccf72ddaa251286880e" 945 "e13201ff48890bbfc33d79bacaec71e7a778507bd5f1a66422e39415be03" 946 "e71141ba324f5b93131929182c88a9fa4062836066cebe74b5c6690c7d10" 947 "1106c240ab7ebd54e4e3301fd086ce6adac922fb2713a2b0887cba13b9bc" 948 "68ce5cfff241cd3246", 949 16, 950 ) 951 952 @pytest.mark.parametrize( 953 ("key_file", "password"), [("bad-oid-dsa-key.pem", None)] 954 ) 955 def test_load_bad_oid_key(self, key_file, password, backend): 956 with pytest.raises(ValueError): 957 load_vectors_from_file( 958 os.path.join("asymmetric", "PKCS8", key_file), 959 lambda pemfile: load_pem_private_key( 960 pemfile.read().encode(), password, backend 961 ), 962 ) 963 964 @pytest.mark.parametrize( 965 ("key_file", "password"), [("bad-encryption-oid.pem", b"password")] 966 ) 967 def test_load_bad_encryption_oid_key(self, key_file, password, backend): 968 with pytest.raises(ValueError): 969 load_vectors_from_file( 970 os.path.join("asymmetric", "PKCS8", key_file), 971 lambda pemfile: load_pem_private_key( 972 pemfile.read().encode(), password, backend 973 ), 974 ) 975 976 977@pytest.mark.requires_backend_interface(interface=RSABackend) 978class TestRSASSHSerialization(object): 979 def test_load_ssh_public_key_unsupported(self, backend): 980 ssh_key = b"ecdsa-sha2-junk AAAAE2VjZHNhLXNoYTItbmlzdHAyNTY=" 981 982 with pytest.raises(UnsupportedAlgorithm): 983 load_ssh_public_key(ssh_key, backend) 984 985 def test_load_ssh_public_key_bad_format(self, backend): 986 ssh_key = b"ssh-rsa not-a-real-key" 987 988 with pytest.raises(ValueError): 989 load_ssh_public_key(ssh_key, backend) 990 991 def test_load_ssh_public_key_rsa_too_short(self, backend): 992 ssh_key = b"ssh-rsa" 993 994 with pytest.raises(ValueError): 995 load_ssh_public_key(ssh_key, backend) 996 997 def test_load_ssh_public_key_truncated_int(self, backend): 998 ssh_key = b"ssh-rsa AAAAB3NzaC1yc2EAAAA=" 999 1000 with pytest.raises(ValueError): 1001 load_ssh_public_key(ssh_key, backend) 1002 1003 ssh_key = b"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAACKr+IHXo" 1004 1005 with pytest.raises(ValueError): 1006 load_ssh_public_key(ssh_key, backend) 1007 1008 def test_load_ssh_public_key_rsa_comment_with_spaces(self, backend): 1009 ssh_key = ( 1010 b"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDDu/XRP1kyK6Cgt36gts9XAk" 1011 b"FiiuJLW6RU0j3KKVZSs1I7Z3UmU9/9aVh/rZV43WQG8jaR6kkcP4stOR0DEtll" 1012 b"PDA7ZRBnrfiHpSQYQ874AZaAoIjgkv7DBfsE6gcDQLub0PFjWyrYQUJhtOLQEK" 1013 b"vY/G0vt2iRL3juawWmCFdTK3W3XvwAdgGk71i6lHt+deOPNEPN2H58E4odrZ2f" 1014 b"sxn/adpDqfb2sM0kPwQs0aWvrrKGvUaustkivQE4XWiSFnB0oJB/lKK/CKVKuy" 1015 b"///ImSCGHQRvhwariN2tvZ6CBNSLh3iQgeB0AkyJlng7MXB2qYq/Ci2FUOryCX" 1016 # Extra section appended 1017 b"2MzHvnbv testkey@localhost extra" 1018 ) 1019 1020 load_ssh_public_key(ssh_key, backend) 1021 1022 def test_load_ssh_public_key_rsa_extra_data_after_modulo(self, backend): 1023 ssh_key = ( 1024 b"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDDu/XRP1kyK6Cgt36gts9XAk" 1025 b"FiiuJLW6RU0j3KKVZSs1I7Z3UmU9/9aVh/rZV43WQG8jaR6kkcP4stOR0DEtll" 1026 b"PDA7ZRBnrfiHpSQYQ874AZaAoIjgkv7DBfsE6gcDQLub0PFjWyrYQUJhtOLQEK" 1027 b"vY/G0vt2iRL3juawWmCFdTK3W3XvwAdgGk71i6lHt+deOPNEPN2H58E4odrZ2f" 1028 b"sxn/adpDqfb2sM0kPwQs0aWvrrKGvUaustkivQE4XWiSFnB0oJB/lKK/CKVKuy" 1029 b"///ImSCGHQRvhwariN2tvZ6CBNSLh3iQgeB0AkyJlng7MXB2qYq/Ci2FUOryCX" 1030 b"2MzHvnbvAQ== testkey@localhost" 1031 ) 1032 1033 with pytest.raises(ValueError): 1034 load_ssh_public_key(ssh_key, backend) 1035 1036 def test_load_ssh_public_key_rsa_different_string(self, backend): 1037 ssh_key = ( 1038 # "AAAAB3NzA" the final A is capitalized here to cause the string 1039 # ssh-rsa inside the base64 encoded blob to be incorrect. It should 1040 # be a lower case 'a'. 1041 b"ssh-rsa AAAAB3NzAC1yc2EAAAADAQABAAABAQDDu/XRP1kyK6Cgt36gts9XAk" 1042 b"FiiuJLW6RU0j3KKVZSs1I7Z3UmU9/9aVh/rZV43WQG8jaR6kkcP4stOR0DEtll" 1043 b"PDA7ZRBnrfiHpSQYQ874AZaAoIjgkv7DBfsE6gcDQLub0PFjWyrYQUJhtOLQEK" 1044 b"vY/G0vt2iRL3juawWmCFdTK3W3XvwAdgGk71i6lHt+deOPNEPN2H58E4odrZ2f" 1045 b"sxn/adpDqfb2sM0kPwQs0aWvrrKGvUaustkivQE4XWiSFnB0oJB/lKK/CKVKuy" 1046 b"///ImSCGHQRvhwariN2tvZ6CBNSLh3iQgeB0AkyJlng7MXB2qYq/Ci2FUOryCX" 1047 b"2MzHvnbvAQ== testkey@localhost" 1048 ) 1049 with pytest.raises(ValueError): 1050 load_ssh_public_key(ssh_key, backend) 1051 1052 def test_load_ssh_public_key_rsa(self, backend): 1053 ssh_key = ( 1054 b"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDDu/XRP1kyK6Cgt36gts9XAk" 1055 b"FiiuJLW6RU0j3KKVZSs1I7Z3UmU9/9aVh/rZV43WQG8jaR6kkcP4stOR0DEtll" 1056 b"PDA7ZRBnrfiHpSQYQ874AZaAoIjgkv7DBfsE6gcDQLub0PFjWyrYQUJhtOLQEK" 1057 b"vY/G0vt2iRL3juawWmCFdTK3W3XvwAdgGk71i6lHt+deOPNEPN2H58E4odrZ2f" 1058 b"sxn/adpDqfb2sM0kPwQs0aWvrrKGvUaustkivQE4XWiSFnB0oJB/lKK/CKVKuy" 1059 b"///ImSCGHQRvhwariN2tvZ6CBNSLh3iQgeB0AkyJlng7MXB2qYq/Ci2FUOryCX" 1060 b"2MzHvnbv testkey@localhost" 1061 ) 1062 1063 key = load_ssh_public_key(ssh_key, backend) 1064 1065 assert key is not None 1066 assert isinstance(key, rsa.RSAPublicKey) 1067 1068 numbers = key.public_numbers() 1069 1070 expected_e = 0x10001 1071 expected_n = int( 1072 "00C3BBF5D13F59322BA0A0B77EA0B6CF570241628AE24B5BA454D" 1073 "23DCA295652B3523B67752653DFFD69587FAD9578DD6406F23691" 1074 "EA491C3F8B2D391D0312D9653C303B651067ADF887A5241843CEF" 1075 "8019680A088E092FEC305FB04EA070340BB9BD0F1635B2AD84142" 1076 "61B4E2D010ABD8FC6D2FB768912F78EE6B05A60857532B75B75EF" 1077 "C007601A4EF58BA947B7E75E38F3443CDD87E7C138A1DAD9D9FB3" 1078 "19FF69DA43A9F6F6B0CD243F042CD1A5AFAEB286BD46AEB2D922B" 1079 "D01385D6892167074A0907F94A2BF08A54ABB2FFFFC89920861D0" 1080 "46F8706AB88DDADBD9E8204D48B87789081E074024C8996783B31" 1081 "7076A98ABF0A2D8550EAF2097D8CCC7BE76EF", 1082 16, 1083 ) 1084 1085 expected = rsa.RSAPublicNumbers(expected_e, expected_n) 1086 1087 assert numbers == expected 1088 1089 1090@pytest.mark.requires_backend_interface(interface=DSABackend) 1091class TestDSSSSHSerialization(object): 1092 def test_load_ssh_public_key_dss_too_short(self, backend): 1093 ssh_key = b"ssh-dss" 1094 1095 with pytest.raises(ValueError): 1096 load_ssh_public_key(ssh_key, backend) 1097 1098 def test_load_ssh_public_key_dss_comment_with_spaces(self, backend): 1099 ssh_key = ( 1100 b"ssh-dss AAAAB3NzaC1kc3MAAACBALmwUtfwdjAUjU2Dixd5DvT0NDcjjr69UD" 1101 b"LqSD/Xt5Al7D3GXr1WOrWGpjO0NE9qzRCvMTU7zykRH6XjuNXB6Hvv48Zfm4vm" 1102 b"nHQHFmmMg2bI75JbnOwdzWnnPZJrVU4rS23dFFPqs5ug+EbhVVrcwzxahjcSjJ" 1103 b"7WEQSkVQWnSPbbAAAAFQDXmpD3DIkGvLSBf1GdUF4PHKtUrQAAAIB/bJFwss+2" 1104 b"fngmfG/Li5OyL7A9iVoGdkUaFaxEUROTp7wkm2z49fXFAir+/U31v50Tu98YLf" 1105 b"WvKlxdHcdgQYV9Ww5LIrhWwwD4UKOwC6w5S3KHVbi3pWUi7vxJFXOWfeu1mC/J" 1106 b"TWqMKR91j+rmOtdppWIZRyIVIqLcMdGO3m+2VgAAAIANFDz5KQH5NvoljpoRQi" 1107 b"RgyPjxWXiE7vjLElKj4v8KrpanAywBzdhIW1y/tzpGuwRwj5ihi8iNTHgSsoTa" 1108 b"j5AG5HPomJf5vJElxpu/2O9pHA52wcNObIQ7j+JA5uWusxNIbl+pF6sSiP8abr" 1109 b"z53N7tPF/IhHTjBHb1Ol7IFu9p9A== testkey@localhost extra" 1110 ) 1111 1112 load_ssh_public_key(ssh_key, backend) 1113 1114 def test_load_ssh_public_key_dss_extra_data_after_modulo(self, backend): 1115 ssh_key = ( 1116 b"ssh-dss AAAAB3NzaC1kc3MAAACBALmwUtfwdjAUjU2Dixd5DvT0NDcjjr69UD" 1117 b"LqSD/Xt5Al7D3GXr1WOrWGpjO0NE9qzRCvMTU7zykRH6XjuNXB6Hvv48Zfm4vm" 1118 b"nHQHFmmMg2bI75JbnOwdzWnnPZJrVU4rS23dFFPqs5ug+EbhVVrcwzxahjcSjJ" 1119 b"7WEQSkVQWnSPbbAAAAFQDXmpD3DIkGvLSBf1GdUF4PHKtUrQAAAIB/bJFwss+2" 1120 b"fngmfG/Li5OyL7A9iVoGdkUaFaxEUROTp7wkm2z49fXFAir+/U31v50Tu98YLf" 1121 b"WvKlxdHcdgQYV9Ww5LIrhWwwD4UKOwC6w5S3KHVbi3pWUi7vxJFXOWfeu1mC/J" 1122 b"TWqMKR91j+rmOtdppWIZRyIVIqLcMdGO3m+2VgAAAIANFDz5KQH5NvoljpoRQi" 1123 b"RgyPjxWXiE7vjLElKj4v8KrpanAywBzdhIW1y/tzpGuwRwj5ihi8iNTHgSsoTa" 1124 b"j5AG5HPomJf5vJElxpu/2O9pHA52wcNObIQ7j+JA5uWusxNIbl+pF6sSiP8abr" 1125 b"z53N7tPF/IhHTjBHb1Ol7IFu9p9AAwMD== testkey@localhost" 1126 ) 1127 1128 with pytest.raises(ValueError): 1129 load_ssh_public_key(ssh_key, backend) 1130 1131 def test_load_ssh_public_key_dss_different_string(self, backend): 1132 ssh_key = ( 1133 # "AAAAB3NzA" the final A is capitalized here to cause the string 1134 # ssh-dss inside the base64 encoded blob to be incorrect. It should 1135 # be a lower case 'a'. 1136 b"ssh-dss AAAAB3NzAC1kc3MAAACBALmwUtfwdjAUjU2Dixd5DvT0NDcjjr69UD" 1137 b"LqSD/Xt5Al7D3GXr1WOrWGpjO0NE9qzRCvMTU7zykRH6XjuNXB6Hvv48Zfm4vm" 1138 b"nHQHFmmMg2bI75JbnOwdzWnnPZJrVU4rS23dFFPqs5ug+EbhVVrcwzxahjcSjJ" 1139 b"7WEQSkVQWnSPbbAAAAFQDXmpD3DIkGvLSBf1GdUF4PHKtUrQAAAIB/bJFwss+2" 1140 b"fngmfG/Li5OyL7A9iVoGdkUaFaxEUROTp7wkm2z49fXFAir+/U31v50Tu98YLf" 1141 b"WvKlxdHcdgQYV9Ww5LIrhWwwD4UKOwC6w5S3KHVbi3pWUi7vxJFXOWfeu1mC/J" 1142 b"TWqMKR91j+rmOtdppWIZRyIVIqLcMdGO3m+2VgAAAIANFDz5KQH5NvoljpoRQi" 1143 b"RgyPjxWXiE7vjLElKj4v8KrpanAywBzdhIW1y/tzpGuwRwj5ihi8iNTHgSsoTa" 1144 b"j5AG5HPomJf5vJElxpu/2O9pHA52wcNObIQ7j+JA5uWusxNIbl+pF6sSiP8abr" 1145 b"z53N7tPF/IhHTjBHb1Ol7IFu9p9A== testkey@localhost" 1146 ) 1147 with pytest.raises(ValueError): 1148 load_ssh_public_key(ssh_key, backend) 1149 1150 def test_load_ssh_public_key_dss(self, backend): 1151 ssh_key = ( 1152 b"ssh-dss AAAAB3NzaC1kc3MAAACBALmwUtfwdjAUjU2Dixd5DvT0NDcjjr69UD" 1153 b"LqSD/Xt5Al7D3GXr1WOrWGpjO0NE9qzRCvMTU7zykRH6XjuNXB6Hvv48Zfm4vm" 1154 b"nHQHFmmMg2bI75JbnOwdzWnnPZJrVU4rS23dFFPqs5ug+EbhVVrcwzxahjcSjJ" 1155 b"7WEQSkVQWnSPbbAAAAFQDXmpD3DIkGvLSBf1GdUF4PHKtUrQAAAIB/bJFwss+2" 1156 b"fngmfG/Li5OyL7A9iVoGdkUaFaxEUROTp7wkm2z49fXFAir+/U31v50Tu98YLf" 1157 b"WvKlxdHcdgQYV9Ww5LIrhWwwD4UKOwC6w5S3KHVbi3pWUi7vxJFXOWfeu1mC/J" 1158 b"TWqMKR91j+rmOtdppWIZRyIVIqLcMdGO3m+2VgAAAIANFDz5KQH5NvoljpoRQi" 1159 b"RgyPjxWXiE7vjLElKj4v8KrpanAywBzdhIW1y/tzpGuwRwj5ihi8iNTHgSsoTa" 1160 b"j5AG5HPomJf5vJElxpu/2O9pHA52wcNObIQ7j+JA5uWusxNIbl+pF6sSiP8abr" 1161 b"z53N7tPF/IhHTjBHb1Ol7IFu9p9A== testkey@localhost" 1162 ) 1163 1164 key = load_ssh_public_key(ssh_key, backend) 1165 1166 assert key is not None 1167 assert isinstance(key, dsa.DSAPublicKey) 1168 1169 numbers = key.public_numbers() 1170 1171 expected_y = int( 1172 "d143cf92901f936fa258e9a11422460c8f8f1597884eef8cb1252a3e2ff0aae" 1173 "96a7032c01cdd8485b5cbfb73a46bb04708f98a18bc88d4c7812b284da8f900" 1174 "6e473e89897f9bc9125c69bbfd8ef691c0e76c1c34e6c843b8fe240e6e5aeb3" 1175 "13486e5fa917ab1288ff1a6ebcf9dcdeed3c5fc88474e30476f53a5ec816ef6" 1176 "9f4", 1177 16, 1178 ) 1179 expected_p = int( 1180 "b9b052d7f07630148d4d838b17790ef4f43437238ebebd5032ea483fd7b7902" 1181 "5ec3dc65ebd563ab586a633b4344f6acd10af31353bcf29111fa5e3b8d5c1e8" 1182 "7befe3c65f9b8be69c740716698c8366c8ef925b9cec1dcd69e73d926b554e2" 1183 "b4b6ddd1453eab39ba0f846e1555adcc33c5a8637128c9ed61104a45505a748" 1184 "f6db", 1185 16, 1186 ) 1187 expected_q = 1230879958723280233885494314531920096931919647917 1188 expected_g = int( 1189 "7f6c9170b2cfb67e78267c6fcb8b93b22fb03d895a0676451a15ac44511393a" 1190 "7bc249b6cf8f5f5c5022afefd4df5bf9d13bbdf182df5af2a5c5d1dc7604185" 1191 "7d5b0e4b22b856c300f850a3b00bac394b728755b8b7a56522eefc491573967" 1192 "debb5982fc94d6a8c291f758feae63ad769a5621947221522a2dc31d18ede6f" 1193 "b656", 1194 16, 1195 ) 1196 expected = dsa.DSAPublicNumbers( 1197 expected_y, 1198 dsa.DSAParameterNumbers(expected_p, expected_q, expected_g), 1199 ) 1200 1201 assert numbers == expected 1202 1203 1204@pytest.mark.requires_backend_interface(interface=EllipticCurveBackend) 1205class TestECDSASSHSerialization(object): 1206 def test_load_ssh_public_key_ecdsa_nist_p256(self, backend): 1207 _skip_curve_unsupported(backend, ec.SECP256R1()) 1208 1209 ssh_key = ( 1210 b"ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAy" 1211 b"NTYAAABBBGG2MfkHXp0UkxUyllDzWNBAImsvt5t7pFtTXegZK2WbGxml8zMrgWi5" 1212 b"teIg1TO03/FD9hbpBFgBeix3NrCFPls= root@cloud-server-01" 1213 ) 1214 key = load_ssh_public_key(ssh_key, backend) 1215 assert isinstance(key, ec.EllipticCurvePublicKey) 1216 1217 expected_x = int( 1218 "44196257377740326295529888716212621920056478823906609851236662550" 1219 "785814128027", 1220 10, 1221 ) 1222 expected_y = int( 1223 "12257763433170736656417248739355923610241609728032203358057767672" 1224 "925775019611", 1225 10, 1226 ) 1227 1228 assert key.public_numbers() == ec.EllipticCurvePublicNumbers( 1229 expected_x, expected_y, ec.SECP256R1() 1230 ) 1231 1232 def test_load_ssh_public_key_byteslike(self, backend): 1233 _skip_curve_unsupported(backend, ec.SECP256R1()) 1234 1235 ssh_key = ( 1236 b"ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAy" 1237 b"NTYAAABBBGG2MfkHXp0UkxUyllDzWNBAImsvt5t7pFtTXegZK2WbGxml8zMrgWi5" 1238 b"teIg1TO03/FD9hbpBFgBeix3NrCFPls= root@cloud-server-01" 1239 ) 1240 assert load_ssh_public_key(bytearray(ssh_key), backend) 1241 if six.PY3: 1242 assert load_ssh_public_key(memoryview(ssh_key), backend) 1243 assert load_ssh_public_key(memoryview(bytearray(ssh_key)), backend) 1244 1245 def test_load_ssh_public_key_ecdsa_nist_p384(self, backend): 1246 _skip_curve_unsupported(backend, ec.SECP384R1()) 1247 ssh_key = ( 1248 b"ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAz" 1249 b"ODQAAABhBMzucOm9wbwg4iMr5QL0ya0XNQGXpw4wM5f12E3tWhdcrzyGHyel71t1" 1250 b"4bvF9JZ2/WIuSxUr33XDl8jYo+lMQ5N7Vanc7f7i3AR1YydatL3wQfZStQ1I3rBa" 1251 b"qQtRSEU8Tg== root@cloud-server-01" 1252 ) 1253 key = load_ssh_public_key(ssh_key, backend) 1254 1255 expected_x = int( 1256 "31541830871345183397582554827482786756220448716666815789487537666" 1257 "592636882822352575507883817901562613492450642523901", 1258 10, 1259 ) 1260 expected_y = int( 1261 "15111413269431823234030344298767984698884955023183354737123929430" 1262 "995703524272335782455051101616329050844273733614670", 1263 10, 1264 ) 1265 1266 assert key.public_numbers() == ec.EllipticCurvePublicNumbers( 1267 expected_x, expected_y, ec.SECP384R1() 1268 ) 1269 1270 def test_load_ssh_public_key_ecdsa_nist_p521(self, backend): 1271 _skip_curve_unsupported(backend, ec.SECP521R1()) 1272 ssh_key = ( 1273 b"ecdsa-sha2-nistp521 AAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAAAIbmlzdHA1" 1274 b"MjEAAACFBAGTrRhMSEgF6Ni+PXNz+5fjS4lw3ypUILVVQ0Av+0hQxOx+MyozELon" 1275 b"I8NKbrbBjijEs1GuImsmkTmWsMXS1j2A7wB4Kseh7W9KA9IZJ1+TMrzWUEwvOOXi" 1276 b"wT23pbaWWXG4NaM7vssWfZBnvz3S174TCXnJ+DSccvWBFnKP0KchzLKxbg== " 1277 b"root@cloud-server-01" 1278 ) 1279 key = load_ssh_public_key(ssh_key, backend) 1280 1281 expected_x = int( 1282 "54124123120178189598842622575230904027376313369742467279346415219" 1283 "77809037378785192537810367028427387173980786968395921877911964629" 1284 "142163122798974160187785455", 1285 10, 1286 ) 1287 expected_y = int( 1288 "16111775122845033200938694062381820957441843014849125660011303579" 1289 "15284560361402515564433711416776946492019498546572162801954089916" 1290 "006665939539407104638103918", 1291 10, 1292 ) 1293 1294 assert key.public_numbers() == ec.EllipticCurvePublicNumbers( 1295 expected_x, expected_y, ec.SECP521R1() 1296 ) 1297 1298 def test_load_ssh_public_key_ecdsa_nist_p256_trailing_data(self, backend): 1299 ssh_key = ( 1300 b"ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAy" 1301 b"NTYAAABBBGG2MfkHXp0UkxUyllDzWNBAImsvt5t7pFtTXegZK2WbGxml8zMrgWi5" 1302 b"teIg1TO03/FD9hbpBFgBeix3NrCFPltB= root@cloud-server-01" 1303 ) 1304 with pytest.raises(ValueError): 1305 load_ssh_public_key(ssh_key, backend) 1306 1307 def test_load_ssh_public_key_ecdsa_nist_p256_missing_data(self, backend): 1308 ssh_key = ( 1309 b"ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAy" 1310 b"NTYAAABBBGG2MfkHXp0UkxUyllDzWNBAImsvt5t7pFtTXegZK2WbGxml8zMrgWi5" 1311 b"teIg1TO03/FD9hbpBFgBeix3NrCF= root@cloud-server-01" 1312 ) 1313 with pytest.raises(ValueError): 1314 load_ssh_public_key(ssh_key, backend) 1315 1316 def test_load_ssh_public_key_ecdsa_nist_p256_compressed(self, backend): 1317 # If we ever implement compressed points, note that this is not a valid 1318 # one, it just has the compressed marker in the right place. 1319 ssh_key = ( 1320 b"ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAy" 1321 b"NTYAAABBAWG2MfkHXp0UkxUyllDzWNBAImsvt5t7pFtTXegZK2WbGxml8zMrgWi5" 1322 b"teIg1TO03/FD9hbpBFgBeix3NrCFPls= root@cloud-server-01" 1323 ) 1324 with pytest.raises(NotImplementedError): 1325 load_ssh_public_key(ssh_key, backend) 1326 1327 def test_load_ssh_public_key_ecdsa_nist_p256_bad_curve_name(self, backend): 1328 ssh_key = ( 1329 # The curve name in here is changed to be "nistp255". 1330 b"ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAy" 1331 b"NTUAAABBBGG2MfkHXp0UkxUyllDzWNBAImsvt5t7pFtTXegZK2WbGxml8zMrgWi5" 1332 b"teIg1TO03/FD9hbpBFgBeix3NrCFPls= root@cloud-server-01" 1333 ) 1334 with pytest.raises(ValueError): 1335 load_ssh_public_key(ssh_key, backend) 1336 1337 1338@pytest.mark.supported( 1339 only_if=lambda backend: backend.ed25519_supported(), 1340 skip_message="Requires OpenSSL with Ed25519 support", 1341) 1342class TestEd25519SSHSerialization(object): 1343 def test_load_ssh_public_key(self, backend): 1344 ssh_key = ( 1345 b"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIG2fgpmpYO61qeAxGd0wgRaN/E4" 1346 b"GR+xWvBmvxjxrB1vG user@chiron.local" 1347 ) 1348 key = load_ssh_public_key(ssh_key, backend) 1349 assert isinstance(key, ed25519.Ed25519PublicKey) 1350 assert key.public_bytes(Encoding.Raw, PublicFormat.Raw) == ( 1351 b"m\x9f\x82\x99\xa9`\xee\xb5\xa9\xe01\x19\xdd0\x81\x16\x8d\xfc" 1352 b"N\x06G\xecV\xbc\x19\xaf\xc6<k\x07[\xc6" 1353 ) 1354 1355 def test_public_bytes_openssh(self, backend): 1356 ssh_key = ( 1357 b"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIG2fgpmpYO61qeAxGd0wgRaN/E4" 1358 b"GR+xWvBmvxjxrB1vG" 1359 ) 1360 key = load_ssh_public_key(ssh_key, backend) 1361 assert isinstance(key, ed25519.Ed25519PublicKey) 1362 assert ( 1363 key.public_bytes(Encoding.OpenSSH, PublicFormat.OpenSSH) == ssh_key 1364 ) 1365 1366 def test_load_ssh_public_key_not_32_bytes(self, backend): 1367 ssh_key = ( 1368 b"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI22fgpmpYO61qeAxGd0wgRaN/E4" 1369 b"GR+xWvBmvxjxrB1vGaGVs user@chiron.local" 1370 ) 1371 with pytest.raises(ValueError): 1372 load_ssh_public_key(ssh_key, backend) 1373 1374 def test_load_ssh_public_key_trailing_data(self, backend): 1375 ssh_key = ( 1376 b"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIG2fgpmpYO61qeAxGd0wgRa" 1377 b"N/E4GR+xWvBmvxjxrB1vGdHJhaWxpbmdkYXRh user@chiron.local" 1378 ) 1379 with pytest.raises(ValueError): 1380 load_ssh_public_key(ssh_key, backend) 1381 1382 1383class TestKeySerializationEncryptionTypes(object): 1384 def test_non_bytes_password(self): 1385 with pytest.raises(ValueError): 1386 BestAvailableEncryption(object()) 1387 1388 def test_encryption_with_zero_length_password(self): 1389 with pytest.raises(ValueError): 1390 BestAvailableEncryption(b"") 1391 1392 1393@pytest.mark.supported( 1394 only_if=lambda backend: backend.ed25519_supported(), 1395 skip_message="Requires OpenSSL with Ed25519 support", 1396) 1397class TestEd25519Serialization(object): 1398 def test_load_der_private_key(self, backend): 1399 data = load_vectors_from_file( 1400 os.path.join("asymmetric", "Ed25519", "ed25519-pkcs8-enc.der"), 1401 lambda derfile: derfile.read(), 1402 mode="rb", 1403 ) 1404 unencrypted = load_vectors_from_file( 1405 os.path.join("asymmetric", "Ed25519", "ed25519-pkcs8.der"), 1406 lambda derfile: derfile.read(), 1407 mode="rb", 1408 ) 1409 key = load_der_private_key(data, b"password", backend) 1410 assert ( 1411 key.private_bytes( 1412 Encoding.DER, PrivateFormat.PKCS8, NoEncryption() 1413 ) 1414 == unencrypted 1415 ) 1416 1417 def test_load_pem_private_key(self, backend): 1418 data = load_vectors_from_file( 1419 os.path.join("asymmetric", "Ed25519", "ed25519-pkcs8-enc.pem"), 1420 lambda pemfile: pemfile.read(), 1421 mode="rb", 1422 ) 1423 unencrypted = load_vectors_from_file( 1424 os.path.join("asymmetric", "Ed25519", "ed25519-pkcs8.pem"), 1425 lambda pemfile: pemfile.read(), 1426 mode="rb", 1427 ) 1428 key = load_pem_private_key(data, b"password", backend) 1429 assert ( 1430 key.private_bytes( 1431 Encoding.PEM, PrivateFormat.PKCS8, NoEncryption() 1432 ) 1433 == unencrypted 1434 ) 1435 1436 @pytest.mark.parametrize( 1437 ("key_path", "encoding", "loader"), 1438 [ 1439 ( 1440 ["Ed25519", "ed25519-pub.pem"], 1441 Encoding.PEM, 1442 load_pem_public_key, 1443 ), 1444 ( 1445 ["Ed25519", "ed25519-pub.der"], 1446 Encoding.DER, 1447 load_der_public_key, 1448 ), 1449 ], 1450 ) 1451 def test_load_public_key(self, key_path, encoding, loader, backend): 1452 data = load_vectors_from_file( 1453 os.path.join("asymmetric", *key_path), 1454 lambda pemfile: pemfile.read(), 1455 mode="rb", 1456 ) 1457 public_key = loader(data, backend) 1458 assert ( 1459 public_key.public_bytes( 1460 encoding, PublicFormat.SubjectPublicKeyInfo 1461 ) 1462 == data 1463 ) 1464 1465 def test_openssl_serialization_unsupported(self, backend): 1466 key = ed25519.Ed25519PrivateKey.generate() 1467 with pytest.raises(ValueError): 1468 key.private_bytes( 1469 Encoding.PEM, 1470 PrivateFormat.TraditionalOpenSSL, 1471 NoEncryption(), 1472 ) 1473 with pytest.raises(ValueError): 1474 key.private_bytes( 1475 Encoding.DER, 1476 PrivateFormat.TraditionalOpenSSL, 1477 NoEncryption(), 1478 ) 1479 1480 1481@pytest.mark.supported( 1482 only_if=lambda backend: backend.x448_supported(), 1483 skip_message="Requires OpenSSL with X448 support", 1484) 1485class TestX448Serialization(object): 1486 def test_load_der_private_key(self, backend): 1487 data = load_vectors_from_file( 1488 os.path.join("asymmetric", "X448", "x448-pkcs8-enc.der"), 1489 lambda derfile: derfile.read(), 1490 mode="rb", 1491 ) 1492 unencrypted = load_vectors_from_file( 1493 os.path.join("asymmetric", "X448", "x448-pkcs8.der"), 1494 lambda derfile: derfile.read(), 1495 mode="rb", 1496 ) 1497 key = load_der_private_key(data, b"password", backend) 1498 assert ( 1499 key.private_bytes( 1500 Encoding.DER, PrivateFormat.PKCS8, NoEncryption() 1501 ) 1502 == unencrypted 1503 ) 1504 1505 def test_load_pem_private_key(self, backend): 1506 data = load_vectors_from_file( 1507 os.path.join("asymmetric", "X448", "x448-pkcs8-enc.pem"), 1508 lambda pemfile: pemfile.read(), 1509 mode="rb", 1510 ) 1511 unencrypted = load_vectors_from_file( 1512 os.path.join("asymmetric", "X448", "x448-pkcs8.pem"), 1513 lambda pemfile: pemfile.read(), 1514 mode="rb", 1515 ) 1516 key = load_pem_private_key(data, b"password", backend) 1517 assert ( 1518 key.private_bytes( 1519 Encoding.PEM, PrivateFormat.PKCS8, NoEncryption() 1520 ) 1521 == unencrypted 1522 ) 1523 1524 @pytest.mark.parametrize( 1525 ("key_path", "encoding", "loader"), 1526 [ 1527 (["X448", "x448-pub.pem"], Encoding.PEM, load_pem_public_key), 1528 (["X448", "x448-pub.der"], Encoding.DER, load_der_public_key), 1529 ], 1530 ) 1531 def test_load_public_key(self, key_path, encoding, loader, backend): 1532 data = load_vectors_from_file( 1533 os.path.join("asymmetric", *key_path), 1534 lambda pemfile: pemfile.read(), 1535 mode="rb", 1536 ) 1537 public_key = loader(data, backend) 1538 assert ( 1539 public_key.public_bytes( 1540 encoding, PublicFormat.SubjectPublicKeyInfo 1541 ) 1542 == data 1543 ) 1544 1545 def test_openssl_serialization_unsupported(self, backend): 1546 key = x448.X448PrivateKey.generate() 1547 with pytest.raises(ValueError): 1548 key.private_bytes( 1549 Encoding.PEM, 1550 PrivateFormat.TraditionalOpenSSL, 1551 NoEncryption(), 1552 ) 1553 with pytest.raises(ValueError): 1554 key.private_bytes( 1555 Encoding.DER, 1556 PrivateFormat.TraditionalOpenSSL, 1557 NoEncryption(), 1558 ) 1559 1560 def test_openssh_serialization_unsupported(self, backend): 1561 key = x448.X448PrivateKey.generate() 1562 with pytest.raises(ValueError): 1563 key.public_key().public_bytes( 1564 Encoding.OpenSSH, PublicFormat.OpenSSH 1565 ) 1566 with pytest.raises(ValueError): 1567 key.private_bytes( 1568 Encoding.PEM, PrivateFormat.OpenSSH, NoEncryption() 1569 ) 1570 1571 1572@pytest.mark.supported( 1573 only_if=lambda backend: backend.x25519_supported(), 1574 skip_message="Requires OpenSSL with X25519 support", 1575) 1576class TestX25519Serialization(object): 1577 def test_load_der_private_key(self, backend): 1578 data = load_vectors_from_file( 1579 os.path.join("asymmetric", "X25519", "x25519-pkcs8-enc.der"), 1580 lambda derfile: derfile.read(), 1581 mode="rb", 1582 ) 1583 unencrypted = load_vectors_from_file( 1584 os.path.join("asymmetric", "X25519", "x25519-pkcs8.der"), 1585 lambda derfile: derfile.read(), 1586 mode="rb", 1587 ) 1588 key = load_der_private_key(data, b"password", backend) 1589 assert ( 1590 key.private_bytes( 1591 Encoding.DER, PrivateFormat.PKCS8, NoEncryption() 1592 ) 1593 == unencrypted 1594 ) 1595 1596 def test_load_pem_private_key(self, backend): 1597 data = load_vectors_from_file( 1598 os.path.join("asymmetric", "X25519", "x25519-pkcs8-enc.pem"), 1599 lambda pemfile: pemfile.read(), 1600 mode="rb", 1601 ) 1602 unencrypted = load_vectors_from_file( 1603 os.path.join("asymmetric", "X25519", "x25519-pkcs8.pem"), 1604 lambda pemfile: pemfile.read(), 1605 mode="rb", 1606 ) 1607 key = load_pem_private_key(data, b"password", backend) 1608 assert ( 1609 key.private_bytes( 1610 Encoding.PEM, PrivateFormat.PKCS8, NoEncryption() 1611 ) 1612 == unencrypted 1613 ) 1614 1615 @pytest.mark.parametrize( 1616 ("key_path", "encoding", "loader"), 1617 [ 1618 (["X25519", "x25519-pub.pem"], Encoding.PEM, load_pem_public_key), 1619 (["X25519", "x25519-pub.der"], Encoding.DER, load_der_public_key), 1620 ], 1621 ) 1622 def test_load_public_key(self, key_path, encoding, loader, backend): 1623 data = load_vectors_from_file( 1624 os.path.join("asymmetric", *key_path), 1625 lambda pemfile: pemfile.read(), 1626 mode="rb", 1627 ) 1628 public_key = loader(data, backend) 1629 assert ( 1630 public_key.public_bytes( 1631 encoding, PublicFormat.SubjectPublicKeyInfo 1632 ) 1633 == data 1634 ) 1635 1636 def test_openssl_serialization_unsupported(self, backend): 1637 key = x25519.X25519PrivateKey.generate() 1638 with pytest.raises(ValueError): 1639 key.private_bytes( 1640 Encoding.PEM, 1641 PrivateFormat.TraditionalOpenSSL, 1642 NoEncryption(), 1643 ) 1644 with pytest.raises(ValueError): 1645 key.private_bytes( 1646 Encoding.DER, 1647 PrivateFormat.TraditionalOpenSSL, 1648 NoEncryption(), 1649 ) 1650 1651 def test_openssh_serialization_unsupported(self, backend): 1652 key = x25519.X25519PrivateKey.generate() 1653 with pytest.raises(ValueError): 1654 key.public_key().public_bytes( 1655 Encoding.OpenSSH, PublicFormat.OpenSSH 1656 ) 1657 with pytest.raises(ValueError): 1658 key.private_bytes( 1659 Encoding.PEM, PrivateFormat.OpenSSH, NoEncryption() 1660 ) 1661 1662 1663@pytest.mark.supported( 1664 only_if=lambda backend: backend.ed448_supported(), 1665 skip_message="Requires OpenSSL with Ed448 support", 1666) 1667class TestEd448Serialization(object): 1668 def test_load_der_private_key(self, backend): 1669 data = load_vectors_from_file( 1670 os.path.join("asymmetric", "Ed448", "ed448-pkcs8-enc.der"), 1671 lambda derfile: derfile.read(), 1672 mode="rb", 1673 ) 1674 unencrypted = load_vectors_from_file( 1675 os.path.join("asymmetric", "Ed448", "ed448-pkcs8.der"), 1676 lambda derfile: derfile.read(), 1677 mode="rb", 1678 ) 1679 key = load_der_private_key(data, b"password", backend) 1680 assert ( 1681 key.private_bytes( 1682 Encoding.DER, PrivateFormat.PKCS8, NoEncryption() 1683 ) 1684 == unencrypted 1685 ) 1686 1687 def test_load_pem_private_key(self, backend): 1688 data = load_vectors_from_file( 1689 os.path.join("asymmetric", "Ed448", "ed448-pkcs8-enc.pem"), 1690 lambda pemfile: pemfile.read(), 1691 mode="rb", 1692 ) 1693 unencrypted = load_vectors_from_file( 1694 os.path.join("asymmetric", "Ed448", "ed448-pkcs8.pem"), 1695 lambda pemfile: pemfile.read(), 1696 mode="rb", 1697 ) 1698 key = load_pem_private_key(data, b"password", backend) 1699 assert ( 1700 key.private_bytes( 1701 Encoding.PEM, PrivateFormat.PKCS8, NoEncryption() 1702 ) 1703 == unencrypted 1704 ) 1705 1706 @pytest.mark.parametrize( 1707 ("key_path", "encoding", "loader"), 1708 [ 1709 (["Ed448", "ed448-pub.pem"], Encoding.PEM, load_pem_public_key), 1710 (["Ed448", "ed448-pub.der"], Encoding.DER, load_der_public_key), 1711 ], 1712 ) 1713 def test_load_public_key(self, key_path, encoding, loader, backend): 1714 data = load_vectors_from_file( 1715 os.path.join("asymmetric", *key_path), 1716 lambda pemfile: pemfile.read(), 1717 mode="rb", 1718 ) 1719 public_key = loader(data, backend) 1720 assert ( 1721 public_key.public_bytes( 1722 encoding, PublicFormat.SubjectPublicKeyInfo 1723 ) 1724 == data 1725 ) 1726 1727 def test_openssl_serialization_unsupported(self, backend): 1728 key = ed448.Ed448PrivateKey.generate() 1729 with pytest.raises(ValueError): 1730 key.private_bytes( 1731 Encoding.PEM, 1732 PrivateFormat.TraditionalOpenSSL, 1733 NoEncryption(), 1734 ) 1735 with pytest.raises(ValueError): 1736 key.private_bytes( 1737 Encoding.DER, 1738 PrivateFormat.TraditionalOpenSSL, 1739 NoEncryption(), 1740 ) 1741 1742 def test_openssh_serialization_unsupported(self, backend): 1743 key = ed448.Ed448PrivateKey.generate() 1744 with pytest.raises(ValueError): 1745 key.public_key().public_bytes( 1746 Encoding.OpenSSH, 1747 PublicFormat.OpenSSH, 1748 ) 1749 with pytest.raises(ValueError): 1750 key.private_bytes( 1751 Encoding.PEM, 1752 PrivateFormat.OpenSSH, 1753 NoEncryption(), 1754 ) 1755 1756 1757class TestDHSerialization(object): 1758 """Test all options with least-supported key type.""" 1759 1760 @pytest.mark.skip_fips(reason="non-FIPS parameters") 1761 def test_dh_public_key(self, backend): 1762 data = load_vectors_from_file( 1763 os.path.join("asymmetric", "DH", "dhkey.pem"), 1764 lambda pemfile: pemfile.read(), 1765 mode="rb", 1766 ) 1767 public_key = load_pem_private_key(data, None, backend).public_key() 1768 for enc in ( 1769 Encoding.PEM, 1770 Encoding.DER, 1771 Encoding.OpenSSH, 1772 Encoding.Raw, 1773 Encoding.X962, 1774 ): 1775 for fmt in ( 1776 PublicFormat.SubjectPublicKeyInfo, 1777 PublicFormat.PKCS1, 1778 PublicFormat.OpenSSH, 1779 PublicFormat.Raw, 1780 PublicFormat.CompressedPoint, 1781 PublicFormat.UncompressedPoint, 1782 ): 1783 if ( 1784 enc in (Encoding.PEM, Encoding.DER) 1785 and fmt == PublicFormat.SubjectPublicKeyInfo 1786 ): 1787 # tested elsewhere 1788 continue 1789 with pytest.raises(ValueError): 1790 public_key.public_bytes(enc, fmt) 1791 1792 @pytest.mark.skip_fips(reason="non-FIPS parameters") 1793 def test_dh_private_key(self, backend): 1794 data = load_vectors_from_file( 1795 os.path.join("asymmetric", "DH", "dhkey.pem"), 1796 lambda pemfile: pemfile.read(), 1797 mode="rb", 1798 ) 1799 private_key = load_pem_private_key(data, None, backend) 1800 for enc in ( 1801 Encoding.PEM, 1802 Encoding.DER, 1803 Encoding.OpenSSH, 1804 Encoding.Raw, 1805 Encoding.X962, 1806 ): 1807 for fmt in ( 1808 PrivateFormat.PKCS8, 1809 PrivateFormat.TraditionalOpenSSL, 1810 PrivateFormat.Raw, 1811 ): 1812 if ( 1813 enc in (Encoding.PEM, Encoding.DER) 1814 and fmt is PrivateFormat.PKCS8 1815 ): 1816 # tested elsewhere 1817 continue 1818 with pytest.raises(ValueError): 1819 private_key.private_bytes(enc, fmt, NoEncryption()) 1820 1821 1822@pytest.mark.requires_backend_interface(interface=RSABackend) 1823@pytest.mark.requires_backend_interface(interface=DSABackend) 1824@pytest.mark.requires_backend_interface(interface=EllipticCurveBackend) 1825class TestOpenSSHSerialization(object): 1826 @pytest.mark.parametrize( 1827 ("key_file", "cert_file"), 1828 [ 1829 ("rsa-psw.key.pub", None), 1830 ("rsa-nopsw.key.pub", "rsa-nopsw.key-cert.pub"), 1831 ("dsa-psw.key.pub", None), 1832 ("dsa-nopsw.key.pub", "dsa-nopsw.key-cert.pub"), 1833 ("ecdsa-psw.key.pub", None), 1834 ("ecdsa-nopsw.key.pub", "ecdsa-nopsw.key-cert.pub"), 1835 ("ed25519-psw.key.pub", None), 1836 ("ed25519-nopsw.key.pub", "ed25519-nopsw.key-cert.pub"), 1837 ], 1838 ) 1839 def test_load_ssh_public_key(self, key_file, cert_file, backend): 1840 if "ed25519" in key_file and not backend.ed25519_supported(): 1841 pytest.skip("Requires OpenSSL with Ed25519 support") 1842 1843 # normal public key 1844 pub_data = load_vectors_from_file( 1845 os.path.join("asymmetric", "OpenSSH", key_file), 1846 lambda f: f.read(), 1847 mode="rb", 1848 ) 1849 public_key = load_ssh_public_key(pub_data, backend) 1850 nocomment_data = b" ".join(pub_data.split()[:2]) 1851 assert ( 1852 public_key.public_bytes(Encoding.OpenSSH, PublicFormat.OpenSSH) 1853 == nocomment_data 1854 ) 1855 1856 self.run_partial_pubkey(pub_data, backend) 1857 1858 # parse public key with ssh certificate 1859 if cert_file: 1860 cert_data = load_vectors_from_file( 1861 os.path.join("asymmetric", "OpenSSH", cert_file), 1862 lambda f: f.read(), 1863 mode="rb", 1864 ) 1865 cert_key = load_ssh_public_key(cert_data, backend) 1866 assert ( 1867 cert_key.public_bytes(Encoding.OpenSSH, PublicFormat.OpenSSH) 1868 == nocomment_data 1869 ) 1870 1871 # try with more spaces 1872 cert_data = b" \t ".join(cert_data.split()) 1873 cert_key = load_ssh_public_key(cert_data, backend) 1874 assert ( 1875 cert_key.public_bytes(Encoding.OpenSSH, PublicFormat.OpenSSH) 1876 == nocomment_data 1877 ) 1878 1879 self.run_partial_pubkey(cert_data, backend) 1880 1881 def run_partial_pubkey(self, pubdata, backend): 1882 parts = pubdata.split() 1883 raw = base64.b64decode(parts[1]) 1884 for i in range(1, len(raw)): 1885 frag = base64.b64encode(raw[:i]) 1886 new_pub = b" ".join([parts[0], frag]) 1887 with pytest.raises(ValueError): 1888 load_ssh_public_key(new_pub, backend) 1889 1890 @pytest.mark.parametrize( 1891 ("key_file",), 1892 [ 1893 ("rsa-nopsw.key",), 1894 ("rsa-psw.key",), 1895 ("dsa-nopsw.key",), 1896 ("dsa-psw.key",), 1897 ("ecdsa-nopsw.key",), 1898 ("ecdsa-psw.key",), 1899 ("ed25519-nopsw.key",), 1900 ("ed25519-psw.key",), 1901 ], 1902 ) 1903 def test_load_ssh_private_key(self, key_file, backend): 1904 if "ed25519" in key_file and not backend.ed25519_supported(): 1905 pytest.skip("Requires OpenSSL with Ed25519 support") 1906 if "-psw" in key_file and not ssh._bcrypt_supported: 1907 pytest.skip("Requires bcrypt module") 1908 1909 # read public and private key from ssh-keygen 1910 priv_data = load_vectors_from_file( 1911 os.path.join("asymmetric", "OpenSSH", key_file), 1912 lambda f: f.read(), 1913 mode="rb", 1914 ) 1915 pub_data = load_vectors_from_file( 1916 os.path.join("asymmetric", "OpenSSH", key_file + ".pub"), 1917 lambda f: f.read(), 1918 mode="rb", 1919 ) 1920 nocomment_data = b" ".join(pub_data.split()[:2]) 1921 1922 # load and compare 1923 password = None 1924 if "-psw" in key_file: 1925 password = b"password" 1926 private_key = load_ssh_private_key(priv_data, password, backend) 1927 assert ( 1928 private_key.public_key().public_bytes( 1929 Encoding.OpenSSH, PublicFormat.OpenSSH 1930 ) 1931 == nocomment_data 1932 ) 1933 1934 # bytearray 1935 private_key = load_ssh_private_key( 1936 bytearray(priv_data), password, backend 1937 ) 1938 assert ( 1939 private_key.public_key().public_bytes( 1940 Encoding.OpenSSH, PublicFormat.OpenSSH 1941 ) 1942 == nocomment_data 1943 ) 1944 1945 if six.PY3: 1946 # memoryview(bytes) 1947 private_key = load_ssh_private_key( 1948 memoryview(priv_data), password, backend 1949 ) 1950 assert ( 1951 private_key.public_key().public_bytes( 1952 Encoding.OpenSSH, PublicFormat.OpenSSH 1953 ) 1954 == nocomment_data 1955 ) 1956 1957 # memoryview(bytearray) 1958 private_key = load_ssh_private_key( 1959 memoryview(bytearray(priv_data)), password, backend 1960 ) 1961 assert ( 1962 private_key.public_key().public_bytes( 1963 Encoding.OpenSSH, PublicFormat.OpenSSH 1964 ) 1965 == nocomment_data 1966 ) 1967 1968 # serialize with own code and reload 1969 encryption = NoEncryption() 1970 if password: 1971 encryption = BestAvailableEncryption(password) 1972 priv_data2 = private_key.private_bytes( 1973 Encoding.PEM, 1974 PrivateFormat.OpenSSH, 1975 encryption, 1976 ) 1977 private_key2 = load_ssh_private_key(priv_data2, password, backend) 1978 assert ( 1979 private_key2.public_key().public_bytes( 1980 Encoding.OpenSSH, PublicFormat.OpenSSH 1981 ) 1982 == nocomment_data 1983 ) 1984 1985 # make sure multi-line base64 is used 1986 maxline = max(map(len, priv_data2.split(b"\n"))) 1987 assert maxline < 80 1988 1989 @pytest.mark.supported( 1990 only_if=lambda backend: ssh._bcrypt_supported, 1991 skip_message="Requires that bcrypt exists", 1992 ) 1993 def test_bcrypt_encryption(self, backend): 1994 private_key = ec.generate_private_key(ec.SECP256R1(), backend) 1995 pub1 = private_key.public_key().public_bytes( 1996 Encoding.OpenSSH, PublicFormat.OpenSSH 1997 ) 1998 1999 for psw in ( 2000 b"1", 2001 b"1234", 2002 b"1234" * 4, 2003 b"x" * 72, 2004 ): 2005 # BestAvailableEncryption does not handle bytes-like? 2006 best = BestAvailableEncryption(psw) 2007 encdata = private_key.private_bytes( 2008 Encoding.PEM, PrivateFormat.OpenSSH, best 2009 ) 2010 decoded_key = load_ssh_private_key(encdata, psw, backend) 2011 pub2 = decoded_key.public_key().public_bytes( 2012 Encoding.OpenSSH, PublicFormat.OpenSSH 2013 ) 2014 assert pub1 == pub2 2015 2016 # bytearray 2017 decoded_key2 = load_ssh_private_key( 2018 bytearray(encdata), psw, backend 2019 ) 2020 pub2 = decoded_key2.public_key().public_bytes( 2021 Encoding.OpenSSH, PublicFormat.OpenSSH 2022 ) 2023 assert pub1 == pub2 2024 2025 if six.PY3: 2026 # memoryview(bytes) 2027 decoded_key2 = load_ssh_private_key( 2028 memoryview(encdata), psw, backend 2029 ) 2030 pub2 = decoded_key2.public_key().public_bytes( 2031 Encoding.OpenSSH, PublicFormat.OpenSSH 2032 ) 2033 assert pub1 == pub2 2034 2035 # memoryview(bytearray) 2036 decoded_key2 = load_ssh_private_key( 2037 memoryview(bytearray(encdata)), psw, backend 2038 ) 2039 pub2 = decoded_key2.public_key().public_bytes( 2040 Encoding.OpenSSH, PublicFormat.OpenSSH 2041 ) 2042 assert pub1 == pub2 2043 2044 with pytest.raises(ValueError): 2045 decoded_key = load_ssh_private_key(encdata, None, backend) 2046 with pytest.raises(ValueError): 2047 decoded_key = load_ssh_private_key(encdata, b"wrong", backend) 2048 2049 @pytest.mark.supported( 2050 only_if=lambda backend: not ssh._bcrypt_supported, 2051 skip_message="Requires that bcrypt is missing", 2052 ) 2053 def test_missing_bcrypt(self, backend): 2054 priv_data = load_vectors_from_file( 2055 os.path.join("asymmetric", "OpenSSH", "ecdsa-psw.key"), 2056 lambda f: f.read(), 2057 mode="rb", 2058 ) 2059 with pytest.raises(UnsupportedAlgorithm): 2060 load_ssh_private_key(priv_data, b"password", backend) 2061 2062 private_key = ec.generate_private_key(ec.SECP256R1(), backend) 2063 with pytest.raises(UnsupportedAlgorithm): 2064 private_key.private_bytes( 2065 Encoding.PEM, 2066 PrivateFormat.OpenSSH, 2067 BestAvailableEncryption(b"x"), 2068 ) 2069 2070 def test_fraglist_corners(self): 2071 f = ssh._FragList() 2072 with pytest.raises(ValueError): 2073 f.put_mpint(-1) 2074 f.put_mpint(0) 2075 f.put_mpint(0x80) 2076 assert f.tobytes() == b"\0\0\0\0" + b"\0\0\0\x02" + b"\0\x80" 2077 2078 def make_file( 2079 self, 2080 magic=b"openssh-key-v1\0", 2081 ciphername=b"none", 2082 kdfname=b"none", 2083 kdfoptions=b"", 2084 nkeys=1, 2085 pub_type=b"ecdsa-sha2-nistp256", 2086 pub_fields=( 2087 b"nistp256", 2088 b"\x04" * 65, 2089 ), 2090 priv_type=None, 2091 priv_fields=(b"nistp256", b"\x04" * 65, b"\x7F" * 32), 2092 comment=b"comment", 2093 checkval1=b"1234", 2094 checkval2=b"1234", 2095 pad=None, 2096 header=b"-----BEGIN OPENSSH PRIVATE KEY-----\n", 2097 footer=b"-----END OPENSSH PRIVATE KEY-----\n", 2098 cut=8192, 2099 ): 2100 """Create private key file""" 2101 if not priv_type: 2102 priv_type = pub_type 2103 2104 pub = ssh._FragList() 2105 for elem in (pub_type,) + pub_fields: 2106 pub.put_sshstr(elem) 2107 2108 secret = ssh._FragList([checkval1, checkval2]) 2109 for i in range(nkeys): 2110 for elem in (priv_type,) + priv_fields + (comment,): 2111 secret.put_sshstr(elem) 2112 2113 if pad is None: 2114 pad_len = 8 - (secret.size() % 8) 2115 pad = bytearray(range(1, 1 + pad_len)) 2116 secret.put_raw(pad) 2117 2118 main = ssh._FragList([magic]) 2119 main.put_sshstr(ciphername) 2120 main.put_sshstr(kdfname) 2121 main.put_sshstr(kdfoptions) 2122 main.put_u32(nkeys) 2123 for i in range(nkeys): 2124 main.put_sshstr(pub) 2125 main.put_sshstr(secret) 2126 2127 res = main.tobytes() 2128 return ssh._ssh_pem_encode(res[:cut], header, footer) 2129 2130 def test_ssh_make_file(self, backend): 2131 # check if works by default 2132 data = self.make_file() 2133 key = load_ssh_private_key(data, None, backend) 2134 assert isinstance(key, ec.EllipticCurvePrivateKey) 2135 2136 def test_load_ssh_private_key_errors(self, backend): 2137 # bad kdf 2138 data = self.make_file(kdfname=b"unknown", ciphername=b"aes256-ctr") 2139 with pytest.raises(UnsupportedAlgorithm): 2140 load_ssh_private_key(data, None, backend) 2141 2142 # bad cipher 2143 data = self.make_file(ciphername=b"unknown", kdfname=b"bcrypt") 2144 with pytest.raises(UnsupportedAlgorithm): 2145 load_ssh_private_key(data, None, backend) 2146 2147 # bad magic 2148 data = self.make_file(magic=b"unknown") 2149 with pytest.raises(ValueError): 2150 load_ssh_private_key(data, None, backend) 2151 2152 # too few keys 2153 data = self.make_file(nkeys=0) 2154 with pytest.raises(ValueError): 2155 load_ssh_private_key(data, None, backend) 2156 2157 # too many keys 2158 data = self.make_file(nkeys=2) 2159 with pytest.raises(ValueError): 2160 load_ssh_private_key(data, None, backend) 2161 2162 def test_ssh_errors_bad_values(self, backend): 2163 # bad curve 2164 data = self.make_file(pub_type=b"ecdsa-sha2-nistp444") 2165 with pytest.raises(UnsupportedAlgorithm): 2166 load_ssh_private_key(data, None, backend) 2167 2168 # curve mismatch 2169 data = self.make_file(priv_type=b"ecdsa-sha2-nistp384") 2170 with pytest.raises(ValueError): 2171 load_ssh_private_key(data, None, backend) 2172 2173 # invalid bigint 2174 data = self.make_file( 2175 priv_fields=(b"nistp256", b"\x04" * 65, b"\x80" * 32) 2176 ) 2177 with pytest.raises(ValueError): 2178 load_ssh_private_key(data, None, backend) 2179 2180 def test_ssh_errors_pubpriv_mismatch(self, backend): 2181 # ecdsa public-private mismatch 2182 data = self.make_file( 2183 pub_fields=( 2184 b"nistp256", 2185 b"\x04" + b"\x05" * 64, 2186 ) 2187 ) 2188 with pytest.raises(ValueError): 2189 load_ssh_private_key(data, None, backend) 2190 2191 # rsa public-private mismatch 2192 data = self.make_file( 2193 pub_type=b"ssh-rsa", 2194 pub_fields=(b"x" * 32,) * 2, 2195 priv_fields=(b"z" * 32,) * 6, 2196 ) 2197 with pytest.raises(ValueError): 2198 load_ssh_private_key(data, None, backend) 2199 2200 # dsa public-private mismatch 2201 data = self.make_file( 2202 pub_type=b"ssh-dss", 2203 pub_fields=(b"x" * 32,) * 4, 2204 priv_fields=(b"z" * 32,) * 5, 2205 ) 2206 with pytest.raises(ValueError): 2207 load_ssh_private_key(data, None, backend) 2208 2209 # ed25519 public-private mismatch 2210 sk = b"x" * 32 2211 pk1 = b"y" * 32 2212 pk2 = b"z" * 32 2213 data = self.make_file( 2214 pub_type=b"ssh-ed25519", 2215 pub_fields=(pk1,), 2216 priv_fields=( 2217 pk1, 2218 sk + pk2, 2219 ), 2220 ) 2221 with pytest.raises(ValueError): 2222 load_ssh_private_key(data, None, backend) 2223 data = self.make_file( 2224 pub_type=b"ssh-ed25519", 2225 pub_fields=(pk1,), 2226 priv_fields=( 2227 pk2, 2228 sk + pk1, 2229 ), 2230 ) 2231 with pytest.raises(ValueError): 2232 load_ssh_private_key(data, None, backend) 2233 2234 def test_ssh_errors_bad_wrapper(self, backend): 2235 # wrong header 2236 data = self.make_file(header=b"-----BEGIN RSA PRIVATE KEY-----\n") 2237 with pytest.raises(ValueError): 2238 load_ssh_private_key(data, None, backend) 2239 2240 # wring footer 2241 data = self.make_file(footer=b"-----END RSA PRIVATE KEY-----\n") 2242 with pytest.raises(ValueError): 2243 load_ssh_private_key(data, None, backend) 2244 2245 def test_ssh_no_padding(self, backend): 2246 # no padding must work, if data is on block boundary 2247 data = self.make_file(pad=b"", comment=b"") 2248 key = load_ssh_private_key(data, None, backend) 2249 assert isinstance(key, ec.EllipticCurvePrivateKey) 2250 2251 # no padding with right last byte 2252 data = self.make_file(pad=b"", comment=b"\x08" * 8) 2253 key = load_ssh_private_key(data, None, backend) 2254 assert isinstance(key, ec.EllipticCurvePrivateKey) 2255 2256 # avoid unexpected padding removal 2257 data = self.make_file(pad=b"", comment=b"1234\x01\x02\x03\x04") 2258 key = load_ssh_private_key(data, None, backend) 2259 assert isinstance(key, ec.EllipticCurvePrivateKey) 2260 2261 # bad padding with right size 2262 data = self.make_file(pad=b"\x08" * 8, comment=b"") 2263 with pytest.raises(ValueError): 2264 load_ssh_private_key(data, None, backend) 2265 2266 def test_ssh_errors_bad_secrets(self, backend): 2267 # checkval mismatch 2268 data = self.make_file(checkval2=b"4321") 2269 with pytest.raises(ValueError): 2270 load_ssh_private_key(data, None, backend) 2271 2272 # bad padding, correct=1 2273 data = self.make_file(pad=b"\x01\x02") 2274 with pytest.raises(ValueError): 2275 load_ssh_private_key(data, None, backend) 2276 data = self.make_file(pad=b"") 2277 with pytest.raises(ValueError): 2278 load_ssh_private_key(data, None, backend) 2279 2280 @pytest.mark.supported( 2281 only_if=lambda backend: backend.elliptic_curve_supported( 2282 ec.SECP192R1() 2283 ), 2284 skip_message="Requires backend support for ec.SECP192R1", 2285 ) 2286 def test_serialize_ssh_private_key_errors_bad_curve(self, backend): 2287 private_key = ec.generate_private_key(ec.SECP192R1(), backend) 2288 with pytest.raises(ValueError): 2289 private_key.private_bytes( 2290 Encoding.PEM, PrivateFormat.OpenSSH, NoEncryption() 2291 ) 2292 2293 def test_serialize_ssh_private_key_errors(self, backend): 2294 # bad encoding 2295 private_key = ec.generate_private_key(ec.SECP256R1(), backend) 2296 with pytest.raises(ValueError): 2297 private_key.private_bytes( 2298 Encoding.DER, PrivateFormat.OpenSSH, NoEncryption() 2299 ) 2300 2301 # bad object type 2302 with pytest.raises(ValueError): 2303 ssh.serialize_ssh_private_key(object(), None) 2304 2305 private_key = ec.generate_private_key(ec.SECP256R1(), backend) 2306 2307 # too long password 2308 with pytest.raises(ValueError): 2309 private_key.private_bytes( 2310 Encoding.PEM, 2311 PrivateFormat.OpenSSH, 2312 BestAvailableEncryption(b"p" * 73), 2313 ) 2314 2315 # unknown encryption class 2316 with pytest.raises(ValueError): 2317 private_key.private_bytes( 2318 Encoding.PEM, 2319 PrivateFormat.OpenSSH, 2320 DummyKeySerializationEncryption(), 2321 ) 2322 2323 @pytest.mark.parametrize( 2324 ("key_path", "supported"), 2325 [ 2326 (["Traditional_OpenSSL_Serialization", "dsa.1024.pem"], True), 2327 (["Traditional_OpenSSL_Serialization", "dsa.2048.pem"], False), 2328 (["Traditional_OpenSSL_Serialization", "dsa.3072.pem"], False), 2329 ], 2330 ) 2331 def test_dsa_private_key_sizes(self, key_path, supported, backend): 2332 key = load_vectors_from_file( 2333 os.path.join("asymmetric", *key_path), 2334 lambda pemfile: load_pem_private_key( 2335 pemfile.read(), None, backend 2336 ), 2337 mode="rb", 2338 ) 2339 assert isinstance(key, dsa.DSAPrivateKey) 2340 if supported: 2341 res = key.private_bytes( 2342 Encoding.PEM, PrivateFormat.OpenSSH, NoEncryption() 2343 ) 2344 assert isinstance(res, bytes) 2345 else: 2346 with pytest.raises(ValueError): 2347 key.private_bytes( 2348 Encoding.PEM, PrivateFormat.OpenSSH, NoEncryption() 2349 ) 2350