From 0f82c7c1d456acfde9d788cab175c25818c118f5 Mon Sep 17 00:00:00 2001 From: "viktor.tarasov" Date: Thu, 18 Mar 2010 12:30:39 +0000 Subject: [PATCH] oberthur: pkcs15init emulator Now the native Oberthur card format is supported for emulation of pkcs15 and pkcs15init. It means that card personalized with OpenSC and the obejcts created with OpenSC will be usable with the native Oberthur's middleware and vice-versa. git-svn-id: https://www.opensc-project.org/svnp/opensc/trunk@4137 c6295689-39f2-0310-b995-f0e70906c6a9 --- src/libopensc/pkcs15-oberthur.c | 2 +- src/pkcs15init/Makefile.am | 7 +- src/pkcs15init/pkcs15-oberthur-awp.c | 1856 ++++++++++++++++++++++++++ src/pkcs15init/pkcs15-oberthur.c | 116 +- 4 files changed, 1968 insertions(+), 13 deletions(-) create mode 100644 src/pkcs15init/pkcs15-oberthur-awp.c diff --git a/src/libopensc/pkcs15-oberthur.c b/src/libopensc/pkcs15-oberthur.c index 2645c4fa..a080a407 100644 --- a/src/libopensc/pkcs15-oberthur.c +++ b/src/libopensc/pkcs15-oberthur.c @@ -101,7 +101,7 @@ static int sc_oberthur_parse_privateinfo (struct sc_pkcs15_card *, unsigned char static int sc_awp_parse_df(struct sc_pkcs15_card *, struct sc_pkcs15_df *); struct crypto_container { - unsigned int id_pub; + unsigned id_pub; unsigned id_prv; unsigned id_cert; }; diff --git a/src/pkcs15init/Makefile.am b/src/pkcs15init/Makefile.am index 7244c3e7..c9175f23 100644 --- a/src/pkcs15init/Makefile.am +++ b/src/pkcs15init/Makefile.am @@ -34,6 +34,7 @@ libpkcs15init_la_SOURCES = \ pkcs15-westcos.c \ pkcs15-gpk.c pkcs15-miocos.c pkcs15-cflex.c \ pkcs15-cardos.c pkcs15-jcop.c pkcs15-starcos.c \ - pkcs15-oberthur.c pkcs15-setcos.c pkcs15-incrypto34.c \ - pkcs15-muscle.c pkcs15-asepcos.c pkcs15-rutoken.c \ - pkcs15-entersafe.c pkcs15-rtecp.c pkcs15-myeid.c + pkcs15-setcos.c pkcs15-incrypto34.c pkcs15-muscle.c \ + pkcs15-asepcos.c pkcs15-rutoken.c pkcs15-entersafe.c \ + pkcs15-rtecp.c pkcs15-myeid.c \ + pkcs15-oberthur.c pkcs15-oberthur-awp.c diff --git a/src/pkcs15init/pkcs15-oberthur-awp.c b/src/pkcs15init/pkcs15-oberthur-awp.c new file mode 100644 index 00000000..ae629d4d --- /dev/null +++ b/src/pkcs15init/pkcs15-oberthur-awp.c @@ -0,0 +1,1856 @@ +/* + * Oberthur AWP extention for PKCS #15 initialization + * + * Copyright (C) 2010 Viktor Tarasov + * Copyright (C) 2002 Juha Yrj�l� + * + * 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 + * + * best view with tabstop=4 + * + */ + +#include +#include +#include + +#include "config.h" +#include "libopensc/opensc.h" +#include "libopensc/cardctl.h" +#include "libopensc/log.h" +#include "profile.h" +#include "pkcs15-init.h" +#include "pkcs15-oberthur.h" + +#ifdef ENABLE_OPENSSL + +struct awp_lv zero_lv = { 0, NULL }; +struct awp_lv x30_lv = { 0x10, (unsigned char *)"0000000000000000" }; + +static unsigned char * +awp_get_commonName(X509 *x) +{ + unsigned char *ret = NULL; + int r; + + r = X509_NAME_get_index_by_NID(X509_get_subject_name(x), + NID_commonName, -1); + if (r >= 0) { + X509_NAME_ENTRY *ne; + ASN1_STRING *a_str; + + if (!(ne = X509_NAME_get_entry(X509_get_subject_name(x), r))) + ; + else if (!(a_str = X509_NAME_ENTRY_get_data(ne))) + ; + else if (a_str->type == 0x0C) { + ret = malloc(a_str->length + 1); + if (ret) { + memcpy(ret, a_str->data, a_str->length); + *(ret + a_str->length) = '\0'; + } + } + else { + unsigned char *tmp = NULL; + + r = ASN1_STRING_to_UTF8(&tmp, a_str); + if (r > 0) { + ret = malloc(r + 1); + if (ret) { + memcpy(ret, tmp, r); + *(ret + r) = '\0'; + } + + OPENSSL_free(tmp); + } + } + } + + return ret; +} + +static int +awp_new_file(struct sc_pkcs15_card *p15card, struct sc_profile *profile, + unsigned int type, unsigned int num, + struct sc_file **info_out, struct sc_file **obj_out) +{ + struct sc_context *ctx = p15card->card->ctx; + struct sc_file *ifile=NULL, *ofile=NULL; + char name[NAME_MAX_LEN], *itag=NULL, *desc=NULL, *otag=NULL; + + SC_FUNC_CALLED(ctx, 1); + sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "type 0x%X; num %i; info %p; obj %p\n", type, num, info_out, obj_out); + switch (type) { + case SC_PKCS15_TYPE_CERT_X509: + desc = "Oberthur AWP certificate info"; + itag = "certificate-info"; + otag = "template-certificate"; + break; + case SC_PKCS15_TYPE_PRKEY_RSA: + case COSM_TYPE_PRKEY_RSA: + desc = "Oberthur AWP private key info"; + itag = "private-key-info"; + otag = "template-private-key"; + break; + case SC_PKCS15_TYPE_PUBKEY_RSA: + case COSM_TYPE_PUBKEY_RSA: + desc = "Oberthur AWP public key info"; + itag = "public-key-info"; + otag = "template-public-key"; + break; + case SC_PKCS15_TYPE_DATA_OBJECT: + desc = "Oberthur AWP data object info"; + itag = "public-data-info"; + otag = "template-public-data"; + break; + case SC_PKCS15_TYPE_AUTH_PIN: + case COSM_TOKENINFO : + desc = "Oberthur AWP token info"; + itag = "token-info"; + num = 0; + break; + case COSM_PUBLIC_LIST: + desc = "Oberthur AWP public object list"; + itag = "public-list"; + num = 0; + break; + case COSM_PRIVATE_LIST: + desc = "Oberthur AWP private object list"; + itag = "private-list"; + num = 0; + break; + case COSM_CONTAINER_LIST: + desc = "Oberthur AWP container list"; + itag = "container-list"; + num = 0; + break; + default: + return SC_ERROR_INVALID_ARGUMENTS; + } + + if (itag) { + snprintf(name, sizeof(name),"%s-%s", COSM_TITLE, itag); + sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "info template %s\n",name); + if (sc_profile_get_file(profile, name, &ifile) < 0) { + sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "profile does not defines template '%s'\n", name); + return SC_ERROR_INCONSISTENT_PROFILE; + } + } + + if (otag) { + sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "obj template %s\n",otag); + if (sc_profile_get_file(profile, otag, &ofile) < 0) { + sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "profile does not defines template '%s'\n", name); + return SC_ERROR_INCONSISTENT_PROFILE; + } + + ofile->id |= (num & 0xFF); + ofile->path.value[ofile->path.len-1] |= (num & 0xFF); + } + + if (ifile) { + if(info_out) { + if (ofile) { + ifile->id = ofile->id | 0x100; + + ifile->path = ofile->path; + ifile->path.value[ifile->path.len-2] |= 0x01; + } + + sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "info_file(id:%04X,size:%i,rlen:%i)", + ifile->id, ifile->size, ifile->record_length); + *info_out = ifile; + } + else { + sc_file_free(ifile); + } + } + + if (ofile) { + sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "obj file %04X; size %i; ", ofile->id, ofile->size); + if (obj_out) + *obj_out = ofile; + else + sc_file_free(ofile); + } + + SC_FUNC_RETURN(ctx, 1, SC_SUCCESS); +} + + +static int +awp_update_blob(struct sc_context *ctx, + unsigned char **blob, int *blob_size, + struct awp_lv *lv, int type) +{ + unsigned char *pp; + + SC_FUNC_CALLED(ctx, 1); + switch (type) { + case TLV_TYPE_LLV : + if (!(pp = realloc(*blob, *blob_size + 2 + lv->len))) + return SC_ERROR_MEMORY_FAILURE; + *(pp + *blob_size) = (lv->len >> 8) & 0xFF; + *(pp + *blob_size + 1) = lv->len & 0xFF; + memcpy(pp + *blob_size + 2, lv->value, (lv->len & 0xFF)); + *blob_size += 2 + lv->len; + break; + case TLV_TYPE_LV : + if (!(pp = realloc(*blob, *blob_size + 1 + lv->len))) + return SC_ERROR_MEMORY_FAILURE; + *(pp + *blob_size) = lv->len & 0xFF; + memcpy(pp + *blob_size + 1, lv->value, (lv->len & 0xFF)); + *blob_size += 1 + lv->len; + break; + case TLV_TYPE_V : + if (!(pp = realloc(*blob, *blob_size + lv->len))) + return SC_ERROR_MEMORY_FAILURE; + memcpy(pp + *blob_size, lv->value, lv->len); + *blob_size += lv->len; + break; + default: + sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "Invalid tlv type %i\n",type); + return SC_ERROR_INCORRECT_PARAMETERS; + } + + *blob = pp; + + SC_FUNC_RETURN(ctx, 1, SC_SUCCESS); +} + + +static int +awp_new_container_entry(struct sc_pkcs15_card *p15card, unsigned char *buff, int len) +{ + struct sc_context *ctx = p15card->card->ctx; + int ii, mm, rv = 0; + int marks[5] = {4,6,8,10,0}; + unsigned char rand[0x10]; + + SC_FUNC_CALLED(ctx, 1); + if (len<0x34) + SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_INCORRECT_PARAMETERS, "Invalid container update size"); + + rv = sc_get_challenge(p15card->card, rand, sizeof(rand)); + SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, rv, "Cannot get challenge"); + + *(buff + 12) = 0x26; + *(buff + 13) = '{'; + for (ii=0, mm = 0; iicard->ctx; + int rv; + unsigned char *buff = NULL; + + SC_FUNC_CALLED(ctx, 1); + sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "container file(file-id:%X,rlen:%i,rcount:%i)\n", + list_file->id, list_file->record_length, list_file->record_count); + + buff = malloc(list_file->record_length); + if (!buff) + SC_FUNC_RETURN(ctx, 1, SC_ERROR_MEMORY_FAILURE); + + memset(buff, 0, list_file->record_length); + + rv = awp_new_container_entry(p15card, buff, list_file->record_length); + sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "rv:%i", rv); + SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, rv, "Cannot create container"); + + *(buff + 0) = (acc->pubkey_id >> 8) & 0xFF; + *(buff + 1) = acc->pubkey_id & 0xFF; + *(buff + 2) = (acc->prkey_id >> 8) & 0xFF; + *(buff + 3) = acc->prkey_id & 0xFF; + *(buff + 4) = (acc->cert_id >> 8) & 0xFF; + *(buff + 5) = acc->cert_id & 0xFF; + + rv = sc_select_file(p15card->card, &list_file->path, NULL); + sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "rv:%i", rv); + if (rv == SC_ERROR_FILE_NOT_FOUND) { + rv = sc_pkcs15init_create_file(profile, p15card, list_file); + sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "rv:%i", rv); + } + + if (!rv) { + rv = sc_append_record(p15card->card, buff, list_file->record_length, SC_RECORD_BY_REC_NR); + sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "rv:%i", rv); + } + + free(buff); + + SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, rv, "return after failure"); + + rv = 0; + SC_FUNC_RETURN(ctx, 1, rv); +} + + +static int +awp_create_container(struct sc_pkcs15_card *p15card, struct sc_profile *profile, int type, + struct awp_lv *key_id, struct awp_crypto_container *acc) +{ + struct sc_context *ctx = p15card->card->ctx; + struct sc_file *clist = NULL, *file = NULL; + int rv = 0, rec_offs; + unsigned char *list = NULL; + + SC_FUNC_CALLED(ctx, 1); + sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "create container(%X:%X:%X)\n", acc->prkey_id, acc->cert_id, acc->pubkey_id); + + rv = awp_new_file(p15card, profile, COSM_CONTAINER_LIST, 0, &clist, NULL); + SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, rv, "Create container failed"); + sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "contaner cfile(rcount:%i,rlength:%i)\n", clist->record_count, clist->record_length); + + rv = sc_select_file(p15card->card, &clist->path, &file); + SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, rv, "Create container failed: cannot select container's list"); + file->record_length = clist->record_length; + + sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "contaner file(rcount:%i,rlength:%i)\n", file->record_count, file->record_length); + rec_offs = 0; + sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "Append new record %i for private key\n", file->record_count + 1); + + rv = awp_create_container_record(p15card, profile, file, acc); + + if (clist) + sc_file_free(clist); + if (file) + sc_file_free(file); + if (list) + free(list); + + SC_FUNC_RETURN(ctx, 1, rv); +} + + +static int +awp_update_container_entry (struct sc_pkcs15_card *p15card, struct sc_profile *profile, + struct sc_file *list_file, int type, int file_id, + int rec, int offs) +{ + struct sc_context *ctx = p15card->card->ctx; + int rv; + unsigned char *buff = NULL; + + SC_FUNC_CALLED(ctx, 1); + sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "update container entry(type:%X,len:%i,count %i,rec %i,offs %i\n", type, file_id, rec, offs); + sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "container file(file-id:%X,rlen:%i,rcount:%i)\n", + list_file->id, list_file->record_length, list_file->record_count); + + buff = malloc(list_file->record_length); + if (!buff) + SC_FUNC_RETURN(ctx, 1, SC_ERROR_MEMORY_FAILURE); + + memset(buff, 0, list_file->record_length); + + if (rec > list_file->record_count) { + rv = awp_new_container_entry(p15card, buff, list_file->record_length); + SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, rv, "Cannot create container"); + } + else { + rv = sc_select_file(p15card->card, &list_file->path, NULL); + SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, rv, "Cannot select list_file"); + + rv = sc_read_record(p15card->card, rec, buff, list_file->record_length, SC_RECORD_BY_REC_NR); + SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, rv, "Cannot read record"); + } + + switch (type) { + case SC_PKCS15_TYPE_PUBKEY_RSA: + case COSM_TYPE_PUBKEY_RSA: + if (*(buff + offs + 4)) + sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "Insert public key to container that contains certificate %02X%02X\n", + *(buff + offs + 4), *(buff + offs + 5)); + *(buff + offs + 0) = (file_id >> 8) & 0xFF; + *(buff + offs + 1) = file_id & 0xFF; + break; + case SC_PKCS15_TYPE_PRKEY_RSA: + case COSM_TYPE_PRKEY_RSA: + if (*(buff + offs + 2)) + SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_INVALID_CARD, "private key exists already"); + + *(buff + offs + 2) = (file_id >> 8) & 0xFF; + *(buff + offs + 3) = file_id & 0xFF; + break; + case SC_PKCS15_TYPE_CERT_X509 : + *(buff + offs + 4) = (file_id >> 8) & 0xFF; + *(buff + offs + 5) = file_id & 0xFF; + break; + default: + SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_INCORRECT_PARAMETERS, "invalid object type"); + } + + if (rec > list_file->record_count) { + rv = sc_select_file(p15card->card, &list_file->path, NULL); + if (rv == SC_ERROR_FILE_NOT_FOUND) + rv = sc_pkcs15init_create_file(profile, p15card, list_file); + + if (!rv) + rv = sc_append_record(p15card->card, buff, list_file->record_length, SC_RECORD_BY_REC_NR); + } + else { + rv = sc_update_record(p15card->card, rec, buff, list_file->record_length, SC_RECORD_BY_REC_NR); + sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "rv:%i", rv); + } + + free(buff); + + SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, rv, "return after failure"); + + rv = 0; + SC_FUNC_RETURN(ctx, 1, rv); +} + + +static int +awp_remove_container_entry (struct sc_pkcs15_card *p15card, struct sc_profile *profile, + int type, int file_id) +{ + struct sc_context *ctx = p15card->card->ctx; + struct sc_file *clist=NULL, *file=NULL; + int rv = 0, ii; + unsigned rec, rec_len; + unsigned char *buff=NULL, id[2]; + + SC_FUNC_CALLED(ctx, 1); + sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "file_id %X\n", file_id); + + rv = awp_new_file(p15card, profile, COSM_CONTAINER_LIST, 0, &clist, NULL); + if (rv) + goto done; + + rv = sc_select_file(p15card->card, &clist->path, &file); + if (rv) + goto done; + + if (!(buff = malloc(file->record_length))) { + rv = SC_ERROR_MEMORY_FAILURE; + goto done; + } + + id[0] = (file_id >> 8) & 0xFF; + id[1] = file_id & 0xFF; + + for (rec = 1; rec <= file->record_count; rec++) { + rv = sc_read_record(p15card->card, rec, buff, file->record_length, SC_RECORD_BY_REC_NR); + if (rv < 0) + break; + rec_len = rv; + + for (ii=0; ii<12; ii+=2) + if (!memcmp(id, buff+ii, 2)) + break; + if (ii==12) + continue; + + *(buff + ii + 0) = 0; + *(buff + ii + 1) = 0; + + if (type == SC_PKCS15_TYPE_PRKEY_RSA || type == COSM_TYPE_PRKEY_RSA) + memset(buff + ii/6*6, 0, 6); + + if (!memcmp(buff,"\0\0\0\0\0\0\0\0\0\0\0\0",12)) { + rv = sc_pkcs15init_authenticate(profile, p15card, file, SC_AC_OP_ERASE); + if (rv) + break; + rv = sc_delete_record(p15card->card, rec); + + if (rv) + break; + + rv = awp_remove_container_entry(p15card, profile, type, file_id); + break; + } + else { + rv = sc_pkcs15init_authenticate(profile, p15card, file, SC_AC_OP_UPDATE); + if (rv) + break; + rv = sc_update_record(p15card->card, rec, buff, rec_len, SC_RECORD_BY_REC_NR); + } + + if (rv<0) + break; + } + + if (rv>0) + rv = 0; + +done: + if (buff) free(buff); + if (file) sc_file_free(file); + if (clist) sc_file_free(clist); + + SC_FUNC_RETURN(ctx, 1, rv); +} + + +static int +awp_update_container(struct sc_pkcs15_card *p15card, struct sc_profile *profile, int type, + struct awp_lv *key_id, unsigned obj_id, unsigned int *prkey_id) +{ + struct sc_context *ctx = p15card->card->ctx; + struct sc_file *clist = NULL, *file = NULL; + struct sc_path private_path; + int rv = 0, rec, rec_offs; + unsigned char *list = NULL; + + SC_FUNC_CALLED(ctx, 1); + sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "update container(type:%X,obj_id:%X)\n", type, obj_id); + + if (prkey_id) + *prkey_id = 0; + + /* + * Get path of the DF that contains private objects. + */ + rv = awp_new_file(p15card, profile, SC_PKCS15_TYPE_PRKEY_RSA, 1, NULL, &file); + if (rv) + goto done; + private_path = file->path; + sc_file_free(file), file=NULL; + + rv = awp_new_file(p15card, profile, COSM_CONTAINER_LIST, 0, &clist, NULL); + if (rv) + goto done; + sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "contaner cfile(rcount:%i,rlength:%i)\n", clist->record_count, clist->record_length); + + rv = sc_select_file(p15card->card, &clist->path, &file); + if (rv) + goto done; + file->record_length = clist->record_length; + + sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "contaner file(rcount:%i,rlength:%i)\n", file->record_count, file->record_length); + if (type == SC_PKCS15_TYPE_PRKEY_RSA || type == COSM_TYPE_PRKEY_RSA) { + rec_offs = 0; + sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "Append new record %i for private key\n", file->record_count + 1); + rv = awp_update_container_entry(p15card, profile, file, type, obj_id, file->record_count + 1, rec_offs); + sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "rv:%i\n", rv); + goto done; + } + + list = malloc(AWP_CONTAINER_RECORD_LEN * file->record_count); + if (!list) { + rv = SC_ERROR_MEMORY_FAILURE; + goto done; + } + + rv = sc_pkcs15init_authenticate(profile, p15card, file, SC_AC_OP_READ); + if (rv) + goto done; + + for (rec=0; rec < file->record_count; rec++) { + unsigned char tmp[256]; + + rv = sc_read_record(p15card->card, rec + 1, tmp, sizeof(tmp), SC_RECORD_BY_REC_NR); + if (rv >= AWP_CONTAINER_RECORD_LEN) + memcpy(list + rec*AWP_CONTAINER_RECORD_LEN, tmp, AWP_CONTAINER_RECORD_LEN); + else + goto done; + } + + for (rec=0, rv=0; !rv && rec < file->record_count; rec++) { + for (rec_offs=0; !rv && rec_offs<12; rec_offs+=6) { + int offs; + + sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "rec %i; rec_offs %i\n", rec, rec_offs); + offs = rec*AWP_CONTAINER_RECORD_LEN + rec_offs; + if (*(list + offs + 2)) { + unsigned char *buff = NULL; + int id_offs; + struct sc_path path = private_path; + struct sc_file *ff = NULL; + + sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "container contains PrKey %02X%02X\n", *(list + offs + 2), *(list + offs + 3)); + path.value[path.len - 2] = *(list + offs + 2) | 0x01; + path.value[path.len - 1] = *(list + offs + 3); + rv = sc_select_file(p15card->card, &path, &ff); + if (rv) + continue; + + sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "file id %X; size %i\n", ff->id, ff->size); + buff = malloc(ff->size); + if (!buff) { + rv = SC_ERROR_MEMORY_FAILURE; + break; + } + + rv = sc_pkcs15init_authenticate(profile, p15card, ff, SC_AC_OP_READ); + if (rv) { + sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "failed %s\n","sc_pkcs15init_authenticate()"); + break; + } + + rv = sc_read_binary(p15card->card, 0, buff, ff->size, 0); + if (rv == ff->size) { + rv = 0; + id_offs = 5 + *(buff+3); + sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "rec %i; id offset %i\n",rec, id_offs); + if (key_id->len == *(buff + id_offs) && + !memcmp(key_id->value, buff + id_offs + 1, key_id->len)) { + sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "found key file friend %s\n",""); + if (!rv) + rv = awp_update_container_entry(p15card, profile, file, type, obj_id, rec + 1, rec_offs); + + if (rv >= 0 && prkey_id) { + *prkey_id = *(list + offs + 2) * 0x100 + *(list + offs + 3); + sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "*prkey_id 0x%X\n", *prkey_id); + } + } + } + + free(buff); + sc_file_free(ff); + } + } + } + +done: + if (clist) sc_file_free(clist); + if (file) sc_file_free(file); + if (list) free(list); + + SC_FUNC_RETURN(ctx, 1, rv); +} + + +static int +awp_update_df_create_pin(struct sc_pkcs15_card *p15card, struct sc_profile *profile, + struct sc_pkcs15_object *pinobj) +{ + SC_FUNC_CALLED(p15card->card->ctx, 1); + /* No update DF when creating PIN objects */ + SC_FUNC_RETURN(p15card->card->ctx, 1, SC_SUCCESS); +} + + +static int +awp_set_certificate_info (struct sc_pkcs15_card *p15card, + struct sc_profile *profile, + struct sc_file *file, + struct awp_cert_info *ci) +{ + struct sc_context *ctx = p15card->card->ctx; + int r = 0, blob_size; + unsigned char *blob; + const char *default_cert_label = "Certificate"; + + SC_FUNC_CALLED(ctx, 1); + blob_size = 2; + if (!(blob = malloc(blob_size))) { + r = SC_ERROR_MEMORY_FAILURE; + goto done; + } + + *blob = (COSM_TAG_CERT >> 8) & 0xFF; + *(blob + 1) = COSM_TAG_CERT & 0xFF; + + if (ci->label.len + && ci->label.len != strlen(default_cert_label) + && memcmp(ci->label.value, default_cert_label, strlen(default_cert_label))) + r = awp_update_blob(ctx, &blob, &blob_size, &ci->label, TLV_TYPE_LLV); + else + r = awp_update_blob(ctx, &blob, &blob_size, &ci->cn, TLV_TYPE_LLV); + if (r) + goto done; + + r = awp_update_blob(ctx, &blob, &blob_size, &ci->id, TLV_TYPE_LLV); + if (r) + goto done; + + r = awp_update_blob(ctx, &blob, &blob_size, &ci->subject, TLV_TYPE_LLV); + if (r) + goto done; + + if (ci->issuer.len != ci->subject.len || + memcmp(ci->issuer.value, ci->subject.value, ci->subject.len)) { + r = awp_update_blob(ctx, &blob, &blob_size, &ci->issuer, TLV_TYPE_LLV); + if (r) + goto done; + r = awp_update_blob(ctx, &blob, &blob_size, &ci->serial, TLV_TYPE_LLV); + if (r) + goto done; + } + else { + r = awp_update_blob(ctx, &blob, &blob_size, &zero_lv, TLV_TYPE_LLV); + if (r) + goto done; + r = awp_update_blob(ctx, &blob, &blob_size, &zero_lv, TLV_TYPE_LLV); + if (r) + goto done; + } + + file->size = blob_size; + r = sc_pkcs15init_create_file(profile, p15card, file); + if (r) + goto done; + + r = sc_pkcs15init_update_file(profile, p15card, file, blob, blob_size); + if (r < 0) + goto done; + + r = 0; +done: + if (blob) + free(blob); + + SC_FUNC_RETURN(ctx, 1, r); +} + + +int +awp_update_object_list(struct sc_pkcs15_card *p15card, struct sc_profile *profile, + unsigned int type, int num) +{ + struct sc_context *ctx = p15card->card->ctx; + struct sc_file *obj_file = NULL, *lst_file = NULL; + struct sc_file *file = NULL; + char obj_name[NAME_MAX_LEN], lst_name[NAME_MAX_LEN]; + unsigned char *buff = NULL; + int rv, ii; + + SC_FUNC_CALLED(ctx, 1); + sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "type %i, num %i\n", type, num); + switch (type) { + case SC_PKCS15_TYPE_CERT_X509: + snprintf(obj_name, NAME_MAX_LEN, "template-certificate"); + snprintf(lst_name, NAME_MAX_LEN,"%s-public-list", + COSM_TITLE); + break; + case SC_PKCS15_TYPE_PUBKEY_RSA: + case COSM_TYPE_PUBKEY_RSA: + snprintf(obj_name, NAME_MAX_LEN, "template-public-key"); + snprintf(lst_name, NAME_MAX_LEN,"%s-public-list", + COSM_TITLE); + break; + case SC_PKCS15_TYPE_DATA_OBJECT: + snprintf(obj_name, NAME_MAX_LEN, "template-public-data"); + snprintf(lst_name, NAME_MAX_LEN,"%s-public-list", + COSM_TITLE); + break; + case SC_PKCS15_TYPE_PRKEY_RSA: + case COSM_TYPE_PRKEY_RSA: + snprintf(obj_name, NAME_MAX_LEN,"template-private-key"); + snprintf(lst_name, NAME_MAX_LEN,"%s-private-list", + COSM_TITLE); + break; + default: + sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "Not supported file type %X", type); + return SC_ERROR_INVALID_ARGUMENTS; + } + + sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "obj_name %s; num 0x%X\n",obj_name, num); + sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "lst_name %s\n",lst_name); + if (sc_profile_get_file(profile, obj_name, &obj_file) < 0) { + sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "No profile template '%s'\n", obj_name); + rv = SC_ERROR_NOT_SUPPORTED; + goto done; + } + else if (sc_profile_get_file(profile, lst_name, &lst_file) < 0) { + sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "No profile template '%s'\n", lst_name); + rv = SC_ERROR_NOT_SUPPORTED; + goto done; + } + + obj_file->id |= (num & 0xFF); + obj_file->path.value[obj_file->path.len-1] |= (num & 0xFF); + + rv = sc_select_file(p15card->card, &obj_file->path, &file); + sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "rv %i\n",rv); + if (rv) + goto done; + + if (type == SC_PKCS15_TYPE_PUBKEY_RSA || type == COSM_TYPE_PUBKEY_RSA) { + if (file->size==PUBKEY_512_ASN1_SIZE) + file->size = 512; + else if (file->size==PUBKEY_1024_ASN1_SIZE) + file->size = 1024; + else if (file->size==PUBKEY_2048_ASN1_SIZE) + file->size = 2048; + } + + buff = malloc(lst_file->size); + if (!buff) { + rv = SC_ERROR_MEMORY_FAILURE; + goto done; + } + + rv = sc_pkcs15init_authenticate(profile, p15card, lst_file, SC_AC_OP_READ); + sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "rv %i\n",rv); + if (rv) + goto done; + rv = sc_pkcs15init_authenticate(profile, p15card, lst_file, SC_AC_OP_UPDATE); + sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "rv %i\n",rv); + if (rv) + goto done; + + rv = sc_select_file(p15card->card, &lst_file->path, NULL); + sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "rv %i\n",rv); + if (rv == SC_ERROR_FILE_NOT_FOUND) + rv = sc_pkcs15init_create_file(profile, p15card, lst_file); + sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "rv %i\n",rv); + if (rv < 0) + goto done; + + rv = sc_read_binary(p15card->card, 0, buff, lst_file->size, lst_file->ef_structure); + sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "rv %i\n",rv); + if (rv < 0) + goto done; + + for (ii=0; ii < lst_file->size; ii+=5) + if (*(buff + ii) != COSM_LIST_TAG) + break; + if (ii>=lst_file->size) { + rv = SC_ERROR_UNKNOWN_DATA_RECEIVED; + goto done; + } + + sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "ii %i, rv %i; %X; %i\n", ii, rv, file->id, file->size); + *(buff + ii) = COSM_LIST_TAG; + *(buff + ii + 1) = (file->id >> 8) & 0xFF; + *(buff + ii + 2) = file->id & 0xFF; + *(buff + ii + 3) = (file->size >> 8) & 0xFF; + *(buff + ii + 4) = file->size & 0xFF; + + rv = sc_update_binary(p15card->card, ii, buff + ii, 5, 0); + sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "rv %i\n",rv); + if (rv < 0) + goto done; + + rv = 0; +done: + if (buff) + free(buff); + sc_file_free(lst_file); + sc_file_free(obj_file); + sc_file_free(file); + + SC_FUNC_RETURN(ctx, 1, rv); +} + + +static int +awp_encode_key_info(struct sc_pkcs15_card *p15card, struct sc_pkcs15_object *obj, + struct sc_pkcs15_pubkey_rsa *pubkey, struct awp_key_info *ki) +{ + struct sc_context *ctx = p15card->card->ctx; + struct sc_pkcs15_prkey_info *key_info; + int r = 0; + + SC_FUNC_CALLED(ctx, 1); + ERR_load_ERR_strings(); + ERR_load_crypto_strings(); + + key_info = (struct sc_pkcs15_prkey_info *)obj->data; + + sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "object(%s,type:%X)\n", obj->label, obj->type); + if (obj->type == SC_PKCS15_TYPE_PUBKEY_RSA || obj->type == COSM_TYPE_PUBKEY_RSA ) + ki->flags = COSM_TAG_PUBKEY_RSA; + else if (obj->type == SC_PKCS15_TYPE_PRKEY_RSA || obj->type == COSM_TYPE_PRKEY_RSA) + ki->flags = COSM_TAG_PRVKEY_RSA; + else + return SC_ERROR_INCORRECT_PARAMETERS; + + if (obj->type == COSM_TYPE_PUBKEY_RSA || obj->type == COSM_TYPE_PRKEY_RSA) + ki->flags |= COSM_GENERATED; + + if (obj->label) { + ki->label.value = (unsigned char *)strdup(obj->label); + ki->label.len = strlen(obj->label); + } + sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "cosm_encode_key_info() label(%i):%s\n",ki->label.len, ki->label.value); + + /* + * Oberthur saves modulus value without tag and length. + */ + sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "pubkey->modulus.len %i\n",pubkey->modulus.len); + ki->modulus.value = malloc(pubkey->modulus.len); + if (!ki->modulus.value) { + r = SC_ERROR_MEMORY_FAILURE; + goto done; + } + memcpy(ki->modulus.value, pubkey->modulus.data, pubkey->modulus.len); + ki->modulus.len = pubkey->modulus.len; + + /* + * Oberthur saves exponents as length and value, without tag. + */ + ki->exponent.value = malloc(pubkey->exponent.len); + if (!ki->exponent.value) { + r = SC_ERROR_MEMORY_FAILURE; + goto done; + } + memcpy(ki->exponent.value, pubkey->exponent.data, pubkey->exponent.len); + ki->exponent.len = pubkey->exponent.len; + + /* + * ID + */ + ki->id.value = calloc(1, key_info->id.len); + if (!ki->id.value) + SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_MEMORY_FAILURE, "AWP encode cert failed: ID allocation error"); + memcpy(ki->id.value, key_info->id.value, key_info->id.len); + ki->id.len = key_info->id.len; + + sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "cosm_encode_key_info() label:%s\n",ki->label.value); +done: + ERR_load_ERR_strings(); + ERR_load_crypto_strings(); + SC_FUNC_RETURN(ctx, 1, r); +} + + +static void +awp_free_key_info(struct awp_key_info *ki) +{ + if (ki->modulus.value) + free(ki->modulus.value); + if (ki->exponent.value) + free(ki->exponent.value); + if (ki->id.value) + free(ki->id.value); +} + + +static int +awp_set_key_info (struct sc_pkcs15_card *p15card, struct sc_profile *profile, struct sc_file *file, + struct awp_key_info *ki, struct awp_cert_info *ci) +{ + struct sc_context *ctx = p15card->card->ctx; + int r = 0, blob_size; + unsigned char *blob; + + SC_FUNC_CALLED(ctx, 1); + sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "file:%p,kinfo:%p,cinfo:%p\n", file, ki, ci); + blob_size = 2; + blob = malloc(blob_size); + if (!blob) + SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_MEMORY_FAILURE, "AWP set key info failed: blob allocation error"); + + sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "label:%s\n",ki->label.value); + + *blob = (ki->flags >> 8) & 0xFF; + *(blob + 1) = ki->flags & 0xFF; + if (ci && ci->label.len) + r = awp_update_blob(ctx, &blob, &blob_size, &ci->label, TLV_TYPE_LLV); + else if (ci && !ci->label.len) + r = awp_update_blob(ctx, &blob, &blob_size, &ci->cn, TLV_TYPE_LLV); + else + r = awp_update_blob(ctx, &blob, &blob_size, &ki->label, TLV_TYPE_LLV); + sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "rv:%i\n", r); + if (r) + goto done; + + r = awp_update_blob(ctx, &blob, &blob_size, &ki->id, TLV_TYPE_LLV); + sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "rv:%i\n", r); + if (r) + goto done; + + r = awp_update_blob(ctx, &blob, &blob_size, &x30_lv, TLV_TYPE_V); + sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "rv:%i\n", r); + if (r) + goto done; + + if (ci) + r = awp_update_blob(ctx, &blob, &blob_size, &(ci->subject), TLV_TYPE_LLV); + else + r = awp_update_blob(ctx, &blob, &blob_size, &zero_lv, TLV_TYPE_LLV); + sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "rv:%i\n", r); + if (r) + goto done; + + if ((ki->flags & ~COSM_GENERATED) != COSM_TAG_PUBKEY_RSA) { + r = awp_update_blob(ctx, &blob, &blob_size, &ki->modulus, TLV_TYPE_V); + sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "rv:%i\n", r); + if (r) + goto done; + + r = awp_update_blob(ctx, &blob, &blob_size, &ki->exponent, TLV_TYPE_LV); + sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "rv:%i\n", r); + if (r) + goto done; + } + + file->size = blob_size; + r = sc_pkcs15init_create_file(profile, p15card, file); + sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "rv:%i\n", r); + if (r == SC_ERROR_FILE_ALREADY_EXISTS) { + r = cosm_delete_file(p15card, profile, file); + if (!r) + r = sc_pkcs15init_create_file(profile, p15card, file); + } + + if (r<0) + goto done; + + r = sc_pkcs15init_update_file(profile, p15card, file, blob, blob_size); + sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "rv:%i\n", r); + if (r < 0) + goto done; + + r = 0; +done: + if (blob) + free(blob); + + SC_FUNC_RETURN(ctx, 1, r); +} + + +static int +awp_encode_cert_info(struct sc_pkcs15_card *p15card, struct sc_pkcs15_object *obj, + struct awp_cert_info *ci) +{ + struct sc_context *ctx = p15card->card->ctx; + struct sc_pkcs15_cert_info *cert_info; + struct sc_pkcs15_pubkey_rsa pubkey; + int r = 0; + unsigned char *buff = NULL, *ptr; + BIO *mem = NULL; + X509 *x = NULL; + + SC_FUNC_CALLED(ctx, 1); + + ERR_load_ERR_strings(); + ERR_load_crypto_strings(); + + if (!obj || !ci) + SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_INVALID_ARGUMENTS, "AWP encode cert failed: invalid parameters"); + + cert_info = (struct sc_pkcs15_cert_info *)obj->data; + + sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "Encode cert(%s,id:%s,der(%p,%i))\n", obj->label, + sc_pkcs15_print_id(&cert_info->id), obj->content.value, obj->content.len); + memset(&pubkey, 0, sizeof(pubkey)); + + if (obj->label) { + ci->label.value = (unsigned char *)strdup(obj->label); + ci->label.len = strlen(obj->label); + } + + mem = BIO_new_mem_buf(obj->content.value, obj->content.len); + if (!mem) + SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_INVALID_DATA, "AWP encode cert failed: invalid data"); + + x = d2i_X509_bio(mem, NULL); + if (!x) + SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_INVALID_DATA, "AWP encode cert failed: x509 parse error"); + + buff = OPENSSL_malloc(i2d_X509(x,NULL) + EVP_MAX_MD_SIZE); + if (!buff) + SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_MEMORY_FAILURE, "AWP encode cert failed: memory allocation error"); + + /* + * subject commonName. + */ + ptr = awp_get_commonName(x); + if (!ptr) + SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_INTERNAL, "AWP encode cert failed: cannot get CommonName"); + ci->cn.value = ptr; + ci->cn.len = strlen((char *)ptr); + + /* + * subject DN + */ + ptr = buff; + r = i2d_X509_NAME(X509_get_subject_name(x),&ptr); + if (r<=0) + SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_INTERNAL, "AWP encode cert failed: cannot get SubjectName"); + + ci->subject.value = malloc(r); + if (!ci->subject.value) + SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_MEMORY_FAILURE, "AWP encode cert failed: subject allocation error"); + memcpy(ci->subject.value, buff, r); + ci->subject.len = r; + + /* + * issuer DN + */ + ptr = buff; + r = i2d_X509_NAME(X509_get_issuer_name(x),&ptr); + if (r <= 0) + SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_INTERNAL, "AWP encode cert failed: cannot get IssuerName"); + + ci->issuer.value = malloc(r); + if (!ci->issuer.value) + SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_MEMORY_FAILURE, "AWP encode cert failed: issuer allocation error"); + memcpy(ci->issuer.value, buff, r); + ci->issuer.len = r; + + /* + * ID + */ + ci->id.value = calloc(1, cert_info->id.len); + if (!ci->id.value) + SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_MEMORY_FAILURE, "AWP encode cert failed: ID allocation error"); + memcpy(ci->id.value, cert_info->id.value, cert_info->id.len); + ci->id.len = cert_info->id.len; + + /* + * serial number + */ + do { + int encoded_len; + unsigned char encoded[0x40], *encoded_ptr; + + encoded_ptr = encoded; + encoded_len = i2c_ASN1_INTEGER(X509_get_serialNumber(x), &encoded_ptr); + + if (!(ci->serial.value = malloc(encoded_len + 3))) { + r = SC_ERROR_MEMORY_FAILURE; + sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "rv %i\n", r); + goto done; + } + + memcpy(ci->serial.value + 2, encoded, encoded_len); + *(ci->serial.value + 0) = V_ASN1_INTEGER; + *(ci->serial.value + 1) = encoded_len; + ci->serial.len = encoded_len + 2; + + sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "cert. serial encoded length %i\n", encoded_len); + } while (0); + + ci->x509 = X509_dup(x); +done: + ERR_print_errors_fp(stderr); + ERR_clear_error(); + ERR_free_strings(); + if (pubkey.exponent.data) free(pubkey.exponent.data); + if (pubkey.modulus.data) free(pubkey.modulus.data); + if (x) X509_free(x); + if (mem) BIO_free(mem); + if (buff) OPENSSL_free(buff); + + SC_FUNC_RETURN(ctx, 1, r); +} + + +static void +awp_free_cert_info(struct awp_cert_info *ci) +{ + if (ci->cn.len && ci->cn.value) + free(ci->cn.value); + + if (ci->id.len && ci->id.value) + free(ci->id.value); + + if (ci->subject.len && ci->subject.value) + free(ci->subject.value); + + if (ci->issuer.len && ci->issuer.value) + free(ci->issuer.value); + + if (ci->x509) + X509_free(ci->x509); + + memset(ci,0,sizeof(struct awp_cert_info)); +} + + +static int +awp_get_lv(struct sc_context *ctx, unsigned char *buf, size_t buf_len, + size_t offs, int len_len, + struct awp_lv *out) +{ + int len = 0, ii; + + if (buf_len - offs < 2) + return 0; + + if (len_len > 2) { + len = len_len; + len_len = 0; + } + else { + for (len=0, ii=0; iivalue) + free(out->value); + + out->value = malloc(len); + if (!out->value) + return SC_ERROR_MEMORY_FAILURE; + memcpy(out->value, buf + offs + len_len, len); + out->len = len; + } + + return len_len + len; +} + + +static int +awp_parse_key_info(struct sc_context *ctx, unsigned char *buf, size_t buf_len, + struct awp_key_info *ikey) +{ + size_t offs; + int len; + + SC_FUNC_CALLED(ctx, 1); + offs = 0; + + /* Flags */ + if (buf_len - offs < 2) + SC_FUNC_RETURN(ctx, 1, SC_SUCCESS); + ikey->flags = *(buf + offs) * 0x100 + *(buf + offs + 1); + offs += 2; + + /* Label */ + len = awp_get_lv(ctx, buf, buf_len, offs, 2, &ikey->label); + SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, len, "AWP parse key info failed: label"); + if (!len) + SC_FUNC_RETURN(ctx, 1, SC_SUCCESS); + offs += len; + + /* Ignore Key ID */ + len = awp_get_lv(ctx, buf, buf_len, offs, 2, &ikey->id); + SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, len, "AWP parse key info failed: ID"); + if (!len) + SC_FUNC_RETURN(ctx, 1, SC_SUCCESS); + offs += len; + + while (*(buf + offs) == '0') + offs++; + + /* Subject */ + len = awp_get_lv(ctx, buf, buf_len, offs, 2, &ikey->subject); + SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, len, "AWP parse key info failed: subject"); + if (!len) + SC_FUNC_RETURN(ctx, 1, SC_SUCCESS); + offs += len; + + /* Modulus */ + if (buf_len - offs > 64 && buf_len - offs < 128) + len = awp_get_lv(ctx, buf, buf_len, offs, 64, &ikey->modulus); + else if (buf_len - offs > 128 && buf_len - offs < 256) + len = awp_get_lv(ctx, buf, buf_len, offs, 128, &ikey->modulus); + else + len = awp_get_lv(ctx, buf, buf_len, offs, 256, &ikey->modulus); + SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, len, "AWP parse key info failed: modulus"); + if (!len) + SC_FUNC_RETURN(ctx, 1, SC_SUCCESS); + offs += len; + + /* Exponent */ + len = awp_get_lv(ctx, buf, buf_len, offs, 1, &ikey->exponent); + SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, len, "AWP parse key info failed: exponent"); + if (!len) + SC_FUNC_RETURN(ctx, 1, SC_SUCCESS); + offs += len; + + SC_FUNC_RETURN(ctx, 1, SC_SUCCESS); +} + + +static int +awp_update_key_info(struct sc_pkcs15_card *p15card, struct sc_profile *profile, + unsigned prvkey_id, struct awp_cert_info *ci) +{ + struct sc_context *ctx = p15card->card->ctx; + struct sc_file *key_file=NULL, *info_file=NULL, *file=NULL; + struct awp_key_info ikey; + int rv = 0; + unsigned char *buf; + size_t buf_len; + + SC_FUNC_CALLED(ctx, 1); + + rv = awp_new_file(p15card, profile, SC_PKCS15_TYPE_PRKEY_RSA, prvkey_id & 0xFF, &info_file, &key_file); + SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, rv, "AWP update key info failed: instantiation error"); + sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "key id %X; info id%X\n", key_file->id, info_file->id); + + rv = sc_pkcs15init_authenticate(profile, p15card, info_file, SC_AC_OP_READ); + if (rv) { + sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "AWP update key info failed: 'READ' authentication error\n"); + goto done; + } + + rv = sc_select_file(p15card->card, &info_file->path, &file); + if (rv) { + sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "AWP update key info failed: cannot select info file\n"); + goto done; + } + + buf = calloc(1,file->size); + if (!buf) + SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_MEMORY_FAILURE, "AWP update key info failed: allocation error"); + + rv = sc_read_binary(p15card->card, 0, buf, file->size, 0); + if (rv < 0) { + sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "AWP update key info failed: read info file error\n"); + goto done; + } + buf_len = rv; + + memset(&ikey, 0, sizeof(ikey)); + rv = awp_parse_key_info(ctx, buf, buf_len, &ikey); + if (rv < 0) { + sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "AWP update key info failed: parse key info error\n"); + goto done; + } + free(buf); + + rv = awp_set_key_info(p15card, profile, info_file, &ikey, ci); + SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, rv, "AWP update key info failed: set key info error"); +done: + sc_file_free(file); + sc_file_free(key_file); + sc_file_free(info_file); + + SC_FUNC_RETURN(ctx, 1, rv); +} + + +static int +awp_update_df_create_cert(struct sc_pkcs15_card *p15card, struct sc_profile *profile, + struct sc_pkcs15_object *obj) +{ + struct sc_context *ctx = p15card->card->ctx; + struct sc_file *info_file=NULL, *obj_file=NULL; + struct awp_cert_info icert; + struct sc_pkcs15_der der; + struct sc_path path; + unsigned prvkey_id, obj_id; + int rv; + + SC_FUNC_CALLED(ctx, 1); + + der = obj->content; + path = ((struct sc_pkcs15_cert_info *)obj->data)->path; + obj_id = (path.value[path.len-1] & 0xFF) + (path.value[path.len-2] & 0xFF) * 0x100; + + rv = awp_new_file(p15card, profile, SC_PKCS15_TYPE_CERT_X509, obj_id & 0xFF, &info_file, &obj_file); + SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, rv, "COSM new file error"); + + memset(&icert, 0, sizeof(icert)); + sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "Cert Der(%p,%i)", der.value, der.len); + rv = awp_encode_cert_info(p15card, obj, &icert); + SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, rv, "'Create Cert' update DF failed: cannot encode info"); + + rv = awp_set_certificate_info(p15card, profile, info_file, &icert); + SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, rv, "'Create Cert' update DF failed: cannot set info"); + + rv = awp_update_object_list(p15card, profile, SC_PKCS15_TYPE_CERT_X509, obj_id & 0xFF); + SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, rv, "'Create Cert' update DF failed: cannot update list"); + + rv = awp_update_container(p15card, profile, SC_PKCS15_TYPE_CERT_X509, &icert.id, obj_id, &prvkey_id); + SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, rv, "'Create Cert' update DF failed: cannot update container"); + + sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "PrvKeyID:%04X", prvkey_id); + + if (prvkey_id) + rv = awp_update_key_info(p15card, profile, prvkey_id, &icert); + SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, rv, "'Create Cert' update DF failed: cannot update key info"); + + awp_free_cert_info(&icert); + + if (info_file) + sc_file_free(info_file); + if (obj_file) + sc_file_free(obj_file); + + SC_FUNC_RETURN(ctx, 1, rv); +} + + +static int +awp_update_df_create_prvkey(struct sc_pkcs15_card *p15card, struct sc_profile *profile, + struct sc_pkcs15_object *key_obj) +{ + struct sc_context *ctx = p15card->card->ctx; + struct sc_pkcs15_pubkey pubkey; + struct sc_pkcs15_der der; + struct awp_key_info ikey; + struct awp_cert_info icert; + struct sc_file *info_file=NULL, *obj_file=NULL; + struct sc_pkcs15_prkey_info *key_info; + struct sc_pkcs15_object *cert_obj = NULL, *pubkey_obj = NULL; + struct sc_path path; + struct awp_crypto_container cc; + int rv; + + SC_FUNC_CALLED(ctx, 1); + + key_info = (struct sc_pkcs15_prkey_info *)key_obj->data; + der = key_obj->content; + + memset(&cc, 0, sizeof(cc)); + path = key_info->path; + cc.prkey_id = (path.value[path.len-1] & 0xFF) + (path.value[path.len-2] & 0xFF) * 0x100; + + rv = sc_pkcs15_find_cert_by_id(p15card, &key_info->id, &cert_obj); + if (!rv) { + struct sc_pkcs15_cert_info *cert_info = (struct sc_pkcs15_cert_info *) cert_obj->data; + struct sc_pkcs15_cert *p15cert; + + path = cert_info->path; + cc.cert_id = (path.value[path.len-1] & 0xFF) + (path.value[path.len-2] & 0xFF) * 0x100; + + rv = sc_pkcs15_read_certificate(p15card, cert_info, &p15cert); + SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, rv, "AWP 'update private key' DF failed: cannot get certificate"); + + rv = sc_pkcs15_allocate_object_content(cert_obj, p15cert->data, p15cert->data_len); + SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, rv, "AWP 'update private key' DF failed: cannot allocate content"); + + rv = awp_encode_cert_info(p15card, cert_obj, &icert); + SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, rv, "AWP 'update private key' DF failed: cannot encode cert info"); + + sc_pkcs15_free_certificate(p15cert); + } + + rv = sc_pkcs15_find_pubkey_by_id(p15card, &key_info->id, &pubkey_obj); + if (!rv) { + path = ((struct sc_pkcs15_cert_info *)pubkey_obj->data)->path; + cc.pubkey_id = (path.value[path.len-1] & 0xFF) + (path.value[path.len-2] & 0xFF) * 0x100; + } + + rv = awp_new_file(p15card, profile, key_obj->type, cc.prkey_id & 0xFF, &info_file, &obj_file); + SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, rv, "New private key info file error"); + + pubkey.algorithm = SC_ALGORITHM_RSA; + sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "PrKey Der(%p,%i)", der.value, der.len); + rv = sc_pkcs15_decode_pubkey(ctx, &pubkey, der.value, der.len); + SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, rv, "AWP 'update private key' DF failed: decode public key error"); + + memset(&ikey, 0, sizeof(ikey)); + rv = awp_encode_key_info(p15card, key_obj, &pubkey.u.rsa, &ikey); + SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, rv, "AWP 'update private key' DF failed: encode info error"); + + rv = awp_set_key_info(p15card, profile, info_file, &ikey, cert_obj ? &icert : NULL); + SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, rv, "AWP 'update private key' DF failed: set info error"); + + rv = awp_update_object_list(p15card, profile, key_obj->type, cc.prkey_id & 0xFF); + SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, rv, "AWP 'update private key' DF failed: update object list error"); + + rv = awp_create_container(p15card, profile, key_obj->type, &ikey.id, &cc); + SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, rv, "AWP 'update private key' DF failed: update container error"); + + if (cert_obj) + awp_free_cert_info(&icert); + + awp_free_key_info(&ikey); + SC_FUNC_RETURN(ctx, 1, rv); +} + + +static int +awp_update_df_create_pubkey(struct sc_pkcs15_card *p15card, struct sc_profile *profile, + struct sc_pkcs15_object *obj) +{ + struct sc_context *ctx = p15card->card->ctx; + struct sc_pkcs15_pubkey pubkey; + struct sc_pkcs15_der der; + struct awp_key_info ikey; + struct sc_file *info_file=NULL, *obj_file=NULL; + struct sc_path path; + unsigned obj_id; + int index, rv; + + SC_FUNC_CALLED(ctx, 1); + + path = ((struct sc_pkcs15_pubkey_info *)obj->data)->path; + der = obj->content; + index = path.value[path.len-1] & 0xFF; + obj_id = (path.value[path.len-1] & 0xFF) + (path.value[path.len-2] & 0xFF) * 0x100; + + rv = awp_new_file(p15card, profile, obj->type, index, &info_file, &obj_file); + SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, rv, "New public key info file error"); + + pubkey.algorithm = SC_ALGORITHM_RSA; + sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "PrKey Der(%p,%i)", der.value, der.len); + rv = sc_pkcs15_decode_pubkey(ctx, &pubkey, der.value, der.len); + SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, rv, "AWP 'update public key' DF failed: decode public key error"); + + memset(&ikey, 0, sizeof(ikey)); + rv = awp_encode_key_info(p15card, obj, &pubkey.u.rsa, &ikey); + SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, rv, "AWP 'update public key' DF failed: encode info error"); + + rv = awp_set_key_info(p15card, profile, info_file, &ikey, NULL); + SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, rv, "AWP 'update public key' DF failed: set info error"); + + rv = awp_update_object_list(p15card, profile, obj->type, index); + SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, rv, "AWP 'update public key' DF failed: update object list error"); + + rv = awp_update_container(p15card, profile, obj->type, &ikey.id, obj_id, NULL); + SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, rv, "AWP 'update public key' DF failed: update container error"); + + awp_free_key_info(&ikey); + SC_FUNC_RETURN(ctx, 1, rv); +} + + +static int +awp_update_df_create_data(struct sc_pkcs15_card *p15card, struct sc_profile *profile, + struct sc_pkcs15_object *obj) +{ + struct sc_context *ctx = p15card->card->ctx; + int rv = SC_ERROR_NOT_SUPPORTED; + + SC_FUNC_CALLED(ctx, 1); + SC_FUNC_RETURN(ctx, 1, rv); +} + + +int +awp_update_df_create(struct sc_pkcs15_card *p15card, struct sc_profile *profile, + struct sc_pkcs15_object *object) +{ + struct sc_context *ctx = p15card->card->ctx; + int rv; + + SC_FUNC_CALLED(ctx, 1); + if (!object) + SC_FUNC_RETURN(ctx, 1, SC_SUCCESS); + + switch (object->type) { + case SC_PKCS15_TYPE_AUTH_PIN: + rv = awp_update_df_create_pin(p15card, profile, object); + break; + case SC_PKCS15_TYPE_CERT_X509: + rv = awp_update_df_create_cert(p15card, profile, object); + break; + case SC_PKCS15_TYPE_PRKEY_RSA: + rv = awp_update_df_create_prvkey(p15card, profile, object); + break; + case SC_PKCS15_TYPE_PUBKEY_RSA: + rv = awp_update_df_create_pubkey(p15card, profile, object); + break; + case SC_PKCS15_TYPE_DATA_OBJECT: + rv = awp_update_df_create_data(p15card, profile, object); + break; + default: + SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_INVALID_ARGUMENTS, "'Create' update DF failed: unsupported object type"); + } + + SC_FUNC_RETURN(ctx, 1, rv); +} + + +static int +awp_delete_from_container(struct sc_pkcs15_card *p15card, + struct sc_profile *profile, int type, int file_id) +{ + struct sc_context *ctx = p15card->card->ctx; + struct sc_file *clist=NULL, *file=NULL; + unsigned rec, rec_len; + int rv = 0, ii; + unsigned char *buff=NULL; + + SC_FUNC_CALLED(ctx, 1); + sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "update container entry (type:%X,file-id:%X)\n", type, file_id); + + rv = awp_new_file(p15card, profile, COSM_CONTAINER_LIST, 0, &clist, NULL); + SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, rv, "AWP update contaner entry: cannot get allocate AWP file"); + + rv = sc_select_file(p15card->card, &clist->path, &file); + SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, rv, "AWP update contaner entry: cannot select container list file"); + + buff = malloc(file->record_length); + if (!buff) + SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_MEMORY_FAILURE, "AWP update container entry: allocation error"); + + for (rec = 1; rec <= file->record_count; rec++) { + rv = sc_read_record(p15card->card, rec, buff, file->record_length, SC_RECORD_BY_REC_NR); + if (rv < 0) { + sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "AWP update contaner entry: read record error %i", rv); + break; + } + rec_len = rv; + + for (ii=0; ii<12; ii+=2) + if (file_id == (*(buff+ii) * 0x100 + *(buff+ii+1))) + break; + if (ii==12) + continue; + + if (type == SC_PKCS15_TYPE_PRKEY_RSA || type == COSM_TYPE_PRKEY_RSA) + memset(buff + ii/6*6, 0, 6); + else + memset(buff + ii, 0, 2); + + if (!memcmp(buff,"\0\0\0\0\0\0\0\0\0\0\0\0",12)) { + rv = sc_pkcs15init_authenticate(profile, p15card, file, SC_AC_OP_ERASE); + if (rv < 0) { + sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "AWP update contaner entry: 'erase' authentication error %i", rv); + break; + } + + rv = sc_delete_record(p15card->card, rec); + if (rv < 0) { + sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "AWP update contaner entry: delete record error %i", rv); + break; + } + } + else { + rv = sc_pkcs15init_authenticate(profile, p15card, file, SC_AC_OP_UPDATE); + if (rv < 0) { + sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "AWP update contaner entry: 'update' authentication error %i", rv); + break; + } + + rv = sc_update_record(p15card->card, rec, buff, rec_len, SC_RECORD_BY_REC_NR); + if (rv < 0) { + sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "AWP update contaner entry: update record error %i", rv); + break; + } + } + } + + if (rv > 0) + rv = 0; + + if (buff) free(buff); + if (file) sc_file_free(file); + if (clist) sc_file_free(clist); + + SC_FUNC_RETURN(ctx, 1, rv); +} + + +static int +awp_remove_from_object_list( struct sc_pkcs15_card *p15card, struct sc_profile *profile, + int type, unsigned int obj_id) +{ + struct sc_context *ctx = p15card->card->ctx; + struct sc_file *lst_file=NULL, *lst=NULL; + int rv = 0, ii; + char lst_name[NAME_MAX_LEN]; + unsigned char *buff=NULL; + unsigned char id[2]; + + SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_NORMAL); + sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "type %X; obj_id %X\n",type, obj_id); + + switch (type) { + case SC_PKCS15_TYPE_PRKEY_RSA: + case COSM_TYPE_PRKEY_RSA: + snprintf(lst_name, NAME_MAX_LEN,"%s-private-list", COSM_TITLE); + break; + case SC_PKCS15_TYPE_PUBKEY_RSA: + case SC_PKCS15_TYPE_CERT_X509: + case SC_PKCS15_TYPE_DATA_OBJECT: + case COSM_TYPE_PUBKEY_RSA: + snprintf(lst_name, NAME_MAX_LEN,"%s-public-list", COSM_TITLE); + break; + default: + SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_INCORRECT_PARAMETERS, "AWP update object list: invalid type"); + } + + sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "AWP update object list: select '%s' file\n", lst_name); + rv = sc_profile_get_file(profile, lst_name, &lst_file); + SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, rv, "AWP update object list: cannot instantiate list file"); + + rv = sc_select_file(p15card->card, &lst_file->path, &lst); + SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, rv, "AWP update object list: cannot select list file"); + + rv = sc_pkcs15init_authenticate(profile, p15card, lst, SC_AC_OP_READ); + SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, rv, "AWP update object list: 'read' authentication failed"); + + buff = malloc(lst->size); + if (!buff) + SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_MEMORY_FAILURE, "AWP update object list: allocation error"); + + rv = sc_read_binary(p15card->card, 0, buff, lst->size, 0); + if (rv != lst->size) + goto done; + + id[0] = (obj_id >> 8) & 0xFF; + id[1] = obj_id & 0xFF; + for (ii=0; iisize; ii+=5) { + if (*(buff+ii)==0xFF && *(buff+ii+1)==id[0] && *(buff+ii+2)==id[1]) { + rv = sc_pkcs15init_authenticate(profile, p15card, lst, SC_AC_OP_UPDATE); + if (rv) + goto done; + + rv = sc_update_binary(p15card->card, ii, (unsigned char *)"\0", 1, 0); + if (rv && rv!=1) + rv = SC_ERROR_INVALID_CARD; + break; + } + } + + if (rv > 0) + rv = 0; +done: + if (buff) + free(buff); + if (lst) + sc_file_free(lst); + if (lst_file) + sc_file_free(lst_file); + + SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_NORMAL, rv); +} + + +static int +awp_update_df_delete_cert(struct sc_pkcs15_card *p15card, struct sc_profile *profile, + struct sc_pkcs15_object *obj) +{ + struct sc_context *ctx = p15card->card->ctx; + struct sc_file *info_file = NULL; + struct sc_path path; + int rv = SC_ERROR_NOT_SUPPORTED; + unsigned file_id; + + SC_FUNC_CALLED(ctx, 1); + + path = ((struct sc_pkcs15_cert_info *) obj->data)->path; + file_id = path.value[path.len-2] * 0x100 + path.value[path.len-1]; + sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "file-id:%X\n", file_id); + + rv = awp_new_file(p15card, profile, obj->type, file_id & 0xFF, &info_file, NULL); + SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, rv, "AWP 'delete cert' update DF failed: cannt get allocate new AWP file"); + sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "info file-id:%X\n", info_file->id); + + rv = cosm_delete_file(p15card, profile, info_file); + if (rv != SC_ERROR_FILE_NOT_FOUND) + SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, rv, "AWP 'delete cert' update DF failed: delete info file error"); + + rv = awp_delete_from_container(p15card, profile, obj->type, file_id); + SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, rv, "AWP 'delete cert' update DF failed: cannot update container"); + + rv = awp_remove_from_object_list(p15card, profile, obj->type, file_id); + SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, rv, "AWP 'delete cert' update DF failed: cannot remove object"); + + SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_NORMAL, rv); +} + + +static int +awp_update_df_delete_prvkey(struct sc_pkcs15_card *p15card, struct sc_profile *profile, + struct sc_pkcs15_object *obj) +{ + struct sc_context *ctx = p15card->card->ctx; + struct sc_file *info_file = NULL; + struct sc_path path; + int rv = SC_ERROR_NOT_SUPPORTED; + unsigned file_id; + + SC_FUNC_CALLED(ctx, 1); + + path = ((struct sc_pkcs15_prkey_info *) obj->data)->path; + file_id = path.value[path.len-2] * 0x100 + path.value[path.len-1]; + sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "file-id:%X\n", file_id); + + rv = awp_new_file(p15card, profile, obj->type, file_id & 0xFF, &info_file, NULL); + SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, rv, "AWP 'delete prkey' update DF failed: cannt get allocate new AWP file"); + sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "info file-id:%X\n", info_file->id); + + rv = cosm_delete_file(p15card, profile, info_file); + if (rv != SC_ERROR_FILE_NOT_FOUND) + SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, rv, "AWP 'delete prkey' update DF failed: delete info file error"); + + rv = awp_delete_from_container(p15card, profile, obj->type, file_id); + SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, rv, "AWP 'delete prkey' update DF failed: cannot update container"); + + rv = awp_remove_from_object_list(p15card, profile, obj->type, file_id); + SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, rv, "AWP 'delete prkey' update DF failed: cannot remove object"); + + SC_FUNC_RETURN(ctx, 1, rv); +} + + +static int +awp_update_df_delete_pubkey(struct sc_pkcs15_card *p15card, struct sc_profile *profile, + struct sc_pkcs15_object *obj) +{ + struct sc_context *ctx = p15card->card->ctx; + struct sc_file *info_file = NULL; + struct sc_path path; + int rv = SC_ERROR_NOT_SUPPORTED; + unsigned file_id; + + SC_FUNC_CALLED(ctx, 1); + + path = ((struct sc_pkcs15_pubkey_info *) obj->data)->path; + file_id = path.value[path.len-2] * 0x100 + path.value[path.len-1]; + sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "file-id:%X\n", file_id); + + rv = awp_new_file(p15card, profile, obj->type, file_id & 0xFF, &info_file, NULL); + SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, rv, "AWP 'delete pubkey' update DF failed: cannt get allocate new AWP file"); + sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "info file-id:%X\n", info_file->id); + + rv = cosm_delete_file(p15card, profile, info_file); + if (rv != SC_ERROR_FILE_NOT_FOUND) + SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, rv, "AWP 'delete pubkey' update DF failed: delete info file error"); + + rv = awp_delete_from_container(p15card, profile, obj->type, file_id); + SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, rv, "AWP 'delete pubkey' update DF failed: cannot update container"); + + rv = awp_remove_from_object_list(p15card, profile, obj->type, file_id); + SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, rv, "AWP 'delete pubkey' update DF failed: cannot remove object"); + + SC_FUNC_RETURN(ctx, 1, rv); +} + + +static int +awp_update_df_delete_data(struct sc_pkcs15_card *p15card, struct sc_profile *profile, + struct sc_pkcs15_object *obj) +{ + struct sc_context *ctx = p15card->card->ctx; + int rv = SC_ERROR_NOT_SUPPORTED; + + SC_FUNC_CALLED(ctx, 1); + SC_FUNC_RETURN(ctx, 1, rv); +} + +int +awp_update_df_delete(struct sc_pkcs15_card *p15card, struct sc_profile *profile, + struct sc_pkcs15_object *object) +{ + struct sc_context *ctx = p15card->card->ctx; + int rv; + + SC_FUNC_CALLED(ctx, 1); + if (!object) + SC_FUNC_RETURN(ctx, 1, SC_SUCCESS); + + switch (object->type) { + case SC_PKCS15_TYPE_CERT_X509: + rv = awp_update_df_delete_cert(p15card, profile, object); + break; + case SC_PKCS15_TYPE_PRKEY_RSA: + rv = awp_update_df_delete_prvkey(p15card, profile, object); + break; + case SC_PKCS15_TYPE_PUBKEY_RSA: + rv = awp_update_df_delete_pubkey(p15card, profile, object); + break; + case SC_PKCS15_TYPE_DATA_OBJECT: + rv = awp_update_df_delete_data(p15card, profile, object); + break; + default: + SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_INVALID_ARGUMENTS, "'Create' update DF failed: unsupported object type"); + } + + SC_FUNC_RETURN(ctx, 1, rv); +} + +#endif /* #ifdef ENABLE_OPENSSL */ diff --git a/src/pkcs15init/pkcs15-oberthur.c b/src/pkcs15init/pkcs15-oberthur.c index b34b2bc8..a27db74f 100644 --- a/src/pkcs15init/pkcs15-oberthur.c +++ b/src/pkcs15init/pkcs15-oberthur.c @@ -20,23 +20,20 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "config.h" - #include #include #include #include #include #include -#ifdef ENABLE_OPENSSL -#include -#endif +#include "config.h" #include "libopensc/opensc.h" #include "libopensc/cardctl.h" #include "libopensc/log.h" -#include "pkcs15-init.h" #include "profile.h" +#include "pkcs15-init.h" +#include "pkcs15-oberthur.h" #define COSM_TITLE "OberthurAWP" @@ -265,10 +262,11 @@ cosm_create_dir(struct sc_profile *profile, struct sc_pkcs15_card *p15card, }; SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_VERBOSE); - + +#if 0 rv = sc_pkcs15init_create_file(profile, p15card, df); SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, rv, "Failed to create DIR DF"); - +#endif /* Oberthur AWP file system is expected.*/ /* Create private objects DF */ for (ii = 0; create_dfs[ii]; ii++) { @@ -785,6 +783,98 @@ cosm_store_key(struct sc_profile *profile, struct sc_pkcs15_card *p15card, } +static int +cosm_emu_update_dir (struct sc_pkcs15_card *p15card, + struct sc_profile *profile, struct sc_app_info *info) +{ + SC_FUNC_CALLED(p15card->card->ctx, 1); + /* No DIR file in the native Oberthur card */ + SC_FUNC_RETURN(p15card->card->ctx, 1, SC_SUCCESS); +} + + +static int +cosm_emu_update_any_df(struct sc_pkcs15_card *p15card, struct sc_profile *profile, + unsigned op, struct sc_pkcs15_object *object) +{ + struct sc_context *ctx = p15card->card->ctx; + int rv = SC_ERROR_NOT_SUPPORTED; + + SC_FUNC_CALLED(ctx, 1); + switch(op) { + case SC_AC_OP_ERASE: + sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "Update DF; erase object('%s',type:%X)", object->label, object->type); + rv = awp_update_df_delete(p15card, profile, object); + break; + case SC_AC_OP_CREATE: + sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "Update DF; create object('%s',type:%X)", object->label, object->type); + rv = awp_update_df_create(p15card, profile, object); + break; + } + + SC_FUNC_RETURN(ctx, 1, rv); +} + + +static int +cosm_emu_update_tokeninfo(struct sc_pkcs15_card *p15card, struct sc_profile *profile, + struct sc_pkcs15_tokeninfo *tinfo) +{ + struct sc_context *ctx = p15card->card->ctx; + struct sc_file *file = NULL; + int rv, flags = 0, label_len; + unsigned char *buf = NULL; + + SC_FUNC_CALLED(ctx, 1); + + if (sc_profile_get_file(profile, COSM_TITLE"-token-info", &file)) + SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_INCONSISTENT_PROFILE, "cannot find "COSM_TITLE"-token-info"); + + buf = calloc(1, file->size); + if (!buf) + SC_FUNC_RETURN(ctx, 1, SC_ERROR_MEMORY_FAILURE); + + label_len = strlen(tinfo->label) > (file->size - 4) ? (file->size - 4) : strlen(tinfo->label); + memcpy(buf, tinfo->label, label_len); + memset(buf + label_len, ' ', file->size - 4 - label_len); + + if (p15card->flags & SC_PKCS15_CARD_FLAG_PRN_GENERATION) + flags |= 0x01; + + if (p15card->flags & SC_PKCS15_CARD_FLAG_LOGIN_REQUIRED) + flags |= 0x04; + + if (p15card->flags & SC_PKCS15_CARD_FLAG_USER_PIN_INITIALIZED) + flags |= 0x08; + + if (p15card->flags & SC_PKCS15_CARD_FLAG_TOKEN_INITIALIZED) + flags |= 0x0400; + + memset(buf + file->size - 4, 0, 4); + *(buf + file->size - 1) = flags % 0x100; + *(buf + file->size - 2) = (flags % 0x10000) / 0x100; + + sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "Update token info (label:'%s',flags:%X,p15card->flags:%X)", buf, flags, p15card->flags); + rv = sc_pkcs15init_update_file(profile, p15card, file, buf, file->size); + free(buf); + + if (rv > 0) + rv = 0; + + SC_FUNC_RETURN(ctx, 1, rv); +} + + +static int +cosm_emu_write_info(struct sc_pkcs15_card *p15card, + struct sc_profile *profile, struct sc_pkcs15_object *pin_obj) +{ + SC_FUNC_CALLED(p15card->card->ctx, 1); + /* No OpenSC Info file in the native Oberthur card */ + SC_FUNC_RETURN(p15card->card->ctx, 1, SC_SUCCESS); +} + + static struct sc_pkcs15init_operations sc_pkcs15init_oberthur_operations = { cosm_erase_card, @@ -800,7 +890,15 @@ sc_pkcs15init_oberthur_operations = { NULL, NULL, /* encode private/public key */ NULL, /* finalize_card */ - NULL /* delete_object */ + NULL, /* delete_object */ +#ifdef ENABLE_OPENSSL + cosm_emu_update_dir, + cosm_emu_update_any_df, + cosm_emu_update_tokeninfo, + cosm_emu_write_info +#else + NULL, NULL, NULL, NULL +#endif }; struct sc_pkcs15init_operations *