def test_sample_readme_cwt_with_user_defined_claims(self): with open(key_path("private_key_ed25519.pem")) as key_file: private_key = COSEKey.from_pem(key_file.read(), kid="01") token = cwt.encode( { 1: "coaps://as.example", # iss 2: "dajiaji", # sub 7: b"123", # cti -70001: "foo", -70002: ["bar"], -70003: {"baz": "qux"}, -70004: 123, }, private_key, ) with open(key_path("public_key_ed25519.pem")) as key_file: public_key = COSEKey.from_pem(key_file.read(), kid="01") raw = cwt.decode(token, public_key) assert raw[-70001] == "foo" assert isinstance(raw[-70002], list) assert raw[-70002][0] == "bar" assert isinstance(raw[-70003], dict) assert raw[-70003]["baz"] == "qux" assert raw[-70004] == 123 readable = Claims.new(raw) assert readable.get(-70001) == "foo" assert readable.get(-70002)[0] == "bar" assert readable.get(-70003)["baz"] == "qux" assert readable.get(-70004) == 123
def test_cose_decode_mac0_with_multiple_kid(self): ctx = COSE.new(alg_auto_inclusion=True, kid_auto_inclusion=True) key1 = COSEKey.from_symmetric_key(alg="HS256", kid="01") key2 = COSEKey.from_symmetric_key(alg="HS256", kid="01") key3 = COSEKey.from_symmetric_key(alg="HS256", kid="02") encoded = ctx.encode_and_mac(b"Hello world!", key2) assert b"Hello world!" == ctx.decode(encoded, [key1, key2, key3])
def test_sample_readme_cwt_with_pop_cose_key(self): with open(key_path("private_key_ed25519.pem")) as key_file: private_key = COSEKey.from_pem(key_file.read(), kid="issuer-01") with open(key_path("public_key_es256.pem")) as key_file: pop_key = COSEKey.from_pem(key_file.read()) token = cwt.encode( { 1: "coaps://as.example", # iss 2: "dajiaji", # sub 7: b"123", # cti 8: { # cnf 1: pop_key.to_dict(), }, }, private_key, ) with open(key_path("public_key_ed25519.pem")) as key_file: public_key = COSEKey.from_pem(key_file.read(), kid="issuer-01") decoded = cwt.decode(token, public_key) assert 8 in decoded and isinstance(decoded[8], dict) assert 1 in decoded[8] and isinstance(decoded[8][1], dict) extracted = COSEKey.new(decoded[8][1]) assert extracted.kty == 2 # EC2 assert extracted.crv == 1 # P-256
def test_sample_readme_cwt_with_pop_encrypted_cose_key(self): with open(key_path("private_key_ed25519.pem")) as key_file: private_key = COSEKey.from_pem(key_file.read(), kid="issuer-01") enc_key = COSEKey.from_symmetric_key( "a-client-secret-of-cwt-recipient", # Just 32 bytes! alg="ChaCha20/Poly1305", kid="presenter-01", ) pop_key = COSEKey.from_symmetric_key( "a-client-secret-of-cwt-presenter", alg="HMAC 256/256", ) token = cwt.encode( { 1: "coaps://as.example", # iss 2: "dajiaji", # sub 7: b"123", # cti 8: { # cnf 2: EncryptedCOSEKey.from_cose_key(pop_key, enc_key), }, }, private_key, ) with open(key_path("public_key_ed25519.pem")) as key_file: public_key = COSEKey.from_pem(key_file.read(), kid="issuer-01") decoded = cwt.decode(token, public_key) assert 8 in decoded and isinstance(decoded[8], dict) assert 2 in decoded[8] and isinstance(decoded[8][2], list) extracted = EncryptedCOSEKey.to_cose_key(decoded[8][2], enc_key) assert extracted.kty == 4 # Symmetric assert extracted.alg == 5 # HMAC 256/256 assert extracted.key == b"a-client-secret-of-cwt-presenter"
def test_cose_decode_mac_with_different_multiple_keys_2(self): ctx = COSE.new(alg_auto_inclusion=True, verify_kid=True) key = COSEKey.from_symmetric_key(alg="HS256") material1 = base64.urlsafe_b64encode(token_bytes(16)).decode() material2 = base64.urlsafe_b64encode(token_bytes(16)).decode() material3 = base64.urlsafe_b64encode(token_bytes(16)).decode() r2 = Recipient.from_jwk({ "kid": "03", "kty": "oct", "alg": "A128KW", "k": material2 }) r2.apply(key) encoded = ctx.encode_and_mac(b"Hello world!", key, recipients=[r2]) shared_key1 = COSEKey.from_jwk({ "kid": "01", "kty": "oct", "alg": "A128KW", "k": material1 }) shared_key3 = COSEKey.from_jwk({ "kid": "02", "kty": "oct", "alg": "A128KW", "k": material3 }) with pytest.raises(ValueError) as err: ctx.decode(encoded, keys=[shared_key1, shared_key3]) pytest.fail("decode() should fail.") assert "key is not found." in str(err.value)
def test_sample_readme_cwt_with_pop_encrypted_cose_key_readable(self): with open(key_path("private_key_ed25519.pem")) as key_file: private_key = COSEKey.from_pem(key_file.read(), kid="issuer-01") enc_key = COSEKey.from_symmetric_key( "a-client-secret-of-cwt-recipient", # Just 32 bytes! alg="ChaCha20/Poly1305", kid="presenter-01", ) pop_key = COSEKey.from_symmetric_key( "a-client-secret-of-cwt-presenter", alg="HMAC 256/256", ) token = cwt.encode( { "iss": "coaps://as.example", "sub": "dajiaji", "cti": "123", "cnf": { # 'eck'(Encrypted Cose Key) is a keyword defined by this library. "eck": EncryptedCOSEKey.from_cose_key(pop_key, enc_key), }, }, private_key, ) with open(key_path("public_key_ed25519.pem")) as key_file: public_key = COSEKey.from_pem(key_file.read(), kid="issuer-01") decoded = cwt.decode(token, public_key) assert 8 in decoded and isinstance(decoded[8], dict) assert 2 in decoded[8] and isinstance(decoded[8][2], list) c = Claims.new(decoded) extracted = EncryptedCOSEKey.to_cose_key(c.cnf, enc_key) assert extracted.kty == 4 # Symmetric assert extracted.alg == 5 # HMAC 256/256 assert extracted.key == b"a-client-secret-of-cwt-presenter"
def test_sample_readme_signed_cwt_ed25519_with_jwk(self): # The sender side: private_key = COSEKey.from_jwk( { "kid": "01", "kty": "OKP", "key_ops": ["sign"], "alg": "EdDSA", "crv": "Ed25519", "x": "2E6dX83gqD_D0eAmqnaHe1TC1xuld6iAKXfw2OVATr0", "d": "L8JS08VsFZoZxGa9JvzYmCWOwg7zaKcei3KZmYsj7dc", } ) token = cwt.encode({"iss": "coaps://as.example", "sub": "dajiaji", "cti": "123"}, private_key) # The recipient side: public_key = COSEKey.from_jwk( { "kid": "01", "kty": "OKP", "key_ops": ["verify"], "crv": "Ed25519", "x": "2E6dX83gqD_D0eAmqnaHe1TC1xuld6iAKXfw2OVATr0", } ) decoded = cwt.decode(token, public_key) assert 1 in decoded and decoded[1] == "coaps://as.example"
def test_cose_wg_examples_ecdh_wrap_p256_ss_wrap_128_01(self): # The sender side: enc_key = COSEKey.from_symmetric_key( # bytes.fromhex("B2353161740AACF1F7163647984B522A"), alg="A128GCM", ) rec = Recipient.from_jwk({ "kty": "EC", "crv": "P-256", "alg": "ECDH-SS+A128KW", "x": "7cvYCcdU22WCwW1tZXR8iuzJLWGcd46xfxO1XJs-SPU", "y": "DzhJXgz9RI6TseNmwEfLoNVns8UmvONsPzQDop2dKoo", "d": "Uqr4fay_qYQykwcNCB2efj_NFaQRRQ-6fHZm763jt5w", }) pub_key = COSEKey.from_jwk({ "kty": "EC", "crv": "P-256", "kid": "*****@*****.**", "x": "Ze2loSV3wrroKUN_4zhwGhCqo3Xhu1td4QjeQ5wIVR0", "y": "HlLtdXARY_f55A3fnzQbPcm6hgr34Mp8p-nuzQCE0Zw", # "d":"r_kHyZ-a06rmxM3yESK84r1otSg-aQcVStkRhA-iCM8" }) rec.apply(enc_key, recipient_key=pub_key, context={"alg": "A128GCM"}) ctx = COSE.new(alg_auto_inclusion=True) encoded = ctx.encode_and_encrypt( b"This is the content.", key=enc_key, nonce=b"\x02\xd1\xf7\xe6\xf2lC\xd4\x86\x8d\x87\xce", recipients=[rec], ) # The recipient side: priv_key = COSEKey.from_jwk({ "kty": "EC", "crv": "P-256", "alg": "ECDH-SS+A128KW", "kid": "*****@*****.**", "x": "Ze2loSV3wrroKUN_4zhwGhCqo3Xhu1td4QjeQ5wIVR0", "y": "HlLtdXARY_f55A3fnzQbPcm6hgr34Mp8p-nuzQCE0Zw", "d": "r_kHyZ-a06rmxM3yESK84r1otSg-aQcVStkRhA-iCM8", }) assert b"This is the content." == ctx.decode( encoded, priv_key, context={"alg": "A128GCM"})
def test_cose_wg_examples_aes_wrap_128_03(self): cwt_str = "D8618543A10107A054546869732069732074686520636F6E74656E742E58400021C21B2A7FADB677DAB64389B3FDA4AAC892D5C81B786A459E4182104A1501462FFD471422AF4D48BEEB864951D5947A55E3155E670DFC4A96017B0FD0E725818340A20122044A6F75722D7365637265745848792C46CE0BC689747133FA0DB1F5E2BC4DAAE22F906E93DFCA2DF44F0DF6C2CEF16EA8FC91D52AD662C4B49DD0D689E1086EC754347957F80F95C92C887521641B8F637D91C6E258" mac_key = COSEKey.from_symmetric_key( bytes.fromhex( "DDDC08972DF9BE62855291A17A1B4CF767C2DC762CB551911893BF7754988B0A286127BFF5D60C4CBC877CAC4BF3BA02C07AD544C951C3CA2FC46B70219BC3DC" ), alg="HS512", ) recipient = Recipient.from_jwk( { "kty": "oct", "alg": "A128KW", "kid": "our-secret", "k": "hJtXIZ2uSN5kbQfbtTNWbg", }, ) recipient.apply(mac_key) ctx = COSE.new() encoded = ctx.encode_and_mac( b"This is the content.", key=mac_key, protected={1: 7}, recipients=[recipient], ) assert encoded == bytes.fromhex(cwt_str) key = COSEKey.from_jwk( { "kty": "oct", "alg": "A128KW", "kid": "our-secret", "k": "hJtXIZ2uSN5kbQfbtTNWbg", }, ) res = ctx.decode(encoded, keys=[key]) assert res == b"This is the content."
def test_cose_usage_examples_cose_mac_aes_key_wrap(self): # The sender side: mac_key = COSEKey.from_symmetric_key(alg="HS512") r = Recipient.from_jwk( { "kty": "oct", "alg": "A128KW", "kid": "01", "k": "hJtXIZ2uSN5kbQfbtTNWbg", # A shared wrapping key }, ) r.apply(mac_key) ctx = COSE.new(alg_auto_inclusion=True) encoded = ctx.encode_and_mac(b"Hello world!", key=mac_key, recipients=[r]) # The recipient side: shared_key = COSEKey.from_jwk( { "kty": "oct", "alg": "A128KW", "kid": "01", "k": "hJtXIZ2uSN5kbQfbtTNWbg", }, ) assert b"Hello world!" == ctx.decode(encoded, shared_key)
def test_cose_usage_examples_cose_encrypt_ecdh_ss_a128kw(self): # The sender side: enc_key = COSEKey.from_symmetric_key(alg="A128GCM") nonce = enc_key.generate_nonce() r = Recipient.from_jwk({ "kty": "EC", "crv": "P-256", "alg": "ECDH-SS+A128KW", "x": "7cvYCcdU22WCwW1tZXR8iuzJLWGcd46xfxO1XJs-SPU", "y": "DzhJXgz9RI6TseNmwEfLoNVns8UmvONsPzQDop2dKoo", "d": "Uqr4fay_qYQykwcNCB2efj_NFaQRRQ-6fHZm763jt5w", }) pub_key = COSEKey.from_jwk({ "kty": "EC", "crv": "P-256", "kid": "*****@*****.**", "x": "Ze2loSV3wrroKUN_4zhwGhCqo3Xhu1td4QjeQ5wIVR0", "y": "HlLtdXARY_f55A3fnzQbPcm6hgr34Mp8p-nuzQCE0Zw", }) r.apply(enc_key, recipient_key=pub_key, context={"alg": "A128GCM"}) ctx = COSE.new(alg_auto_inclusion=True) encoded = ctx.encode_and_encrypt( b"Hello world!", key=enc_key, nonce=nonce, recipients=[r], ) # The recipient side: priv_key = COSEKey.from_jwk({ "kty": "EC", "crv": "P-256", "alg": "ECDH-SS+A128KW", "kid": "*****@*****.**", "x": "Ze2loSV3wrroKUN_4zhwGhCqo3Xhu1td4QjeQ5wIVR0", "y": "HlLtdXARY_f55A3fnzQbPcm6hgr34Mp8p-nuzQCE0Zw", "d": "r_kHyZ-a06rmxM3yESK84r1otSg-aQcVStkRhA-iCM8", }) assert b"Hello world!" == ctx.decode(encoded, priv_key, context={"alg": "A128GCM"})
def test_cose_decode_ecdh_aes_key_wrap_without_context(self): with open(key_path("public_key_es256.pem")) as key_file: public_key = COSEKey.from_pem(key_file.read(), kid="01") enc_key = COSEKey.from_symmetric_key(alg="A128GCM") recipient = Recipient.from_jwk({ "kty": "EC", "crv": "P-256", "alg": "ECDH-ES+A128KW" }) recipient.apply(enc_key, recipient_key=public_key, context={"alg": "A128GCM"}) ctx = COSE.new(alg_auto_inclusion=True) encoded = ctx.encode_and_encrypt( b"This is the content.", key=enc_key, recipients=[recipient], ) with open(key_path("private_key_es256.pem")) as key_file: private_key = COSEKey.from_pem(key_file.read(), kid="01") with pytest.raises(ValueError) as err: ctx.decode(encoded, private_key) pytest.fail("decode should fail.") assert "context should be set." in str(err.value)
def test_key_builder_from_pem_private_with_invalid_key_ops( self, invalid, msg): with open(key_path("private_key_ed25519.pem")) as key_file: with pytest.raises(ValueError) as err: COSEKey.from_pem(key_file.read(), key_ops=invalid) pytest.fail("from_pem should fail.") assert msg in str(err.value)
def test_key_builder_from_pem_okp_with_invalid_alg(self, invalid_alg): with open(key_path("private_key_ed25519.pem")) as key_file: with pytest.raises(ValueError) as err: COSEKey.from_pem(key_file.read(), alg=invalid_alg) pytest.fail("from_pem() should fail.") assert f"Unsupported or unknown alg for OKP: {invalid_alg}." in str( err.value)
def test_key_builder_from_pem_with_kid(self, kid, expected): with open(key_path("private_key_ed25519.pem")) as key_file: private_key = COSEKey.from_pem(key_file.read(), kid=kid) with open(key_path("public_key_ed25519.pem")) as key_file: public_key = COSEKey.from_pem(key_file.read(), kid=kid) assert private_key.kid == expected assert public_key.kid == expected
def refresh_trustlist(self): self._dscs = [] self._trustlist = [] # Get a trust-list signer certificate. r = requests.get(self._base_url + "/cert") if r.status_code != 200: raise Exception(f"Received {r.status_code} from /cert") key = r.text cose_key = COSEKey.from_pem(key) # Get DSCs r = requests.get(self._base_url + "/trust-list") if r.status_code != 200: raise Exception(f"Received {r.status_code} from /trust-list") decoded = jwt.decode( r.text, cose_key.key, algorithms=["ES256"], options={"verify_aud": False}, ) for v in decoded["dsc_trust_list"].values(): for k in v["keys"]: if "use" in k and k["use"] == "enc": # Workaround for Swedish DSC. del k["use"] if k["kty"] == "RSA": k["alg"] = "PS256" self._dscs.append(COSEKey.from_jwk(k)) self._trustlist.append(k) # Update trustlist store. with open(self._trustlist_store_path, "w") as f: json.dump(self._trustlist, f, indent=4) return
def test_cose_decode_mac_with_multiple_keys_without_kid(self, ctx): key = COSEKey.from_symmetric_key(alg="HS256") material1 = base64.urlsafe_b64encode(token_bytes(16)).decode() material2 = base64.urlsafe_b64encode(token_bytes(16)).decode() material3 = base64.urlsafe_b64encode(token_bytes(16)).decode() r1 = Recipient.from_jwk({ "kty": "oct", "alg": "A128KW", "k": material1 }) r2 = Recipient.from_jwk({ "kty": "oct", "alg": "A128KW", "k": material2 }) r1.apply(key) r2.apply(key) encoded = ctx.encode_and_mac(b"Hello world!", key, recipients=[r2, r1]) shared_key1 = COSEKey.from_jwk({ "kty": "oct", "alg": "A128KW", "k": material1 }) shared_key3 = COSEKey.from_jwk({ "kty": "oct", "alg": "A128KW", "k": material3 }) assert b"Hello world!" == ctx.decode(encoded, keys=[shared_key3, shared_key1])
def test_key_builder_from_jwk_without_use(self): try: with open(key_path("public_key_ed25519.json")) as key_file: obj = json.loads(key_file.read()) del obj["use"] COSEKey.from_jwk(obj) except Exception: pytest.fail("from_jwk should not fail.")
def test_key_builder_from_jwk_with_byte_formatted_kid(self): try: with open(key_path("public_key_ed25519.json")) as key_file: obj = json.loads(key_file.read()) obj["kid"] = b"01" COSEKey.from_jwk(obj) except Exception: pytest.fail("from_jwk should not fail.")
def test_cose_decode_encrypt0_with_multiple_kid(self): ctx = COSE.new(alg_auto_inclusion=True, kid_auto_inclusion=True) key1 = COSEKey.from_symmetric_key(alg="ChaCha20/Poly1305", kid="01") key2 = COSEKey.from_symmetric_key(alg="ChaCha20/Poly1305", kid="01") key3 = COSEKey.from_symmetric_key(alg="ChaCha20/Poly1305", kid="02") encoded = ctx.encode_and_encrypt(b"Hello world!", key2) decoded = ctx.decode(encoded, [key1, key2, key3]) assert decoded == b"Hello world!"
def test_key_builder_from_symmetric_key_with_invalid_key_ops( self, key_ops): with pytest.raises(ValueError) as err: COSEKey.from_symmetric_key("mysecret", alg="HS256", key_ops=key_ops) pytest.fail("from_symmetric_key should fail.") assert "Unsupported or unknown key_ops." in str(err.value)
def test_key_builder_from_pem(self, private_key_path, public_key_path): try: with open(key_path(private_key_path)) as key_file: COSEKey.from_pem(key_file.read()) with open(key_path(public_key_path)) as key_file: COSEKey.from_pem(key_file.read()) except Exception: pytest.fail("from_pem should not fail.")
def test_cose_decode_encrypt0_with_different_multiple_keys(self, ctx): key1 = COSEKey.from_symmetric_key(alg="ChaCha20/Poly1305") key2 = COSEKey.from_symmetric_key(alg="ChaCha20/Poly1305") key3 = COSEKey.from_symmetric_key(alg="ChaCha20/Poly1305") encoded = ctx.encode_and_encrypt(b"Hello world!", key1) with pytest.raises(DecodeError) as err: ctx.decode(encoded, [key2, key3]) pytest.fail("decode() should fail.") assert "Failed to decrypt." in str(err.value)
def test_key_builder_from_pem_with_alg(self, private_key_path, public_key_path): try: with open(key_path(private_key_path)) as key_file: COSEKey.from_pem(key_file.read(), alg="ECDH-SS+HKDF-256") with open(key_path(public_key_path)) as key_file: COSEKey.from_pem(key_file.read(), alg="ECDH-SS+HKDF-256") except Exception: pytest.fail("from_pem should not fail.")
def test_sample_readme_signed_cwt_ps256(self): with open(key_path("private_key_rsa.pem")) as key_file: private_key = COSEKey.from_pem(key_file.read(), alg="PS256", kid="01") token = cwt.encode({"iss": "coaps://as.example", "sub": "dajiaji", "cti": "123"}, private_key) with open(key_path("public_key_rsa.pem")) as key_file: public_key = COSEKey.from_pem(key_file.read(), alg="PS256", kid="01") decoded = cwt.decode(token, public_key) assert 1 in decoded and decoded[1] == "coaps://as.example"
def test_cose_decode_mac0_with_different_multiple_keys(self, ctx): key1 = COSEKey.from_symmetric_key(alg="HS256") key2 = COSEKey.from_symmetric_key(alg="HS256") key3 = COSEKey.from_symmetric_key(alg="HS256") encoded = ctx.encode_and_mac(b"Hello world!", key1) with pytest.raises(VerifyError) as err: ctx.decode(encoded, [key2, key3]) pytest.fail("decode() should fail.") assert "Failed to compare digest." in str(err.value)
def test_encrypted_cose_key_from_cose_key_with_invalid_encryption_key( self): enc_key = COSEKey.from_symmetric_key(alg="HMAC 256/64") pop_key = COSEKey.from_symmetric_key(alg="HMAC 256/256") with pytest.raises(ValueError) as err: EncryptedCOSEKey.from_cose_key(pop_key, enc_key) pytest.fail("to_ should fail.") assert "Nonce generation is not supported for the key. Set a nonce explicitly." in str( err.value)
def test_cose_decode_signature1_with_multiple_keys_without_kid(self, ctx): with open(key_path("public_key_es256.pem")) as key_file: key1 = COSEKey.from_pem(key_file.read()) with open(key_path("public_key_ed25519.pem")) as key_file: key2 = COSEKey.from_pem(key_file.read()) with open(key_path("private_key_ed25519.pem")) as key_file: private_key = COSEKey.from_pem(key_file.read()) encoded = ctx.encode_and_sign(b"Hello world!", private_key) decoded = ctx.decode(encoded, [key1, key2]) assert decoded == b"Hello world!"
def test_cose_decode_signature1_with_ca_certs_without_kid(self): with open(key_path("cert_es256.pem")) as key_file: public_key = COSEKey.from_pem(key_file.read()) with open(key_path("private_key_cert_es256.pem")) as key_file: private_key = COSEKey.from_pem(key_file.read()) ctx = COSE.new(alg_auto_inclusion=True, ca_certs=key_path("cacert.pem")) encoded = ctx.encode_and_sign(b"Hello world!", private_key) decoded = ctx.decode(encoded, [public_key]) assert decoded == b"Hello world!"
def test_cose_decode_encrypt0_with_different_multiple_keys_2(self): ctx = COSE.new(alg_auto_inclusion=True, kid_auto_inclusion=True) key1 = COSEKey.from_symmetric_key(alg="ChaCha20/Poly1305", kid="01") key2 = COSEKey.from_symmetric_key(alg="ChaCha20/Poly1305") key3 = COSEKey.from_symmetric_key(alg="ChaCha20/Poly1305") encoded = ctx.encode_and_encrypt(b"Hello world!", key1) with pytest.raises(ValueError) as err: ctx.decode(encoded, [key2, key3]) pytest.fail("decode() should fail.") assert "key is not found." in str(err.value)