diff --git a/ChangeLog b/ChangeLog index 66ded49..1b5bd12 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2013-10-09 Niibe Yutaka + + * src/ac.c (verify_admin_00): New. Add authentication by loading + signature key. + (verify_admin_0): Use verify_admin_00. + + * src/openpgp.c (cmd_change_password): Admin keystring handling as + same as user's. + 2013-10-08 Niibe Yutaka * src/openpgp.c (modify_binary): Allow odd size of certificate. diff --git a/src/ac.c b/src/ac.c index fc40ac5..8aaea8c 100644 --- a/src/ac.c +++ b/src/ac.c @@ -1,7 +1,7 @@ /* * ac.c -- Check access condition * - * Copyright (C) 2010, 2012 Free Software Initiative of Japan + * Copyright (C) 2010, 2012, 2013 Free Software Initiative of Japan * Author: NIIBE Yutaka * * This file is a part of Gnuk, a GnuPG USB Token implementation. @@ -186,6 +186,32 @@ calc_md (int count, const uint8_t *salt, const uint8_t *pw, int pw_len, sha256_finish (&sha256_ctx, md); } + +static int +verify_admin_00 (const uint8_t *pw, int buf_len, int pw_len_known, + const uint8_t *ks) +{ + int pw_len; + int r1, r2; + uint8_t keystring[KEYSTRING_MD_SIZE]; + + pw_len = ks[0]; + if ((pw_len_known >= 0 && pw_len_known != pw_len) || buf_len < pw_len) + return -1; + + s2k (BY_ADMIN, pw, pw_len, keystring); + r1 = gpg_do_load_prvkey (GPG_KEY_FOR_SIGNING, BY_ADMIN, keystring); + r2 = 0; + + if (r1 < 0 || r2 < 0) + return -1; + else if (r1 == 0 && r2 == 0) + if (ks != NULL && memcmp (ks+1, keystring, KEYSTRING_MD_SIZE) != 0) + return -1; + + return pw_len; +} + uint8_t keystring_md_pw3[KEYSTRING_MD_SIZE]; uint8_t admin_authorized; @@ -198,22 +224,11 @@ verify_admin_0 (const uint8_t *pw, int buf_len, int pw_len_known) pw3_keystring = gpg_do_read_simple (NR_DO_KEYSTRING_PW3); if (pw3_keystring != NULL) { - int count; - uint8_t md[KEYSTRING_MD_SIZE]; - const uint8_t *salt; - if (gpg_pw_locked (PW_ERR_PW3)) return 0; - pw_len = pw3_keystring[0]; - if ((pw_len_known >= 0 && pw_len_known != pw_len) || pw_len > buf_len) - goto failure; - - salt = &pw3_keystring[1]; - count = decode_iterate_count (pw3_keystring[1+8]); - calc_md (count, salt, pw, pw_len, md); - - if (memcmp (md, &pw3_keystring[1+8+1], KEYSTRING_MD_SIZE) != 0) + pw_len = verify_admin_00 (pw, buf_len, pw_len_known, pw3_keystring); + if (pw_len < 0) { failure: gpg_pw_increment_err_counter (PW_ERR_PW3); @@ -221,7 +236,7 @@ verify_admin_0 (const uint8_t *pw, int buf_len, int pw_len_known) } admin_authorized = BY_ADMIN; - success: /* OK, the user is now authenticated */ + success: /* OK, the admin is now authenticated. */ gpg_pw_reset_err_counter (PW_ERR_PW3); return pw_len; } diff --git a/src/gnuk.h b/src/gnuk.h index 9336b82..544fe47 100644 --- a/src/gnuk.h +++ b/src/gnuk.h @@ -181,6 +181,7 @@ extern void s2k (int who, const unsigned char *input, unsigned int ilen, #define KEYSTRING_SIZE_RC (KEYSTRING_PASSLEN_SIZE+KEYSTRING_MD_SIZE) #define KEYSTRING_SIZE_PW3 (KEYSTRING_PASSLEN_SIZE+KEYSTRING_SALT_SIZE \ +KEYSTRING_ITER_SIZE+KEYSTRING_MD_SIZE) +#define KEYSTRING_SIZE (KEYSTRING_PASSLEN_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); diff --git a/src/openpgp-do.c b/src/openpgp-do.c index 57b6909..e6f0a4a 100644 --- a/src/openpgp-do.c +++ b/src/openpgp-do.c @@ -578,7 +578,7 @@ proc_resetting_code (const uint8_t *data, int len) else if (r == 0) { DEBUG_INFO ("done (no prvkey).\r\n"); - gpg_do_write_simple (NR_DO_KEYSTRING_RC, new_ks0, KEYSTRING_SIZE_RC); + gpg_do_write_simple (NR_DO_KEYSTRING_RC, new_ks0, KEYSTRING_SIZE); } else { diff --git a/src/openpgp.c b/src/openpgp.c index f745a53..5f5f938 100644 --- a/src/openpgp.c +++ b/src/openpgp.c @@ -255,6 +255,7 @@ cmd_change_password (void) int who = p2 - 0x80; int who_old; int r; + int pw3_null = 0; DEBUG_INFO ("Change PW\r\n"); DEBUG_BYTE (who); @@ -328,9 +329,9 @@ cmd_change_password (void) newpw_len = strlen (OPENPGP_CARD_INITIAL_PW3); memcpy (newpw, OPENPGP_CARD_INITIAL_PW3, newpw_len); gpg_do_write_simple (NR_DO_KEYSTRING_PW3, NULL, 0); + pw3_null = 1; } - else - gpg_set_pw3 (newpw, newpw_len); + who_old = admin_authorized; } } @@ -352,7 +353,7 @@ cmd_change_password (void) } else if (r == 0 && who == BY_USER) /* no prvkey */ { - gpg_do_write_simple (NR_DO_KEYSTRING_PW1, new_ks0, KEYSTRING_SIZE_PW1); + gpg_do_write_simple (NR_DO_KEYSTRING_PW1, new_ks0, KEYSTRING_SIZE); ac_reset_pso_cds (); ac_reset_other (); if (admin_authorized == BY_USER) @@ -370,9 +371,21 @@ cmd_change_password (void) DEBUG_INFO ("Changed length of DO_KEYSTRING_PW1.\r\n"); GPG_SUCCESS (); } - else /* r >= 0 && who == BY_ADMIN */ +#if 0 + else if (r > 0 && who == BY_ADMIN) { - DEBUG_INFO ("done.\r\n"); + if (!pw3_null) + gpg_do_write_simple (NR_DO_KEYSTRING_PW3, new_ks0, 1); + ac_reset_admin (); + DEBUG_INFO ("Changed length of DO_KEYSTRING_PW3.\r\n"); + GPG_SUCCESS (); + } +#endif + else /* r == 0 && who == BY_ADMIN */ /* no prvkey */ + { + if (!pw3_null) + gpg_do_write_simple (NR_DO_KEYSTRING_PW3, new_ks0, KEYSTRING_SIZE); + DEBUG_INFO ("Changed DO_KEYSTRING_PW3.\r\n"); ac_reset_admin (); GPG_SUCCESS (); } @@ -462,8 +475,7 @@ cmd_reset_user_password (void) if (memcmp (ks_rc+1, old_ks, KEYSTRING_MD_SIZE) != 0) goto sec_fail; DEBUG_INFO ("done (no prvkey).\r\n"); - gpg_do_write_simple (NR_DO_KEYSTRING_PW1, new_ks0, - KEYSTRING_SIZE_PW1); + gpg_do_write_simple (NR_DO_KEYSTRING_PW1, new_ks0, KEYSTRING_SIZE); ac_reset_pso_cds (); ac_reset_other (); if (admin_authorized == BY_USER) @@ -514,8 +526,7 @@ cmd_reset_user_password (void) else if (r == 0) { DEBUG_INFO ("done (no privkey).\r\n"); - gpg_do_write_simple (NR_DO_KEYSTRING_PW1, new_ks0, - KEYSTRING_SIZE_PW1); + gpg_do_write_simple (NR_DO_KEYSTRING_PW1, new_ks0, KEYSTRING_SIZE); ac_reset_pso_cds (); ac_reset_other (); if (admin_authorized == BY_USER)