static int create_sysdf(sc_profile_t *profile, sc_card_t *card, const char *name) { sc_file_t *file; sc_path_t path; int r; assert(profile && card && card->ctx && name); r = sc_profile_get_file(profile, name, &file); if (r == SC_SUCCESS) { assert(file); path = file->path; assert(path.len > 2); if (path.len > 2) path.len -= 2; r = sc_select_file(card, &path, NULL); if (r == SC_SUCCESS) r = sc_file_add_acl_entry(file, SC_AC_OP_CREATE, SC_AC_CHV, RTECP_USER_PIN_REF); if (r == SC_SUCCESS) r = sc_file_add_acl_entry(file, SC_AC_OP_DELETE, SC_AC_NEVER, SC_AC_KEY_REF_NONE); if (r == SC_SUCCESS) r = sc_create_file(card, file); assert(file); sc_file_free(file); } sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "Create %s failed: %s\n", name, sc_strerror(r)); 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; }
/* * Card-specific initialization of PKCS15 meta-information */ static int rtecp_init(sc_profile_t *profile, sc_pkcs15_card_t *p15card) { sc_card_t *card; sc_file_t *file; int r; if (!profile || !p15card || !p15card->card || !p15card->card->ctx) return SC_ERROR_INVALID_ARGUMENTS; card = p15card->card; r = sc_profile_get_file(profile, "MF", &file); SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "Get MF info failed"); assert(file); r = sc_create_file(card, file); assert(file); sc_file_free(file); SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "Create MF failed"); r = sc_profile_get_file(profile, "DIR", &file); SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "Get DIR file info failed"); assert(file); r = sc_create_file(card, file); assert(file); sc_file_free(file); SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "Create DIR file failed"); create_sysdf(profile, card, "Sys-DF"); create_sysdf(profile, card, "SysKey-DF"); create_sysdf(profile, card, "PuKey-DF"); create_sysdf(profile, card, "PrKey-DF"); create_sysdf(profile, card, "SKey-DF"); create_sysdf(profile, card, "Cer-DF"); create_sysdf(profile, card, "LCHV-DF"); create_sysdf(profile, card, "Resrv1-DF"); create_sysdf(profile, card, "Resrv2-DF"); create_sysdf(profile, card, "Resrv3-DF"); create_sysdf(profile, card, "Resrv4-DF"); return sc_select_file(card, sc_get_mf_path(), NULL); }
static int create_file(sc_file_t *file) { int r; r = sc_create_file(card, file); if (r) { check_ret(r, SC_AC_OP_CREATE, "CREATE FILE failed", current_file); return -1; } /* Make sure we're back in the parent directory, because on some cards * CREATE FILE also selects the newly created file. */ select_current_path_or_die(); return 0; }
/* * Create a DF */ static int setcos_create_dir(sc_profile_t *profile, sc_pkcs15_card_t *p15card, sc_file_t *df) { struct sc_context *ctx = p15card->card->ctx; int r; SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_VERBOSE); r = sc_pkcs15init_fixup_file(profile, p15card, df); SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, r, "SetCOS file ACL fixup failed"); r = sc_create_file(p15card->card, df); SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, r, "SetCOS create file failed"); SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_NORMAL, r); }
static int create_file(sc_file_t *file) { int r; r = sc_create_file(card, file); if (r) { check_ret(r, SC_AC_OP_CREATE, "CREATE FILE failed", current_file); return -1; } /* Make sure we're back in the parent directory, because on some cards * CREATE FILE also selects the newly created file. */ r = sc_select_file(card, ¤t_path, NULL); if (r) { printf("unable to select parent file: %s\n", sc_strerror(r)); die(1); } return 0; }
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); }
/* * 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); }
/* * Create a DF */ static int rtecp_create_dir(sc_profile_t *profile, sc_pkcs15_card_t *p15card, sc_file_t *df) { if (!profile || !p15card || !p15card->card || !df) return SC_ERROR_INVALID_ARGUMENTS; return sc_create_file(p15card->card, df); }
/* * Create a new PIN inside a DF */ static int westcos_pkcs15_create_pin(sc_profile_t *profile, sc_pkcs15_card_t *p15card, sc_file_t *df, sc_pkcs15_object_t *pin_obj, const u8 *pin, size_t pin_len, const u8 *puk, size_t puk_len) { int r; sc_file_t *pinfile = NULL; if(pin_len>9 || puk_len>9) return SC_ERROR_INVALID_ARGUMENTS; r = sc_profile_get_file(profile, "PINFILE", &pinfile); if(r < 0) return r; r = sc_create_file(p15card->card, pinfile); if(r) { if(r != SC_ERROR_FILE_ALREADY_EXISTS) return (r); r = sc_select_file(p15card->card, &pinfile->path, NULL); if(r) return (r); } if(pinfile) sc_file_free(pinfile); 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 = pin_len; pin_cmd.data = 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) return SC_ERROR_CARD_CMD_FAILED; ck.new_key.key_len = ret; r = sc_card_ctl(p15card->card, SC_CARDCTL_WESTCOS_CHANGE_KEY, &ck); if(r) return r; } 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 = puk_len; puk_cmd.data = 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) return SC_ERROR_CARD_CMD_FAILED; ck.new_key.key_len = ret; r = sc_card_ctl(p15card->card, SC_CARDCTL_WESTCOS_CHANGE_KEY, &ck); if(r) return r; } return 0; }
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 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); }