def test_fail_on_missing_symkpk(): cose_key = {KpKty: KtySymmetric, KpAlg: A128GCM} with pytest.raises(CoseInvalidKey) as excinfo: CoseKey.from_dict(cose_key) assert "SymKpK parameter cannot be None" in str(excinfo.value)
def test_dict_valid_deletion(): cose_key = { KpKty: KtyEC2, EC2KpD: p256_d, EC2KpX: p256_x, EC2KpY: p256_y, KpAlg: Es256, EC2KpCurve: P256, KpKeyOps: [SignOp] } key = CoseKey.from_dict(cose_key) del key[KpAlg] assert KpAlg not in key key = CoseKey.from_dict(cose_key) del key[3] assert KpAlg not in key key = CoseKey.from_dict(cose_key) del key[EC2KpD] assert EC2KpD not in key key = CoseKey.from_dict(cose_key) del key[-4] assert EC2KpD not in key key = CoseKey.from_dict(cose_key) del key[EC2KpY] assert EC2KpY not in key assert EC2KpX not in key
def add_kid(kid_b64, key_b64): kid = b64decode(kid_b64) asn1data = b64decode(key_b64) pub = serialization.load_der_public_key(asn1data) if (isinstance(pub, RSAPublicKey)): kids[kid_b64] = CoseKey.from_dict({ KpKty: KtyRSA, KpAlg: Ps256, # RSSASSA-PSS-with-SHA-256-and-MFG1 RSAKpE: int_to_bytes(pub.public_numbers().e), RSAKpN: int_to_bytes(pub.public_numbers().n) }) elif (isinstance(pub, EllipticCurvePublicKey)): kids[kid_b64] = CoseKey.from_dict({ KpKty: KtyEC2, EC2KpCurve: P256, # Ought o be pk.curve - but the two libs clash KpAlg: Es256, # ecdsa-with-SHA256 EC2KpX: pub.public_numbers().x.to_bytes(32, byteorder="big"), EC2KpY: pub.public_numbers().y.to_bytes(32, byteorder="big") }) else: print( f"Skipping unexpected/unknown key type (keyid={kid_b64}, {pub.__class__.__name__}).", file=sys.stderr)
def test_fail_on_missing_symkpk(): cose_key = {KpKty: KtySymmetric, KpAlg: A128GCM} with pytest.raises(CoseInvalidKey) as excinfo: CoseKey.from_dict(cose_key) assert "COSE Symmetric Key must have an SymKpK attribute" in str( excinfo.value)
def test_fail_on_missing_symmetric_kty(length): cose_key = {SymKpK: os.urandom(length)} with pytest.raises(CoseIllegalKeyType) as excinfo: CoseKey.from_dict(cose_key) assert "Could not decode CoseKey type, KpKty not set or unknown." in str( excinfo.value)
def _dsc(config_env: Dict): if TEST_CONTEXT in config_env.keys( ) and CERTIFICATE in config_env[TEST_CONTEXT].keys(): cert_code = config_env[TEST_CONTEXT][CERTIFICATE] x = y = e = n = None cert = x509.load_pem_x509_certificate( f'-----BEGIN CERTIFICATE-----\n{cert_code}\n-----END CERTIFICATE-----' .encode()) fingerprint = cert.fingerprint(SHA256()) keyid = fingerprint[0:8] if isinstance(cert.public_key(), rsa.RSAPublicKey): e = int_to_bytes(cert.public_key().public_numbers().e) n = int_to_bytes(cert.public_key().public_numbers().n) elif isinstance(cert.public_key(), ec.EllipticCurvePublicKey): x = int_to_bytes(cert.public_key().public_numbers().x) y = int_to_bytes(cert.public_key().public_numbers().y) else: raise Exception( f'Unsupported Certificate Algorithm: {cert.signature_algorithm_oid} for verification.' ) try: dsc_supported_operations = { eku.dotted_string for eku in cert.extensions.get_extension_for_class( x509.ExtendedKeyUsage).value } except ExtensionNotFound: dsc_supported_operations = set() dsc_not_valid_before = cert.not_valid_before.replace( tzinfo=timezone.utc) dsc_not_valid_after = cert.not_valid_after.replace(tzinfo=timezone.utc) key = None if x and y: key = CoseKey.from_dict({ KpKeyOps: [VerifyOp], KpKty: KtyEC2, EC2KpCurve: P256, # Ought o be pk.curve - but the two libs clash KpAlg: Es256, # ECDSA using P-256 and SHA-256 EC2KpX: x, EC2KpY: y, }) elif e and n: key = CoseKey.from_dict({ KpKeyOps: [VerifyOp], KpKty: KtyRSA, KpAlg: Ps256, # RSASSA-PSS using SHA-256 and MGF1 with SHA-256 RSAKpE: e, RSAKpN: n, }) return key, keyid, dsc_supported_operations, dsc_not_valid_before, dsc_not_valid_after
def test_fail_on_invalid_symmetric_key_length(): cose_key = {KpKty: KtySymmetric, SymKpK: os.urandom(17)} with pytest.raises(CoseInvalidKey) as excinfo: CoseKey.from_dict(cose_key) assert "Key length should be either 16, 24, or 32 bytes" in str( excinfo.value) with pytest.raises(CoseInvalidKey) as excinfo: _ = SymmetricKey(k=os.urandom(17)) assert "Key length should be either 16, 24, or 32 bytes" in str( excinfo.value)
def test_dict_valid_deletion(): cose_key = { KpKty: KtySymmetric, SymKpK: os.urandom(16), KpAlg: A128GCM, KpKeyOps: [EncryptOp] } key = CoseKey.from_dict(cose_key) del key[KpAlg] assert KpAlg not in key key = CoseKey.from_dict(cose_key) del key[3] assert KpAlg not in key
def test_fail_on_missing_crv_attr(): cose_key = {KpKty: KtyOKP, OKPKpX: os.urandom(32), OKPKpD: os.urandom(32)} with pytest.raises(CoseInvalidKey) as excinfo: _ = CoseKey.from_dict(cose_key) assert "COSE curve cannot be None" in str(excinfo.value)
def test_dict_operations_on_ec2_key(): cose_key = { KpKty: KtyEC2, EC2KpX: p256_x, KpAlg: Es256, EC2KpCurve: P256, KpKeyOps: [SignOp] } key = CoseKey.from_dict(cose_key) assert KpKty in key assert EC2KpD not in key assert EC2KpY in key assert 1 in key assert 3 in key assert KpAlg in key assert 'ALG' in key del key['ALG'] key['subject_name'] = 'verifying key' assert 'subject_name' in key assert 'ALG' not in key
def test_fail_on_missing_crv_attr(): cose_key = {KpKty: KtyEC2, EC2KpX: p256_x, EC2KpY: p256_y} with pytest.raises(CoseInvalidKey) as excinfo: _ = CoseKey.from_dict(cose_key) assert "COSE curve cannot be None" in str(excinfo.value)
def test_simple_enc0message(): msg = Enc0Message( phdr={Algorithm: A128GCM, IV: b'000102030405060708090a0b0c'}, uhdr={KID: b'kid1'}, payload='some secret message'.encode('utf-8')) assert str(msg) == "<COSE_Encrypt0: [{'Algorithm': 'A128GCM', 'IV': \"b'00010' ... (26 B)\"}, {'KID': b'kid1'}, " \ "b'some ' ... (19 B)]>" cose_key = { KpKty: KtySymmetric, SymKpK: unhexlify(b'000102030405060708090a0b0c0d0e0f'), KpKeyOps: [EncryptOp, DecryptOp]} cose_key = CoseKey.from_dict(cose_key) assert str(cose_key) == "<COSE_Key(Symmetric): {'SymKpK': \"b'\\\\x00\\\\x01\\\\x02\\\\x03\\\\x04' ... (16 B)\", " \ "'KpKty': 'KtySymmetric', 'KpKeyOps': ['EncryptOp', 'DecryptOp']}>" msg.key = cose_key # the encode() function performs the encryption automatically encoded = msg.encode() assert hexlify(encoded) == b'd0835820a2010105581a3030303130323033303430353036303730383039306130623063a104446b696' \ b'4315823cca3441a2464d240e09fe9ee0ea42a7852a4f41d9945325c1f8d3b1353b8eb83e6a62f' # decode and decrypt decoded = CoseMessage.decode(encoded) decoded.key = cose_key assert hexlify(decoded.payload) == b'cca3441a2464d240e09fe9ee0ea42a7852a4f41d9945325c1f8d3b1353b8eb83e6a62f' assert decoded.decrypt() == b'some secret message'
def test_simple_sign1message(): msg = Sign1Message( phdr={Algorithm: EdDSA, KID: b'kid2'}, payload='signed message'.encode('utf-8') ) assert str(msg) == "<COSE_Sign1: [{'Algorithm': 'EdDSA', 'KID': b'kid2'}, {}, b'signe' ... (14 B), b'' ... (0 B)]>" cose_key = { KpKty: KtyOKP, OKPKpCurve: Ed25519, KpKeyOps: [SignOp, VerifyOp], OKPKpD: unhexlify(b'9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60'), OKPKpX: unhexlify(b'd75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a')} cose_key = CoseKey.from_dict(cose_key) assert str(cose_key) == "<COSE_Key(OKPKey): {'OKPKpD': \"b'\\\\x9da\\\\xb1\\\\x9d\\\\xef' ... (32 B)\"," \ " 'OKPKpX': \"b'\\\\xd7Z\\\\x98\\\\x01\\\\x82' ... (32 B)\"," \ " 'OKPKpCurve': 'Ed25519', 'KpKty': 'KtyOKP', 'KpKeyOps': ['SignOp', 'VerifyOp']}>" msg.key = cose_key encoded = msg.encode() assert hexlify(encoded) == b'd28449a2012704446b696432a04e7369676e6564206d6573736167655840cc87665ffd3' \ b'fa33d96f3b606fcedeaef839423221872d0bfa196e069a189a607c2284924c3abb80e94' \ b'2466cd300cc5d18fe4e5ea1f3ebdb62ef8419109447d03' decoded = CoseMessage.decode(encoded) assert str(decoded) == "<COSE_Sign1: [{'Algorithm': 'EdDSA', 'KID': b'kid2'}, {}, b'signe' ... (14 B), " \ "b'\\xcc\\x87f_\\xfd' ... (64 B)]>" decoded.key = cose_key assert decoded.verify_signature() assert decoded.payload == b'signed message'
def test_fail_on_missing_crv_attr(): cose_key = {KpKty: KtyEC2, EC2KpX: os.urandom(32), EC2KpY: os.urandom(32)} with pytest.raises(CoseInvalidKey) as excinfo: _ = CoseKey.from_dict(cose_key) assert "COSE EC2 Key must have an EC2KpCurve attribute" in str(excinfo.value)
def test_fail_on_missing_key_values_from_dict(crv): d = {'KTY': 'EC2', 'CURVE': 'P_384'} with pytest.raises(CoseInvalidKey) as excinfo: _ = CoseKey.from_dict(d) assert "Either the public values or the private value must be specified" in str(excinfo.value)
def test_okp_public_keys_from_dicts(kty_attr, kty_value, crv_attr, crv_value, x_attr, x_value): # The public and private values used in this test do not form a valid elliptic curve key, # but we don't care about that here d = {kty_attr: kty_value, crv_attr: crv_value, x_attr: x_value} cose_key = CoseKey.from_dict(d) assert _is_valid_okp_key(cose_key)
def test_simple_mac0message(): msg = Mac0Message( phdr={Algorithm: HMAC256}, uhdr={KID: b'kid3'}, payload='authenticated message'.encode('utf-8')) assert str(msg) == "<COSE_Mac0: [{'Algorithm': 'HMAC256'}, {'KID': b'kid3'}, b'authe' ... (21 B), b'' ... (0 B)]>" cose_key = { KpKty: KtySymmetric, SymKpK: unhexlify(b'000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f'), KpKeyOps: [MacCreateOp, MacVerifyOp]} cose_key = CoseKey.from_dict(cose_key) assert str(cose_key) == "<COSE_Key(Symmetric): {'SymKpK': \"b'\\\\x00\\\\x01\\\\x02\\\\x03\\\\x04' ... (32 B)\", " \ "'KpKty': 'KtySymmetric', 'KpKeyOps': ['MacCreateOp', 'MacVerifyOp']}>" msg.key = cose_key # the encode() function automatically computes the authentication tag encoded = msg.encode() assert hexlify(encoded) == b'd18443a10105a104446b6964335561757468656e74696361746564206d657373616765582019f' \ b'6c7d8ddfeaceea6ba4f1cafb563cbf3be157653e29f3258b2957cf23f4e17' # decode and authenticate tag decoded = CoseMessage.decode(encoded) assert str(decoded) == "<COSE_Mac0: [{'Algorithm': 'HMAC256'}, {'KID': b'kid3'}, b'authe' ... (21 B), " \ "b'\\x19\\xf6\\xc7\\xd8\\xdd' ... (32 B)]>" decoded.key = cose_key assert hexlify(decoded.payload) == b'61757468656e74696361746564206d657373616765' assert hexlify(decoded.auth_tag) == b'19f6c7d8ddfeaceea6ba4f1cafb563cbf3be157653e29f3258b2957cf23f4e17' assert decoded.verify_tag()
def test_ec2_public_keys_from_dicts(kty_attr, kty_value, crv_attr, crv_value, x_attr, x_value, y_attr, y_value): dct = { kty_attr: kty_value, crv_attr: crv_value, x_attr: x_value, y_attr: y_value } cose_key = CoseKey.from_dict(dct) assert _is_valid_ec2_key(cose_key)
def test_existing_non_empty_keyops_list(): cose_key = { KpKty: KtySymmetric, SymKpK: os.urandom(16), KpAlg: A128GCM, KpKeyOps: [EncryptOp] } key = CoseKey.from_dict(cose_key) assert KpKeyOps in key
def test_remove_empty_keyops_list(): cose_key = { KpKty: KtySymmetric, SymKpK: os.urandom(16), KpAlg: A128GCM, KpKeyOps: [] } key = CoseKey.from_dict(cose_key) assert KpKeyOps not in key
def test_dict_invalid_deletion(): cose_key = { KpKty: KtySymmetric, SymKpK: os.urandom(16), KpAlg: A128GCM, KpKeyOps: [EncryptOp] } key = CoseKey.from_dict(cose_key) with pytest.raises(CoseInvalidKey) as excinfo: del key[KpKty]
def test_remove_empty_keyops_list(): cose_key = { KpKty: KtyEC2, EC2KpD: p384_d, KpAlg: Es256, EC2KpCurve: P256, KpKeyOps: [] } key = CoseKey.from_dict(cose_key) assert KpKeyOps not in key
def test_dict_operations_on_symmetric_key(): cose_key = { KpKty: KtySymmetric, SymKpK: os.urandom(16), KpAlg: A128GCM, KpKeyOps: [EncryptOp] } key = CoseKey.from_dict(cose_key) assert KpKty in key assert 3 in key
def test_existing_non_empty_keyops_list(): cose_key = { KpKty: KtyEC2, EC2KpD: p256_d, KpAlg: Es256, EC2KpCurve: P256, KpKeyOps: [SignOp] } key = CoseKey.from_dict(cose_key) assert KpKeyOps in key
def test_existing_non_empty_keyops_list(): cose_key = { KpKty: KtyOKP, OKPKpD: os.urandom(16), KpAlg: EdDSA, OKPKpCurve: Ed448, KpKeyOps: [SignOp] } key = CoseKey.from_dict(cose_key) assert KpKeyOps in key
def test_dict_operations_on_okp_key(): cose_key = {KpKty: KtyOKP, OKPKpD: os.urandom(16), KpAlg: EdDSA, OKPKpCurve: Ed448, KpKeyOps: [SignOp]} key = CoseKey.from_dict(cose_key) assert KpKty in key assert OKPKpD in key assert OKPKpX not in key assert 1 in key assert -4 in key assert KpAlg in key assert 'ALG' in key
def test_remove_empty_keyops_list(): cose_key = { KpKty: KtyOKP, OKPKpD: os.urandom(16), KpAlg: EdDSA, OKPKpCurve: Ed25519, KpKeyOps: [] } key = CoseKey.from_dict(cose_key) assert KpKeyOps not in key
def test_symmetric_key_example2(): simple_dict = { 'KTY': KtySymmetric, 'ALG': A128GCM, 'K': unhexlify(b'000102030405060708090a0b0c0d0e0f')} cose_key = CoseKey.from_dict(simple_dict) # encode/serialize key serialized_key = cose_key.encode() assert str(serialized_key) == \ str(b'\xa3\x01\x04\x03\x01 P\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f') assert str(CoseKey.decode(serialized_key)) == "<COSE_Key(Symmetric): " \ "{'SymKpK': \"b'\\\\x00\\\\x01\\\\x02\\\\x03\\\\x04' ... (16 B)\", " \ "'KpKty': 'KtySymmetric', 'KpAlg': 'A128GCM'}>"
def test_dict_invalid_deletion(): cose_key = { KpKty: KtyEC2, EC2KpD: os.urandom(32), EC2KpX: os.urandom(32), EC2KpY: os.urandom(32), KpAlg: Es256, EC2KpCurve: P256, KpKeyOps: [SignOp]} key = CoseKey.from_dict(cose_key) del key[EC2KpY] assert EC2KpY not in key assert EC2KpX not in key with pytest.raises(CoseInvalidKey) as excinfo: del key[EC2KpD] assert "Deleting <class 'cose.keys.keyparam.EC2KpD'> attribute would lead to an invalid COSE EC2 Key" in str( excinfo.value)
def test_dict_operations_on_rsa_key(): cose_key = {KpKty: KtyRSA, RSAKpE: os.urandom(4), RSAKpN: os.urandom(256), KpKeyOps: [SignOp]} key = CoseKey.from_dict(cose_key) assert KpKty in key assert RSAKpE in key assert RSAKpN in key assert RSAKpD not in key assert -1 in key assert -2 in key assert KpAlg not in key assert 'ALG' not in key assert 'KEY_OPS' in key del key['KEY_OPS'] key['subject_name'] = 'signing key' assert 'subject_name' in key assert 'KEY_OPS' not in key