From 4df326215566af6e8e64e92333bb86cd324f9723 Mon Sep 17 00:00:00 2001 From: keaidang <133363849+keaidang@users.noreply.github.com> Date: Tue, 8 Jul 2025 21:35:02 +0800 Subject: [PATCH] Bug fixes --- src/openpgp/piv.c | 909 ++++++++++++++++++++++++++++++---------------- 1 file changed, 593 insertions(+), 316 deletions(-) diff --git a/src/openpgp/piv.c b/src/openpgp/piv.c index e2568bf..7c3d3a6 100644 --- a/src/openpgp/piv.c +++ b/src/openpgp/piv.c @@ -34,7 +34,7 @@ #include "mbedtls/x509_crt.h" #include "openpgp.h" -#define PIV_ALGO_3DES 0x03 +#define PIV_ALGO_3DES 0x03 #define PIV_ALGO_AES128 0x08 #define PIV_ALGO_AES192 0x0a #define PIV_ALGO_AES256 0x0c @@ -66,24 +66,29 @@ uint8_t piv_aid[] = { 5, - 0xA0, 0x00, 0x00, 0x03, 0x8, + 0xA0, + 0x00, + 0x00, + 0x03, + 0x8, }; uint8_t yk_aid[] = { 8, - 0xA0, 0x00, 0x00, 0x05, 0x27, 0x20, 0x1, 0x1 -}; + 0xA0, 0x00, 0x00, 0x05, 0x27, 0x20, 0x1, 0x1}; bool has_pwpiv = false; uint8_t session_pwpiv[32]; int piv_process_apdu(); -static int get_serial() { +static int get_serial() +{ uint32_t serial = (pico_serial.id[0] & 0x7F) << 24 | pico_serial.id[1] << 16 | pico_serial.id[2] << 8 | pico_serial.id[3]; return serial; } -static int x509_create_cert(void *pk_ctx, uint8_t algo, uint8_t slot, bool attestation, uint8_t *buffer, size_t buffer_size) { +static int x509_create_cert(void *pk_ctx, uint8_t algo, uint8_t slot, bool attestation, uint8_t *buffer, size_t buffer_size) +{ mbedtls_x509write_cert ctx; mbedtls_x509write_crt_init(&ctx); mbedtls_x509write_crt_set_version(&ctx, MBEDTLS_X509_CRT_VERSION_3); @@ -95,16 +100,19 @@ static int x509_create_cert(void *pk_ctx, uint8_t algo, uint8_t slot, bool attes mbedtls_ecdsa_context actx; // attestation key mbedtls_pk_init(&skey); mbedtls_pk_init(&ikey); - if (algo == PIV_ALGO_RSA1024 || algo == PIV_ALGO_RSA2048) { + if (algo == PIV_ALGO_RSA1024 || algo == PIV_ALGO_RSA2048) + { mbedtls_pk_setup(&skey, mbedtls_pk_info_from_type(MBEDTLS_PK_RSA)); } - else if (algo == PIV_ALGO_ECCP256 || algo == PIV_ALGO_ECCP384) { + else if (algo == PIV_ALGO_ECCP256 || algo == PIV_ALGO_ECCP384) + { mbedtls_pk_setup(&skey, mbedtls_pk_info_from_type(MBEDTLS_PK_ECKEY)); } skey.pk_ctx = pk_ctx; mbedtls_x509write_crt_set_subject_key(&ctx, &skey); char buf_sname[256]; - if (attestation) { + if (attestation) + { sprintf(buf_sname, "C=ES,O=Pico Keys,CN=Pico OpenPGP PIV Attestation %X", slot); mbedtls_x509write_crt_set_subject_name(&ctx, buf_sname); mbedtls_x509write_crt_set_issuer_name(&ctx, "C=ES,O=Pico Keys,CN=Pico OpenPGP PIV Slot F9"); @@ -120,18 +128,22 @@ static int x509_create_cert(void *pk_ctx, uint8_t algo, uint8_t slot, bool attes mbedtls_x509write_crt_set_extension(&ctx, "\x2B\x06\x01\x04\x01\x82\xC4\x0A\x03\x07", 10, 0, (const uint8_t *)&serial, sizeof(serial)); int meta_len = 0; uint8_t *meta; - if ((meta_len = meta_find(slot, &meta)) >= 0) { + if ((meta_len = meta_find(slot, &meta)) >= 0) + { mbedtls_x509write_crt_set_extension(&ctx, "\x2B\x06\x01\x04\x01\x82\xC4\x0A\x03\x08", 10, 0, &meta[1], 2); } uint8_t v = 1; mbedtls_x509write_crt_set_extension(&ctx, "\x2B\x06\x01\x04\x01\x82\xC4\x0A\x03\x09", 10, 0, &v, sizeof(serial)); } - else { + else + { uint8_t wslot = slot; - if (slot == EF_PIV_KEY_ATTESTATION) { + if (slot == EF_PIV_KEY_ATTESTATION) + { wslot = 0xF9; } - else if (slot == EF_PIV_KEY_RETIRED18) { + else if (slot == EF_PIV_KEY_RETIRED18) + { wslot = 0x93; } sprintf(buf_sname, "C=ES,O=Pico Keys,CN=Pico OpenPGP PIV Slot %X", wslot); @@ -139,86 +151,102 @@ static int x509_create_cert(void *pk_ctx, uint8_t algo, uint8_t slot, bool attes mbedtls_x509write_crt_set_subject_name(&ctx, buf_sname); mbedtls_x509write_crt_set_issuer_key(&ctx, &skey); } - if (algo == PIV_ALGO_ECCP384) { + if (algo == PIV_ALGO_ECCP384) + { mbedtls_x509write_crt_set_md_alg(&ctx, MBEDTLS_MD_SHA384); } - else { + else + { mbedtls_x509write_crt_set_md_alg(&ctx, MBEDTLS_MD_SHA256); } - if (slot == EF_PIV_KEY_ATTESTATION) { + if (slot == EF_PIV_KEY_ATTESTATION) + { mbedtls_x509write_crt_set_basic_constraints(&ctx, 1, 1); } - else { + else + { mbedtls_x509write_crt_set_basic_constraints(&ctx, 0, 0); } mbedtls_x509write_crt_set_subject_key_identifier(&ctx); mbedtls_x509write_crt_set_authority_key_identifier(&ctx); mbedtls_x509write_crt_set_key_usage(&ctx, MBEDTLS_X509_KU_DIGITAL_SIGNATURE | - MBEDTLS_X509_KU_KEY_CERT_SIGN); + MBEDTLS_X509_KU_KEY_CERT_SIGN); int ret = mbedtls_x509write_crt_der(&ctx, buffer, buffer_size, random_gen, NULL); /* skey cannot be freed, as it is freed later */ - if (attestation) { + if (attestation) + { mbedtls_ecdsa_free(&actx); } mbedtls_x509write_crt_free(&ctx); return ret; } -static void scan_files_piv() { +static void scan_files_piv() +{ scan_flash(); file_t *ef = search_by_fid(EF_PIV_KEY_CARDMGM, NULL, SPECIFY_EF); - if ((ef = search_by_fid(EF_PW_PRIV, NULL, SPECIFY_ANY))) { - if (file_get_size(ef) == 0) { + if ((ef = search_by_fid(EF_PW_PRIV, NULL, SPECIFY_ANY))) + { + if (file_get_size(ef) == 0) + { printf("PW status is empty. Initializing to default\r\n"); - const uint8_t def[] = { 0x1, 127, 127, 127, 3, 3, 3, 3, 3 }; + const uint8_t def[] = {0x1, 127, 127, 127, 3, 3, 3, 3, 3}; file_put_data(ef, def, sizeof(def)); } - else if (file_get_size(ef) == 7) { + else if (file_get_size(ef) == 7) + { printf("PW status is older. Initializing to default\r\n"); - uint8_t def[9] = { 0 }; + uint8_t def[9] = {0}; memcpy(def, file_get_data(ef), 7); def[7] = def[8] = 3; // PIV retries file_put_data(ef, def, sizeof(def)); } } - if ((ef = search_by_fid(EF_PW_RETRIES, NULL, SPECIFY_ANY))) { - if (file_get_size(ef) == 0) { + if ((ef = search_by_fid(EF_PW_RETRIES, NULL, SPECIFY_ANY))) + { + if (file_get_size(ef) == 0) + { printf("PW retries is empty. Initializing to default\r\n"); - const uint8_t def[] = { 0x1, 3, 3, 3, 3, 3 }; + const uint8_t def[] = {0x1, 3, 3, 3, 3, 3}; file_put_data(ef, def, sizeof(def)); } - else if (file_get_size(ef) == 4) { + else if (file_get_size(ef) == 4) + { printf("PW retries is older. Initializing to default\r\n"); - uint8_t def[6] = { 0 }; + uint8_t def[6] = {0}; memcpy(def, file_get_data(ef), 4); def[4] = def[5] = 3; // PIV retries file_put_data(ef, def, sizeof(def)); } } bool reset_dek = false; - if ((ef = search_by_fid(EF_DEK, NULL, SPECIFY_ANY))) { - if (file_get_size(ef) == 0 || file_get_size(ef) == IV_SIZE+32*3) { + if ((ef = search_by_fid(EF_DEK, NULL, SPECIFY_ANY))) + { + if (file_get_size(ef) == 0 || file_get_size(ef) == IV_SIZE + 32 * 3) + { printf("DEK is empty or older\r\n"); - const uint8_t defpin[6] = { 0x31, 0x32, 0x33, 0x34, 0x35, 0x36 }; + const uint8_t defpin[6] = {0x31, 0x32, 0x33, 0x34, 0x35, 0x36}; const uint8_t *dek = random_bytes_get(IV_SIZE + 32); uint8_t def[IV_SIZE + 32 + 32 + 32 + 32]; - if (file_get_size(ef) > 0) { + if (file_get_size(ef) > 0) + { memcpy(def, file_get_data(ef), file_get_size(ef)); } - else { + else + { memcpy(def, dek, IV_SIZE); } - memcpy(def + IV_SIZE + 32*3, dek + IV_SIZE, 32); + memcpy(def + IV_SIZE + 32 * 3, dek + IV_SIZE, 32); hash_multi(defpin, sizeof(defpin), session_pwpiv); - aes_encrypt_cfb_256(session_pwpiv, def, def + IV_SIZE + 32*3, 32); + aes_encrypt_cfb_256(session_pwpiv, def, def + IV_SIZE + 32 * 3, 32); file_put_data(ef, def, sizeof(def)); has_pwpiv = true; uint8_t *key = (uint8_t *)"\x01\x02\x03\x04\x05\x06\x07\x08\x01\x02\x03\x04\x05\x06\x07\x08\x01\x02\x03\x04\x05\x06\x07\x08"; file_t *ef = search_by_fid(EF_PIV_KEY_CARDMGM, NULL, SPECIFY_ANY); file_put_data(ef, key, 24); - uint8_t meta[] = { PIV_ALGO_AES192, PINPOLICY_ALWAYS, TOUCHPOLICY_ALWAYS, ORIGIN_GENERATED }; + uint8_t meta[] = {PIV_ALGO_AES192, PINPOLICY_ALWAYS, TOUCHPOLICY_ALWAYS, ORIGIN_GENERATED}; meta_add(EF_PIV_KEY_CARDMGM, meta, sizeof(meta)); has_pwpiv = false; memset(session_pwpiv, 0, sizeof(session_pwpiv)); @@ -226,28 +254,34 @@ static void scan_files_piv() { reset_dek = true; } } - if ((ef = search_by_fid(EF_PIV_PIN, NULL, SPECIFY_ANY))) { - if (!ef->data || reset_dek) { + if ((ef = search_by_fid(EF_PIV_PIN, NULL, SPECIFY_ANY))) + { + if (!ef->data || reset_dek) + { printf("PIV PIN is empty. Initializing with default password\r\n"); - const uint8_t def[8] = { 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0xFF, 0xFF }; + const uint8_t def[8] = {0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0xFF, 0xFF}; uint8_t dhash[33]; dhash[0] = sizeof(def); double_hash_pin(def, sizeof(def), dhash + 1); file_put_data(ef, dhash, sizeof(dhash)); } } - if ((ef = search_by_fid(EF_PIV_PUK, NULL, SPECIFY_ANY))) { - if (!ef->data) { + if ((ef = search_by_fid(EF_PIV_PUK, NULL, SPECIFY_ANY))) + { + if (!ef->data) + { printf("PIV PUK is empty. Initializing with default password\r\n"); - const uint8_t def[8] = { 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38 }; + const uint8_t def[8] = {0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38}; uint8_t dhash[33]; dhash[0] = sizeof(def); double_hash_pin(def, sizeof(def), dhash + 1); file_put_data(ef, dhash, sizeof(dhash)); } } - if ((ef = search_by_fid(EF_PIV_KEY_ATTESTATION, NULL, SPECIFY_ANY))) { - if (!ef->data) { + if ((ef = search_by_fid(EF_PIV_KEY_ATTESTATION, NULL, SPECIFY_ANY))) + { + if (!ef->data) + { printf("ATTESTATION key is empty. Initializing with random one\r\n"); mbedtls_ecdsa_context ecdsa; mbedtls_ecdsa_init(&ecdsa); @@ -263,19 +297,22 @@ static void scan_files_piv() { low_flash_available(); } -void init_piv() { +void init_piv() +{ scan_files_piv(); has_pwpiv = false; // cmd_select(); } -int piv_unload() { +int piv_unload() +{ return PICOKEY_OK; } -void select_piv_aid() { +void select_piv_aid() +{ res_APDU[res_APDU_size++] = 0x61; - res_APDU[res_APDU_size++] = 0; //filled later + res_APDU[res_APDU_size++] = 0; // filled later res_APDU[res_APDU_size++] = 0x4F; res_APDU[res_APDU_size++] = 2; res_APDU[res_APDU_size++] = 0x01; @@ -300,8 +337,9 @@ void select_piv_aid() { res_APDU[res_APDU_size++] = 0x00; } -int piv_select_aid(app_t *a, uint8_t force) { - (void) force; +int piv_select_aid(app_t *a, uint8_t force) +{ + (void)force; a->process_apdu = piv_process_apdu; a->unload = piv_unload; init_piv(); @@ -309,35 +347,42 @@ int piv_select_aid(app_t *a, uint8_t force) { return PICOKEY_OK; } -INITIALIZER( piv_ctor ) { +INITIALIZER(piv_ctor) +{ register_app(piv_select_aid, piv_aid); register_app(piv_select_aid, yk_aid); } -static int cmd_version() { +static int cmd_version() +{ res_APDU[res_APDU_size++] = PIV_VERSION_MAJOR; res_APDU[res_APDU_size++] = PIV_VERSION_MINOR; res_APDU[res_APDU_size++] = 0x0; return SW_OK(); } -static int cmd_select() { - if (P2(apdu) != 0x1) { +static int cmd_select() +{ + if (P2(apdu) != 0x1) + { return SW_WRONG_P1P2(); } - if (memcmp(apdu.data, piv_aid, 5) == 0) { + if (memcmp(apdu.data, piv_aid, 5) == 0) + { select_piv_aid(); } return SW_OK(); } -int piv_parse_discovery(const file_t *ef) { +int piv_parse_discovery(const file_t *ef) +{ memcpy(res_APDU, "\x7E\x12\x4F\x0B\xA0\x00\x00\x03\x08\x00\x00\x10\x00\x01\x00\x5F\x2F\x02\x40\x10", 20); res_APDU_size = 20; return res_APDU_size; } -static int cmd_get_serial() { +static int cmd_get_serial() +{ uint32_t serial = get_serial(); res_APDU[res_APDU_size++] = serial >> 24; res_APDU[res_APDU_size++] = serial >> 16; @@ -347,108 +392,138 @@ static int cmd_get_serial() { } extern int check_pin(const file_t *pin, const uint8_t *data, size_t len); -static int cmd_verify() { +static int cmd_verify() +{ uint8_t key_ref = P2(apdu); - if (P1(apdu) != 0x00 && P1(apdu) != 0xFF) { + if (P1(apdu) != 0x00 && P1(apdu) != 0xFF) + { return SW_INCORRECT_P1P2(); } - if (key_ref != 0x80) { + if (key_ref != 0x80) + { return SW_REFERENCE_NOT_FOUND(); } file_t *pw, *pw_status; uint16_t fid = EF_PIV_PIN; - if (!(pw = search_by_fid(fid, NULL, SPECIFY_EF))) { + if (!(pw = search_by_fid(fid, NULL, SPECIFY_EF))) + { return SW_REFERENCE_NOT_FOUND(); } - if (!(pw_status = search_by_fid(EF_PW_PRIV, NULL, SPECIFY_EF))) { + if (!(pw_status = search_by_fid(EF_PW_PRIV, NULL, SPECIFY_EF))) + { return SW_REFERENCE_NOT_FOUND(); } - if (file_get_data(pw)[0] == 0) { //not initialized + if (file_get_data(pw)[0] == 0) + { // not initialized return SW_REFERENCE_NOT_FOUND(); } - if (apdu.nc > 0) { + if (apdu.nc > 0) + { uint16_t ret = check_pin(pw, apdu.data, apdu.nc); - if (ret == 0x9000) { + if (ret == 0x9000) + { has_pwpiv = true; hash_multi(apdu.data, apdu.nc, session_pwpiv); } - return ret; //SW already set + return ret; // SW already set } uint8_t retries = *(file_get_data(pw_status) + 3 + (fid & 0xf)); - if (retries == 0) { + if (retries == 0) + { return SW_PIN_BLOCKED(); } - if ((key_ref == 0x80 && has_pwpiv)) { + if ((key_ref == 0x80 && has_pwpiv)) + { return SW_OK(); } return set_res_sw(0x63, 0xc0 | retries); } -static int cmd_get_data() { - if (P1(apdu) != 0x3F || P2(apdu) != 0xFF) { +static int cmd_get_data() +{ + if (P1(apdu) != 0x3F || P2(apdu) != 0xFF) + { return SW_INCORRECT_P1P2(); } - if (apdu.data[0] != 0x5C || (apdu.data[1] & 0x80) || apdu.data[1] >= 4 || apdu.data[1] == 0) { + if (apdu.data[0] != 0x5C || (apdu.data[1] & 0x80) || apdu.data[1] >= 4 || apdu.data[1] == 0) + { return SW_WRONG_DATA(); } uint32_t fid = apdu.data[2]; - for (uint8_t lt = 1; lt < apdu.data[1]; lt++) { + for (uint8_t lt = 1; lt < apdu.data[1]; lt++) + { fid <<= 8; fid |= apdu.data[2 + lt]; } - if ((fid & 0xFFFF00) != 0x5FC100 && (fid & 0xFFFF) != EF_PIV_BITGT && (fid & 0xFFFF) != EF_PIV_DISCOVERY && (fid & 0xFFFF) != EF_PIV_ATTESTATION) { + if ((fid & 0xFFFF00) != 0x5FC100 && (fid & 0xFFFF) != EF_PIV_BITGT && (fid & 0xFFFF) != EF_PIV_DISCOVERY && (fid & 0xFFFF) != EF_PIV_ATTESTATION) + { return SW_FILE_NOT_FOUND(); } file_t *ef = NULL; - if ((ef = search_by_fid((uint16_t)(fid & 0xFFFF), NULL, SPECIFY_EF))) { + if ((ef = search_by_fid((uint16_t)(fid & 0xFFFF), NULL, SPECIFY_EF))) + { uint16_t data_len = 0; res_APDU_size = 2; // Minimum: TAG+LEN - if ((ef->type & FILE_DATA_FUNC) == FILE_DATA_FUNC) { - data_len = ((int (*)(const file_t *))(ef->data))((const file_t *) ef); + if ((ef->type & FILE_DATA_FUNC) == FILE_DATA_FUNC) + { + data_len = ((int (*)(const file_t *))(ef->data))((const file_t *)ef); } - else { - if (ef->data) { + else + { + if (ef->data) + { data_len = file_get_size(ef); memcpy(res_APDU + res_APDU_size, file_get_data(ef), data_len); } } - if (data_len == 0) { + if (data_len == 0) + { return SW_FILE_NOT_FOUND(); } - if (data_len > 255) { + if (data_len > 255) + { memmove(res_APDU + res_APDU_size + 2, res_APDU + res_APDU_size, data_len); } - else if (data_len > 127) { + else if (data_len > 127) + { memmove(res_APDU + res_APDU_size + 1, res_APDU + res_APDU_size, data_len); } res_APDU[0] = 0x53; res_APDU_size = 1 + format_tlv_len(data_len, res_APDU + 1) + data_len; } - else { + else + { return SW_FILE_NOT_FOUND(); } return SW_OK(); } -static int cmd_get_metadata() { - if (P1(apdu) != 0x00) { +static int cmd_get_metadata() +{ + if (P1(apdu) != 0x00) + { return SW_INCORRECT_P1P2(); } uint8_t *meta = NULL; uint16_t key_ref = P2(apdu); - if (key_ref == 0x80) { + if (key_ref == 0x80) + { key_ref = EF_PIV_PIN; } - else if (key_ref == 0x81) { + else if (key_ref == 0x81) + { key_ref = EF_PIV_PUK; } file_t *ef_key = search_by_fid(key_ref, NULL, SPECIFY_EF); - if (!file_has_data(ef_key)) { + if (!file_has_data(ef_key)) + { return SW_REFERENCE_NOT_FOUND(); } - if (key_ref != EF_PIV_PIN && key_ref != EF_PIV_PUK) { + if (key_ref != EF_PIV_PIN && key_ref != EF_PIV_PUK) + { int meta_len = 0; - if ((meta_len = meta_find(key_ref, &meta)) <= 0) { + if ((meta_len = meta_find(key_ref, &meta)) <= 0) + { return SW_REFERENCE_NOT_FOUND(); } res_APDU[res_APDU_size++] = 0x1; @@ -461,21 +536,25 @@ static int cmd_get_metadata() { res_APDU[res_APDU_size++] = 0x3; res_APDU[res_APDU_size++] = 1; res_APDU[res_APDU_size++] = meta[3]; - if (meta[0] == PIV_ALGO_RSA1024 || meta[0] == PIV_ALGO_RSA2048 || meta[0] == PIV_ALGO_RSA3072 || meta[0] == PIV_ALGO_RSA4096 || meta[0] == PIV_ALGO_ECCP256 || meta[0] == PIV_ALGO_ECCP384) { + if (meta[0] == PIV_ALGO_RSA1024 || meta[0] == PIV_ALGO_RSA2048 || meta[0] == PIV_ALGO_RSA3072 || meta[0] == PIV_ALGO_RSA4096 || meta[0] == PIV_ALGO_ECCP256 || meta[0] == PIV_ALGO_ECCP384) + { res_APDU[res_APDU_size++] = 0x4; res_APDU[res_APDU_size++] = 0; // Filled later uint8_t *pk = &res_APDU[res_APDU_size]; - if (meta[0] == PIV_ALGO_RSA1024 || meta[0] == PIV_ALGO_RSA2048 || meta[0] == PIV_ALGO_RSA3072 || meta[0] == PIV_ALGO_RSA4096) { + if (meta[0] == PIV_ALGO_RSA1024 || meta[0] == PIV_ALGO_RSA2048 || meta[0] == PIV_ALGO_RSA3072 || meta[0] == PIV_ALGO_RSA4096) + { mbedtls_rsa_context ctx; mbedtls_rsa_init(&ctx); int r = load_private_key_rsa(&ctx, ef_key, false); - if (r != PICOKEY_OK) { + if (r != PICOKEY_OK) + { mbedtls_rsa_free(&ctx); return SW_EXEC_ERROR(); } res_APDU[res_APDU_size++] = 0x81; res_APDU[res_APDU_size++] = 0x82; - put_uint16_t_be(mbedtls_mpi_size(&ctx.N), res_APDU + res_APDU_size); res_APDU_size += 2; + put_uint16_t_be(mbedtls_mpi_size(&ctx.N), res_APDU + res_APDU_size); + res_APDU_size += 2; mbedtls_mpi_write_binary(&ctx.N, res_APDU + res_APDU_size, mbedtls_mpi_size(&ctx.N)); res_APDU_size += mbedtls_mpi_size(&ctx.N); res_APDU[res_APDU_size++] = 0x82; @@ -484,11 +563,13 @@ static int cmd_get_metadata() { res_APDU_size += mbedtls_mpi_size(&ctx.E); mbedtls_rsa_free(&ctx); } - else { + else + { mbedtls_ecdsa_context ctx; mbedtls_ecdsa_init(&ctx); int r = load_private_key_ecdsa(&ctx, ef_key, false); - if (r != PICOKEY_OK) { + if (r != PICOKEY_OK) + { mbedtls_ecdsa_free(&ctx); return SW_EXEC_ERROR(); } @@ -497,7 +578,8 @@ static int cmd_get_metadata() { mbedtls_ecp_point_write_binary(&ctx.grp, &ctx.Q, MBEDTLS_ECP_PF_UNCOMPRESSED, &plen, pt, sizeof(pt)); mbedtls_ecdsa_free(&ctx); res_APDU[res_APDU_size++] = 0x86; - if (plen >= 128) { + if (plen >= 128) + { res_APDU[res_APDU_size++] = 0x81; } res_APDU[res_APDU_size++] = plen; @@ -505,48 +587,58 @@ static int cmd_get_metadata() { res_APDU_size += plen; } uint16_t pk_len = res_APDU_size - (pk - res_APDU); - if (pk_len > 255) { + if (pk_len > 255) + { memmove(pk + 2, pk, pk_len); pk[-1] = 0x82; pk[0] = pk_len >> 8; pk[1] = pk_len & 0xff; res_APDU_size += 2; } - else if (pk_len > 127) { + else if (pk_len > 127) + { memmove(pk + 1, pk, pk_len); pk[-1] = 0x81; pk[0] = pk_len; res_APDU_size += 1; } - else { + else + { pk[-1] = pk_len; } } } - if (key_ref == EF_PIV_PIN || key_ref == EF_PIV_PUK || key_ref == EF_PIV_KEY_CARDMGM) { + if (key_ref == EF_PIV_PIN || key_ref == EF_PIV_PUK || key_ref == EF_PIV_KEY_CARDMGM) + { uint8_t dhash[32]; int32_t eq = false; - if (key_ref == EF_PIV_PIN) { + if (key_ref == EF_PIV_PIN) + { double_hash_pin((const uint8_t *)"\x31\x32\x33\x34\x35\x36\xFF\xFF", 8, dhash); eq = memcmp(dhash, file_get_data(ef_key) + 1, file_get_size(ef_key) - 1); } - else if (key_ref == EF_PIV_PUK) { + else if (key_ref == EF_PIV_PUK) + { double_hash_pin((const uint8_t *)"\x31\x32\x33\x34\x35\x36\x37\x38", 8, dhash); eq = memcmp(dhash, file_get_data(ef_key) + 1, file_get_size(ef_key) - 1); } - else if (key_ref == EF_PIV_KEY_CARDMGM) { + else if (key_ref == EF_PIV_KEY_CARDMGM) + { eq = memcmp("\x01\x02\x03\x04\x05\x06\x07\x08\x01\x02\x03\x04\x05\x06\x07\x08\x01\x02\x03\x04\x05\x06\x07\x08", file_get_data(ef_key), file_get_size(ef_key)); } res_APDU[res_APDU_size++] = 0x5; res_APDU[res_APDU_size++] = 1; res_APDU[res_APDU_size++] = eq; - if (key_ref == EF_PIV_PIN || key_ref == EF_PIV_PUK) { + if (key_ref == EF_PIV_PIN || key_ref == EF_PIV_PUK) + { file_t *pw_status; - if (!(pw_status = search_by_fid(EF_PW_PRIV, NULL, SPECIFY_EF))) { + if (!(pw_status = search_by_fid(EF_PW_PRIV, NULL, SPECIFY_EF))) + { return SW_REFERENCE_NOT_FOUND(); } uint8_t retries = *(file_get_data(pw_status) + 3 + (key_ref & 0xf)); - if (!(pw_status = search_by_fid(EF_PW_RETRIES, NULL, SPECIFY_EF))) { + if (!(pw_status = search_by_fid(EF_PW_RETRIES, NULL, SPECIFY_EF))) + { return SW_REFERENCE_NOT_FOUND(); } uint8_t total = *(file_get_data(pw_status) + (key_ref & 0xf)); @@ -561,62 +653,80 @@ static int cmd_get_metadata() { uint8_t challenge[16]; bool has_challenge = false; bool has_mgm = false; -static int cmd_authenticate() { +static int cmd_authenticate() +{ uint8_t algo = P1(apdu), key_ref = P2(apdu); - if (apdu.nc == 0) { + if (apdu.nc == 0) + { return SW_WRONG_LENGTH(); } - if (apdu.data[0] != 0x7C) { + if (apdu.data[0] != 0x7C) + { return SW_WRONG_DATA(); } - if (key_ref == EF_PIV_KEY_CARDMGM) { - if (algo != PIV_ALGO_AES128 && algo != PIV_ALGO_AES192 && algo != PIV_ALGO_AES256 && algo != PIV_ALGO_3DES) { + if (key_ref == EF_PIV_KEY_CARDMGM) + { + if (algo != PIV_ALGO_AES128 && algo != PIV_ALGO_AES192 && algo != PIV_ALGO_AES256 && algo != PIV_ALGO_3DES) + { return SW_INCORRECT_P1P2(); } file_t *ef_mgm = search_by_fid(key_ref, NULL, SPECIFY_EF); - if (!file_has_data(ef_mgm)) { + if (!file_has_data(ef_mgm)) + { return SW_MEMORY_FAILURE(); } uint16_t mgm_len = file_get_size(ef_mgm); - if ((algo == PIV_ALGO_AES128 && mgm_len != 16) || (algo == PIV_ALGO_AES192 && mgm_len != 24) || (algo == PIV_ALGO_AES256 && mgm_len != 32) || (algo == PIV_ALGO_3DES && mgm_len != 24)) { + if ((algo == PIV_ALGO_AES128 && mgm_len != 16) || (algo == PIV_ALGO_AES192 && mgm_len != 24) || (algo == PIV_ALGO_AES256 && mgm_len != 32) || (algo == PIV_ALGO_3DES && mgm_len != 24)) + { return SW_INCORRECT_P1P2(); } } uint8_t *meta = NULL; int meta_len = 0; - if ((meta_len = meta_find(key_ref, &meta)) <= 0) { + if ((meta_len = meta_find(key_ref, &meta)) <= 0) + { return SW_REFERENCE_NOT_FOUND(); } - if (meta[1] == PINPOLICY_DEFAULT) { - if (key_ref == EF_PIV_KEY_SIGNATURE) { + if (meta[1] == PINPOLICY_DEFAULT) + { + if (key_ref == EF_PIV_KEY_SIGNATURE) + { meta[1] = PINPOLICY_ALWAYS; } - else { + else + { meta[1] = PINPOLICY_ONCE; } } - if ((meta[1] == PINPOLICY_ALWAYS || meta[1] == PINPOLICY_ONCE) && (!has_pwpiv && (key_ref == EF_PIV_KEY_AUTHENTICATION || key_ref == EF_PIV_KEY_SIGNATURE || key_ref == EF_PIV_KEY_KEYMGM || key_ref == EF_PIV_KEY_CARDAUTH || IS_RETIRED(key_ref)))) { + if ((meta[1] == PINPOLICY_ALWAYS || meta[1] == PINPOLICY_ONCE) && (!has_pwpiv && (key_ref == EF_PIV_KEY_AUTHENTICATION || key_ref == EF_PIV_KEY_SIGNATURE || key_ref == EF_PIV_KEY_KEYMGM || key_ref == EF_PIV_KEY_CARDAUTH || IS_RETIRED(key_ref)))) + { return SW_SECURITY_STATUS_NOT_SATISFIED(); } uint8_t chal_len = (algo == PIV_ALGO_3DES ? sizeof(challenge) / 2 : sizeof(challenge)); - asn1_ctx_t ctxi, a7c = { 0 }; + asn1_ctx_t ctxi, a7c = {0}; asn1_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi); - if (!asn1_find_tag(&ctxi, 0x7C, &a7c) || asn1_len(&ctxi) == 0) { + if (!asn1_find_tag(&ctxi, 0x7C, &a7c) || asn1_len(&ctxi) == 0) + { return SW_WRONG_DATA(); } - asn1_ctx_t a80 = { 0 }, a81 = { 0 }, a82 = { 0 }; + asn1_ctx_t a80 = {0}, a81 = {0}, a82 = {0}; asn1_find_tag(&a7c, 0x80, &a80); asn1_find_tag(&a7c, 0x81, &a81); asn1_find_tag(&a7c, 0x82, &a82); - if (a80.data) { - if (a80.len == 0) { + if (a80.data) + { + if (a80.len == 0) + { memcpy(challenge, random_bytes_get(sizeof(challenge)), sizeof(challenge)); - if (algo == PIV_ALGO_AES128 || algo == PIV_ALGO_AES192 || algo == PIV_ALGO_AES256 || algo == PIV_ALGO_3DES) { - if (key_ref != EF_PIV_KEY_CARDMGM) { + if (algo == PIV_ALGO_AES128 || algo == PIV_ALGO_AES192 || algo == PIV_ALGO_AES256 || algo == PIV_ALGO_3DES) + { + if (key_ref != EF_PIV_KEY_CARDMGM) + { return SW_INCORRECT_P1P2(); } file_t *ef_mgm = search_by_fid(key_ref, NULL, SPECIFY_EF); - if (!file_has_data(ef_mgm)) { + if (!file_has_data(ef_mgm)) + { return SW_MEMORY_FAILURE(); } uint16_t mgm_len = file_get_size(ef_mgm); @@ -625,11 +735,13 @@ static int cmd_authenticate() { res_APDU[res_APDU_size++] = 0x80; res_APDU[res_APDU_size++] = 16; int r = 0; - if (algo == PIV_ALGO_3DES) { + if (algo == PIV_ALGO_3DES) + { mbedtls_des3_context ctx; mbedtls_des3_init(&ctx); r = mbedtls_des3_set3key_enc(&ctx, file_get_data(ef_mgm)); - if (r != 0) { + if (r != 0) + { mbedtls_des3_free(&ctx); return SW_EXEC_ERROR(); } @@ -637,11 +749,13 @@ static int cmd_authenticate() { res_APDU_size += 8; mbedtls_des3_free(&ctx); } - else { + else + { mbedtls_aes_context ctx; mbedtls_aes_init(&ctx); r = mbedtls_aes_setkey_enc(&ctx, file_get_data(ef_mgm), mgm_len * 8); - if (r != 0) { + if (r != 0) + { mbedtls_aes_free(&ctx); return SW_EXEC_ERROR(); } @@ -649,29 +763,37 @@ static int cmd_authenticate() { res_APDU_size += 16; mbedtls_aes_free(&ctx); } - if (r != 0) { + if (r != 0) + { return SW_EXEC_ERROR(); } has_challenge = true; } } - else { - if (!has_challenge) { + else + { + if (!has_challenge) + { return SW_INCORRECT_PARAMS(); } - if (!asn1_len(&a81)) { + if (!asn1_len(&a81)) + { return SW_INCORRECT_PARAMS(); } - if (key_ref != EF_PIV_KEY_CARDMGM) { + if (key_ref != EF_PIV_KEY_CARDMGM) + { return SW_INCORRECT_P1P2(); } - if (memcmp(a80.data, challenge, a80.len) == 0) { + if (memcmp(a80.data, challenge, a80.len) == 0) + { has_mgm = true; } } } - if (a81.data) { - if (!a81.len) { + if (a81.data) + { + if (!a81.len) + { memcpy(challenge, random_bytes_get(sizeof(challenge)), sizeof(challenge)); res_APDU[res_APDU_size++] = 0x7C; res_APDU[res_APDU_size++] = chal_len + 2; @@ -681,50 +803,61 @@ static int cmd_authenticate() { res_APDU_size += chal_len; has_challenge = true; } - else { + else + { file_t *ef_key = search_by_fid(key_ref == 0x93 ? EF_PIV_KEY_RETIRED18 : key_ref, NULL, SPECIFY_EF); - if (!file_has_data(ef_key)) { + if (!file_has_data(ef_key)) + { return SW_MEMORY_FAILURE(); } - if (algo == PIV_ALGO_RSA1024 || algo == PIV_ALGO_RSA2048 || algo == PIV_ALGO_RSA3072 || algo == PIV_ALGO_RSA4096) { + if (algo == PIV_ALGO_RSA1024 || algo == PIV_ALGO_RSA2048 || algo == PIV_ALGO_RSA3072 || algo == PIV_ALGO_RSA4096) + { mbedtls_rsa_context ctx; mbedtls_rsa_init(&ctx); int r = load_private_key_rsa(&ctx, ef_key, false); - if (r != PICOKEY_OK) { + if (r != PICOKEY_OK) + { mbedtls_rsa_free(&ctx); return SW_EXEC_ERROR(); } size_t olen = file_get_size(ef_key); - if (algo == PIV_ALGO_RSA1024) { + if (algo == PIV_ALGO_RSA1024) + { memcpy(res_APDU, "\x7C\x81\x00\x82\x81\x00", 6); res_APDU_size = 6; } - else { + else + { memcpy(res_APDU, "\x7C\x82\x00\x00\x82\x82\x00\x00", 8); res_APDU_size = 8; } r = mbedtls_rsa_private(&ctx, random_gen, NULL, a81.data, res_APDU + res_APDU_size); mbedtls_rsa_free(&ctx); - if (algo == PIV_ALGO_RSA1024) { + if (algo == PIV_ALGO_RSA1024) + { res_APDU[res_APDU_size - 1] = olen; res_APDU[res_APDU_size - 4] = olen + 3; } - else { + else + { res_APDU[res_APDU_size - 2] = olen >> 8; res_APDU[res_APDU_size - 1] = olen & 0xFF; res_APDU[res_APDU_size - 6] = (olen + 4) >> 8; res_APDU[res_APDU_size - 5] = (olen + 4) & 0xFF; } res_APDU_size += olen; - if (r != 0) { + if (r != 0) + { return SW_EXEC_ERROR(); } } - else if (algo == PIV_ALGO_ECCP256 || algo == PIV_ALGO_ECCP384) { + else if (algo == PIV_ALGO_ECCP256 || algo == PIV_ALGO_ECCP384) + { mbedtls_ecdsa_context ctx; mbedtls_ecdsa_init(&ctx); int r = load_private_key_ecdsa(&ctx, ef_key, false); - if (r != PICOKEY_OK) { + if (r != PICOKEY_OK) + { mbedtls_ecdsa_free(&ctx); return SW_EXEC_ERROR(); } @@ -736,23 +869,28 @@ static int cmd_authenticate() { res_APDU[res_APDU_size - 1] = olen; res_APDU[res_APDU_size - 3] = olen + 2; res_APDU_size += olen; - if (r != 0) { + if (r != 0) + { return SW_EXEC_ERROR(); } } - else if (algo == PIV_ALGO_AES128 || algo == PIV_ALGO_AES192 || algo == PIV_ALGO_AES256 || algo == PIV_ALGO_3DES) { + else if (algo == PIV_ALGO_AES128 || algo == PIV_ALGO_AES192 || algo == PIV_ALGO_AES256 || algo == PIV_ALGO_3DES) + { uint16_t key_len = file_get_size(ef_key); memcpy(res_APDU, "\x7C\x12\x82\x10", 4); res_APDU_size = 4; int r = 0; - if (algo == PIV_ALGO_3DES) { - if (a81.len % 8 != 0) { + if (algo == PIV_ALGO_3DES) + { + if (a81.len % 8 != 0) + { return SW_DATA_INVALID(); } mbedtls_des3_context ctx; mbedtls_des3_init(&ctx); r = mbedtls_des3_set3key_enc(&ctx, file_get_data(ef_key)); - if (r != 0) { + if (r != 0) + { mbedtls_des3_free(&ctx); return SW_EXEC_ERROR(); } @@ -760,14 +898,17 @@ static int cmd_authenticate() { mbedtls_des3_free(&ctx); res_APDU_size += 8; } - else { - if (a81.len % 16 != 0) { + else + { + if (a81.len % 16 != 0) + { return SW_DATA_INVALID(); } mbedtls_aes_context ctx; mbedtls_aes_init(&ctx); r = mbedtls_aes_setkey_enc(&ctx, file_get_data(ef_key), key_len * 8); - if (r != 0) { + if (r != 0) + { mbedtls_aes_free(&ctx); return SW_EXEC_ERROR(); } @@ -775,28 +916,36 @@ static int cmd_authenticate() { mbedtls_aes_free(&ctx); res_APDU_size += 16; } - if (r != 0) { + if (r != 0) + { return SW_EXEC_ERROR(); } } } } - if (a82.data) { - if (!a82.len) { + if (a82.data) + { + if (!a82.len) + { // Should be handled by a81 or a80 } - else { - if (key_ref != EF_PIV_KEY_CARDMGM) { + else + { + if (key_ref != EF_PIV_KEY_CARDMGM) + { return SW_INCORRECT_P1P2(); } - if (!has_challenge) { + if (!has_challenge) + { return SW_INCORRECT_PARAMS(); } - if (chal_len != a82.len) { + if (chal_len != a82.len) + { return SW_DATA_INVALID(); } file_t *ef_key = search_by_fid(key_ref, NULL, SPECIFY_EF); - if (!file_has_data(ef_key)) { + if (!file_has_data(ef_key)) + { return SW_MEMORY_FAILURE(); } uint16_t key_len = file_get_size(ef_key); @@ -806,95 +955,117 @@ static int cmd_authenticate() { mbedtls_des3_context ctx; mbedtls_des3_init(&ctx); r = mbedtls_des3_set3key_dec(&ctx, file_get_data(ef_key)); - if (r != 0) { + if (r != 0) + { mbedtls_des3_free(&ctx); return SW_EXEC_ERROR(); } r = mbedtls_des3_crypt_ecb(&ctx, a82.data, res_APDU); mbedtls_des3_free(&ctx); } - else { + else + { mbedtls_aes_context ctx; mbedtls_aes_init(&ctx); r = mbedtls_aes_setkey_dec(&ctx, file_get_data(ef_key), key_len * 8); - if (r != 0) { + if (r != 0) + { mbedtls_aes_free(&ctx); return SW_EXEC_ERROR(); } r = mbedtls_aes_crypt_ecb(&ctx, MBEDTLS_AES_DECRYPT, a82.data, res_APDU); mbedtls_aes_free(&ctx); } - if (r != 0) { + if (r != 0) + { return SW_EXEC_ERROR(); } - if (memcmp(res_APDU, challenge, chal_len) != 0) { + if (memcmp(res_APDU, challenge, chal_len) != 0) + { return SW_DATA_INVALID(); } } } - if (meta[1] == PINPOLICY_ALWAYS) { + if (meta[1] == PINPOLICY_ALWAYS) + { has_pwpiv = false; } return SW_OK(); } -static int cmd_asym_keygen() { +static int cmd_asym_keygen() +{ uint8_t key_ref = P2(apdu); - if (apdu.nc == 0) { + if (apdu.nc == 0) + { return SW_WRONG_LENGTH(); } - if (apdu.data[0] != 0xAC) { + if (apdu.data[0] != 0xAC) + { return SW_WRONG_DATA(); } - if (P1(apdu) != 0x0) { + if (P1(apdu) != 0x0) + { return SW_INCORRECT_P1P2(); } - if (!has_mgm) { + if (!has_mgm) + { return SW_SECURITY_STATUS_NOT_SATISFIED(); } - if (key_ref != EF_PIV_KEY_AUTHENTICATION && key_ref != EF_PIV_KEY_SIGNATURE && key_ref != EF_PIV_KEY_KEYMGM && key_ref != EF_PIV_KEY_CARDAUTH && !(key_ref >= EF_PIV_KEY_RETIRED1 && key_ref <= EF_PIV_KEY_RETIRED20)) { + if (key_ref != EF_PIV_KEY_AUTHENTICATION && key_ref != EF_PIV_KEY_SIGNATURE && key_ref != EF_PIV_KEY_KEYMGM && key_ref != EF_PIV_KEY_CARDAUTH && !(key_ref >= EF_PIV_KEY_RETIRED1 && key_ref <= EF_PIV_KEY_RETIRED20)) + { return SW_INCORRECT_P1P2(); } asn1_ctx_t ctxi, aac = {0}; asn1_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi); - if (!asn1_find_tag(&ctxi, 0xAC, &aac) || asn1_len(&aac) == 0) { + if (!asn1_find_tag(&ctxi, 0xAC, &aac) || asn1_len(&aac) == 0) + { return SW_WRONG_DATA(); } asn1_ctx_t a80 = {0}, aaa = {0}, aab = {0}; asn1_find_tag(&aac, 0x80, &a80); asn1_find_tag(&aac, 0xAA, &aaa); asn1_find_tag(&aac, 0xAB, &aab); - if (asn1_len(&a80) == 0) { + if (asn1_len(&a80) == 0) + { return SW_WRONG_DATA(); } uint16_t key_cert = 0; - if (key_ref == EF_PIV_KEY_AUTHENTICATION) { + if (key_ref == EF_PIV_KEY_AUTHENTICATION) + { key_cert = EF_PIV_AUTHENTICATION; } - else if (key_ref == EF_PIV_KEY_SIGNATURE) { + else if (key_ref == EF_PIV_KEY_SIGNATURE) + { key_cert = EF_PIV_SIGNATURE; } - else if (key_ref == EF_PIV_KEY_KEYMGM) { + else if (key_ref == EF_PIV_KEY_KEYMGM) + { key_cert = EF_PIV_KEY_MANAGEMENT; } - else if (key_ref == EF_PIV_KEY_CARDAUTH) { + else if (key_ref == EF_PIV_KEY_CARDAUTH) + { key_cert = EF_PIV_CARD_AUTH; } - else { + else + { key_cert = key_ref + 0xC08B; } - if (a80.data[0] == PIV_ALGO_RSA1024 || a80.data[0] == PIV_ALGO_RSA2048) { + if (a80.data[0] == PIV_ALGO_RSA1024 || a80.data[0] == PIV_ALGO_RSA2048) + { printf("KEYPAIR RSA\r\n"); asn1_ctx_t a81 = {0}; asn1_find_tag(&aac, 0x81, &a81); mbedtls_rsa_context rsa; mbedtls_rsa_init(&rsa); int exponent = 65537, nlen = (a80.data[0] == PIV_ALGO_RSA1024 ? 1024 : 2048); - if (asn1_len(&a81)) { + if (asn1_len(&a81)) + { exponent = (int)asn1_get_uint(&a81); } int r = mbedtls_rsa_gen_key(&rsa, random_gen, NULL, nlen, exponent); - if (r != 0) { + if (r != 0) + { mbedtls_rsa_free(&rsa); return SW_EXEC_ERROR(); } @@ -905,17 +1076,20 @@ static int cmd_asym_keygen() { file_put_data(ef, cert + sizeof(cert) - r, r); r = store_keys(&rsa, ALGO_RSA, key_ref == 0x93 ? EF_PIV_KEY_RETIRED18 : key_ref, false); mbedtls_rsa_free(&rsa); - if (r != PICOKEY_OK) { + if (r != PICOKEY_OK) + { return SW_EXEC_ERROR(); } } - else if (a80.data[0] == PIV_ALGO_ECCP256 || a80.data[0] == PIV_ALGO_ECCP384) { + else if (a80.data[0] == PIV_ALGO_ECCP256 || a80.data[0] == PIV_ALGO_ECCP384) + { printf("KEYPAIR ECDSA\r\n"); mbedtls_ecp_group_id gid = a80.data[0] == PIV_ALGO_ECCP256 ? MBEDTLS_ECP_DP_SECP256R1 : MBEDTLS_ECP_DP_SECP384R1; mbedtls_ecdsa_context ecdsa; mbedtls_ecdsa_init(&ecdsa); int r = mbedtls_ecdsa_genkey(&ecdsa, gid, random_gen, NULL); - if (r != 0) { + if (r != 0) + { mbedtls_ecdsa_free(&ecdsa); return SW_EXEC_ERROR(); } @@ -926,17 +1100,21 @@ static int cmd_asym_keygen() { file_put_data(ef, cert + sizeof(cert) - r, r); r = store_keys(&ecdsa, ALGO_ECDSA, key_ref == 0x93 ? EF_PIV_KEY_RETIRED18 : key_ref, false); mbedtls_ecdsa_free(&ecdsa); - if (r != PICOKEY_OK) { + if (r != PICOKEY_OK) + { return SW_EXEC_ERROR(); } } - else if (a80.data[0] == PIV_ALGO_X25519) { + else if (a80.data[0] == PIV_ALGO_X25519) + { } - else { + else + { return SW_DATA_INVALID(); } uint8_t def_pinpol = PINPOLICY_ONCE; - if (key_ref == EF_PIV_KEY_SIGNATURE) { + if (key_ref == EF_PIV_KEY_SIGNATURE) + { def_pinpol = PINPOLICY_ALWAYS; } uint8_t meta[] = {a80.data[0], asn1_len(&aaa) ? aaa.data[0] : def_pinpol, asn1_len(&aab) ? aab.data[0] : TOUCHPOLICY_ALWAYS, ORIGIN_GENERATED}; @@ -945,28 +1123,37 @@ static int cmd_asym_keygen() { return SW_OK(); } -static int cmd_put_data() { - if (P1(apdu) != 0x3F || P2(apdu) != 0xFF) { +static int cmd_put_data() +{ + if (P1(apdu) != 0x3F || P2(apdu) != 0xFF) + { return SW_INCORRECT_P1P2(); } asn1_ctx_t ctxi, a5c = {0}, a53 = {0}; asn1_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi); - if (apdu.data[0] != 0x7E && apdu.data[0] != 0x7F && (!asn1_find_tag(&ctxi, 0x5C, &a5c) || !asn1_find_tag(&ctxi, 0x53, &a53))) { + if (apdu.data[0] != 0x7E && apdu.data[0] != 0x7F && (!asn1_find_tag(&ctxi, 0x5C, &a5c) || !asn1_find_tag(&ctxi, 0x53, &a53))) + { return SW_WRONG_DATA(); } - if (a5c.data && a53.data) { - if (a5c.len != 3 || a5c.data[0] != 0x5F || a5c.data[1] != 0xC1) { + if (a5c.data && a53.data) + { + if (a5c.len != 3 || a5c.data[0] != 0x5F) + { return SW_WRONG_DATA(); } + uint16_t fid = (a5c.data[1] << 8 | a5c.data[2]); file_t *ef = search_by_fid(fid, NULL, SPECIFY_EF); - if (!ef) { - return SW_MEMORY_FAILURE(); + if (!ef) + { + return SW_FILE_NOT_FOUND(); } - if (a53.len > 0) { + if (a53.len > 0) + { file_put_data(ef, a53.data, a53.len); } - else { + else + { flash_clear_file(ef); } low_flash_available(); @@ -974,60 +1161,105 @@ static int cmd_put_data() { return SW_OK(); } -static int cmd_set_mgmkey() { - if (P1(apdu) != 0xFF) { +static int cmd_set_mgmkey() +{ + if (P1(apdu) != 0xFF) + { return SW_INCORRECT_P1P2(); } - if (apdu.nc < 5) { + + uint8_t touch_p2 = P2(apdu); + if (touch_p2 != 0xFF && touch_p2 != 0xFE) + { + return SW_INCORRECT_P1P2(); + } + + if (apdu.nc < 3) + { return SW_WRONG_LENGTH(); } - uint8_t touch = P2(apdu); - if (touch != 0xFF && touch != 0xFE) { - if (touch == 0xFF) { - touch = TOUCHPOLICY_NEVER; - } - else if (touch == 0xFE) { - touch = TOUCHPOLICY_ALWAYS; - } + + uint8_t algo = apdu.data[0]; + uint8_t key_ref_tag = apdu.data[1]; + uint8_t key_len = apdu.data[2]; + + if (apdu.nc != (3 + key_len)) + { + return SW_WRONG_LENGTH(); } - uint8_t algo = apdu.data[0], key_ref = apdu.data[1], pinlen = apdu.data[2]; - if ((key_ref != EF_PIV_KEY_CARDMGM) || (!(algo == PIV_ALGO_AES128 && pinlen == 16) && !(algo == PIV_ALGO_AES192 && pinlen == 24) && !(algo == PIV_ALGO_AES256 && pinlen == 32) && !(algo == PIV_ALGO_3DES && pinlen == 24))) { + + if (key_ref_tag != EF_PIV_KEY_CARDMGM) + { return SW_WRONG_DATA(); } - file_t *ef = search_by_fid(key_ref, NULL, SPECIFY_ANY); - file_put_data(ef, apdu.data + 3, pinlen); + + if (!((algo == PIV_ALGO_AES128 && key_len == 16) || + (algo == PIV_ALGO_AES192 && key_len == 24) || + (algo == PIV_ALGO_AES256 && key_len == 32) || + (algo == PIV_ALGO_3DES && key_len == 24))) + { + return SW_WRONG_DATA(); + } + + file_t *ef = search_by_fid(key_ref_tag, NULL, SPECIFY_ANY); + if (!ef) + { + return SW_FILE_NOT_FOUND(); + } + file_put_data(ef, apdu.data + 3, key_len); + uint8_t *meta = NULL, new_meta[4]; int meta_len = 0; - if ((meta_len = meta_find(key_ref, &meta)) <= 0) { + if ((meta_len = meta_find(key_ref_tag, &meta)) <= 0) + { return SW_REFERENCE_NOT_FOUND(); } + + uint8_t touch_policy; + if (touch_p2 == 0xFF) + { + touch_policy = TOUCHPOLICY_NEVER; + } + else + { + touch_policy = TOUCHPOLICY_ALWAYS; + } + memcpy(new_meta, meta, 4); new_meta[0] = algo; - new_meta[2] = touch; - meta_add(key_ref, new_meta, sizeof(new_meta)); + new_meta[2] = touch_policy; + meta_add(key_ref_tag, new_meta, sizeof(new_meta)); + low_flash_available(); return SW_OK(); } -static int cmd_move_key() { - if (apdu.nc != 0) { +static int cmd_move_key() +{ + if (apdu.nc != 0) + { return SW_WRONG_LENGTH(); } uint8_t to = P1(apdu), from = P2(apdu); - if ((!IS_KEY(to) && to != 0xFF) || !IS_KEY(from)) { + if ((!IS_KEY(to) && to != 0xFF) || !IS_KEY(from)) + { return SW_INCORRECT_P1P2(); } - if (from == 0x93) { + if (from == 0x93) + { from = EF_PIV_KEY_RETIRED18; } - if (to == 0x93) { + if (to == 0x93) + { to = EF_PIV_KEY_RETIRED18; } file_t *efs, *efd; - if (!(efs = search_by_fid(from, NULL, SPECIFY_EF)) || (!(efd = search_by_fid(to, NULL, SPECIFY_EF)) && to != 0xFF)) { + if (!(efs = search_by_fid(from, NULL, SPECIFY_EF)) || (!(efd = search_by_fid(to, NULL, SPECIFY_EF)) && to != 0xFF)) + { return SW_FILE_NOT_FOUND(); } - if (to != 0xFF) { + if (to != 0xFF) + { file_put_data(efd, file_get_data(efs), file_get_size(efs)); } flash_clear_file(efs); @@ -1035,18 +1267,22 @@ static int cmd_move_key() { return SW_OK(); } -static int cmd_change_pin() { +static int cmd_change_pin() +{ uint8_t pin_ref = P2(apdu); - if (P1(apdu) != 0x0 || (pin_ref != 0x80 && pin_ref != 0x81)) { + if (P1(apdu) != 0x0 || (pin_ref != 0x80 && pin_ref != 0x81)) + { return SW_INCORRECT_P1P2(); } file_t *ef = search_by_fid(pin_ref == 0x80 ? EF_PIV_PIN : EF_PIV_PUK, NULL, SPECIFY_ANY); - if (!ef) { + if (!ef) + { return SW_MEMORY_FAILURE(); } uint8_t *pin_data = file_get_data(ef), pin_len = apdu.nc - pin_data[0]; uint16_t ret = check_pin(ef, apdu.data, pin_data[0]); - if (ret != 0x9000) { + if (ret != 0x9000) + { return ret; } uint8_t dhash[33]; @@ -1057,17 +1293,21 @@ static int cmd_change_pin() { return SW_OK(); } -static int cmd_reset_retry() { - if (P1(apdu) != 0x0 || P2(apdu) != 0x80) { +static int cmd_reset_retry() +{ + if (P1(apdu) != 0x0 || P2(apdu) != 0x80) + { return SW_INCORRECT_P1P2(); } file_t *ef = search_by_fid(EF_PIV_PUK, NULL, SPECIFY_ANY); - if (!ef) { + if (!ef) + { return SW_MEMORY_FAILURE(); } uint8_t *puk_data = file_get_data(ef), pin_len = apdu.nc - puk_data[0]; uint16_t ret = check_pin(ef, apdu.data, puk_data[0]); - if (ret != 0x9000) { + if (ret != 0x9000) + { return ret; } uint8_t dhash[33]; @@ -1080,9 +1320,11 @@ static int cmd_reset_retry() { return SW_OK(); } -static int cmd_set_retries() { +static int cmd_set_retries() +{ file_t *ef = search_by_fid(EF_PW_RETRIES, NULL, SPECIFY_ANY); - if (!ef) { + if (!ef) + { return SW_MEMORY_FAILURE(); } uint8_t *tmp = (uint8_t *)calloc(1, file_get_size(ef)); @@ -1093,7 +1335,7 @@ static int cmd_set_retries() { free(tmp); ef = search_by_fid(EF_PIV_PIN, NULL, SPECIFY_ANY); - const uint8_t def_pin[8] = { 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0xFF, 0xFF }; + const uint8_t def_pin[8] = {0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0xFF, 0xFF}; uint8_t dhash[33]; dhash[0] = sizeof(def_pin); double_hash_pin(def_pin, sizeof(def_pin), dhash + 1); @@ -1111,8 +1353,10 @@ static int cmd_set_retries() { return SW_OK(); } -static int cmd_reset() { - if (P1(apdu) != 0x0 || P2(apdu) != 0x0) { +static int cmd_reset() +{ + if (P1(apdu) != 0x0 || P2(apdu) != 0x0) + { return SW_INCORRECT_P1P2(); } file_t *pw_status; @@ -1121,7 +1365,8 @@ static int cmd_reset() { return SW_REFERENCE_NOT_FOUND(); } uint8_t retPIN = *(file_get_data(pw_status) + 3 + (EF_PIV_PIN & 0xf)), retPUK = *(file_get_data(pw_status) + 3 + (EF_PIV_PUK & 0xf)); - if (retPIN != 0 || retPUK != 0) { + if (retPIN != 0 || retPUK != 0) + { return SW_INCORRECT_PARAMS(); } initialize_flash(true); @@ -1130,53 +1375,65 @@ static int cmd_reset() { return SW_OK(); } -static int cmd_attestation() { +static int cmd_attestation() +{ uint8_t key_ref = P1(apdu); - if (P2(apdu) != 0x00) { + if (P2(apdu) != 0x00) + { return SW_INCORRECT_P1P2(); } - if (!IS_KEY(key_ref)) { + if (!IS_KEY(key_ref)) + { return SW_REFERENCE_NOT_FOUND(); } file_t *ef_key = NULL; int meta_len = 0; uint8_t *meta = NULL; - if (!(ef_key = search_by_fid(key_ref == 0x93 ? EF_PIV_KEY_RETIRED18 : key_ref, NULL, SPECIFY_EF)) || !file_has_data(ef_key)) { + if (!(ef_key = search_by_fid(key_ref == 0x93 ? EF_PIV_KEY_RETIRED18 : key_ref, NULL, SPECIFY_EF)) || !file_has_data(ef_key)) + { return SW_REFERENCE_NOT_FOUND(); } - if ((meta_len = meta_find(key_ref, &meta)) <= 0) { + if ((meta_len = meta_find(key_ref, &meta)) <= 0) + { return SW_REFERENCE_NOT_FOUND(); } - if (meta[3] != ORIGIN_GENERATED) { + if (meta[3] != ORIGIN_GENERATED) + { return SW_INCORRECT_PARAMS(); } int r = 0; - if (meta[0] == PIV_ALGO_RSA1024 || meta[0] == PIV_ALGO_RSA2048) { + if (meta[0] == PIV_ALGO_RSA1024 || meta[0] == PIV_ALGO_RSA2048) + { mbedtls_rsa_context ctx; mbedtls_rsa_init(&ctx); r = load_private_key_rsa(&ctx, ef_key, false); - if (r != PICOKEY_OK) { + if (r != PICOKEY_OK) + { mbedtls_rsa_free(&ctx); return SW_EXEC_ERROR(); } r = x509_create_cert(&ctx, meta[0], key_ref, true, res_APDU, 2048); mbedtls_rsa_free(&ctx); } - else if (meta[0] == PIV_ALGO_ECCP256 || meta[0] == PIV_ALGO_ECCP384) { + else if (meta[0] == PIV_ALGO_ECCP256 || meta[0] == PIV_ALGO_ECCP384) + { mbedtls_ecdsa_context ctx; mbedtls_ecdsa_init(&ctx); r = load_private_key_ecdsa(&ctx, ef_key, false); - if (r != PICOKEY_OK) { + if (r != PICOKEY_OK) + { mbedtls_ecdsa_free(&ctx); return SW_EXEC_ERROR(); } r = x509_create_cert(&ctx, meta[0], key_ref, true, res_APDU, 2048); mbedtls_ecdsa_free(&ctx); } - else { + else + { return SW_WRONG_DATA(); } - if (r <= 0) { + if (r <= 0) + { return SW_EXEC_ERROR(); } memmove(res_APDU, res_APDU + 2048 - r, r); @@ -1184,143 +1441,163 @@ static int cmd_attestation() { return SW_OK(); } -static int cmd_import_asym() { +static int cmd_import_asym() +{ uint8_t algo = P1(apdu), key_ref = P2(apdu); - if (key_ref != EF_PIV_KEY_AUTHENTICATION && key_ref != EF_PIV_KEY_SIGNATURE && key_ref != EF_PIV_KEY_KEYMGM && key_ref != EF_PIV_KEY_CARDAUTH && !(key_ref >= EF_PIV_KEY_RETIRED1 && key_ref <= EF_PIV_KEY_RETIRED20)) { + if (key_ref != EF_PIV_KEY_AUTHENTICATION && key_ref != EF_PIV_KEY_SIGNATURE && key_ref != EF_PIV_KEY_KEYMGM && key_ref != EF_PIV_KEY_CARDAUTH && !(key_ref >= EF_PIV_KEY_RETIRED1 && key_ref <= EF_PIV_KEY_RETIRED20)) + { return SW_INCORRECT_P1P2(); } asn1_ctx_t ctxi, aaa = {0}, aab = {0}; asn1_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi); asn1_find_tag(&ctxi, 0xAA, &aaa); asn1_find_tag(&ctxi, 0xAB, &aab); - if (algo == PIV_ALGO_RSA1024 || algo == PIV_ALGO_RSA2048 || algo == PIV_ALGO_RSA3072 || algo == PIV_ALGO_RSA4096) { - asn1_ctx_t a1 = { 0 }, a2 = { 0 }; + if (algo == PIV_ALGO_RSA1024 || algo == PIV_ALGO_RSA2048 || algo == PIV_ALGO_RSA3072 || algo == PIV_ALGO_RSA4096) + { + asn1_ctx_t a1 = {0}, a2 = {0}; asn1_find_tag(&ctxi, 0x01, &a1); asn1_find_tag(&ctxi, 0x02, &a2); - if (asn1_len(&a1) <= 0 || asn1_len(&a2) <= 0) { + if (asn1_len(&a1) <= 0 || asn1_len(&a2) <= 0) + { return SW_WRONG_DATA(); } mbedtls_rsa_context rsa; mbedtls_rsa_init(&rsa); int r = mbedtls_mpi_read_binary(&rsa.P, a1.data, a1.len); - if (r != 0) { + if (r != 0) + { mbedtls_rsa_free(&rsa); return SW_WRONG_DATA(); } r = mbedtls_mpi_read_binary(&rsa.Q, a2.data, a2.len); - if (r != 0) { + if (r != 0) + { mbedtls_rsa_free(&rsa); return SW_WRONG_DATA(); } int exponent = 65537; mbedtls_mpi_lset(&rsa.E, exponent); r = mbedtls_rsa_import(&rsa, NULL, &rsa.P, &rsa.Q, NULL, &rsa.E); - if (r != 0) { + if (r != 0) + { mbedtls_rsa_free(&rsa); return SW_EXEC_ERROR(); } r = mbedtls_rsa_complete(&rsa); - if (r != 0) { + if (r != 0) + { mbedtls_rsa_free(&rsa); return SW_EXEC_ERROR(); } r = mbedtls_rsa_check_privkey(&rsa); - if (r != 0) { + if (r != 0) + { mbedtls_rsa_free(&rsa); return SW_EXEC_ERROR(); } r = store_keys(&rsa, ALGO_RSA, key_ref == 0x93 ? EF_PIV_KEY_RETIRED18 : key_ref, false); mbedtls_rsa_free(&rsa); - if (r != 0) { + if (r != 0) + { return SW_EXEC_ERROR(); } } - else if (algo == PIV_ALGO_ECCP256 || algo == PIV_ALGO_ECCP384) { + else if (algo == PIV_ALGO_ECCP256 || algo == PIV_ALGO_ECCP384) + { asn1_ctx_t a6 = {0}; asn1_find_tag(&ctxi, 0x06, &a6); - if (asn1_len(&a6) <= 0) { + if (asn1_len(&a6) <= 0) + { return SW_WRONG_DATA(); } mbedtls_ecp_group_id gid = algo == PIV_ALGO_ECCP256 ? MBEDTLS_ECP_DP_SECP256R1 : MBEDTLS_ECP_DP_SECP384R1; mbedtls_ecdsa_context ecdsa; mbedtls_ecdsa_init(&ecdsa); int r = mbedtls_ecp_read_key(gid, &ecdsa, a6.data, a6.len); - if (r != 0) { + if (r != 0) + { mbedtls_ecdsa_free(&ecdsa); return SW_EXEC_ERROR(); } r = mbedtls_ecp_mul(&ecdsa.grp, &ecdsa.Q, &ecdsa.d, &ecdsa.grp.G, random_gen, NULL); - if (r != 0) { + if (r != 0) + { mbedtls_ecdsa_free(&ecdsa); return SW_EXEC_ERROR(); } r = mbedtls_ecp_check_pub_priv(&ecdsa, &ecdsa, random_gen, NULL); - if (r != 0) { + if (r != 0) + { mbedtls_ecdsa_free(&ecdsa); return SW_EXEC_ERROR(); } r = store_keys(&ecdsa, ALGO_ECDSA, key_ref == 0x93 ? EF_PIV_KEY_RETIRED18 : key_ref, false); mbedtls_ecdsa_free(&ecdsa); - if (r != 0) { + if (r != 0) + { return SW_EXEC_ERROR(); } } - else { + else + { return SW_WRONG_DATA(); } uint8_t def_pinpol = PINPOLICY_ONCE; - if (key_ref == EF_PIV_KEY_SIGNATURE) { + if (key_ref == EF_PIV_KEY_SIGNATURE) + { def_pinpol = PINPOLICY_ALWAYS; } - uint8_t meta[] = { algo, asn1_len(&aaa) ? aaa.data[0] : def_pinpol, asn1_len(&aab) ? aab.data[0] : TOUCHPOLICY_ALWAYS, ORIGIN_IMPORTED }; + uint8_t meta[] = {algo, asn1_len(&aaa) ? aaa.data[0] : def_pinpol, asn1_len(&aab) ? aab.data[0] : TOUCHPOLICY_ALWAYS, ORIGIN_IMPORTED}; meta_add(key_ref, meta, sizeof(meta)); return SW_OK(); } -#define INS_VERIFY 0x20 -#define INS_VERSION 0xFD -#define INS_SELECT 0xA4 -#define INS_YK_SERIAL 0xF8 -#define INS_VERIFY 0x20 -#define INS_GET_DATA 0xCB -#define INS_GET_METADATA 0xF7 -#define INS_AUTHENTICATE 0x87 -#define INS_ASYM_KEYGEN 0x47 -#define INS_PUT_DATA 0xDB -#define INS_SET_MGMKEY 0xFF -#define INS_MOVE_KEY 0xF6 -#define INS_CHANGE_PIN 0x24 -#define INS_RESET_RETRY 0x2C -#define INS_SET_RETRIES 0xFA -#define INS_RESET 0xFB -#define INS_ATTESTATION 0xF9 -#define INS_IMPORT_ASYM 0xFE +#define INS_VERIFY 0x20 +#define INS_VERSION 0xFD +#define INS_SELECT 0xA4 +#define INS_YK_SERIAL 0xF8 +#define INS_VERIFY 0x20 +#define INS_GET_DATA 0xCB +#define INS_GET_METADATA 0xF7 +#define INS_AUTHENTICATE 0x87 +#define INS_ASYM_KEYGEN 0x47 +#define INS_PUT_DATA 0xDB +#define INS_SET_MGMKEY 0xFF +#define INS_MOVE_KEY 0xF6 +#define INS_CHANGE_PIN 0x24 +#define INS_RESET_RETRY 0x2C +#define INS_SET_RETRIES 0xFA +#define INS_RESET 0xFB +#define INS_ATTESTATION 0xF9 +#define INS_IMPORT_ASYM 0xFE static const cmd_t cmds[] = { - { INS_VERSION, cmd_version }, - { INS_SELECT, cmd_select }, - { INS_YK_SERIAL, cmd_get_serial }, - { INS_VERIFY, cmd_verify }, - { INS_GET_DATA, cmd_get_data }, - { INS_GET_METADATA, cmd_get_metadata }, - { INS_AUTHENTICATE, cmd_authenticate }, - { INS_ASYM_KEYGEN, cmd_asym_keygen }, - { INS_PUT_DATA, cmd_put_data }, - { INS_SET_MGMKEY, cmd_set_mgmkey }, - { INS_MOVE_KEY, cmd_move_key }, - { INS_CHANGE_PIN, cmd_change_pin }, - { INS_RESET_RETRY, cmd_reset_retry }, - { INS_SET_RETRIES, cmd_set_retries }, - { INS_RESET, cmd_reset }, - { INS_ATTESTATION, cmd_attestation }, - { INS_IMPORT_ASYM, cmd_import_asym }, - { 0x00, 0x0 } -}; + {INS_VERSION, cmd_version}, + {INS_SELECT, cmd_select}, + {INS_YK_SERIAL, cmd_get_serial}, + {INS_VERIFY, cmd_verify}, + {INS_GET_DATA, cmd_get_data}, + {INS_GET_METADATA, cmd_get_metadata}, + {INS_AUTHENTICATE, cmd_authenticate}, + {INS_ASYM_KEYGEN, cmd_asym_keygen}, + {INS_PUT_DATA, cmd_put_data}, + {INS_SET_MGMKEY, cmd_set_mgmkey}, + {INS_MOVE_KEY, cmd_move_key}, + {INS_CHANGE_PIN, cmd_change_pin}, + {INS_RESET_RETRY, cmd_reset_retry}, + {INS_SET_RETRIES, cmd_set_retries}, + {INS_RESET, cmd_reset}, + {INS_ATTESTATION, cmd_attestation}, + {INS_IMPORT_ASYM, cmd_import_asym}, + {0x00, 0x0}}; -int piv_process_apdu() { +int piv_process_apdu() +{ sm_unwrap(); - for (const cmd_t *cmd = cmds; cmd->ins != 0x00; cmd++) { - if (cmd->ins == INS(apdu)) { + for (const cmd_t *cmd = cmds; cmd->ins != 0x00; cmd++) + { + if (cmd->ins == INS(apdu)) + { int r = cmd->cmd_handler(); sm_wrap(); return r;