new password management
This commit is contained in:
14
ChangeLog
14
ChangeLog
@@ -1,5 +1,19 @@
|
||||
2010-11-30 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
New private key management.
|
||||
* src/ac.c (ac_reset_pso_cds, ac_reset_pso_other): Call
|
||||
gpg_do_clear_prvkey.
|
||||
(verify_pso_other): load private keys here.
|
||||
* src/openpgp-do.c (kd): Keydata for Signing, Decryption, and
|
||||
Authentication.
|
||||
(gpg_do_load_prvkey, gpg_do_write_prvkey): Use kd[].
|
||||
(gpg_do_clear_prvkey): New function.
|
||||
* src/openpgp.c (cmd_pso, cmd_internal_authenticate): Use new API
|
||||
of rsa_sign and rsa_decrypt.
|
||||
* src/call-rsa.c (rsa_sign): New argument KD.
|
||||
(rsa_decrypt): Likewise.
|
||||
|
||||
Don't use malloc/free in C library.
|
||||
* src/stdlib.h (malloc, free): Use chHeapAlloc and chHeapFree.
|
||||
|
||||
2010-11-26 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
2
NEWS
2
NEWS
@@ -9,6 +9,8 @@ ST-Link part (with STM32F103C8T6) of STM8S Discovery board is now supported.
|
||||
|
||||
** Digital signing for SHA224/SHA256/SHA384/SHA512 digestInfo is now possible.
|
||||
|
||||
** Fixes for password management.
|
||||
|
||||
** More improved USB-CCID/ICCD implementation.
|
||||
Gnuk works better with GPG's in-stock protocol stack. Still,
|
||||
changes are needed for GPG (scd/ccid-driver.c) to support the case
|
||||
|
||||
22
README
22
README
@@ -1,7 +1,7 @@
|
||||
Gnuk - software for GPG USB Token
|
||||
|
||||
Version 0.4
|
||||
2010-11-09
|
||||
Version 0.5
|
||||
2010-12-XX
|
||||
Niibe Yutaka
|
||||
Free Software Initiative of Japan
|
||||
|
||||
@@ -26,7 +26,7 @@ USB Token by Gnuk everywhere.
|
||||
Release notes
|
||||
=============
|
||||
|
||||
This is fifth release of Gnuk. While it works well for specific
|
||||
This is sixth release of Gnuk. While it works well for specific
|
||||
usages, it is still experimental.
|
||||
|
||||
Tested features are:
|
||||
@@ -51,12 +51,12 @@ Tested features are:
|
||||
|
||||
* INTERNAL AUTHENTICATE
|
||||
|
||||
* Changing value of password status bytes (0x00C4).
|
||||
|
||||
It is known not-working well:
|
||||
|
||||
* Key import multiple times
|
||||
|
||||
* Changing value of password status bytes (0x00C4).
|
||||
|
||||
* For some version of kernel and libccid, --enable-debug can't
|
||||
work well. Please disable DEBUG option if it doesn't work well.
|
||||
|
||||
@@ -68,10 +68,14 @@ Not (yet) supported feature(s):
|
||||
Targets
|
||||
=======
|
||||
|
||||
We use Olimex STM32-H103 board. DFU support is added, it's mainly for
|
||||
CQ STARM and STBee Mini but those targets are not tested extensively.
|
||||
That's because we don't have a Free Software tool to write through
|
||||
DFU.
|
||||
We use Olimex STM32-H103 board. We also use STM32 part of STM8S
|
||||
Discovery Kit.
|
||||
|
||||
With DfuSe support, CQ STARM and STBee Mini are also our targets. But
|
||||
those target with DfuSe are basically not for normal use but for
|
||||
experiment, because it would be impossible for DfuSe to disable read
|
||||
from flash. For real use, kill DfuSe and enable read protect using
|
||||
JTAG debugger.
|
||||
|
||||
I think that it could run on Olimex STM32-P103, or STBee too.
|
||||
Besides, we are porting it to STM32 Primer 2.
|
||||
|
||||
26
src/ac.c
26
src/ac.c
@@ -44,15 +44,15 @@ ac_check_status (uint8_t ac_flag)
|
||||
void
|
||||
ac_reset_pso_cds (void)
|
||||
{
|
||||
gpg_do_clear_prvkey (GPG_KEY_FOR_SIGNING);
|
||||
auth_status &= ~AC_PSO_CDS_AUTHORIZED;
|
||||
}
|
||||
|
||||
uint8_t pw1_keystring[KEYSTRING_SIZE_PW1];
|
||||
|
||||
void
|
||||
ac_reset_pso_other (void)
|
||||
{
|
||||
memset (pw1_keystring, 0, KEYSTRING_SIZE_PW1);
|
||||
gpg_do_clear_prvkey (GPG_KEY_FOR_DECRYPTION);
|
||||
gpg_do_clear_prvkey (GPG_KEY_FOR_AUTHENTICATION);
|
||||
auth_status &= ~AC_PSO_OTHER_AUTHORIZED;
|
||||
}
|
||||
|
||||
@@ -89,31 +89,35 @@ int
|
||||
verify_pso_other (const uint8_t *pw, int pw_len)
|
||||
{
|
||||
const uint8_t *ks_pw1;
|
||||
uint8_t pw1_keystring[KEYSTRING_SIZE_PW1];
|
||||
|
||||
DEBUG_INFO ("verify_pso_other\r\n");
|
||||
|
||||
if (gpg_passwd_locked (PW_ERR_PW1))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* We check only the length of password string here.
|
||||
* Real check is defered to decrypt/authenticate routines.
|
||||
*/
|
||||
ks_pw1 = gpg_do_read_simple (NR_DO_KEYSTRING_PW1);
|
||||
if ((ks_pw1 == NULL && pw_len == strlen (OPENPGP_CARD_INITIAL_PW1))
|
||||
|| (ks_pw1 != NULL && pw_len == ks_pw1[0]))
|
||||
{ /* No problem */
|
||||
/*
|
||||
* We don't call gpg_reset_pw_err_counters here, because
|
||||
* password may be wrong.
|
||||
*/
|
||||
pw1_keystring[0] = pw_len;
|
||||
sha1 (pw, pw_len, pw1_keystring+1);
|
||||
if (gpg_do_load_prvkey (GPG_KEY_FOR_DECRYPTION, BY_USER,
|
||||
pw1_keystring + 1) < 0)
|
||||
goto error;
|
||||
|
||||
if (gpg_do_load_prvkey (GPG_KEY_FOR_AUTHENTICATION, BY_USER,
|
||||
pw1_keystring + 1) < 0)
|
||||
goto error;
|
||||
|
||||
/* Reset counter as it's success now */
|
||||
gpg_reset_pw_err_counter (PW_ERR_PW1);
|
||||
auth_status |= AC_PSO_OTHER_AUTHORIZED;
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
error:
|
||||
gpg_increment_pw_err_counter (PW_ERR_PW1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -33,7 +33,8 @@
|
||||
static rsa_context rsa_ctx;
|
||||
|
||||
int
|
||||
rsa_sign (const uint8_t *raw_message, uint8_t *output, int msg_len)
|
||||
rsa_sign (const uint8_t *raw_message, uint8_t *output, int msg_len,
|
||||
struct key_data *kd)
|
||||
{
|
||||
mpi P1, Q1, H;
|
||||
int r;
|
||||
@@ -43,8 +44,8 @@ rsa_sign (const uint8_t *raw_message, uint8_t *output, int msg_len)
|
||||
|
||||
rsa_ctx.len = 2048 / 8;
|
||||
mpi_read_string (&rsa_ctx.E, 16, "10001");
|
||||
mpi_read_binary (&rsa_ctx.P, &kd.data[0], rsa_ctx.len / 2);
|
||||
mpi_read_binary (&rsa_ctx.Q, &kd.data[128], rsa_ctx.len / 2);
|
||||
mpi_read_binary (&rsa_ctx.P, &kd->data[0], rsa_ctx.len / 2);
|
||||
mpi_read_binary (&rsa_ctx.Q, &kd->data[128], rsa_ctx.len / 2);
|
||||
mpi_mul_mpi (&rsa_ctx.N, &rsa_ctx.P, &rsa_ctx.Q);
|
||||
mpi_sub_int (&P1, &rsa_ctx.P, 1);
|
||||
mpi_sub_int (&Q1, &rsa_ctx.Q, 1);
|
||||
@@ -114,7 +115,8 @@ modulus_free (const uint8_t *p)
|
||||
}
|
||||
|
||||
int
|
||||
rsa_decrypt (const uint8_t *input, uint8_t *output, int msg_len)
|
||||
rsa_decrypt (const uint8_t *input, uint8_t *output, int msg_len,
|
||||
struct key_data *kd)
|
||||
{
|
||||
mpi P1, Q1, H;
|
||||
int r;
|
||||
@@ -130,8 +132,8 @@ rsa_decrypt (const uint8_t *input, uint8_t *output, int msg_len)
|
||||
DEBUG_WORD (msg_len);
|
||||
|
||||
mpi_read_string (&rsa_ctx.E, 16, "10001");
|
||||
mpi_read_binary (&rsa_ctx.P, &kd.data[0], 2048 / 8 / 2);
|
||||
mpi_read_binary (&rsa_ctx.Q, &kd.data[128], 2048 / 8 / 2);
|
||||
mpi_read_binary (&rsa_ctx.P, &kd->data[0], 2048 / 8 / 2);
|
||||
mpi_read_binary (&rsa_ctx.Q, &kd->data[128], 2048 / 8 / 2);
|
||||
mpi_mul_mpi (&rsa_ctx.N, &rsa_ctx.P, &rsa_ctx.Q);
|
||||
mpi_sub_int (&P1, &rsa_ctx.P, 1);
|
||||
mpi_sub_int (&Q1, &rsa_ctx.Q, 1);
|
||||
|
||||
@@ -81,7 +81,7 @@ extern void gpg_do_public_key (uint8_t kk_byte);
|
||||
|
||||
|
||||
enum kind_of_key {
|
||||
GPG_KEY_FOR_SIGNING,
|
||||
GPG_KEY_FOR_SIGNING = 0,
|
||||
GPG_KEY_FOR_DECRYPTION,
|
||||
GPG_KEY_FOR_AUTHENTICATION,
|
||||
};
|
||||
@@ -140,6 +140,7 @@ extern int flash_key_write (uint8_t *key_addr, const uint8_t *key_data, const ui
|
||||
#define KEYSTRING_SIZE_PW3 (KEYSTRING_PASSLEN_SIZE+KEYSTRING_SALT_SIZE \
|
||||
+KEYSTRING_ITER_SIZE+KEYSTRING_MD_SIZE)
|
||||
|
||||
extern void gpg_do_clear_prvkey (enum kind_of_key kk);
|
||||
extern int gpg_do_load_prvkey (enum kind_of_key kk, int who, const uint8_t *keystring);
|
||||
extern int gpg_do_chks_prvkey (enum kind_of_key kk,
|
||||
int who_old, const uint8_t *old_ks,
|
||||
@@ -148,7 +149,7 @@ extern int gpg_do_chks_prvkey (enum kind_of_key kk,
|
||||
extern int gpg_change_keystring (int who_old, const uint8_t *old_ks,
|
||||
int who_new, const uint8_t *new_ks);
|
||||
|
||||
extern struct key_data kd;
|
||||
extern struct key_data kd[3];
|
||||
|
||||
#ifdef DEBUG
|
||||
#define DEBUG_INFO(msg) put_string (msg)
|
||||
@@ -164,10 +165,10 @@ extern struct key_data kd;
|
||||
#define DEBUG_BINARY(s,len)
|
||||
#endif
|
||||
|
||||
extern int rsa_sign (const uint8_t *, uint8_t *, int);
|
||||
extern int rsa_sign (const uint8_t *, uint8_t *, int, struct key_data *);
|
||||
extern const uint8_t *modulus_calc (const uint8_t *, int);
|
||||
extern void modulus_free (const uint8_t *);
|
||||
extern int rsa_decrypt (const uint8_t *input, uint8_t *output, int msg_len);
|
||||
extern int rsa_decrypt (const uint8_t *, uint8_t *, int, struct key_data *);
|
||||
|
||||
extern int gpg_do_write_prvkey (enum kind_of_key kk, const uint8_t *key_data, int key_len, const uint8_t *keystring);
|
||||
|
||||
|
||||
@@ -528,7 +528,8 @@ encrypt (const uint8_t *key_str, uint8_t *data, int len)
|
||||
aes_crypt_cfb128 (&aes, AES_ENCRYPT, len, &iv_offset, iv, data, data);
|
||||
}
|
||||
|
||||
struct key_data kd;
|
||||
/* Signing, Decryption, and Authentication */
|
||||
struct key_data kd[3];
|
||||
|
||||
static void
|
||||
decrypt (const uint8_t *key_str, uint8_t *data, int len)
|
||||
@@ -561,6 +562,12 @@ get_do_ptr_nr_for_kk (enum kind_of_key kk)
|
||||
return NR_DO_PRVKEY_SIG;
|
||||
}
|
||||
|
||||
void
|
||||
gpg_do_clear_prvkey (enum kind_of_key kk)
|
||||
{
|
||||
memset ((void *)&kd[kk], 0, sizeof (struct key_data));
|
||||
}
|
||||
|
||||
/*
|
||||
* Return 1 on success,
|
||||
* 0 if none,
|
||||
@@ -578,13 +585,13 @@ gpg_do_load_prvkey (enum kind_of_key kk, int who, const uint8_t *keystring)
|
||||
return 0;
|
||||
|
||||
key_addr = *(uint8_t **)&(do_data)[1];
|
||||
memcpy (kd.data, key_addr, KEY_CONTENT_LEN);
|
||||
memcpy (((uint8_t *)&kd.check), do_data+5, ADDITIONAL_DATA_SIZE);
|
||||
memcpy (kd[kk].data, key_addr, KEY_CONTENT_LEN);
|
||||
memcpy (((uint8_t *)&kd[kk].check), do_data+5, ADDITIONAL_DATA_SIZE);
|
||||
memcpy (dek, do_data+5+16*who, DATA_ENCRYPTION_KEY_SIZE);
|
||||
|
||||
decrypt (keystring, dek, DATA_ENCRYPTION_KEY_SIZE);
|
||||
decrypt (dek, (uint8_t *)&kd, sizeof (struct key_data));
|
||||
if (memcmp (kd.magic, GNUK_MAGIC, KEY_MAGIC_LEN) != 0)
|
||||
decrypt (dek, (uint8_t *)&kd[kk], sizeof (struct key_data));
|
||||
if (memcmp (kd[kk].magic, GNUK_MAGIC, KEY_MAGIC_LEN) != 0)
|
||||
{
|
||||
DEBUG_INFO ("gpg_do_load_prvkey failed.\r\n");
|
||||
return -1;
|
||||
@@ -653,10 +660,10 @@ gpg_do_write_prvkey (enum kind_of_key kk, const uint8_t *key_data, int key_len,
|
||||
DEBUG_INFO ("key_addr: ");
|
||||
DEBUG_WORD ((uint32_t)key_addr);
|
||||
|
||||
memcpy (kd.data, key_data, KEY_CONTENT_LEN);
|
||||
kd.check = calc_check32 (key_data, KEY_CONTENT_LEN);
|
||||
kd.random = get_random ();
|
||||
memcpy (kd.magic, GNUK_MAGIC, KEY_MAGIC_LEN);
|
||||
memcpy (kd[kk].data, key_data, KEY_CONTENT_LEN);
|
||||
kd[kk].check = calc_check32 (key_data, KEY_CONTENT_LEN);
|
||||
kd[kk].random = get_random ();
|
||||
memcpy (kd[kk].magic, GNUK_MAGIC, KEY_MAGIC_LEN);
|
||||
|
||||
if (do_data) /* We have old prvkey */
|
||||
{
|
||||
@@ -684,9 +691,9 @@ gpg_do_write_prvkey (enum kind_of_key kk, const uint8_t *key_data, int key_len,
|
||||
ks_rc = gpg_do_read_simple (NR_DO_KEYSTRING_RC);
|
||||
}
|
||||
|
||||
encrypt (dek, (uint8_t *)&kd, sizeof (struct key_data));
|
||||
encrypt (dek, (uint8_t *)&kd[kk], sizeof (struct key_data));
|
||||
|
||||
r = flash_key_write (key_addr, kd.data, modulus);
|
||||
r = flash_key_write (key_addr, kd[kk].data, modulus);
|
||||
modulus_free (modulus);
|
||||
|
||||
if (r < 0)
|
||||
@@ -698,9 +705,13 @@ gpg_do_write_prvkey (enum kind_of_key kk, const uint8_t *key_data, int key_len,
|
||||
}
|
||||
|
||||
pd->key_addr = key_addr;
|
||||
memcpy (pd->crm_encrypted, (uint8_t *)&kd.check, ADDITIONAL_DATA_SIZE);
|
||||
memcpy (pd->crm_encrypted, (uint8_t *)&kd[kk].check, ADDITIONAL_DATA_SIZE);
|
||||
|
||||
if (kk == GPG_KEY_FOR_SIGNING)
|
||||
ac_reset_pso_cds ();
|
||||
else
|
||||
ac_reset_pso_other ();
|
||||
|
||||
ac_reset_pso_cds ();
|
||||
if (ks_pw1)
|
||||
encrypt (ks_pw1+1, pd->dek_encrypted_1, DATA_ENCRYPTION_KEY_SIZE);
|
||||
else
|
||||
|
||||
@@ -258,6 +258,7 @@ cmd_change_password (void)
|
||||
{
|
||||
gpg_do_write_simple (NR_DO_KEYSTRING_PW1, new_ks0, KEYSTRING_SIZE_PW1);
|
||||
ac_reset_pso_cds ();
|
||||
ac_reset_pso_other ();
|
||||
gpg_reset_pw_err_counter (PW_ERR_PW1);
|
||||
DEBUG_INFO ("Changed DO_KEYSTRING_PW1.\r\n");
|
||||
GPG_SUCCESS ();
|
||||
@@ -266,6 +267,7 @@ cmd_change_password (void)
|
||||
{
|
||||
gpg_do_write_simple (NR_DO_KEYSTRING_PW1, new_ks0, 1);
|
||||
ac_reset_pso_cds ();
|
||||
ac_reset_pso_other ();
|
||||
gpg_reset_pw_err_counter (PW_ERR_PW1);
|
||||
DEBUG_INFO ("Changed length of DO_KEYSTRING_PW1.\r\n");
|
||||
GPG_SUCCESS ();
|
||||
@@ -344,6 +346,7 @@ cmd_reset_user_password (void)
|
||||
DEBUG_INFO ("done (no prvkey).\r\n");
|
||||
gpg_do_write_simple (NR_DO_KEYSTRING_PW1, new_ks0, KEYSTRING_SIZE_PW1);
|
||||
ac_reset_pso_cds ();
|
||||
ac_reset_pso_other ();
|
||||
gpg_reset_pw_err_counter (PW_ERR_RC);
|
||||
gpg_reset_pw_err_counter (PW_ERR_PW1);
|
||||
GPG_SUCCESS ();
|
||||
@@ -352,6 +355,7 @@ cmd_reset_user_password (void)
|
||||
{
|
||||
DEBUG_INFO ("done.\r\n");
|
||||
ac_reset_pso_cds ();
|
||||
ac_reset_pso_other ();
|
||||
gpg_reset_pw_err_counter (PW_ERR_RC);
|
||||
gpg_reset_pw_err_counter (PW_ERR_PW1);
|
||||
GPG_SUCCESS ();
|
||||
@@ -388,6 +392,7 @@ cmd_reset_user_password (void)
|
||||
DEBUG_INFO ("done (no privkey).\r\n");
|
||||
gpg_do_write_simple (NR_DO_KEYSTRING_PW1, new_ks0, KEYSTRING_SIZE_PW1);
|
||||
ac_reset_pso_cds ();
|
||||
ac_reset_pso_other ();
|
||||
gpg_reset_pw_err_counter (PW_ERR_PW1);
|
||||
GPG_SUCCESS ();
|
||||
}
|
||||
@@ -395,6 +400,7 @@ cmd_reset_user_password (void)
|
||||
{
|
||||
DEBUG_INFO ("done.\r\n");
|
||||
ac_reset_pso_cds ();
|
||||
ac_reset_pso_other ();
|
||||
gpg_reset_pw_err_counter (PW_ERR_PW1);
|
||||
GPG_SUCCESS ();
|
||||
}
|
||||
@@ -575,7 +581,8 @@ cmd_pso (void)
|
||||
{
|
||||
DEBUG_SHORT (len); /* Should be cmd_APDU_size - 8 [- 1] */
|
||||
|
||||
r = rsa_sign (&cmd_APDU[data_start], res_APDU, len);
|
||||
r = rsa_sign (&cmd_APDU[data_start], res_APDU, len,
|
||||
&kd[GPG_KEY_FOR_SIGNING]);
|
||||
if (r < 0)
|
||||
{
|
||||
ac_reset_pso_cds ();
|
||||
@@ -602,23 +609,11 @@ cmd_pso (void)
|
||||
return;
|
||||
}
|
||||
|
||||
if ((r = gpg_do_load_prvkey (GPG_KEY_FOR_DECRYPTION, BY_USER,
|
||||
pw1_keystring + 1)) < 0)
|
||||
{
|
||||
gpg_increment_pw_err_counter (PW_ERR_PW1);
|
||||
GPG_SECURITY_FAILURE ();
|
||||
return;
|
||||
}
|
||||
else
|
||||
/* Reset counter as it's success now */
|
||||
gpg_reset_pw_err_counter (PW_ERR_PW1);
|
||||
|
||||
ac_reset_pso_other ();
|
||||
|
||||
/* Skip padding 0x00 */
|
||||
data_start++;
|
||||
len--;
|
||||
r = rsa_decrypt (&cmd_APDU[data_start], res_APDU, len);
|
||||
r = rsa_decrypt (&cmd_APDU[data_start], res_APDU, len,
|
||||
&kd[GPG_KEY_FOR_DECRYPTION]);
|
||||
if (r < 0)
|
||||
GPG_ERROR ();
|
||||
}
|
||||
@@ -661,20 +656,8 @@ cmd_internal_authenticate (void)
|
||||
return;
|
||||
}
|
||||
|
||||
if ((r = gpg_do_load_prvkey (GPG_KEY_FOR_AUTHENTICATION, BY_USER,
|
||||
pw1_keystring + 1)) < 0)
|
||||
{
|
||||
gpg_increment_pw_err_counter (PW_ERR_PW1);
|
||||
GPG_SECURITY_FAILURE ();
|
||||
return;
|
||||
}
|
||||
else
|
||||
/* Reset counter as it's success now */
|
||||
gpg_reset_pw_err_counter (PW_ERR_PW1);
|
||||
|
||||
ac_reset_pso_other ();
|
||||
|
||||
r = rsa_sign (&cmd_APDU[data_start], res_APDU, len);
|
||||
r = rsa_sign (&cmd_APDU[data_start], res_APDU, len,
|
||||
&kd[GPG_KEY_FOR_AUTHENTICATION]);
|
||||
if (r < 0)
|
||||
GPG_ERROR ();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user