static int entersafe_store_key(sc_profile_t *profile, sc_pkcs15_card_t *p15card, sc_pkcs15_object_t *obj, sc_pkcs15_prkey_t *key) { sc_pkcs15_prkey_info_t *kinfo = (sc_pkcs15_prkey_info_t *) obj->data; sc_card_t *card = p15card->card; sc_entersafe_wkey_data data; sc_file_t *tfile; const sc_acl_entry_t *acl_entry; int r; SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); if (key->algorithm != SC_ALGORITHM_RSA) /* ignore DSA keys */ SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE,SC_ERROR_INVALID_ARGUMENTS); r = sc_profile_get_file(profile, "PKCS15-AODF", &tfile); if (r < 0) return r; acl_entry = sc_file_get_acl_entry(tfile, SC_AC_OP_UPDATE); if (acl_entry->method != SC_AC_NONE) { r = sc_pkcs15init_authenticate(profile, p15card, tfile, SC_AC_OP_UPDATE); if(r<0) r = SC_ERROR_SECURITY_STATUS_NOT_SATISFIED; } sc_file_free(tfile); SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "cant verify pin"); data.key_id = (u8) kinfo->key_reference; data.usage=0x22; data.key_data.rsa=&key->u.rsa; return sc_card_ctl(card, SC_CARDCTL_ENTERSAFE_WRITE_KEY, &data); }
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; }
/* * Create a new PIN inside a DF */ static int cflex_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) { struct sc_context *ctx = p15card->card->ctx; sc_pkcs15_auth_info_t *auth_info = (sc_pkcs15_auth_info_t *) pin_obj->data; struct sc_pkcs15_pin_attributes *pin_attrs = &auth_info->attrs.pin; sc_file_t *dummies[2]; int ndummies, pin_type, puk_type, r; sc_file_t *file; SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_NORMAL); if (auth_info->auth_type != SC_PKCS15_PIN_AUTH_TYPE_PIN) return SC_ERROR_OBJECT_NOT_VALID; /* If the profile doesn't specify a reference for this PIN, guess */ if (pin_attrs->flags & SC_PKCS15_PIN_FLAG_SO_PIN) { pin_type = SC_PKCS15INIT_SO_PIN; puk_type = SC_PKCS15INIT_SO_PUK; if (pin_attrs->reference != 2) return SC_ERROR_INVALID_ARGUMENTS; } else { pin_type = SC_PKCS15INIT_USER_PIN; puk_type = SC_PKCS15INIT_USER_PUK; if (pin_attrs->reference != 1) return SC_ERROR_INVALID_ARGUMENTS; } /* Get file definition from the profile */ if (sc_profile_get_file(profile, (pin_attrs->reference == 1)? "CHV1" : "CHV2", &file) < 0 && sc_profile_get_file(profile, "CHV", &file) < 0) SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_FILE_NOT_FOUND, "profile does not define pin file ACLs"); ndummies = cflex_create_dummy_chvs(profile, p15card, file, SC_AC_OP_CREATE, dummies); SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, ndummies, "Unable to create dummy CHV file"); r = cflex_create_pin_file(profile, p15card, &df->path, pin_attrs->reference, pin, pin_len, sc_profile_get_pin_retries(profile, pin_type), puk, puk_len, sc_profile_get_pin_retries(profile, puk_type), NULL, 0); cflex_delete_dummy_chvs(profile, p15card, ndummies, dummies); SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_VERBOSE, r); }
/* * Erase the card via rm */ static int cflex_erase_card(struct sc_profile *profile, sc_pkcs15_card_t *p15card) { struct sc_context *ctx = p15card->card->ctx; sc_file_t *df = profile->df_info->file, *dir, *userpinfile = NULL; int r; SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_NORMAL); /* 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. * */ if (sc_profile_get_file(profile, "DIR", &dir) >= 0) { r = cflex_delete_file(profile, p15card, dir); sc_file_free(dir); if (r < 0 && r != SC_ERROR_FILE_NOT_FOUND) goto out; } r=cflex_delete_file(profile, p15card, df); /* If the user pin file isn't in a sub-DF of the pkcs15 DF, delete it */ if (sc_profile_get_file(profile, "pinfile-1", &userpinfile) >= 0 && userpinfile->path.len <= profile->df_info->file->path.len + 2 && memcmp(userpinfile->path.value, profile->df_info->file->path.value, userpinfile->path.len) != 0) { r = cflex_delete_file(profile, p15card, userpinfile); sc_file_free(userpinfile); userpinfile=NULL; } out: /* Forget all cached keys, the pin files on card are all gone. */ if (userpinfile) sc_file_free(userpinfile); sc_free_apps(p15card->card); if (r == SC_ERROR_FILE_NOT_FOUND) r=0; SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_VERBOSE, 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); }
/* * Setup file struct & path: get correct template from the profile, construct full path * num = number of objects of this type already on the card */ static int myeid_new_file(sc_profile_t *profile, sc_card_t *card, unsigned int type, unsigned int num, sc_file_t **out) { sc_file_t *file; sc_path_t *p; char name[64]; const char *tag; int r; SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); if (type == SC_PKCS15_TYPE_PRKEY_RSA) tag = "private-key"; else if (type == SC_PKCS15_TYPE_PUBKEY_RSA) tag = "public-key"; else if ((type & SC_PKCS15_TYPE_CLASS_MASK) == SC_PKCS15_TYPE_CERT) tag = "certificate"; else if ((type & SC_PKCS15_TYPE_CLASS_MASK) == SC_PKCS15_TYPE_DATA_OBJECT) tag = "data"; else { sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "Unsupported file type"); return SC_ERROR_INVALID_ARGUMENTS; } /* Get template from profile */ snprintf(name, sizeof(name), "template-%s", tag); if (sc_profile_get_file(profile, name, &file) < 0) { sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "Profile doesn't define %s", name); return SC_ERROR_NOT_SUPPORTED; } /* Auto-increment FID for next object */ file->id += num; p = &file->path; *p = profile->df_info->file->path; p->value[p->len++] = (u8) (file->id / 256); p->value[p->len++] = (u8) (file->id % 256); /* Increment FID until there's no file with such path */ r = sc_select_file(card, p, NULL); while(r == 0) { file->id++; p->value[p->len - 2] = (u8) (file->id / 256); p->value[p->len - 1] = (u8) (file->id % 256); r = sc_select_file(card, p, NULL); } *out = file; SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, 0); }
/* * Create a new PIN */ static int setcos_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) { struct sc_context *ctx = p15card->card->ctx; sc_pkcs15_auth_info_t *auth_info = (sc_pkcs15_auth_info_t *) pin_obj->data; sc_file_t *pinfile = NULL; int r, ignore_ac = 0; SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_VERBOSE); if (auth_info->auth_type != SC_PKCS15_PIN_AUTH_TYPE_PIN) return SC_ERROR_OBJECT_NOT_VALID; /* Create the global pin file if it doesn't exist yet */ r = sc_profile_get_file(profile, "pinfile", &pinfile); SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, r, "No 'pinfile' template in profile"); r = sc_select_file(p15card->card, &pinfile->path, &pinfile); SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, r, "Cannot select 'pinfile'"); sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "pinfile->status:%X", pinfile->status); sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "create PIN with reference:%X, flags:%X, path:%s", auth_info->attrs.pin.reference, auth_info->attrs.pin.flags, sc_print_path(&auth_info->path)); if (pinfile->status == SC_FILE_STATUS_CREATION) ignore_ac = 1; r = setcos_create_pin_internal(profile, p15card, ignore_ac, auth_info, pin, pin_len, puk, puk_len); /* If pinfile is in 'Creation' state and SOPIN has been created, * change status of MF and 'pinfile' to 'Operational:Activated' */ if (ignore_ac && (auth_info->attrs.pin.flags & SC_PKCS15_PIN_FLAG_SO_PIN)) { sc_file_t *mf = profile->mf_info->file; r = sc_card_ctl(p15card->card, SC_CARDCTL_SETCOS_ACTIVATE_FILE, NULL); SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, r, "Cannot set 'pinfile' into the activated state"); r = sc_select_file(p15card->card, &mf->path, NULL); SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, r, "Cannot select MF"); r = sc_card_ctl(p15card->card, SC_CARDCTL_SETCOS_ACTIVATE_FILE, NULL); SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, r, "Cannot set MF into the activated state"); } sc_file_free(pinfile); SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_NORMAL, r); }
/* * Create a DF */ static int myeid_create_dir(sc_profile_t *profile, sc_pkcs15_card_t *p15card, sc_file_t *df) { struct sc_context *ctx = NULL; struct sc_file *file = NULL; int r = 0, ii; static const char *create_dfs[] = { "PKCS15-PrKDF", "PKCS15-PuKDF", "PKCS15-CDF", "PKCS15-CDF-TRUSTED", "PKCS15-DODF", NULL }; static const int create_dfs_val[] = { SC_PKCS15_PRKDF, SC_PKCS15_PUKDF, SC_PKCS15_CDF, SC_PKCS15_CDF_TRUSTED, SC_PKCS15_DODF }; if (!profile || !p15card || !p15card->card || !df) return SC_ERROR_INVALID_ARGUMENTS; ctx = p15card->card->ctx; LOG_FUNC_CALLED(ctx); sc_log(ctx, "id (%x)", df->id); if (df->id == 0x5015) { sc_log(ctx, "Select (%x)", df->id); r = sc_select_file(p15card->card, &df->path, NULL); for (ii = 0; create_dfs[ii]; ii++) { sc_log(ctx, "Create '%s'", create_dfs[ii]); r = sc_profile_get_file(profile, create_dfs[ii], &file); if (file) sc_file_free(file); if (r) { sc_log(ctx, "Inconsistent profile: cannot find %s", create_dfs[ii]); LOG_FUNC_RETURN(ctx, SC_ERROR_INCONSISTENT_PROFILE); } r = sc_pkcs15init_add_object(p15card, profile, create_dfs_val[ii], NULL); if (r != SC_ERROR_FILE_ALREADY_EXISTS) LOG_TEST_RET(ctx, r, "Failed to create MyEID xDF file"); } } LOG_FUNC_RETURN(p15card->card->ctx, r); }
static int entersafe_generate_key(sc_profile_t *profile, sc_pkcs15_card_t *p15card, sc_pkcs15_object_t *obj, sc_pkcs15_pubkey_t *pubkey) { int r; sc_entersafe_gen_key_data gendat; sc_pkcs15_prkey_info_t *kinfo = (sc_pkcs15_prkey_info_t *) obj->data; sc_card_t *card = p15card->card; sc_file_t *tfile; const sc_acl_entry_t *acl_entry; SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); if (obj->type != SC_PKCS15_TYPE_PRKEY_RSA) return SC_ERROR_NOT_SUPPORTED; r = sc_profile_get_file(profile, "PKCS15-AODF", &tfile); if (r < 0) return r; acl_entry = sc_file_get_acl_entry(tfile, SC_AC_OP_UPDATE); if (acl_entry->method != SC_AC_NONE) { r = sc_pkcs15init_authenticate(profile, p15card, tfile, SC_AC_OP_UPDATE); if(r<0) r = SC_ERROR_SECURITY_STATUS_NOT_SATISFIED; } sc_file_free(tfile); SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "cant verify pin"); /* generate key pair */ gendat.key_id = (u8) kinfo->key_reference; gendat.key_length = (size_t) kinfo->modulus_length; gendat.modulus = NULL; r = sc_card_ctl(card, SC_CARDCTL_ENTERSAFE_GENERATE_KEY, &gendat); SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "EnterSafe generate RSA key pair failed"); /* get the modulus via READ PUBLIC KEY */ if (pubkey) { u8 *buf; struct sc_pkcs15_pubkey_rsa *rsa = &pubkey->u.rsa; /* set the modulus */ rsa->modulus.data = gendat.modulus; rsa->modulus.len = kinfo->modulus_length >> 3; /* set the exponent (always 0x10001) */ buf = malloc(3); if (!buf) return SC_ERROR_OUT_OF_MEMORY; buf[0] = 0x01; buf[1] = 0x00; buf[2] = 0x01; rsa->exponent.data = buf; rsa->exponent.len = 3; pubkey->algorithm = SC_ALGORITHM_RSA; } else
/* * Create the MF and global pin file if they don't exist. */ static int setcos_init_card(sc_profile_t *profile, sc_pkcs15_card_t *p15card) { struct sc_context *ctx = p15card->card->ctx; sc_file_t *mf = profile->mf_info->file; sc_file_t *pinfile; int r; SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_VERBOSE); /* Create the MF if it doesn't exist yet */ r = sc_select_file(p15card->card, &mf->path, NULL); if (r == SC_ERROR_FILE_NOT_FOUND) { sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "MF doesn't exist, creating now"); /* Fix up the file's ACLs */ r = sc_pkcs15init_fixup_file(profile, p15card, mf); SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, r, "MF fixup failed"); mf->status = SC_FILE_STATUS_CREATION; r = sc_create_file(p15card->card, mf); SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, r, "MF creation failed"); } SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, r, "Cannot select MF"); /* Create the global pin file if it doesn't exist yet */ r = sc_profile_get_file(profile, "pinfile", &pinfile); SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, r, "Cannot get 'pinfile' from profile"); r = sc_select_file(p15card->card, &pinfile->path, NULL); if (r == SC_ERROR_FILE_NOT_FOUND) { sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "Global pin file doesn't exist, creating now"); /* Fix up the file's ACLs */ r = sc_pkcs15init_fixup_file(profile, p15card, pinfile); if (r < 0) sc_file_free(pinfile); SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, r, "Pinfile fixup failed"); /* Set life cycle state to SC_FILE_STATUS_CREATION, * which means that all ACs are ignored. */ pinfile->status = SC_FILE_STATUS_CREATION; r = sc_create_file(p15card->card, pinfile); if (r < 0) sc_file_free(pinfile); SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, r, "Pinfile creation failed"); } sc_file_free(pinfile); SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, r, "Select pinfile failed"); SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_NORMAL, r); }
static int entersafe_store_key(sc_profile_t *profile, sc_pkcs15_card_t *p15card, sc_pkcs15_object_t *obj, sc_pkcs15_prkey_t *key) { sc_pkcs15_prkey_info_t *kinfo = (sc_pkcs15_prkey_info_t *) obj->data; sc_card_t *card = p15card->card; sc_entersafe_wkey_data data; sc_file_t *tfile; const sc_acl_entry_t *acl_entry; int r; struct sc_pkcs15_prkey_info *key_info = (struct sc_pkcs15_prkey_info *)obj->data; size_t keybits = key_info->modulus_length; SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); if ( key->algorithm != SC_ALGORITHM_RSA ) { /* ignore DSA keys */ SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE,SC_ERROR_INVALID_ARGUMENTS); } /* Disable RSA:512bits */ if ( ( keybits < 1024 ) || ( keybits > 2048 ) || ( keybits % 0x20 ) ) { sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "Unsupported key size %"SC_FORMAT_LEN_SIZE_T"u\n", keybits); return SC_ERROR_INVALID_ARGUMENTS; } r = sc_profile_get_file(profile, "PKCS15-AODF", &tfile); if (r < 0) return r; acl_entry = sc_file_get_acl_entry(tfile, SC_AC_OP_UPDATE); if (acl_entry->method != SC_AC_NONE) { r = sc_pkcs15init_authenticate(profile, p15card, tfile, SC_AC_OP_UPDATE); if(r<0) r = SC_ERROR_SECURITY_STATUS_NOT_SATISFIED; } sc_file_free(tfile); SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "cant verify pin"); data.key_id = (u8) kinfo->key_reference; data.usage=0x22; data.key_data.rsa=&key->u.rsa; return sc_card_ctl(card, SC_CARDCTL_ENTERSAFE_WRITE_KEY, &data); }
/* * Create a new DF * This will usually be the application DF */ static int gpk_create_dir(sc_profile_t *profile, sc_pkcs15_card_t *p15card, sc_file_t *df) { struct sc_file *pinfile; int r, locked; SC_FUNC_CALLED(p15card->card->ctx, SC_LOG_DEBUG_VERBOSE); if (sc_card_ctl(p15card->card, SC_CARDCTL_GPK_IS_LOCKED, &locked) == 0 && locked) { sc_debug(p15card->card->ctx, SC_LOG_DEBUG_NORMAL, "This card is already personalized, unable to " "create PKCS#15 structure."); return SC_ERROR_NOT_SUPPORTED; } /* Create the DF. */ r = sc_pkcs15init_create_file(profile, p15card, df); if (r < 0) return r; /* See if there's a file called "pinfile" that resides within * this DF. If so, create it */ if (sc_profile_get_file(profile, "pinfile", &pinfile) >= 0) { /* Build the pin file's path from the DF path + its * file ID */ pinfile->path = df->path; sc_append_file_id(&pinfile->path, pinfile->id); r = gpk_init_pinfile(profile, p15card, pinfile); sc_file_free(pinfile); if (r < 0) return r; /* TODO: What for it was used ? for (i = 0; i < GPK_MAX_PINS; i++) * sc_keycache_put_pin(&df->path, GPK_PIN_SCOPE|i, (const u8 *) " "); */ } SC_FUNC_RETURN(p15card->card->ctx, SC_LOG_DEBUG_NORMAL, r); }
/* * Create a DF */ static int myeid_create_dir(sc_profile_t *profile, sc_pkcs15_card_t *p15card, sc_file_t *df) { struct sc_context *ctx = p15card->card->ctx; struct sc_file *file = NULL; int r=0, ii; static const char *create_dfs[] = { "PKCS15-PrKDF", "PKCS15-PuKDF", "PKCS15-CDF", "PKCS15-DODF", NULL }; if (!profile || !p15card || !df) return SC_ERROR_INVALID_ARGUMENTS; SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_VERBOSE); sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "id (%x)",df->id); if(df->id == 0x5015) { sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "Select (%x)",df->id); r = sc_select_file(p15card->card, &df->path, NULL); for (ii = 0; create_dfs[ii]; ii++) { sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "Create '%s'", create_dfs[ii]); if (sc_profile_get_file(profile, create_dfs[ii], &file)) { sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "Inconsistent profile: cannot find %s", create_dfs[ii]); SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_INCONSISTENT_PROFILE); } r = sc_pkcs15init_create_file(profile, p15card, file); sc_file_free(file); if (r != SC_ERROR_FILE_ALREADY_EXISTS) SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, r, "Failed to create MyEID xDF file"); } } SC_FUNC_RETURN(p15card->card->ctx, SC_LOG_DEBUG_NORMAL, r); }
/* * Select a reference for a private key object */ static int rtecp_select_key_reference(sc_profile_t *profile, sc_pkcs15_card_t *p15card, sc_pkcs15_prkey_info_t *key_info) { sc_file_t *df; int r; if (!profile || !p15card || !p15card->card || !p15card->card->ctx || !key_info) return SC_ERROR_INVALID_ARGUMENTS; if (key_info->key_reference <= 0) key_info->key_reference = 1; else if (key_info->key_reference > 0xFF) return SC_ERROR_TOO_MANY_OBJECTS; r = sc_profile_get_file(profile, "PrKey-DF", &df); SC_TEST_RET(p15card->card->ctx, SC_LOG_DEBUG_NORMAL, r, "Get PrKey-DF info failed"); assert(df); key_info->path = df->path; sc_file_free(df); r = sc_append_file_id(&key_info->path, key_info->key_reference); return r; }
/* * Create a new DF * This will usually be the application DF */ static int gpk_create_dir(sc_profile_t *profile, sc_card_t *card, sc_file_t *df) { struct sc_file *pinfile; int r, locked, i; if (sc_card_ctl(card, SC_CARDCTL_GPK_IS_LOCKED, &locked) == 0 && locked) { sc_error(card->ctx, "This card is already personalized, unable to " "create PKCS#15 structure."); return SC_ERROR_NOT_SUPPORTED; } /* Create the DF. */ r = sc_pkcs15init_create_file(profile, card, df); if (r < 0) return r; /* See if there's a file called "pinfile" that resides within * this DF. If so, create it */ if (sc_profile_get_file(profile, "pinfile", &pinfile) >= 0) { /* Build the pin file's path from the DF path + its * file ID */ pinfile->path = df->path; sc_append_file_id(&pinfile->path, pinfile->id); r = gpk_init_pinfile(profile, card, pinfile); sc_file_free(pinfile); if (r < 0) return r; for (i = 0; i < GPK_MAX_PINS; i++) sc_keycache_put_pin(&df->path, GPK_PIN_SCOPE|i, (const u8 *) " "); } return r; }
/* * Delete object * * Applied to private key: used to delete public part internal file */ static int rtecp_delete_object(struct sc_profile *profile, struct sc_pkcs15_card *p15card, struct sc_pkcs15_object *obj, const struct sc_path *path) { sc_context_t *ctx; sc_file_t *df; sc_path_t pubkey_path; int key_ref; int r; if (!profile || !p15card || !p15card->card || !p15card->card->ctx) return SC_ERROR_INVALID_ARGUMENTS; ctx = p15card->card->ctx; LOG_FUNC_CALLED(ctx); sc_log(ctx, "delete object: type %X, path %s", obj->type, sc_print_path(path)); if ((obj->type & SC_PKCS15_TYPE_CLASS_MASK) != SC_PKCS15_TYPE_PRKEY) LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_SUPPORTED); key_ref = ((struct sc_pkcs15_prkey_info *)obj->data)->key_reference; sc_log(ctx, "key reference %04i", key_ref); r = sc_profile_get_file(profile, "PuKey-DF", &df); LOG_TEST_RET(ctx, r, "Get PuKey-DF info failed"); pubkey_path = df->path; sc_file_free(df); r = sc_append_file_id(&pubkey_path, key_ref); LOG_TEST_RET(ctx, r, "Append ID to file failed"); sc_log(ctx, "delete pubkey file %s", sc_print_path(&pubkey_path)); r = sc_pkcs15init_delete_by_path(profile, p15card, &pubkey_path); if (r && r != SC_ERROR_FILE_NOT_FOUND) LOG_FUNC_RETURN(ctx, r); LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_SUPPORTED); }
static int cflex_create_pin_file(sc_profile_t *profile, sc_pkcs15_card_t *p15card, sc_path_t *df_path, int ref, const u8 *pin, size_t pin_len, int pin_tries, const u8 *puk, size_t puk_len, int puk_tries, sc_file_t **file_ret, int unprotected) { struct sc_context *ctx = p15card->card->ctx; struct sc_pkcs15_object *pin_obj = NULL; unsigned char buffer[23]; sc_path_t path; sc_file_t *dummies[2], *file; int r, ndummies; SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_NORMAL); if (file_ret) *file_ret = NULL; /* Build the CHV path */ path = *df_path; path.value[path.len++] = ref - 1; path.value[path.len++] = 0; /* See if the CHV already exists */ r = sc_select_file(p15card->card, &path, NULL); if (r >= 0) return SC_ERROR_FILE_ALREADY_EXISTS; /* Get the file definition from the profile */ if (sc_profile_get_file_by_path(profile, &path, &file) < 0 && sc_profile_get_file(profile, (ref == 1)? "CHV1" : "CHV2", &file) < 0 && sc_profile_get_file(profile, "CHV", &file) < 0) SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_FILE_NOT_FOUND, "profile does not define pin file ACLs"); file->path = path; file->size = 23; file->id = (ref == 1)? 0x0000 : 0x0100; if (unprotected) { sc_file_add_acl_entry(file, SC_AC_OP_UPDATE, SC_AC_NONE, SC_AC_KEY_REF_NONE); } /* Build the contents of the file */ buffer[0] = buffer[1] = buffer[2] = 0xFF; put_pin(profile, buffer + 3, pin, pin_len, pin_tries); put_pin(profile, buffer + 13, puk, puk_len, puk_tries); /* For updating the file, create a dummy CHV files if * necessary */ ndummies = cflex_create_dummy_chvs(profile, p15card, file, SC_AC_OP_UPDATE, dummies); SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, ndummies, "Unable to create dummy CHV file"); if (!unprotected) { struct sc_pin_cmd_data pin_cmd; memset(&pin_cmd, 0, sizeof(pin_cmd)); pin_cmd.cmd = SC_PIN_CMD_VERIFY; pin_cmd.pin_type = SC_AC_CHV; pin_cmd.pin_reference = ref; pin_cmd.pin1.data = dummy_pin_value; pin_cmd.pin1.len = sizeof(dummy_pin_value); r = sc_pin_cmd(p15card->card, &pin_cmd, NULL); SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, r, "Cannot verify dummy PIN"); }; if (ref == 2) { /* Cache dummy SOPIN value */ r = sc_pkcs15_find_pin_by_type_and_reference(p15card, NULL, SC_AC_CHV, ref, &pin_obj); if (!r && pin_obj) sc_pkcs15_pincache_add(p15card, pin_obj, dummy_pin_value, sizeof(dummy_pin_value)); } r = sc_pkcs15init_create_file(profile, p15card, file); SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, r, "Failed to create PIN file"); r = sc_update_binary(p15card->card, 0, buffer, 23, 0); SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, r, "Failed to update PIN file"); if (r < 0 || file_ret == NULL) sc_file_free(file); else *file_ret = file; /* Delete the dummy CHV files */ cflex_delete_dummy_chvs(profile, p15card, ndummies, dummies); if (pin_obj) { /* Cache new SOPIN value */ sc_pkcs15_pincache_add(p15card, pin_obj, pin, pin_len); } SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_VERBOSE, r); }
/* * Store a key on the card */ static int rtecp_store_key(sc_profile_t *profile, sc_pkcs15_card_t *p15card, sc_pkcs15_object_t *obj, sc_pkcs15_prkey_t *key) { sc_card_t *card; sc_pkcs15_prkey_info_t *key_info; sc_file_t *pukey_df; sc_path_t path; unsigned char *buf; size_t buf_len, key_len, len, i; int r; if (!profile || !p15card || !p15card->card || !p15card->card->ctx || !obj || !obj->data || !key) return SC_ERROR_INVALID_ARGUMENTS; card = p15card->card; SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); if ((obj->type != SC_PKCS15_TYPE_PRKEY_RSA || key->algorithm != SC_ALGORITHM_RSA) && (obj->type != SC_PKCS15_TYPE_PRKEY_GOSTR3410 || key->algorithm != SC_ALGORITHM_GOSTR3410)) return SC_ERROR_NOT_SUPPORTED; key_info = (sc_pkcs15_prkey_info_t *)obj->data; assert(key_info); if (key->algorithm == SC_ALGORITHM_RSA) { assert(key_info->modulus_length % 128 == 0); len = key_info->modulus_length / 8 / 2; key_len = len * 5 + 8; buf_len = key_len; } else { assert(key_info->modulus_length == SC_PKCS15_GOSTR3410_KEYSIZE); len = key_info->modulus_length / 8; key_len = len; buf_len = len; } if (key->algorithm == SC_ALGORITHM_RSA && (!key->u.rsa.p.data || !key->u.rsa.q.data || !key->u.rsa.iqmp.data || !key->u.rsa.dmp1.data || !key->u.rsa.dmq1.data || !key->u.rsa.modulus.data || !key->u.rsa.exponent.data || key->u.rsa.p.len != len || key->u.rsa.q.len != len || key->u.rsa.iqmp.len != len || key->u.rsa.dmp1.len != len || key->u.rsa.dmq1.len != len || key->u.rsa.modulus.len != 2*len || key->u.rsa.exponent.len > len || key->u.rsa.exponent.len == 0)) return SC_ERROR_INVALID_ARGUMENTS; if (key->algorithm == SC_ALGORITHM_GOSTR3410 && (!key->u.gostr3410.d.data || key->u.gostr3410.d.len != len)) return SC_ERROR_INVALID_ARGUMENTS; buf = calloc(1, buf_len); if (!buf) SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_OUT_OF_MEMORY); assert(key_len <= buf_len); if (key->algorithm == SC_ALGORITHM_RSA) { /* p */ for (i = 0; i < len; ++i) buf[i] = key->u.rsa.p.data[len - 1 - i]; /* q */ for (i = 0; i < len; ++i) buf[len + 4 + i] = key->u.rsa.q.data[len - 1 - i]; /* iqmp */ for (i = 0; i < len; ++i) buf[len + 4 + len + 4 + i] = key->u.rsa.iqmp.data[len - 1 - i]; /* dmp1 */ for (i = 0; i < len; ++i) buf[len + 4 + len + 4 + len + i] = key->u.rsa.dmp1.data[len - 1 - i]; /* dmq1 */ for (i = 0; i < len; ++i) buf[len * 4 + 8 + i] = key->u.rsa.dmq1.data[len - 1 - i]; } else { /* d */ for (i = 0; i < len; ++i) buf[i] = key->u.gostr3410.d.data[len - 1 - i]; } path = key_info->path; r = sc_select_file(card, &path, NULL); if (r == SC_SUCCESS) r = sc_change_reference_data(card, 0, 0, NULL, 0, buf, key_len, NULL); assert(buf); sc_mem_clear(buf, key_len); /* store public key */ if (key->algorithm == SC_ALGORITHM_RSA) key_len = len * 3; else goto end; assert(key_len <= buf_len); if (key->algorithm == SC_ALGORITHM_RSA) { /* modulus */ for (i = 0; i < 2*len; ++i) buf[i] = key->u.rsa.modulus.data[2*len - 1 - i]; /* exponent */ for (i = 0; i < key->u.rsa.exponent.len && i < len; ++i) buf[2 * len + i] = key->u.rsa.exponent.data[ key->u.rsa.exponent.len - 1 - i]; } if (r == SC_SUCCESS) { r = sc_profile_get_file(profile, "PuKey-DF", &pukey_df); if (r == SC_SUCCESS) { assert(pukey_df); path = pukey_df->path; r = sc_append_file_id(&path, key_info->key_reference); sc_file_free(pukey_df); } else if (card->ctx->debug >= 2) sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "%s\n", "Get PuKey-DF info failed"); } if (r == SC_SUCCESS) { r = sc_select_file(card, &path, NULL); if (r == SC_SUCCESS) r = sc_change_reference_data(card, 0, 0, NULL, 0, buf, key_len, NULL); if (r && card->ctx->debug >= 2) sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "%s\n", "Store public key failed"); } end: assert(buf); free(buf); SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, 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 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; }
/* * 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); }
/* * Allocate a file */ static int miocos_new_file(struct sc_profile *profile, sc_card_t *card, unsigned int type, unsigned int num, sc_file_t **out) { struct sc_file *file; struct sc_path *p; char name[64]; const char *tag = NULL, *desc = NULL; while (1) { switch (type) { case SC_PKCS15_TYPE_PRKEY_RSA: desc = "RSA private key"; tag = "private-key"; break; case SC_PKCS15_TYPE_PUBKEY_RSA: desc = "RSA public key"; tag = "public-key"; break; case SC_PKCS15_TYPE_PRKEY: desc = "extractable private key"; tag = "extractable-key"; break; case SC_PKCS15_TYPE_CERT: desc = "certificate"; tag = "certificate"; break; case SC_PKCS15_TYPE_DATA_OBJECT: desc = "data object"; tag = "data"; break; } if (tag) break; /* If this is a specific type such as * SC_PKCS15_TYPE_CERT_FOOBAR, fall back to * the generic class (SC_PKCS15_TYPE_CERT) */ if (!(type & ~SC_PKCS15_TYPE_CLASS_MASK)) { sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "File type not supported by card driver"); return SC_ERROR_INVALID_ARGUMENTS; } type &= SC_PKCS15_TYPE_CLASS_MASK; } _snprintf(name, sizeof(name), "template-%s", tag); if (sc_profile_get_file(profile, name, &file) < 0) { sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "Profile doesn't define %s template (%s)", desc, name); return SC_ERROR_NOT_SUPPORTED; } /* Now construct file from template */ file->id += num; p = &file->path; *p = profile->df_info->file->path; p->value[p->len++] = file->id >> 8; p->value[p->len++] = file->id; *out = file; return 0; }
/* * Key generation */ static int cardos_generate_key(sc_profile_t *profile, sc_pkcs15_card_t *p15card, sc_pkcs15_object_t *obj, sc_pkcs15_pubkey_t *pubkey) { struct sc_context *ctx = p15card->card->ctx; struct sc_pkcs15_prkey_info *key_info = (sc_pkcs15_prkey_info_t *) obj->data; struct sc_pkcs15_prkey_rsa key_obj; struct sc_cardctl_cardos_genkey_info args; struct sc_file *temp; u8 abignum[256]; int algorithm = 0, r, delete_it = 0, use_ext_rsa = 0; size_t keybits, rsa_max_size; int pin_id = -1; if (obj->type != SC_PKCS15_TYPE_PRKEY_RSA) return SC_ERROR_NOT_SUPPORTED; rsa_max_size = (p15card->card->caps & SC_CARD_CAP_RSA_2048) ? 2048 : 1024; keybits = key_info->modulus_length & ~7UL; if (keybits > rsa_max_size) { sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "Unable to generate key, max size is %lu", (unsigned long) rsa_max_size); return SC_ERROR_INVALID_ARGUMENTS; } if (keybits > 1024) use_ext_rsa = 1; if (cardos_key_algorithm(key_info->usage, keybits, &algorithm) < 0) { sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "CardOS does not support keys " "that can both sign _and_ decrypt."); return SC_ERROR_NOT_SUPPORTED; } if (sc_profile_get_file(profile, "tempfile", &temp) < 0) { sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "Profile doesn't define temporary file " "for key generation."); return SC_ERROR_NOT_SUPPORTED; } pin_id = sc_pkcs15init_get_pin_reference(p15card, profile, SC_AC_SYMBOLIC, SC_PKCS15INIT_USER_PIN); if (pin_id >= 0) { r = sc_pkcs15init_verify_secret(profile, p15card, NULL, SC_AC_CHV, pin_id); if (r < 0) return r; } if (use_ext_rsa == 0) temp->ef_structure = SC_FILE_EF_LINEAR_VARIABLE_TLV; else temp->ef_structure = SC_FILE_EF_TRANSPARENT; if ((r = sc_pkcs15init_create_file(profile, p15card, temp)) < 0) goto out; delete_it = 1; init_key_object(&key_obj, abignum, keybits >> 3); r = cardos_put_key(profile, p15card, algorithm, key_info, &key_obj); if (r < 0) goto out; memset(&args, 0, sizeof(args)); args.key_id = key_info->key_reference; args.key_bits = keybits; args.fid = temp->id; r = sc_card_ctl(p15card->card, SC_CARDCTL_CARDOS_GENERATE_KEY, &args); if (r < 0) goto out; r = cardos_extract_pubkey(p15card->card, pubkey, temp, use_ext_rsa); out: if (delete_it != 0) sc_pkcs15init_rmdir(p15card, profile, temp); sc_file_free(temp); if (r < 0) { if (pubkey->u.rsa.modulus.data) free (pubkey->u.rsa.modulus.data); if (pubkey->u.rsa.exponent.data) free (pubkey->u.rsa.exponent.data); } return r; }
/* * Generate a keypair */ static int jcop_generate_key(sc_profile_t *profile, sc_pkcs15_card_t *p15card, sc_pkcs15_object_t *obj, sc_pkcs15_pubkey_t *pubkey) { sc_pkcs15_prkey_info_t *key_info = (sc_pkcs15_prkey_info_t *) obj->data; struct sc_cardctl_jcop_genkey args; sc_file_t *temppubfile=NULL, *keyfile=NULL; unsigned char *keybuf=NULL; size_t mod_len, exp_len, pub_len, keybits; int r,delete_ok=0; if (obj->type != SC_PKCS15_TYPE_PRKEY_RSA) { sc_debug(p15card->card->ctx, SC_LOG_DEBUG_NORMAL, "JCOP supports only RSA keys."); return SC_ERROR_NOT_SUPPORTED; } r=sc_profile_get_file(profile, "temp-pubkey", &temppubfile); if (r < 0) goto out; r = sc_select_file(p15card->card, &key_info->path, &keyfile); if (r < 0) goto out; mod_len = key_info->modulus_length / 8; exp_len = 4; pub_len = 2 + mod_len + exp_len; temppubfile->size = pub_len; r = sc_pkcs15init_fixup_file(profile, p15card, temppubfile); if (r < 0) goto out; r = sc_pkcs15init_create_file(profile, p15card, temppubfile); if (r < 0) goto out; delete_ok=1; r = sc_pkcs15init_authenticate(profile, p15card, temppubfile, SC_AC_OP_UPDATE); if (r < 0) goto out; r = sc_pkcs15init_authenticate(profile, p15card, keyfile, SC_AC_OP_UPDATE); if (r < 0) goto out; keybits = key_info->modulus_length; /* generate key */ /* keysize is _not_ passed to the card at any point. it appears to infer it from the file size */ memset(&args, 0, sizeof(args)); args.exponent = 0x10001; sc_append_file_id(&args.pub_file_ref, temppubfile->id); sc_append_file_id(&args.pri_file_ref, keyfile->id); keybuf = malloc(keybits / 8); if (!keybuf) { r=SC_ERROR_OUT_OF_MEMORY; goto out; } args.pubkey = keybuf; args.pubkey_len = keybits / 8; r = sc_card_ctl(p15card->card, SC_CARDCTL_JCOP_GENERATE_KEY, (void *)&args); if (r < 0) goto out; /* extract public key */ pubkey->algorithm = SC_ALGORITHM_RSA; pubkey->u.rsa.modulus.len = keybits / 8; pubkey->u.rsa.modulus.data = keybuf; pubkey->u.rsa.exponent.len = 3; pubkey->u.rsa.exponent.data = malloc(3); if (!pubkey->u.rsa.exponent.data) { pubkey->u.rsa.modulus.data = NULL; r=SC_ERROR_OUT_OF_MEMORY; goto out; } memcpy(pubkey->u.rsa.exponent.data, "\x01\x00\x01", 3); out: if (r < 0 && keybuf) free(keybuf); if (delete_ok) sc_pkcs15init_rmdir(p15card, profile, temppubfile); if (keyfile) sc_file_free(keyfile); if (temppubfile) sc_file_free(temppubfile); return r; }
/* * Key generation */ static int incrypto34_generate_key(sc_profile_t *profile, sc_pkcs15_card_t *p15card, sc_pkcs15_object_t *obj, sc_pkcs15_pubkey_t *pubkey) { sc_pkcs15_prkey_info_t *key_info = (sc_pkcs15_prkey_info_t *) obj->data; sc_card_t *card = p15card->card; struct sc_pkcs15_prkey_rsa key_obj; struct sc_cardctl_incrypto34_genkey_info args; struct sc_file *temp; u8 abignum[RSAKEY_MAX_SIZE]; unsigned int keybits; int algorithm, r, delete_it = 0; if (obj->type != SC_PKCS15_TYPE_PRKEY_RSA) { sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "Incrypto34 supports only RSA keys."); return SC_ERROR_NOT_SUPPORTED; } if (incrypto34_key_algorithm(key_info->usage, &algorithm) < 0) { sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "Incrypto34 does not support keys " "that can both sign _and_ decrypt."); return SC_ERROR_NOT_SUPPORTED; } keybits = key_info->modulus_length & ~7UL; if (keybits > RSAKEY_MAX_BITS) { sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "Unable to generate key, max size is %d", RSAKEY_MAX_BITS); return SC_ERROR_INVALID_ARGUMENTS; } if (sc_profile_get_file(profile, "tempfile", &temp) < 0) { sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "Profile doesn't define temporary file " "for key generation."); return SC_ERROR_NOT_SUPPORTED; } memset(pubkey, 0, sizeof(*pubkey)); if ((r = sc_pkcs15init_create_file(profile, p15card, temp)) < 0) goto out; delete_it = 1; /* Create a key object, initializing components to 0xff */ memset(&key_obj, 0, sizeof(key_obj)); memset(abignum, 0xFF, sizeof(abignum)); key_obj.modulus.data = abignum; key_obj.modulus.len = keybits >> 3; key_obj.d.data = abignum; key_obj.d.len = keybits >> 3; r = incrypto34_put_key(profile, p15card, algorithm, key_info, &key_obj); if (r < 0) goto out; memset(&args, 0, sizeof(args)); args.key_id = key_info->key_reference; args.key_bits = keybits; args.fid = temp->id; r = sc_card_ctl(card, SC_CARDCTL_INCRYPTO34_GENERATE_KEY, &args); if (r < 0) goto out; /* extract public key from file and delete it */ if ((r = sc_select_file(card, &temp->path, NULL)) < 0) goto out; r = incrypto34_extract_pubkey(card, 1, 0x10, &pubkey->u.rsa.modulus); if (r < 0) goto out; r = incrypto34_extract_pubkey(card, 2, 0x11, &pubkey->u.rsa.exponent); if (r < 0) goto out; pubkey->algorithm = SC_ALGORITHM_RSA; out: if (delete_it) { sc_pkcs15init_rmdir(p15card, profile, temp); } sc_file_free(temp); if (r < 0) { if (pubkey->u.rsa.modulus.data) free (pubkey->u.rsa.modulus.data); if (pubkey->u.rsa.exponent.data) free (pubkey->u.rsa.exponent.data); } return r; }
/* * Create a new PIN */ static int setcos_create_pin_internal(sc_profile_t *profile, sc_pkcs15_card_t *p15card, int ignore_ac, sc_pkcs15_auth_info_t *auth_info, const u8 *pin, size_t pin_len, const u8 *puk, size_t puk_len) { struct sc_context *ctx = p15card->card->ctx; u8 data[32]; int r; struct sc_cardctl_setcos_data_obj data_obj; sc_file_t *pinfile = NULL; SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_VERBOSE); if (auth_info->auth_type != SC_PKCS15_PIN_AUTH_TYPE_PIN) return SC_ERROR_OBJECT_NOT_VALID; if (auth_info->attrs.pin.reference >= SETCOS_MAX_PINS) return SC_ERROR_INVALID_ARGUMENTS; if (pin == NULL || puk == NULL || pin_len < 4 || puk_len < 4) return SC_ERROR_INVALID_PIN_LENGTH; /* Verify required access rights if needed (i.e. if the * pin file isn't in the CREATE life cycle state). */ if (!ignore_ac) { r = sc_profile_get_file(profile, "pinfile", &pinfile); if (r >= 0) r = sc_pkcs15init_authenticate(profile, p15card, pinfile, SC_AC_OP_UPDATE); sc_file_free(pinfile); if (r < 0) return r; } /* Make command to add a pin-record */ data_obj.P1 = 01; data_obj.P2 = 01; /* setcos pin number */ data[0] = auth_info->attrs.pin.reference; memset(&data[1], auth_info->attrs.pin.pad_char, 16); /* padding */ memcpy(&data[1], (u8 *)pin, pin_len); /* copy pin*/ memcpy(&data[9], (u8 *)puk, puk_len); /* copy puk */ data[17] = auth_info->tries_left & 0x0F; data[18] = auth_info->tries_left & 0x0F; /* 0xF0: unlimited unblock tries */ data[19] = 0xF0 | setcos_puk_retries(profile, auth_info->attrs.pin.reference); /* Allow an unlimited number of signatures after a pin verification. * If set to 1 or so, we would have a UserConsent PIN. */ data[20] = 0x00; if (auth_info->attrs.pin.type == 0) data[21] = 0x01; /* BCD */ else data[21] = 0x00; /* ASCII */ if ((auth_info->attrs.pin.flags & 0x010) == 0) /* test for initial pin */ data[21] |= 0x80; data[22] = 0x00; /* not used */ data[23] = 0x00; /* not used */ data_obj.Data = data; data_obj.DataLen = 24; r = sc_card_ctl(p15card->card, SC_CARDCTL_SETCOS_PUTDATA, &data_obj); SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_VERBOSE, r); }
static int entersafe_create_dir(sc_profile_t *profile, sc_pkcs15_card_t *p15card, sc_file_t *df) { struct sc_card *card = p15card->card; int ret; SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); {/* df */ sc_entersafe_create_data df_data; df_data.type = SC_ENTERSAFE_DF_DATA; df_data.data.df.file_id[0]=(df->id >> 8) & 0xFF; df_data.data.df.file_id[1]=df->id & 0xFF; df_data.data.df.file_count=0x30; df_data.data.df.flag=0x01; df_data.data.df.ikf_size[0]=(df->size>>8)&0xFF; df_data.data.df.ikf_size[1]=df->size&0xFF; df_data.data.df.create_ac=0x10; df_data.data.df.append_ac=0xC0; df_data.data.df.lock_ac=0x10; memcpy(df_data.data.df.aid,df->name,df->namelen); ret = sc_card_ctl(card, SC_CARDCTL_ENTERSAFE_CREATE_FILE, &df_data); SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL,ret,"Crate DF failed"); } {/* GPKF */ sc_file_t *gpkf_file; sc_entersafe_create_data ef_data; /* get p15_gpkf profile */ ret = sc_profile_get_file(profile, "p15_gpkf", &gpkf_file); SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL,ret,"Get GPKF info failed"); ef_data.type=SC_ENTERSAFE_EF_DATA; ef_data.data.ef.file_id[0]=(gpkf_file->id>>8)&0xFF; ef_data.data.ef.file_id[1]=gpkf_file->id&0xFF; ef_data.data.ef.size[0]=(gpkf_file->size>>8)&0xFF; ef_data.data.ef.size[1]=gpkf_file->size&0xFF; ef_data.data.ef.attr[0]=0x15; ef_data.data.ef.attr[1]=0x80; ef_data.data.ef.name=0x00; memset(ef_data.data.ef.ac,0x10,sizeof(ef_data.data.ef.ac)); memset(ef_data.data.ef.sm,0x00,sizeof(ef_data.data.ef.sm)); sc_file_free(gpkf_file); ret = sc_card_ctl(card, SC_CARDCTL_ENTERSAFE_CREATE_FILE, &ef_data); SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL,ret,"Create GPKF failed"); } {/* p15 efs */ const char * create_efs[]={ "PKCS15-ODF", "PKCS15-TokenInfo", "PKCS15-UnusedSpace", "PKCS15-AODF", "PKCS15-PrKDF", "PKCS15-PuKDF", "PKCS15-CDF", "PKCS15-DODF", NULL, }; int i; sc_file_t *file=0; sc_entersafe_create_data tmp; for(i = 0; create_efs[i]; ++i) { if (sc_profile_get_file(profile, create_efs[i], &file)) { sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "Inconsistent profile: cannot find %s", create_efs[i]); SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE,SC_ERROR_INCONSISTENT_PROFILE); } tmp.type=SC_ENTERSAFE_EF_DATA; tmp.data.ef.file_id[0]=(file->id>>8)&0xFF; tmp.data.ef.file_id[1]=file->id&0xFF; tmp.data.ef.size[0]=(file->size>>8)&0xFF; tmp.data.ef.size[1]=file->size&0xFF; tmp.data.ef.attr[0]=0x00; tmp.data.ef.attr[1]=0x00; tmp.data.ef.name=0x00; memset(tmp.data.ef.ac,ENTERSAFE_AC_ALWAYS,sizeof(tmp.data.ef.ac)); tmp.data.ef.ac[0]=process_acl_entry(file,SC_AC_OP_READ,ENTERSAFE_AC_ALWAYS); /* read */ tmp.data.ef.ac[1]=process_acl_entry(file,SC_AC_OP_UPDATE,ENTERSAFE_AC_ALWAYS); /* update */ memset(tmp.data.ef.sm,0x00,sizeof(tmp.data.ef.sm)); sc_file_free(file); ret = sc_card_ctl(card, SC_CARDCTL_ENTERSAFE_CREATE_FILE, &tmp); SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL,ret,"Create pkcs15 file failed"); } } {/* Preinstall keys */ ret = sc_card_ctl(card, SC_CARDCTL_ENTERSAFE_PREINSTALL_KEYS, 0); SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL,ret,"Preinstall keys failed"); } SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE,ret); }
static int entersafe_init_card(sc_profile_t *profile, sc_pkcs15_card_t *p15card) { struct sc_card *card = p15card->card; int ret; {/* MF */ sc_file_t *mf_file; sc_entersafe_create_data mf_data; SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); ret = sc_profile_get_file(profile, "MF", &mf_file); SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL,ret,"Get MF info failed"); mf_data.type = SC_ENTERSAFE_MF_DATA; mf_data.data.df.file_id[0]=0x3F; mf_data.data.df.file_id[1]=0x00; mf_data.data.df.file_count=0x04; mf_data.data.df.flag=0x11; mf_data.data.df.ikf_size[0]=(mf_file->size>>8)&0xFF; mf_data.data.df.ikf_size[1]=mf_file->size&0xFF; mf_data.data.df.create_ac=0x10; mf_data.data.df.append_ac=0xC0; mf_data.data.df.lock_ac=0x10; memcpy(mf_data.data.df.aid,mf_file->name,mf_file->namelen); sc_file_free(mf_file); ret = sc_card_ctl(card, SC_CARDCTL_ENTERSAFE_CREATE_FILE, &mf_data); SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL,ret,"Create MF failed"); } {/* EF(DIR) */ sc_file_t *dir_file; size_t fid,size; sc_entersafe_create_data ef_data; u8 *buff=0; /* get dir profile */ ret = sc_profile_get_file(profile, "dir", &dir_file); SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL,ret,"Get EF(DIR) info failed"); fid=dir_file->id; size=dir_file->size; sc_file_free(dir_file); ef_data.type=SC_ENTERSAFE_EF_DATA; ef_data.data.ef.file_id[0]=(fid>>8)&0xFF; ef_data.data.ef.file_id[1]=fid&0xFF; ef_data.data.ef.size[0]=(size>>8)&0xFF; ef_data.data.ef.size[1]=size&0xFF; ef_data.data.ef.attr[0]=0x00; ef_data.data.ef.attr[1]=0x00; ef_data.data.ef.name=0x00; memset(ef_data.data.ef.ac,0x10,sizeof(ef_data.data.ef.ac)); memset(ef_data.data.ef.sm,0x00,sizeof(ef_data.data.ef.sm)); ret = sc_card_ctl(card, SC_CARDCTL_ENTERSAFE_CREATE_FILE, &ef_data); SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL,ret,"Create EF(DIR) failed"); /* fill file by 0 */ buff = calloc(1,size); if(!buff) SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE,SC_SUCCESS); memset(buff,0,size); ret = sc_update_binary(card,0,buff,size,0); free(buff); SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL,ret,"Initialize EF(DIR) failed"); } SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE,SC_SUCCESS); }