/* * Certificates with a related private key are stored in the fid range CE00 - CEFF. The * second byte in the fid matches the key id. * Certificates without a related private key (e.g. CA certificates) are stored in the fid range * CA00 - CAFF. The second byte is a free selected id. */ static int sc_hsm_emu_store_cert(struct sc_pkcs15_card *p15card, struct sc_profile *profile, struct sc_pkcs15_object *object, struct sc_pkcs15_der *data) { struct sc_context *ctx = p15card->card->ctx; struct sc_pkcs15_cert_info *cert_info = (struct sc_pkcs15_cert_info *) object->data; struct sc_pkcs15_object *prkey; sc_path_t path; u8 id[2]; int r; r = sc_pkcs15_find_object_by_id(p15card, SC_PKCS15_TYPE_PRKEY, &cert_info->id , &prkey); if (r == SC_ERROR_OBJECT_NOT_FOUND) { r = sc_hsm_determine_free_id(p15card, CA_CERTIFICATE_PREFIX); LOG_TEST_RET(p15card->card->ctx, r, "Out of identifier to store certificate description"); id[0] = CA_CERTIFICATE_PREFIX; id[1] = r; } else { LOG_TEST_RET(p15card->card->ctx, r, "Error locating matching private key"); id[0] = EE_CERTIFICATE_PREFIX; id[1] = ((struct sc_pkcs15_prkey_info *)prkey->data)->key_reference; } sc_path_set(&path, SC_PATH_TYPE_FILE_ID, id, 2, 0, -1); cert_info->path = path; r = sc_hsm_update_ef(p15card, id[0], id[1], 1, data->value, data->len); return r; }
static int sc_hsm_emu_store_binary(struct sc_pkcs15_card *p15card, struct sc_profile *profile, struct sc_pkcs15_object *object, struct sc_pkcs15_der *data) { struct sc_context *ctx = p15card->card->ctx; struct sc_pkcs15_data_info *data_info = (struct sc_pkcs15_data_info *) object->data; sc_path_t path; u8 id[2]; int r; r = sc_hsm_determine_free_id(p15card, DCOD_PREFIX); LOG_TEST_RET(p15card->card->ctx, r, "Out of identifier to store data description"); if (object->flags & SC_PKCS15_CO_FLAG_PRIVATE) { id[0] = PROT_DATA_PREFIX; } else { id[0] = DATA_PREFIX; } id[1] = r; sc_path_set(&path, SC_PATH_TYPE_FILE_ID, id, 2, 0, -1); data_info->path = path; r = sc_hsm_update_ef(p15card, id[0], id[1], 1, data->value, data->len); return r; }
static int read_file(sc_pkcs15_card_t * p15card, u8 fid[2], u8 *efbin, size_t *len) { sc_path_t path; int r; sc_path_set(&path, SC_PATH_TYPE_FILE_ID, fid, 2, 0, 0); /* look this up with our AID */ path.aid = sc_hsm_aid; /* we don't have a pre-known size of the file */ path.count = -1; if (!p15card->opts.use_file_cache || SC_SUCCESS != sc_pkcs15_read_cached_file(p15card, &path, &efbin, len)) { /* avoid re-selection of SC-HSM */ path.aid.len = 0; r = sc_select_file(p15card->card, &path, NULL); LOG_TEST_RET(p15card->card->ctx, r, "Could not select EF"); r = sc_read_binary(p15card->card, 0, efbin, *len, 0); LOG_TEST_RET(p15card->card->ctx, r, "Could not read EF"); *len = r; if (p15card->opts.use_file_cache) { /* save this with our AID */ path.aid = sc_hsm_aid; sc_pkcs15_cache_file(p15card, &path, efbin, *len); } } return SC_SUCCESS; }
static int do_ls(int argc, char **argv) { u8 buf[256], *cur = buf; int r, count; r = sc_list_files(card, buf, sizeof(buf)); if (r < 0) { check_ret(r, SC_AC_OP_LIST_FILES, "unable to receive file listing", current_file); return -1; } count = r; printf("FileID\tType Size\n"); while (count >= 2) { sc_path_t path; sc_file_t *file = NULL; char filename[10]; int i = 0; int matches = 0; /* construct file name */ sprintf(filename, "%02X%02X", cur[0], cur[1]); /* compare file name against patterns */ for (i = 0; i < argc; i++) { if (pattern_match(argv[i], filename)) { matches = 1; break; } } /* if any filename pattern were given, filter only matching file names */ if (argc == 0 || matches) { if (current_path.type != SC_PATH_TYPE_DF_NAME) { path = current_path; sc_append_path_id(&path, cur, 2); } else { if (sc_path_set(&path, SC_PATH_TYPE_FILE_ID, cur, 2, 0, 0) != SC_SUCCESS) { printf("unable to set path.\n"); die(1); } } r = sc_select_file(card, &path, &file); if (r) { printf(" %02X%02X unable to select file, %s\n", cur[0], cur[1], sc_strerror(r)); } else { file->id = (cur[0] << 8) | cur[1]; print_file(file); sc_file_free(file); } } cur += 2; count -= 2; select_current_path_or_die(); } return 0; }
/* SELECT FILE: call the ISO SELECT FILE implementation and parse * asepcos specific security attributes. */ static int asepcos_select_file(sc_card_t *card, const sc_path_t *in_path, sc_file_t **file) { int r; sc_path_t npath = *in_path; LOG_FUNC_CALLED(card->ctx); if (in_path->type == SC_PATH_TYPE_PATH) { /* check the current DF to avoid unnecessary re-selection of * the MF (as this might invalidate a security status) */ sc_path_t tpath; memset(&tpath, 0, sizeof tpath); r = asepcos_get_current_df_path(card, &tpath); /* workaround: as opensc can't handle paths with file id * and application names in it let's ignore the current * DF if the returned path contains a unsupported tag. */ if (r != SC_ERROR_INVALID_ASN1_OBJECT && r != SC_SUCCESS) return r; if (r == SC_SUCCESS && sc_compare_path_prefix(&tpath, &npath) != 0) { /* remove the currently selected DF from the path */ if (tpath.len == npath.len) { /* we are already in the requested DF */ if (file == NULL) /* no file information requested => * nothing to do */ return SC_SUCCESS; } else { /* shorten path */ r = sc_path_set(&npath, 0, &in_path->value[tpath.len], npath.len - tpath.len, 0, 0); if (r != SC_SUCCESS) return r; if (npath.len == 2) npath.type = SC_PATH_TYPE_FILE_ID; else npath.type = SC_PATH_TYPE_PATH; } } } r = iso_ops->select_file(card, &npath, file); /* XXX: this doesn't look right */ if (file != NULL && *file != NULL) if ((*file)->ef_structure == SC_FILE_EF_UNKNOWN) (*file)->ef_structure = SC_FILE_EF_TRANSPARENT; if (r == SC_SUCCESS && file != NULL && *file != NULL) { r = asepcos_parse_sec_attr(card, *file, (*file)->sec_attr, (*file)->sec_attr_len); if (r != SC_SUCCESS) sc_log(card->ctx, "error parsing security attributes"); } LOG_FUNC_RETURN(card->ctx, r); }
static int do_ls(int argc, char **argv) { u8 buf[256], *cur = buf; int r, count; if (argc) goto usage; r = sc_list_files(card, buf, sizeof(buf)); if (r < 0) { check_ret(r, SC_AC_OP_LIST_FILES, "unable to receive file listing", current_file); return -1; } count = r; printf("FileID\tType Size\n"); while (count >= 2) { sc_path_t path; sc_file_t *file = NULL; if (current_path.type != SC_PATH_TYPE_DF_NAME) { path = current_path; sc_append_path_id(&path, cur, 2); } else { if (sc_path_set(&path, SC_PATH_TYPE_FILE_ID, cur, 2, 0, 0) != SC_SUCCESS) { printf("unable to set path.\n"); die(1); } } r = sc_select_file(card, &path, &file); if (r) { check_ret(r, SC_AC_OP_SELECT, "unable to select file", current_file); return -1; } file->id = (cur[0] << 8) | cur[1]; cur += 2; count -= 2; print_file(file); sc_file_free(file); r = sc_select_file(card, ¤t_path, NULL); if (r) { printf("unable to select parent DF: %s\n", sc_strerror(r)); die(1); } } return 0; usage: puts("Usage: ls"); return -1; }
static int sc_hsm_delete_ef(sc_pkcs15_card_t *p15card, u8 prefix, u8 id) { sc_card_t *card = p15card->card; 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_delete_file(card, &path); LOG_TEST_RET(card->ctx, r, "Could not delete file"); LOG_FUNC_RETURN(card->ctx, r); }
/* * Add a unrelated certificate object and description in PKCS#15 format to the framework */ static int sc_pkcs15emu_sc_hsm_add_cd(sc_pkcs15_card_t * p15card, u8 id) { sc_card_t *card = p15card->card; sc_pkcs15_cert_info_t *cert_info; sc_pkcs15_object_t obj; sc_file_t *file = NULL; sc_path_t path; u8 fid[2]; u8 efbin[512]; const u8 *ptr; size_t len; int r; fid[0] = CD_PREFIX; fid[1] = id; /* Try to select a related EF containing the PKCS#15 description of the data */ sc_path_set(&path, SC_PATH_TYPE_FILE_ID, fid, sizeof(fid), 0, 0); r = sc_select_file(card, &path, &file); if (r != SC_SUCCESS) { return SC_SUCCESS; } sc_file_free(file); r = sc_read_binary(p15card->card, 0, efbin, sizeof(efbin), 0); LOG_TEST_RET(card->ctx, r, "Could not read EF.DCOD"); memset(&obj, 0, sizeof(obj)); ptr = efbin; len = r; r = sc_pkcs15_decode_cdf_entry(p15card, &obj, &ptr, &len); LOG_TEST_RET(card->ctx, r, "Could not decode EF.CD"); cert_info = (sc_pkcs15_cert_info_t *)obj.data; r = sc_pkcs15emu_add_x509_cert(p15card, &obj, cert_info); LOG_TEST_RET(card->ctx, r, "Could not add data object to framework"); return SC_SUCCESS; }
static int sc_pkcs15emu_sc_hsm_read_tokeninfo (sc_pkcs15_card_t * p15card) { sc_card_t *card = p15card->card; sc_path_t path; int r; u8 efbin[512]; LOG_FUNC_CALLED(card->ctx); /* Read token info */ sc_path_set(&path, SC_PATH_TYPE_FILE_ID, (u8 *) "\x2F\x03", 2, 0, 0); r = sc_select_file(card, &path, NULL); LOG_TEST_RET(card->ctx, r, "Could not select EF.TokenInfo"); r = sc_read_binary(p15card->card, 0, efbin, sizeof(efbin), 0); LOG_TEST_RET(card->ctx, r, "Could not read EF.TokenInfo"); r = sc_pkcs15_parse_tokeninfo(card->ctx, p15card->tokeninfo, efbin, r); LOG_TEST_RET(card->ctx, r, "Could not decode EF.TokenInfo"); LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); }
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_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 void unwrap_key(sc_card_t *card, u8 keyid, const char *inf, const char *pin, int force) { sc_cardctl_sc_hsm_wrapped_key_t wrapped_key; struct sc_pin_cmd_data data; u8 keyblob[MAX_WRAPPED_KEY]; const u8 *ptr,*prkd,*cert; FILE *in = NULL; sc_path_t path; u8 fid[2]; char *lpin = NULL; unsigned int cla, tag; int r, keybloblen; size_t len, olen, prkd_len, cert_len; in = fopen(inf, "rb"); if (in == NULL) { perror(inf); return; } if ((keybloblen = fread(keyblob, 1, sizeof(keyblob), in)) < 0) { perror(inf); return; } fclose(in); ptr = keyblob; if ((sc_asn1_read_tag(&ptr, keybloblen, &cla, &tag, &len) != SC_SUCCESS) || ((cla & SC_ASN1_TAG_CONSTRUCTED) != SC_ASN1_TAG_CONSTRUCTED) || ((tag != SC_ASN1_TAG_SEQUENCE)) ){ fprintf(stderr, "Invalid wrapped key format (Outer sequence).\n"); return; } if ((sc_asn1_read_tag(&ptr, len, &cla, &tag, &olen) != SC_SUCCESS) || (cla & SC_ASN1_TAG_CONSTRUCTED) || ((tag != SC_ASN1_TAG_OCTET_STRING)) ){ fprintf(stderr, "Invalid wrapped key format (Key binary).\n"); return; } wrapped_key.wrapped_key = (u8 *)ptr; wrapped_key.wrapped_key_length = olen; ptr += olen; prkd = ptr; prkd_len = determineLength(ptr, keybloblen - (ptr - keyblob)); ptr += prkd_len; cert = ptr; cert_len = determineLength(ptr, keybloblen - (ptr - keyblob)); printf("Wrapped key contains:\n"); printf(" Key blob\n"); if (prkd_len > 0) { printf(" Private Key Description (PRKD)\n"); } if (cert_len > 0) { printf(" Certificate\n"); } if ((prkd_len > 0) && !force) { fid[0] = PRKD_PREFIX; fid[1] = keyid; /* Try to select a related EF containing the PKCS#15 description of the key */ sc_path_set(&path, SC_PATH_TYPE_FILE_ID, fid, sizeof(fid), 0, 0); r = sc_select_file(card, &path, NULL); if (r == SC_SUCCESS) { fprintf(stderr, "Found existing private key description in EF with fid %02x%02x. Please remove key first, select unused key reference or use --force.\n", fid[0], fid[1]); return; } } if ((cert_len > 0) && !force) { fid[0] = EE_CERTIFICATE_PREFIX; fid[1] = keyid; /* Try to select a related EF containing the certificate */ sc_path_set(&path, SC_PATH_TYPE_FILE_ID, fid, sizeof(fid), 0, 0); r = sc_select_file(card, &path, NULL); if (r == SC_SUCCESS) { fprintf(stderr, "Found existing certificate in EF with fid %02x%02x. Please remove certificate first, select unused key reference or use --force.\n", fid[0], fid[1]); return; } } if (pin == NULL) { printf("Enter User PIN : "); util_getpass(&lpin, NULL, stdin); printf("\n"); } else { lpin = (u8 *)pin; } memset(&data, 0, sizeof(data)); data.cmd = SC_PIN_CMD_VERIFY; data.pin_type = SC_AC_CHV; data.pin_reference = ID_USER_PIN; data.pin1.data = lpin; data.pin1.len = strlen(lpin); r = sc_pin_cmd(card, &data, NULL); if (r < 0) { fprintf(stderr, "PIN verification failed with %s\n", sc_strerror(r)); return; } if (pin == NULL) { free(lpin); } if (force) { fid[0] = KEY_PREFIX; fid[1] = keyid; sc_path_set(&path, SC_PATH_TYPE_FILE_ID, fid, 2, 0, -1); sc_delete_file(card, &path); } wrapped_key.key_id = keyid; r = sc_card_ctl(card, SC_CARDCTL_SC_HSM_UNWRAP_KEY, (void *)&wrapped_key); if (r == SC_ERROR_INS_NOT_SUPPORTED) { // Not supported or not initialized for key shares return; } if (r < 0) { fprintf(stderr, "sc_card_ctl(*, SC_CARDCTL_SC_HSM_UNWRAP_KEY, *) failed with %s\n", sc_strerror(r)); return; } if (prkd_len > 0) { r = update_ef(card, PRKD_PREFIX, keyid, force, prkd, prkd_len); if (r < 0) { fprintf(stderr, "Updating private key description failed with %s\n", sc_strerror(r)); return; } } if (cert_len > 0) { r = update_ef(card, EE_CERTIFICATE_PREFIX, keyid, force, cert, cert_len); if (r < 0) { fprintf(stderr, "Updating certificate failed with %s\n", sc_strerror(r)); return; } } printf("Key successfully imported\n"); }
/* * Initialize PKCS#15 emulation with user PIN, private keys, certificate and data objects * */ static int sc_pkcs15emu_sc_hsm_init (sc_pkcs15_card_t * p15card) { sc_card_t *card = p15card->card; sc_file_t *file = NULL; sc_path_t path; u8 filelist[MAX_EXT_APDU_LENGTH]; int filelistlength; int r, i; sc_cvc_t devcert; struct sc_app_info *appinfo; struct sc_pkcs15_auth_info pin_info; struct sc_pkcs15_object pin_obj; u8 efbin[512]; u8 *ptr; size_t len; LOG_FUNC_CALLED(card->ctx); appinfo = calloc(1, sizeof(struct sc_app_info)); if (appinfo == NULL) { LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY); } appinfo->aid = sc_hsm_aid; appinfo->ddo.aid = sc_hsm_aid; p15card->app = appinfo; sc_path_set(&path, SC_PATH_TYPE_DF_NAME, sc_hsm_aid.value, sc_hsm_aid.len, 0, 0); r = sc_select_file(card, &path, &file); LOG_TEST_RET(card->ctx, r, "Could not select SmartCard-HSM application"); p15card->card->version.hw_major = 24; /* JCOP 2.4.1r3 */ p15card->card->version.hw_minor = 13; p15card->card->version.fw_major = file->prop_attr[file->prop_attr_len - 2]; p15card->card->version.fw_minor = file->prop_attr[file->prop_attr_len - 1]; sc_file_free(file); /* Read device certificate to determine serial number */ len = sizeof efbin; r = read_file(p15card, (u8 *) "\x2F\x02", efbin, &len); LOG_TEST_RET(card->ctx, r, "Could not select EF.C_DevAut"); ptr = efbin; memset(&devcert, 0 ,sizeof(devcert)); r = sc_pkcs15emu_sc_hsm_decode_cvc(p15card, (const u8 **)&ptr, &len, &devcert); LOG_TEST_RET(card->ctx, r, "Could not decode EF.C_DevAut"); sc_pkcs15emu_sc_hsm_read_tokeninfo(p15card); if (p15card->tokeninfo->label == NULL) { p15card->tokeninfo->label = strdup("SmartCard-HSM"); if (p15card->tokeninfo->label == NULL) LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY); } if ((p15card->tokeninfo->manufacturer_id != NULL) && !strcmp("(unknown)", p15card->tokeninfo->manufacturer_id)) { free(p15card->tokeninfo->manufacturer_id); p15card->tokeninfo->manufacturer_id = NULL; } if (p15card->tokeninfo->manufacturer_id == NULL) { p15card->tokeninfo->manufacturer_id = strdup("www.CardContact.de"); if (p15card->tokeninfo->manufacturer_id == NULL) LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY); } appinfo->label = strdup(p15card->tokeninfo->label); if (appinfo->label == NULL) LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY); len = strnlen(devcert.chr, sizeof devcert.chr); /* Strip last 5 digit sequence number from CHR */ assert(len >= 8); len -= 5; p15card->tokeninfo->serial_number = calloc(len + 1, 1); if (p15card->tokeninfo->serial_number == NULL) LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY); memcpy(p15card->tokeninfo->serial_number, devcert.chr, len); *(p15card->tokeninfo->serial_number + len) = 0; sc_hsm_set_serialnr(card, p15card->tokeninfo->serial_number); sc_pkcs15emu_sc_hsm_free_cvc(&devcert); memset(&pin_info, 0, sizeof(pin_info)); memset(&pin_obj, 0, sizeof(pin_obj)); pin_info.auth_id.len = 1; pin_info.auth_id.value[0] = 1; pin_info.path.aid = sc_hsm_aid; pin_info.auth_type = SC_PKCS15_PIN_AUTH_TYPE_PIN; pin_info.attrs.pin.reference = 0x81; pin_info.attrs.pin.flags = SC_PKCS15_PIN_FLAG_LOCAL|SC_PKCS15_PIN_FLAG_INITIALIZED|SC_PKCS15_PIN_FLAG_EXCHANGE_REF_DATA; pin_info.attrs.pin.type = SC_PKCS15_PIN_TYPE_ASCII_NUMERIC; pin_info.attrs.pin.min_length = 6; pin_info.attrs.pin.stored_length = 0; pin_info.attrs.pin.max_length = 15; pin_info.attrs.pin.pad_char = '\0'; pin_info.tries_left = 3; pin_info.max_tries = 3; strlcpy(pin_obj.label, "UserPIN", sizeof(pin_obj.label)); pin_obj.flags = SC_PKCS15_CO_FLAG_PRIVATE|SC_PKCS15_CO_FLAG_MODIFIABLE; r = sc_pkcs15emu_add_pin_obj(p15card, &pin_obj, &pin_info); if (r < 0) LOG_FUNC_RETURN(card->ctx, r); memset(&pin_info, 0, sizeof(pin_info)); memset(&pin_obj, 0, sizeof(pin_obj)); pin_info.auth_id.len = 1; pin_info.auth_id.value[0] = 2; pin_info.path.aid = sc_hsm_aid; pin_info.auth_type = SC_PKCS15_PIN_AUTH_TYPE_PIN; pin_info.attrs.pin.reference = 0x88; pin_info.attrs.pin.flags = SC_PKCS15_PIN_FLAG_LOCAL|SC_PKCS15_PIN_FLAG_INITIALIZED|SC_PKCS15_PIN_FLAG_UNBLOCK_DISABLED|SC_PKCS15_PIN_FLAG_SO_PIN; pin_info.attrs.pin.type = SC_PKCS15_PIN_TYPE_BCD; pin_info.attrs.pin.min_length = 16; pin_info.attrs.pin.stored_length = 0; pin_info.attrs.pin.max_length = 16; pin_info.attrs.pin.pad_char = '\0'; pin_info.tries_left = 15; pin_info.max_tries = 15; strlcpy(pin_obj.label, "SOPIN", sizeof(pin_obj.label)); pin_obj.flags = SC_PKCS15_CO_FLAG_PRIVATE; r = sc_pkcs15emu_add_pin_obj(p15card, &pin_obj, &pin_info); if (r < 0) LOG_FUNC_RETURN(card->ctx, r); filelistlength = sc_list_files(card, filelist, sizeof(filelist)); LOG_TEST_RET(card->ctx, filelistlength, "Could not enumerate file and key identifier"); for (i = 0; i < filelistlength; i += 2) { switch(filelist[i]) { case KEY_PREFIX: r = sc_pkcs15emu_sc_hsm_add_prkd(p15card, filelist[i + 1]); break; case DCOD_PREFIX: r = sc_pkcs15emu_sc_hsm_add_dcod(p15card, filelist[i + 1]); break; case CD_PREFIX: r = sc_pkcs15emu_sc_hsm_add_cd(p15card, filelist[i + 1]); break; } if (r != SC_SUCCESS) { sc_log(card->ctx, "Error %d adding elements to framework", r); } } LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); }
/* * Add a key and the key description in PKCS#15 format to the framework */ static int sc_pkcs15emu_sc_hsm_add_prkd(sc_pkcs15_card_t * p15card, u8 keyid) { sc_card_t *card = p15card->card; sc_pkcs15_cert_info_t cert_info; sc_pkcs15_object_t cert_obj; struct sc_pkcs15_object prkd; sc_pkcs15_prkey_info_t *key_info; u8 fid[2]; /* enough to hold a complete certificate */ u8 efbin[4096]; u8 *ptr; size_t len; int r; fid[0] = PRKD_PREFIX; fid[1] = keyid; /* Try to select a related EF containing the PKCS#15 description of the key */ len = sizeof efbin; r = read_file(p15card, fid, efbin, &len); LOG_TEST_RET(card->ctx, r, "Could not read EF.PRKD"); ptr = efbin; memset(&prkd, 0, sizeof(prkd)); r = sc_pkcs15_decode_prkdf_entry(p15card, &prkd, (const u8 **)&ptr, &len); LOG_TEST_RET(card->ctx, r, "Could not decode EF.PRKD"); /* All keys require user PIN authentication */ prkd.auth_id.len = 1; prkd.auth_id.value[0] = 1; /* * Set private key flag as all keys are private anyway */ prkd.flags |= SC_PKCS15_CO_FLAG_PRIVATE; key_info = (sc_pkcs15_prkey_info_t *)prkd.data; key_info->key_reference = keyid; key_info->path.aid.len = 0; if (prkd.type == SC_PKCS15_TYPE_PRKEY_RSA) { r = sc_pkcs15emu_add_rsa_prkey(p15card, &prkd, key_info); } else { r = sc_pkcs15emu_add_ec_prkey(p15card, &prkd, key_info); } LOG_TEST_RET(card->ctx, r, "Could not add private key to framework"); /* Check if we also have a certificate for the private key */ fid[0] = EE_CERTIFICATE_PREFIX; len = sizeof efbin; r = read_file(p15card, fid, efbin, &len); LOG_TEST_RET(card->ctx, r, "Could not read EF"); if (r < 0) { return SC_SUCCESS; } if (efbin[0] == 0x67) { /* Decode CSR and create public key object */ sc_pkcs15emu_sc_hsm_add_pubkey(p15card, efbin, len, key_info, prkd.label); return SC_SUCCESS; /* Ignore any errors */ } if (efbin[0] != 0x30) { return SC_SUCCESS; } memset(&cert_info, 0, sizeof(cert_info)); memset(&cert_obj, 0, sizeof(cert_obj)); cert_info.id = key_info->id; sc_path_set(&cert_info.path, SC_PATH_TYPE_FILE_ID, fid, 2, 0, 0); cert_info.path.count = -1; if (p15card->opts.use_file_cache) { /* look this up with our AID, which should already be cached from the * call to `read_file`. This may have the side effect that OpenSC's * caching layer re-selects our applet *if the cached file cannot be * found/used* and we may loose the authentication status. We assume * that caching works perfectly without this side effect. */ cert_info.path.aid = sc_hsm_aid; } strlcpy(cert_obj.label, prkd.label, sizeof(cert_obj.label)); r = sc_pkcs15emu_add_x509_cert(p15card, &cert_obj, &cert_info); LOG_TEST_RET(card->ctx, r, "Could not add certificate"); return SC_SUCCESS; }
/* * Add a key and the key description in PKCS#15 format to the framework */ static int sc_pkcs15emu_sc_hsm_add_prkd(sc_pkcs15_card_t * p15card, u8 keyid) { sc_card_t *card = p15card->card; sc_pkcs15_cert_info_t cert_info; sc_pkcs15_object_t cert_obj; struct sc_pkcs15_object prkd; sc_pkcs15_prkey_info_t *key_info; sc_file_t *file = NULL; sc_path_t path; u8 fid[2]; u8 efbin[512]; u8 *ptr; size_t len; int r; fid[0] = PRKD_PREFIX; fid[1] = keyid; /* Try to select a related EF containing the PKCS#15 description of the key */ sc_path_set(&path, SC_PATH_TYPE_FILE_ID, fid, sizeof(fid), 0, 0); r = sc_select_file(card, &path, &file); if (r != SC_SUCCESS) { return SC_SUCCESS; } sc_file_free(file); r = sc_read_binary(p15card->card, 0, efbin, sizeof(efbin), 0); LOG_TEST_RET(card->ctx, r, "Could not read EF.PRKD"); memset(&prkd, 0, sizeof(prkd)); ptr = efbin; len = r; r = sc_pkcs15_decode_prkdf_entry(p15card, &prkd, (const u8 **)&ptr, &len); LOG_TEST_RET(card->ctx, r, "Could not decode EF.PRKD"); /* All keys require user PIN authentication */ prkd.auth_id.len = 1; prkd.auth_id.value[0] = 1; /* * Set private key flag as all keys are private anyway */ prkd.flags |= SC_PKCS15_CO_FLAG_PRIVATE; key_info = (sc_pkcs15_prkey_info_t *)prkd.data; key_info->key_reference = keyid; if (prkd.type == SC_PKCS15_TYPE_PRKEY_RSA) { r = sc_pkcs15emu_add_rsa_prkey(p15card, &prkd, key_info); } else { r = sc_pkcs15emu_add_ec_prkey(p15card, &prkd, key_info); } LOG_TEST_RET(card->ctx, r, "Could not add private key to framework"); /* Check if we also have a certificate for the private key */ fid[0] = EE_CERTIFICATE_PREFIX; sc_path_set(&path, SC_PATH_TYPE_FILE_ID, fid, sizeof(fid), 0, 0); r = sc_select_file(card, &path, &file); if (r != SC_SUCCESS) { return SC_SUCCESS; } sc_file_free(file); /* Check if the certificate is a X.509 certificate */ r = sc_read_binary(p15card->card, 0, efbin, 1, 0); if (r < 0) { return SC_SUCCESS; } if (efbin[0] == 0x67) { /* Decode CSR and create public key object */ sc_pkcs15emu_sc_hsm_add_pubkey(p15card, key_info, prkd.label); return SC_SUCCESS; /* Ignore any errors */ } if (efbin[0] != 0x30) { return SC_SUCCESS; } memset(&cert_info, 0, sizeof(cert_info)); memset(&cert_obj, 0, sizeof(cert_obj)); cert_info.id = key_info->id; cert_info.path = path; cert_info.path.count = -1; strlcpy(cert_obj.label, prkd.label, sizeof(cert_obj.label)); r = sc_pkcs15emu_add_x509_cert(p15card, &cert_obj, &cert_info); LOG_TEST_RET(card->ctx, r, "Could not add certificate"); return SC_SUCCESS; }
int main(int argc, char * const argv[]) { int err = 0, r, c, long_optind = 0; int action_count = 0; int do_initialize = 0; int do_unblock = 0; int do_change_admin = 0; sc_path_t path; const char *opt_so_pin = NULL; const char *opt_pin = NULL; const char *opt_serial_number = NULL; const char *opt_new_key = NULL; sc_context_param_t ctx_param; setbuf(stderr, NULL); setbuf(stdout, NULL); while (1) { c = getopt_long(argc, argv, "XUCr:wv", options, &long_optind); if (c == -1) break; if (c == '?') util_print_usage_and_die(app_name, options, option_help, NULL); switch (c) { case 'X': do_initialize = 1; action_count++; break; case OPT_SO_PIN: util_get_pin(optarg, &opt_so_pin); break; case OPT_PIN: util_get_pin(optarg, &opt_pin); break; case OPT_SERIAL_NUMBER: util_get_pin(optarg, &opt_serial_number); break; case OPT_NEW_KEY: util_get_pin(optarg, &opt_new_key); break; case 'U': do_unblock = 1; action_count++; break; case 'C': do_change_admin = 1; action_count++; break; case 'r': opt_reader = optarg; break; case 'v': verbose++; break; case 'w': opt_wait = 1; break; } } CRYPTO_malloc_init(); ERR_load_crypto_strings(); OpenSSL_add_all_algorithms(); memset(&ctx_param, 0, sizeof(sc_context_param_t)); ctx_param.app_name = app_name; r = sc_context_create(&ctx, &ctx_param); if (r != SC_SUCCESS) { fprintf(stderr, "Failed to establish context: %s\n", sc_strerror(r)); exit(1); } /* Only change if not in opensc.conf */ if (verbose > 1 && ctx->debug == 0) { ctx->debug = verbose; sc_ctx_log_to_file(ctx, "stderr"); } r = util_connect_card(ctx, &card, opt_reader, opt_wait, verbose); if (r != SC_SUCCESS) { if (r < 0) { fprintf(stderr, "Failed to connect to card: %s\n", sc_strerror(err)); } goto end; } sc_path_set(&path, SC_FILE_TYPE_WORKING_EF, gids_aid.value, gids_aid.len, 0, 0); r = sc_select_file(card, &path, NULL); if (r != SC_SUCCESS) { fprintf(stderr, "Failed to select application: %s\n", sc_strerror(r)); goto fail; } if (do_initialize && initialize(card, opt_so_pin, opt_pin, opt_serial_number)) goto fail; if (do_unblock && unblock(card, opt_so_pin, opt_pin)) goto fail; if (do_change_admin && changeAdminKey(card, opt_so_pin, opt_new_key)) goto fail; if (action_count == 0) { print_info(card); } err = 0; goto end; fail: err = 1; end: if (card) { sc_unlock(card); sc_disconnect_card(card); } if (ctx) sc_release_context(ctx); ERR_print_errors_fp(stderr); return err; }
int main(int argc, char * const argv[]) { int err = 0, r, c, long_optind = 0; int action_count = 0; int do_initialize = 0; int do_import_dkek_share = 0; int do_create_dkek_share = 0; int do_wrap_key = 0; int do_unwrap_key = 0; sc_path_t path; sc_file_t *file = NULL; const char *opt_so_pin = NULL; const char *opt_pin = NULL; const char *opt_filename = NULL; char *opt_password = NULL; int opt_retry_counter = 3; int opt_dkek_shares = -1; int opt_key_reference = -1; int opt_password_shares_threshold = -1; int opt_password_shares_total = -1; int opt_force = 0; int opt_iter = 10000000; sc_context_param_t ctx_param; setbuf(stderr, NULL); setbuf(stdout, NULL); while (1) { c = getopt_long(argc, argv, "XC:I:W:U:s:i:fr:wv", options, &long_optind); if (c == -1) break; if (c == '?') util_print_usage_and_die(app_name, options, option_help, NULL); switch (c) { case 'X': do_initialize = 1; action_count++; break; case 'C': do_create_dkek_share = 1; opt_filename = optarg; action_count++; break; case 'I': do_import_dkek_share = 1; opt_filename = optarg; action_count++; break; case 'W': do_wrap_key = 1; opt_filename = optarg; action_count++; break; case 'U': do_unwrap_key = 1; opt_filename = optarg; action_count++; break; case OPT_PASSWORD: opt_password = optarg; break; case OPT_SO_PIN: opt_so_pin = optarg; break; case OPT_PIN: opt_pin = optarg; break; case OPT_RETRY: opt_retry_counter = atol(optarg); break; case OPT_PASSWORD_SHARES_THRESHOLD: opt_password_shares_threshold = atol(optarg); break; case OPT_PASSWORD_SHARES_TOTAL: opt_password_shares_total = atol(optarg); break; case 's': opt_dkek_shares = atol(optarg); break; case 'f': opt_force = 1; break; case 'i': opt_key_reference = atol(optarg); break; case 'r': opt_reader = optarg; break; case 'v': verbose++; break; case 'w': opt_wait = 1; break; } } CRYPTO_malloc_init(); ERR_load_crypto_strings(); OpenSSL_add_all_algorithms(); memset(&ctx_param, 0, sizeof(sc_context_param_t)); ctx_param.app_name = app_name; r = sc_context_create(&ctx, &ctx_param); if (r != SC_SUCCESS) { fprintf(stderr, "Failed to establish context: %s\n", sc_strerror(r)); return 1; } /* Only change if not in opensc.conf */ if (verbose > 1 && ctx->debug == 0) { ctx->debug = verbose; sc_ctx_log_to_file(ctx, "stderr"); } err = util_connect_card(ctx, &card, opt_reader, opt_wait, verbose); if (r != SC_SUCCESS) { fprintf(stderr, "Failed to connect to card: %s\n", sc_strerror(r)); goto end; } sc_path_set(&path, SC_PATH_TYPE_DF_NAME, sc_hsm_aid.value, sc_hsm_aid.len, 0, 0); r = sc_select_file(card, &path, &file); if (r != SC_SUCCESS) { fprintf(stderr, "Failed to select application: %s\n", sc_strerror(r)); goto end; } if (do_initialize) { initialize(card, opt_so_pin, opt_pin, opt_retry_counter, opt_dkek_shares); } if (do_create_dkek_share) { create_dkek_share(card, opt_filename, opt_iter, opt_password, opt_password_shares_threshold, opt_password_shares_total); } if (do_import_dkek_share) { import_dkek_share(card, opt_filename, opt_iter, opt_password, opt_password_shares_total); } if (do_wrap_key) { wrap_key(card, opt_key_reference, opt_filename, opt_pin); } if (do_unwrap_key) { unwrap_key(card, opt_key_reference, opt_filename, opt_pin, opt_force); } if (action_count == 0) { print_info(card, file); } end: if (card) { sc_unlock(card); sc_disconnect_card(card); } if (ctx) sc_release_context(ctx); ERR_print_errors_fp(stderr); return err; }
static void wrap_key(sc_card_t *card, u8 keyid, const char *outf, const char *pin) { sc_cardctl_sc_hsm_wrapped_key_t wrapped_key; struct sc_pin_cmd_data data; sc_file_t *file = NULL; sc_path_t path; FILE *out = NULL; u8 fid[2]; u8 ef_prkd[MAX_PRKD]; u8 ef_cert[MAX_CERT]; u8 keyblob[MAX_WRAPPED_KEY]; u8 *key; u8 *ptr; char *lpin = NULL; size_t key_len; int r, ef_prkd_len, ef_cert_len; if (pin == NULL) { printf("Enter User PIN : "); util_getpass(&lpin, NULL, stdin); printf("\n"); } else { lpin = (u8 *)pin; } memset(&data, 0, sizeof(data)); data.cmd = SC_PIN_CMD_VERIFY; data.pin_type = SC_AC_CHV; data.pin_reference = ID_USER_PIN; data.pin1.data = lpin; data.pin1.len = strlen(lpin); r = sc_pin_cmd(card, &data, NULL); if (r < 0) { fprintf(stderr, "PIN verification failed with %s\n", sc_strerror(r)); return; } if (pin == NULL) { free(lpin); } wrapped_key.key_id = keyid; r = sc_card_ctl(card, SC_CARDCTL_SC_HSM_WRAP_KEY, (void *)&wrapped_key); if (r == SC_ERROR_INS_NOT_SUPPORTED) { // Not supported or not initialized for key shares return; } if (r < 0) { fprintf(stderr, "sc_card_ctl(*, SC_CARDCTL_SC_HSM_WRAP_KEY, *) failed with %s\n", sc_strerror(r)); return; } fid[0] = PRKD_PREFIX; fid[1] = keyid; ef_prkd_len = 0; /* Try to select a related EF containing the PKCS#15 description of the key */ sc_path_set(&path, SC_PATH_TYPE_FILE_ID, fid, sizeof(fid), 0, 0); r = sc_select_file(card, &path, NULL); if (r == SC_SUCCESS) { ef_prkd_len = sc_read_binary(card, 0, ef_prkd, sizeof(ef_prkd), 0); if (ef_prkd_len < 0) { fprintf(stderr, "Error reading PRKD file %s. Skipping.\n", sc_strerror(ef_prkd_len)); ef_prkd_len = 0; } else { ef_prkd_len = determineLength(ef_prkd, ef_prkd_len); } } fid[0] = EE_CERTIFICATE_PREFIX; fid[1] = keyid; ef_cert_len = 0; /* Try to select a related EF containing the certificate for the key */ sc_path_set(&path, SC_PATH_TYPE_FILE_ID, fid, sizeof(fid), 0, 0); r = sc_select_file(card, &path, NULL); if (r == SC_SUCCESS) { ef_cert_len = sc_read_binary(card, 0, ef_cert, sizeof(ef_cert), 0); if (ef_cert_len < 0) { fprintf(stderr, "Error reading certificate %s. Skipping\n", sc_strerror(ef_cert_len)); ef_cert_len = 0; } else { ef_cert_len = determineLength(ef_cert, ef_cert_len); } } ptr = keyblob; // Encode key in octet string object sc_asn1_write_element(card->ctx, SC_ASN1_OCTET_STRING, wrapped_key.wrapped_key, wrapped_key.wrapped_key_length, &key, &key_len); memcpy(ptr, key, key_len); ptr += key_len; free(key); // Add private key description if (ef_prkd_len > 0) { memcpy(ptr, ef_prkd, ef_prkd_len); ptr += ef_prkd_len; } // Add certificate if (ef_cert_len > 0) { memcpy(ptr, ef_cert, ef_cert_len); ptr += ef_cert_len; } // Encode key in octet string object sc_asn1_write_element(card->ctx, SC_ASN1_SEQUENCE|SC_ASN1_CONS, keyblob, ptr - keyblob, &key, &key_len); out = fopen(outf, "wb"); if (out == NULL) { perror(outf); free(key); return; } if (fwrite(key, 1, key_len, out) != key_len) { perror(outf); free(key); return; } free(key); fclose(out); }
static int do_find(int argc, char **argv) { u8 fid[2], end[2]; sc_path_t path; int r; fid[0] = 0; fid[1] = 0; end[0] = 0xFF; end[1] = 0xFF; switch (argc) { case 2: if (arg_to_fid(argv[1], end) != 0) return usage(do_find); /* fall through */ case 1: if (arg_to_fid(argv[0], fid) != 0) return usage(do_find); /* fall through */ case 0: break; default: return usage(do_find); } printf("FileID\tType Size\n"); while (1) { sc_file_t *file = NULL; printf("(%02X%02X)\r", fid[0], fid[1]); fflush(stdout); if (current_path.type != SC_PATH_TYPE_DF_NAME) { path = current_path; sc_append_path_id(&path, fid, sizeof fid); } else { if (sc_path_set(&path, SC_PATH_TYPE_FILE_ID, fid, 2, 0, 0) != SC_SUCCESS) { printf("unable to set path.\n"); die(1); } } r = sc_select_file(card, &path, &file); switch (r) { case SC_SUCCESS: file->id = (fid[0] << 8) | fid[1]; print_file(file); sc_file_free(file); select_current_path_or_die(); break; case SC_ERROR_NOT_ALLOWED: case SC_ERROR_SECURITY_STATUS_NOT_SATISFIED: printf("(%02X%02X)\t%s\n", fid[0], fid[1], sc_strerror(r)); break; } if (fid[0] == end[0] && fid[1] == end[1]) break; fid[1] = fid[1] + 1; if (fid[1] == 0) fid[0] = fid[0] + 1; } return 0; }