2002-06-04 08:51:03 +00:00
|
|
|
/*
|
2003-10-13 16:13:12 +00:00
|
|
|
* CardOS specific operation for PKCS15 initialization
|
2002-06-04 08:51:03 +00:00
|
|
|
*
|
2005-12-28 19:38:55 +00:00
|
|
|
* Copyright (C) 2005 Nils Larsch <nils@larsch.net>
|
2002-06-04 08:51:03 +00:00
|
|
|
* 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>
|
2003-10-14 09:57:29 +00:00
|
|
|
#include <opensc/log.h>
|
2005-12-28 19:38:55 +00:00
|
|
|
#include <opensc/cards.h>
|
|
|
|
#include <opensc/asn1.h>
|
2002-06-04 08:51:03 +00:00
|
|
|
#include "pkcs15-init.h"
|
|
|
|
#include "profile.h"
|
|
|
|
|
2002-06-04 20:06:33 +00:00
|
|
|
#ifndef MIN
|
|
|
|
# define MIN(a, b) (((a) < (b))? (a) : (b))
|
|
|
|
#endif
|
|
|
|
|
2002-06-04 08:51:03 +00:00
|
|
|
struct tlv {
|
|
|
|
unsigned char * base;
|
|
|
|
unsigned char * end;
|
|
|
|
unsigned char * current;
|
|
|
|
unsigned char * next;
|
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Local functions
|
|
|
|
*/
|
2006-01-23 21:48:08 +00:00
|
|
|
static int cardos_store_pin(sc_profile_t *profile, sc_card_t *card,
|
2003-10-13 16:13:12 +00:00
|
|
|
sc_pkcs15_pin_info_t *pin_info, int puk_id,
|
|
|
|
const u8 *pin, size_t pin_len);
|
2006-01-23 21:48:08 +00:00
|
|
|
static int cardos_create_sec_env(sc_profile_t *, sc_card_t *,
|
2003-10-13 16:13:12 +00:00
|
|
|
unsigned int, unsigned int);
|
2010-02-21 16:21:57 +00:00
|
|
|
static int cardos_put_key(struct sc_profile *, sc_pkcs15_card_t *,
|
2003-10-15 13:21:04 +00:00
|
|
|
int, sc_pkcs15_prkey_info_t *,
|
|
|
|
struct sc_pkcs15_prkey_rsa *);
|
2005-12-28 19:38:55 +00:00
|
|
|
static int cardos_key_algorithm(unsigned int, size_t, int *);
|
|
|
|
static int cardos_extract_pubkey(sc_card_t *, sc_pkcs15_pubkey_t *,
|
|
|
|
sc_file_t *, int);
|
2006-01-23 22:02:07 +00:00
|
|
|
static int do_cardos_extract_pubkey(sc_card_t *card, int nr, u8 tag,
|
2005-12-28 19:38:55 +00:00
|
|
|
sc_pkcs15_bignum_t *bn);
|
2002-06-04 08:51:03 +00:00
|
|
|
|
2002-06-05 12:53:30 +00:00
|
|
|
/* 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
|
|
|
|
*/
|
2006-01-23 21:48:08 +00:00
|
|
|
#define CARDOS_PIN_ID_MIN 1
|
|
|
|
#define CARDOS_PIN_ID_MAX 15
|
|
|
|
#define CARDOS_KEY_ID_MIN 16
|
|
|
|
#define CARDOS_KEY_ID_MAX 31
|
|
|
|
#define CARDOS_AC_NEVER 0xFF
|
|
|
|
|
|
|
|
#define CARDOS_ALGO_RSA 0x08
|
|
|
|
#define CARDOS_ALGO_RSA_PURE 0x0C
|
|
|
|
#define CARDOS_ALGO_RSA_SIG 0x88
|
|
|
|
#define CARDOS_ALGO_RSA_PURE_SIG 0x8C
|
|
|
|
#define CARDOS_ALGO_RSA_SIG_SHA1 0xC8
|
|
|
|
#define CARDOS_ALGO_RSA_PURE_SIG_SHA1 0xCC
|
2005-12-28 19:38:55 +00:00
|
|
|
#define CARDOS_ALGO_EXT_RSA_PURE 0x0a
|
|
|
|
#define CARDOS_ALGO_EXT_RSA_SIG_PURE 0x8a
|
2006-01-23 21:48:08 +00:00
|
|
|
#define CARDOS_ALGO_PIN 0x87
|
2002-06-04 08:51:03 +00:00
|
|
|
|
2007-07-09 14:17:43 +00:00
|
|
|
static void tlv_init(struct tlv *tlv, u8 *base, size_t size)
|
2002-06-04 08:51:03 +00:00
|
|
|
{
|
|
|
|
tlv->base = base;
|
|
|
|
tlv->end = base + size;
|
|
|
|
tlv->current = tlv->next = base;
|
|
|
|
}
|
|
|
|
|
2007-07-09 14:17:43 +00:00
|
|
|
static void tlv_next(struct tlv *tlv, u8 tag)
|
2002-06-04 08:51:03 +00:00
|
|
|
{
|
|
|
|
assert(tlv->next + 2 < tlv->end);
|
|
|
|
tlv->current = tlv->next;
|
|
|
|
*(tlv->next++) = tag;
|
|
|
|
*(tlv->next++) = 0;
|
|
|
|
}
|
|
|
|
|
2007-07-09 14:17:43 +00:00
|
|
|
static void tlv_add(struct tlv *tlv, u8 val)
|
2002-06-04 08:51:03 +00:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2002-06-05 15:02:59 +00:00
|
|
|
/*
|
|
|
|
* 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 int
|
2010-02-21 16:21:57 +00:00
|
|
|
cardos_erase(struct sc_profile *profile, sc_pkcs15_card_t *p15card)
|
2002-06-05 15:02:59 +00:00
|
|
|
{
|
2010-02-21 16:21:57 +00:00
|
|
|
return sc_pkcs15init_erase_card_recursively(p15card, profile, -1);
|
2002-06-05 15:02:59 +00:00
|
|
|
}
|
|
|
|
|
2002-06-04 08:51:03 +00:00
|
|
|
/*
|
2003-10-13 16:13:12 +00:00
|
|
|
* Create the Application DF
|
2002-06-04 08:51:03 +00:00
|
|
|
*/
|
|
|
|
static int
|
2010-02-21 16:21:57 +00:00
|
|
|
cardos_create_dir(sc_profile_t *profile, sc_pkcs15_card_t *p15card, sc_file_t *df)
|
2003-10-13 16:13:12 +00:00
|
|
|
{
|
|
|
|
int r;
|
|
|
|
|
|
|
|
/* Create the application DF */
|
2010-02-21 16:21:57 +00:00
|
|
|
if ((r = sc_pkcs15init_create_file(profile, p15card, df)) < 0)
|
2003-10-13 16:13:12 +00:00
|
|
|
return r;
|
|
|
|
|
2010-02-21 16:21:57 +00:00
|
|
|
if ((r = sc_select_file(p15card->card, &df->path, NULL)) < 0)
|
2003-10-13 16:13:12 +00:00
|
|
|
return r;
|
|
|
|
|
|
|
|
/* Create a default security environment for this DF.
|
|
|
|
* This SE autometically becomes the current SE when the
|
|
|
|
* DF is selected. */
|
2010-02-21 16:21:57 +00:00
|
|
|
if ((r = cardos_create_sec_env(profile, p15card->card, 0x01, 0x00)) < 0)
|
2003-10-13 16:13:12 +00:00
|
|
|
return r;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Caller passes in a suggested PIN reference.
|
|
|
|
* See if it's good, and if it isn't, propose something better
|
|
|
|
*/
|
|
|
|
static int
|
2010-02-21 16:21:57 +00:00
|
|
|
cardos_select_pin_reference(sc_profile_t *profile, sc_pkcs15_card_t *p15card,
|
2003-10-13 16:13:12 +00:00
|
|
|
sc_pkcs15_pin_info_t *pin_info)
|
|
|
|
{
|
|
|
|
int preferred, current;
|
|
|
|
|
|
|
|
if ((current = pin_info->reference) < 0)
|
2006-01-23 21:48:08 +00:00
|
|
|
current = CARDOS_PIN_ID_MIN;
|
2003-10-13 16:13:12 +00:00
|
|
|
|
|
|
|
if (pin_info->flags & SC_PKCS15_PIN_FLAG_SO_PIN) {
|
|
|
|
preferred = 1;
|
|
|
|
} else {
|
|
|
|
preferred = current;
|
|
|
|
/* PINs are even numbered, PUKs are odd */
|
|
|
|
if (!(preferred & 1))
|
|
|
|
preferred++;
|
|
|
|
if (preferred >= 126)
|
|
|
|
return SC_ERROR_TOO_MANY_OBJECTS;
|
|
|
|
}
|
|
|
|
|
2006-01-23 21:48:08 +00:00
|
|
|
if (current > preferred || preferred > CARDOS_PIN_ID_MAX)
|
2003-10-13 16:13:12 +00:00
|
|
|
return SC_ERROR_TOO_MANY_OBJECTS;
|
|
|
|
pin_info->reference = preferred;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Store a PIN
|
|
|
|
*/
|
|
|
|
static int
|
2010-02-21 16:21:57 +00:00
|
|
|
cardos_create_pin(sc_profile_t *profile, sc_pkcs15_card_t *p15card, sc_file_t *df,
|
2003-10-17 11:21:48 +00:00
|
|
|
sc_pkcs15_object_t *pin_obj,
|
2003-10-13 16:13:12 +00:00
|
|
|
const u8 *pin, size_t pin_len,
|
|
|
|
const u8 *puk, size_t puk_len)
|
|
|
|
{
|
2003-10-17 11:21:48 +00:00
|
|
|
sc_pkcs15_pin_info_t *pin_info = (sc_pkcs15_pin_info_t *) pin_obj->data;
|
2010-02-21 16:21:57 +00:00
|
|
|
struct sc_card *card = p15card->card;
|
2006-01-23 21:48:08 +00:00
|
|
|
unsigned int puk_id = CARDOS_AC_NEVER;
|
2003-10-13 16:13:12 +00:00
|
|
|
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 (puk && puk_len) {
|
|
|
|
struct sc_pkcs15_pin_info puk_info;
|
|
|
|
|
|
|
|
sc_profile_get_pin_info(profile,
|
|
|
|
SC_PKCS15INIT_USER_PUK, &puk_info);
|
|
|
|
puk_info.reference = puk_id = pin_info->reference + 1;
|
2006-01-23 21:48:08 +00:00
|
|
|
r = cardos_store_pin(profile, card,
|
|
|
|
&puk_info, CARDOS_AC_NEVER,
|
2003-10-13 16:13:12 +00:00
|
|
|
puk, puk_len);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (r >= 0) {
|
2006-01-23 21:48:08 +00:00
|
|
|
r = cardos_store_pin(profile, card,
|
2005-12-28 19:38:55 +00:00
|
|
|
pin_info, puk_id, pin, pin_len);
|
2003-10-13 16:13:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Select a key reference
|
|
|
|
*/
|
|
|
|
static int
|
2010-02-21 16:21:57 +00:00
|
|
|
cardos_select_key_reference(sc_profile_t *profile, sc_pkcs15_card_t *p15card,
|
2003-10-13 16:13:12 +00:00
|
|
|
sc_pkcs15_prkey_info_t *key_info)
|
|
|
|
{
|
2006-01-23 21:48:08 +00:00
|
|
|
if (key_info->key_reference < CARDOS_KEY_ID_MIN)
|
|
|
|
key_info->key_reference = CARDOS_KEY_ID_MIN;
|
|
|
|
if (key_info->key_reference > CARDOS_KEY_ID_MAX)
|
2003-10-13 16:13:12 +00:00
|
|
|
return SC_ERROR_TOO_MANY_OBJECTS;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Create a private key object.
|
|
|
|
* This is a no-op.
|
|
|
|
*/
|
|
|
|
static int
|
2010-02-21 16:21:57 +00:00
|
|
|
cardos_create_key(sc_profile_t *profile, sc_pkcs15_card_t *p15card,
|
2003-10-13 16:13:12 +00:00
|
|
|
sc_pkcs15_object_t *obj)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Store a private key object.
|
|
|
|
*/
|
|
|
|
static int
|
2010-02-21 16:21:57 +00:00
|
|
|
cardos_store_key(sc_profile_t *profile, sc_pkcs15_card_t *p15card,
|
2003-10-13 16:13:12 +00:00
|
|
|
sc_pkcs15_object_t *obj,
|
|
|
|
sc_pkcs15_prkey_t *key)
|
|
|
|
{
|
2010-02-21 16:21:57 +00:00
|
|
|
struct sc_context *ctx = p15card->card->ctx;
|
2003-10-13 16:13:12 +00:00
|
|
|
sc_pkcs15_prkey_info_t *key_info = (sc_pkcs15_prkey_info_t *) obj->data;
|
2010-01-31 20:26:45 +00:00
|
|
|
struct sc_file *file = NULL;
|
2009-10-22 09:18:16 +00:00
|
|
|
int algorithm = 0, r;
|
2003-10-13 16:13:12 +00:00
|
|
|
|
|
|
|
if (obj->type != SC_PKCS15_TYPE_PRKEY_RSA) {
|
2010-02-21 16:21:57 +00:00
|
|
|
sc_debug(ctx, "CardOS supports RSA keys only.");
|
2003-10-13 16:13:12 +00:00
|
|
|
return SC_ERROR_NOT_SUPPORTED;
|
|
|
|
}
|
|
|
|
|
2005-12-28 19:38:55 +00:00
|
|
|
if (cardos_key_algorithm(key_info->usage, key_info->modulus_length, &algorithm) < 0) {
|
2010-02-21 16:21:57 +00:00
|
|
|
sc_debug(ctx, "CardOS does not support keys "
|
2003-10-13 16:13:12 +00:00
|
|
|
"that can both sign _and_ decrypt.");
|
|
|
|
return SC_ERROR_NOT_SUPPORTED;
|
|
|
|
}
|
|
|
|
|
2010-02-21 16:21:57 +00:00
|
|
|
r = sc_select_file(p15card->card, &key_info->path, &file);
|
2010-01-31 20:26:45 +00:00
|
|
|
if (r) {
|
2010-02-21 16:21:57 +00:00
|
|
|
sc_debug(ctx, "Failed to store key: cannot select parent DF");
|
2010-01-31 20:26:45 +00:00
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2010-02-21 16:21:57 +00:00
|
|
|
r = sc_pkcs15init_authenticate(profile, p15card, file, SC_AC_OP_UPDATE);
|
2010-01-31 20:26:45 +00:00
|
|
|
sc_file_free(file);
|
|
|
|
if (r) {
|
2010-02-21 16:21:57 +00:00
|
|
|
sc_debug(ctx, "Failed to store key: 'UPDATE' authentication failed");
|
2010-01-31 20:26:45 +00:00
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2010-02-21 16:21:57 +00:00
|
|
|
r = cardos_put_key(profile, p15card, algorithm, key_info, &key->u.rsa);
|
2003-10-13 16:13:12 +00:00
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2005-12-28 19:38:55 +00:00
|
|
|
static void init_key_object(struct sc_pkcs15_prkey_rsa *key,
|
|
|
|
u8 *data, size_t len)
|
|
|
|
{
|
|
|
|
/* Create a key object, initializing components to 0xff */
|
|
|
|
memset(key, 0x00, sizeof(*key));
|
|
|
|
memset(data, 0xff, len);
|
|
|
|
key->modulus.data = data;
|
|
|
|
key->modulus.len = len;
|
|
|
|
key->d.data = data;
|
|
|
|
key->d.len = len;
|
|
|
|
key->p.len = len >> 1;
|
|
|
|
key->p.data = data;
|
|
|
|
key->q.len = len >> 1;
|
|
|
|
key->q.data = data;
|
|
|
|
key->iqmp.len = len >> 1;
|
|
|
|
key->iqmp.data = data;
|
|
|
|
key->dmp1.len = len >> 1;
|
|
|
|
key->dmp1.data = data;
|
|
|
|
key->dmq1.len = len >> 1;
|
|
|
|
key->dmq1.data = data;
|
|
|
|
}
|
|
|
|
|
2003-10-13 16:13:12 +00:00
|
|
|
/*
|
|
|
|
* Key generation
|
|
|
|
*/
|
|
|
|
static int
|
2010-02-21 16:21:57 +00:00
|
|
|
cardos_generate_key(sc_profile_t *profile, sc_pkcs15_card_t *p15card,
|
2003-10-13 16:13:12 +00:00
|
|
|
sc_pkcs15_object_t *obj,
|
|
|
|
sc_pkcs15_pubkey_t *pubkey)
|
|
|
|
{
|
2010-02-21 16:21:57 +00:00
|
|
|
struct sc_context *ctx = p15card->card->ctx;
|
|
|
|
struct sc_pkcs15_prkey_info *key_info = (sc_pkcs15_prkey_info_t *) obj->data;
|
2003-10-13 16:13:12 +00:00
|
|
|
struct sc_pkcs15_prkey_rsa key_obj;
|
2006-01-23 21:48:08 +00:00
|
|
|
struct sc_cardctl_cardos_genkey_info args;
|
2003-10-13 16:13:12 +00:00
|
|
|
struct sc_file *temp;
|
2005-12-28 19:38:55 +00:00
|
|
|
u8 abignum[256];
|
2009-10-22 09:18:16 +00:00
|
|
|
int algorithm = 0, r, delete_it = 0, use_ext_rsa = 0;
|
2005-12-28 19:38:55 +00:00
|
|
|
size_t keybits, rsa_max_size;
|
2008-07-21 14:35:21 +00:00
|
|
|
int pin_id = -1;
|
|
|
|
|
2005-12-28 19:38:55 +00:00
|
|
|
if (obj->type != SC_PKCS15_TYPE_PRKEY_RSA)
|
2003-10-13 16:13:12 +00:00
|
|
|
return SC_ERROR_NOT_SUPPORTED;
|
2005-12-28 19:38:55 +00:00
|
|
|
|
2010-02-21 16:21:57 +00:00
|
|
|
rsa_max_size = (p15card->card->caps & SC_CARD_CAP_RSA_2048) ? 2048 : 1024;
|
2005-12-28 19:38:55 +00:00
|
|
|
keybits = key_info->modulus_length & ~7UL;
|
|
|
|
if (keybits > rsa_max_size) {
|
2010-02-21 16:21:57 +00:00
|
|
|
sc_debug(ctx, "Unable to generate key, max size is %lu",
|
2006-05-01 10:02:50 +00:00
|
|
|
(unsigned long) rsa_max_size);
|
2005-12-28 19:38:55 +00:00
|
|
|
return SC_ERROR_INVALID_ARGUMENTS;
|
2003-10-13 16:13:12 +00:00
|
|
|
}
|
|
|
|
|
2005-12-28 19:38:55 +00:00
|
|
|
if (keybits > 1024)
|
|
|
|
use_ext_rsa = 1;
|
|
|
|
|
|
|
|
if (cardos_key_algorithm(key_info->usage, keybits, &algorithm) < 0) {
|
2010-02-21 16:21:57 +00:00
|
|
|
sc_debug(ctx, "CardOS does not support keys "
|
2003-10-13 16:13:12 +00:00
|
|
|
"that can both sign _and_ decrypt.");
|
|
|
|
return SC_ERROR_NOT_SUPPORTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sc_profile_get_file(profile, "tempfile", &temp) < 0) {
|
2010-02-21 16:21:57 +00:00
|
|
|
sc_debug(ctx, "Profile doesn't define temporary file "
|
2003-10-14 09:57:29 +00:00
|
|
|
"for key generation.");
|
2003-10-13 16:13:12 +00:00
|
|
|
return SC_ERROR_NOT_SUPPORTED;
|
|
|
|
}
|
2010-02-21 18:24:41 +00:00
|
|
|
|
|
|
|
pin_id = sc_pkcs15init_get_pin_reference(p15card, profile, &key_info->path,
|
2010-02-21 16:21:57 +00:00
|
|
|
SC_AC_SYMBOLIC, SC_PKCS15INIT_USER_PIN);
|
|
|
|
if (pin_id >= 0) {
|
|
|
|
r = sc_pkcs15init_verify_key(profile, p15card, NULL, SC_AC_CHV, pin_id);
|
2008-07-21 14:35:21 +00:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
}
|
2005-12-28 19:38:55 +00:00
|
|
|
if (use_ext_rsa == 0)
|
|
|
|
temp->ef_structure = SC_FILE_EF_LINEAR_VARIABLE_TLV;
|
|
|
|
else
|
|
|
|
temp->ef_structure = SC_FILE_EF_TRANSPARENT;
|
2003-10-13 16:13:12 +00:00
|
|
|
|
2010-02-21 16:21:57 +00:00
|
|
|
if ((r = sc_pkcs15init_create_file(profile, p15card, temp)) < 0)
|
2003-10-13 16:13:12 +00:00
|
|
|
goto out;
|
|
|
|
delete_it = 1;
|
|
|
|
|
2005-12-28 19:38:55 +00:00
|
|
|
init_key_object(&key_obj, abignum, keybits >> 3);
|
|
|
|
|
2010-02-21 16:21:57 +00:00
|
|
|
r = cardos_put_key(profile, p15card, algorithm, key_info, &key_obj);
|
2003-10-13 16:13:12 +00:00
|
|
|
if (r < 0)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
memset(&args, 0, sizeof(args));
|
|
|
|
args.key_id = key_info->key_reference;
|
|
|
|
args.key_bits = keybits;
|
|
|
|
args.fid = temp->id;
|
2010-02-21 16:21:57 +00:00
|
|
|
r = sc_card_ctl(p15card->card, SC_CARDCTL_CARDOS_GENERATE_KEY, &args);
|
2003-10-13 16:13:12 +00:00
|
|
|
if (r < 0)
|
|
|
|
goto out;
|
|
|
|
|
2010-02-21 16:21:57 +00:00
|
|
|
r = cardos_extract_pubkey(p15card->card, pubkey, temp, use_ext_rsa);
|
2005-12-28 19:38:55 +00:00
|
|
|
out:
|
|
|
|
if (delete_it != 0)
|
2010-02-21 16:21:57 +00:00
|
|
|
sc_pkcs15init_rmdir(p15card, profile, temp);
|
2003-10-13 16:13:12 +00:00
|
|
|
sc_file_free(temp);
|
2005-12-28 19:38:55 +00:00
|
|
|
|
2003-10-13 16:13:12 +00:00
|
|
|
if (r < 0) {
|
|
|
|
if (pubkey->u.rsa.modulus.data)
|
|
|
|
free (pubkey->u.rsa.modulus.data);
|
|
|
|
if (pubkey->u.rsa.exponent.data)
|
|
|
|
free (pubkey->u.rsa.exponent.data);
|
|
|
|
}
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Store a PIN or PUK
|
|
|
|
*/
|
|
|
|
static int
|
2006-01-23 21:48:08 +00:00
|
|
|
cardos_store_pin(sc_profile_t *profile, sc_card_t *card,
|
2003-10-13 16:13:12 +00:00
|
|
|
sc_pkcs15_pin_info_t *pin_info, int puk_id,
|
2002-06-05 12:53:30 +00:00
|
|
|
const u8 *pin, size_t pin_len)
|
2002-06-04 08:51:03 +00:00
|
|
|
{
|
2006-01-23 21:48:08 +00:00
|
|
|
struct sc_cardctl_cardos_obj_info args;
|
2002-06-04 08:51:03 +00:00
|
|
|
unsigned char buffer[256];
|
2007-04-23 19:23:51 +00:00
|
|
|
unsigned char pinpadded[256];
|
2002-06-04 08:51:03 +00:00
|
|
|
struct tlv tlv;
|
2002-06-05 12:53:30 +00:00
|
|
|
unsigned int attempts, minlen, maxlen;
|
2005-12-28 19:38:55 +00:00
|
|
|
int r;
|
2002-06-04 08:51:03 +00:00
|
|
|
|
2002-06-04 20:06:33 +00:00
|
|
|
/* 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));
|
2005-12-28 19:38:55 +00:00
|
|
|
if (pin_len > maxlen) {
|
2009-09-14 08:46:59 +00:00
|
|
|
sc_debug(card->ctx, "invalid pin length: %u (max %u)\n",
|
2005-12-28 19:38:55 +00:00
|
|
|
pin_len, maxlen);
|
|
|
|
return SC_ERROR_INVALID_ARGUMENTS;
|
|
|
|
}
|
2002-06-04 20:06:33 +00:00
|
|
|
memcpy(pinpadded, pin, pin_len);
|
|
|
|
while (pin_len < maxlen)
|
|
|
|
pinpadded[pin_len++] = profile->pin_pad_char;
|
|
|
|
pin = pinpadded;
|
2002-06-04 08:51:03 +00:00
|
|
|
|
2003-10-13 16:13:12 +00:00
|
|
|
attempts = pin_info->tries_left;
|
|
|
|
minlen = pin_info->min_length;
|
2002-06-04 20:06:33 +00:00
|
|
|
|
2002-06-04 08:51:03 +00:00
|
|
|
tlv_init(&tlv, buffer, sizeof(buffer));
|
|
|
|
|
|
|
|
/* object address: class, id */
|
|
|
|
tlv_next(&tlv, 0x83);
|
|
|
|
tlv_add(&tlv, 0x00); /* class byte: usage TEST, k=0 */
|
2003-10-13 16:13:12 +00:00
|
|
|
tlv_add(&tlv, pin_info->reference);
|
2002-06-04 08:51:03 +00:00
|
|
|
|
|
|
|
/* parameters */
|
|
|
|
tlv_next(&tlv, 0x85);
|
|
|
|
tlv_add(&tlv, 0x02); /* options byte */
|
|
|
|
tlv_add(&tlv, attempts & 0xf); /* flags byte */
|
2006-01-23 21:48:08 +00:00
|
|
|
tlv_add(&tlv, CARDOS_ALGO_PIN); /* algorithm = pin-test */
|
2002-06-04 08:51:03 +00:00
|
|
|
tlv_add(&tlv, attempts & 0xf); /* errcount = attempts */
|
|
|
|
|
2002-06-04 19:43:30 +00:00
|
|
|
/* 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 */
|
2005-12-28 19:38:55 +00:00
|
|
|
tlv_add(&tlv, 0xff);
|
2002-06-04 19:43:30 +00:00
|
|
|
|
2005-12-28 19:38:55 +00:00
|
|
|
/* ARA counter: number of times the test object can be used before
|
|
|
|
* another verification is required (~ user consent)
|
|
|
|
* (0x00 unlimited usage)
|
|
|
|
*/
|
2002-06-04 19:43:30 +00:00
|
|
|
tlv_add(&tlv, 0x00);
|
|
|
|
|
2003-10-13 16:13:12 +00:00
|
|
|
tlv_add(&tlv, minlen); /* minlen */
|
2002-06-04 08:51:03 +00:00
|
|
|
|
|
|
|
/* AC conditions */
|
|
|
|
tlv_next(&tlv, 0x86);
|
2003-10-13 16:13:12 +00:00
|
|
|
tlv_add(&tlv, 0x00); /* use: always */
|
|
|
|
tlv_add(&tlv, pin_info->reference); /* change: PIN */
|
|
|
|
tlv_add(&tlv, puk_id); /* unblock: PUK */
|
2002-06-04 08:51:03 +00:00
|
|
|
|
2002-06-04 19:43:30 +00:00
|
|
|
/* data: PIN */
|
|
|
|
tlv_next(&tlv, 0x8f);
|
|
|
|
while (pin_len--)
|
|
|
|
tlv_add(&tlv, *pin++);
|
|
|
|
|
2002-06-04 08:51:03 +00:00
|
|
|
args.data = buffer;
|
|
|
|
args.len = tlv_len(&tlv);
|
|
|
|
|
2005-12-28 19:38:55 +00:00
|
|
|
/* ensure we are in the correct lifecycle */
|
|
|
|
r = sc_pkcs15init_set_lifecycle(card, SC_CARDCTRL_LIFECYCLE_ADMIN);
|
|
|
|
if (r < 0 && r != SC_ERROR_NOT_SUPPORTED)
|
|
|
|
return r;
|
|
|
|
|
2006-01-23 21:48:08 +00:00
|
|
|
return sc_card_ctl(card, SC_CARDCTL_CARDOS_PUT_DATA_OCI, &args);
|
2002-06-04 08:51:03 +00:00
|
|
|
}
|
|
|
|
|
2002-06-11 18:15:41 +00:00
|
|
|
/*
|
|
|
|
* Create an empty security environment
|
|
|
|
*/
|
|
|
|
static int
|
2006-01-23 21:48:08 +00:00
|
|
|
cardos_create_sec_env(struct sc_profile *profile, sc_card_t *card,
|
2002-06-11 18:15:41 +00:00
|
|
|
unsigned int se_id, unsigned int key_id)
|
|
|
|
{
|
2006-01-23 21:48:08 +00:00
|
|
|
struct sc_cardctl_cardos_obj_info args;
|
2002-06-11 18:15:41 +00:00
|
|
|
struct tlv tlv;
|
|
|
|
unsigned char buffer[64];
|
2005-12-28 19:38:55 +00:00
|
|
|
int r;
|
2002-06-11 18:15:41 +00:00
|
|
|
|
|
|
|
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);
|
2005-12-28 19:38:55 +00:00
|
|
|
|
|
|
|
/* ensure we are in the correct lifecycle */
|
|
|
|
r = sc_pkcs15init_set_lifecycle(card, SC_CARDCTRL_LIFECYCLE_ADMIN);
|
|
|
|
if (r < 0 && r != SC_ERROR_NOT_SUPPORTED)
|
|
|
|
return r;
|
|
|
|
|
2006-01-23 21:48:08 +00:00
|
|
|
return sc_card_ctl(card, SC_CARDCTL_CARDOS_PUT_DATA_SECI, &args);
|
2002-06-11 18:15:41 +00:00
|
|
|
}
|
|
|
|
|
2002-10-02 10:50:15 +00:00
|
|
|
/*
|
|
|
|
* 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
|
|
|
|
*/
|
2003-10-16 14:31:11 +00:00
|
|
|
#define USAGE_ANY_SIGN (SC_PKCS15_PRKEY_USAGE_SIGN|\
|
|
|
|
SC_PKCS15_PRKEY_USAGE_NONREPUDIATION)
|
2002-10-02 10:50:15 +00:00
|
|
|
#define USAGE_ANY_DECIPHER (SC_PKCS15_PRKEY_USAGE_DECRYPT|\
|
|
|
|
SC_PKCS15_PRKEY_USAGE_UNWRAP)
|
|
|
|
|
2005-12-28 19:38:55 +00:00
|
|
|
static int cardos_key_algorithm(unsigned int usage, size_t keylen, int *algop)
|
2002-10-02 10:50:15 +00:00
|
|
|
{
|
|
|
|
int sign = 0, decipher = 0;
|
|
|
|
|
|
|
|
if (usage & USAGE_ANY_SIGN) {
|
2005-12-28 19:38:55 +00:00
|
|
|
if (keylen <= 1024)
|
2006-01-23 21:48:08 +00:00
|
|
|
*algop = CARDOS_ALGO_RSA_PURE_SIG;
|
2005-12-28 19:38:55 +00:00
|
|
|
else
|
|
|
|
*algop = CARDOS_ALGO_EXT_RSA_SIG_PURE;
|
2003-10-16 14:31:11 +00:00
|
|
|
sign = 1;
|
2002-10-02 10:50:15 +00:00
|
|
|
}
|
|
|
|
if (usage & USAGE_ANY_DECIPHER) {
|
2005-12-28 19:38:55 +00:00
|
|
|
if (keylen <= 1024)
|
2006-01-23 21:48:08 +00:00
|
|
|
*algop = CARDOS_ALGO_RSA_PURE;
|
2005-12-28 19:38:55 +00:00
|
|
|
else
|
|
|
|
*algop = CARDOS_ALGO_EXT_RSA_PURE;
|
2003-10-16 14:31:11 +00:00
|
|
|
decipher = 1;
|
2002-10-02 10:50:15 +00:00
|
|
|
}
|
2003-10-16 14:31:11 +00:00
|
|
|
return (sign == decipher)? -1 : 0;
|
2002-10-02 10:50:15 +00:00
|
|
|
}
|
|
|
|
|
2002-06-06 09:17:52 +00:00
|
|
|
/*
|
|
|
|
* Create a private key object
|
|
|
|
*/
|
2006-01-23 21:48:08 +00:00
|
|
|
#define CARDOS_KEY_OPTIONS 0x02
|
|
|
|
#define CARDOS_KEY_FLAGS 0x00
|
2002-06-06 09:17:52 +00:00
|
|
|
static int
|
2006-01-23 21:48:08 +00:00
|
|
|
cardos_store_key_component(sc_card_t *card,
|
2002-10-02 10:50:15 +00:00
|
|
|
int algorithm,
|
2002-06-06 09:17:52 +00:00
|
|
|
unsigned int key_id, unsigned int pin_id,
|
|
|
|
unsigned int num,
|
|
|
|
const u8 *data, size_t len,
|
2005-12-28 19:38:55 +00:00
|
|
|
int last, int use_prefix)
|
2002-06-06 09:17:52 +00:00
|
|
|
{
|
2006-01-23 21:48:08 +00:00
|
|
|
struct sc_cardctl_cardos_obj_info args;
|
2002-06-06 09:17:52 +00:00
|
|
|
struct tlv tlv;
|
|
|
|
unsigned char buffer[256];
|
2008-05-22 12:13:19 +00:00
|
|
|
#ifdef SET_SM_BYTES
|
2002-06-11 18:15:41 +00:00
|
|
|
unsigned int n;
|
2005-12-28 19:38:55 +00:00
|
|
|
#endif
|
|
|
|
int r;
|
2002-06-06 09:17:52 +00:00
|
|
|
|
|
|
|
/* Initialize the TLV encoder */
|
|
|
|
tlv_init(&tlv, buffer, sizeof(buffer));
|
|
|
|
|
|
|
|
/* Object address */
|
|
|
|
tlv_next(&tlv, 0x83);
|
|
|
|
tlv_add(&tlv, 0x20|num); /* PSO, n-th component */
|
|
|
|
tlv_add(&tlv, key_id);
|
|
|
|
|
|
|
|
/* Object parameters */
|
|
|
|
tlv_next(&tlv, 0x85);
|
2006-01-23 21:48:08 +00:00
|
|
|
tlv_add(&tlv, CARDOS_KEY_OPTIONS|(last? 0x00 : 0x20));
|
|
|
|
tlv_add(&tlv, CARDOS_KEY_FLAGS);
|
2002-10-02 10:50:15 +00:00
|
|
|
tlv_add(&tlv, algorithm);
|
2002-06-06 09:17:52 +00:00
|
|
|
tlv_add(&tlv, 0x00);
|
2002-06-11 18:15:41 +00:00
|
|
|
tlv_add(&tlv, 0xFF); /* use count */
|
|
|
|
tlv_add(&tlv, 0xFF); /* DEK (whatever this is) */
|
2002-06-06 09:17:52 +00:00
|
|
|
tlv_add(&tlv, 0x00);
|
|
|
|
tlv_add(&tlv, 0x00);
|
|
|
|
|
|
|
|
/* AC bytes */
|
|
|
|
tlv_next(&tlv, 0x86);
|
|
|
|
tlv_add(&tlv, pin_id); /* AC USE */
|
|
|
|
tlv_add(&tlv, pin_id); /* AC CHANGE */
|
2002-06-17 10:58:04 +00:00
|
|
|
tlv_add(&tlv, pin_id); /* UNKNOWN */
|
2005-12-28 19:38:55 +00:00
|
|
|
tlv_add(&tlv, 0); /* rfu */
|
|
|
|
tlv_add(&tlv, 0); /* rfu */
|
|
|
|
tlv_add(&tlv, 0); /* rfu */
|
|
|
|
#if 0
|
|
|
|
tlv_add(&tlv, pin_id); /* AC GENKEY */
|
|
|
|
#else
|
2002-06-17 10:58:04 +00:00
|
|
|
tlv_add(&tlv, 0);
|
2005-12-28 19:38:55 +00:00
|
|
|
#endif
|
2002-06-06 09:17:52 +00:00
|
|
|
|
2008-05-22 12:13:19 +00:00
|
|
|
#ifdef SET_SM_BYTES
|
2005-12-28 19:38:55 +00:00
|
|
|
/* it shouldn't be necessary to set the default value */
|
2002-06-11 18:15:41 +00:00
|
|
|
/* SM bytes */
|
|
|
|
tlv_next(&tlv, 0x8B);
|
|
|
|
for (n = 0; n < 16; n++)
|
|
|
|
tlv_add(&tlv, 0xFF);
|
2005-12-28 19:38:55 +00:00
|
|
|
#endif
|
2002-06-11 18:15:41 +00:00
|
|
|
|
2002-06-07 20:29:07 +00:00
|
|
|
/* key component */
|
2002-06-06 09:17:52 +00:00
|
|
|
tlv_next(&tlv, 0x8f);
|
2005-12-28 19:38:55 +00:00
|
|
|
if (use_prefix != 0) {
|
|
|
|
tlv_add(&tlv, len+1);
|
|
|
|
tlv_add(&tlv, 0);
|
|
|
|
}
|
2002-06-06 09:17:52 +00:00
|
|
|
while (len--)
|
|
|
|
tlv_add(&tlv, *data++);
|
|
|
|
|
|
|
|
args.data = buffer;
|
|
|
|
args.len = tlv_len(&tlv);
|
2005-12-28 19:38:55 +00:00
|
|
|
|
|
|
|
/* ensure we are in the correct lifecycle */
|
|
|
|
r = sc_pkcs15init_set_lifecycle(card, SC_CARDCTRL_LIFECYCLE_ADMIN);
|
|
|
|
if (r < 0 && r != SC_ERROR_NOT_SUPPORTED)
|
|
|
|
return r;
|
|
|
|
|
2006-01-23 21:48:08 +00:00
|
|
|
return sc_card_ctl(card, SC_CARDCTL_CARDOS_PUT_DATA_OCI, &args);
|
2002-06-06 09:17:52 +00:00
|
|
|
}
|
|
|
|
|
2010-02-21 16:21:57 +00:00
|
|
|
|
|
|
|
static int
|
|
|
|
cardos_put_key(sc_profile_t *profile, struct sc_pkcs15_card *p15card,
|
2005-12-28 19:38:55 +00:00
|
|
|
int algorithm, sc_pkcs15_prkey_info_t *key_info,
|
|
|
|
struct sc_pkcs15_prkey_rsa *key)
|
2002-06-06 09:17:52 +00:00
|
|
|
{
|
2010-02-21 16:21:57 +00:00
|
|
|
struct sc_card *card = p15card->card;
|
2003-10-15 13:21:04 +00:00
|
|
|
int r, key_id, pin_id;
|
2002-06-07 20:29:07 +00:00
|
|
|
|
2010-02-21 16:21:57 +00:00
|
|
|
pin_id = sc_pkcs15init_get_pin_reference(p15card, profile, &key_info->path,
|
|
|
|
SC_AC_SYMBOLIC, SC_PKCS15INIT_USER_PIN);
|
2003-10-15 13:21:04 +00:00
|
|
|
if (pin_id < 0)
|
2002-06-11 18:15:41 +00:00
|
|
|
pin_id = 0;
|
2002-06-06 09:17:52 +00:00
|
|
|
|
2010-02-21 16:21:57 +00:00
|
|
|
key_id = key_info->key_reference;
|
2006-07-13 21:01:46 +00:00
|
|
|
if (key_info->modulus_length > 1024 && (card->type == SC_CARD_TYPE_CARDOS_M4_2 ||
|
2007-12-19 09:58:29 +00:00
|
|
|
card->type == SC_CARD_TYPE_CARDOS_M4_3 ||card->type == SC_CARD_TYPE_CARDOS_M4_2B ||
|
|
|
|
card->type == SC_CARD_TYPE_CARDOS_M4_2C )) {
|
2006-01-23 21:48:08 +00:00
|
|
|
r = cardos_store_key_component(card, algorithm, key_id, pin_id, 0,
|
2005-12-28 19:38:55 +00:00
|
|
|
key->p.data, key->p.len, 0, 0);
|
|
|
|
if (r != SC_SUCCESS)
|
|
|
|
return r;
|
2006-01-23 21:48:08 +00:00
|
|
|
r = cardos_store_key_component(card, algorithm, key_id, pin_id, 1,
|
2005-12-28 19:38:55 +00:00
|
|
|
key->q.data, key->q.len, 0, 0);
|
|
|
|
if (r != SC_SUCCESS)
|
|
|
|
return r;
|
2006-01-23 21:48:08 +00:00
|
|
|
r = cardos_store_key_component(card, algorithm, key_id, pin_id, 2,
|
2005-12-28 19:38:55 +00:00
|
|
|
key->dmp1.data, key->dmp1.len, 0, 0);
|
|
|
|
if (r != SC_SUCCESS)
|
|
|
|
return r;
|
2006-01-23 21:48:08 +00:00
|
|
|
r = cardos_store_key_component(card, algorithm, key_id, pin_id, 3,
|
2005-12-28 19:38:55 +00:00
|
|
|
key->dmq1.data, key->dmq1.len, 0, 0);
|
|
|
|
if (r != SC_SUCCESS)
|
|
|
|
return r;
|
2006-01-23 21:48:08 +00:00
|
|
|
r = cardos_store_key_component(card, algorithm, key_id, pin_id, 4,
|
2005-12-28 19:38:55 +00:00
|
|
|
key->iqmp.data, key->iqmp.len, 1, 0);
|
|
|
|
} else {
|
2006-01-23 21:48:08 +00:00
|
|
|
r = cardos_store_key_component(card, algorithm, key_id, pin_id, 0,
|
2005-12-28 19:38:55 +00:00
|
|
|
key->modulus.data, key->modulus.len, 0, 1);
|
|
|
|
if (r != SC_SUCCESS)
|
|
|
|
return r;
|
2006-01-23 21:48:08 +00:00
|
|
|
r = cardos_store_key_component(card, algorithm, key_id, pin_id, 1,
|
2005-12-28 19:38:55 +00:00
|
|
|
key->d.data, key->d.len, 1, 1);
|
|
|
|
}
|
2002-06-11 18:15:41 +00:00
|
|
|
|
2002-06-06 09:17:52 +00:00
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2002-06-17 10:58:04 +00:00
|
|
|
/*
|
|
|
|
* Extract a key component from the public key file populated by
|
|
|
|
* GENERATE KEY PAIR
|
|
|
|
*/
|
2005-12-28 19:38:55 +00:00
|
|
|
static int parse_ext_pubkey_file(sc_card_t *card, const u8 *data, size_t len,
|
|
|
|
sc_pkcs15_pubkey_t *pubkey)
|
|
|
|
{
|
|
|
|
const u8 *p;
|
2006-02-12 18:30:53 +00:00
|
|
|
size_t ilen = 0, tlen = 0;
|
2005-12-28 19:38:55 +00:00
|
|
|
|
|
|
|
if (data == NULL || len < 32)
|
|
|
|
return SC_ERROR_INVALID_ARGUMENTS;
|
2006-02-12 18:30:53 +00:00
|
|
|
data = sc_asn1_find_tag(card->ctx, data, len, 0x7f49, &ilen);
|
|
|
|
if (data == NULL) {
|
2009-09-14 08:46:59 +00:00
|
|
|
sc_debug(card->ctx, "invalid public key data: missing tag");
|
2006-02-12 18:30:53 +00:00
|
|
|
return SC_ERROR_INTERNAL;
|
2005-12-28 19:38:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
p = sc_asn1_find_tag(card->ctx, data, ilen, 0x81, &tlen);
|
|
|
|
if (p == NULL) {
|
2009-09-14 08:46:59 +00:00
|
|
|
sc_debug(card->ctx, "invalid public key data: missing modulus");
|
2005-12-28 19:38:55 +00:00
|
|
|
return SC_ERROR_INTERNAL;
|
|
|
|
}
|
|
|
|
pubkey->u.rsa.modulus.len = tlen;
|
|
|
|
pubkey->u.rsa.modulus.data = malloc(tlen);
|
|
|
|
if (pubkey->u.rsa.modulus.data == NULL)
|
|
|
|
return SC_ERROR_OUT_OF_MEMORY;
|
|
|
|
memcpy(pubkey->u.rsa.modulus.data, p, tlen);
|
|
|
|
|
|
|
|
p = sc_asn1_find_tag(card->ctx, data, ilen, 0x82, &tlen);
|
|
|
|
if (p == NULL) {
|
2009-09-14 08:46:59 +00:00
|
|
|
sc_debug(card->ctx, "invalid public key data: missing exponent");
|
2005-12-28 19:38:55 +00:00
|
|
|
return SC_ERROR_INTERNAL;
|
|
|
|
}
|
|
|
|
pubkey->u.rsa.exponent.len = tlen;
|
|
|
|
pubkey->u.rsa.exponent.data = malloc(tlen);
|
|
|
|
if (pubkey->u.rsa.exponent.data == NULL)
|
|
|
|
return SC_ERROR_OUT_OF_MEMORY;
|
|
|
|
memcpy(pubkey->u.rsa.exponent.data, p, tlen);
|
|
|
|
|
|
|
|
return SC_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2002-06-17 10:58:04 +00:00
|
|
|
static int
|
2006-01-23 22:02:07 +00:00
|
|
|
do_cardos_extract_pubkey(sc_card_t *card, int nr, u8 tag,
|
2002-06-17 10:58:04 +00:00
|
|
|
sc_pkcs15_bignum_t *bn)
|
|
|
|
{
|
|
|
|
u8 buf[256];
|
|
|
|
int r, count;
|
|
|
|
|
|
|
|
r = sc_read_record(card, nr, buf, sizeof(buf), SC_RECORD_BY_REC_NR);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
count = r - 4;
|
|
|
|
if (count <= 0 || buf[0] != tag || buf[1] != count + 2
|
2005-12-28 19:38:55 +00:00
|
|
|
|| buf[2] != count + 1 || buf[3] != 0)
|
2002-06-17 10:58:04 +00:00
|
|
|
return SC_ERROR_INTERNAL;
|
|
|
|
bn->len = count;
|
2002-10-19 16:51:37 +00:00
|
|
|
bn->data = (u8 *) malloc(count);
|
2005-12-28 19:38:55 +00:00
|
|
|
if (bn->data == NULL)
|
|
|
|
return SC_ERROR_OUT_OF_MEMORY;
|
2002-06-17 10:58:04 +00:00
|
|
|
memcpy(bn->data, buf + 4, count);
|
2005-12-28 19:38:55 +00:00
|
|
|
return SC_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int cardos_extract_pubkey(sc_card_t *card, sc_pkcs15_pubkey_t *pubkey,
|
|
|
|
sc_file_t *tfile, int use_ext_rsa)
|
|
|
|
{
|
|
|
|
int r;
|
|
|
|
|
|
|
|
memset(pubkey, 0, sizeof(*pubkey));
|
|
|
|
|
|
|
|
r = sc_select_file(card, &tfile->path, NULL);
|
|
|
|
if (r != SC_SUCCESS)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
if (use_ext_rsa == 0) {
|
2006-01-23 22:02:07 +00:00
|
|
|
r = do_cardos_extract_pubkey(card, 1, 0x10, &pubkey->u.rsa.modulus);
|
2005-12-28 19:38:55 +00:00
|
|
|
if (r != SC_SUCCESS)
|
|
|
|
return r;
|
2006-01-23 22:02:07 +00:00
|
|
|
r = do_cardos_extract_pubkey(card, 2, 0x11, &pubkey->u.rsa.exponent);
|
2005-12-28 19:38:55 +00:00
|
|
|
} else {
|
|
|
|
u8 *buf;
|
|
|
|
|
|
|
|
buf = malloc(tfile->size);
|
|
|
|
if (buf == NULL)
|
|
|
|
return SC_ERROR_OUT_OF_MEMORY;
|
|
|
|
r = sc_read_binary(card, 0, buf, tfile->size, 0);
|
|
|
|
if (r > 0)
|
|
|
|
r = parse_ext_pubkey_file(card, buf, (size_t)r, pubkey);
|
|
|
|
free(buf);
|
|
|
|
}
|
|
|
|
|
|
|
|
pubkey->algorithm = SC_ALGORITHM_RSA;
|
|
|
|
|
|
|
|
return r;
|
2002-06-17 10:58:04 +00:00
|
|
|
}
|
|
|
|
|
2006-01-23 21:48:08 +00:00
|
|
|
static struct sc_pkcs15init_operations sc_pkcs15init_cardos_operations = {
|
|
|
|
cardos_erase,
|
2005-08-14 22:33:43 +00:00
|
|
|
NULL, /* init_card */
|
2006-01-23 21:48:08 +00:00
|
|
|
cardos_create_dir,
|
2005-08-14 22:33:43 +00:00
|
|
|
NULL, /* create_domain */
|
2006-01-23 21:48:08 +00:00
|
|
|
cardos_select_pin_reference,
|
|
|
|
cardos_create_pin,
|
|
|
|
cardos_select_key_reference,
|
|
|
|
cardos_create_key,
|
|
|
|
cardos_store_key,
|
|
|
|
cardos_generate_key,
|
2005-08-14 22:33:43 +00:00
|
|
|
NULL, NULL, /* encode private/public key */
|
|
|
|
NULL, /* finalize_card */
|
2005-08-22 09:20:13 +00:00
|
|
|
NULL /* delete_object */
|
2005-08-10 21:31:18 +00:00
|
|
|
};
|
2003-10-13 20:41:00 +00:00
|
|
|
|
2003-10-14 08:17:59 +00:00
|
|
|
struct sc_pkcs15init_operations *
|
2006-01-23 21:48:08 +00:00
|
|
|
sc_pkcs15init_get_cardos_ops(void)
|
2003-10-13 20:41:00 +00:00
|
|
|
{
|
2006-01-23 21:48:08 +00:00
|
|
|
return &sc_pkcs15init_cardos_operations;
|
2003-10-13 20:41:00 +00:00
|
|
|
}
|