Add PIN encoding detection for StarCOS 3x cards

This commit is contained in:
dojo 2019-12-04 12:53:01 +01:00 committed by Frank Morgner
parent 5fa633075d
commit c99d62c04a
1 changed files with 187 additions and 1 deletions

View File

@ -80,8 +80,22 @@ typedef struct starcos_ex_data_st {
int sec_ops; /* the currently selected security operation,
* i.e. SC_SEC_OPERATION_AUTHENTICATE etc. */
unsigned int fix_digestInfo;
unsigned int pin_encoding;
} starcos_ex_data;
#define PIN_ENCODING_DETERMINE 0
#define PIN_ENCODING_DEFAULT SC_PIN_ENCODING_GLP
// known pin formats for StarCOS 3.x cards
#define PIN_FORMAT_F1 0x11
#define PIN_FORMAT_F2 0x12
#define PIN_FORMAT_RSA 0x1230
#define PIN_FORMAT_BCD 0x13
#define PIN_FORMAT_ASCII 0x14
#define PIN_FORMAT_PW_ASCII 0x21
// default is the Format 2 PIN Block which is GLP in OpenSC
#define PIN_FORMAT_DEFAULT PIN_FORMAT_F2
#define CHECK_NOT_SUPPORTED_V3_4(card) \
do { \
if ((card)->type == SC_CARD_TYPE_STARCOS_V3_4) { \
@ -102,6 +116,171 @@ static int starcos_match_card(sc_card_t *card)
return 1;
}
typedef struct starcos_ctrl_ref_template_st {
unsigned int transmission_format;
#if 0
// not relevant values for now
unsigned int se_reference;
unsigned int ssec_initial_value;
#endif
} starcos_ctrl_ref_template;
// tags
#define TAG_STARCOS35_PIN_REFERENCE 0x88
#define TAG_STARCOS3X_SUPPORTED_SEC_MECHANISMS_tag 0x7B
#define TAG_STARCOS3X_CTRL_REF_TEMPLATE 0xA4
#define TAG_STARCOS3X_TRANSMISSION_FORMAT 0x89
static const char * starcos_ef_pwdd = "3F000015";
static const char * starcos_ef_keyd = "3F000013";
/**
* Parses supported securiy mechanisms record data.
* It returns SC_SUCCESS and the ctrl_ref_template structure data on success
*/
static int starcos_parse_supported_sec_mechanisms(struct sc_card *card, const unsigned char * buf, size_t buflen, starcos_ctrl_ref_template * ctrl_ref_template)
{
struct sc_context *ctx = card->ctx;
const unsigned char *supported_sec_mechanisms_tag = NULL;
size_t taglen;
LOG_FUNC_CALLED(ctx);
supported_sec_mechanisms_tag = sc_asn1_find_tag(ctx, buf, buflen, TAG_STARCOS3X_SUPPORTED_SEC_MECHANISMS_tag, &taglen);
if (supported_sec_mechanisms_tag != NULL && taglen >= 1) {
const unsigned char *tx_fmt_tag = NULL;
const unsigned char *ctrl_ref_template_tag = NULL;
size_t supported_sec_mechanisms_taglen = taglen;
// control-reference template is either included in the supported security mechanisms tag or it can be the CRT tag itself (EF.PWDD)
ctrl_ref_template_tag = sc_asn1_find_tag(ctx, supported_sec_mechanisms_tag, taglen, TAG_STARCOS3X_CTRL_REF_TEMPLATE, &taglen);
if ( ctrl_ref_template_tag == NULL || taglen == 0 ) {
ctrl_ref_template_tag = supported_sec_mechanisms_tag;
taglen = supported_sec_mechanisms_taglen;
}
tx_fmt_tag = sc_asn1_find_tag(ctx, ctrl_ref_template_tag, taglen, TAG_STARCOS3X_TRANSMISSION_FORMAT, &taglen);
if ( tx_fmt_tag != NULL && taglen >= 1 ) {
ctrl_ref_template->transmission_format = *(tx_fmt_tag + 0);
LOG_FUNC_RETURN(ctx, SC_SUCCESS);
}
}
LOG_FUNC_RETURN(ctx, SC_ERROR_TEMPLATE_NOT_FOUND);
}
static int starcos_determine_pin_format34(sc_card_t *card, unsigned int * pin_format)
{
struct sc_context *ctx = card->ctx;
struct sc_path path;
struct sc_file *file;
unsigned char buf[256];
int rv;
int retval = SC_SUCCESS;
int rec_no=1;
LOG_FUNC_CALLED(ctx);
sc_format_path(starcos_ef_pwdd, &path);
rv = sc_select_file(card, &path, &file);
LOG_TEST_RET(ctx, rv, "Cannot select EF.PWDD file");
if ( (rv = sc_read_record(card, rec_no, buf, sizeof(buf), SC_RECORD_BY_REC_NR)) > 0 ) {
starcos_ctrl_ref_template ctrl_ref_template;
memset((void*)&ctrl_ref_template, 0, sizeof(ctrl_ref_template));
rv = starcos_parse_supported_sec_mechanisms(card, buf, rv, &ctrl_ref_template);
if ( rv == SC_SUCCESS ) {
*pin_format = ctrl_ref_template.transmission_format;
sc_log(ctx, "Determined StarCOS 3.4 PIN format: 0x%x", *pin_format);
} else {
sc_log(ctx, "Failed to parse record %d of EF.PWD, err=%d", rec_no, rv);
retval = rv;
}
} else {
sc_log(ctx, "Failed to read record %d of EF.PWDD, err=%d", rec_no, rv);
retval = rv;
}
sc_file_free(file);
LOG_FUNC_RETURN(ctx, retval);
}
static int starcos_determine_pin_format35(sc_card_t *card, unsigned int * pin_format)
{
struct sc_context *ctx = card->ctx;
struct sc_path path;
struct sc_file *file;
unsigned char buf[256];
int rv;
int retval = SC_ERROR_RECORD_NOT_FOUND;
int rec_no=1;
starcos_ctrl_ref_template ctrl_ref_template;
LOG_FUNC_CALLED(ctx);
sc_format_path(starcos_ef_keyd, &path);
rv = sc_select_file(card, &path, &file);
LOG_TEST_RET(ctx, rv, "Cannot select EF.KEYD file");
while ( (rv = sc_read_record(card, rec_no++, buf, sizeof(buf), SC_RECORD_BY_REC_NR)) > 0 ) {
if ( buf[0] != TAG_STARCOS35_PIN_REFERENCE ) continue;
memset((void*)&ctrl_ref_template, 0, sizeof(ctrl_ref_template));
rv = starcos_parse_supported_sec_mechanisms(card, buf, rv, &ctrl_ref_template);
if ( rv == SC_SUCCESS ) {
*pin_format = ctrl_ref_template.transmission_format;
sc_log(ctx, "Determined StarCOS 3.5 PIN format: 0x%x", *pin_format);
retval = rv;
// assuming that all PINs and PUKs have the same transmission format
break;
} else {
sc_log(ctx, "Failed to parse record %d of EF.KEYD, err=%d", rec_no-1, rv);
retval = rv;
}
}
sc_file_free(file);
LOG_FUNC_RETURN(ctx, retval);
}
/**
* Determine v3.x PIN encoding by parsing either
* EF.PWDD (for v3.4) or EF.KEYD (for v3.5)
*
* It returns an OpenSC PIN encoding, using the default value on failure
*/
static unsigned int starcos_determine_pin_encoding(sc_card_t *card)
{
unsigned int pin_format = PIN_FORMAT_DEFAULT;
unsigned int encoding = PIN_ENCODING_DETERMINE;
if ( card->type == SC_CARD_TYPE_STARCOS_V3_4 ) {
starcos_determine_pin_format34(card, &pin_format);
} else if ( card->type == SC_CARD_TYPE_STARCOS_V3_5 ) {
starcos_determine_pin_format35(card, &pin_format);
}
switch (pin_format) {
case PIN_FORMAT_PW_ASCII:
case PIN_FORMAT_ASCII:
encoding = SC_PIN_ENCODING_ASCII;
break;
case PIN_FORMAT_BCD:
encoding = SC_PIN_ENCODING_BCD;
break;
case PIN_FORMAT_F1:
case PIN_FORMAT_F2:
encoding = SC_PIN_ENCODING_GLP;
break;
}
sc_log(card->ctx, "Determined PIN encoding: %d", encoding);
return encoding;
}
static int starcos_init(sc_card_t *card)
{
unsigned int flags;
@ -114,6 +293,7 @@ static int starcos_init(sc_card_t *card)
card->name = "STARCOS";
card->cla = 0x00;
card->drv_data = (void *)ex_data;
ex_data->pin_encoding = PIN_ENCODING_DETERMINE;
flags = SC_ALGORITHM_RSA_PAD_PKCS1
| SC_ALGORITHM_ONBOARD_KEY_GEN
@ -168,6 +348,11 @@ static int starcos_init(sc_card_t *card)
}
}
if ( ex_data->pin_encoding == PIN_ENCODING_DETERMINE ) {
// about to determine PIN encoding
ex_data->pin_encoding = starcos_determine_pin_encoding(card);
}
return 0;
}
@ -1854,11 +2039,12 @@ static int starcos_pin_cmd(sc_card_t *card, struct sc_pin_cmd_data *data,
int r;
LOG_FUNC_CALLED(card->ctx);
starcos_ex_data * ex_data = (starcos_ex_data*)card->drv_data;
switch (card->type) {
case SC_CARD_TYPE_STARCOS_V3_4:
case SC_CARD_TYPE_STARCOS_V3_5:
data->flags |= SC_PIN_CMD_NEED_PADDING;
data->pin1.encoding = SC_PIN_ENCODING_GLP;
data->pin1.encoding = ex_data->pin_encoding;
/* fall through */
default:
r = iso_ops->pin_cmd(card, data, tries_left);