📄 pkcs15-etoken.c
字号:
/* * eToken PRO 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 <opensc/scrandom.h>#include "pkcs15-init.h"#include "profile.h"#ifndef MIN# define MIN(a, b) (((a) < (b))? (a) : (b))#endifstruct tlv { unsigned char * base; unsigned char * end; unsigned char * current; unsigned char * next;};#define RSAKEY_MAX_BITS 1024#define RSAKEY_MAX_SIZE (RSAKEY_MAX_BITS/8)struct rsakey { struct bignum { size_t len; u8 data[RSAKEY_MAX_SIZE]; } n, d;};/* * 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 *, ...);/* Object IDs for PIN objects. * SO PIN = 0x01, SO PUK = 0x02 * each user pin is 2*N+1, each corresponding PUK is 2*N+2 */#define ETOKEN_PIN_ID(idx) (((idx) << 1) + 0x01)#define ETOKEN_PUK_ID(idx) (((idx) << 1) + 0x02)#define ETOKEN_MAX_PINS 0x10#define ETOKEN_KEY_ID(idx) (0x40 + (idx))#define ETOKEN_SE_ID(idx) (0x40 + (idx))#define ETOKEN_AC_NEVER 0xFF#define ETOKEN_ALGO_RSA 0x08#define ETOKEN_ALGO_RSA_PURE 0x0C#define ETOKEN_ALGO_RSA_SIG 0x88#define ETOKEN_ALGO_RSA_PURE_SIG 0x8C#define ETOKEN_ALGO_RSA_SIG_SHA1 0xC8#define ETOKEN_ALGO_RSA_PURE_SIG_SHA1 0xCC#define ETOKEN_SIGN_RSA ETOKEN_ALGO_RSA_PURE_SIG#define ETOKEN_DECIPHER_RSA ETOKEN_ALGO_RSA_PURE#define ETOKEN_ALGO_PIN 0x87static inline voidtlv_init(struct tlv *tlv, u8 *base, size_t size){ tlv->base = base; tlv->end = base + size; tlv->current = tlv->next = base;}static inline voidtlv_next(struct tlv *tlv, u8 tag){ assert(tlv->next + 2 < tlv->end); tlv->current = tlv->next; *(tlv->next++) = tag; *(tlv->next++) = 0;}static inline voidtlv_add(struct tlv *tlv, u8 val){ assert(tlv->next + 1 < tlv->end); *(tlv->next++) = val; tlv->current[1]++;}static size_ttlv_len(struct tlv *tlv){ return tlv->next - tlv->base;}/* * Try to delete pkcs15 structure * This is not quite the same as erasing the whole token, but * it's close enough to be useful. */static intetoken_erase(struct sc_profile *profile, struct sc_card *card){ return sc_pkcs15init_erase_card_recursively(card, profile, -1);}/* * Initialize pin file */static intetoken_store_pin(struct sc_profile *profile, struct sc_card *card, int pin_type, unsigned int pin_id, unsigned int puk_id, const u8 *pin, size_t pin_len){ struct sc_pkcs15_pin_info params; struct sc_cardctl_etoken_obj_info args; unsigned char buffer[256]; unsigned char pinpadded[16]; struct tlv tlv; unsigned int attempts, minlen, maxlen; /* We need to do padding because pkcs15-lib.c does it. * Would be nice to have a flag in the profile that says * "no padding required". */ maxlen = MIN(profile->pin_maxlen, sizeof(pinpadded)); if (pin_len > maxlen) pin_len = maxlen; memcpy(pinpadded, pin, pin_len); while (pin_len < maxlen) pinpadded[pin_len++] = profile->pin_pad_char; pin = pinpadded; sc_profile_get_pin_info(profile, pin_type, ¶ms); attempts = params.tries_left; minlen = params.min_length; /* Set the profile's PIN reference */ params.reference = pin_id; params.path = profile->df_info->file->path; sc_profile_set_pin_info(profile, pin_type, ¶ms); 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 */ /* usecount: not documented, but seems to work like this: * - value of 0xff means pin can be presented any number * of times * - anything less: max # of times before BS object is blocked. */ tlv_add(&tlv, 0xff); /* DEK: not documented, no idea what it means */ tlv_add(&tlv, 0x00); /* ARA counter: not documented, no idea what it means */ tlv_add(&tlv, 0x00); tlv_add(&tlv, minlen); /* minlen */ /* AC conditions */ tlv_next(&tlv, 0x86); tlv_add(&tlv, 0x00); /* use: always */ tlv_add(&tlv, pin_id); /* change: PIN */ tlv_add(&tlv, puk_id); /* unblock: PUK */ /* data: PIN */ tlv_next(&tlv, 0x8f); while (pin_len--) tlv_add(&tlv, *pin++); args.data = buffer; args.len = tlv_len(&tlv); return sc_card_ctl(card, SC_CARDCTL_ETOKEN_PUT_DATA_OCI, &args);}/* * Create an empty security environment */static intetoken_create_sec_env(struct sc_profile *profile, struct sc_card *card, unsigned int se_id, unsigned int key_id){ struct sc_cardctl_etoken_obj_info args; struct tlv tlv; unsigned char buffer[64]; tlv_init(&tlv, buffer, sizeof(buffer)); tlv_next(&tlv, 0x83); tlv_add(&tlv, se_id); tlv_next(&tlv, 0x86); tlv_add(&tlv, 0); tlv_add(&tlv, 0); tlv_next(&tlv, 0x8f); tlv_add(&tlv, key_id); tlv_add(&tlv, key_id); tlv_add(&tlv, key_id); tlv_add(&tlv, key_id); tlv_add(&tlv, key_id); tlv_add(&tlv, key_id); args.data = buffer; args.len = tlv_len(&tlv); return sc_card_ctl(card, SC_CARDCTL_ETOKEN_PUT_DATA_SECI, &args);}/* * Initialize the Application DF and pin file */static intetoken_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. * First, the SO pin and PUK. Don't create objects for * these if none specified. */ if (pin && pin_len) { u8 puk_id = ETOKEN_AC_NEVER; if (r >= 0 && puk && puk_len) { puk_id = ETOKEN_PUK_ID(0); r = etoken_store_pin(profile, card, SC_PKCS15INIT_SO_PUK, puk_id, ETOKEN_AC_NEVER, puk, puk_len); } if (r >= 0) { r = etoken_store_pin(profile, card, SC_PKCS15INIT_SO_PIN, ETOKEN_PIN_ID(0), puk_id, pin, pin_len); } } /* Create a default security environment for this DF. * This SE autometically becomes the current SE when the * DF is selected. */ if (r >= 0) r = etoken_create_sec_env(profile, card, 0x01, 0x00); return r;}/* * Store a PIN */static intetoken_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){ struct sc_file *df = profile->df_info->file; unsigned int puk_id = ETOKEN_AC_NEVER, pin_id; int r; if (!pin || !pin_len) return SC_ERROR_INVALID_ARGUMENTS; r = sc_select_file(card, &df->path, NULL); if (r < 0) return r; if (index >= ETOKEN_MAX_PINS) return SC_ERROR_TOO_MANY_OBJECTS; if (puk && puk_len) { puk_id = ETOKEN_PUK_ID(index); r = etoken_store_pin(profile, card, SC_PKCS15INIT_USER_PUK, puk_id, ETOKEN_AC_NEVER, puk, puk_len); } if (r >= 0) { pin_id = ETOKEN_PIN_ID(index); r = etoken_store_pin(profile, card, SC_PKCS15INIT_USER_PIN, pin_id, puk_id, pin, pin_len); info->reference = pin_id; info->path = df->path; } return r;}/* * Determine the key algorithm based on the intended usage * Note that CardOS/M4 does not support keys that can be used * for signing _and_ decipherment */#define USAGE_ANY_SIGN (SC_PKCS15_PRKEY_USAGE_SIGN)#define USAGE_ANY_DECIPHER (SC_PKCS15_PRKEY_USAGE_DECRYPT|\ SC_PKCS15_PRKEY_USAGE_UNWRAP)static intetoken_key_algorithm(unsigned int usage, int *algop){ int sign = 0, decipher = 0; if (usage & USAGE_ANY_SIGN) { *algop = ETOKEN_SIGN_RSA; sign++; } if (usage & USAGE_ANY_DECIPHER) { *algop = ETOKEN_DECIPHER_RSA; decipher++; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -