diff --git a/pico-keys-sdk b/pico-keys-sdk index b3b2b67..c165ae4 160000 --- a/pico-keys-sdk +++ b/pico-keys-sdk @@ -1 +1 @@ -Subproject commit b3b2b67034334dfbd1030ed8dc6ac4d463faacd7 +Subproject commit c165ae4838bd2edcbac260cca3247979d9910edc diff --git a/src/fido/cbor_client_pin.c b/src/fido/cbor_client_pin.c index 703b156..78579a8 100644 --- a/src/fido/cbor_client_pin.c +++ b/src/fido/cbor_client_pin.c @@ -44,6 +44,7 @@ uint32_t max_usage_time_period = 600 * 1000; bool needs_power_cycle = false; static mbedtls_ecdh_context hkey; static bool hkey_init = false; +extern int encrypt_keydev_f1(const uint8_t keydev[32]); int beginUsingPinUvAuthToken(bool userIsPresent) { paut.user_present = userIsPresent; @@ -199,11 +200,7 @@ int decrypt(uint8_t protocol, const uint8_t *key, const uint8_t *in, uint16_t in return -1; } -int authenticate(uint8_t protocol, - const uint8_t *key, - const uint8_t *data, - size_t len, - uint8_t *sign) { +int authenticate(uint8_t protocol, const uint8_t *key, const uint8_t *data, size_t len, uint8_t *sign) { uint8_t hmac[32]; int ret = mbedtls_md_hmac(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), key, 32, data, len, hmac); @@ -231,10 +228,10 @@ int verify(uint8_t protocol, const uint8_t *key, const uint8_t *data, uint16_t l return ret; } if (protocol == 1) { - return memcmp(sign, hmac, 16); + return ct_memcmp(sign, hmac, 16); } else if (protocol == 2) { - return memcmp(sign, hmac, 32); + return ct_memcmp(sign, hmac, 32); } return -1; } @@ -269,17 +266,15 @@ int pinUvAuthTokenUsageTimerObserver() { return 0; } -int check_mkek_encrypted(const uint8_t *dhash) { - if (file_get_size(ef_mkek) == MKEK_IV_SIZE + MKEK_KEY_SIZE) { - hash_multi(dhash, 16, session_pin); // Only for storing MKEK - uint8_t mkek[MKEK_SIZE] = {0}; - memcpy(mkek, file_get_data(ef_mkek), MKEK_IV_SIZE + MKEK_KEY_SIZE); - int ret = store_mkek(mkek); - mbedtls_platform_zeroize(mkek, sizeof(mkek)); - mbedtls_platform_zeroize(session_pin, sizeof(session_pin)); - if (ret != PICOKEY_OK) { - return CTAP2_ERR_PIN_AUTH_INVALID; - } +int check_keydev_encrypted(const uint8_t pin_token[32]) { + if (file_get_data(ef_keydev) && *file_get_data(ef_keydev) == 0x01) { + uint8_t tmp_keydev[61]; + tmp_keydev[0] = 0x02; // Change format to encrypted + encrypt_with_aad(pin_token, file_get_data(ef_keydev) + 1, 32, tmp_keydev + 1); + DEBUG_DATA(tmp_keydev, sizeof(tmp_keydev)); + file_put_data(ef_keydev, tmp_keydev, sizeof(tmp_keydev)); + mbedtls_platform_zeroize(tmp_keydev, sizeof(tmp_keydev)); + low_flash_available(); } return PICOKEY_OK; } @@ -294,11 +289,11 @@ int cbor_client_pin(const uint8_t *data, size_t len) { CborEncoder encoder, mapEncoder; CborValue map; CborError error = CborNoError; - CborByteString pinUvAuthParam = { 0 }, newPinEnc = { 0 }, pinHashEnc = { 0 }, kax = { 0 }, - kay = { 0 }; + CborByteString pinUvAuthParam = { 0 }, newPinEnc = { 0 }, pinHashEnc = { 0 }, kax = { 0 }, kay = { 0 }; CborCharString rpId = { 0 }; CBOR_CHECK(cbor_parser_init(data, len, 0, &parser, &map)); uint64_t val_c = 1; + uint8_t keydev[32] = {0}; if (hkey_init == false) { initialize(); } @@ -425,11 +420,12 @@ int cbor_client_pin(const uint8_t *data, size_t len) { hsh[1] = pin_len; hsh[2] = 1; // New format indicator mbedtls_md(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), paddedNewPin, pin_len, dhash); - double_hash_pin_otp(dhash, 16, hsh + 3); + pin_derive_verifier(dhash, 16, hsh + 3); file_put_data(ef_pin, hsh, sizeof(hsh)); low_flash_available(); - ret = check_mkek_encrypted(dhash); + pin_derive_session(dhash, 16, session_pin); + ret = check_keydev_encrypted(session_pin); if (ret != PICOKEY_OK) { CBOR_ERROR(ret); } @@ -494,10 +490,10 @@ int cbor_client_pin(const uint8_t *data, size_t len) { double_hash_pin(paddedNewPin, 16, dhash); } else { - double_hash_pin_otp(paddedNewPin, 16, dhash); + pin_derive_verifier(paddedNewPin, 16, dhash); } - if (memcmp(dhash, file_get_data(ef_pin) + off, 32) != 0) { + if (ct_memcmp(dhash, file_get_data(ef_pin) + off, 32) != 0) { regenerate(); mbedtls_platform_zeroize(sharedSecret, sizeof(sharedSecret)); if (retries == 0) { @@ -514,12 +510,25 @@ int cbor_client_pin(const uint8_t *data, size_t len) { if (off == 2) { // Upgrade pin file to new format pin_data[2] = 1; // New format indicator - double_hash_pin_otp(paddedNewPin, 16, pin_data + 3); + pin_derive_verifier(paddedNewPin, 16, pin_data + 3); + + hash_multi(paddedNewPin, 16, session_pin); + ret = load_keydev(keydev); + if (ret != PICOKEY_OK) { + CBOR_ERROR(CTAP2_ERR_PIN_INVALID); + } + encrypt_keydev_f1(keydev); } - hash_multi(paddedNewPin, 16, session_pin); + pin_derive_session(paddedNewPin, 16, session_pin); pin_data[0] = MAX_PIN_RETRIES; file_put_data(ef_pin, pin_data, sizeof(pin_data)); low_flash_available(); + + ret = check_keydev_encrypted(session_pin); + if (ret != PICOKEY_OK) { + CBOR_ERROR(ret); + } + new_pin_mismatches = 0; ret = decrypt((uint8_t)pinUvAuthProtocol, sharedSecret, newPinEnc.data, (uint16_t)newPinEnc.len, paddedNewPin); mbedtls_platform_zeroize(sharedSecret, sizeof(sharedSecret)); @@ -541,35 +550,32 @@ int cbor_client_pin(const uint8_t *data, size_t len) { if (pin_len < minPin) { CBOR_ERROR(CTAP2_ERR_PIN_POLICY_VIOLATION); } + + // New PIN is valid and verified + ret = load_keydev(keydev); + if (ret != PICOKEY_OK) { + CBOR_ERROR(CTAP2_ERR_PIN_INVALID); + } + encrypt_keydev_f1(keydev); + + mbedtls_md(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), paddedNewPin, pin_len, dhash); + pin_derive_session(dhash, 16, session_pin); + ret = check_keydev_encrypted(session_pin); + if (ret != PICOKEY_OK) { + CBOR_ERROR(ret); + } + low_flash_available(); + pin_data[0] = MAX_PIN_RETRIES; pin_data[1] = pin_len; pin_data[2] = 1; // New format indicator - mbedtls_md(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), paddedNewPin, pin_len, dhash); - double_hash_pin_otp(dhash, 16, pin_data + 3); + pin_derive_verifier(dhash, 16, pin_data + 3); - if (file_has_data(ef_minpin) && file_get_data(ef_minpin)[1] == 1 && - memcmp(pin_data + 3, file_get_data(ef_pin) + 3, 32) == 0) { + if (file_has_data(ef_minpin) && file_get_data(ef_minpin)[1] == 1 && ct_memcmp(pin_data + 3, file_get_data(ef_pin) + 3, 32) == 0) { CBOR_ERROR(CTAP2_ERR_PIN_POLICY_VIOLATION); } - - uint8_t mkek[MKEK_SIZE] = {0}; - ret = load_mkek(mkek); - if (ret != PICOKEY_OK) { - CBOR_ERROR(ret); - } file_put_data(ef_pin, pin_data, sizeof(pin_data)); - ret = check_mkek_encrypted(dhash); - if (ret != PICOKEY_OK) { - CBOR_ERROR(ret); - } - - hash_multi(dhash, 16, session_pin); - ret = store_mkek(mkek); - mbedtls_platform_zeroize(mkek, sizeof(mkek)); - if (ret != PICOKEY_OK) { - CBOR_ERROR(ret); - } mbedtls_platform_zeroize(pin_data, sizeof(pin_data)); mbedtls_platform_zeroize(dhash, sizeof(dhash)); if (file_has_data(ef_minpin) && file_get_data(ef_minpin)[1] == 1) { @@ -642,11 +648,12 @@ int cbor_client_pin(const uint8_t *data, size_t len) { double_hash_pin(paddedNewPin, 16, dhash); } else { - double_hash_pin_otp(paddedNewPin, 16, dhash); + pin_derive_verifier(paddedNewPin, 16, dhash); } - if (memcmp(dhash, file_get_data(ef_pin) + off, 32) != 0) { + if (ct_memcmp(dhash, file_get_data(ef_pin) + off, 32) != 0) { regenerate(); mbedtls_platform_zeroize(sharedSecret, sizeof(sharedSecret)); + mbedtls_platform_zeroize(dhash, sizeof(dhash)); if (retries == 0) { CBOR_ERROR(CTAP2_ERR_PIN_BLOCKED); } @@ -658,25 +665,31 @@ int cbor_client_pin(const uint8_t *data, size_t len) { CBOR_ERROR(CTAP2_ERR_PIN_INVALID); } } - - ret = check_mkek_encrypted(paddedNewPin); - if (ret != PICOKEY_OK) { - CBOR_ERROR(ret); - } - - hash_multi(paddedNewPin, 16, session_pin); - pin_data[0] = MAX_PIN_RETRIES; - new_pin_mismatches = 0; + mbedtls_platform_zeroize(dhash, sizeof(dhash)); if (off == 2) { // Upgrade pin file to new format pin_data[2] = 1; // New format indicator - double_hash_pin_otp(paddedNewPin, 16, pin_data + 3); + pin_derive_verifier(paddedNewPin, 16, pin_data + 3); + hash_multi(paddedNewPin, 16, session_pin); + ret = load_keydev(keydev); + if (ret != PICOKEY_OK) { + CBOR_ERROR(CTAP2_ERR_PIN_INVALID); + } + encrypt_keydev_f1(keydev); } + pin_derive_session(paddedNewPin, 16, session_pin); + ret = check_keydev_encrypted(session_pin); + if (ret != PICOKEY_OK) { + CBOR_ERROR(ret); + } + + pin_data[0] = MAX_PIN_RETRIES; + new_pin_mismatches = 0; + file_put_data(ef_pin, pin_data, sizeof(pin_data)); mbedtls_platform_zeroize(pin_data, sizeof(pin_data)); - mbedtls_platform_zeroize(dhash, sizeof(dhash)); low_flash_available(); file_t *ef_minpin = search_by_fid(EF_MINPINLEN, NULL, SPECIFY_EF); @@ -684,7 +697,6 @@ int cbor_client_pin(const uint8_t *data, size_t len) { CBOR_ERROR(CTAP2_ERR_PIN_INVALID); } uint8_t pinUvAuthToken_enc[32 + IV_SIZE], *pdata = NULL; - ; if (permissions & CTAP_PERMISSION_PCMR) { ppaut.permissions = CTAP_PERMISSION_PCMR; pdata = ppaut.data; @@ -722,6 +734,7 @@ err: CBOR_FREE_BYTE_STRING(kax); CBOR_FREE_BYTE_STRING(kay); CBOR_FREE_BYTE_STRING(rpId); + mbedtls_platform_zeroize(keydev, sizeof(keydev)); if (error != CborNoError) { if (error == CborErrorImproperValue) { return CTAP2_ERR_CBOR_UNEXPECTED_TYPE; diff --git a/src/fido/fido.c b/src/fido/fido.c index b9a0ef8..b05e1fb 100644 --- a/src/fido/fido.c +++ b/src/fido/fido.c @@ -204,7 +204,7 @@ int x509_create_cert(mbedtls_ecdsa_context *ecdsa, uint8_t *buffer, size_t buffe return ret; } -int load_keydev(uint8_t *key) { +int load_keydev(uint8_t key[32]) { if (has_keydev_dec == false && !file_has_data(ef_keydev)) { return PICOKEY_ERR_MEMORY_FATAL; } @@ -213,13 +213,39 @@ int load_keydev(uint8_t *key) { memcpy(key, keydev_dec, sizeof(keydev_dec)); } else { - memcpy(key, file_get_data(ef_keydev), file_get_size(ef_keydev)); - - if (mkek_decrypt(key, 32) != PICOKEY_OK) { - return PICOKEY_EXEC_ERROR; + uint16_t fid_size = file_get_size(ef_keydev); + if (fid_size == 32) { + memcpy(key, file_get_data(ef_keydev), 32); + if (mkek_decrypt(key, 32) != PICOKEY_OK) { + return PICOKEY_EXEC_ERROR; + } + if (otp_key_1 && aes_decrypt(otp_key_1, NULL, 32 * 8, PICO_KEYS_AES_MODE_CBC, key, 32) != PICOKEY_OK) { + return PICOKEY_EXEC_ERROR; + } } - if (otp_key_1 && aes_decrypt(otp_key_1, NULL, 32 * 8, PICO_KEYS_AES_MODE_CBC, key, 32) != PICOKEY_OK) { - return PICOKEY_EXEC_ERROR; + else if (fid_size == 33 || fid_size == 61) { + uint8_t format = *file_get_data(ef_keydev); + if (format == 0x01 || format == 0x02) { // Format indicator + if (format == 0x02) { + uint8_t tmp_key[61]; + memcpy(tmp_key, file_get_data(ef_keydev), sizeof(tmp_key)); + int ret = decrypt_with_aad(session_pin, tmp_key + 1, 60, key); + if (ret != PICOKEY_OK) { + return PICOKEY_EXEC_ERROR; + } + } + else { + memcpy(key, file_get_data(ef_keydev) + 1, 32); + } + uint8_t kbase[32]; + derive_kbase(kbase); + int ret = aes_decrypt(kbase, pico_serial_hash, 32 * 8, PICO_KEYS_AES_MODE_CBC, key, 32); + if (ret != PICOKEY_OK) { + mbedtls_platform_zeroize(kbase, sizeof(kbase)); + return PICOKEY_EXEC_ERROR; + } + mbedtls_platform_zeroize(kbase, sizeof(kbase)); + } } } @@ -315,6 +341,23 @@ int derive_key(const uint8_t *app_id, bool new_key, uint8_t *key_handle, int cur return r; } +int encrypt_keydev_f1(const uint8_t keydev[32]) { + uint8_t kdata[33] = {0}; + kdata[0] = 0x01; // Format indicator + memcpy(kdata + 1, keydev, 32); + uint8_t kbase[32]; + derive_kbase(kbase); + int ret = aes_encrypt(kbase, pico_serial_hash, 32 * 8, PICO_KEYS_AES_MODE_CBC, kdata + 1, 32); + mbedtls_platform_zeroize(kbase, sizeof(kbase)); + if (ret != PICOKEY_OK) { + return ret; + } + ret = file_put_data(ef_keydev, kdata, 33); + mbedtls_platform_zeroize(kdata, sizeof(kdata)); + low_flash_available(); + return ret; +} + int scan_files_fido() { ef_keydev = search_by_fid(EF_KEY_DEV, NULL, SPECIFY_EF); ef_keydev_enc = search_by_fid(EF_KEY_DEV_ENC, NULL, SPECIFY_EF); @@ -330,17 +373,16 @@ int scan_files_fido() { mbedtls_ecdsa_free(&ecdsa); return ret; } - uint8_t kdata[64]; + uint8_t keydev[32] = {0}; size_t key_size = 0; - ret = mbedtls_ecp_write_key_ext(&ecdsa, &key_size, kdata, sizeof(kdata)); - if (ret != PICOKEY_OK) { - return ret; + ret = mbedtls_ecp_write_key_ext(&ecdsa, &key_size, keydev, sizeof(keydev)); + if (ret != 0 || key_size != 32) { + mbedtls_platform_zeroize(keydev, sizeof(keydev)); + mbedtls_ecdsa_free(&ecdsa); + return ret != 0 ? ret : PICOKEY_EXEC_ERROR; } - if (otp_key_1) { - ret = aes_encrypt(otp_key_1, NULL, 32 * 8, PICO_KEYS_AES_MODE_CBC, kdata, 32); - } - ret = file_put_data(ef_keydev, kdata, (uint16_t)key_size); - mbedtls_platform_zeroize(kdata, sizeof(kdata)); + encrypt_keydev_f1(keydev); + mbedtls_platform_zeroize(keydev, sizeof(keydev)); mbedtls_ecdsa_free(&ecdsa); if (ret != PICOKEY_OK) { return ret; @@ -351,21 +393,6 @@ int scan_files_fido() { else { printf("FATAL ERROR: KEY DEV not found in memory!\r\n"); } - if (ef_mkek) { // No encrypted MKEK - if (!file_has_data(ef_mkek)) { - uint8_t mkek[MKEK_IV_SIZE + MKEK_KEY_SIZE]; - random_gen(NULL, mkek, sizeof(mkek)); - file_put_data(ef_mkek, mkek, sizeof(mkek)); - int ret = aes_encrypt_cfb_256(MKEK_KEY(mkek), MKEK_IV(mkek), file_get_data(ef_keydev), 32); - mbedtls_platform_zeroize(mkek, sizeof(mkek)); - if (ret != 0) { - printf("FATAL ERROR: MKEK encryption failed!\r\n"); - } - } - } - else { - printf("FATAL ERROR: MKEK not found in memory!\r\n"); - } ef_certdev = search_by_fid(EF_EE_DEV, NULL, SPECIFY_EF); if (ef_certdev) { if (!file_has_data(ef_certdev)) { @@ -409,13 +436,6 @@ int scan_files_fido() { printf("FATAL ERROR: Global counter not found in memory!\r\n"); } ef_pin = search_by_fid(EF_PIN, NULL, SPECIFY_EF); - if (file_get_size(ef_pin) == 18) { // Upgrade PIN storage - uint8_t pin_data[34] = { 0 }, dhash[32]; - memcpy(pin_data, file_get_data(ef_pin), 18); - double_hash_pin(pin_data + 2, 16, dhash); - memcpy(pin_data + 2, dhash, 32); - file_put_data(ef_pin, pin_data, 34); - } ef_authtoken = search_by_fid(EF_AUTHTOKEN, NULL, SPECIFY_EF); if (ef_authtoken) { if (!file_has_data(ef_authtoken)) { diff --git a/src/fido/fido.h b/src/fido/fido.h index 75e5928..bc42f8e 100644 --- a/src/fido/fido.h +++ b/src/fido/fido.h @@ -51,7 +51,7 @@ extern void init_fido(); extern mbedtls_ecp_group_id fido_curve_to_mbedtls(int curve); extern int mbedtls_curve_to_fido(mbedtls_ecp_group_id id); extern int fido_load_key(int curve, const uint8_t *cred_id, mbedtls_ecp_keypair *key); -extern int load_keydev(uint8_t *key); +extern int load_keydev(uint8_t key[32]); extern int encrypt(uint8_t protocol, const uint8_t *key, const uint8_t *in, uint16_t in_len, uint8_t *out); extern int decrypt(uint8_t protocol, const uint8_t *key, const uint8_t *in, uint16_t in_len, uint8_t *out); extern int ecdh(uint8_t protocol, const mbedtls_ecp_point *Q, uint8_t *sharedSecret); diff --git a/src/fido/kek.c b/src/fido/kek.c index 943217a..325dcca 100644 --- a/src/fido/kek.c +++ b/src/fido/kek.c @@ -85,46 +85,6 @@ void release_mkek(uint8_t *mkek) { mbedtls_platform_zeroize(mkek, MKEK_SIZE); } -int store_mkek(const uint8_t *mkek) { - uint8_t tmp_mkek[MKEK_SIZE]; - if (mkek == NULL) { - const uint8_t *rd = random_bytes_get(MKEK_IV_SIZE + MKEK_KEY_SIZE); - memcpy(tmp_mkek, rd, MKEK_IV_SIZE + MKEK_KEY_SIZE); - } - else { - memcpy(tmp_mkek, mkek, MKEK_SIZE); - } - if (otp_key_1) { - mkek_masked(tmp_mkek, otp_key_1); - } - *(uint32_t *) MKEK_CHECKSUM(tmp_mkek) = crc32c(MKEK_KEY(tmp_mkek), MKEK_KEY_SIZE); - uint8_t tmp_mkek_pin[MKEK_SIZE]; - memcpy(tmp_mkek_pin, tmp_mkek, MKEK_SIZE); - file_t *tf = search_file(EF_MKEK); - if (!tf) { - release_mkek(tmp_mkek); - release_mkek(tmp_mkek_pin); - return PICOKEY_ERR_FILE_NOT_FOUND; - } - aes_encrypt_cfb_256(session_pin, MKEK_IV(tmp_mkek_pin), MKEK_KEY(tmp_mkek_pin), MKEK_KEY_SIZE + MKEK_KEY_CS_SIZE); - file_put_data(tf, tmp_mkek_pin, MKEK_SIZE); - release_mkek(tmp_mkek_pin); - low_flash_available(); - release_mkek(tmp_mkek); - return PICOKEY_OK; -} - -int mkek_encrypt(uint8_t *data, uint16_t len) { - int r; - uint8_t mkek[MKEK_SIZE + 4]; - if ((r = load_mkek(mkek)) != PICOKEY_OK) { - return r; - } - r = aes_encrypt_cfb_256(MKEK_KEY(mkek), MKEK_IV(mkek), data, len); - release_mkek(mkek); - return r; -} - int mkek_decrypt(uint8_t *data, uint16_t len) { int r; uint8_t mkek[MKEK_SIZE + 4];