opensc/src/libopensc/pkcs15-cardos.c

178 lines
5.5 KiB
C

/*
* PKCS15 emulation layer for CardOS cards
* Adapted from PKCS15 emulation layer for IAS/ECC card.
*
* Copyright (C) 2020, Douglas E. Engert <DEEngert@gmail.com>
* Copyright (C) 2016, Viktor Tarasov <viktor.tarasov@gmail.com>
* Copyright (C) 2004, Bud P. Bruegger <bud@comune.grosseto.it>
* Copyright (C) 2004, Antonino Iacono <ant_iacono@tin.it>
* Copyright (C) 2003, Olaf Kirch <okir@suse.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
*/
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#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);
}