- 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
This commit is contained in:
frankmorgner
2010-06-10 11:14:39 +00:00
parent a1fdced1f5
commit c64e9ac527
2 changed files with 130 additions and 38 deletions

View File

@@ -19,6 +19,7 @@
#include "binutil.h"
#include "pace.h"
#include "scutil.h"
#include <asm/byteorder.h>
#include <opensc/log.h>
#include <openssl/pace.h>
#include <stdint.h>
@@ -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;

View File

@@ -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).");