1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163
|
"""Test cases for "metadata.py"."""
import copy
import unittest
from pathlib import Path
from cryptography.hazmat.primitives.serialization import load_pem_private_key
from securesystemslib.dsse import Envelope
from securesystemslib.exceptions import VerificationError
from securesystemslib.signer import CryptoSigner, Signature
PEMS_DIR = Path(__file__).parent / "data" / "pems"
class TestEnvelope(unittest.TestCase):
"""Test metadata interface provided by DSSE envelope."""
@classmethod
def setUpClass(cls):
cls.signers: list[CryptoSigner] = []
for keytype in ["rsa", "ecdsa", "ed25519"]:
path = PEMS_DIR / f"{keytype}_private.pem"
with open(path, "rb") as f:
data = f.read()
private_key = load_pem_private_key(data, None)
signer = CryptoSigner(private_key)
cls.signers.append(signer)
cls.signature_dict = {
"keyid": "11fa391a0ed7a447",
"sig": "MEYCIQCTQuRWZSj87PanpQ==",
}
cls.envelope_dict = {
"payload": "aGVsbG8gd29ybGQ=",
"payloadType": "http://example.com/HelloWorld",
"signatures": [cls.signature_dict],
}
cls.pae = b"DSSEv1 29 http://example.com/HelloWorld 11 hello world"
def test_envelope_from_dict_with_duplicate_signatures(self):
"""Test envelope from_dict generates error with duplicate signature keyids"""
envelope_dict = copy.deepcopy(self.envelope_dict)
# add duplicate keyid.
envelope_dict["signatures"].append(copy.deepcopy(self.signature_dict))
# assert that calling from_dict will raise an error.
expected_error_message = (
f"Multiple signatures found for keyid {self.signature_dict['keyid']}"
)
with self.assertRaises(ValueError) as context:
Envelope.from_dict(envelope_dict)
self.assertEqual(str(context.exception), expected_error_message)
def test_envelope_from_to_dict(self):
"""Test envelope to_dict and from_dict methods."""
envelope_dict = copy.deepcopy(self.envelope_dict)
# create envelope object from its dict.
envelope_obj = Envelope.from_dict(envelope_dict)
for signature in envelope_obj.signatures.values():
self.assertIsInstance(signature, Signature)
# Assert envelope dict created by to_dict will be equal.
self.assertDictEqual(self.envelope_dict, envelope_obj.to_dict())
def test_envelope_eq_(self):
"""Test envelope equality."""
envelope_obj = Envelope.from_dict(copy.deepcopy(self.envelope_dict))
# Assert that object and None will not be equal.
self.assertNotEqual(None, envelope_obj)
# Assert a copy of envelope_obj will be equal to envelope_obj.
envelope_obj_2 = copy.deepcopy(envelope_obj)
self.assertEqual(envelope_obj, envelope_obj_2)
# Assert that changing the "payload" will make the objects not equal.
envelope_obj_2.payload = b"wrong_payload"
self.assertNotEqual(envelope_obj, envelope_obj_2)
envelope_obj_2.payload = envelope_obj.payload
# Assert that changing the "payload_type" will make the objects not equal.
envelope_obj_2.payload_type = "wrong_payload_type"
self.assertNotEqual(envelope_obj, envelope_obj_2)
envelope_obj_2.payload = envelope_obj.payload
# Assert that changing the "signatures" will make the objects not equal.
sig_obg = Signature("", self.signature_dict["sig"])
envelope_obj_2.signatures = [sig_obg]
self.assertNotEqual(envelope_obj, envelope_obj_2)
def test_preauthencoding(self):
"""Test envelope Pre-Auth-Encoding."""
envelope_obj = Envelope.from_dict(copy.deepcopy(self.envelope_dict))
# Checking for Pre-Auth-Encoding generated is correct.
self.assertEqual(self.pae, envelope_obj.pae())
def test_sign_and_verify(self):
"""Test for creating and verifying DSSE signatures."""
# Create an Envelope with no signatures.
envelope_dict = copy.deepcopy(self.envelope_dict)
envelope_dict["signatures"] = []
envelope_obj = Envelope.from_dict(envelope_dict)
key_list = []
for signer in self.signers:
envelope_obj.sign(signer)
# Create a List of "Key" from key_dict.
key_list.append(signer.public_key)
# Check for signatures of Envelope.
self.assertEqual(len(self.signers), len(envelope_obj.signatures))
for signature in envelope_obj.signatures.values():
self.assertIsInstance(signature, Signature)
# Test for invalid threshold value for keys_list.
# threshold is 0.
with self.assertRaises(ValueError):
envelope_obj.verify(key_list, 0)
# threshold is greater than no of keys.
with self.assertRaises(ValueError):
envelope_obj.verify(key_list, 4)
# Test with valid keylist and threshold.
verified_keys = envelope_obj.verify(key_list, len(key_list))
self.assertEqual(len(verified_keys), len(key_list))
# Test for unknown keys and threshold of 1.
new_key_list = []
for key in key_list:
new_key = copy.deepcopy(key)
# if it has a different keyid, it is a different key in sslib
new_key.keyid = reversed(key.keyid)
new_key_list.append(new_key)
with self.assertRaises(VerificationError):
envelope_obj.verify(new_key_list, 1)
all_keys = key_list + new_key_list
envelope_obj.verify(all_keys, 3)
# Test with duplicate keys.
duplicate_keys = key_list + key_list
with self.assertRaises(VerificationError):
envelope_obj.verify(duplicate_keys, 4) # 3 unique keys, threshold 4.
# Run the unit tests.
if __name__ == "__main__":
unittest.main()
|