blue-app-openpgp-card/src/gpg_data.c
Cédric Mesnil bfb950e21b Initial commit
Functional application in beta stage
2017-03-21 16:32:26 +01:00

650 lines
20 KiB
C

/* Copyright 2017 Cedric Mesnil <cslashm@gmail.com>, Ledger SAS
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "os.h"
#include "cx.h"
#include "gpg_types.h"
#include "gpg_api.h"
#include "gpg_vars.h"
int gpg_apdu_select_data(unsigned int ref, int reccord) {
G_gpg_vstate.DO_current = ref;
G_gpg_vstate.DO_reccord = reccord;
G_gpg_vstate.DO_offset = 0;
return SW_OK;
}
int gpg_apdu_get_data(unsigned int ref) {
int sw;
if (G_gpg_vstate.DO_current != ref) {
G_gpg_vstate.DO_current = ref;
G_gpg_vstate.DO_reccord = 0;
G_gpg_vstate.DO_offset = 0;
}
sw = SW_OK;
gpg_io_discard(1);
switch (ref) {
/* ----------------- Optional DO for private use ----------------- */
case 0x0101:
gpg_io_insert(N_gpg_pstate->private_DO1.value, N_gpg_pstate->private_DO1.length);
break;
case 0x0102:
gpg_io_insert(N_gpg_pstate->private_DO2.value, N_gpg_pstate->private_DO2.length);
break;
case 0x0103:
gpg_io_insert(N_gpg_pstate->private_DO3.value, N_gpg_pstate->private_DO3.length);
break;
case 0x0104:
gpg_io_insert(N_gpg_pstate->private_DO4.value, N_gpg_pstate->private_DO4.length);
break;
/* ----------------- Config key slot ----------------- */
case 0x01F0:
gpg_io_insert(N_gpg_pstate->config_slot, 3);
gpg_io_insert_u8(G_gpg_vstate.slot);
break;
case 0x01F1:
gpg_io_insert(N_gpg_pstate->config_slot, 3);
break;
case 0x01F2:
gpg_io_insert_u8(G_gpg_vstate.slot);
break;
/* ----------------- Application ----------------- */
/* Full Application identifier */
case 0x004F:
gpg_io_insert(N_gpg_pstate->AID, 16);
break;
/* Historical bytes, */
case 0x5F52:
gpg_io_insert(N_gpg_pstate->histo, 15);
break;
/* Extended length information */
case 0x7F66:
gpg_io_insert(C_ext_length, sizeof(C_ext_length));
break;
/* ----------------- User -----------------*/
/* Login data */
case 0x005E:
gpg_io_insert(N_gpg_pstate->login.value, N_gpg_pstate->login.length);
break;
/* Uniform resource locator */
case 0x5F50:
gpg_io_insert(N_gpg_pstate->url.value, N_gpg_pstate->url.length);
break;
/* Name, Language, Sex */
case 0x65:
gpg_io_insert_tlv(0x5B, N_gpg_pstate->name.length, N_gpg_pstate->name.value);
gpg_io_insert_tlv(0x5F2D, N_gpg_pstate->lang.length, N_gpg_pstate->lang.value);
gpg_io_insert_tlv(0x5F35, 1, N_gpg_pstate->sex);
break;
/* ----------------- aid, histo, ext_length, ... ----------------- */
case 0x6E:
gpg_io_insert_tlv(0x4F, 16, N_gpg_pstate->AID);
gpg_io_insert_tlv(0x5F52, 15, N_gpg_pstate->histo);
gpg_io_insert_tlv(0x7F66, sizeof(C_ext_length), C_ext_length);
gpg_io_mark();
gpg_io_insert_tlv(0xC0,
sizeof(C_ext_capabilities),
C_ext_capabilities);
gpg_io_insert_tlv(0xC1, G_gpg_vstate.kslot->sig.attributes.length, G_gpg_vstate.kslot->sig.attributes.value);
gpg_io_insert_tlv(0xC2, G_gpg_vstate.kslot->dec.attributes.length, G_gpg_vstate.kslot->dec.attributes.value);
gpg_io_insert_tlv(0xC3, G_gpg_vstate.kslot->aut.attributes.length, G_gpg_vstate.kslot->aut.attributes.value);
gpg_io_insert_tl(0xC4, 7);
gpg_io_insert(N_gpg_pstate->PW_status,4);
gpg_io_insert_u8(N_gpg_pstate->PW1.counter);
gpg_io_insert_u8(N_gpg_pstate->RC.counter);
gpg_io_insert_u8(N_gpg_pstate->PW3.counter);
gpg_io_insert_tl(0xC5, 60);
gpg_io_insert(G_gpg_vstate.kslot->sig.fingerprints, 20);
gpg_io_insert(G_gpg_vstate.kslot->dec.fingerprints, 20);
gpg_io_insert(G_gpg_vstate.kslot->aut.fingerprints, 20);
gpg_io_insert_tl(0xC6, 60);
gpg_io_insert(G_gpg_vstate.kslot->sig.CA_fingerprints, 20);
gpg_io_insert(G_gpg_vstate.kslot->dec.CA_fingerprints, 20);
gpg_io_insert(G_gpg_vstate.kslot->aut.CA_fingerprints, 20);
gpg_io_insert_tl(0xCD, 12);
gpg_io_insert(G_gpg_vstate.kslot->sig.date, 4);
gpg_io_insert(G_gpg_vstate.kslot->dec.date, 4);
gpg_io_insert(G_gpg_vstate.kslot->aut.date, 4);
gpg_io_set_offset(IO_OFFSET_MARK);
gpg_io_insert_tl(0x73, G_gpg_vstate.io_length- G_gpg_vstate.io_offset);
gpg_io_set_offset(IO_OFFSET_END);
break;
/* ----------------- User Interaction Flag (UIF) for PSO:CDS ----------------- */
case 0x00D6:
gpg_io_insert(G_gpg_vstate.kslot->sig.UIF, 2);
break;
case 0x00D7:
gpg_io_insert(G_gpg_vstate.kslot->dec.UIF, 2);
break;
case 0x00D8:
gpg_io_insert(G_gpg_vstate.kslot->aut.UIF, 2);
break;
/* ----------------- Security support template ----------------- */
case 0x7A:
gpg_io_insert_tl(0x93,3);
gpg_io_insert_u24(G_gpg_vstate.kslot->sig_count);
break;
/* ----------------- Cardholder certificate ----------------- */
case 0x7F21:
switch (G_gpg_vstate.DO_reccord) {
case 0:
gpg_io_insert(G_gpg_vstate.kslot->aut.CA.value,G_gpg_vstate.kslot->aut.CA.length);
break;
case 1:
gpg_io_insert(G_gpg_vstate.kslot->dec.CA.value,G_gpg_vstate.kslot->dec.CA.length);
break;
case 2:
gpg_io_insert(G_gpg_vstate.kslot->sig.CA.value,G_gpg_vstate.kslot->sig.CA.length);
break;
default :
sw = SW_RECORD_NOT_FOUND;
}
break;
/* ----------------- PW Status Bytes ----------------- */
case 0x00C4:
gpg_io_insert(N_gpg_pstate->PW_status,4);
gpg_io_insert_u8(N_gpg_pstate->PW1.counter);
gpg_io_insert_u8(N_gpg_pstate->RC.counter);
gpg_io_insert_u8(N_gpg_pstate->PW3.counter);
break;
/* WAT */
default:
sw = SW_REFERENCED_DATA_NOT_FOUND;
break;
}
return sw;
}
int gpg_apdu_get_next_data(unsigned int ref) {
int sw;
if ((ref != 0x7F21) || (G_gpg_vstate.DO_current != 0x7F21)) {
return SW_CONDITIONS_NOT_SATISFIED;
}
sw = gpg_apdu_get_data(ref);
if (sw == SW_OK) {
G_gpg_vstate.DO_reccord++;
}
return sw;
}
int gpg_apdu_put_data(unsigned int ref) {
unsigned int t,l,sw;
unsigned int *ptr_l;
unsigned char *ptr_v;
G_gpg_vstate.DO_current = ref;
sw = SW_OK;
switch (ref) {
/* ----------------- Optional DO for private use ----------------- */
case 0x0101:
ptr_l = &N_gpg_pstate->private_DO1.length;
ptr_v = N_gpg_pstate->private_DO1.value;
goto WRITE_PRIVATE_DO;
case 0x0102:
ptr_l = &N_gpg_pstate->private_DO2.length;
ptr_v = N_gpg_pstate->private_DO2.value;
goto WRITE_PRIVATE_DO;
case 0x0103:
ptr_l = &N_gpg_pstate->private_DO3.length;
ptr_v = N_gpg_pstate->private_DO3.value;
goto WRITE_PRIVATE_DO;
case 0x0104:
ptr_l = &N_gpg_pstate->private_DO4.length;
ptr_v = N_gpg_pstate->private_DO4.value;
goto WRITE_PRIVATE_DO;
WRITE_PRIVATE_DO:
if (G_gpg_vstate.io_length > GPG_EXT_PRIVATE_DO_LENGTH) {
THROW(SW_WRONG_LENGTH);
}
gpg_nvm_write(ptr_v, G_gpg_vstate.work.io_buffer+G_gpg_vstate.io_offset, G_gpg_vstate.io_length);
gpg_nvm_write(ptr_l, &G_gpg_vstate.io_length, sizeof(unsigned int));
sw = SW_OK;
break;
/* ----------------- Config key slot ----------------- */
case 0x01F1:
if (G_gpg_vstate.io_length != 3) {
THROW(SW_WRONG_LENGTH);
}
if ((G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset +0] != GPG_KEYS_SLOTS) ||
(G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset +1] >= GPG_KEYS_SLOTS) ||
(G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset +2] > 3)) {
THROW(SW_WRONG_DATA);
}
gpg_nvm_write(N_gpg_pstate->config_slot, G_gpg_vstate.work.io_buffer+G_gpg_vstate.io_offset,3);
sw = SW_OK;
break;
case 0x01F2:
if (G_gpg_vstate.io_length != 1) {
THROW(SW_WRONG_LENGTH);
}
if (G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset] >= GPG_KEYS_SLOTS) {
THROW(SW_WRONG_DATA);
}
G_gpg_vstate.slot = G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset];
sw = SW_OK;
break;
/* ----------------- Serial -----------------*/
case 0x4f:
if (G_gpg_vstate.io_length != 4) {
THROW(SW_WRONG_LENGTH);
}
nvm_write(&N_gpg_pstate->AID[10], &G_gpg_vstate.work.io_buffer[G_gpg_vstate.io_offset], 4);
sw = SW_OK;
break;
/* ----------------- Extended Header list -----------------*/
case 0x3FFF: {
void *pkey,*vkey;
unsigned int len_e,len_p,len_q;
unsigned int endof,ksz,reset_cnt;
gpg_key_t *keygpg;
unsigned int dh;
//fecth 4D
gpg_io_fetch_tl(&t,&l);
if (t!=0x4D) {
THROW(SW_REFERENCED_DATA_NOT_FOUND);
}
//fecth B8/B6/A4
gpg_io_fetch_tl(&t,&l);
dh = 0;
reset_cnt = 0;
switch(t) {
case 0xB6:
keygpg = &G_gpg_vstate.kslot->sig;
reset_cnt = 0x11111111;
break;
case 0xA4:
keygpg = &G_gpg_vstate.kslot->aut;
break;
case 0xB8:
keygpg = &G_gpg_vstate.kslot->dec;
dh = 0x11;
break;
default:
THROW(SW_REFERENCED_DATA_NOT_FOUND);
}
//fecth 7f78
gpg_io_fetch_tl(&t,&l);
if (t!=0x7f48) {
THROW(SW_REFERENCED_DATA_NOT_FOUND);
}
len_e = 0; len_p = 0; len_q = 0;
endof = G_gpg_vstate.io_offset+l;
while (G_gpg_vstate.io_offset<endof) {
gpg_io_fetch_tl(&t,&l);
switch (t) {
case 0x91:
len_e = l;
break;
case 0x92:
len_p = l;
break;
case 0x93:
len_q = l;
break;
break;
case 0x94:
case 0x95:
case 0x96:
case 0x97:
break;
default:
THROW(SW_REFERENCED_DATA_NOT_FOUND);
}
}
//fecth 5f78
gpg_io_fetch_tl(&t,&l);
if (t!=0x5f48) {
THROW(SW_REFERENCED_DATA_NOT_FOUND);
}
// --- RSA KEY ---
if (keygpg->attributes.value[0] == 0x01) {
unsigned int e;
unsigned char *p,*q,*pq;
cx_rsa_public_key_t *rsa_pub;
cx_rsa_private_key_t *rsa_priv, *pkey;
unsigned int pkey_size;
//check length
ksz = (keygpg->attributes.value[1]<<8)|keygpg->attributes.value[2];
ksz = ksz >> 3;
switch(ksz) {
case 1024/8:
rsa_pub = (cx_rsa_public_key_t*)&G_gpg_vstate.work.rsa1024.public;
rsa_priv = (cx_rsa_private_key_t*)&G_gpg_vstate.work.rsa1024.private;
pkey = (cx_rsa_private_key_t*)&keygpg->key.rsa1024;
pkey_size = sizeof(cx_rsa_1024_private_key_t);
break;
case 2048/8:
rsa_pub = (cx_rsa_public_key_t*)&G_gpg_vstate.work.rsa2048.public;
rsa_priv = (cx_rsa_private_key_t*)&G_gpg_vstate.work.rsa2048.private;
pkey = (cx_rsa_private_key_t*)&keygpg->key.rsa2048;
pkey_size = sizeof(cx_rsa_2048_private_key_t);
break;
case 3072/8:
rsa_pub = (cx_rsa_public_key_t*)&G_gpg_vstate.work.rsa3072.public;
rsa_priv = (cx_rsa_private_key_t*)&G_gpg_vstate.work.rsa3072.private;
pkey = (cx_rsa_private_key_t*)&keygpg->key.rsa3072;
pkey_size = sizeof(cx_rsa_3072_private_key_t);
break;
case 4096/8:
rsa_pub = (cx_rsa_public_key_t*)&G_gpg_vstate.work.rsa4096.public;
rsa_priv = (cx_rsa_private_key_t*)&G_gpg_vstate.work.rsa4096.private;
pkey = (cx_rsa_private_key_t*)&keygpg->key.rsa4096;
pkey_size = sizeof(cx_rsa_4096_private_key_t);
break;
}
ksz = ksz>>1;
if ( (len_e>4)||(len_e==0) ||
(len_p > ksz )||
(len_q > ksz)) {
THROW(SW_WRONG_DATA);
}
//fetch e
e = 0;
switch(len_e) {
case 4:
e = (e<<8) | gpg_io_fetch_u8();
case 3:
e = (e<<8) | gpg_io_fetch_u8();
case 2:
e = (e<<8) | gpg_io_fetch_u8();
case 1:
e = (e<<8) | gpg_io_fetch_u8();
}
//move p,q over pub key, this only work because adr<rsa_pub> < adr<p>
p = G_gpg_vstate.work.io_buffer + G_gpg_vstate.io_offset;
q = p + len_p;
pq = (unsigned char*)rsa_pub;
os_memmove(pq+ksz-len_p, p, len_p);
os_memmove(pq+2*ksz-len_q, q, len_q);
os_memset(pq, 0, ksz-len_p);
os_memset(pq+ksz, 0, ksz-len_q);
//regenerate RSA private key
cx_rsa_generate_pair(ksz<<1, rsa_pub, rsa_priv, e, pq);
//write keys
nvm_write(&keygpg->pub_key.rsa, rsa_pub->e, 4);
nvm_write(pkey, rsa_priv, pkey_size);
if (reset_cnt) {
reset_cnt = 0;
nvm_write(&G_gpg_vstate.kslot->sig_count,&reset_cnt,sizeof(unsigned int));
}
}
// --- ECC KEY ---
else if ((keygpg->attributes.value[0] == 19) ||
(keygpg->attributes.value[0] == 18) ||
(keygpg->attributes.value[0] == 22) ) {
unsigned int curve;
ksz = 0;
curve = gpg_oid2curve(&keygpg->attributes.value[1], keygpg->attributes.length-1);
if (curve == 0) {
THROW(SW_WRONG_DATA);
}
ksz = 32;
if (ksz == 32) {
G_gpg_vstate.work.ecfp256.private.curve = curve;
G_gpg_vstate.work.ecfp256.private.d_len = ksz;
os_memmove(G_gpg_vstate.work.ecfp256.private.d, G_gpg_vstate.work.io_buffer+G_gpg_vstate.io_offset,ksz);
cx_ecfp_generate_pair(curve, &G_gpg_vstate.work.ecfp256.public, &G_gpg_vstate.work.ecfp256.private, 1);
nvm_write(&keygpg->pub_key.ecfp256, &G_gpg_vstate.work.ecfp256.public, sizeof(cx_ecfp_public_key_t));
nvm_write(&keygpg->key.ecfp256, &G_gpg_vstate.work.ecfp256.private, sizeof(cx_ecfp_private_key_t));
if (reset_cnt) {
reset_cnt = 0;
nvm_write(&G_gpg_vstate.kslot->sig_count,&reset_cnt,sizeof(unsigned int));
}
}
}
// --- UNSUPPORTED KEY ---
else {
THROW(SW_REFERENCED_DATA_NOT_FOUND);
}
break;
} //endof of 3fff
/* ----------------- User -----------------*/
/* Name */
case 0x5B:
if (G_gpg_vstate.io_length > sizeof(N_gpg_pstate->name.value)) {
THROW(SW_WRONG_LENGTH);
}
gpg_nvm_write(N_gpg_pstate->name.value, G_gpg_vstate.work.io_buffer, G_gpg_vstate.io_length);
gpg_nvm_write(&N_gpg_pstate->name.length, &G_gpg_vstate.io_length, sizeof(unsigned int));
sw = SW_OK;
break;
/* Login data */
case 0x5E:
if (G_gpg_vstate.io_length > sizeof(N_gpg_pstate->login.value)) {
THROW(SW_WRONG_LENGTH);
}
gpg_nvm_write(N_gpg_pstate->login.value, G_gpg_vstate.work.io_buffer, G_gpg_vstate.io_length);
gpg_nvm_write(&N_gpg_pstate->login.length, &G_gpg_vstate.io_length, sizeof(unsigned int));
sw = SW_OK;
break;
/* Language preferences */
case 0x5F2D:
if (G_gpg_vstate.io_length > sizeof(N_gpg_pstate->lang.value)) {
THROW(SW_WRONG_LENGTH);
}
gpg_nvm_write(N_gpg_pstate->lang.value, G_gpg_vstate.work.io_buffer, G_gpg_vstate.io_length);
gpg_nvm_write(&N_gpg_pstate->lang.length, &G_gpg_vstate.io_length, sizeof(unsigned int));
sw = SW_OK;
break;
/* Sex */
case 0x5F35:
if (G_gpg_vstate.io_length != sizeof(N_gpg_pstate->sex)) {
THROW(SW_WRONG_LENGTH);
}
gpg_nvm_write(N_gpg_pstate->sex, G_gpg_vstate.work.io_buffer, G_gpg_vstate.io_length);
sw = SW_OK;
break;
/* Uniform resource locator */
case 0x5F50:
if (G_gpg_vstate.io_length > sizeof(N_gpg_pstate->url.value)) {
THROW(SW_WRONG_LENGTH);
}
gpg_nvm_write(N_gpg_pstate->url.value, G_gpg_vstate.work.io_buffer, G_gpg_vstate.io_length);
gpg_nvm_write(&N_gpg_pstate->url.length, &G_gpg_vstate.io_length, sizeof(unsigned int));
sw = SW_OK;
break;
/* ----------------- Cardholder certificate ----------------- */
case 0x7F21:
ptr_v = NULL;
switch ( G_gpg_vstate.DO_reccord) {
case 0:
ptr_l = &G_gpg_vstate.kslot->aut.CA.length;
ptr_v = G_gpg_vstate.kslot->aut.CA.value;
goto WRITE_CA;
case 1:
ptr_l = &G_gpg_vstate.kslot->sig.CA.length;
ptr_v = G_gpg_vstate.kslot->sig.CA.value;
goto WRITE_CA;
case 2:
ptr_l = &G_gpg_vstate.kslot->dec.CA.length;
ptr_v = G_gpg_vstate.kslot->dec.CA.value;
goto WRITE_CA;
default:
sw = SW_REFERENCED_DATA_NOT_FOUND;
break;
}
WRITE_CA:
if (G_gpg_vstate.io_length > GPG_EXT_CARD_HOLDER_CERT_LENTH) {
THROW(SW_WRONG_LENGTH);
}
gpg_nvm_write(ptr_v, G_gpg_vstate.work.io_buffer, G_gpg_vstate.io_length);
gpg_nvm_write(ptr_l, &G_gpg_vstate.io_length, sizeof(unsigned int));
sw = SW_OK;
break;
/* ----------------- Algorithm attributes ----------------- */
case 0xC1:
ptr_l = &G_gpg_vstate.kslot->sig.attributes.length;
ptr_v = G_gpg_vstate.kslot->sig.attributes.value;
goto WRITE_ATTRIBUTES;
case 0xC2:
ptr_l = &G_gpg_vstate.kslot->dec.attributes.length;
ptr_v = G_gpg_vstate.kslot->dec.attributes.value;
goto WRITE_ATTRIBUTES;
case 0xC3:
ptr_l = &G_gpg_vstate.kslot->aut.attributes.length;
ptr_v = G_gpg_vstate.kslot->aut.attributes.value;
goto WRITE_ATTRIBUTES;
WRITE_ATTRIBUTES:
if (G_gpg_vstate.io_length > 12) {
THROW(SW_WRONG_LENGTH);
}
gpg_nvm_write(ptr_v, G_gpg_vstate.work.io_buffer, G_gpg_vstate.io_length);
gpg_nvm_write(ptr_l, &G_gpg_vstate.io_length, sizeof(unsigned int));
sw = SW_OK;
break;
/* ----------------- PWS status ----------------- */
case 0xC4:
gpg_io_fetch_nv(N_gpg_pstate->PW_status, 1);
break;
/* ----------------- Fingerprints ----------------- */
case 0xC7:
ptr_v = G_gpg_vstate.kslot->sig.fingerprints;
goto WRITE_FINGERPRINTS;
case 0xC8:
ptr_v = G_gpg_vstate.kslot->dec.fingerprints;
goto WRITE_FINGERPRINTS;
case 0xC9:
ptr_v =G_gpg_vstate.kslot->aut.fingerprints;
goto WRITE_FINGERPRINTS;
case 0xCA:
ptr_v = G_gpg_vstate.kslot->sig.CA_fingerprints;
goto WRITE_FINGERPRINTS;
case 0xCB:
ptr_v = G_gpg_vstate.kslot->dec.CA_fingerprints;
goto WRITE_FINGERPRINTS;
case 0xCC:
ptr_v = G_gpg_vstate.kslot->aut.CA_fingerprints;
goto WRITE_FINGERPRINTS;
WRITE_FINGERPRINTS:
if (G_gpg_vstate.io_length != 20) {
THROW(SW_WRONG_LENGTH);
}
gpg_nvm_write(ptr_v, G_gpg_vstate.work.io_buffer, 20);
sw = SW_OK;
break;
/* ----------------- Generation date/time ----------------- */
case 0xCE:
ptr_v = G_gpg_vstate.kslot->sig.date;
goto WRITE_DATE;
case 0xCF:
ptr_v = G_gpg_vstate.kslot->dec.date;
goto WRITE_DATE;
case 0xD0:
ptr_v = G_gpg_vstate.kslot->aut.date;
goto WRITE_DATE;
WRITE_DATE:
if (G_gpg_vstate.io_length != 4) {
THROW(SW_WRONG_LENGTH);
}
gpg_nvm_write(ptr_v, G_gpg_vstate.work.io_buffer, 4);
sw = SW_OK;
break;
/* ----------------- AES key ----------------- */
{
void *pkey;
cx_aes_key_t aes_key;
case 0xD1:
pkey = &N_gpg_pstate->SM_enc;
goto init_aes_key;
case 0xD2:
pkey = &N_gpg_pstate->SM_mac;
goto init_aes_key;
case 0xD5:
pkey = &G_gpg_vstate.kslot->AES_dec;
goto init_aes_key;
init_aes_key:
cx_aes_init_key(G_gpg_vstate.work.io_buffer, G_gpg_vstate.io_length, &aes_key);
gpg_nvm_write(pkey, &aes_key, sizeof(cx_aes_key_t));
break;
/* AES key: one shot */
case 0xF4:
cx_aes_init_key(G_gpg_vstate.work.io_buffer, G_gpg_vstate.io_length, &aes_key);
gpg_nvm_write(&N_gpg_pstate->SM_enc, &aes_key, sizeof(cx_aes_key_t));
cx_aes_init_key(G_gpg_vstate.work.io_buffer+16, G_gpg_vstate.io_length, &aes_key);
gpg_nvm_write(&N_gpg_pstate->SM_mac, &aes_key, sizeof(cx_aes_key_t));
break;
}
/* ----------------- RC ----------------- */
case 0xD3:
sw = gpg_apdu_change_ref_data(ID_RC);
break;
/* ----------------- UIF ----------------- */
case 0xD6:
ptr_v = G_gpg_vstate.kslot->sig.UIF;
goto WRITE_UIF;
case 0xD7:
ptr_v = G_gpg_vstate.kslot->dec.UIF;
goto WRITE_UIF;
case 0xD8:
ptr_v = G_gpg_vstate.kslot->aut.UIF;
goto WRITE_UIF;
WRITE_UIF:
if (G_gpg_vstate.io_length != 2) {
THROW(SW_WRONG_LENGTH);
}
gpg_nvm_write(ptr_v, G_gpg_vstate.work.io_buffer, 2);
sw = SW_OK;
break;
/* ----------------- WAT ----------------- */
default:
sw = SW_REFERENCED_DATA_NOT_FOUND;
break;
}
gpg_io_discard(1);
return sw;
}