/* * eToken PRO specific operation for PKCS15 initialization * * Copyright (C) 2002 Olaf Kirch * * 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 #endif #include #include #include #include #include #include #include #include "pkcs15-init.h" #include "profile.h" struct tlv { unsigned char * base; unsigned char * end; unsigned char * current; unsigned char * next; }; /* * Local functions */ static int etoken_new_file(struct sc_profile *, struct sc_card *, unsigned int, unsigned int, struct sc_file **); static void error(struct sc_profile *, const char *, ...); /* We should make these object IDs configurable via the profile */ #define ETOKEN_SO_PIN_ID 0x01 #define ETOKEN_SO_PUK_ID 0x02 #define ETOKEN_PIN_ID 0x03 #define ETOKEN_PUK_ID 0x04 #define ETOKEN_AC_NEVER 0xFF #define ETOKEN_ALGO_PIN 0x87 #define ETOKEN_DEFAULT_PIN "null-pin" #define ETOKEN_DEFAULT_PIN_LEN (sizeof(ETOKEN_DEFAULT_PIN)-1) struct etoken_pin_info { int profile_id; u8 id; u8 unblock; }; static struct etoken_pin_info etoken_so_pin = { SC_PKCS15INIT_SO_PIN, ETOKEN_SO_PIN_ID, ETOKEN_SO_PUK_ID }; static struct etoken_pin_info etoken_so_puk = { SC_PKCS15INIT_SO_PUK, ETOKEN_SO_PUK_ID, ETOKEN_AC_NEVER }; static struct etoken_pin_info etoken_user_pin = { SC_PKCS15INIT_USER_PIN, ETOKEN_PIN_ID, ETOKEN_PUK_ID }; static struct etoken_pin_info etoken_user_puk = { SC_PKCS15INIT_USER_PUK, ETOKEN_PUK_ID, ETOKEN_SO_PIN_ID }; static inline void tlv_init(struct tlv *tlv, u8 *base, size_t size) { tlv->base = base; tlv->end = base + size; tlv->current = tlv->next = base; } static inline void tlv_next(struct tlv *tlv, u8 tag) { assert(tlv->next + 2 < tlv->end); tlv->current = tlv->next; *(tlv->next++) = tag; *(tlv->next++) = 0; } static inline void tlv_add(struct tlv *tlv, u8 val) { assert(tlv->next + 1 < tlv->end); *(tlv->next++) = val; tlv->current[1]++; } static size_t tlv_len(struct tlv *tlv) { return tlv->next - tlv->base; } static int etoken_set_ac(struct sc_file *file, int op, struct sc_acl_entry *acl) { /* XXX TBD */ return 0; } /* * Initialize pin file */ static int etoken_new_pin(struct sc_profile *profile, struct sc_card *card, struct etoken_pin_info *info, const u8 *pin, size_t pin_len) { struct sc_pkcs15_pin_info params; struct sc_cardctl_etoken_pin_info args; unsigned char buffer[256]; struct tlv tlv; unsigned int pin_id, puk_id, attempts, minlen; /* XXX hack for testing */ if (!pin_len) { pin = ETOKEN_DEFAULT_PIN; pin_len = ETOKEN_DEFAULT_PIN_LEN; } sc_profile_get_pin_info(profile, info->profile_id, ¶ms); attempts = params.tries_left; minlen = params.min_length; pin_id = info->id; puk_id = info->unblock; tlv_init(&tlv, buffer, sizeof(buffer)); /* object address: class, id */ tlv_next(&tlv, 0x83); tlv_add(&tlv, 0x00); /* class byte: usage TEST, k=0 */ tlv_add(&tlv, pin_id); /* parameters */ tlv_next(&tlv, 0x85); tlv_add(&tlv, 0x02); /* options byte */ tlv_add(&tlv, attempts & 0xf); /* flags byte */ tlv_add(&tlv, ETOKEN_ALGO_PIN); /* algorithm = pin-test */ tlv_add(&tlv, attempts & 0xf); /* errcount = attempts */ tlv_add(&tlv, 0x00); /* usecount = 0 */ tlv_add(&tlv, 0x00); /* DEK (?) */ tlv_add(&tlv, 0x00); /* ARA counter (?) */ tlv_add(&tlv, minlen); /* data: PIN */ tlv_next(&tlv, 0x8f); while (pin_len--) tlv_add(&tlv, *pin++); /* AC conditions */ tlv_next(&tlv, 0x86); tlv_add(&tlv, 0x00); /* use: always */ tlv_add(&tlv, puk_id); /* change: PUK */ tlv_add(&tlv, puk_id); /* unblock: PUK */ args.data = buffer; args.len = tlv_len(&tlv); return sc_card_ctl(card, SC_CARDCTL_ETOKEN_PUT_DATA_OCI, &args); } /* * Initialize the Application DF and pin file */ static int etoken_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_file *df = profile->df_info->file; int r; /* Create the application DF */ r = sc_pkcs15init_create_file(profile, card, df); if (r >= 0) r = sc_select_file(card, &df->path, NULL); /* Create the PIN objects */ if (r >= 0) r = etoken_new_pin(profile, card, &etoken_so_puk, puk, puk_len); if (r >= 0) r = etoken_new_pin(profile, card, &etoken_so_pin, pin, pin_len); if (r >= 0) r = etoken_new_pin(profile, card, &etoken_user_pin, 0, 0); if (r >= 0) r = etoken_new_pin(profile, card, &etoken_user_puk, 0, 0); return r; } /* * Store a PIN */ static int etoken_put_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) { return SC_ERROR_NOT_SUPPORTED; #if 0 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; #endif } /* * Store a private key */ static int etoken_new_key(struct sc_profile *profile, struct sc_card *card, struct sc_pkcs15_prkey *key, unsigned int index, struct sc_pkcs15_prkey_info *info) { return SC_ERROR_NOT_SUPPORTED; } /* * Allocate a file */ static int etoken_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; } static void error(struct sc_profile *profile, const char *fmt, ...) { char buffer[256]; va_list ap; va_start(ap, fmt); vsnprintf(buffer, sizeof(buffer), fmt, ap); va_end(ap); if (profile->cbs) profile->cbs->error("%s", buffer); } struct sc_pkcs15init_operations sc_pkcs15init_etoken_operations = { NULL, etoken_init_app, etoken_put_pin, etoken_new_key, etoken_new_file, };