Skip to content

Commit

Permalink
Merge pull request #29 from dajiaji/add-cwt-test
Browse files Browse the repository at this point in the history
Add cwt test
  • Loading branch information
dajiaji committed Apr 24, 2021
2 parents b451639 + 507165c commit 566f660
Show file tree
Hide file tree
Showing 4 changed files with 181 additions and 33 deletions.
2 changes: 1 addition & 1 deletion cwt/cose.py
Expand Up @@ -139,4 +139,4 @@ def decode(self, data: Union[bytes, CBORTag], key: COSEKey) -> Dict[int, Any]:
msg = self._dumps(["Signature", data.value[0], b"", data.value[2]])
raise NotImplementedError()

raise ValueError("Unsupported or unknown tag: %d" % data.tag)
raise ValueError(f"Unsupported or unknown CBOR tag({data.tag}).")
7 changes: 3 additions & 4 deletions cwt/cwt.py
Expand Up @@ -145,8 +145,7 @@ def encode_and_encrypt(
self._set_default_value(claims)
protected: Dict[int, Any] = {1: key.alg}
unprotected: Dict[int, Any] = {4: key.kid} if key.kid else {}
if nonce:
unprotected[5] = nonce
unprotected[5] = nonce
res = self._cose.encode_and_encrypt(
protected, unprotected, claims, key, nonce, out="cbor2/CBORTag"
)
Expand Down Expand Up @@ -188,9 +187,9 @@ def _validate(self, claims: Union[Dict[int, Any], bytes]):
if isinstance(claims, bytes):
nested = self._loads(claims)
if not isinstance(nested, CBORTag):
raise ValueError("bytes-formatted claims need CBOR(COSE) Tag.")
raise ValueError("A bytes-formatted claims needs CBOR(COSE) Tag.")
if nested.tag not in [16, 96, 17, 97, 18, 98]:
raise ValueError("Unsupported or unknown CBOR tag.")
raise ValueError(f"Unsupported or unknown CBOR tag({nested.tag}).")
return
if -260 in claims and not isinstance(claims[-260], dict):
raise ValueError("hcert(-260) should be map.")
Expand Down
8 changes: 4 additions & 4 deletions docs/conf.py
Expand Up @@ -38,10 +38,10 @@
]

nitpick_ignore = [
('py:class', 'cwt.cose_key.COSEKey'),
('py:class', 'cwt.cbor_processor.CBORProcessor'),
('py:class', '_cbor2.CBORTag'),
('py:class', 'cwt.exceptions.CWTError'),
("py:class", "cwt.cose_key.COSEKey"),
("py:class", "cwt.cbor_processor.CBORProcessor"),
("py:class", "_cbor2.CBORTag"),
("py:class", "cwt.exceptions.CWTError"),
]

# Add any paths that contain templates here, relative to this directory.
Expand Down
197 changes: 173 additions & 24 deletions tests/test_cwt.py
Expand Up @@ -8,10 +8,11 @@
"""
from secrets import token_bytes

# import cbor2
import cbor2
import pytest
from cbor2 import CBORTag

from cwt import CWT, DecodeError, VerifyError, cose_key
from cwt import CWT, DecodeError, EncodeError, VerifyError, cose_key

from .utils import key_path, now

Expand Down Expand Up @@ -58,12 +59,12 @@ def test_cwt_constructor_with_invalid_args(self, invalid):
""""""
with pytest.raises(ValueError) as err:
CWT(options=invalid)
pytest.fail("CWT() should be fail.")
pytest.fail("CWT() should fail.")
assert "should be" in str(err.value)

def test_cwt_encode_and_mac_with_default_alg(self, ctx):
""""""
key = cose_key.from_symmetric_key("mysecretpassword")
key = cose_key.from_symmetric_key("mysecret")
token = ctx.encode_and_mac(
{1: "https://as.example", 2: "someone", 7: b"123"}, key
)
Expand All @@ -77,6 +78,39 @@ def test_cwt_encode_and_mac_with_default_alg(self, ctx):
assert decoded[4] == decoded[5] + ctx.expires_in
assert 7 in decoded and decoded[7] == b"123"

@pytest.mark.parametrize(
"alg",
[
"HMAC 256/64",
"HMAC 256/256",
"HMAC 384/384",
"HMAC 512/512",
],
)
def test_cwt_encode_and_mac_with_valid_alg_hmac(self, ctx, alg):
""""""
key = cose_key.from_symmetric_key("mysecret", alg=alg)
token = ctx.encode_and_mac(
{1: "https://as.example", 2: "someone", 7: b"123"}, key
)
decoded = ctx.decode(token, key)
assert 1 in decoded and decoded[1] == "https://as.example"
assert 2 in decoded and decoded[2] == "someone"
assert 7 in decoded and decoded[7] == b"123"

def test_cwt_encode_and_mac_with_tagged(self, ctx):
""""""
key = cose_key.from_symmetric_key("mysecret", alg="HMAC 256/64")
token = ctx.encode_and_mac(
{1: "https://as.example", 2: "someone", 7: b"123"},
key,
tagged=True,
)
decoded = ctx.decode(token, key)
assert 1 in decoded and decoded[1] == "https://as.example"
assert 2 in decoded and decoded[2] == "someone"
assert 7 in decoded and decoded[7] == b"123"

@pytest.mark.parametrize(
"invalid",
[
Expand All @@ -96,31 +130,67 @@ def test_cwt_encode_and_mac_with_default_alg(self, ctx):
)
def test_cwt_encode_and_mac_with_invalid_args(self, ctx, invalid):
""""""
key = cose_key.from_symmetric_key("mysecretpassword")
key = cose_key.from_symmetric_key("mysecret")
with pytest.raises(ValueError) as err:
ctx.encode_and_mac(invalid, key)
pytest.fail("encode_and_mac should be fail.")
pytest.fail("encode_and_mac should fail.")
assert "should be" in str(err.value)

@pytest.mark.parametrize(
"alg",
"invalid, msg",
[
"HMAC 256/64",
"HMAC 256/256",
"HMAC 384/384",
"HMAC 512/512",
(
{1: "https://as.example", 2: "someone", 7: b"123", 4: "exp"},
"exp(4) should be int or float.",
),
(
{1: "https://as.example", 2: "someone", 7: b"123", 5: "nbf"},
"nbf(5) should be int or float.",
),
],
)
def test_cwt_encode_and_mac_with_valid_alg_hmac(self, ctx, alg):
def test_cwt_encode_and_mac_with_invalid_claims(self, ctx, invalid, msg):
""""""
key = cose_key.from_symmetric_key("mysecret")
with pytest.raises(ValueError) as err:
ctx.encode_and_mac(invalid, key)
pytest.fail("encode_and_mac should fail.")
assert msg in str(err.value)

def test_cwt_encode_and_mac_with_invalid_cbor_format(self, ctx):
""""""
key = cose_key.from_symmetric_key("mysecret", alg="HMAC 256/64")
with pytest.raises(EncodeError) as err:
ctx.encode_and_mac(
b'{1: "https://as.example", 2: "someone", 7: "123"',
key,
)
pytest.fail("encode_and_mac should fail.")
assert "Failed to encode." in str(err.value)

def test_cwt_encode_and_mac_with_untagged_cbor_bytes(self, ctx):
""""""
key = cose_key.from_symmetric_key("mysecretpassword", alg=alg)
key = cose_key.from_symmetric_key("mysecret", alg="HMAC 256/64")
with pytest.raises(ValueError) as err:
ctx.encode_and_mac(
cbor2.dumps({1: "https://as.example", 2: "someone", 7: "123"}),
key,
)
pytest.fail("encode_and_mac should fail.")
assert "A bytes-formatted claims needs CBOR(COSE) Tag." in str(err.value)

def test_cwt_encode_and_mac_with_invalid_tagged_cwt(self, ctx):
""""""
key = cose_key.from_symmetric_key("mysecret", alg="HMAC 256/64")
token = ctx.encode_and_mac(
{1: "https://as.example", 2: "someone", 7: b"123"}, key
{1: "https://as.example", 2: "someone", 7: b"123"},
key,
)
decoded = ctx.decode(token, key)
assert 1 in decoded and decoded[1] == "https://as.example"
assert 2 in decoded and decoded[2] == "someone"
assert 7 in decoded and decoded[7] == b"123"
tagged_token = cbor2.dumps(CBORTag(62, token))
with pytest.raises(ValueError) as err:
ctx.encode_and_mac(tagged_token, key)
pytest.fail("encode_and_mac should fail.")
assert "Unsupported or unknown CBOR tag(62)." in str(err.value)

@pytest.mark.parametrize(
"alg, nonce, key",
Expand Down Expand Up @@ -148,6 +218,22 @@ def test_cwt_encode_and_encrypt_with_valid_alg_aes_ccm(self, ctx, alg, nonce, ke
assert 2 in decoded and decoded[2] == "someone"
assert 7 in decoded and decoded[7] == b"123"

def test_cwt_encode_and_encrypt_with_tagged(self, ctx):
""""""
key = token_bytes(16)
nonce = token_bytes(13)
enc_key = cose_key.from_symmetric_key(key, alg="AES-CCM-16-64-128")
token = ctx.encode_and_encrypt(
{1: "https://as.example", 2: "someone", 7: b"123"},
enc_key,
nonce=nonce,
tagged=True,
)
decoded = ctx.decode(token, enc_key)
assert 1 in decoded and decoded[1] == "https://as.example"
assert 2 in decoded and decoded[2] == "someone"
assert 7 in decoded and decoded[7] == b"123"

@pytest.mark.parametrize(
"private_key_path, public_key_path",
[
Expand Down Expand Up @@ -178,6 +264,22 @@ def test_cwt_encode_and_sign_with_valid_alg(
assert 2 in decoded and decoded[2] == "someone"
assert 7 in decoded and decoded[7] == b"123"

def test_cwt_encode_and_sign_with_tagged(self, ctx):
""""""
with open(key_path("private_key_es256.pem")) as key_file:
private_key = cose_key.from_pem(key_file.read())
with open(key_path("public_key_es256.pem")) as key_file:
public_key = cose_key.from_pem(key_file.read())
token = ctx.encode_and_sign(
{1: "https://as.example", 2: "someone", 7: b"123"},
private_key,
tagged=True,
)
decoded = ctx.decode(token, public_key)
assert 1 in decoded and decoded[1] == "https://as.example"
assert 2 in decoded and decoded[2] == "someone"
assert 7 in decoded and decoded[7] == b"123"

def test_cwt_encode_and_encrypt_with_invalid_nonce(self, ctx):
""""""
enc_key = cose_key.from_symmetric_key(token_bytes(16), alg="AES-CCM-16-64-128")
Expand All @@ -187,19 +289,19 @@ def test_cwt_encode_and_encrypt_with_invalid_nonce(self, ctx):
enc_key,
nonce=token_bytes(7), # should be 13
)
pytest.fail("encode_and_encrypt should be fail: res=%s" % vars(res))
pytest.fail("encode_and_encrypt should fail: res=%s" % vars(res))
assert "The length of nonce should be" in str(err.value)

def test_cwt_decode_with_invalid_mac_key(self, ctx):
""""""
key = cose_key.from_symmetric_key("mysecretpassword")
key = cose_key.from_symmetric_key("mysecret")
token = ctx.encode_and_mac(
{1: "https://as.example", 2: "someone", 7: b"123"}, key
)
wrong_key = cose_key.from_symmetric_key("xxxxxxxxxx")
with pytest.raises(VerifyError) as err:
res = ctx.decode(token, wrong_key)
pytest.fail("decode should be fail: res=%s" % vars(res))
pytest.fail("decode should fail: res=%s" % vars(res))
assert "Failed to compare digest" in str(err.value)

def test_cwt_decode_with_invalid_enc_key(self, ctx):
Expand All @@ -215,7 +317,7 @@ def test_cwt_decode_with_invalid_enc_key(self, ctx):
)
with pytest.raises(DecodeError) as err:
ctx.decode(token, wrong_key)
pytest.fail("decode should be fail.")
pytest.fail("decode should fail.")
assert "Failed to decrypt" in str(err.value)

@pytest.mark.parametrize(
Expand All @@ -239,9 +341,56 @@ def test_cwt_decode_with_invalid_enc_key(self, ctx):
)
def test_cwt_decode_with_invalid_claim(self, ctx, invalid, msg):
""""""
mac_key = cose_key.from_symmetric_key("mysecretpassword")
mac_key = cose_key.from_symmetric_key("mysecret")
token = ctx.encode_and_mac(invalid, mac_key)
with pytest.raises(VerifyError) as err:
ctx.decode(token, mac_key)
pytest.fail("decode should be fail.")
pytest.fail("decode should fail.")
assert msg in str(err.value)

def test_cwt_decode_with_invalid_tagged_cwt(self, ctx):
""""""
key = cose_key.from_symmetric_key("mysecret", alg="HMAC 256/64")
token = ctx.encode_and_mac(
{1: "https://as.example", 2: "someone", 7: b"123"},
key,
)
tagged_token = cbor2.dumps(CBORTag(62, token))
with pytest.raises(ValueError) as err:
ctx.decode(tagged_token, key)
pytest.fail("decode should fail.")
assert "Unsupported or unknown CBOR tag(62)." in str(err.value)

@pytest.mark.parametrize(
"claims",
[
{1: "https://as.example", 2: "someone", 7: b"123", 4: now() + 100},
{1: "https://as.example", 2: "someone", 7: b"123", 5: now() - 100},
],
)
def test_cwt__verify_with_valid_args(self, ctx, claims):
""""""
try:
ctx._verify(claims)
except Exception:
pytest.fail("_verify should not fail.")

@pytest.mark.parametrize(
"invalid, msg",
[
(
{1: "https://as.example", 2: "someone", 7: b"123", 4: "exp"},
"exp should be int or float.",
),
(
{1: "https://as.example", 2: "someone", 7: b"123", 5: "nbf"},
"nbf should be int or float.",
),
],
)
def test_cwt__verify_with_invalid_args(self, ctx, invalid, msg):
""""""
with pytest.raises(ValueError) as err:
ctx._verify(invalid)
pytest.fail("_verify should fail.")
assert msg in str(err.value)

0 comments on commit 566f660

Please sign in to comment.