implement key generation
This commit is contained in:
10
ChangeLog
10
ChangeLog
@@ -1,5 +1,15 @@
|
||||
2012-06-07 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
Implement key generation.
|
||||
* src/openpgp.c (cmd_pgp_gakp): Call gpg_do_keygen.
|
||||
* src/openpgp-do.c (proc_key_import): Call with modulus = NULL.
|
||||
(gpg_do_keygen): New function.
|
||||
(gpg_reset_digital_signature_counter): New function.
|
||||
(gpg_do_write_prvkey): New argument MODULUS. Call
|
||||
gpg_reset_digital_signature_counter.
|
||||
* src/call-rsa.c (rsa_genkey): New function.
|
||||
* src/random.c (random_byte): New function.
|
||||
|
||||
PolarSSL modification.
|
||||
* polarssl-0.14.0/library/rsa.c (rsa_gen_key): Don't set D, DP,
|
||||
DQ, and QP. It's only for key generation.
|
||||
|
||||
16
README
16
README
@@ -135,6 +135,7 @@ Tested features are:
|
||||
* Card holder certificate
|
||||
* Removal of keys (Overriding key import is not supported,
|
||||
but you can remove all keys to import again).
|
||||
* Key generation on device side
|
||||
|
||||
It is known not-working well:
|
||||
|
||||
@@ -142,10 +143,6 @@ It is known not-working well:
|
||||
work well. Please make sure to disable DEBUG option if it
|
||||
doesn't work well.
|
||||
|
||||
Not supported feature(s):
|
||||
|
||||
* Key generation on device side
|
||||
|
||||
|
||||
Targets
|
||||
=======
|
||||
@@ -566,9 +563,12 @@ command is:
|
||||
Note that the factory setting of user password is "123456" and admin
|
||||
password is "12345678" as the specification.
|
||||
|
||||
No, Gnuk doesn't support key generation. You need to create your
|
||||
keys on your computer, and import them to Gnuk Token. After you create
|
||||
your keys (they must be 2048-bit RSA), you can import them.
|
||||
It is recommended to create your keys on your computer, and import
|
||||
them to Gnuk Token. After you create your keys (they must be 2048-bit
|
||||
RSA), you can import them.
|
||||
|
||||
Gnuk supports key generation, but this feature is young and should be
|
||||
considered experimental.
|
||||
|
||||
For detail, please see doc/DEMO and doc/DEMO-2.
|
||||
|
||||
@@ -577,7 +577,7 @@ you can import the keys (again) to (possibly another) Gnuk Token. In
|
||||
this case, you can use GnuPG's option to specify the home directory by
|
||||
--homedir.
|
||||
|
||||
After creating keys by:
|
||||
After creating keys on your computer by:
|
||||
|
||||
$ gpg --gen-key
|
||||
...
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
120
src/openpgp-do.c
120
src/openpgp-do.c
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
27
src/random.c
27
src/random.c
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user