/* * pkcs15-tccardos.c: PKCS#15 profile for TC CardOS M4 cards * * Copyright (C) 2005 Nils Larsch * * 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 */ #if HAVE_CONFIG_H #include "config.h" #endif #include #include #include "internal.h" #include "log.h" #include "pkcs15.h" #define MANU_ID "SIEMENS AG" #define TC_CARDOS_APP_DF "3F001002" #define TC_CARDOS_LABEL "TC CardOS M4" #define TC_CARDOS_SIGN 0x0020 #define TC_CARDOS_AUTH 0x0040 #define TC_CARDOS_DEC 0x0080 #define TC_CARDOS_NOPIN 0x1000 #define TC_CARDOS_LOCALPIN 0x2000 #define TC_CARDOS_GLOBALPIN 0x3000 #define TC_CARDOS_PIN_MASK 0x3000 int sc_pkcs15emu_tccardos_init_ex(sc_pkcs15_card_t *p15card, struct sc_aid *, sc_pkcs15emu_opt_t *opts); static int read_file(struct sc_card *card, const char *file, u8 *buf, size_t *len) { int r; struct sc_path path; struct sc_file *fid = NULL; sc_format_path(file, &path); r = sc_select_file(card, &path, &fid); if (r != SC_SUCCESS || !fid) return r; if (fid->size < *len) *len = fid->size; r = sc_read_binary(card, 0, buf, *len, 0); free(fid); if ((size_t)r < *len) return SC_ERROR_INTERNAL; return SC_SUCCESS; } static const char *get_keyholder(int fileId) { u8 tmp = fileId & 0x0f; if (tmp < 0x08) return "CH"; else if (tmp < 0x0d) return "CA"; else if (tmp == 0x0e) return "RCA"; else return "error"; } static const char *get_service(int fileId) { u8 tmp = (fileId >> 8) & 0x0f; if (tmp == 0) return "DS"; else if (tmp == 2 || tmp == 3) return "KE"; else if (tmp == 5) return "AUT"; else return "error"; } static int create_cert_obj(sc_pkcs15_card_t *p15card, int fileId) { sc_pkcs15_object_t p15obj; sc_pkcs15_cert_info_t cinfo; memset(&p15obj, 0, sizeof(p15obj)); memset(&cinfo, 0, sizeof(cinfo)); /* the certificate attributes */ cinfo.id.value[0] = (fileId >> 8) & 0xff; cinfo.id.value[1] = fileId & 0xff; cinfo.id.len = 2; cinfo.authority = fileId & 0x08 ? 1 : 0; cinfo.path.value[0] = (fileId >> 8) & 0xff; cinfo.path.value[1] = fileId & 0xff; cinfo.path.len = 2; cinfo.path.type = SC_PATH_TYPE_FILE_ID; cinfo.path.index = 0; cinfo.path.count = -1; /* compose the certificate name from the fileID */ sprintf(p15obj.label, "C.%s.%s", get_keyholder(fileId), get_service(fileId)); p15obj.flags = 0; /* XXX */ p15obj.user_consent = 0; return sc_pkcs15emu_add_x509_cert(p15card, &p15obj, &cinfo); } static int create_pkey_obj(sc_pkcs15_card_t *p15card, int cert, int key_descr, unsigned int keyId, unsigned int pinId) { sc_pkcs15_object_t p15obj; sc_pkcs15_prkey_info_t pinfo; /* init data objects */ memset(&p15obj, 0, sizeof(p15obj)); memset(&pinfo, 0, sizeof(pinfo)); /* the private key attributes */ pinfo.id.value[0] = (cert >> 8) & 0xff; pinfo.id.value[1] = cert & 0xff; pinfo.id.len = 2; pinfo.native = 1; pinfo.key_reference = (u8)keyId; pinfo.modulus_length = 1024; /* XXX */ pinfo.access_flags = SC_PKCS15_PRKEY_ACCESS_NEVEREXTRACTABLE; pinfo.usage = 0; if (key_descr & TC_CARDOS_SIGN) pinfo.usage = SC_PKCS15_PRKEY_USAGE_SIGN | SC_PKCS15_PRKEY_USAGE_NONREPUDIATION; if (key_descr & TC_CARDOS_AUTH) pinfo.usage |= SC_PKCS15_PRKEY_USAGE_SIGN; if (key_descr & TC_CARDOS_DEC) pinfo.usage = SC_PKCS15_PRKEY_USAGE_ENCRYPT | SC_PKCS15_PRKEY_USAGE_DECRYPT | SC_PKCS15_PRKEY_USAGE_WRAP | SC_PKCS15_PRKEY_USAGE_UNWRAP; sc_format_path(TC_CARDOS_APP_DF, &pinfo.path); pinfo.path.index = 0; pinfo.path.count = 0; /* the common object attributes */ sprintf(p15obj.label, "SK.CH.%s", get_service(cert)); if (pinId && (key_descr & TC_CARDOS_PIN_MASK)) { p15obj.auth_id.value[0] = (u8)pinId; p15obj.auth_id.len = 1; } p15obj.flags = SC_PKCS15_CO_FLAG_PRIVATE; p15obj.user_consent = 0; p15obj.type = SC_PKCS15_TYPE_PRKEY_RSA; return sc_pkcs15emu_add_rsa_prkey(p15card, &p15obj, &pinfo); } static int create_pin_obj(sc_pkcs15_card_t *p15card, int cert, int key_descr, unsigned int pinId) { sc_pkcs15_object_t p15obj; sc_pkcs15_auth_info_t ainfo; /* init data objects */ memset(&p15obj, 0, sizeof(p15obj)); memset(&ainfo, 0, sizeof(ainfo)); /* the authentication object attributes */ ainfo.auth_id.value[0] = (u8)pinId; ainfo.auth_id.len = 1; ainfo.auth_type = SC_PKCS15_PIN_AUTH_TYPE_PIN; ainfo.attrs.pin.reference = (u8)pinId; ainfo.attrs.pin.flags = SC_PKCS15_PIN_FLAG_EXCHANGE_REF_DATA; if ((key_descr & TC_CARDOS_PIN_MASK) == TC_CARDOS_LOCALPIN) ainfo.attrs.pin.flags |= SC_PKCS15_PIN_FLAG_LOCAL; ainfo.attrs.pin.type = SC_PKCS15_PIN_TYPE_BCD; /* XXX */ ainfo.attrs.pin.min_length = 6; /* XXX */ ainfo.attrs.pin.stored_length = 8; /* XXX */ ainfo.attrs.pin.max_length = 8; ainfo.attrs.pin.pad_char = 0; ainfo.tries_left = 3; /* XXX */ ainfo.logged_in = SC_PIN_STATE_UNKNOWN; sc_format_path(TC_CARDOS_APP_DF, &ainfo.path); ainfo.path.index = 0; ainfo.path.count = 0; /* the common object attributes */ sprintf(p15obj.label, "PIN.CH.%s", get_service(cert)); p15obj.flags = SC_PKCS15_CO_FLAG_PRIVATE; p15obj.user_consent = 0; p15obj.type = SC_PKCS15_TYPE_AUTH_PIN; return sc_pkcs15emu_add_pin_obj(p15card, &p15obj, &ainfo); } #define MAX_INFO1_SIZE 256 #define MAX_INFO2_SIZE 256 static int parse_EF_CardInfo(sc_pkcs15_card_t *p15card) { int r; u8 info1[MAX_INFO1_SIZE]; size_t info1_len = MAX_INFO1_SIZE; u8 info2[MAX_INFO2_SIZE]; size_t info2_len = MAX_INFO2_SIZE; u8 *p1, *p2; size_t i; unsigned int key_num; struct sc_context *ctx = p15card->card->ctx; size_t offset; /* read EF_CardInfo1 */ r = read_file(p15card->card, "3F001003b200", info1, &info1_len); if (r != SC_SUCCESS) return SC_ERROR_WRONG_CARD; /* read EF_CardInfo2 */ r = read_file(p15card->card, "3F001003b201", info2, &info2_len); if (r != SC_SUCCESS) return SC_ERROR_WRONG_CARD; /* get the number of private keys */ key_num = ((unsigned int) info1[info1_len-1]) | (((unsigned int) info1[info1_len-2]) << 8) | (((unsigned int) info1[info1_len-3]) << 16) | (((unsigned int) info1[info1_len-4]) << 24); sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "found %d private keys\n", (int)key_num); /* set p1 to the address of the first key descriptor */ offset = info1_len - 4 - key_num * 2; if (offset >= sizeof info1) return SC_ERROR_INVALID_DATA; p1 = info1 + offset; p2 = info2; for (i=0; icard; /* check if we have the correct card OS */ if (strcmp(card->name, "CardOS M4")) return SC_ERROR_WRONG_CARD; /* create pkcs15 objects */ r = parse_EF_CardInfo(p15card); if (r != SC_SUCCESS) return r; /* set card label */ if (p15card->tokeninfo->label != NULL) free(p15card->tokeninfo->label); p15card->tokeninfo->label = strdup(TC_CARDOS_LABEL); if (p15card->tokeninfo->label == NULL) return SC_ERROR_OUT_OF_MEMORY; /* set the manufacturer ID */ if (p15card->tokeninfo->manufacturer_id != NULL) free(p15card->tokeninfo->manufacturer_id); p15card->tokeninfo->manufacturer_id = strdup(MANU_ID); if (p15card->tokeninfo->manufacturer_id == NULL) return SC_ERROR_OUT_OF_MEMORY; /* set the serial number */ r = read_file(p15card->card, "3F002F02", gdo, &gdo_len); if (r != SC_SUCCESS) return SC_ERROR_INTERNAL; sc_bin_to_hex(gdo + 7, 8, hex_buf, sizeof(hex_buf), 0); p15card->tokeninfo->serial_number = strdup(hex_buf); if (p15card->tokeninfo->serial_number == NULL) return SC_ERROR_OUT_OF_MEMORY; /* select the application DF */ sc_format_path(TC_CARDOS_APP_DF, &path); r = sc_select_file(card, &path, &file); if (r != SC_SUCCESS || file == NULL) return SC_ERROR_INTERNAL; /* set the application DF */ if (p15card->file_app) free(p15card->file_app); p15card->file_app = file; return SC_SUCCESS; } int sc_pkcs15emu_tccardos_init_ex(sc_pkcs15_card_t *p15card, struct sc_aid *aid, sc_pkcs15emu_opt_t *opts) { return sc_pkcs15_tccardos_init_func(p15card); }