📄 pkcs15-lib.c
字号:
/* * Initialize Cards according to PKCS#15. * * This is a fill in the blanks sort of exercise. You need a * profile that describes characteristics of your card, and the * application specific layout on the card. This program will * set up the card according to this specification (including * PIN initialization etc) and create the corresponding PKCS15 * structure. * * There are a very few tasks that are too card specific to have * a generic implementation; that is how PINs and keys are stored * on the card. These should be implemented in pkcs15-<cardname>.c * * Copyright (C) 2002, Olaf Kirch <okir@lst.de> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */#ifdef HAVE_CONFIG_H#include <config.h>#endif#include <stdio.h>#include <stdlib.h>#include <ctype.h>#include <stdarg.h>#include <string.h>#include <limits.h>#ifdef HAVE_STRINGS_H#include <strings.h>#endif#include <assert.h>#ifdef HAVE_OPENSSL#include <openssl/bn.h>#include <openssl/evp.h>#include <openssl/pem.h>#include <openssl/err.h>#include <openssl/rand.h>#include <openssl/rsa.h>#include <openssl/pkcs12.h>#endif#include <opensc/pkcs15.h>#include "profile.h"#include "pkcs15-init.h"#include <opensc/cardctl.h>/* Default ID for new key/pin */#define DEFAULT_ID 0x45#define DEFAULT_PRKEY_FLAGS 0x1d#define DEFAULT_PUBKEY_FLAGS 0x02#define DEFAULT_CERT_FLAGS 0x02#define DEFAULT_DATA_FLAGS 0x03/* Handle encoding of PKCS15 on the card */typedef int (*pkcs15_encoder)(struct sc_context *, struct sc_pkcs15_card *, u8 **, size_t *);static int sc_pkcs15init_store_data(struct sc_pkcs15_card *, struct sc_profile *, unsigned int, sc_pkcs15_der_t *, struct sc_path *);static size_t sc_pkcs15init_keybits(sc_pkcs15_bignum_t *);static int sc_pkcs15init_update_dir(struct sc_pkcs15_card *, struct sc_profile *profile, struct sc_app_info *app);static int sc_pkcs15init_update_tokeninfo(struct sc_pkcs15_card *, struct sc_profile *profile);static int sc_pkcs15init_update_odf(struct sc_pkcs15_card *, struct sc_profile *profile);static int sc_pkcs15init_add_object(struct sc_pkcs15_card *, struct sc_profile *profile, unsigned int df_type, struct sc_pkcs15_object *);static int sc_pkcs15init_map_usage(unsigned long, int);static int set_so_pin_from_card(struct sc_pkcs15_card *, struct sc_profile *);static int set_user_pin_from_authid(struct sc_pkcs15_card *, struct sc_profile *, struct sc_pkcs15_id *);static int do_select_parent(struct sc_profile *, struct sc_card *, struct sc_file *, struct sc_file **);static int aodf_add_pin(struct sc_pkcs15_card *, struct sc_profile *, const struct sc_pkcs15_pin_info *, const char *);static int check_key_compatibility(struct sc_pkcs15_card *, struct sc_pkcs15_prkey *, unsigned int, unsigned int, unsigned int);static int prkey_fixup(sc_pkcs15_prkey_t *);static int prkey_bits(sc_pkcs15_prkey_t *);static int prkey_pkcs15_algo(sc_pkcs15_prkey_t *);static int select_id(struct sc_pkcs15_card *, int, struct sc_pkcs15_id *);static struct sc_pkcs15_df * find_df_by_type(struct sc_pkcs15_card *, int);static void default_error_handler(const char *fmt, ...);static void default_debug_handler(const char *fmt, ...);/* Card specific functions */extern struct sc_pkcs15init_operations sc_pkcs15init_gpk_operations;extern struct sc_pkcs15init_operations sc_pkcs15init_miocos_operations;extern struct sc_pkcs15init_operations sc_pkcs15init_cflex_operations;extern struct sc_pkcs15init_operations sc_pkcs15init_etoken_operations;static struct sc_pkcs15init_callbacks default_callbacks = { default_error_handler, default_debug_handler};static struct sc_pkcs15init_callbacks *callbacks = &default_callbacks;#define p15init_error callbacks->error#define p15init_debug callbacks->debug/* * Set the application callbacks */voidsc_pkcs15init_set_callbacks(struct sc_pkcs15init_callbacks *cb){ callbacks = cb;}/* Returns 1 if the a profile was found in the card's card_driver block * in the config file, or 0 otherwise. * card_prof_name is a PATH_MAX -sized buffer that will hold the profile name */static int get_profile_from_config(struct sc_card *card, char *card_prof_name){ struct sc_context *ctx = card->ctx; const char *tmp; scconf_block **blocks, *blk; int i; for (i = 0; ctx->conf_blocks[i]; i++) { blocks = scconf_find_blocks(ctx->conf, ctx->conf_blocks[i], "card_driver", card->driver->short_name); blk = blocks[0]; free(blocks); if (blk == NULL) continue; tmp = scconf_get_str(blk, "profile", NULL); if (tmp != NULL) { strncpy(card_prof_name, tmp, PATH_MAX); return 1; } } return 0;}/* * Set up profile */intsc_pkcs15init_bind(struct sc_card *card, const char *name, const char *card_profile_name, struct sc_profile **result){ struct sc_profile *profile; const char *driver = card->driver->short_name; char card_prof_name[PATH_MAX]; int r; /* Put the card into administrative mode */ r = sc_pkcs15init_set_lifecycle(card, SC_CARDCTRL_LIFECYCLE_ADMIN); if (r < 0 && r != SC_ERROR_NOT_SUPPORTED) return r; profile = sc_profile_new(); profile->cbs = callbacks; if (!strcasecmp(driver, "GPK")) profile->ops = &sc_pkcs15init_gpk_operations; else if (!strcasecmp(driver, "MioCOS")) profile->ops = &sc_pkcs15init_miocos_operations; else if (!strcasecmp(driver, "flex")) profile->ops = &sc_pkcs15init_cflex_operations; else if (!strcasecmp(driver, "eToken")) profile->ops = &sc_pkcs15init_etoken_operations; else { p15init_error("Unsupported card driver %s", driver); sc_profile_free(profile); return SC_ERROR_NOT_SUPPORTED; } /* 1. Use card_profile_name if present, * 2. otherwise look in the config file, or * 3. otherwise use the default profile name. */ if (card_profile_name != NULL) strcpy(card_prof_name, card_profile_name); /* 1 */ else if (!get_profile_from_config(card, card_prof_name)) /* 2 */ strcpy(card_prof_name, driver); /* 3 */ if ((r = sc_profile_load(profile, name)) < 0 || (r = sc_profile_load(profile, card_prof_name)) < 0 || (r = sc_profile_finish(profile)) < 0) { fprintf(stderr, "Failed to load profile: %s\n", sc_strerror(r)); sc_profile_free(profile); return r; } *result = profile; if (r == 0) *result = profile; return r;}voidsc_pkcs15init_unbind(struct sc_profile *profile){ sc_profile_free(profile);}/* * Set the card's lifecycle */intsc_pkcs15init_set_lifecycle(sc_card_t *card, int lcycle){ return sc_card_ctl(card, SC_CARDCTL_LIFECYCLE_SET, &lcycle);}/* * Erase the card */intsc_pkcs15init_erase_card(struct sc_card *card, struct sc_profile *profile){ if (profile->ops->erase_card == NULL) return SC_ERROR_NOT_SUPPORTED; return profile->ops->erase_card(profile, card);}intsc_pkcs15init_erase_card_recursively(struct sc_card *card, struct sc_profile *profile, int so_pin_ref){ struct sc_pkcs15_card *p15orig = profile->p15_card; struct sc_pkcs15_pin_info sopin, temp; struct sc_file *df = profile->df_info->file, *dir; int r; /* Frob: need to tell the upper layers about the SO PIN id */ sc_profile_get_pin_info(profile, SC_PKCS15INIT_SO_PIN, &sopin); if (so_pin_ref != -1) { temp = sopin; temp.reference = so_pin_ref; sc_profile_set_pin_info(profile, SC_PKCS15INIT_SO_PIN, &temp); } else { struct sc_pkcs15_card *p15card = NULL; card->ctx->log_errors = 0; if (sc_pkcs15_bind(card, &p15card) >= 0) { set_so_pin_from_card(p15card, profile); profile->p15_card = p15card; } card->ctx->log_errors = 1; } /* Delete EF(DIR). This may not be very nice * against other applications that use this file, but * extremely useful for testing :) * Note we need to delete if before the DF because we create * it *after* the DF. Some cards (e.g. the cryptoflex) want * us to delete file in reverse order of creation. * */ if (sc_profile_get_file(profile, "DIR", &dir) >= 0) { r = sc_pkcs15init_rmdir(card, profile, dir); sc_file_free(dir); if (r < 0 && r != SC_ERROR_FILE_NOT_FOUND) goto out; } card->ctx->log_errors = 0; r = sc_select_file(card, &df->path, &df); card->ctx->log_errors = 1; if (r >= 0) { r = sc_pkcs15init_rmdir(card, profile, df); sc_file_free(df); } if (r == SC_ERROR_FILE_NOT_FOUND) r = 0; /* Unfrob the SO pin reference, and return */out: sc_profile_set_pin_info(profile, SC_PKCS15INIT_SO_PIN, &sopin); sc_profile_forget_secrets(profile, SC_AC_CHV, -1); sc_free_apps(card); if (profile->p15_card != p15orig) { sc_pkcs15_unbind(profile->p15_card); profile->p15_card = p15orig; } return r;}/* * Try to delete a file (and, in the DF case, its contents). * Note that this will not work if a pkcs#15 file's ERASE AC * references a pin other than the SO pin. */intsc_pkcs15init_rmdir(struct sc_card *card, struct sc_profile *profile, struct sc_file *df){ u8 buffer[1024]; struct sc_path path; struct sc_file *file, *parent; int r = 0, nfids;#if 0 if (card->ctx->debug) { int n; printf("%s(", __FUNCTION__); path = df->path; for (n = 0; n < path.len; n++) printf("%02x", path.value[n]); printf(")\n"); }#endif if (df == NULL) return SC_ERROR_INTERNAL; if (df->type == SC_FILE_TYPE_DF) { r = sc_pkcs15init_authenticate(profile, card, df, SC_AC_OP_LIST_FILES); if (r < 0) return r; card->ctx->log_errors = 0; r = sc_list_files(card, buffer, sizeof(buffer)); card->ctx->log_errors = 1; if (r < 0) return r; path = df->path; path.len += 2; nfids = r / 2; while (r >= 0 && nfids--) { path.value[path.len-2] = buffer[2*nfids]; path.value[path.len-1] = buffer[2*nfids+1]; r = sc_select_file(card, &path, &file); if (r < 0) { if (r == SC_ERROR_FILE_NOT_FOUND) continue; break; } r = sc_pkcs15init_rmdir(card, profile, file); sc_file_free(file); } if (r < 0) return r; } /* Select the parent DF */ path = df->path; path.len -= 2; r = sc_select_file(card, &path, &parent); if (r < 0) return r; r = sc_pkcs15init_authenticate(profile, card, parent, SC_AC_OP_DELETE); sc_file_free(parent); if (r < 0) return r; r = sc_pkcs15init_authenticate(profile, card, df, SC_AC_OP_ERASE); if (r < 0) return r; memset(&path, 0, sizeof(path)); path.type = SC_PATH_TYPE_FILE_ID; path.value[0] = df->id >> 8; path.value[1] = df->id & 0xFF; path.len = 2; card->ctx->log_errors = 0; r = sc_delete_file(card, &path); card->ctx->log_errors = 1; return r;}/* * Initialize the PKCS#15 application */intsc_pkcs15init_add_app(struct sc_card *card, struct sc_profile *profile, struct sc_pkcs15init_initargs *args){ struct sc_pkcs15_card *p15card = profile->p15_card; struct sc_pkcs15_pin_info pin_info; struct sc_app_info *app; int r; p15card->card = card; if (card->app_count >= SC_MAX_CARD_APPS) { p15init_error("Too many applications on this card."); return SC_ERROR_TOO_MANY_OBJECTS; } /* If the profile requires an SO PIN, check min/max length */ sc_profile_get_pin_info(profile, SC_PKCS15INIT_SO_PIN, &pin_info); if (args->so_pin_len == 0) { /* Mark the SO PIN as "not set" */ pin_info.reference = -1; sc_profile_set_pin_info(profile, SC_PKCS15INIT_SO_PIN, &pin_info); } else if (args->so_pin_len && args->so_pin_len < pin_info.min_length) { p15init_error("SO PIN too short (min length %u)", pin_info.min_length); return SC_ERROR_WRONG_LENGTH; } if (args->so_pin_len > pin_info.max_length) args->so_pin_len = pin_info.max_length; sc_profile_get_pin_info(profile, SC_PKCS15INIT_SO_PUK, &pin_info); if (args->so_puk_len && args->so_puk_len < pin_info.min_length) { p15init_error("SO PUK too short (min length %u)", pin_info.min_length); return SC_ERROR_WRONG_LENGTH; } if (args->so_puk_len > pin_info.max_length) args->so_puk_len = pin_info.max_length; /* Create the application DF and store the PINs */ r = profile->ops->init_app(profile, card, args->so_pin, args->so_pin_len, args->so_puk, args->so_puk_len); if (r < 0) return r; /* Store the PKCS15 information on the card * We cannot use sc_pkcs15_create() because it makes * all sorts of assumptions about DF and EF names, and * doesn't work if secure messaging is required for the * MF (which is the case with the GPK) */ app = (struct sc_app_info *) calloc(1, sizeof(*app)); app->path = p15card->file_app->path; if (p15card->file_app->namelen <= SC_MAX_AID_SIZE) { app->aid_len = p15card->file_app->namelen; memcpy(app->aid, p15card->file_app->name, app->aid_len); } if (args->serial) sc_pkcs15init_set_serial(profile, args->serial); if (args->label) { if (p15card->label) free(p15card->label); p15card->label = strdup(args->label); } app->label = strdup(p15card->label); /* XXX: encode the DDO? */ /* See if we've set an SO PIN */ sc_profile_get_pin_info(profile, SC_PKCS15INIT_SO_PIN, &pin_info); if (pin_info.reference != -1 && args->so_pin_len) { sc_profile_set_secret(profile, SC_AC_SYMBOLIC, SC_PKCS15INIT_SO_PIN, args->so_pin, args->so_pin_len); pin_info.flags |= SC_PKCS15_PIN_FLAG_SO_PIN; r = aodf_add_pin(p15card, profile, &pin_info, "Security Officer PIN"); } else { r = sc_pkcs15init_add_object(p15card, profile, SC_PKCS15_AODF, NULL); } if (r >= 0) r = sc_pkcs15init_update_dir(p15card, profile, app); if (r >= 0) r = sc_pkcs15init_update_tokeninfo(p15card, profile); return r;}/* * Store a PIN/PUK pair */intsc_pkcs15init_store_pin(struct sc_pkcs15_card *p15card, struct sc_profile *profile, struct sc_pkcs15init_pinargs *args){ struct sc_pkcs15_pin_info pin_info; struct sc_card *card = p15card->card; int r, index; /* No auth_id given: select one */ if (args->auth_id.len == 0) { struct sc_pkcs15_object *dummy; unsigned int n; args->auth_id.len = 1; card->ctx->log_errors = 0; for (n = 1, r = 0; n < 256; n++) { args->auth_id.value[0] = n; r = sc_pkcs15_find_pin_by_auth_id(p15card, &args->auth_id, &dummy); if (r == SC_ERROR_OBJECT_NOT_FOUND) break; } card->ctx->log_errors = 1; if (r != SC_ERROR_OBJECT_NOT_FOUND) { p15init_error("No auth_id specified for new PIN"); return SC_ERROR_INVALID_ARGUMENTS; } } else { struct sc_pkcs15_object *dummy; /* Make sure we don't get duplicate PIN IDs */ card->ctx->log_errors = 0; r = sc_pkcs15_find_pin_by_auth_id(p15card, &args->auth_id, &dummy); if (r != SC_ERROR_OBJECT_NOT_FOUND) { p15init_error("There already is a PIN with this ID."); return SC_ERROR_INVALID_ARGUMENTS; } } sc_profile_get_pin_info(profile, SC_PKCS15INIT_USER_PIN, &pin_info); pin_info.auth_id = args->auth_id; /* Get the number of PINs we already have */ index = sc_pkcs15_get_objects(p15card, SC_PKCS15_TYPE_AUTH, NULL, 0); /* Set the SO PIN reference from card */ if ((r = set_so_pin_from_card(p15card, profile)) < 0) return r; /* Now store the PINs */ r = profile->ops->new_pin(profile, card, &pin_info, index, args->pin, args->pin_len, args->puk, args->puk_len); /* Fix up any ACLs referring to the user pin */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -