implement key generation

This commit is contained in:
NIIBE Yutaka
2012-06-07 10:48:25 +09:00
parent 2db7875da7
commit 39a3cb8b09
7 changed files with 191 additions and 27 deletions

View File

@@ -1,7 +1,7 @@
/*
* call-rsa.c -- Glue code between RSA computation and OpenPGP card protocol
*
* Copyright (C) 2010, 2011 Free Software Initiative of Japan
* Copyright (C) 2010, 2011, 2012 Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
* This file is a part of Gnuk, a GnuPG USB Token implementation.
@@ -211,3 +211,35 @@ rsa_verify (const uint8_t *pubkey, const uint8_t *hash, const uint8_t *sig)
return 0;
}
}
#define RSA_EXPONENT 0x10001
const uint8_t *
rsa_genkey (void)
{
int r;
uint8_t index = 0;
uint8_t *p_q_modulus = (uint8_t *)malloc (KEY_CONTENT_LEN*2);
uint8_t *p = p_q_modulus;
uint8_t *q = p_q_modulus + KEY_CONTENT_LEN/2;
uint8_t *modulus = p_q_modulus + KEY_CONTENT_LEN;
if (p_q_modulus == NULL)
return NULL;
rsa_init (&rsa_ctx, RSA_PKCS_V15, 0);
r = rsa_gen_key (&rsa_ctx, random_byte, &index,
KEY_CONTENT_LEN * 8, RSA_EXPONENT);
if (r < 0)
{
free (p_q_modulus);
rsa_free (&rsa_ctx);
return NULL;
}
mpi_write_binary (&rsa_ctx.P, p, KEY_CONTENT_LEN/2);
mpi_write_binary (&rsa_ctx.Q, q, KEY_CONTENT_LEN/2);
mpi_write_binary (&rsa_ctx.N, modulus, KEY_CONTENT_LEN);
rsa_free (&rsa_ctx);
return p_q_modulus;
}

View File

@@ -120,6 +120,7 @@ extern void gpg_data_copy (const uint8_t *p);
extern void gpg_do_get_data (uint16_t tag, int with_tag);
extern void gpg_do_put_data (uint16_t tag, const uint8_t *data, int len);
extern void gpg_do_public_key (uint8_t kk_byte);
extern void gpg_do_keygen (uint8_t kk_byte);
extern const uint8_t *gpg_get_firmware_update_key (uint8_t keyno);
@@ -234,6 +235,7 @@ extern void modulus_free (const uint8_t *);
extern int rsa_decrypt (const uint8_t *, uint8_t *, int, struct key_data *);
extern int rsa_verify (const uint8_t *pubkey, const uint8_t *hash,
const uint8_t *signature);
extern const uint8_t *rsa_genkey (void);
extern const uint8_t *gpg_do_read_simple (uint8_t);
extern void gpg_do_write_simple (uint8_t, const uint8_t *, int);
@@ -327,6 +329,8 @@ extern const uint8_t *random_bytes_get (void);
extern void random_bytes_free (const uint8_t *);
/* 4-byte salt */
extern uint32_t get_salt (void);
/* iterator returning a byta at a time */
extern uint8_t random_byte (void *arg);
extern uint32_t hardclock (void);

View File

@@ -1,7 +1,7 @@
/*
* openpgp-do.c -- OpenPGP card Data Objects (DO) handling
*
* Copyright (C) 2010, 2011 Free Software Initiative of Japan
* Copyright (C) 2010, 2011, 2012 Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
* This file is a part of Gnuk, a GnuPG USB Token implementation.
@@ -163,6 +163,17 @@ gpg_write_digital_signature_counter (const uint8_t *p, uint32_t dsc)
}
}
static void
gpg_reset_digital_signature_counter (void)
{
if (digital_signature_counter != 0)
{
flash_put_data (NR_COUNTER_DS);
flash_put_data (NR_COUNTER_DS_LSB);
digital_signature_counter = 0;
}
}
void
gpg_increment_digital_signature_counter (void)
{
@@ -673,12 +684,11 @@ static int8_t num_prv_keys;
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 *keystring_admin, const uint8_t *modulus)
{
uint8_t nr = get_do_ptr_nr_for_kk (kk);
const uint8_t *p;
int r;
const uint8_t *modulus;
struct prvkey_data *pd;
uint8_t *key_addr;
const uint8_t *dek;
@@ -686,10 +696,7 @@ gpg_do_write_prvkey (enum kind_of_key kk, const uint8_t *key_data, int key_len,
const uint8_t *ks_pw1;
const uint8_t *ks_rc;
struct key_data_internal kdi;
#if 0
assert (key_len == KEY_CONTENT_LEN);
#endif
int modulus_allocated_here = 0;
DEBUG_INFO ("Key import\r\n");
DEBUG_SHORT (key_len);
@@ -698,15 +705,23 @@ gpg_do_write_prvkey (enum kind_of_key kk, const uint8_t *key_data, int key_len,
/* No replace support, you need to remove it first. */
return -1;
if (key_len != KEY_CONTENT_LEN)
return -1;
pd = (struct prvkey_data *)malloc (sizeof (struct prvkey_data));
if (pd == NULL)
return -1;
modulus = modulus_calc (key_data, key_len);
if (modulus == NULL)
{
free (pd);
return -1;
modulus = modulus_calc (key_data, key_len);
if (modulus == NULL)
{
free (pd);
return -1;
}
modulus_allocated_here = 1;
}
DEBUG_INFO ("Getting keystore address...\r\n");
@@ -714,7 +729,8 @@ gpg_do_write_prvkey (enum kind_of_key kk, const uint8_t *key_data, int key_len,
if (key_addr == NULL)
{
free (pd);
modulus_free (modulus);
if (modulus_allocated_here)
modulus_free (modulus);
return -1;
}
@@ -736,7 +752,8 @@ gpg_do_write_prvkey (enum kind_of_key kk, const uint8_t *key_data, int key_len,
encrypt (dek, (uint8_t *)&kdi, sizeof (struct key_data_internal));
r = flash_key_write (key_addr, kdi.data, modulus);
modulus_free (modulus);
if (modulus_allocated_here)
modulus_free (modulus);
if (r < 0)
{
@@ -749,7 +766,10 @@ gpg_do_write_prvkey (enum kind_of_key kk, const uint8_t *key_data, int key_len,
memcpy (pd->crm_encrypted, (uint8_t *)&kdi.check, ADDITIONAL_DATA_SIZE);
if (kk == GPG_KEY_FOR_SIGNING)
ac_reset_pso_cds ();
{
ac_reset_pso_cds ();
gpg_reset_digital_signature_counter ();
}
else
ac_reset_other ();
@@ -908,7 +928,7 @@ proc_key_import (const uint8_t *data, int len)
/* It should starts with 00 01 00 01 (E) */
/* Skip E, 4-byte */
r = gpg_do_write_prvkey (kk, &data[26], len - 26, keystring_admin);
r = gpg_do_write_prvkey (kk, &data[26], len - 26, keystring_admin, NULL);
if (r < 0)
return 0;
else
@@ -1460,3 +1480,75 @@ gpg_do_write_simple (uint8_t nr, const uint8_t *data, int size)
else
*do_data_p = NULL;
}
void
gpg_do_keygen (uint8_t kk_byte)
{
enum kind_of_key kk;
const uint8_t *keystring_admin;
const uint8_t *p_q_modulus;
const uint8_t *p_q;
const uint8_t *modulus;
int r;
DEBUG_INFO ("Keygen\r\n");
DEBUG_BYTE (kk_byte);
if (kk_byte == 0xb6)
kk = GPG_KEY_FOR_SIGNING;
else if (kk_byte == 0xb8)
kk = GPG_KEY_FOR_DECRYPTION;
else /* 0xa4 */
kk = GPG_KEY_FOR_AUTHENTICATION;
if (admin_authorized == BY_ADMIN)
keystring_admin = keystring_md_pw3;
else
keystring_admin = NULL;
p_q_modulus = rsa_genkey ();
if (p_q_modulus == NULL)
{
GPG_MEMORY_FAILURE ();
return;
}
p_q = p_q_modulus;
modulus = p_q_modulus + KEY_CONTENT_LEN;
r = gpg_do_write_prvkey (kk, p_q, KEY_CONTENT_LEN,
keystring_admin, modulus);
free ((uint8_t *)p_q_modulus);
if (r < 0)
{
GPG_ERROR ();
return;
}
DEBUG_INFO ("Calling gpg_do_public_key...\r\n");
if (kk == GPG_KEY_FOR_SIGNING)
{
/* Authintication has been reset within gpg_do_write_prvkey. */
/* But GnuPG expects it's ready for signing. */
/* Thus, we call verify_pso_cds here. */
const uint8_t *ks_pw1 = gpg_do_read_simple (NR_DO_KEYSTRING_PW1);
const uint8_t *pw;
int pw_len;
if (ks_pw1)
{
pw = ks_pw1+1;
pw_len = ks_pw1[0];
}
else
{
pw = (const uint8_t *)OPENPGP_CARD_INITIAL_PW1;
pw_len = strlen (OPENPGP_CARD_INITIAL_PW3);
}
verify_pso_cds (pw, pw_len);
}
gpg_do_public_key (kk_byte);
}

View File

@@ -480,12 +480,11 @@ cmd_pgp_gakp (void)
/* Get public key */
gpg_do_public_key (apdu.cmd_apdu_data[0]);
else
{ /* Generate key pair */
{
if (!ac_check_status (AC_ADMIN_AUTHORIZED))
GPG_SECURITY_FAILURE ();
/* XXX: Not yet supported */
GPG_ERROR ();
/* Generate key pair */
gpg_do_keygen (apdu.cmd_apdu_data[0]);
}
}

View File

@@ -70,3 +70,30 @@ get_salt (void)
{
return neug_get (NEUG_KICK_FILLING);
}
/*
* Rundom byte iterator
*/
uint8_t
random_byte (void *arg)
{
uint8_t *index_p = (uint8_t *)arg;
uint8_t index = *index_p;
uint8_t *p = ((uint8_t *)random_word) + index;
uint8_t v;
neug_wait_full ();
v = *p;
if (++index >= RANDOM_BYTES_LENGTH)
{
index = 0;
neug_flush ();
}
*index_p = index;
return v;
}