Adding RSA and ECDH decrypt.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
This commit is contained in:
Pol Henarejos
2022-04-23 23:35:35 +02:00
parent 7d4024a2cb
commit 7094767500

View File

@@ -24,6 +24,7 @@
#include "crypto_utils.h" #include "crypto_utils.h"
#include "mbedtls/rsa.h" #include "mbedtls/rsa.h"
#include "mbedtls/ecdsa.h" #include "mbedtls/ecdsa.h"
#include "mbedtls/ecdh.h"
bool has_pw1 = false; bool has_pw1 = false;
bool has_pw3 = false; bool has_pw3 = false;
@@ -388,6 +389,20 @@ int parse_pw_status(const file_t *f, int mode) {
#define ALGO_AES_192 0x72 #define ALGO_AES_192 0x72
#define ALGO_AES_256 0x74 #define ALGO_AES_256 0x74
#define ALGO_RSA_1K 0
#define ALGO_RSA_2k 1
#define ALGO_RSA_3K 2
#define ALGO_RSA_4K 3
#define ALGO_X448 4
#define ALGO_P256K1 5
#define ALGO_P256R1 6
#define ALGO_P384R1 7
#define ALGO_P521R1 8
#define ALGO_BP256R1 9
#define ALGO_BP384R1 10
#define ALGO_BP512R1 11
#define ALGO_CV22519 12
static const uint8_t algorithm_attr_x448[] = { static const uint8_t algorithm_attr_x448[] = {
4, 4,
ALGO_ECDH, ALGO_ECDH,
@@ -395,6 +410,14 @@ static const uint8_t algorithm_attr_x448[] = {
0x2b, 0x65, 0x6f 0x2b, 0x65, 0x6f
}; };
static const uint8_t algorithm_attr_rsa1k[] = {
6,
ALGO_RSA,
0x04, 0x00, /* Length modulus (in bit): 2048 */
0x00, 0x20, /* Length exponent (in bit): 32 */
0x00 /* 0: Acceptable format is: P and Q */
};
static const uint8_t algorithm_attr_rsa2k[] = { static const uint8_t algorithm_attr_rsa2k[] = {
6, 6,
ALGO_RSA, ALGO_RSA,
@@ -403,6 +426,14 @@ static const uint8_t algorithm_attr_rsa2k[] = {
0x00 /* 0: Acceptable format is: P and Q */ 0x00 /* 0: Acceptable format is: P and Q */
}; };
static const uint8_t algorithm_attr_rsa3k[] = {
6,
ALGO_RSA,
0x0C, 0x00, /* Length modulus (in bit): 2048 */
0x00, 0x20, /* Length exponent (in bit): 32 */
0x00 /* 0: Acceptable format is: P and Q */
};
static const uint8_t algorithm_attr_rsa4k[] = { static const uint8_t algorithm_attr_rsa4k[] = {
6, 6,
ALGO_RSA, ALGO_RSA,
@@ -459,6 +490,14 @@ static const uint8_t algorithm_attr_cv25519[] = {
0x2b, 0x06, 0x01, 0x04, 0x01, 0x97, 0x55, 0x01, 0x05, 0x01 0x2b, 0x06, 0x01, 0x04, 0x01, 0x97, 0x55, 0x01, 0x05, 0x01
}; };
static const uint8_t *algorithm_attr[] = {
algorithm_attr_rsa1k, algorithm_attr_rsa2k, algorithm_attr_rsa3k, algorithm_attr_rsa4k,
algorithm_attr_x448, algorithm_attr_p256k1,
algorithm_attr_p256r1, algorithm_attr_p384r1, algorithm_attr_p521r1,
algorithm_attr_bp256r1, algorithm_attr_bp384r1, algorithm_attr_bp512r1,
algorithm_attr_cv25519
};
int parse_algo(const uint8_t *algo, uint16_t tag) { int parse_algo(const uint8_t *algo, uint16_t tag) {
res_APDU[res_APDU_size++] = tag & 0xff; res_APDU[res_APDU_size++] = tag & 0xff;
memcpy(res_APDU+res_APDU_size, algo, algo[0]+1); memcpy(res_APDU+res_APDU_size, algo, algo[0]+1);
@@ -921,7 +960,6 @@ static int cmd_keypair_gen() {
algo = file_read(algo_ef->data+2); algo = file_read(algo_ef->data+2);
algo_len = file_read_uint16(algo_ef->data); algo_len = file_read_uint16(algo_ef->data);
} }
DEBUG_PAYLOAD(algo,algo_len);
if (P1(apdu) == 0x80) { //generate if (P1(apdu) == 0x80) { //generate
if (algo[0] == ALGO_RSA) { if (algo[0] == ALGO_RSA) {
int exponent = 65537, nlen = (algo[1] << 8) | algo[2]; int exponent = 65537, nlen = (algo[1] << 8) | algo[2];
@@ -985,11 +1023,19 @@ static int cmd_keypair_gen() {
return SW_INCORRECT_P1P2(); return SW_INCORRECT_P1P2();
} }
static int cmd_pso_sig() { static int cmd_pso() {
if (P1(apdu) != 0x9E || P2(apdu) != 0x9A) uint16_t algo_fid = 0x0, pk_fid = 0x0;
if (P1(apdu) == 0x9E && P2(apdu) == 0x9A) {
algo_fid = EF_ALGO_PRIV1;
pk_fid = EF_PK_SIG;
}
else if (P1(apdu) == 0x80 && P2(apdu) == 0x86) {
algo_fid = EF_ALGO_PRIV2;
pk_fid = EF_PK_DEC;
}
else
return SW_INCORRECT_P1P2(); return SW_INCORRECT_P1P2();
int r = CCID_OK; file_t *algo_ef = search_by_fid(algo_fid, NULL, SPECIFY_EF);
file_t *algo_ef = search_by_fid(EF_ALGO_PRIV1, NULL, SPECIFY_EF);
if (!algo_ef) if (!algo_ef)
return SW_FILE_NOT_FOUND(); return SW_FILE_NOT_FOUND();
const uint8_t *algo = algorithm_attr_rsa2k+1; const uint8_t *algo = algorithm_attr_rsa2k+1;
@@ -998,81 +1044,146 @@ static int cmd_pso_sig() {
algo_len = file_read_uint16(algo_ef->data); algo_len = file_read_uint16(algo_ef->data);
algo = file_read(algo_ef->data+2); algo = file_read(algo_ef->data+2);
} }
file_t *ef = search_by_fid(EF_PK_SIG, NULL, SPECIFY_EF); file_t *ef = search_by_fid(pk_fid, NULL, SPECIFY_EF);
if (!ef) if (!ef)
return SW_FILE_NOT_FOUND(); return SW_FILE_NOT_FOUND();
int r = CCID_OK;
int key_size = file_read_uint16(ef->data);
if (algo[0] == ALGO_RSA) { if (algo[0] == ALGO_RSA) {
int key_size = file_read_uint16(ef->data);
mbedtls_rsa_context ctx; mbedtls_rsa_context ctx;
mbedtls_rsa_init(&ctx); mbedtls_rsa_init(&ctx);
r = load_private_key_rsa(&ctx, ef); r = load_private_key_rsa(&ctx, ef);
if (r != CCID_OK) if (r != CCID_OK)
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
mbedtls_md_type_t md = MBEDTLS_MD_NONE; if (P1(apdu) == 0x9E && P2(apdu) == 0x9A) {
if (memcmp(apdu.cmd_apdu_data, "\x30\x51\x30\x0D\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x01\x05\x00",17)) mbedtls_md_type_t md = MBEDTLS_MD_NONE;
md = MBEDTLS_MD_SHA256; if (memcmp(apdu.cmd_apdu_data, "\x30\x51\x30\x0D\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x01\x05\x00",17))
else if (memcmp(apdu.cmd_apdu_data, "\x30\x51\x30\x0D\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x02\x05\x00",17)) md = MBEDTLS_MD_SHA256;
md = MBEDTLS_MD_SHA384; else if (memcmp(apdu.cmd_apdu_data, "\x30\x51\x30\x0D\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x02\x05\x00",17))
else if (memcmp(apdu.cmd_apdu_data, "\x30\x51\x30\x0D\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x03\x05\x00",17)) md = MBEDTLS_MD_SHA384;
md = MBEDTLS_MD_SHA512; else if (memcmp(apdu.cmd_apdu_data, "\x30\x51\x30\x0D\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x03\x05\x00",17))
uint8_t hash_len = apdu.cmd_apdu_data[18]; md = MBEDTLS_MD_SHA512;
printf("md %d, hash_len %d\r\n",md,hash_len); uint8_t hash_len = apdu.cmd_apdu_data[18];
if (md == MBEDTLS_MD_SHA256 && hash_len != 32) if (md == MBEDTLS_MD_SHA256 && hash_len != 32)
return SW_WRONG_DATA(); return SW_WRONG_DATA();
else if (md == MBEDTLS_MD_SHA384 && hash_len != 48) else if (md == MBEDTLS_MD_SHA384 && hash_len != 48)
return SW_WRONG_DATA(); return SW_WRONG_DATA();
else if (md == MBEDTLS_MD_SHA512 && hash_len != 64) else if (md == MBEDTLS_MD_SHA512 && hash_len != 64)
return SW_WRONG_DATA(); return SW_WRONG_DATA();
const uint8_t *hash = apdu.cmd_apdu_data+19; const uint8_t *hash = apdu.cmd_apdu_data+19;
uint8_t *signature = calloc( 1, ctx.len ); uint8_t *signature = calloc( 1, ctx.len );
r = mbedtls_rsa_pkcs1_sign(&ctx, random_gen, NULL, md, hash_len, hash, signature); r = mbedtls_rsa_pkcs1_sign(&ctx, random_gen, NULL, md, hash_len, hash, signature);
printf("sign r %d\r\n",r); memcpy(res_APDU, signature, key_size);
memcpy(res_APDU, signature, key_size); free(signature);
free(signature); mbedtls_rsa_free(&ctx);
mbedtls_rsa_free(&ctx); if (r != 0) {
if (r != 0) { return SW_EXEC_ERROR();
return SW_EXEC_ERROR(); }
res_APDU_size = key_size;
//apdu.expected_res_size = key_size;
}
else if (P1(apdu) == 0x80 && P2(apdu) == 0x86) {
if (apdu.cmd_apdu_data_len < key_size) //needs padding
memset(apdu.cmd_apdu_data+apdu.cmd_apdu_data_len, 0, key_size-apdu.cmd_apdu_data_len);
size_t olen = 0;
r = mbedtls_rsa_pkcs1_decrypt(&ctx, random_gen, NULL, &olen, apdu.cmd_apdu_data+1, res_APDU, key_size);
if (r != 0) {
mbedtls_rsa_free(&ctx);
return SW_EXEC_ERROR();
}
res_APDU_size = olen;
mbedtls_rsa_free(&ctx);
} }
res_APDU_size = key_size;
//apdu.expected_res_size = key_size;
} }
else if (algo[0] == ALGO_ECDH || algo[0] == ALGO_ECDSA) { else if (algo[0] == ALGO_ECDH || algo[0] == ALGO_ECDSA) {
if (P1(apdu) == 0x9E && P2(apdu) == 0x9A) {
mbedtls_ecdsa_context ctx; mbedtls_ecdsa_context ctx;
mbedtls_ecdsa_init(&ctx); mbedtls_ecdsa_init(&ctx);
mbedtls_md_type_t md = MBEDTLS_MD_SHA256; mbedtls_md_type_t md = MBEDTLS_MD_SHA256;
if (apdu.cmd_apdu_data_len == 32) if (apdu.cmd_apdu_data_len == 32)
md = MBEDTLS_MD_SHA256; md = MBEDTLS_MD_SHA256;
else if (apdu.cmd_apdu_data_len == 20) else if (apdu.cmd_apdu_data_len == 20)
md = MBEDTLS_MD_SHA1; md = MBEDTLS_MD_SHA1;
else if (apdu.cmd_apdu_data_len == 28) else if (apdu.cmd_apdu_data_len == 28)
md = MBEDTLS_MD_SHA224; md = MBEDTLS_MD_SHA224;
else if (apdu.cmd_apdu_data_len == 48) else if (apdu.cmd_apdu_data_len == 48)
md = MBEDTLS_MD_SHA384; md = MBEDTLS_MD_SHA384;
else if (apdu.cmd_apdu_data_len == 64) else if (apdu.cmd_apdu_data_len == 64)
md = MBEDTLS_MD_SHA512; md = MBEDTLS_MD_SHA512;
r = load_private_key_ecdsa(&ctx, ef); r = load_private_key_ecdsa(&ctx, ef);
if (r != CCID_OK) if (r != CCID_OK)
return SW_CONDITIONS_NOT_SATISFIED(); return SW_CONDITIONS_NOT_SATISFIED();
size_t olen = 0; size_t olen = 0;
uint8_t buf[MBEDTLS_ECDSA_MAX_LEN]; uint8_t buf[MBEDTLS_ECDSA_MAX_LEN];
mbedtls_mpi ri, si; mbedtls_mpi ri, si;
mbedtls_mpi_init(&ri); mbedtls_mpi_init(&ri);
mbedtls_mpi_init(&si); mbedtls_mpi_init(&si);
r = mbedtls_ecdsa_sign(&ctx.grp, &ri, &si, &ctx.d, apdu.cmd_apdu_data, apdu.cmd_apdu_data_len, random_gen, NULL); r = mbedtls_ecdsa_sign(&ctx.grp, &ri, &si, &ctx.d, apdu.cmd_apdu_data, apdu.cmd_apdu_data_len, random_gen, NULL);
if (r != 0) { if (r != 0) {
mbedtls_mpi_free(&ri);
mbedtls_mpi_free(&si);
mbedtls_ecdsa_free(&ctx);
return SW_EXEC_ERROR();
}
mbedtls_mpi_write_binary(&ri, res_APDU, mbedtls_mpi_size(&ri));
res_APDU_size = mbedtls_mpi_size(&ri);
mbedtls_mpi_write_binary(&si, res_APDU+res_APDU_size, mbedtls_mpi_size(&si));
res_APDU_size += mbedtls_mpi_size(&si);
mbedtls_mpi_free(&ri); mbedtls_mpi_free(&ri);
mbedtls_mpi_free(&si); mbedtls_mpi_free(&si);
mbedtls_ecdsa_free(&ctx); mbedtls_ecdsa_free(&ctx);
return SW_EXEC_ERROR();
} }
mbedtls_mpi_write_binary(&ri, res_APDU, mbedtls_mpi_size(&ri)); else if (P1(apdu) == 0x80 && P2(apdu) == 0x86) {
res_APDU_size = mbedtls_mpi_size(&ri); mbedtls_ecdh_context ctx;
mbedtls_mpi_write_binary(&si, res_APDU+res_APDU_size, mbedtls_mpi_size(&si)); uint8_t kdata[67];
res_APDU_size += mbedtls_mpi_size(&si); uint8_t *data = apdu.cmd_apdu_data;
mbedtls_mpi_free(&ri); if (*data++ != 0xA6)
mbedtls_mpi_free(&si); return SW_WRONG_DATA();
mbedtls_ecdsa_free(&ctx); if (*data == 0x82) data += 3;
else if (*data == 0x81) data += 2;
else data++;
if (*data != 0x7f || *(data+1) != 0x49)
return SW_WRONG_DATA();
data += 2;
if (*data == 0x82) data += 3;
else if (*data == 0x81) data += 2;
else data++;
if (*data++ != 0x86)
return SW_WRONG_DATA();
uint16_t dlen = 0;
if (*data == 0x82) { dlen = (*(data+1) << 8) | *(data+2); data += 3; }
else if (*data == 0x81) { dlen = *(data+1); data += 2; }
else { dlen = *data++; }
if (dlen != 2*key_size-1)
return SW_WRONG_LENGTH();
memcpy(kdata, file_read(ef->data+2), key_size);
mbedtls_ecdh_init(&ctx);
mbedtls_ecp_group_id gid = kdata[0];
r = mbedtls_ecdh_setup(&ctx, gid);
if (r != 0) {
mbedtls_ecdh_free(&ctx);
return SW_DATA_INVALID();
}
r = mbedtls_mpi_read_binary(&ctx.ctx.mbed_ecdh.d, kdata+1, key_size-1);
if (r != 0) {
mbedtls_ecdh_free(&ctx);
return SW_DATA_INVALID();
}
r = mbedtls_ecdh_read_public(&ctx, data-1, dlen+1);
if (r != 0) {
mbedtls_ecdh_free(&ctx);
return SW_DATA_INVALID();
}
size_t olen = 0;
res_APDU[0] = 0x04;
r = mbedtls_ecdh_calc_secret(&ctx, &olen, res_APDU+1, MBEDTLS_ECP_MAX_BYTES, random_gen, NULL);
if (r != 0) {
mbedtls_ecdh_free(&ctx);
return SW_EXEC_ERROR();
}
res_APDU_size = olen+1;
mbedtls_ecdh_free(&ctx);
}
} }
return SW_OK(); return SW_OK();
} }
@@ -1108,11 +1219,11 @@ typedef struct cmd
#define INS_VERIFY 0x20 #define INS_VERIFY 0x20
#define INS_CHANGE_PIN 0x24 #define INS_CHANGE_PIN 0x24
#define INS_PSO_SIG 0x2A #define INS_PSO 0x2A
#define INS_RESET_RETRY 0x2C #define INS_RESET_RETRY 0x2C
#define INS_ACTIVATE_FILE 0x44 #define INS_ACTIVATE_FILE 0x44
#define INS_CHALLENGE 0x84
#define INS_KEYPAIR_GEN 0x47 #define INS_KEYPAIR_GEN 0x47
#define INS_CHALLENGE 0x84
#define INS_SELECT 0xA4 #define INS_SELECT 0xA4
#define INS_GET_DATA 0xCA #define INS_GET_DATA 0xCA
#define INS_PUT_DATA 0xDA #define INS_PUT_DATA 0xDA
@@ -1126,7 +1237,7 @@ static const cmd_t cmds[] = {
{ INS_CHANGE_PIN, cmd_change_pin }, { INS_CHANGE_PIN, cmd_change_pin },
{ INS_RESET_RETRY, cmd_reset_retry }, { INS_RESET_RETRY, cmd_reset_retry },
{ INS_KEYPAIR_GEN, cmd_keypair_gen }, { INS_KEYPAIR_GEN, cmd_keypair_gen },
{ INS_PSO_SIG, cmd_pso_sig }, { INS_PSO, cmd_pso },
{ INS_TERMINATE_DF, cmd_terminate_df }, { INS_TERMINATE_DF, cmd_terminate_df },
{ INS_ACTIVATE_FILE, cmd_activate_file }, { INS_ACTIVATE_FILE, cmd_activate_file },
{ INS_CHALLENGE, cmd_challenge }, { INS_CHALLENGE, cmd_challenge },