2007-11-12 10:18:54 +00:00
|
|
|
/*
|
|
|
|
* 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
|
|
|
|
*/
|
|
|
|
|
2012-12-10 16:00:11 +00:00
|
|
|
/* Initially written by David Mattes <david.mattes@boeing.com> */
|
|
|
|
/* Support for multiple key containers by Lukas Wunner <lukas@wunner.de> */
|
2007-11-13 07:52:43 +00:00
|
|
|
|
2015-04-22 21:55:33 +00:00
|
|
|
#if HAVE_CONFIG_H
|
2010-03-04 08:14:36 +00:00
|
|
|
#include "config.h"
|
2015-04-22 21:55:33 +00:00
|
|
|
#endif
|
2010-03-04 08:14:36 +00:00
|
|
|
|
2007-11-12 10:18:54 +00:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
|
2010-03-04 08:14:36 +00:00
|
|
|
#include "internal.h"
|
|
|
|
#include "pkcs15.h"
|
|
|
|
|
2007-11-12 10:18:54 +00:00
|
|
|
#define MANU_ID "Gemplus"
|
|
|
|
#define APPLET_NAME "GemSAFE V1"
|
|
|
|
#define DRIVER_SERIAL_NUMBER "v0.9"
|
2012-12-10 16:00:11 +00:00
|
|
|
#define GEMSAFE_APP_PATH "3F001600"
|
|
|
|
#define GEMSAFE_PATH "3F0016000004"
|
|
|
|
|
|
|
|
/* Apparently, the Applet max read "quanta" is 248 bytes
|
|
|
|
* Gemalto ClassicClient reads files in chunks of 238 bytes
|
|
|
|
*/
|
|
|
|
#define GEMSAFE_READ_QUANTUM 248
|
|
|
|
#define GEMSAFE_MAX_OBJLEN 28672
|
2007-11-12 10:18:54 +00:00
|
|
|
|
|
|
|
static int
|
|
|
|
sc_pkcs15emu_add_cert(sc_pkcs15_card_t *p15card,
|
|
|
|
int type, int authority,
|
|
|
|
const sc_path_t *path,
|
|
|
|
const sc_pkcs15_id_t *id,
|
|
|
|
const char *label, int obj_flags);
|
|
|
|
|
|
|
|
static int
|
|
|
|
sc_pkcs15emu_add_pin(sc_pkcs15_card_t *p15card,
|
|
|
|
const sc_pkcs15_id_t *id, const char *label,
|
|
|
|
const sc_path_t *path, int ref, int type,
|
|
|
|
unsigned int min_length,
|
|
|
|
unsigned int max_length,
|
|
|
|
int flags, int tries_left, const char pad_char, int obj_flags);
|
|
|
|
|
|
|
|
static int
|
|
|
|
sc_pkcs15emu_add_prkey(sc_pkcs15_card_t *p15card,
|
|
|
|
const sc_pkcs15_id_t *id,
|
|
|
|
const char *label,
|
|
|
|
int type, unsigned int modulus_length, int usage,
|
|
|
|
const sc_path_t *path, int ref,
|
|
|
|
const sc_pkcs15_id_t *auth_id, int obj_flags);
|
|
|
|
|
|
|
|
typedef struct cdata_st {
|
2012-12-10 16:00:11 +00:00
|
|
|
char *label;
|
2007-11-12 10:18:54 +00:00
|
|
|
int authority;
|
|
|
|
const char *path;
|
2012-12-10 16:00:11 +00:00
|
|
|
size_t index;
|
|
|
|
size_t count;
|
2007-11-12 10:18:54 +00:00
|
|
|
const char *id;
|
|
|
|
int obj_flags;
|
|
|
|
} cdata;
|
|
|
|
|
2012-12-10 16:00:11 +00:00
|
|
|
const unsigned int gemsafe_cert_max = 12;
|
|
|
|
|
|
|
|
cdata gemsafe_cert[] = {
|
|
|
|
{"DS certificate #1", 0, GEMSAFE_PATH, 0, 0, "45", SC_PKCS15_CO_FLAG_MODIFIABLE},
|
|
|
|
{"DS certificate #2", 0, GEMSAFE_PATH, 0, 0, "46", SC_PKCS15_CO_FLAG_MODIFIABLE},
|
|
|
|
{"DS certificate #3", 0, GEMSAFE_PATH, 0, 0, "47", SC_PKCS15_CO_FLAG_MODIFIABLE},
|
|
|
|
{"DS certificate #4", 0, GEMSAFE_PATH, 0, 0, "48", SC_PKCS15_CO_FLAG_MODIFIABLE},
|
|
|
|
{"DS certificate #5", 0, GEMSAFE_PATH, 0, 0, "49", SC_PKCS15_CO_FLAG_MODIFIABLE},
|
|
|
|
{"DS certificate #6", 0, GEMSAFE_PATH, 0, 0, "50", SC_PKCS15_CO_FLAG_MODIFIABLE},
|
|
|
|
{"DS certificate #7", 0, GEMSAFE_PATH, 0, 0, "51", SC_PKCS15_CO_FLAG_MODIFIABLE},
|
|
|
|
{"DS certificate #8", 0, GEMSAFE_PATH, 0, 0, "52", SC_PKCS15_CO_FLAG_MODIFIABLE},
|
|
|
|
{"DS certificate #9", 0, GEMSAFE_PATH, 0, 0, "53", SC_PKCS15_CO_FLAG_MODIFIABLE},
|
|
|
|
{"DS certificate #10", 0, GEMSAFE_PATH, 0, 0, "54", SC_PKCS15_CO_FLAG_MODIFIABLE},
|
|
|
|
{"DS certificate #11", 0, GEMSAFE_PATH, 0, 0, "55", SC_PKCS15_CO_FLAG_MODIFIABLE},
|
|
|
|
{"DS certificate #12", 0, GEMSAFE_PATH, 0, 0, "56", SC_PKCS15_CO_FLAG_MODIFIABLE},
|
2007-11-12 10:18:54 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
typedef struct pdata_st {
|
2012-12-10 16:00:11 +00:00
|
|
|
const u8 atr[SC_MAX_ATR_SIZE];
|
|
|
|
const size_t atr_len;
|
2007-11-12 10:18:54 +00:00
|
|
|
const char *id;
|
|
|
|
const char *label;
|
|
|
|
const char *path;
|
2012-12-10 16:00:11 +00:00
|
|
|
const int ref;
|
|
|
|
const int type;
|
|
|
|
const unsigned int maxlen;
|
|
|
|
const unsigned int minlen;
|
|
|
|
const int flags;
|
|
|
|
const int tries_left;
|
2007-11-12 10:18:54 +00:00
|
|
|
const char pad_char;
|
2012-12-10 16:00:11 +00:00
|
|
|
const int obj_flags;
|
2007-11-13 07:52:43 +00:00
|
|
|
} pindata;
|
2007-11-12 10:18:54 +00:00
|
|
|
|
2012-12-10 16:00:11 +00:00
|
|
|
const unsigned int gemsafe_pin_max = 2;
|
|
|
|
|
2007-11-12 10:18:54 +00:00
|
|
|
const pindata gemsafe_pin[] = {
|
2012-12-10 16:00:11 +00:00
|
|
|
/* ATR-specific PIN policies, first match found is used: */
|
|
|
|
{ {0x3B, 0x7D, 0x96, 0x00, 0x00, 0x80, 0x31, 0x80, 0x65,
|
|
|
|
0xB0, 0x83, 0x11, 0x48, 0xC8, 0x83, 0x00, 0x90, 0x00}, 18,
|
|
|
|
"01", "DS pin", GEMSAFE_PATH, 0x01, SC_PKCS15_PIN_TYPE_ASCII_NUMERIC,
|
|
|
|
8, 4, SC_PKCS15_PIN_FLAG_NEEDS_PADDING | SC_PKCS15_PIN_FLAG_LOCAL,
|
|
|
|
3, 0x00, SC_PKCS15_CO_FLAG_MODIFIABLE | SC_PKCS15_CO_FLAG_PRIVATE },
|
|
|
|
/* default PIN policy comes last: */
|
|
|
|
{ { 0 }, 0,
|
|
|
|
"01", "DS pin", GEMSAFE_PATH, 0x01, SC_PKCS15_PIN_TYPE_BCD,
|
2007-11-13 07:52:43 +00:00
|
|
|
16, 6, SC_PKCS15_PIN_FLAG_NEEDS_PADDING | SC_PKCS15_PIN_FLAG_LOCAL,
|
2012-12-10 16:00:11 +00:00
|
|
|
3, 0xFF, SC_PKCS15_CO_FLAG_MODIFIABLE | SC_PKCS15_CO_FLAG_PRIVATE }
|
2007-11-12 10:18:54 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
typedef struct prdata_st {
|
|
|
|
const char *id;
|
2012-12-10 16:00:11 +00:00
|
|
|
char *label;
|
2007-11-12 10:18:54 +00:00
|
|
|
unsigned int modulus_len;
|
|
|
|
int usage;
|
|
|
|
const char *path;
|
|
|
|
int ref;
|
|
|
|
const char *auth_id;
|
|
|
|
int obj_flags;
|
|
|
|
} prdata;
|
|
|
|
|
|
|
|
#define USAGE_NONREP SC_PKCS15_PRKEY_USAGE_NONREPUDIATION
|
|
|
|
#define USAGE_KE SC_PKCS15_PRKEY_USAGE_ENCRYPT | \
|
|
|
|
SC_PKCS15_PRKEY_USAGE_DECRYPT | \
|
|
|
|
SC_PKCS15_PRKEY_USAGE_WRAP | \
|
|
|
|
SC_PKCS15_PRKEY_USAGE_UNWRAP
|
|
|
|
#define USAGE_AUT SC_PKCS15_PRKEY_USAGE_ENCRYPT | \
|
|
|
|
SC_PKCS15_PRKEY_USAGE_DECRYPT | \
|
|
|
|
SC_PKCS15_PRKEY_USAGE_WRAP | \
|
|
|
|
SC_PKCS15_PRKEY_USAGE_UNWRAP | \
|
|
|
|
SC_PKCS15_PRKEY_USAGE_SIGN
|
|
|
|
|
2012-12-10 16:00:11 +00:00
|
|
|
prdata gemsafe_prkeys[] = {
|
|
|
|
{ "45", "DS key #1", 1024, USAGE_AUT, GEMSAFE_PATH, 0x03, "01", SC_PKCS15_CO_FLAG_PRIVATE},
|
|
|
|
{ "46", "DS key #2", 1024, USAGE_AUT, GEMSAFE_PATH, 0x04, "01", SC_PKCS15_CO_FLAG_PRIVATE},
|
|
|
|
{ "47", "DS key #3", 1024, USAGE_AUT, GEMSAFE_PATH, 0x05, "01", SC_PKCS15_CO_FLAG_PRIVATE},
|
|
|
|
{ "48", "DS key #4", 1024, USAGE_AUT, GEMSAFE_PATH, 0x06, "01", SC_PKCS15_CO_FLAG_PRIVATE},
|
|
|
|
{ "49", "DS key #5", 1024, USAGE_AUT, GEMSAFE_PATH, 0x07, "01", SC_PKCS15_CO_FLAG_PRIVATE},
|
|
|
|
{ "50", "DS key #6", 1024, USAGE_AUT, GEMSAFE_PATH, 0x08, "01", SC_PKCS15_CO_FLAG_PRIVATE},
|
|
|
|
{ "51", "DS key #7", 1024, USAGE_AUT, GEMSAFE_PATH, 0x09, "01", SC_PKCS15_CO_FLAG_PRIVATE},
|
|
|
|
{ "52", "DS key #8", 1024, USAGE_AUT, GEMSAFE_PATH, 0x0a, "01", SC_PKCS15_CO_FLAG_PRIVATE},
|
|
|
|
{ "53", "DS key #9", 1024, USAGE_AUT, GEMSAFE_PATH, 0x0b, "01", SC_PKCS15_CO_FLAG_PRIVATE},
|
|
|
|
{ "54", "DS key #10", 1024, USAGE_AUT, GEMSAFE_PATH, 0x0c, "01", SC_PKCS15_CO_FLAG_PRIVATE},
|
|
|
|
{ "55", "DS key #11", 1024, USAGE_AUT, GEMSAFE_PATH, 0x0d, "01", SC_PKCS15_CO_FLAG_PRIVATE},
|
|
|
|
{ "56", "DS key #12", 1024, USAGE_AUT, GEMSAFE_PATH, 0x0e, "01", SC_PKCS15_CO_FLAG_PRIVATE},
|
2007-11-12 10:18:54 +00:00
|
|
|
};
|
|
|
|
|
2012-12-10 16:00:11 +00:00
|
|
|
static int gemsafe_get_cert_len(sc_card_t *card)
|
2007-11-12 10:18:54 +00:00
|
|
|
{
|
|
|
|
int r;
|
2012-12-10 16:00:11 +00:00
|
|
|
u8 ibuf[GEMSAFE_MAX_OBJLEN];
|
|
|
|
u8 *iptr;
|
|
|
|
struct sc_path path;
|
2007-11-12 10:18:54 +00:00
|
|
|
struct sc_file *file;
|
|
|
|
size_t objlen, certlen;
|
2012-12-10 16:00:11 +00:00
|
|
|
unsigned int ind, i=0;
|
2007-11-12 10:18:54 +00:00
|
|
|
|
2012-12-10 16:00:11 +00:00
|
|
|
sc_format_path(GEMSAFE_PATH, &path);
|
|
|
|
r = sc_select_file(card, &path, &file);
|
|
|
|
if (r != SC_SUCCESS || !file)
|
|
|
|
return SC_ERROR_INTERNAL;
|
2020-05-09 23:01:34 +00:00
|
|
|
sc_file_free(file);
|
2007-11-12 10:18:54 +00:00
|
|
|
|
|
|
|
/* Initial read */
|
2012-12-10 16:00:11 +00:00
|
|
|
r = sc_read_binary(card, 0, ibuf, GEMSAFE_READ_QUANTUM, 0);
|
2007-11-13 07:52:43 +00:00
|
|
|
if (r < 0)
|
2012-12-10 16:00:11 +00:00
|
|
|
return SC_ERROR_INTERNAL;
|
2007-11-12 10:18:54 +00:00
|
|
|
|
|
|
|
/* Actual stored object size is encoded in first 2 bytes
|
|
|
|
* (allocated EF space is much greater!)
|
|
|
|
*/
|
|
|
|
objlen = (((size_t) ibuf[0]) << 8) | ibuf[1];
|
2017-03-14 19:02:30 +00:00
|
|
|
sc_log(card->ctx, "Stored object is of size: %"SC_FORMAT_LEN_SIZE_T"u",
|
|
|
|
objlen);
|
2012-12-10 16:00:11 +00:00
|
|
|
if (objlen < 1 || objlen > GEMSAFE_MAX_OBJLEN) {
|
2017-03-14 19:02:30 +00:00
|
|
|
sc_log(card->ctx, "Invalid object size: %"SC_FORMAT_LEN_SIZE_T"u",
|
|
|
|
objlen);
|
2012-12-10 16:00:11 +00:00
|
|
|
return SC_ERROR_INTERNAL;
|
2007-11-12 10:18:54 +00:00
|
|
|
}
|
|
|
|
|
2012-12-10 16:00:11 +00:00
|
|
|
/* It looks like the first thing in the block is a table of
|
|
|
|
* which keys are allocated. The table is small and is in the
|
|
|
|
* first 248 bytes. Example for a card with 10 key containers:
|
|
|
|
* 01 f0 00 03 03 b0 00 03 <= 1st key unallocated
|
|
|
|
* 01 f0 00 04 03 b0 00 04 <= 2nd key unallocated
|
|
|
|
* 01 fe 14 00 05 03 b0 00 05 <= 3rd key allocated
|
|
|
|
* 01 fe 14 01 06 03 b0 00 06 <= 4th key allocated
|
|
|
|
* 01 f0 00 07 03 b0 00 07 <= 5th key unallocated
|
|
|
|
* ...
|
|
|
|
* 01 f0 00 0c 03 b0 00 0c <= 10th key unallocated
|
|
|
|
* For allocated keys, the fourth byte seems to indicate the
|
|
|
|
* default key and the fifth byte indicates the key_ref of
|
|
|
|
* the private key.
|
2008-08-20 15:17:59 +00:00
|
|
|
*/
|
|
|
|
ind = 2; /* skip length */
|
2018-05-25 21:34:14 +00:00
|
|
|
while (ibuf[ind] == 0x01 && i < gemsafe_cert_max) {
|
2008-08-20 15:17:59 +00:00
|
|
|
if (ibuf[ind+1] == 0xFE) {
|
2012-12-10 16:00:11 +00:00
|
|
|
gemsafe_prkeys[i].ref = ibuf[ind+4];
|
2015-03-29 13:55:10 +00:00
|
|
|
sc_log(card->ctx, "Key container %d is allocated and uses key_ref %d",
|
|
|
|
i+1, gemsafe_prkeys[i].ref);
|
2012-12-10 16:00:11 +00:00
|
|
|
ind += 9;
|
2015-03-29 13:55:10 +00:00
|
|
|
}
|
|
|
|
else {
|
2012-12-10 16:00:11 +00:00
|
|
|
gemsafe_prkeys[i].label = NULL;
|
|
|
|
gemsafe_cert[i].label = NULL;
|
2015-03-29 13:55:10 +00:00
|
|
|
sc_log(card->ctx, "Key container %d is unallocated", i+1);
|
2012-12-10 16:00:11 +00:00
|
|
|
ind += 8;
|
2008-08-20 15:17:59 +00:00
|
|
|
}
|
2012-12-10 16:00:11 +00:00
|
|
|
i++;
|
2008-08-20 15:17:59 +00:00
|
|
|
}
|
|
|
|
|
2012-12-10 16:00:11 +00:00
|
|
|
/* Delete additional key containers from the data structures if
|
2018-04-14 17:38:34 +00:00
|
|
|
* this card can't accommodate them.
|
2012-12-10 16:00:11 +00:00
|
|
|
*/
|
|
|
|
for (; i < gemsafe_cert_max; i++) {
|
|
|
|
gemsafe_prkeys[i].label = NULL;
|
|
|
|
gemsafe_cert[i].label = NULL;
|
|
|
|
}
|
2007-11-12 10:18:54 +00:00
|
|
|
|
2012-12-10 16:00:11 +00:00
|
|
|
/* Read entire file, then dissect in memory.
|
|
|
|
* Gemalto ClassicClient seems to do it the same way.
|
|
|
|
*/
|
|
|
|
iptr = ibuf + GEMSAFE_READ_QUANTUM;
|
|
|
|
while ((size_t)(iptr - ibuf) < objlen) {
|
|
|
|
r = sc_read_binary(card, iptr - ibuf, iptr,
|
|
|
|
MIN(GEMSAFE_READ_QUANTUM, objlen - (iptr - ibuf)), 0);
|
2007-11-12 10:18:54 +00:00
|
|
|
if (r < 0) {
|
2015-03-29 13:55:10 +00:00
|
|
|
sc_log(card->ctx, "Could not read cert object");
|
2012-12-10 16:00:11 +00:00
|
|
|
return SC_ERROR_INTERNAL;
|
2007-11-12 10:18:54 +00:00
|
|
|
}
|
2012-12-10 16:00:11 +00:00
|
|
|
iptr += GEMSAFE_READ_QUANTUM;
|
2007-11-12 10:18:54 +00:00
|
|
|
}
|
|
|
|
|
2012-12-10 16:00:11 +00:00
|
|
|
/* Search buffer for certificates, they start with 0x3082. */
|
|
|
|
i = 0;
|
|
|
|
while (ind < objlen - 1) {
|
|
|
|
if (ibuf[ind] == 0x30 && ibuf[ind+1] == 0x82) {
|
|
|
|
/* Find next allocated key container */
|
|
|
|
while (i < gemsafe_cert_max && gemsafe_cert[i].label == NULL)
|
|
|
|
i++;
|
|
|
|
if (i == gemsafe_cert_max) {
|
2015-03-29 13:55:10 +00:00
|
|
|
sc_log(card->ctx, "Warning: Found orphaned certificate at offset %d", ind);
|
2012-12-10 16:00:11 +00:00
|
|
|
return SC_SUCCESS;
|
|
|
|
}
|
|
|
|
/* DER cert len is encoded this way */
|
2015-09-17 19:14:49 +00:00
|
|
|
if (ind+3 >= sizeof ibuf)
|
|
|
|
return SC_ERROR_INVALID_DATA;
|
2012-12-10 16:00:11 +00:00
|
|
|
certlen = ((((size_t) ibuf[ind+2]) << 8) | ibuf[ind+3]) + 4;
|
2017-03-14 19:02:30 +00:00
|
|
|
sc_log(card->ctx,
|
|
|
|
"Found certificate of key container %d at offset %d, len %"SC_FORMAT_LEN_SIZE_T"u",
|
|
|
|
i+1, ind, certlen);
|
2012-12-10 16:00:11 +00:00
|
|
|
gemsafe_cert[i].index = ind;
|
|
|
|
gemsafe_cert[i].count = certlen;
|
|
|
|
ind += certlen;
|
|
|
|
i++;
|
|
|
|
} else
|
|
|
|
ind++;
|
|
|
|
}
|
2007-11-12 10:18:54 +00:00
|
|
|
|
2012-12-10 16:00:11 +00:00
|
|
|
/* Delete additional key containers from the data structures if
|
|
|
|
* they're missing on the card.
|
|
|
|
*/
|
|
|
|
for (; i < gemsafe_cert_max; i++) {
|
|
|
|
if (gemsafe_cert[i].label) {
|
2015-03-29 13:55:10 +00:00
|
|
|
sc_log(card->ctx, "Warning: Certificate of key container %d is missing", i+1);
|
2012-12-10 16:00:11 +00:00
|
|
|
gemsafe_prkeys[i].label = NULL;
|
|
|
|
gemsafe_cert[i].label = NULL;
|
|
|
|
}
|
|
|
|
}
|
2007-11-13 07:52:43 +00:00
|
|
|
|
2012-12-10 16:00:11 +00:00
|
|
|
return SC_SUCCESS;
|
2007-11-12 10:18:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int gemsafe_detect_card( sc_pkcs15_card_t *p15card)
|
|
|
|
{
|
2009-07-22 10:06:32 +00:00
|
|
|
if (strcmp(p15card->card->name, "GemSAFE V1"))
|
|
|
|
return SC_ERROR_WRONG_CARD;
|
|
|
|
|
2012-12-10 16:00:11 +00:00
|
|
|
return SC_SUCCESS;
|
2007-11-12 10:18:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int sc_pkcs15emu_gemsafeV1_init( sc_pkcs15_card_t *p15card)
|
|
|
|
{
|
2012-12-10 16:00:11 +00:00
|
|
|
int r;
|
|
|
|
unsigned int i;
|
|
|
|
struct sc_path path;
|
|
|
|
struct sc_file *file = NULL;
|
|
|
|
struct sc_card *card = p15card->card;
|
|
|
|
struct sc_apdu apdu;
|
|
|
|
u8 rbuf[SC_MAX_APDU_BUFFER_SIZE];
|
|
|
|
|
2015-03-29 13:55:10 +00:00
|
|
|
sc_log(p15card->card->ctx, "Setting pkcs15 parameters");
|
2012-12-10 16:00:11 +00:00
|
|
|
|
2020-06-10 10:35:19 +00:00
|
|
|
free(p15card->tokeninfo->label);
|
2019-05-28 15:46:44 +00:00
|
|
|
p15card->tokeninfo->label = strdup(APPLET_NAME);
|
2012-12-10 16:00:11 +00:00
|
|
|
if (!p15card->tokeninfo->label)
|
|
|
|
return SC_ERROR_INTERNAL;
|
|
|
|
|
2020-06-10 10:35:19 +00:00
|
|
|
free(p15card->tokeninfo->serial_number);
|
2019-05-28 15:46:44 +00:00
|
|
|
p15card->tokeninfo->serial_number = strdup(DRIVER_SERIAL_NUMBER);
|
2012-12-10 16:00:11 +00:00
|
|
|
if (!p15card->tokeninfo->serial_number)
|
|
|
|
return SC_ERROR_INTERNAL;
|
|
|
|
|
|
|
|
/* the GemSAFE applet version number */
|
|
|
|
sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xca, 0xdf, 0x03);
|
|
|
|
apdu.cla = 0x80;
|
|
|
|
apdu.resp = rbuf;
|
|
|
|
apdu.resplen = sizeof(rbuf);
|
2018-04-14 17:38:34 +00:00
|
|
|
/* Manual says Le=0x05, but should be 0x08 to return full version number */
|
2012-12-10 16:00:11 +00:00
|
|
|
apdu.le = 0x08;
|
|
|
|
apdu.lc = 0;
|
|
|
|
apdu.datalen = 0;
|
|
|
|
r = sc_transmit_apdu(card, &apdu);
|
2015-03-29 13:55:10 +00:00
|
|
|
LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
|
|
|
|
|
2012-12-10 16:00:11 +00:00
|
|
|
if (apdu.sw1 != 0x90 || apdu.sw2 != 0x00)
|
|
|
|
return SC_ERROR_INTERNAL;
|
|
|
|
if (r != SC_SUCCESS)
|
|
|
|
return SC_ERROR_INTERNAL;
|
|
|
|
|
|
|
|
/* the manufacturer ID, in this case GemPlus */
|
2020-06-10 10:35:19 +00:00
|
|
|
free(p15card->tokeninfo->manufacturer_id);
|
2019-05-28 15:46:44 +00:00
|
|
|
p15card->tokeninfo->manufacturer_id = strdup(MANU_ID);
|
2012-12-10 16:00:11 +00:00
|
|
|
if (!p15card->tokeninfo->manufacturer_id)
|
|
|
|
return SC_ERROR_INTERNAL;
|
|
|
|
|
|
|
|
/* determine allocated key containers and length of certificates */
|
|
|
|
r = gemsafe_get_cert_len(card);
|
|
|
|
if (r != SC_SUCCESS)
|
|
|
|
return SC_ERROR_INTERNAL;
|
|
|
|
|
|
|
|
/* set certs */
|
2015-03-29 13:55:10 +00:00
|
|
|
sc_log(p15card->card->ctx, "Setting certificates");
|
2012-12-10 16:00:11 +00:00
|
|
|
for (i = 0; i < gemsafe_cert_max; i++) {
|
|
|
|
struct sc_pkcs15_id p15Id;
|
|
|
|
struct sc_path path;
|
|
|
|
|
|
|
|
if (gemsafe_cert[i].label == NULL)
|
|
|
|
continue;
|
|
|
|
sc_format_path(gemsafe_cert[i].path, &path);
|
|
|
|
sc_pkcs15_format_id(gemsafe_cert[i].id, &p15Id);
|
|
|
|
path.index = gemsafe_cert[i].index;
|
|
|
|
path.count = gemsafe_cert[i].count;
|
|
|
|
sc_pkcs15emu_add_cert(p15card, SC_PKCS15_TYPE_CERT_X509,
|
|
|
|
gemsafe_cert[i].authority, &path, &p15Id,
|
|
|
|
gemsafe_cert[i].label, gemsafe_cert[i].obj_flags);
|
|
|
|
}
|
2007-11-12 10:18:54 +00:00
|
|
|
|
2012-12-10 16:00:11 +00:00
|
|
|
/* set gemsafe_pin */
|
2015-03-29 13:55:10 +00:00
|
|
|
sc_log(p15card->card->ctx, "Setting PIN");
|
2012-12-10 16:00:11 +00:00
|
|
|
for (i=0; i < gemsafe_pin_max; i++) {
|
|
|
|
struct sc_pkcs15_id p15Id;
|
|
|
|
struct sc_path path;
|
|
|
|
|
|
|
|
sc_pkcs15_format_id(gemsafe_pin[i].id, &p15Id);
|
|
|
|
sc_format_path(gemsafe_pin[i].path, &path);
|
|
|
|
if (gemsafe_pin[i].atr_len == 0 ||
|
|
|
|
(gemsafe_pin[i].atr_len == p15card->card->atr.len &&
|
|
|
|
memcmp(p15card->card->atr.value, gemsafe_pin[i].atr,
|
|
|
|
p15card->card->atr.len) == 0)) {
|
|
|
|
sc_pkcs15emu_add_pin(p15card, &p15Id, gemsafe_pin[i].label,
|
|
|
|
&path, gemsafe_pin[i].ref, gemsafe_pin[i].type,
|
|
|
|
gemsafe_pin[i].minlen, gemsafe_pin[i].maxlen,
|
|
|
|
gemsafe_pin[i].flags, gemsafe_pin[i].tries_left,
|
|
|
|
gemsafe_pin[i].pad_char, gemsafe_pin[i].obj_flags);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/* set private keys */
|
2015-03-29 13:55:10 +00:00
|
|
|
sc_log(p15card->card->ctx, "Setting private keys");
|
2012-12-10 16:00:11 +00:00
|
|
|
for (i = 0; i < gemsafe_cert_max; i++) {
|
|
|
|
struct sc_pkcs15_id p15Id, authId, *pauthId;
|
|
|
|
struct sc_path path;
|
2015-03-29 13:55:10 +00:00
|
|
|
int key_ref = 0x03;
|
2012-12-10 16:00:11 +00:00
|
|
|
|
|
|
|
if (gemsafe_prkeys[i].label == NULL)
|
|
|
|
continue;
|
|
|
|
sc_pkcs15_format_id(gemsafe_prkeys[i].id, &p15Id);
|
|
|
|
if (gemsafe_prkeys[i].auth_id) {
|
|
|
|
sc_pkcs15_format_id(gemsafe_prkeys[i].auth_id, &authId);
|
|
|
|
pauthId = &authId;
|
|
|
|
} else
|
|
|
|
pauthId = NULL;
|
|
|
|
sc_format_path(gemsafe_prkeys[i].path, &path);
|
2015-03-29 13:55:10 +00:00
|
|
|
/*
|
2012-12-10 16:00:11 +00:00
|
|
|
* The key ref may be different for different sites;
|
|
|
|
* by adding flags=n where the low order 4 bits can be
|
|
|
|
* the key ref we can force it.
|
|
|
|
*/
|
|
|
|
if ( p15card->card->flags & 0x0F) {
|
|
|
|
key_ref = p15card->card->flags & 0x0F;
|
2018-11-22 08:31:29 +00:00
|
|
|
sc_log(p15card->card->ctx,
|
2012-12-10 16:00:11 +00:00
|
|
|
"Overriding key_ref %d with %d\n",
|
|
|
|
gemsafe_prkeys[i].ref, key_ref);
|
|
|
|
} else
|
|
|
|
key_ref = gemsafe_prkeys[i].ref;
|
|
|
|
sc_pkcs15emu_add_prkey(p15card, &p15Id, gemsafe_prkeys[i].label,
|
|
|
|
SC_PKCS15_TYPE_PRKEY_RSA,
|
|
|
|
gemsafe_prkeys[i].modulus_len, gemsafe_prkeys[i].usage,
|
|
|
|
&path, key_ref, pauthId,
|
|
|
|
gemsafe_prkeys[i].obj_flags);
|
|
|
|
}
|
2007-11-12 10:18:54 +00:00
|
|
|
|
2012-12-10 16:00:11 +00:00
|
|
|
/* select the application DF */
|
2015-03-29 13:55:10 +00:00
|
|
|
sc_log(p15card->card->ctx, "Selecting application DF");
|
2012-12-10 16:00:11 +00:00
|
|
|
sc_format_path(GEMSAFE_APP_PATH, &path);
|
|
|
|
r = sc_select_file(card, &path, &file);
|
|
|
|
if (r != SC_SUCCESS || !file)
|
|
|
|
return SC_ERROR_INTERNAL;
|
|
|
|
/* set the application DF */
|
2020-02-04 13:20:15 +00:00
|
|
|
sc_file_free(p15card->file_app);
|
2012-12-10 16:00:11 +00:00
|
|
|
p15card->file_app = file;
|
|
|
|
|
|
|
|
return SC_SUCCESS;
|
2007-11-12 10:18:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int sc_pkcs15emu_gemsafeV1_init_ex( sc_pkcs15_card_t *p15card,
|
2019-03-26 14:14:25 +00:00
|
|
|
struct sc_aid *aid)
|
2007-11-12 10:18:54 +00:00
|
|
|
{
|
2019-03-26 14:14:25 +00:00
|
|
|
if (gemsafe_detect_card(p15card))
|
|
|
|
return SC_ERROR_WRONG_CARD;
|
|
|
|
return sc_pkcs15emu_gemsafeV1_init(p15card);
|
2007-11-12 10:18:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static sc_pkcs15_df_t *
|
2008-03-17 15:09:16 +00:00
|
|
|
sc_pkcs15emu_get_df(sc_pkcs15_card_t *p15card, unsigned int type)
|
2007-11-12 10:18:54 +00:00
|
|
|
{
|
|
|
|
sc_pkcs15_df_t *df;
|
|
|
|
sc_file_t *file;
|
|
|
|
int created = 0;
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
for (df = p15card->df_list; df; df = df->next) {
|
|
|
|
if (df->type == type) {
|
|
|
|
if (created)
|
|
|
|
df->enumerated = 1;
|
|
|
|
return df;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(created == 0);
|
|
|
|
|
|
|
|
file = sc_file_new();
|
|
|
|
if (!file)
|
|
|
|
return NULL;
|
|
|
|
sc_format_path("11001101", &file->path);
|
2011-04-10 04:09:33 +00:00
|
|
|
sc_pkcs15_add_df(p15card, type, &file->path);
|
2007-11-12 10:18:54 +00:00
|
|
|
sc_file_free(file);
|
|
|
|
created++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
sc_pkcs15emu_add_object(sc_pkcs15_card_t *p15card, int type,
|
|
|
|
const char *label, void *data,
|
|
|
|
const sc_pkcs15_id_t *auth_id, int obj_flags)
|
|
|
|
{
|
|
|
|
sc_pkcs15_object_t *obj;
|
|
|
|
int df_type;
|
|
|
|
|
2009-05-12 14:27:39 +00:00
|
|
|
obj = calloc(1, sizeof(*obj));
|
2007-11-12 10:18:54 +00:00
|
|
|
|
|
|
|
obj->type = type;
|
|
|
|
obj->data = data;
|
2007-11-13 07:52:43 +00:00
|
|
|
|
2007-11-12 10:18:54 +00:00
|
|
|
if (label)
|
|
|
|
strncpy(obj->label, label, sizeof(obj->label)-1);
|
|
|
|
|
|
|
|
obj->flags = obj_flags;
|
|
|
|
if (auth_id)
|
|
|
|
obj->auth_id = *auth_id;
|
|
|
|
|
|
|
|
switch (type & SC_PKCS15_TYPE_CLASS_MASK) {
|
|
|
|
case SC_PKCS15_TYPE_AUTH:
|
|
|
|
df_type = SC_PKCS15_AODF;
|
|
|
|
break;
|
|
|
|
case SC_PKCS15_TYPE_PRKEY:
|
|
|
|
df_type = SC_PKCS15_PRKDF;
|
|
|
|
break;
|
|
|
|
case SC_PKCS15_TYPE_PUBKEY:
|
|
|
|
df_type = SC_PKCS15_PUKDF;
|
|
|
|
break;
|
|
|
|
case SC_PKCS15_TYPE_CERT:
|
|
|
|
df_type = SC_PKCS15_CDF;
|
|
|
|
break;
|
|
|
|
default:
|
2015-03-29 13:55:10 +00:00
|
|
|
sc_log(p15card->card->ctx, "Unknown PKCS15 object type %d", type);
|
2009-05-12 14:29:30 +00:00
|
|
|
free(obj);
|
2007-11-12 10:18:54 +00:00
|
|
|
return SC_ERROR_INVALID_ARGUMENTS;
|
|
|
|
}
|
|
|
|
|
|
|
|
obj->df = sc_pkcs15emu_get_df(p15card, df_type);
|
|
|
|
sc_pkcs15_add_object(p15card, obj);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
sc_pkcs15emu_add_pin(sc_pkcs15_card_t *p15card,
|
|
|
|
const sc_pkcs15_id_t *id, const char *label,
|
|
|
|
const sc_path_t *path, int ref, int type,
|
|
|
|
unsigned int min_length,
|
|
|
|
unsigned int max_length,
|
|
|
|
int flags, int tries_left, const char pad_char, int obj_flags)
|
|
|
|
{
|
2011-06-05 15:46:25 +00:00
|
|
|
sc_pkcs15_auth_info_t *info;
|
2007-11-13 07:52:43 +00:00
|
|
|
|
2009-05-12 14:27:39 +00:00
|
|
|
info = calloc(1, sizeof(*info));
|
2015-03-29 13:55:10 +00:00
|
|
|
if (!info)
|
|
|
|
LOG_FUNC_RETURN(p15card->card->ctx, SC_ERROR_OUT_OF_MEMORY);
|
|
|
|
|
2011-06-05 15:46:25 +00:00
|
|
|
info->auth_type = SC_PKCS15_PIN_AUTH_TYPE_PIN;
|
2012-11-09 13:33:23 +00:00
|
|
|
info->auth_method = SC_AC_CHV;
|
2007-11-12 10:18:54 +00:00
|
|
|
info->auth_id = *id;
|
2011-06-05 15:46:25 +00:00
|
|
|
info->attrs.pin.min_length = min_length;
|
|
|
|
info->attrs.pin.max_length = max_length;
|
|
|
|
info->attrs.pin.stored_length = max_length;
|
|
|
|
info->attrs.pin.type = type;
|
|
|
|
info->attrs.pin.reference = ref;
|
|
|
|
info->attrs.pin.flags = flags;
|
|
|
|
info->attrs.pin.pad_char = pad_char;
|
2007-11-12 10:18:54 +00:00
|
|
|
info->tries_left = tries_left;
|
2016-08-11 16:26:01 +00:00
|
|
|
info->logged_in = SC_PIN_STATE_UNKNOWN;
|
2007-11-13 07:52:43 +00:00
|
|
|
|
2007-11-12 10:18:54 +00:00
|
|
|
if (path)
|
2007-11-13 07:52:43 +00:00
|
|
|
info->path = *path;
|
|
|
|
|
2015-03-29 13:55:10 +00:00
|
|
|
return sc_pkcs15emu_add_object(p15card, SC_PKCS15_TYPE_AUTH_PIN, label, info, NULL, obj_flags);
|
2007-11-12 10:18:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
sc_pkcs15emu_add_cert(sc_pkcs15_card_t *p15card,
|
|
|
|
int type, int authority,
|
|
|
|
const sc_path_t *path,
|
|
|
|
const sc_pkcs15_id_t *id,
|
|
|
|
const char *label, int obj_flags)
|
|
|
|
{
|
|
|
|
sc_pkcs15_cert_info_t *info;
|
2009-05-12 14:27:39 +00:00
|
|
|
info = calloc(1, sizeof(*info));
|
2015-03-29 13:55:10 +00:00
|
|
|
if (!info)
|
|
|
|
{
|
|
|
|
LOG_FUNC_RETURN(p15card->card->ctx, SC_ERROR_OUT_OF_MEMORY);
|
|
|
|
}
|
2007-11-12 10:18:54 +00:00
|
|
|
info->id = *id;
|
|
|
|
info->authority = authority;
|
|
|
|
if (path)
|
|
|
|
info->path = *path;
|
|
|
|
|
|
|
|
return sc_pkcs15emu_add_object(p15card, type, label, info, NULL, obj_flags);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
sc_pkcs15emu_add_prkey(sc_pkcs15_card_t *p15card,
|
|
|
|
const sc_pkcs15_id_t *id,
|
|
|
|
const char *label,
|
|
|
|
int type, unsigned int modulus_length, int usage,
|
|
|
|
const sc_path_t *path, int ref,
|
|
|
|
const sc_pkcs15_id_t *auth_id, int obj_flags)
|
|
|
|
{
|
2007-11-13 07:52:43 +00:00
|
|
|
sc_pkcs15_prkey_info_t *info;
|
|
|
|
|
2009-05-12 14:27:39 +00:00
|
|
|
info = calloc(1, sizeof(*info));
|
2015-03-29 13:55:10 +00:00
|
|
|
if (!info)
|
|
|
|
{
|
|
|
|
LOG_FUNC_RETURN(p15card->card->ctx, SC_ERROR_OUT_OF_MEMORY);
|
|
|
|
}
|
2007-11-12 10:18:54 +00:00
|
|
|
info->id = *id;
|
|
|
|
info->modulus_length = modulus_length;
|
|
|
|
info->usage = usage;
|
|
|
|
info->native = 1;
|
|
|
|
info->access_flags = SC_PKCS15_PRKEY_ACCESS_SENSITIVE
|
|
|
|
| SC_PKCS15_PRKEY_ACCESS_ALWAYSSENSITIVE
|
|
|
|
| SC_PKCS15_PRKEY_ACCESS_NEVEREXTRACTABLE
|
|
|
|
| SC_PKCS15_PRKEY_ACCESS_LOCAL;
|
|
|
|
info->key_reference = ref;
|
2007-11-13 07:52:43 +00:00
|
|
|
|
2007-11-12 10:18:54 +00:00
|
|
|
if (path)
|
|
|
|
info->path = *path;
|
|
|
|
|
|
|
|
return sc_pkcs15emu_add_object(p15card, type, label,
|
|
|
|
info, auth_id, obj_flags);
|
|
|
|
}
|
|
|
|
|
2008-04-28 07:57:03 +00:00
|
|
|
/* SC_IMPLEMENT_DRIVER_VERSION("0.9.4") */
|