mirror of
https://github.com/trussed-dev/fido2-tests.git
synced 2026-06-20 04:16:30 -07:00
hmac-secret tests
This commit is contained in:
committed by
Nicolas Stalder
parent
937bcd8a75
commit
ad5cb2ed07
@@ -0,0 +1,168 @@
|
||||
import pytest
|
||||
|
||||
from cryptography.hazmat.backends import default_backend
|
||||
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
|
||||
from fido2.utils import sha256, hmac_sha256
|
||||
from fido2.ctap import CtapError
|
||||
|
||||
from tests.utils import FidoRequest, verify, shannon_entropy
|
||||
|
||||
|
||||
def get_salt_params(cipher, shared_secret, salts):
|
||||
enc = cipher.encryptor()
|
||||
salt_enc = b""
|
||||
for salt in salts:
|
||||
salt_enc += enc.update(salt)
|
||||
salt_enc += enc.finalize()
|
||||
|
||||
salt_auth = hmac_sha256(shared_secret, salt_enc)[:16]
|
||||
return salt_enc, salt_auth
|
||||
|
||||
|
||||
salt1 = b"\xa5" * 32
|
||||
salt2 = b"\x96" * 32
|
||||
salt3 = b"\x03" * 32
|
||||
salt4 = b"\x5a" * 16
|
||||
salt5 = b"\x96" * 64
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def MCHmacSecret(resetDevice,):
|
||||
req = FidoRequest(extensions={"hmac-secret": True}, options={"rk": True})
|
||||
res = resetDevice.sendMC(*req.toMC())
|
||||
setattr(res, "request", req)
|
||||
return res
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
def sharedSecret(device, MCHmacSecret):
|
||||
return device.client.pin_protocol.get_shared_secret()
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
def cipher(device, sharedSecret):
|
||||
key_agreement, shared_secret = sharedSecret
|
||||
return Cipher(
|
||||
algorithms.AES(shared_secret), modes.CBC(b"\x00" * 16), default_backend()
|
||||
)
|
||||
|
||||
|
||||
class TestHmacSecret(object):
|
||||
def test_hmac_secret_make_credential(self, MCHmacSecret):
|
||||
assert MCHmacSecret.auth_data.extensions
|
||||
assert "hmac-secret" in MCHmacSecret.auth_data.extensions
|
||||
assert MCHmacSecret.auth_data.extensions["hmac-secret"] == True
|
||||
|
||||
def test_hmac_secret_info(self, info):
|
||||
assert "hmac-secret" in info.extensions
|
||||
|
||||
def test_fake_extension(self, device):
|
||||
req = FidoRequest(extensions={"tetris": True})
|
||||
res = device.sendMC(*req.toMC())
|
||||
|
||||
def test_get_shared_secret(self, sharedSecret):
|
||||
pass
|
||||
|
||||
@pytest.mark.parametrize("salts", [(salt1,), (salt1, salt2)])
|
||||
def test_hmac_secret(self, device, MCHmacSecret, cipher, sharedSecret, salts):
|
||||
print("salts:", salts)
|
||||
key_agreement, shared_secret = sharedSecret
|
||||
salt_enc, salt_auth = get_salt_params(cipher, shared_secret, salts)
|
||||
req = FidoRequest(
|
||||
extensions={"hmac-secret": {1: key_agreement, 2: salt_enc, 3: salt_auth}}
|
||||
)
|
||||
auth = device.sendGA(*req.toGA())
|
||||
|
||||
ext = auth.auth_data.extensions
|
||||
assert ext
|
||||
assert "hmac-secret" in ext
|
||||
assert isinstance(ext["hmac-secret"], bytes)
|
||||
assert len(ext["hmac-secret"]) == len(salts) * 32
|
||||
|
||||
verify(MCHmacSecret, auth, req.cdh)
|
||||
|
||||
dec = cipher.decryptor()
|
||||
key = dec.update(ext["hmac-secret"]) + dec.finalize()
|
||||
|
||||
print(shannon_entropy(ext["hmac-secret"]))
|
||||
if len(salts) == 1:
|
||||
assert shannon_entropy(ext["hmac-secret"]) > 4.6
|
||||
assert shannon_entropy(key) > 4.6
|
||||
if len(salts) == 2:
|
||||
assert shannon_entropy(ext["hmac-secret"]) > 5.4
|
||||
assert shannon_entropy(key) > 5.4
|
||||
|
||||
def test_missing_keyAgreement(self, device, cipher, sharedSecret):
|
||||
key_agreement, shared_secret = sharedSecret
|
||||
|
||||
salt_enc, salt_auth = get_salt_params(cipher, shared_secret, (salt3,))
|
||||
|
||||
req = FidoRequest(extensions={"hmac-secret": {2: salt_enc, 3: salt_auth}})
|
||||
|
||||
with pytest.raises(CtapError):
|
||||
device.sendGA(*req.toGA())
|
||||
|
||||
def test_missing_saltAuth(self, device, cipher, sharedSecret):
|
||||
key_agreement, shared_secret = sharedSecret
|
||||
|
||||
salt_enc, salt_auth = get_salt_params(cipher, shared_secret, (salt3,))
|
||||
|
||||
req = FidoRequest(extensions={"hmac-secret": {1: key_agreement, 2: salt_enc}})
|
||||
|
||||
with pytest.raises(CtapError) as e:
|
||||
device.sendGA(*req.toGA())
|
||||
assert e.value.code == CtapError.ERR.MISSING_PARAMETER
|
||||
|
||||
def test_missing_saltEnc(self, device, cipher, sharedSecret):
|
||||
key_agreement, shared_secret = sharedSecret
|
||||
|
||||
salt_enc, salt_auth = get_salt_params(cipher, shared_secret, (salt3,))
|
||||
|
||||
req = FidoRequest(extensions={"hmac-secret": {1: key_agreement, 3: salt_auth}})
|
||||
|
||||
with pytest.raises(CtapError) as e:
|
||||
device.sendGA(*req.toGA())
|
||||
assert e.value.code == CtapError.ERR.MISSING_PARAMETER
|
||||
|
||||
def test_bad_auth(self, device, cipher, sharedSecret):
|
||||
|
||||
key_agreement, shared_secret = sharedSecret
|
||||
|
||||
salt_enc, salt_auth = get_salt_params(cipher, shared_secret, (salt3,))
|
||||
|
||||
bad_auth = list(salt_auth[:])
|
||||
bad_auth[len(bad_auth) // 2] = bad_auth[len(bad_auth) // 2] ^ 1
|
||||
bad_auth = bytes(bad_auth)
|
||||
|
||||
req = FidoRequest(
|
||||
extensions={"hmac-secret": {1: key_agreement, 2: salt_enc, 3: bad_auth}}
|
||||
)
|
||||
|
||||
with pytest.raises(CtapError) as e:
|
||||
device.sendGA(*req.toGA())
|
||||
assert e.value.code == CtapError.ERR.EXTENSION_FIRST
|
||||
|
||||
@pytest.mark.parametrize("salts", [(salt4,), (salt4, salt5)])
|
||||
def test_invalid_salt_length(self, device, cipher, sharedSecret, salts):
|
||||
key_agreement, shared_secret = sharedSecret
|
||||
salt_enc, salt_auth = get_salt_params(cipher, shared_secret, salts)
|
||||
|
||||
req = FidoRequest(
|
||||
extensions={"hmac-secret": {1: key_agreement, 2: salt_enc, 3: salt_auth}}
|
||||
)
|
||||
|
||||
with pytest.raises(CtapError) as e:
|
||||
device.sendGA(*req.toGA())
|
||||
assert e.value.code == CtapError.ERR.INVALID_LENGTH
|
||||
# auth = self.testGA(
|
||||
# "Send GA request with incorrect salt length %d, expect INVALID_LENGTH"
|
||||
#% len(salt_enc),
|
||||
# rp["id"],
|
||||
# cdh,
|
||||
# other={
|
||||
# "extensions": {
|
||||
# "hmac-secret": {1: key_agreement, 2: salt_enc, 3: salt_auth}
|
||||
# }
|
||||
# },
|
||||
# expectedError=CtapError.ERR.INVALID_LENGTH,
|
||||
# )
|
||||
Reference in New Issue
Block a user