diff --git a/src/openpgp/piv.c b/src/openpgp/piv.c index 9151af2..5f9cf18 100644 --- a/src/openpgp/piv.c +++ b/src/openpgp/piv.c @@ -395,20 +395,103 @@ static int cmd_get_metadata() { return SW_INCORRECT_P1P2(); } uint8_t *meta = NULL; - int meta_len = 0; - if ((meta_len = meta_find(P2(apdu), &meta)) <= 0) { - return SW_REFERENCE_NOT_FOUND(); + uint16_t key_ref = P2(apdu); + if (key_ref == 0x80) { + key_ref = EF_PIV_PIN; + } + 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)) { + return SW_MEMORY_FAILURE(); + } + if (key_ref != EF_PIV_PIN && key_ref != EF_PIV_PUK) { + int meta_len = 0; + if ((meta_len = meta_find(key_ref, &meta)) <= 0) { + return SW_REFERENCE_NOT_FOUND(); + } + res_APDU[res_APDU_size++] = 0x1; + res_APDU[res_APDU_size++] = 1; + res_APDU[res_APDU_size++] = meta[0]; + res_APDU[res_APDU_size++] = 0x2; + res_APDU[res_APDU_size++] = 2; + res_APDU[res_APDU_size++] = meta[1]; + res_APDU[res_APDU_size++] = meta[2]; + 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_ECCP256 || meta[0] == PIV_ALGO_ECCP384) { + res_APDU[res_APDU_size++] = 0x4; + if (meta[0] == PIV_ALGO_RSA1024 || meta[0] == PIV_ALGO_RSA2048) { + mbedtls_rsa_context ctx; + mbedtls_rsa_init(&ctx); + int r = load_private_key_rsa(&ctx, ef_key, false); + if (r != CCID_OK) { + mbedtls_rsa_free(&ctx); + return SW_EXEC_ERROR(); + } + res_APDU[res_APDU_size++] = 0x81; + res_APDU[res_APDU_size++] = 0x82; + put_uint16_t(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; + res_APDU[res_APDU_size++] = mbedtls_mpi_size(&ctx.E) & 0xff; + mbedtls_mpi_write_binary(&ctx.E, res_APDU + res_APDU_size, mbedtls_mpi_size(&ctx.E)); + res_APDU_size += mbedtls_mpi_size(&ctx.E); + mbedtls_rsa_free(&ctx); + } + else { + mbedtls_ecdsa_context ctx; + mbedtls_ecdsa_init(&ctx); + int r = load_private_key_ecdsa(&ctx, ef_key, false); + if (r != CCID_OK) { + mbedtls_ecdsa_free(&ctx); + return SW_EXEC_ERROR(); + } + uint8_t pt[MBEDTLS_ECP_MAX_PT_LEN]; + size_t plen = 0; + 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) { + res_APDU[res_APDU_size++] = 0x81; + } + res_APDU[res_APDU_size++] = plen; + memcpy(res_APDU + res_APDU_size, pt, plen); + res_APDU_size += plen; + } + } + } + if (key_ref == EF_PIV_PIN || key_ref == EF_PIV_PUK || key_ref == EF_PIV_KEY_MANAGEMENT) { + uint8_t dhash[32]; + int32_t eq = false; + 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) { + 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_MANAGEMENT) { + 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) { + file_t *pw_status; + 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)); + res_APDU[res_APDU_size++] = 0x6; + res_APDU[res_APDU_size++] = 1; + res_APDU[res_APDU_size++] = retries; + } } - res_APDU[res_APDU_size++] = 0x1; - res_APDU[res_APDU_size++] = 1; - res_APDU[res_APDU_size++] = meta[0]; - res_APDU[res_APDU_size++] = 0x2; - res_APDU[res_APDU_size++] = 2; - res_APDU[res_APDU_size++] = meta[1]; - res_APDU[res_APDU_size++] = meta[2]; - res_APDU[res_APDU_size++] = 0x3; - res_APDU[res_APDU_size++] = 1; - res_APDU[res_APDU_size++] = meta[3]; return SW_OK(); } uint8_t challenge[16]; @@ -649,14 +732,17 @@ static int cmd_asym_keygen() { if (!asn1_find_tag(&ctxi, 0xAC, &aac) || asn1_len(&aac) == 0) { return SW_WRONG_DATA(); } - asn1_ctx_t a80 = {0}, a81 = {0}; + asn1_ctx_t a80 = {0}, aaa = {0}, aab = {0}; asn1_find_tag(&aac, 0x80, &a80); - asn1_find_tag(&aac, 0x81, &a81); + asn1_find_tag(&aac, 0xAA, &aaa); + asn1_find_tag(&aac, 0xAB, &aab); if (asn1_len(&a80) == 0) { return SW_WRONG_DATA(); } 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); uint8_t index = 0; @@ -696,6 +782,9 @@ static int cmd_asym_keygen() { } else if (a80.data[0] == PIV_ALGO_X25519) { } + uint8_t meta[] = {a80.data[0], asn1_len(&aaa) ? aaa.data[0] : PINPOLICY_ALWAYS, asn1_len(&aab) ? aab.data[0] : TOUCHPOLICY_ALWAYS, ORIGIN_GENERATED}; + meta_add(key_ref, meta, sizeof(meta)); + low_flash_available(); return SW_OK(); }