static int entersafe_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) { struct sc_card *card = p15card->card; int r; sc_pkcs15_auth_info_t *auth_info = (sc_pkcs15_auth_info_t *) pin_obj->data; SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); if (auth_info->auth_type != SC_PKCS15_PIN_AUTH_TYPE_PIN) return SC_ERROR_OBJECT_NOT_VALID; {/*pin*/ sc_entersafe_wkey_data data; if (!pin || !pin_len || pin_len > 16) return SC_ERROR_INVALID_ARGUMENTS; data.key_id = auth_info->attrs.pin.reference; data.usage=0x0B; data.key_data.symmetric.EC=0x33; data.key_data.symmetric.ver=0x00; /* pad pin with 0 */ memset(data.key_data.symmetric.key_val, 0, sizeof(data.key_data.symmetric.key_val)); memcpy(data.key_data.symmetric.key_val, pin, pin_len); data.key_data.symmetric.key_len=16; r = sc_card_ctl(card, SC_CARDCTL_ENTERSAFE_WRITE_KEY, &data); /* Cache new PIN value. */ sc_pkcs15_pincache_add(p15card, pin_obj, pin, pin_len); } {/*puk*/ sc_entersafe_wkey_data data; if (!puk || !puk_len || puk_len > 16) return SC_ERROR_INVALID_ARGUMENTS; data.key_id = auth_info->attrs.pin.reference+1; data.usage=0x0B; data.key_data.symmetric.EC=0x33; data.key_data.symmetric.ver=0x00; /* pad pin with 0 */ memset(data.key_data.symmetric.key_val, 0, sizeof(data.key_data.symmetric.key_val)); memcpy(data.key_data.symmetric.key_val, puk, puk_len); data.key_data.symmetric.key_len=16; r = sc_card_ctl(card, SC_CARDCTL_ENTERSAFE_WRITE_KEY, &data); } SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE,r); }
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); }
/* * Unblock a PIN. */ int sc_pkcs15_unblock_pin(struct sc_pkcs15_card *p15card, struct sc_pkcs15_object *pin_obj, const u8 *puk, size_t puklen, const u8 *newpin, size_t newpinlen) { int r; sc_card_t *card; struct sc_pin_cmd_data data; struct sc_pkcs15_object *puk_obj; struct sc_pkcs15_pin_info *puk_info = NULL; struct sc_pkcs15_pin_info *pin_info = (struct sc_pkcs15_pin_info *)pin_obj->data; /* make sure the pins are in valid range */ if ((r = _validate_pin(p15card, pin_info, newpinlen)) != SC_SUCCESS) return r; card = p15card->card; /* get pin_info object of the puk (this is a little bit complicated * as we don't have the id of the puk (at least now)) * note: for compatibility reasons we give no error if no puk object * is found */ /* first step: try to get the pkcs15 object of the puk */ r = sc_pkcs15_find_pin_by_auth_id(p15card, &pin_obj->auth_id, &puk_obj); if (r >= 0 && puk_obj) { /* second step: get the pkcs15 info object of the puk */ puk_info = (struct sc_pkcs15_pin_info *)puk_obj->data; } if (!puk_info) { sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "Unable to get puk object, using pin object instead!"); puk_info = pin_info; } /* make sure the puk is in valid range */ if ((r = _validate_pin(p15card, puk_info, puklen)) != SC_SUCCESS) return r; r = sc_lock(card); SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "sc_lock() failed"); /* the path in the pin object is optional */ if (pin_info->path.len > 0) { r = sc_select_file(card, &pin_info->path, NULL); if (r) goto out; } /* set pin_cmd data */ memset(&data, 0, sizeof(data)); data.cmd = SC_PIN_CMD_UNBLOCK; data.pin_type = SC_AC_CHV; data.pin_reference = pin_info->reference; data.pin1.data = puk; data.pin1.len = puklen; data.pin1.pad_char = pin_info->pad_char; data.pin1.min_length = pin_info->min_length; data.pin1.max_length = pin_info->max_length; data.pin1.pad_length = pin_info->stored_length; data.pin2.data = newpin; data.pin2.len = newpinlen; data.pin2.pad_char = puk_info->pad_char; data.pin2.min_length = puk_info->min_length; data.pin2.max_length = puk_info->max_length; data.pin2.pad_length = puk_info->stored_length; if (pin_info->flags & SC_PKCS15_PIN_FLAG_NEEDS_PADDING) data.flags |= SC_PIN_CMD_NEED_PADDING; switch (pin_info->type) { case SC_PKCS15_PIN_TYPE_BCD: data.pin1.encoding = SC_PIN_ENCODING_BCD; break; case SC_PKCS15_PIN_TYPE_ASCII_NUMERIC: data.pin1.encoding = SC_PIN_ENCODING_ASCII; break; } switch (puk_info->type) { case SC_PKCS15_PIN_TYPE_BCD: data.pin2.encoding = SC_PIN_ENCODING_BCD; break; case SC_PKCS15_PIN_TYPE_ASCII_NUMERIC: data.pin2.encoding = SC_PIN_ENCODING_ASCII; break; } if(p15card->card->reader->capabilities & SC_READER_CAP_PIN_PAD) { data.flags |= SC_PIN_CMD_USE_PINPAD; if (pin_info->flags & SC_PKCS15_PIN_FLAG_SO_PIN) { data.pin1.prompt = "Please enter PUK"; data.pin2.prompt = "Please enter new SO PIN"; } else { data.pin1.prompt = "Please enter PUK"; data.pin2.prompt = "Please enter new PIN"; } } r = sc_pin_cmd(card, &data, &pin_info->tries_left); if (r == SC_SUCCESS) sc_pkcs15_pincache_add(p15card, pin_obj, newpin, newpinlen); out: sc_unlock(card); return r; }
/* * Change a PIN. */ int sc_pkcs15_change_pin(struct sc_pkcs15_card *p15card, struct sc_pkcs15_object *pin_obj, const u8 *oldpin, size_t oldpinlen, const u8 *newpin, size_t newpinlen) { int r; sc_card_t *card; struct sc_pin_cmd_data data; struct sc_pkcs15_pin_info *pin_info = (struct sc_pkcs15_pin_info *)pin_obj->data; /* make sure the pins are in valid range */ if ((r = _validate_pin(p15card, pin_info, oldpinlen)) != SC_SUCCESS) return r; if ((r = _validate_pin(p15card, pin_info, newpinlen)) != SC_SUCCESS) return r; card = p15card->card; r = sc_lock(card); SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "sc_lock() failed"); /* the path in the pin object is optional */ if (pin_info->path.len > 0) { r = sc_select_file(card, &pin_info->path, NULL); if (r) goto out; } /* set pin_cmd data */ memset(&data, 0, sizeof(data)); data.cmd = SC_PIN_CMD_CHANGE; data.pin_type = SC_AC_CHV; data.pin_reference = pin_info->reference; data.pin1.data = oldpin; data.pin1.len = oldpinlen; data.pin1.pad_char = pin_info->pad_char; data.pin1.min_length = pin_info->min_length; data.pin1.max_length = pin_info->max_length; data.pin1.pad_length = pin_info->stored_length; data.pin2.data = newpin; data.pin2.len = newpinlen; data.pin2.pad_char = pin_info->pad_char; data.pin2.min_length = pin_info->min_length; data.pin2.max_length = pin_info->max_length; data.pin2.pad_length = pin_info->stored_length; if (pin_info->flags & SC_PKCS15_PIN_FLAG_NEEDS_PADDING) data.flags |= SC_PIN_CMD_NEED_PADDING; switch (pin_info->type) { case SC_PKCS15_PIN_TYPE_BCD: data.pin1.encoding = SC_PIN_ENCODING_BCD; data.pin2.encoding = SC_PIN_ENCODING_BCD; break; case SC_PKCS15_PIN_TYPE_ASCII_NUMERIC: data.pin1.encoding = SC_PIN_ENCODING_ASCII; data.pin2.encoding = SC_PIN_ENCODING_ASCII; break; } if((!oldpin || !newpin) && p15card->card->reader->capabilities & SC_READER_CAP_PIN_PAD) { data.flags |= SC_PIN_CMD_USE_PINPAD; if (pin_info->flags & SC_PKCS15_PIN_FLAG_SO_PIN) { data.pin1.prompt = "Please enter SO PIN"; data.pin2.prompt = "Please enter new SO PIN"; } else { data.pin1.prompt = "Please enter PIN"; data.pin2.prompt = "Please enter new PIN"; } } r = sc_pin_cmd(card, &data, &pin_info->tries_left); if (r == SC_SUCCESS) sc_pkcs15_pincache_add(p15card, pin_obj, newpin, newpinlen); out: sc_unlock(card); return r; }
/* * Verify a PIN. * * If the code given to us has zero length, this means we * should ask the card reader to obtain the PIN from the * reader's PIN pad */ int sc_pkcs15_verify_pin(struct sc_pkcs15_card *p15card, struct sc_pkcs15_object *pin_obj, const unsigned char *pincode, size_t pinlen) { struct sc_context *ctx = p15card->card->ctx; struct sc_pkcs15_pin_info *pin_info = (struct sc_pkcs15_pin_info *)pin_obj->data; int r; sc_card_t *card; struct sc_pin_cmd_data data; SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_NORMAL); sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "PIN(%p;len:%i)", pincode, pinlen); r = _validate_pin(p15card, pin_info, pinlen); SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, r, "PIN value do not conforms the PIN policy"); card = p15card->card; r = sc_lock(card); SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, r, "sc_lock() failed"); /* the path in the pin object is optional */ if (pin_info->path.len > 0) { r = sc_select_file(card, &pin_info->path, NULL); if (r) goto out; } /* Initialize arguments */ memset(&data, 0, sizeof(data)); data.cmd = SC_PIN_CMD_VERIFY; data.pin_type = pin_info->auth_method; data.pin_reference = pin_info->reference; data.pin1.min_length = pin_info->min_length; data.pin1.max_length = pin_info->max_length; data.pin1.pad_length = pin_info->stored_length; data.pin1.pad_char = pin_info->pad_char; data.pin1.data = pincode; data.pin1.len = pinlen; if (pin_info->flags & SC_PKCS15_PIN_FLAG_NEEDS_PADDING) data.flags |= SC_PIN_CMD_NEED_PADDING; switch (pin_info->type) { case SC_PKCS15_PIN_TYPE_BCD: data.pin1.encoding = SC_PIN_ENCODING_BCD; break; case SC_PKCS15_PIN_TYPE_ASCII_NUMERIC: data.pin1.encoding = SC_PIN_ENCODING_ASCII; break; default: /* assume/hope the card driver knows how to encode the pin */ data.pin1.encoding = 0; } if(p15card->card->reader->capabilities & SC_READER_CAP_PIN_PAD) { if (!pincode && !pinlen) data.flags |= SC_PIN_CMD_USE_PINPAD; if (pin_info->flags & SC_PKCS15_PIN_FLAG_SO_PIN) data.pin1.prompt = "Please enter SO PIN"; else data.pin1.prompt = "Please enter PIN"; } r = sc_pin_cmd(card, &data, &pin_info->tries_left); if (r == SC_SUCCESS) sc_pkcs15_pincache_add(p15card, pin_obj, pincode, pinlen); out: sc_unlock(card); return r; }
/* * Change a PIN. */ int sc_pkcs15_change_pin(struct sc_pkcs15_card *p15card, struct sc_pkcs15_object *pin_obj, const u8 *oldpin, size_t oldpinlen, const u8 *newpin, size_t newpinlen) { struct sc_context *ctx = p15card->card->ctx; struct sc_pin_cmd_data data; struct sc_pkcs15_auth_info *auth_info = (struct sc_pkcs15_auth_info *)pin_obj->data; struct sc_card *card = p15card->card; int r; LOG_FUNC_CALLED(ctx); if (auth_info->auth_type != SC_PKCS15_PIN_AUTH_TYPE_PIN) LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_SUPPORTED); /* make sure the pins are in valid range */ r = _validate_pin(p15card, auth_info, oldpinlen); LOG_TEST_RET(ctx, r, "Old PIN value do not conform PIN policy"); r = _validate_pin(p15card, auth_info, newpinlen); LOG_TEST_RET(ctx, r, "New PIN value do not conform PIN policy"); card = p15card->card; r = sc_lock(card); LOG_TEST_RET(ctx, r, "sc_lock() failed"); /* the path in the pin object is optional */ if ((auth_info->path.len > 0) || ((auth_info->path.aid.len > 0))) { r = sc_select_file(card, &auth_info->path, NULL); if (r) goto out; } /* set pin_cmd data */ memset(&data, 0, sizeof(data)); data.cmd = SC_PIN_CMD_CHANGE; data.pin_type = SC_AC_CHV; data.pin_reference = auth_info->attrs.pin.reference; data.pin1.data = oldpin; data.pin1.len = oldpinlen; data.pin1.pad_char = auth_info->attrs.pin.pad_char; data.pin1.min_length = auth_info->attrs.pin.min_length; data.pin1.max_length = auth_info->attrs.pin.max_length; data.pin1.pad_length = auth_info->attrs.pin.stored_length; data.pin2.data = newpin; data.pin2.len = newpinlen; data.pin2.pad_char = auth_info->attrs.pin.pad_char; data.pin2.min_length = auth_info->attrs.pin.min_length; data.pin2.max_length = auth_info->attrs.pin.max_length; data.pin2.pad_length = auth_info->attrs.pin.stored_length; if (auth_info->attrs.pin.flags & SC_PKCS15_PIN_FLAG_NEEDS_PADDING) data.flags |= SC_PIN_CMD_NEED_PADDING; switch (auth_info->attrs.pin.type) { case SC_PKCS15_PIN_TYPE_BCD: data.pin1.encoding = SC_PIN_ENCODING_BCD; data.pin2.encoding = SC_PIN_ENCODING_BCD; break; case SC_PKCS15_PIN_TYPE_ASCII_NUMERIC: data.pin1.encoding = SC_PIN_ENCODING_ASCII; data.pin2.encoding = SC_PIN_ENCODING_ASCII; break; } if((!oldpin || !newpin) && p15card->card->reader->capabilities & SC_READER_CAP_PIN_PAD) { data.flags |= SC_PIN_CMD_USE_PINPAD; if (auth_info->attrs.pin.flags & SC_PKCS15_PIN_FLAG_SO_PIN) { data.pin1.prompt = "Please enter SO PIN"; data.pin2.prompt = "Please enter new SO PIN"; } else { data.pin1.prompt = "Please enter PIN"; data.pin2.prompt = "Please enter new PIN"; } } r = sc_pin_cmd(card, &data, &auth_info->tries_left); if (r == SC_SUCCESS) sc_pkcs15_pincache_add(p15card, pin_obj, newpin, newpinlen); out: sc_unlock(card); return r; }
/* * Verify a PIN. * * If the code given to us has zero length, this means we * should ask the card reader to obtain the PIN from the * reader's PIN pad */ int sc_pkcs15_verify_pin(struct sc_pkcs15_card *p15card, struct sc_pkcs15_object *pin_obj, const unsigned char *pincode, size_t pinlen) { struct sc_context *ctx = p15card->card->ctx; struct sc_pkcs15_auth_info *auth_info = (struct sc_pkcs15_auth_info *)pin_obj->data; int r; sc_card_t *card; struct sc_pin_cmd_data data; LOG_FUNC_CALLED(ctx); sc_log(ctx, "PIN(type:%X;method:%X;len:)", auth_info->auth_type, auth_info->auth_method, pinlen); if (pinlen > SC_MAX_PIN_SIZE) LOG_TEST_RET(ctx, SC_ERROR_INVALID_PIN_LENGTH, "Invalid PIN size"); card = p15card->card; /* Initialize arguments */ memset(&data, 0, sizeof(data)); data.cmd = SC_PIN_CMD_VERIFY; data.pin_type = auth_info->auth_method; if (auth_info->auth_type == SC_PKCS15_PIN_AUTH_TYPE_PIN) { data.pin_reference = auth_info->attrs.pin.reference; data.pin1.min_length = auth_info->attrs.pin.min_length; data.pin1.max_length = auth_info->attrs.pin.max_length; data.pin1.pad_length = auth_info->attrs.pin.stored_length; data.pin1.pad_char = auth_info->attrs.pin.pad_char; data.pin1.data = pincode; data.pin1.len = pinlen; if (auth_info->attrs.pin.flags & SC_PKCS15_PIN_FLAG_NEEDS_PADDING) data.flags |= SC_PIN_CMD_NEED_PADDING; switch (auth_info->attrs.pin.type) { case SC_PKCS15_PIN_TYPE_BCD: data.pin1.encoding = SC_PIN_ENCODING_BCD; break; case SC_PKCS15_PIN_TYPE_ASCII_NUMERIC: data.pin1.encoding = SC_PIN_ENCODING_ASCII; break; default: /* assume/hope the card driver knows how to encode the pin */ data.pin1.encoding = 0; } } else if (auth_info->auth_type == SC_PKCS15_PIN_AUTH_TYPE_AUTH_KEY) { struct sc_pkcs15_object *skey_obj = NULL; struct sc_pkcs15_id *skey_id = &auth_info->attrs.authkey.skey_id; struct sc_pkcs15_skey_info *skey_info = NULL; r = sc_pkcs15_find_skey_by_id(p15card, skey_id, &skey_obj); if (r) { sc_log(ctx, "cannot find secret key with id:%s", sc_pkcs15_print_id(skey_id)); LOG_FUNC_RETURN(ctx, r); } skey_info = (struct sc_pkcs15_skey_info *)skey_obj->data; sc_log(ctx, "found secret key '%s'", skey_obj->label); data.pin_reference = skey_info->key_reference; } if(p15card->card->reader->capabilities & SC_READER_CAP_PIN_PAD) { if (!pincode && !pinlen) data.flags |= SC_PIN_CMD_USE_PINPAD; if (auth_info->attrs.pin.flags & SC_PKCS15_PIN_FLAG_SO_PIN) data.pin1.prompt = "Please enter SO PIN"; else data.pin1.prompt = "Please enter PIN"; } r = sc_lock(card); LOG_TEST_RET(ctx, r, "sc_lock() failed"); /* the path in the pin object is optional */ if ((auth_info->path.len > 0) || ((auth_info->path.aid.len > 0))) { r = sc_select_file(card, &auth_info->path, NULL); if (r) goto out; } r = sc_pin_cmd(card, &data, &auth_info->tries_left); sc_log(ctx, "PIN cmd result %i", r); if (r == SC_SUCCESS) sc_pkcs15_pincache_add(p15card, pin_obj, pincode, pinlen); out: sc_unlock(card); LOG_FUNC_RETURN(ctx, r); }