📄 pkcs15-gpk.c
字号:
/* * GPK specific operation for PKCS15 initialization * * Copyright (C) 2002 Olaf Kirch <okir@lst.de> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */#ifdef HAVE_CONFIG_H#include <config.h>#endif#include <sys/types.h>#include <stdlib.h>#include <string.h>#include <assert.h>#include <stdarg.h>#include <opensc/opensc.h>#include <opensc/cardctl.h>#include "pkcs15-init.h"#include "profile.h"#define GPK_MAX_PINS 8#define GPK_FTYPE_SECRET_CODE 0x21#define GPK_FTYPE_PUBLIC_KEY 0x2C/* * Key components (for storing private keys) */struct pkcomp { unsigned char tag; u8 * data; unsigned int size;};struct pkpart { struct pkcomp components[7]; unsigned int count; unsigned int size;};struct pkdata { unsigned int algo; unsigned int usage; struct pkpart _public, _private; unsigned int bits, bytes;};/* * Local functions */static int gpk_new_pin(struct sc_profile *profile, struct sc_card *card, struct sc_pkcs15_pin_info *info, unsigned int index, const u8 *pin, size_t pin_len, const u8 *puk, size_t puk_len);static int gpk_new_file(struct sc_profile *, struct sc_card *, unsigned int, unsigned int, struct sc_file **);static int gpk_encode_rsa_key(struct sc_profile *, struct sc_pkcs15_prkey_rsa *, struct pkdata *, struct sc_pkcs15_prkey_info *);static int gpk_encode_dsa_key(struct sc_profile *, struct sc_pkcs15_prkey_dsa *, struct pkdata *, struct sc_pkcs15_prkey_info *);static int gpk_store_pk(struct sc_profile *, struct sc_card *, struct sc_file *, struct pkdata *);static void error(struct sc_profile *, const char *, ...);static void debug(struct sc_profile *, const char *, ...);/* * Erase the card */static intgpk_erase_card(struct sc_profile *pro, struct sc_card *card){ int locked; if (sc_card_ctl(card, SC_CARDCTL_GPK_IS_LOCKED, &locked) == 0 && locked) { error(pro, "This card is already personalized, unable to " "create PKCS#15 structure."); return SC_ERROR_NOT_SUPPORTED; } return sc_card_ctl(card, SC_CARDCTL_ERASE_CARD, NULL);}/* * Lock a file operation */static intgpk_lock(struct sc_card *card, struct sc_file *file, unsigned int op){ struct sc_cardctl_gpk_lock args; args.file = file; args.operation = op; return sc_card_ctl(card, SC_CARDCTL_GPK_LOCK, &args);}/* * Lock the pin file */static intgpk_lock_pinfile(struct sc_profile *profile, struct sc_card *card, struct sc_file *pinfile){ struct sc_path path; struct sc_file *parent = NULL; int r; /* Select the parent DF */ path = pinfile->path; if (path.len >= 2) path.len -= 2; if (path.len == 0) sc_format_path("3F00", &path); if ((r = sc_select_file(card, &path, &parent)) < 0) return r; /* Present PINs etc as necessary */ r = sc_pkcs15init_authenticate(profile, card, parent, SC_AC_OP_LOCK); if (r >= 0) r = gpk_lock(card, pinfile, SC_AC_OP_WRITE); sc_file_free(parent); return r;}/* * Initialize pin file */static intgpk_init_pinfile(struct sc_profile *profile, struct sc_card *card, struct sc_file *file){ struct sc_pkcs15_pin_info sopin_info, pin_info; const struct sc_acl_entry *acl; unsigned char buffer[GPK_MAX_PINS * 8], *blk; struct sc_file *pinfile; unsigned int so_attempts[2], user_attempts[2]; unsigned int npins, i, j, cks; int r; /* Set defaults */ sc_profile_get_pin_info(profile, SC_PKCS15INIT_SO_PIN, &sopin_info); so_attempts[0] = sopin_info.tries_left; sc_profile_get_pin_info(profile, SC_PKCS15INIT_SO_PUK, &pin_info); so_attempts[1] = pin_info.tries_left; sc_profile_get_pin_info(profile, SC_PKCS15INIT_USER_PIN, &pin_info); user_attempts[0] = pin_info.tries_left; sc_profile_get_pin_info(profile, SC_PKCS15INIT_USER_PUK, &pin_info); user_attempts[1] = pin_info.tries_left; sc_file_dup(&pinfile, file); /* Create the PIN file. */ acl = sc_file_get_acl_entry(pinfile, SC_AC_OP_WRITE); if (acl->method != SC_AC_NEVER) { error(profile, "PIN file most be protected by WRITE=NEVER"); return SC_ERROR_INVALID_ARGUMENTS; } sc_file_add_acl_entry(pinfile, SC_AC_OP_WRITE, SC_AC_NONE, 0); if (pinfile->size == 0) pinfile->size = GPK_MAX_PINS * 8; /* Now create the file */ if ((r = sc_pkcs15init_create_file(profile, card, pinfile)) < 0 || (r = sc_select_file(card, &pinfile->path, NULL)) < 0) goto out; /* Set up the PIN file contents. * We assume the file will contain pairs of PINs/PUKs */ npins = pinfile->size / 8; memset(buffer, 0, sizeof(buffer)); for (i = 0, blk = buffer; i < npins; blk += 8, i += 1) { /* Determine the number of PIN/PUK presentation * attempts. If the profile defines a SO PIN, * it will be stored in the first PIN/PUK pair. */ blk[0] = user_attempts[i & 1]; if (i < 2 && so_attempts[0]) blk[0] = so_attempts[i & 1]; if ((i & 1) == 0) { /* This is a PIN. If there's room in the file, * the next will be a PUK so take note of the * unlock code */ if (i + 1 < npins) blk[2] = 0x8 | (i + 1); } /* Compute the CKS */ for (j = 0, cks = 0; j < 8; j++) cks ^= blk[j]; blk[3] = ~cks; } r = sc_write_binary(card, 0, buffer, npins * 8, 0); if (r >= 0) r = gpk_lock_pinfile(profile, card, pinfile);out: sc_file_free(pinfile); return r;}/* * Initialize the Application DF and pin file */static intgpk_init_app(struct sc_profile *profile, struct sc_card *card, const unsigned char *pin, size_t pin_len, const unsigned char *puk, size_t puk_len){ struct sc_pkcs15_pin_info sopin_info; struct sc_file *pinfile; int r, locked; if (sc_card_ctl(card, SC_CARDCTL_GPK_IS_LOCKED, &locked) == 0 && locked) { error(profile, "This card is already personalized, unable to " "create PKCS#15 structure."); return SC_ERROR_NOT_SUPPORTED; } /* Profile must define a "pinfile" */ if (sc_profile_get_file(profile, "pinfile", &pinfile) < 0) { error(profile, "Profile doesn't define a \"pinfile\""); return SC_ERROR_NOT_SUPPORTED; } /* Create the application DF */ r = sc_pkcs15init_create_file(profile, card, profile->df_info->file); /* Create the PIN file */ if (r >= 0) r = gpk_init_pinfile(profile, card, pinfile); sc_profile_get_pin_info(profile, SC_PKCS15INIT_SO_PIN, &sopin_info); if (r >= 0 && pin_len) { r = gpk_new_pin(profile, card, &sopin_info, 0, pin, pin_len, puk, puk_len); if (r >= 0) sc_profile_set_pin_info(profile, SC_PKCS15INIT_SO_PIN, &sopin_info); } sc_file_free(pinfile); return r;}/* * Store a PIN */static intgpk_new_pin(struct sc_profile *profile, struct sc_card *card, struct sc_pkcs15_pin_info *info, unsigned int index, const u8 *pin, size_t pin_len, const u8 *puk, size_t puk_len){ unsigned char nulpin[8]; int r; /* Profile must define a "pinfile" */ if (sc_profile_get_path(profile, "pinfile", &info->path) < 0) { error(profile, "Profile doesn't define a \"pinfile\""); return SC_ERROR_INVALID_ARGUMENTS; } if (info->path.len > 2) info->path.len -= 2; r = sc_select_file(card, &info->path, NULL); if (r < 0) return r; index <<= 2; if (index >= GPK_MAX_PINS) return SC_ERROR_TOO_MANY_OBJECTS; if (puk == NULL || puk_len == 0) { puk = pin; puk_len = pin_len; } /* 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, 0x8 | index, 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, 0x8 | (index + 1), nulpin, sizeof(nulpin), puk, puk_len, NULL); info->reference = 0x8 | index; return r;}/* * Store a private key */static intgpk_new_key(struct sc_profile *profile, struct sc_card *card, struct sc_pkcs15_prkey *key, unsigned int index, struct sc_pkcs15_prkey_info *info){ struct sc_file *keyfile = NULL; struct pkdata data; int r; switch (key->algorithm) { case SC_ALGORITHM_RSA: r = gpk_new_file(profile, card, SC_PKCS15_TYPE_PRKEY_RSA, index, &keyfile); if (r >= 0) r = gpk_encode_rsa_key(profile, &key->u.rsa, &data, info); break; case SC_ALGORITHM_DSA: r = gpk_new_file(profile, card, SC_PKCS15_TYPE_PRKEY_DSA, index, &keyfile); if (r >= 0) r = gpk_encode_dsa_key(profile, &key->u.dsa, &data, info); break; default: return SC_ERROR_NOT_SUPPORTED; } /* Fix up PIN references in file ACL */ if (r >= 0) r = sc_pkcs15init_fixup_file(profile, keyfile); if (r >= 0) r = gpk_store_pk(profile, card, keyfile, &data); if (keyfile) { info->path = keyfile->path; sc_file_free(keyfile); } return r;}/* * Allocate a file */static intgpk_new_file(struct sc_profile *profile, struct sc_card *card, unsigned int type, unsigned int num, struct sc_file **out){ struct sc_file *file; struct sc_path *p; char name[64], *tag, *desc; desc = tag = 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;#ifdef SC_PKCS15_TYPE_PRKEY_DSA case SC_PKCS15_TYPE_PRKEY_DSA: desc = "DSA private key"; tag = "private-key"; break; case SC_PKCS15_TYPE_PUBKEY_DSA: desc = "DSA public key"; tag = "public-key"; break;#endif 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)) { error(profile, "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) { error(profile, "Profile doesn't define %s template (%s)\n", 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;}/* * GPK public/private key file handling is hideous. * 600 lines of coke sweat and tears... *//* * Create the PK file * XXX: Handle the UPDATE ACL = NEVER case just like for EFsc files */static intgpk_pkfile_create(struct sc_profile *profile, struct sc_card *card, struct sc_file *file){ struct sc_file *found = NULL; int r; card->ctx->log_errors = 0; r = sc_select_file(card, &file->path, &found); card->ctx->log_errors = 1; if (r == SC_ERROR_FILE_NOT_FOUND) { r = sc_pkcs15init_create_file(profile, card, file); if (r >= 0) r = sc_select_file(card, &file->path, &found); } else { /* XXX: make sure the file has correct type and size? */ } if (r >= 0) r = sc_pkcs15init_authenticate(profile, card, file, SC_AC_OP_UPDATE); if (found) sc_file_free(found); return r;}static intgpk_pkfile_keybits(unsigned int bits, unsigned char *p){ switch (bits) { case 512: *p = 0x00; return 0; case 768: *p = 0x10; return 0; case 1024: *p = 0x11; return 0; } return SC_ERROR_NOT_SUPPORTED;}static intgpk_pkfile_keyalgo(unsigned int algo, unsigned char *p){ switch (algo) { case SC_ALGORITHM_RSA: *p = 0x00; return 0; case SC_ALGORITHM_DSA: *p = 0x01; return 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -