From c64e9ac52772e439dfcf642b332dd8cd067251e4 Mon Sep 17 00:00:00 2001 From: frankmorgner Date: Thu, 10 Jun 2010 11:14:39 +0000 Subject: [PATCH] - implemented passing a CHAT to the card. - note that the type PACE_CHAT should be integrated into OpenPACE - added parameters for passing CHAT and certificate description to pace-tool git-svn-id: https://vsmartcard.svn.sourceforge.net/svnroot/vsmartcard@146 96b47cad-a561-4643-ad3b-153ac7d7599c --- ccid/src/pace-tool.c | 74 ++++++++++++++++++++++++++++------ ccid/src/pace.c | 94 +++++++++++++++++++++++++++++++------------- 2 files changed, 130 insertions(+), 38 deletions(-) diff --git a/ccid/src/pace-tool.c b/ccid/src/pace-tool.c index 822142e..d3e8ab4 100644 --- a/ccid/src/pace-tool.c +++ b/ccid/src/pace-tool.c @@ -19,6 +19,7 @@ #include "binutil.h" #include "pace.h" #include "scutil.h" +#include #include #include #include @@ -43,6 +44,10 @@ static const char *can = NULL; static u8 usecan = 0; static const char *mrz = NULL; static u8 usemrz = 0; +static u8 chat[0xff]; +static size_t chatlen = 0; +static u8 desc[0xffff]; +static size_t desclen = 0; static const char *cdriver = NULL; static sc_context_t *ctx = NULL; @@ -55,6 +60,8 @@ static sc_reader_t *reader; #define OPT_PUK 'u' #define OPT_CAN 'a' #define OPT_MRZ 'z' +#define OPT_CHAT 'C' +#define OPT_CERTDESC 'D' #define OPT_CHANGE_PIN 'N' #define OPT_RESUME_PIN 'R' #define OPT_TRANSLATE 't' @@ -70,6 +77,8 @@ static const struct option options[] = { { "puk", optional_argument, NULL, OPT_PUK }, { "can", optional_argument, NULL, OPT_CAN }, { "mrz", optional_argument, NULL, OPT_MRZ }, + { "chat", required_argument, NULL, OPT_CHAT }, + { "cert-desc", required_argument, NULL, OPT_CERTDESC }, { "new-pin", optional_argument, NULL, OPT_CHANGE_PIN }, { "resume-pin", no_argument, NULL, OPT_RESUME_PIN }, { "translate", no_argument, NULL, OPT_TRANSLATE }, @@ -81,10 +90,12 @@ static const char *option_help[] = { "Print help and exit", "Number of reader to use (default: auto-detect)", "Which card driver to use (default: auto-detect)", - "Run PACE with PIN", + "Run PACE with (transport) PIN", "Run PACE with PUK", "Run PACE with CAN", "Run PACE with MRZ (insert MRZ without newlines)", + "Card holder authorization template to use (hex string)", + "Certificate description to use (hex string)", "Install a new PIN", "Resume PIN (uses CAN to activate last retry)", "Send plaintext APDUs through the PACE SM channel", @@ -94,9 +105,11 @@ static const char *option_help[] = { int pace_get_channel(struct sm_ctx *oldpacectx, sc_card_t *card, enum s_type pin_id, const char *pin, size_t pinlen, + const char *chat, size_t chatlen, const char *desc, size_t desclen, __u8 **out, size_t *outlen, struct sm_ctx *sctx) { - u8 buf[0xff + 5]; + u8 buf[0xff + 0xff + 0xffff + 5]; + __le16 word; switch (pin_id) { case PACE_MRZ: @@ -109,17 +122,38 @@ int pace_get_channel(struct sm_ctx *oldpacectx, sc_card_t *card, return SC_ERROR_INVALID_ARGUMENTS; } - if (pinlen > sizeof(buf) - 5) { - sc_error(card->ctx, "%s too long (maximal %u bytes supported)", + if (pinlen > 0xff) { + sc_error(card->ctx, "%s " + "too long (maximal %u bytes supported)", pace_secret_name(pin_id), - sizeof(buf) - 5); + 0xff); + return SC_ERROR_INVALID_ARGUMENTS; } + if (chatlen > 0xff) { + sc_error(card->ctx, "CHAT " + "too long (maximal %u bytes supported)", + 0xff); + return SC_ERROR_INVALID_ARGUMENTS; + } + if (desclen > 0xffff) { + sc_error(card->ctx, "Certificate description " + "too long (maximal %u bytes supported)", + 0xffff); + return SC_ERROR_INVALID_ARGUMENTS; + } + buf[0] = pin_id; - buf[1] = 0; // length_chat - buf[2] = pinlen; // length_pin - memcpy(&buf[3], pin, pinlen); - buf[3 + pinlen] = 0; // length_cert_desc - buf[4 + pinlen]= 0; // length_cert_desc + + buf[1] = chatlen; + memcpy(&buf[2], chat, chatlen); + + buf[2 + chatlen] = pinlen; + memcpy(&buf[3 + chatlen], pin, pinlen); + + word = __cpu_to_le16(desclen); + memcpy(&buf[3 + chatlen + pinlen], &word, sizeof word); + memcpy(&buf[3 + chatlen + pinlen + sizeof word], + desc, desclen); return EstablishPACEChannel(oldpacectx, card, buf, out, outlen, sctx); } @@ -195,7 +229,7 @@ main (int argc, char **argv) memset(&tmpctx, 0, sizeof(tmpctx)); while (1) { - i = getopt_long(argc, argv, "hr:i:u:a:z:N::Rtvoc:", options, &oindex); + i = getopt_long(argc, argv, "hr:i::u::a::z::C:D:N::Rtvoc:", options, &oindex); if (i == -1) break; switch (i) { @@ -242,6 +276,20 @@ main (int argc, char **argv) if (!mrz) can = getenv("MRZ"); break; + case OPT_CHAT: + chatlen = sizeof chat; + if (sc_hex_to_bin(optarg, chat, &chatlen) < 0) { + parse_error(argv[0], options, option_help, optarg, oindex); + exit(2); + } + break; + case OPT_CERTDESC: + desclen = sizeof desc; + if (sc_hex_to_bin(optarg, desc, &desclen) < 0) { + parse_error(argv[0], options, option_help, optarg, oindex); + exit(2); + } + break; case OPT_CHANGE_PIN: dochangepin = 1; newpin = optarg; @@ -300,6 +348,7 @@ main (int argc, char **argv) t_start = time(NULL); i = pace_get_channel(NULL, card, PACE_CAN, can, can ? strlen(can) : 0, + chat, chatlen, desc, desclen, &channeldata, &channeldatalen, &tmpctx); if (i < 0) goto err; @@ -309,6 +358,7 @@ main (int argc, char **argv) i = pace_get_channel(&tmpctx, card, PACE_PIN, pin, pin ? strlen(pin) : 0, + chat, chatlen, desc, desclen, &channeldata, &channeldatalen, &sctx); if (i < 0) goto err; @@ -321,6 +371,7 @@ main (int argc, char **argv) t_start = time(NULL); i = pace_get_channel(NULL, card, PACE_PIN, pin, pin ? strlen(pin) : 0, + chat, chatlen, desc, desclen, &channeldata, &channeldatalen, &sctx); if (i < 0) goto err; @@ -357,6 +408,7 @@ main (int argc, char **argv) t_start = time(NULL); i = pace_get_channel(NULL, card, id, s, s ? strlen(s) : 0, + chat, chatlen, desc, desclen, &channeldata, &channeldatalen, &sctx); if (i < 0) goto err; diff --git a/ccid/src/pace.c b/ccid/src/pace.c index 3e7ae06..3d74bdc 100644 --- a/ccid/src/pace.c +++ b/ccid/src/pace.c @@ -33,18 +33,31 @@ #define ASN1_APP_IMP_OPT(stname, field, type, tag) ASN1_EX_TYPE(ASN1_TFLG_IMPTAG|ASN1_TFLG_APPLICATION|ASN1_TFLG_OPTIONAL, tag, stname, field, type) +#define ASN1_APP_IMP(stname, field, type, tag) ASN1_EX_TYPE(ASN1_TFLG_IMPTAG|ASN1_TFLG_APPLICATION, tag, stname, field, type) /* * MSE:Set AT */ +/* XXX should be part of OpenPACE */ +typedef struct pace_chat_st { + ASN1_OBJECT *terminal_type; + ASN1_OCTET_STRING *relative_authorization; +} PACE_CHAT; +ASN1_SEQUENCE(PACE_CHAT) = { + ASN1_SIMPLE(PACE_CHAT, terminal_type, ASN1_OBJECT), + /* tag: 0x53*/ + ASN1_APP_IMP(PACE_CHAT, relative_authorization, ASN1_OCTET_STRING, 0x13) /* discretionary data */ +} ASN1_SEQUENCE_END(PACE_CHAT) +IMPLEMENT_ASN1_FUNCTIONS(PACE_CHAT) + typedef struct pace_mse_set_at_cd_st { ASN1_OBJECT *cryptographic_mechanism_reference; ASN1_INTEGER *key_reference1; ASN1_INTEGER *key_reference2; ASN1_OCTET_STRING *auxiliary_data; ASN1_OCTET_STRING *eph_pub_key; - ASN1_OCTET_STRING *cha_template; + PACE_CHAT *cha_template; } PACE_MSE_SET_AT_C; ASN1_SEQUENCE(PACE_MSE_SET_AT_C) = { /* 0x80 @@ -64,7 +77,7 @@ ASN1_SEQUENCE(PACE_MSE_SET_AT_C) = { ASN1_IMP_OPT(PACE_MSE_SET_AT_C, eph_pub_key, ASN1_OCTET_STRING, 0x11), /* 0x7F4C * Certificate Holder Authorization Template */ - ASN1_APP_IMP_OPT(PACE_MSE_SET_AT_C, cha_template, ASN1_OCTET_STRING, 0x4c), + ASN1_APP_IMP_OPT(PACE_MSE_SET_AT_C, cha_template, PACE_CHAT, 0x4c), } ASN1_SEQUENCE_END(PACE_MSE_SET_AT_C) IMPLEMENT_ASN1_FUNCTIONS(PACE_MSE_SET_AT_C) @@ -108,8 +121,8 @@ typedef struct pace_gen_auth_rapdu_body_st { ASN1_OCTET_STRING *mapping_data; ASN1_OCTET_STRING *eph_pub_key; ASN1_OCTET_STRING *auth_token; - ASN1_OCTET_STRING *cert_auth1; - ASN1_OCTET_STRING *cert_auth2; + ASN1_OCTET_STRING *cur_car; + ASN1_OCTET_STRING *prev_car; } PACE_GEN_AUTH_R_BODY; ASN1_SEQUENCE(PACE_GEN_AUTH_R_BODY) = { /* 0x80 @@ -125,11 +138,11 @@ ASN1_SEQUENCE(PACE_GEN_AUTH_R_BODY) = { * Authentication Token */ ASN1_IMP_OPT(PACE_GEN_AUTH_R_BODY, auth_token, ASN1_OCTET_STRING, 6), /* 0x87 - * Certification Authority Reference */ - ASN1_IMP_OPT(PACE_GEN_AUTH_R_BODY, cert_auth1, ASN1_OCTET_STRING, 7), + * Most recent Certification Authority Reference */ + ASN1_IMP_OPT(PACE_GEN_AUTH_R_BODY, cur_car, ASN1_OCTET_STRING, 7), /* 0x88 - * Certification Authority Reference */ - ASN1_IMP_OPT(PACE_GEN_AUTH_R_BODY, cert_auth2, ASN1_OCTET_STRING, 8), + * Previous Certification Authority Reference */ + ASN1_IMP_OPT(PACE_GEN_AUTH_R_BODY, prev_car, ASN1_OCTET_STRING, 8), } ASN1_SEQUENCE_END(PACE_GEN_AUTH_R_BODY) IMPLEMENT_ASN1_FUNCTIONS(PACE_GEN_AUTH_R_BODY) @@ -240,7 +253,8 @@ err: } static int pace_mse_set_at(const struct sm_ctx *oldpacectx, sc_card_t *card, - int protocol, int secret_key, int reference, u8 *sw1, u8 *sw2) + int protocol, int secret_key, const u8 *chat, + size_t length_chat, u8 *sw1, u8 *sw2) { sc_apdu_t apdu; unsigned char *d = NULL; @@ -259,34 +273,43 @@ static int pace_mse_set_at(const struct sm_ctx *oldpacectx, sc_card_t *card, apdu.cse = SC_APDU_CASE_3_SHORT; apdu.flags = SC_APDU_FLAGS_NO_GET_RESP|SC_APDU_FLAGS_NO_RETRY_WL; + data = PACE_MSE_SET_AT_C_new(); if (!data) { r = SC_ERROR_OUT_OF_MEMORY; goto err; } + data->cryptographic_mechanism_reference = OBJ_nid2obj(protocol); data->key_reference1 = ASN1_INTEGER_new(); - //data->key_reference2 = ASN1_INTEGER_new(); + if (!data->cryptographic_mechanism_reference - || !data->key_reference1 - //|| !data->key_reference2 - ) { + || !data->key_reference1) { r = SC_ERROR_OUT_OF_MEMORY; goto err; } - if (!ASN1_INTEGER_set(data->key_reference1, secret_key) - //|| !ASN1_INTEGER_set(data->key_reference2, reference) - ) { + + if (!ASN1_INTEGER_set(data->key_reference1, secret_key)) { r = SC_ERROR_INTERNAL; goto err; } + + if (length_chat) { + if (!d2i_PACE_CHAT(&data->cha_template, (const unsigned char **) &chat, + length_chat)) { + r = SC_ERROR_INTERNAL; + goto err; + } + } + + r = i2d_PACE_MSE_SET_AT_C(data, &d); if (r < 0) { r = SC_ERROR_INTERNAL; goto err; } /* The tag/length for the sequence (0x30) is omitted in the command apdu. */ - /* FIXME is there a OpenSSL way to get the value only or even a define for + /* XXX is there a OpenSSL way to get the value only or even a define for * the tag? */ apdu.data = sc_asn1_find_tag(card->ctx, d, r, 0x30, &apdu.datalen); apdu.lc = apdu.datalen; @@ -448,7 +471,9 @@ static int pace_gen_auth(const struct sm_ctx *oldpacectx, sc_card_t *card, if (!r_data->enc_nonce || r_data->mapping_data || r_data->eph_pub_key - || r_data->auth_token) { + || r_data->auth_token + || r_data->cur_car + || r_data->prev_car) { sc_error(card->ctx, "Response data of general authenticate for " "step %d should (only) contain the " "encrypted nonce.", step); @@ -462,7 +487,9 @@ static int pace_gen_auth(const struct sm_ctx *oldpacectx, sc_card_t *card, if (r_data->enc_nonce || !r_data->mapping_data || r_data->eph_pub_key - || r_data->auth_token) { + || r_data->auth_token + || r_data->cur_car + || r_data->prev_car) { sc_error(card->ctx, "Response data of general authenticate for " "step %d should (only) contain the " "mapping data.", step); @@ -476,7 +503,9 @@ static int pace_gen_auth(const struct sm_ctx *oldpacectx, sc_card_t *card, if (r_data->enc_nonce || r_data->mapping_data || !r_data->eph_pub_key - || r_data->auth_token) { + || r_data->auth_token + || r_data->cur_car + || r_data->prev_car) { sc_error(card->ctx, "Response data of general authenticate for " "step %d should (only) contain the " "ephemeral public key.", step); @@ -499,6 +528,13 @@ static int pace_gen_auth(const struct sm_ctx *oldpacectx, sc_card_t *card, } p = r_data->auth_token->data; l = r_data->auth_token->length; + /* XXX CAR sould be returned as result in some way */ + if (r_data->cur_car) + bin_log(card->ctx, "Most recent Certificate Authority Reference", + r_data->cur_car->data, r_data->cur_car->length); + if (r_data->prev_car) + bin_log(card->ctx, "Previous Certificate Authority Reference", + r_data->prev_car->data, r_data->prev_car->length); break; default: r = SC_ERROR_INVALID_ARGUMENTS; @@ -515,7 +551,7 @@ static int pace_gen_auth(const struct sm_ctx *oldpacectx, sc_card_t *card, err: if (c_data) { - /* FIXME + /* XXX if (c_data->mapping_data) ASN1_OCTET_STRING_free(c_data->mapping_data); if (c_data->eph_pub_key) @@ -527,7 +563,7 @@ err: if (d) free(d); if (r_data) { - /* FIXME + /* XXX if (r_data->mapping_data) ASN1_OCTET_STRING_free(r_data->mapping_data); if (r_data->eph_pub_key) @@ -667,6 +703,10 @@ int EstablishPACEChannel(const struct sm_ctx *oldpacectx, sc_card_t *card, in++; chat = in; in += length_chat; + /* XXX make this human readable */ + if (length_chat) + bin_log(card->ctx, "Card holder authorization template", + chat, length_chat); length_pin = *in; in++; @@ -677,6 +717,10 @@ int EstablishPACEChannel(const struct sm_ctx *oldpacectx, sc_card_t *card, length_cert_desc = __le16_to_cpu(word); in += sizeof word; certificate_description = in; + /* XXX make this human readable */ + if (length_cert_desc) + bin_log(card->ctx, "Certificate description", + certificate_description, length_cert_desc); if (!*out) { @@ -694,10 +738,6 @@ int EstablishPACEChannel(const struct sm_ctx *oldpacectx, sc_card_t *card, word = __cpu_to_le16(length_ef_cardaccess); memcpy(*out + 2, &word, sizeof word); memcpy(*out + 4, ef_cardaccess, length_ef_cardaccess); - /* XXX CAR */ - /*(*out)[length_ef_cardaccess + 2] = 0;*/ - /* XXX CARprev */ - /*(*out)[length_ef_cardaccess + 3] = 0;*/ } else { second_execution = 1; memcpy(&word, *out + 2, sizeof word); @@ -714,7 +754,7 @@ int EstablishPACEChannel(const struct sm_ctx *oldpacectx, sc_card_t *card, goto err; } - r = pace_mse_set_at(oldpacectx, card, info->protocol, pin_id, 1, *out, *out+1); + r = pace_mse_set_at(oldpacectx, card, info->protocol, pin_id, chat, length_chat, *out, *out+1); if (r < 0) { sc_error(card->ctx, "Could not select protocol proberties " "(MSE: Set AT).");