diff --git a/ChangeLog b/ChangeLog index 97bf755..b18c49b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,25 @@ +2012-01-18 Niibe Yutaka + + Clean up API between application layer and CCID layer. + * tool/gnuk_put_binary.py, gnuk_put_binary_libusb.py: Don't append + 0x9000 at the data, any more. + * src/usb-icc.c (icc_data_size, icc_buffer, icc_seq): Make them + internal. + (res_APDU_size, res_APDU_pointer): Removed. + (icc_handle_data, USBthread): Follow new API of struct apdu. + * src/call-rsa.c (rsa_sign, rsa_decrypt): Likewise. + * src/openpgp.c (CLS, INS, P1, P2): New. + (set_res_apdu, cmd_verify, cmd_change_password) + (cmd_reset_user_password, cmd_put_data, cmd_pgp_gakp) + (cmd_read_binary, cmd_select_file, cmd_pso) + (cmd_internal_authenticate, cmd_update_binary, cmd_write_binary) + (process_command_apdu, GPGthread): Follow new API of struct apdu. + * src/openpgp-do.c (gpg_do_get_data, gpg_do_public_key): Follow + new API of struct apdu. + * src/gnuk.h (struct apdu, apdu): New. + (cmd_APDU, icc_data_size, cmd_APDU_size, icc_buffer): Removed. + (res_APDU, res_APDU_size): Use members of struct apdu. + 2012-01-16 Niibe Yutaka Adopt new USB API. diff --git a/src/call-rsa.c b/src/call-rsa.c index 8705d04..cf7530b 100644 --- a/src/call-rsa.c +++ b/src/call-rsa.c @@ -25,6 +25,7 @@ #include "config.h" #include "ch.h" #include "gnuk.h" +#include "openpgp.h" #include "polarssl/config.h" #include "polarssl/rsa.h" @@ -84,10 +85,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; + res_APDU_size = RSA_SIGNATURE_LENGTH; DEBUG_INFO ("done.\r\n"); + GPG_SUCCESS (); return 0; } } @@ -177,10 +177,9 @@ rsa_decrypt (const uint8_t *input, uint8_t *output, int msg_len, } else { - res_APDU[output_len] = 0x90; - res_APDU[output_len+1] = 0x00; - res_APDU_size = output_len + 2; + res_APDU_size = output_len; DEBUG_INFO ("done.\r\n"); + GPG_SUCCESS (); return 0; } } diff --git a/src/gnuk.h b/src/gnuk.h index e0d72d6..464e036 100644 --- a/src/gnuk.h +++ b/src/gnuk.h @@ -1,3 +1,17 @@ +/* + * We declare some of libc functions here, because we will + * remove dependency on libc in future, possibly. + */ +extern size_t strlen (const char *s); +extern int strncmp(const char *s1, const char *s2, size_t n); +extern void *memcpy (void *dest, const void *src, size_t n); +extern void *memset (void *s, int c, size_t n); +extern int memcmp (const void *s1, const void *s2, size_t n); +extern void *memmove(void *dest, const void *src, size_t n); + +/* + * Debug functions + */ extern Thread *stdout_thread; #define EV_TX_READY ((eventmask_t)1) @@ -11,16 +25,26 @@ extern void put_binary (const char *s, int len); extern void _write (const char *, int); + /* - * We declare some of libc functions here, because we will - * remove dependency on libc in future. + * Application layer <-> CCID layer data structure */ -extern size_t strlen (const char *s); -extern int strncmp(const char *s1, const char *s2, size_t n); -extern void *memcpy (void *dest, const void *src, size_t n); -extern void *memset (void *s, int c, size_t n); -extern int memcmp (const void *s1, const void *s2, size_t n); -extern void *memmove(void *dest, const void *src, size_t n); +struct apdu { + uint8_t seq; + + /* command APDU */ + uint8_t *cmd_apdu_head; /* CLS INS P1 P2 [ internal Lc ] */ + uint8_t *cmd_apdu_data; + uint16_t cmd_apdu_data_len; /* Nc, calculated by Lc field */ + uint32_t expected_res_size; /* Ne, calculated by Le field */ + + /* response APDU */ + uint16_t sw; + uint8_t *res_apdu_data; + uint16_t res_apdu_data_len; +}; + +extern struct apdu apdu; #define EV_EXEC_FINISHED ((eventmask_t)2) /* GPG Execution finished */ @@ -38,12 +62,8 @@ extern void *memmove(void *dest, const void *src, size_t n); #define ICC_MSG_HEADER_SIZE 10 -#define cmd_APDU (&icc_buffer[ICC_MSG_HEADER_SIZE]) -#define res_APDU (&icc_buffer[ICC_MSG_HEADER_SIZE]) -extern int icc_data_size; -#define cmd_APDU_size icc_data_size -extern int res_APDU_size; -extern const uint8_t *res_APDU_pointer; +#define res_APDU apdu.res_apdu_data +#define res_APDU_size apdu.res_apdu_data_len /* USB buffer size of LL (Low-level): size of single Bulk transaction */ #define USB_LL_BUF_SIZE 64 @@ -54,7 +74,6 @@ extern const uint8_t *res_APDU_pointer; */ #define USB_BUF_SIZE ((10 + 10 + MAX_CMD_APDU_SIZE + USB_LL_BUF_SIZE - 1) \ / USB_LL_BUF_SIZE * USB_LL_BUF_SIZE) -extern uint8_t icc_buffer[USB_BUF_SIZE]; enum icc_state { diff --git a/src/openpgp-do.c b/src/openpgp-do.c index 714a0d0..47cec3b 100644 --- a/src/openpgp-do.c +++ b/src/openpgp-do.c @@ -1250,16 +1250,13 @@ gpg_do_get_data (uint16_t tag, int with_tag) #if defined(CERTDO_SUPPORT) if (tag == GPG_DO_CH_CERTIFICATE) { - res_APDU_pointer = &ch_certificate_start; - res_APDU_size = ((res_APDU_pointer[2] << 8) | res_APDU_pointer[3]); - if (res_APDU_size == 0xffff) - { - res_APDU_pointer = NULL; - GPG_NO_RECORD (); - } + apdu.res_apdu_data = &ch_certificate_start; + apdu.res_apdu_data_len = ((apdu.res_apdu_data[2] << 8) | apdu.res_apdu_data[3]); + if (apdu.res_apdu_data_len == 0xffff) + GPG_NO_RECORD (); else - /* Add length of (tag+len) and status word (0x9000) at the end */ - res_APDU_size += 4 + 2; + /* Add length of (tag+len) */ + apdu.res_apdu_data_len += 4; } else #endif @@ -1278,9 +1275,8 @@ gpg_do_get_data (uint16_t tag, int with_tag) GPG_SECURITY_FAILURE (); else { - *res_p++ = 0x90; - *res_p++ = 0x00; res_APDU_size = res_p - res_APDU; + GPG_SUCCESS (); } } else @@ -1414,8 +1410,8 @@ gpg_do_public_key (uint8_t kk_byte) *res_p++ = 0x01; *res_p++ = 0x00; *res_p++ = 0x01; /* Success */ - *res_p++ = 0x90; *res_p++ = 0x00; res_APDU_size = res_p - res_APDU; + GPG_SUCCESS (); } DEBUG_INFO ("done.\r\n"); diff --git a/src/openpgp.c b/src/openpgp.c index 763b481..d73d773 100644 --- a/src/openpgp.c +++ b/src/openpgp.c @@ -29,6 +29,11 @@ #include "polarssl/config.h" #include "polarssl/sha1.h" +#define CLS(a) a.cmd_apdu_head[0] +#define INS(a) a.cmd_apdu_head[1] +#define P1(a) a.cmd_apdu_head[2] +#define P2(a) a.cmd_apdu_head[3] + #define INS_VERIFY 0x20 #define INS_CHANGE_REFERENCE_DATA 0x24 #define INS_PSO 0x2a @@ -64,9 +69,7 @@ select_file_TOP_result[] __attribute__ ((aligned (1))) = { void set_res_apdu (uint8_t sw1, uint8_t sw2) { - res_APDU_size = 2; - res_APDU[0] = sw1; - res_APDU[1] = sw2; + apdu.sw = (sw1 << 8) | sw2; } #define FILE_NONE 0 @@ -117,22 +120,15 @@ static void cmd_verify (void) { int len; - uint8_t p2 = cmd_APDU[3]; + uint8_t p2 = P2 (apdu); int r; - int data_start = 5; const uint8_t *pw; DEBUG_INFO (" - VERIFY\r\n"); DEBUG_BYTE (p2); - len = cmd_APDU[4]; - if (len == 0) /* extended length */ - { - len = (cmd_APDU[5]<<8) | cmd_APDU[6]; - data_start = 7; - } - - pw = &cmd_APDU[data_start]; + len = apdu.cmd_apdu_data_len; + pw = apdu.cmd_apdu_data; if (p2 == 0x81) r = verify_pso_cds (pw, len); @@ -213,8 +209,8 @@ cmd_change_password (void) uint8_t old_ks[KEYSTRING_MD_SIZE]; uint8_t new_ks0[KEYSTRING_MD_SIZE+1]; uint8_t *new_ks = &new_ks0[1]; - uint8_t p1 = cmd_APDU[2]; /* 0: change (old+new), 1: exchange (new) */ - uint8_t p2 = cmd_APDU[3]; + uint8_t p1 = P1 (apdu); /* 0: change (old+new), 1: exchange (new) */ + uint8_t p2 = P2 (apdu); int len; const uint8_t *pw; const uint8_t *newpw; @@ -225,13 +221,8 @@ cmd_change_password (void) DEBUG_INFO ("Change PW\r\n"); DEBUG_BYTE (who); - len = cmd_APDU[4]; - pw = &cmd_APDU[5]; - if (len == 0) /* extended length */ - { - len = (cmd_APDU[5]<<8) | cmd_APDU[6]; - pw += 2; - } + len = apdu.cmd_apdu_data_len; + pw = apdu.cmd_apdu_data; if (p1 != 0) { @@ -329,7 +320,7 @@ cmd_change_password (void) static void cmd_reset_user_password (void) { - uint8_t p1 = cmd_APDU[2]; + uint8_t p1 = P1 (apdu); int len; const uint8_t *pw; const uint8_t *newpw; @@ -341,13 +332,8 @@ cmd_reset_user_password (void) DEBUG_INFO ("Reset PW1\r\n"); DEBUG_BYTE (p1); - len = cmd_APDU[4]; - pw = &cmd_APDU[5]; - if (len == 0) /* extended length */ - { - len = (cmd_APDU[5]<<8) | cmd_APDU[6]; - pw += 2; - } + len = apdu.cmd_apdu_data_len; + pw = apdu.cmd_apdu_data; if (p1 == 0x00) /* by User with Reseting Code */ { @@ -469,17 +455,9 @@ cmd_put_data (void) if (file_selection != FILE_DF_OPENPGP) GPG_NO_RECORD(); - tag = ((cmd_APDU[2]<<8) | cmd_APDU[3]); - data = &cmd_APDU[5]; - - len = cmd_APDU_size - 5; - if (len >= 256) - /* extended Lc */ - { - data += 2; - len -= 2; - } - + tag = ((P1 (apdu)<<8) | P2 (apdu)); + len = apdu.cmd_apdu_data_len; + data = apdu.cmd_apdu_data; gpg_do_put_data (tag, data, len); } @@ -487,16 +465,11 @@ static void cmd_pgp_gakp (void) { DEBUG_INFO (" - Generate Asymmetric Key Pair\r\n"); - DEBUG_BYTE (cmd_APDU[2]); + DEBUG_BYTE (P1 (apdu)); - if (cmd_APDU[2] == 0x81) + if (P1 (apdu) == 0x81) /* Get public key */ - { - if (cmd_APDU[4] == 0) - gpg_do_public_key (cmd_APDU[7]); - else - gpg_do_public_key (cmd_APDU[5]); - } + gpg_do_public_key (apdu.cmd_apdu_data[0]); else { /* Generate key pair */ if (!ac_check_status (AC_ADMIN_AUTHORIZED)) @@ -514,7 +487,7 @@ cmd_read_binary (void) if (file_selection == FILE_EF_SERIAL) { - if (cmd_APDU[3] >= 6) + if (P2 (apdu) >= 6) GPG_BAD_P0_P1 (); else { @@ -529,19 +502,23 @@ cmd_read_binary (void) static void cmd_select_file (void) { - if (cmd_APDU[2] == 4) /* Selection by DF name */ + if (P1 (apdu) == 4) /* Selection by DF name */ { DEBUG_INFO (" - select DF by name\r\n"); /* name = D2 76 00 01 24 01 */ - if (cmd_APDU[4] != 6 || memcmp (openpgpcard_aid, &cmd_APDU[5], 6) != 0) + if (apdu.cmd_apdu_data_len != 6 + || memcmp (openpgpcard_aid, apdu.cmd_apdu_data, 6) != 0) { + DEBUG_WORD (apdu.cmd_apdu_data_len); + DEBUG_BINARY (apdu.cmd_apdu_data, apdu.cmd_apdu_data_len); + GPG_NO_FILE (); return; } file_selection = FILE_DF_OPENPGP; - if ((cmd_APDU[3] & 0x0c) == 0x0c) /* No FCI */ + if ((P2 (apdu) & 0x0c) == 0x0c) /* No FCI */ GPG_SUCCESS (); else { @@ -553,8 +530,8 @@ cmd_select_file (void) res_APDU_size += 2; } } - else if (cmd_APDU[4] == 2 - && cmd_APDU[5] == 0x2f && cmd_APDU[6] == 0x02) + else if (apdu.cmd_apdu_data_len == 2 + && apdu.cmd_apdu_data[0] == 0x2f && apdu.cmd_apdu_data[1] == 0x02) { DEBUG_INFO (" - select 0x2f02 EF\r\n"); /* @@ -563,11 +540,11 @@ cmd_select_file (void) GPG_SUCCESS (); file_selection = FILE_EF_SERIAL; } - else if (cmd_APDU[4] == 2 - && cmd_APDU[5] == 0x3f && cmd_APDU[6] == 0x00) + else if (apdu.cmd_apdu_data_len == 2 + && apdu.cmd_apdu_data[0] == 0x3f && apdu.cmd_apdu_data[1] == 0x00) { DEBUG_INFO (" - select ROOT MF\r\n"); - if (cmd_APDU[3] == 0x0c) + if (P2 (apdu) == 0x0c) { GPG_SUCCESS (); } @@ -575,12 +552,11 @@ cmd_select_file (void) { int len = sizeof (select_file_TOP_result); - res_APDU_size = 2 + len; + res_APDU_size = len; memcpy (res_APDU, select_file_TOP_result, len); res_APDU[2] = (data_objects_number_of_bytes & 0xff); res_APDU[3] = (data_objects_number_of_bytes >> 8); - res_APDU[len] = 0x90; - res_APDU[len+1] = 0x00; + GPG_SUCCESS (); } file_selection = FILE_MF; @@ -598,7 +574,7 @@ cmd_select_file (void) static void cmd_get_data (void) { - uint16_t tag = ((cmd_APDU[2]<<8) | cmd_APDU[3]); + uint16_t tag = ((P1 (apdu)<<8) | P2 (apdu)); DEBUG_INFO (" - Get Data\r\n"); @@ -611,21 +587,14 @@ cmd_get_data (void) static void cmd_pso (void) { - int len = cmd_APDU[4]; - int data_start = 5; + int len = apdu.cmd_apdu_data_len; int r; - if (len == 0) - { - len = (cmd_APDU[5]<<8) | cmd_APDU[6]; - data_start = 7; - } - DEBUG_INFO (" - PSO: "); DEBUG_WORD ((uint32_t)&r); - DEBUG_BINARY (cmd_APDU, cmd_APDU_size); + DEBUG_BINARY (apdu.cmd_apdu_data, apdu.cmd_apdu_data_len); - if (cmd_APDU[2] == 0x9e && cmd_APDU[3] == 0x9a) + if (P1 (apdu) == 0x9e && P2 (apdu) == 0x9a) { if (!ac_check_status (AC_PSO_CDS_AUTHORIZED)) { @@ -634,24 +603,24 @@ cmd_pso (void) return; } - if (cmd_APDU_size != 7 + 34 + 2 /* MD5 */ - /* Header (with Extended Lc)=7, size of digestInfo, and Le=2-byte */ - && cmd_APDU_size != 7 + 35 + 2 /* SHA1 / RIPEMD-160 */ - && cmd_APDU_size != 7 + 47 + 2 /* SHA224 */ - && cmd_APDU_size != 7 + 51 + 2 /* SHA256 */ - && cmd_APDU_size != 7 + 67 + 2 /* SHA384 */ - && cmd_APDU_size != 7 + 83 + 2) /* SHA512 */ + /* Check size of digestInfo */ + if (len != 34 /* MD5 */ + && len != 35 /* SHA1 / RIPEMD-160 */ + && len != 47 /* SHA224 */ + && len != 51 /* SHA256 */ + && len != 67 /* SHA384 */ + && len != 83) /* SHA512 */ { DEBUG_INFO (" wrong length: "); - DEBUG_SHORT (cmd_APDU_size); + DEBUG_SHORT (len); GPG_ERROR (); } else { - DEBUG_SHORT (len); /* Should be cmd_APDU_size - 8 [- 1] */ + DEBUG_SHORT (len); DEBUG_BINARY (&kd[GPG_KEY_FOR_SIGNING], KEY_CONTENT_LEN); - r = rsa_sign (&cmd_APDU[data_start], res_APDU, len, + r = rsa_sign (apdu.cmd_apdu_data, res_APDU, len, &kd[GPG_KEY_FOR_SIGNING]); if (r < 0) { @@ -663,7 +632,7 @@ cmd_pso (void) gpg_increment_digital_signature_counter (); } } - else if (cmd_APDU[2] == 0x80 && cmd_APDU[3] == 0x86) + else if (P1 (apdu) == 0x80 && P2 (apdu) == 0x86) { DEBUG_SHORT (len); DEBUG_BINARY (&kd[GPG_KEY_FOR_DECRYPTION], KEY_CONTENT_LEN); @@ -676,9 +645,8 @@ cmd_pso (void) } /* Skip padding 0x00 */ - data_start++; len--; - r = rsa_decrypt (&cmd_APDU[data_start], res_APDU, len, + r = rsa_decrypt (apdu.cmd_apdu_data+1, res_APDU, len, &kd[GPG_KEY_FOR_DECRYPTION]); if (r < 0) GPG_ERROR (); @@ -686,9 +654,9 @@ cmd_pso (void) else { DEBUG_INFO (" - ??"); - DEBUG_BYTE (cmd_APDU[2]); + DEBUG_BYTE (P1 (apdu)); DEBUG_INFO (" - ??"); - DEBUG_BYTE (cmd_APDU[3]); + DEBUG_BYTE (P2 (apdu)); GPG_ERROR (); } @@ -698,19 +666,12 @@ cmd_pso (void) static void cmd_internal_authenticate (void) { - int len = cmd_APDU[4]; - int data_start = 5; + int len = apdu.cmd_apdu_data_len; int r; - 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) + if (P1 (apdu) == 0x00 && P2 (apdu) == 0x00) { DEBUG_SHORT (len); @@ -721,7 +682,7 @@ cmd_internal_authenticate (void) return; } - r = rsa_sign (&cmd_APDU[data_start], res_APDU, len, + r = rsa_sign (apdu.cmd_apdu_data, res_APDU, len, &kd[GPG_KEY_FOR_AUTHENTICATION]); if (r < 0) GPG_ERROR (); @@ -729,9 +690,9 @@ cmd_internal_authenticate (void) else { DEBUG_INFO (" - ??"); - DEBUG_BYTE (cmd_APDU[2]); + DEBUG_BYTE (P1 (apdu)); DEBUG_INFO (" - ??"); - DEBUG_BYTE (cmd_APDU[3]); + DEBUG_BYTE (P2 (apdu)); GPG_ERROR (); } @@ -742,17 +703,10 @@ cmd_internal_authenticate (void) static void cmd_update_binary (void) { - int len = cmd_APDU[4]; - int data_start = 5; + int len = apdu.cmd_apdu_data_len; uint16_t offset; int r; - if (len == 0) - { - len = (cmd_APDU[5]<<8) | cmd_APDU[6]; - data_start = 7; - } - DEBUG_INFO (" - UPDATE BINARY\r\n"); if (!ac_check_status (AC_ADMIN_AUTHORIZED)) @@ -762,10 +716,10 @@ cmd_update_binary (void) return; } - if ((cmd_APDU[2] & 0x80)) - if ((cmd_APDU[2] & 0x7f) <= FILEID_RANDOM) + if ((P1 (apdu) & 0x80)) + if ((P1 (apdu) & 0x7f) <= FILEID_RANDOM) { - file_selection = FILE_EF_CH_CERTIFICATE + (cmd_APDU[2] & 0x7f); + file_selection = FILE_EF_CH_CERTIFICATE + (P1 (apdu) & 0x7f); r = flash_erase_binary (file_selection - FILE_EF_CH_CERTIFICATE); if (r < 0) { @@ -790,14 +744,14 @@ cmd_update_binary (void) return; } - offset = (cmd_APDU[2] << 8) | cmd_APDU[3]; + offset = (P1 (apdu) << 8) | P2 (apdu); } DEBUG_SHORT (len); DEBUG_SHORT (offset); r = flash_write_binary (file_selection - FILE_EF_CH_CERTIFICATE, - &cmd_APDU[data_start], len, offset); + apdu.cmd_apdu_data, len, offset); if (r < 0) { DEBUG_INFO ("memory error.\r\n"); @@ -813,17 +767,10 @@ cmd_update_binary (void) static void cmd_write_binary (void) { - int len = cmd_APDU[4]; - int data_start = 5; + int len = apdu.cmd_apdu_data_len; uint16_t offset; int r; - if (len == 0) - { - len = (cmd_APDU[5]<<8) | cmd_APDU[6]; - data_start = 7; - } - DEBUG_INFO (" - WRITE BINARY\r\n"); if (!ac_check_status (AC_ADMIN_AUTHORIZED)) @@ -833,10 +780,10 @@ cmd_write_binary (void) return; } - if ((cmd_APDU[2] & 0x80)) - if ((cmd_APDU[2] & 0x7f) <= FILEID_SERIAL_NO) + if ((P1 (apdu) & 0x80)) + if ((P1 (apdu) & 0x7f) <= FILEID_SERIAL_NO) { - file_selection = FILE_EF_CH_CERTIFICATE + (cmd_APDU[2] & 0x7f); + file_selection = FILE_EF_CH_CERTIFICATE + (P1 (apdu) & 0x7f); offset = 0; } else @@ -854,14 +801,14 @@ cmd_write_binary (void) return; } - offset = (cmd_APDU[2] << 8) | cmd_APDU[3]; + offset = (P1 (apdu) << 8) | P2 (apdu); } DEBUG_SHORT (len); DEBUG_SHORT (offset); r = flash_write_binary (file_selection - FILE_EF_CH_CERTIFICATE, - &cmd_APDU[data_start], len, offset); + apdu.cmd_apdu_data, len, offset); if (r < 0) { DEBUG_INFO ("memory error.\r\n"); @@ -901,7 +848,7 @@ static void process_command_apdu (void) { int i; - uint8_t cmd = cmd_APDU[1]; + uint8_t cmd = INS (apdu); for (i = 0; i < NUM_CMDS; i++) if (cmds[i].command == cmd) @@ -935,12 +882,10 @@ GPGthread (void *arg) DEBUG_INFO ("GPG!: "); - res_APDU_pointer = NULL; - if (m == EV_VERIFY_CMD_AVAILABLE) { #if defined(PINPAD_SUPPORT) - if (cmd_APDU[1] != INS_VERIFY) + if (INS (apdu) != INS_VERIFY) { GPG_CONDITION_NOT_SATISFIED (); goto done; @@ -952,9 +897,8 @@ GPGthread (void *arg) GPG_ERROR (); goto done; } - memcpy (&cmd_APDU[5], pin_input_buffer, pw_len); - cmd_APDU[4] = pw_len; - icc_data_size = 5 + pw_len; + memcpy (apdu.cmd_apdu_data, pin_input_buffer, pw_len); + apdu.cmd_apdu_data_len = pw_len; #else GPG_ERROR (); goto done; @@ -963,12 +907,12 @@ GPGthread (void *arg) else if (m == EV_MODIFY_CMD_AVAILABLE) { #if defined(PINPAD_SUPPORT) - uint8_t bConfirmPIN = cmd_APDU[4]; - uint8_t *p = &cmd_APDU[5]; + uint8_t bConfirmPIN = apdu.cmd_apdu_data[5]; + uint8_t *p = apdu.cmd_apdu_data; - if (cmd_APDU[1] != INS_CHANGE_REFERENCE_DATA - && cmd_APDU[1] != INS_RESET_RETRY_COUNTER - && cmd_APDU[1] != INS_PUT_DATA) + if (INS (apdu) != INS_CHANGE_REFERENCE_DATA + && INS (apdu) != INS_RESET_RETRY_COUNTER + && INS (apdu) != INS_PUT_DATA) { GPG_CONDITION_NOT_SATISFIED (); goto done; @@ -1012,8 +956,7 @@ GPGthread (void *arg) } } - len = cmd_APDU[4] = pw_len + newpw_len; - icc_data_size = 5 + len; + apdu.cmd_apdu_data_len = pw_len + newpw_len; #else GPG_ERROR (); goto done; @@ -1022,12 +965,9 @@ GPGthread (void *arg) else if (m == EV_NOP) continue; - if (icc_data_size != 0) - { - process_command_apdu (); - done: - chEvtSignal (icc_thread, EV_EXEC_FINISHED); - } + process_command_apdu (); + done: + chEvtSignal (icc_thread, EV_EXEC_FINISHED); } gpg_fini (); diff --git a/src/usb-icc.c b/src/usb-icc.c index daa8752..3d442cb 100644 --- a/src/usb-icc.c +++ b/src/usb-icc.c @@ -31,6 +31,8 @@ #include "usb_istr.h" #include "usb_lld.h" +struct apdu apdu; + #define ICC_SET_PARAMS 0x61 /* non-ICCD command */ #define ICC_POWER_ON 0x62 #define ICC_POWER_OFF 0x63 @@ -74,7 +76,7 @@ struct icc_header { uint16_t param; } __attribute__((packed)); -int icc_data_size; +static int icc_data_size; /* * USB-ICC communication could be considered "half duplex". @@ -94,8 +96,8 @@ int icc_data_size; * The buffer will be filled by multiple RX transactions (Bulk-OUT) * or will be used for multiple TX transactions (Bulk-IN) */ -uint8_t icc_buffer[USB_BUF_SIZE]; -uint8_t icc_seq; +static uint8_t icc_buffer[USB_BUF_SIZE]; +static uint8_t icc_seq; /* * Pointer to ICC_BUFFER @@ -391,9 +393,6 @@ icc_power_off (void) return ICC_STATE_START; } -int res_APDU_size; -const uint8_t *res_APDU_pointer; - static void icc_send_data_block (int len, uint8_t status, uint8_t chain) { @@ -501,6 +500,87 @@ icc_handle_data (void) { if (icc_header->param == 0) { /* Give this message to GPG thread */ + run_gpg_thread: + apdu.seq = icc_seq; + apdu.cmd_apdu_head = &icc_buffer[ICC_MSG_HEADER_SIZE]; + + apdu.sw = 0x9000; + apdu.res_apdu_data_len = 0; + apdu.res_apdu_data = &icc_buffer[ICC_MSG_HEADER_SIZE]; + + if (icc_data_size < 4) + { + icc_error (ICC_MSG_HEADER_SIZE + icc_data_size); + next_state = ICC_STATE_WAIT; + break; + } + else if (icc_data_size == 4) + { /* No Lc and No Le */ + apdu.cmd_apdu_data = NULL; + apdu.cmd_apdu_data_len = 0; + apdu.expected_res_size = 0; + apdu.cmd_apdu_head[4] = 0; + } + else if (icc_data_size == 5) + { /* No Lc but Le */ + apdu.cmd_apdu_data = NULL; + apdu.cmd_apdu_data_len = 0; + apdu.expected_res_size = apdu.cmd_apdu_head[4]; + if (apdu.expected_res_size == 0) + apdu.expected_res_size = 256; + apdu.cmd_apdu_head[4] = 0; + } + else if (apdu.cmd_apdu_head[4] == 0) + { /* extended Lc or extended Le */ + apdu.cmd_apdu_data = apdu.cmd_apdu_head + 7; + apdu.cmd_apdu_data_len + = (apdu.cmd_apdu_head[5] << 8) + apdu.cmd_apdu_head[6]; + if (icc_data_size == 7) + { /* No Lc but extended Le */ + apdu.expected_res_size = apdu.cmd_apdu_data_len; + apdu.cmd_apdu_data_len = 0; + } + else if (icc_data_size == apdu.cmd_apdu_data_len + 7) + apdu.expected_res_size = 0; + else if (icc_data_size == apdu.cmd_apdu_data_len + 7 + 2) + { + apdu.expected_res_size + = (icc_buffer[ICC_MSG_HEADER_SIZE + 7 + + apdu.cmd_apdu_data_len] << 8) + | icc_buffer[ICC_MSG_HEADER_SIZE + 7 + + apdu.cmd_apdu_data_len + 1]; + if (apdu.expected_res_size == 0) + apdu.expected_res_size = 65536; + } + else + { + icc_error (ICC_MSG_HEADER_SIZE + 5); + next_state = ICC_STATE_WAIT; + break; + } + } + else /* short Lc */ + { + apdu.cmd_apdu_data = apdu.cmd_apdu_head + 5; + apdu.cmd_apdu_data_len = apdu.cmd_apdu_head[4]; + if (icc_data_size == apdu.cmd_apdu_data_len + 5) + apdu.expected_res_size = 0; + else if (icc_data_size == apdu.cmd_apdu_data_len + 5 + 1) + { + apdu.expected_res_size + = icc_buffer[ICC_MSG_HEADER_SIZE + 5 + + apdu.cmd_apdu_data_len]; + if (apdu.expected_res_size == 0) + apdu.expected_res_size = 256; + } + else + { + icc_error (ICC_MSG_HEADER_SIZE + 5); + next_state = ICC_STATE_WAIT; + break; + } + } + chEvtSignal (gpg_thread, EV_CMD_AVAILABLE); next_state = ICC_STATE_EXECUTE; } @@ -523,19 +603,28 @@ icc_handle_data (void) { if (icc_buffer[10] == 0x00) /* PIN verification */ { - cmd_APDU[0] = icc_buffer[25]; - cmd_APDU[1] = icc_buffer[26]; - cmd_APDU[2] = icc_buffer[27]; - cmd_APDU[3] = icc_buffer[28]; - icc_data_size = 4; - cmd_APDU[4] = 0; /* bConfirmPIN */ - cmd_APDU[5] = icc_buffer[17]; /* bEntryValidationCondition */ - cmd_APDU[6] = icc_buffer[18]; /* bNumberMessage */ - cmd_APDU[7] = icc_buffer[19]; /* wLangId L */ - cmd_APDU[8] = icc_buffer[20]; /* wLangId H */ - cmd_APDU[9] = icc_buffer[21]; /* bMsgIndex, bMsgIndex1 */ - cmd_APDU[10] = 0; /* bMsgIndex2 */ - cmd_APDU[11] = 0; /* bMsgIndex3 */ + icc_buffer[ICC_MSG_HEADER_SIZE+0] = icc_buffer[25]; + icc_buffer[ICC_MSG_HEADER_SIZE+1] = icc_buffer[26]; + icc_buffer[ICC_MSG_HEADER_SIZE+2] = icc_buffer[27]; + icc_buffer[ICC_MSG_HEADER_SIZE+3] = icc_buffer[28]; + /**/ + icc_buffer[ICC_MSG_HEADER_SIZE+5] = 0; /* bConfirmPIN */ + icc_buffer[ICC_MSG_HEADER_SIZE+6] = icc_buffer[17]; /* bEntryValidationCondition */ + icc_buffer[ICC_MSG_HEADER_SIZE+7] = icc_buffer[18]; /* bNumberMessage */ + icc_buffer[ICC_MSG_HEADER_SIZE+8] = icc_buffer[19]; /* wLangId L */ + icc_buffer[ICC_MSG_HEADER_SIZE+9] = icc_buffer[20]; /* wLangId H */ + icc_buffer[ICC_MSG_HEADER_SIZE+10] = icc_buffer[21]; /* bMsgIndex */ + + apdu.seq = icc_seq; + apdu.cmd_apdu_head = &icc_buffer[ICC_MSG_HEADER_SIZE+0]; + apdu.cmd_apdu_data = &icc_buffer[ICC_MSG_HEADER_SIZE+5]; + apdu.cmd_apdu_data_len = 6; + apdu.expected_res_size = 0; + + apdu.sw = 0x9000; + apdu.res_apdu_data_len = 0; + apdu.res_apdu_data = &icc_buffer[ICC_MSG_HEADER_SIZE]; + chEvtSignal (gpg_thread, EV_VERIFY_CMD_AVAILABLE); next_state = ICC_STATE_EXECUTE; } @@ -547,22 +636,32 @@ icc_handle_data (void) num_msgs = 1; else if (num_msgs == 0xff) num_msgs = 3; - cmd_APDU[0] = icc_buffer[27 + num_msgs]; - cmd_APDU[1] = icc_buffer[28 + num_msgs]; - cmd_APDU[2] = icc_buffer[29 + num_msgs]; - cmd_APDU[3] = icc_buffer[30 + num_msgs]; - icc_data_size = 4; - cmd_APDU[4] = icc_buffer[19]; /* bConfirmPIN */ - cmd_APDU[5] = icc_buffer[20]; /* bEntryValidationCondition */ - cmd_APDU[6] = icc_buffer[21]; /* bNumberMessage */ - cmd_APDU[7] = icc_buffer[22]; /* wLangId L */ - cmd_APDU[8] = icc_buffer[23]; /* wLangId H */ - cmd_APDU[9] = icc_buffer[24]; /* bMsgIndex, bMsgIndex1 */ - cmd_APDU[10] = cmd_APDU[11] = 0; + icc_buffer[ICC_MSG_HEADER_SIZE+0] = icc_buffer[27 + num_msgs]; + icc_buffer[ICC_MSG_HEADER_SIZE+1] = icc_buffer[28 + num_msgs]; + icc_buffer[ICC_MSG_HEADER_SIZE+2] = icc_buffer[29 + num_msgs]; + icc_buffer[ICC_MSG_HEADER_SIZE+3] = icc_buffer[30 + num_msgs]; + /**/ + icc_buffer[ICC_MSG_HEADER_SIZE+5] = icc_buffer[19]; /* bConfirmPIN */ + icc_buffer[ICC_MSG_HEADER_SIZE+6] = icc_buffer[20]; /* bEntryValidationCondition */ + icc_buffer[ICC_MSG_HEADER_SIZE+7] = icc_buffer[21]; /* bNumberMessage */ + icc_buffer[ICC_MSG_HEADER_SIZE+8] = icc_buffer[22]; /* wLangId L */ + icc_buffer[ICC_MSG_HEADER_SIZE+9] = icc_buffer[23]; /* wLangId H */ + icc_buffer[ICC_MSG_HEADER_SIZE+10] = icc_buffer[24]; /* bMsgIndex, bMsgIndex1 */ if (num_msgs >= 2) - cmd_APDU[10] = icc_buffer[25]; /* bMsgIndex2 */ + icc_buffer[ICC_MSG_HEADER_SIZE+11] = icc_buffer[25]; /* bMsgIndex2 */ if (num_msgs == 3) - cmd_APDU[11] = icc_buffer[26]; /* bMsgIndex3 */ + icc_buffer[ICC_MSG_HEADER_SIZE+12] = icc_buffer[26]; /* bMsgIndex3 */ + + apdu.seq = icc_seq; + apdu.cmd_apdu_head = &icc_buffer[ICC_MSG_HEADER_SIZE+0]; + apdu.cmd_apdu_data = &icc_buffer[ICC_MSG_HEADER_SIZE+5]; + apdu.cmd_apdu_data_len = 5 + num_msgs; + apdu.expected_res_size = 0; + + apdu.sw = 0x9000; + apdu.res_apdu_data_len = 0; + apdu.res_apdu_data = &icc_buffer[ICC_MSG_HEADER_SIZE]; + chEvtSignal (gpg_thread, EV_MODIFY_CMD_AVAILABLE); next_state = ICC_STATE_EXECUTE; } @@ -594,8 +693,7 @@ icc_handle_data (void) icc_next_p -= ICC_MSG_HEADER_SIZE; icc_data_size = icc_next_p - icc_buffer - ICC_MSG_HEADER_SIZE; icc_chain_p = NULL; - next_state = ICC_STATE_EXECUTE; - chEvtSignal (gpg_thread, EV_CMD_AVAILABLE); + goto run_gpg_thread; } else /* icc_header->param == 3 is not supported. */ { @@ -633,25 +731,59 @@ icc_handle_data (void) { if (icc_header->param == 0x10) { - if (res_APDU_pointer != NULL) + int len = apdu.res_apdu_data_len; + + if (apdu.res_apdu_data == NULL) + { /* send last byte of 0x9000 */ + icc_buffer[ICC_MSG_HEADER_SIZE] = 0x00; + len = 1; + } + else if (apdu.res_apdu_data != &icc_buffer[ICC_MSG_HEADER_SIZE]) { - memcpy (res_APDU, res_APDU_pointer, - ICC_RESPONSE_MSG_DATA_SIZE); - res_APDU_pointer += ICC_RESPONSE_MSG_DATA_SIZE; + if (apdu.res_apdu_data_len >= ICC_RESPONSE_MSG_DATA_SIZE) + { + memcpy (&icc_buffer[ICC_MSG_HEADER_SIZE], + apdu.res_apdu_data, ICC_RESPONSE_MSG_DATA_SIZE); + apdu.res_apdu_data += ICC_RESPONSE_MSG_DATA_SIZE; + } + else if (apdu.res_apdu_data_len + <= ICC_RESPONSE_MSG_DATA_SIZE - 2) + { + memcpy (&icc_buffer[ICC_MSG_HEADER_SIZE], + apdu.res_apdu_data, apdu.res_apdu_data_len); + icc_buffer[ICC_MSG_HEADER_SIZE+apdu.res_apdu_data_len] + = 0x90; + icc_buffer[ICC_MSG_HEADER_SIZE+apdu.res_apdu_data_len+1] + = 0x00; + apdu.res_apdu_data = NULL; + len += 2; + } + else if (apdu.res_apdu_data_len + == ICC_RESPONSE_MSG_DATA_SIZE - 1) + { + memcpy (&icc_buffer[ICC_MSG_HEADER_SIZE], + apdu.res_apdu_data, apdu.res_apdu_data_len); + icc_buffer[ICC_MSG_HEADER_SIZE+apdu.res_apdu_data_len] + = 0x90; + apdu.res_apdu_data = NULL; + len += 1; + } } else - memmove (res_APDU, res_APDU+ICC_RESPONSE_MSG_DATA_SIZE, - res_APDU_size); + memmove (&icc_buffer[ICC_MSG_HEADER_SIZE], + &icc_buffer[ICC_MSG_HEADER_SIZE] + +ICC_RESPONSE_MSG_DATA_SIZE, + apdu.res_apdu_data_len); - if (res_APDU_size <= ICC_RESPONSE_MSG_DATA_SIZE) + if (len <= ICC_RESPONSE_MSG_DATA_SIZE) { - icc_send_data_block (res_APDU_size, 0, 0x02); + icc_send_data_block (len, 0, 0x02); next_state = ICC_STATE_WAIT; } else { icc_send_data_block (ICC_RESPONSE_MSG_DATA_SIZE, 0, 0x03); - res_APDU_size -= ICC_RESPONSE_MSG_DATA_SIZE; + apdu.res_apdu_data_len -= ICC_RESPONSE_MSG_DATA_SIZE; } } else @@ -721,26 +853,36 @@ USBthread (void *arg) else if (m == EV_EXEC_FINISHED) if (icc_state == ICC_STATE_EXECUTE) { - if (res_APDU_pointer != NULL) + if (apdu.res_apdu_data != &icc_buffer[ICC_MSG_HEADER_SIZE]) { - memcpy (res_APDU, res_APDU_pointer, ICC_RESPONSE_MSG_DATA_SIZE); - res_APDU_pointer += ICC_RESPONSE_MSG_DATA_SIZE; + /* Assume that + * apdu.res_apdu_data_len > ICC_RESPONSE_MSG_DATA_SIZE + */ + memcpy (&icc_buffer[ICC_MSG_HEADER_SIZE], + apdu.res_apdu_data, ICC_RESPONSE_MSG_DATA_SIZE); + apdu.res_apdu_data += ICC_RESPONSE_MSG_DATA_SIZE; + } + else + { + icc_buffer[ICC_MSG_HEADER_SIZE+apdu.res_apdu_data_len] = (apdu.sw >> 8); + icc_buffer[ICC_MSG_HEADER_SIZE+apdu.res_apdu_data_len+1] = (apdu.sw & 0xff); + apdu.res_apdu_data_len += 2; } - if (res_APDU_size <= ICC_RESPONSE_MSG_DATA_SIZE) + if (apdu.res_apdu_data_len <= ICC_RESPONSE_MSG_DATA_SIZE) { - icc_send_data_block (res_APDU_size, 0, 0); + icc_send_data_block (apdu.res_apdu_data_len, 0, 0); icc_state = ICC_STATE_WAIT; } else { icc_send_data_block (ICC_RESPONSE_MSG_DATA_SIZE, 0, 0x01); - res_APDU_size -= ICC_RESPONSE_MSG_DATA_SIZE; + apdu.res_apdu_data_len -= ICC_RESPONSE_MSG_DATA_SIZE; icc_state = ICC_STATE_SEND; } } else - { /* XXX: error */ + { /* error */ DEBUG_INFO ("ERR07\r\n"); } else if (m == EV_TX_FINISHED) diff --git a/tool/gnuk_put_binary.py b/tool/gnuk_put_binary.py index f0e83cc..d3de957 100755 --- a/tool/gnuk_put_binary.py +++ b/tool/gnuk_put_binary.py @@ -47,7 +47,7 @@ class GnukToken(object): apdu = [0x00, 0x20, 0x00, 0x80+who, 0, 0, len(passwd)] + s2l(passwd) response, sw1, sw2 = self.connection.transmit(apdu) if not (sw1 == 0x90 and sw2 == 0x00): - raise ValueError, "cmd_verify" + raise ValueError, ("%02x%02x" % (sw1, sw2)) def cmd_write_binary(self, fileid, data, is_update): count = 0 @@ -66,22 +66,22 @@ class GnukToken(object): response, sw1, sw2 = self.connection.transmit(apdu) if not (sw1 == 0x90 and sw2 == 0x00): if is_update: - raise ValueError, "cmd_update_binary" + raise ValueError, ("%02x%02x" % (sw1, sw2)) else: - raise ValueError, "cmd_write_binary" + raise ValueError, ("%02x%02x" % (sw1, sw2)) count += 1 def cmd_select_openpgp(self): apdu = [0x00, 0xa4, 0x04, 0x00, 6, 0xd2, 0x76, 0x00, 0x01, 0x24, 0x01 ] response, sw1, sw2 = self.connection.transmit(apdu) if not (sw1 == 0x90 and sw2 == 0x00): - raise ValueError, "cmd_select_openpgp" + raise ValueError, ("%02x%02x" % (sw1, sw2)) def cmd_get_data(self, tagh, tagl): apdu = [0x00, 0xca, tagh, tagl] response, sw1, sw2 = self.connection.transmit(apdu) if not (sw1 == 0x90 and sw2 == 0x00): - raise ValueError, "cmd_get_data" + raise ValueError, ("%02x%02x" % (sw1, sw2)) return response def compare(data_original, data_in_device): @@ -165,6 +165,5 @@ if __name__ == '__main__': data = f.read() f.close() print "%s: %d" % (filename, len(data)) - data += "\x90\x00" print "Updating card holder certificate" main(fileid, is_update, data, passwd) diff --git a/tool/gnuk_put_binary_libusb.py b/tool/gnuk_put_binary_libusb.py index 4d7afef..ae47ba9 100755 --- a/tool/gnuk_put_binary_libusb.py +++ b/tool/gnuk_put_binary_libusb.py @@ -289,6 +289,5 @@ if __name__ == '__main__': data = f.read() f.close() print "%s: %d" % (filename, len(data)) - data += "\x90\x00" print "Updating card holder certificate" main(fileid, is_update, data)