From 85e1c317b6fb612cd71a29d60d8290098c75885a Mon Sep 17 00:00:00 2001 From: Frank Morgner Date: Wed, 19 Sep 2012 00:59:44 +0200 Subject: [PATCH] libnpa: Implementation of CA --- npa/src/npa.c | 502 +++++++++++++++++++++++++++++++++++----------- npa/src/npa/npa.h | 7 + 2 files changed, 394 insertions(+), 115 deletions(-) diff --git a/npa/src/npa.c b/npa/src/npa.c index 80da19e..423dc91 100644 --- a/npa/src/npa.c +++ b/npa/src/npa.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -77,82 +78,137 @@ IMPLEMENT_ASN1_FUNCTIONS(NPA_MSE_C) /* - * General Authenticate + * General Authenticate for PACE */ /* Protocol Command Data */ -typedef struct npa_gen_auth_cd_st { +typedef struct npa_gen_auth_pace_cd_st { ASN1_OCTET_STRING *mapping_data; ASN1_OCTET_STRING *eph_pub_key; ASN1_OCTET_STRING *auth_token; -} NPA_GEN_AUTH_C_BODY; -ASN1_SEQUENCE(NPA_GEN_AUTH_C_BODY) = { +} NPA_GEN_AUTH_PACE_C_BODY; +ASN1_SEQUENCE(NPA_GEN_AUTH_PACE_C_BODY) = { /* 0x81 * Mapping Data */ - ASN1_IMP_OPT(NPA_GEN_AUTH_C_BODY, mapping_data, ASN1_OCTET_STRING, 1), + ASN1_IMP_OPT(NPA_GEN_AUTH_PACE_C_BODY, mapping_data, ASN1_OCTET_STRING, 1), /* 0x83 * Ephemeral Public Key */ - ASN1_IMP_OPT(NPA_GEN_AUTH_C_BODY, eph_pub_key, ASN1_OCTET_STRING, 3), + ASN1_IMP_OPT(NPA_GEN_AUTH_PACE_C_BODY, eph_pub_key, ASN1_OCTET_STRING, 3), /* 0x85 * Authentication Token */ - ASN1_IMP_OPT(NPA_GEN_AUTH_C_BODY, auth_token, ASN1_OCTET_STRING, 5), -} ASN1_SEQUENCE_END(NPA_GEN_AUTH_C_BODY) -DECLARE_ASN1_FUNCTIONS(NPA_GEN_AUTH_C_BODY) -IMPLEMENT_ASN1_FUNCTIONS(NPA_GEN_AUTH_C_BODY) + ASN1_IMP_OPT(NPA_GEN_AUTH_PACE_C_BODY, auth_token, ASN1_OCTET_STRING, 5), +} ASN1_SEQUENCE_END(NPA_GEN_AUTH_PACE_C_BODY) +DECLARE_ASN1_FUNCTIONS(NPA_GEN_AUTH_PACE_C_BODY) +IMPLEMENT_ASN1_FUNCTIONS(NPA_GEN_AUTH_PACE_C_BODY) -typedef NPA_GEN_AUTH_C_BODY NPA_GEN_AUTH_C; +typedef NPA_GEN_AUTH_PACE_C_BODY NPA_GEN_AUTH_PACE_C; /* 0x7C * Dynamic Authentication Data */ -ASN1_ITEM_TEMPLATE(NPA_GEN_AUTH_C) = +ASN1_ITEM_TEMPLATE(NPA_GEN_AUTH_PACE_C) = ASN1_EX_TEMPLATE_TYPE( ASN1_TFLG_IMPTAG|ASN1_TFLG_APPLICATION, - 0x1c, NPA_GEN_AUTH_C, NPA_GEN_AUTH_C_BODY) -ASN1_ITEM_TEMPLATE_END(NPA_GEN_AUTH_C) -DECLARE_ASN1_FUNCTIONS(NPA_GEN_AUTH_C) -IMPLEMENT_ASN1_FUNCTIONS(NPA_GEN_AUTH_C) + 0x1c, NPA_GEN_AUTH_PACE_C, NPA_GEN_AUTH_PACE_C_BODY) +ASN1_ITEM_TEMPLATE_END(NPA_GEN_AUTH_PACE_C) +DECLARE_ASN1_FUNCTIONS(NPA_GEN_AUTH_PACE_C) +IMPLEMENT_ASN1_FUNCTIONS(NPA_GEN_AUTH_PACE_C) /* Protocol Response Data */ -typedef struct npa_gen_auth_rapdu_body_st { +typedef struct npa_gen_auth_pace_rapdu_body_st { ASN1_OCTET_STRING *enc_nonce; ASN1_OCTET_STRING *mapping_data; ASN1_OCTET_STRING *eph_pub_key; ASN1_OCTET_STRING *auth_token; ASN1_OCTET_STRING *cur_car; ASN1_OCTET_STRING *prev_car; -} NPA_GEN_AUTH_R_BODY; -ASN1_SEQUENCE(NPA_GEN_AUTH_R_BODY) = { +} NPA_GEN_AUTH_PACE_R_BODY; +ASN1_SEQUENCE(NPA_GEN_AUTH_PACE_R_BODY) = { /* 0x80 * Encrypted Nonce */ - ASN1_IMP_OPT(NPA_GEN_AUTH_R_BODY, enc_nonce, ASN1_OCTET_STRING, 0), + ASN1_IMP_OPT(NPA_GEN_AUTH_PACE_R_BODY, enc_nonce, ASN1_OCTET_STRING, 0), /* 0x82 * Mapping Data */ - ASN1_IMP_OPT(NPA_GEN_AUTH_R_BODY, mapping_data, ASN1_OCTET_STRING, 2), + ASN1_IMP_OPT(NPA_GEN_AUTH_PACE_R_BODY, mapping_data, ASN1_OCTET_STRING, 2), /* 0x84 * Ephemeral Public Key */ - ASN1_IMP_OPT(NPA_GEN_AUTH_R_BODY, eph_pub_key, ASN1_OCTET_STRING, 4), + ASN1_IMP_OPT(NPA_GEN_AUTH_PACE_R_BODY, eph_pub_key, ASN1_OCTET_STRING, 4), /* 0x86 * Authentication Token */ - ASN1_IMP_OPT(NPA_GEN_AUTH_R_BODY, auth_token, ASN1_OCTET_STRING, 6), + ASN1_IMP_OPT(NPA_GEN_AUTH_PACE_R_BODY, auth_token, ASN1_OCTET_STRING, 6), /* 0x87 * Most recent Certification Authority Reference */ - ASN1_IMP_OPT(NPA_GEN_AUTH_R_BODY, cur_car, ASN1_OCTET_STRING, 7), + ASN1_IMP_OPT(NPA_GEN_AUTH_PACE_R_BODY, cur_car, ASN1_OCTET_STRING, 7), /* 0x88 * Previous Certification Authority Reference */ - ASN1_IMP_OPT(NPA_GEN_AUTH_R_BODY, prev_car, ASN1_OCTET_STRING, 8), -} ASN1_SEQUENCE_END(NPA_GEN_AUTH_R_BODY) -DECLARE_ASN1_FUNCTIONS(NPA_GEN_AUTH_R_BODY) -IMPLEMENT_ASN1_FUNCTIONS(NPA_GEN_AUTH_R_BODY) + ASN1_IMP_OPT(NPA_GEN_AUTH_PACE_R_BODY, prev_car, ASN1_OCTET_STRING, 8), +} ASN1_SEQUENCE_END(NPA_GEN_AUTH_PACE_R_BODY) +DECLARE_ASN1_FUNCTIONS(NPA_GEN_AUTH_PACE_R_BODY) +IMPLEMENT_ASN1_FUNCTIONS(NPA_GEN_AUTH_PACE_R_BODY) -typedef NPA_GEN_AUTH_R_BODY NPA_GEN_AUTH_R; +typedef NPA_GEN_AUTH_PACE_R_BODY NPA_GEN_AUTH_PACE_R; /* 0x7C * Dynamic Authentication Data */ -ASN1_ITEM_TEMPLATE(NPA_GEN_AUTH_R) = +ASN1_ITEM_TEMPLATE(NPA_GEN_AUTH_PACE_R) = ASN1_EX_TEMPLATE_TYPE( ASN1_TFLG_IMPTAG|ASN1_TFLG_APPLICATION, - 0x1c, NPA_GEN_AUTH_R, NPA_GEN_AUTH_R_BODY) -ASN1_ITEM_TEMPLATE_END(NPA_GEN_AUTH_R) -DECLARE_ASN1_FUNCTIONS(NPA_GEN_AUTH_R) -IMPLEMENT_ASN1_FUNCTIONS(NPA_GEN_AUTH_R) + 0x1c, NPA_GEN_AUTH_PACE_R, NPA_GEN_AUTH_PACE_R_BODY) +ASN1_ITEM_TEMPLATE_END(NPA_GEN_AUTH_PACE_R) +DECLARE_ASN1_FUNCTIONS(NPA_GEN_AUTH_PACE_R) +IMPLEMENT_ASN1_FUNCTIONS(NPA_GEN_AUTH_PACE_R) + + +/* + * General Authenticate for CA + */ + +/* Protocol Command Data */ +typedef struct npa_gen_auth_ca_cd_st { + ASN1_OCTET_STRING *eph_pub_key; +} NPA_GEN_AUTH_CA_C_BODY; +ASN1_SEQUENCE(NPA_GEN_AUTH_CA_C_BODY) = { + /* 0x80 + * Ephemeral Public Key */ + ASN1_IMP_OPT(NPA_GEN_AUTH_CA_C_BODY, eph_pub_key, ASN1_OCTET_STRING, 0), +} ASN1_SEQUENCE_END(NPA_GEN_AUTH_CA_C_BODY) +DECLARE_ASN1_FUNCTIONS(NPA_GEN_AUTH_CA_C_BODY) +IMPLEMENT_ASN1_FUNCTIONS(NPA_GEN_AUTH_CA_C_BODY) + +typedef NPA_GEN_AUTH_CA_C_BODY NPA_GEN_AUTH_CA_C; +/* 0x7C + * Dynamic Authentication Data */ +ASN1_ITEM_TEMPLATE(NPA_GEN_AUTH_CA_C) = + ASN1_EX_TEMPLATE_TYPE( + ASN1_TFLG_IMPTAG|ASN1_TFLG_APPLICATION, + 0x1c, NPA_GEN_AUTH_CA_C, NPA_GEN_AUTH_CA_C_BODY) +ASN1_ITEM_TEMPLATE_END(NPA_GEN_AUTH_CA_C) +DECLARE_ASN1_FUNCTIONS(NPA_GEN_AUTH_CA_C) +IMPLEMENT_ASN1_FUNCTIONS(NPA_GEN_AUTH_CA_C) + +/* Protocol Response Data */ +typedef struct npa_gen_auth_ca_rapdu_body_st { + ASN1_OCTET_STRING *nonce; + ASN1_OCTET_STRING *auth_token; +} NPA_GEN_AUTH_CA_R_BODY; +ASN1_SEQUENCE(NPA_GEN_AUTH_CA_R_BODY) = { + /* 0x81 + * Nonce */ + ASN1_IMP_OPT(NPA_GEN_AUTH_CA_R_BODY, nonce, ASN1_OCTET_STRING, 1), + /* 0x82 + * Authentication Token */ + ASN1_IMP_OPT(NPA_GEN_AUTH_CA_R_BODY, auth_token, ASN1_OCTET_STRING, 2), +} ASN1_SEQUENCE_END(NPA_GEN_AUTH_CA_R_BODY) +DECLARE_ASN1_FUNCTIONS(NPA_GEN_AUTH_CA_R_BODY) +IMPLEMENT_ASN1_FUNCTIONS(NPA_GEN_AUTH_CA_R_BODY) + +typedef NPA_GEN_AUTH_CA_R_BODY NPA_GEN_AUTH_CA_R; +/* 0x7C + * Dynamic Authentication Data */ +ASN1_ITEM_TEMPLATE(NPA_GEN_AUTH_CA_R) = + ASN1_EX_TEMPLATE_TYPE( + ASN1_TFLG_IMPTAG|ASN1_TFLG_APPLICATION, + 0x1c, NPA_GEN_AUTH_CA_R, NPA_GEN_AUTH_CA_R_BODY) +ASN1_ITEM_TEMPLATE_END(NPA_GEN_AUTH_CA_R) +DECLARE_ASN1_FUNCTIONS(NPA_GEN_AUTH_CA_R) +IMPLEMENT_ASN1_FUNCTIONS(NPA_GEN_AUTH_CA_R) @@ -261,11 +317,11 @@ int GetReadersPACECapabilities(u8 *bitmap) #define ISO_READ_BINARY 0xB0 #define ISO_P1_FLAG_SFID 0x80 -/** Read EF.CardAccess. +/** Read an EF. * @note MF must be selected before calling this function. * */ -int get_ef_card_access(sc_card_t *card, - u8 **ef_cardaccess, size_t *length_ef_cardaccess) +static int get_ef(struct sm_ctx *npactx, sc_card_t *card, unsigned char sfid, + u8 **ef, size_t *ef_len) { int r; /* we read less bytes than possible. this is a workaround for acr 122, @@ -276,57 +332,78 @@ int get_ef_card_access(sc_card_t *card, sc_file_t *file = NULL; u8 *p; - if (!card || !ef_cardaccess || !length_ef_cardaccess) { + if (!card || !ef || !ef_len) { r = SC_ERROR_INVALID_ARGUMENTS; goto err; } - *length_ef_cardaccess = 0; + *ef_len = 0; - sc_format_apdu(card, &apdu, SC_APDU_CASE_2_EXT, - ISO_READ_BINARY, ISO_P1_FLAG_SFID|SFID_EF_CARDACCESS, 0); + if (read > SC_MAX_APDU_BUFFER_SIZE - 2) + sc_format_apdu(card, &apdu, SC_APDU_CASE_2_EXT, + ISO_READ_BINARY, ISO_P1_FLAG_SFID|sfid, 0); + else + sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, + ISO_READ_BINARY, ISO_P1_FLAG_SFID|sfid, 0); - p = realloc(*ef_cardaccess, read); + p = realloc(*ef, read); if (!p) { r = SC_ERROR_OUT_OF_MEMORY; goto err; } - *ef_cardaccess = p; - apdu.resp = *ef_cardaccess; + *ef = p; + apdu.resp = *ef; apdu.resplen = read; apdu.le = read; - r = sc_transmit_apdu(card, &apdu); + if (!npactx) + r = sc_transmit_apdu(card, &apdu); + else + r = sm_transmit_apdu(npactx, card, &apdu); /* emulate the behaviour of sc_read_binary */ if (r >= 0) r = apdu.resplen; while(1) { if (r >= 0 && r != read) { - *length_ef_cardaccess += r; + *ef_len += r; break; } if (r < 0) { - sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not read EF.CardAccess."); + sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not read EF."); goto err; } - *length_ef_cardaccess += r; + *ef_len += r; - p = realloc(*ef_cardaccess, *length_ef_cardaccess + read); + p = realloc(*ef, *ef_len + read); if (!p) { r = SC_ERROR_OUT_OF_MEMORY; goto err; } - *ef_cardaccess = p; + *ef = p; - r = sc_read_binary(card, *length_ef_cardaccess, - *ef_cardaccess + *length_ef_cardaccess, read, 0); + if (!npactx) + r = sc_read_binary(card, *ef_len, + *ef + *ef_len, read, 0); + else { + if (*ef_len > 0x7fff) { + r = SC_ERROR_OFFSET_TOO_LARGE; + goto err; + } + apdu.p1 = (*ef_len >> 8) & 0x7F; + apdu.p2 = *ef_len & 0xFF; + apdu.resp = *ef + *ef_len; + r = sm_transmit_apdu(npactx, card, &apdu); + /* emulate the behaviour of sc_read_binary */ + if (r >= 0) + r = apdu.resplen; + } } /* test cards only return an empty FCI template, * so we can't determine any file proberties */ - if (file && *length_ef_cardaccess < file->size) { + if (file && *ef_len < file->size) { sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Actual filesize differs from the size in file " - "proberties (%u!=%u).", *length_ef_cardaccess, file->size); + "proberties (%u!=%u).", *ef_len, file->size); r = SC_ERROR_FILE_TOO_SMALL; goto err; } @@ -334,13 +411,17 @@ int get_ef_card_access(sc_card_t *card, r = SC_SUCCESS; err: - if (file) { - free(file); - } + free(file); return r; } +int get_ef_card_access(struct sm_ctx *oldnpactx, sc_card_t *card, + u8 **ef_cardaccess, size_t *length_ef_cardaccess) +{ + return get_ef(oldnpactx, card, SFID_EF_CARDACCESS, ef_cardaccess, length_ef_cardaccess); +} + static int format_mse_cdata(struct sc_context *ctx, int protocol, const unsigned char *key_reference1, size_t key_reference1_len, const unsigned char *key_reference2, size_t key_reference2_len, @@ -349,8 +430,9 @@ static int format_mse_cdata(struct sc_context *ctx, int protocol, const CVC_CHAT *chat, unsigned char **cdata) { NPA_MSE_C *data = NULL; - unsigned char *data_sequence; - const unsigned char *data_no_sequence, *p; + unsigned char *data_sequence = NULL; + const unsigned char *data_no_sequence; + unsigned char *p; long length; int r, class, tag; @@ -437,7 +519,8 @@ static int format_mse_cdata(struct sc_context *ctx, int protocol, r = SC_ERROR_OUT_OF_MEMORY; goto err; } - memcpy(*cdata, data_no_sequence, length); + memcpy(p, data_no_sequence, length); + *cdata = p; r = length; err: @@ -446,14 +529,15 @@ err: data->chat = NULL; NPA_MSE_C_free(data); } - if (data_sequence) - free(data_sequence); + free(data_sequence); return r; } static int npa_mse(struct sm_ctx *oldnpactx, sc_card_t *card, unsigned char p1, - int protocol, const unsigned char *secret_key, size_t secret_key_len, + int protocol, const unsigned char *key_reference1, + size_t key_reference1_len, const unsigned char *key_reference2, + size_t key_reference2_len, const CVC_CHAT *chat, u8 *sw1, u8 *sw2) { sc_apdu_t apdu; @@ -473,8 +557,9 @@ static int npa_mse(struct sm_ctx *oldnpactx, sc_card_t *card, unsigned char p1, apdu.cse = SC_APDU_CASE_3_SHORT; apdu.flags = SC_APDU_FLAGS_NO_GET_RESP|SC_APDU_FLAGS_NO_RETRY_WL; - r = format_mse_cdata(card->ctx, protocol, secret_key, secret_key_len, NULL, - 0, NULL, 0, NULL, 0, chat, &d); + r = format_mse_cdata(card->ctx, protocol, key_reference1, + key_reference1_len, key_reference2, key_reference2_len, NULL, 0, + NULL, 0, chat, &d); if (r < 0) goto err; apdu.data = d; @@ -502,8 +587,7 @@ static int npa_mse(struct sm_ctx *oldnpactx, sc_card_t *card, unsigned char p1, *sw2 = apdu.sw2; err: - if (d) - free(d); + free(d); return r; } @@ -515,7 +599,7 @@ static int npa_mse_set_at_pace(struct sm_ctx *oldnpactx, sc_card_t *card, int r, tries; char key = secret_key; - r = npa_mse(oldnpactx, card, 0xC1, protocol, &key, sizeof key, chat, sw1, sw2); + r = npa_mse(oldnpactx, card, 0xC1, protocol, &key, sizeof key, NULL, 0, chat, sw1, sw2); if (*sw1 == 0x63) { if ((*sw2 & 0xc0) == 0xc0) { @@ -547,8 +631,8 @@ static int npa_gen_auth_1_encrypted_nonce(struct sm_ctx *oldnpactx, sc_card_t *card, u8 **enc_nonce, size_t *enc_nonce_len) { sc_apdu_t apdu; - NPA_GEN_AUTH_C *c_data = NULL; - NPA_GEN_AUTH_R *r_data = NULL; + NPA_GEN_AUTH_PACE_C *c_data = NULL; + NPA_GEN_AUTH_PACE_R *r_data = NULL; unsigned char *d = NULL, *p; int r, l; unsigned char resp[maxresp]; @@ -559,12 +643,12 @@ static int npa_gen_auth_1_encrypted_nonce(struct sm_ctx *oldnpactx, apdu.cse = SC_APDU_CASE_4_SHORT; apdu.flags = SC_APDU_FLAGS_NO_GET_RESP|SC_APDU_FLAGS_NO_RETRY_WL; - c_data = NPA_GEN_AUTH_C_new(); + c_data = NPA_GEN_AUTH_PACE_C_new(); if (!c_data) { r = SC_ERROR_OUT_OF_MEMORY; goto err; } - r = i2d_NPA_GEN_AUTH_C(c_data, &d); + r = i2d_NPA_GEN_AUTH_PACE_C(c_data, &d); if (r < 0) { ssl_error(card->ctx); r = SC_ERROR_INTERNAL; @@ -591,7 +675,7 @@ static int npa_gen_auth_1_encrypted_nonce(struct sm_ctx *oldnpactx, bin_log(card->ctx, SC_LOG_DEBUG_NORMAL, "General authenticate (Encrypted Nonce) response data", apdu.resp, apdu.resplen); - if (!d2i_NPA_GEN_AUTH_R(&r_data, + if (!d2i_NPA_GEN_AUTH_PACE_R(&r_data, (const unsigned char **) &apdu.resp, apdu.resplen)) { sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not parse general authenticate response data."); ssl_error(card->ctx); @@ -624,11 +708,10 @@ static int npa_gen_auth_1_encrypted_nonce(struct sm_ctx *oldnpactx, err: if (c_data) - NPA_GEN_AUTH_C_free(c_data); - if (d) - free(d); + NPA_GEN_AUTH_PACE_C_free(c_data); + free(d); if (r_data) - NPA_GEN_AUTH_R_free(r_data); + NPA_GEN_AUTH_PACE_R_free(r_data); return r; } @@ -637,8 +720,8 @@ static int npa_gen_auth_2_map_nonce(struct sm_ctx *oldnpactx, size_t *map_data_out_len) { sc_apdu_t apdu; - NPA_GEN_AUTH_C *c_data = NULL; - NPA_GEN_AUTH_R *r_data = NULL; + NPA_GEN_AUTH_PACE_C *c_data = NULL; + NPA_GEN_AUTH_PACE_R *r_data = NULL; unsigned char *d = NULL, *p; int r, l; unsigned char resp[maxresp]; @@ -649,7 +732,7 @@ static int npa_gen_auth_2_map_nonce(struct sm_ctx *oldnpactx, apdu.cse = SC_APDU_CASE_4_SHORT; apdu.flags = SC_APDU_FLAGS_NO_GET_RESP|SC_APDU_FLAGS_NO_RETRY_WL; - c_data = NPA_GEN_AUTH_C_new(); + c_data = NPA_GEN_AUTH_PACE_C_new(); if (!c_data) { r = SC_ERROR_OUT_OF_MEMORY; goto err; @@ -662,7 +745,7 @@ static int npa_gen_auth_2_map_nonce(struct sm_ctx *oldnpactx, r = SC_ERROR_INTERNAL; goto err; } - r = i2d_NPA_GEN_AUTH_C(c_data, &d); + r = i2d_NPA_GEN_AUTH_PACE_C(c_data, &d); if (r < 0) { ssl_error(card->ctx); r = SC_ERROR_INTERNAL; @@ -689,7 +772,7 @@ static int npa_gen_auth_2_map_nonce(struct sm_ctx *oldnpactx, bin_log(card->ctx, SC_LOG_DEBUG_NORMAL, "General authenticate (Map Nonce) response data", apdu.resp, apdu.resplen); - if (!d2i_NPA_GEN_AUTH_R(&r_data, + if (!d2i_NPA_GEN_AUTH_PACE_R(&r_data, (const unsigned char **) &apdu.resp, apdu.resplen)) { sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not parse general authenticate response data."); ssl_error(card->ctx); @@ -722,11 +805,10 @@ static int npa_gen_auth_2_map_nonce(struct sm_ctx *oldnpactx, err: if (c_data) - NPA_GEN_AUTH_C_free(c_data); - if (d) - free(d); + NPA_GEN_AUTH_PACE_C_free(c_data); + free(d); if (r_data) - NPA_GEN_AUTH_R_free(r_data); + NPA_GEN_AUTH_PACE_R_free(r_data); return r; } @@ -735,8 +817,8 @@ static int npa_gen_auth_3_perform_key_agreement( const u8 *in, size_t in_len, u8 **eph_pub_key_out, size_t *eph_pub_key_out_len) { sc_apdu_t apdu; - NPA_GEN_AUTH_C *c_data = NULL; - NPA_GEN_AUTH_R *r_data = NULL; + NPA_GEN_AUTH_PACE_C *c_data = NULL; + NPA_GEN_AUTH_PACE_R *r_data = NULL; unsigned char *d = NULL, *p; int r, l; unsigned char resp[maxresp]; @@ -747,7 +829,7 @@ static int npa_gen_auth_3_perform_key_agreement( apdu.cse = SC_APDU_CASE_4_SHORT; apdu.flags = SC_APDU_FLAGS_NO_GET_RESP|SC_APDU_FLAGS_NO_RETRY_WL; - c_data = NPA_GEN_AUTH_C_new(); + c_data = NPA_GEN_AUTH_PACE_C_new(); if (!c_data) { r = SC_ERROR_OUT_OF_MEMORY; goto err; @@ -760,7 +842,7 @@ static int npa_gen_auth_3_perform_key_agreement( r = SC_ERROR_INTERNAL; goto err; } - r = i2d_NPA_GEN_AUTH_C(c_data, &d); + r = i2d_NPA_GEN_AUTH_PACE_C(c_data, &d); if (r < 0) { ssl_error(card->ctx); r = SC_ERROR_INTERNAL; @@ -787,7 +869,7 @@ static int npa_gen_auth_3_perform_key_agreement( bin_log(card->ctx, SC_LOG_DEBUG_NORMAL, "General authenticate (Perform Key Agreement) response data", apdu.resp, apdu.resplen); - if (!d2i_NPA_GEN_AUTH_R(&r_data, + if (!d2i_NPA_GEN_AUTH_PACE_R(&r_data, (const unsigned char **) &apdu.resp, apdu.resplen)) { sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not parse general authenticate response data."); ssl_error(card->ctx); @@ -820,11 +902,10 @@ static int npa_gen_auth_3_perform_key_agreement( err: if (c_data) - NPA_GEN_AUTH_C_free(c_data); - if (d) - free(d); + NPA_GEN_AUTH_PACE_C_free(c_data); + free(d); if (r_data) - NPA_GEN_AUTH_R_free(r_data); + NPA_GEN_AUTH_PACE_R_free(r_data); return r; } @@ -835,24 +916,22 @@ static int npa_gen_auth_4_mutual_authentication( u8 **prev_car, size_t *prev_car_len) { sc_apdu_t apdu; - NPA_GEN_AUTH_C *c_data = NULL; - NPA_GEN_AUTH_R *r_data = NULL; + NPA_GEN_AUTH_PACE_C *c_data = NULL; + NPA_GEN_AUTH_PACE_R *r_data = NULL; unsigned char *d = NULL, *p; int r, l; unsigned char resp[maxresp]; memset(&apdu, 0, sizeof apdu); - apdu.cla = 0x10; apdu.ins = 0x86; apdu.cse = SC_APDU_CASE_4_SHORT; apdu.flags = SC_APDU_FLAGS_NO_GET_RESP|SC_APDU_FLAGS_NO_RETRY_WL; - c_data = NPA_GEN_AUTH_C_new(); + c_data = NPA_GEN_AUTH_PACE_C_new(); if (!c_data) { r = SC_ERROR_OUT_OF_MEMORY; goto err; } - apdu.cla = 0; c_data->auth_token = ASN1_OCTET_STRING_new(); if (!c_data->auth_token || !M_ASN1_OCTET_STRING_set( @@ -861,7 +940,7 @@ static int npa_gen_auth_4_mutual_authentication( r = SC_ERROR_INTERNAL; goto err; } - r = i2d_NPA_GEN_AUTH_C(c_data, &d); + r = i2d_NPA_GEN_AUTH_PACE_C(c_data, &d); if (r < 0) { ssl_error(card->ctx); r = SC_ERROR_INTERNAL; @@ -888,7 +967,7 @@ static int npa_gen_auth_4_mutual_authentication( bin_log(card->ctx, SC_LOG_DEBUG_NORMAL, "General authenticate (Perform Key Agreement) response data", apdu.resp, apdu.resplen); - if (!d2i_NPA_GEN_AUTH_R(&r_data, + if (!d2i_NPA_GEN_AUTH_PACE_R(&r_data, (const unsigned char **) &apdu.resp, apdu.resplen)) { sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not parse general authenticate response data."); ssl_error(card->ctx); @@ -945,11 +1024,10 @@ static int npa_gen_auth_4_mutual_authentication( err: if (c_data) - NPA_GEN_AUTH_C_free(c_data); - if (d) - free(d); + NPA_GEN_AUTH_PACE_C_free(c_data); + free(d); if (r_data) - NPA_GEN_AUTH_R_free(r_data); + NPA_GEN_AUTH_PACE_R_free(r_data); return r; } @@ -1161,7 +1239,7 @@ int EstablishPACEChannel(struct sm_ctx *oldnpactx, sc_card_t *card, r = sc_perform_pace(card, &pace_input, pace_output); } else { if (!pace_output->ef_cardaccess_length || !pace_output->ef_cardaccess) { - r = get_ef_card_access(card, &pace_output->ef_cardaccess, + r = get_ef_card_access(oldnpactx, card, &pace_output->ef_cardaccess, &pace_output->ef_cardaccess_length); if (r < 0) { sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not get EF.CardAccess."); @@ -1407,15 +1485,15 @@ err: static int npa_mse_set_dst_ta(struct sm_ctx *npactx, sc_card_t *card, const unsigned char *car, size_t car_len) { - return npa_mse(npactx, card, 0x81, 0, car, car_len, NULL, - NULL, NULL); + return npa_mse(npactx, card, 0x81, 0, car, car_len, NULL, 0, NULL, NULL, + NULL); } static int npa_mse_set_at_ta(struct sm_ctx *npactx, sc_card_t *card, const unsigned char *chr, size_t chr_len) { - return npa_mse(npactx, card, 0xa1, 0, chr, chr_len, NULL, - NULL, NULL); + return npa_mse(npactx, card, 0xa1, 0, chr, chr_len, NULL, 0, NULL, NULL, + NULL); } static int npa_get_challenge(struct sm_ctx *npactx, sc_card_t *card, @@ -1646,6 +1724,202 @@ err: SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, r); } +static int npa_mse_set_at_ca(struct sm_ctx *npactx, sc_card_t *card, + const unsigned char *key_ref, size_t key_ref_len) +{ + return npa_mse(npactx, card, 0x41, 0, NULL, 0, key_ref, key_ref_len, NULL, + NULL, NULL); +} + +static int npa_gen_auth_ca(struct sm_ctx *npactx, sc_card_t *card, + const BUF_MEM *eph_pub_key, BUF_MEM **nonce, BUF_MEM **token) +{ + sc_apdu_t apdu; + NPA_GEN_AUTH_CA_C *c_data = NULL; + NPA_GEN_AUTH_CA_R *r_data = NULL; + unsigned char *d = NULL; + int r; + unsigned char resp[maxresp]; + + memset(&apdu, 0, sizeof apdu); + apdu.ins = 0x86; + apdu.cse = SC_APDU_CASE_4_SHORT; + apdu.flags = SC_APDU_FLAGS_NO_GET_RESP|SC_APDU_FLAGS_NO_RETRY_WL; + + c_data = NPA_GEN_AUTH_CA_C_new(); + if (!c_data) { + r = SC_ERROR_OUT_OF_MEMORY; + goto err; + } + c_data->eph_pub_key = ASN1_OCTET_STRING_new(); + if (!c_data->eph_pub_key + || !M_ASN1_OCTET_STRING_set( c_data->eph_pub_key, + eph_pub_key->data, eph_pub_key->length)) { + ssl_error(card->ctx); + r = SC_ERROR_INTERNAL; + goto err; + } + r = i2d_NPA_GEN_AUTH_CA_C(c_data, &d); + if (r < 0) { + ssl_error(card->ctx); + r = SC_ERROR_INTERNAL; + goto err; + } + apdu.data = (const u8 *) d; + apdu.datalen = r; + apdu.lc = r; + + bin_log(card->ctx, SC_LOG_DEBUG_NORMAL, "General authenticate (Perform Key Agreement) command data", apdu.data, apdu.datalen); + + apdu.resplen = sizeof resp; + apdu.resp = resp; + if (npactx) + r = sm_transmit_apdu(npactx, card, &apdu); + else + r = sc_transmit_apdu(card, &apdu); + if (r < 0) + goto err; + + r = sc_check_sw(card, apdu.sw1, apdu.sw2); + if (r < 0) + goto err; + + bin_log(card->ctx, SC_LOG_DEBUG_NORMAL, "General authenticate (Perform Key Agreement) response data", apdu.resp, apdu.resplen); + + if (!d2i_NPA_GEN_AUTH_CA_R(&r_data, + (const unsigned char **) &apdu.resp, apdu.resplen)) { + sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not parse general authenticate response data."); + ssl_error(card->ctx); + r = SC_ERROR_INTERNAL; + goto err; + } + + if (!r_data->nonce || !r_data->auth_token) { + sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Response data of general authenticate for CA" + "should contain the nonce and the authentication token."); + r = SC_ERROR_UNKNOWN_DATA_RECEIVED; + goto err; + } + + if (*nonce) + BUF_MEM_free(*nonce); + *nonce = BUF_MEM_create_init(r_data->nonce->data, + r_data->nonce->length); + if (*token) + BUF_MEM_free(*token); + *token = BUF_MEM_create_init(r_data->auth_token->data, + r_data->auth_token->length); + if (!*nonce || !*token) { + r = SC_ERROR_OUT_OF_MEMORY; + goto err; + } + +err: + if (c_data) + NPA_GEN_AUTH_CA_C_free(c_data); + if (r_data) + NPA_GEN_AUTH_CA_R_free(r_data); + free(d); + + return r; +} + +int get_ef_card_security(struct sm_ctx *npactx, sc_card_t *card, + u8 **ef_security, size_t *length_ef_security) +{ + return get_ef(npactx, card, SFID_EF_CARDSECURITY, ef_security, length_ef_security); +} + +int perform_chip_authentication(struct sm_ctx *ctx, sc_card_t *card) +{ + int r; + BUF_MEM *picc_pubkey = NULL, *nonce = NULL, *token = NULL, *eph_pub_key = NULL; + unsigned char *ef_cardsecurity = NULL; + size_t ef_cardsecurity_len; + + if (!card || !ctx->priv_data) { + r = SC_ERROR_INVALID_ARGUMENTS; + goto err; + } + struct npa_sm_ctx *eacsmctx = ctx->priv_data; + + eacsmctx->flags = 0; + + + /* Passive Authentication */ + r = get_ef_card_security(ctx, card, &ef_cardsecurity, &ef_cardsecurity_len); + if (r < 0) { + sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not get EF.CardSecurity."); + goto err; + } + /* FIXME patch OpenPACE to do verification of EF.CardSecurity and + * to call EAC_CTX_init_ca */ + picc_pubkey = CA_get_pubkey(ef_cardsecurity, ef_cardsecurity_len); + if (!picc_pubkey) { + sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not verify EF.CardSecurity."); + ssl_error(card->ctx); + r = SC_ERROR_INTERNAL; + goto err; + } + + + if (!CA_STEP4_compute_shared_secret(eacsmctx->ctx, picc_pubkey)) { + sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not compute shared secret."); + ssl_error(card->ctx); + r = SC_ERROR_INTERNAL; + goto err; + } + + + unsigned char key_ref = 1; + r = npa_mse_set_at_ca(ctx, card, &key_ref, sizeof key_ref); + if (r < 0) { + sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not select protocol proberties " + "(MSE: Set AT failed)."); + goto err; + } + + + eph_pub_key = CA_STEP2_get_eph_pubkey(eacsmctx->ctx); + if (!eph_pub_key) { + sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not derive keys."); + ssl_error(card->ctx); + r = SC_ERROR_INTERNAL; + goto err; + } + r = npa_gen_auth_ca(ctx, card, eph_pub_key, &nonce, &token); + + + if (r < 0 || !CA_STEP6_derive_keys(eacsmctx->ctx, nonce, token)) { + sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not derive keys."); + ssl_error(card->ctx); + r = SC_ERROR_INTERNAL; + goto err; + } + + + /* Initialize secure channel */ + if (!EAC_CTX_set_encryption_ctx(eacsmctx->ctx, EAC_ID_CA)) { + sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not initialize encryption."); + ssl_error(card->ctx); + r = SC_ERROR_INTERNAL; + goto err; + } + +err: + free(ef_cardsecurity); + if (picc_pubkey) + BUF_MEM_free(picc_pubkey); + if (nonce) + BUF_MEM_free(nonce); + if (token) + BUF_MEM_free(token); + if (eph_pub_key) + BUF_MEM_free(eph_pub_key); + + SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, r); +} + static const char *MRZ_name = "MRZ"; static const char *PIN_name = "PIN"; static const char *PUK_name = "PUK"; @@ -1831,8 +2105,7 @@ err: BUF_MEM_free(inbuf); if (macbuf) BUF_MEM_free(macbuf); - if (ssc) - free(ssc); + free(ssc); return r; } @@ -2125,8 +2398,7 @@ err: BUF_MEM_free(signature); if (cert) OPENSSL_free(cert); - if (sequence) - free(sequence); + free(sequence); if (templates) OPENSSL_free(templates); diff --git a/npa/src/npa/npa.h b/npa/src/npa/npa.h index 61620af..f685a9c 100644 --- a/npa/src/npa/npa.h +++ b/npa/src/npa/npa.h @@ -153,6 +153,13 @@ int EstablishPACEChannel(struct sm_ctx *oldpacectx, sc_card_t *card, struct establish_pace_channel_output *pace_output, struct sm_ctx *sctx, enum eac_tr_version tr_version); +int perform_terminal_authentication(struct sm_ctx *ctx, sc_card_t *card, + const unsigned char **certs, const size_t *certs_lens, + const unsigned char *privkey, size_t privkey_len, + const unsigned char *auxiliary_data, size_t auxiliary_data_len); + +int perform_chip_authentication(struct sm_ctx *ctx, sc_card_t *card); + /** * @brief Sends a reset retry counter APDU *