static int entersafe_gen_random(sc_card_t *card,u8 *buff,size_t size) { int r=SC_SUCCESS; u8 rbuf[SC_MAX_APDU_BUFFER_SIZE]={0}; sc_apdu_t apdu; SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); sc_format_apdu(card,&apdu,SC_APDU_CASE_2_SHORT,0x84,0x00,0x00); apdu.resp=rbuf; apdu.le=size; apdu.resplen=sizeof(rbuf); r=sc_transmit_apdu(card,&apdu); SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "entersafe gen random failed"); if(apdu.resplen!=size) SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL,SC_ERROR_INTERNAL); memcpy(buff,rbuf,size); SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL,r); }
static int ias_compute_signature(sc_card_t *card, const u8 * data, size_t data_len, u8 * out, size_t outlen) { int r; size_t len = 0; sc_apdu_t apdu; u8 sbuf[SC_MAX_APDU_BUFFER_SIZE]; sc_context_t *ctx = card->ctx; SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_VERBOSE); if (data_len > 64) { sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "error: input data too long: %lu bytes\n", data_len); return SC_ERROR_INVALID_ARGUMENTS; } /* Send the data */ sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x88, 0x02, 0x00); memcpy(sbuf, data, data_len); apdu.data = sbuf; apdu.lc = data_len; apdu.datalen = data_len; r = sc_transmit_apdu(card, &apdu); SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "APDU transmit failed"); /* Get the result */ if (apdu.sw1 == 0x90 && apdu.sw2 == 0x00) { len = card->type == SC_CARD_TYPE_IAS_PTEID ? PTEID_RSA_KEYSIZE : outlen; r = iso_ops->get_response(card, &len, out); if (r == 0) SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, len); else SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r); } SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, sc_check_sw(card, apdu.sw1, apdu.sw2)); }
static int atrust_acos_decipher(struct sc_card *card, const u8 * crgram, size_t crgram_len, u8 * out, size_t outlen) { int r; struct sc_apdu apdu; u8 rbuf[SC_MAX_APDU_BUFFER_SIZE]; u8 sbuf[SC_MAX_APDU_BUFFER_SIZE]; assert(card != NULL && crgram != NULL && out != NULL); SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_NORMAL); if (crgram_len > 255) SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_INVALID_ARGUMENTS); /* INS: 0x2A PERFORM SECURITY OPERATION * P1: 0x80 Resp: Plain value * P2: 0x86 Cmd: Padding indicator byte followed by cryptogram */ sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0x2A, 0x80, 0x86); apdu.resp = rbuf; apdu.resplen = sizeof(rbuf); sbuf[0] = 0; /* padding indicator byte, 0x00 = No further indication */ memcpy(sbuf + 1, crgram, crgram_len); apdu.data = sbuf; apdu.lc = crgram_len + 1; apdu.datalen = crgram_len + 1; apdu.le = 256; r = sc_transmit_apdu(card, &apdu); SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "APDU transmit failed"); if (apdu.sw1 == 0x90 && apdu.sw2 == 0x00) { size_t len = apdu.resplen > outlen ? outlen : apdu.resplen; memcpy(out, apdu.resp, len); SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, len); } SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, sc_check_sw(card, apdu.sw1, apdu.sw2)); }
static int iasecc_sm_get_challenge(struct sc_card *card, unsigned char *out, size_t len) { struct sc_context *ctx = card->ctx; struct sc_apdu apdu; unsigned char rbuf[SC_MAX_APDU_BUFFER_SIZE]; int rv; sc_log(ctx, "SM get challenge: length %i",len); sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0x84, 0, 0); apdu.le = len; apdu.resplen = len; apdu.resp = rbuf; rv = sc_transmit_apdu(card, &apdu); LOG_TEST_RET(ctx, rv, "APDU transmit failed"); rv = sc_check_sw(card, apdu.sw1, apdu.sw2); LOG_TEST_RET(ctx, rv, "Command failed"); memcpy(out, rbuf, apdu.resplen); LOG_FUNC_RETURN(ctx, apdu.resplen); }
static int esteid_select(struct sc_card *card, unsigned char p1, unsigned char id1, unsigned char id2) { struct sc_apdu apdu; unsigned char sbuf[2]; LOG_FUNC_CALLED(card->ctx); // Select EF/DF sbuf[0] = id1; sbuf[1] = id2; sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0xA4, p1, 0x0C); if (id1 != 0x3F && id2 != 0x00) { apdu.cse = SC_APDU_CASE_3_SHORT; apdu.lc = 2; apdu.data = sbuf; apdu.datalen = 2; } apdu.le = 0; apdu.resplen = 0; SC_TRANSMIT_TEST_RET(card, apdu, "SELECT failed"); LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); }
static int iso7816_append_record(sc_card_t *card, const u8 *buf, size_t count, unsigned long flags) { sc_apdu_t apdu; int r; if (count > 256) { sc_error(card->ctx, "Trying to send too many bytes\n"); return SC_ERROR_INVALID_ARGUMENTS; } sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xE2, 0, 0); apdu.p2 = (flags & SC_RECORD_EF_ID_MASK) << 3; apdu.lc = count; apdu.datalen = count; apdu.data = buf; r = sc_transmit_apdu(card, &apdu); SC_TEST_RET(card->ctx, r, "APDU transmit failed"); SC_TEST_RET(card->ctx, sc_check_sw(card, apdu.sw1, apdu.sw2), "Card returned error"); SC_FUNC_RETURN(card->ctx, 3, count); }
static int iso7816_read_record(struct sc_card *card, unsigned int rec_nr, u8 *buf, size_t count, unsigned long flags) { struct sc_apdu apdu; int r; sc_format_apdu(card, &apdu, SC_APDU_CASE_2, 0xB2, rec_nr, 0); apdu.p2 = (flags & SC_RECORD_EF_ID_MASK) << 3; if (flags & SC_RECORD_BY_REC_NR) apdu.p2 |= 0x04; apdu.le = count; apdu.resplen = count; apdu.resp = buf; fixup_transceive_length(card, &apdu); r = sc_transmit_apdu(card, &apdu); LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); if (apdu.resplen == 0) LOG_FUNC_RETURN(card->ctx, sc_check_sw(card, apdu.sw1, apdu.sw2)); LOG_FUNC_RETURN(card->ctx, apdu.resplen); }
static int atrust_acos_logout(struct sc_card *card) { int r; struct sc_apdu apdu; const u8 mf_buf[2] = {0x3f, 0x00}; sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xA4, 0x00, 0x0C); apdu.le = 0; apdu.lc = 2; apdu.data = mf_buf; apdu.datalen = 2; apdu.resplen = 0; r = sc_transmit_apdu(card, &apdu); SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "APDU re-transmit failed"); if (apdu.sw1 == 0x69 && apdu.sw2 == 0x85) /* the only possible reason for this error here is, afaik, * that no MF exists, but then there's no need to logout * => return SC_SUCCESS */ return SC_SUCCESS; return sc_check_sw(card, apdu.sw1, apdu.sw2); }
static int iso7816_update_record(struct sc_card *card, unsigned int rec_nr, const u8 *buf, size_t count, unsigned long flags) { struct sc_apdu apdu; int r; sc_format_apdu(card, &apdu, SC_APDU_CASE_3, 0xDC, rec_nr, 0); apdu.p2 = (flags & SC_RECORD_EF_ID_MASK) << 3; if (flags & SC_RECORD_BY_REC_NR) apdu.p2 |= 0x04; apdu.lc = count; apdu.datalen = count; apdu.data = buf; fixup_transceive_length(card, &apdu); r = sc_transmit_apdu(card, &apdu); LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); r = sc_check_sw(card, apdu.sw1, apdu.sw2); LOG_TEST_RET(card->ctx, r, "Card returned error"); LOG_FUNC_RETURN(card->ctx, count); }
static int cardos_list_files(sc_card_t *card, u8 *buf, size_t buflen) { sc_apdu_t apdu; u8 rbuf[256], offset = 0; const u8 *p = rbuf, *q; int r; size_t fids = 0, len; SC_FUNC_CALLED(card->ctx, 1); /* 0x16: DIRECTORY */ /* 0x02: list both DF and EF */ get_next_part: sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0x16, 0x02, offset); apdu.cla = 0x80; apdu.le = 256; apdu.resplen = 256; apdu.resp = rbuf; r = sc_transmit_apdu(card, &apdu); SC_TEST_RET(card->ctx, r, "APDU transmit failed"); r = sc_check_sw(card, apdu.sw1, apdu.sw2); SC_TEST_RET(card->ctx, r, "DIRECTORY command returned error"); if (apdu.resplen > 256) { sc_error(card->ctx, "directory listing > 256 bytes, cutting"); r = 256; } len = apdu.resplen; while (len != 0) { size_t tlen = 0, ilen = 0; /* is there a file informatin block (0x6f) ? */ p = sc_asn1_find_tag(card->ctx, p, len, 0x6f, &tlen); if (p == NULL) { sc_error(card->ctx, "directory tag missing"); return SC_ERROR_INTERNAL; } if (tlen == 0) /* empty directory */ break; q = sc_asn1_find_tag(card->ctx, p, tlen, 0x86, &ilen); if (q == NULL || ilen != 2) { sc_error(card->ctx, "error parsing file id TLV object"); return SC_ERROR_INTERNAL; } /* put file id in buf */ if (buflen >= 2) { buf[fids++] = q[0]; buf[fids++] = q[1]; buflen -= 2; } else /* not enought space left in buffer => break */ break; /* extract next offset */ q = sc_asn1_find_tag(card->ctx, p, tlen, 0x8a, &ilen); if (q != NULL && ilen == 1) { offset = (u8)ilen; if (offset != 0) goto get_next_part; } len -= tlen + 2; p += tlen; } r = fids; SC_FUNC_RETURN(card->ctx, 1, r); }
static int jpki_pin_cmd(sc_card_t *card, struct sc_pin_cmd_data *data, int *tries_left) { int rc; sc_path_t path; sc_apdu_t apdu; struct jpki_private_data *priv = JPKI_DRVDATA(card); int max_tries = 0; LOG_FUNC_CALLED(card->ctx); if (tries_left) { *tries_left = -1; } switch (data->pin_reference) { case 1: sc_format_path(JPKI_AUTH_PIN, &path); path.type = SC_PATH_TYPE_FILE_ID; rc = sc_select_file(card, &path, NULL); max_tries = JPKI_AUTH_PIN_MAX_TRIES; break; case 2: sc_format_path(JPKI_SIGN_PIN, &path); path.type = SC_PATH_TYPE_FILE_ID; rc = sc_select_file(card, &path, NULL); max_tries = JPKI_SIGN_PIN_MAX_TRIES; break; default: sc_log(card->ctx, "Unknown PIN reference: %d", data->pin_reference); LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS); } LOG_TEST_RET(card->ctx, rc, "SELECT_FILE error"); switch (data->cmd) { case SC_PIN_CMD_VERIFY: sc_format_apdu(card, &apdu, SC_APDU_CASE_3, 0x20, 0x00, 0x80); apdu.data = data->pin1.data; apdu.datalen = data->pin1.len; apdu.lc = data->pin1.len; rc = sc_transmit_apdu(card, &apdu); LOG_TEST_RET(card->ctx, rc, "APDU transmit failed"); rc = sc_check_sw(card, apdu.sw1, apdu.sw2); if (rc == SC_SUCCESS) { data->pin1.logged_in = SC_PIN_STATE_LOGGED_IN; data->pin1.tries_left = max_tries; } else { data->pin1.logged_in = SC_PIN_STATE_LOGGED_OUT; data->pin1.tries_left = apdu.sw2 & 0xF; } priv->logged_in = data->pin1.logged_in; LOG_TEST_RET(card->ctx, rc, "VERIFY failed"); break; case SC_PIN_CMD_GET_INFO: sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0x20, 0x00, 0x80); rc = sc_transmit_apdu(card, &apdu); LOG_TEST_RET(card->ctx, rc, "APDU transmit failed"); if (apdu.sw1 != 0x63) { sc_log(card->ctx, "VERIFY GET_INFO error"); LOG_FUNC_RETURN(card->ctx, SC_ERROR_CARD_CMD_FAILED); } data->pin1.logged_in = priv->logged_in; data->pin1.tries_left = apdu.sw2 & 0xF; if (tries_left) { *tries_left = data->pin1.tries_left; } break; default: sc_log(card->ctx, "Card does not support PIN command: %d", data->cmd); LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED); } LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); }
static int jpki_select_file(struct sc_card *card, const struct sc_path *path, struct sc_file **file_out) { struct jpki_private_data *drvdata = JPKI_DRVDATA(card); int rc; sc_apdu_t apdu; struct sc_file *file = NULL; LOG_FUNC_CALLED(card->ctx); sc_log(card->ctx, "jpki_select_file: path=%s, len=%"SC_FORMAT_LEN_SIZE_T"u", sc_print_path(path), path->len); if (path->len == 2 && memcmp(path->value, "\x3F\x00", 2) == 0) { drvdata->selected = SELECT_MF; if (file_out) { sc_file_dup(file_out, drvdata->mf); if (*file_out == NULL) { LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY); } } return 0; } sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xA4, 0, 0); switch (path->type) { case SC_PATH_TYPE_FILE_ID: apdu.p1 = 2; break; case SC_PATH_TYPE_DF_NAME: apdu.p1 = 4; break; default: LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS); } apdu.p2 = 0x0C; apdu.data = path->value; apdu.datalen = path->len; apdu.lc = path->len; rc = sc_transmit_apdu(card, &apdu); LOG_TEST_RET(card->ctx, rc, "APDU transmit failed"); rc = sc_check_sw(card, apdu.sw1, apdu.sw2); LOG_TEST_RET(card->ctx, rc, "SW Check failed"); if (!file_out) { LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); } /* read certificate file size */ if (path->len == 2 && ( memcmp(path->value, "\x00\x0A", 2) == 0 || memcmp(path->value, "\x00\x01", 2) == 0 || memcmp(path->value, "\x00\x0B", 2) == 0 || memcmp(path->value, "\x00\x02", 2) == 0 ) ) { u8 buf[4]; rc = sc_read_binary(card, 0, buf, 4, 0); LOG_TEST_RET(card->ctx, rc, "SW Check failed"); file = sc_file_new(); if (!file) { LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY); } file->path = *path; file->size = (buf[2] << 8 | buf[3]) + 4; *file_out = file; } LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); }
static int ias_select_file(sc_card_t *card, const sc_path_t *in_path, sc_file_t **file_out) { int r, pathlen, stripped_len; u8 buf[SC_MAX_APDU_BUFFER_SIZE]; u8 pathbuf[SC_MAX_PATH_SIZE], *path; sc_apdu_t apdu; sc_file_t *file; stripped_len = 0; path = pathbuf; file = NULL; assert(card != NULL && in_path != NULL); if (in_path->len > SC_MAX_PATH_SIZE) return SC_ERROR_INVALID_ARGUMENTS; memcpy(path, in_path->value, in_path->len); pathlen = in_path->len; sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0xA4, 0, 0); apdu.p2 = 0; /* First record, return FCI */ switch (in_path->type) { case SC_PATH_TYPE_FILE_ID: apdu.p1 = 2; if (pathlen != 2) return SC_ERROR_INVALID_ARGUMENTS; break; case SC_PATH_TYPE_DF_NAME: apdu.p1 = 4; break; case SC_PATH_TYPE_PATH: apdu.p1 = 9; /* Strip the MF */ if (pathlen >= 2 && memcmp(path, "\x3f\x00", 2) == 0) { if (pathlen == 2) { /* Only 3f00 provided */ apdu.p1 = 0; break; } path += 2; pathlen -= 2; } /* Optimization based on the normal Portuguese eID usage pattern: * paths with len >= 4 shall be stripped - this avoids unnecessary * "file not found" errors. Other cards may benefit from this also. * * This works perfectly for the Portuguese eID card, but if you * are adapting this driver to another card, "false positives" may * occur depending, of course, on the file structure of the card. * * Please have this in mind if adapting this driver to another card. */ if (pathlen >= 4) { stripped_len = pathlen - 2; path += stripped_len; pathlen = 2; } else if (pathlen == 2) { apdu.p1 = 0; } break; case SC_PATH_TYPE_FROM_CURRENT: apdu.p1 = 9; break; case SC_PATH_TYPE_PARENT: apdu.p1 = 3; apdu.p2 = 0x0C; pathlen = 0; apdu.cse = SC_APDU_CASE_2_SHORT; break; default: SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_INVALID_ARGUMENTS); } apdu.lc = pathlen; apdu.data = path; apdu.datalen = pathlen; if (file_out != NULL) { apdu.resp = buf; apdu.resplen = sizeof(buf); apdu.le = 256; } else { apdu.p2 = 0x0C; apdu.cse = (apdu.lc == 0) ? SC_APDU_CASE_1 : SC_APDU_CASE_3_SHORT; } r = sc_transmit_apdu(card, &apdu); SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "APDU transmit failed"); if (file_out == NULL) { if (apdu.sw1 == 0x61) SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, 0); SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, sc_check_sw(card, apdu.sw1, apdu.sw2)); } /* A "file not found" error was received, this can mean two things: * 1) the file does not exist * 2) the current DF may be incorrect due to the optimization applied * earlier. If the path was previously stripped, select the first DF * and try to re-select the path with the full value. */ if (stripped_len > 0 && apdu.sw1 == 0x6A && apdu.sw2 == 0x82) { sc_path_t tpath; /* Restore original path value */ path -= stripped_len; pathlen += stripped_len; memset(&tpath, 0, sizeof(sc_path_t)); tpath.type = SC_PATH_TYPE_PATH; tpath.len = 2; tpath.value[0] = path[0]; tpath.value[1] = path[1]; /* Go up in the hierarchy to the correct DF */ r = ias_select_file(card, &tpath, NULL); SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "Error selecting parent."); /* We're now in the right place, reconstruct the APDU and retry */ path += 2; pathlen -= 2; apdu.lc = pathlen; apdu.data = path; apdu.datalen = pathlen; if (file_out != NULL) apdu.resplen = sizeof(buf); r = sc_transmit_apdu(card, &apdu); SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "APDU transmit failed"); if (file_out == NULL) { if (apdu.sw1 == 0x61) SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, 0); SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, sc_check_sw(card, apdu.sw1, apdu.sw2)); } } r = sc_check_sw(card, apdu.sw1, apdu.sw2); if (r) SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r); if (apdu.resplen < 2) SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_UNKNOWN_DATA_RECEIVED); switch (apdu.resp[0]) { case 0x6F: file = sc_file_new(); if (file == NULL) SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_OUT_OF_MEMORY); file->path = *in_path; if (card->ops->process_fci == NULL) { sc_file_free(file); SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_NOT_SUPPORTED); } if ((size_t)apdu.resp[1] + 2 <= apdu.resplen) card->ops->process_fci(card, file, apdu.resp+2, apdu.resp[1]); *file_out = file; break; case 0x00: /* proprietary coding */ SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_UNKNOWN_DATA_RECEIVED); default: SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_UNKNOWN_DATA_RECEIVED); } return SC_SUCCESS; }
static int sc_pkcs15emu_gemsafeV1_init( sc_pkcs15_card_t *p15card) { int r; unsigned int i; struct sc_path path; struct sc_file *file = NULL; struct sc_card *card = p15card->card; struct sc_apdu apdu; u8 rbuf[SC_MAX_APDU_BUFFER_SIZE]; sc_debug(p15card->card->ctx, SC_LOG_DEBUG_NORMAL, "Setting pkcs15 parameters\n"); if (p15card->tokeninfo->label) free(p15card->tokeninfo->label); p15card->tokeninfo->label = malloc(strlen(APPLET_NAME) + 1); if (!p15card->tokeninfo->label) return SC_ERROR_INTERNAL; strcpy(p15card->tokeninfo->label, APPLET_NAME); if (p15card->tokeninfo->serial_number) free(p15card->tokeninfo->serial_number); p15card->tokeninfo->serial_number = malloc(strlen(DRIVER_SERIAL_NUMBER) + 1); if (!p15card->tokeninfo->serial_number) return SC_ERROR_INTERNAL; strcpy(p15card->tokeninfo->serial_number, DRIVER_SERIAL_NUMBER); /* the GemSAFE applet version number */ sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xca, 0xdf, 0x03); apdu.cla = 0x80; apdu.resp = rbuf; apdu.resplen = sizeof(rbuf); /* Manual says Le=0x05, but should be 0x08 to return full version numer */ apdu.le = 0x08; apdu.lc = 0; apdu.datalen = 0; r = sc_transmit_apdu(card, &apdu); SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "APDU transmit failed"); if (apdu.sw1 != 0x90 || apdu.sw2 != 0x00) return SC_ERROR_INTERNAL; if (r != SC_SUCCESS) return SC_ERROR_INTERNAL; /* the manufacturer ID, in this case GemPlus */ if (p15card->tokeninfo->manufacturer_id) free(p15card->tokeninfo->manufacturer_id); p15card->tokeninfo->manufacturer_id = malloc(strlen(MANU_ID) + 1); if (!p15card->tokeninfo->manufacturer_id) return SC_ERROR_INTERNAL; strcpy(p15card->tokeninfo->manufacturer_id, MANU_ID); /* determine allocated key containers and length of certificates */ r = gemsafe_get_cert_len(card); if (r != SC_SUCCESS) return SC_ERROR_INTERNAL; /* set certs */ sc_debug(p15card->card->ctx, SC_LOG_DEBUG_NORMAL, "Setting certificates\n"); for (i = 0; i < gemsafe_cert_max; i++) { struct sc_pkcs15_id p15Id; struct sc_path path; if (gemsafe_cert[i].label == NULL) continue; sc_format_path(gemsafe_cert[i].path, &path); sc_pkcs15_format_id(gemsafe_cert[i].id, &p15Id); path.index = gemsafe_cert[i].index; path.count = gemsafe_cert[i].count; sc_pkcs15emu_add_cert(p15card, SC_PKCS15_TYPE_CERT_X509, gemsafe_cert[i].authority, &path, &p15Id, gemsafe_cert[i].label, gemsafe_cert[i].obj_flags); } /* set gemsafe_pin */ sc_debug(p15card->card->ctx, SC_LOG_DEBUG_NORMAL, "Setting PIN\n"); for (i=0; i < gemsafe_pin_max; i++) { struct sc_pkcs15_id p15Id; struct sc_path path; sc_pkcs15_format_id(gemsafe_pin[i].id, &p15Id); sc_format_path(gemsafe_pin[i].path, &path); if (gemsafe_pin[i].atr_len == 0 || (gemsafe_pin[i].atr_len == p15card->card->atr.len && memcmp(p15card->card->atr.value, gemsafe_pin[i].atr, p15card->card->atr.len) == 0)) { sc_pkcs15emu_add_pin(p15card, &p15Id, gemsafe_pin[i].label, &path, gemsafe_pin[i].ref, gemsafe_pin[i].type, gemsafe_pin[i].minlen, gemsafe_pin[i].maxlen, gemsafe_pin[i].flags, gemsafe_pin[i].tries_left, gemsafe_pin[i].pad_char, gemsafe_pin[i].obj_flags); break; } }; /* set private keys */ sc_debug(p15card->card->ctx, SC_LOG_DEBUG_NORMAL, "Setting private keys\n"); for (i = 0; i < gemsafe_cert_max; i++) { struct sc_pkcs15_id p15Id, authId, *pauthId; struct sc_path path; int key_ref = 0x03; if (gemsafe_prkeys[i].label == NULL) continue; sc_pkcs15_format_id(gemsafe_prkeys[i].id, &p15Id); if (gemsafe_prkeys[i].auth_id) { sc_pkcs15_format_id(gemsafe_prkeys[i].auth_id, &authId); pauthId = &authId; } else pauthId = NULL; sc_format_path(gemsafe_prkeys[i].path, &path); /* * The key ref may be different for different sites; * by adding flags=n where the low order 4 bits can be * the key ref we can force it. */ if ( p15card->card->flags & 0x0F) { key_ref = p15card->card->flags & 0x0F; sc_debug(p15card->card->ctx, SC_LOG_DEBUG_NORMAL, "Overriding key_ref %d with %d\n", gemsafe_prkeys[i].ref, key_ref); } else key_ref = gemsafe_prkeys[i].ref; sc_pkcs15emu_add_prkey(p15card, &p15Id, gemsafe_prkeys[i].label, SC_PKCS15_TYPE_PRKEY_RSA, gemsafe_prkeys[i].modulus_len, gemsafe_prkeys[i].usage, &path, key_ref, pauthId, gemsafe_prkeys[i].obj_flags); } /* select the application DF */ sc_debug(p15card->card->ctx, SC_LOG_DEBUG_NORMAL,"Selecting application DF\n"); sc_format_path(GEMSAFE_APP_PATH, &path); r = sc_select_file(card, &path, &file); if (r != SC_SUCCESS || !file) return SC_ERROR_INTERNAL; /* set the application DF */ if (p15card->file_app) free(p15card->file_app); p15card->file_app = file; return SC_SUCCESS; }
/* * @brief Generate a private key on the card. */ static int isoApplet_ctl_generate_key(sc_card_t *card, sc_cardctl_isoApplet_genkey_t *args) { int r; sc_apdu_t apdu; u8 rbuf[SC_MAX_EXT_APDU_BUFFER_SIZE]; u8 sbuf[SC_MAX_EXT_APDU_BUFFER_SIZE]; u8 *p; const u8 *inner_tag_value; const u8 *outer_tag_value; unsigned int tag; size_t outer_tag_len; size_t inner_tag_len; unsigned int cla; LOG_FUNC_CALLED(card->ctx); /* MANAGE SECURITY ENVIRONMENT (SET). Set the algorithm and key references. */ sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x22, 0x41, 0x00); p = sbuf; *p++ = 0x80; /* algorithm reference */ *p++ = 0x01; *p++ = args->algorithm_ref; *p++ = 0x84; /* Private key reference */ *p++ = 0x01; *p++ = args->priv_key_ref; r = p - sbuf; p = NULL; apdu.lc = r; apdu.datalen = r; apdu.data = sbuf; r = sc_transmit_apdu(card, &apdu); LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); r = sc_check_sw(card, apdu.sw1, apdu.sw2); LOG_TEST_RET(card->ctx, r, "Card returned error"); /* GENERATE ASYMMETRIC KEY PAIR * We use a larger buffer here, even if the card does not support extended apdus. * There are two cases: * 1) The card can do ext. apdus: The data fits in one apdu. * 2) The card can't do ext. apdus: sc_transmit_apdu will handle that - the * card will send SW_BYTES_REMAINING, OpenSC will automaticall do a * GET RESPONSE to get the remaining data, and will append it to the data * buffer. */ if(args->algorithm_ref == SC_ISOAPPLET_ALG_REF_EC_GEN) { sc_format_apdu(card, &apdu, SC_APDU_CASE_4, 0x46, 0x00, 0x00); apdu.data = sbuf; p = sbuf; r = isoApplet_put_ec_params(card, &args->pubkey.ec.params, p, sizeof(sbuf), &p); LOG_TEST_RET(card->ctx, r, "Error composing EC params."); apdu.datalen = p - sbuf; apdu.lc = p - sbuf; /* Use APDU chaining if the card does not support extended apdus * and the data does not fit in one short apdu. */ if ((apdu.datalen > 255) && !(card->caps & SC_CARD_CAP_APDU_EXT)) { apdu.flags |= SC_APDU_FLAGS_CHAINING; } } else { sc_format_apdu(card, &apdu, SC_APDU_CASE_2, 0x46, 0x42, 0x00); } apdu.resp = rbuf; apdu.resplen = sizeof(rbuf); apdu.le = 256; r = sc_transmit_apdu(card, &apdu); LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); r = sc_check_sw(card, apdu.sw1, apdu.sw2); if(apdu.sw1 == 0x6A && apdu.sw2 == 0x81) { sc_log(card->ctx, "Key generation not supported by the card with that particular key type. " "Your card may not support the specified algorithm used by the applet / specified by you. " "In most cases, this happens when trying to generate EC keys not supported by your java card. " "In this case, look for supported field lengths and whether FP and/or F2M are supported."); } LOG_TEST_RET(card->ctx, r, "Card returned error"); /* Parse the public key / response. */ outer_tag_value = apdu.resp; r = sc_asn1_read_tag(&outer_tag_value, apdu.resplen, &cla, &tag, &outer_tag_len); LOG_TEST_RET(card->ctx, r, "Error in ASN1 handling."); /* Interindustry template for nesting one set of public key data objects */ if((tag != 0x1F49) || (cla != 0x60)) { LOG_TEST_RET(card->ctx, SC_ERROR_INVALID_DATA, "The data returned by the card is unexpected."); } switch(args->algorithm_ref) { case SC_ISOAPPLET_ALG_REF_RSA_GEN_2048: /* Search for the modulus tag (81). */ inner_tag_value = sc_asn1_find_tag(card->ctx, outer_tag_value, outer_tag_len, (unsigned int) 0x81, &inner_tag_len); if(inner_tag_value == NULL || inner_tag_len != 256) { LOG_TEST_RET(card->ctx, SC_ERROR_INVALID_DATA, "Card returned no or a invalid modulus."); } if(inner_tag_len > args->pubkey.rsa.modulus.len) { LOG_FUNC_RETURN(card->ctx, SC_ERROR_BUFFER_TOO_SMALL); } memcpy(args->pubkey.rsa.modulus.value, inner_tag_value, inner_tag_len); args->pubkey.rsa.modulus.len = inner_tag_len; /* Exponent tag (82) */ inner_tag_value = sc_asn1_find_tag(card->ctx, outer_tag_value, outer_tag_len, (unsigned int) 0x82, &inner_tag_len); if(inner_tag_value == NULL || inner_tag_len != 3) { LOG_TEST_RET(card->ctx, SC_ERROR_INVALID_DATA, "Card returned no or a invalid exponent."); } if(inner_tag_len > args->pubkey.rsa.exponent.len) { LOG_FUNC_RETURN(card->ctx, SC_ERROR_BUFFER_TOO_SMALL); } if(memcmp(inner_tag_value, "\x01\x00\x01", 3) != 0) { LOG_TEST_RET(card->ctx, SC_ERROR_INCOMPATIBLE_KEY, "Key generation error: Unexpected public key exponent."); } memcpy(args->pubkey.rsa.exponent.value, inner_tag_value, inner_tag_len); args->pubkey.rsa.exponent.len = inner_tag_len; p = NULL; break; case SC_ISOAPPLET_ALG_REF_EC_GEN: /* Compare the parameters received from the card to the ones sent to the card. */ inner_tag_value = sc_asn1_find_tag(card->ctx, outer_tag_value, outer_tag_len, (unsigned int) 0x81, &inner_tag_len); if(inner_tag_value == NULL || inner_tag_len != args->pubkey.ec.params.prime.len || memcmp(inner_tag_value, args->pubkey.ec.params.prime.value, inner_tag_len) != 0) LOG_TEST_RET(card->ctx, SC_ERROR_INVALID_DATA, "Card returned no or a invalid prime."); inner_tag_value = sc_asn1_find_tag(card->ctx, outer_tag_value, outer_tag_len, (unsigned int) 0x82, &inner_tag_len); if(inner_tag_value == NULL || inner_tag_len != args->pubkey.ec.params.coefficientA.len || memcmp(inner_tag_value, args->pubkey.ec.params.coefficientA.value, inner_tag_len) != 0) LOG_TEST_RET(card->ctx, SC_ERROR_INVALID_DATA, "Card returned no or a invalid coefficient A."); inner_tag_value = sc_asn1_find_tag(card->ctx, outer_tag_value, outer_tag_len, (unsigned int) 0x83, &inner_tag_len); if(inner_tag_value == NULL || inner_tag_len != args->pubkey.ec.params.coefficientB.len || memcmp(inner_tag_value, args->pubkey.ec.params.coefficientB.value, inner_tag_len) != 0) LOG_TEST_RET(card->ctx, SC_ERROR_INVALID_DATA, "Card returned no or a invalid coefficient B."); inner_tag_value = sc_asn1_find_tag(card->ctx, outer_tag_value, outer_tag_len, (unsigned int) 0x84, &inner_tag_len); if(inner_tag_value == NULL || inner_tag_len != args->pubkey.ec.params.basePointG.len || memcmp(inner_tag_value, args->pubkey.ec.params.basePointG.value, inner_tag_len) != 0) LOG_TEST_RET(card->ctx, SC_ERROR_INVALID_DATA, "Card returned no or a invalid base point G."); inner_tag_value = sc_asn1_find_tag(card->ctx, outer_tag_value, outer_tag_len, (unsigned int) 0x85, &inner_tag_len); if(inner_tag_value == NULL || inner_tag_len != args->pubkey.ec.params.order.len || memcmp(inner_tag_value, args->pubkey.ec.params.order.value, inner_tag_len) != 0) LOG_TEST_RET(card->ctx, SC_ERROR_INVALID_DATA, "Card returned no or a invalid order."); inner_tag_value = sc_asn1_find_tag(card->ctx, outer_tag_value, outer_tag_len, (unsigned int) 0x87, &inner_tag_len); if(inner_tag_value == NULL || inner_tag_len != args->pubkey.ec.params.coFactor.len || memcmp(inner_tag_value, args->pubkey.ec.params.coFactor.value, inner_tag_len) != 0) LOG_TEST_RET(card->ctx, SC_ERROR_INVALID_DATA, "Card returned no or a invalid cofactor."); /* Extract public key */ inner_tag_value = sc_asn1_find_tag(card->ctx, outer_tag_value, outer_tag_len, (unsigned int) 0x86, &inner_tag_len); if(inner_tag_value == NULL || inner_tag_len != args->pubkey.ec.ecPointQ.len) LOG_TEST_RET(card->ctx, SC_ERROR_INVALID_DATA, "Card returned no or a invalid EC point Q."); memcpy(args->pubkey.ec.ecPointQ.value, inner_tag_value, inner_tag_len); break; default: LOG_TEST_RET(card->ctx, SC_ERROR_NOT_SUPPORTED, "Unable to parse public key: Unsupported algorithm."); }/* switch */ LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); }
static int get_language(sc_card_t *card) { sc_apdu_t apdu; u8 prefs[240], *lg_value; u8 path[] = { 0x3F, 0x00, 0xDF, 0x01, 0x40, 0x39 }; int r, i, len; /* Get the language from the card's preferences file */ assert(card != NULL); sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xA4, 0x08, 0x0C); apdu.lc = sizeof(path); apdu.data = path; apdu.datalen = sizeof(path); apdu.resplen = 0; apdu.le = 0; r = sc_lock(card); if (r < 0) goto prefs_error; r = sc_transmit_apdu(card, &apdu); if (r < 0) { sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "Select_File[prefs_file] command failed: %d\n", r); sc_unlock(card); goto prefs_error; } r = sc_check_sw(card, apdu.sw1, apdu.sw2); if (r < 0) { sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "Select_File[prefs_file]: card returned %d\n", r); sc_unlock(card); goto prefs_error; } r = iso_ops->read_binary(card, 0, prefs, sizeof(prefs), 0); sc_unlock(card); if (r <= 0) { sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "Read_Binary[prefs_file] returned %d\n", r); goto prefs_error; } #if 0 dumphex("Prefs: ", prefs, r); #endif i = get_pref(prefs, r, "[gen]", "lg", &len); if (i <= 0 || len < 2) { sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "Couldn't find language in prefs file: %d\n", i); goto prefs_error; } lg_value = prefs + i; /* language code(s) found, starts here */ i = 0; while (1) { while (i <= len - 2 && (lg_value[i] == ' ' || lg_value[i] == '|')) i++; if (i > len - 2) goto prefs_error; r = str2lang(card->ctx, lg_value + i); if (r >= 0) return r; i += 2; } prefs_error: /* If troubles with the card's prefs file, get the language from the OS */ #ifdef _WIN32 switch (GetUserDefaultLangID() & 0x00FF) { case 0x13: return LNG_DUTCH; case 0x0C: return LNG_FRENCH; case 0x07: return LNG_GERMAN; default: return LNG_ENG; } #endif return LNG_ENG; /* default */ }
static int mcrd_init(sc_card_t * card) { unsigned long flags; struct mcrd_priv_data *priv; int r; sc_path_t tmppath; sc_apdu_t apdu; priv = calloc(1, sizeof *priv); if (!priv) return SC_ERROR_OUT_OF_MEMORY; card->drv_data = priv; card->cla = 0x00; card->caps = SC_CARD_CAP_RNG; if (is_esteid_card(card)) { /* Reset the MULTOS card to get to a known state */ if (card->type == SC_CARD_TYPE_MCRD_ESTEID_V11) sc_reset(card, 0); /* Select the EstEID AID to get to a known state. * For some reason a reset is required as well... */ if (card->type == SC_CARD_TYPE_MCRD_ESTEID_V30) { flags = SC_ALGORITHM_RSA_RAW | SC_ALGORITHM_RSA_HASH_SHA1 | SC_ALGORITHM_RSA_PAD_PKCS1 | SC_ALGORITHM_RSA_HASH_SHA256; /* EstEID v3.0 has 2048 bit keys */ _sc_card_add_rsa_alg(card, 2048, flags, 0); sc_reset(card, 0); sc_format_apdu(card, &apdu, SC_APDU_CASE_3, 0xA4, 0x04, 0x00); apdu.lc = sizeof(EstEID_v3_AID); apdu.data = EstEID_v3_AID; apdu.datalen = sizeof(EstEID_v3_AID); apdu.resplen = 0; apdu.le = 0; r = sc_transmit_apdu(card, &apdu); SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "APDU transmit failed"); sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "SELECT AID: %02X%02X", apdu.sw1, apdu.sw2); if(apdu.sw1 != 0x90 && apdu.sw2 != 0x00) { sc_format_apdu(card, &apdu, SC_APDU_CASE_3, 0xA4, 0x04, 0x00); apdu.lc = sizeof(EstEID_v35_AID); apdu.data = EstEID_v35_AID; apdu.datalen = sizeof(EstEID_v35_AID); apdu.resplen = 0; apdu.le = 0; r = sc_transmit_apdu(card, &apdu); SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "APDU transmit failed"); sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "SELECT AID: %02X%02X", apdu.sw1, apdu.sw2); if (apdu.sw1 != 0x90 && apdu.sw2 != 0x00) { sc_format_apdu(card, &apdu, SC_APDU_CASE_3, 0xA4, 0x04, 0x00); apdu.lc = sizeof(AzeDIT_v35_AID); apdu.data = AzeDIT_v35_AID; apdu.datalen = sizeof(AzeDIT_v35_AID); apdu.resplen = 0; apdu.le = 0; r = sc_transmit_apdu(card, &apdu); SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "APDU transmit failed"); sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "SELECT AID: %02X%02X", apdu.sw1, apdu.sw2); if (apdu.sw1 != 0x90 && apdu.sw2 != 0x00) SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_CARD_CMD_FAILED); } } } else { /* EstEID v1.0 and 1.1 have 1024 bit keys */ flags = SC_ALGORITHM_RSA_RAW | SC_ALGORITHM_RSA_PAD_PKCS1 | SC_ALGORITHM_RSA_HASH_SHA1; _sc_card_add_rsa_alg(card, 1024, flags, 0); } } else { flags = SC_ALGORITHM_RSA_RAW |SC_ALGORITHM_RSA_PAD_PKCS1 | SC_ALGORITHM_RSA_HASH_NONE; _sc_card_add_rsa_alg(card, 512, flags, 0); _sc_card_add_rsa_alg(card, 768, flags, 0); _sc_card_add_rsa_alg(card, 1024, flags, 0); } priv->curpath[0] = MFID; priv->curpathlen = 1; sc_format_path ("3f00", &tmppath); r = sc_select_file (card, &tmppath, NULL); /* Not needed for the fixed EstEID profile */ if (!is_esteid_card(card)) load_special_files(card); return r; }
/** atrust_acos_set_security_env * sets the security enviroment * \param card pointer to the sc_card object * \param env pointer to a sc_security_env object * \param se_num not used here * \return SC_SUCCESS on success or an error code * * This function sets the security enviroment (using the * command MANAGE SECURITY ENVIROMENT). In case a COMPUTE SIGNATURE * operation is requested , this function tries to detect whether * COMPUTE SIGNATURE or INTERNAL AUTHENTICATE must be used for signature * calculation. */ static int atrust_acos_set_security_env(struct sc_card *card, const struct sc_security_env *env, int se_num) { u8 *p, *pp, keyID; int r, operation = env->operation; struct sc_apdu apdu; u8 sbuf[SC_MAX_APDU_BUFFER_SIZE]; atrust_acos_ex_data *ex_data = (atrust_acos_ex_data *)card->drv_data; p = sbuf; keyID = env->key_ref[0]; /* copy key reference, if present */ if (env->flags & SC_SEC_ENV_KEY_REF_PRESENT) { if (env->flags & SC_SEC_ENV_KEY_REF_ASYMMETRIC) *p++ = 0x83; else *p++ = 0x84; *p++ = env->key_ref_len; memcpy(p, env->key_ref, env->key_ref_len); p += env->key_ref_len; } pp = p; if (operation == SC_SEC_OPERATION_DECIPHER){ if (env->algorithm_flags & SC_ALGORITHM_RSA_PAD_PKCS1) { *p++ = 0x80; *p++ = 0x01; *p++ = 0x02; } else return SC_ERROR_INVALID_ARGUMENTS; sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x22, 0x81, 0xb8); apdu.data = sbuf; apdu.datalen = p - sbuf; apdu.lc = p - sbuf; apdu.le = 0; r = sc_transmit_apdu(card, &apdu); SC_TEST_RET(card->ctx, r, "APDU transmit failed"); if (apdu.sw1 != 0x90 || apdu.sw2 != 0x00) SC_FUNC_RETURN(card->ctx, 4, sc_check_sw(card, apdu.sw1, apdu.sw2)); return SC_SUCCESS; } /* try COMPUTE SIGNATURE */ if (operation == SC_SEC_OPERATION_SIGN && ( env->algorithm_flags & SC_ALGORITHM_RSA_PAD_PKCS1 || env->algorithm_flags & SC_ALGORITHM_RSA_PAD_ISO9796)) { if (env->flags & SC_SEC_ENV_ALG_REF_PRESENT) { *p++ = 0x80; *p++ = 0x01; *p++ = env->algorithm_ref & 0xFF; } else if (env->flags & SC_SEC_ENV_ALG_PRESENT && env->algorithm == SC_ALGORITHM_RSA) { /* set the method to use based on the algorithm_flags */ *p++ = 0x80; *p++ = 0x01; if (env->algorithm_flags & SC_ALGORITHM_RSA_PAD_PKCS1) { if (env->algorithm_flags & SC_ALGORITHM_RSA_HASH_SHA1) *p++ = 0x12; else if (env->algorithm_flags & SC_ALGORITHM_RSA_HASH_RIPEMD160) *p++ = 0x22; else if (env->algorithm_flags & SC_ALGORITHM_RSA_HASH_MD5) *p++ = 0x32; else { /* can't use COMPUTE SIGNATURE => * try INTERNAL AUTHENTICATE */ p = pp; operation = SC_SEC_OPERATION_AUTHENTICATE; goto try_authenticate; } } else if (env->algorithm_flags & SC_ALGORITHM_RSA_PAD_ISO9796) { if (env->algorithm_flags & SC_ALGORITHM_RSA_HASH_SHA1) *p++ = 0x11; else if (env->algorithm_flags & SC_ALGORITHM_RSA_HASH_RIPEMD160) *p++ = 0x21; else return SC_ERROR_INVALID_ARGUMENTS; } else return SC_ERROR_INVALID_ARGUMENTS; } sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x22, 0x41, 0xb6); apdu.data = sbuf; apdu.datalen = p - sbuf; apdu.lc = p - sbuf; apdu.le = 0; /* suppress errors, as don't know whether to use * COMPUTE SIGNATURE or INTERNAL AUTHENTICATE */ sc_ctx_suppress_errors_on(card->ctx); r = sc_transmit_apdu(card, &apdu); sc_ctx_suppress_errors_off(card->ctx); SC_TEST_RET(card->ctx, r, "APDU transmit failed"); if (apdu.sw1 == 0x90 && apdu.sw2 == 0x00) { ex_data->fix_digestInfo = 0; ex_data->sec_ops = SC_SEC_OPERATION_SIGN; return SC_SUCCESS; } /* reset pointer */ p = pp; /* doesn't work => try next op */ operation = SC_SEC_OPERATION_AUTHENTICATE; } try_authenticate: /* try INTERNAL AUTHENTICATE */ if (operation == SC_SEC_OPERATION_AUTHENTICATE && env->algorithm_flags & SC_ALGORITHM_RSA_PAD_PKCS1) { *p++ = 0x80; *p++ = 0x01; *p++ = 0x01; sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x22, 0x41, 0xa4); apdu.data = sbuf; apdu.datalen = p - sbuf; apdu.lc = p - sbuf; apdu.le = 0; r = sc_transmit_apdu(card, &apdu); SC_TEST_RET(card->ctx, r, "APDU transmit failed"); if (apdu.sw1 != 0x90 || apdu.sw2 != 0x00) SC_FUNC_RETURN(card->ctx, 4, sc_check_sw(card, apdu.sw1, apdu.sw2)); ex_data->fix_digestInfo = env->algorithm_flags; ex_data->sec_ops = SC_SEC_OPERATION_AUTHENTICATE; return SC_SUCCESS; } return SC_ERROR_INVALID_ARGUMENTS; }
/* * @brief Import a private key. */ static int isoApplet_ctl_import_key(sc_card_t *card, sc_cardctl_isoApplet_import_key_t *args) { int r; sc_apdu_t apdu; u8 sbuf[SC_MAX_APDU_BUFFER_SIZE]; u8 *p; LOG_FUNC_CALLED(card->ctx); /* * Private keys are not stored in the filesystem. * ISO 7816-8 - section C.2 describes: * "Usage of the PUT DATA command for private key import" * The applet uses this PUT DATA to import private keys, if private key import is allowed. * * The first step is to perform a MANAGE SECURITY ENVIRONMENT as it would be done * with on-card key generation. The second step is PUT DATA (instead of * GENERATE ASYMMETRIC KEYPAIR). */ /* MANAGE SECURITY ENVIRONMENT (SET). Set the algorithm and key references. */ sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x22, 0x41, 0x00); p = sbuf; *p++ = 0x80; /* algorithm reference */ *p++ = 0x01; *p++ = args->algorithm_ref; *p++ = 0x84; /* Private key reference */ *p++ = 0x01; *p++ = args->priv_key_ref; r = p - sbuf; p = NULL; apdu.lc = r; apdu.datalen = r; apdu.data = sbuf; r = sc_transmit_apdu(card, &apdu); LOG_TEST_RET(card->ctx, r, "%s: APDU transmit failed"); r = sc_check_sw(card, apdu.sw1, apdu.sw2); LOG_TEST_RET(card->ctx, r, "Card returned error"); /* PUT DATA */ switch(args->algorithm_ref) { case SC_ISOAPPLET_ALG_REF_RSA_GEN_2048: r = isoApplet_put_data_prkey_rsa(card, args); LOG_TEST_RET(card->ctx, r, "Error in PUT DATA."); break; case SC_ISOAPPLET_ALG_REF_EC_GEN: r = isoApplet_put_data_prkey_ec(card, args); LOG_TEST_RET(card->ctx, r, "Error in PUT DATA."); break; default: LOG_TEST_RET(card->ctx, SC_ERROR_NOT_SUPPORTED, "Uknown algorithm refernce."); } LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); }
/* * @brief Use PUT DATA to import a private EC key. * * Format of transmitted data: * 0xE0 - Private class, constructed encoding, number one. * 0x81 - prime * 0x82 - coefficient A * 0x83 - coefficient B * 0x84 - base point G * 0x85 - order * 0x87 - cofactor * 0x88 - private D (private key) * * @param card * @param ec The EC private key to import. * * @return SC_ERROR_INVALID_ARGUMENTS: Curve parameters or private component is missing. * other errors: Transmit errors / errors returned by card. * ASN1 errors. */ static int isoApplet_put_data_prkey_ec(sc_card_t *card, sc_cardctl_isoApplet_import_key_t *args) { sc_apdu_t apdu; u8 sbuf[SC_MAX_EXT_APDU_BUFFER_SIZE]; int r; u8 *p; size_t tags_len; LOG_FUNC_CALLED(card->ctx); if(!args->privkey.ec.privateD.value || !args->privkey.ec.params.prime.value || !args->privkey.ec.params.coefficientA.value || !args->privkey.ec.params.coefficientB.value || !args->privkey.ec.params.basePointG.value || !args->privkey.ec.params.order.value || !args->privkey.ec.params.coFactor.value ) { LOG_TEST_RET(card->ctx, SC_ERROR_INVALID_ARGUMENTS, "Missing information about EC private key."); } /* Calculate the length of all inner tag-length-value entries, but do not write anything yet. */ tags_len = 0; r = sc_asn1_put_tag(0x81, NULL, args->privkey.ec.params.prime.len, NULL, 0, NULL); LOG_TEST_RET(card->ctx, r, "Error handling TLV."); tags_len += r; r = sc_asn1_put_tag(0x82, NULL, args->privkey.ec.params.coefficientA.len, NULL, 0, NULL); LOG_TEST_RET(card->ctx, r, "Error handling TLV."); tags_len += r; r = sc_asn1_put_tag(0x83, NULL, args->privkey.ec.params.coefficientB.len, NULL, 0, NULL); LOG_TEST_RET(card->ctx, r, "Error handling TLV."); tags_len += r; r = sc_asn1_put_tag(0x84, NULL, args->privkey.ec.params.basePointG.len, NULL, 0, NULL); LOG_TEST_RET(card->ctx, r, "Error handling TLV."); tags_len += r; r = sc_asn1_put_tag(0x85, NULL, args->privkey.ec.params.order.len, NULL, 0, NULL); LOG_TEST_RET(card->ctx, r, "Error handling TLV."); tags_len += r; r = sc_asn1_put_tag(0x87, NULL, args->privkey.ec.params.coFactor.len, NULL, 0, NULL); LOG_TEST_RET(card->ctx, r, "Error handling TLV."); tags_len += r; r = sc_asn1_put_tag(0x88, NULL, args->privkey.ec.privateD.len, NULL, 0, NULL); LOG_TEST_RET(card->ctx, r, "Error handling TLV."); tags_len += r; /* Write the outer tag and length information. */ p = sbuf; r = sc_asn1_put_tag(0xE0, NULL, tags_len, p, sizeof(sbuf), &p); LOG_TEST_RET(card->ctx, r, "Error handling TLV."); /* Write inner tags. */ r = isoApplet_put_ec_params(card, &args->privkey.ec.params, p, sizeof(sbuf) - (p - sbuf), &p); if(r < 0) { sc_log(card->ctx, "Error composing EC params."); goto out; } r = sc_asn1_put_tag(0x88, args->privkey.ec.privateD.value, args->privkey.ec.privateD.len, p, sizeof(sbuf) - (p - sbuf), &p); if(r < 0) goto out; /* Send to card. */ sc_format_apdu(card, &apdu, SC_APDU_CASE_3, 0xDB, 0x3F, 0xFF); apdu.lc = p - sbuf; apdu.datalen = p - sbuf; apdu.data = sbuf; r = sc_transmit_apdu(card, &apdu); if(r < 0) { sc_log(card->ctx, "APDU transmit failed"); goto out; } r = sc_check_sw(card, apdu.sw1, apdu.sw2); if(apdu.sw1 == 0x6D && apdu.sw2 == 0x00) { sc_log(card->ctx, "The applet returned that the PUT DATA instruction byte is not supported. " "If you are using an older applet version and are trying to import keys, please update your applet first."); } else if(apdu.sw1 == 0x6A && apdu.sw2 == 0x81) { sc_log(card->ctx, "Key import not supported by the card with that particular key type. " "Your card may not support the specified algorithm used by the applet / specified by you. " "In most cases, this happens when trying to import EC keys not supported by your java card. " "In this case, look for supported field lengths and whether FP and/or F2M are supported. " "If you tried to import a private RSA key, check the key length."); } else if(apdu.sw1 == 0x69 && apdu.sw2 == 0x00) { sc_log(card->ctx, "Key import not allowed by the applet's security policy. " "If you want to allow key import, set DEF_PRIVATE_KEY_IMPORT_ALLOWED in the IsoApplet," " rebuild and reinstall the applet."); } if(r < 0) { sc_log(card->ctx, "Card returned error"); goto out; } r = SC_SUCCESS; out: sc_mem_clear(sbuf, sizeof(sbuf)); LOG_FUNC_RETURN(card->ctx, r); }
/* * @brief Use PUT DATA to import a private RSA key. * * For simplicity, command chaining has to be used. One chunk (apdu) must contain * one RSA field (P, Q, etc.). The first apdu must contain the outer tag (7F48). * * @param card * @param rsa The RSA private key to import. * * @return SC_ERROR_INVALID_ARGUMENTS: The RSA key does not contain CRT fields. * other errors: Transmit errors / errors returned by card. */ static int isoApplet_put_data_prkey_rsa(sc_card_t *card, sc_cardctl_isoApplet_import_key_t *args) { sc_apdu_t apdu; u8 sbuf[SC_MAX_EXT_APDU_BUFFER_SIZE]; u8 *p = NULL; int r; size_t tags_len; LOG_FUNC_CALLED(card->ctx); if(!args->privkey.rsa.p.value || !args->privkey.rsa.q.value || !args->privkey.rsa.iqmp.value || !args->privkey.rsa.dmp1.value || !args->privkey.rsa.dmq1.value) { LOG_TEST_RET(card->ctx, SC_ERROR_INVALID_ARGUMENTS, "RSA key is missing information."); } /* Note: The format is according to ISO 2-byte tag 7F48 * "T-L pair to indicate a private key data object" */ /* Calculate the length of all inner tag-length-value entries, but do not write anything yet. */ tags_len = 0; r = sc_asn1_put_tag(0x92, NULL, args->privkey.rsa.p.len, NULL, 0, NULL); LOG_TEST_RET(card->ctx, r, "Error handling TLV."); tags_len += r; r = sc_asn1_put_tag(0x93, NULL, args->privkey.rsa.q.len, NULL, 0, NULL); LOG_TEST_RET(card->ctx, r, "Error handling TLV."); tags_len += r; r = sc_asn1_put_tag(0x94, NULL, args->privkey.rsa.iqmp.len, NULL, 0, NULL); LOG_TEST_RET(card->ctx, r, "Error handling TLV."); tags_len += r; r = sc_asn1_put_tag(0x95, NULL, args->privkey.rsa.dmp1.len, NULL, 0, NULL); LOG_TEST_RET(card->ctx, r, "Error handling TLV."); tags_len += r; r = sc_asn1_put_tag(0x96, NULL, args->privkey.rsa.dmq1.len, NULL, 0, NULL); LOG_TEST_RET(card->ctx, r, "Error handling TLV."); tags_len += r; /* Write the outer tag and length information. */ p = sbuf; r = sc_asn1_put_tag(0x7F48, NULL, tags_len, p, sizeof(sbuf), &p); LOG_TEST_RET(card->ctx, r, "Error handling TLV."); /* Write inner tags. */ /* p */ r = sc_asn1_put_tag(0x92, args->privkey.rsa.p.value, args->privkey.rsa.p.len, p, sizeof(sbuf) - (p - sbuf), &p); if(r < 0) goto out; /* q */ r = sc_asn1_put_tag(0x93, args->privkey.rsa.q.value, args->privkey.rsa.q.len, p, sizeof(sbuf) - (p - sbuf), &p); if(r < 0) goto out; /* 1/q mod p */ r = sc_asn1_put_tag(0x94, args->privkey.rsa.iqmp.value, args->privkey.rsa.iqmp.len, p, sizeof(sbuf) - (p - sbuf), &p); if(r < 0) goto out; /* d mod (p-1) */ r = sc_asn1_put_tag(0x95, args->privkey.rsa.dmp1.value, args->privkey.rsa.dmp1.len, p, sizeof(sbuf) - (p - sbuf), &p); if(r < 0) goto out; /* d mod (q-1) */ r = sc_asn1_put_tag(0x96, args->privkey.rsa.dmq1.value, args->privkey.rsa.dmq1.len, p, sizeof(sbuf) - (p - sbuf), &p); if(r < 0) goto out; /* Send to card, using chaining or extended APDUs. */ sc_format_apdu(card, &apdu, SC_APDU_CASE_3, 0xDB, 0x3F, 0xFF); apdu.data = sbuf; apdu.datalen = p - sbuf; apdu.lc = p - sbuf; if ((card->caps & SC_CARD_CAP_APDU_EXT) == 0) { /* The lower layers will automatically do chaining */ apdu.flags |= SC_APDU_FLAGS_CHAINING; } r = sc_transmit_apdu(card, &apdu); if(r < 0) goto out; r = sc_check_sw(card, apdu.sw1, apdu.sw2); if(apdu.sw1 == 0x6A && apdu.sw2 == 0x81) { sc_log(card->ctx, "Key import not supported by the card with that particular key type. " "Your card may not support the specified algorithm used by the applet / specified by you. " "In most cases, this happens when trying to import EC keys not supported by your java card. " "In this case, look for supported field lengths and whether FP and/or F2M are supported. " "If you tried to import a private RSA key, check the key length."); } if(apdu.sw1 == 0x69 && apdu.sw2 == 0x00) { sc_log(card->ctx, "Key import not allowed by the applet's security policy. " "If you want to allow key import, set DEF_PRIVATE_KEY_IMPORT_ALLOWED in the IsoApplet," " rebuild and reinstall the applet."); } if(r < 0) goto out; r = SC_SUCCESS; out: sc_mem_clear(sbuf, sizeof(sbuf)); LOG_FUNC_RETURN(card->ctx, r); }
int iasecc_sm_external_authentication(struct sc_card *card, unsigned skey_ref, int *tries_left) { struct sc_context *ctx = card->ctx; #ifdef ENABLE_SM struct sm_info *sm_info = &card->sm_ctx.info; struct sm_cwa_session *cwa_session = &sm_info->session.cwa; struct sc_remote_data rdata; struct sc_apdu apdu; unsigned char sbuf[0x100]; int rv, offs; LOG_FUNC_CALLED(ctx); sc_log(ctx, "iasecc_sm_external_authentication(): SKey ref %i", skey_ref); if (card->sm_ctx.sm_mode == SM_MODE_NONE) LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "Cannot do 'External Authentication' without SM activated "); strncpy(sm_info->config_section, card->sm_ctx.config_section, sizeof(sm_info->config_section)); sm_info->cmd = SM_CMD_EXTERNAL_AUTH; sm_info->serialnr = card->serialnr; sm_info->card_type = card->type; sm_info->sm_type = SM_TYPE_CWA14890; cwa_session->params.crt_at.usage = IASECC_UQB_AT_EXTERNAL_AUTHENTICATION; cwa_session->params.crt_at.algo = IASECC_ALGORITHM_ROLE_AUTH; cwa_session->params.crt_at.refs[0] = skey_ref; offs = 0; sbuf[offs++] = IASECC_CRT_TAG_ALGO; sbuf[offs++] = 0x01; sbuf[offs++] = IASECC_ALGORITHM_ROLE_AUTH; sbuf[offs++] = IASECC_CRT_TAG_REFERENCE; sbuf[offs++] = 0x01; sbuf[offs++] = skey_ref; sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x22, 0x81, 0xA4); apdu.data = sbuf; apdu.datalen = offs; apdu.lc = offs; rv = sc_transmit_apdu(card, &apdu); LOG_TEST_RET(ctx, rv, "iasecc_sm_external_authentication(): APDU transmit failed"); rv = sc_check_sw(card, apdu.sw1, apdu.sw2); LOG_TEST_RET(ctx, rv, "iasecc_sm_external_authentication(): set SE error"); rv = sc_get_challenge(card, cwa_session->card_challenge, sizeof(cwa_session->card_challenge)); LOG_TEST_RET(ctx, rv, "iasecc_sm_external_authentication(): set SE error"); sc_remote_data_init(&rdata); if (!card->sm_ctx.module.ops.initialize) LOG_TEST_RET(ctx, SC_ERROR_SM_NOT_INITIALIZED, "No SM module"); rv = card->sm_ctx.module.ops.initialize(ctx, sm_info, &rdata); LOG_TEST_RET(ctx, rv, "SM: INITIALIZE failed"); sc_log(ctx, "sm_iasecc_external_authentication(): rdata length %i\n", rdata.length); rv = iasecc_sm_transmit_apdus (card, &rdata, NULL, 0); if (rv == SC_ERROR_PIN_CODE_INCORRECT && tries_left) *tries_left = (rdata.data + rdata.length - 1)->apdu.sw2 & 0x0F; LOG_TEST_RET(ctx, rv, "sm_iasecc_external_authentication(): execute failed"); LOG_FUNC_RETURN(ctx, rv); #else LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "built without support of SM and External Authentication"); return SC_ERROR_NOT_SUPPORTED; #endif }
static int cardos_init(sc_card_t *card) { unsigned long flags, rsa_2048 = 0; size_t data_field_length; sc_apdu_t apdu; u8 rbuf[2]; card->name = "CardOS M4"; card->cla = 0x00; /* Set up algorithm info. */ flags = SC_ALGORITHM_NEED_USAGE | SC_ALGORITHM_RSA_RAW | SC_ALGORITHM_RSA_HASH_NONE | SC_ALGORITHM_ONBOARD_KEY_GEN ; _sc_card_add_rsa_alg(card, 512, flags, 0); _sc_card_add_rsa_alg(card, 768, flags, 0); _sc_card_add_rsa_alg(card, 1024, flags, 0); if (card->type == SC_CARD_TYPE_CARDOS_M4_2) { int r = cardos_have_2048bit_package(card); if (r < 0) return r; if (r == 1) rsa_2048 = 1; card->caps |= SC_CARD_CAP_APDU_EXT; } else if (card->type == SC_CARD_TYPE_CARDOS_M4_3 || card->type == SC_CARD_TYPE_CARDOS_M4_2B || card->type == SC_CARD_TYPE_CARDOS_M4_2C || card->type == SC_CARD_TYPE_CARDOS_M4_4 || card->type == SC_CARD_TYPE_CARDOS_V5_0) { rsa_2048 = 1; card->caps |= SC_CARD_CAP_APDU_EXT; } /* probe DATA FIELD LENGTH with GET DATA */ sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xca, 0x01, 0x8D); apdu.le = sizeof rbuf; apdu.resp = rbuf; apdu.resplen = sizeof(rbuf); SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, sc_transmit_apdu(card, &apdu), "APDU transmit failed"); SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, sc_check_sw(card, apdu.sw1, apdu.sw2), "GET DATA command returned error"); if (apdu.resplen != 2) return SC_ERROR_WRONG_LENGTH; data_field_length = ((rbuf[0] << 8) | rbuf[1]); /* strip the length of possible Lc and Le bytes */ if (card->caps & SC_CARD_CAP_APDU_EXT) card->max_send_size = data_field_length - 6; else card->max_send_size = data_field_length - 3; /* strip the length of SW bytes */ card->max_recv_size = data_field_length - 2; if (rsa_2048 == 1) { _sc_card_add_rsa_alg(card, 1280, flags, 0); _sc_card_add_rsa_alg(card, 1536, flags, 0); _sc_card_add_rsa_alg(card, 1792, flags, 0); _sc_card_add_rsa_alg(card, 2048, flags, 0); } return 0; }
static int ias_set_security_env(sc_card_t *card, const sc_security_env_t *env, int se_num) { int r; sc_apdu_t apdu; u8 sbuf[SC_MAX_APDU_BUFFER_SIZE]; sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "ias_set_security_env, keyRef = 0x%0x, algo = 0x%0x\n", *env->key_ref, env->algorithm_flags); assert(card != NULL && env != NULL); sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x22, 0x41, 0); switch (env->operation) { case SC_SEC_OPERATION_DECIPHER: apdu.p2 = 0xB8; /* confidentiality template */ sbuf[0] = 0x95; /* tag for usage qualifier byte */ sbuf[1] = 0x01; /* tag length */ sbuf[2] = 0x40; /* data decryption */ sbuf[3] = 0x84; /* tag for private key reference */ sbuf[4] = 0x01; /* tag length */ sbuf[5] = *env->key_ref; /* key reference */ sbuf[6] = 0x80; /* tag for algorithm reference */ sbuf[7] = 0x01; /* tag length */ if (env->algorithm_flags & SC_ALGORITHM_RSA_PAD_PKCS1) sbuf[8] = 0x1A; /* RSA PKCS#1 with no data formatting */ else { sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "Set Sec Env: unsupported algo 0X%0X\n", env->algorithm_flags); return SC_ERROR_INVALID_ARGUMENTS; } apdu.lc = 9; apdu.datalen = 9; break; case SC_SEC_OPERATION_SIGN: apdu.p2 = 0xA4; /* authentication template */ sbuf[0] = 0x95; /* tag for usage qualifier byte */ sbuf[1] = 0x01; /* tag length */ sbuf[2] = 0x40; /* internal authentication */ sbuf[3] = 0x84; /* tag for private key reference */ sbuf[4] = 0x01; /* tag length */ sbuf[5] = *env->key_ref; /* key reference */ sbuf[6] = 0x80; /* tag for algorithm reference */ sbuf[7] = 0x01; /* tag length */ if (env->algorithm_flags & SC_ALGORITHM_RSA_PAD_PKCS1) sbuf[8] = 0x02; /* RSA PKCS#1 with no data formatting */ else { sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "Set Sec Env: unsupported algo 0X%0X\n", env->algorithm_flags); return SC_ERROR_INVALID_ARGUMENTS; } apdu.lc = 9; apdu.datalen = 9; break; default: return SC_ERROR_INVALID_ARGUMENTS; } apdu.le = 0; apdu.data = sbuf; apdu.resplen = 0; r = sc_transmit_apdu(card, &apdu); SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "Set Security Env APDU transmit failed"); r = sc_check_sw(card, apdu.sw1, apdu.sw2); SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "Card's Set Security Env command returned error"); return r; }
static int atrust_acos_compute_signature(struct sc_card *card, const u8 * data, size_t datalen, u8 * out, size_t outlen) { int r; struct sc_apdu apdu; u8 rbuf[SC_MAX_APDU_BUFFER_SIZE]; u8 sbuf[SC_MAX_APDU_BUFFER_SIZE]; atrust_acos_ex_data *ex_data = (atrust_acos_ex_data *)card->drv_data; if (datalen > SC_MAX_APDU_BUFFER_SIZE) SC_FUNC_RETURN(card->ctx, 4, SC_ERROR_INVALID_ARGUMENTS); if (ex_data->sec_ops == SC_SEC_OPERATION_SIGN) { /* compute signature with the COMPUTE SIGNATURE command */ /* set the hash value */ sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x2A, 0x90, 0x81); apdu.resp = rbuf; apdu.resplen = sizeof(rbuf); apdu.le = 0; memcpy(sbuf, data, datalen); apdu.data = sbuf; apdu.lc = datalen; apdu.datalen = datalen; r = sc_transmit_apdu(card, &apdu); SC_TEST_RET(card->ctx, r, "APDU transmit failed"); if (apdu.sw1 != 0x90 || apdu.sw2 != 0x00) SC_FUNC_RETURN(card->ctx, 4, sc_check_sw(card, apdu.sw1, apdu.sw2)); /* call COMPUTE SIGNATURE */ sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0x2A, 0x9E, 0x9A); apdu.resp = rbuf; apdu.resplen = sizeof(rbuf); apdu.le = 256; apdu.lc = 0; apdu.datalen = 0; apdu.sensitive = 1; r = sc_transmit_apdu(card, &apdu); SC_TEST_RET(card->ctx, r, "APDU transmit failed"); if (apdu.sw1 == 0x90 && apdu.sw2 == 0x00) { size_t len = apdu.resplen > outlen ? outlen : apdu.resplen; memcpy(out, apdu.resp, len); SC_FUNC_RETURN(card->ctx, 4, len); } } else if (ex_data->sec_ops == SC_SEC_OPERATION_AUTHENTICATE) { size_t tmp_len; /* call INTERNAL AUTHENTICATE */ sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0x88, 0x10, 0x00); /* fix/create DigestInfo structure (if necessary) */ if (ex_data->fix_digestInfo) { unsigned int flags = ex_data->fix_digestInfo & SC_ALGORITHM_RSA_HASHES; if (flags == 0x0) /* XXX: assume no hash is wanted */ flags = SC_ALGORITHM_RSA_HASH_NONE; tmp_len = sizeof(sbuf); r = sc_pkcs1_encode(card->ctx, flags, data, datalen, sbuf, &tmp_len, sizeof(sbuf)); if (r < 0) return r; } else { memcpy(sbuf, data, datalen); tmp_len = datalen; } apdu.lc = tmp_len; apdu.data = sbuf; apdu.datalen = tmp_len; apdu.resp = rbuf; apdu.resplen = sizeof(rbuf); apdu.le = 256; r = sc_transmit_apdu(card, &apdu); SC_TEST_RET(card->ctx, r, "APDU transmit failed"); if (apdu.sw1 != 0x90 || apdu.sw2 != 0x00) SC_FUNC_RETURN(card->ctx, 4, sc_check_sw(card, apdu.sw1, apdu.sw2)); { size_t len = apdu.resplen > outlen ? outlen : apdu.resplen; memcpy(out, apdu.resp, len); SC_FUNC_RETURN(card->ctx, 4, len); } } else SC_FUNC_RETURN(card->ctx, 4, SC_ERROR_INVALID_ARGUMENTS); /* clear old state */ ex_data->sec_ops = 0; ex_data->fix_digestInfo = 0; SC_FUNC_RETURN(card->ctx, 4, sc_check_sw(card, apdu.sw1, apdu.sw2)); }
static int isoApplet_set_security_env(sc_card_t *card, const sc_security_env_t *env, int se_num) { sc_apdu_t apdu; u8 sbuf[SC_MAX_APDU_BUFFER_SIZE]; u8 *p; int r; struct isoApplet_drv_data *drvdata = DRVDATA(card); LOG_FUNC_CALLED(card->ctx); if(se_num != 0) { LOG_TEST_RET(card->ctx, SC_ERROR_NOT_SUPPORTED, "IsoApplet does not support storing of security environments."); } assert(card != NULL && env != NULL); sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x22, 0x41, 0); switch (env->operation) { case SC_SEC_OPERATION_DECIPHER: apdu.p2 = 0xB8; break; case SC_SEC_OPERATION_SIGN: apdu.p2 = 0xB6; break; default: return SC_ERROR_INVALID_ARGUMENTS; } p = sbuf; if (env->flags & SC_SEC_ENV_ALG_PRESENT) { switch(env->algorithm) { case SC_ALGORITHM_RSA: if( env->algorithm_flags & SC_ALGORITHM_RSA_PAD_PKCS1 ) { drvdata->sec_env_alg_ref = ISOAPPLET_ALG_REF_RSA_PAD_PKCS1; } else { LOG_TEST_RET(card->ctx, SC_ERROR_NOT_SUPPORTED, "IsoApplet only supports RSA with PKCS1 padding."); } break; case SC_ALGORITHM_EC: if( env->algorithm_flags & SC_ALGORITHM_ECDSA_RAW ) { drvdata->sec_env_alg_ref = ISOAPPLET_ALG_REF_ECDSA; drvdata->sec_env_ec_field_length = env->algorithm_ref; } else { LOG_TEST_RET(card->ctx, SC_ERROR_NOT_SUPPORTED, "IsoApplet only supports raw ECDSA."); } break; default: LOG_TEST_RET(card->ctx, SC_ERROR_NOT_SUPPORTED, "Unsupported algorithm."); } *p++ = 0x80; /* algorithm reference */ *p++ = 0x01; *p++ = drvdata->sec_env_alg_ref; } if (env->flags & SC_SEC_ENV_FILE_REF_PRESENT) { *p++ = 0x81; *p++ = env->file_ref.len; assert(sizeof(sbuf) - (p - sbuf) >= env->file_ref.len); memcpy(p, env->file_ref.value, env->file_ref.len); p += env->file_ref.len; } if (env->flags & SC_SEC_ENV_KEY_REF_PRESENT) { if (env->flags & SC_SEC_ENV_KEY_REF_ASYMMETRIC) *p++ = 0x83; else *p++ = 0x84; *p++ = env->key_ref_len; assert(sizeof(sbuf) - (p - sbuf) >= env->key_ref_len); memcpy(p, env->key_ref, env->key_ref_len); p += env->key_ref_len; } r = p - sbuf; apdu.lc = r; apdu.datalen = r; apdu.data = sbuf; if (apdu.datalen != 0) { r = sc_transmit_apdu(card, &apdu); LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); r = sc_check_sw(card, apdu.sw1, apdu.sw2); LOG_TEST_RET(card->ctx, r, "Card returned error"); } LOG_FUNC_RETURN(card->ctx, r); }
static int gemsafe_build_pin_apdu(struct sc_card *card, struct sc_apdu *apdu, struct sc_pin_cmd_data *data) { static u8 sbuf[SC_MAX_APDU_BUFFER_SIZE]; int r, len = 0, pad = 0, use_pin_pad = 0, ins, p1 = 0; switch (data->pin_type) { case SC_AC_CHV: break; default: return SC_ERROR_INVALID_ARGUMENTS; } if (data->flags & SC_PIN_CMD_NEED_PADDING) pad = 1; if (data->flags & SC_PIN_CMD_USE_PINPAD) use_pin_pad = 1; data->pin1.offset = 5; switch (data->cmd) { case SC_PIN_CMD_VERIFY: ins = 0x20; if ((r = sc_build_pin(sbuf, sizeof(sbuf), &data->pin1, pad)) < 0) return r; len = r; break; case SC_PIN_CMD_CHANGE: ins = 0x24; if (data->pin1.len != 0 || use_pin_pad) { if ((r = sc_build_pin(sbuf, sizeof(sbuf), &data->pin1, pad)) < 0) return r; len += r; } else { /* implicit test */ p1 = 1; } data->pin2.offset = data->pin1.offset + len; if ((r = sc_build_pin(sbuf+len, sizeof(sbuf)-len, &data->pin2, pad)) < 0) return r; len += r; break; case SC_PIN_CMD_UNBLOCK: ins = 0x2C; if (data->pin1.len != 0 || use_pin_pad) { if ((r = sc_build_pin(sbuf, sizeof(sbuf), &data->pin1, pad)) < 0) return r; len += r; } else { p1 |= 0x02; } if (data->pin2.len != 0 || use_pin_pad) { data->pin2.offset = data->pin1.offset + len; if ((r = sc_build_pin(sbuf+len, sizeof(sbuf)-len, &data->pin2, pad)) < 0) return r; len += r; } else { p1 |= 0x01; } break; default: return SC_ERROR_NOT_SUPPORTED; } sc_format_apdu(card, apdu, SC_APDU_CASE_3_SHORT, ins, p1, data->pin_reference); apdu->lc = len; apdu->datalen = len; apdu->data = sbuf; apdu->resplen = 0; return 0; }
static int cardos_match_card(sc_card_t *card) { unsigned char atr[SC_MAX_ATR_SIZE]; int i; i = _sc_match_atr(card, cardos_atrs, &card->type); if (i < 0) return 0; memcpy(atr, card->atr.value, sizeof(atr)); /* Do not change card type for CIE! */ if (card->type == SC_CARD_TYPE_CARDOS_CIE_V1) return 1; if (card->type == SC_CARD_TYPE_CARDOS_M4_4) return 1; if (card->type == SC_CARD_TYPE_CARDOS_V5_0) return 1; if (card->type == SC_CARD_TYPE_CARDOS_M4_2) { int rv; sc_apdu_t apdu; u8 rbuf[SC_MAX_APDU_BUFFER_SIZE]; /* first check some additional ATR bytes */ if ((atr[4] != 0xff && atr[4] != 0x02) || (atr[6] != 0x10 && atr[6] != 0x0a) || (atr[9] != 0x55 && atr[9] != 0x58)) return 0; /* get the os version using GET DATA and compare it with * version in the ATR */ sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "checking cardos version ..."); sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xca, 0x01, 0x82); apdu.resp = rbuf; apdu.resplen = sizeof(rbuf); apdu.le = 256; apdu.lc = 0; rv = sc_transmit_apdu(card, &apdu); SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, rv, "APDU transmit failed"); if (apdu.sw1 != 0x90 || apdu.sw2 != 0x00) return 0; if (apdu.resp[0] != atr[10] || apdu.resp[1] != atr[11]) /* version mismatch */ return 0; if (atr[11] <= 0x04) { sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "found cardos m4.01"); card->type = SC_CARD_TYPE_CARDOS_M4_01; } else if (atr[11] == 0x08) { sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "found cardos v4.3b"); card->type = SC_CARD_TYPE_CARDOS_M4_3; } else if (atr[11] == 0x09) { sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "found cardos v4.2b"); card->type = SC_CARD_TYPE_CARDOS_M4_2B; } else if (atr[11] >= 0x0B) { sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "found cardos v4.2c or higher"); card->type = SC_CARD_TYPE_CARDOS_M4_2C; } else { sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "found cardos m4.2"); } } return 1; }
static int starcos_select_fid(sc_card_t *card, unsigned int id_hi, unsigned int id_lo, sc_file_t **file_out) { sc_apdu_t apdu; u8 data[] = {id_hi & 0xff, id_lo & 0xff}; u8 resp[SC_MAX_APDU_BUFFER_SIZE]; int bIsDF = 0, r; /* request FCI to distinguish between EFs and DFs */ sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0xA4, 0x00, 0x00); apdu.p2 = 0x00; apdu.resp = (u8*)resp; apdu.resplen = SC_MAX_APDU_BUFFER_SIZE; apdu.le = 256; apdu.lc = 2; apdu.data = (u8*)data; apdu.datalen = 2; r = sc_transmit_apdu(card, &apdu); SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "APDU transmit failed"); if (apdu.p2 == 0x00 && apdu.sw1 == 0x62 && apdu.sw2 == 0x84 ) { /* no FCI => we have a DF (see comment in process_fci()) */ bIsDF = 1; apdu.p2 = 0x0C; apdu.cse = SC_APDU_CASE_3_SHORT; apdu.resplen = 0; apdu.le = 0; r = sc_transmit_apdu(card, &apdu); SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "APDU re-transmit failed"); } else if (apdu.sw1 == 0x61 || (apdu.sw1 == 0x90 && apdu.sw2 == 0x00)) { /* SELECT returned some data (possible FCI) => * try a READ BINARY to see if a EF is selected */ sc_apdu_t apdu2; u8 resp2[2]; sc_format_apdu(card, &apdu2, SC_APDU_CASE_2_SHORT, 0xB0, 0, 0); apdu2.resp = (u8*)resp2; apdu2.resplen = 2; apdu2.le = 1; apdu2.lc = 0; r = sc_transmit_apdu(card, &apdu2); SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "APDU transmit failed"); if (apdu2.sw1 == 0x69 && apdu2.sw2 == 0x86) /* no current EF is selected => we have a DF */ bIsDF = 1; } if (apdu.sw1 != 0x61 && (apdu.sw1 != 0x90 || apdu.sw2 != 0x00)) SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, sc_check_sw(card, apdu.sw1, apdu.sw2)); /* update cache */ if (bIsDF) { card->cache.current_path.type = SC_PATH_TYPE_PATH; card->cache.current_path.value[0] = 0x3f; card->cache.current_path.value[1] = 0x00; if (id_hi == 0x3f && id_lo == 0x00) card->cache.current_path.len = 2; else { card->cache.current_path.len = 4; card->cache.current_path.value[2] = id_hi; card->cache.current_path.value[3] = id_lo; } } if (file_out) { sc_file_t *file = sc_file_new(); if (!file) SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_OUT_OF_MEMORY); file->id = (id_hi << 8) + id_lo; file->path = card->cache.current_path; if (bIsDF) { /* we have a DF */ file->type = SC_FILE_TYPE_DF; file->ef_structure = SC_FILE_EF_UNKNOWN; file->size = 0; file->namelen = 0; file->magic = SC_FILE_MAGIC; *file_out = file; } else { /* ok, assume we have a EF */ r = process_fci(card->ctx, file, apdu.resp, apdu.resplen); if (r != SC_SUCCESS) { sc_file_free(file); return r; } *file_out = file; } } SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_SUCCESS); }
static int ias_build_pin_apdu(sc_card_t *card, sc_apdu_t *apdu, struct sc_pin_cmd_data *data) { static u8 sbuf[SC_MAX_APDU_BUFFER_SIZE]; int r, len, pad, use_pin_pad, ins, p1; len = pad = use_pin_pad = p1 = 0; assert(card != NULL); switch (data->pin_type) { case SC_AC_CHV: break; default: return SC_ERROR_INVALID_ARGUMENTS; } if (data->flags & SC_PIN_CMD_USE_PINPAD) use_pin_pad = 1; /* "needs-padding" necessary for the PTEID card, * but not defined in the pin structure */ if ((data->flags & SC_PIN_CMD_NEED_PADDING) || card->type == SC_CARD_TYPE_IAS_PTEID) pad = 1; data->pin1.offset = 5; switch (data->cmd) { case SC_PIN_CMD_VERIFY: ins = 0x20; if ( (r = sc_build_pin(sbuf, sizeof(sbuf), &data->pin1, pad)) < 0) return r; len = r; break; case SC_PIN_CMD_CHANGE: ins = 0x24; if ((data->flags & SC_PIN_CMD_IMPLICIT_CHANGE) == 0 && (data->pin1.len != 0 || use_pin_pad)) { if ( (r = sc_build_pin(sbuf, sizeof(sbuf), &data->pin1, pad)) < 0) return r; len += r; } else { /* implicit test */ p1 = 1; } data->pin2.offset = data->pin1.offset + len; if ( (r = sc_build_pin(sbuf+len, sizeof(sbuf)-len, &data->pin2, pad)) < 0) return r; len += r; break; case SC_PIN_CMD_UNBLOCK: ins = 0x2C; if (data->pin1.len != 0 || use_pin_pad) { if ( (r = sc_build_pin(sbuf, sizeof(sbuf), &data->pin1, pad)) < 0) return r; len += r; } else { p1 |= 0x02; } if (data->pin2.len != 0 || use_pin_pad) { data->pin2.offset = data->pin1.offset + len; if ( (r = sc_build_pin(sbuf+len, sizeof(sbuf)-len, &data->pin2, pad)) < 0) return r; len += r; } else { p1 |= 0x01; } break; default: return SC_ERROR_NOT_SUPPORTED; } sc_format_apdu(card, apdu, SC_APDU_CASE_3_SHORT, ins, p1, data->pin_reference); apdu->lc = len; apdu->datalen = len; apdu->data = sbuf; apdu->resplen = 0; return SC_SUCCESS; }