diff --git a/pico-keys-sdk b/pico-keys-sdk index 5e9ae65..89a8042 160000 --- a/pico-keys-sdk +++ b/pico-keys-sdk @@ -1 +1 @@ -Subproject commit 5e9ae65046bf718295c87ee8a969354a1840effa +Subproject commit 89a8042634f88a390bf16adb95418dd9e4511516 diff --git a/src/hsm/cmd_change_pin.c b/src/hsm/cmd_change_pin.c index 9a96b9f..5328a74 100644 --- a/src/hsm/cmd_change_pin.c +++ b/src/hsm/cmd_change_pin.c @@ -48,11 +48,11 @@ int cmd_change_pin(void) { //encrypt MKEK with new pin if (P2(apdu) == 0x81) { - hash_multi(apdu.data + pin_len, (uint16_t)(apdu.nc - pin_len), session_pin); + pin_derive_session(apdu.data + pin_len, (uint16_t)(apdu.nc - pin_len), session_pin); has_session_pin = true; } else if (P2(apdu) == 0x88) { - hash_multi(apdu.data + pin_len, (uint16_t)(apdu.nc - pin_len), session_sopin); + pin_derive_session(apdu.data + pin_len, (uint16_t)(apdu.nc - pin_len), session_sopin); has_session_sopin = true; } r = store_mkek(mkek); @@ -60,9 +60,10 @@ int cmd_change_pin(void) { if (r != PICOKEY_OK) { return SW_EXEC_ERROR(); } - uint8_t dhash[33]; + uint8_t dhash[34]; dhash[0] = (uint8_t)apdu.nc - pin_len; - double_hash_pin(apdu.data + pin_len, (uint16_t)(apdu.nc - pin_len), dhash + 1); + dhash[1] = 1; // Format + pin_derive_verifier(apdu.data + pin_len, (uint16_t)(apdu.nc - pin_len), dhash + 2); file_put_data(file_pin, dhash, sizeof(dhash)); low_flash_available(); return SW_OK(); diff --git a/src/hsm/cmd_initialize.c b/src/hsm/cmd_initialize.c index 092908e..5a5de3d 100644 --- a/src/hsm/cmd_initialize.c +++ b/src/hsm/cmd_initialize.c @@ -60,21 +60,23 @@ int cmd_initialize(void) { } else if (tag == 0x81) { //user pin if (file_pin1 && file_pin1->data) { - uint8_t dhash[33]; - dhash[0] = (uint8_t)tag_len; - double_hash_pin(tag_data, tag_len, dhash + 1); - file_put_data(file_pin1, dhash, sizeof(dhash)); - hash_multi(tag_data, tag_len, session_pin); + uint8_t pin_data[34]; + pin_data[0] = (uint8_t)tag_len; + pin_data[1] = 1; // Format + pin_derive_verifier(tag_data, tag_len, pin_data + 2); + file_put_data(file_pin1, pin_data, sizeof(pin_data)); + pin_derive_session(tag_data, tag_len, session_pin); has_session_pin = true; } } else if (tag == 0x82) { //sopin pin if (file_sopin && file_sopin->data) { - uint8_t dhash[33]; - dhash[0] = (uint8_t)tag_len; - double_hash_pin(tag_data, tag_len, dhash + 1); - file_put_data(file_sopin, dhash, sizeof(dhash)); - hash_multi(tag_data, tag_len, session_sopin); + uint8_t pin_data[34]; + pin_data[0] = (uint8_t)tag_len; + pin_data[1] = 1; // Format + pin_derive_verifier(tag_data, tag_len, pin_data + 2); + file_put_data(file_sopin, pin_data, sizeof(pin_data)); + pin_derive_session(tag_data, tag_len, session_sopin); has_session_sopin = true; } } diff --git a/src/hsm/cmd_reset_retry.c b/src/hsm/cmd_reset_retry.c index b2b129e..c63f690 100644 --- a/src/hsm/cmd_reset_retry.c +++ b/src/hsm/cmd_reset_retry.c @@ -55,10 +55,6 @@ int cmd_reset_retry(void) { } newpin_len = (uint8_t)apdu.nc; } - uint8_t dhash[33]; - dhash[0] = newpin_len; - double_hash_pin(apdu.data + (apdu.nc - newpin_len), newpin_len, dhash + 1); - file_put_data(file_pin1, dhash, sizeof(dhash)); if (pin_reset_retries(file_pin1, true) != PICOKEY_OK) { return SW_MEMORY_FAILURE(); } @@ -67,13 +63,18 @@ int cmd_reset_retry(void) { if (r != PICOKEY_OK) { return SW_EXEC_ERROR(); } - hash_multi(apdu.data + (apdu.nc - newpin_len), newpin_len, session_pin); + pin_derive_session(apdu.data + (apdu.nc - newpin_len), newpin_len, session_pin); has_session_pin = true; r = store_mkek(mkek); release_mkek(mkek); if (r != PICOKEY_OK) { return SW_EXEC_ERROR(); } + uint8_t dhash[34]; + dhash[0] = newpin_len; + dhash[1] = 1; // Format + pin_derive_verifier(apdu.data + (apdu.nc - newpin_len), newpin_len, dhash + 2); + file_put_data(file_pin1, dhash, sizeof(dhash)); low_flash_available(); return SW_OK(); } diff --git a/src/hsm/kek.c b/src/hsm/kek.c index dc2d7b9..dc6391a 100644 --- a/src/hsm/kek.c +++ b/src/hsm/kek.c @@ -47,18 +47,19 @@ int load_mkek(uint8_t *mkek) { if (has_session_pin == false && has_session_sopin == false) { return PICOKEY_NO_LOGIN; } + file_t *ef = NULL; const uint8_t *pin = NULL; if (pin == NULL && has_session_pin == true) { file_t *tf = search_file(EF_MKEK); if (file_has_data(tf)) { - memcpy(mkek, file_get_data(tf), MKEK_SIZE); + ef = tf; pin = session_pin; } } if (pin == NULL && has_session_sopin == true) { file_t *tf = search_file(EF_MKEK_SO); if (file_has_data(tf)) { - memcpy(mkek, file_get_data(tf), MKEK_SIZE); + ef = tf; pin = session_sopin; } } @@ -66,21 +67,42 @@ int load_mkek(uint8_t *mkek) { return PICOKEY_EXEC_ERROR; } - if (has_mkek_mask) { - mkek_masked(mkek, mkek_mask); + uint16_t fid_size = file_get_size(ef); + if (fid_size == MKEK_SIZE_OLD) { + memcpy(mkek, file_get_data(ef), MKEK_SIZE_OLD); + if (has_mkek_mask) { + mkek_masked(mkek, mkek_mask); + } + int ret = aes_decrypt_cfb_256(pin, MKEK_IV(mkek), MKEK_KEY(mkek), MKEK_KEY_SIZE + MKEK_KEY_CS_SIZE); + if (ret != 0) { + return PICOKEY_EXEC_ERROR; + } + uint32_t mkek_checksum = 0; + memcpy(&mkek_checksum, MKEK_CHECKSUM(mkek), sizeof(mkek_checksum)); + if (crc32c(MKEK_KEY(mkek), MKEK_KEY_SIZE) != mkek_checksum) { + return PICOKEY_WRONG_DKEK; + } + if (otp_key_1) { + mkek_masked(mkek, otp_key_1); + } } - - int ret = aes_decrypt_cfb_256(pin, MKEK_IV(mkek), MKEK_KEY(mkek), MKEK_KEY_SIZE + MKEK_KEY_CS_SIZE); - if (ret != 0) { - return PICOKEY_EXEC_ERROR; + else if (fid_size == MKEK_FILE_SIZE) { + uint8_t format = *file_get_data(ef); + if (format == 0x03) { // Format indicator + uint8_t tmp_key[MKEK_FILE_SIZE]; + memcpy(tmp_key, file_get_data(ef), sizeof(tmp_key)); + int ret = decrypt_with_aad(pin, tmp_key + 1, MKEK_FILE_SIZE - 1, 2, mkek); + mbedtls_platform_zeroize(tmp_key, sizeof(tmp_key)); + if (ret != PICOKEY_OK) { + return PICOKEY_EXEC_ERROR; + } + } + else { + return PICOKEY_EXEC_ERROR; + } } - uint32_t mkek_checksum = 0; - memcpy(&mkek_checksum, MKEK_CHECKSUM(mkek), sizeof(mkek_checksum)); - if (crc32c(MKEK_KEY(mkek), MKEK_KEY_SIZE) != mkek_checksum) { - return PICOKEY_WRONG_DKEK; - } - if (otp_key_1) { - mkek_masked(mkek, otp_key_1); + else { + return PICOKEY_ERR_FILE_NOT_FOUND; } return PICOKEY_OK; } @@ -113,47 +135,30 @@ int store_mkek(const uint8_t *mkek) { if (has_session_pin == false && has_session_sopin == false) { return PICOKEY_NO_LOGIN; } - uint8_t tmp_mkek[MKEK_SIZE]; + uint8_t tmp_mkek[MKEK_FILE_SIZE]; + tmp_mkek[0] = 0x03; // Format indicator 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); + mkek = random_bytes_get(MKEK_SIZE); } - else { - memcpy(tmp_mkek, mkek, MKEK_SIZE); - } - if (otp_key_1) { - mkek_masked(tmp_mkek, otp_key_1); - } - uint32_t mkek_checksum = crc32c(MKEK_KEY(tmp_mkek), MKEK_KEY_SIZE); - memcpy(MKEK_CHECKSUM(tmp_mkek), &mkek_checksum, sizeof(mkek_checksum)); if (has_session_pin) { - 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); + file_t *ef = search_file(EF_MKEK); + if (!ef) { 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); + encrypt_with_aad(session_pin, mkek, MKEK_SIZE, 2, tmp_mkek + 1); + file_put_data(ef, tmp_mkek, sizeof(tmp_mkek)); } if (has_session_sopin) { - uint8_t tmp_mkek_sopin[MKEK_SIZE]; - memcpy(tmp_mkek_sopin, tmp_mkek, MKEK_SIZE); - file_t *tf = search_file(EF_MKEK_SO); - if (!tf) { - release_mkek(tmp_mkek); - release_mkek(tmp_mkek_sopin); + file_t *ef = search_file(EF_MKEK_SO); + if (!ef) { return PICOKEY_ERR_FILE_NOT_FOUND; } - aes_encrypt_cfb_256(session_sopin, MKEK_IV(tmp_mkek_sopin), MKEK_KEY(tmp_mkek_sopin), MKEK_KEY_SIZE + MKEK_KEY_CS_SIZE); - file_put_data(tf, tmp_mkek_sopin, MKEK_SIZE); - release_mkek(tmp_mkek_sopin); + encrypt_with_aad(session_sopin, mkek, MKEK_SIZE, 2, tmp_mkek + 1); + file_put_data(ef, tmp_mkek, sizeof(tmp_mkek)); } low_flash_available(); - release_mkek(tmp_mkek); + mbedtls_platform_zeroize(tmp_mkek, sizeof(tmp_mkek)); + return PICOKEY_OK; } @@ -246,7 +251,7 @@ static int dkek_kmac(uint8_t id, uint8_t *kmac) { //kmac 32 bytes int mkek_encrypt(uint8_t *data, uint16_t len) { int r; - uint8_t mkek[MKEK_SIZE + 4]; + uint8_t mkek[MKEK_SIZE]; if ((r = load_mkek(mkek)) != PICOKEY_OK) { return r; } @@ -257,7 +262,7 @@ int mkek_encrypt(uint8_t *data, uint16_t len) { int mkek_decrypt(uint8_t *data, uint16_t len) { int r; - uint8_t mkek[MKEK_SIZE + 4]; + uint8_t mkek[MKEK_SIZE]; if ((r = load_mkek(mkek)) != PICOKEY_OK) { return r; } diff --git a/src/hsm/kek.h b/src/hsm/kek.h index 0293f16..8467877 100644 --- a/src/hsm/kek.h +++ b/src/hsm/kek.h @@ -34,21 +34,9 @@ extern int import_dkek_share(uint8_t, const uint8_t *share); extern int dkek_kcv(uint8_t, uint8_t *kcv); extern int mkek_encrypt(uint8_t *data, uint16_t len); extern int mkek_decrypt(uint8_t *data, uint16_t len); -extern int dkek_encode_key(uint8_t, - void *key_ctx, - int key_type, - uint8_t *out, - uint16_t *out_len, - const uint8_t *, - uint16_t); +extern int dkek_encode_key(uint8_t, void *key_ctx, int key_type, uint8_t *out, uint16_t *out_len, const uint8_t *, uint16_t); extern int dkek_type_key(const uint8_t *in); -extern int dkek_decode_key(uint8_t, - void *key_ctx, - const uint8_t *in, - uint16_t in_len, - int *key_size_out, - uint8_t **, - uint16_t *); +extern int dkek_decode_key(uint8_t, void *key_ctx, const uint8_t *in, uint16_t in_len, int *key_size_out, uint8_t **, uint16_t *); #define MAX_DKEK_ENCODE_KEY_BUFFER (8 + 1 + 12 + 6 + (8 + 2 * 4 + 2 * 4096 / 8 + 3 + 13) + 16) @@ -57,12 +45,15 @@ extern int dkek_decode_key(uint8_t, #define MKEK_IV_SIZE (IV_SIZE) #define MKEK_KEY_SIZE (32) #define MKEK_KEY_CS_SIZE (4) -#define MKEK_SIZE (MKEK_IV_SIZE + MKEK_KEY_SIZE + MKEK_KEY_CS_SIZE) +#define MKEK_SIZE_OLD (MKEK_IV_SIZE + MKEK_KEY_SIZE + MKEK_KEY_CS_SIZE) #define MKEK_IV(p) (p) #define MKEK_KEY(p) (MKEK_IV(p) + MKEK_IV_SIZE) #define MKEK_CHECKSUM(p) (MKEK_KEY(p) + MKEK_KEY_SIZE) #define DKEK_KEY_SIZE (32) +#define MKEK_SIZE (MKEK_IV_SIZE + MKEK_KEY_SIZE) +#define MKEK_FILE_SIZE (1 + (12 + MKEK_SIZE + 16)) + extern uint8_t mkek_mask[MKEK_KEY_SIZE]; extern bool has_mkek_mask; diff --git a/src/hsm/sc_hsm.c b/src/hsm/sc_hsm.c index 7b3d575..c2cf5ff 100644 --- a/src/hsm/sc_hsm.c +++ b/src/hsm/sc_hsm.c @@ -209,8 +209,10 @@ void reset_puk_store(void) { uint16_t fterm_data_len = file_get_size(fterm); asn1_ctx_t ctxi; asn1_ctx_init(fterm_data, fterm_data_len, &ctxi); + DEBUG_DATA(fterm_data,fterm_data_len); while (walk_tlv(&ctxi, &p, NULL, NULL, NULL)) { add_cert_puk_store(pq, (uint16_t)(p - pq), false); + DEBUG_PAYLOAD(pq, (p - pq)); pq = p; } } @@ -362,12 +364,18 @@ uint16_t check_pin(const file_t *pin, const uint8_t *data, uint16_t len) { isUserAuthenticated = false; } has_session_pin = has_session_sopin = false; - uint8_t dhash[32]; - double_hash_pin(data, len, dhash); - if (sizeof(dhash) != file_get_size(pin) - 1) { // 1 byte for pin len - return SW_CONDITIONS_NOT_SATISFIED(); + uint8_t dhash[32], off = 2; + if (sizeof(dhash) == file_get_size(pin) - 1) { // Old style + off = 1; + double_hash_pin(data, len, dhash); } - if (memcmp(file_get_data(pin) + 1, dhash, sizeof(dhash)) != 0) { + else if (sizeof(dhash) == file_get_size(pin) - 2) { + pin_derive_verifier(data, len, dhash); + } + else { + return SW_WRONG_DATA(); + } + if (memcmp(file_get_data(pin) + off, dhash, sizeof(dhash)) != 0) { int retries; if ((retries = pin_wrong_retry(pin)) < PICOKEY_OK) { return SW_PIN_BLOCKED(); @@ -381,15 +389,54 @@ uint16_t check_pin(const file_t *pin, const uint8_t *data, uint16_t len) { if (r != PICOKEY_OK) { return SW_MEMORY_FAILURE(); } + if (off == 1) { // Upgrade PIN format + if (r != PICOKEY_OK) { + return SW_MEMORY_FAILURE(); + } + if (pin == file_pin1) { + hash_multi(data, len, session_pin); + has_session_pin = true; + } + else if (pin == file_sopin) { + hash_multi(data, len, session_sopin); + has_session_sopin = true; + } + uint8_t mkek[MKEK_SIZE_OLD]; // Old MKEK size, as it is encrypted with old PIN format + r = load_mkek(mkek); //loads the MKEK with old format + if (r != PICOKEY_OK) { + return SW_MEMORY_FAILURE(); + } + if (pin == file_pin1) { + pin_derive_session(data, len, session_pin); + } + else if (pin == file_sopin) { + pin_derive_session(data, len, session_sopin); + } + r = store_mkek(mkek); //stores the MKEK with new format + mbedtls_platform_zeroize(mkek, sizeof(mkek)); + if (r != PICOKEY_OK) { + return SW_MEMORY_FAILURE(); + } + + uint8_t pin_data[34]; + pin_data[0] = len; + pin_data[1] = 1; // new format indicator + pin_derive_verifier(data, len, pin_data + 2); + r = file_put_data((file_t *) pin, pin_data, sizeof(pin_data)); + if (r != PICOKEY_OK) { + return SW_MEMORY_FAILURE(); + } + low_flash_available(); + } if (pka_enabled() == false) { isUserAuthenticated = true; } if (pin == file_pin1) { - hash_multi(data, len, session_pin); + pin_derive_session(data, len, session_pin); has_session_pin = true; } else if (pin == file_sopin) { - hash_multi(data, len, session_sopin); + pin_derive_session(data, len, session_sopin); has_session_sopin = true; } if (pending_save_dkek != 0xff) {