diff --git a/ccid/src/ccid.c b/ccid/src/ccid.c index 7fc6103..e2ce3f4 100644 --- a/ccid/src/ccid.c +++ b/ccid/src/ccid.c @@ -769,6 +769,205 @@ write_pin(sc_apdu_t *apdu, struct sc_pin_cmd_pin *pin, uint8_t blocksize, blocksize - justify_offset, pin, encoding, sc_result); } +static int +perform_PC_to_RDR_Secure_EstablishPACEChannel(sc_card_t *card, + const __u8 *abData, size_t abDatalen, + __u8 **abDataOut, size_t *abDataOutLen) +{ + struct establish_pace_channel_input pace_input; + struct establish_pace_channel_output pace_output; + size_t parsed = 0; + int sc_result; + __le16 word; + __u8 *p; + + if (!abDataOut || !abDataOutLen) + return SC_ERROR_INVALID_ARGUMENTS; + + memset(&pace_input, 0, sizeof(pace_input)); + memset(&pace_output, 0, sizeof(pace_output)); + + + if (abDatalen < parsed+1) { + sc_error(ctx, "Buffer too small, could not get PinID"); + return SC_ERROR_INVALID_ARGUMENTS; + } + pace_input.pin_id = abData[parsed]; + parsed++; + + + if (abDatalen < parsed+1) { + sc_error(ctx, "Buffer too small, could not get lengthCHAT"); + return SC_ERROR_INVALID_ARGUMENTS; + } + pace_input.chat_length = abData[parsed]; + parsed++; + + if (abDatalen < parsed+pace_input.chat_length) { + sc_error(ctx, "Buffer too small, could not get CHAT"); + return SC_ERROR_INVALID_ARGUMENTS; + } + pace_input.chat = &abData[parsed]; + parsed += pace_input.chat_length; + /* XXX make this human readable */ + if (pace_input.chat_length) + bin_log(ctx, "Card holder authorization template", + pace_input.chat, pace_input.chat_length); + + + if (abDatalen < parsed+1) { + sc_error(ctx, "Buffer too small, could not get lengthPIN"); + return SC_ERROR_INVALID_ARGUMENTS; + } + pace_input.pin_length = abData[parsed]; + parsed++; + + if (abDatalen < parsed+pace_input.pin_length) { + sc_error(ctx, "Buffer too small, could not get PIN"); + return SC_ERROR_INVALID_ARGUMENTS; + } + pace_input.pin = &abData[parsed]; + parsed += pace_input.pin_length; + + + if (abDatalen < parsed+sizeof(word)) { + sc_error(ctx, "Buffer too small, could not get lengthCertificateDescription"); + return SC_ERROR_INVALID_ARGUMENTS; + } + memcpy(&word, &abData[parsed], sizeof word); + pace_input.certificate_description_length = __le16_to_cpu(word); + parsed += sizeof word; + + if (abDatalen < parsed+pace_input.certificate_description_length) { + sc_error(ctx, "Buffer too small, could not get CertificateDescription"); + return SC_ERROR_INVALID_ARGUMENTS; + } + pace_input.certificate_description = &abData[parsed]; + parsed += pace_input.certificate_description_length; + /* XXX make this human readable */ + if (pace_input.certificate_description_length) + bin_log(ctx, "Certificate description", + pace_input.certificate_description, + pace_input.certificate_description_length); + + + /*if (sc_reset(card) < 0)*/ + /*sc_error(ctx, "Could not reset card, will continue anyway");*/ + + sc_result = EstablishPACEChannel(NULL, card, pace_input, &pace_output, + &sctx); + if (sc_result < 0) + return sc_result; + + + p = realloc(*abDataOut, 2 + /* Statusbytes */ + 2+pace_output.ef_cardaccess_length + /* EF.CardAccess */ + 1+pace_output.recent_car_length + /* Most recent CAR */ + 1+pace_output.previous_car_length + /* Previous CAR */ + 2+pace_output.id_icc_length); /* XXX */ + if (!p) + return SC_ERROR_OUT_OF_MEMORY; + *abDataOut = p; + + + *p = pace_output.mse_set_at_sw1; + p += 1; + + *p = pace_output.mse_set_at_sw2; + p += 1; + + + if (pace_output.ef_cardaccess_length > 0xffff) { + sc_error(ctx, "EF.CardAcces %u bytes too long", + pace_output.ef_cardaccess_length-0xffff); + return SC_ERROR_INVALID_DATA; + } + word = __cpu_to_le16(pace_output.ef_cardaccess_length); + memcpy(p, &word, sizeof word); + p += sizeof word; + + memcpy(p, pace_output.ef_cardaccess, + pace_output.ef_cardaccess_length); + p += pace_output.ef_cardaccess_length; + + + if (pace_output.recent_car_length > 0xff) { + sc_error(ctx, "Most recent CAR %u bytes too long", + pace_output.recent_car_length-0xff); + return SC_ERROR_INVALID_DATA; + } + *p = pace_output.recent_car_length; + p += 1; + + memcpy(p, pace_output.recent_car, + pace_output.recent_car_length); + p += pace_output.recent_car_length; + + + if (pace_output.previous_car_length > 0xff) { + sc_error(ctx, "Most previous CAR %u bytes too long", + pace_output.previous_car_length-0xff); + return SC_ERROR_INVALID_DATA; + } + *p = pace_output.previous_car_length; + p += 1; + + memcpy(p, pace_output.previous_car, + pace_output.previous_car_length); + p += pace_output.previous_car_length; + + + if (pace_output.id_icc_length > 0xffff) { + sc_error(ctx, "ID ICC %u bytes too long", + pace_output.id_icc_length-0xffff); + return SC_ERROR_INVALID_DATA; + } + word = __cpu_to_le16(pace_output.id_icc_length); + memcpy(p, &word, sizeof word); + p += sizeof word; + + memcpy(p, pace_output.id_icc, + pace_output.id_icc_length); + p += pace_output.id_icc_length; + + + *abDataOutLen = 2 + + 2+pace_output.ef_cardaccess_length + + 1+pace_output.recent_car_length + + 1+pace_output.previous_car_length + + 2+pace_output.id_icc_length; + + return SC_SUCCESS; +} + +static int +perform_PC_to_RDR_Secure_GetReadersPACECapabilities(__u8 **abDataOut, + size_t *abDataOutLen) +{ + int sc_result; + __u8 *result; + + if (!abDataOut || !abDataOutLen) + return SC_ERROR_INVALID_ARGUMENTS; + + result = realloc(*abDataOut, 2); + if (!result) + return SC_ERROR_OUT_OF_MEMORY; + *abDataOut = result; + + /* lengthBitMap */ + *result = 1; + result++; + + sc_result = GetReadersPACECapabilities(result); + if (sc_result < 0) + return sc_result; + + *abDataOutLen = 2; + + return SC_SUCCESS; +} + static int perform_PC_to_RDR_Secure(const __u8 *in, size_t inlen, __u8** out, size_t *outlen) { @@ -779,10 +978,7 @@ perform_PC_to_RDR_Secure(const __u8 *in, size_t inlen, __u8** out, size_t *outle const __u8* abData = in + sizeof *request; size_t abDatalen = inlen - sizeof *request; u8 *abDataOut = NULL; - size_t resplen = 0, parsed; - __le16 word; - struct establish_pace_channel_input pace_input; - struct establish_pace_channel_output pace_output; + size_t resplen = 0; RDR_to_PC_DataBlock_t *result; if (!in || !out || !outlen) @@ -796,8 +992,6 @@ perform_PC_to_RDR_Secure(const __u8 *in, size_t inlen, __u8** out, size_t *outle memset(&curr_pin, 0, sizeof(curr_pin)); memset(&new_pin, 0, sizeof(new_pin)); - memset(&pace_input, 0, sizeof(pace_input)); - memset(&pace_output, 0, sizeof(pace_output)); if (request->bSlot > sizeof *card_in_slot) { sc_error(ctx, "Received request to invalid slot (bSlot=0x%02x)", request->bSlot); @@ -858,82 +1052,15 @@ perform_PC_to_RDR_Secure(const __u8 *in, size_t inlen, __u8** out, size_t *outle #ifdef WITH_PACE case 0x10: - if (abDatalen < 1) { - sc_error(ctx, "Not enough data for input of GetReadersPACECapabilities"); - sc_result = SC_ERROR_INVALID_DATA; - goto err; - } - - sc_result = - GetReadersPACECapabilities(card_in_slot[request->bSlot], - abData + 1, abDatalen-1, &abDataOut, &resplen); + sc_result = perform_PC_to_RDR_Secure_GetReadersPACECapabilities( + &abDataOut, &resplen); goto err; break; case 0x20: - parsed = 1; - if (abDatalen < parsed+1) { - sc_error(ctx, "Buffer too small, could not get PinID"); - goto err; - } - pace_input.pin_id = abData[parsed]; - parsed++; - - if (abDatalen < parsed+1) { - sc_error(ctx, "Buffer too small, could not get lengthCHAT"); - goto err; - } - pace_input.chat_length = abData[parsed]; - parsed++; - - if (abDatalen < parsed+pace_input.chat_length) { - sc_error(ctx, "Buffer too small, could not get CHAT"); - goto err; - } - pace_input.chat = &abData[parsed]; - parsed += pace_input.chat_length; - /* XXX make this human readable */ - if (pace_input.chat_length) - bin_log(ctx, "Card holder authorization template", - pace_input.chat, pace_input.chat_length); - - if (abDatalen < parsed+1) { - sc_error(ctx, "Buffer too small, could not get lengthPIN"); - goto err; - } - pace_input.pin_length = abData[parsed]; - parsed++; - - if (abDatalen < parsed+pace_input.pin_length) { - sc_error(ctx, "Buffer too small, could not get PIN"); - goto err; - } - pace_input.pin = &abData[parsed]; - parsed += pace_input.pin_length; - - if (abDatalen < parsed+sizeof(word)) { - sc_error(ctx, "Buffer too small, could not get lengthCertificateDescription"); - goto err; - } - memcpy(&word, &abData[parsed], sizeof word); - pace_input.certificate_description_length = __le16_to_cpu(word); - parsed += sizeof word; - - if (abDatalen < parsed+pace_input.certificate_description_length) { - sc_error(ctx, "Buffer too small, could not get CertificateDescription"); - goto err; - } - pace_input.certificate_description = &abData[parsed]; - parsed+= pace_input.certificate_description_length; - /* XXX make this human readable */ - if (pace_input.certificate_description_length) - bin_log(ctx, "Certificate description", - pace_input.certificate_description, - pace_input.certificate_description_length); - - sc_result = EstablishPACEChannel(NULL, - card_in_slot[request->bSlot], pace_input, - &abDataOut, &resplen, &sctx); + sc_result = perform_PC_to_RDR_Secure_EstablishPACEChannel( + card_in_slot[request->bSlot], abData+1, abDatalen-1, + &abDataOut, &resplen); goto err; break; #endif @@ -1079,7 +1206,7 @@ err: } else { *outlen = sizeof *result; debug_sc_result(sc_result); - sc_error(ctx, "Could not get memory for response apdu." + sc_error(ctx, "Some error occurred." " Returning package without payload."); } result->bError = get_bError(sc_result); diff --git a/ccid/src/pace-tool.c b/ccid/src/pace-tool.c index df22ff3..9b96015 100644 --- a/ccid/src/pace-tool.c +++ b/ccid/src/pace-tool.c @@ -166,17 +166,17 @@ int main (int argc, char **argv) { int i, oindex = 0; - __u8 *channeldata = NULL; size_t channeldatalen; struct sm_ctx sctx, tmpctx; struct establish_pace_channel_input pace_input; + struct establish_pace_channel_output pace_output; time_t t_start, t_end; - u8 *out = NULL; size_t outlen; memset(&sctx, 0, sizeof(sctx)); memset(&tmpctx, 0, sizeof(tmpctx)); memset(&pace_input, 0, sizeof(pace_input)); + memset(&pace_output, 0, sizeof(pace_output)); while (1) { i = getopt_long(argc, argv, "hr:i::u::a::z::C:D:N::RUtvoc:", options, &oindex); @@ -311,7 +311,7 @@ main (int argc, char **argv) pace_input.pin_length = 0; } t_start = time(NULL); - i = EstablishPACEChannel(NULL, card, pace_input, &out, &outlen, + i = EstablishPACEChannel(NULL, card, pace_input, &pace_output, &tmpctx); t_end = time(NULL); if (i < 0) @@ -328,7 +328,7 @@ main (int argc, char **argv) pace_input.pin_length = 0; } t_start = time(NULL); - i = EstablishPACEChannel(&tmpctx, card, pace_input, &out, &outlen, + i = EstablishPACEChannel(&tmpctx, card, pace_input, &pace_output, &sctx); t_end = time(NULL); if (i < 0) @@ -347,7 +347,7 @@ main (int argc, char **argv) pace_input.pin_length = 0; } t_start = time(NULL); - i = EstablishPACEChannel(NULL, card, pace_input, &out, &outlen, + i = EstablishPACEChannel(NULL, card, pace_input, &pace_output, &sctx); t_end = time(NULL); if (i < 0) @@ -371,7 +371,7 @@ main (int argc, char **argv) pace_input.pin_length = 0; } t_start = time(NULL); - i = EstablishPACEChannel(NULL, card, pace_input, &out, &outlen, + i = EstablishPACEChannel(NULL, card, pace_input, &pace_output, &sctx); t_end = time(NULL); if (i < 0) @@ -419,7 +419,7 @@ main (int argc, char **argv) } t_start = time(NULL); - i = EstablishPACEChannel(NULL, card, pace_input, &out, &outlen, + i = EstablishPACEChannel(NULL, card, pace_input, &pace_output, &sctx); t_end = time(NULL); if (i < 0) @@ -435,8 +435,6 @@ main (int argc, char **argv) } err: - if (channeldata) - free(channeldata); sc_disconnect_card(card, 0); sc_release_context(ctx); diff --git a/ccid/src/pace.c b/ccid/src/pace.c index 1a237a5..a6999c0 100644 --- a/ccid/src/pace.c +++ b/ccid/src/pace.c @@ -19,7 +19,6 @@ #include "pace.h" #include "sm.h" #include "scutil.h" -#include #include #include #include @@ -160,29 +159,20 @@ IMPLEMENT_ASN1_FUNCTIONS(PACE_GEN_AUTH_R) const size_t maxresp = SC_MAX_APDU_BUFFER_SIZE - 2; -int GetReadersPACECapabilities(sc_card_t *card, - const __u8 *in, size_t inlen, __u8 **out, size_t *outlen) { - if (!out || !outlen) +int GetReadersPACECapabilities(u8 *bitmap) +{ + if (!bitmap) return SC_ERROR_INVALID_ARGUMENTS; - __u8 *result = realloc(*out, 2); - if (!result) - return SC_ERROR_OUT_OF_MEMORY; - *out = result; - *outlen = 2; - - /* lengthBitMap */ - *result = 1; - result++; /* BitMap */ - *result = PACE_BITMAP_PACE|PACE_BITMAP_EID; + *bitmap = PACE_BITMAP_PACE|PACE_BITMAP_EID; return SC_SUCCESS; } /** select and read EF.CardAccess */ static int get_ef_card_access(sc_card_t *card, - __u8 **ef_cardaccess, size_t *length_ef_cardaccess) + u8 **ef_cardaccess, size_t *length_ef_cardaccess) { int r; /* we read less bytes than possible. this is a workaround for acr 122, @@ -190,7 +180,7 @@ static int get_ef_card_access(sc_card_t *card, size_t read = maxresp - 8; sc_path_t path; sc_file_t *file = NULL; - __u8 *p; + u8 *p; memset(&path, 0, sizeof path); r = sc_append_file_id(&path, FID_EF_CARDACCESS); @@ -959,10 +949,10 @@ void ssl_error(sc_context_t *ctx) { int EstablishPACEChannel(const struct sm_ctx *oldpacectx, sc_card_t *card, struct establish_pace_channel_input pace_input, - __u8 **out, size_t *outlen, struct sm_ctx *sctx) + struct establish_pace_channel_output *pace_output, + struct sm_ctx *sctx) { - size_t length_ef_cardaccess, recent_car_len, prev_car_len; - __u8 *ef_cardaccess = NULL, *p = NULL, *recent_car = NULL, *prev_car = NULL; + u8 *p = NULL; PACEInfo *info = NULL; PACEDomainParameterInfo *static_dp = NULL, *eph_dp = NULL; BUF_MEM *enc_nonce = NULL, *nonce = NULL, *mdata = NULL, *mdata_opp = NULL, @@ -971,42 +961,25 @@ int EstablishPACEChannel(const struct sm_ctx *oldpacectx, sc_card_t *card, PACE_SEC *sec = NULL; PACE_CTX *pctx = NULL; int r; - __le16 word; if (!card) return SC_ERROR_CARD_NOT_PRESENT; - if (!out || !outlen) + if (!pace_output || !sctx) return SC_ERROR_INVALID_ARGUMENTS; - if (!oldpacectx) { - /* PACE is executed the first time */ - r = get_ef_card_access(card, &ef_cardaccess, &length_ef_cardaccess); + if (!pace_output->ef_cardaccess_length || !pace_output->ef_cardaccess) { + r = get_ef_card_access(card, &pace_output->ef_cardaccess, + &pace_output->ef_cardaccess_length); if (r < 0) { sc_error(card->ctx, "Could not get EF.CardAccess."); goto err; } - /* get enough memory for status bytes and EF.CardAccess */ - p = realloc(*out, 6 + length_ef_cardaccess); - if (!p) { - r = SC_ERROR_OUT_OF_MEMORY; - goto err; - } - *out = p; - word = __cpu_to_le16(length_ef_cardaccess); - memcpy((*out) + 2, &word, sizeof word); - memcpy((*out) + 4, ef_cardaccess, length_ef_cardaccess); - } else { - /* PACE is executed the second time. EF.CardAccess should already be - * present */ - memcpy(&word, (*out) + 2, sizeof word); - length_ef_cardaccess = __le16_to_cpu(word); - ef_cardaccess = (*out) + 4; } - *outlen = 4+length_ef_cardaccess; - bin_log(card->ctx, "EF.CardAccess", ef_cardaccess, length_ef_cardaccess); + bin_log(card->ctx, "EF.CardAccess", pace_output->ef_cardaccess, + pace_output->ef_cardaccess_length); - if (!parse_ef_card_access(ef_cardaccess, length_ef_cardaccess, - &info, &static_dp)) { + if (!parse_ef_card_access(pace_output->ef_cardaccess, + pace_output->ef_cardaccess_length, &info, &static_dp)) { sc_error(card->ctx, "Could not parse EF.CardAccess."); ssl_error(card->ctx); r = SC_ERROR_INTERNAL; @@ -1014,7 +987,8 @@ int EstablishPACEChannel(const struct sm_ctx *oldpacectx, sc_card_t *card, } r = pace_mse_set_at(oldpacectx, card, info->protocol, pace_input.pin_id, - pace_input.chat, pace_input.chat_length, *out, (*out)+1); + pace_input.chat, pace_input.chat_length, + &pace_output->mse_set_at_sw1, &pace_output->mse_set_at_sw2); if (r < 0) { sc_error(card->ctx, "Could not select protocol proberties " "(MSE: Set AT)."); @@ -1112,23 +1086,9 @@ int EstablishPACEChannel(const struct sm_ctx *oldpacectx, sc_card_t *card, goto err; } r = pace_gen_auth_4_mutual_authentication(oldpacectx, card, (u8 *) token->data, token->length, - (u8 **) &token_opp->data, &token_opp->length, &recent_car, &recent_car_len, - &prev_car, &prev_car_len); - - /* get enough memory for CARs */ - p = realloc(*out, (*outlen) + 1 + recent_car_len + 1 + prev_car_len); - if (!p) { - r = SC_ERROR_OUT_OF_MEMORY; - goto err; - } - *out = p; - (*out)[*outlen] = recent_car_len; - memcpy((*out) + (*outlen) + 1, - recent_car, recent_car_len); - (*out)[(*outlen) + 1 + recent_car_len] = prev_car_len; - memcpy((*out) + (*outlen) + 1 + recent_car_len + 1, - prev_car, prev_car_len); - *outlen += 1 + recent_car_len + 1 + prev_car_len; + (u8 **) &token_opp->data, &token_opp->length, + &pace_output->recent_car, &pace_output->recent_car_length, + &pace_output->previous_car, &pace_output->previous_car_length); if (r < 0) { sc_error(card->ctx, "Could not exchange authentication token with card " @@ -1145,15 +1105,7 @@ int EstablishPACEChannel(const struct sm_ctx *oldpacectx, sc_card_t *card, goto err; } - /* get enough memory for IDicc */ - p = realloc(*out, (*outlen) + 2); - if (!p) { - r = SC_ERROR_OUT_OF_MEMORY; - goto err; - } - *out = p; - memset((*out) + (*outlen), 0, 2); - *outlen += 2; + /* XXX IDicc */ /* XXX parse CHAT to check role of terminal */ @@ -1178,8 +1130,6 @@ int EstablishPACEChannel(const struct sm_ctx *oldpacectx, sc_card_t *card, sctx->active = 1; err: - if (ef_cardaccess && !oldpacectx) - free(ef_cardaccess); if (info) PACEInfo_free(info); if (static_dp) diff --git a/ccid/src/pace.h b/ccid/src/pace.h index 1a72589..a3a43f1 100644 --- a/ccid/src/pace.h +++ b/ccid/src/pace.h @@ -21,7 +21,6 @@ #include "pace_lib.h" #include "sm.h" -#include #include #include #include @@ -97,11 +96,12 @@ struct establish_pace_channel_output { unsigned char *id_icc; }; -int GetReadersPACECapabilities(sc_card_t *card, const unsigned char *in, - size_t inlen, unsigned char **out, size_t *outlen); +int GetReadersPACECapabilities(u8 *bitmap); + int EstablishPACEChannel(const struct sm_ctx *oldpacectx, sc_card_t *card, struct establish_pace_channel_input pace_input, - unsigned char **out, size_t *outlen, struct sm_ctx *sctx); + struct establish_pace_channel_output *pace_output, + struct sm_ctx *sctx); int pace_reset_retry_counter(struct sm_ctx *ctx, sc_card_t *card, enum s_type pin_id, int ask_for_secret,