Compare commits
13 Commits
Author | SHA1 | Date | |
---|---|---|---|
d4e61421b6 | |||
690d7c716a | |||
78e3b291c2 | |||
b47854c335 | |||
2af747ddaa | |||
9ead11de8d | |||
f17faca689 | |||
ca66b6e43b | |||
1cd1b3c295 | |||
df2cff2350 | |||
f5d50e001d | |||
235785b225 | |||
303c42901a |
@ -1 +1 @@
|
|||||||
2.3.0
|
2.4.0
|
||||||
|
@ -38,6 +38,7 @@ void generate_private_key(uint8_t * data, int len, uint8_t * data2, int len2, ui
|
|||||||
void crypto_ecc256_make_key_pair(uint8_t * pubkey, uint8_t * privkey);
|
void crypto_ecc256_make_key_pair(uint8_t * pubkey, uint8_t * privkey);
|
||||||
void crypto_ecc256_shared_secret(const uint8_t * pubkey, const uint8_t * privkey, uint8_t * shared_secret);
|
void crypto_ecc256_shared_secret(const uint8_t * pubkey, const uint8_t * privkey, uint8_t * shared_secret);
|
||||||
|
|
||||||
|
#define CRYPTO_TRANSPORT_KEY2 ((uint8_t*)2)
|
||||||
#define CRYPTO_TRANSPORT_KEY ((uint8_t*)1)
|
#define CRYPTO_TRANSPORT_KEY ((uint8_t*)1)
|
||||||
#define CRYPTO_MASTER_KEY ((uint8_t*)0)
|
#define CRYPTO_MASTER_KEY ((uint8_t*)0)
|
||||||
|
|
||||||
|
30
fido2/ctap.c
30
fido2/ctap.c
@ -355,9 +355,9 @@ static int ctap_make_extensions(CTAP_extensions * ext, uint8_t * ext_encoder_buf
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Generate credRandom
|
// Generate credRandom
|
||||||
crypto_sha256_hmac_init(CRYPTO_TRANSPORT_KEY, 0, credRandom);
|
crypto_sha256_hmac_init(CRYPTO_TRANSPORT_KEY2, 0, credRandom);
|
||||||
crypto_sha256_update((uint8_t*)&ext->hmac_secret.credential->id, sizeof(CredentialId));
|
crypto_sha256_update((uint8_t*)&ext->hmac_secret.credential->id, sizeof(CredentialId));
|
||||||
crypto_sha256_hmac_final(CRYPTO_TRANSPORT_KEY, 0, credRandom);
|
crypto_sha256_hmac_final(CRYPTO_TRANSPORT_KEY2, 0, credRandom);
|
||||||
|
|
||||||
// Decrypt saltEnc
|
// Decrypt saltEnc
|
||||||
crypto_aes256_init(shared_secret, NULL);
|
crypto_aes256_init(shared_secret, NULL);
|
||||||
@ -432,6 +432,12 @@ static unsigned int get_credential_id_size(CTAP_credentialDescriptor * cred)
|
|||||||
return sizeof(CredentialId);
|
return sizeof(CredentialId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int ctap2_user_presence_test()
|
||||||
|
{
|
||||||
|
device_set_status(CTAPHID_STATUS_UPNEEDED);
|
||||||
|
return ctap_user_presence_test(CTAP2_UP_DELAY_MS);
|
||||||
|
}
|
||||||
|
|
||||||
static int ctap_make_auth_data(struct rpId * rp, CborEncoder * map, uint8_t * auth_data_buf, uint32_t * len, CTAP_credInfo * credInfo)
|
static int ctap_make_auth_data(struct rpId * rp, CborEncoder * map, uint8_t * auth_data_buf, uint32_t * len, CTAP_credInfo * credInfo)
|
||||||
{
|
{
|
||||||
CborEncoder cose_key;
|
CborEncoder cose_key;
|
||||||
@ -459,11 +465,9 @@ static int ctap_make_auth_data(struct rpId * rp, CborEncoder * map, uint8_t * au
|
|||||||
|
|
||||||
count = auth_data_update_count(&authData->head);
|
count = auth_data_update_count(&authData->head);
|
||||||
|
|
||||||
device_set_status(CTAPHID_STATUS_UPNEEDED);
|
|
||||||
|
|
||||||
int but;
|
int but;
|
||||||
|
|
||||||
but = ctap_user_presence_test(CTAP2_UP_DELAY_MS);
|
but = ctap2_user_presence_test(CTAP2_UP_DELAY_MS);
|
||||||
|
|
||||||
if (!but)
|
if (!but)
|
||||||
{
|
{
|
||||||
@ -473,6 +477,7 @@ static int ctap_make_auth_data(struct rpId * rp, CborEncoder * map, uint8_t * au
|
|||||||
{
|
{
|
||||||
return CTAP2_ERR_KEEPALIVE_CANCEL;
|
return CTAP2_ERR_KEEPALIVE_CANCEL;
|
||||||
}
|
}
|
||||||
|
|
||||||
device_set_status(CTAPHID_STATUS_PROCESSING);
|
device_set_status(CTAPHID_STATUS_PROCESSING);
|
||||||
|
|
||||||
authData->head.flags = (but << 0);
|
authData->head.flags = (but << 0);
|
||||||
@ -605,7 +610,6 @@ int ctap_calculate_signature(uint8_t * data, int datalen, uint8_t * clientDataHa
|
|||||||
crypto_sha256_final(hashbuf);
|
crypto_sha256_final(hashbuf);
|
||||||
|
|
||||||
crypto_ecc256_sign(hashbuf, 32, sigbuf);
|
crypto_ecc256_sign(hashbuf, 32, sigbuf);
|
||||||
|
|
||||||
return ctap_encode_der_sig(sigbuf,sigder);
|
return ctap_encode_der_sig(sigbuf,sigder);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -701,11 +705,11 @@ uint8_t ctap_make_credential(CborEncoder * encoder, uint8_t * request, int lengt
|
|||||||
}
|
}
|
||||||
if (MC.pinAuthEmpty)
|
if (MC.pinAuthEmpty)
|
||||||
{
|
{
|
||||||
if (!ctap_user_presence_test(CTAP2_UP_DELAY_MS))
|
if (!ctap2_user_presence_test(CTAP2_UP_DELAY_MS))
|
||||||
{
|
{
|
||||||
return CTAP2_ERR_OPERATION_DENIED;
|
return CTAP2_ERR_OPERATION_DENIED;
|
||||||
}
|
}
|
||||||
return ctap_is_pin_set() == 1 ? CTAP2_ERR_PIN_INVALID : CTAP2_ERR_PIN_NOT_SET;
|
return ctap_is_pin_set() == 1 ? CTAP2_ERR_PIN_AUTH_INVALID : CTAP2_ERR_PIN_NOT_SET;
|
||||||
}
|
}
|
||||||
if ((MC.paramsParsed & MC_requiredMask) != MC_requiredMask)
|
if ((MC.paramsParsed & MC_requiredMask) != MC_requiredMask)
|
||||||
{
|
{
|
||||||
@ -1056,7 +1060,7 @@ uint8_t ctap_end_get_assertion(CborEncoder * map, CTAP_credentialDescriptor * cr
|
|||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
sigder_sz = ctap_calculate_signature(auth_data_buf, sizeof(CTAP_authDataHeader), clientDataHash, auth_data_buf, sigbuf, sigder);
|
sigder_sz = ctap_calculate_signature(auth_data_buf, auth_data_buf_sz, clientDataHash, auth_data_buf, sigbuf, sigder);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -1137,11 +1141,11 @@ uint8_t ctap_get_assertion(CborEncoder * encoder, uint8_t * request, int length)
|
|||||||
|
|
||||||
if (GA.pinAuthEmpty)
|
if (GA.pinAuthEmpty)
|
||||||
{
|
{
|
||||||
if (!ctap_user_presence_test(CTAP2_UP_DELAY_MS))
|
if (!ctap2_user_presence_test(CTAP2_UP_DELAY_MS))
|
||||||
{
|
{
|
||||||
return CTAP2_ERR_OPERATION_DENIED;
|
return CTAP2_ERR_OPERATION_DENIED;
|
||||||
}
|
}
|
||||||
return ctap_is_pin_set() == 1 ? CTAP2_ERR_PIN_INVALID : CTAP2_ERR_PIN_NOT_SET;
|
return ctap_is_pin_set() == 1 ? CTAP2_ERR_PIN_AUTH_INVALID : CTAP2_ERR_PIN_NOT_SET;
|
||||||
}
|
}
|
||||||
if (GA.pinAuthPresent)
|
if (GA.pinAuthPresent)
|
||||||
{
|
{
|
||||||
@ -1604,7 +1608,6 @@ uint8_t ctap_request(uint8_t * pkt_raw, int length, CTAP_RESPONSE * resp)
|
|||||||
switch(cmd)
|
switch(cmd)
|
||||||
{
|
{
|
||||||
case CTAP_MAKE_CREDENTIAL:
|
case CTAP_MAKE_CREDENTIAL:
|
||||||
device_set_status(CTAPHID_STATUS_PROCESSING);
|
|
||||||
printf1(TAG_CTAP,"CTAP_MAKE_CREDENTIAL\n");
|
printf1(TAG_CTAP,"CTAP_MAKE_CREDENTIAL\n");
|
||||||
timestamp();
|
timestamp();
|
||||||
status = ctap_make_credential(&encoder, pkt_raw, length);
|
status = ctap_make_credential(&encoder, pkt_raw, length);
|
||||||
@ -1615,7 +1618,6 @@ uint8_t ctap_request(uint8_t * pkt_raw, int length, CTAP_RESPONSE * resp)
|
|||||||
|
|
||||||
break;
|
break;
|
||||||
case CTAP_GET_ASSERTION:
|
case CTAP_GET_ASSERTION:
|
||||||
device_set_status(CTAPHID_STATUS_PROCESSING);
|
|
||||||
printf1(TAG_CTAP,"CTAP_GET_ASSERTION\n");
|
printf1(TAG_CTAP,"CTAP_GET_ASSERTION\n");
|
||||||
timestamp();
|
timestamp();
|
||||||
status = ctap_get_assertion(&encoder, pkt_raw, length);
|
status = ctap_get_assertion(&encoder, pkt_raw, length);
|
||||||
@ -1647,7 +1649,7 @@ uint8_t ctap_request(uint8_t * pkt_raw, int length, CTAP_RESPONSE * resp)
|
|||||||
break;
|
break;
|
||||||
case CTAP_RESET:
|
case CTAP_RESET:
|
||||||
printf1(TAG_CTAP,"CTAP_RESET\n");
|
printf1(TAG_CTAP,"CTAP_RESET\n");
|
||||||
if (ctap_user_presence_test(CTAP2_UP_DELAY_MS))
|
if (ctap2_user_presence_test(CTAP2_UP_DELAY_MS))
|
||||||
{
|
{
|
||||||
ctap_reset();
|
ctap_reset();
|
||||||
}
|
}
|
||||||
|
@ -342,6 +342,7 @@ static uint8_t USBD_HID_Setup (USBD_HandleTypeDef *pdev,
|
|||||||
uint8_t *pbuf = NULL;
|
uint8_t *pbuf = NULL;
|
||||||
uint16_t status_info = 0U;
|
uint16_t status_info = 0U;
|
||||||
USBD_StatusTypeDef ret = USBD_OK;
|
USBD_StatusTypeDef ret = USBD_OK;
|
||||||
|
req->wLength = req->wLength & 0x7f;
|
||||||
|
|
||||||
switch (req->bmRequest & USB_REQ_TYPE_MASK)
|
switch (req->bmRequest & USB_REQ_TYPE_MASK)
|
||||||
{
|
{
|
||||||
@ -386,6 +387,7 @@ static uint8_t USBD_HID_Setup (USBD_HandleTypeDef *pdev,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case USB_REQ_GET_DESCRIPTOR:
|
case USB_REQ_GET_DESCRIPTOR:
|
||||||
|
req->wLength = req->wLength & 0x7f;
|
||||||
if(req->wValue >> 8 == HID_REPORT_DESC)
|
if(req->wValue >> 8 == HID_REPORT_DESC)
|
||||||
{
|
{
|
||||||
len = MIN(HID_FIDO_REPORT_DESC_SIZE , req->wLength);
|
len = MIN(HID_FIDO_REPORT_DESC_SIZE , req->wLength);
|
||||||
|
@ -157,6 +157,11 @@ void crypto_sha256_hmac_final(uint8_t * key, uint32_t klen, uint8_t * hmac)
|
|||||||
key = master_secret;
|
key = master_secret;
|
||||||
klen = sizeof(master_secret)/2;
|
klen = sizeof(master_secret)/2;
|
||||||
}
|
}
|
||||||
|
else if (key == CRYPTO_TRANSPORT_KEY2)
|
||||||
|
{
|
||||||
|
key = transport_secret;
|
||||||
|
klen = 32;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if(klen > 64)
|
if(klen > 64)
|
||||||
|
@ -211,7 +211,7 @@ class FIDO2Tests(Tester):
|
|||||||
assert "hmac-secret" in reg.auth_data.extensions
|
assert "hmac-secret" in reg.auth_data.extensions
|
||||||
assert reg.auth_data.extensions["hmac-secret"] == True
|
assert reg.auth_data.extensions["hmac-secret"] == True
|
||||||
|
|
||||||
reg = self.testMC(
|
self.testMC(
|
||||||
"Send MC with fake extension set to true, expect SUCCESS",
|
"Send MC with fake extension set to true, expect SUCCESS",
|
||||||
cdh,
|
cdh,
|
||||||
rp,
|
rp,
|
||||||
@ -278,6 +278,10 @@ class FIDO2Tests(Tester):
|
|||||||
assert shannon_entropy(ext["hmac-secret"]) > 5.4
|
assert shannon_entropy(ext["hmac-secret"]) > 5.4
|
||||||
assert shannon_entropy(key) > 5.4
|
assert shannon_entropy(key) > 5.4
|
||||||
|
|
||||||
|
with Test("Check that the assertion is valid"):
|
||||||
|
credential_data = AttestedCredentialData(reg.auth_data.credential_data)
|
||||||
|
auth.verify(cdh, credential_data.public_key)
|
||||||
|
|
||||||
salt_enc, salt_auth = get_salt_params((salt3,))
|
salt_enc, salt_auth = get_salt_params((salt3,))
|
||||||
|
|
||||||
auth = self.testGA(
|
auth = self.testGA(
|
||||||
@ -743,6 +747,40 @@ class FIDO2Tests(Tester):
|
|||||||
expectedError=CtapError.ERR.SUCCESS,
|
expectedError=CtapError.ERR.SUCCESS,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
with Test("Check assertion is correct"):
|
||||||
|
credential_data = AttestedCredentialData(prev_reg.auth_data.credential_data)
|
||||||
|
prev_auth.verify(cdh, credential_data.public_key)
|
||||||
|
assert (
|
||||||
|
prev_auth.credential["id"]
|
||||||
|
== prev_reg.auth_data.credential_data.credential_id
|
||||||
|
)
|
||||||
|
|
||||||
|
self.reboot()
|
||||||
|
|
||||||
|
prev_auth = self.testGA(
|
||||||
|
"Send GA request after reboot, expect success",
|
||||||
|
rp["id"],
|
||||||
|
cdh,
|
||||||
|
allow_list,
|
||||||
|
expectedError=CtapError.ERR.SUCCESS,
|
||||||
|
)
|
||||||
|
|
||||||
|
with Test("Check assertion is correct"):
|
||||||
|
credential_data = AttestedCredentialData(prev_reg.auth_data.credential_data)
|
||||||
|
prev_auth.verify(cdh, credential_data.public_key)
|
||||||
|
assert (
|
||||||
|
prev_auth.credential["id"]
|
||||||
|
== prev_reg.auth_data.credential_data.credential_id
|
||||||
|
)
|
||||||
|
|
||||||
|
prev_auth = self.testGA(
|
||||||
|
"Send GA request, expect success",
|
||||||
|
rp["id"],
|
||||||
|
cdh,
|
||||||
|
allow_list,
|
||||||
|
expectedError=CtapError.ERR.SUCCESS,
|
||||||
|
)
|
||||||
|
|
||||||
with Test("Test auth_data is 37 bytes"):
|
with Test("Test auth_data is 37 bytes"):
|
||||||
assert len(prev_auth.auth_data) == 37
|
assert len(prev_auth.auth_data) == 37
|
||||||
|
|
||||||
@ -1096,7 +1134,10 @@ class FIDO2Tests(Tester):
|
|||||||
rp["id"],
|
rp["id"],
|
||||||
cdh,
|
cdh,
|
||||||
other={"pin_auth": b"", "pin_protocol": pin_protocol},
|
other={"pin_auth": b"", "pin_protocol": pin_protocol},
|
||||||
expectedError=CtapError.ERR.PIN_NOT_SET,
|
expectedError=[
|
||||||
|
CtapError.ERR.PIN_AUTH_INVALID,
|
||||||
|
CtapError.ERR.NO_CREDENTIALS,
|
||||||
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
with Test("Setting pin code, expect SUCCESS"):
|
with Test("Setting pin code, expect SUCCESS"):
|
||||||
@ -1110,14 +1151,17 @@ class FIDO2Tests(Tester):
|
|||||||
user,
|
user,
|
||||||
key_params,
|
key_params,
|
||||||
other={"pin_auth": b"", "pin_protocol": pin_protocol},
|
other={"pin_auth": b"", "pin_protocol": pin_protocol},
|
||||||
expectedError=CtapError.ERR.PIN_INVALID,
|
expectedError=CtapError.ERR.PIN_AUTH_INVALID,
|
||||||
)
|
)
|
||||||
self.testGA(
|
self.testGA(
|
||||||
"Send MC request with new pin auth",
|
"Send MC request with new pin auth",
|
||||||
rp["id"],
|
rp["id"],
|
||||||
cdh,
|
cdh,
|
||||||
other={"pin_auth": b"", "pin_protocol": pin_protocol},
|
other={"pin_auth": b"", "pin_protocol": pin_protocol},
|
||||||
expectedError=CtapError.ERR.PIN_INVALID,
|
expectedError=[
|
||||||
|
CtapError.ERR.PIN_AUTH_INVALID,
|
||||||
|
CtapError.ERR.NO_CREDENTIALS,
|
||||||
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
self.testReset()
|
self.testReset()
|
||||||
@ -1273,13 +1317,13 @@ class FIDO2Tests(Tester):
|
|||||||
|
|
||||||
self.testReset()
|
self.testReset()
|
||||||
|
|
||||||
self.test_get_info()
|
# self.test_get_info()
|
||||||
|
#
|
||||||
self.test_get_assertion()
|
# self.test_get_assertion()
|
||||||
|
#
|
||||||
self.test_make_credential()
|
# self.test_make_credential()
|
||||||
|
#
|
||||||
self.test_rk(None)
|
# self.test_rk(None)
|
||||||
|
|
||||||
self.test_client_pin()
|
self.test_client_pin()
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@ import time, struct
|
|||||||
|
|
||||||
from fido2.hid import CtapHidDevice
|
from fido2.hid import CtapHidDevice
|
||||||
from fido2.client import Fido2Client
|
from fido2.client import Fido2Client
|
||||||
|
from fido2.attestation import Attestation
|
||||||
from fido2.ctap1 import CTAP1
|
from fido2.ctap1 import CTAP1
|
||||||
from fido2.utils import Timeout
|
from fido2.utils import Timeout
|
||||||
|
|
||||||
@ -201,7 +202,18 @@ class Tester:
|
|||||||
self.ctap.reset()
|
self.ctap.reset()
|
||||||
|
|
||||||
def testMC(self, test, *args, **kwargs):
|
def testMC(self, test, *args, **kwargs):
|
||||||
return self.testFunc(self.ctap.make_credential, test, *args, **kwargs)
|
attestation_object = self.testFunc(
|
||||||
|
self.ctap.make_credential, test, *args, **kwargs
|
||||||
|
)
|
||||||
|
if attestation_object:
|
||||||
|
verifier = Attestation.for_type(attestation_object.fmt)
|
||||||
|
client_data = args[0]
|
||||||
|
verifier().verify(
|
||||||
|
attestation_object.att_statement,
|
||||||
|
attestation_object.auth_data,
|
||||||
|
client_data,
|
||||||
|
)
|
||||||
|
return attestation_object
|
||||||
|
|
||||||
def testGA(self, test, *args, **kwargs):
|
def testGA(self, test, *args, **kwargs):
|
||||||
return self.testFunc(self.ctap.get_assertion, test, *args, **kwargs)
|
return self.testFunc(self.ctap.get_assertion, test, *args, **kwargs)
|
||||||
|
@ -78,6 +78,16 @@ class U2FTests(Tester):
|
|||||||
auth = self.authenticate(chal, appid, regs[i].key_handle)
|
auth = self.authenticate(chal, appid, regs[i].key_handle)
|
||||||
auth.verify(appid, chal, regs[i].public_key)
|
auth.verify(appid, chal, regs[i].public_key)
|
||||||
|
|
||||||
|
self.reboot()
|
||||||
|
|
||||||
|
for i in range(0, self.user_count):
|
||||||
|
with Test(
|
||||||
|
"Post reboot, Checking previous registration %d/%d"
|
||||||
|
% (i + 1, self.user_count)
|
||||||
|
):
|
||||||
|
auth = self.authenticate(chal, appid, regs[i].key_handle)
|
||||||
|
auth.verify(appid, chal, regs[i].public_key)
|
||||||
|
|
||||||
print("Check that all previous credentials are registered...")
|
print("Check that all previous credentials are registered...")
|
||||||
for i in range(0, self.user_count):
|
for i in range(0, self.user_count):
|
||||||
with Test("Check that previous credential %d is registered" % i):
|
with Test("Check that previous credential %d is registered" % i):
|
||||||
|
Reference in New Issue
Block a user