int sc_pkcs15_parse_unusedspace(const u8 * buf, size_t buflen, struct sc_pkcs15_card *card) { const u8 *p = buf; size_t left = buflen; int r; sc_path_t path, dummy_path; sc_pkcs15_id_t auth_id; struct sc_asn1_entry asn1_unusedspace[] = { { "UnusedSpace", SC_ASN1_STRUCT, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, 0, NULL, NULL }, { NULL, 0, 0, 0, NULL, NULL } }; struct sc_asn1_entry asn1_unusedspace_values[] = { { "path", SC_ASN1_PATH, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, 0, NULL, NULL }, { "authId", SC_ASN1_PKCS15_ID, SC_ASN1_TAG_OCTET_STRING, SC_ASN1_OPTIONAL, NULL, NULL }, { NULL, 0, 0, 0, NULL, NULL } }; /* Clean the list if already present */ while (card->unusedspace_list) sc_pkcs15_remove_unusedspace(card, card->unusedspace_list); sc_format_path("3F00", &dummy_path); dummy_path.index = dummy_path.count = 0; sc_format_asn1_entry(asn1_unusedspace, asn1_unusedspace_values, NULL, 1); sc_format_asn1_entry(asn1_unusedspace_values, &path, NULL, 1); sc_format_asn1_entry(asn1_unusedspace_values+1, &auth_id, NULL, 0); while (left > 0) { memset(&auth_id, 0, sizeof(auth_id)); r = sc_asn1_decode(card->card->ctx, asn1_unusedspace, p, left, &p, &left); if (r == SC_ERROR_ASN1_END_OF_CONTENTS) break; if (r < 0) return r; /* If the path length is 0, it's a dummy path then don't add it. * If the path length isn't included (-1) then it's against the standard * but we'll just ignore it instead of returning an error. */ if (path.count > 0) { r = sc_pkcs15_make_absolute_path(&card->file_app->path, &path); if (r < 0) return r; r = sc_pkcs15_add_unusedspace(card, &path, &auth_id); if (r) return r; } } card->unusedspace_read = 1; return 0; }
void sc_pkcs15_card_free(struct sc_pkcs15_card *p15card) { if (p15card == NULL) return; assert(p15card->magic == SC_PKCS15_CARD_MAGIC); while (p15card->obj_list) sc_pkcs15_remove_object(p15card, p15card->obj_list); while (p15card->df_list) sc_pkcs15_remove_df(p15card, p15card->df_list); while (p15card->unusedspace_list) sc_pkcs15_remove_unusedspace(p15card, p15card->unusedspace_list); p15card->unusedspace_read = 0; if (p15card->file_app != NULL) sc_file_free(p15card->file_app); if (p15card->file_tokeninfo != NULL) sc_file_free(p15card->file_tokeninfo); if (p15card->file_odf != NULL) sc_file_free(p15card->file_odf); if (p15card->file_unusedspace != NULL) sc_file_free(p15card->file_unusedspace); p15card->magic = 0; if (p15card->label != NULL) free(p15card->label); if (p15card->serial_number != NULL) free(p15card->serial_number); if (p15card->manufacturer_id != NULL) free(p15card->manufacturer_id); if (p15card->last_update != NULL) free(p15card->last_update); if (p15card->preferred_language != NULL) free(p15card->preferred_language); if (p15card->seInfo != NULL) { size_t i; for (i = 0; i < p15card->num_seInfo; i++) free(p15card->seInfo[i]); free(p15card->seInfo); } free(p15card); }
int sc_pkcs15_encode_unusedspace(sc_context_t *ctx, struct sc_pkcs15_card *p15card, u8 **buf, size_t *buflen) { sc_path_t dummy_path; static const struct sc_asn1_entry c_asn1_unusedspace[] = { { "UnusedSpace", SC_ASN1_STRUCT, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, 0, NULL, NULL }, { NULL, 0, 0, 0, NULL, NULL } }; static const struct sc_asn1_entry c_asn1_unusedspace_values[] = { { "path", SC_ASN1_PATH, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, 0, NULL, NULL }, { "authId", SC_ASN1_PKCS15_ID, SC_ASN1_TAG_OCTET_STRING, SC_ASN1_OPTIONAL, NULL, NULL }, { NULL, 0, 0, 0, NULL, NULL } }; struct sc_asn1_entry *asn1_unusedspace = NULL; struct sc_asn1_entry *asn1_values = NULL; int unusedspace_count = 0, r, c = 0; sc_pkcs15_unusedspace_t *unusedspace; sc_format_path("3F00", &dummy_path); dummy_path.index = dummy_path.count = 0; unusedspace = p15card->unusedspace_list; for ( ; unusedspace != NULL; unusedspace = unusedspace->next) unusedspace_count++; if (unusedspace_count == 0) { /* The standard says there has to be at least 1 entry, * so we use a path with a length of 0 bytes */ r = sc_pkcs15_add_unusedspace(p15card, &dummy_path, NULL); if (r) return r; unusedspace_count = 1; } asn1_unusedspace = (struct sc_asn1_entry *) malloc(sizeof(struct sc_asn1_entry) * (unusedspace_count + 1)); if (asn1_unusedspace == NULL) { r = SC_ERROR_OUT_OF_MEMORY; goto err; } asn1_values = (struct sc_asn1_entry *) malloc(sizeof(struct sc_asn1_entry) * (unusedspace_count * 3)); if (asn1_values == NULL) { r = SC_ERROR_OUT_OF_MEMORY; goto err; } for (unusedspace = p15card->unusedspace_list; unusedspace != NULL; unusedspace = unusedspace->next) { sc_copy_asn1_entry(c_asn1_unusedspace, asn1_unusedspace + c); sc_format_asn1_entry(asn1_unusedspace + c, asn1_values + 3*c, NULL, 1); sc_copy_asn1_entry(c_asn1_unusedspace_values, asn1_values + 3*c); sc_format_asn1_entry(asn1_values + 3*c, &unusedspace->path, NULL, 1); sc_format_asn1_entry(asn1_values + 3*c+1, &unusedspace->auth_id, NULL, unusedspace->auth_id.len); c++; } asn1_unusedspace[c].name = NULL; r = sc_asn1_encode(ctx, asn1_unusedspace, buf, buflen); err: if (asn1_values != NULL) free(asn1_values); if (asn1_unusedspace != NULL) free(asn1_unusedspace); /* If we added the dummy entry, remove it now */ if (unusedspace_count == 1 && sc_compare_path(&p15card->unusedspace_list->path, &dummy_path)) sc_pkcs15_remove_unusedspace(p15card, p15card->unusedspace_list); return r; }
int card_helper_create_cert_file(sc_card_t *card, struct _virtual_file_t *virtual_file, size_t fcert_len, struct _virtual_file_t **certificate_virtual_file) { int r = SC_SUCCESS; sc_path_t fcert_path; sc_pkcs15_unusedspace_t *unused_space=NULL; sc_pkcs15_card_t *temp_p15card = NULL; int old_use_virtual_fs; /*!< backup of use_virtual_fs */ assert(card!=NULL && virtual_file!=NULL && certificate_virtual_file!=NULL); SC_FUNC_CALLED(card->ctx, 1); /* we backup use_virtual_fs */ old_use_virtual_fs = card_is_virtual_fs_active(card); /* we want to use card without virtual fs */ card_set_virtual_fs_state(card, 0); if(*certificate_virtual_file) { virtual_file_free(*certificate_virtual_file); *certificate_virtual_file = NULL; } memset(&fcert_path, 0, sizeof(struct sc_path)); /* 2. Look for a suitable file on UnusedSpace struct which fits the final certificate file size. 2.1 If found, take file's path to reuse it. 2.2 If not, create a file on Certificate Directory with final certificate len as its size */ /* we create a fake p15card structure */ temp_p15card = sc_pkcs15_card_new(); temp_p15card->card = card; r = sc_find_free_unusedspace( temp_p15card, fcert_len, &unused_space ); if (r!=SC_SUCCESS) goto chccf_end; if(unused_space) { /* we got a path */ r = sc_path_set_dnie ( &fcert_path, unused_space->path.type, unused_space->path.value, unused_space->path.len, unused_space->path.index, unused_space->path.count ); if (r!=SC_SUCCESS) goto chccf_end; } else { sc_path_t temp_path; /* move to certificate DF */ sc_format_path("3F006061", &temp_path); r = card_select_file(card, &temp_path, NULL); if(r != SC_SUCCESS) goto chccf_end; /* we start at 0x7001 file ID */ sc_format_path("7001", &fcert_path); do { r = card_create_cert_file( card, &fcert_path, fcert_len ); if (r == SC_ERROR_OBJECT_ALREADY_EXISTS) { fcert_path.value[1]++; } if(r!=SC_SUCCESS && r!=SC_ERROR_OBJECT_ALREADY_EXISTS) goto chccf_end; } while (r!=SC_SUCCESS); r = SC_SUCCESS; } /* create certificate file into vfs */ r = virtual_fs_append_new_virtual_file( DRVDATA(card)->virtual_fs, &fcert_path, virtual_file->data, virtual_file->data_size, virtual_file->data_size, 1, virtual_file_sync_state_synced, card_sync_card_to_virtual_fs_certificate_file_callback, virtual_file_sync_state_sync_pending, card_sync_virtual_fs_to_card_certificate_file_callback ); if(r != SC_SUCCESS) goto chccf_end; /* retrieve just created virtual file */ *certificate_virtual_file = virtual_fs_find_by_path( DRVDATA(card)->virtual_fs, &fcert_path ); chccf_end: /* we restore use_virtual_fs */ card_set_virtual_fs_state(card, old_use_virtual_fs); if (unused_space) { /* Delete UnusedSpace object if reused and also frees reserved memory */ sc_pkcs15_remove_unusedspace(temp_p15card, unused_space); } if (temp_p15card) { /* set to NULL without freeing because we reused structure */ temp_p15card->card = NULL; /* now free temp structure */ sc_pkcs15_card_free(temp_p15card); temp_p15card = NULL; } SC_FUNC_RETURN(card->ctx, 1, r); }