Support modifiable key algo attrs and divert on runtime

This commit is contained in:
NIIBE Yutaka
2014-12-12 13:45:58 +09:00
parent 8f33df9819
commit 9cba1e2a8e
4 changed files with 282 additions and 303 deletions

View File

@@ -1,3 +1,22 @@
2014-11-21 Niibe Yutaka <gniibe@fsij.org>
* src/gnuk.h (ALGO_RSA4K, ALGO_NISTP256R1, ALGO_SECP256K1)
(ALGO_ED25519, ALGO_RSA2K): New.
(struct key_data_internal): Move to ...
* src/openpgp-do.c (struct key_data_internal): ... here.
(CHECKSUM_ADDR, kdi_len): New.
(CKDC_CALC, CKDC_CHECK): New.
(compute_key_data_checksum): Add arg PRVKEY_LEN.
(gpg_do_load_prvkey, gpg_do_delete_prvkey): Support modifiable key
algo attributes.
(gpg_do_write_prvkey, gpg_do_public_key, gpg_do_keygen): Likewise.
(gpg_do_clear_prvkey): Use MAX_PRVKEY_LEN.
* src/openpgp.c (gpg_init): Call flash_init_keys after
gpg_data_scan.
(cmd_pso): Support modifiable key algo attributes.
(cmd_internal_authenticate): Likewise.
2014-11-21 Niibe Yutaka <gniibe@fsij.org>
* src/openpgp-do.c (algorithm_attr_rsa2k): Rename from *_rsa.

View File

@@ -109,6 +109,12 @@ void gpg_do_keygen (uint8_t kk_byte);
const uint8_t *gpg_get_firmware_update_key (uint8_t keyno);
/* Constants: algo+size */
#define ALGO_RSA4K 0
#define ALGO_NISTP256R1 1
#define ALGO_SECP256K1 2
#define ALGO_ED25519 3
#define ALGO_RSA2K 255
enum kind_of_key {
GPG_KEY_FOR_SIGNING = 0,
@@ -122,6 +128,9 @@ enum size_of_key {
GPG_KEY_PRIVATE,
};
int gpg_get_algo_attr (enum kind_of_key kk);
int gpg_get_algo_attr_key_size (enum kind_of_key kk, enum size_of_key s);
const uint8_t *flash_init (void);
void flash_init_keys (void);
void flash_do_release (const uint8_t *);
@@ -160,18 +169,10 @@ extern uint8_t random_bits_start;
#define MAX_PRVKEY_LEN 512 /* Maximum is the case for RSA 4096-bit. */
struct key_data {
const uint8_t *pubkey; /* Pointer to public key*/
const uint8_t *pubkey; /* Pointer to public key */
uint8_t data[MAX_PRVKEY_LEN]; /* decrypted private key data content */
};
struct key_data_internal {
uint32_t data[KEY_CONTENT_LEN/4]; /*
* Secret key data.
* RSA: p and q, ECDSA: d, EdDSA: a+seed
*/
uint32_t checksum[DATA_ENCRYPTION_KEY_SIZE/4];
};
struct prvkey_data {
/*
* IV: Initial Vector
@@ -260,11 +261,15 @@ uint8_t *rsa_genkey (int);
int ecdsa_sign_p256r1 (const uint8_t *hash, uint8_t *output,
const uint8_t *key_data);
uint8_t *ecdsa_compute_public_p256r1 (const uint8_t *key_data);
uint8_t *ecc_compute_public_p256r1 (const uint8_t *key_data);
int ecdh_decrypt_p256r1 (const uint8_t *input, uint8_t *output,
const uint8_t *key_data);
int ecdsa_sign_p256k1 (const uint8_t *hash, uint8_t *output,
const uint8_t *key_data);
uint8_t *ecdsa_compute_public_p256k1 (const uint8_t *key_data);
uint8_t *ecc_compute_public_p256k1 (const uint8_t *key_data);
int ecdh_decrypt_p256k1 (const uint8_t *input, uint8_t *output,
const uint8_t *key_data);
int eddsa_sign_25519 (const uint8_t *input, size_t ilen, uint32_t *output,
const uint8_t *sk_a, const uint8_t *seed,

View File

@@ -861,26 +861,42 @@ get_do_ptr_nr_for_kk (enum kind_of_key kk)
void
gpg_do_clear_prvkey (enum kind_of_key kk)
{
memset (kd[kk].data, 0, KEY_CONTENT_LEN);
memset (kd[kk].data, 0, MAX_PRVKEY_LEN);
}
#define CHECKSUM_ADDR(kdi,prvkey_len) \
(&(kdi).data[prvkey_len / sizeof (uint32_t)])
#define kdi_len(prvkey_len) (prvkey_len+DATA_ENCRYPTION_KEY_SIZE)
struct key_data_internal {
uint32_t data[(MAX_PRVKEY_LEN+DATA_ENCRYPTION_KEY_SIZE) / sizeof (uint32_t)];
/*
* Secret key data.
* RSA: p and q, ECDSA/ECDH: d, EdDSA: a+seed
*/
/* Checksum */
};
#define CKDC_CALC 0
#define CKDC_CHECK 1
static int
compute_key_data_checksum (struct key_data_internal *kdi, int check_or_calc)
compute_key_data_checksum (struct key_data_internal *kdi, int prvkey_len,
int check_or_calc)
{
unsigned int i;
uint32_t d[4] = { 0, 0, 0, 0 };
uint32_t *checksum = CHECKSUM_ADDR (*kdi, prvkey_len);
for (i = 0; i < KEY_CONTENT_LEN / sizeof (uint32_t); i++)
for (i = 0; i < prvkey_len / sizeof (uint32_t); i++)
d[i&3] ^= kdi->data[i];
if (check_or_calc == 0) /* store */
if (check_or_calc == CKDC_CALC) /* store */
{
memcpy (kdi->checksum, d, DATA_ENCRYPTION_KEY_SIZE);
memcpy (checksum, d, DATA_ENCRYPTION_KEY_SIZE);
return 0;
}
else /* check */
return memcmp (kdi->checksum, d, DATA_ENCRYPTION_KEY_SIZE) == 0;
return memcmp (checksum, d, DATA_ENCRYPTION_KEY_SIZE) == 0;
}
/*
@@ -892,6 +908,7 @@ int
gpg_do_load_prvkey (enum kind_of_key kk, int who, const uint8_t *keystring)
{
uint8_t nr = get_do_ptr_nr_for_kk (kk);
int prvkey_len = gpg_get_algo_attr_key_size (kk, GPG_KEY_PRIVATE);
const uint8_t *do_data = do_ptr[nr];
const uint8_t *key_addr;
uint8_t dek[DATA_ENCRYPTION_KEY_SIZE];
@@ -904,24 +921,25 @@ gpg_do_load_prvkey (enum kind_of_key kk, int who, const uint8_t *keystring)
if (do_data == NULL)
return 0;
key_addr = kd[kk].key_addr;
memcpy (kdi.data, key_addr, KEY_CONTENT_LEN);
key_addr = kd[kk].pubkey - prvkey_len;
memcpy (kdi.data, key_addr, prvkey_len);
iv = &do_data[1];
memcpy (kdi.checksum, iv + INITIAL_VECTOR_SIZE, DATA_ENCRYPTION_KEY_SIZE);
memcpy (CHECKSUM_ADDR (kdi, prvkey_len),
iv + INITIAL_VECTOR_SIZE, DATA_ENCRYPTION_KEY_SIZE);
memcpy (dek, iv+16*(who+1), DATA_ENCRYPTION_KEY_SIZE);
memcpy (dek, iv + DATA_ENCRYPTION_KEY_SIZE*(who+1), DATA_ENCRYPTION_KEY_SIZE);
decrypt_dek (keystring, dek);
decrypt (dek, iv, (uint8_t *)&kdi, sizeof (struct key_data_internal));
decrypt (dek, iv, (uint8_t *)&kdi, kdi_len (prvkey_len));
memset (dek, 0, DATA_ENCRYPTION_KEY_SIZE);
if (!compute_key_data_checksum (&kdi, 1))
if (!compute_key_data_checksum (&kdi, prvkey_len, CKDC_CHECK))
{
DEBUG_INFO ("gpg_do_load_prvkey failed.\r\n");
return -1;
}
memcpy (kd[kk].data, kdi.data, KEY_CONTENT_LEN);
DEBUG_BINARY (kd[kk].data, KEY_CONTENT_LEN);
memcpy (kd[kk].data, kdi.data, prvkey_len);
DEBUG_BINARY (kd[kk].data, prvkey_len);
return 1;
}
@@ -934,15 +952,17 @@ gpg_do_delete_prvkey (enum kind_of_key kk)
uint8_t nr = get_do_ptr_nr_for_kk (kk);
const uint8_t *do_data = do_ptr[nr];
uint8_t *key_addr;
int prvkey_len = gpg_get_algo_attr_key_size (kk, GPG_KEY_PRIVATE);
int key_size = gpg_get_algo_attr_key_size (kk, GPG_KEY_STORAGE);
if (do_data == NULL)
return;
do_ptr[nr] = NULL;
flash_do_release (do_data);
key_addr = kd[kk].key_addr;
kd[kk].key_addr = NULL;
flash_key_release (key_addr);
key_addr = (uint8_t *)kd[kk].pubkey - prvkey_len;
kd[kk].pubkey = NULL;
flash_key_release (key_addr, key_size);
if (admin_authorized == BY_ADMIN && kk == GPG_KEY_FOR_SIGNING)
{ /* Recover admin keystring DO. */
@@ -973,10 +993,12 @@ gpg_do_delete_prvkey (enum kind_of_key kk)
}
static int
gpg_do_write_prvkey (enum kind_of_key kk, const uint8_t *key_data, int key_len,
const uint8_t *keystring_admin, const uint8_t *pubkey)
gpg_do_write_prvkey (enum kind_of_key kk, const uint8_t *key_data,
int prvkey_len, const uint8_t *keystring_admin,
const uint8_t *pubkey)
{
uint8_t nr = get_do_ptr_nr_for_kk (kk);
int attr = gpg_get_algo_attr (kk);;
const uint8_t *p;
int r;
struct prvkey_data *pd;
@@ -984,86 +1006,52 @@ gpg_do_write_prvkey (enum kind_of_key kk, const uint8_t *key_data, int key_len,
const uint8_t *dek, *iv;
struct key_data_internal kdi;
uint8_t *pubkey_allocated_here = NULL;
int pubkey_len = KEY_CONTENT_LEN;
int pubkey_len;
uint8_t ks[KEYSTRING_MD_SIZE];
enum kind_of_key kk0;
DEBUG_INFO ("Key import\r\n");
DEBUG_SHORT (key_len);
DEBUG_SHORT (prvkey_len);
/* Delete it first, if any. */
gpg_do_delete_prvkey (kk);
#if defined(RSA_AUTH) && defined(RSA_SIG)
if (key_len != KEY_CONTENT_LEN)
return -1;
#elif defined(RSA_AUTH) && !defined(RSA_SIG)
/* ECDSA with p256k1 for signature */
if (kk != GPG_KEY_FOR_SIGNING && key_len != KEY_CONTENT_LEN)
return -1;
if (kk == GPG_KEY_FOR_SIGNING)
{
pubkey_len = key_len * 2;
if (key_len != 32)
return -1;
}
#elif !defined(RSA_AUTH) && defined(RSA_SIG)
#if defined(ECDSA_AUTH)
/* ECDSA with p256r1 for authentication */
if (kk != GPG_KEY_FOR_AUTHENTICATION && key_len != KEY_CONTENT_LEN)
return -1;
if (kk == GPG_KEY_FOR_AUTHENTICATION)
{
pubkey_len = key_len * 2;
if (key_len != 32)
return -1;
}
#else
/* EdDSA with Ed25519 for authentication */
if (kk != GPG_KEY_FOR_AUTHENTICATION && key_len != KEY_CONTENT_LEN)
return -1;
if (kk == GPG_KEY_FOR_AUTHENTICATION)
{
pubkey_len = key_len / 2;
if (key_len != 64)
return -1;
}
#endif
#else
#error "not supported."
#endif
pd = (struct prvkey_data *)malloc (sizeof (struct prvkey_data));
if (pd == NULL)
return -1;
if (attr == ALGO_NISTP256R1 || attr == ALGO_SECP256K1)
{
pubkey_len = prvkey_len * 2;
if (prvkey_len != 32)
return -1;
}
else if (attr == ALGO_ED25519)
{
pubkey_len = prvkey_len / 2;
if (prvkey_len != 64)
return -1;
}
else /* RSA */
{
int key_size = gpg_get_algo_attr_key_size (kk, GPG_KEY_STORAGE);
pubkey_len = prvkey_len;
if (prvkey_len + pubkey_len != key_size)
return -1;
}
if (pubkey == NULL)
{
#if defined(RSA_AUTH) && defined(RSA_SIG)
pubkey_allocated_here = modulus_calc (key_data, key_len);
#elif defined(RSA_AUTH) && !defined(RSA_SIG)
/* ECDSA with p256k1 for signature */
if (kk == GPG_KEY_FOR_SIGNING)
pubkey_allocated_here = ecdsa_compute_public_p256k1 (key_data);
else
pubkey_allocated_here = modulus_calc (key_data, key_len);
#elif !defined(RSA_AUTH) && defined(RSA_SIG)
#if defined(ECDSA_AUTH)
/* ECDSA with p256r1 for authentication */
if (kk == GPG_KEY_FOR_AUTHENTICATION)
pubkey_allocated_here = ecdsa_compute_public_p256r1 (key_data);
else
pubkey_allocated_here = modulus_calc (key_data, key_len);
#else
/* EdDSA with Ed25519 for authentication */
if (kk == GPG_KEY_FOR_AUTHENTICATION)
if (attr == ALGO_SECP256K1)
pubkey_allocated_here = ecc_compute_public_p256k1 (key_data);
else if (attr == ALGO_NISTP256R1)
pubkey_allocated_here = ecc_compute_public_p256r1 (key_data);
else if (attr == ALGO_ED25519)
pubkey_allocated_here = eddsa_compute_public_25519 (key_data);
else
pubkey_allocated_here = modulus_calc (key_data, key_len);
#endif
#else
#error "not supported."
#endif
else /* RSA */
pubkey_allocated_here = modulus_calc (key_data, prvkey_len);
if (pubkey_allocated_here == NULL)
{
free (pd);
@@ -1083,38 +1071,17 @@ gpg_do_write_prvkey (enum kind_of_key kk, const uint8_t *key_data, int key_len,
free (pd);
return -1;
}
kd[kk].key_addr = key_addr;
kd[kk].pubkey = key_addr + prvkey_len;
num_prv_keys++;
DEBUG_INFO ("key_addr: ");
DEBUG_WORD ((uint32_t)key_addr);
#if defined(RSA_AUTH) && defined(RSA_SIG)
memcpy (kdi.data, key_data, KEY_CONTENT_LEN);
#elif defined(RSA_AUTH) && !defined(RSA_SIG)
/* ECDSA with p256k1 for signature */
if (kk == GPG_KEY_FOR_SIGNING)
{
memcpy (kdi.data, key_data, key_len);
memset ((uint8_t *)kdi.data + key_len, 0, KEY_CONTENT_LEN - key_len);
}
else
memcpy (kdi.data, key_data, KEY_CONTENT_LEN);
#elif !defined(RSA_AUTH) && defined(RSA_SIG)
/* ECDSA with p256r1 for authentication */
/* EdDSA with Ed25519 for authentication */
if (kk == GPG_KEY_FOR_AUTHENTICATION)
{
memcpy (kdi.data, key_data, key_len);
memset ((uint8_t *)kdi.data + key_len, 0, KEY_CONTENT_LEN - key_len);
}
else
memcpy (kdi.data, key_data, KEY_CONTENT_LEN);
#else
#error "not supported."
#endif
compute_key_data_checksum (&kdi, 0);
memcpy (kdi.data, key_data, prvkey_len);
memset ((uint8_t *)kdi.data + prvkey_len, 0, MAX_PRVKEY_LEN - prvkey_len);
compute_key_data_checksum (&kdi, prvkey_len, CKDC_CALC);
dek = random_bytes_get (); /* 32-byte random bytes */
iv = dek + DATA_ENCRYPTION_KEY_SIZE;
@@ -1136,9 +1103,9 @@ gpg_do_write_prvkey (enum kind_of_key kk, const uint8_t *key_data, int key_len,
gpg_do_chks_prvkey (kk0, BY_RESETCODE, NULL, 0, NULL);
}
encrypt (dek, iv, (uint8_t *)&kdi, sizeof (struct key_data_internal));
encrypt (dek, iv, (uint8_t *)&kdi, kdi_len (prvkey_len));
r = flash_key_write (key_addr, (const uint8_t *)kdi.data,
r = flash_key_write (key_addr, (const uint8_t *)kdi.data, prvkey_len,
pubkey_allocated_here? pubkey_allocated_here: pubkey,
pubkey_len);
if (pubkey_allocated_here)
@@ -1156,7 +1123,8 @@ gpg_do_write_prvkey (enum kind_of_key kk, const uint8_t *key_data, int key_len,
}
memcpy (pd->iv, iv, INITIAL_VECTOR_SIZE);
memcpy (pd->checksum_encrypted, kdi.checksum, DATA_ENCRYPTION_KEY_SIZE);
memcpy (pd->checksum_encrypted, CHECKSUM_ADDR (kdi, prvkey_len),
DATA_ENCRYPTION_KEY_SIZE);
encrypt_dek (ks, pd->dek_encrypted_1);
@@ -1916,15 +1884,15 @@ gpg_do_put_data (uint16_t tag, const uint8_t *data, int len)
void
gpg_do_public_key (uint8_t kk_byte)
{
const uint8_t *key_addr;
enum kind_of_key kk;
enum kind_of_key kk = kkb_to_kk (kk_byte);
int attr = gpg_get_algo_attr (kk);
int pubkey_len = gpg_get_algo_attr_key_size (kk, GPG_KEY_PUBLIC);
const uint8_t *pubkey = kd[kk].pubkey;
DEBUG_INFO ("Public key\r\n");
DEBUG_BYTE (kk_byte);
kk = kkb_to_kk (kk_byte);
key_addr = kd[kk].key_addr;
if (key_addr == NULL)
if (pubkey == NULL)
{
DEBUG_INFO ("none.\r\n");
GPG_NO_RECORD ();
@@ -1936,20 +1904,8 @@ gpg_do_public_key (uint8_t kk_byte)
/* TAG */
*res_p++ = 0x7f; *res_p++ = 0x49;
#if defined(RSA_AUTH) && defined(RSA_SIG)
if (0)
#elif defined(RSA_AUTH) && !defined(RSA_SIG)
/* ECDSA with p256k1 for signature */
if (kk_byte == 0xb6)
#elif !defined(RSA_AUTH) && defined(RSA_SIG)
/* ECDSA with p256r1 for authentication */
/* EdDSA with Ed25519 for authentication */
if (kk_byte == 0xa4)
#else
#error "not supported."
#endif
#if defined(ECDSA_AUTH)
{ /* ECDSA */
if (attr == ALGO_NISTP256R1 || attr == ALGO_SECP256K1)
{ /* ECDSA or ECDH */
/* LEN */
*res_p++ = 2 + 1 + 64;
{
@@ -1957,11 +1913,11 @@ gpg_do_public_key (uint8_t kk_byte)
*res_p++ = 0x86; *res_p++ = 0x41;
*res_p++ = 0x04; /* No compression of EC point. */
/* 64-byte binary (big endian): X || Y */
memcpy (res_p, key_addr + KEY_CONTENT_LEN, 64);
memcpy (res_p, pubkey, 64);
res_p += 64;
}
}
#else /* EDDSA_AUTH */
else if (attr == ALGO_ED25519)
{ /* EdDSA */
/* LEN */
*res_p++ = 2 + 32;
@@ -1969,22 +1925,22 @@ gpg_do_public_key (uint8_t kk_byte)
/*TAG*/ /* LEN = 32 */
*res_p++ = 0x86; *res_p++ = 0x20;
/* 32-byte binary (little endian): Y with parity */
memcpy (res_p, key_addr + KEY_CONTENT_LEN, 32);
memcpy (res_p, pubkey, 32);
res_p += 32;
}
}
#endif
else
{ /* RSA */
/* LEN = 9+256 */
*res_p++ = 0x82; *res_p++ = 0x01; *res_p++ = 0x09;
/* LEN = 9+256or512 */
*res_p++ = 0x82; *res_p++ = pubkey_len > 256? 0x02: 0x01; *res_p++ = 0x09;
{
/*TAG*/ /* LEN = 256 */
*res_p++ = 0x81; *res_p++ = 0x82; *res_p++ = 0x01; *res_p++ = 0x00;
/* 256-byte binary (big endian) */
memcpy (res_p, key_addr + KEY_CONTENT_LEN, KEY_CONTENT_LEN);
res_p += 256;
/*TAG*/ /* LEN = 256or512 */
*res_p++ = 0x81;
*res_p++ = 0x82; *res_p++ = pubkey_len > 256? 0x02: 0x01;*res_p++ = 0x00;
/* PUBKEY_LEN-byte binary (big endian) */
memcpy (res_p, pubkey, pubkey_len);
res_p += pubkey_len;
}
{
/*TAG*/ /* LEN= 3 */
@@ -2038,7 +1994,8 @@ gpg_do_write_simple (uint8_t nr, const uint8_t *data, int size)
void
gpg_do_keygen (uint8_t kk_byte)
{
enum kind_of_key kk;
enum kind_of_key kk = kkb_to_kk (kk_byte);
int pubkey_len = gpg_get_algo_attr_key_size (kk, GPG_KEY_PUBLIC);
const uint8_t *keystring_admin;
uint8_t *p_q_modulus;
const uint8_t *p_q;
@@ -2048,13 +2005,12 @@ gpg_do_keygen (uint8_t kk_byte)
DEBUG_INFO ("Keygen\r\n");
DEBUG_BYTE (kk_byte);
kk = kkb_to_kk (kk_byte);
if (admin_authorized == BY_ADMIN)
keystring_admin = keystring_md_pw3;
else
keystring_admin = NULL;
p_q_modulus = rsa_genkey ();
p_q_modulus = rsa_genkey (pubkey_len);
if (p_q_modulus == NULL)
{
GPG_MEMORY_FAILURE ();
@@ -2062,10 +2018,10 @@ gpg_do_keygen (uint8_t kk_byte)
}
p_q = p_q_modulus;
modulus = p_q_modulus + KEY_CONTENT_LEN;
modulus = p_q_modulus + pubkey_len;
r = gpg_do_write_prvkey (kk, p_q, KEY_CONTENT_LEN, keystring_admin, modulus);
memset (p_q_modulus, 0, KEY_CONTENT_LEN*2);
r = gpg_do_write_prvkey (kk, p_q, pubkey_len, keystring_admin, modulus);
memset (p_q_modulus, 0, pubkey_len * 2);
free (p_q_modulus);
if (r < 0)
{

View File

@@ -107,6 +107,7 @@ gpg_init (void)
file_selection = FILE_NONE;
flash_data_start = flash_init ();
gpg_data_scan (flash_data_start);
flash_init_keys ();
}
static void
@@ -815,14 +816,21 @@ static void
cmd_pso (void)
{
int len = apdu.cmd_apdu_data_len;
int r;
int r = -1;
int attr;
int pubkey_len;
DEBUG_INFO (" - PSO: ");
DEBUG_WORD ((uint32_t)&r);
DEBUG_BINARY (apdu.cmd_apdu_data, apdu.cmd_apdu_data_len);
DEBUG_SHORT (len);
if (P1 (apdu) == 0x9e && P2 (apdu) == 0x9a)
{
attr = gpg_get_algo_attr (GPG_KEY_FOR_SIGNING);
pubkey_len = gpg_get_algo_attr_key_size (GPG_KEY_FOR_SIGNING,
GPG_KEY_PUBLIC);
if (!ac_check_status (AC_PSO_CDS_AUTHORIZED))
{
DEBUG_INFO ("security error.");
@@ -830,64 +838,81 @@ cmd_pso (void)
return;
}
#ifdef RSA_SIG
/* Check size of digestInfo */
if (len != 34 /* MD5 */
&& len != 35 /* SHA1 / RIPEMD-160 */
&& len != 47 /* SHA224 */
&& len != 51 /* SHA256 */
&& len != 67 /* SHA384 */
&& len != 83) /* SHA512 */
if (attr == ALGO_RSA2K || attr == ALGO_RSA4K)
{
DEBUG_INFO (" wrong length: ");
DEBUG_SHORT (len);
GPG_ERROR ();
}
else
{
DEBUG_SHORT (len);
DEBUG_BINARY (kd[GPG_KEY_FOR_SIGNING].data, KEY_CONTENT_LEN);
/* Check size of digestInfo */
if (len != 34 /* MD5 */
&& len != 35 /* SHA1 / RIPEMD-160 */
&& len != 47 /* SHA224 */
&& len != 51 /* SHA256 */
&& len != 67 /* SHA384 */
&& len != 83) /* SHA512 */
{
DEBUG_INFO (" wrong length");
GPG_CONDITION_NOT_SATISFIED ();
return;
}
DEBUG_BINARY (kd[GPG_KEY_FOR_SIGNING].data, pubkey_len);
r = rsa_sign (apdu.cmd_apdu_data, res_APDU, len,
&kd[GPG_KEY_FOR_SIGNING]);
&kd[GPG_KEY_FOR_SIGNING], pubkey_len);
if (r < 0)
{
ac_reset_pso_cds ();
GPG_ERROR ();
}
ac_reset_pso_cds ();
else
/* Success */
gpg_increment_digital_signature_counter ();
}
#else
/* ECDSA with p256k1 for signature */
if (len != ECDSA_HASH_LEN)
else if (attr == ALGO_NISTP256R1 || attr == ALGO_SECP256K1)
{
DEBUG_INFO (" wrong length: ");
GPG_CONDITION_NOT_SATISFIED ();
}
else
{
DEBUG_SHORT (len);
/* ECDSA with p256r1/p256k1 for signature */
if (len != ECDSA_HASH_LEN)
{
DEBUG_INFO (" wrong length");
GPG_CONDITION_NOT_SATISFIED ();
return;
}
res_APDU_size = ECDSA_SIGNATURE_LENGTH;
r = ecdsa_sign_p256k1 (apdu.cmd_apdu_data, res_APDU,
kd[GPG_KEY_FOR_SIGNING].data);
if (attr == ALGO_NISTP256R1)
r = ecdsa_sign_p256r1 (apdu.cmd_apdu_data, res_APDU,
kd[GPG_KEY_FOR_SIGNING].data);
else /* ALGO_SECP256K1 */
r = ecdsa_sign_p256k1 (apdu.cmd_apdu_data, res_APDU,
kd[GPG_KEY_FOR_SIGNING].data);
if (r < 0)
{
ac_reset_pso_cds ();
GPG_ERROR ();
}
ac_reset_pso_cds ();
else
/* Success */
gpg_increment_digital_signature_counter ();
{ /* Success */
gpg_increment_digital_signature_counter ();
res_APDU_size = ECDSA_SIGNATURE_LENGTH;
}
}
else if (attr == ALGO_ED25519)
{
uint32_t output[64/4]; /* Require 4-byte alignment. */
if (len > EDDSA_HASH_LEN_MAX)
{
DEBUG_INFO ("wrong hash length.");
GPG_CONDITION_NOT_SATISFIED ();
return;
}
res_APDU_size = EDDSA_SIGNATURE_LENGTH;
r = eddsa_sign_25519 (apdu.cmd_apdu_data, len, output,
kd[GPG_KEY_FOR_AUTHENTICATION].data,
kd[GPG_KEY_FOR_AUTHENTICATION].data+32,
kd[GPG_KEY_FOR_AUTHENTICATION].pubkey);
memcpy (res_APDU, output, EDDSA_SIGNATURE_LENGTH);
}
#endif
}
else if (P1 (apdu) == 0x80 && P2 (apdu) == 0x86)
{
DEBUG_SHORT (len);
DEBUG_BINARY (kd[GPG_KEY_FOR_DECRYPTION].data, KEY_CONTENT_LEN);
attr = gpg_get_algo_attr (GPG_KEY_FOR_DECRYPTION);
pubkey_len = gpg_get_algo_attr_key_size (GPG_KEY_FOR_DECRYPTION,
GPG_KEY_PUBLIC);
DEBUG_BINARY (kd[GPG_KEY_FOR_DECRYPTION].data, pubkey_len);
if (!ac_check_status (AC_OTHER_AUTHORIZED))
{
@@ -896,19 +921,40 @@ cmd_pso (void)
return;
}
/* Skip padding 0x00 */
len--;
if (len != KEY_CONTENT_LEN)
GPG_CONDITION_NOT_SATISFIED ();
else
if (attr == ALGO_RSA2K || attr == ALGO_RSA4K)
{
/* Skip padding 0x00 */
len--;
if (len != pubkey_len)
{
GPG_CONDITION_NOT_SATISFIED ();
return;
}
r = rsa_decrypt (apdu.cmd_apdu_data+1, res_APDU, len,
&kd[GPG_KEY_FOR_DECRYPTION]);
if (r < 0)
GPG_ERROR ();
}
else if (attr == ALGO_NISTP256R1 || attr == ALGO_SECP256K1)
{
/* Format is in big endian MPI: 04 || x || y */
if (len != 65 || apdu.cmd_apdu_data[0] != 4)
{
GPG_CONDITION_NOT_SATISFIED ();
return;
}
if (attr == ALGO_NISTP256R1)
r = ecdh_decrypt_p256r1 (apdu.cmd_apdu_data, res_APDU,
kd[GPG_KEY_FOR_DECRYPTION].data);
else
r = ecdh_decrypt_p256k1 (apdu.cmd_apdu_data, res_APDU,
kd[GPG_KEY_FOR_DECRYPTION].data);
if (r == 0)
res_APDU_size = 65;
}
}
else
if (r < 0)
{
DEBUG_INFO (" - ??");
DEBUG_BYTE (P1 (apdu));
@@ -921,28 +967,39 @@ cmd_pso (void)
}
#if defined(RSA_AUTH)
#define MAX_DIGEST_INFO_LEN 102 /* 40% */
#define MAX_RSA_DIGEST_INFO_LEN 102 /* 40% */
static void
cmd_internal_authenticate (void)
{
int attr = gpg_get_algo_attr (GPG_KEY_FOR_AUTHENTICATION);
int pubkey_len = gpg_get_algo_attr_key_size (GPG_KEY_FOR_AUTHENTICATION,
GPG_KEY_PUBLIC);
int len = apdu.cmd_apdu_data_len;
int r;
int r = -1;
DEBUG_INFO (" - INTERNAL AUTHENTICATE\r\n");
if (P1 (apdu) == 0x00 && P2 (apdu) == 0x00)
if (P1 (apdu) != 0x00 || P2 (apdu) != 0x00)
{
DEBUG_SHORT (len);
DEBUG_INFO (" - ??");
DEBUG_BYTE (P1 (apdu));
DEBUG_INFO (" - ??");
DEBUG_BYTE (P2 (apdu));
GPG_CONDITION_NOT_SATISFIED ();
return;
}
if (!ac_check_status (AC_OTHER_AUTHORIZED))
{
DEBUG_INFO ("security error.");
GPG_SECURITY_FAILURE ();
return;
}
DEBUG_SHORT (len);
if (!ac_check_status (AC_OTHER_AUTHORIZED))
{
DEBUG_INFO ("security error.");
GPG_SECURITY_FAILURE ();
return;
}
if (len > MAX_DIGEST_INFO_LEN)
if (attr == ALGO_RSA2K || attr == ALGO_RSA4K)
{
if (len > MAX_RSA_DIGEST_INFO_LEN)
{
DEBUG_INFO ("input is too long.");
GPG_CONDITION_NOT_SATISFIED ();
@@ -950,41 +1007,10 @@ cmd_internal_authenticate (void)
}
r = rsa_sign (apdu.cmd_apdu_data, res_APDU, len,
&kd[GPG_KEY_FOR_AUTHENTICATION]);
if (r < 0)
GPG_ERROR ();
}
else
&kd[GPG_KEY_FOR_AUTHENTICATION], pubkey_len);
}
else if (attr == ALGO_NISTP256R1)
{
DEBUG_INFO (" - ??");
DEBUG_BYTE (P1 (apdu));
DEBUG_INFO (" - ??");
DEBUG_BYTE (P2 (apdu));
GPG_ERROR ();
}
DEBUG_INFO ("INTERNAL AUTHENTICATE done.\r\n");
}
#elif defined(ECDSA_AUTH)
static void
cmd_internal_authenticate (void)
{
int len = apdu.cmd_apdu_data_len;
int r;
DEBUG_INFO (" - INTERNAL AUTHENTICATE\r\n");
if (P1 (apdu) == 0x00 && P2 (apdu) == 0x00)
{
DEBUG_SHORT (len);
if (!ac_check_status (AC_OTHER_AUTHORIZED))
{
DEBUG_INFO ("security error.");
GPG_SECURITY_FAILURE ();
return;
}
if (len != ECDSA_HASH_LEN)
{
DEBUG_INFO ("wrong hash length.");
@@ -995,42 +1021,24 @@ cmd_internal_authenticate (void)
res_APDU_size = ECDSA_SIGNATURE_LENGTH;
r = ecdsa_sign_p256r1 (apdu.cmd_apdu_data, res_APDU,
kd[GPG_KEY_FOR_AUTHENTICATION].data);
if (r < 0)
GPG_ERROR ();
}
else
else if (attr == ALGO_SECP256K1)
{
DEBUG_INFO (" - ??");
DEBUG_BYTE (P1 (apdu));
DEBUG_INFO (" - ??");
DEBUG_BYTE (P2 (apdu));
GPG_ERROR ();
}
DEBUG_INFO ("INTERNAL AUTHENTICATE done.\r\n");
}
#elif defined(EDDSA_AUTH)
static void
cmd_internal_authenticate (void)
{
int len = apdu.cmd_apdu_data_len;
int r;
DEBUG_INFO (" - INTERNAL AUTHENTICATE\r\n");
if (P1 (apdu) == 0x00 && P2 (apdu) == 0x00)
{
uint32_t output[64/4]; /* Require 4-byte alignment. */
DEBUG_SHORT (len);
if (!ac_check_status (AC_OTHER_AUTHORIZED))
if (len != ECDSA_HASH_LEN)
{
DEBUG_INFO ("security error.");
GPG_SECURITY_FAILURE ();
DEBUG_INFO ("wrong hash length.");
GPG_CONDITION_NOT_SATISFIED ();
return;
}
res_APDU_size = ECDSA_SIGNATURE_LENGTH;
r = ecdsa_sign_p256k1 (apdu.cmd_apdu_data, res_APDU,
kd[GPG_KEY_FOR_AUTHENTICATION].data);
}
else if (attr == ALGO_ED25519)
{
uint32_t output[64/4]; /* Require 4-byte alignment. */
if (len > EDDSA_HASH_LEN_MAX)
{
DEBUG_INFO ("wrong hash length.");
@@ -1040,27 +1048,18 @@ cmd_internal_authenticate (void)
res_APDU_size = EDDSA_SIGNATURE_LENGTH;
r = eddsa_sign_25519 (apdu.cmd_apdu_data, len, output,
kd[GPG_KEY_FOR_AUTHENTICATION].data,
kd[GPG_KEY_FOR_AUTHENTICATION].data+32,
kd[GPG_KEY_FOR_AUTHENTICATION].key_addr + KEY_CONTENT_LEN);
kd[GPG_KEY_FOR_AUTHENTICATION].data,
kd[GPG_KEY_FOR_AUTHENTICATION].data+32,
kd[GPG_KEY_FOR_AUTHENTICATION].pubkey);
memcpy (res_APDU, output, EDDSA_SIGNATURE_LENGTH);
if (r < 0)
GPG_ERROR ();
}
else
{
DEBUG_INFO (" - ??");
DEBUG_BYTE (P1 (apdu));
DEBUG_INFO (" - ??");
DEBUG_BYTE (P2 (apdu));
GPG_ERROR ();
}
if (r < 0)
GPG_ERROR ();
DEBUG_INFO ("INTERNAL AUTHENTICATE done.\r\n");
}
#else
#error "Authentication not defined."
#endif
#define MBD_OPRATION_WRITE 0
#define MBD_OPRATION_UPDATE 1