static int parse_ddo(struct sc_pkcs15_card *p15card, const u8 * buf, size_t buflen) { struct sc_asn1_entry asn1_ddo[5]; sc_path_t odf_path, ti_path, us_path; int r; sc_copy_asn1_entry(c_asn1_ddo, asn1_ddo); sc_format_asn1_entry(asn1_ddo + 1, &odf_path, NULL, 0); sc_format_asn1_entry(asn1_ddo + 2, &ti_path, NULL, 0); sc_format_asn1_entry(asn1_ddo + 3, &us_path, NULL, 0); r = sc_asn1_decode(p15card->card->ctx, asn1_ddo, buf, buflen, NULL, NULL); if (r) { sc_error(p15card->card->ctx, "DDO parsing failed: %s\n", sc_strerror(r)); return r; } if (asn1_ddo[1].flags & SC_ASN1_PRESENT) { p15card->file_odf = sc_file_new(); if (p15card->file_odf == NULL) goto mem_err; p15card->file_odf->path = odf_path; } if (asn1_ddo[2].flags & SC_ASN1_PRESENT) { p15card->file_tokeninfo = sc_file_new(); if (p15card->file_tokeninfo == NULL) goto mem_err; p15card->file_tokeninfo->path = ti_path; } if (asn1_ddo[3].flags & SC_ASN1_PRESENT) { p15card->file_unusedspace = sc_file_new(); if (p15card->file_unusedspace == NULL) goto mem_err; p15card->file_unusedspace->path = us_path; } return 0; mem_err: if (p15card->file_odf != NULL) { sc_file_free(p15card->file_odf); p15card->file_odf = NULL; } if (p15card->file_tokeninfo != NULL) { sc_file_free(p15card->file_tokeninfo); p15card->file_tokeninfo = NULL; } if (p15card->file_unusedspace != NULL) { sc_file_free(p15card->file_unusedspace); p15card->file_unusedspace = NULL; } return SC_ERROR_OUT_OF_MEMORY; }
static sc_pkcs15_df_t * sc_pkcs15emu_get_df(sc_pkcs15_card_t *p15card, unsigned int type) { sc_pkcs15_df_t *df; sc_file_t *file; int created = 0; while (1) { for (df = p15card->df_list; df; df = df->next) { if (df->type == type) { if (created) df->enumerated = 1; return df; } } assert(created == 0); file = sc_file_new(); if (!file) return NULL; sc_format_path("11001101", &file->path); sc_pkcs15_add_df(p15card, type, &file->path); sc_file_free(file); created++; } }
static int do_create(int argc, char **argv) { sc_path_t path; sc_file_t *file; unsigned int size; int r, op; if (argc != 2) return usage(do_create); if (arg_to_path(argv[0], &path, 1) != 0) return usage(do_create); /* %z isn't supported everywhere */ if (sscanf(argv[1], "%u", &size) != 1) return usage(do_create); file = sc_file_new(); file->id = (path.value[0] << 8) | path.value[1]; file->type = SC_FILE_TYPE_WORKING_EF; file->ef_structure = SC_FILE_EF_TRANSPARENT; file->size = (size_t) size; file->status = SC_FILE_STATUS_ACTIVATED; for (op = 0; op < SC_MAX_AC_OPS; op++) sc_file_add_acl_entry(file, op, SC_AC_NONE, 0); r = create_file(file); sc_file_free(file); return r; }
static int do_mkdir(int argc, char **argv) { sc_path_t path; sc_file_t *file; unsigned int size; int r, op; if (argc != 2) return usage(do_mkdir); if (arg_to_path(argv[0], &path, 1) != 0) return usage(do_mkdir); if (sscanf(argv[1], "%u", &size) != 1) return usage(do_mkdir); file = sc_file_new(); file->id = (path.value[0] << 8) | path.value[1]; file->type = SC_FILE_TYPE_DF; file->size = size; file->status = SC_FILE_STATUS_ACTIVATED; for (op = 0; op < SC_MAX_AC_OPS; op++) sc_file_add_acl_entry(file, op, SC_AC_NONE, 0); r = create_file(file); sc_file_free(file); return r; }
static int create_file_cert(sc_card_t *card) { int r; int size = 0; sc_path_t path; sc_file_t *file = NULL; sc_format_path("3F00", &path); r = sc_select_file(card, &path, &file); if(r) goto out; if(file) { size = (file->size) - 32; sc_file_free(file); file = NULL; } else { size = 2048; } sc_format_path("0002", &path); r = sc_select_file(card, &path, NULL); if(r) { if(r != SC_ERROR_FILE_NOT_FOUND) goto out; file = sc_file_new(); if(file == NULL) { printf("Memory error.\n"); goto out; } file->type = SC_FILE_TYPE_WORKING_EF; file->ef_structure = SC_FILE_EF_TRANSPARENT; file->shareable = 0; file->size = size; r = sc_file_add_acl_entry(file, SC_AC_OP_READ, SC_AC_NONE, 0); if(r) goto out; r = sc_file_add_acl_entry(file, SC_AC_OP_UPDATE, SC_AC_CHV, 0); if(r) goto out; r = sc_file_add_acl_entry(file, SC_AC_OP_ERASE, SC_AC_CHV, 0); if(r) goto out; file->path = path; r = sc_create_file(card, file); if(r) goto out; } out: if(file) sc_file_free(file); return r; }
static int belpic_select_file(sc_card_t *card, const sc_path_t *in_path, sc_file_t **file_out) { sc_context_t *ctx; sc_apdu_t apdu; u8 pathbuf[SC_MAX_PATH_SIZE], *path = pathbuf; int r, pathlen; sc_file_t *file = NULL; assert(card != NULL && in_path != NULL); ctx = card->ctx; memcpy(path, in_path->value, in_path->len); pathlen = in_path->len; sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xA4, 0x08, 0x0C); apdu.lc = pathlen; apdu.data = path; apdu.datalen = pathlen; apdu.resplen = 0; apdu.le = 0; r = sc_transmit_apdu(card, &apdu); SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "Select File APDU transmit failed"); r = sc_check_sw(card, apdu.sw1, apdu.sw2); if (r) SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r); next_idx = (size_t)-1; /* reset */ if (file_out != NULL) { file = sc_file_new(); file->path = *in_path; if (pathlen >= 2) file->id = (in_path->value[pathlen - 2] << 8) | in_path->value[pathlen - 1]; file->size = BELPIC_MAX_FILE_SIZE; file->shareable = 1; file->ef_structure = SC_FILE_EF_TRANSPARENT; if (pathlen == 2 && memcmp("\x3F\x00", in_path->value, 2) == 0) file->type = SC_FILE_TYPE_DF; else file->type = SC_FILE_TYPE_WORKING_EF; *file_out = file; } return 0; }
static sc_file_t * init_file(unsigned int type) { struct sc_file *file; unsigned int op; file = sc_file_new(); for (op = 0; op < SC_MAX_AC_OPS; op++) { sc_file_add_acl_entry(file, op, SC_AC_NONE, 0); } file->type = type; file->status = SC_FILE_STATUS_ACTIVATED; if (file->type != SC_FILE_TYPE_DF) file->ef_structure = SC_FILE_EF_TRANSPARENT; return file; }
static int dump_ef(sc_card_t * card, const char *path, u8 * buf, size_t * buf_len) { int rv; sc_file_t *file = sc_file_new(); sc_format_path(path, &file->path); sc_select_file(card, &file->path, &file); if (file->size > *buf_len) return SC_ERROR_BUFFER_TOO_SMALL; rv = sc_read_binary(card, 0, buf, file->size, 0); if (rv < 0) return rv; *buf_len = rv; return SC_SUCCESS; }
static int starcos_select_aid(sc_card_t *card, u8 aid[16], size_t len, sc_file_t **file_out) { sc_apdu_t apdu; int r; size_t i = 0; sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xA4, 0x04, 0x0C); apdu.lc = len; apdu.data = (u8*)aid; apdu.datalen = len; 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"); /* check return value */ if (!(apdu.sw1 == 0x90 && apdu.sw2 == 0x00) && apdu.sw1 != 0x61 ) SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, sc_check_sw(card, apdu.sw1, apdu.sw2)); /* update cache */ card->cache.current_path.type = SC_PATH_TYPE_DF_NAME; card->cache.current_path.len = len; memcpy(card->cache.current_path.value, aid, len); 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->type = SC_FILE_TYPE_DF; file->ef_structure = SC_FILE_EF_UNKNOWN; file->path.len = 0; file->size = 0; /* AID */ for (i = 0; i < len; i++) file->name[i] = aid[i]; file->namelen = len; file->id = 0x0000; file->magic = SC_FILE_MAGIC; *file_out = file; } SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_SUCCESS); }
static int jpki_init(struct sc_card *card) { struct jpki_private_data *drvdata; sc_file_t *mf; int flags; LOG_FUNC_CALLED(card->ctx); drvdata = malloc(sizeof (struct jpki_private_data)); if (!drvdata) LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY); memset(drvdata, 0, sizeof (struct jpki_private_data)); /* create virtual MF */ mf = sc_file_new(); if (!mf) { free(drvdata); LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY); } sc_format_path("3f00", &mf->path); mf->type = SC_FILE_TYPE_DF; mf->shareable = 0; mf->ef_structure = SC_FILE_EF_UNKNOWN; mf->size = 0; mf->id = 0x3f00; mf->status = SC_FILE_STATUS_ACTIVATED; sc_file_add_acl_entry(mf, SC_AC_OP_SELECT, SC_AC_NONE, 0); sc_file_add_acl_entry(mf, SC_AC_OP_LIST_FILES, SC_AC_NONE, 0); sc_file_add_acl_entry(mf, SC_AC_OP_LOCK, SC_AC_NEVER, 0); sc_file_add_acl_entry(mf, SC_AC_OP_DELETE, SC_AC_NEVER, 0); sc_file_add_acl_entry(mf, SC_AC_OP_CREATE, SC_AC_NEVER, 0); drvdata->mf = mf; drvdata->selected = SELECT_MF; card->name = "jpki"; card->drv_data = drvdata; flags = SC_ALGORITHM_RSA_HASH_NONE | SC_ALGORITHM_RSA_PAD_PKCS1; _sc_card_add_rsa_alg(card, 2048, flags, 0); LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); }
static int entersafe_select_aid(sc_card_t *card, const sc_path_t *in_path, sc_file_t **file_out) { int r = 0; if (card->cache.valid && card->cache.current_path.type == SC_PATH_TYPE_DF_NAME && card->cache.current_path.len == in_path->len && memcmp(card->cache.current_path.value, in_path->value, in_path->len)==0 ) { if(file_out) { *file_out = sc_file_new(); if(!file_out) SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_OUT_OF_MEMORY); } } else { r = iso_ops->select_file(card,in_path,file_out); SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "APDU transmit failed"); /* update cache */ card->cache.current_path.type = SC_PATH_TYPE_DF_NAME; card->cache.current_path.len = in_path->len; memcpy(card->cache.current_path.value,in_path->value,in_path->len); } if (file_out) { sc_file_t *file = *file_out; assert(file); file->type = SC_FILE_TYPE_DF; file->ef_structure = SC_FILE_EF_UNKNOWN; file->path.len = 0; file->size = 0; /* AID */ memcpy(file->name,in_path->value,in_path->len); file->namelen = in_path->len; file->id = 0x0000; } SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r); }
static int esteid_select_file(struct sc_card *card, const struct sc_path *in_path, struct sc_file **file_out) { unsigned char pathbuf[SC_MAX_PATH_SIZE], *path = pathbuf; size_t pathlen; struct sc_file *file = NULL; LOG_FUNC_CALLED(card->ctx); // Only support full paths if (in_path->type != SC_PATH_TYPE_PATH) { LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS); } memcpy(path, in_path->value, in_path->len); pathlen = in_path->len; while (pathlen >= 2) { if (memcmp(path, "\x3F\x00", 2) == 0) { LOG_TEST_RET(card->ctx, esteid_select(card, 0x00, 0x3F, 0x00), "MF select failed"); } else if (path[0] == 0xAD) { LOG_TEST_RET(card->ctx, esteid_select(card, 0x01, path[0], path[1]), "DF select failed"); } else if (pathlen == 2) { LOG_TEST_RET(card->ctx, esteid_select(card, 0x02, path[0], path[1]), "EF select failed"); if (file_out != NULL) // Just make a dummy file { file = sc_file_new(); if (file == NULL) LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY); file->path = *in_path; file->size = 1536; // Dummy size, to be above 1024 *file_out = file; } } path += 2; pathlen -= 2; } LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); }
static int sc_hsm_update_ef(sc_pkcs15_card_t *p15card, u8 prefix, u8 id, int erase, u8 *buf, size_t buflen) { sc_card_t *card = p15card->card; sc_file_t *file = NULL; sc_file_t newfile; sc_path_t path; u8 fid[2]; int r; fid[0] = prefix; fid[1] = id; sc_path_set(&path, SC_PATH_TYPE_FILE_ID, fid, 2, 0, -1); r = sc_select_file(card, &path, NULL); if ((r == SC_SUCCESS) && erase) { r = sc_delete_file(card, &path); LOG_TEST_RET(card->ctx, r, "Could not delete file"); r = SC_ERROR_FILE_NOT_FOUND; } if (r == SC_ERROR_FILE_NOT_FOUND) { file = sc_file_new(); file->id = (path.value[0] << 8) | path.value[1]; file->type = SC_FILE_TYPE_WORKING_EF; file->ef_structure = SC_FILE_EF_TRANSPARENT; file->size = (size_t) 0; file->status = SC_FILE_STATUS_ACTIVATED; r = sc_create_file(card, file); sc_file_free(file); LOG_TEST_RET(card->ctx, r, "Could not create file"); } r = sc_update_binary(card, 0, buf, buflen, 0); LOG_FUNC_RETURN(card->ctx, r); }
static int update_ef(sc_card_t *card, u8 prefix, u8 id, int erase, const u8 *buf, size_t buflen) { sc_file_t *file = NULL; sc_file_t newfile; sc_path_t path; u8 fid[2]; int r; fid[0] = prefix; fid[1] = id; sc_path_set(&path, SC_PATH_TYPE_FILE_ID, fid, 2, 0, -1); r = sc_select_file(card, &path, NULL); if ((r == SC_SUCCESS) && erase) { r = sc_delete_file(card, &path); r = SC_ERROR_FILE_NOT_FOUND; } if (r == SC_ERROR_FILE_NOT_FOUND) { file = sc_file_new(); file->id = (path.value[0] << 8) | path.value[1]; file->type = SC_FILE_TYPE_WORKING_EF; file->ef_structure = SC_FILE_EF_TRANSPARENT; file->size = (size_t) 0; file->status = SC_FILE_STATUS_ACTIVATED; r = sc_create_file(card, file); sc_file_free(file); if (r < 0) { return r; } } r = sc_update_binary(card, 0, buf, buflen, 0); return r; }
static int sc_pkcs15_bind_internal(sc_pkcs15_card_t *p15card) { unsigned char *buf = NULL; int err, ok = 0; size_t len; sc_path_t tmppath; sc_card_t *card = p15card->card; sc_context_t *ctx = card->ctx; sc_pkcs15_tokeninfo_t tokeninfo; if (ctx->debug > 4) sc_debug(ctx, "trying normal pkcs15 processing\n"); /* Enumerate apps now */ if (card->app_count < 0) { err = sc_enum_apps(card); if (err < 0 && err != SC_ERROR_FILE_NOT_FOUND) { sc_error(ctx, "unable to enumerate apps: %s\n", sc_strerror(err)); goto end; } } p15card->file_app = sc_file_new(); if (p15card->file_app == NULL) { err = SC_ERROR_OUT_OF_MEMORY; goto end; } sc_format_path("3F005015", &p15card->file_app->path); if (card->app_count > 0) { const sc_app_info_t *info; info = sc_find_pkcs15_app(card); if (info != NULL) { if (info->path.len) p15card->file_app->path = info->path; if (info->ddo != NULL) parse_ddo(p15card, info->ddo, info->ddo_len); } } /* Check if pkcs15 directory exists */ sc_ctx_suppress_errors_on(card->ctx); err = sc_select_file(card, &p15card->file_app->path, NULL); #if 1 /* If the above test failed on cards without EF(DIR), * try to continue read ODF from 3F005031. -aet */ if ((err == SC_ERROR_FILE_NOT_FOUND) && (card->app_count < 1)) { sc_format_path("3F00", &p15card->file_app->path); err = SC_NO_ERROR; } #endif sc_ctx_suppress_errors_off(card->ctx); if (err < 0) goto end; if (p15card->file_odf == NULL) { /* check if an ODF is present; suppress errors as we * don't know yet whether we have a pkcs15 card */ tmppath = p15card->file_app->path; sc_append_path_id(&tmppath, (const u8 *) "\x50\x31", 2); sc_ctx_suppress_errors_on(card->ctx); err = sc_select_file(card, &tmppath, &p15card->file_odf); sc_ctx_suppress_errors_off(card->ctx); } else { tmppath = p15card->file_odf->path; sc_file_free(p15card->file_odf); p15card->file_odf = NULL; err = sc_select_file(card, &tmppath, &p15card->file_odf); } if (err != SC_SUCCESS) { char pbuf[SC_MAX_PATH_STRING_SIZE]; int r = sc_path_print(pbuf, sizeof(pbuf), &tmppath); if (r != SC_SUCCESS) pbuf[0] = '\0'; sc_debug(ctx, "EF(ODF) not found in '%s'\n", pbuf); goto end; } if ((len = p15card->file_odf->size) == 0) { sc_error(card->ctx, "EF(ODF) is empty\n"); goto end; } buf = malloc(len); if(buf == NULL) return SC_ERROR_OUT_OF_MEMORY; err = sc_read_binary(card, 0, buf, len, 0); if (err < 0) goto end; if (err < 2) { err = SC_ERROR_PKCS15_APP_NOT_FOUND; goto end; } len = err; if (parse_odf(buf, len, p15card)) { err = SC_ERROR_PKCS15_APP_NOT_FOUND; sc_error(card->ctx, "Unable to parse ODF\n"); goto end; } free(buf); buf = NULL; if (card->ctx->debug) { sc_pkcs15_df_t *df; sc_debug(card->ctx, "The following DFs were found:\n"); for (df = p15card->df_list; df; df = df->next) { char pbuf[SC_MAX_PATH_STRING_SIZE]; int r = sc_path_print(pbuf, sizeof(pbuf), &df->path); if (r != SC_SUCCESS) pbuf[0] = '\0'; sc_debug(card->ctx, " DF type %u, path %s, index %u, count %d\n", df->type, pbuf, df->path.index, df->path.count); } } if (p15card->file_tokeninfo == NULL) { tmppath = p15card->file_app->path; sc_append_path_id(&tmppath, (const u8 *) "\x50\x32", 2); } else { tmppath = p15card->file_tokeninfo->path; sc_file_free(p15card->file_tokeninfo); p15card->file_tokeninfo = NULL; } err = sc_select_file(card, &tmppath, &p15card->file_tokeninfo); if (err) goto end; if ((len = p15card->file_tokeninfo->size) == 0) { sc_error(card->ctx, "EF(TokenInfo) is empty\n"); goto end; } buf = malloc(len); if(buf == NULL) return SC_ERROR_OUT_OF_MEMORY; err = sc_read_binary(card, 0, buf, len, 0); if (err < 0) goto end; if (err <= 2) { err = SC_ERROR_PKCS15_APP_NOT_FOUND; goto end; } memset(&tokeninfo, 0, sizeof(tokeninfo)); err = sc_pkcs15_parse_tokeninfo(ctx, &tokeninfo, buf, (size_t)err); if (err != SC_SUCCESS) goto end; p15card->version = tokeninfo.version; p15card->label = tokeninfo.label; p15card->serial_number = tokeninfo.serial_number; p15card->manufacturer_id = tokeninfo.manufacturer_id; p15card->last_update = tokeninfo.last_update; p15card->flags = tokeninfo.flags; p15card->preferred_language = tokeninfo.preferred_language; p15card->seInfo = tokeninfo.seInfo; p15card->num_seInfo = tokeninfo.num_seInfo; /* for cardos cards initialized by Siemens: sign with decrypt */ if (strcmp(p15card->card->driver->short_name,"cardos") == 0 && ( strcmp(p15card->manufacturer_id,"Siemens AG (C)") == 0 || strcmp(p15card->manufacturer_id,"Prime") == 0 )) p15card->flags |= SC_PKCS15_CARD_FLAG_SIGN_WITH_DECRYPT; ok = 1; end: if(buf != NULL) free(buf); if (!ok) { sc_pkcs15_card_clear(p15card); return err; } return SC_SUCCESS; }
int main(int argc, char *argv[]) { int r, c, long_optind = 0; sc_context_param_t ctx_param; sc_card_t *card = NULL; sc_context_t *ctx = NULL; sc_file_t *file = NULL; sc_path_t path; RSA *rsa = NULL; BIGNUM *bn = NULL; BIO *mem = NULL; static const char *pin = NULL; static const char *puk = NULL; while (1) { c = getopt_long(argc, argv, "r:wgol:ix:y:nut:fj:k:hv", \ options, &long_optind); if (c == -1) break; if (c == '?' || c == 'h') util_print_usage_and_die(app_name, options, option_help, NULL); switch (c) { case 'r': opt_reader = optarg; break; case 'w': opt_wait = 1; break; case 'g': if(keylen == 0) keylen = 1536; break; case 'o': overwrite = 1; break; case 'l': keylen = atoi(optarg); break; case 'i': install_pin = 1; break; case 'x': util_get_pin(optarg, &pin); break; case 'y': util_get_pin(optarg, &puk); break; case 'n': new_pin = 1; break; case 'u': unlock = 1; break; case 't': cert = optarg; break; case 'f': finalize = 1; break; case 'j': get_filename = optarg; break; case 'k': put_filename = optarg; break; case 'v': verbose++; break; } } memset(&ctx_param, 0, sizeof(ctx_param)); ctx_param.ver = 0; ctx_param.app_name = argv[0]; r = sc_context_create(&ctx, &ctx_param); if (r) { printf("Failed to establish context: %s\n", sc_strerror(r)); return 1; } if (verbose > 1) { ctx->debug = verbose; sc_ctx_log_to_file(ctx, "stderr"); } if (opt_driver != NULL) { r = sc_set_card_driver(ctx, opt_driver); if (r) { printf("Driver '%s' not found!\n", opt_driver); goto out; } } r = util_connect_card(ctx, &card, opt_reader, opt_wait, 0); if (r) goto out; sc_format_path("3F00", &path); r = sc_select_file(card, &path, NULL); if(r) goto out; if(install_pin) { sc_format_path("AAAA", &path); r = sc_select_file(card, &path, NULL); if(r) { if(r != SC_ERROR_FILE_NOT_FOUND) goto out; file = sc_file_new(); if(file == NULL) { printf("Not enougth memory.\n"); goto out; } file->type = SC_FILE_TYPE_INTERNAL_EF; file->ef_structure = SC_FILE_EF_TRANSPARENT; file->shareable = 0; file->id = 0xAAAA; file->size = 37; r = sc_file_add_acl_entry(file, SC_AC_OP_READ, SC_AC_NONE, 0); if(r) goto out; r = sc_file_add_acl_entry(file, SC_AC_OP_UPDATE, SC_AC_NONE, 0); if(r) goto out; r = sc_file_add_acl_entry(file, SC_AC_OP_ERASE, SC_AC_NONE, 0); if(r) goto out; /* sc_format_path("3F00AAAA", &(file->path)); */ file->path = path; r = sc_create_file(card, file); if(r) goto out; } if(pin != NULL) { sc_changekey_t ck; struct sc_pin_cmd_pin pin_cmd; int ret; memset(&pin_cmd, 0, sizeof(pin_cmd)); memset(&ck, 0, sizeof(ck)); memcpy(ck.key_template, "\x1e\x00\x00\x10", 4); pin_cmd.encoding = SC_PIN_ENCODING_GLP; pin_cmd.len = strlen(pin); pin_cmd.data = (u8*)pin; pin_cmd.max_length = 8; ret = sc_build_pin(ck.new_key.key_value, sizeof(ck.new_key.key_value), &pin_cmd, 1); if(ret < 0) goto out; ck.new_key.key_len = ret; r = sc_card_ctl(card, SC_CARDCTL_WESTCOS_CHANGE_KEY, &ck); if(r) goto out; } if(puk != NULL) { sc_changekey_t ck; struct sc_pin_cmd_pin puk_cmd; int ret; memset(&puk_cmd, 0, sizeof(puk_cmd)); memset(&ck, 0, sizeof(ck)); memcpy(ck.key_template, "\x1e\x00\x00\x20", 4); puk_cmd.encoding = SC_PIN_ENCODING_GLP; puk_cmd.len = strlen(puk); puk_cmd.data = (u8*)puk; puk_cmd.max_length = 8; ret = sc_build_pin(ck.new_key.key_value, sizeof(ck.new_key.key_value), &puk_cmd, 1); if(ret < 0) goto out; ck.new_key.key_len = ret; r = sc_card_ctl(card, SC_CARDCTL_WESTCOS_CHANGE_KEY, &ck); if(r) goto out; } } if(new_pin) { if(change_pin(card, 0, pin, puk)) printf("Wrong pin.\n"); goto out; } if(unlock) { if(unlock_pin(card, 0, puk, pin)) printf("Error unblocking pin.\n"); goto out; } printf("verify pin.\n"); { if(verify_pin(card, 0, pin)) { printf("Wrong pin.\n"); goto out; } } if(keylen) { size_t lg; struct sc_pkcs15_pubkey key; struct sc_pkcs15_pubkey_rsa *dst = &(key.u.rsa); u8 *pdata; memset(&key, 0, sizeof(key)); key.algorithm = SC_ALGORITHM_RSA; printf("Generate key of length %d.\n", keylen); #if OPENSSL_VERSION_NUMBER>=0x00908000L rsa = RSA_new(); bn = BN_new(); mem = BIO_new(BIO_s_mem()); if(rsa == NULL || bn == NULL || mem == NULL) { printf("Not enougth memory.\n"); goto out; } if(!BN_set_word(bn, RSA_F4) || !RSA_generate_key_ex(rsa, keylen, bn, NULL)) #else rsa = RSA_generate_key(keylen, RSA_F4, NULL, NULL); mem = BIO_new(BIO_s_mem()); if(mem == NULL) { printf("Not enougth memory.\n"); goto out; } if (!rsa) #endif { printf("RSA_generate_key_ex return %ld\n", ERR_get_error()); goto out; } RSA_set_method(rsa, RSA_PKCS1_OpenSSL()); if(!i2d_RSAPrivateKey_bio(mem, rsa)) { printf("i2d_RSAPrivateKey_bio return %ld\n", ERR_get_error()); goto out; } lg = BIO_get_mem_data(mem, &pdata); sc_format_path("0001", &path); r = sc_select_file(card, &path, NULL); if(r) { if(r != SC_ERROR_FILE_NOT_FOUND) goto out; file = sc_file_new(); if(file == NULL) { printf("Not enougth memory.\n"); goto out; } file->type = SC_FILE_TYPE_WORKING_EF; file->ef_structure = SC_FILE_EF_TRANSPARENT; file->shareable = 0; file->size = ((lg/4)+1)*4; r = sc_file_add_acl_entry(file, SC_AC_OP_READ, SC_AC_CHV, 0); if(r) goto out; r = sc_file_add_acl_entry(file, SC_AC_OP_UPDATE, SC_AC_CHV, 0); if(r) goto out; r = sc_file_add_acl_entry(file, SC_AC_OP_ERASE, SC_AC_CHV, 0); if(r) goto out; file->path = path; printf("File key creation %s, size %"SC_FORMAT_LEN_SIZE_T"d.\n", file->path.value, file->size); r = sc_create_file(card, file); if(r) goto out; } else { if(!overwrite) { printf("Key file already exist,"\ " use -o to replace it.\n"); goto out; } } printf("Private key length is %"SC_FORMAT_LEN_SIZE_T"d\n", lg); printf("Write private key.\n"); r = sc_update_binary(card,0,pdata,lg,0); if(r<0) goto out; printf("Private key correctly written.\n"); r = create_file_cert(card); if(r) goto out; { const BIGNUM *rsa_n, *rsa_e; RSA_get0_key(rsa, &rsa_n, &rsa_e, NULL); if (!do_convert_bignum(&dst->modulus, rsa_n) || !do_convert_bignum(&dst->exponent, rsa_e)) goto out; } r = sc_pkcs15_encode_pubkey(ctx, &key, &pdata, &lg); if(r) goto out; printf("Public key length %"SC_FORMAT_LEN_SIZE_T"d\n", lg); sc_format_path("3F000002", &path); r = sc_select_file(card, &path, NULL); if(r) goto out; printf("Write public key.\n"); r = sc_update_binary(card,0,pdata,lg,0); if(r<0) goto out; printf("Public key correctly written.\n"); } if(cert) { BIO *bio; X509 *xp; u8 *pdata; bio = BIO_new(BIO_s_file()); if (BIO_read_filename(bio, cert) <= 0) { BIO_free(bio); printf("Can't open file %s.\n", cert); goto out; } xp = PEM_read_bio_X509(bio, NULL, NULL, NULL); BIO_free(bio); if (xp == NULL) { print_openssl_error(); goto out; } else { int lg = cert2der(xp, &pdata); sc_format_path("0002", &path); r = sc_select_file(card, &path, NULL); if(r) goto out; /* FIXME: verify if the file has a compatible size... */ printf("Write certificate %s.\n", cert); r = sc_update_binary(card,0,pdata,lg,0); if(r == SC_ERROR_SECURITY_STATUS_NOT_SATISFIED) { if(verify_pin(card, 0, pin)) { printf("Wrong pin.\n"); } else { r = sc_update_binary(card,0,pdata,lg,0); } } if(r<0) { if(pdata) free(pdata); goto out; } if(xp) X509_free(xp); if(pdata) free(pdata); printf("Certificate correctly written.\n"); } } if(finalize) { int mode = SC_CARDCTRL_LIFECYCLE_USER; if(card->atr.value[10] != 0x82) { sc_format_path("0001", &path); r = sc_select_file(card, &path, NULL); if(r) { printf("This card don't have private key"\ " and can't be finalize.\n"); goto out; } printf("Finalize card...\n"); if(sc_card_ctl(card, SC_CARDCTL_WESTCOS_AUT_KEY, NULL) || sc_card_ctl(card, SC_CARDCTL_LIFECYCLE_SET, &mode)) { printf("Error finalizing card,"\ " card isn't secure.\n"); goto out; } } printf("Card correctly finalized.\n"); } if(get_filename) { FILE *fp; u8 *b; if(file) { sc_file_free(file); file = NULL; } sc_format_path(get_filename, &path); r = sc_select_file(card, &path, &file); if(r) { printf("Error file not found.\n"); goto out; } b = malloc(file->size); if(b == NULL) { printf("Not enougth memory.\n"); goto out; } r = sc_read_binary(card, 0, b, file->size, 0); if(r == SC_ERROR_SECURITY_STATUS_NOT_SATISFIED) { if(verify_pin(card, 0, pin)) { printf("Wrong pin.\n"); goto out; } r = sc_read_binary(card, 0, b, file->size, 0); } if(r<0) { printf("Error reading file.\n"); goto out; } fp = fopen(get_filename, "wb"); fwrite(b, 1, file->size, fp); fclose(fp); free(b); } if(put_filename) { FILE *fp; u8 *b; if(file) { sc_file_free(file); file = NULL; } sc_format_path(put_filename, &path); r = sc_select_file(card, &path, &file); if(r) { printf("File not found.\n"); goto out; } b = malloc(file->size); if(b == NULL) { printf("Not enougth memory.\n"); goto out; } memset(b, 0, file->size); fp = fopen(put_filename, "rb"); fread(b, 1, file->size, fp); fclose(fp); r = sc_update_binary(card, 0, b, file->size, 0); if(r == SC_ERROR_SECURITY_STATUS_NOT_SATISFIED) { if(verify_pin(card, 0, pin)) { printf("Wrong pin.\n"); } else { r = sc_update_binary(card, 0, b, file->size, 0); } } if(r<0) { free(b); printf("Error writing file.\n"); goto out; } free(b); } out: if(mem) BIO_free(mem); if(bn) BN_free(bn); if(rsa) RSA_free(rsa); if(file) sc_file_free(file); if (card) { sc_unlock(card); sc_disconnect_card(card); } sc_release_context(ctx); return EXIT_SUCCESS; }
/* * Create an empty key object */ static int rtecp_create_key(sc_profile_t *profile, sc_pkcs15_card_t *p15card, sc_pkcs15_object_t *obj) { sc_context_t *ctx; /* RSA_PRkey/ Adds Miller- * RSA_PUBkey Rabin tests Attempts Reserve */ const unsigned char prkey_prop[] = { 0x23, 0, 0, 0xAA, 0, 0 }; const unsigned char pbkey_prop[] = { 0x33, 0, 0, 0xAA, 0, 0 }; /* GOSTR3410_PRkey/ * GOSTR3410_PUBkey paramset Attempts Reserve */ unsigned char prgkey_prop[] = { 0x03, '?', 0, 0xAA, 0, 0 }; unsigned char pbgkey_prop[] = { 0x13, '?', 0, 0xAA, 0, 0 }; /* AccessMode - Update Use - - - Delete */ unsigned char prkey_sec[15] = { 0x46, 0, '?', '?', 0, 0, 0, '?' }; unsigned char pbkey_sec[15] = { 0x46, 0, '?', 0, 0, 0, 0, '?' }; unsigned char auth_id, paramset; sc_pkcs15_prkey_info_t *key_info; sc_file_t *file; int r; if (!profile || !p15card || !p15card->card || !p15card->card->ctx || !obj || !obj->data) return SC_ERROR_INVALID_ARGUMENTS; ctx = p15card->card->ctx; SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_VERBOSE); if (obj->type != SC_PKCS15_TYPE_PRKEY_RSA && obj->type != SC_PKCS15_TYPE_PRKEY_GOSTR3410) return SC_ERROR_NOT_SUPPORTED; if (obj->auth_id.len != 1) return SC_ERROR_INVALID_ARGUMENTS; auth_id = obj->auth_id.value[0]; key_info = (sc_pkcs15_prkey_info_t *)obj->data; assert(key_info); if ((obj->type == SC_PKCS15_TYPE_PRKEY_RSA && key_info->modulus_length % 128 != 0) || (obj->type == SC_PKCS15_TYPE_PRKEY_GOSTR3410 && key_info->modulus_length != SC_PKCS15_GOSTR3410_KEYSIZE)) { sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "Unsupported key size %u\n", key_info->modulus_length); return SC_ERROR_INVALID_ARGUMENTS; } if (obj->type == SC_PKCS15_TYPE_PRKEY_GOSTR3410) { if (key_info->params.len < sizeof(int)) return SC_ERROR_INVALID_ARGUMENTS; if (((int*)key_info->params.data)[0] < 1 || ((int*)key_info->params.data)[0] > 3) return SC_ERROR_INVALID_ARGUMENTS; paramset = ((unsigned int*)key_info->params.data)[0] & 0x03; assert(sizeof(prgkey_prop)/sizeof(prgkey_prop[0]) > 1); assert(sizeof(pbgkey_prop)/sizeof(pbgkey_prop[0]) > 1); prgkey_prop[1] = 0x10 + (paramset << 4); pbgkey_prop[1] = prgkey_prop[1]; } r = sc_profile_get_file(profile, "PKCS15-AppDF", &file); SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, r, "Get PKCS15-AppDF info failed"); r = sc_file_add_acl_entry(file, SC_AC_OP_CREATE, SC_AC_CHV, auth_id); if (r == SC_SUCCESS) r = sc_pkcs15init_authenticate(profile, p15card, file, SC_AC_OP_CREATE); assert(file); sc_file_free(file); SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, r, "Authenticate failed"); file = sc_file_new(); if (!file) SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_OUT_OF_MEMORY); file->id = key_info->key_reference; r = sc_file_set_type_attr(file, (const u8*)"\x10\x00", 2); /* private key file */ if (obj->type == SC_PKCS15_TYPE_PRKEY_RSA) file->size = key_info->modulus_length / 8 / 2 * 5 + 8; else file->size = key_info->modulus_length / 8; if (r == SC_SUCCESS) { assert(sizeof(prkey_sec)/sizeof(prkey_sec[0]) > 7); prkey_sec[2] = auth_id; prkey_sec[3] = auth_id; prkey_sec[7] = auth_id; r = sc_file_set_sec_attr(file, prkey_sec, sizeof(prkey_sec)); } if (r == SC_SUCCESS) { if (obj->type == SC_PKCS15_TYPE_PRKEY_RSA) r = sc_file_set_prop_attr(file, prkey_prop, sizeof(prkey_prop)); else r = sc_file_set_prop_attr(file, prgkey_prop,sizeof(prgkey_prop)); } if (r == SC_SUCCESS) { sc_log(ctx, "create private key file id:%04i", file->id); r = sc_create_file(p15card->card, file); } /* public key file */ if (obj->type == SC_PKCS15_TYPE_PRKEY_RSA) file->size = key_info->modulus_length / 8 / 2 * 3; else file->size = key_info->modulus_length / 8 * 2; if (r == SC_SUCCESS) { assert(sizeof(pbkey_sec)/sizeof(pbkey_sec[0]) > 7); pbkey_sec[2] = auth_id; pbkey_sec[7] = auth_id; r = sc_file_set_sec_attr(file, pbkey_sec, sizeof(pbkey_sec)); } if (r == SC_SUCCESS) { if (obj->type == SC_PKCS15_TYPE_PRKEY_RSA) r = sc_file_set_prop_attr(file, pbkey_prop, sizeof(pbkey_prop)); else r = sc_file_set_prop_attr(file, pbgkey_prop,sizeof(pbgkey_prop)); } if (r == SC_SUCCESS) { sc_log(ctx, "create public key file id:%04i", file->id); r = sc_create_file(p15card->card, file); } assert(file); sc_file_free(file); SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_NORMAL, r); }
/* * Create a PIN object within the given DF */ static int rtecp_create_pin(sc_profile_t *profile, sc_pkcs15_card_t *p15card, sc_file_t *df, sc_pkcs15_object_t *pin_obj, const unsigned char *pin, size_t pin_len, const unsigned char *puk, size_t puk_len) { sc_context_t *ctx; sc_pkcs15_auth_info_t *auth_info; sc_file_t *file = NULL; /* GCHV min-length Flags Attempts Reserve */ unsigned char prop[] = { 0x01, '?', 0x01, '?', 0, 0 }; /* AccessMode Unblock Change Delete */ unsigned char sec[15] = { 0x43, '?', '?', 0, 0, 0, 0, 0xFF }; char pin_sname[0x10]; int r, reset_by_sopin = 0; (void)puk; /* no warning */ if (!profile || !p15card || !p15card->card || !p15card->card->ctx || !df || !pin_obj || !pin_obj->data || !pin || !pin_len) return SC_ERROR_INVALID_ARGUMENTS; ctx = p15card->card->ctx; SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_VERBOSE); if (puk_len != 0) { sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "Do not enter User unblocking PIN (PUK): %s\n", sc_strerror(SC_ERROR_NOT_SUPPORTED)); return SC_ERROR_NOT_SUPPORTED; } auth_info = (sc_pkcs15_auth_info_t *)pin_obj->data; if (auth_info->auth_type != SC_PKCS15_PIN_AUTH_TYPE_PIN) return SC_ERROR_OBJECT_NOT_VALID; if (auth_info->attrs.pin.reference != RTECP_SO_PIN_REF && auth_info->attrs.pin.reference != RTECP_USER_PIN_REF) { sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "PIN reference %i not found in standard" " (Rutoken ECP) PINs\n", auth_info->attrs.pin.reference); return SC_ERROR_NOT_SUPPORTED; } snprintf(pin_sname, sizeof(pin_sname), "CHV%i", auth_info->attrs.pin.reference); if (auth_info->attrs.pin.reference == RTECP_USER_PIN_REF) { r = sc_profile_get_file(profile, pin_sname, &file); if (!r) { const struct sc_acl_entry *acl = NULL; r = sc_pkcs15init_fixup_file(profile, p15card, file); if (r < 0) sc_file_free(file); SC_TEST_RET(p15card->card->ctx, SC_LOG_DEBUG_NORMAL, r, "Cannot fixup the ACLs of PIN file"); acl = sc_file_get_acl_entry(file, SC_AC_OP_PIN_RESET); if (acl && acl->method == SC_AC_CHV && acl->key_ref == RTECP_SO_PIN_REF) { sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "Allow reset of User PIN with SoPIN\n"); reset_by_sopin = 1; } sc_file_free(file); } } file = sc_file_new(); if (!file) SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_OUT_OF_MEMORY); file->id = auth_info->attrs.pin.reference; file->size = pin_len; assert(sizeof(sec)/sizeof(sec[0]) > 2); sec[1] = (auth_info->attrs.pin.reference == RTECP_SO_PIN_REF) ? 0xFF : RTECP_SO_PIN_REF; sec[2] = (unsigned char)auth_info->attrs.pin.reference | (reset_by_sopin ? RTECP_SO_PIN_REF : 0); r = sc_file_set_sec_attr(file, sec, sizeof(sec)); if (r == SC_SUCCESS) { assert(sizeof(prop)/sizeof(prop[0]) > 3); prop[1] = (unsigned char)auth_info->attrs.pin.min_length; prop[3] = 0x11 * (unsigned char)(auth_info->tries_left & 0x0F); r = sc_file_set_prop_attr(file, prop, sizeof(prop)); } if (r == SC_SUCCESS) r = sc_file_set_type_attr(file, (const u8*)"\x10\x00", 2); if (r == SC_SUCCESS) r = sc_create_file(p15card->card, file); sc_file_free(file); if (r == SC_SUCCESS) r = sc_change_reference_data(p15card->card, SC_AC_CHV, auth_info->attrs.pin.reference, NULL, 0, pin, pin_len, NULL); SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_NORMAL, r); }
static int sc_pkcs15emu_dnie_init(sc_pkcs15_card_t * p15card) { u8 buf[1024]; sc_pkcs15_df_t *df; sc_pkcs15_object_t *p15_obj; size_t len = sizeof(buf); int rv; sc_context_t *ctx = p15card->card->ctx; LOG_FUNC_CALLED(ctx); /* Check for correct card driver (i.e. iso7816) */ if (strcmp(p15card->card->driver->short_name, "dnie") != 0) return SC_ERROR_WRONG_CARD; /* Check for correct card atr */ if (dnie_match_card(p15card->card) != 1) return SC_ERROR_WRONG_CARD; /* Set root path of this application */ p15card->file_app = sc_file_new(); sc_format_path("3F00", &p15card->file_app->path); /* Load TokenInfo */ rv = dump_ef(p15card->card, "3F0050155032", buf, &len); if (rv != SC_SUCCESS) { sc_log(ctx, "Reading of EF.TOKENINFO failed: %d", rv); LOG_FUNC_RETURN(ctx, rv); } rv = sc_pkcs15_parse_tokeninfo(p15card->card->ctx, p15card->tokeninfo, buf, len); if (rv != SC_SUCCESS) { sc_log(ctx, "Decoding of EF.TOKENINFO failed: %d", rv); LOG_FUNC_RETURN(ctx, rv); } /* Only accept the original stuff */ if (strcmp(p15card->tokeninfo->manufacturer_id, "DGP-FNMT") != 0) LOG_FUNC_RETURN(ctx, SC_ERROR_WRONG_CARD); /* Load ODF */ rv = dump_ef(p15card->card, "3F0050155031", buf, &len); if (rv != SC_SUCCESS) { sc_log(ctx, "Reading of ODF failed: %d", rv); LOG_FUNC_RETURN(ctx, rv); } rv = parse_odf(buf, len, p15card); if (rv != SC_SUCCESS) { sc_log(ctx, "Decoding of ODF failed: %d", rv); LOG_FUNC_RETURN(ctx, rv); } /* Decode EF.PrKDF, EF.PuKDF and EF.CDF */ for (df = p15card->df_list; df != NULL; df = df->next) { if (df->type == SC_PKCS15_PRKDF) { rv = sc_pkcs15_parse_df(p15card, df); if (rv != SC_SUCCESS) { sc_log(ctx, "Decoding of EF.PrKDF (%s) failed: %d", sc_print_path(&df->path), rv); } } if (df->type == SC_PKCS15_PUKDF) { rv = sc_pkcs15_parse_df(p15card, df); if (rv != SC_SUCCESS) { sc_log(ctx, "Decoding of EF.PuKDF (%s) failed: %d", sc_print_path(&df->path), rv); } } if (df->type == SC_PKCS15_CDF) { rv = sc_pkcs15_parse_df(p15card, df); if (rv != SC_SUCCESS) { sc_log(ctx, "Decoding of EF.CDF (%s) failed: %d", sc_print_path(&df->path), rv); } } if (df->type == SC_PKCS15_DODF) { rv = sc_pkcs15_parse_df(p15card, df); if (rv != SC_SUCCESS) { sc_log(ctx, "Decoding of EF.DODF (%s) failed: %d", sc_print_path(&df->path), rv); } } } /* Perform required fixes */ p15_obj = p15card->obj_list; while (p15_obj != NULL) { /* Add missing 'auth_id' to private objects */ if ((p15_obj->flags & SC_PKCS15_CO_FLAG_PRIVATE) && (p15_obj->auth_id.len == 0)) { p15_obj->auth_id.value[0] = 0x01; p15_obj->auth_id.len = 1; } /* Remove found public keys as cannot be read_binary()'d */ if ( p15_obj->df && (p15_obj->df->type == SC_PKCS15_PUKDF) ) { sc_pkcs15_object_t *puk = p15_obj; p15_obj = p15_obj->next; sc_pkcs15_remove_object(p15card, puk); sc_pkcs15_free_object(puk); } else { p15_obj = p15_obj->next; } } LOG_FUNC_RETURN(ctx, SC_SUCCESS); }
int card_sync_card_to_virtual_fs_any_df( sc_card_t *card, struct _virtual_file_t *virtual_file, virtual_fs_t *virtual_fs, int type ) { int r = SC_SUCCESS; unsigned char *encoded_pkcs15 = NULL; size_t encoded_pkcs15_size = 0; sc_pkcs15_card_t *temp_pkcs15_card = NULL; sc_pkcs15_object_t *obj = NULL; unsigned char *card_data = NULL; size_t card_data_length = 0; SC_FUNC_CALLED(card->ctx, 1); if(!card || !virtual_file) return SC_ERROR_INVALID_ARGUMENTS; /* get file */ r = card_helper_read_file(card, &virtual_file->path, &card_data, &card_data_length); if(r < 0) goto end; /* create a new pkcs15_card structure */ temp_pkcs15_card = sc_pkcs15_card_new(); if(!temp_pkcs15_card) { r = SC_ERROR_OUT_OF_MEMORY; goto end; } /* we set some important fields */ temp_pkcs15_card->card = card; temp_pkcs15_card->file_app = sc_file_new(); if (!temp_pkcs15_card->file_app) { r = SC_ERROR_OUT_OF_MEMORY; goto end; } sc_format_path("3F00", &temp_pkcs15_card->file_app->path); temp_pkcs15_card->tokeninfo->flags=SC_PKCS15_TOKEN_PRN_GENERATION | SC_PKCS15_TOKEN_EID_COMPLIANT; /* Convert card df read to a list of same type of pkcs15 objects. This function uses our internal card decoding parser. */ r = sc_pkcs15_parse_card_df( temp_pkcs15_card, type, card_data, card_data_length ); if(r != SC_SUCCESS) { sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "Card parsing failed\n"); goto end; } /* we need to correct some PKCS#15 data */ for(obj = temp_pkcs15_card->obj_list; obj != NULL; obj = obj->next) { switch(obj->type & SC_PKCS15_TYPE_CLASS_MASK) { case SC_PKCS15_TYPE_CERT: r = card_sync_card_to_virtual_fs_filter_cert(card, virtual_file, virtual_fs, obj); break; case SC_PKCS15_TYPE_PRKEY: r = card_sync_card_to_virtual_fs_filter_prkey(card, virtual_file, virtual_fs, obj); break; case SC_PKCS15_TYPE_PUBKEY: r = card_sync_card_to_virtual_fs_filter_pukey(card, virtual_file, virtual_fs, obj); break; case SC_PKCS15_TYPE_AUTH: if(obj->data) { sc_pkcs15_pin_info_t * pin=obj->data; /* remove security officer pin */ pin->flags &= (~SC_PKCS15_PIN_FLAG_SO_PIN); sc_format_path("3F00", &pin->path); pin->stored_length= (pin->max_length>pin->stored_length) ? pin->max_length : pin->stored_length; } break; case SC_PKCS15_TYPE_DATA_OBJECT: r = card_sync_card_to_virtual_fs_filter_data_object(card, virtual_file, virtual_fs, obj); break; default: /* ignore this object */ break; } } if(r != SC_SUCCESS) { sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "Object filtering failed\n"); goto end; } /* generate pkcs#15 stream for the appropiate object type */ r = sc_standard_pkcs15_encode_any_df( card->ctx, temp_pkcs15_card, type, /* encode only specific objects type */ &encoded_pkcs15, &encoded_pkcs15_size ); if(r != SC_SUCCESS) { sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "Standard PKCS#15 encoding failed\n"); goto end; } r = virtual_file_data_update(virtual_file, 0, encoded_pkcs15, encoded_pkcs15_size); if(r == SC_SUCCESS) { /* add a trailing 0 */ r = virtual_file_data_update(virtual_file, encoded_pkcs15_size, (const unsigned char *)"\0", 1); } end: if(card_data) { free(card_data); card_data = NULL; } if(temp_pkcs15_card) { /* set to NULL without freeing because we reused structure */ temp_pkcs15_card->card = NULL; /* now free temp structure */ sc_pkcs15_card_free(temp_pkcs15_card); temp_pkcs15_card = NULL; } if(encoded_pkcs15) { free(encoded_pkcs15); encoded_pkcs15 = NULL; } SC_FUNC_RETURN(card->ctx, 1, r); }
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 sc_pkcs15emu_dnie_init(sc_pkcs15_card_t * p15card) { u8 buf[1024]; sc_pkcs15_df_t *df; sc_pkcs15_object_t *p15_obj; size_t len = sizeof(buf); int rv; struct sc_pkcs15_cert_info *p15_info = NULL; sc_context_t *ctx = p15card->card->ctx; LOG_FUNC_CALLED(ctx); /* Check for correct card driver (i.e. iso7816) */ if (strcmp(p15card->card->driver->short_name, "dnie") != 0) return SC_ERROR_WRONG_CARD; /* Check for correct card atr */ if (dnie_match_card(p15card->card) != 1) return SC_ERROR_WRONG_CARD; #ifdef ENABLE_OPENSSL /* The two keys inside DNIe 3.0 needs login before performing any signature. * They are CKA_ALWAYS_AUTHENTICATE although they are not tagged like that. * For the moment caching is forced if 3.0 is detected to make it work properly. */ if (p15card->card->atr.value[15] >= DNIE_30_VERSION) { p15card->opts.use_pin_cache = 1; p15card->opts.pin_cache_counter = DNIE_30_CACHE_COUNTER; sc_log(ctx, "DNIe 3.0 detected - PKCS#15 options reset: use_file_cache=%d use_pin_cache=%d pin_cache_counter=%d pin_cache_ignore_user_consent=%d", p15card->opts.use_file_cache, p15card->opts.use_pin_cache, p15card->opts.pin_cache_counter, p15card->opts.pin_cache_ignore_user_consent); } #endif /* Set root path of this application */ p15card->file_app = sc_file_new(); sc_format_path("3F00", &p15card->file_app->path); /* Load TokenInfo */ rv = dump_ef(p15card->card, "3F0050155032", buf, &len); if (rv != SC_SUCCESS) { sc_log(ctx, "Reading of EF.TOKENINFO failed: %d", rv); LOG_FUNC_RETURN(ctx, rv); } rv = sc_pkcs15_parse_tokeninfo(p15card->card->ctx, p15card->tokeninfo, buf, len); if (rv != SC_SUCCESS) { sc_log(ctx, "Decoding of EF.TOKENINFO failed: %d", rv); LOG_FUNC_RETURN(ctx, rv); } /* Only accept the original stuff */ if (strcmp(p15card->tokeninfo->manufacturer_id, "DGP-FNMT") != 0) LOG_FUNC_RETURN(ctx, SC_ERROR_WRONG_CARD); /* Load ODF */ rv = dump_ef(p15card->card, "3F0050155031", buf, &len); if (rv != SC_SUCCESS) { sc_log(ctx, "Reading of ODF failed: %d", rv); LOG_FUNC_RETURN(ctx, rv); } rv = parse_odf(buf, len, p15card); if (rv != SC_SUCCESS) { sc_log(ctx, "Decoding of ODF failed: %d", rv); LOG_FUNC_RETURN(ctx, rv); } /* Decode EF.PrKDF, EF.PuKDF and EF.CDF */ for (df = p15card->df_list; df != NULL; df = df->next) { if (df->type == SC_PKCS15_PRKDF) { rv = sc_pkcs15_parse_df(p15card, df); if (rv != SC_SUCCESS) { sc_log(ctx, "Decoding of EF.PrKDF (%s) failed: %d", sc_print_path(&df->path), rv); } } if (df->type == SC_PKCS15_PUKDF) { rv = sc_pkcs15_parse_df(p15card, df); if (rv != SC_SUCCESS) { sc_log(ctx, "Decoding of EF.PuKDF (%s) failed: %d", sc_print_path(&df->path), rv); } } if (df->type == SC_PKCS15_CDF) { rv = sc_pkcs15_parse_df(p15card, df); if (rv != SC_SUCCESS) { sc_log(ctx, "Decoding of EF.CDF (%s) failed: %d", sc_print_path(&df->path), rv); } } if (df->type == SC_PKCS15_DODF) { rv = sc_pkcs15_parse_df(p15card, df); if (rv != SC_SUCCESS) { sc_log(ctx, "Decoding of EF.DODF (%s) failed: %d", sc_print_path(&df->path), rv); } } } /* Perform required fixes */ p15_obj = p15card->obj_list; while (p15_obj != NULL) { /* Add missing 'auth_id' to private objects */ if ((p15_obj->flags & SC_PKCS15_CO_FLAG_PRIVATE) && (p15_obj->auth_id.len == 0)) { p15_obj->auth_id.value[0] = 0x01; p15_obj->auth_id.len = 1; }; /* Set path count to -1 for public certificates, as they will need to be decompressed and read_binary()'d, so we make sure we end up reading the file->size and not the path->count which is the compressed size on newer DNIe versions */ if ( p15_obj->df && (p15_obj->df->type == SC_PKCS15_CDF) ) { p15_info = (struct sc_pkcs15_cert_info *) p15_obj ->data; p15_info ->path.count = -1; } /* Remove found public keys as cannot be read_binary()'d */ if ( p15_obj->df && (p15_obj->df->type == SC_PKCS15_PUKDF) ) { sc_pkcs15_object_t *puk = p15_obj; p15_obj = p15_obj->next; sc_pkcs15_remove_object(p15card, puk); sc_pkcs15_free_object(puk); } else { p15_obj = p15_obj->next; } } LOG_FUNC_RETURN(ctx, SC_SUCCESS); }
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_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 entersafe_select_path(sc_card_t *card, const u8 pathbuf[16], const size_t len, sc_file_t **file_out) { u8 n_pathbuf[SC_MAX_PATH_SIZE]; const u8 *path=pathbuf; size_t pathlen=len; int bMatch = -1; unsigned int i; int r; if (pathlen%2 != 0 || pathlen > 6 || pathlen <= 0) SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_INVALID_ARGUMENTS); /* if pathlen == 6 then the first FID must be MF (== 3F00) */ if (pathlen == 6 && ( path[0] != 0x3f || path[1] != 0x00 )) SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_INVALID_ARGUMENTS); /* unify path (the first FID should be MF) */ if (path[0] != 0x3f || path[1] != 0x00) { n_pathbuf[0] = 0x3f; n_pathbuf[1] = 0x00; for (i=0; i< pathlen; i++) n_pathbuf[i+2] = pathbuf[i]; path = n_pathbuf; pathlen += 2; } /* check current working directory */ if (card->cache.valid && card->cache.current_path.type == SC_PATH_TYPE_PATH && card->cache.current_path.len >= 2 && card->cache.current_path.len <= pathlen ) { bMatch = 0; for (i=0; i < card->cache.current_path.len; i+=2) if (card->cache.current_path.value[i] == path[i] && card->cache.current_path.value[i+1] == path[i+1] ) bMatch += 2; } if ( card->cache.valid && bMatch > 2 ) { if ( pathlen - bMatch == 2 ) { /* we are in the rigth directory */ return entersafe_select_fid(card, path[bMatch], path[bMatch+1], file_out); } else if ( pathlen - bMatch > 2 ) { /* two more steps to go */ sc_path_t new_path; /* first step: change directory */ r = entersafe_select_fid(card, path[bMatch], path[bMatch+1], NULL); SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "SELECT FILE (DF-ID) failed"); memset(&new_path, 0, sizeof(sc_path_t)); new_path.type = SC_PATH_TYPE_PATH; new_path.len = pathlen - bMatch-2; memcpy(new_path.value, &(path[bMatch+2]), new_path.len); /* final step: select file */ return entersafe_select_file(card, &new_path, file_out); } else /* if (bMatch - pathlen == 0) */ { /* done: we are already in the * requested directory */ sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "cache hit\n"); /* copy file info (if necessary) */ 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 = (path[pathlen-2] << 8) + path[pathlen-1]; file->path = card->cache.current_path; 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; } /* nothing left to do */ return SC_SUCCESS; } } else { /* no usable cache */ for ( i=0; i<pathlen-2; i+=2 ) { r = entersafe_select_fid(card, path[i], path[i+1], NULL); SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "SELECT FILE (DF-ID) failed"); } return entersafe_select_fid(card, path[pathlen-2], path[pathlen-1], file_out); } }
static int starcos_select_file(sc_card_t *card, const sc_path_t *in_path, sc_file_t **file_out) { u8 pathbuf[SC_MAX_PATH_SIZE], *path = pathbuf; int r; size_t i, pathlen; char pbuf[SC_MAX_PATH_STRING_SIZE]; SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); r = sc_path_print(pbuf, sizeof(pbuf), &card->cache.current_path); if (r != SC_SUCCESS) pbuf[0] = '\0'; sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "current path (%s, %s): %s (len: %u)\n", (card->cache.current_path.type==SC_PATH_TYPE_DF_NAME?"aid":"path"), (card->cache.valid?"valid":"invalid"), pbuf, card->cache.current_path.len); memcpy(path, in_path->value, in_path->len); pathlen = in_path->len; if (in_path->type == SC_PATH_TYPE_FILE_ID) { /* SELECT EF/DF with ID */ /* Select with 2byte File-ID */ if (pathlen != 2) SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE,SC_ERROR_INVALID_ARGUMENTS); return starcos_select_fid(card, path[0], path[1], file_out); } else if (in_path->type == SC_PATH_TYPE_DF_NAME) { /* SELECT DF with AID */ /* Select with 1-16byte Application-ID */ if (card->cache.valid && card->cache.current_path.type == SC_PATH_TYPE_DF_NAME && card->cache.current_path.len == pathlen && memcmp(card->cache.current_path.value, pathbuf, pathlen) == 0 ) { sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "cache hit\n"); SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_SUCCESS); } else return starcos_select_aid(card, pathbuf, pathlen, file_out); } else if (in_path->type == SC_PATH_TYPE_PATH) { u8 n_pathbuf[SC_MAX_PATH_SIZE]; int bMatch = -1; /* Select with path (sequence of File-IDs) */ /* Starcos (S 2.1 and SPK 2.3) only supports one * level of subdirectories, therefore a path is * at most 3 FID long (the last one being the FID * of a EF) => pathlen must be even and less than 6 */ if (pathlen%2 != 0 || pathlen > 6 || pathlen <= 0) SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_INVALID_ARGUMENTS); /* if pathlen == 6 then the first FID must be MF (== 3F00) */ if (pathlen == 6 && ( path[0] != 0x3f || path[1] != 0x00 )) SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_INVALID_ARGUMENTS); /* unify path (the first FID should be MF) */ if (path[0] != 0x3f || path[1] != 0x00) { n_pathbuf[0] = 0x3f; n_pathbuf[1] = 0x00; for (i=0; i< pathlen; i++) n_pathbuf[i+2] = pathbuf[i]; path = n_pathbuf; pathlen += 2; } /* check current working directory */ if (card->cache.valid && card->cache.current_path.type == SC_PATH_TYPE_PATH && card->cache.current_path.len >= 2 && card->cache.current_path.len <= pathlen ) { bMatch = 0; for (i=0; i < card->cache.current_path.len; i+=2) if (card->cache.current_path.value[i] == path[i] && card->cache.current_path.value[i+1] == path[i+1] ) bMatch += 2; } if ( card->cache.valid && bMatch >= 0 ) { if ( pathlen - bMatch == 2 ) /* we are in the rigth directory */ return starcos_select_fid(card, path[bMatch], path[bMatch+1], file_out); else if ( pathlen - bMatch > 2 ) { /* two more steps to go */ sc_path_t new_path; /* first step: change directory */ r = starcos_select_fid(card, path[bMatch], path[bMatch+1], NULL); SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "SELECT FILE (DF-ID) failed"); memset(&new_path, 0, sizeof(sc_path_t)); new_path.type = SC_PATH_TYPE_PATH; new_path.len = pathlen - bMatch-2; memcpy(new_path.value, &(path[bMatch+2]), new_path.len); /* final step: select file */ return starcos_select_file(card, &new_path, file_out); } else /* if (bMatch - pathlen == 0) */ { /* done: we are already in the * requested directory */ sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "cache hit\n"); /* copy file info (if necessary) */ 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 = (path[pathlen-2] << 8) + path[pathlen-1]; file->path = card->cache.current_path; 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; } /* nothing left to do */ return SC_SUCCESS; } } else { /* no usable cache */ for ( i=0; i<pathlen-2; i+=2 ) { r = starcos_select_fid(card, path[i], path[i+1], NULL); SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "SELECT FILE (DF-ID) failed"); } return starcos_select_fid(card, path[pathlen-2], path[pathlen-1], file_out); } } else SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_INVALID_ARGUMENTS); }
/* * Create a PIN object within the given DF */ static int rtecp_create_pin(sc_profile_t *profile, sc_pkcs15_card_t *p15card, sc_file_t *df, sc_pkcs15_object_t *pin_obj, const unsigned char *pin, size_t pin_len, const unsigned char *puk, size_t puk_len) { sc_context_t *ctx; sc_pkcs15_pin_info_t *pin_info; sc_file_t *file; /* GCHV min-length Flags Attempts Reserve */ unsigned char prop[] = { 0x01, '?', 0x01, '?', 0, 0 }; /* AccessMode Unblock Change Delete */ unsigned char sec[15] = { 0x43, '?', '?', 0, 0, 0, 0, 0xFF }; int r; (void)puk; /* no warning */ if (!profile || !p15card || !p15card->card || !p15card->card->ctx || !df || !pin_obj || !pin_obj->data || !pin || !pin_len) return SC_ERROR_INVALID_ARGUMENTS; ctx = p15card->card->ctx; SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_VERBOSE); if (puk_len != 0) { sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "Do not enter User unblocking PIN (PUK): %s\n", sc_strerror(SC_ERROR_NOT_SUPPORTED)); return SC_ERROR_NOT_SUPPORTED; } pin_info = (sc_pkcs15_pin_info_t *)pin_obj->data; if (pin_info->reference != RTECP_SO_PIN_REF && pin_info->reference != RTECP_USER_PIN_REF) { sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "PIN reference %i not found in standard" " (Rutoken ECP) PINs\n", pin_info->reference); return SC_ERROR_NOT_SUPPORTED; } file = sc_file_new(); if (!file) SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_OUT_OF_MEMORY); file->id = pin_info->reference; file->size = pin_len; assert(sizeof(sec)/sizeof(sec[0]) > 2); sec[1] = (pin_info->reference == RTECP_SO_PIN_REF) ? 0xFF : RTECP_SO_PIN_REF; sec[2] = (unsigned char)pin_info->reference; r = sc_file_set_sec_attr(file, sec, sizeof(sec)); if (r == SC_SUCCESS) { assert(sizeof(prop)/sizeof(prop[0]) > 3); prop[1] = (unsigned char)pin_info->min_length; prop[3] = 0x11 * (unsigned char)(pin_info->tries_left & 0x0F); r = sc_file_set_prop_attr(file, prop, sizeof(prop)); } if (r == SC_SUCCESS) r = sc_file_set_type_attr(file, (const u8*)"\x10\x00", 2); if (r == SC_SUCCESS) r = sc_create_file(p15card->card, file); sc_file_free(file); if (r == SC_SUCCESS) r = sc_change_reference_data(p15card->card, SC_AC_CHV, pin_info->reference, NULL, 0, pin, pin_len, NULL); SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_NORMAL, r); }