mirror of
https://github.com/polhenarejos/pico-openpgp.git
synced 2026-08-28 15:41:00 +01:00
fix(openpgp): harden stored data and key handling
This commit is contained in:
@@ -24,7 +24,9 @@ int cmd_get_data(void) {
|
||||
if (apdu.nc > 0) {
|
||||
return SW_WRONG_LENGTH();
|
||||
}
|
||||
res_APDU_size = 0;
|
||||
uint16_t fid = (P1(apdu) << 8) | P2(apdu);
|
||||
uint16_t requested_fid = fid;
|
||||
file_t *ef;
|
||||
if (!(ef = file_search_by_fid(fid, NULL, SPECIFY_EF))) {
|
||||
return SW_REFERENCE_NOT_FOUND();
|
||||
@@ -42,18 +44,28 @@ int cmd_get_data(void) {
|
||||
else if (!file_authenticate_action(ef, ACL_OP_READ_SEARCH)) {
|
||||
return SW_SECURITY_STATUS_NOT_SATISFIED();
|
||||
}
|
||||
if (currentEF && currentEF->fid == fid) { // previously selected same EF
|
||||
if (fid == EF_CH_CERT) {
|
||||
if (currentEF && currentEF->fid >= EF_CH_1 && currentEF->fid <= EF_CH_3) {
|
||||
ef = currentEF;
|
||||
}
|
||||
else if (!(ef = file_search_by_fid(EF_CH_1, NULL, SPECIFY_EF))) {
|
||||
return SW_REFERENCE_NOT_FOUND();
|
||||
}
|
||||
}
|
||||
else if (currentEF && currentEF->fid == fid) { // previously selected same EF
|
||||
ef = currentEF;
|
||||
}
|
||||
else {
|
||||
select_file(ef);
|
||||
}
|
||||
if (ef->data) {
|
||||
if (fid == EF_PW_STATUS || fid == EF_HIST_BYTES || fid == EF_FULL_AID || fid == EF_SEC_TPL) {
|
||||
if (requested_fid == EF_PW_STATUS || requested_fid == EF_HIST_BYTES ||
|
||||
requested_fid == EF_FULL_AID || requested_fid == EF_SEC_TPL) {
|
||||
is_gpg = true;
|
||||
}
|
||||
uint16_t fids[] = { 1, fid };
|
||||
uint16_t fids[] = { 1, ef->fid };
|
||||
uint16_t data_len = parse_do(fids, 1);
|
||||
data_len = MIN(data_len, res_APDU_size);
|
||||
if (!(ef->type & FILE_DATA_FLASH)) {
|
||||
uint8_t *p = NULL;
|
||||
uint16_t tg = 0;
|
||||
@@ -86,6 +98,8 @@ int cmd_get_data(void) {
|
||||
if (data_len >= 256) {
|
||||
off++;
|
||||
}
|
||||
data_len = MIN(data_len, OPENPGP_MAX_RESPONSE_SIZE - off);
|
||||
res_APDU_size = data_len;
|
||||
memmove(res_APDU + off, res_APDU, data_len);
|
||||
off = 0;
|
||||
if (P1(apdu) > 0x0) {
|
||||
|
||||
@@ -142,8 +142,14 @@ int cmd_import_data(void) {
|
||||
algo = file_get_data(algo_ef);
|
||||
algo_len = file_get_size(algo_ef);
|
||||
}
|
||||
if (algo_len == 0 || algo_len > OPENPGP_MAX_ALGORITHM_ATTR_SIZE) {
|
||||
return SW_WRONG_DATA();
|
||||
}
|
||||
int r = 0;
|
||||
if (algo[0] == ALGO_RSA) {
|
||||
if (algo_len < 3) {
|
||||
return SW_WRONG_DATA();
|
||||
}
|
||||
mbedtls_rsa_context rsa;
|
||||
if (p[0] == NULL || len[0] == 0 || p[1] == NULL || len[1] == 0 || p[2] == NULL ||
|
||||
len[2] == 0) {
|
||||
|
||||
@@ -32,12 +32,17 @@ int cmd_internal_aut(void) {
|
||||
const uint8_t *algo = algorithm_attr_rsa2k + 1;
|
||||
if (algo_ef && algo_ef->data) {
|
||||
algo = file_get_data(algo_ef);
|
||||
uint16_t algo_len = file_get_size(algo_ef);
|
||||
if (algo_len == 0 || algo_len > OPENPGP_MAX_ALGORITHM_ATTR_SIZE) {
|
||||
return SW_WRONG_DATA();
|
||||
}
|
||||
}
|
||||
file_t *ef = file_search_by_fid(pk_aut, NULL, SPECIFY_EF);
|
||||
if (!ef) {
|
||||
return SW_REFERENCE_NOT_FOUND();
|
||||
}
|
||||
if (wait_button_pressed_fid(EF_UIF_AUT) == true) {
|
||||
uint16_t uif_fid = pk_aut == EF_PK_DEC ? EF_UIF_DEC : EF_UIF_AUT;
|
||||
if (wait_button_pressed_fid(uif_fid) == true) {
|
||||
return SW_SECURE_MESSAGE_EXEC_ERROR();
|
||||
}
|
||||
int r = PICOKEYS_OK;
|
||||
|
||||
@@ -56,8 +56,14 @@ int cmd_keypair_gen(void) {
|
||||
algo = file_get_data(algo_ef);
|
||||
algo_len = file_get_size(algo_ef);
|
||||
}
|
||||
if (algo_len == 0 || algo_len > OPENPGP_MAX_ALGORITHM_ATTR_SIZE) {
|
||||
return SW_WRONG_DATA();
|
||||
}
|
||||
if (P1(apdu) == 0x80) { //generate
|
||||
if (algo[0] == ALGO_RSA) {
|
||||
if (algo_len < 3) {
|
||||
return SW_WRONG_DATA();
|
||||
}
|
||||
int exponent = 65537, nlen = (algo[1] << 8) | algo[2];
|
||||
printf("KEYPAIR RSA %d\r\n", nlen);
|
||||
//if (nlen != 2048 && nlen != 4096)
|
||||
@@ -117,9 +123,10 @@ int cmd_keypair_gen(void) {
|
||||
uint8_t key_size = 32;
|
||||
memcpy(aes_key, random_bytes_get(key_size), key_size);
|
||||
r = store_keys(aes_key, ALGO_AES_256, EF_AES_KEY, true);
|
||||
/* if storing the key fails, we silently continue */
|
||||
//if (r != PICOKEYS_OK)
|
||||
// return SW_EXEC_ERROR();
|
||||
mbedtls_platform_zeroize(aes_key, sizeof(aes_key));
|
||||
if (r != PICOKEYS_OK) {
|
||||
return SW_EXEC_ERROR();
|
||||
}
|
||||
}
|
||||
flash_commit();
|
||||
return SW_OK();
|
||||
@@ -129,7 +136,7 @@ int cmd_keypair_gen(void) {
|
||||
if (!file_has_data(ef)) {
|
||||
return SW_REFERENCE_NOT_FOUND();
|
||||
}
|
||||
res_APDU_size = file_get_size(ef);
|
||||
res_APDU_size = MIN(file_get_size(ef), OPENPGP_MAX_RESPONSE_SIZE);
|
||||
memcpy(res_APDU, file_get_data(ef), res_APDU_size);
|
||||
return SW_OK();
|
||||
}
|
||||
|
||||
+54
-14
@@ -27,6 +27,7 @@
|
||||
|
||||
int cmd_pso(void) {
|
||||
uint16_t algo_fid = 0x0, pk_fid = 0x0;
|
||||
uint16_t uif_fid = 0x0;
|
||||
bool is_aes = false;
|
||||
if (P1(apdu) == 0x9E && P2(apdu) == 0x9A) {
|
||||
if (!has_pw3 && !has_pw1) {
|
||||
@@ -34,6 +35,7 @@ int cmd_pso(void) {
|
||||
}
|
||||
algo_fid = EF_ALGO_PRIV1;
|
||||
pk_fid = EF_PK_SIG;
|
||||
uif_fid = EF_UIF_SIG;
|
||||
}
|
||||
else if (P1(apdu) == 0x80 && P2(apdu) == 0x86) {
|
||||
if (!has_pw3 && !has_pw2) {
|
||||
@@ -41,6 +43,15 @@ int cmd_pso(void) {
|
||||
}
|
||||
algo_fid = algo_dec;
|
||||
pk_fid = pk_dec;
|
||||
uif_fid = pk_dec == EF_PK_AUT ? EF_UIF_AUT : EF_UIF_DEC;
|
||||
}
|
||||
else if (P1(apdu) == 0x86 && P2(apdu) == 0x80) {
|
||||
if (!has_pw3 && !has_pw2) {
|
||||
return SW_SECURITY_STATUS_NOT_SATISFIED();
|
||||
}
|
||||
algo_fid = algo_dec;
|
||||
pk_fid = pk_dec;
|
||||
uif_fid = pk_dec == EF_PK_AUT ? EF_UIF_AUT : EF_UIF_DEC;
|
||||
}
|
||||
else {
|
||||
return SW_INCORRECT_P1P2();
|
||||
@@ -52,32 +63,41 @@ int cmd_pso(void) {
|
||||
const uint8_t *algo = algorithm_attr_rsa2k + 1;
|
||||
if (algo_ef && algo_ef->data) {
|
||||
algo = file_get_data(algo_ef);
|
||||
}
|
||||
if (apdu.data[0] == 0x2) { //AES PSO?
|
||||
if (((apdu.nc - 1) % 16 == 0 && P1(apdu) == 0x80 && P2(apdu) == 0x86) ||
|
||||
(apdu.nc % 16 == 0 && P1(apdu) == 0x86 && P2(apdu) == 0x80)) {
|
||||
pk_fid = EF_AES_KEY;
|
||||
is_aes = true;
|
||||
uint16_t algo_len = file_get_size(algo_ef);
|
||||
if (algo_len == 0 || algo_len > OPENPGP_MAX_ALGORITHM_ATTR_SIZE) {
|
||||
return SW_WRONG_DATA();
|
||||
}
|
||||
}
|
||||
bool aes_decipher = apdu.nc > 0 && P1(apdu) == 0x80 && P2(apdu) == 0x86 &&
|
||||
apdu.data[0] == 0x02 && (apdu.nc - 1) % 16 == 0;
|
||||
bool aes_encipher = apdu.nc > 0 && P1(apdu) == 0x86 && P2(apdu) == 0x80 &&
|
||||
apdu.nc % 16 == 0;
|
||||
if (aes_decipher || aes_encipher) {
|
||||
pk_fid = EF_AES_KEY;
|
||||
is_aes = true;
|
||||
}
|
||||
else if (P1(apdu) == 0x86 && P2(apdu) == 0x80) {
|
||||
return SW_WRONG_LENGTH();
|
||||
}
|
||||
file_t *ef = file_search_by_fid(pk_fid, NULL, SPECIFY_EF);
|
||||
if (!ef) {
|
||||
return SW_REFERENCE_NOT_FOUND();
|
||||
}
|
||||
if (wait_button_pressed_fid(pk_fid == EF_PK_SIG ? EF_UIF_SIG : EF_UIF_DEC) == true) {
|
||||
if (wait_button_pressed_fid(uif_fid) == true) {
|
||||
return SW_SECURE_MESSAGE_EXEC_ERROR();
|
||||
}
|
||||
int r = PICOKEYS_OK;
|
||||
size_t key_size = file_get_size(ef);
|
||||
size_t key_size = 0;
|
||||
if (is_aes) {
|
||||
uint8_t aes_key[32];
|
||||
r = load_aes_key(aes_key, ef);
|
||||
r = load_aes_key(aes_key, &key_size, ef);
|
||||
if (r != PICOKEYS_OK) {
|
||||
memset(aes_key, 0, sizeof(aes_key));
|
||||
return SW_EXEC_ERROR();
|
||||
}
|
||||
const uint16_t aes_key_bits = (uint16_t)(key_size * 8);
|
||||
if (P1(apdu) == 0x80 && P2(apdu) == 0x86) { //decipher
|
||||
r = aes_decrypt(aes_key, NULL, key_size, PICOKEYS_AES_MODE_CBC, apdu.data + 1, apdu.nc - 1);
|
||||
r = aes_decrypt(aes_key, NULL, aes_key_bits, PICOKEYS_AES_MODE_CBC, apdu.data + 1, apdu.nc - 1);
|
||||
memset(aes_key, 0, sizeof(aes_key));
|
||||
if (r != PICOKEYS_OK) {
|
||||
return SW_EXEC_ERROR();
|
||||
@@ -86,7 +106,7 @@ int cmd_pso(void) {
|
||||
res_APDU_size = apdu.nc - 1;
|
||||
}
|
||||
else if (P1(apdu) == 0x86 && P2(apdu) == 0x80) { //encipher
|
||||
r = aes_encrypt(aes_key, NULL, key_size, PICOKEYS_AES_MODE_CBC, apdu.data, apdu.nc);
|
||||
r = aes_encrypt(aes_key, NULL, aes_key_bits, PICOKEYS_AES_MODE_CBC, apdu.data, apdu.nc);
|
||||
memset(aes_key, 0, sizeof(aes_key));
|
||||
if (r != PICOKEYS_OK) {
|
||||
return SW_EXEC_ERROR();
|
||||
@@ -105,6 +125,7 @@ int cmd_pso(void) {
|
||||
mbedtls_rsa_free(&ctx);
|
||||
return SW_EXEC_ERROR();
|
||||
}
|
||||
key_size = mbedtls_rsa_get_len(&ctx);
|
||||
if (P1(apdu) == 0x9E && P2(apdu) == 0x9A) {
|
||||
size_t olen = 0;
|
||||
r = rsa_sign(&ctx, apdu.data, apdu.nc, res_APDU, &olen);
|
||||
@@ -165,23 +186,42 @@ int cmd_pso(void) {
|
||||
}
|
||||
//if (len != 2*key_size-1)
|
||||
// return SW_WRONG_LENGTH();
|
||||
memcpy(kdata, file_get_data(ef), key_size);
|
||||
if (dek_decrypt(kdata, key_size) != 0) {
|
||||
if (load_key_data(ef, kdata, sizeof(kdata), &key_size, true) != PICOKEYS_OK ||
|
||||
key_size < 2) {
|
||||
mbedtls_platform_zeroize(kdata, sizeof(kdata));
|
||||
return SW_EXEC_ERROR();
|
||||
}
|
||||
mbedtls_ecdh_init(&ctx);
|
||||
mbedtls_ecp_group_id gid = kdata[0];
|
||||
r = mbedtls_ecdh_setup(&ctx, gid);
|
||||
if (r != 0) {
|
||||
mbedtls_platform_zeroize(kdata, sizeof(kdata));
|
||||
mbedtls_ecdh_free(&ctx);
|
||||
return SW_DATA_INVALID();
|
||||
}
|
||||
r = mbedtls_ecp_read_key(gid, (mbedtls_ecdsa_context *)&ctx.ctx.mbed_ecdh, kdata + 1, key_size - 1);
|
||||
mbedtls_platform_zeroize(kdata, sizeof(kdata));
|
||||
if (r != 0) {
|
||||
mbedtls_ecdh_free(&ctx);
|
||||
return SW_DATA_INVALID();
|
||||
}
|
||||
r = mbedtls_ecdh_read_public(&ctx, data - 1, len + 1);
|
||||
if (mbedtls_ecp_get_type(&ctx.ctx.mbed_ecdh.grp) == MBEDTLS_ECP_TYPE_MONTGOMERY) {
|
||||
size_t montgomery_len = mbedtls_mpi_size(&ctx.ctx.mbed_ecdh.grp.P);
|
||||
const uint8_t *peer = data;
|
||||
if (len == montgomery_len + 1 && data[0] == 0x40) {
|
||||
peer = data + 1;
|
||||
len--;
|
||||
}
|
||||
if (len != montgomery_len) {
|
||||
mbedtls_ecdh_free(&ctx);
|
||||
return SW_WRONG_LENGTH();
|
||||
}
|
||||
r = mbedtls_ecp_point_read_binary(&ctx.ctx.mbed_ecdh.grp, &ctx.ctx.mbed_ecdh.Qp,
|
||||
peer, len);
|
||||
}
|
||||
else {
|
||||
r = mbedtls_ecdh_read_public(&ctx, data - 1, len + 1);
|
||||
}
|
||||
if (r != 0) {
|
||||
mbedtls_ecdh_free(&ctx);
|
||||
return SW_DATA_INVALID();
|
||||
|
||||
@@ -19,13 +19,20 @@
|
||||
|
||||
int cmd_put_data(void) {
|
||||
uint16_t fid = (P1(apdu) << 8) | P2(apdu);
|
||||
uint16_t requested_fid = fid;
|
||||
bool is_algorithm_attr = fid == EF_ALGO_SIG || fid == EF_ALGO_DEC || fid == EF_ALGO_AUT;
|
||||
file_t *ef;
|
||||
if (fid == EF_RESET_CODE) {
|
||||
fid = EF_RC;
|
||||
}
|
||||
else if (fid == EF_ALGO_SIG || fid == EF_ALGO_DEC || fid == EF_ALGO_AUT) {
|
||||
else if (is_algorithm_attr) {
|
||||
fid |= 0x1000;
|
||||
}
|
||||
if (is_algorithm_attr && apdu.nc > 0 &&
|
||||
(apdu.nc > OPENPGP_MAX_ALGORITHM_ATTR_SIZE ||
|
||||
(apdu.data[0] == ALGO_RSA && apdu.nc < 3))) {
|
||||
return SW_WRONG_DATA();
|
||||
}
|
||||
if (!(ef = file_search_by_fid(fid, NULL, SPECIFY_EF))) {
|
||||
return SW_REFERENCE_NOT_FOUND();
|
||||
}
|
||||
@@ -40,15 +47,39 @@ int cmd_put_data(void) {
|
||||
}
|
||||
if (fid == EF_PW_STATUS) {
|
||||
fid = EF_PW_PRIV;
|
||||
apdu.nc = 4; //we silently ommit the reset parameters
|
||||
if (apdu.nc == 0) {
|
||||
return SW_WRONG_LENGTH();
|
||||
}
|
||||
if (!(ef = file_search_by_fid(fid, NULL, SPECIFY_EF))) {
|
||||
return SW_REFERENCE_NOT_FOUND();
|
||||
}
|
||||
}
|
||||
if (currentEF && currentEF->fid == fid) { // previously selected same EF
|
||||
if (requested_fid == EF_CH_CERT) {
|
||||
if (currentEF && currentEF->fid >= EF_CH_1 && currentEF->fid <= EF_CH_3) {
|
||||
ef = currentEF;
|
||||
}
|
||||
else if (!(ef = file_search_by_fid(EF_CH_1, NULL, SPECIFY_EF))) {
|
||||
return SW_REFERENCE_NOT_FOUND();
|
||||
}
|
||||
fid = ef->fid;
|
||||
}
|
||||
else if (currentEF && currentEF->fid == fid) { // previously selected same EF
|
||||
ef = currentEF;
|
||||
}
|
||||
if (ef->type & FILE_DATA_FLASH) {
|
||||
int r = 0;
|
||||
if (apdu.nc > 0) {
|
||||
if (fid == EF_RC) {
|
||||
if (requested_fid == EF_PW_STATUS) {
|
||||
uint8_t pw_status[7] = { 0x1, 127, 127, 127, 3, 3, 3 };
|
||||
if (file_has_data(ef)) {
|
||||
memset(pw_status, 0, sizeof(pw_status));
|
||||
uint16_t status_len = MIN(file_get_size(ef), sizeof(pw_status));
|
||||
memcpy(pw_status, file_get_data(ef), status_len);
|
||||
}
|
||||
memcpy(pw_status, apdu.data, MIN(apdu.nc, 4));
|
||||
r = file_put_data(ef, pw_status, sizeof(pw_status));
|
||||
}
|
||||
else if (fid == EF_RC) {
|
||||
has_rc = false;
|
||||
if ((r = load_dek()) != PICOKEYS_OK) {
|
||||
return SW_EXEC_ERROR();
|
||||
@@ -59,7 +90,7 @@ int cmd_put_data(void) {
|
||||
pin_derive_verifier(apdu.data, apdu.nc, dhash + 2);
|
||||
file_put_data(ef, dhash, sizeof(dhash));
|
||||
|
||||
file_t *tf = file_search_by_fid(EF_DEK, NULL, SPECIFY_EF);
|
||||
file_t *tf = file_search_by_fid(EF_DEK_RC, NULL, SPECIFY_EF);
|
||||
if (!tf) {
|
||||
return SW_REFERENCE_NOT_FOUND();
|
||||
}
|
||||
@@ -79,7 +110,10 @@ int cmd_put_data(void) {
|
||||
flash_commit();
|
||||
}
|
||||
else {
|
||||
file_delete(ef);
|
||||
if (flash_clear_file(ef) != PICOKEYS_OK) {
|
||||
return SW_MEMORY_FAILURE();
|
||||
}
|
||||
flash_commit();
|
||||
}
|
||||
}
|
||||
return SW_OK();
|
||||
|
||||
@@ -23,29 +23,40 @@ int cmd_select_data(void) {
|
||||
if (P2(apdu) != 0x4) {
|
||||
return SW_WRONG_P1P2();
|
||||
}
|
||||
if (apdu.nc < 5u) {
|
||||
return SW_WRONG_LENGTH();
|
||||
}
|
||||
if (apdu.data[0] != 0x60) {
|
||||
return SW_WRONG_DATA();
|
||||
}
|
||||
if (apdu.nc != (uint32_t) apdu.data[1] + 2u || apdu.nc < 5u) {
|
||||
if (apdu.nc != (uint32_t) apdu.data[1] + 2u) {
|
||||
return SW_WRONG_LENGTH();
|
||||
}
|
||||
if (apdu.data[2] != 0x5C) {
|
||||
return SW_WRONG_DATA();
|
||||
}
|
||||
if (apdu.data[3] == 2) {
|
||||
if (apdu.nc < 6u) {
|
||||
return SW_WRONG_LENGTH();
|
||||
}
|
||||
fid = (apdu.data[4] << 8) | apdu.data[5];
|
||||
}
|
||||
else {
|
||||
else if (apdu.data[3] == 1) {
|
||||
fid = apdu.data[4];
|
||||
}
|
||||
else {
|
||||
return SW_WRONG_DATA();
|
||||
}
|
||||
if (fid != EF_CH_CERT || P1(apdu) >= 3) {
|
||||
return SW_REFERENCE_NOT_FOUND();
|
||||
}
|
||||
if (!(ef = file_search_by_fid(fid, NULL, SPECIFY_EF))) {
|
||||
return SW_REFERENCE_NOT_FOUND();
|
||||
}
|
||||
if (!file_authenticate_action(ef, ACL_OP_UPDATE_ERASE)) {
|
||||
return SW_SECURITY_STATUS_NOT_SATISFIED();
|
||||
}
|
||||
fid &= ~0x6000; //Now get private DO
|
||||
fid += P1(apdu);
|
||||
fid = EF_CH_1 + P1(apdu);
|
||||
if (!(ef = file_search_by_fid(fid, NULL, SPECIFY_EF))) {
|
||||
return SW_REFERENCE_NOT_FOUND();
|
||||
}
|
||||
|
||||
+68
-12
@@ -32,6 +32,32 @@ int parse_algoinfo(const file_t *f, int mode);
|
||||
int parse_app_data(const file_t *f, int mode);
|
||||
int parse_discrete_do(const file_t *f, int mode);
|
||||
|
||||
static uint16_t response_remaining(void) {
|
||||
return res_APDU_size < OPENPGP_MAX_RESPONSE_SIZE ?
|
||||
OPENPGP_MAX_RESPONSE_SIZE - res_APDU_size : 0;
|
||||
}
|
||||
|
||||
static uint8_t encoded_len_size(uint16_t len) {
|
||||
if (len >= 256) {
|
||||
return 3;
|
||||
}
|
||||
if (len >= 128) {
|
||||
return 2;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static uint16_t fit_tlv_value(uint16_t len, uint16_t available, uint8_t tag_size) {
|
||||
if (available <= tag_size + 1) {
|
||||
return 0;
|
||||
}
|
||||
uint16_t fitted = MIN(len, available - tag_size - 1);
|
||||
while (fitted + tag_size + encoded_len_size(fitted) > available) {
|
||||
fitted--;
|
||||
}
|
||||
return fitted;
|
||||
}
|
||||
|
||||
int parse_do(uint16_t *fids, int mode) {
|
||||
int len = 0;
|
||||
file_t *ef;
|
||||
@@ -39,14 +65,27 @@ int parse_do(uint16_t *fids, int mode) {
|
||||
if ((ef = file_search_by_fid(fids[i + 1], NULL, SPECIFY_EF))) {
|
||||
uint16_t data_len;
|
||||
if ((ef->type & FILE_DATA_FUNC) == FILE_DATA_FUNC) {
|
||||
if (mode == 1 && response_remaining() < 16) {
|
||||
break;
|
||||
}
|
||||
int (*file_data_func)(const file_t *, int) = NULL;
|
||||
memcpy(&file_data_func, &ef->data, sizeof(file_data_func));
|
||||
uint16_t initial_size = res_APDU_size;
|
||||
data_len = file_data_func(ef, mode);
|
||||
if (mode == 1) {
|
||||
data_len = res_APDU_size - initial_size;
|
||||
}
|
||||
}
|
||||
else {
|
||||
data_len = file_get_size(ef);
|
||||
if (mode == 1) {
|
||||
if (fids[0] > 1 && res_APDU_size > 0) {
|
||||
uint8_t tag_size = fids[i + 1] < 0x0100 ? 1 : 2;
|
||||
uint16_t available = response_remaining();
|
||||
data_len = fit_tlv_value(data_len, available, tag_size);
|
||||
if (available < tag_size + encoded_len_size(data_len)) {
|
||||
break;
|
||||
}
|
||||
if (fids[i + 1] < 0x0100) {
|
||||
res_APDU[res_APDU_size++] = fids[i + 1] & 0xff;
|
||||
}
|
||||
@@ -56,6 +95,9 @@ int parse_do(uint16_t *fids, int mode) {
|
||||
}
|
||||
res_APDU_size += tlv_format_len(data_len, res_APDU + res_APDU_size);
|
||||
}
|
||||
else {
|
||||
data_len = MIN(data_len, response_remaining());
|
||||
}
|
||||
if (file_has_data(ef)) {
|
||||
memcpy(res_APDU + res_APDU_size, file_get_data(ef), data_len);
|
||||
}
|
||||
@@ -69,19 +111,24 @@ int parse_do(uint16_t *fids, int mode) {
|
||||
}
|
||||
|
||||
int parse_trium(uint16_t fid, uint8_t num, size_t size) {
|
||||
uint16_t initial_size = res_APDU_size;
|
||||
for (uint8_t i = 0; i < num; i++) {
|
||||
uint16_t output_len = MIN(size, response_remaining());
|
||||
if (output_len == 0) {
|
||||
break;
|
||||
}
|
||||
file_t *ef;
|
||||
if ((ef = file_search_by_fid(fid + i, NULL, SPECIFY_EF)) && ef->data) {
|
||||
uint16_t data_len = file_get_size(ef);
|
||||
uint16_t data_len = MIN(file_get_size(ef), output_len);
|
||||
memcpy(res_APDU + res_APDU_size, file_get_data(ef), data_len);
|
||||
res_APDU_size += data_len;
|
||||
memset(res_APDU + res_APDU_size + data_len, 0, output_len - data_len);
|
||||
}
|
||||
else {
|
||||
memset(res_APDU + res_APDU_size, 0, size);
|
||||
res_APDU_size += size;
|
||||
memset(res_APDU + res_APDU_size, 0, output_len);
|
||||
}
|
||||
res_APDU_size += output_len;
|
||||
}
|
||||
return num * size;
|
||||
return res_APDU_size - initial_size;
|
||||
}
|
||||
|
||||
int parse_ch_data(const file_t *f, int mode) {
|
||||
@@ -106,13 +153,15 @@ int parse_sec_tpl(const file_t *f, int mode) {
|
||||
(void) mode;
|
||||
res_APDU[res_APDU_size++] = EF_SEC_TPL & 0xff;
|
||||
res_APDU[res_APDU_size++] = 5;
|
||||
res_APDU[res_APDU_size++] = EF_SIG_COUNT & 0xff;
|
||||
res_APDU[res_APDU_size++] = 3;
|
||||
memset(res_APDU + res_APDU_size, 0, 3);
|
||||
file_t *ef = file_search_by_fid(EF_SIG_COUNT, NULL, SPECIFY_ANY);
|
||||
if (ef && ef->data) {
|
||||
res_APDU[res_APDU_size++] = EF_SIG_COUNT & 0xff;
|
||||
res_APDU[res_APDU_size++] = 3;
|
||||
memcpy(res_APDU + res_APDU_size, file_get_data(ef), 3);
|
||||
res_APDU_size += 3;
|
||||
uint16_t data_len = MIN(file_get_size(ef), 3);
|
||||
memcpy(res_APDU + res_APDU_size, file_get_data(ef), data_len);
|
||||
}
|
||||
res_APDU_size += 3;
|
||||
return 5 + 2;
|
||||
}
|
||||
|
||||
@@ -193,10 +242,12 @@ int parse_pw_status(const file_t *f, int mode) {
|
||||
res_APDU[res_APDU_size++] = 7;
|
||||
}
|
||||
ef = file_search_by_fid(EF_PW_PRIV, NULL, SPECIFY_ANY);
|
||||
memset(res_APDU + res_APDU_size, 0, 7);
|
||||
if (ef && ef->data) {
|
||||
memcpy(res_APDU + res_APDU_size, file_get_data(ef), 7);
|
||||
res_APDU_size += 7;
|
||||
uint16_t data_len = MIN(file_get_size(ef), 7);
|
||||
memcpy(res_APDU + res_APDU_size, file_get_data(ef), data_len);
|
||||
}
|
||||
res_APDU_size += 7;
|
||||
return res_APDU_size - init_len;
|
||||
}
|
||||
|
||||
@@ -373,8 +424,13 @@ int parse_algoinfo(const file_t *f, int mode) {
|
||||
datalen += parse_algo(algorithm_attr_rsa2k, f->fid);
|
||||
}
|
||||
else {
|
||||
uint16_t len = file_get_size(ef);
|
||||
uint16_t len = MIN(file_get_size(ef), OPENPGP_MAX_ALGORITHM_ATTR_SIZE);
|
||||
len = MIN(len, response_remaining());
|
||||
if (res_APDU_size > 0) {
|
||||
if (response_remaining() < 2) {
|
||||
return datalen;
|
||||
}
|
||||
len = MIN(len, response_remaining() - 2);
|
||||
res_APDU[res_APDU_size++] = f->fid & 0xff;
|
||||
res_APDU[res_APDU_size++] = len & 0xff;
|
||||
datalen += 2;
|
||||
|
||||
+4
-1
@@ -252,8 +252,11 @@ file_t file_entries[] = {
|
||||
/* 59 */ { .fid = EF_DEK_PW3, .parent = 0, .name = NULL,
|
||||
.type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL,
|
||||
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_NONE },
|
||||
/* 60 */ { .fid = EF_AES_KEY, .parent = 0, .name = NULL,
|
||||
.type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL,
|
||||
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_NONE },
|
||||
// ** PIV ** //
|
||||
/* 60 */ { .fid = EF_PIV_ADMIN_DATA, .parent = 0, .name = NULL,
|
||||
/* 61 */ { .fid = EF_PIV_ADMIN_DATA, .parent = 0, .name = NULL,
|
||||
.type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL,
|
||||
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP },
|
||||
/* 61 */ { .fid = EF_PIV_ATTESTATION, .parent = 0, .name = NULL,
|
||||
|
||||
+236
-49
@@ -26,6 +26,8 @@
|
||||
#include "random.h"
|
||||
#include "eac.h"
|
||||
#include "mbedtls/asn1.h"
|
||||
#include "mbedtls/gcm.h"
|
||||
#include "mbedtls/md.h"
|
||||
#include "usb.h"
|
||||
#include "ccid/ccid.h"
|
||||
#include "otp.h"
|
||||
@@ -44,6 +46,7 @@ uint8_t session_rc[32];
|
||||
uint8_t session_pw3[32];
|
||||
uint8_t dek[DEK_SIZE];
|
||||
uint16_t algo_dec = EF_ALGO_PRIV2, algo_aut = EF_ALGO_PRIV3, pk_dec = EF_PK_DEC, pk_aut = EF_PK_AUT;
|
||||
extern bool is_gpg;
|
||||
|
||||
uint8_t openpgp_aid[] = {
|
||||
6,
|
||||
@@ -272,7 +275,7 @@ static void release_dek(void) {
|
||||
extern bool has_pwpiv;
|
||||
extern uint8_t session_pwpiv[32];
|
||||
int load_dek(void) {
|
||||
if (!has_pw1 && !has_pw2 && !has_pw3 && !has_pwpiv) {
|
||||
if (!has_pw1 && !has_pw2 && !has_pw3 && !has_rc && !has_pwpiv) {
|
||||
return PICOKEYS_NO_LOGIN;
|
||||
}
|
||||
int r = PICOKEYS_OK;
|
||||
@@ -298,6 +301,28 @@ int load_dek(void) {
|
||||
r = aes_decrypt_cfb_256(session_pw1, dek, dek + IV_SIZE, 32);
|
||||
}
|
||||
}
|
||||
else if (has_rc) {
|
||||
file_t *ef_dek_rc = file_search(EF_DEK_RC);
|
||||
if (file_has_data(ef_dek_rc)) {
|
||||
uint8_t *ef_data = file_get_data(ef_dek_rc);
|
||||
if (ef_data[0] == 0x3) { // Format
|
||||
r = decrypt_with_aad(session_rc, ef_data + 1, DEK_AAD_SIZE, PIN_KDF_DEFAULT_VERSION, dek);
|
||||
}
|
||||
else {
|
||||
return PICOKEYS_ERR_NULL_PARAM;
|
||||
}
|
||||
}
|
||||
else {
|
||||
file_t *tf = file_search_by_fid(EF_DEK, NULL, SPECIFY_EF);
|
||||
if (!tf) {
|
||||
return PICOKEYS_ERR_FILE_NOT_FOUND;
|
||||
}
|
||||
|
||||
memcpy(dek, file_get_data(tf), IV_SIZE);
|
||||
memcpy(dek + IV_SIZE, file_get_data(tf) + IV_SIZE + 32, 32);
|
||||
r = aes_decrypt_cfb_256(session_rc, dek, dek + IV_SIZE, 32);
|
||||
}
|
||||
}
|
||||
else if (has_pw3) {
|
||||
file_t *ef_dek_pw3 = file_search(EF_DEK_PW3);
|
||||
if (file_has_data(ef_dek_pw3)) {
|
||||
@@ -349,17 +374,7 @@ int load_dek(void) {
|
||||
return PICOKEYS_OK;
|
||||
}
|
||||
|
||||
int dek_encrypt(uint8_t *data, size_t len) {
|
||||
int r;
|
||||
if ((r = load_dek()) != PICOKEYS_OK) {
|
||||
return r;
|
||||
}
|
||||
r = aes_encrypt_cfb_256(dek + IV_SIZE, dek, data, len);
|
||||
release_dek();
|
||||
return r;
|
||||
}
|
||||
|
||||
int dek_decrypt(uint8_t *data, size_t len) {
|
||||
static int dek_decrypt_legacy(uint8_t *data, size_t len) {
|
||||
int r;
|
||||
if ((r = load_dek()) != PICOKEYS_OK) {
|
||||
return r;
|
||||
@@ -369,6 +384,164 @@ int dek_decrypt(uint8_t *data, size_t len) {
|
||||
return r;
|
||||
}
|
||||
|
||||
#define ENCRYPTED_KEY_MAGIC_SIZE 4
|
||||
#define ENCRYPTED_KEY_NONCE_SIZE 12
|
||||
#define ENCRYPTED_KEY_TAG_SIZE 16
|
||||
#define ENCRYPTED_KEY_OVERHEAD (ENCRYPTED_KEY_MAGIC_SIZE + ENCRYPTED_KEY_NONCE_SIZE + ENCRYPTED_KEY_TAG_SIZE)
|
||||
|
||||
static const uint8_t encrypted_key_magic[ENCRYPTED_KEY_MAGIC_SIZE] = { 'P', 'G', 'K', 1 };
|
||||
|
||||
static int derive_encrypted_key_nonce(uint16_t fid, const uint8_t *plaintext, size_t plaintext_len, uint8_t nonce[ENCRYPTED_KEY_NONCE_SIZE]) {
|
||||
const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256);
|
||||
if (!md_info) {
|
||||
return PICOKEYS_EXEC_ERROR;
|
||||
}
|
||||
mbedtls_md_context_t md;
|
||||
mbedtls_md_init(&md);
|
||||
uint8_t digest[32] = { 0 };
|
||||
uint8_t fid_data[2] = { fid >> 8, fid & 0xff };
|
||||
int r = mbedtls_md_setup(&md, md_info, 1);
|
||||
if (r == 0) {
|
||||
r = mbedtls_md_hmac_starts(&md, dek, sizeof(dek));
|
||||
}
|
||||
if (r == 0) {
|
||||
r = mbedtls_md_hmac_update(&md, fid_data, sizeof(fid_data));
|
||||
}
|
||||
if (r == 0) {
|
||||
r = mbedtls_md_hmac_update(&md, plaintext, plaintext_len);
|
||||
}
|
||||
if (r == 0) {
|
||||
r = mbedtls_md_hmac_finish(&md, digest);
|
||||
}
|
||||
mbedtls_md_free(&md);
|
||||
if (r == 0) {
|
||||
memcpy(nonce, digest, ENCRYPTED_KEY_NONCE_SIZE);
|
||||
}
|
||||
mbedtls_platform_zeroize(digest, sizeof(digest));
|
||||
return r == 0 ? PICOKEYS_OK : PICOKEYS_EXEC_ERROR;
|
||||
}
|
||||
|
||||
static void encrypted_key_aad(uint16_t fid, uint8_t aad[ENCRYPTED_KEY_MAGIC_SIZE + 2]) {
|
||||
memcpy(aad, encrypted_key_magic, ENCRYPTED_KEY_MAGIC_SIZE);
|
||||
aad[ENCRYPTED_KEY_MAGIC_SIZE] = fid >> 8;
|
||||
aad[ENCRYPTED_KEY_MAGIC_SIZE + 1] = fid & 0xff;
|
||||
}
|
||||
|
||||
static int store_encrypted_key(file_t *ef, const uint8_t *plaintext, size_t plaintext_len) {
|
||||
if (!ef || !plaintext || plaintext_len > UINT16_MAX - ENCRYPTED_KEY_OVERHEAD) {
|
||||
return PICOKEYS_WRONG_DATA;
|
||||
}
|
||||
int r = load_dek();
|
||||
if (r != PICOKEYS_OK) {
|
||||
return r;
|
||||
}
|
||||
|
||||
size_t record_len = plaintext_len + ENCRYPTED_KEY_OVERHEAD;
|
||||
uint8_t *record = calloc(1, record_len);
|
||||
if (!record) {
|
||||
release_dek();
|
||||
return PICOKEYS_ERR_MEMORY_FATAL;
|
||||
}
|
||||
memcpy(record, encrypted_key_magic, ENCRYPTED_KEY_MAGIC_SIZE);
|
||||
uint8_t *nonce = record + ENCRYPTED_KEY_MAGIC_SIZE;
|
||||
uint8_t *ciphertext = nonce + ENCRYPTED_KEY_NONCE_SIZE;
|
||||
uint8_t *tag = ciphertext + plaintext_len;
|
||||
uint8_t aad[ENCRYPTED_KEY_MAGIC_SIZE + 2];
|
||||
encrypted_key_aad(ef->fid, aad);
|
||||
|
||||
r = derive_encrypted_key_nonce(ef->fid, plaintext, plaintext_len, nonce);
|
||||
mbedtls_gcm_context gcm;
|
||||
mbedtls_gcm_init(&gcm);
|
||||
if (r == PICOKEYS_OK) {
|
||||
r = mbedtls_gcm_setkey(&gcm, MBEDTLS_CIPHER_ID_AES, dek + IV_SIZE, 256);
|
||||
}
|
||||
if (r == 0) {
|
||||
r = mbedtls_gcm_crypt_and_tag(&gcm, MBEDTLS_GCM_ENCRYPT, plaintext_len, nonce, ENCRYPTED_KEY_NONCE_SIZE, aad, sizeof(aad), plaintext, ciphertext, ENCRYPTED_KEY_TAG_SIZE, tag);
|
||||
}
|
||||
mbedtls_gcm_free(&gcm);
|
||||
release_dek();
|
||||
if (r != 0) {
|
||||
mbedtls_platform_zeroize(record, record_len);
|
||||
free(record);
|
||||
return PICOKEYS_EXEC_ERROR;
|
||||
}
|
||||
|
||||
r = file_put_data(ef, record, (uint16_t)record_len);
|
||||
mbedtls_platform_zeroize(record, record_len);
|
||||
free(record);
|
||||
return r;
|
||||
}
|
||||
|
||||
int load_key_data(file_t *fkey, uint8_t *out, size_t out_size, size_t *out_len, bool use_dek) {
|
||||
if (!file_has_data(fkey) || !out || !out_len) {
|
||||
return PICOKEYS_WRONG_DATA;
|
||||
}
|
||||
size_t stored_len = file_get_size(fkey);
|
||||
const uint8_t *stored = file_get_data(fkey);
|
||||
|
||||
if (!use_dek) {
|
||||
if (stored_len > out_size) {
|
||||
return PICOKEYS_WRONG_DATA;
|
||||
}
|
||||
memcpy(out, stored, stored_len);
|
||||
*out_len = stored_len;
|
||||
return PICOKEYS_OK;
|
||||
}
|
||||
|
||||
if (stored_len >= ENCRYPTED_KEY_MAGIC_SIZE &&
|
||||
memcmp(stored, encrypted_key_magic, ENCRYPTED_KEY_MAGIC_SIZE) == 0) {
|
||||
if (stored_len < ENCRYPTED_KEY_OVERHEAD) {
|
||||
return PICOKEYS_WRONG_DATA;
|
||||
}
|
||||
size_t plaintext_len = stored_len - ENCRYPTED_KEY_OVERHEAD;
|
||||
if (plaintext_len > out_size) {
|
||||
return PICOKEYS_WRONG_DATA;
|
||||
}
|
||||
const uint8_t *nonce = stored + ENCRYPTED_KEY_MAGIC_SIZE;
|
||||
const uint8_t *ciphertext = nonce + ENCRYPTED_KEY_NONCE_SIZE;
|
||||
const uint8_t *tag = ciphertext + plaintext_len;
|
||||
uint8_t aad[ENCRYPTED_KEY_MAGIC_SIZE + 2];
|
||||
encrypted_key_aad(fkey->fid, aad);
|
||||
|
||||
int r = load_dek();
|
||||
if (r != PICOKEYS_OK) {
|
||||
return r;
|
||||
}
|
||||
mbedtls_gcm_context gcm;
|
||||
mbedtls_gcm_init(&gcm);
|
||||
r = mbedtls_gcm_setkey(&gcm, MBEDTLS_CIPHER_ID_AES, dek + IV_SIZE, 256);
|
||||
if (r == 0) {
|
||||
r = mbedtls_gcm_auth_decrypt(&gcm, plaintext_len, nonce, ENCRYPTED_KEY_NONCE_SIZE, aad, sizeof(aad), tag, ENCRYPTED_KEY_TAG_SIZE, ciphertext, out);
|
||||
}
|
||||
mbedtls_gcm_free(&gcm);
|
||||
release_dek();
|
||||
if (r != 0) {
|
||||
mbedtls_platform_zeroize(out, out_size);
|
||||
return PICOKEYS_WRONG_DATA;
|
||||
}
|
||||
*out_len = plaintext_len;
|
||||
return PICOKEYS_OK;
|
||||
}
|
||||
|
||||
if (stored_len > out_size) {
|
||||
return PICOKEYS_WRONG_DATA;
|
||||
}
|
||||
memcpy(out, stored, stored_len);
|
||||
int r = dek_decrypt_legacy(out, stored_len);
|
||||
if (r != 0) {
|
||||
mbedtls_platform_zeroize(out, out_size);
|
||||
return PICOKEYS_EXEC_ERROR;
|
||||
}
|
||||
r = store_encrypted_key(fkey, out, stored_len);
|
||||
if (r != PICOKEYS_OK) {
|
||||
mbedtls_platform_zeroize(out, out_size);
|
||||
return r;
|
||||
}
|
||||
flash_commit();
|
||||
*out_len = stored_len;
|
||||
return PICOKEYS_OK;
|
||||
}
|
||||
|
||||
static void init_openpgp(void) {
|
||||
isUserAuthenticated = false;
|
||||
has_pw1 = has_pw2 = has_pw3 = false;
|
||||
@@ -406,6 +579,7 @@ static int openpgp_select_aid(app_t *a, uint8_t force) {
|
||||
(void) force;
|
||||
a->process_apdu = openpgp_process_apdu;
|
||||
a->unload = openpgp_unload;
|
||||
is_gpg = true;
|
||||
init_openpgp();
|
||||
file_process_fci(file_openpgp, 1);
|
||||
memcpy(res_APDU + res_APDU_size, "\x64\x06\x53\x04", 4);
|
||||
@@ -674,16 +848,8 @@ int store_keys(void *key_ctx, int type, uint16_t key_id, bool use_kek) {
|
||||
}
|
||||
memcpy(kdata, key_ctx, key_size);
|
||||
}
|
||||
if (use_kek) {
|
||||
r = dek_encrypt(kdata, key_size);
|
||||
if (r != PICOKEYS_OK) {
|
||||
return r;
|
||||
}
|
||||
}
|
||||
//r = aes_encrypt_cfb_256(file_read(pw3->data+2), session_pw3, kdata, key_size);
|
||||
//if (r != PICOKEYS_OK)
|
||||
// return r;
|
||||
r = file_put_data(ef, kdata, key_size);
|
||||
r = use_kek ? store_encrypted_key(ef, kdata, key_size) : file_put_data(ef, kdata, key_size);
|
||||
mbedtls_platform_zeroize(kdata, sizeof(kdata));
|
||||
if (r != PICOKEYS_OK) {
|
||||
return r;
|
||||
}
|
||||
@@ -692,54 +858,72 @@ int store_keys(void *key_ctx, int type, uint16_t key_id, bool use_kek) {
|
||||
}
|
||||
|
||||
int load_private_key_rsa(mbedtls_rsa_context *ctx, file_t *fkey, bool use_dek) {
|
||||
int key_size = file_get_size(fkey);
|
||||
size_t key_size = 0;
|
||||
uint8_t kdata[4096 / 8];
|
||||
memcpy(kdata, file_get_data(fkey), key_size);
|
||||
if (use_dek && dek_decrypt(kdata, key_size) != 0) {
|
||||
return PICOKEYS_EXEC_ERROR;
|
||||
int r = load_key_data(fkey, kdata, sizeof(kdata), &key_size, use_dek);
|
||||
if (r != PICOKEYS_OK || key_size == 0 || key_size % 2 != 0) {
|
||||
mbedtls_platform_zeroize(kdata, sizeof(kdata));
|
||||
return r == PICOKEYS_OK ? PICOKEYS_WRONG_DATA : r;
|
||||
}
|
||||
if (mbedtls_mpi_read_binary(&ctx->P, kdata, key_size / 2) != 0) {
|
||||
mbedtls_rsa_free(ctx);
|
||||
mbedtls_platform_zeroize(kdata, sizeof(kdata));
|
||||
return PICOKEYS_WRONG_DATA;
|
||||
}
|
||||
if (mbedtls_mpi_read_binary(&ctx->Q, kdata + key_size / 2, key_size / 2) != 0) {
|
||||
mbedtls_rsa_free(ctx);
|
||||
mbedtls_platform_zeroize(kdata, sizeof(kdata));
|
||||
return PICOKEYS_WRONG_DATA;
|
||||
}
|
||||
if (mbedtls_mpi_lset(&ctx->E, 0x10001) != 0) {
|
||||
mbedtls_rsa_free(ctx);
|
||||
mbedtls_platform_zeroize(kdata, sizeof(kdata));
|
||||
return PICOKEYS_EXEC_ERROR;
|
||||
}
|
||||
if (mbedtls_rsa_import(ctx, NULL, &ctx->P, &ctx->Q, NULL, &ctx->E) != 0) {
|
||||
mbedtls_rsa_free(ctx);
|
||||
mbedtls_platform_zeroize(kdata, sizeof(kdata));
|
||||
return PICOKEYS_WRONG_DATA;
|
||||
}
|
||||
if (mbedtls_rsa_complete(ctx) != 0) {
|
||||
mbedtls_rsa_free(ctx);
|
||||
mbedtls_platform_zeroize(kdata, sizeof(kdata));
|
||||
return PICOKEYS_WRONG_DATA;
|
||||
}
|
||||
if (mbedtls_rsa_check_privkey(ctx) != 0) {
|
||||
mbedtls_rsa_free(ctx);
|
||||
mbedtls_platform_zeroize(kdata, sizeof(kdata));
|
||||
return PICOKEYS_WRONG_DATA;
|
||||
}
|
||||
mbedtls_platform_zeroize(kdata, sizeof(kdata));
|
||||
return PICOKEYS_OK;
|
||||
}
|
||||
|
||||
int load_private_key_ecdsa(mbedtls_ecp_keypair *ctx, file_t *fkey, bool use_dek) {
|
||||
int key_size = file_get_size(fkey);
|
||||
size_t key_size = 0;
|
||||
uint8_t kdata[67]; //Worst case, 521 bit + 1byte
|
||||
memcpy(kdata, file_get_data(fkey), key_size);
|
||||
if (use_dek && dek_decrypt(kdata, key_size) != 0) {
|
||||
return PICOKEYS_EXEC_ERROR;
|
||||
int r = load_key_data(fkey, kdata, sizeof(kdata), &key_size, use_dek);
|
||||
if (r != PICOKEYS_OK || key_size < 2) {
|
||||
mbedtls_platform_zeroize(kdata, sizeof(kdata));
|
||||
return r == PICOKEYS_OK ? PICOKEYS_WRONG_DATA : r;
|
||||
}
|
||||
mbedtls_ecp_group_id gid = kdata[0];
|
||||
int r = mbedtls_ecp_read_key(gid, ctx, kdata + 1, key_size - 1);
|
||||
r = mbedtls_ecp_read_key(gid, ctx, kdata + 1, key_size - 1);
|
||||
if (r != 0) {
|
||||
mbedtls_ecp_keypair_free(ctx);
|
||||
mbedtls_platform_zeroize(kdata, sizeof(kdata));
|
||||
return PICOKEYS_EXEC_ERROR;
|
||||
}
|
||||
mbedtls_platform_zeroize(kdata, sizeof(kdata));
|
||||
r = mbedtls_ecp_keypair_calc_public(ctx, random_fill_iterator, NULL);
|
||||
#if defined(MBEDTLS_ECP_EDWARDS_ENABLED)
|
||||
if (mbedtls_ecp_get_type(&ctx->grp) == MBEDTLS_ECP_TYPE_EDWARDS) {
|
||||
r = mbedtls_ecp_point_edwards(&ctx->grp, &ctx->Q, &ctx->d, random_fill_iterator, NULL);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
r = mbedtls_ecp_keypair_calc_public(ctx, random_fill_iterator, NULL);
|
||||
}
|
||||
if (r != 0) {
|
||||
mbedtls_ecp_keypair_free(ctx);
|
||||
return PICOKEYS_EXEC_ERROR;
|
||||
@@ -747,51 +931,54 @@ int load_private_key_ecdsa(mbedtls_ecp_keypair *ctx, file_t *fkey, bool use_dek)
|
||||
return PICOKEYS_OK;
|
||||
}
|
||||
|
||||
int load_aes_key(uint8_t *aes_key, file_t *fkey) {
|
||||
int key_size = file_get_size(fkey);
|
||||
memcpy(aes_key, file_get_data(fkey), key_size);
|
||||
if (dek_decrypt(aes_key, key_size) != 0) {
|
||||
return PICOKEYS_EXEC_ERROR;
|
||||
int load_aes_key(uint8_t *aes_key, size_t *key_size, file_t *fkey) {
|
||||
int r = load_key_data(fkey, aes_key, 32, key_size, true);
|
||||
if (r != PICOKEYS_OK || (*key_size != 16 && *key_size != 24 && *key_size != 32)) {
|
||||
mbedtls_platform_zeroize(aes_key, 32);
|
||||
return r == PICOKEYS_OK ? PICOKEYS_WRONG_DATA : r;
|
||||
}
|
||||
return PICOKEYS_OK;
|
||||
return r;
|
||||
}
|
||||
|
||||
mbedtls_ecp_group_id get_ec_group_id_from_attr(const uint8_t *algo, size_t algo_len) {
|
||||
if (memcmp(algorithm_attr_p256k1 + 2, algo, algo_len) == 0) {
|
||||
#define ALGORITHM_ATTR_MATCH(attr) \
|
||||
(algo_len == (size_t)((attr)[0] - 1u) && memcmp((attr) + 2, algo, algo_len) == 0)
|
||||
if (ALGORITHM_ATTR_MATCH(algorithm_attr_p256k1)) {
|
||||
return MBEDTLS_ECP_DP_SECP256K1;
|
||||
}
|
||||
else if (memcmp(algorithm_attr_p256r1 + 2, algo, algo_len) == 0) {
|
||||
else if (ALGORITHM_ATTR_MATCH(algorithm_attr_p256r1)) {
|
||||
return MBEDTLS_ECP_DP_SECP256R1;
|
||||
}
|
||||
else if (memcmp(algorithm_attr_p384r1 + 2, algo, algo_len) == 0) {
|
||||
else if (ALGORITHM_ATTR_MATCH(algorithm_attr_p384r1)) {
|
||||
return MBEDTLS_ECP_DP_SECP384R1;
|
||||
}
|
||||
else if (memcmp(algorithm_attr_p521r1 + 2, algo, algo_len) == 0) {
|
||||
else if (ALGORITHM_ATTR_MATCH(algorithm_attr_p521r1)) {
|
||||
return MBEDTLS_ECP_DP_SECP521R1;
|
||||
}
|
||||
else if (memcmp(algorithm_attr_bp256r1 + 2, algo, algo_len) == 0) {
|
||||
else if (ALGORITHM_ATTR_MATCH(algorithm_attr_bp256r1)) {
|
||||
return MBEDTLS_ECP_DP_BP256R1;
|
||||
}
|
||||
else if (memcmp(algorithm_attr_bp384r1 + 2, algo, algo_len) == 0) {
|
||||
else if (ALGORITHM_ATTR_MATCH(algorithm_attr_bp384r1)) {
|
||||
return MBEDTLS_ECP_DP_BP384R1;
|
||||
}
|
||||
else if (memcmp(algorithm_attr_bp512r1 + 2, algo, algo_len) == 0) {
|
||||
else if (ALGORITHM_ATTR_MATCH(algorithm_attr_bp512r1)) {
|
||||
return MBEDTLS_ECP_DP_BP512R1;
|
||||
}
|
||||
else if (memcmp(algorithm_attr_cv25519 + 2, algo, algo_len) == 0) {
|
||||
else if (ALGORITHM_ATTR_MATCH(algorithm_attr_cv25519)) {
|
||||
return MBEDTLS_ECP_DP_CURVE25519;
|
||||
}
|
||||
else if (memcmp(algorithm_attr_x448 + 2, algo, algo_len) == 0) {
|
||||
else if (ALGORITHM_ATTR_MATCH(algorithm_attr_x448)) {
|
||||
return MBEDTLS_ECP_DP_CURVE448;
|
||||
}
|
||||
#ifdef MBEDTLS_EDDSA_C
|
||||
else if (memcmp(algorithm_attr_ed25519 + 2, algo, algo_len) == 0) {
|
||||
else if (ALGORITHM_ATTR_MATCH(algorithm_attr_ed25519)) {
|
||||
return MBEDTLS_ECP_DP_ED25519;
|
||||
}
|
||||
else if (memcmp(algorithm_attr_ed448 + 2, algo, algo_len) == 0) {
|
||||
else if (ALGORITHM_ATTR_MATCH(algorithm_attr_ed448)) {
|
||||
return MBEDTLS_ECP_DP_ED448;
|
||||
}
|
||||
#endif
|
||||
#undef ALGORITHM_ATTR_MATCH
|
||||
return MBEDTLS_ECP_DP_NONE;
|
||||
}
|
||||
|
||||
|
||||
+8
-14
@@ -42,16 +42,8 @@ extern uint8_t dek[IV_SIZE + 32];
|
||||
extern int store_keys(void *key_ctx, int type, uint16_t key_id, bool use_kek);
|
||||
extern void make_rsa_response(mbedtls_rsa_context *rsa);
|
||||
extern void make_ecdsa_response(mbedtls_ecdsa_context *ecdsa);
|
||||
extern int ecdsa_sign(mbedtls_ecdsa_context *ctx,
|
||||
const uint8_t *data,
|
||||
size_t data_len,
|
||||
uint8_t *out,
|
||||
size_t *out_len);
|
||||
extern int rsa_sign(mbedtls_rsa_context *ctx,
|
||||
const uint8_t *data,
|
||||
size_t data_len,
|
||||
uint8_t *out,
|
||||
size_t *out_len);
|
||||
extern int ecdsa_sign(mbedtls_ecdsa_context *ctx, const uint8_t *data, size_t data_len, uint8_t *out, size_t *out_len);
|
||||
extern int rsa_sign(mbedtls_rsa_context *ctx, const uint8_t *data, size_t data_len, uint8_t *out, size_t *out_len);
|
||||
extern int load_private_key_rsa(mbedtls_rsa_context *ctx, file_t *fkey, bool use_dek);
|
||||
extern int load_private_key_ecdsa(mbedtls_ecdsa_context *ctx, file_t *fkey, bool use_dek);
|
||||
extern int pin_reset_retries(const file_t *pin, bool force);
|
||||
@@ -74,11 +66,9 @@ extern int reset_sig_count(void);
|
||||
extern uint16_t algo_dec, algo_aut, pk_dec, pk_aut;
|
||||
extern bool wait_button_pressed_fid(uint16_t fid);
|
||||
extern void scan_files_openpgp(void);
|
||||
extern int load_aes_key(uint8_t *aes_key, file_t *fkey);
|
||||
extern int load_aes_key(uint8_t *aes_key, size_t *key_size, file_t *fkey);
|
||||
extern int load_key_data(file_t *fkey, uint8_t *out, size_t out_size, size_t *out_len, bool use_dek);
|
||||
extern int inc_sig_count(void);
|
||||
extern int dek_encrypt(uint8_t *data, size_t len);
|
||||
extern int dek_decrypt(uint8_t *data, size_t len);
|
||||
|
||||
int cmd_select(void);
|
||||
int cmd_get_data(void);
|
||||
int cmd_get_next_data(void);
|
||||
@@ -104,4 +94,8 @@ int cmd_get_bulk_data(void);
|
||||
|
||||
#define DEK_FILE_SIZE_OLD (IV_SIZE + 32 + 32 + 32 + 32)
|
||||
|
||||
#define OPENPGP_MAX_ALGORITHM_ATTR_SIZE 16
|
||||
#define OPENPGP_MAX_OBJECT_SIZE 2048
|
||||
#define OPENPGP_MAX_RESPONSE_SIZE 2048
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user