/* * PKCS15 emulation layer for CardOS cards * Adapted from PKCS15 emulation layer for IAS/ECC card. * * Copyright (C) 2020, Douglas E. Engert * Copyright (C) 2016, Viktor Tarasov * Copyright (C) 2004, Bud P. Bruegger * Copyright (C) 2004, Antonino Iacono * Copyright (C) 2003, 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 */ #if HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include "internal.h" #include "pkcs15.h" /* * Called after sc_pkcs15_bind_internal * Create new flags based on supported_algos. */ static int cardos_fix_token_info(sc_pkcs15_card_t *p15card) { sc_card_t *card; struct sc_supported_algo_info (*saa)[SC_MAX_SUPPORTED_ALGORITHMS]; struct sc_supported_algo_info *sa; struct sc_cardctl_cardos_pass_algo_flags *passed = NULL; int r = 0; int i; card = p15card->card; SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); passed = calloc(1, sizeof(struct sc_cardctl_cardos_pass_algo_flags)); if (!passed) LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_ENOUGH_MEMORY); passed->pass = 1; /* get used_flags and card_flags from card */ r = sc_card_ctl(p15card->card, SC_CARDCTL_CARDOS_PASS_ALGO_FLAGS, passed); if (r < 0) { free(passed); LOG_FUNC_RETURN(card->ctx, r); } saa = &(p15card->tokeninfo->supported_algos); sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "Original Flags: 0x%8.8lx card->flags:0x%8.8lx", passed->used_flags, passed->card_flags); if (passed->card_flags) { /* user forced the flags, use them */ passed->new_flags = passed->card_flags; /* from card_atr flags */ } else { for (i = 0, sa = saa[0]; i < SC_MAX_SUPPORTED_ALGORITHMS; i++, sa++) { if (sa->reference == 0 && sa->mechanism == 0 && sa->operations == 0 && sa->algo_ref == 0) break; sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "supported_algos[%d] mechanism:0x%8.8x", i, sa->mechanism); switch(sa->mechanism) { case 0x01 : /* * Card appears to use lower 4 bits of reference as key, and upper * 4 bits as mech for card. * Also has a bug if mechanism = 1 (CKM_RSA_PKCS1) and reference 0x10 * bit is set mechanism should be 3 (CKM_RSA_X_509) * correct the mechanism in tokenInfo */ if (sa->reference & 0x10) { sc_log(card->ctx, "Changing mechanism to CKM_RSA_X_509 based on reference"); passed->new_flags |= SC_ALGORITHM_RSA_RAW | SC_ALGORITHM_RSA_PAD_NONE; sa->mechanism = 0x03; } else passed->new_flags |= SC_ALGORITHM_RSA_PAD_PKCS1; break; case 0x03 : passed->new_flags |= SC_ALGORITHM_RSA_RAW | SC_ALGORITHM_RSA_PAD_NONE; break; case 0x06 : passed->new_flags |= SC_ALGORITHM_RSA_HASH_SHA1; break; case 0x1041: passed->ec_flags |= SC_ALGORITHM_ECDSA_RAW; /* no old_ec_flags */ /* TODO turn on sizes from ec curves OIDS */ break; default: sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "UNKNOWN MECH: 0x%8.8x", sa->mechanism); } sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "New_flags 0x%8.8lx New_ec_flags: 0x%8.8lx", passed->new_flags, passed->ec_flags); } if (passed->new_flags == 0) { if (p15card->tokeninfo && p15card->tokeninfo->flags & SC_PKCS15_TOKEN_EID_COMPLIANT) { sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "EID_COMPLIANT flag found"); passed->new_flags = (passed->used_flags & ~SC_ALGORITHM_SPECIFIC_FLAGS) | SC_ALGORITHM_RSA_PAD_PKCS1; } else passed->new_flags = passed->used_flags; /* from default cardos_init */ } } sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL,"Final New_flags 0x%8.8lx New_ec_flags: 0x%8.8lx", passed->new_flags, passed->ec_flags); passed->pass = 2; /* tell card driver to use the new flags */ r = sc_card_ctl(p15card->card, SC_CARDCTL_CARDOS_PASS_ALGO_FLAGS, passed); free(passed); LOG_FUNC_RETURN(card->ctx, r); } static int cardos_pkcs15emu_detect_card(sc_pkcs15_card_t *p15card) { if (p15card->card->type < SC_CARD_TYPE_CARDOS_BASE) return SC_ERROR_WRONG_CARD; if (p15card->card->type >= SC_CARD_TYPE_CARDOS_BASE + 1000) return SC_ERROR_WRONG_CARD; return SC_SUCCESS; } static int sc_pkcs15emu_cardos_init(struct sc_pkcs15_card *p15card, struct sc_aid *aid) { sc_card_t *card = p15card->card; int r; LOG_FUNC_CALLED(card->ctx); r = sc_pkcs15_bind_internal(p15card, aid); LOG_TEST_RET(card->ctx, r, "sc_pkcs15_bind_internal failed"); /* If card has created algorithms, return */ sc_log(card->ctx, " card->algorithms:%p card->algorithm_count:%d", card->algorithms, card->algorithm_count); if (!card->algorithms && card->algorithm_count == 0) { r = cardos_fix_token_info(p15card); } LOG_FUNC_RETURN(card->ctx, r); } int sc_pkcs15emu_cardos_init_ex(struct sc_pkcs15_card *p15card, struct sc_aid *aid) { if (cardos_pkcs15emu_detect_card(p15card)) return SC_ERROR_WRONG_CARD; return sc_pkcs15emu_cardos_init(p15card, aid); }