static int do_change(int argc, char **argv) { int ref, r, tries_left = -1; u8 oldpin[30]; u8 newpin[30]; size_t oldpinlen = 0; size_t newpinlen = 0; if (argc < 1 || argc > 3) goto usage; if (strncasecmp(argv[0], "CHV", 3)) { printf("Invalid type.\n"); goto usage; } if (sscanf(argv[0] + 3, "%d", &ref) != 1) { printf("Invalid key reference.\n"); goto usage; } if (argc == 3) { oldpinlen = sizeof(oldpin); if (parse_string_or_hexdata(argv[1], oldpin, &oldpinlen) != 0) { printf("Invalid key value.\n"); goto usage; } } if (argc >= 2) { newpinlen = sizeof(newpin); if (parse_string_or_hexdata(argv[argc-1], newpin, &newpinlen) != 0) { printf("Invalid key value.\n"); goto usage; } } r = sc_change_reference_data (card, SC_AC_CHV, ref, oldpinlen ? oldpin : NULL, oldpinlen, newpinlen ? newpin : NULL, newpinlen, &tries_left); if (r) { if (r == SC_ERROR_PIN_CODE_INCORRECT) { if (tries_left >= 0) printf("Incorrect code, %d tries left.\n", tries_left); else printf("Incorrect code.\n"); } printf("Unable to change PIN code: %s\n", sc_strerror(r)); return -1; } printf("PIN changed.\n"); return 0; usage: printf("Usage: change CHV<pin ref> [[<old pin>] <new pin>]\n"); printf("Examples: \n"); printf("\tChange PIN: change CHV2 00:00:00:00:00:00 \"foobar\"\n"); printf("\tSet PIN: change CHV2 \"foobar\"\n"); printf("\tChange PIN with pinpad': change CHV2\n"); return -1; }
/* * Store a PIN */ static int jcop_create_pin(sc_profile_t *profile, sc_card_t *card, 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_pkcs15_pin_info_t *pin_info = (sc_pkcs15_pin_info_t *) pin_obj->data; unsigned char nulpin[16]; unsigned char padpin[16]; int r, type; if (pin_info->flags & SC_PKCS15_PIN_FLAG_SO_PIN) { type = SC_PKCS15INIT_SO_PIN; /* SO PIN reference must be 0 */ if (pin_info->reference != 3) return SC_ERROR_INVALID_ARGUMENTS; } else { type = SC_PKCS15INIT_USER_PIN; if (pin_info->reference >= 3) return SC_ERROR_TOO_MANY_OBJECTS; } if (puk != NULL && puk_len > 0) { return SC_ERROR_NOT_SUPPORTED; } r = sc_select_file(card, &df->path, NULL); if (r < 0) return r; /* Current PIN is 00:00:00:00:00:00:00:00... */ memset(nulpin, 0, sizeof(nulpin)); memset(padpin, 0, sizeof(padpin)); memcpy(padpin, pin, pin_len); r = sc_change_reference_data(card, SC_AC_CHV, pin_info->reference, nulpin, sizeof(nulpin), padpin, sizeof(padpin), NULL); if (r < 0) return r; sc_keycache_set_pin_name(&df->path, pin_info->reference, type); pin_info->flags &= ~SC_PKCS15_PIN_FLAG_LOCAL; return r; }
/* * Store a PIN */ static int jcop_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_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; unsigned char nulpin[16]; unsigned char padpin[16]; int r; if (auth_info->auth_type != SC_PKCS15_PIN_AUTH_TYPE_PIN) return SC_ERROR_OBJECT_NOT_VALID; if (pin_attrs->flags & SC_PKCS15_PIN_FLAG_SO_PIN) { /* SO PIN reference must be 0 */ if (pin_attrs->reference != 3) return SC_ERROR_INVALID_ARGUMENTS; } else { if (pin_attrs->reference >= 3) return SC_ERROR_TOO_MANY_OBJECTS; } if (puk != NULL && puk_len > 0) { return SC_ERROR_NOT_SUPPORTED; } r = sc_select_file(p15card->card, &df->path, NULL); if (r < 0) return r; /* Current PIN is 00:00:00:00:00:00:00:00... */ memset(nulpin, 0, sizeof(nulpin)); memset(padpin, 0, sizeof(padpin)); memcpy(padpin, pin, pin_len); r = sc_change_reference_data(p15card->card, SC_AC_CHV, pin_attrs->reference, nulpin, sizeof(nulpin), padpin, sizeof(padpin), NULL); if (r < 0) return r; pin_attrs->flags &= ~SC_PKCS15_PIN_FLAG_LOCAL; return r; }
/* * Store a PIN */ static int gpk_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) { 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; u8 nulpin[8]; int r; SC_FUNC_CALLED(p15card->card->ctx, SC_LOG_DEBUG_VERBOSE); if (auth_info->auth_type != SC_PKCS15_PIN_AUTH_TYPE_PIN) return SC_ERROR_OBJECT_NOT_VALID; if (pin_attrs->flags & SC_PKCS15_PIN_FLAG_SO_PIN) { /* SO PIN reference must be 0 */ if (pin_attrs->reference != (GPK_PIN_SCOPE | 0)) return SC_ERROR_INVALID_ARGUMENTS; } else { /* PIN references must be even numbers * (the odd numbered PIN entries contain the * PUKs). * Returning SC_ERROR_INVALID_PIN_REFERENCE will * tell the caller to pick a different value. */ if ((pin_attrs->reference & 1) || !(pin_attrs->reference & GPK_PIN_SCOPE)) return SC_ERROR_INVALID_PIN_REFERENCE; if (pin_attrs->reference >= (GPK_PIN_SCOPE + GPK_MAX_PINS)) return SC_ERROR_TOO_MANY_OBJECTS; } /* No PUK given, but the PIN file specifies an unblock * PIN for every PIN. * Use the same value for the PUK for now. * Alternatively, we could leave the unblock PIN at the default * value, but deliberately block it. */ if (puk == NULL || puk_len == 0) { puk = pin; puk_len = pin_len; } r = sc_select_file(p15card->card, &df->path, NULL); sc_debug(p15card->card->ctx, SC_LOG_DEBUG_NORMAL, "select df path: %i", r); if (r < 0) return r; /* Current PIN is 00:00:00:00:00:00:00:00 */ memset(nulpin, 0, sizeof(nulpin)); r = sc_change_reference_data(p15card->card, SC_AC_CHV, pin_attrs->reference, nulpin, sizeof(nulpin), pin, pin_len, NULL); sc_debug(p15card->card->ctx, SC_LOG_DEBUG_NORMAL, "change CHV %i", r); if (r < 0) return r; /* Current PUK is 00:00:00:00:00:00:00:00 */ r = sc_change_reference_data(p15card->card, SC_AC_CHV, pin_attrs->reference + 1, nulpin, sizeof(nulpin), puk, puk_len, NULL); sc_debug(p15card->card->ctx, SC_LOG_DEBUG_NORMAL, "change CHV+1 %i", r); if (r < 0) return r; SC_FUNC_RETURN(p15card->card->ctx, SC_LOG_DEBUG_NORMAL, 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 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); }
/* * Store a PIN */ static int gpk_create_pin(sc_profile_t *profile, sc_card_t *card, sc_file_t *df, sc_pkcs15_object_t *pin_obj, const u8 *pin, size_t pin_len, const u8 *puk, size_t puk_len) { sc_pkcs15_pin_info_t *pin_info = (sc_pkcs15_pin_info_t *) pin_obj->data; u8 nulpin[8]; int r, type; if (pin_info->flags & SC_PKCS15_PIN_FLAG_SO_PIN) { type = SC_PKCS15INIT_SO_PIN; /* SO PIN reference must be 0 */ if (pin_info->reference != (GPK_PIN_SCOPE | 0)) return SC_ERROR_INVALID_ARGUMENTS; } else { type = SC_PKCS15INIT_USER_PIN; /* PIN references must be even numbers * (the odd numbered PIN entries contain the * PUKs). * Returning SC_ERROR_INVALID_PIN_REFERENCE will * tell the caller to pick a different value. */ if ((pin_info->reference & 1) || !(pin_info->reference & GPK_PIN_SCOPE)) return SC_ERROR_INVALID_PIN_REFERENCE; if (pin_info->reference >= (GPK_PIN_SCOPE + GPK_MAX_PINS)) return SC_ERROR_TOO_MANY_OBJECTS; } /* No PUK given, but the PIN file specifies an unblock * PIN for every PIN. * Use the same value for the PUK for now. * Alternatively, we could leave the unblock PIN at the default * value, but deliberately block it. */ if (puk == NULL || puk_len == 0) { puk = pin; puk_len = pin_len; } r = sc_select_file(card, &df->path, NULL); if (r < 0) return r; /* Current PIN is 00:00:00:00:00:00:00:00 */ memset(nulpin, 0, sizeof(nulpin)); r = sc_change_reference_data(card, SC_AC_CHV, pin_info->reference, nulpin, sizeof(nulpin), pin, pin_len, NULL); if (r < 0) return r; /* Current PUK is 00:00:00:00:00:00:00:00 */ r = sc_change_reference_data(card, SC_AC_CHV, pin_info->reference + 1, nulpin, sizeof(nulpin), puk, puk_len, NULL); if (r < 0) return r; sc_keycache_set_pin_name(&df->path, pin_info->reference, type); return r; }
static int do_change(int argc, char **argv) { int ref, r, tries_left = -1; u8 oldpin[30]; u8 newpin[30]; const char *s; size_t oldpinlen = sizeof(oldpin), i; size_t newpinlen = sizeof(newpin); if (argc < 1 || argc > 3) goto usage; if (strncasecmp(argv[0], "CHV", 3)) { printf("Invalid type.\n"); goto usage; } if (sscanf(argv[0] + 3, "%d", &ref) != 1) { printf("Invalid key reference.\n"); goto usage; } argc--; argv++; if (argc == 0) { /* set without verification */ oldpinlen = 0; newpinlen = 0; } else if (argc == 1) { /* set without verification */ oldpinlen = 0; } else { if (argv[0][0] == '"') { for (s = argv[0] + 1, i = 0; i < sizeof(oldpin) && *s && *s != '"'; i++) oldpin[i] = *s++; oldpinlen = i; } else if (sc_hex_to_bin(argv[0], oldpin, &oldpinlen) != 0) { printf("Invalid key value.\n"); goto usage; } argc--; argv++; } if (argc) { if (argv[0][0] == '"') { for (s = argv[0] + 1, i = 0; i < sizeof(newpin) && *s && *s != '"'; i++) newpin[i] = *s++; newpinlen = i; } else if (sc_hex_to_bin(argv[0], newpin, &newpinlen) != 0) { printf("Invalid key value.\n"); goto usage; } } r = sc_change_reference_data (card, SC_AC_CHV, ref, oldpinlen ? oldpin : NULL, oldpinlen, newpinlen ? newpin : NULL, newpinlen, &tries_left); if (r) { if (r == SC_ERROR_PIN_CODE_INCORRECT) { if (tries_left >= 0) printf("Incorrect code, %d tries left.\n", tries_left); else printf("Incorrect code.\n"); } printf("Unable to change PIN code: %s\n", sc_strerror(r)); return -1; } printf("PIN changed.\n"); return 0; usage: printf("Usage: change CHV<pin ref> [[<old pin>] <new pin>]\n"); printf("Examples: \n"); printf("\tChange PIN: change CHV2 00:00:00:00:00:00 \"foobar\"\n"); printf("\tSet PIN: change CHV2 \"foobar\"\n"); printf("\tChange PIN with pinpad': change CHV2\n"); return -1; }
/* * 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); }