Adding RSA and ECDH decrypt.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
This commit is contained in:
@@ -24,6 +24,7 @@
|
||||
#include "crypto_utils.h"
|
||||
#include "mbedtls/rsa.h"
|
||||
#include "mbedtls/ecdsa.h"
|
||||
#include "mbedtls/ecdh.h"
|
||||
|
||||
bool has_pw1 = 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_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[] = {
|
||||
4,
|
||||
ALGO_ECDH,
|
||||
@@ -395,6 +410,14 @@ static const uint8_t algorithm_attr_x448[] = {
|
||||
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[] = {
|
||||
6,
|
||||
ALGO_RSA,
|
||||
@@ -403,6 +426,14 @@ static const uint8_t algorithm_attr_rsa2k[] = {
|
||||
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[] = {
|
||||
6,
|
||||
ALGO_RSA,
|
||||
@@ -459,6 +490,14 @@ static const uint8_t algorithm_attr_cv25519[] = {
|
||||
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) {
|
||||
res_APDU[res_APDU_size++] = tag & 0xff;
|
||||
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_len = file_read_uint16(algo_ef->data);
|
||||
}
|
||||
DEBUG_PAYLOAD(algo,algo_len);
|
||||
if (P1(apdu) == 0x80) { //generate
|
||||
if (algo[0] == ALGO_RSA) {
|
||||
int exponent = 65537, nlen = (algo[1] << 8) | algo[2];
|
||||
@@ -985,11 +1023,19 @@ static int cmd_keypair_gen() {
|
||||
return SW_INCORRECT_P1P2();
|
||||
}
|
||||
|
||||
static int cmd_pso_sig() {
|
||||
if (P1(apdu) != 0x9E || P2(apdu) != 0x9A)
|
||||
static int cmd_pso() {
|
||||
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();
|
||||
int r = CCID_OK;
|
||||
file_t *algo_ef = search_by_fid(EF_ALGO_PRIV1, NULL, SPECIFY_EF);
|
||||
file_t *algo_ef = search_by_fid(algo_fid, NULL, SPECIFY_EF);
|
||||
if (!algo_ef)
|
||||
return SW_FILE_NOT_FOUND();
|
||||
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 = 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)
|
||||
return SW_FILE_NOT_FOUND();
|
||||
int r = CCID_OK;
|
||||
int key_size = file_read_uint16(ef->data);
|
||||
if (algo[0] == ALGO_RSA) {
|
||||
int key_size = file_read_uint16(ef->data);
|
||||
mbedtls_rsa_context ctx;
|
||||
mbedtls_rsa_init(&ctx);
|
||||
r = load_private_key_rsa(&ctx, ef);
|
||||
if (r != CCID_OK)
|
||||
return SW_EXEC_ERROR();
|
||||
mbedtls_md_type_t md = MBEDTLS_MD_NONE;
|
||||
if (memcmp(apdu.cmd_apdu_data, "\x30\x51\x30\x0D\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x01\x05\x00",17))
|
||||
md = MBEDTLS_MD_SHA256;
|
||||
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_SHA384;
|
||||
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_SHA512;
|
||||
uint8_t hash_len = apdu.cmd_apdu_data[18];
|
||||
printf("md %d, hash_len %d\r\n",md,hash_len);
|
||||
if (md == MBEDTLS_MD_SHA256 && hash_len != 32)
|
||||
return SW_WRONG_DATA();
|
||||
else if (md == MBEDTLS_MD_SHA384 && hash_len != 48)
|
||||
return SW_WRONG_DATA();
|
||||
else if (md == MBEDTLS_MD_SHA512 && hash_len != 64)
|
||||
return SW_WRONG_DATA();
|
||||
const uint8_t *hash = apdu.cmd_apdu_data+19;
|
||||
uint8_t *signature = calloc( 1, ctx.len );
|
||||
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);
|
||||
free(signature);
|
||||
mbedtls_rsa_free(&ctx);
|
||||
if (r != 0) {
|
||||
return SW_EXEC_ERROR();
|
||||
if (P1(apdu) == 0x9E && P2(apdu) == 0x9A) {
|
||||
mbedtls_md_type_t md = MBEDTLS_MD_NONE;
|
||||
if (memcmp(apdu.cmd_apdu_data, "\x30\x51\x30\x0D\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x01\x05\x00",17))
|
||||
md = MBEDTLS_MD_SHA256;
|
||||
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_SHA384;
|
||||
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_SHA512;
|
||||
uint8_t hash_len = apdu.cmd_apdu_data[18];
|
||||
if (md == MBEDTLS_MD_SHA256 && hash_len != 32)
|
||||
return SW_WRONG_DATA();
|
||||
else if (md == MBEDTLS_MD_SHA384 && hash_len != 48)
|
||||
return SW_WRONG_DATA();
|
||||
else if (md == MBEDTLS_MD_SHA512 && hash_len != 64)
|
||||
return SW_WRONG_DATA();
|
||||
const uint8_t *hash = apdu.cmd_apdu_data+19;
|
||||
uint8_t *signature = calloc( 1, ctx.len );
|
||||
r = mbedtls_rsa_pkcs1_sign(&ctx, random_gen, NULL, md, hash_len, hash, signature);
|
||||
memcpy(res_APDU, signature, key_size);
|
||||
free(signature);
|
||||
mbedtls_rsa_free(&ctx);
|
||||
if (r != 0) {
|
||||
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) {
|
||||
|
||||
mbedtls_ecdsa_context ctx;
|
||||
mbedtls_ecdsa_init(&ctx);
|
||||
mbedtls_md_type_t md = MBEDTLS_MD_SHA256;
|
||||
if (apdu.cmd_apdu_data_len == 32)
|
||||
md = MBEDTLS_MD_SHA256;
|
||||
else if (apdu.cmd_apdu_data_len == 20)
|
||||
md = MBEDTLS_MD_SHA1;
|
||||
else if (apdu.cmd_apdu_data_len == 28)
|
||||
md = MBEDTLS_MD_SHA224;
|
||||
else if (apdu.cmd_apdu_data_len == 48)
|
||||
md = MBEDTLS_MD_SHA384;
|
||||
else if (apdu.cmd_apdu_data_len == 64)
|
||||
md = MBEDTLS_MD_SHA512;
|
||||
r = load_private_key_ecdsa(&ctx, ef);
|
||||
if (r != CCID_OK)
|
||||
return SW_CONDITIONS_NOT_SATISFIED();
|
||||
size_t olen = 0;
|
||||
uint8_t buf[MBEDTLS_ECDSA_MAX_LEN];
|
||||
mbedtls_mpi ri, si;
|
||||
mbedtls_mpi_init(&ri);
|
||||
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);
|
||||
if (r != 0) {
|
||||
if (P1(apdu) == 0x9E && P2(apdu) == 0x9A) {
|
||||
mbedtls_ecdsa_context ctx;
|
||||
mbedtls_ecdsa_init(&ctx);
|
||||
mbedtls_md_type_t md = MBEDTLS_MD_SHA256;
|
||||
if (apdu.cmd_apdu_data_len == 32)
|
||||
md = MBEDTLS_MD_SHA256;
|
||||
else if (apdu.cmd_apdu_data_len == 20)
|
||||
md = MBEDTLS_MD_SHA1;
|
||||
else if (apdu.cmd_apdu_data_len == 28)
|
||||
md = MBEDTLS_MD_SHA224;
|
||||
else if (apdu.cmd_apdu_data_len == 48)
|
||||
md = MBEDTLS_MD_SHA384;
|
||||
else if (apdu.cmd_apdu_data_len == 64)
|
||||
md = MBEDTLS_MD_SHA512;
|
||||
r = load_private_key_ecdsa(&ctx, ef);
|
||||
if (r != CCID_OK)
|
||||
return SW_CONDITIONS_NOT_SATISFIED();
|
||||
size_t olen = 0;
|
||||
uint8_t buf[MBEDTLS_ECDSA_MAX_LEN];
|
||||
mbedtls_mpi ri, si;
|
||||
mbedtls_mpi_init(&ri);
|
||||
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);
|
||||
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(&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(&si);
|
||||
mbedtls_ecdsa_free(&ctx);
|
||||
else if (P1(apdu) == 0x80 && P2(apdu) == 0x86) {
|
||||
mbedtls_ecdh_context ctx;
|
||||
uint8_t kdata[67];
|
||||
uint8_t *data = apdu.cmd_apdu_data;
|
||||
if (*data++ != 0xA6)
|
||||
return SW_WRONG_DATA();
|
||||
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();
|
||||
}
|
||||
@@ -1108,11 +1219,11 @@ typedef struct cmd
|
||||
|
||||
#define INS_VERIFY 0x20
|
||||
#define INS_CHANGE_PIN 0x24
|
||||
#define INS_PSO_SIG 0x2A
|
||||
#define INS_PSO 0x2A
|
||||
#define INS_RESET_RETRY 0x2C
|
||||
#define INS_ACTIVATE_FILE 0x44
|
||||
#define INS_CHALLENGE 0x84
|
||||
#define INS_KEYPAIR_GEN 0x47
|
||||
#define INS_CHALLENGE 0x84
|
||||
#define INS_SELECT 0xA4
|
||||
#define INS_GET_DATA 0xCA
|
||||
#define INS_PUT_DATA 0xDA
|
||||
@@ -1126,7 +1237,7 @@ static const cmd_t cmds[] = {
|
||||
{ INS_CHANGE_PIN, cmd_change_pin },
|
||||
{ INS_RESET_RETRY, cmd_reset_retry },
|
||||
{ INS_KEYPAIR_GEN, cmd_keypair_gen },
|
||||
{ INS_PSO_SIG, cmd_pso_sig },
|
||||
{ INS_PSO, cmd_pso },
|
||||
{ INS_TERMINATE_DF, cmd_terminate_df },
|
||||
{ INS_ACTIVATE_FILE, cmd_activate_file },
|
||||
{ INS_CHALLENGE, cmd_challenge },
|
||||
|
||||
Reference in New Issue
Block a user