diff --git a/src/libopensc/Makefile.am b/src/libopensc/Makefile.am index c4df1137..48c2626d 100644 --- a/src/libopensc/Makefile.am +++ b/src/libopensc/Makefile.am @@ -11,7 +11,7 @@ noinst_HEADERS = cards.h ctbcs.h internal.h esteid.h muscle.h muscle-filesystem. cardctl.h asn1.h log.h \ errors.h types.h compression.h itacns.h iso7816.h \ authentic.h iasecc.h iasecc-sdo.h sm.h card-sc-hsm.h \ - pace.h cwa14890.h cwa-dnie.h card-gids.h + pace.h cwa14890.h cwa-dnie.h card-gids.h aux-data.h AM_CPPFLAGS = -DOPENSC_CONF_PATH=\"$(sysconfdir)/opensc.conf\" \ -I$(top_srcdir)/src @@ -50,6 +50,7 @@ libopensc_la_SOURCES = \ pkcs15-itacns.c pkcs15-gemsafeV1.c pkcs15-sc-hsm.c \ pkcs15-dnie.c pkcs15-gids.c \ compression.c p15card-helper.c sm.c \ + aux-data.c \ libopensc.exports if WIN32 libopensc_la_SOURCES += $(top_builddir)/win32/versioninfo.rc diff --git a/src/libopensc/Makefile.mak b/src/libopensc/Makefile.mak index c18dc1f0..845ca39b 100644 --- a/src/libopensc/Makefile.mak +++ b/src/libopensc/Makefile.mak @@ -33,6 +33,7 @@ OBJECTS = \ pkcs15-itacns.obj pkcs15-gemsafeV1.obj pkcs15-sc-hsm.obj \ pkcs15-dnie.obj pkcs15-gids.obj \ compression.obj p15card-helper.obj sm.obj \ + aux-data.obj \ $(TOPDIR)\win32\versioninfo.res all: $(TOPDIR)\win32\versioninfo.res $(TARGET) diff --git a/src/libopensc/aux-data.c b/src/libopensc/aux-data.c new file mode 100644 index 00000000..78fd94bc --- /dev/null +++ b/src/libopensc/aux-data.c @@ -0,0 +1,200 @@ +/* + * aux-data.c: Auxiliary data help functions + * + * Copyright (C) 2016 Viktor Tarasov + * + * 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 + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include + +#include "common/compat_strlcat.h" + +#include +#include +#include +#include + + +int +sc_aux_data_allocate(struct sc_context *ctx, struct sc_auxiliary_data **dst, struct sc_auxiliary_data *src) +{ + int rv = SC_ERROR_INTERNAL; + + LOG_FUNC_CALLED(ctx); + + if (!dst) + LOG_TEST_RET(ctx, SC_ERROR_INVALID_ARGUMENTS, "Cannot allocate auxiliary data"); + + if (*dst == NULL) { + *dst = calloc(1, sizeof(struct sc_auxiliary_data)); + if (*dst == NULL) + LOG_TEST_RET(ctx, SC_ERROR_OUT_OF_MEMORY, "Cannot allocate aux. data"); + } + + if ((src == NULL) || (src->type == SC_AUX_DATA_TYPE_NO_DATA)) + LOG_FUNC_RETURN(ctx, SC_SUCCESS); + + switch(src->type) { + case SC_AUX_DATA_TYPE_MD_CMAP_RECORD: + **dst = *src; + rv = SC_SUCCESS; + break; + default: + sc_log(ctx, "Invalid aux-data type %X", src->type); + LOG_TEST_RET(ctx, SC_ERROR_INVALID_ARGUMENTS, "Unknown aux-data type"); + } + + LOG_FUNC_RETURN(ctx, rv); +} + + +int +sc_aux_data_set_md_guid(struct sc_context *ctx, struct sc_auxiliary_data *aux_data, char *guid) +{ + struct sc_md_cmap_record *rec; + int rv = SC_ERROR_INTERNAL; + + LOG_FUNC_CALLED(ctx); + if (!aux_data || !guid || strlen(guid) > SC_MD_MAX_CONTAINER_NAME_LEN) + LOG_TEST_RET(ctx, SC_ERROR_INVALID_ARGUMENTS, "Cannot set guid for MD container"); + + switch(aux_data->type) { + case SC_AUX_DATA_TYPE_NO_DATA: + memset(aux_data, 0, sizeof(*aux_data)); + aux_data->type = SC_AUX_DATA_TYPE_MD_CMAP_RECORD; + case SC_AUX_DATA_TYPE_MD_CMAP_RECORD: + rec = &aux_data->data.cmap_record; + memcpy(rec->guid, guid, strlen(guid)); + rec->guid_len = strlen(guid); + sc_log(ctx, "set MD container GUID '%s'", aux_data->data.cmap_record.guid); + rv = SC_SUCCESS; + break; + default: + sc_log(ctx, "Invalid aux-data type %X", aux_data->type); + LOG_TEST_RET(ctx, SC_ERROR_INVALID_ARGUMENTS, "Unknown aux-data type"); + } + + LOG_FUNC_RETURN(ctx, rv); + return rv; +} + + +int +sc_aux_data_set_md_flags(struct sc_context *ctx, struct sc_auxiliary_data *aux_data, unsigned char flags) +{ + int rv = SC_ERROR_INTERNAL; + + LOG_FUNC_CALLED(ctx); + if (!aux_data) + LOG_TEST_RET(ctx, SC_ERROR_INVALID_ARGUMENTS, "Cannot set flags of MD container"); + + switch(aux_data->type) { + case SC_AUX_DATA_TYPE_NO_DATA: + memset(aux_data, 0, sizeof(*aux_data)); + aux_data->type = SC_AUX_DATA_TYPE_MD_CMAP_RECORD; + case SC_AUX_DATA_TYPE_MD_CMAP_RECORD: + aux_data->data.cmap_record.flags = flags; + sc_log(ctx, "set MD container flags '0x%X'", flags); + rv = SC_SUCCESS; + break; + default: + sc_log(ctx, "Invalid aux-data type %X", aux_data->type); + LOG_TEST_RET(ctx, SC_ERROR_INVALID_ARGUMENTS, "Unknown aux-data type"); + } + + LOG_FUNC_RETURN(ctx, rv); +} + + +int +sc_aux_data_get_md_guid(struct sc_context *ctx, struct sc_auxiliary_data *aux_data, + unsigned flags, unsigned char *out, size_t *out_size) +{ + struct sc_md_cmap_record *cmap_record = NULL; + char guid[SC_MD_MAX_CONTAINER_NAME_LEN + 3]; + + LOG_FUNC_CALLED(ctx); + if(!aux_data || !out || !out_size) + LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS); + + if (aux_data->type != SC_AUX_DATA_TYPE_MD_CMAP_RECORD) + LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_SUPPORTED); + + cmap_record = &aux_data->data.cmap_record; + + *guid = '\0'; + if (!flags) + strcpy(guid, "{"); + strlcat(guid, (char *)cmap_record->guid, sizeof(guid)-1); + if (!flags) + strlcat(guid, "}", sizeof(guid)); + + if (*out_size < strlen(guid)) + LOG_FUNC_RETURN(ctx, SC_ERROR_BUFFER_TOO_SMALL); + + memset(out, 0, *out_size); + memcpy(out, guid, strlen(guid)); + *out_size = strlen(guid); + + sc_log(ctx, "aux-data: returns guid '%s'", (char *)out); + LOG_FUNC_RETURN(ctx, SC_SUCCESS); +} + + +int +sc_aux_data_get_md_flags(struct sc_context *ctx, struct sc_auxiliary_data *aux_data, + unsigned char *flags) +{ + struct sc_md_cmap_record *cmap_record = NULL; + + LOG_FUNC_CALLED(ctx); + if(!aux_data || !flags) + LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS); + + if (aux_data->type != SC_AUX_DATA_TYPE_MD_CMAP_RECORD) + LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_SUPPORTED); + + *flags = aux_data->data.cmap_record.flags; + + sc_log(ctx, "aux-data: returns flags '0x%X'", *flags); + LOG_FUNC_RETURN(ctx, SC_SUCCESS); +} + + +void +sc_aux_data_free(struct sc_auxiliary_data **data) +{ + if (data == NULL || *data == NULL) + return; + + switch((*data)->type) { + case SC_AUX_DATA_TYPE_MD_CMAP_RECORD: + free(*data); + break; + default: + break; + } + + *data = NULL; +} + diff --git a/src/libopensc/aux-data.h b/src/libopensc/aux-data.h new file mode 100644 index 00000000..20b5ee1d --- /dev/null +++ b/src/libopensc/aux-data.h @@ -0,0 +1,85 @@ +/* + * aux-data.h: Non PKCS#15, non ISO7816 data + * Used to pass auxiliary data from non PKCS#15, non ISO7816 appliations (like minidriver) + * to card specific part through the standard PKCS#15 and ISO7816 frameworks + * + * Copyright (C) 2016 Viktor Tarasov + * + * 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 + */ + +#ifndef _AUX_DATA_H +#define _AUX_DATA_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "cardctl.h" +#include "internal.h" +#include "errors.h" +#include "asn1.h" +#include "types.h" + +#define SC_AUX_DATA_TYPE_NO_DATA 0x00 +#define SC_AUX_DATA_TYPE_MD_CMAP_RECORD 0x01 + +/* From Windows Smart Card Minidriver Specification + * Version 7.06 + * + * #define MAX_CONTAINER_NAME_LEN 39 + * #define CONTAINER_MAP_VALID_CONTAINER 1 + * #define CONTAINER_MAP_DEFAULT_CONTAINER 2 + * typedef struct _CONTAINER_MAP_RECORD + * { + * WCHAR wszGuid [MAX_CONTAINER_NAME_LEN + 1]; + * BYTE bFlags; + * BYTE bReserved; + * WORD wSigKeySizeBits; + * WORD wKeyExchangeKeySizeBits; + * } CONTAINER_MAP_RECORD, *PCONTAINER_MAP_RECORD; + */ +#define SC_MD_MAX_CONTAINER_NAME_LEN 39 +#define SC_MD_CONTAINER_MAP_VALID_CONTAINER 0x01 +#define SC_MD_CONTAINER_MAP_DEFAULT_CONTAINER 0x02 + +struct sc_md_cmap_record { + unsigned char guid[SC_MD_MAX_CONTAINER_NAME_LEN + 1]; + size_t guid_len; + unsigned flags; + unsigned keysize_sign; + unsigned keysize_keyexchange; +}; + +struct sc_auxiliary_data { + unsigned type; + union { + struct sc_md_cmap_record cmap_record; + } data; +}; + +int sc_aux_data_set_md_flags(struct sc_context *, struct sc_auxiliary_data *, unsigned char); +int sc_aux_data_allocate(struct sc_context *, struct sc_auxiliary_data **, struct sc_auxiliary_data *); +int sc_aux_data_set_md_guid(struct sc_context *, struct sc_auxiliary_data *, char *); +void sc_aux_data_free(struct sc_auxiliary_data **); +int sc_aux_data_get_md_guid(struct sc_context *, struct sc_auxiliary_data *, unsigned, + unsigned char *, size_t *); +int sc_aux_data_get_md_flags(struct sc_context *, struct sc_auxiliary_data *, unsigned char *); + +#ifdef __cplusplus +} +#endif + +#endif /* ifndef _AUX_DATA_H */ diff --git a/src/libopensc/libopensc.exports b/src/libopensc/libopensc.exports index cbb51c15..248df73b 100644 --- a/src/libopensc/libopensc.exports +++ b/src/libopensc/libopensc.exports @@ -53,6 +53,11 @@ sc_asn1_verify_tag sc_asn1_write_element sc_asn1_sig_value_sequence_to_rs sc_asn1_sig_value_rs_to_sequence +sc_aux_data_set_md_flags +sc_aux_data_allocate +sc_aux_data_set_md_guid +sc_aux_data_free +sc_aux_data_get_md_guid sc_base64_decode sc_base64_encode sc_bin_to_hex diff --git a/src/libopensc/pkcs15-prkey.c b/src/libopensc/pkcs15-prkey.c index af1bc359..f199aeae 100644 --- a/src/libopensc/pkcs15-prkey.c +++ b/src/libopensc/pkcs15-prkey.c @@ -31,6 +31,7 @@ #include "asn1.h" #include "pkcs15.h" #include "common/compat_strlcpy.h" +#include "aux-data.h" #ifdef ENABLE_OPENSSL #include @@ -597,6 +598,8 @@ void sc_pkcs15_free_prkey_info(sc_pkcs15_prkey_info_t *key) sc_pkcs15_free_key_params(&key->params); + sc_aux_data_free(&key->aux_data); + free(key); } diff --git a/src/libopensc/pkcs15.c b/src/libopensc/pkcs15.c index e3d197ce..c0c7bc31 100644 --- a/src/libopensc/pkcs15.c +++ b/src/libopensc/pkcs15.c @@ -88,7 +88,7 @@ static const struct sc_asn1_entry c_asn1_profile_indication[C_ASN1_PROFILE_INDIC #define C_ASN1_TOKI_ATTRS_SIZE 15 static const struct sc_asn1_entry c_asn1_toki_attrs[C_ASN1_TOKI_ATTRS_SIZE] = { - { "version", SC_ASN1_INTEGER, SC_ASN1_TAG_INTEGER, 0, NULL, NULL }, + { "version", SC_ASN1_INTEGER, SC_ASN1_TAG_INTEGER, 0, NULL, NULL }, { "serialNumber", SC_ASN1_OCTET_STRING, SC_ASN1_TAG_OCTET_STRING, SC_ASN1_OPTIONAL, NULL, NULL }, { "manufacturerID", SC_ASN1_UTF8STRING, SC_ASN1_TAG_UTF8STRING, SC_ASN1_OPTIONAL, NULL, NULL }, { "label", SC_ASN1_UTF8STRING, SC_ASN1_CTX | 0, SC_ASN1_OPTIONAL, NULL, NULL }, @@ -111,9 +111,11 @@ static const struct sc_asn1_entry c_asn1_tokeninfo[] = { { NULL, 0, 0, 0, NULL, NULL } }; -static void sc_pkcs15_free_unusedspace(struct sc_pkcs15_card *p15card); -static void sc_pkcs15_remove_dfs(struct sc_pkcs15_card *p15card); -static void sc_pkcs15_remove_objects(struct sc_pkcs15_card *p15card); +static void sc_pkcs15_free_unusedspace(struct sc_pkcs15_card *); +static void sc_pkcs15_remove_dfs(struct sc_pkcs15_card *); +static void sc_pkcs15_remove_objects(struct sc_pkcs15_card *); +static int sc_pkcs15_aux_get_md_guid(struct sc_pkcs15_card *, const struct sc_pkcs15_object *, + unsigned, unsigned char *, size_t *); int sc_pkcs15_parse_tokeninfo(sc_context_t *ctx, sc_pkcs15_tokeninfo_t *ti, const u8 *buf, size_t blen) @@ -132,7 +134,7 @@ int sc_pkcs15_parse_tokeninfo(sc_context_t *ctx, u8 preferred_language[3]; size_t lang_length = sizeof(preferred_language); struct sc_asn1_entry asn1_supported_algorithms[SC_MAX_SUPPORTED_ALGORITHMS + 1], - asn1_algo_infos[SC_MAX_SUPPORTED_ALGORITHMS][7]; + asn1_algo_infos[SC_MAX_SUPPORTED_ALGORITHMS][7]; size_t reference_len = sizeof(ti->supported_algos[0].reference); size_t mechanism_len = sizeof(ti->supported_algos[0].mechanism); size_t operations_len = sizeof(ti->supported_algos[0].operations); @@ -268,7 +270,7 @@ sc_pkcs15_encode_tokeninfo(sc_context_t *ctx, sc_pkcs15_tokeninfo_t *ti, struct sc_asn1_entry asn1_toki_attrs[C_ASN1_TOKI_ATTRS_SIZE]; struct sc_asn1_entry asn1_tokeninfo[2]; struct sc_asn1_entry asn1_supported_algorithms[SC_MAX_SUPPORTED_ALGORITHMS + 1], - asn1_algo_infos[SC_MAX_SUPPORTED_ALGORITHMS][7]; + asn1_algo_infos[SC_MAX_SUPPORTED_ALGORITHMS][7]; size_t reference_len = sizeof(ti->supported_algos[0].reference); size_t mechanism_len = sizeof(ti->supported_algos[0].mechanism); size_t operations_len = sizeof(ti->supported_algos[0].operations); @@ -408,7 +410,7 @@ fix_authentic_ddo(struct sc_pkcs15_card *p15card) sc_file_free(p15card->file_odf); p15card->file_odf = NULL; } - if (p15card->file_tokeninfo != NULL) { + if (p15card->file_tokeninfo != NULL) { sc_file_free(p15card->file_tokeninfo); p15card->file_tokeninfo = NULL; } @@ -1206,8 +1208,8 @@ sc_pkcs15_bind(struct sc_card *card, struct sc_aid *aid, p15card->opts.pin_cache_ignore_user_consent); } sc_log(ctx, "PKCS#15 options: use_file_cache=%d use_pin_cache=%d pin_cache_counter=%d pin_cache_ignore_user_consent=%d", - p15card->opts.use_file_cache, p15card->opts.use_pin_cache, - p15card->opts.pin_cache_counter, p15card->opts.pin_cache_ignore_user_consent); + p15card->opts.use_file_cache, p15card->opts.use_pin_cache,p15card->opts.pin_cache_counter, + p15card->opts.pin_cache_ignore_user_consent); r = sc_lock(card); if (r) { @@ -1564,9 +1566,8 @@ sc_pkcs15_search_objects(struct sc_pkcs15_card *p15card, struct sc_pkcs15_search int sc_pkcs15_get_objects_cond(struct sc_pkcs15_card *p15card, unsigned int type, - int (* func)(struct sc_pkcs15_object *, void *), - void *func_arg, - struct sc_pkcs15_object **ret, size_t ret_size) + int (* func)(struct sc_pkcs15_object *, void *), + void *func_arg, struct sc_pkcs15_object **ret, size_t ret_size) { return __sc_pkcs15_search_objects(p15card, 0, type, func, func_arg, ret, ret_size); @@ -1789,8 +1790,7 @@ sc_pkcs15_find_data_object_by_name(struct sc_pkcs15_card *p15card, const char *a int sc_pkcs15_find_prkey_by_id_usage(struct sc_pkcs15_card *p15card, const struct sc_pkcs15_id *id, - unsigned int usage, - struct sc_pkcs15_object **out) + unsigned int usage, struct sc_pkcs15_object **out) { struct sc_pkcs15_search_key sk; @@ -2704,7 +2704,7 @@ sc_pkcs15_serialize_guid(unsigned char *in, size_t in_size, unsigned flags, int sc_pkcs15_get_object_guid(struct sc_pkcs15_card *p15card, const struct sc_pkcs15_object *obj, - unsigned flags, unsigned char *out, size_t *out_size) + unsigned flags, unsigned char *out, size_t *out_size) { struct sc_context *ctx = p15card->card->ctx; struct sc_serial_number serialnr; @@ -2721,6 +2721,12 @@ sc_pkcs15_get_object_guid(struct sc_pkcs15_card *p15card, const struct sc_pkcs15 LOG_FUNC_RETURN(ctx, rv); } + rv = sc_pkcs15_aux_get_md_guid(p15card, obj, flags, out, out_size); + if (rv == SC_SUCCESS) + LOG_FUNC_RETURN(ctx, SC_SUCCESS); + else if (rv != SC_ERROR_NOT_SUPPORTED) + LOG_TEST_RET(ctx, rv, "Failed to get alternative object GUID"); + memset(out, 0, *out_size); rv = sc_pkcs15_get_object_id(obj, &id); @@ -2751,9 +2757,9 @@ sc_pkcs15_get_object_guid(struct sc_pkcs15_card *p15card, const struct sc_pkcs15 memcpy(guid_bin + id.len, serialnr.value, serialnr.len); guid_bin_size = id.len + serialnr.len; - /* + /* * If OpenSSL is available (SHA1), then rather use the hash of the data - * - this also protects against data being too short + * - this also protects against data being too short */ #ifdef ENABLE_OPENSSL SHA1(guid_bin, guid_bin_size, guid_bin); @@ -2775,6 +2781,31 @@ sc_pkcs15_get_object_guid(struct sc_pkcs15_card *p15card, const struct sc_pkcs15 } +static int +sc_pkcs15_aux_get_md_guid(struct sc_pkcs15_card *p15card, const struct sc_pkcs15_object *obj, + unsigned flags, + unsigned char *out, size_t *out_size) +{ + struct sc_context *ctx = p15card->card->ctx; + struct sc_pkcs15_prkey_info *prkey_info = NULL; + int rv; + + LOG_FUNC_CALLED(ctx); + if(!out || !out_size) + LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS); + + if ((obj->type & SC_PKCS15_TYPE_CLASS_MASK) != SC_PKCS15_TYPE_PRKEY) + LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_SUPPORTED); + + prkey_info = (struct sc_pkcs15_prkey_info *)obj->data; + if (!prkey_info->aux_data || prkey_info->aux_data->type != SC_AUX_DATA_TYPE_MD_CMAP_RECORD) + LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_SUPPORTED); + + rv = sc_aux_data_get_md_guid(ctx, prkey_info->aux_data, flags, out, out_size); + LOG_FUNC_RETURN(ctx, rv); +} + + void sc_pkcs15_free_key_params(struct sc_pkcs15_key_params *params) { diff --git a/src/libopensc/pkcs15.h b/src/libopensc/pkcs15.h index a25b4336..b8aa6598 100644 --- a/src/libopensc/pkcs15.h +++ b/src/libopensc/pkcs15.h @@ -26,6 +26,7 @@ extern "C" { #endif #include "libopensc/opensc.h" +#include "libopensc/aux-data.h" #define SC_PKCS15_CACHE_DIR ".eid" @@ -388,8 +389,8 @@ struct sc_pkcs15_prkey_info { struct sc_path path; - /* Used by minidriver and its on-card support */ - /*struct sc_md_cmap_record cmap_record;*/ + /* Non-pkcs15 data, like MD CMAP record */ + struct sc_auxiliary_data *aux_data; }; typedef struct sc_pkcs15_prkey_info sc_pkcs15_prkey_info_t;