/* * Oberthur AWP extension for PKCS #15 initialization * * Copyright (C) 2010 Viktor Tarasov * Copyright (C) 2002 Juha Yrjola * * 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 "pkcs15-oberthur.h" #include "libopensc/opensc.h" #include "libopensc/cardctl.h" #include "libopensc/log.h" #include "profile.h" #include "pkcs15-init.h" #include "libopensc/asn1.h" #ifdef ENABLE_OPENSSL #include "libopensc/sc-ossl-compat.h" 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]; const char *itag=NULL, *otag=NULL; LOG_FUNC_CALLED(ctx); sc_log(ctx, "type 0x%X; num %i; info %p; obj %p", type, num, info_out, obj_out); switch (type) { case SC_PKCS15_TYPE_CERT_X509: itag = "certificate-info"; otag = "template-certificate"; break; case SC_PKCS15_TYPE_PRKEY_RSA: case COSM_TYPE_PRKEY_RSA: itag = "private-key-info"; otag = "template-private-key"; break; case SC_PKCS15_TYPE_PUBKEY_RSA: case COSM_TYPE_PUBKEY_RSA: itag = "public-key-info"; otag = "template-public-key"; break; case SC_PKCS15_TYPE_DATA_OBJECT: itag = "data-info"; otag = "template-data"; break; case COSM_TYPE_PRIVDATA_OBJECT: itag = "privdata-info"; otag = "template-privdata"; break; case SC_PKCS15_TYPE_AUTH_PIN: case COSM_TOKENINFO : itag = "token-info"; num = 0; break; case COSM_PUBLIC_LIST: itag = "public-list"; num = 0; break; case COSM_PRIVATE_LIST: itag = "private-list"; num = 0; break; case COSM_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_log(ctx, "info template %s",name); if (sc_profile_get_file(profile, name, &ifile) < 0) { sc_log(ctx, "profile does not defines template '%s'", name); return SC_ERROR_INCONSISTENT_PROFILE; } } if (otag) { sc_log(ctx, "obj template %s",otag); if (sc_profile_get_file(profile, otag, &ofile) < 0) { sc_file_free(ifile); sc_log(ctx, "profile does not defines template '%s'", 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_log(ctx, "info_file(id:%04X,size:%"SC_FORMAT_LEN_SIZE_T"u,rlen:%"SC_FORMAT_LEN_SIZE_T"u)", ifile->id, ifile->size, ifile->record_length); *info_out = ifile; } else { sc_file_free(ifile); } } if (ofile) { sc_log(ctx, "obj file %04X; size %"SC_FORMAT_LEN_SIZE_T"u; ", ofile->id, ofile->size); if (obj_out) *obj_out = ofile; else sc_file_free(ofile); } LOG_FUNC_RETURN(ctx, 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; LOG_FUNC_CALLED(ctx); switch (type) { case TLV_TYPE_LLV : if (!(pp = realloc(*blob, *blob_size + 2 + lv->len))) return SC_ERROR_OUT_OF_MEMORY; *(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_OUT_OF_MEMORY; *(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 (0 == *blob_size + lv->len) return SC_ERROR_INVALID_DATA; if (!(pp = realloc(*blob, *blob_size + lv->len))) return SC_ERROR_OUT_OF_MEMORY; memcpy(pp + *blob_size, lv->value, lv->len); *blob_size += lv->len; break; default: sc_log(ctx, "Invalid tlv type %i",type); return SC_ERROR_INCORRECT_PARAMETERS; } *blob = pp; LOG_FUNC_RETURN(ctx, SC_SUCCESS); } static int awp_new_container_entry(struct sc_pkcs15_card *p15card, unsigned char *buff, size_t len) { struct sc_context *ctx = p15card->card->ctx; int mm, rv = 0; unsigned ii, marks[5] = {4,6,8,10,0}; unsigned char rand_buf[0x10]; LOG_FUNC_CALLED(ctx); if (len<0x34) LOG_TEST_RET(ctx, SC_ERROR_INCORRECT_PARAMETERS, "Invalid container update size"); rv = sc_get_challenge(p15card->card, rand_buf, sizeof(rand_buf)); LOG_TEST_RET(ctx, rv, "Cannot get challenge"); *(buff + 12) = 0x26; *(buff + 13) = '{'; for (ii=0, mm = 0; iicard->ctx; int rv; unsigned char *buff = NULL; LOG_FUNC_CALLED(ctx); sc_log(ctx, "container file(file-id:%X,rlen:%"SC_FORMAT_LEN_SIZE_T"u,rcount:%"SC_FORMAT_LEN_SIZE_T"u)", list_file->id, list_file->record_length, list_file->record_count); buff = malloc(list_file->record_length); if (!buff) LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY); memset(buff, 0, list_file->record_length); rv = awp_new_container_entry(p15card, buff, list_file->record_length); if (rv < 0) { free(buff); sc_log(ctx, "Cannot create container"); LOG_FUNC_RETURN(ctx, rv); } *(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); 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); free(buff); LOG_FUNC_RETURN(ctx, 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; LOG_FUNC_CALLED(ctx); sc_log(ctx, "create container(%X:%X:%X)", acc->prkey_id, acc->cert_id, acc->pubkey_id); rv = awp_new_file(p15card, profile, COSM_CONTAINER_LIST, 0, &clist, NULL); LOG_TEST_RET(ctx, rv, "Create container failed"); sc_log(ctx, "contaner cfile(rcount:%"SC_FORMAT_LEN_SIZE_T"u,rlength:%"SC_FORMAT_LEN_SIZE_T"u)", clist->record_count, clist->record_length); rv = sc_select_file(p15card->card, &clist->path, &file); LOG_TEST_RET(ctx, rv, "Create container failed: cannot select container's list"); file->record_length = clist->record_length; sc_log(ctx, "contaner file(rcount:%"SC_FORMAT_LEN_SIZE_T"u,rlength:%"SC_FORMAT_LEN_SIZE_T"u)", file->record_count, file->record_length); sc_log(ctx, "Append new record %"SC_FORMAT_LEN_SIZE_T"u for private key", file->record_count + 1); rv = awp_create_container_record(p15card, profile, file, acc); sc_file_free(file); sc_file_free(clist); LOG_FUNC_RETURN(ctx, 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, size_t rec, int offs) { struct sc_context *ctx = p15card->card->ctx; int rv; unsigned char *buff = NULL; LOG_FUNC_CALLED(ctx); sc_log(ctx, "update container entry(type:%X,id %i,rec %"SC_FORMAT_LEN_SIZE_T"u,offs %i", type, file_id, rec, offs); sc_log(ctx, "container file(file-id:%X,rlen:%"SC_FORMAT_LEN_SIZE_T"u,rcount:%"SC_FORMAT_LEN_SIZE_T"u)", list_file->id, list_file->record_length, list_file->record_count); buff = malloc(list_file->record_length); if (!buff) LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY); memset(buff, 0, list_file->record_length); if (rec > list_file->record_count) { rv = awp_new_container_entry(p15card, buff, list_file->record_length); } else { rv = sc_select_file(p15card->card, &list_file->path, NULL); if (!rv) rv = sc_read_record(p15card->card, rec, buff, list_file->record_length, SC_RECORD_BY_REC_NR); } if (rv < 0) { free(buff); LOG_FUNC_RETURN(ctx, rv); } switch (type) { case SC_PKCS15_TYPE_PUBKEY_RSA: case COSM_TYPE_PUBKEY_RSA: if (*(buff + offs + 4)) sc_log(ctx, "Insert public key to container that contains certificate %02X%02X", *(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)) { free(buff); LOG_TEST_RET(ctx, 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: free(buff); LOG_FUNC_RETURN(ctx, SC_ERROR_INCORRECT_PARAMETERS); } 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); } free(buff); LOG_FUNC_RETURN(ctx, 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; size_t rec, rec_offs; unsigned char *list = NULL; LOG_FUNC_CALLED(ctx); sc_log(ctx, "update container(type:%X,obj_id:%X)", 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; rv = sc_select_file(p15card->card, &clist->path, &file); if (rv) goto done; file->record_length = clist->record_length; if (type == SC_PKCS15_TYPE_PRKEY_RSA || type == COSM_TYPE_PRKEY_RSA) { rec_offs = 0; rv = awp_update_container_entry(p15card, profile, file, type, obj_id, file->record_count + 1, rec_offs); goto done; } list = malloc(AWP_CONTAINER_RECORD_LEN * file->record_count); if (!list) { rv = SC_ERROR_OUT_OF_MEMORY; 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_log(ctx, "rec %"SC_FORMAT_LEN_SIZE_T"u; rec_offs %"SC_FORMAT_LEN_SIZE_T"u", 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; 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; rv = sc_pkcs15init_authenticate(profile, p15card, ff, SC_AC_OP_READ); if (rv) { sc_file_free(ff); break; } buff = malloc(ff->size); if (!buff) rv = SC_ERROR_OUT_OF_MEMORY; if (!rv) { rv = sc_read_binary(p15card->card, 0, buff, ff->size, 0); if ((unsigned)rv == ff->size) { rv = 0; id_offs = 5 + *(buff+3); if (key_id->len == *(buff + id_offs) && !memcmp(key_id->value, buff + id_offs + 1, key_id->len)) { sc_log(ctx, "found key file friend"); 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); } } } free(buff); sc_file_free(ff); if (rv) break; } } } done: sc_file_free(clist); sc_file_free(file); if (list) free(list); LOG_FUNC_RETURN(ctx, 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"; LOG_FUNC_CALLED(ctx); blob_size = 2; if (!(blob = malloc(blob_size))) { r = SC_ERROR_OUT_OF_MEMORY; goto done; } /* TODO: cert flags */ *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); LOG_FUNC_RETURN(ctx, r); } static 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; unsigned ii; LOG_FUNC_CALLED(ctx); sc_log(ctx, "type %i, num %i", 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-data"); snprintf(lst_name, NAME_MAX_LEN,"%s-public-list", COSM_TITLE); break; case COSM_TYPE_PRIVDATA_OBJECT: snprintf(obj_name, NAME_MAX_LEN, "template-privdata"); snprintf(lst_name, NAME_MAX_LEN,"%s-private-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_log(ctx, "Not supported file type %X", type); return SC_ERROR_INVALID_ARGUMENTS; } sc_log(ctx, "obj_name %s; num 0x%X",obj_name, num); sc_log(ctx, "lst_name %s",lst_name); if (sc_profile_get_file(profile, obj_name, &obj_file) < 0) { sc_log(ctx, "No profile template '%s'", obj_name); rv = SC_ERROR_NOT_SUPPORTED; goto done; } else if (sc_profile_get_file(profile, lst_name, &lst_file) < 0) { sc_log(ctx, "No profile template '%s'", 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); 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_OUT_OF_MEMORY; goto done; } rv = sc_pkcs15init_authenticate(profile, p15card, lst_file, SC_AC_OP_READ); if (rv) goto done; rv = sc_pkcs15init_authenticate(profile, p15card, lst_file, SC_AC_OP_UPDATE); if (rv) goto done; rv = sc_select_file(p15card->card, &lst_file->path, NULL); if (rv == SC_ERROR_FILE_NOT_FOUND) rv = sc_pkcs15init_create_file(profile, p15card, lst_file); if (rv < 0) goto done; rv = sc_read_binary(p15card->card, 0, buff, lst_file->size, lst_file->ef_structure); 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_log(ctx, "ii %i, rv %i; %X; %"SC_FORMAT_LEN_SIZE_T"u", 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_log(ctx, "rv %i",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); LOG_FUNC_RETURN(ctx, 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; LOG_FUNC_CALLED(ctx); #if OPENSSL_VERSION_NUMBER < 0x30000000L ERR_load_ERR_strings(); #endif ERR_load_crypto_strings(); key_info = (struct sc_pkcs15_prkey_info *)obj->data; sc_log(ctx, "object(%s,type:%X)", 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; ki->label.value = (unsigned char *)strdup(obj->label); ki->label.len = strlen(obj->label); sc_log(ctx, "cosm_encode_key_info() label(%u):%s", ki->label.len, ki->label.value); /* * Oberthur saves modulus value without tag and length. */ sc_log(ctx, "pubkey->modulus.len %"SC_FORMAT_LEN_SIZE_T"u", pubkey->modulus.len); ki->modulus.value = malloc(pubkey->modulus.len); if (!ki->modulus.value) { r = SC_ERROR_OUT_OF_MEMORY; 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_OUT_OF_MEMORY; 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) LOG_TEST_RET(ctx, SC_ERROR_OUT_OF_MEMORY, "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_log(ctx, "cosm_encode_key_info() label:%s",ki->label.value); done: #if OPENSSL_VERSION_NUMBER < 0x30000000L ERR_load_ERR_strings(); #endif ERR_load_crypto_strings(); LOG_FUNC_RETURN(ctx, r); } static void awp_free_key_info(struct awp_key_info *ki) { free(ki->modulus.value); free(ki->exponent.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; LOG_FUNC_CALLED(ctx); sc_log(ctx, "file:%p, kinfo:%p, cinfo:%p", file, ki, ci); blob_size = 2; blob = malloc(blob_size); if (!blob) LOG_TEST_RET(ctx, SC_ERROR_OUT_OF_MEMORY, "AWP set key info failed: blob allocation error"); sc_log(ctx, "label:%s",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); if (r) goto done; r = awp_update_blob(ctx, &blob, &blob_size, &ki->id, TLV_TYPE_LLV); if (r) goto done; r = awp_update_blob(ctx, &blob, &blob_size, &x30_lv, TLV_TYPE_V); 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); 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); if (r) goto done; r = awp_update_blob(ctx, &blob, &blob_size, &ki->exponent, TLV_TYPE_LV); if (r) goto done; } file->size = blob_size; r = sc_pkcs15init_create_file(profile, p15card, file); 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); if (r < 0) goto done; r = 0; done: if (blob) free(blob); LOG_FUNC_RETURN(ctx, 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; LOG_FUNC_CALLED(ctx); #if OPENSSL_VERSION_NUMBER < 0x30000000L ERR_load_ERR_strings(); #endif ERR_load_crypto_strings(); if (!obj || !ci) LOG_TEST_RET(ctx, SC_ERROR_INVALID_ARGUMENTS, "AWP encode cert failed: invalid parameters"); cert_info = (struct sc_pkcs15_cert_info *)obj->data; sc_log(ctx, "Encode cert(%s,id:%s,der(%p,%"SC_FORMAT_LEN_SIZE_T"u))", obj->label, sc_pkcs15_print_id(&cert_info->id), obj->content.value, obj->content.len); memset(&pubkey, 0, sizeof(pubkey)); 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) LOG_TEST_RET(ctx, SC_ERROR_INVALID_DATA, "AWP encode cert failed: invalid data"); x = d2i_X509_bio(mem, NULL); if (!x) LOG_TEST_RET(ctx, SC_ERROR_INVALID_DATA, "AWP encode cert failed: x509 parse error"); buff = OPENSSL_malloc(i2d_X509(x,NULL) + EVP_MAX_MD_SIZE); if (!buff) LOG_TEST_RET(ctx, SC_ERROR_OUT_OF_MEMORY, "AWP encode cert failed: memory allocation error"); /* * subject commonName. */ ptr = awp_get_commonName(x); if (!ptr) { r = SC_ERROR_INTERNAL; LOG_TEST_GOTO_ERR(ctx, r, "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) { r = SC_ERROR_INTERNAL; LOG_TEST_GOTO_ERR(ctx, r, "AWP encode cert failed: cannot get SubjectName"); } ci->subject.value = malloc(r); if (!ci->subject.value) { r = SC_ERROR_OUT_OF_MEMORY; LOG_TEST_GOTO_ERR(ctx, r, "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) { r = SC_ERROR_INTERNAL; LOG_TEST_GOTO_ERR(ctx, r, "AWP encode cert failed: cannot get IssuerName"); } ci->issuer.value = malloc(r); if (!ci->issuer.value) { r = SC_ERROR_OUT_OF_MEMORY; LOG_TEST_GOTO_ERR(ctx, r, "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) { r = SC_ERROR_OUT_OF_MEMORY; LOG_TEST_GOTO_ERR(ctx, r, "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 */ #if OPENSSL_VERSION_NUMBER >= 0x10100000L /* TODO the der encoding of a ANS1_INTEGER is a TLV, the original code only as using the * i2c_ASN1_INTEGER which is not in OpenSSL 1.1 * It was adding the tag V_ASN1_INTEGER and the one byte length back in in effect creating * a DER encoded ASN1_INTEGER * So we can simplify the code and make compatible with OpenSSL 1.1. This needs to be tested */ ci->serial.len = 0; ci->serial.value = NULL; /* get length */ ci->serial.len = i2d_ASN1_INTEGER(X509_get_serialNumber(x), NULL); if (ci->serial.len > 0) { if (!(ci->serial.value = malloc(ci->serial.len))) { ci->serial.len = 0; r = SC_ERROR_OUT_OF_MEMORY; goto err; } ci->serial.len = i2d_ASN1_INTEGER(X509_get_serialNumber(x), &ci->serial.value); } /* if len == 0, and value == NULL, then the cert did not have a serial number.*/ sc_log(ctx, "cert. serial encoded length %i", ci->serial.len); #else 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_OUT_OF_MEMORY; goto err; } 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_log(ctx, "cert. serial encoded length %i", encoded_len); } while (0); #endif ci->x509 = X509_dup(x); err: 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); LOG_FUNC_RETURN(ctx, r); } static void awp_free_cert_info(struct awp_cert_info *ci) { if (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_encode_data_info(struct sc_pkcs15_card *p15card, struct sc_pkcs15_object *obj, struct awp_data_info *di) { struct sc_context *ctx = p15card->card->ctx; struct sc_pkcs15_data_info *data_info; int r = 0; unsigned char *buf = NULL; size_t buflen; LOG_FUNC_CALLED(ctx); if (!obj || !di) LOG_TEST_RET(ctx, SC_ERROR_INVALID_ARGUMENTS, "AWP encode data failed: invalid parameters"); data_info = (struct sc_pkcs15_data_info *)obj->data; sc_log(ctx, "Encode data(%s,id:%s,der(%p,%"SC_FORMAT_LEN_SIZE_T"u))", obj->label, sc_pkcs15_print_id(&data_info->id), obj->content.value, obj->content.len); di->flags = 0x0000; di->label.value = (unsigned char *)strdup(obj->label); di->label.len = strlen(obj->label); di->app.len = strlen(data_info->app_label); if (di->app.len) { di->app.value = (unsigned char *)strdup(data_info->app_label); if (!di->app.value) LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY); } r = sc_asn1_encode_object_id(&buf, &buflen, &data_info->app_oid); LOG_TEST_RET(ctx, r, "AWP encode data failed: cannot encode OID"); di->oid.len = buflen + 2; di->oid.value = malloc(di->oid.len); if (!di->oid.value) { free(buf); LOG_TEST_RET(ctx, SC_ERROR_OUT_OF_MEMORY, "AWP encode data failed: cannot allocate OID"); } *(di->oid.value + 0) = 0x06; *(di->oid.value + 1) = buflen; memcpy(di->oid.value + 2, buf, buflen); free(buf); LOG_FUNC_RETURN(ctx, r); } static void awp_free_data_info(struct awp_data_info *di) { if (di->label.len && di->label.value) free(di->label.value); if (di->app.len && di->app.value) free(di->app.value); if (di->oid.len && di->oid.value) free(di->oid.value); memset(di, 0, sizeof(struct awp_data_info)); } static int awp_set_data_info (struct sc_pkcs15_card *p15card, struct sc_profile *profile, struct sc_file *file, struct awp_data_info *di) { struct sc_context *ctx = p15card->card->ctx; int r = 0, blob_size; unsigned char *blob; LOG_FUNC_CALLED(ctx); sc_log(ctx, "Set 'DATA' info %p", di); blob_size = 2; if (!(blob = malloc(blob_size))) { r = SC_ERROR_OUT_OF_MEMORY; goto done; } *blob = (di->flags >> 8) & 0xFF; *(blob + 1) = di->flags & 0xFF; r = awp_update_blob(ctx, &blob, &blob_size, &di->label, TLV_TYPE_LLV); if (r) goto done; r = awp_update_blob(ctx, &blob, &blob_size, &di->app, TLV_TYPE_LLV); if (r) goto done; r = awp_update_blob(ctx, &blob, &blob_size, &di->oid, 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); LOG_FUNC_RETURN(ctx, r); } 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_OUT_OF_MEMORY; 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; LOG_FUNC_CALLED(ctx); offs = 0; /* Flags */ if (buf_len - offs < 2) LOG_FUNC_RETURN(ctx, 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); LOG_TEST_RET(ctx, len, "AWP parse key info failed: label"); if (!len) LOG_FUNC_RETURN(ctx, SC_SUCCESS); offs += len; /* Ignore Key ID */ len = awp_get_lv(ctx, buf, buf_len, offs, 2, &ikey->id); LOG_TEST_RET(ctx, len, "AWP parse key info failed: ID"); if (!len) LOG_FUNC_RETURN(ctx, SC_SUCCESS); offs += len; while (*(buf + offs) == '0') offs++; /* Subject */ len = awp_get_lv(ctx, buf, buf_len, offs, 2, &ikey->subject); LOG_TEST_RET(ctx, len, "AWP parse key info failed: subject"); if (!len) LOG_FUNC_RETURN(ctx, 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); LOG_TEST_RET(ctx, len, "AWP parse key info failed: modulus"); if (!len) LOG_FUNC_RETURN(ctx, SC_SUCCESS); offs += len; /* Exponent */ len = awp_get_lv(ctx, buf, buf_len, offs, 1, &ikey->exponent); LOG_TEST_RET(ctx, len, "AWP parse key info failed: exponent"); if (!len) LOG_FUNC_RETURN(ctx, SC_SUCCESS); LOG_FUNC_RETURN(ctx, 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; LOG_FUNC_CALLED(ctx); rv = awp_new_file(p15card, profile, SC_PKCS15_TYPE_PRKEY_RSA, prvkey_id & 0xFF, &info_file, &key_file); LOG_TEST_RET(ctx, rv, "AWP update key info failed: instantiation error"); sc_log(ctx, "key id %X; info id%X", key_file->id, info_file->id); rv = sc_pkcs15init_authenticate(profile, p15card, info_file, SC_AC_OP_READ); if (rv) { sc_log(ctx, "AWP update key info failed: 'READ' authentication error"); goto done; } rv = sc_select_file(p15card->card, &info_file->path, &file); if (rv) { sc_log(ctx, "AWP update key info failed: cannot select info file"); goto done; } buf = calloc(1,file->size); if (!buf) LOG_TEST_RET(ctx, SC_ERROR_OUT_OF_MEMORY, "AWP update key info failed: allocation error"); rv = sc_read_binary(p15card->card, 0, buf, file->size, 0); if (rv < 0) { sc_log(ctx, "AWP update key info failed: read info file error"); goto done; } buf_len = rv; memset(&ikey, 0, sizeof(ikey)); rv = awp_parse_key_info(ctx, buf, buf_len, &ikey); if (rv < 0) { sc_log(ctx, "AWP update key info failed: parse key info error"); goto done; } free(buf); rv = awp_set_key_info(p15card, profile, info_file, &ikey, ci); LOG_TEST_RET(ctx, 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); LOG_FUNC_RETURN(ctx, 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; LOG_FUNC_CALLED(ctx); 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); LOG_TEST_RET(ctx, rv, "COSM new file error"); memset(&icert, 0, sizeof(icert)); sc_log(ctx, "Cert Der(%p,%"SC_FORMAT_LEN_SIZE_T"u)", der.value, der.len); rv = awp_encode_cert_info(p15card, obj, &icert); SC_TEST_GOTO_ERR(ctx, SC_LOG_DEBUG_VERBOSE, rv, "'Create Cert' update DF failed: cannot encode info"); rv = awp_set_certificate_info(p15card, profile, info_file, &icert); SC_TEST_GOTO_ERR(ctx, SC_LOG_DEBUG_VERBOSE, 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_GOTO_ERR(ctx, SC_LOG_DEBUG_VERBOSE, 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_GOTO_ERR(ctx, SC_LOG_DEBUG_VERBOSE, rv, "'Create Cert' update DF failed: cannot update container"); sc_log(ctx, "PrvKeyID:%04X", prvkey_id); if (prvkey_id) rv = awp_update_key_info(p15card, profile, prvkey_id, &icert); SC_TEST_GOTO_ERR(ctx, SC_LOG_DEBUG_VERBOSE, rv, "'Create Cert' update DF failed: cannot update key info"); awp_free_cert_info(&icert); err: sc_file_free(info_file); sc_file_free(obj_file); LOG_FUNC_RETURN(ctx, 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; 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; struct sc_pkcs15_cert *p15cert = NULL; int rv; LOG_FUNC_CALLED(ctx); memset(&ikey, 0, sizeof(ikey)); memset(&icert, 0, sizeof(icert)); 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; 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_GOTO_ERR(ctx, SC_LOG_DEBUG_VERBOSE, rv, "AWP 'update private key' DF failed: cannot get certificate"); rv = sc_pkcs15_allocate_object_content(ctx, cert_obj, p15cert->data.value, p15cert->data.len); SC_TEST_GOTO_ERR(ctx, SC_LOG_DEBUG_VERBOSE, rv, "AWP 'update private key' DF failed: cannot allocate content"); rv = awp_encode_cert_info(p15card, cert_obj, &icert); SC_TEST_GOTO_ERR(ctx, SC_LOG_DEBUG_VERBOSE, rv, "AWP 'update private key' DF failed: cannot encode cert info"); sc_pkcs15_free_certificate(p15cert); p15cert = NULL; } 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, NULL); SC_TEST_GOTO_ERR(ctx, SC_LOG_DEBUG_VERBOSE, rv, "New private key info file error"); pubkey.algorithm = SC_ALGORITHM_RSA; sc_log(ctx, "PrKey Der(%p,%"SC_FORMAT_LEN_SIZE_T"u)", der.value, der.len); rv = sc_pkcs15_decode_pubkey(ctx, &pubkey, der.value, der.len); SC_TEST_GOTO_ERR(ctx, SC_LOG_DEBUG_VERBOSE, rv, "AWP 'update private key' DF failed: decode public key error"); rv = awp_encode_key_info(p15card, key_obj, &pubkey.u.rsa, &ikey); SC_TEST_GOTO_ERR(ctx, SC_LOG_DEBUG_VERBOSE, 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_GOTO_ERR(ctx, SC_LOG_DEBUG_VERBOSE, 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_GOTO_ERR(ctx, SC_LOG_DEBUG_VERBOSE, 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_GOTO_ERR(ctx, SC_LOG_DEBUG_VERBOSE, rv, "AWP 'update private key' DF failed: update container error"); err: if (p15cert) sc_pkcs15_free_certificate(p15cert); sc_file_free(info_file); if (cert_obj) awp_free_cert_info(&icert); awp_free_key_info(&ikey); LOG_FUNC_RETURN(ctx, 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; struct sc_path path; unsigned obj_id; int index, rv; LOG_FUNC_CALLED(ctx); 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; memset(&ikey, 0, sizeof(ikey)); rv = awp_new_file(p15card, profile, obj->type, index, &info_file, NULL); SC_TEST_GOTO_ERR(ctx, SC_LOG_DEBUG_VERBOSE, rv, "New public key info file error"); pubkey.algorithm = SC_ALGORITHM_RSA; sc_log(ctx, "PrKey Der(%p,%"SC_FORMAT_LEN_SIZE_T"u)", der.value, der.len); rv = sc_pkcs15_decode_pubkey(ctx, &pubkey, der.value, der.len); SC_TEST_GOTO_ERR(ctx, SC_LOG_DEBUG_VERBOSE, rv, "AWP 'update public key' DF failed: decode public key error"); rv = awp_encode_key_info(p15card, obj, &pubkey.u.rsa, &ikey); SC_TEST_GOTO_ERR(ctx, SC_LOG_DEBUG_VERBOSE, rv, "AWP 'update public key' DF failed: encode info error"); rv = awp_set_key_info(p15card, profile, info_file, &ikey, NULL); SC_TEST_GOTO_ERR(ctx, SC_LOG_DEBUG_VERBOSE, rv, "AWP 'update public key' DF failed: set info error"); rv = awp_update_object_list(p15card, profile, obj->type, index); SC_TEST_GOTO_ERR(ctx, SC_LOG_DEBUG_VERBOSE, 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_GOTO_ERR(ctx, SC_LOG_DEBUG_VERBOSE, rv, "AWP 'update public key' DF failed: update container error"); err: awp_free_key_info(&ikey); sc_file_free(info_file); LOG_FUNC_RETURN(ctx, 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; struct sc_file *info_file=NULL, *obj_file=NULL; struct awp_data_info idata; struct sc_path path; unsigned obj_id, obj_type = obj->auth_id.len ? COSM_TYPE_PRIVDATA_OBJECT : SC_PKCS15_TYPE_DATA_OBJECT; int rv; LOG_FUNC_CALLED(ctx); memset(&idata, 0, sizeof(idata)); path = ((struct sc_pkcs15_data_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, obj_type, obj_id & 0xFF, &info_file, &obj_file); LOG_TEST_GOTO_ERR(ctx, rv, "COSM new file error"); rv = awp_encode_data_info(p15card, obj, &idata); LOG_TEST_GOTO_ERR(ctx, rv, "'Create Data' update DF failed: cannot encode info"); rv = awp_set_data_info(p15card, profile, info_file, &idata); LOG_TEST_GOTO_ERR(ctx, rv, "'Create Data' update DF failed: cannot set info"); rv = awp_update_object_list(p15card, profile, obj_type, obj_id & 0xFF); LOG_TEST_GOTO_ERR(ctx, rv, "'Create Data' update DF failed: cannot update list"); err: awp_free_data_info(&idata); sc_file_free(info_file); sc_file_free(obj_file); LOG_FUNC_RETURN(ctx, 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_ERROR_INTERNAL; LOG_FUNC_CALLED(ctx); if (!object) LOG_FUNC_RETURN(ctx, 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: LOG_TEST_RET(ctx, SC_ERROR_INVALID_ARGUMENTS, "'Create' update DF failed: unsupported object type"); } LOG_FUNC_RETURN(ctx, 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; LOG_FUNC_CALLED(ctx); sc_log(ctx, "update container entry (type:%X,file-id:%X)", type, file_id); rv = awp_new_file(p15card, profile, COSM_CONTAINER_LIST, 0, &clist, NULL); LOG_TEST_RET(ctx, rv, "AWP update contaner entry: cannot get allocate AWP file"); rv = sc_select_file(p15card->card, &clist->path, &file); LOG_TEST_RET(ctx, rv, "AWP update contaner entry: cannot select container list file"); buff = malloc(file->record_length); if (!buff) LOG_TEST_RET(ctx, SC_ERROR_OUT_OF_MEMORY, "AWP update container entry: allocation error"); for (rec = 1; rec <= (unsigned)file->record_count; rec++) { rv = sc_read_record(p15card->card, rec, buff, file->record_length, SC_RECORD_BY_REC_NR); if (rv < 0) { sc_log(ctx, "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_log(ctx, "AWP update contaner entry: 'erase' authentication error %i", rv); break; } rv = sc_delete_record(p15card->card, rec); if (rv < 0) { sc_log(ctx, "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_log(ctx, "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_log(ctx, "AWP update contaner entry: update record error %i", rv); break; } } } if (rv > 0) rv = 0; free(buff); sc_file_free(clist); sc_file_free(file); LOG_FUNC_RETURN(ctx, 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; unsigned ii; char lst_name[NAME_MAX_LEN]; unsigned char *buff=NULL; unsigned char id[2]; LOG_FUNC_CALLED(ctx); sc_log(ctx, "type %X; obj_id %X",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: LOG_TEST_RET(ctx, SC_ERROR_INCORRECT_PARAMETERS, "AWP update object list: invalid type"); } sc_log(ctx, "AWP update object list: select '%s' file", lst_name); rv = sc_profile_get_file(profile, lst_name, &lst_file); LOG_TEST_RET(ctx, rv, "AWP update object list: cannot instantiate list file"); rv = sc_select_file(p15card->card, &lst_file->path, &lst); LOG_TEST_RET(ctx, rv, "AWP update object list: cannot select list file"); rv = sc_pkcs15init_authenticate(profile, p15card, lst, SC_AC_OP_READ); LOG_TEST_RET(ctx, rv, "AWP update object list: 'read' authentication failed"); buff = malloc(lst->size); if (!buff) LOG_TEST_RET(ctx, SC_ERROR_OUT_OF_MEMORY, "AWP update object list: allocation error"); rv = sc_read_binary(p15card->card, 0, buff, lst->size, 0); if (rv != (int)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); sc_file_free(lst); sc_file_free(lst_file); LOG_FUNC_RETURN(ctx, 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; LOG_FUNC_CALLED(ctx); path = ((struct sc_pkcs15_cert_info *) obj->data)->path; file_id = path.value[path.len-2] * 0x100 + path.value[path.len-1]; sc_log(ctx, "file-id:%X", file_id); rv = awp_new_file(p15card, profile, obj->type, file_id & 0xFF, &info_file, NULL); LOG_TEST_RET(ctx, rv, "AWP 'delete cert' update DF failed: cannot get allocate new AWP file"); sc_log(ctx, "info file-id:%X", info_file->id); rv = cosm_delete_file(p15card, profile, info_file); if (rv != SC_ERROR_FILE_NOT_FOUND) LOG_TEST_RET(ctx, rv, "AWP 'delete cert' update DF failed: delete info file error"); rv = awp_delete_from_container(p15card, profile, obj->type, file_id); LOG_TEST_RET(ctx, rv, "AWP 'delete cert' update DF failed: cannot update container"); rv = awp_remove_from_object_list(p15card, profile, obj->type, file_id); LOG_TEST_RET(ctx, rv, "AWP 'delete cert' update DF failed: cannot remove object"); LOG_FUNC_RETURN(ctx, 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; LOG_FUNC_CALLED(ctx); path = ((struct sc_pkcs15_prkey_info *) obj->data)->path; file_id = path.value[path.len-2] * 0x100 + path.value[path.len-1]; sc_log(ctx, "file-id:%X", file_id); rv = awp_new_file(p15card, profile, obj->type, file_id & 0xFF, &info_file, NULL); LOG_TEST_RET(ctx, rv, "AWP 'delete prkey' update DF failed: cannot get allocate new AWP file"); sc_log(ctx, "info file-id:%X", info_file->id); rv = cosm_delete_file(p15card, profile, info_file); if (rv != SC_ERROR_FILE_NOT_FOUND) LOG_TEST_RET(ctx, rv, "AWP 'delete prkey' update DF failed: delete info file error"); rv = awp_delete_from_container(p15card, profile, obj->type, file_id); LOG_TEST_RET(ctx, rv, "AWP 'delete prkey' update DF failed: cannot update container"); rv = awp_remove_from_object_list(p15card, profile, obj->type, file_id); LOG_TEST_RET(ctx, rv, "AWP 'delete prkey' update DF failed: cannot remove object"); LOG_FUNC_RETURN(ctx, 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; LOG_FUNC_CALLED(ctx); path = ((struct sc_pkcs15_pubkey_info *) obj->data)->path; file_id = path.value[path.len-2] * 0x100 + path.value[path.len-1]; sc_log(ctx, "file-id:%X", file_id); rv = awp_new_file(p15card, profile, obj->type, file_id & 0xFF, &info_file, NULL); LOG_TEST_RET(ctx, rv, "AWP 'delete pubkey' update DF failed: cannot get allocate new AWP file"); sc_log(ctx, "info file-id:%X", info_file->id); rv = cosm_delete_file(p15card, profile, info_file); if (rv != SC_ERROR_FILE_NOT_FOUND) LOG_TEST_RET(ctx, rv, "AWP 'delete pubkey' update DF failed: delete info file error"); rv = awp_delete_from_container(p15card, profile, obj->type, file_id); LOG_TEST_RET(ctx, rv, "AWP 'delete pubkey' update DF failed: cannot update container"); rv = awp_remove_from_object_list(p15card, profile, obj->type, file_id); LOG_TEST_RET(ctx, rv, "AWP 'delete pubkey' update DF failed: cannot remove object"); LOG_FUNC_RETURN(ctx, 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; struct sc_file *info_file = NULL; struct sc_path path; int rv = SC_ERROR_NOT_SUPPORTED; unsigned file_id; LOG_FUNC_CALLED(ctx); path = ((struct sc_pkcs15_data_info *) obj->data)->path; file_id = path.value[path.len-2] * 0x100 + path.value[path.len-1]; sc_log(ctx, "file-id:%X", file_id); rv = awp_new_file(p15card, profile, obj->type, file_id & 0xFF, &info_file, NULL); LOG_TEST_RET(ctx, rv, "AWP 'delete DATA' update DF failed: cannot get allocate new AWP file"); sc_log(ctx, "info file-id:%X", info_file->id); rv = cosm_delete_file(p15card, profile, info_file); if (rv != SC_ERROR_FILE_NOT_FOUND) LOG_TEST_RET(ctx, rv, "AWP 'delete DATA' update DF failed: delete info file error"); rv = awp_remove_from_object_list(p15card, profile, obj->type, file_id); LOG_TEST_RET(ctx, rv, "AWP 'delete DATA' update DF failed: cannot remove object"); LOG_FUNC_RETURN(ctx, 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_ERROR_INTERNAL; LOG_FUNC_CALLED(ctx); if (!object) LOG_FUNC_RETURN(ctx, 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: LOG_TEST_RET(ctx, SC_ERROR_INVALID_ARGUMENTS, "'Create' update DF failed: unsupported object type"); } SC_FUNC_RETURN(ctx, 1, rv); } #endif /* #ifdef ENABLE_OPENSSL */