📄 pkcs15-lib.c
字号:
voidsc_pkcs15init_set_pin_data(struct sc_profile *profile, int pin_id, const void *value, size_t len){ sc_profile_set_secret(profile, SC_AC_SYMBOLIC, pin_id, (const u8 *) value, len);}/* * PIN verification */intdo_get_and_verify_secret(struct sc_profile *pro, struct sc_card *card, int type, int reference, u8 *pinbuf, size_t *pinsize, int verify){ struct sc_pkcs15_pin_info pin_info; struct sc_cardctl_default_key data; const char *ident, *label = NULL; unsigned int pin_id = (unsigned int) -1; size_t defsize = 0; u8 defbuf[32]; int r; ident = "authentication data"; if (type == SC_AC_CHV) { sc_pkcs15_object_t *pin_obj; ident = "PIN"; memset(&pin_info, 0, sizeof(pin_info)); if (sc_profile_get_pin_id(pro, reference, &pin_id) >= 0) { sc_profile_get_pin_info(pro, pin_id, &pin_info); } else if (pro->p15_card && sc_pkcs15_find_pin_by_reference(pro->p15_card, reference, &pin_obj) == 0) { memcpy(&pin_info, pin_obj->data, sizeof(pin_info)); } else { /* This is all info we have */ pin_info.reference = reference; } } else if (type == SC_AC_PRO) { ident = "secure messaging key"; } else if (type == SC_AC_AUT) { ident = "authentication key"; } else if (type == SC_AC_SYMBOLIC) { switch (reference) { case SC_PKCS15INIT_USER_PIN: ident = "user PIN"; break; case SC_PKCS15INIT_SO_PIN: ident = "SO PIN"; break; } pin_id = reference; sc_profile_get_pin_info(pro, pin_id, &pin_info); type = SC_AC_CHV; reference = pin_info.reference; /* If reference is -1, this means the card issuer * didn't set this PIN */ if (reference == -1) return 0; } /* Try to get the cached secret, e.g. CHV1 */ r = sc_profile_get_secret(pro, type, reference, pinbuf, pinsize); if (r >= 0) goto found; /* If this secret is linked to a symbolic PIN, e.g. SOPIN1, * see if we've cached it under that name */ if (pin_id != -1) { r = sc_profile_get_secret(pro, SC_AC_SYMBOLIC, pin_id, pinbuf, pinsize); if (r >= 0) goto found; } if (type != SC_AC_CHV) { /* Okay, nothing in our cache. * Ask the card driver whether it knows a default key * for this one. */ data.method = type; data.key_ref = reference; data.len = sizeof(defbuf); data.key_data = defbuf; if (sc_card_ctl(card, SC_CARDCTL_GET_DEFAULT_KEY, &data) >= 0) defsize = data.len; } else if (pro->p15_card) { /* Get the label, if we have one */ struct sc_pkcs15_object *obj; int r; r = sc_pkcs15_find_pin_by_reference(pro->p15_card, reference, &obj); if (r >= 0 && obj->label[0]) label = obj->label; } if (callbacks) { switch (type) { case SC_AC_CHV: if (callbacks->get_pin) { r = callbacks->get_pin(pro, pin_id, &pin_info, label, pinbuf, pinsize); } break; default: if (callbacks->get_key) { r = callbacks->get_key(pro, type, reference, defbuf, defsize, pinbuf, pinsize); } break; } } if (r < 0) return r;found: /* We got something. Cache it */ sc_profile_set_secret(pro, type, reference, pinbuf, *pinsize); /* If it's a PIN, pad it out */ if (type == SC_AC_CHV) { int left = pro->pin_maxlen - *pinsize; if (left > 0) { memset(pinbuf + *pinsize, pro->pin_pad_char, left); *pinsize = pro->pin_maxlen; } /* If it's associated with a symbolic PIN, store it under * the symbolic name as well */ if (pin_id != -1) sc_profile_set_secret(pro, SC_AC_SYMBOLIC, pin_id, pinbuf, *pinsize); } if (verify && (r = sc_verify(card, type, reference, pinbuf, *pinsize, 0)) < 0) { p15init_error("Failed to verify %s (ref=0x%x)", ident, reference); } return r;}static intdo_verify_pin(struct sc_profile *pro, struct sc_card *card, unsigned int type, unsigned int reference){ size_t pinsize; u8 pinbuf[32]; pinsize = sizeof(pinbuf); return do_get_and_verify_secret(pro, card, type, reference, pinbuf, &pinsize, 1);}voidsc_pkcs15init_set_secret(struct sc_profile *pro, int type, int reference, u8 *key, size_t len){ sc_profile_set_secret(pro, type, reference, key, len);}intsc_pkcs15init_get_secret(struct sc_profile *pro, struct sc_card *card, int type, int reference, u8 *pinbuf, size_t *pinsize){ return do_get_and_verify_secret(pro, card, type, reference, pinbuf, pinsize, 0);}/* * Present a single PIN to the card */intsc_pkcs15init_present_pin(struct sc_profile *profile, struct sc_card *card, unsigned int id){ return do_verify_pin(profile, card, SC_AC_SYMBOLIC, id);}/* * Find out whether the card was initialized using an SO PIN, * and if so, set the profile information */intset_so_pin_from_card(struct sc_pkcs15_card *p15card, struct sc_profile *profile){ struct sc_pkcs15_pin_info pin; struct sc_pkcs15_object *obj; int r; r = sc_pkcs15_find_so_pin(p15card, &obj); if (r == 0) { pin = *(struct sc_pkcs15_pin_info *) obj->data; } else if (r == SC_ERROR_OBJECT_NOT_FOUND) { sc_profile_get_pin_info(profile, SC_PKCS15INIT_SO_PIN, &pin); pin.reference = -1; } else { return r; } sc_profile_set_pin_info(profile, SC_PKCS15INIT_SO_PIN, &pin); return 0;}/* * If the user specified an auth_id, select the corresponding * PIN entry and set the reference data */static intset_user_pin_from_authid(struct sc_pkcs15_card *p15card, struct sc_profile *profile, struct sc_pkcs15_id *auth_id){ struct sc_pkcs15_object *objp; int r; if (auth_id->len == 0) return 0; r = sc_pkcs15_find_pin_by_auth_id(p15card, auth_id, &objp); if (r < 0) return r; sc_profile_set_pin_info(profile, SC_PKCS15INIT_USER_PIN, (struct sc_pkcs15_pin_info *) objp->data); return 0;}/* * Present any authentication info as required by the file. * * XXX: There's a problem here if e.g. the SO PIN defined by * the profile is optional, and hasn't been set. In this case, * it would be better if we based our authentication on the * real ACLs of the file (i.e. the data returned by a previous * sc_select_file()). Current practice though is to prefer * checking against the ACL defined by the profile (introduced by * Juha for some reason) and I'm not sure we can change this * easily. */intsc_pkcs15init_authenticate(struct sc_profile *pro, struct sc_card *card, struct sc_file *file, int op){ const struct sc_acl_entry *acl; int r = 0;#if 0 /* Fix up the file's ACLs */ if ((r = sc_pkcs15init_fixup_file(pro, file)) < 0) return r;#endif acl = sc_file_get_acl_entry(file, op); for (; r == 0 && acl; acl = acl->next) { if (acl->method == SC_AC_NEVER) return SC_ERROR_SECURITY_STATUS_NOT_SATISFIED; if (acl->method == SC_AC_NONE) break; r = do_verify_pin(pro, card, acl->method, acl->key_ref); } return r;}intdo_select_parent(struct sc_profile *pro, struct sc_card *card, struct sc_file *file, struct sc_file **parent){ struct sc_path path; int r; /* Get the parent's path */ path = file->path; if (path.len >= 2) path.len -= 2; if (path.len == 0) sc_format_path("3F00", &path); /* Select the parent DF. */ *parent = NULL; card->ctx->log_errors = 0; r = sc_select_file(card, &path, parent); card->ctx->log_errors = 1; /* If DF doesn't exist, create it (unless it's the MF, * but then something's badly broken anyway :-) */ if (r == SC_ERROR_FILE_NOT_FOUND && path.len != 2) { r = sc_profile_get_file_by_path(pro, &path, parent); if (r < 0) { char buffer[SC_MAX_PATH_SIZE*2+1]; size_t n; buffer[0] = '\0'; for (n = 0; n < path.len; n++) sprintf(buffer+2*n, "%02x", path.value[n]); p15init_error("profile doesn't define a DF %s"); return r; } if (!(r = sc_pkcs15init_create_file(pro, card, *parent))) r = sc_select_file(card, &path, NULL); } return r;}intsc_pkcs15init_create_file(struct sc_profile *pro, struct sc_card *card, struct sc_file *file){ struct sc_file *parent = NULL; int r; /* Select parent DF and verify PINs/key as necessary */ if ((r = do_select_parent(pro, card, file, &parent)) < 0 || (r = sc_pkcs15init_authenticate(pro, card, parent, SC_AC_OP_CREATE)) < 0) goto out; /* Fix up the file's ACLs */ if ((r = sc_pkcs15init_fixup_file(pro, file)) < 0) return r; r = sc_create_file(card, file);out: if (parent) sc_file_free(parent); return r;}intsc_pkcs15init_update_file(struct sc_profile *profile, struct sc_card *card, struct sc_file *file, void *data, unsigned int datalen){ struct sc_file *info = NULL; int r; card->ctx->log_errors = 0; if ((r = sc_select_file(card, &file->path, &info)) < 0) { card->ctx->log_errors = 1; /* Create file if it doesn't exist */ if (file->size < datalen) file->size = datalen; if (r != SC_ERROR_FILE_NOT_FOUND || (r = sc_pkcs15init_create_file(profile, card, file)) < 0 || (r = sc_select_file(card, &file->path, &info)) < 0) return r; } card->ctx->log_errors = 1; if (info->size < datalen) { char buf[16]; sc_bin_to_hex(file->path.value, file->path.len, buf, sizeof(buf), 0); p15init_error("File %s too small - please increase size in profile", buf); sc_file_free(info); return SC_ERROR_TOO_MANY_OBJECTS; } /* Present authentication info needed */ r = sc_pkcs15init_authenticate(profile, card, file, SC_AC_OP_UPDATE); if (r >= 0 && datalen) r = sc_update_binary(card, 0, (const u8 *) data, datalen, 0); sc_file_free(info); return r;}/* * Fix up all file ACLs */intsc_pkcs15init_fixup_file(struct sc_profile *profile, struct sc_file *file){ struct sc_pkcs15_pin_info so_pin, user_pin; struct sc_acl_entry so_acl, user_acl; unsigned int op, needfix = 0; /* First, loop over all ACLs to find out whether there * are still any symbolic references. */ for (op = 0; op < SC_MAX_AC_OPS; op++) { const struct sc_acl_entry *acl; acl = sc_file_get_acl_entry(file, op); for (; acl; acl = acl->next) { if (acl->method == SC_AC_SYMBOLIC) needfix++; } } if (!needfix) return 0; sc_profile_get_pin_info(profile, SC_PKCS15INIT_SO_PIN, &so_pin); sc_profile_get_pin_info(profile, SC_PKCS15INIT_USER_PIN, &user_pin); /* If the profile doesn't specify a SO pin, change all * ACLs that reference $sopin to NONE */ so_acl.method = SC_AC_CHV; so_acl.key_ref = so_pin.reference; if (so_acl.key_ref == -1) { so_acl.method = SC_AC_NONE; so_acl.key_ref = 0; }#if 0 /* If we haven't got a user pin, barf */ user_acl.method = SC_AC_CHV; user_acl.key_ref = user_pin.reference;#else /* Not setting a user pin is legitimate. */ user_acl.method = SC_AC_CHV; user_acl.key_ref = user_pin.reference; if (user_acl.key_ref == -1) { user_acl.method = SC_AC_NONE; user_acl.key_ref = 0; }#endif return sc_pkcs15init_fixup_acls(profile, file, &so_acl, &user_acl);}/* * Fix up a file's ACLs by replacing all occurrences of a symbolic * PIN name with the real reference. */intsc_pkcs15init_fixup_acls(struct sc_profile *profile, struct sc_file *file, struct sc_acl_entry *so_acl, struct sc_acl_entry *user_acl){ struct sc_acl_entry acls[16]; unsigned int op, num; int r = 0; for (op = 0; r == 0 && op < SC_MAX_AC_OPS; op++) { const struct sc_acl_entry *acl; const char *what; int added = 0; /* First, get original ACLs */ acl = sc_file_get_acl_entry(file, op); for (num = 0; num < 16 && acl; num++, acl = acl->next) acls[num] = *acl; sc_file_clear_acl_entries(file, op); for (acl = acls; acl < acls + num; acl++) { if (acl->method != SC_AC_SYMBOLIC) goto next; if (acl->key_ref == SC_PKCS15INIT_SO_PIN) { acl = so_acl; what = "SO PIN"; } else if (acl->key_ref == SC_PKCS15INIT_USER_PIN) { acl = user_acl; what = "user PIN"; } else { p15init_error("ACL references unknown symbolic PIN %d", acl->key_ref); return SC_ERROR_INVALID_ARGUMENTS; } /* If we weren't given a replacement ACL, * leave the original ACL untouched */ if (acl == NULL || acl->key_ref == -1) { p15init_error("ACL references %s, which is not defined", what); return SC_ERROR_INVALID_ARGUMENTS; } if (acl->method == SC_AC_NONE) continue; next: sc_file_add_acl_entry(file, op, acl->method, acl->key_ref); added++; } if (!added) sc_file_add_acl_entry(file, op, SC_AC_NONE, 0); } return r;}intsc_pkcs15init_get_pin_info(struct sc_profile *profile, unsigned int id, struct sc_pkcs15_pin_info *pin){ sc_profile_get_pin_info(profile, id, pin); return 0;}intsc_pkcs15init_get_manufacturer(struct sc_profile *profile, const char **res){ *res = profile->p15_card->manufacturer_id; return 0;}intsc_pkcs15init_get_serial(struct sc_profile *profile, const char **res){ *res = profile->p15_card->serial_number; return 0;}intsc_pkcs15init_set_serial(struct sc_profile *profile, const char *serial){ if (profile->p15_card->serial_number) free(profile->p15_card->serial_number); profile->p15_card->serial_number = strdup(serial); return 0;}intsc_pkcs15init_get_label(struct sc_profile *profile, const char **res){ *res = profile->p15_card->label; return 0;}voiddefault_error_handler(const char *fmt, ...){ va_list ap; va_start(ap, fmt); vfprintf(stderr, fmt, ap); fputs("\n", stderr); va_end(ap);}voiddefault_debug_handler(const char *fmt, ...){ /* Nothing */}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -