From 8a88c279bf47c7866574412978696737b18d82b2 Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Sat, 16 Oct 2010 09:22:18 +0900 Subject: [PATCH] Implement "INTERNAL AUTHENTICATE" command. --- AUTHORS | 1 + ChangeLog | 23 +++++++++++ src/ac.c | 44 ++++++++++++-------- src/call-rsa.c | 6 ++- src/gnuk.h | 21 ++++++++-- src/openpgp.c | 107 ++++++++++++++++++++++++++++++++++++++++++------- 6 files changed, 166 insertions(+), 36 deletions(-) diff --git a/AUTHORS b/AUTHORS index 7ab8c40..dcea8e7 100644 --- a/AUTHORS +++ b/AUTHORS @@ -10,6 +10,7 @@ NIIBE Yutaka: Founder of the project. Wrote: gnuk.svg + src/configure src/ac.c src/main.c src/usb_lld.h diff --git a/ChangeLog b/ChangeLog index de1813f..b547735 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,26 @@ +2010-10-16 NIIBE Yutaka + + Implement "INTERNAL AUTHENTICATE" command. + + * src/gnuk.h (BY_USER, BY_RESETCODE, BY_ADMIN): New defines. + (NUM_ALL_PRV_KEYS): Now it's 3 (was: 2). + + * src/openpgp.c (INS_INTERNAL_AUTHENTICATE): New define. + (cmd_internal_authenticate): New function. + (cmds): Added INS_INTERNAL_AUTHENTICATE. + (cmd_change_password): Use BY_USER. + (cmd_reset_user_password): Use BY_USER, BY_RESETCODE, BY_ADMIN. + (cmd_pso): Load GPG_KEY_FOR_DECRYPTION here. + (cmd_pso): Removed adding status word into res_APDU... + * src/call-rsa.c (rsa_sign): and moved adding status word into + res_APDU here. + + * src/ac.c (pw1_keystring): New variable. + (ac_reset_pso_other): Clear pw1_keystring. + (verify_pso_cds): Use BY_USER. + (verify_pso_other): Just check the length of password here, and + defer real check to cmd_pso or cmd_internal_authenticate. + 2010-10-14 NIIBE Yutaka Adding 'configure' support. diff --git a/src/ac.c b/src/ac.c index 3222c7d..8f39747 100644 --- a/src/ac.c +++ b/src/ac.c @@ -28,9 +28,12 @@ ac_reset_pso_cds (void) 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); auth_status &= ~AC_PSO_OTHER_AUTHORIZED; } @@ -52,7 +55,7 @@ verify_pso_cds (const uint8_t *pw, int pw_len) keystring[0] = pw_len; sha1 (pw, pw_len, keystring+1); memcpy (pwsb, pw_status_bytes, SIZE_PW_STATUS_BYTES); - if ((r = gpg_do_load_prvkey (GPG_KEY_FOR_SIGNING, 1, keystring+1)) < 0) + if ((r = gpg_do_load_prvkey (GPG_KEY_FOR_SIGNING, BY_USER, keystring+1)) < 0) { pwsb[PW_STATUS_PW1]--; gpg_do_write_simple (NR_DO_PW_STATUS, pwsb, SIZE_PW_STATUS_BYTES); @@ -71,34 +74,41 @@ verify_pso_cds (const uint8_t *pw, int pw_len) int verify_pso_other (const uint8_t *pw, int pw_len) { - int r; const uint8_t *pw_status_bytes = gpg_do_read_simple (NR_DO_PW_STATUS); - uint8_t keystring[KEYSTRING_SIZE_PW1]; uint8_t pwsb[SIZE_PW_STATUS_BYTES]; + const uint8_t *ks_pw1; + + DEBUG_INFO ("verify_pso_other\r\n"); if (pw_status_bytes == NULL || pw_status_bytes[PW_STATUS_PW1] == 0) /* locked */ return 0; - DEBUG_INFO ("verify_pso_other\r\n"); - - keystring[0] = pw_len; - sha1 (pw, pw_len, keystring+1); memcpy (pwsb, pw_status_bytes, SIZE_PW_STATUS_BYTES); - if ((r = gpg_do_load_prvkey (GPG_KEY_FOR_DECRYPTION, 1, keystring+1)) < 0) + + /* + * We check only the length of password string now. + * 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 reset pwsb[PW_STATUS_PW1] here. + * Because password may be wrong. + */ + pw1_keystring[0] = pw_len; + sha1 (pw, pw_len, pw1_keystring+1); + auth_status |= AC_PSO_OTHER_AUTHORIZED; + return 1; + } + else { pwsb[PW_STATUS_PW1]--; gpg_do_write_simple (NR_DO_PW_STATUS, pwsb, SIZE_PW_STATUS_BYTES); - return r; + return 0; } - else if (pwsb[PW_STATUS_PW1] != 3) - { - pwsb[PW_STATUS_PW1] = 3; - gpg_do_write_simple (NR_DO_PW_STATUS, pwsb, SIZE_PW_STATUS_BYTES); - } - - auth_status |= AC_PSO_OTHER_AUTHORIZED; - return 1; } /* diff --git a/src/call-rsa.c b/src/call-rsa.c index 12a3bcd..6fc90c7 100644 --- a/src/call-rsa.c +++ b/src/call-rsa.c @@ -28,6 +28,8 @@ #include "polarssl/config.h" #include "polarssl/rsa.h" +#define RSA_SIGNATURE_LENGTH 256 /* 256 byte == 2048-bit */ + static rsa_context rsa_ctx; int @@ -76,6 +78,9 @@ rsa_sign (const uint8_t *raw_message, uint8_t *output, int msg_len) } else { + res_APDU[RSA_SIGNATURE_LENGTH] = 0x90; + res_APDU[RSA_SIGNATURE_LENGTH+1] = 0x00; + res_APDU_size = RSA_SIGNATURE_LENGTH + 2; DEBUG_INFO ("done.\r\n"); return 0; } @@ -165,7 +170,6 @@ rsa_decrypt (const uint8_t *input, uint8_t *output, int msg_len) res_APDU[output_len] = 0x90; res_APDU[output_len+1] = 0x00; res_APDU_size = output_len + 2; - DEBUG_INFO ("done.\r\n"); return 0; } diff --git a/src/gnuk.h b/src/gnuk.h index bebae09..7cdc30d 100644 --- a/src/gnuk.h +++ b/src/gnuk.h @@ -104,12 +104,23 @@ struct key_data { #define DATA_ENCRYPTION_KEY_SIZE 16 struct prvkey_data { const uint8_t *key_addr; + /* + * CRM: [C]heck, [R]andom, and [M]agic in struct key_data + * + */ uint8_t crm_encrypted[ADDITIONAL_DATA_SIZE]; - uint8_t dek_encrypted_1[DATA_ENCRYPTION_KEY_SIZE]; - uint8_t dek_encrypted_2[DATA_ENCRYPTION_KEY_SIZE]; - uint8_t dek_encrypted_3[DATA_ENCRYPTION_KEY_SIZE]; + /* + * DEK: Data Encryption Key + */ + uint8_t dek_encrypted_1[DATA_ENCRYPTION_KEY_SIZE]; /* For user */ + uint8_t dek_encrypted_2[DATA_ENCRYPTION_KEY_SIZE]; /* For resetcode */ + uint8_t dek_encrypted_3[DATA_ENCRYPTION_KEY_SIZE]; /* For admin */ }; +#define BY_USER 1 +#define BY_RESETCODE 2 +#define BY_ADMIN 3 + extern int flash_key_write (uint8_t *key_addr, const uint8_t *key_data, const uint8_t *modulus); #define KEYSTRING_PASSLEN_SIZE 1 @@ -204,7 +215,9 @@ extern void gpg_do_reset_pw_counter (uint8_t which); extern void set_led (int); -#define NUM_ALL_PRV_KEYS 2 /* SIG and DEC *//* we don't support AUT yet */ +#define NUM_ALL_PRV_KEYS 3 /* SIG, DEC and AUT */ + +extern uint8_t pw1_keystring[KEYSTRING_SIZE_PW1]; #define OPENPGP_CARD_INITIAL_PW1 "123456" diff --git a/src/openpgp.c b/src/openpgp.c index 2b6634d..dcc368b 100644 --- a/src/openpgp.c +++ b/src/openpgp.c @@ -29,13 +29,12 @@ #include "polarssl/config.h" #include "polarssl/sha1.h" -#define RSA_SIGNATURE_LENGTH 256 /* 256 byte == 2048-bit */ - #define INS_VERIFY 0x20 #define INS_CHANGE_REFERENCE_DATA 0x24 #define INS_PSO 0x2a #define INS_RESET_RETRY_COUNTER 0x2c #define INS_PGP_GENERATE_ASYMMETRIC_KEY_PAIR 0x47 +#define INS_INTERNAL_AUTHENTICATE 0x88 #define INS_SELECT_FILE 0xa4 #define INS_READ_BINARY 0xb0 #define INS_GET_DATA 0xca @@ -180,7 +179,7 @@ cmd_change_password (void) pw += 2; } - if (who == 1) /* PW1 */ + if (who == BY_USER) /* PW1 */ { const uint8_t *pk = gpg_do_read_simple (NR_DO_KEYSTRING_PW1); @@ -243,21 +242,21 @@ cmd_change_password (void) DEBUG_INFO ("security error.\r\n"); GPG_SECURITY_FAILURE (); } - else if (r == 0 && who == 1) /* no prvkey */ + else if (r == 0 && who == BY_USER) /* no prvkey */ { gpg_do_write_simple (NR_DO_KEYSTRING_PW1, new_ks0, KEYSTRING_SIZE_PW1); ac_reset_pso_cds (); gpg_do_reset_pw_counter (PW_STATUS_PW1); DEBUG_INFO ("Changed DO_KEYSTRING_PW1.\r\n"); } - else if (r > 0 && who == 1) + else if (r > 0 && who == BY_USER) { gpg_do_write_simple (NR_DO_KEYSTRING_PW1, new_ks0, 1); ac_reset_pso_cds (); gpg_do_reset_pw_counter (PW_STATUS_PW1); DEBUG_INFO ("Changed length of DO_KEYSTRING_PW1.\r\n"); } - else /* r >= 0 && who == 3 */ + else /* r >= 0 && who == BY_ADMIN */ { DEBUG_INFO ("done.\r\n"); gpg_do_reset_pw_counter (PW_STATUS_PW3); @@ -313,7 +312,7 @@ cmd_reset_user_password (void) sha1 (pw, pw_len, old_ks); sha1 (newpw, newpw_len, new_ks); new_ks0[0] = newpw_len; - r = gpg_change_keystring (2, old_ks, 1, new_ks); + r = gpg_change_keystring (BY_RESETCODE, old_ks, BY_USER, new_ks); if (r < -2) { DEBUG_INFO ("memory error.\r\n"); @@ -362,7 +361,7 @@ cmd_reset_user_password (void) newpw = pw; sha1 (newpw, newpw_len, new_ks); new_ks0[0] = newpw_len; - r = gpg_change_keystring (3, old_ks, 1, new_ks); + r = gpg_change_keystring (BY_ADMIN, old_ks, BY_USER, new_ks); if (r < -2) { DEBUG_INFO ("memory error.\r\n"); @@ -570,10 +569,6 @@ cmd_pso (void) { /* Success */ const uint8_t *pw_status_bytes = gpg_do_read_simple (NR_DO_PW_STATUS); - res_APDU[RSA_SIGNATURE_LENGTH] = 0x90; - res_APDU[RSA_SIGNATURE_LENGTH+1] = 0x00; - res_APDU_size = RSA_SIGNATURE_LENGTH + 2; - if (pw_status_bytes[0] == 0) ac_reset_pso_cds (); @@ -583,14 +578,34 @@ cmd_pso (void) } else if (cmd_APDU[2] == 0x80 && cmd_APDU[3] == 0x86) { - if (!ac_check_status (AC_PSO_OTHER_AUTHORIZED)) + const uint8_t *pw_status_bytes = gpg_do_read_simple (NR_DO_PW_STATUS); + uint8_t pwsb[SIZE_PW_STATUS_BYTES]; + + DEBUG_SHORT (len); + + if (pw_status_bytes == NULL + || pw_status_bytes[PW_STATUS_PW1] == 0 /* locked */ + || !ac_check_status (AC_PSO_OTHER_AUTHORIZED)) { DEBUG_INFO ("security error."); GPG_SECURITY_FAILURE (); return; } - DEBUG_SHORT (len); + memcpy (pwsb, pw_status_bytes, SIZE_PW_STATUS_BYTES); + if ((r = gpg_do_load_prvkey (GPG_KEY_FOR_DECRYPTION, BY_USER, + pw1_keystring + 1)) < 0) + { + pwsb[PW_STATUS_PW1]--; + gpg_do_write_simple (NR_DO_PW_STATUS, pwsb, SIZE_PW_STATUS_BYTES); + GPG_SECURITY_FAILURE (); + return; + } + else if (pwsb[PW_STATUS_PW1] != 3) /* Failure in the past? */ + { /* Reset counter as it's success now */ + pwsb[PW_STATUS_PW1] = 3; + gpg_do_write_simple (NR_DO_PW_STATUS, pwsb, SIZE_PW_STATUS_BYTES); + } ac_reset_pso_other (); @@ -613,6 +628,69 @@ cmd_pso (void) DEBUG_INFO ("PSO done.\r\n"); } +static void +cmd_internal_authenticate (void) +{ + int len = cmd_APDU[4]; + int data_start = 5; + int r; + const uint8_t *pw_status_bytes = gpg_do_read_simple (NR_DO_PW_STATUS); + uint8_t pwsb[SIZE_PW_STATUS_BYTES]; + + if (len == 0) + { + len = (cmd_APDU[5]<<8) | cmd_APDU[6]; + data_start = 7; + } + + DEBUG_INFO (" - INTERNAL AUTHENTICATE\r\n"); + + if (cmd_APDU[2] == 0x00 && cmd_APDU[3] == 0x00) + { + DEBUG_SHORT (len); + + if (pw_status_bytes == NULL + || pw_status_bytes[PW_STATUS_PW1] == 0 /* locked */ + || !ac_check_status (AC_PSO_OTHER_AUTHORIZED)) + { + DEBUG_INFO ("security error."); + GPG_SECURITY_FAILURE (); + return; + } + + memcpy (pwsb, pw_status_bytes, SIZE_PW_STATUS_BYTES); + if ((r = gpg_do_load_prvkey (GPG_KEY_FOR_AUTHENTICATION, BY_USER, + pw1_keystring + 1)) < 0) + { + pwsb[PW_STATUS_PW1]--; + gpg_do_write_simple (NR_DO_PW_STATUS, pwsb, SIZE_PW_STATUS_BYTES); + GPG_SECURITY_FAILURE (); + return; + } + else if (pwsb[PW_STATUS_PW1] != 3) /* Failure in the past? */ + { /* Reset counter as it's success now */ + pwsb[PW_STATUS_PW1] = 3; + gpg_do_write_simple (NR_DO_PW_STATUS, pwsb, SIZE_PW_STATUS_BYTES); + } + + ac_reset_pso_other (); + + r = rsa_sign (&cmd_APDU[data_start], res_APDU, len); + if (r < 0) + GPG_ERROR (); + } + else + { + DEBUG_INFO (" - ??"); + DEBUG_BYTE (cmd_APDU[2]); + DEBUG_INFO (" - ??"); + DEBUG_BYTE (cmd_APDU[3]); + GPG_ERROR (); + } + + DEBUG_INFO ("INTERNAL AUTHENTICATE done.\r\n"); +} + struct command { uint8_t command; @@ -625,6 +703,7 @@ const struct command cmds[] = { { INS_PSO, cmd_pso }, { INS_RESET_RETRY_COUNTER, cmd_reset_user_password }, { INS_PGP_GENERATE_ASYMMETRIC_KEY_PAIR, cmd_pgp_gakp }, + { INS_INTERNAL_AUTHENTICATE, cmd_internal_authenticate }, { INS_SELECT_FILE, cmd_select_file }, { INS_READ_BINARY, cmd_read_binary }, { INS_GET_DATA, cmd_get_data },