|
5 | 5 |
|
6 | 6 | try:
|
7 | 7 | from ecdsa.der import unpem
|
| 8 | + from ecdsa import der |
8 | 9 | from kyber_py.ml_kem.pkcs import (
|
9 | 10 | ek_to_pem,
|
10 | 11 | ek_from_pem,
|
| 12 | + ek_from_der, |
11 | 13 | dk_to_pem,
|
12 | 14 | dk_from_pem,
|
| 15 | + dk_from_der, |
13 | 16 | )
|
14 | 17 |
|
15 | 18 | ECDSA_PRESENT = True
|
@@ -615,3 +618,366 @@ def setUpClass(cls):
|
615 | 618 | uYOILhF1
|
616 | 619 | -----END PUBLIC KEY-----
|
617 | 620 | """
|
| 621 | + |
| 622 | + |
| 623 | +@unittest.skipUnless(ECDSA_PRESENT, "requires ecdsa package") |
| 624 | +class TestMalfomedKeys(unittest.TestCase): |
| 625 | + @classmethod |
| 626 | + def setUpClass(cls): |
| 627 | + cls.kem = ML_KEM_512 |
| 628 | + cls.seed = bytes(64) |
| 629 | + cls.ek, cls.dk = cls.kem.key_derive(cls.seed) |
| 630 | + |
| 631 | + def test_ek_sanity_check(self): |
| 632 | + enc = der.encode_sequence( |
| 633 | + der.encode_sequence( |
| 634 | + der.encode_oid(*self.kem.oid), |
| 635 | + ), |
| 636 | + der.encode_bitstring(self.ek, 0), |
| 637 | + ) |
| 638 | + |
| 639 | + kem, key = ek_from_der(enc) |
| 640 | + |
| 641 | + self.assertEqual(kem, self.kem) |
| 642 | + self.assertEqual(key, self.ek) |
| 643 | + |
| 644 | + def test_ek_trailing_junk_after_pub_key(self): |
| 645 | + enc = der.encode_sequence( |
| 646 | + der.encode_sequence( |
| 647 | + der.encode_oid(*self.kem.oid), |
| 648 | + ), |
| 649 | + der.encode_bitstring(self.ek, 0), |
| 650 | + ) + b'\x00' |
| 651 | + |
| 652 | + with self.assertRaises(der.UnexpectedDER) as e: |
| 653 | + ek_from_der(enc) |
| 654 | + |
| 655 | + self.assertIn("Trailing junk after DER public key", str(e.exception)) |
| 656 | + |
| 657 | + def test_ek_wrong_oid(self): |
| 658 | + enc = der.encode_sequence( |
| 659 | + der.encode_sequence( |
| 660 | + der.encode_oid(1, 2, 3, 4), |
| 661 | + ), |
| 662 | + der.encode_bitstring(self.ek, 0), |
| 663 | + ) |
| 664 | + |
| 665 | + with self.assertRaises(der.UnexpectedDER) as e: |
| 666 | + ek_from_der(enc) |
| 667 | + |
| 668 | + self.assertIn("Not recognised algoritm OID: (1, 2, 3, 4)", |
| 669 | + str(e.exception)) |
| 670 | + |
| 671 | + def test_ek_parameters_in_alg_id(self): |
| 672 | + enc = der.encode_sequence( |
| 673 | + der.encode_sequence( |
| 674 | + der.encode_oid(*self.kem.oid), |
| 675 | + der.encode_sequence(), |
| 676 | + ), |
| 677 | + der.encode_bitstring(self.ek, 0), |
| 678 | + ) |
| 679 | + |
| 680 | + with self.assertRaises(der.UnexpectedDER) as e: |
| 681 | + ek_from_der(enc) |
| 682 | + |
| 683 | + self.assertIn("Parameters specified for ML-KEM OID", |
| 684 | + str(e.exception)) |
| 685 | + |
| 686 | + def test_ek_junk_after_public_key(self): |
| 687 | + enc = der.encode_sequence( |
| 688 | + der.encode_sequence( |
| 689 | + der.encode_oid(*self.kem.oid), |
| 690 | + ), |
| 691 | + der.encode_bitstring(self.ek, 0), |
| 692 | + der.encode_integer(2), |
| 693 | + ) |
| 694 | + |
| 695 | + with self.assertRaises(der.UnexpectedDER) as e: |
| 696 | + ek_from_der(enc) |
| 697 | + |
| 698 | + self.assertIn("Trailing junk after public key bitsting", |
| 699 | + str(e.exception)) |
| 700 | + |
| 701 | + def test_ek_unexpected_size_of_key(self): |
| 702 | + enc = der.encode_sequence( |
| 703 | + der.encode_sequence( |
| 704 | + der.encode_oid(*self.kem.oid), |
| 705 | + ), |
| 706 | + der.encode_bitstring(self.ek + b'\x00', 0), |
| 707 | + ) |
| 708 | + |
| 709 | + with self.assertRaises(der.UnexpectedDER) as e: |
| 710 | + ek_from_der(enc) |
| 711 | + |
| 712 | + self.assertIn("Wrong key size for the OID in structure", |
| 713 | + str(e.exception)) |
| 714 | + |
| 715 | + def test_dk_sanity_both(self): |
| 716 | + enc = der.encode_sequence( |
| 717 | + der.encode_integer(0), |
| 718 | + der.encode_sequence( |
| 719 | + der.encode_oid(*self.kem.oid), |
| 720 | + ), |
| 721 | + der.encode_octet_string( |
| 722 | + der.encode_sequence( |
| 723 | + der.encode_octet_string(self.seed), |
| 724 | + der.encode_octet_string(self.dk), |
| 725 | + ), |
| 726 | + ), |
| 727 | + ) |
| 728 | + |
| 729 | + kem, expanded, seed, ek = dk_from_der(enc) |
| 730 | + |
| 731 | + self.assertEqual(self.kem, kem) |
| 732 | + self.assertEqual(self.dk, expanded) |
| 733 | + self.assertEqual(self.seed, seed) |
| 734 | + self.assertEqual(self.ek, ek) |
| 735 | + |
| 736 | + def test_dk_sanity_seed(self): |
| 737 | + enc = der.encode_sequence( |
| 738 | + der.encode_integer(0), |
| 739 | + der.encode_sequence( |
| 740 | + der.encode_oid(*self.kem.oid), |
| 741 | + ), |
| 742 | + der.encode_octet_string( |
| 743 | + der.encode_implicit(0, self.seed), |
| 744 | + ), |
| 745 | + ) |
| 746 | + |
| 747 | + kem, expanded, seed, ek = dk_from_der(enc) |
| 748 | + |
| 749 | + self.assertEqual(self.kem, kem) |
| 750 | + self.assertEqual(self.dk, expanded) |
| 751 | + self.assertEqual(self.seed, seed) |
| 752 | + self.assertEqual(self.ek, ek) |
| 753 | + |
| 754 | + def test_dk_sanity_expanded_only(self): |
| 755 | + enc = der.encode_sequence( |
| 756 | + der.encode_integer(0), |
| 757 | + der.encode_sequence( |
| 758 | + der.encode_oid(*self.kem.oid), |
| 759 | + ), |
| 760 | + der.encode_octet_string( |
| 761 | + der.encode_octet_string(self.dk), |
| 762 | + ), |
| 763 | + ) |
| 764 | + |
| 765 | + kem, expanded, seed, ek = dk_from_der(enc) |
| 766 | + |
| 767 | + self.assertEqual(self.kem, kem) |
| 768 | + self.assertEqual(self.dk, expanded) |
| 769 | + self.assertEqual(None, seed) |
| 770 | + self.assertEqual(self.ek, ek) |
| 771 | + |
| 772 | + def test_dk_trailing_junk(self): |
| 773 | + enc = der.encode_sequence( |
| 774 | + der.encode_integer(0), |
| 775 | + der.encode_sequence( |
| 776 | + der.encode_oid(*self.kem.oid), |
| 777 | + ), |
| 778 | + der.encode_octet_string( |
| 779 | + der.encode_sequence( |
| 780 | + der.encode_octet_string(self.seed), |
| 781 | + der.encode_octet_string(self.dk), |
| 782 | + ), |
| 783 | + ), |
| 784 | + ) + b'\x00' |
| 785 | + |
| 786 | + with self.assertRaises(der.UnexpectedDER) as e: |
| 787 | + dk_from_der(enc) |
| 788 | + |
| 789 | + self.assertIn("Trailing junk after private key structure", |
| 790 | + str(e.exception)) |
| 791 | + |
| 792 | + def test_dk_wrong_version(self): |
| 793 | + enc = der.encode_sequence( |
| 794 | + der.encode_integer(1), |
| 795 | + der.encode_sequence( |
| 796 | + der.encode_oid(*self.kem.oid), |
| 797 | + ), |
| 798 | + der.encode_octet_string( |
| 799 | + der.encode_sequence( |
| 800 | + der.encode_octet_string(self.seed), |
| 801 | + der.encode_octet_string(self.dk), |
| 802 | + ), |
| 803 | + ), |
| 804 | + ) |
| 805 | + |
| 806 | + with self.assertRaises(der.UnexpectedDER) as e: |
| 807 | + dk_from_der(enc) |
| 808 | + |
| 809 | + self.assertIn("Unsupported version: 1", |
| 810 | + str(e.exception)) |
| 811 | + |
| 812 | + def test_dk_wrong_oid(self): |
| 813 | + enc = der.encode_sequence( |
| 814 | + der.encode_integer(0), |
| 815 | + der.encode_sequence( |
| 816 | + der.encode_oid(1, 3, 2, 1), |
| 817 | + ), |
| 818 | + der.encode_octet_string( |
| 819 | + der.encode_sequence( |
| 820 | + der.encode_octet_string(self.seed), |
| 821 | + der.encode_octet_string(self.dk), |
| 822 | + ), |
| 823 | + ), |
| 824 | + ) |
| 825 | + |
| 826 | + with self.assertRaises(der.UnexpectedDER) as e: |
| 827 | + dk_from_der(enc) |
| 828 | + |
| 829 | + self.assertIn("Not recognised algorithm OID: (1, 3, 2, 1)", |
| 830 | + str(e.exception)) |
| 831 | + |
| 832 | + def test_dk_junk_after_oid(self): |
| 833 | + enc = der.encode_sequence( |
| 834 | + der.encode_integer(0), |
| 835 | + der.encode_sequence( |
| 836 | + der.encode_oid(*self.kem.oid), |
| 837 | + der.encode_integer(1), |
| 838 | + ), |
| 839 | + der.encode_octet_string( |
| 840 | + der.encode_sequence( |
| 841 | + der.encode_octet_string(self.seed), |
| 842 | + der.encode_octet_string(self.dk), |
| 843 | + ), |
| 844 | + ), |
| 845 | + ) |
| 846 | + |
| 847 | + with self.assertRaises(der.UnexpectedDER) as e: |
| 848 | + dk_from_der(enc) |
| 849 | + |
| 850 | + self.assertIn("Junk after algorithm OID", |
| 851 | + str(e.exception)) |
| 852 | + |
| 853 | + def test_dk_junk_after_both_encoding(self): |
| 854 | + enc = der.encode_sequence( |
| 855 | + der.encode_integer(0), |
| 856 | + der.encode_sequence( |
| 857 | + der.encode_oid(*self.kem.oid), |
| 858 | + ), |
| 859 | + der.encode_octet_string( |
| 860 | + der.encode_sequence( |
| 861 | + der.encode_octet_string(self.seed), |
| 862 | + der.encode_octet_string(self.dk), |
| 863 | + ) + b'\x00', |
| 864 | + ), |
| 865 | + ) |
| 866 | + |
| 867 | + with self.assertRaises(der.UnexpectedDER) as e: |
| 868 | + dk_from_der(enc) |
| 869 | + |
| 870 | + self.assertIn("Junk after both encoding", |
| 871 | + str(e.exception)) |
| 872 | + |
| 873 | + def test_dk_junk_in_both_encoding(self): |
| 874 | + enc = der.encode_sequence( |
| 875 | + der.encode_integer(0), |
| 876 | + der.encode_sequence( |
| 877 | + der.encode_oid(*self.kem.oid), |
| 878 | + ), |
| 879 | + der.encode_octet_string( |
| 880 | + der.encode_sequence( |
| 881 | + der.encode_octet_string(self.seed), |
| 882 | + der.encode_octet_string(self.dk), |
| 883 | + der.encode_integer(1), |
| 884 | + ), |
| 885 | + ), |
| 886 | + ) |
| 887 | + |
| 888 | + with self.assertRaises(der.UnexpectedDER) as e: |
| 889 | + dk_from_der(enc) |
| 890 | + |
| 891 | + self.assertIn("Junk after 'expandedKey' in 'both' value", |
| 892 | + str(e.exception)) |
| 893 | + |
| 894 | + def test_dk_wrong_expanded_key_size(self): |
| 895 | + enc = der.encode_sequence( |
| 896 | + der.encode_integer(0), |
| 897 | + der.encode_sequence( |
| 898 | + der.encode_oid(*self.kem.oid), |
| 899 | + ), |
| 900 | + der.encode_octet_string( |
| 901 | + der.encode_sequence( |
| 902 | + der.encode_octet_string(self.seed), |
| 903 | + der.encode_octet_string(self.dk + b'\x00'), |
| 904 | + ), |
| 905 | + ), |
| 906 | + ) |
| 907 | + |
| 908 | + with self.assertRaises(der.UnexpectedDER) as e: |
| 909 | + dk_from_der(enc) |
| 910 | + |
| 911 | + self.assertIn("Invalid expanded key size in encoding", |
| 912 | + str(e.exception)) |
| 913 | + |
| 914 | + def test_dk_wrong_seed_size(self): |
| 915 | + enc = der.encode_sequence( |
| 916 | + der.encode_integer(0), |
| 917 | + der.encode_sequence( |
| 918 | + der.encode_oid(*self.kem.oid), |
| 919 | + ), |
| 920 | + der.encode_octet_string( |
| 921 | + der.encode_sequence( |
| 922 | + der.encode_octet_string(self.seed + b'\x00'), |
| 923 | + der.encode_octet_string(self.dk), |
| 924 | + ), |
| 925 | + ), |
| 926 | + ) |
| 927 | + |
| 928 | + with self.assertRaises(der.UnexpectedDER) as e: |
| 929 | + dk_from_der(enc) |
| 930 | + |
| 931 | + self.assertIn("Invalid length of seed in encoding", |
| 932 | + str(e.exception)) |
| 933 | + |
| 934 | + def test_dk_wrong_tag_in_seed_encoding(self): |
| 935 | + enc = der.encode_sequence( |
| 936 | + der.encode_integer(0), |
| 937 | + der.encode_sequence( |
| 938 | + der.encode_oid(*self.kem.oid), |
| 939 | + ), |
| 940 | + der.encode_octet_string( |
| 941 | + der.encode_implicit(1, self.seed), |
| 942 | + ), |
| 943 | + ) |
| 944 | + |
| 945 | + with self.assertRaises(der.UnexpectedDER) as e: |
| 946 | + dk_from_der(enc) |
| 947 | + |
| 948 | + self.assertIn("Unexpected tag in private key encoding", |
| 949 | + str(e.exception)) |
| 950 | + |
| 951 | + def test_dk_junk_after_seed_encoding(self): |
| 952 | + enc = der.encode_sequence( |
| 953 | + der.encode_integer(0), |
| 954 | + der.encode_sequence( |
| 955 | + der.encode_oid(*self.kem.oid), |
| 956 | + ), |
| 957 | + der.encode_octet_string( |
| 958 | + der.encode_implicit(0, self.seed) + b'\x00', |
| 959 | + ), |
| 960 | + ) |
| 961 | + |
| 962 | + with self.assertRaises(der.UnexpectedDER) as e: |
| 963 | + dk_from_der(enc) |
| 964 | + |
| 965 | + self.assertIn("Junk after seed encoding", |
| 966 | + str(e.exception)) |
| 967 | + |
| 968 | + def test_dk_junk_after_expanded_key(self): |
| 969 | + enc = der.encode_sequence( |
| 970 | + der.encode_integer(0), |
| 971 | + der.encode_sequence( |
| 972 | + der.encode_oid(*self.kem.oid), |
| 973 | + ), |
| 974 | + der.encode_octet_string( |
| 975 | + der.encode_octet_string(self.dk) + b'\x00', |
| 976 | + ), |
| 977 | + ) |
| 978 | + |
| 979 | + with self.assertRaises(der.UnexpectedDER) as e: |
| 980 | + dk_from_der(enc) |
| 981 | + |
| 982 | + self.assertIn("Junk after expandedKey", |
| 983 | + str(e.exception)) |
0 commit comments