Compare commits

..

13 Commits
2.4.0 ... 2.4.2

8 changed files with 103 additions and 27 deletions

View File

@ -1 +1 @@
2.3.0 2.4.0

View File

@ -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)

View File

@ -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();
} }

View File

@ -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);

View File

@ -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)

View File

@ -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()

View File

@ -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)

View File

@ -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):