2001-11-06 18:34:19 +00:00
|
|
|
/*
|
2002-01-17 11:44:27 +00:00
|
|
|
* pkcs15.c: PKCS #15 general functions
|
2001-11-01 15:43:20 +00:00
|
|
|
*
|
2006-12-19 21:31:17 +00:00
|
|
|
* Copyright (C) 2001, 2002 Juha Yrjölä <juha.yrjola@iki.fi>
|
2001-11-06 18:34:19 +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,
|
2001-11-01 15:43:20 +00:00
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
2001-11-06 18:34:19 +00:00
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Lesser General Public License for more details.
|
2001-11-01 15:43:20 +00:00
|
|
|
*
|
2001-11-06 18:34:19 +00:00
|
|
|
* 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
|
2001-11-01 15:43:20 +00:00
|
|
|
*/
|
|
|
|
|
2002-04-05 10:44:51 +00:00
|
|
|
#include "internal.h"
|
|
|
|
#include "pkcs15.h"
|
|
|
|
#include "asn1.h"
|
2001-11-01 15:43:20 +00:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <assert.h>
|
2005-09-01 14:01:58 +00:00
|
|
|
#include <ltdl.h>
|
2001-11-01 15:43:20 +00:00
|
|
|
|
2006-09-24 14:05:06 +00:00
|
|
|
static const struct sc_asn1_entry c_asn1_twlabel[] = {
|
|
|
|
{ "twlabel", SC_ASN1_UTF8STRING, SC_ASN1_TAG_UTF8STRING, 0, NULL, NULL },
|
|
|
|
{ NULL, 0, 0, 0, NULL, NULL }
|
|
|
|
};
|
2003-04-03 09:46:26 +00:00
|
|
|
|
2002-01-13 23:56:13 +00:00
|
|
|
static const struct sc_asn1_entry c_asn1_toki[] = {
|
2006-01-20 20:52:36 +00:00
|
|
|
{ "version", SC_ASN1_INTEGER, SC_ASN1_TAG_INTEGER, 0, NULL, NULL },
|
2006-10-04 07:00:15 +00:00
|
|
|
{ "serialNumber", SC_ASN1_OCTET_STRING, SC_ASN1_TAG_OCTET_STRING, SC_ASN1_OPTIONAL, NULL, NULL },
|
2006-01-20 20:52:36 +00:00
|
|
|
{ "manufacturerID", SC_ASN1_UTF8STRING, SC_ASN1_TAG_UTF8STRING, SC_ASN1_OPTIONAL, NULL, NULL },
|
2005-08-05 16:24:35 +00:00
|
|
|
{ "label", SC_ASN1_UTF8STRING, SC_ASN1_CTX | 0, SC_ASN1_OPTIONAL, NULL, NULL },
|
2006-09-24 14:05:06 +00:00
|
|
|
/* XXX the Taiwanese ID card erroneously uses explicit tagging */
|
|
|
|
{ "label-tw", SC_ASN1_STRUCT, SC_ASN1_CTX | 0 | SC_ASN1_CONS, SC_ASN1_OPTIONAL, NULL, NULL },
|
2006-01-20 20:52:36 +00:00
|
|
|
{ "tokenflags", SC_ASN1_BIT_FIELD, SC_ASN1_TAG_BIT_STRING, 0, NULL, NULL },
|
2006-10-30 18:51:48 +00:00
|
|
|
{ "seInfo", SC_ASN1_SE_INFO, SC_ASN1_CONS | SC_ASN1_TAG_SEQUENCE, SC_ASN1_OPTIONAL, NULL, NULL },
|
2005-08-05 16:24:35 +00:00
|
|
|
{ "recordInfo", SC_ASN1_STRUCT, SC_ASN1_CONS | SC_ASN1_CTX | 1, SC_ASN1_OPTIONAL, NULL, NULL },
|
|
|
|
{ "supportedAlgorithms", SC_ASN1_STRUCT, SC_ASN1_CONS | SC_ASN1_CTX | 2, SC_ASN1_OPTIONAL, NULL, NULL },
|
|
|
|
{ "issuerId", SC_ASN1_UTF8STRING, SC_ASN1_CTX | 3, SC_ASN1_OPTIONAL, NULL, NULL },
|
|
|
|
{ "holderId", SC_ASN1_UTF8STRING, SC_ASN1_CTX | 4, SC_ASN1_OPTIONAL, NULL, NULL },
|
|
|
|
{ "lastUpdate", SC_ASN1_GENERALIZEDTIME, SC_ASN1_CTX | 5, SC_ASN1_OPTIONAL, NULL, NULL },
|
2006-01-20 20:52:36 +00:00
|
|
|
{ "preferredLanguage", SC_ASN1_PRINTABLESTRING, SC_ASN1_TAG_PRINTABLESTRING, SC_ASN1_OPTIONAL, NULL, NULL },
|
2005-08-05 16:24:35 +00:00
|
|
|
{ NULL, 0, 0, 0, NULL, NULL }
|
2002-01-13 23:56:13 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static const struct sc_asn1_entry c_asn1_tokeninfo[] = {
|
2006-01-20 20:52:36 +00:00
|
|
|
{ "TokenInfo", SC_ASN1_STRUCT, SC_ASN1_CONS | SC_ASN1_TAG_SEQUENCE, 0, NULL, NULL },
|
2005-08-05 16:24:35 +00:00
|
|
|
{ NULL, 0, 0, 0, NULL, NULL }
|
2002-01-13 23:56:13 +00:00
|
|
|
};
|
|
|
|
|
2006-03-07 07:22:58 +00:00
|
|
|
int sc_pkcs15_parse_tokeninfo(sc_context_t *ctx,
|
|
|
|
sc_pkcs15_tokeninfo_t *ti, const u8 *buf, size_t blen)
|
2001-11-01 15:43:20 +00:00
|
|
|
{
|
2003-05-30 08:54:42 +00:00
|
|
|
int r;
|
2001-12-16 18:46:32 +00:00
|
|
|
u8 serial[128];
|
2003-05-30 08:54:42 +00:00
|
|
|
size_t i;
|
2002-05-26 12:31:23 +00:00
|
|
|
size_t serial_len = sizeof(serial);
|
2003-05-14 16:29:47 +00:00
|
|
|
u8 mnfid[SC_PKCS15_MAX_LABEL_SIZE];
|
2006-03-07 07:22:58 +00:00
|
|
|
size_t mnfid_len = sizeof(mnfid);
|
2003-05-14 16:29:47 +00:00
|
|
|
u8 label[SC_PKCS15_MAX_LABEL_SIZE];
|
2002-05-26 12:31:23 +00:00
|
|
|
size_t label_len = sizeof(label);
|
2005-08-05 16:24:35 +00:00
|
|
|
u8 last_update[32];
|
|
|
|
size_t lupdate_len = sizeof(last_update) - 1;
|
2006-03-07 07:22:58 +00:00
|
|
|
size_t flags_len = sizeof(ti->flags);
|
2006-09-24 14:05:06 +00:00
|
|
|
struct sc_asn1_entry asn1_toki[14], asn1_tokeninfo[3], asn1_twlabel[3];
|
2005-08-24 15:54:43 +00:00
|
|
|
u8 preferred_language[3];
|
|
|
|
size_t lang_length = sizeof(preferred_language);
|
2001-11-01 15:43:20 +00:00
|
|
|
|
2005-08-05 16:24:35 +00:00
|
|
|
memset(last_update, 0, sizeof(last_update));
|
2006-09-24 14:05:06 +00:00
|
|
|
sc_copy_asn1_entry(c_asn1_twlabel, asn1_twlabel);
|
2002-01-13 23:56:13 +00:00
|
|
|
sc_copy_asn1_entry(c_asn1_toki, asn1_toki);
|
|
|
|
sc_copy_asn1_entry(c_asn1_tokeninfo, asn1_tokeninfo);
|
2006-09-24 14:05:06 +00:00
|
|
|
sc_format_asn1_entry(asn1_twlabel, label, &label_len, 0);
|
2006-03-07 07:22:58 +00:00
|
|
|
sc_format_asn1_entry(asn1_toki + 0, &ti->version, NULL, 0);
|
2002-01-13 23:56:13 +00:00
|
|
|
sc_format_asn1_entry(asn1_toki + 1, serial, &serial_len, 0);
|
|
|
|
sc_format_asn1_entry(asn1_toki + 2, mnfid, &mnfid_len, 0);
|
|
|
|
sc_format_asn1_entry(asn1_toki + 3, label, &label_len, 0);
|
2006-09-24 14:05:06 +00:00
|
|
|
sc_format_asn1_entry(asn1_toki + 4, asn1_twlabel, NULL, 0);
|
|
|
|
sc_format_asn1_entry(asn1_toki + 5, &ti->flags, &flags_len, 0);
|
2006-10-30 18:51:48 +00:00
|
|
|
sc_format_asn1_entry(asn1_toki + 6, &ti->seInfo, &ti->num_seInfo, 0);
|
2005-08-05 16:24:35 +00:00
|
|
|
sc_format_asn1_entry(asn1_toki + 7, NULL, NULL, 0);
|
|
|
|
sc_format_asn1_entry(asn1_toki + 8, NULL, NULL, 0);
|
|
|
|
sc_format_asn1_entry(asn1_toki + 9, NULL, NULL, 0);
|
2006-09-24 14:05:06 +00:00
|
|
|
sc_format_asn1_entry(asn1_toki + 10, NULL, NULL, 0);
|
|
|
|
sc_format_asn1_entry(asn1_toki + 11, last_update, &lupdate_len, 0);
|
|
|
|
sc_format_asn1_entry(asn1_toki + 12, preferred_language, &lang_length, 0);
|
2002-01-13 23:56:13 +00:00
|
|
|
sc_format_asn1_entry(asn1_tokeninfo, asn1_toki, NULL, 0);
|
|
|
|
|
2006-03-07 07:22:58 +00:00
|
|
|
r = sc_asn1_decode(ctx, asn1_tokeninfo, buf, blen, NULL, NULL);
|
2001-12-16 18:46:32 +00:00
|
|
|
if (r) {
|
2006-03-07 07:22:58 +00:00
|
|
|
sc_error(ctx, "ASN.1 parsing of EF(TokenInfo) failed: %s\n",
|
2003-01-20 09:56:27 +00:00
|
|
|
sc_strerror(r));
|
2006-03-07 07:22:58 +00:00
|
|
|
return r;
|
2005-01-03 17:20:17 +00:00
|
|
|
}
|
2006-03-07 07:22:58 +00:00
|
|
|
ti->version += 1;
|
|
|
|
ti->serial_number = (char *) malloc(serial_len * 2 + 1);
|
|
|
|
if (ti->serial_number == NULL)
|
|
|
|
return SC_ERROR_OUT_OF_MEMORY;
|
|
|
|
ti->serial_number[0] = 0;
|
2001-12-16 18:46:32 +00:00
|
|
|
for (i = 0; i < serial_len; i++) {
|
2001-11-01 15:43:20 +00:00
|
|
|
char byte[3];
|
|
|
|
|
2001-12-16 18:46:32 +00:00
|
|
|
sprintf(byte, "%02X", serial[i]);
|
2006-03-07 07:22:58 +00:00
|
|
|
strcat(ti->serial_number, byte);
|
2001-11-01 15:43:20 +00:00
|
|
|
}
|
2006-03-07 07:22:58 +00:00
|
|
|
if (ti->manufacturer_id == NULL) {
|
2002-03-19 10:04:11 +00:00
|
|
|
if (asn1_toki[2].flags & SC_ASN1_PRESENT)
|
2006-03-07 07:22:58 +00:00
|
|
|
ti->manufacturer_id = strdup((char *) mnfid);
|
2001-12-20 13:57:58 +00:00
|
|
|
else
|
2006-03-07 07:22:58 +00:00
|
|
|
ti->manufacturer_id = strdup("(unknown)");
|
|
|
|
if (ti->manufacturer_id == NULL)
|
|
|
|
return SC_ERROR_OUT_OF_MEMORY;
|
2001-12-20 13:57:58 +00:00
|
|
|
}
|
2006-03-07 07:22:58 +00:00
|
|
|
if (ti->label == NULL) {
|
2006-09-24 14:05:06 +00:00
|
|
|
if (asn1_toki[3].flags & SC_ASN1_PRESENT ||
|
|
|
|
asn1_toki[4].flags & SC_ASN1_PRESENT)
|
2006-03-07 07:22:58 +00:00
|
|
|
ti->label = strdup((char *) label);
|
2002-01-13 23:56:13 +00:00
|
|
|
else
|
2006-03-07 07:22:58 +00:00
|
|
|
ti->label = strdup("(unknown)");
|
|
|
|
if (ti->label == NULL)
|
|
|
|
return SC_ERROR_OUT_OF_MEMORY;
|
|
|
|
}
|
2006-09-24 14:05:06 +00:00
|
|
|
if (asn1_toki[11].flags & SC_ASN1_PRESENT) {
|
2006-03-07 07:22:58 +00:00
|
|
|
ti->last_update = strdup((char *)last_update);
|
|
|
|
if (ti->last_update == NULL)
|
|
|
|
return SC_ERROR_OUT_OF_MEMORY;
|
2002-01-13 23:56:13 +00:00
|
|
|
}
|
2006-09-24 14:05:06 +00:00
|
|
|
if (asn1_toki[12].flags & SC_ASN1_PRESENT) {
|
2005-08-24 15:54:43 +00:00
|
|
|
preferred_language[2] = 0;
|
2006-03-07 07:22:58 +00:00
|
|
|
ti->preferred_language = strdup((char *)preferred_language);
|
|
|
|
if (ti->preferred_language == NULL)
|
|
|
|
return SC_ERROR_OUT_OF_MEMORY;
|
2005-08-24 15:54:43 +00:00
|
|
|
}
|
2006-03-07 07:22:58 +00:00
|
|
|
return SC_SUCCESS;
|
2001-11-01 15:43:20 +00:00
|
|
|
}
|
|
|
|
|
2005-03-08 20:59:35 +00:00
|
|
|
int sc_pkcs15_encode_tokeninfo(sc_context_t *ctx,
|
2006-03-07 07:22:58 +00:00
|
|
|
sc_pkcs15_tokeninfo_t *ti,
|
2002-01-17 11:44:27 +00:00
|
|
|
u8 **buf, size_t *buflen)
|
2002-01-13 23:56:13 +00:00
|
|
|
{
|
2002-12-04 15:36:33 +00:00
|
|
|
int r;
|
2006-03-07 07:22:58 +00:00
|
|
|
int version = ti->version;
|
2005-08-18 13:55:36 +00:00
|
|
|
size_t serial_len, mnfid_len, label_len, flags_len, last_upd_len;
|
2002-01-13 23:56:13 +00:00
|
|
|
|
2006-09-24 14:05:06 +00:00
|
|
|
struct sc_asn1_entry asn1_toki[14], asn1_tokeninfo[2];
|
2002-01-13 23:56:13 +00:00
|
|
|
|
|
|
|
sc_copy_asn1_entry(c_asn1_toki, asn1_toki);
|
|
|
|
sc_copy_asn1_entry(c_asn1_tokeninfo, asn1_tokeninfo);
|
|
|
|
version--;
|
|
|
|
sc_format_asn1_entry(asn1_toki + 0, &version, NULL, 1);
|
2006-03-07 07:22:58 +00:00
|
|
|
if (ti->serial_number != NULL) {
|
2005-08-05 16:24:35 +00:00
|
|
|
u8 serial[128];
|
2005-08-18 13:55:36 +00:00
|
|
|
serial_len = 0;
|
2006-03-07 07:22:58 +00:00
|
|
|
if (strlen(ti->serial_number)/2 > sizeof(serial))
|
2002-01-13 23:56:13 +00:00
|
|
|
return SC_ERROR_BUFFER_TOO_SMALL;
|
2002-12-04 15:36:33 +00:00
|
|
|
serial_len = sizeof(serial);
|
2006-03-07 07:22:58 +00:00
|
|
|
if (sc_hex_to_bin(ti->serial_number, serial, &serial_len) < 0)
|
2002-12-04 15:36:33 +00:00
|
|
|
return SC_ERROR_INVALID_ARGUMENTS;
|
2002-01-13 23:56:13 +00:00
|
|
|
sc_format_asn1_entry(asn1_toki + 1, serial, &serial_len, 1);
|
2005-08-05 16:24:35 +00:00
|
|
|
} else
|
|
|
|
sc_format_asn1_entry(asn1_toki + 1, NULL, NULL, 0);
|
2006-03-07 07:22:58 +00:00
|
|
|
if (ti->manufacturer_id != NULL) {
|
|
|
|
mnfid_len = strlen(ti->manufacturer_id);
|
|
|
|
sc_format_asn1_entry(asn1_toki + 2, ti->manufacturer_id, &mnfid_len, 1);
|
2005-08-05 16:24:35 +00:00
|
|
|
} else
|
|
|
|
sc_format_asn1_entry(asn1_toki + 2, NULL, NULL, 0);
|
2006-03-07 07:22:58 +00:00
|
|
|
if (ti->label != NULL) {
|
|
|
|
label_len = strlen(ti->label);
|
|
|
|
sc_format_asn1_entry(asn1_toki + 3, ti->label, &label_len, 1);
|
2005-08-05 16:24:35 +00:00
|
|
|
} else
|
|
|
|
sc_format_asn1_entry(asn1_toki + 3, NULL, NULL, 0);
|
2006-03-07 07:22:58 +00:00
|
|
|
if (ti->flags) {
|
|
|
|
flags_len = sizeof(ti->flags);
|
2006-09-24 14:05:06 +00:00
|
|
|
sc_format_asn1_entry(asn1_toki + 5, &ti->flags, &flags_len, 1);
|
2005-08-05 16:24:35 +00:00
|
|
|
} else
|
2006-09-24 14:05:06 +00:00
|
|
|
sc_format_asn1_entry(asn1_toki + 5, NULL, NULL, 0);
|
2005-08-05 16:24:35 +00:00
|
|
|
sc_format_asn1_entry(asn1_toki + 6, NULL, NULL, 0);
|
|
|
|
sc_format_asn1_entry(asn1_toki + 7, NULL, NULL, 0);
|
|
|
|
sc_format_asn1_entry(asn1_toki + 8, NULL, NULL, 0);
|
|
|
|
sc_format_asn1_entry(asn1_toki + 9, NULL, NULL, 0);
|
2006-09-24 14:05:06 +00:00
|
|
|
sc_format_asn1_entry(asn1_toki + 10, NULL, NULL, 0);
|
2006-03-07 07:22:58 +00:00
|
|
|
if (ti->last_update != NULL) {
|
|
|
|
last_upd_len = strlen(ti->last_update);
|
2006-09-24 14:05:06 +00:00
|
|
|
sc_format_asn1_entry(asn1_toki + 11, ti->last_update, &last_upd_len, 1);
|
2005-08-05 16:24:35 +00:00
|
|
|
} else
|
2006-09-24 14:05:06 +00:00
|
|
|
sc_format_asn1_entry(asn1_toki + 11, NULL, NULL, 0);
|
|
|
|
sc_format_asn1_entry(asn1_toki + 12, NULL, NULL, 0);
|
2002-01-13 23:56:13 +00:00
|
|
|
sc_format_asn1_entry(asn1_tokeninfo, asn1_toki, NULL, 1);
|
|
|
|
|
2002-01-16 23:59:18 +00:00
|
|
|
r = sc_asn1_encode(ctx, asn1_tokeninfo, buf, buflen);
|
2002-01-13 23:56:13 +00:00
|
|
|
if (r) {
|
2003-08-25 14:21:18 +00:00
|
|
|
sc_error(ctx, "sc_asn1_encode() failed: %s\n", sc_strerror(r));
|
2002-01-13 23:56:13 +00:00
|
|
|
return r;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const struct sc_asn1_entry c_asn1_ddo[] = {
|
2006-10-02 13:46:00 +00:00
|
|
|
{ "oid", SC_ASN1_OBJECT, SC_ASN1_TAG_OBJECT, SC_ASN1_OPTIONAL, NULL, NULL },
|
2006-01-20 20:52:36 +00:00
|
|
|
{ "odfPath", SC_ASN1_PATH, SC_ASN1_CONS | SC_ASN1_TAG_SEQUENCE, SC_ASN1_OPTIONAL, NULL, NULL },
|
2005-08-05 16:24:35 +00:00
|
|
|
{ "tokenInfoPath", SC_ASN1_PATH, SC_ASN1_CONS | SC_ASN1_CTX | 0, SC_ASN1_OPTIONAL, NULL, NULL },
|
|
|
|
{ "unusedPath", SC_ASN1_PATH, SC_ASN1_CONS | SC_ASN1_CTX | 1, SC_ASN1_OPTIONAL, NULL, NULL },
|
|
|
|
{ NULL, 0, 0, 0, NULL, NULL }
|
2002-01-13 23:56:13 +00:00
|
|
|
};
|
|
|
|
|
2002-02-20 09:56:47 +00:00
|
|
|
static int parse_ddo(struct sc_pkcs15_card *p15card, const u8 * buf, size_t buflen)
|
2001-11-01 15:43:20 +00:00
|
|
|
{
|
2002-02-20 09:56:47 +00:00
|
|
|
struct sc_asn1_entry asn1_ddo[5];
|
2005-12-17 19:53:12 +00:00
|
|
|
sc_path_t odf_path, ti_path, us_path;
|
2001-12-16 18:46:32 +00:00
|
|
|
int r;
|
2002-02-20 09:56:47 +00:00
|
|
|
|
2002-01-13 23:56:13 +00:00
|
|
|
sc_copy_asn1_entry(c_asn1_ddo, asn1_ddo);
|
2002-02-20 09:56:47 +00:00
|
|
|
sc_format_asn1_entry(asn1_ddo + 1, &odf_path, NULL, 0);
|
|
|
|
sc_format_asn1_entry(asn1_ddo + 2, &ti_path, NULL, 0);
|
2005-12-17 19:53:12 +00:00
|
|
|
sc_format_asn1_entry(asn1_ddo + 3, &us_path, NULL, 0);
|
2002-02-20 09:56:47 +00:00
|
|
|
|
|
|
|
r = sc_asn1_decode(p15card->card->ctx, asn1_ddo, buf, buflen, NULL, NULL);
|
2001-12-16 18:46:32 +00:00
|
|
|
if (r) {
|
2003-08-25 14:21:18 +00:00
|
|
|
sc_error(p15card->card->ctx, "DDO parsing failed: %s\n",
|
2001-12-16 18:46:32 +00:00
|
|
|
sc_strerror(r));
|
|
|
|
return r;
|
|
|
|
}
|
2002-02-20 09:56:47 +00:00
|
|
|
if (asn1_ddo[1].flags & SC_ASN1_PRESENT) {
|
|
|
|
p15card->file_odf = sc_file_new();
|
|
|
|
if (p15card->file_odf == NULL)
|
|
|
|
goto mem_err;
|
|
|
|
p15card->file_odf->path = odf_path;
|
|
|
|
}
|
|
|
|
if (asn1_ddo[2].flags & SC_ASN1_PRESENT) {
|
|
|
|
p15card->file_tokeninfo = sc_file_new();
|
|
|
|
if (p15card->file_tokeninfo == NULL)
|
|
|
|
goto mem_err;
|
|
|
|
p15card->file_tokeninfo->path = ti_path;
|
2001-11-01 15:43:20 +00:00
|
|
|
}
|
2005-12-17 19:53:12 +00:00
|
|
|
if (asn1_ddo[3].flags & SC_ASN1_PRESENT) {
|
|
|
|
p15card->file_unusedspace = sc_file_new();
|
|
|
|
if (p15card->file_unusedspace == NULL)
|
|
|
|
goto mem_err;
|
|
|
|
p15card->file_unusedspace->path = us_path;
|
|
|
|
}
|
2001-11-01 15:43:20 +00:00
|
|
|
return 0;
|
2002-02-20 09:56:47 +00:00
|
|
|
mem_err:
|
|
|
|
if (p15card->file_odf != NULL) {
|
|
|
|
sc_file_free(p15card->file_odf);
|
|
|
|
p15card->file_odf = NULL;
|
|
|
|
}
|
|
|
|
if (p15card->file_tokeninfo != NULL) {
|
|
|
|
sc_file_free(p15card->file_tokeninfo);
|
|
|
|
p15card->file_tokeninfo = NULL;
|
|
|
|
}
|
2005-12-17 19:53:12 +00:00
|
|
|
if (p15card->file_unusedspace != NULL) {
|
|
|
|
sc_file_free(p15card->file_unusedspace);
|
|
|
|
p15card->file_unusedspace = NULL;
|
|
|
|
}
|
2002-02-20 09:56:47 +00:00
|
|
|
return SC_ERROR_OUT_OF_MEMORY;
|
2001-11-01 15:43:20 +00:00
|
|
|
}
|
|
|
|
|
2002-02-20 09:56:47 +00:00
|
|
|
#if 0
|
|
|
|
static int encode_ddo(struct sc_pkcs15_card *p15card, u8 **buf, size_t *buflen)
|
2002-01-13 23:56:13 +00:00
|
|
|
{
|
2002-02-20 09:56:47 +00:00
|
|
|
struct sc_asn1_entry asn1_ddo[5];
|
2002-01-13 23:56:13 +00:00
|
|
|
int r;
|
|
|
|
size_t label_len;
|
|
|
|
|
|
|
|
sc_copy_asn1_entry(c_asn1_ddo, asn1_ddo);
|
2002-02-20 09:56:47 +00:00
|
|
|
|
2002-01-13 23:56:13 +00:00
|
|
|
sc_format_asn1_entry(asn1_ddo + 1, &card->file_odf.path, NULL, 0);
|
|
|
|
sc_format_asn1_entry(asn1_ddo + 2, &card->file_tokeninfo.path, NULL, 0);
|
2002-02-20 09:56:47 +00:00
|
|
|
|
2002-01-13 23:56:13 +00:00
|
|
|
r = sc_asn1_encode(ctx, asn1_dir, buf, buflen);
|
|
|
|
if (r) {
|
2003-08-25 14:21:18 +00:00
|
|
|
sc_error(ctx, "sc_asn1_encode() failed: %s\n",
|
2002-01-13 23:56:13 +00:00
|
|
|
sc_strerror(r));
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
2002-02-20 09:56:47 +00:00
|
|
|
#endif
|
2002-01-13 23:56:13 +00:00
|
|
|
|
|
|
|
static const struct sc_asn1_entry c_asn1_odf[] = {
|
2005-08-05 16:24:35 +00:00
|
|
|
{ "privateKeys", SC_ASN1_STRUCT, SC_ASN1_CTX | 0 | SC_ASN1_CONS, 0, NULL, NULL },
|
|
|
|
{ "publicKeys", SC_ASN1_STRUCT, SC_ASN1_CTX | 1 | SC_ASN1_CONS, 0, NULL, NULL },
|
|
|
|
{ "trustedPublicKeys", SC_ASN1_STRUCT, SC_ASN1_CTX | 2 | SC_ASN1_CONS, 0, NULL, NULL },
|
2006-07-05 19:36:26 +00:00
|
|
|
{ "secretKeys", SC_ASN1_STRUCT, SC_ASN1_CTX | 3 | SC_ASN1_CONS, 0, NULL, NULL },
|
2005-08-05 16:24:35 +00:00
|
|
|
{ "certificates", SC_ASN1_STRUCT, SC_ASN1_CTX | 4 | SC_ASN1_CONS, 0, NULL, NULL },
|
|
|
|
{ "trustedCertificates", SC_ASN1_STRUCT, SC_ASN1_CTX | 5 | SC_ASN1_CONS, 0, NULL, NULL },
|
|
|
|
{ "usefulCertificates", SC_ASN1_STRUCT, SC_ASN1_CTX | 6 | SC_ASN1_CONS, 0, NULL, NULL },
|
|
|
|
{ "dataObjects", SC_ASN1_STRUCT, SC_ASN1_CTX | 7 | SC_ASN1_CONS, 0, NULL, NULL },
|
|
|
|
{ "authObjects", SC_ASN1_STRUCT, SC_ASN1_CTX | 8 | SC_ASN1_CONS, 0, NULL, NULL },
|
|
|
|
{ NULL, 0, 0, 0, NULL, NULL }
|
2002-01-13 23:56:13 +00:00
|
|
|
};
|
|
|
|
|
2005-08-05 16:24:35 +00:00
|
|
|
static const unsigned int odf_indexes[] = {
|
2002-01-13 23:56:13 +00:00
|
|
|
SC_PKCS15_PRKDF,
|
2002-03-03 00:32:28 +00:00
|
|
|
SC_PKCS15_PUKDF,
|
|
|
|
SC_PKCS15_PUKDF_TRUSTED,
|
2006-07-05 19:36:26 +00:00
|
|
|
SC_PKCS15_SKDF,
|
2002-01-13 23:56:13 +00:00
|
|
|
SC_PKCS15_CDF,
|
|
|
|
SC_PKCS15_CDF_TRUSTED,
|
2002-03-03 00:32:28 +00:00
|
|
|
SC_PKCS15_CDF_USEFUL,
|
2002-01-13 23:56:13 +00:00
|
|
|
SC_PKCS15_DODF,
|
|
|
|
SC_PKCS15_AODF,
|
|
|
|
};
|
|
|
|
|
2004-10-17 20:20:59 +00:00
|
|
|
static int parse_odf(const u8 * buf, size_t buflen, struct sc_pkcs15_card *card)
|
2001-11-01 15:43:20 +00:00
|
|
|
{
|
2001-12-16 18:46:32 +00:00
|
|
|
const u8 *p = buf;
|
2002-01-01 19:56:07 +00:00
|
|
|
size_t left = buflen;
|
2006-09-26 10:55:02 +00:00
|
|
|
int r, i, type;
|
2005-03-08 20:59:35 +00:00
|
|
|
sc_path_t path;
|
2002-01-10 12:33:56 +00:00
|
|
|
struct sc_asn1_entry asn1_obj_or_path[] = {
|
2005-08-05 16:24:35 +00:00
|
|
|
{ "path", SC_ASN1_PATH, SC_ASN1_CONS | SC_ASN1_SEQUENCE, 0, &path, NULL },
|
|
|
|
{ NULL, 0, 0, 0, NULL, NULL }
|
2001-12-19 21:58:04 +00:00
|
|
|
};
|
2006-07-13 20:35:17 +00:00
|
|
|
struct sc_asn1_entry asn1_odf[10];
|
2001-12-16 18:46:32 +00:00
|
|
|
|
2002-01-13 23:56:13 +00:00
|
|
|
sc_copy_asn1_entry(c_asn1_odf, asn1_odf);
|
|
|
|
for (i = 0; asn1_odf[i].name != NULL; i++)
|
|
|
|
sc_format_asn1_entry(asn1_odf + i, asn1_obj_or_path, NULL, 0);
|
2001-12-16 18:46:32 +00:00
|
|
|
while (left > 0) {
|
2002-01-07 18:23:34 +00:00
|
|
|
r = sc_asn1_decode_choice(card->card->ctx, asn1_odf, p, left, &p, &left);
|
2001-12-16 18:46:32 +00:00
|
|
|
if (r == SC_ERROR_ASN1_END_OF_CONTENTS)
|
|
|
|
break;
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2006-09-26 10:55:02 +00:00
|
|
|
type = r;
|
|
|
|
r = sc_pkcs15_make_absolute_path(&card->file_app->path, &path);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
r = sc_pkcs15_add_df(card, odf_indexes[type], &path, NULL);
|
2002-04-19 09:22:44 +00:00
|
|
|
if (r)
|
|
|
|
return r;
|
2002-01-13 23:56:13 +00:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-03-08 20:59:35 +00:00
|
|
|
int sc_pkcs15_encode_odf(sc_context_t *ctx,
|
2002-04-19 09:22:44 +00:00
|
|
|
struct sc_pkcs15_card *p15card,
|
|
|
|
u8 **buf, size_t *buflen)
|
2002-01-13 23:56:13 +00:00
|
|
|
{
|
2005-03-08 20:59:35 +00:00
|
|
|
sc_path_t path;
|
2002-01-13 23:56:13 +00:00
|
|
|
struct sc_asn1_entry asn1_obj_or_path[] = {
|
2005-08-05 16:24:35 +00:00
|
|
|
{ "path", SC_ASN1_PATH, SC_ASN1_CONS | SC_ASN1_SEQUENCE, 0, &path, NULL },
|
|
|
|
{ NULL, 0, 0, 0, NULL, NULL }
|
2002-01-13 23:56:13 +00:00
|
|
|
};
|
|
|
|
struct sc_asn1_entry *asn1_paths = NULL;
|
|
|
|
struct sc_asn1_entry *asn1_odf = NULL;
|
2002-04-19 09:22:44 +00:00
|
|
|
int df_count = 0, r, c = 0;
|
2002-01-13 23:56:13 +00:00
|
|
|
const int nr_indexes = sizeof(odf_indexes)/sizeof(odf_indexes[0]);
|
2002-04-19 09:22:44 +00:00
|
|
|
struct sc_pkcs15_df *df;
|
2002-01-13 23:56:13 +00:00
|
|
|
|
2002-04-19 09:22:44 +00:00
|
|
|
df = p15card->df_list;
|
|
|
|
while (df != NULL) {
|
|
|
|
df_count++;
|
|
|
|
df = df->next;
|
|
|
|
};
|
2002-01-17 11:44:27 +00:00
|
|
|
if (df_count == 0) {
|
2003-08-25 14:21:18 +00:00
|
|
|
sc_error(ctx, "No DF's found.\n");
|
2002-01-17 11:44:27 +00:00
|
|
|
return SC_ERROR_OBJECT_NOT_FOUND;
|
|
|
|
}
|
2002-04-19 14:23:31 +00:00
|
|
|
asn1_odf = (struct sc_asn1_entry *) malloc(sizeof(struct sc_asn1_entry) * (df_count + 1));
|
2002-01-13 23:56:13 +00:00
|
|
|
if (asn1_odf == NULL) {
|
|
|
|
r = SC_ERROR_OUT_OF_MEMORY;
|
|
|
|
goto err;
|
|
|
|
}
|
2002-04-19 14:23:31 +00:00
|
|
|
asn1_paths = (struct sc_asn1_entry *) malloc(sizeof(struct sc_asn1_entry) * (df_count * 2));
|
2002-01-13 23:56:13 +00:00
|
|
|
if (asn1_paths == NULL) {
|
|
|
|
r = SC_ERROR_OUT_OF_MEMORY;
|
|
|
|
goto err;
|
|
|
|
}
|
2002-04-19 09:22:44 +00:00
|
|
|
for (df = p15card->df_list; df != NULL; df = df->next) {
|
2002-01-13 23:56:13 +00:00
|
|
|
int j, type = -1;
|
2002-04-19 09:22:44 +00:00
|
|
|
|
2002-01-13 23:56:13 +00:00
|
|
|
for (j = 0; j < nr_indexes; j++)
|
2002-04-19 09:22:44 +00:00
|
|
|
if (odf_indexes[j] == df->type) {
|
2002-01-13 23:56:13 +00:00
|
|
|
type = j;
|
2001-12-16 18:46:32 +00:00
|
|
|
break;
|
|
|
|
}
|
2002-01-13 23:56:13 +00:00
|
|
|
if (type == -1) {
|
2003-08-25 14:21:18 +00:00
|
|
|
sc_error(ctx, "Unsupported DF type.\n");
|
2002-01-13 23:56:13 +00:00
|
|
|
continue;
|
|
|
|
}
|
2002-04-19 09:22:44 +00:00
|
|
|
asn1_odf[c] = c_asn1_odf[type];
|
|
|
|
sc_format_asn1_entry(asn1_odf + c, asn1_paths + 2*c, NULL, 1);
|
|
|
|
sc_copy_asn1_entry(asn1_obj_or_path, asn1_paths + 2*c);
|
|
|
|
sc_format_asn1_entry(asn1_paths + 2*c, &df->path, NULL, 1);
|
|
|
|
c++;
|
2001-12-16 18:46:32 +00:00
|
|
|
}
|
2002-04-19 09:22:44 +00:00
|
|
|
asn1_odf[c].name = NULL;
|
2002-01-16 23:59:18 +00:00
|
|
|
r = sc_asn1_encode(ctx, asn1_odf, buf, buflen);
|
2002-01-13 23:56:13 +00:00
|
|
|
err:
|
|
|
|
if (asn1_paths != NULL)
|
|
|
|
free(asn1_paths);
|
|
|
|
if (asn1_odf != NULL)
|
|
|
|
free(asn1_odf);
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2007-06-21 10:07:01 +00:00
|
|
|
struct sc_pkcs15_card * sc_pkcs15_card_new(void)
|
2002-01-16 23:59:18 +00:00
|
|
|
{
|
|
|
|
struct sc_pkcs15_card *p15card;
|
|
|
|
|
2005-01-03 17:20:17 +00:00
|
|
|
p15card = (struct sc_pkcs15_card *) calloc(1, sizeof(struct sc_pkcs15_card));
|
2002-01-16 23:59:18 +00:00
|
|
|
if (p15card == NULL)
|
|
|
|
return NULL;
|
2002-01-24 18:37:12 +00:00
|
|
|
p15card->magic = SC_PKCS15_CARD_MAGIC;
|
2002-01-16 23:59:18 +00:00
|
|
|
return p15card;
|
|
|
|
}
|
|
|
|
|
|
|
|
void sc_pkcs15_card_free(struct sc_pkcs15_card *p15card)
|
|
|
|
{
|
2005-08-05 16:24:35 +00:00
|
|
|
if (p15card == NULL)
|
|
|
|
return;
|
|
|
|
assert(p15card->magic == SC_PKCS15_CARD_MAGIC);
|
2002-04-19 09:22:44 +00:00
|
|
|
while (p15card->obj_list)
|
|
|
|
sc_pkcs15_remove_object(p15card, p15card->obj_list);
|
|
|
|
while (p15card->df_list)
|
|
|
|
sc_pkcs15_remove_df(p15card, p15card->df_list);
|
2005-12-17 19:53:12 +00:00
|
|
|
while (p15card->unusedspace_list)
|
|
|
|
sc_pkcs15_remove_unusedspace(p15card, p15card->unusedspace_list);
|
|
|
|
p15card->unusedspace_read = 0;
|
2002-02-20 09:56:47 +00:00
|
|
|
if (p15card->file_app != NULL)
|
|
|
|
sc_file_free(p15card->file_app);
|
|
|
|
if (p15card->file_tokeninfo != NULL)
|
|
|
|
sc_file_free(p15card->file_tokeninfo);
|
|
|
|
if (p15card->file_odf != NULL)
|
|
|
|
sc_file_free(p15card->file_odf);
|
2005-12-17 19:53:12 +00:00
|
|
|
if (p15card->file_unusedspace != NULL)
|
|
|
|
sc_file_free(p15card->file_unusedspace);
|
2002-01-24 18:37:12 +00:00
|
|
|
p15card->magic = 0;
|
2005-08-05 16:24:35 +00:00
|
|
|
if (p15card->label != NULL)
|
2002-02-20 09:56:47 +00:00
|
|
|
free(p15card->label);
|
2005-08-05 16:24:35 +00:00
|
|
|
if (p15card->serial_number != NULL)
|
2002-02-20 09:56:47 +00:00
|
|
|
free(p15card->serial_number);
|
2005-08-05 16:24:35 +00:00
|
|
|
if (p15card->manufacturer_id != NULL)
|
2002-02-20 09:56:47 +00:00
|
|
|
free(p15card->manufacturer_id);
|
2005-08-05 16:24:35 +00:00
|
|
|
if (p15card->last_update != NULL)
|
|
|
|
free(p15card->last_update);
|
|
|
|
if (p15card->preferred_language != NULL)
|
2003-10-31 12:26:24 +00:00
|
|
|
free(p15card->preferred_language);
|
2006-10-30 18:51:48 +00:00
|
|
|
if (p15card->seInfo != NULL) {
|
|
|
|
size_t i;
|
|
|
|
for (i = 0; i < p15card->num_seInfo; i++)
|
|
|
|
free(p15card->seInfo[i]);
|
|
|
|
free(p15card->seInfo);
|
|
|
|
}
|
2002-01-16 23:59:18 +00:00
|
|
|
free(p15card);
|
|
|
|
}
|
|
|
|
|
2004-10-08 21:29:55 +00:00
|
|
|
void sc_pkcs15_card_clear(sc_pkcs15_card_t *p15card)
|
|
|
|
{
|
2005-08-05 16:24:35 +00:00
|
|
|
if (p15card == NULL)
|
|
|
|
return;
|
2004-10-08 21:29:55 +00:00
|
|
|
p15card->version = 0;
|
|
|
|
p15card->flags = 0;
|
2005-08-05 16:24:35 +00:00
|
|
|
while (p15card->obj_list != NULL)
|
2004-10-08 21:29:55 +00:00
|
|
|
sc_pkcs15_remove_object(p15card, p15card->obj_list);
|
|
|
|
p15card->obj_list = NULL;
|
2005-08-05 16:24:35 +00:00
|
|
|
while (p15card->df_list != NULL)
|
2004-10-08 21:29:55 +00:00
|
|
|
sc_pkcs15_remove_df(p15card, p15card->df_list);
|
|
|
|
p15card->df_list = NULL;
|
2005-08-05 16:24:35 +00:00
|
|
|
if (p15card->file_app != NULL) {
|
2004-10-08 21:29:55 +00:00
|
|
|
sc_file_free(p15card->file_app);
|
|
|
|
p15card->file_app = NULL;
|
|
|
|
}
|
2005-08-05 16:24:35 +00:00
|
|
|
if (p15card->file_tokeninfo != NULL) {
|
2004-10-08 21:29:55 +00:00
|
|
|
sc_file_free(p15card->file_tokeninfo);
|
|
|
|
p15card->file_tokeninfo = NULL;
|
|
|
|
}
|
2005-08-05 16:24:35 +00:00
|
|
|
if (p15card->file_odf != NULL) {
|
2004-10-08 21:29:55 +00:00
|
|
|
sc_file_free(p15card->file_odf);
|
|
|
|
p15card->file_odf = NULL;
|
|
|
|
}
|
2005-12-17 19:53:12 +00:00
|
|
|
if (p15card->file_unusedspace != NULL) {
|
|
|
|
sc_file_free(p15card->file_unusedspace);
|
|
|
|
p15card->file_unusedspace = NULL;
|
|
|
|
}
|
2005-08-05 16:24:35 +00:00
|
|
|
if (p15card->label != NULL) {
|
2004-10-08 21:29:55 +00:00
|
|
|
free(p15card->label);
|
|
|
|
p15card->label = NULL;
|
|
|
|
}
|
2005-08-05 16:24:35 +00:00
|
|
|
if (p15card->serial_number != NULL) {
|
2004-10-08 21:29:55 +00:00
|
|
|
free(p15card->serial_number);
|
|
|
|
p15card->serial_number = NULL;
|
|
|
|
}
|
2005-08-05 16:24:35 +00:00
|
|
|
if (p15card->manufacturer_id != NULL) {
|
2004-10-08 21:29:55 +00:00
|
|
|
free(p15card->manufacturer_id);
|
|
|
|
p15card->manufacturer_id = NULL;
|
|
|
|
}
|
2005-08-05 16:24:35 +00:00
|
|
|
if (p15card->last_update != NULL) {
|
|
|
|
free(p15card->last_update);
|
|
|
|
p15card->last_update = NULL;
|
|
|
|
}
|
|
|
|
if (p15card->preferred_language != NULL) {
|
2004-10-08 21:29:55 +00:00
|
|
|
free(p15card->preferred_language);
|
|
|
|
p15card->preferred_language = NULL;
|
|
|
|
}
|
2006-10-30 18:51:48 +00:00
|
|
|
if (p15card->seInfo != NULL) {
|
|
|
|
size_t i;
|
|
|
|
for (i = 0; i < p15card->num_seInfo; i++)
|
|
|
|
free(p15card->seInfo[i]);
|
|
|
|
free(p15card->seInfo);
|
|
|
|
p15card->seInfo = NULL;
|
|
|
|
p15card->num_seInfo = 0;
|
|
|
|
}
|
2004-10-08 21:29:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int sc_pkcs15_bind_internal(sc_pkcs15_card_t *p15card)
|
2001-11-01 15:43:20 +00:00
|
|
|
{
|
2006-07-13 19:59:23 +00:00
|
|
|
unsigned char *buf = NULL;
|
2004-10-08 21:29:55 +00:00
|
|
|
int err, ok = 0;
|
2002-05-26 12:31:23 +00:00
|
|
|
size_t len;
|
2005-03-08 20:59:35 +00:00
|
|
|
sc_path_t tmppath;
|
|
|
|
sc_card_t *card = p15card->card;
|
|
|
|
sc_context_t *ctx = card->ctx;
|
2006-03-07 07:22:58 +00:00
|
|
|
sc_pkcs15_tokeninfo_t tokeninfo;
|
2001-11-01 15:43:20 +00:00
|
|
|
|
2004-10-08 21:29:55 +00:00
|
|
|
if (ctx->debug > 4)
|
|
|
|
sc_debug(ctx, "trying normal pkcs15 processing\n");
|
2003-10-31 12:26:24 +00:00
|
|
|
|
|
|
|
/* Enumerate apps now */
|
2002-02-20 09:56:47 +00:00
|
|
|
if (card->app_count < 0) {
|
|
|
|
err = sc_enum_apps(card);
|
|
|
|
if (err < 0 && err != SC_ERROR_FILE_NOT_FOUND) {
|
2003-08-25 14:21:18 +00:00
|
|
|
sc_error(ctx, "unable to enumerate apps: %s\n", sc_strerror(err));
|
2004-10-08 21:29:55 +00:00
|
|
|
goto end;
|
2002-02-20 09:56:47 +00:00
|
|
|
}
|
2001-12-25 20:45:48 +00:00
|
|
|
}
|
2002-02-20 09:56:47 +00:00
|
|
|
p15card->file_app = sc_file_new();
|
|
|
|
if (p15card->file_app == NULL) {
|
|
|
|
err = SC_ERROR_OUT_OF_MEMORY;
|
2004-10-08 21:29:55 +00:00
|
|
|
goto end;
|
2001-12-25 20:45:48 +00:00
|
|
|
}
|
2002-02-20 09:56:47 +00:00
|
|
|
sc_format_path("3F005015", &p15card->file_app->path);
|
|
|
|
if (card->app_count > 0) {
|
2005-03-08 20:59:35 +00:00
|
|
|
const sc_app_info_t *info;
|
2002-02-20 09:56:47 +00:00
|
|
|
|
2003-02-05 15:43:51 +00:00
|
|
|
info = sc_find_pkcs15_app(card);
|
2002-02-20 09:56:47 +00:00
|
|
|
if (info != NULL) {
|
|
|
|
if (info->path.len)
|
|
|
|
p15card->file_app->path = info->path;
|
|
|
|
if (info->ddo != NULL)
|
|
|
|
parse_ddo(p15card, info->ddo, info->ddo_len);
|
|
|
|
}
|
2001-11-01 15:43:20 +00:00
|
|
|
}
|
2003-04-03 09:46:26 +00:00
|
|
|
|
|
|
|
/* Check if pkcs15 directory exists */
|
2005-10-30 19:08:06 +00:00
|
|
|
sc_ctx_suppress_errors_on(card->ctx);
|
2003-04-03 09:46:26 +00:00
|
|
|
err = sc_select_file(card, &p15card->file_app->path, NULL);
|
2005-02-11 10:05:54 +00:00
|
|
|
#if 1
|
|
|
|
/* If the above test failed on cards without EF(DIR),
|
|
|
|
* try to continue read ODF from 3F005031. -aet
|
|
|
|
*/
|
|
|
|
if ((err == SC_ERROR_FILE_NOT_FOUND) &&
|
|
|
|
(card->app_count < 1)) {
|
|
|
|
sc_format_path("3F00", &p15card->file_app->path);
|
|
|
|
err = SC_NO_ERROR;
|
|
|
|
}
|
|
|
|
#endif
|
2005-10-30 19:08:06 +00:00
|
|
|
sc_ctx_suppress_errors_off(card->ctx);
|
2004-10-08 21:29:55 +00:00
|
|
|
if (err < 0)
|
|
|
|
goto end;
|
2003-04-03 09:46:26 +00:00
|
|
|
|
2002-02-20 09:56:47 +00:00
|
|
|
if (p15card->file_odf == NULL) {
|
2005-10-08 11:08:34 +00:00
|
|
|
/* check if an ODF is present; suppress errors as we
|
|
|
|
* don't know yet whether we have a pkcs15 card */
|
2002-02-20 09:56:47 +00:00
|
|
|
tmppath = p15card->file_app->path;
|
2002-02-24 16:50:29 +00:00
|
|
|
sc_append_path_id(&tmppath, (const u8 *) "\x50\x31", 2);
|
2005-10-30 19:08:06 +00:00
|
|
|
sc_ctx_suppress_errors_on(card->ctx);
|
2005-10-08 11:08:34 +00:00
|
|
|
err = sc_select_file(card, &tmppath, &p15card->file_odf);
|
2005-10-30 19:08:06 +00:00
|
|
|
sc_ctx_suppress_errors_off(card->ctx);
|
2005-10-08 11:08:34 +00:00
|
|
|
|
2002-02-20 09:56:47 +00:00
|
|
|
} else {
|
|
|
|
tmppath = p15card->file_odf->path;
|
|
|
|
sc_file_free(p15card->file_odf);
|
|
|
|
p15card->file_odf = NULL;
|
2005-10-08 11:08:34 +00:00
|
|
|
err = sc_select_file(card, &tmppath, &p15card->file_odf);
|
2001-11-01 15:43:20 +00:00
|
|
|
}
|
2005-10-08 11:08:34 +00:00
|
|
|
if (err != SC_SUCCESS) {
|
2006-01-11 23:41:17 +00:00
|
|
|
char pbuf[SC_MAX_PATH_STRING_SIZE];
|
|
|
|
|
|
|
|
int r = sc_path_print(pbuf, sizeof(pbuf), &tmppath);
|
|
|
|
if (r != SC_SUCCESS)
|
|
|
|
pbuf[0] = '\0';
|
|
|
|
|
|
|
|
sc_debug(ctx, "EF(ODF) not found in '%s'\n", pbuf);
|
2004-10-08 21:29:55 +00:00
|
|
|
goto end;
|
2005-10-08 11:08:34 +00:00
|
|
|
}
|
2002-03-06 12:32:42 +00:00
|
|
|
|
2006-07-05 19:45:53 +00:00
|
|
|
if ((len = p15card->file_odf->size) == 0) {
|
|
|
|
sc_error(card->ctx, "EF(ODF) is empty\n");
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
buf = malloc(len);
|
|
|
|
if(buf == NULL)
|
|
|
|
return SC_ERROR_OUT_OF_MEMORY;
|
2002-03-06 12:32:42 +00:00
|
|
|
err = sc_read_binary(card, 0, buf, len, 0);
|
2002-01-24 16:02:54 +00:00
|
|
|
if (err < 0)
|
2004-10-08 21:29:55 +00:00
|
|
|
goto end;
|
2002-01-24 16:02:54 +00:00
|
|
|
if (err < 2) {
|
|
|
|
err = SC_ERROR_PKCS15_APP_NOT_FOUND;
|
2004-10-08 21:29:55 +00:00
|
|
|
goto end;
|
2001-11-01 15:43:20 +00:00
|
|
|
}
|
2002-01-24 16:02:54 +00:00
|
|
|
len = err;
|
|
|
|
if (parse_odf(buf, len, p15card)) {
|
|
|
|
err = SC_ERROR_PKCS15_APP_NOT_FOUND;
|
2003-08-25 14:21:18 +00:00
|
|
|
sc_error(card->ctx, "Unable to parse ODF\n");
|
2004-10-08 21:29:55 +00:00
|
|
|
goto end;
|
2002-01-24 16:02:54 +00:00
|
|
|
}
|
2006-07-05 19:45:53 +00:00
|
|
|
free(buf);
|
2006-07-13 20:35:17 +00:00
|
|
|
buf = NULL;
|
2003-11-19 20:30:44 +00:00
|
|
|
|
|
|
|
if (card->ctx->debug) {
|
|
|
|
sc_pkcs15_df_t *df;
|
|
|
|
|
|
|
|
sc_debug(card->ctx, "The following DFs were found:\n");
|
|
|
|
for (df = p15card->df_list; df; df = df->next) {
|
2006-01-11 23:41:17 +00:00
|
|
|
char pbuf[SC_MAX_PATH_STRING_SIZE];
|
|
|
|
|
|
|
|
int r = sc_path_print(pbuf, sizeof(pbuf), &df->path);
|
|
|
|
if (r != SC_SUCCESS)
|
|
|
|
pbuf[0] = '\0';
|
|
|
|
|
2003-11-19 20:30:44 +00:00
|
|
|
sc_debug(card->ctx,
|
|
|
|
" DF type %u, path %s, index %u, count %d\n",
|
2006-01-11 23:41:17 +00:00
|
|
|
df->type, pbuf, df->path.index, df->path.count);
|
2003-11-19 20:30:44 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-02-20 09:56:47 +00:00
|
|
|
if (p15card->file_tokeninfo == NULL) {
|
|
|
|
tmppath = p15card->file_app->path;
|
2002-02-24 16:50:29 +00:00
|
|
|
sc_append_path_id(&tmppath, (const u8 *) "\x50\x32", 2);
|
2002-02-20 09:56:47 +00:00
|
|
|
} else {
|
|
|
|
tmppath = p15card->file_tokeninfo->path;
|
|
|
|
sc_file_free(p15card->file_tokeninfo);
|
|
|
|
p15card->file_tokeninfo = NULL;
|
|
|
|
}
|
|
|
|
err = sc_select_file(card, &tmppath, &p15card->file_tokeninfo);
|
2001-11-01 15:43:20 +00:00
|
|
|
if (err)
|
2004-10-08 21:29:55 +00:00
|
|
|
goto end;
|
2002-03-06 13:21:22 +00:00
|
|
|
|
2006-07-05 19:45:53 +00:00
|
|
|
if ((len = p15card->file_tokeninfo->size) == 0) {
|
|
|
|
sc_error(card->ctx, "EF(TokenInfo) is empty\n");
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
buf = malloc(len);
|
|
|
|
if(buf == NULL)
|
|
|
|
return SC_ERROR_OUT_OF_MEMORY;
|
2002-03-06 13:21:22 +00:00
|
|
|
err = sc_read_binary(card, 0, buf, len, 0);
|
2001-11-01 15:43:20 +00:00
|
|
|
if (err < 0)
|
2004-10-08 21:29:55 +00:00
|
|
|
goto end;
|
2001-11-01 15:43:20 +00:00
|
|
|
if (err <= 2) {
|
2002-01-10 12:33:56 +00:00
|
|
|
err = SC_ERROR_PKCS15_APP_NOT_FOUND;
|
2004-10-08 21:29:55 +00:00
|
|
|
goto end;
|
2001-11-01 15:43:20 +00:00
|
|
|
}
|
2006-03-07 07:22:58 +00:00
|
|
|
|
|
|
|
memset(&tokeninfo, 0, sizeof(tokeninfo));
|
|
|
|
err = sc_pkcs15_parse_tokeninfo(ctx, &tokeninfo, buf, (size_t)err);
|
|
|
|
if (err != SC_SUCCESS)
|
|
|
|
goto end;
|
|
|
|
p15card->version = tokeninfo.version;
|
|
|
|
p15card->label = tokeninfo.label;
|
|
|
|
p15card->serial_number = tokeninfo.serial_number;
|
|
|
|
p15card->manufacturer_id = tokeninfo.manufacturer_id;
|
|
|
|
p15card->last_update = tokeninfo.last_update;
|
|
|
|
p15card->flags = tokeninfo.flags;
|
|
|
|
p15card->preferred_language = tokeninfo.preferred_language;
|
2006-10-30 18:51:48 +00:00
|
|
|
p15card->seInfo = tokeninfo.seInfo;
|
|
|
|
p15card->num_seInfo = tokeninfo.num_seInfo;
|
2001-12-22 20:43:09 +00:00
|
|
|
|
2007-07-20 12:19:27 +00:00
|
|
|
/* for cardos cards initialized by Siemens: sign with decrypt */
|
|
|
|
if (strcmp(p15card->card->driver->short_name,"cardos") == 0
|
|
|
|
&& strcmp(p15card->manufacturer_id,"Siemens AG (C)") == 0)
|
|
|
|
p15card->flags |= SC_PKCS15_CARD_FLAG_SIGN_WITH_DECRYPT;
|
|
|
|
|
2004-10-08 21:29:55 +00:00
|
|
|
ok = 1;
|
|
|
|
end:
|
2006-07-05 19:45:53 +00:00
|
|
|
if(buf != NULL)
|
|
|
|
free(buf);
|
2004-10-08 21:29:55 +00:00
|
|
|
if (!ok) {
|
|
|
|
sc_pkcs15_card_clear(p15card);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
return SC_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2005-03-08 20:59:35 +00:00
|
|
|
int sc_pkcs15_bind(sc_card_t *card,
|
2004-10-08 21:29:55 +00:00
|
|
|
struct sc_pkcs15_card **p15card_out)
|
|
|
|
{
|
|
|
|
struct sc_pkcs15_card *p15card = NULL;
|
2005-03-08 20:59:35 +00:00
|
|
|
sc_context_t *ctx;
|
2004-10-08 21:29:55 +00:00
|
|
|
scconf_block *conf_block = NULL, **blocks;
|
|
|
|
int i, r, emu_first, enable_emu;
|
|
|
|
|
|
|
|
assert(sc_card_valid(card) && p15card_out != NULL);
|
|
|
|
ctx = card->ctx;
|
|
|
|
SC_FUNC_CALLED(ctx, 1);
|
|
|
|
p15card = sc_pkcs15_card_new();
|
|
|
|
if (p15card == NULL)
|
|
|
|
return SC_ERROR_OUT_OF_MEMORY;
|
|
|
|
p15card->card = card;
|
|
|
|
|
|
|
|
for (i = 0; ctx->conf_blocks[i] != NULL; i++) {
|
|
|
|
blocks = scconf_find_blocks(ctx->conf, ctx->conf_blocks[i],
|
|
|
|
"framework", "pkcs15");
|
2005-12-05 21:37:59 +00:00
|
|
|
if (blocks && blocks[0] != NULL)
|
2004-10-08 21:29:55 +00:00
|
|
|
conf_block = blocks[0];
|
|
|
|
free(blocks);
|
|
|
|
}
|
2005-03-09 11:45:29 +00:00
|
|
|
|
|
|
|
if (conf_block) {
|
2004-10-08 21:29:55 +00:00
|
|
|
p15card->opts.use_cache = scconf_get_bool(conf_block, "use_caching", 0);
|
2005-03-09 11:45:29 +00:00
|
|
|
}
|
2004-10-08 21:29:55 +00:00
|
|
|
|
|
|
|
r = sc_lock(card);
|
|
|
|
if (r) {
|
|
|
|
sc_error(ctx, "sc_lock() failed: %s\n", sc_strerror(r));
|
|
|
|
sc_pkcs15_card_free(p15card);
|
|
|
|
SC_FUNC_RETURN(ctx, 1, r);
|
|
|
|
}
|
|
|
|
|
|
|
|
enable_emu = scconf_get_bool(conf_block, "enable_pkcs15_emulation", 1);
|
|
|
|
if (enable_emu) {
|
|
|
|
emu_first = scconf_get_bool(conf_block, "try_emulation_first", 0);
|
2007-01-05 16:20:50 +00:00
|
|
|
if (emu_first || sc_pkcs15_is_emulation_only(card)) {
|
2004-10-08 21:29:55 +00:00
|
|
|
r = sc_pkcs15_bind_synthetic(p15card);
|
|
|
|
if (r == SC_SUCCESS)
|
|
|
|
goto done;
|
|
|
|
r = sc_pkcs15_bind_internal(p15card);
|
|
|
|
if (r < 0)
|
|
|
|
goto error;
|
|
|
|
} else {
|
|
|
|
r = sc_pkcs15_bind_internal(p15card);
|
|
|
|
if (r == SC_SUCCESS)
|
|
|
|
goto done;
|
|
|
|
r = sc_pkcs15_bind_synthetic(p15card);
|
|
|
|
if (r < 0)
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
r = sc_pkcs15_bind_internal(p15card);
|
|
|
|
if (r < 0)
|
|
|
|
goto error;
|
|
|
|
}
|
2003-04-03 09:46:26 +00:00
|
|
|
done:
|
2001-11-01 15:43:20 +00:00
|
|
|
*p15card_out = p15card;
|
2001-12-25 20:45:48 +00:00
|
|
|
sc_unlock(card);
|
2001-11-01 15:43:20 +00:00
|
|
|
return 0;
|
2001-12-16 18:46:32 +00:00
|
|
|
error:
|
2001-12-25 20:45:48 +00:00
|
|
|
sc_unlock(card);
|
2003-04-04 09:52:39 +00:00
|
|
|
sc_pkcs15_card_free(p15card);
|
2004-10-08 21:29:55 +00:00
|
|
|
SC_FUNC_RETURN(ctx, 1, r);
|
2001-11-01 15:43:20 +00:00
|
|
|
}
|
|
|
|
|
2004-10-17 20:20:59 +00:00
|
|
|
#if 0
|
2005-03-08 20:59:35 +00:00
|
|
|
int sc_pkcs15_detect(sc_card_t *card)
|
2002-01-08 13:56:50 +00:00
|
|
|
{
|
|
|
|
int r;
|
2005-03-08 20:59:35 +00:00
|
|
|
sc_path_t path;
|
2002-01-08 13:56:50 +00:00
|
|
|
|
|
|
|
sc_format_path("NA0000063504B43532D3135", &path);
|
2002-02-20 09:56:47 +00:00
|
|
|
r = sc_select_file(card, &path, NULL);
|
2002-01-08 13:56:50 +00:00
|
|
|
if (r != 0)
|
|
|
|
return 0;
|
|
|
|
return 1;
|
|
|
|
}
|
2004-10-17 20:20:59 +00:00
|
|
|
#endif
|
2002-01-08 13:56:50 +00:00
|
|
|
|
2001-12-21 23:34:47 +00:00
|
|
|
int sc_pkcs15_unbind(struct sc_pkcs15_card *p15card)
|
2001-11-01 15:43:20 +00:00
|
|
|
{
|
2002-01-24 18:37:12 +00:00
|
|
|
assert(p15card != NULL && p15card->magic == SC_PKCS15_CARD_MAGIC);
|
2001-12-22 20:43:09 +00:00
|
|
|
SC_FUNC_CALLED(p15card->card->ctx, 1);
|
2003-10-31 12:26:24 +00:00
|
|
|
if (p15card->dll_handle)
|
2005-09-01 14:01:58 +00:00
|
|
|
lt_dlclose(p15card->dll_handle);
|
2002-01-16 23:59:18 +00:00
|
|
|
sc_pkcs15_card_free(p15card);
|
2001-11-01 15:43:20 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2003-10-30 11:43:21 +00:00
|
|
|
static int
|
|
|
|
__sc_pkcs15_search_objects(sc_pkcs15_card_t *p15card,
|
2005-08-05 16:24:35 +00:00
|
|
|
unsigned int class_mask, unsigned int type,
|
2003-10-30 11:43:21 +00:00
|
|
|
int (*func)(sc_pkcs15_object_t *, void *),
|
|
|
|
void *func_arg,
|
|
|
|
sc_pkcs15_object_t **ret, size_t ret_size)
|
2002-03-03 00:32:28 +00:00
|
|
|
{
|
2002-04-19 09:22:44 +00:00
|
|
|
sc_pkcs15_object_t *obj;
|
2003-10-30 11:43:21 +00:00
|
|
|
sc_pkcs15_df_t *df;
|
|
|
|
unsigned int df_mask = 0;
|
|
|
|
size_t match_count = 0;
|
|
|
|
int r = 0;
|
|
|
|
|
|
|
|
if (type)
|
|
|
|
class_mask |= SC_PKCS15_TYPE_TO_CLASS(type);
|
|
|
|
|
|
|
|
/* Make sure the class mask we have makes sense */
|
|
|
|
if (class_mask == 0
|
|
|
|
|| (class_mask & ~(SC_PKCS15_SEARCH_CLASS_PRKEY |
|
|
|
|
SC_PKCS15_SEARCH_CLASS_PUBKEY |
|
|
|
|
SC_PKCS15_SEARCH_CLASS_CERT |
|
|
|
|
SC_PKCS15_SEARCH_CLASS_DATA |
|
|
|
|
SC_PKCS15_SEARCH_CLASS_AUTH))) {
|
2002-03-03 00:32:28 +00:00
|
|
|
return SC_ERROR_INVALID_ARGUMENTS;
|
|
|
|
}
|
2003-10-30 11:43:21 +00:00
|
|
|
|
|
|
|
if (class_mask & SC_PKCS15_SEARCH_CLASS_PRKEY)
|
|
|
|
df_mask |= (1 << SC_PKCS15_PRKDF);
|
|
|
|
if (class_mask & SC_PKCS15_SEARCH_CLASS_PUBKEY)
|
|
|
|
df_mask |= (1 << SC_PKCS15_PUKDF)
|
|
|
|
| (1 << SC_PKCS15_PUKDF_TRUSTED);
|
|
|
|
if (class_mask & SC_PKCS15_SEARCH_CLASS_CERT)
|
|
|
|
df_mask |= (1 << SC_PKCS15_CDF)
|
|
|
|
| (1 << SC_PKCS15_CDF_TRUSTED)
|
|
|
|
| (1 << SC_PKCS15_CDF_USEFUL);
|
|
|
|
if (class_mask & SC_PKCS15_SEARCH_CLASS_DATA)
|
|
|
|
df_mask |= (1 << SC_PKCS15_DODF);
|
|
|
|
if (class_mask & SC_PKCS15_SEARCH_CLASS_AUTH)
|
|
|
|
df_mask |= (1 << SC_PKCS15_AODF);
|
|
|
|
|
|
|
|
/* Make sure all the DFs we want to search have been
|
|
|
|
* enumerated. */
|
|
|
|
for (df = p15card->df_list; df != NULL; df = df->next) {
|
|
|
|
if (!(df_mask & (1 << df->type)))
|
|
|
|
continue;
|
|
|
|
if (df->enumerated)
|
|
|
|
continue;
|
|
|
|
/* Enumerate the DF's, so p15card->obj_list is
|
|
|
|
* populated. */
|
|
|
|
r = sc_pkcs15_parse_df(p15card, df);
|
|
|
|
SC_TEST_RET(p15card->card->ctx, r, "DF parsing failed");
|
|
|
|
df->enumerated = 1;
|
2002-03-03 00:32:28 +00:00
|
|
|
}
|
2003-10-30 11:43:21 +00:00
|
|
|
|
|
|
|
/* And now loop over all objects */
|
2002-04-19 09:22:44 +00:00
|
|
|
for (obj = p15card->obj_list; obj != NULL; obj = obj->next) {
|
2003-10-30 11:43:21 +00:00
|
|
|
/* Check object type */
|
|
|
|
if (!(class_mask & SC_PKCS15_TYPE_TO_CLASS(obj->type)))
|
|
|
|
continue;
|
|
|
|
if (type != 0
|
|
|
|
&& obj->type != type
|
2002-04-19 09:22:44 +00:00
|
|
|
&& (obj->type & SC_PKCS15_TYPE_CLASS_MASK) != type)
|
|
|
|
continue;
|
2003-10-30 11:43:21 +00:00
|
|
|
|
|
|
|
/* Potential candidate, apply search function */
|
2002-04-19 09:22:44 +00:00
|
|
|
if (func != NULL && func(obj, func_arg) <= 0)
|
|
|
|
continue;
|
|
|
|
/* Okay, we have a match. */
|
|
|
|
match_count++;
|
|
|
|
if (ret_size <= 0)
|
|
|
|
continue;
|
|
|
|
ret[match_count-1] = obj;
|
|
|
|
if (ret_size <= match_count)
|
|
|
|
break;
|
2002-03-03 00:32:28 +00:00
|
|
|
}
|
2002-04-19 09:22:44 +00:00
|
|
|
return match_count;
|
2002-03-03 00:32:28 +00:00
|
|
|
}
|
|
|
|
|
2005-08-05 16:24:35 +00:00
|
|
|
int sc_pkcs15_get_objects(struct sc_pkcs15_card *p15card, unsigned int type,
|
|
|
|
struct sc_pkcs15_object **ret, size_t ret_size)
|
2002-03-03 00:32:28 +00:00
|
|
|
{
|
2005-02-11 20:09:34 +00:00
|
|
|
return sc_pkcs15_get_objects_cond(p15card, type, NULL, NULL, ret, ret_size);
|
2002-03-03 00:32:28 +00:00
|
|
|
}
|
|
|
|
|
2003-04-17 12:38:08 +00:00
|
|
|
static int compare_obj_id(struct sc_pkcs15_object *obj, const sc_pkcs15_id_t *id)
|
2002-03-03 00:32:28 +00:00
|
|
|
{
|
|
|
|
void *data = obj->data;
|
|
|
|
|
|
|
|
switch (obj->type) {
|
|
|
|
case SC_PKCS15_TYPE_CERT_X509:
|
|
|
|
return sc_pkcs15_compare_id(&((struct sc_pkcs15_cert_info *) data)->id, id);
|
|
|
|
case SC_PKCS15_TYPE_PRKEY_RSA:
|
2002-04-18 10:59:13 +00:00
|
|
|
case SC_PKCS15_TYPE_PRKEY_DSA:
|
2002-03-03 00:32:28 +00:00
|
|
|
return sc_pkcs15_compare_id(&((struct sc_pkcs15_prkey_info *) data)->id, id);
|
|
|
|
case SC_PKCS15_TYPE_PUBKEY_RSA:
|
2002-04-18 10:59:13 +00:00
|
|
|
case SC_PKCS15_TYPE_PUBKEY_DSA:
|
2002-03-03 00:32:28 +00:00
|
|
|
return sc_pkcs15_compare_id(&((struct sc_pkcs15_pubkey_info *) data)->id, id);
|
|
|
|
case SC_PKCS15_TYPE_AUTH_PIN:
|
|
|
|
return sc_pkcs15_compare_id(&((struct sc_pkcs15_pin_info *) data)->auth_id, id);
|
2002-12-18 10:17:01 +00:00
|
|
|
case SC_PKCS15_TYPE_DATA_OBJECT:
|
|
|
|
return sc_pkcs15_compare_id(&((struct sc_pkcs15_data_info *) data)->id, id);
|
2002-03-03 00:32:28 +00:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-08-03 09:05:09 +00:00
|
|
|
static int sc_obj_app_oid(struct sc_pkcs15_object *obj, const struct sc_object_id *app_oid)
|
|
|
|
{
|
|
|
|
if (obj->type & SC_PKCS15_TYPE_DATA_OBJECT)
|
|
|
|
return sc_compare_oid(&((struct sc_pkcs15_data_info *) obj->data)->app_oid, app_oid);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2003-04-17 12:38:08 +00:00
|
|
|
static int compare_obj_usage(sc_pkcs15_object_t *obj, unsigned int mask, unsigned int value)
|
|
|
|
{
|
|
|
|
void *data = obj->data;
|
|
|
|
unsigned int usage;
|
|
|
|
|
|
|
|
switch (obj->type) {
|
|
|
|
case SC_PKCS15_TYPE_PRKEY_RSA:
|
|
|
|
case SC_PKCS15_TYPE_PRKEY_DSA:
|
|
|
|
usage = ((struct sc_pkcs15_prkey_info *) data)->usage;
|
|
|
|
break;
|
|
|
|
case SC_PKCS15_TYPE_PUBKEY_RSA:
|
|
|
|
case SC_PKCS15_TYPE_PUBKEY_DSA:
|
|
|
|
usage = ((struct sc_pkcs15_pubkey_info *) data)->usage;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return 0;
|
|
|
|
}
|
2003-07-22 15:51:17 +00:00
|
|
|
return (usage & mask & value) != 0;
|
2003-04-17 12:38:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int compare_obj_flags(sc_pkcs15_object_t *obj, unsigned int mask, unsigned int value)
|
|
|
|
{
|
|
|
|
void *data = obj->data;
|
|
|
|
unsigned int flags;
|
|
|
|
|
|
|
|
switch (obj->type) {
|
|
|
|
case SC_PKCS15_TYPE_AUTH_PIN:
|
|
|
|
flags = ((struct sc_pkcs15_pin_info *) data)->flags;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return !((flags ^ value) & mask);
|
|
|
|
}
|
|
|
|
|
2003-05-15 11:27:38 +00:00
|
|
|
static int compare_obj_reference(sc_pkcs15_object_t *obj, int value)
|
|
|
|
{
|
|
|
|
void *data = obj->data;
|
|
|
|
int reference;
|
|
|
|
|
|
|
|
switch (obj->type) {
|
|
|
|
case SC_PKCS15_TYPE_AUTH_PIN:
|
|
|
|
reference = ((struct sc_pkcs15_pin_info *) data)->reference;
|
|
|
|
break;
|
2003-10-13 14:35:27 +00:00
|
|
|
case SC_PKCS15_TYPE_PRKEY_RSA:
|
|
|
|
case SC_PKCS15_TYPE_PRKEY_DSA:
|
|
|
|
reference = ((struct sc_pkcs15_prkey_info *) data)->key_reference;
|
|
|
|
break;
|
2003-05-15 11:27:38 +00:00
|
|
|
default:
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return reference == value;
|
|
|
|
}
|
|
|
|
|
2003-10-13 14:35:27 +00:00
|
|
|
static int compare_obj_path(sc_pkcs15_object_t *obj, const sc_path_t *path)
|
|
|
|
{
|
|
|
|
void *data = obj->data;
|
|
|
|
|
|
|
|
switch (obj->type) {
|
|
|
|
case SC_PKCS15_TYPE_CERT_X509:
|
2003-10-13 14:52:03 +00:00
|
|
|
return sc_compare_path(&((struct sc_pkcs15_cert_info *) data)->path, path);
|
2003-10-13 14:35:27 +00:00
|
|
|
case SC_PKCS15_TYPE_PRKEY_RSA:
|
|
|
|
case SC_PKCS15_TYPE_PRKEY_DSA:
|
2003-10-13 14:52:03 +00:00
|
|
|
return sc_compare_path(&((struct sc_pkcs15_prkey_info *) data)->path, path);
|
2003-10-13 14:35:27 +00:00
|
|
|
case SC_PKCS15_TYPE_PUBKEY_RSA:
|
|
|
|
case SC_PKCS15_TYPE_PUBKEY_DSA:
|
2003-10-13 14:52:03 +00:00
|
|
|
return sc_compare_path(&((struct sc_pkcs15_pubkey_info *) data)->path, path);
|
2003-10-13 14:35:27 +00:00
|
|
|
case SC_PKCS15_TYPE_AUTH_PIN:
|
2003-10-13 14:52:03 +00:00
|
|
|
return sc_compare_path(&((struct sc_pkcs15_pin_info *) data)->path, path);
|
2003-10-13 14:35:27 +00:00
|
|
|
case SC_PKCS15_TYPE_DATA_OBJECT:
|
2003-10-13 14:52:03 +00:00
|
|
|
return sc_compare_path(&((struct sc_pkcs15_data_info *) data)->path, path);
|
2003-10-13 14:35:27 +00:00
|
|
|
}
|
2003-10-13 14:52:03 +00:00
|
|
|
return 0;
|
2003-10-13 14:35:27 +00:00
|
|
|
}
|
|
|
|
|
2003-04-17 12:38:08 +00:00
|
|
|
static int compare_obj_key(struct sc_pkcs15_object *obj, void *arg)
|
|
|
|
{
|
|
|
|
struct sc_pkcs15_search_key *sk = (struct sc_pkcs15_search_key *) arg;
|
|
|
|
|
|
|
|
if (sk->id && !compare_obj_id(obj, sk->id))
|
|
|
|
return 0;
|
2005-08-03 09:05:09 +00:00
|
|
|
if (sk->app_oid && !sc_obj_app_oid(obj, sk->app_oid))
|
|
|
|
return 0;
|
2003-04-17 12:38:08 +00:00
|
|
|
if (sk->usage_mask && !compare_obj_usage(obj, sk->usage_mask, sk->usage_value))
|
|
|
|
return 0;
|
|
|
|
if (sk->flags_mask && !compare_obj_flags(obj, sk->flags_mask, sk->flags_value))
|
|
|
|
return 0;
|
2003-05-15 11:27:38 +00:00
|
|
|
if (sk->match_reference && !compare_obj_reference(obj, sk->reference))
|
|
|
|
return 0;
|
2003-10-13 14:35:27 +00:00
|
|
|
if (sk->path && !compare_obj_path(obj, sk->path))
|
|
|
|
return 0;
|
2003-04-17 12:38:08 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int find_by_key(struct sc_pkcs15_card *p15card,
|
2005-08-05 16:24:35 +00:00
|
|
|
unsigned int type, struct sc_pkcs15_search_key *sk,
|
2003-04-17 12:38:08 +00:00
|
|
|
struct sc_pkcs15_object **out)
|
2002-03-03 00:32:28 +00:00
|
|
|
{
|
|
|
|
int r;
|
|
|
|
|
2003-04-17 12:38:08 +00:00
|
|
|
r = sc_pkcs15_get_objects_cond(p15card, type, compare_obj_key, sk, out, 1);
|
2002-03-03 00:32:28 +00:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
if (r == 0)
|
|
|
|
return SC_ERROR_OBJECT_NOT_FOUND;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2003-10-30 11:43:21 +00:00
|
|
|
int
|
|
|
|
sc_pkcs15_search_objects(sc_pkcs15_card_t *p15card, sc_pkcs15_search_key_t *sk,
|
|
|
|
sc_pkcs15_object_t **ret, size_t ret_size)
|
2003-04-17 12:38:08 +00:00
|
|
|
{
|
2003-10-30 11:43:21 +00:00
|
|
|
return __sc_pkcs15_search_objects(p15card,
|
|
|
|
sk->class_mask, sk->type,
|
|
|
|
compare_obj_key, sk,
|
|
|
|
ret, ret_size);
|
|
|
|
}
|
|
|
|
|
2005-08-05 16:24:35 +00:00
|
|
|
int sc_pkcs15_get_objects_cond(struct sc_pkcs15_card *p15card, unsigned int type,
|
2003-10-30 11:43:21 +00:00
|
|
|
int (* func)(struct sc_pkcs15_object *, void *),
|
|
|
|
void *func_arg,
|
2005-08-05 16:24:35 +00:00
|
|
|
struct sc_pkcs15_object **ret, size_t ret_size)
|
2003-10-30 11:43:21 +00:00
|
|
|
{
|
|
|
|
return __sc_pkcs15_search_objects(p15card, 0, type,
|
|
|
|
func, func_arg, ret, ret_size);
|
|
|
|
}
|
|
|
|
|
|
|
|
int sc_pkcs15_find_object_by_id(sc_pkcs15_card_t *p15card,
|
2005-08-05 16:24:35 +00:00
|
|
|
unsigned int type, const sc_pkcs15_id_t *id,
|
2003-10-30 11:43:21 +00:00
|
|
|
sc_pkcs15_object_t **out)
|
|
|
|
{
|
|
|
|
sc_pkcs15_search_key_t sk;
|
|
|
|
int r;
|
2003-04-17 12:38:08 +00:00
|
|
|
|
|
|
|
memset(&sk, 0, sizeof(sk));
|
|
|
|
sk.id = id;
|
|
|
|
|
2003-10-30 11:43:21 +00:00
|
|
|
r = __sc_pkcs15_search_objects(p15card, 0, type,
|
|
|
|
compare_obj_key, &sk,
|
|
|
|
out, 1);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
if (r == 0)
|
|
|
|
return SC_ERROR_OBJECT_NOT_FOUND;
|
|
|
|
return 0;
|
2003-04-17 12:38:08 +00:00
|
|
|
}
|
|
|
|
|
2002-03-03 00:32:28 +00:00
|
|
|
int sc_pkcs15_find_cert_by_id(struct sc_pkcs15_card *p15card,
|
|
|
|
const struct sc_pkcs15_id *id,
|
|
|
|
struct sc_pkcs15_object **out)
|
|
|
|
{
|
2003-10-30 11:43:21 +00:00
|
|
|
return sc_pkcs15_find_object_by_id(p15card, SC_PKCS15_TYPE_CERT, id, out);
|
2002-03-03 00:32:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int sc_pkcs15_find_prkey_by_id(struct sc_pkcs15_card *p15card,
|
|
|
|
const struct sc_pkcs15_id *id,
|
|
|
|
struct sc_pkcs15_object **out)
|
|
|
|
{
|
2003-10-30 11:43:21 +00:00
|
|
|
return sc_pkcs15_find_object_by_id(p15card, SC_PKCS15_TYPE_PRKEY, id, out);
|
2002-03-03 00:32:28 +00:00
|
|
|
}
|
|
|
|
|
2002-04-18 10:59:13 +00:00
|
|
|
int sc_pkcs15_find_pubkey_by_id(struct sc_pkcs15_card *p15card,
|
|
|
|
const struct sc_pkcs15_id *id,
|
|
|
|
struct sc_pkcs15_object **out)
|
|
|
|
{
|
2003-10-30 11:43:21 +00:00
|
|
|
return sc_pkcs15_find_object_by_id(p15card, SC_PKCS15_TYPE_PUBKEY, id, out);
|
2002-04-18 10:59:13 +00:00
|
|
|
}
|
|
|
|
|
2002-03-03 00:32:28 +00:00
|
|
|
int sc_pkcs15_find_pin_by_auth_id(struct sc_pkcs15_card *p15card,
|
|
|
|
const struct sc_pkcs15_id *id,
|
|
|
|
struct sc_pkcs15_object **out)
|
|
|
|
{
|
2003-10-30 11:43:21 +00:00
|
|
|
return sc_pkcs15_find_object_by_id(p15card, SC_PKCS15_TYPE_AUTH_PIN, id, out);
|
2002-03-03 00:32:28 +00:00
|
|
|
}
|
|
|
|
|
2003-05-15 11:27:38 +00:00
|
|
|
int sc_pkcs15_find_pin_by_reference(struct sc_pkcs15_card *p15card,
|
2003-10-21 11:02:48 +00:00
|
|
|
const sc_path_t *path, int reference,
|
2003-05-15 11:27:38 +00:00
|
|
|
struct sc_pkcs15_object **out)
|
|
|
|
{
|
|
|
|
struct sc_pkcs15_search_key sk;
|
|
|
|
|
|
|
|
memset(&sk, 0, sizeof(sk));
|
|
|
|
sk.match_reference = 1;
|
|
|
|
sk.reference = reference;
|
2003-10-21 11:02:48 +00:00
|
|
|
sk.path = path;
|
2003-05-15 11:27:38 +00:00
|
|
|
|
|
|
|
return find_by_key(p15card, SC_PKCS15_TYPE_AUTH_PIN, &sk, out);
|
|
|
|
}
|
|
|
|
|
2002-12-18 10:17:01 +00:00
|
|
|
int sc_pkcs15_find_data_object_by_id(struct sc_pkcs15_card *p15card,
|
|
|
|
const struct sc_pkcs15_id *id,
|
|
|
|
struct sc_pkcs15_object **out)
|
|
|
|
{
|
2003-10-30 11:43:21 +00:00
|
|
|
return sc_pkcs15_find_object_by_id(p15card, SC_PKCS15_TYPE_DATA_OBJECT, id, out);
|
2002-12-18 10:17:01 +00:00
|
|
|
}
|
|
|
|
|
2005-08-03 09:05:09 +00:00
|
|
|
int sc_pkcs15_find_data_object_by_app_oid(struct sc_pkcs15_card *p15card,
|
|
|
|
const struct sc_object_id *app_oid,
|
|
|
|
struct sc_pkcs15_object **out)
|
|
|
|
{
|
|
|
|
sc_pkcs15_search_key_t sk;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
memset(&sk, 0, sizeof(sk));
|
|
|
|
sk.app_oid = app_oid;
|
|
|
|
|
|
|
|
r = __sc_pkcs15_search_objects(p15card, 0, SC_PKCS15_TYPE_DATA_OBJECT,
|
|
|
|
compare_obj_key, &sk,
|
|
|
|
out, 1);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
if (r == 0)
|
|
|
|
return SC_ERROR_OBJECT_NOT_FOUND;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2003-04-17 12:38:08 +00:00
|
|
|
int sc_pkcs15_find_prkey_by_id_usage(struct sc_pkcs15_card *p15card,
|
|
|
|
const struct sc_pkcs15_id *id,
|
|
|
|
unsigned int usage,
|
|
|
|
struct sc_pkcs15_object **out)
|
2002-04-08 15:45:28 +00:00
|
|
|
{
|
2003-04-17 12:38:08 +00:00
|
|
|
struct sc_pkcs15_search_key sk;
|
|
|
|
|
|
|
|
memset(&sk, 0, sizeof(sk));
|
|
|
|
sk.usage_mask = sk.usage_value = usage;
|
|
|
|
sk.id = id;
|
2002-04-08 15:45:28 +00:00
|
|
|
|
2003-04-17 12:38:08 +00:00
|
|
|
return find_by_key(p15card, SC_PKCS15_TYPE_PRKEY, &sk, out);
|
2002-04-08 15:45:28 +00:00
|
|
|
}
|
|
|
|
|
2003-10-13 14:35:27 +00:00
|
|
|
int sc_pkcs15_find_prkey_by_reference(sc_pkcs15_card_t *p15card,
|
|
|
|
const sc_path_t *path,
|
|
|
|
int reference,
|
|
|
|
struct sc_pkcs15_object **out)
|
|
|
|
{
|
|
|
|
struct sc_pkcs15_search_key sk;
|
|
|
|
|
|
|
|
memset(&sk, 0, sizeof(sk));
|
|
|
|
sk.match_reference = 1;
|
|
|
|
sk.reference = reference;
|
|
|
|
sk.path = path;
|
|
|
|
|
|
|
|
return find_by_key(p15card, SC_PKCS15_TYPE_PRKEY, &sk, out);
|
|
|
|
}
|
|
|
|
|
2002-04-08 15:45:28 +00:00
|
|
|
int sc_pkcs15_find_so_pin(struct sc_pkcs15_card *p15card,
|
|
|
|
struct sc_pkcs15_object **out)
|
|
|
|
{
|
2003-04-17 12:38:08 +00:00
|
|
|
struct sc_pkcs15_search_key sk;
|
|
|
|
|
|
|
|
memset(&sk, 0, sizeof(sk));
|
|
|
|
sk.flags_mask = sk.flags_value = SC_PKCS15_PIN_FLAG_SO_PIN;
|
2002-04-08 15:45:28 +00:00
|
|
|
|
2003-04-17 12:38:08 +00:00
|
|
|
return find_by_key(p15card, SC_PKCS15_TYPE_AUTH_PIN, &sk, out);
|
2002-04-08 15:45:28 +00:00
|
|
|
}
|
|
|
|
|
2002-04-19 09:22:44 +00:00
|
|
|
int sc_pkcs15_add_object(struct sc_pkcs15_card *p15card,
|
|
|
|
struct sc_pkcs15_object *obj)
|
2002-01-24 16:02:54 +00:00
|
|
|
{
|
2002-04-19 09:22:44 +00:00
|
|
|
struct sc_pkcs15_object *p = p15card->obj_list;
|
2002-01-24 16:02:54 +00:00
|
|
|
|
2002-04-19 09:22:44 +00:00
|
|
|
obj->next = obj->prev = NULL;
|
|
|
|
if (p15card->obj_list == NULL) {
|
|
|
|
p15card->obj_list = obj;
|
2002-01-16 23:59:18 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
while (p->next != NULL)
|
2002-01-24 16:02:54 +00:00
|
|
|
p = p->next;
|
|
|
|
p->next = obj;
|
2002-04-19 09:22:44 +00:00
|
|
|
obj->prev = p;
|
|
|
|
|
2002-01-16 23:59:18 +00:00
|
|
|
return 0;
|
2002-04-19 09:22:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void sc_pkcs15_remove_object(struct sc_pkcs15_card *p15card,
|
|
|
|
struct sc_pkcs15_object *obj)
|
|
|
|
{
|
|
|
|
if (obj->prev == NULL)
|
|
|
|
p15card->obj_list = obj->next;
|
|
|
|
else
|
|
|
|
obj->prev->next = obj->next;
|
|
|
|
if (obj->next != NULL)
|
|
|
|
obj->next->prev = obj->prev;
|
2004-12-18 14:14:57 +00:00
|
|
|
sc_pkcs15_free_object(obj);
|
|
|
|
}
|
|
|
|
|
|
|
|
void sc_pkcs15_free_object(struct sc_pkcs15_object *obj)
|
|
|
|
{
|
|
|
|
switch (obj->type & SC_PKCS15_TYPE_CLASS_MASK) {
|
|
|
|
case SC_PKCS15_TYPE_PRKEY:
|
|
|
|
sc_pkcs15_free_prkey_info((sc_pkcs15_prkey_info_t *)obj->data);
|
|
|
|
break;
|
|
|
|
case SC_PKCS15_TYPE_PUBKEY:
|
|
|
|
sc_pkcs15_free_pubkey_info((sc_pkcs15_pubkey_info_t *)obj->data);
|
|
|
|
break;
|
|
|
|
case SC_PKCS15_TYPE_CERT:
|
|
|
|
sc_pkcs15_free_cert_info((sc_pkcs15_cert_info_t *)obj->data);
|
|
|
|
break;
|
|
|
|
case SC_PKCS15_TYPE_DATA_OBJECT:
|
|
|
|
sc_pkcs15_free_data_info((sc_pkcs15_data_info_t *)obj->data);
|
|
|
|
break;
|
|
|
|
case SC_PKCS15_TYPE_AUTH:
|
|
|
|
sc_pkcs15_free_pin_info((sc_pkcs15_pin_info_t *)obj->data);
|
|
|
|
break;
|
|
|
|
default:
|
2002-04-19 09:22:44 +00:00
|
|
|
free(obj->data);
|
2004-12-18 14:14:57 +00:00
|
|
|
}
|
|
|
|
|
2002-12-10 13:27:17 +00:00
|
|
|
if (obj->der.value)
|
|
|
|
free(obj->der.value);
|
2002-04-19 09:22:44 +00:00
|
|
|
free(obj);
|
|
|
|
}
|
|
|
|
|
|
|
|
int sc_pkcs15_add_df(struct sc_pkcs15_card *p15card,
|
2005-08-05 16:24:35 +00:00
|
|
|
unsigned int type, const sc_path_t *path,
|
2002-04-19 09:22:44 +00:00
|
|
|
const sc_file_t *file)
|
|
|
|
{
|
|
|
|
struct sc_pkcs15_df *p = p15card->df_list, *newdf;
|
|
|
|
|
2005-01-03 17:20:17 +00:00
|
|
|
newdf = (struct sc_pkcs15_df *) calloc(1, sizeof(struct sc_pkcs15_df));
|
2002-04-19 09:22:44 +00:00
|
|
|
if (newdf == NULL)
|
|
|
|
return SC_ERROR_OUT_OF_MEMORY;
|
|
|
|
newdf->path = *path;
|
|
|
|
newdf->type = type;
|
2005-08-19 17:56:56 +00:00
|
|
|
if (file != NULL) {
|
2002-04-19 09:22:44 +00:00
|
|
|
sc_file_dup(&newdf->file, file);
|
2005-08-19 17:56:56 +00:00
|
|
|
if (newdf->file == NULL) {
|
|
|
|
free(newdf);
|
|
|
|
return SC_ERROR_OUT_OF_MEMORY;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
2002-04-19 09:22:44 +00:00
|
|
|
if (p15card->df_list == NULL) {
|
|
|
|
p15card->df_list = newdf;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
while (p->next != NULL)
|
|
|
|
p = p->next;
|
|
|
|
p->next = newdf;
|
|
|
|
newdf->prev = p;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void sc_pkcs15_remove_df(struct sc_pkcs15_card *p15card,
|
|
|
|
struct sc_pkcs15_df *obj)
|
|
|
|
{
|
|
|
|
if (obj->prev == NULL)
|
|
|
|
p15card->df_list = obj->next;
|
|
|
|
else
|
|
|
|
obj->prev->next = obj->next;
|
|
|
|
if (obj->next != NULL)
|
|
|
|
obj->next->prev = obj->prev;
|
|
|
|
if (obj->file)
|
|
|
|
sc_file_free(obj->file);
|
|
|
|
free(obj);
|
|
|
|
}
|
2002-01-16 23:59:18 +00:00
|
|
|
|
2005-03-08 20:59:35 +00:00
|
|
|
int sc_pkcs15_encode_df(sc_context_t *ctx,
|
2002-04-19 09:22:44 +00:00
|
|
|
struct sc_pkcs15_card *p15card,
|
2002-01-16 23:59:18 +00:00
|
|
|
struct sc_pkcs15_df *df,
|
|
|
|
u8 **buf_out, size_t *bufsize_out)
|
|
|
|
{
|
2004-04-21 18:10:58 +00:00
|
|
|
u8 *buf = NULL, *tmp = NULL;
|
2002-01-16 23:59:18 +00:00
|
|
|
size_t bufsize = 0, tmpsize;
|
2002-04-19 09:22:44 +00:00
|
|
|
const struct sc_pkcs15_object *obj;
|
2005-03-08 20:59:35 +00:00
|
|
|
int (* func)(sc_context_t *, const struct sc_pkcs15_object *nobj,
|
2004-10-17 20:20:59 +00:00
|
|
|
u8 **nbuf, size_t *nbufsize) = NULL;
|
2002-04-19 09:22:44 +00:00
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(p15card != NULL && p15card->magic == SC_PKCS15_CARD_MAGIC);
|
2002-01-16 23:59:18 +00:00
|
|
|
switch (df->type) {
|
|
|
|
case SC_PKCS15_PRKDF:
|
2002-01-17 23:47:03 +00:00
|
|
|
func = sc_pkcs15_encode_prkdf_entry;
|
2002-01-16 23:59:18 +00:00
|
|
|
break;
|
2002-03-03 00:32:28 +00:00
|
|
|
case SC_PKCS15_PUKDF:
|
|
|
|
case SC_PKCS15_PUKDF_TRUSTED:
|
|
|
|
func = sc_pkcs15_encode_pukdf_entry;
|
|
|
|
break;
|
2002-01-16 23:59:18 +00:00
|
|
|
case SC_PKCS15_CDF:
|
|
|
|
case SC_PKCS15_CDF_TRUSTED:
|
|
|
|
case SC_PKCS15_CDF_USEFUL:
|
|
|
|
func = sc_pkcs15_encode_cdf_entry;
|
|
|
|
break;
|
2002-12-18 10:17:01 +00:00
|
|
|
case SC_PKCS15_DODF:
|
|
|
|
func = sc_pkcs15_encode_dodf_entry;
|
|
|
|
break;
|
2002-01-17 23:47:03 +00:00
|
|
|
case SC_PKCS15_AODF:
|
|
|
|
func = sc_pkcs15_encode_aodf_entry;
|
|
|
|
break;
|
2002-01-16 23:59:18 +00:00
|
|
|
}
|
|
|
|
if (func == NULL) {
|
2003-08-25 14:21:18 +00:00
|
|
|
sc_error(ctx, "unknown DF type: %d\n", df->type);
|
2002-01-17 23:47:03 +00:00
|
|
|
*buf_out = NULL;
|
|
|
|
*bufsize_out = 0;
|
|
|
|
return 0;
|
2002-01-16 23:59:18 +00:00
|
|
|
}
|
2002-04-19 09:22:44 +00:00
|
|
|
for (obj = p15card->obj_list; obj != NULL; obj = obj->next) {
|
|
|
|
if (obj->df != df)
|
|
|
|
continue;
|
2002-01-17 23:47:03 +00:00
|
|
|
r = func(ctx, obj, &tmp, &tmpsize);
|
2002-01-16 23:59:18 +00:00
|
|
|
if (r) {
|
2004-04-21 18:10:58 +00:00
|
|
|
free(tmp);
|
2002-01-16 23:59:18 +00:00
|
|
|
free(buf);
|
|
|
|
return r;
|
|
|
|
}
|
2002-04-19 14:23:31 +00:00
|
|
|
buf = (u8 *) realloc(buf, bufsize + tmpsize);
|
2002-01-16 23:59:18 +00:00
|
|
|
memcpy(buf + bufsize, tmp, tmpsize);
|
2002-01-20 21:20:09 +00:00
|
|
|
free(tmp);
|
2002-01-16 23:59:18 +00:00
|
|
|
bufsize += tmpsize;
|
|
|
|
}
|
|
|
|
*buf_out = buf;
|
|
|
|
*bufsize_out = bufsize;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2002-01-24 16:02:54 +00:00
|
|
|
int sc_pkcs15_parse_df(struct sc_pkcs15_card *p15card,
|
2002-04-19 09:22:44 +00:00
|
|
|
struct sc_pkcs15_df *df)
|
2002-01-24 16:02:54 +00:00
|
|
|
{
|
2005-03-08 20:59:35 +00:00
|
|
|
sc_context_t *ctx = p15card->card->ctx;
|
2002-04-19 09:22:44 +00:00
|
|
|
u8 *buf;
|
2005-02-11 20:09:34 +00:00
|
|
|
const u8 *p;
|
2002-04-19 09:22:44 +00:00
|
|
|
size_t bufsize;
|
|
|
|
int r;
|
2002-01-24 16:02:54 +00:00
|
|
|
struct sc_pkcs15_object *obj = NULL;
|
|
|
|
int (* func)(struct sc_pkcs15_card *, struct sc_pkcs15_object *,
|
2004-10-17 20:20:59 +00:00
|
|
|
const u8 **nbuf, size_t *nbufsize) = NULL;
|
2002-01-24 16:02:54 +00:00
|
|
|
|
|
|
|
switch (df->type) {
|
|
|
|
case SC_PKCS15_PRKDF:
|
|
|
|
func = sc_pkcs15_decode_prkdf_entry;
|
|
|
|
break;
|
2002-03-07 12:33:42 +00:00
|
|
|
case SC_PKCS15_PUKDF:
|
|
|
|
func = sc_pkcs15_decode_pukdf_entry;
|
|
|
|
break;
|
2002-01-24 16:02:54 +00:00
|
|
|
case SC_PKCS15_CDF:
|
|
|
|
case SC_PKCS15_CDF_TRUSTED:
|
|
|
|
case SC_PKCS15_CDF_USEFUL:
|
|
|
|
func = sc_pkcs15_decode_cdf_entry;
|
|
|
|
break;
|
2002-12-18 10:17:01 +00:00
|
|
|
case SC_PKCS15_DODF:
|
|
|
|
func = sc_pkcs15_decode_dodf_entry;
|
|
|
|
break;
|
2002-01-24 16:02:54 +00:00
|
|
|
case SC_PKCS15_AODF:
|
|
|
|
func = sc_pkcs15_decode_aodf_entry;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (func == NULL) {
|
2003-08-25 14:21:18 +00:00
|
|
|
sc_error(ctx, "unknown DF type: %d\n", df->type);
|
2002-01-24 16:02:54 +00:00
|
|
|
return SC_ERROR_INVALID_ARGUMENTS;
|
|
|
|
}
|
2002-04-19 09:22:44 +00:00
|
|
|
if (df->file != NULL)
|
|
|
|
r = sc_pkcs15_read_file(p15card, &df->path,
|
|
|
|
&buf, &bufsize, NULL);
|
|
|
|
else
|
|
|
|
r = sc_pkcs15_read_file(p15card, &df->path,
|
|
|
|
&buf, &bufsize, &df->file);
|
2002-12-11 08:54:16 +00:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2002-04-19 09:22:44 +00:00
|
|
|
p = buf;
|
2006-09-26 10:31:03 +00:00
|
|
|
while (bufsize && *p != 0x00) {
|
2002-12-10 13:27:17 +00:00
|
|
|
const u8 *oldp;
|
|
|
|
size_t obj_len;
|
|
|
|
|
2005-01-03 17:20:17 +00:00
|
|
|
obj = (struct sc_pkcs15_object *) calloc(1, sizeof(struct sc_pkcs15_object));
|
2002-04-19 09:22:44 +00:00
|
|
|
if (obj == NULL) {
|
|
|
|
r = SC_ERROR_OUT_OF_MEMORY;
|
|
|
|
goto ret;
|
|
|
|
}
|
2002-12-10 13:27:17 +00:00
|
|
|
oldp = p;
|
2002-01-24 16:02:54 +00:00
|
|
|
r = func(p15card, obj, &p, &bufsize);
|
|
|
|
if (r) {
|
|
|
|
free(obj);
|
2003-10-30 11:43:21 +00:00
|
|
|
if (r == SC_ERROR_ASN1_END_OF_CONTENTS) {
|
|
|
|
r = 0;
|
2002-01-24 16:02:54 +00:00
|
|
|
break;
|
2003-10-30 11:43:21 +00:00
|
|
|
}
|
2002-01-24 16:02:54 +00:00
|
|
|
sc_perror(ctx, r, "Error decoding DF entry");
|
2002-04-19 09:22:44 +00:00
|
|
|
goto ret;
|
2002-01-24 16:02:54 +00:00
|
|
|
}
|
2002-12-10 13:27:17 +00:00
|
|
|
obj_len = p - oldp;
|
|
|
|
|
2003-01-14 19:55:45 +00:00
|
|
|
obj->der.value = (u8 *) malloc(obj_len);
|
2002-12-10 13:27:17 +00:00
|
|
|
if (obj->der.value == NULL) {
|
|
|
|
r = SC_ERROR_OUT_OF_MEMORY;
|
|
|
|
goto ret;
|
|
|
|
}
|
|
|
|
memcpy(obj->der.value, oldp, obj_len);
|
|
|
|
obj->der.len = obj_len;
|
|
|
|
|
2002-04-19 09:22:44 +00:00
|
|
|
obj->df = df;
|
|
|
|
r = sc_pkcs15_add_object(p15card, obj);
|
2002-01-24 16:02:54 +00:00
|
|
|
if (r) {
|
|
|
|
if (obj->data)
|
|
|
|
free(obj->data);
|
|
|
|
free(obj);
|
|
|
|
sc_perror(ctx, r, "Error adding object");
|
2002-04-19 09:22:44 +00:00
|
|
|
goto ret;
|
2002-01-24 16:02:54 +00:00
|
|
|
}
|
2006-09-26 10:31:03 +00:00
|
|
|
};
|
2002-04-19 09:22:44 +00:00
|
|
|
ret:
|
|
|
|
free(buf);
|
|
|
|
return r;
|
2002-01-24 16:02:54 +00:00
|
|
|
}
|
|
|
|
|
2005-12-17 19:53:12 +00:00
|
|
|
int sc_pkcs15_add_unusedspace(struct sc_pkcs15_card *p15card,
|
|
|
|
const sc_path_t *path, const sc_pkcs15_id_t *auth_id)
|
|
|
|
{
|
|
|
|
sc_pkcs15_unusedspace_t *p = p15card->unusedspace_list, *new_unusedspace;
|
|
|
|
|
|
|
|
if (path->count == -1) {
|
2006-01-11 23:41:17 +00:00
|
|
|
char pbuf[SC_MAX_PATH_STRING_SIZE];
|
|
|
|
|
|
|
|
int r = sc_path_print(pbuf, sizeof(pbuf), path);
|
|
|
|
if (r != SC_SUCCESS)
|
|
|
|
pbuf[0] = '\0';
|
|
|
|
|
|
|
|
sc_error(p15card->card->ctx, "No offset and length present in path %s\n", pbuf);
|
2005-12-17 19:53:12 +00:00
|
|
|
return SC_ERROR_INVALID_ARGUMENTS;
|
|
|
|
}
|
|
|
|
|
|
|
|
new_unusedspace = (sc_pkcs15_unusedspace_t *) calloc(1, sizeof(sc_pkcs15_unusedspace_t));
|
|
|
|
if (new_unusedspace == NULL)
|
|
|
|
return SC_ERROR_OUT_OF_MEMORY;
|
|
|
|
new_unusedspace->path = *path;
|
|
|
|
if (auth_id != NULL)
|
|
|
|
new_unusedspace->auth_id = *auth_id;
|
|
|
|
|
|
|
|
if (p15card->unusedspace_list == NULL) {
|
|
|
|
p15card->unusedspace_list = new_unusedspace;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
while (p->next != NULL)
|
|
|
|
p = p->next;
|
|
|
|
p->next = new_unusedspace;
|
|
|
|
new_unusedspace->prev = p;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void sc_pkcs15_remove_unusedspace(struct sc_pkcs15_card *p15card,
|
|
|
|
sc_pkcs15_unusedspace_t *unusedspace)
|
|
|
|
{
|
|
|
|
if (unusedspace->prev == NULL)
|
|
|
|
p15card->unusedspace_list = unusedspace->next;
|
|
|
|
else
|
|
|
|
unusedspace->prev->next = unusedspace->next;
|
|
|
|
if (unusedspace->next != NULL)
|
|
|
|
unusedspace->next->prev = unusedspace->prev;
|
|
|
|
free(unusedspace);
|
|
|
|
}
|
|
|
|
|
|
|
|
int sc_pkcs15_encode_unusedspace(sc_context_t *ctx,
|
|
|
|
struct sc_pkcs15_card *p15card,
|
|
|
|
u8 **buf, size_t *buflen)
|
|
|
|
{
|
2005-12-17 21:52:53 +00:00
|
|
|
sc_path_t dummy_path;
|
2005-12-17 19:53:12 +00:00
|
|
|
static const struct sc_asn1_entry c_asn1_unusedspace[] = {
|
2006-01-20 20:52:36 +00:00
|
|
|
{ "UnusedSpace", SC_ASN1_STRUCT, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, 0, NULL, NULL },
|
2005-12-17 19:53:12 +00:00
|
|
|
{ NULL, 0, 0, 0, NULL, NULL }
|
|
|
|
};
|
|
|
|
static const struct sc_asn1_entry c_asn1_unusedspace_values[] = {
|
2006-01-20 20:52:36 +00:00
|
|
|
{ "path", SC_ASN1_PATH, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, 0, NULL, NULL },
|
|
|
|
{ "authId", SC_ASN1_PKCS15_ID, SC_ASN1_TAG_OCTET_STRING, SC_ASN1_OPTIONAL, NULL, NULL },
|
2005-12-17 19:53:12 +00:00
|
|
|
{ NULL, 0, 0, 0, NULL, NULL }
|
|
|
|
};
|
|
|
|
struct sc_asn1_entry *asn1_unusedspace = NULL;
|
|
|
|
struct sc_asn1_entry *asn1_values = NULL;
|
|
|
|
int unusedspace_count = 0, r, c = 0;
|
|
|
|
sc_pkcs15_unusedspace_t *unusedspace;
|
|
|
|
|
|
|
|
sc_format_path("3F00", &dummy_path);
|
|
|
|
dummy_path.index = dummy_path.count = 0;
|
|
|
|
|
|
|
|
unusedspace = p15card->unusedspace_list;
|
|
|
|
for ( ; unusedspace != NULL; unusedspace = unusedspace->next)
|
|
|
|
unusedspace_count++;
|
|
|
|
if (unusedspace_count == 0) {
|
|
|
|
/* The standard says there has to be at least 1 entry,
|
|
|
|
* so we use a path with a length of 0 bytes */
|
|
|
|
r = sc_pkcs15_add_unusedspace(p15card, &dummy_path, NULL);
|
|
|
|
if (r)
|
|
|
|
return r;
|
|
|
|
unusedspace_count = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
asn1_unusedspace = (struct sc_asn1_entry *)
|
|
|
|
malloc(sizeof(struct sc_asn1_entry) * (unusedspace_count + 1));
|
|
|
|
if (asn1_unusedspace == NULL) {
|
|
|
|
r = SC_ERROR_OUT_OF_MEMORY;
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
asn1_values = (struct sc_asn1_entry *)
|
|
|
|
malloc(sizeof(struct sc_asn1_entry) * (unusedspace_count * 3));
|
|
|
|
if (asn1_values == NULL) {
|
|
|
|
r = SC_ERROR_OUT_OF_MEMORY;
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (unusedspace = p15card->unusedspace_list; unusedspace != NULL; unusedspace = unusedspace->next) {
|
|
|
|
sc_copy_asn1_entry(c_asn1_unusedspace, asn1_unusedspace + c);
|
|
|
|
sc_format_asn1_entry(asn1_unusedspace + c, asn1_values + 3*c, NULL, 1);
|
|
|
|
sc_copy_asn1_entry(c_asn1_unusedspace_values, asn1_values + 3*c);
|
|
|
|
sc_format_asn1_entry(asn1_values + 3*c, &unusedspace->path, NULL, 1);
|
|
|
|
sc_format_asn1_entry(asn1_values + 3*c+1, &unusedspace->auth_id, NULL, unusedspace->auth_id.len);
|
|
|
|
c++;
|
|
|
|
}
|
|
|
|
asn1_unusedspace[c].name = NULL;
|
|
|
|
|
|
|
|
r = sc_asn1_encode(ctx, asn1_unusedspace, buf, buflen);
|
|
|
|
|
|
|
|
err:
|
|
|
|
if (asn1_values != NULL)
|
|
|
|
free(asn1_values);
|
|
|
|
if (asn1_unusedspace != NULL)
|
|
|
|
free(asn1_unusedspace);
|
|
|
|
|
|
|
|
/* If we added the dummy entry, remove it now */
|
|
|
|
if (unusedspace_count == 1 && sc_compare_path(&p15card->unusedspace_list->path, &dummy_path))
|
|
|
|
sc_pkcs15_remove_unusedspace(p15card, p15card->unusedspace_list);
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
int sc_pkcs15_parse_unusedspace(const u8 * buf, size_t buflen, struct sc_pkcs15_card *card)
|
|
|
|
{
|
|
|
|
const u8 *p = buf;
|
|
|
|
size_t left = buflen;
|
2005-12-17 21:52:53 +00:00
|
|
|
int r;
|
2005-12-17 19:53:12 +00:00
|
|
|
sc_path_t path, dummy_path;
|
|
|
|
sc_pkcs15_id_t auth_id;
|
|
|
|
struct sc_asn1_entry asn1_unusedspace[] = {
|
2006-01-20 20:52:36 +00:00
|
|
|
{ "UnusedSpace", SC_ASN1_STRUCT, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, 0, NULL, NULL },
|
2005-12-17 19:53:12 +00:00
|
|
|
{ NULL, 0, 0, 0, NULL, NULL }
|
|
|
|
};
|
|
|
|
struct sc_asn1_entry asn1_unusedspace_values[] = {
|
2006-01-20 20:52:36 +00:00
|
|
|
{ "path", SC_ASN1_PATH, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, 0, NULL, NULL },
|
|
|
|
{ "authId", SC_ASN1_PKCS15_ID, SC_ASN1_TAG_OCTET_STRING, SC_ASN1_OPTIONAL, NULL, NULL },
|
2005-12-17 19:53:12 +00:00
|
|
|
{ NULL, 0, 0, 0, NULL, NULL }
|
|
|
|
};
|
|
|
|
|
|
|
|
/* Clean the list if already present */
|
|
|
|
while (card->unusedspace_list)
|
|
|
|
sc_pkcs15_remove_unusedspace(card, card->unusedspace_list);
|
|
|
|
|
|
|
|
sc_format_path("3F00", &dummy_path);
|
|
|
|
dummy_path.index = dummy_path.count = 0;
|
|
|
|
|
|
|
|
sc_format_asn1_entry(asn1_unusedspace, asn1_unusedspace_values, NULL, 1);
|
|
|
|
sc_format_asn1_entry(asn1_unusedspace_values, &path, NULL, 1);
|
|
|
|
sc_format_asn1_entry(asn1_unusedspace_values+1, &auth_id, NULL, 0);
|
|
|
|
|
|
|
|
while (left > 0) {
|
|
|
|
memset(&auth_id, 0, sizeof(auth_id));
|
|
|
|
r = sc_asn1_decode(card->card->ctx, asn1_unusedspace, p, left, &p, &left);
|
|
|
|
if (r == SC_ERROR_ASN1_END_OF_CONTENTS)
|
|
|
|
break;
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
/* If the path length is 0, it's a dummy path then don't add it.
|
2006-09-26 10:55:02 +00:00
|
|
|
* If the path length isn't included (-1) then it's against the standard
|
2005-12-17 19:53:12 +00:00
|
|
|
* but we'll just ignore it instead of returning an error. */
|
|
|
|
if (path.count > 0) {
|
2006-09-26 10:55:02 +00:00
|
|
|
r = sc_pkcs15_make_absolute_path(&card->file_app->path, &path);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2005-12-17 19:53:12 +00:00
|
|
|
r = sc_pkcs15_add_unusedspace(card, &path, &auth_id);
|
|
|
|
if (r)
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
card->unusedspace_read = 1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2002-04-17 09:00:16 +00:00
|
|
|
int sc_pkcs15_read_file(struct sc_pkcs15_card *p15card,
|
2005-03-08 20:59:35 +00:00
|
|
|
const sc_path_t *in_path,
|
2002-04-19 09:22:44 +00:00
|
|
|
u8 **buf, size_t *buflen,
|
2005-03-08 20:59:35 +00:00
|
|
|
sc_file_t **file_out)
|
2002-04-17 09:00:16 +00:00
|
|
|
{
|
2005-03-08 20:59:35 +00:00
|
|
|
sc_file_t *file = NULL;
|
2002-04-17 09:00:16 +00:00
|
|
|
u8 *data = NULL;
|
2002-12-02 13:38:50 +00:00
|
|
|
size_t len = 0, offset = 0;
|
2006-01-23 17:29:59 +00:00
|
|
|
int r;
|
2002-04-17 09:00:16 +00:00
|
|
|
|
2003-05-13 07:06:29 +00:00
|
|
|
assert(p15card != NULL && in_path != NULL && buf != NULL);
|
2006-01-11 23:41:17 +00:00
|
|
|
|
|
|
|
if (p15card->card->ctx->debug >= 1) {
|
|
|
|
char pbuf[SC_MAX_PATH_STRING_SIZE];
|
|
|
|
|
|
|
|
r = sc_path_print(pbuf, sizeof(pbuf), in_path);
|
|
|
|
if (r != SC_SUCCESS)
|
|
|
|
pbuf[0] = '\0';
|
|
|
|
|
|
|
|
sc_debug(p15card->card->ctx, "called, path=%s, index=%u, count=%d\n",
|
|
|
|
pbuf, in_path->index, in_path->count);
|
|
|
|
}
|
2002-12-02 13:38:50 +00:00
|
|
|
|
2006-01-23 17:29:59 +00:00
|
|
|
r = -1; /* file state: not in cache */
|
2002-04-19 09:22:44 +00:00
|
|
|
if (p15card->opts.use_cache) {
|
2006-09-26 10:55:02 +00:00
|
|
|
r = sc_pkcs15_read_cached_file(p15card, in_path, &data, &len);
|
2002-04-17 09:00:16 +00:00
|
|
|
}
|
|
|
|
if (r) {
|
|
|
|
r = sc_lock(p15card->card);
|
|
|
|
SC_TEST_RET(p15card->card->ctx, r, "sc_lock() failed");
|
2006-09-26 10:55:02 +00:00
|
|
|
r = sc_select_file(p15card->card, in_path, &file);
|
2004-01-06 13:40:52 +00:00
|
|
|
if (r)
|
|
|
|
goto fail_unlock;
|
|
|
|
|
2002-12-02 13:38:50 +00:00
|
|
|
/* Handle the case where the ASN.1 Path object specified
|
|
|
|
* index and length values */
|
2006-09-26 10:55:02 +00:00
|
|
|
if (in_path->count < 0) {
|
2002-12-02 13:38:50 +00:00
|
|
|
len = file->size;
|
|
|
|
offset = 0;
|
|
|
|
} else {
|
2006-09-26 10:55:02 +00:00
|
|
|
offset = in_path->index;
|
|
|
|
len = in_path->count;
|
2002-12-02 13:38:50 +00:00
|
|
|
/* Make sure we're within proper bounds */
|
|
|
|
if (offset >= file->size
|
2004-03-28 20:30:58 +00:00
|
|
|
|| offset + len > file->size) {
|
2004-01-06 13:40:52 +00:00
|
|
|
r = SC_ERROR_INVALID_ASN1_OBJECT;
|
|
|
|
goto fail_unlock;
|
2002-12-02 13:38:50 +00:00
|
|
|
}
|
|
|
|
}
|
2002-04-19 14:23:31 +00:00
|
|
|
data = (u8 *) malloc(len);
|
2002-04-17 09:00:16 +00:00
|
|
|
if (data == NULL) {
|
2004-01-06 13:40:52 +00:00
|
|
|
r = SC_ERROR_OUT_OF_MEMORY;
|
|
|
|
goto fail_unlock;
|
2002-04-17 09:00:16 +00:00
|
|
|
}
|
2006-10-02 16:49:26 +00:00
|
|
|
if (file->ef_structure == SC_FILE_EF_LINEAR_VARIABLE_TLV) {
|
2006-09-26 10:36:35 +00:00
|
|
|
int i;
|
2006-09-26 10:43:28 +00:00
|
|
|
size_t l, record_len;
|
2006-09-26 10:36:35 +00:00
|
|
|
unsigned char *head;
|
|
|
|
|
|
|
|
head = data;
|
|
|
|
for (i=1; ; i++) {
|
|
|
|
l = len - (head - data);
|
|
|
|
if (l > 256) { l = 256; }
|
|
|
|
p15card->card->ctx->suppress_errors++;
|
|
|
|
r = sc_read_record(p15card->card, i, head, l,
|
|
|
|
SC_RECORD_BY_REC_NR);
|
|
|
|
p15card->card->ctx->suppress_errors--;
|
|
|
|
if (r == SC_ERROR_RECORD_NOT_FOUND)
|
|
|
|
break;
|
|
|
|
if (r < 0) {
|
|
|
|
free(data);
|
|
|
|
goto fail_unlock;
|
|
|
|
}
|
2006-09-26 10:43:28 +00:00
|
|
|
if (r < 2)
|
2006-09-26 10:36:35 +00:00
|
|
|
break;
|
2006-09-26 10:43:28 +00:00
|
|
|
record_len = head[1];
|
|
|
|
if (record_len != 0xff) {
|
|
|
|
memmove(head,head+2,r-2);
|
|
|
|
head += (r-2);
|
|
|
|
} else {
|
|
|
|
if (r < 4)
|
|
|
|
break;
|
|
|
|
record_len = head[2] * 256 + head[3];
|
|
|
|
memmove(head,head+4,r-4);
|
|
|
|
head += (r-4);
|
|
|
|
}
|
2006-09-26 10:36:35 +00:00
|
|
|
}
|
|
|
|
len = head-data;
|
|
|
|
r = len;
|
|
|
|
} else {
|
2006-10-02 16:49:26 +00:00
|
|
|
r = sc_read_binary(p15card->card, offset, data, len, 0);
|
|
|
|
if (r < 0) {
|
|
|
|
free(data);
|
|
|
|
goto fail_unlock;
|
|
|
|
}
|
|
|
|
/* sc_read_binary may return less than requested */
|
|
|
|
len = r;
|
|
|
|
}
|
2002-04-17 09:00:16 +00:00
|
|
|
sc_unlock(p15card->card);
|
2004-01-06 13:40:52 +00:00
|
|
|
|
|
|
|
/* Return of release file */
|
|
|
|
if (file_out != NULL)
|
|
|
|
*file_out = file;
|
|
|
|
else
|
|
|
|
sc_file_free(file);
|
2002-04-17 09:00:16 +00:00
|
|
|
}
|
|
|
|
*buf = data;
|
|
|
|
*buflen = len;
|
|
|
|
return 0;
|
2004-01-06 13:40:52 +00:00
|
|
|
|
|
|
|
fail_unlock:
|
|
|
|
if (file)
|
|
|
|
sc_file_free(file);
|
|
|
|
sc_unlock(p15card->card);
|
|
|
|
return r;
|
2002-04-17 09:00:16 +00:00
|
|
|
}
|
|
|
|
|
2001-11-01 15:43:20 +00:00
|
|
|
int sc_pkcs15_compare_id(const struct sc_pkcs15_id *id1,
|
|
|
|
const struct sc_pkcs15_id *id2)
|
|
|
|
{
|
|
|
|
assert(id1 != NULL && id2 != NULL);
|
|
|
|
if (id1->len != id2->len)
|
|
|
|
return 0;
|
|
|
|
return memcmp(id1->value, id2->value, id1->len) == 0;
|
|
|
|
}
|
|
|
|
|
2002-01-17 23:47:03 +00:00
|
|
|
void sc_pkcs15_format_id(const char *str, struct sc_pkcs15_id *id)
|
|
|
|
{
|
2002-12-04 15:36:33 +00:00
|
|
|
size_t len = sizeof(id->value);
|
2002-01-17 23:47:03 +00:00
|
|
|
|
2002-12-04 15:36:33 +00:00
|
|
|
if (sc_hex_to_bin(str, id->value, &len) >= 0)
|
|
|
|
id->len = len;
|
2002-01-17 23:47:03 +00:00
|
|
|
}
|
|
|
|
|
2003-11-19 20:30:44 +00:00
|
|
|
const char *sc_pkcs15_print_id(const struct sc_pkcs15_id *id)
|
2001-11-01 15:43:20 +00:00
|
|
|
{
|
2003-11-19 20:30:44 +00:00
|
|
|
static char buffer[256];
|
2001-11-01 15:43:20 +00:00
|
|
|
|
2003-11-19 20:30:44 +00:00
|
|
|
sc_bin_to_hex(id->value, id->len, buffer, sizeof(buffer), '\0');
|
|
|
|
return buffer;
|
2001-11-01 15:43:20 +00:00
|
|
|
}
|
2001-11-20 22:21:58 +00:00
|
|
|
|
|
|
|
int sc_pkcs15_hex_string_to_id(const char *in, struct sc_pkcs15_id *out)
|
|
|
|
{
|
2002-01-08 13:56:50 +00:00
|
|
|
out->len = sizeof(out->value);
|
2001-11-20 22:21:58 +00:00
|
|
|
return sc_hex_to_bin(in, out->value, &out->len);
|
|
|
|
}
|
2006-09-26 10:55:02 +00:00
|
|
|
|
|
|
|
int sc_pkcs15_make_absolute_path(const sc_path_t *parent, sc_path_t *child)
|
|
|
|
{
|
2006-09-27 12:02:02 +00:00
|
|
|
/* a 0 length path stays a 0 length path */
|
|
|
|
if (child->len == 0)
|
|
|
|
return SC_SUCCESS;
|
|
|
|
|
2006-09-26 10:55:02 +00:00
|
|
|
if (sc_compare_path_prefix(sc_get_mf_path(), child))
|
2006-09-27 12:02:02 +00:00
|
|
|
return SC_SUCCESS;
|
2006-09-26 10:55:02 +00:00
|
|
|
return sc_concatenate_path(child, parent, child);
|
|
|
|
}
|