diff --git a/src/libopensc/Makefile.am b/src/libopensc/Makefile.am index 64a65727..46556f40 100644 --- a/src/libopensc/Makefile.am +++ b/src/libopensc/Makefile.am @@ -23,7 +23,7 @@ bin_SCRIPTS = opensc-config lib_LTLIBRARIES = libopensc.la libopensc_la_SOURCES = sc.c ctx.c module.c asn1.c log.c base64.c \ errors.c sec.c card.c iso7816.c dir.c \ - pkcs15.c pkcs15-cert.c pkcs15-pin.c \ + pkcs15.c pkcs15-cert.c pkcs15-data.c pkcs15-pin.c \ pkcs15-prkey.c pkcs15-pubkey.c pkcs15-sec.c \ pkcs15-wrap.c pkcs15-algo.c \ pkcs15-cache.c $(PCSC_SRC) reader-ctapi.c \ diff --git a/src/libopensc/Makefile.mak b/src/libopensc/Makefile.mak index 9e16d343..037922f8 100644 --- a/src/libopensc/Makefile.mak +++ b/src/libopensc/Makefile.mak @@ -11,7 +11,7 @@ HEADERSDIR = $(TOPDIR)\src\include\opensc OBJECTS = sc.obj ctx.obj module.obj asn1.obj log.obj base64.obj \ errors.obj sec.obj card.obj iso7816.obj dir.obj \ - pkcs15.obj pkcs15-cert.obj pkcs15-pin.obj \ + pkcs15.obj pkcs15-cert.obj pkcs15-data.obj pkcs15-pin.obj \ pkcs15-prkey.obj pkcs15-pubkey.obj pkcs15-sec.obj \ pkcs15-wrap.obj pkcs15-algo.obj \ pkcs15-cache.obj reader-pcsc.obj \ diff --git a/src/libopensc/pkcs15-data.c b/src/libopensc/pkcs15-data.c new file mode 100644 index 00000000..c68f0066 --- /dev/null +++ b/src/libopensc/pkcs15-data.c @@ -0,0 +1,216 @@ +/* + * pkcs15-data.c: PKCS #15 data object functions + * + * Copyright (C) 2002 Danny De Cock + * + * This source file was inspired by pkcs15-cert.c. + * + * 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 + */ + +#include "internal.h" +#include "pkcs15.h" +#include "log.h" +#include "asn1.h" +#include +#include +#include +#include +#ifdef HAVE_UNISTD_H +#include +#endif +#include + +static const struct sc_asn1_entry c_asn1_data_object[] = { + { "dataObject", SC_ASN1_OCTET_STRING, ASN1_OCTET_STRING, 0 }, + { NULL } +}; + +int +asn1_decode_data_object(struct sc_context *ctx, u8 **dataobj, size_t *datalen, + const u8 *buf, size_t buflen, int depth) +{ + struct sc_asn1_entry asn1_data_obj[2]; + u8 *data; + int r; + int data_len; + + data=malloc(buflen+64); + if (data == NULL) { + return SC_ERROR_OUT_OF_MEMORY; + } + sc_copy_asn1_entry(c_asn1_data_object, asn1_data_obj); + sc_format_asn1_entry(asn1_data_obj + 0, data, &data_len, 0); + r = _sc_asn1_decode(ctx, asn1_data_obj, buf, buflen, NULL, NULL, 0, depth + 1); + *datalen=data_len; + if (r < 0) { + free(data); + return r; + } + *dataobj = malloc(*datalen); + memcpy(*dataobj, data, *datalen); + free(data); + return 0; +} + +int +asn1_encode_data_object(struct sc_context *ctx, u8 *dataobj,size_t datalen, + u8 **buf, size_t *buflen, int depth) +{ + int r; + struct sc_asn1_entry asn1_data_obj[2]; + + sc_copy_asn1_entry(c_asn1_data_object, asn1_data_obj); + sc_format_asn1_entry(asn1_data_obj + 0, dataobj, &datalen, 1); + r= _sc_asn1_encode(ctx, asn1_data_obj, buf, buflen, depth + 1); + return r; +} + +int sc_pkcs15_read_data_object(struct sc_pkcs15_card *p15card, + const struct sc_pkcs15_data_info *info, + struct sc_pkcs15_data **data_object_out) +{ + int r; + struct sc_pkcs15_data *data_object; + u8 *data = NULL; + size_t len; + + assert(p15card != NULL && info != NULL && data_object_out != NULL); + SC_FUNC_CALLED(p15card->card->ctx, 1); + + r = sc_pkcs15_read_file(p15card, &info->path, &data, &len, NULL); + if (r) + return r; + data_object = (struct sc_pkcs15_data *) malloc(sizeof(struct sc_pkcs15_data)); + if (data_object == NULL) { + free(data); + return SC_ERROR_OUT_OF_MEMORY; + } + memset(data_object, 0, sizeof(struct sc_pkcs15_data)); + if ((r=asn1_decode_data_object(p15card->card->ctx, &data_object->data, &data_object->data_len, data, len, 0)) < 0) { + return SC_ERROR_INVALID_ASN1_OBJECT; + } + *data_object_out = data_object; + return 0; +} + +static const struct sc_asn1_entry c_asn1_cred_ident[] = { + { "idType", SC_ASN1_INTEGER, ASN1_INTEGER, 0, NULL }, + { "idValue", SC_ASN1_OCTET_STRING, ASN1_OCTET_STRING, 0, NULL }, + { NULL } +}; +static const struct sc_asn1_entry c_asn1_com_data_attr[] = { + { "dataID", SC_ASN1_PKCS15_ID, ASN1_OCTET_STRING, 0, NULL }, + { NULL } +}; +static const struct sc_asn1_entry c_asn1_type_data_attr[] = { + { "dataType", SC_ASN1_STRUCT, ASN1_SEQUENCE | SC_ASN1_CONS, 0, NULL }, + { NULL } +}; +static const struct sc_asn1_entry c_asn1_data[] = { + { "data", SC_ASN1_PKCS15_OBJECT, ASN1_SEQUENCE | SC_ASN1_CONS, 0, NULL }, + { NULL } +}; +static const struct sc_asn1_entry c_asn1_x509_data_attr[] = { + { "dataValue", SC_ASN1_PATH, ASN1_SEQUENCE | SC_ASN1_CONS, 0, NULL }, + { NULL } +}; + +static const struct sc_asn1_entry c_asn1_datalen_object[] = { + { "dataLen", SC_ASN1_OCTET_STRING, ASN1_OCTET_STRING, 0 }, + { NULL } + }; + +int sc_pkcs15_decode_dodf_entry(struct sc_pkcs15_card *p15card, + struct sc_pkcs15_object *obj, + const u8 ** buf, size_t *buflen) +{ + struct sc_context *ctx = p15card->card->ctx; + struct sc_pkcs15_data_info info; + struct sc_asn1_entry asn1_cred_ident[3], asn1_com_data_attr[4], + asn1_x509_data_attr[2], asn1_type_data_attr[2], + asn1_data[2],asn1_datalen[2]; + struct sc_asn1_pkcs15_object data_obj = { obj, asn1_com_data_attr, NULL, + asn1_type_data_attr }; + u8 id_value[128]; + int id_type; + size_t id_value_len = sizeof(id_value); + int r; + sc_copy_asn1_entry(c_asn1_cred_ident, asn1_cred_ident); + sc_copy_asn1_entry(c_asn1_com_data_attr, asn1_com_data_attr); + sc_copy_asn1_entry(c_asn1_x509_data_attr, asn1_x509_data_attr); + sc_copy_asn1_entry(c_asn1_datalen_object , asn1_datalen); + sc_copy_asn1_entry(c_asn1_type_data_attr, asn1_type_data_attr); + sc_copy_asn1_entry(c_asn1_data, asn1_data); + + sc_format_asn1_entry(asn1_cred_ident + 0, &id_type, NULL, 0); + sc_format_asn1_entry(asn1_cred_ident + 1, &id_value, &id_value_len, 0); + sc_format_asn1_entry(asn1_com_data_attr + 0, &info.id, NULL, 0); + sc_format_asn1_entry(asn1_com_data_attr + 1, asn1_cred_ident, NULL, 0); + sc_format_asn1_entry(asn1_x509_data_attr + 0, &info.path, NULL, 0); + sc_format_asn1_entry(asn1_type_data_attr + 0, asn1_x509_data_attr, NULL, 0); + sc_format_asn1_entry(asn1_data + 0, &data_obj, NULL, 0); + + /* Fill in defaults */ + memset(&info, 0, sizeof(info)); + r = sc_asn1_decode(ctx, asn1_data, *buf, *buflen, buf, buflen); + if (r == SC_ERROR_ASN1_END_OF_CONTENTS) + return r; + + SC_TEST_RET(ctx, r, "ASN.1 decoding failed"); + obj->type = SC_PKCS15_TYPE_DATA_OBJECT; + obj->data = malloc(sizeof(info)); + if (obj->data == NULL) + SC_FUNC_RETURN(ctx, 0, SC_ERROR_OUT_OF_MEMORY); + memcpy(obj->data, &info, sizeof(info)); + + return 0; +} + +int sc_pkcs15_encode_dodf_entry(struct sc_context *ctx, + const struct sc_pkcs15_object *obj, + u8 **buf, size_t *bufsize) +{ + struct sc_asn1_entry asn1_cred_ident[3], asn1_com_data_attr[4], + asn1_x509_data_attr[2], asn1_type_data_attr[2], + asn1_data[2],asn1_datalen[2]; + struct sc_pkcs15_data_info *infop = + (struct sc_pkcs15_data_info *) obj->data; + struct sc_asn1_pkcs15_object data_obj = { (struct sc_pkcs15_object *) obj, + asn1_com_data_attr, NULL, + asn1_type_data_attr }; + int r; + sc_copy_asn1_entry(c_asn1_cred_ident, asn1_cred_ident); + sc_copy_asn1_entry(c_asn1_com_data_attr, asn1_com_data_attr); + sc_copy_asn1_entry(c_asn1_x509_data_attr, asn1_x509_data_attr); + sc_copy_asn1_entry(c_asn1_datalen_object, asn1_datalen); + sc_copy_asn1_entry(c_asn1_type_data_attr, asn1_type_data_attr); + sc_copy_asn1_entry(c_asn1_data, asn1_data); + sc_format_asn1_entry(asn1_com_data_attr + 0, (void *) &infop->id, NULL, 1); + sc_format_asn1_entry(asn1_x509_data_attr + 0, (void *) &infop->path, NULL, 1); + sc_format_asn1_entry(asn1_type_data_attr + 0, (void *) asn1_x509_data_attr, NULL, 1); + sc_format_asn1_entry(asn1_data + 0, (void *) &data_obj, NULL, 1); + + r = sc_asn1_encode(ctx, asn1_data, buf, bufsize); + return r; +} + +void sc_pkcs15_free_data_object(struct sc_pkcs15_data *data_object) +{ + assert(data_object != NULL); + + free(data_object->data); + free(data_object); +} diff --git a/src/libopensc/pkcs15.c b/src/libopensc/pkcs15.c index 08171ae4..19d747e2 100644 --- a/src/libopensc/pkcs15.c +++ b/src/libopensc/pkcs15.c @@ -587,6 +587,7 @@ int sc_pkcs15_get_objects_cond(struct sc_pkcs15_card *p15card, int type, const int prkey_df[] = { SC_PKCS15_PRKDF, -1 }; const int pubkey_df[] = { SC_PKCS15_PUKDF, SC_PKCS15_PUKDF_TRUSTED, -1 }; const int cert_df[] = { SC_PKCS15_CDF, SC_PKCS15_CDF_TRUSTED, SC_PKCS15_CDF_USEFUL, -1 }; + const int data_df[] = { SC_PKCS15_DODF, -1 }; const int auth_df[] = { SC_PKCS15_AODF, -1 }; const int *dfs; sc_pkcs15_object_t *obj; @@ -602,6 +603,9 @@ int sc_pkcs15_get_objects_cond(struct sc_pkcs15_card *p15card, int type, case SC_PKCS15_TYPE_CERT: dfs = cert_df; break; + case SC_PKCS15_TYPE_DATA_OBJECT: + dfs = data_df; + break; case SC_PKCS15_TYPE_AUTH: dfs = auth_df; break; @@ -664,6 +668,8 @@ static int compare_obj_id(struct sc_pkcs15_object *obj, void *arg) return sc_pkcs15_compare_id(&((struct sc_pkcs15_pubkey_info *) data)->id, id); case SC_PKCS15_TYPE_AUTH_PIN: return sc_pkcs15_compare_id(&((struct sc_pkcs15_pin_info *) data)->auth_id, id); + case SC_PKCS15_TYPE_DATA_OBJECT: + return sc_pkcs15_compare_id(&((struct sc_pkcs15_data_info *) data)->id, id); } return 0; } @@ -710,6 +716,13 @@ int sc_pkcs15_find_pin_by_auth_id(struct sc_pkcs15_card *p15card, return find_by_id(p15card, SC_PKCS15_TYPE_AUTH_PIN, id, out); } +int sc_pkcs15_find_data_object_by_id(struct sc_pkcs15_card *p15card, + const struct sc_pkcs15_id *id, + struct sc_pkcs15_object **out) +{ + return find_by_id(p15card, SC_PKCS15_TYPE_DATA_OBJECT, id, out); +} + static int compare_flags(struct sc_pkcs15_object *obj, void *arg) { struct sc_pkcs15_pin_info *pin; @@ -841,6 +854,9 @@ int sc_pkcs15_encode_df(struct sc_context *ctx, case SC_PKCS15_CDF_USEFUL: func = sc_pkcs15_encode_cdf_entry; break; + case SC_PKCS15_DODF: + func = sc_pkcs15_encode_dodf_entry; + break; case SC_PKCS15_AODF: func = sc_pkcs15_encode_aodf_entry; break; @@ -894,6 +910,9 @@ int sc_pkcs15_parse_df(struct sc_pkcs15_card *p15card, case SC_PKCS15_CDF_USEFUL: func = sc_pkcs15_decode_cdf_entry; break; + case SC_PKCS15_DODF: + func = sc_pkcs15_decode_dodf_entry; + break; case SC_PKCS15_AODF: func = sc_pkcs15_decode_aodf_entry; break; diff --git a/src/libopensc/pkcs15.h b/src/libopensc/pkcs15.h index c444c13d..c454f390 100644 --- a/src/libopensc/pkcs15.h +++ b/src/libopensc/pkcs15.h @@ -205,6 +205,19 @@ struct sc_pkcs15_cert_info { }; typedef struct sc_pkcs15_cert_info sc_pkcs15_cert_info_t; +struct sc_pkcs15_data { + u8 *data; /* DER encoded raw data object */ + size_t data_len; +}; +typedef struct sc_pkcs15_data sc_pkcs15_data_t; + +struct sc_pkcs15_data_info { + struct sc_pkcs15_id id; /* correlates to data object id */ + /* identifiers [2] SEQUENCE OF CredentialIdentifier{{KeyIdentifiers}} */ + struct sc_path path; +}; +typedef struct sc_pkcs15_data_info sc_pkcs15_data_info_t; + #define SC_PKCS15_PRKEY_USAGE_ENCRYPT 0x01 #define SC_PKCS15_PRKEY_USAGE_DECRYPT 0x02 #define SC_PKCS15_PRKEY_USAGE_SIGN 0x04 @@ -396,6 +409,14 @@ int sc_pkcs15_encode_prkey(struct sc_context *, void sc_pkcs15_erase_prkey(struct sc_pkcs15_prkey *prkey); void sc_pkcs15_free_prkey(struct sc_pkcs15_prkey *prkey); +int sc_pkcs15_read_data_object(struct sc_pkcs15_card *p15card, + const struct sc_pkcs15_data_info *info, + struct sc_pkcs15_data **data_object_out); +int sc_pkcs15_find_data_object_by_id(struct sc_pkcs15_card *p15card, + const struct sc_pkcs15_id *id, + struct sc_pkcs15_object **out); +void sc_pkcs15_free_data_object(struct sc_pkcs15_data *data_object); + int sc_pkcs15_read_certificate(struct sc_pkcs15_card *card, const struct sc_pkcs15_cert_info *info, struct sc_pkcs15_cert **cert); @@ -453,6 +474,9 @@ int sc_pkcs15_encode_prkdf_entry(struct sc_context *ctx, int sc_pkcs15_encode_pukdf_entry(struct sc_context *ctx, const struct sc_pkcs15_object *obj, u8 **buf, size_t *bufsize); +int sc_pkcs15_encode_dodf_entry(struct sc_context *ctx, + const struct sc_pkcs15_object *obj, u8 **buf, + size_t *bufsize); int sc_pkcs15_encode_aodf_entry(struct sc_context *ctx, const struct sc_pkcs15_object *obj, u8 **buf, size_t *bufsize); @@ -464,6 +488,9 @@ int sc_pkcs15_read_df(struct sc_pkcs15_card *p15card, int sc_pkcs15_decode_cdf_entry(struct sc_pkcs15_card *p15card, struct sc_pkcs15_object *obj, const u8 **buf, size_t *bufsize); +int sc_pkcs15_decode_dodf_entry(struct sc_pkcs15_card *p15card, + struct sc_pkcs15_object *obj, + const u8 **buf, size_t *bufsize); int sc_pkcs15_decode_aodf_entry(struct sc_pkcs15_card *p15card, struct sc_pkcs15_object *obj, const u8 **buf, size_t *bufsize); diff --git a/src/pkcs15init/gpk.profile b/src/pkcs15init/gpk.profile index d85deabd..90ec337c 100644 --- a/src/pkcs15init/gpk.profile +++ b/src/pkcs15init/gpk.profile @@ -62,6 +62,16 @@ filesystem { WRITE=$PIN; } + # data objects are stored in transparent EFs. + EF template-data { + file-id = 5000; + structure = transparent; + ACL = *=NEVER, + READ=NONE, + UPDATE=$PIN, + WRITE=$PIN; + } + EF template-public-key { file-id = 8000; structure = transparent; diff --git a/src/pkcs15init/pkcs15-init.h b/src/pkcs15init/pkcs15-init.h index 9639de22..cb42861d 100644 --- a/src/pkcs15init/pkcs15-init.h +++ b/src/pkcs15init/pkcs15-init.h @@ -138,6 +138,13 @@ struct sc_pkcs15init_pubkeyargs { sc_pkcs15_pubkey_t key; }; +struct sc_pkcs15init_dataargs { + struct sc_pkcs15_id id; + const char * label; + + sc_pkcs15_der_t der_encoded; +}; + struct sc_pkcs15init_certargs { struct sc_pkcs15_id id; const char * label; @@ -176,6 +183,10 @@ extern int sc_pkcs15init_store_certificate(struct sc_pkcs15_card *, struct sc_profile *, struct sc_pkcs15init_certargs *, struct sc_pkcs15_object **); +extern int sc_pkcs15init_store_data_object(struct sc_pkcs15_card *, + struct sc_profile *, + struct sc_pkcs15init_dataargs *, + struct sc_pkcs15_object **); extern int sc_pkcs15init_create_file(struct sc_profile *, struct sc_card *, struct sc_file *); diff --git a/src/pkcs15init/pkcs15-lib.c b/src/pkcs15init/pkcs15-lib.c index 1d235fe4..b4e704d5 100644 --- a/src/pkcs15init/pkcs15-lib.c +++ b/src/pkcs15init/pkcs15-lib.c @@ -58,6 +58,7 @@ #define DEFAULT_PRKEY_FLAGS 0x1d #define DEFAULT_PUBKEY_FLAGS 0x02 #define DEFAULT_CERT_FLAGS 0x02 +#define DEFAULT_DATA_FLAGS 0x03 /* Handle encoding of PKCS15 on the card */ typedef int (*pkcs15_encoder)(struct sc_context *, @@ -845,6 +846,10 @@ sc_pkcs15init_store_certificate(struct sc_pkcs15_card *p15card, if ((r = select_id(p15card, SC_PKCS15_TYPE_CERT, &args->id)) < 0) return r; + /* If there is a private key corresponding to the ID given + * by the user, make sure $PIN references the pin protecting + * this key + */ if (args->id.len != 0) { sc_pkcs15_object_t *objp; struct sc_pkcs15_pin_info *pin_info; @@ -894,6 +899,77 @@ sc_pkcs15init_store_certificate(struct sc_pkcs15_card *p15card, return r; } +/* + * Store a data object + */ +int +sc_pkcs15init_store_data_object(struct sc_pkcs15_card *p15card, + struct sc_profile *profile, + struct sc_pkcs15init_dataargs *args, + struct sc_pkcs15_object **res_obj) +{ + struct sc_pkcs15_data_info *data_object_info; + struct sc_pkcs15_object *object; + const char *label; + int r; + + if ((label = args->label) == NULL) + label = "Data Object"; + + /* Select an ID if the user didn't specify one, otherwise + * make sure it's unique */ + if ((r = select_id(p15card, SC_PKCS15_TYPE_DATA_OBJECT, &args->id)) < 0) + return r; + +#ifdef notused + if (args->id.len != 0) { + sc_pkcs15_object_t *objp; + struct sc_pkcs15_pin_info *pin_info; + + r = sc_pkcs15_find_prkey_by_id(p15card, + &args->id, &objp); + if (r == 0) { + r = sc_pkcs15_find_pin_by_auth_id(p15card, + &objp->auth_id, &objp); + } + if (r < 0) { + /* XXX: Fallback to the first PIN object */ + r = sc_pkcs15_get_objects(p15card, SC_PKCS15_TYPE_AUTH_PIN, + &objp, 1); + if (r != 1) + r = SC_ERROR_OBJECT_NOT_FOUND; + } + if (r >= 0) { + pin_info = (struct sc_pkcs15_pin_info *) objp->data; + sc_profile_set_pin_info(profile, + SC_PKCS15INIT_SO_PIN, pin_info); + } + } +#endif + + data_object_info = (struct sc_pkcs15_data_info *) calloc(1, sizeof(*data_object_info)); + data_object_info->id = args->id; + + object = (struct sc_pkcs15_object *) calloc(1, sizeof(*object)); + object->type = SC_PKCS15_TYPE_DATA_OBJECT; + object->data = data_object_info; + object->flags = DEFAULT_DATA_FLAGS; + strncpy(object->label, label, sizeof(object->label)); + r = sc_pkcs15init_store_data(p15card, profile, + SC_PKCS15_TYPE_DATA_OBJECT, &args->der_encoded, + &data_object_info->path); + + /* Now update the DDF */ + if (r >= 0) + r = sc_pkcs15init_add_object(p15card, profile, + SC_PKCS15_DODF, object); + + if (r >= 0 && res_obj) + *res_obj = object; + + return r; +} + static int sc_pkcs15init_store_data(struct sc_pkcs15_card *p15card, struct sc_profile *profile, @@ -907,7 +983,6 @@ sc_pkcs15init_store_data(struct sc_pkcs15_card *p15card, /* Get the number of objects of this type already on this card */ index = sc_pkcs15_get_objects(p15card, type & SC_PKCS15_TYPE_CLASS_MASK, NULL, 0); - /* Set the SO PIN reference from card */ if ((r = set_so_pin_from_card(p15card, profile)) < 0) return r; @@ -918,7 +993,6 @@ sc_pkcs15init_store_data(struct sc_pkcs15_card *p15card, p15init_error("Unable to allocate file"); goto done; } - r = sc_pkcs15init_update_file(profile, p15card->card, file, data->value, data->len); *path = file->path; @@ -1193,6 +1267,9 @@ select_id(struct sc_pkcs15_card *p15card, int type, struct sc_pkcs15_id *id) case SC_PKCS15_TYPE_CERT: func = sc_pkcs15_find_cert_by_id; break; + case SC_PKCS15_TYPE_DATA_OBJECT: + func = sc_pkcs15_find_data_object_by_id; + break; default: return SC_ERROR_INVALID_ARGUMENTS; } diff --git a/src/pkcs15init/pkcs15.profile b/src/pkcs15init/pkcs15.profile index af003160..b3c1bdb8 100644 --- a/src/pkcs15init/pkcs15.profile +++ b/src/pkcs15init/pkcs15.profile @@ -86,6 +86,13 @@ filesystem { size = 128; acl = *=$SOPIN, READ=NONE; } + + EF PKCS15-DODF { + file-id = 4405; + size = 128; + ACL = *=NONE; + } + } } } diff --git a/src/tests/p15dump.c b/src/tests/p15dump.c index f71dd588..524afdc9 100644 --- a/src/tests/p15dump.c +++ b/src/tests/p15dump.c @@ -75,6 +75,7 @@ int main(int argc, char *argv[]) dump_objects("Private keys", SC_PKCS15_TYPE_PRKEY); dump_objects("Public keys", SC_PKCS15_TYPE_PUBKEY); dump_objects("X.509 certificates", SC_PKCS15_TYPE_CERT_X509); + dump_objects("data objects", SC_PKCS15_TYPE_DATA_OBJECT); sc_pkcs15_unbind(p15card); sc_test_cleanup(); diff --git a/src/tests/print.c b/src/tests/print.c index 473c1626..bae8ee8e 100644 --- a/src/tests/print.c +++ b/src/tests/print.c @@ -161,6 +161,24 @@ static void print_cert_x509(const struct sc_pkcs15_object *obj) * and dump the label */ } +static void print_data_object_summary(const struct sc_pkcs15_object *obj) +{ + struct sc_pkcs15_data_info *data_object; + int i; + + data_object = (struct sc_pkcs15_data_info *) obj->data; + printf("\tPath : "); + for (i = 0; i < data_object->path.len; i++) + printf("%02X", data_object->path.value[i]); + printf("\n"); + printf("\tID : "); + sc_pkcs15_print_id(&data_object->id); + printf("\n"); + + /* XXX original p15dump code would read the data object + * and dump the label */ +} + void sc_test_print_object(const struct sc_pkcs15_object *obj) { const char *kind; @@ -191,6 +209,10 @@ void sc_test_print_object(const struct sc_pkcs15_object *obj) printer = print_cert_x509; kind = "X.509 Certificate"; break; + case SC_PKCS15_TYPE_DATA_OBJECT: + printer = print_data_object_summary; + kind = "Data Object"; + break; default: printer = NULL; kind = "Something"; diff --git a/src/tools/pkcs15-init.c b/src/tools/pkcs15-init.c index 77ca60a6..6307fef9 100644 --- a/src/tools/pkcs15-init.c +++ b/src/tools/pkcs15-init.c @@ -72,6 +72,11 @@ static int do_convert_private_key(struct sc_pkcs15_prkey *, EVP_PKEY *); static int do_convert_public_key(struct sc_pkcs15_pubkey *, EVP_PKEY *); static int do_convert_cert(sc_pkcs15_der_t *, X509 *); +static int do_read_data_object(const char *name, u8 **out, size_t *outlen); +static int do_convert_data_object(struct sc_context *ctx, sc_pkcs15_der_t *der, u8 *data,size_t datalen); +static int do_store_data_object(struct sc_profile *profile); +extern int asn1_encode_data_object(struct sc_context *ctx, u8 *dataobj,size_t datalen, + u8 **buf, size_t *buflen, int depth); static int init_keyargs(struct sc_pkcs15init_prkeyargs *); static int read_one_pin(struct sc_profile *, const char *, @@ -129,6 +134,7 @@ const struct option options[] = { { "format", required_argument, 0, 'f' }, { "passphrase", required_argument, 0, OPT_PASSPHRASE }, { "store-certificate", required_argument, 0, 'X' }, + { "store-data", required_argument, 0, 'W' }, { "authority", no_argument, 0, OPT_AUTHORITY }, { "key-usage", required_argument, 0, 'u' }, @@ -163,6 +169,7 @@ const char * option_help[] = { "Specify key file format (default PEM)", "Specify passphrase for unlocking secret key", "Store an X.509 certificate", + "Store a data object", "Mark certificate as a CA certificate", "Specify X.509 key usage (use \"--key-usage help\" for more information)", @@ -183,7 +190,8 @@ enum { ACTION_GENERATE_KEY, ACTION_STORE_PRIVKEY, ACTION_STORE_PUBKEY, - ACTION_STORE_CERT + ACTION_STORE_CERT, + ACTION_STORE_DATA }; static char * action_names[] = { "do nothing", @@ -192,7 +200,8 @@ static char * action_names[] = { "generate key", "store private key", "store public key", - "store certificate" + "store certificate", + "store data object" }; /* Flags for read_one_pin */ @@ -299,6 +308,8 @@ main(int argc, char **argv) r = do_store_public_key(profile, NULL); else if (opt_action == ACTION_STORE_CERT) r = do_store_certificate(profile); + else if (opt_action == ACTION_STORE_DATA) + r = do_store_data_object(profile); else if (opt_action == ACTION_GENERATE_KEY) r = do_generate_key(profile, opt_newkey); else @@ -574,6 +585,33 @@ do_store_certificate(struct sc_profile *profile) return r; } +/* + * Download data object to card + */ +static int +do_store_data_object(struct sc_profile *profile) +{ + struct sc_pkcs15init_dataargs args; + u8 *data; + size_t datalen; + int r=0; + + memset(&args, 0, sizeof(args)); + + if (opt_objectid) + sc_pkcs15_format_id(opt_objectid, &args.id); + args.label = opt_label; + + r = do_read_data_object(opt_infile, &data, &datalen); + if (r >= 0) + r = do_convert_data_object(p15card->card->ctx, &args.der_encoded, data, datalen); + if (r >= 0) + r = sc_pkcs15init_store_data_object(p15card, profile, + &args, NULL); + + return r; +} + /* * Generate a new private key */ @@ -1113,6 +1151,47 @@ do_read_certificate(const char *name, const char *format, X509 **out) return 0; } +static int determine_filesize(const char *filename) { + FILE *fp; + size_t size; + + if ((fp = fopen(filename,"r")) == NULL) { + fatal("Unable to open %s: %m", filename); + } + fseek(fp,0L,SEEK_END); + size = ftell(fp); + fclose(fp); + return size; + } + +static int +do_read_data_object(const char *name, u8 **out, size_t *outlen) +{ + FILE *inf; + size_t filesize = determine_filesize(name); + int c; + + *out = malloc(filesize); + if (*out == NULL) { + return SC_ERROR_OUT_OF_MEMORY; + } + + inf = fopen(name, "r"); + if (inf == NULL) { + fprintf(stderr, "Unable to open '%s' for reading.\n", name); + return -1; + } + c = fread(*out, 1, filesize, inf); + fclose(inf); + if (c < 0) { + perror("read"); + return -1; + } + + *outlen = filesize; + return 0; +} + static int do_convert_bignum(sc_pkcs15_bignum_t *dst, BIGNUM *src) { @@ -1201,6 +1280,13 @@ do_convert_public_key(struct sc_pkcs15_pubkey *key, EVP_PKEY *pk) return 0; } +int +do_convert_data_object(struct sc_context *ctx, sc_pkcs15_der_t *der, + u8 *data,size_t datalen) +{ + return asn1_encode_data_object(ctx, data, datalen, &der->value, &der->len, 0); +} + int do_convert_cert(sc_pkcs15_der_t *der, X509 *cert) { @@ -1316,6 +1402,10 @@ handle_option(int c) opt_action = ACTION_STORE_CERT; opt_infile = optarg; break; + case 'W': + opt_action = ACTION_STORE_DATA; + opt_infile = optarg; + break; case 'd': opt_debug++; break; diff --git a/src/tools/pkcs15-tool.c b/src/tools/pkcs15-tool.c index ff3844de..6e12425b 100644 --- a/src/tools/pkcs15-tool.c +++ b/src/tools/pkcs15-tool.c @@ -57,6 +57,8 @@ const struct option options[] = { { "learn-card", 0, 0, 'L' }, { "read-certificate", 1, 0, 'r' }, { "list-certificates", 0, 0, 'c' }, + { "read-data-object", 1, 0, 'R' }, + { "list-data-objects", 0, 0, 'C' }, { "list-pins", 0, 0, OPT_LIST_PINS }, { "change-pin", 0, 0, OPT_CHANGE_PIN }, { "list-keys", 0, 0, 'k' }, @@ -75,6 +77,8 @@ const char *option_help[] = { "Stores card info to cache", "Reads certificate with ID ", "Lists certificates", + "Reads data object with ID ", + "Lists data objects", "Lists PIN codes", "Changes the PIN code", "Lists private keys", @@ -160,6 +164,49 @@ print_pem_object(const char *kind, const u8*data, size_t data_len) return 0; } +int +list_data_object(const char *kind, const u8*data, size_t data_len) +{ + int i; + + printf("%s (%i bytes): <", kind, data_len); + for (i = 0; i < data_len; i++) + printf(" %02X", data[i]); + printf(" >\n"); + + return 0; +} + +int +print_data_object(const char *kind, const u8*data, size_t data_len) +{ + int i; + + if (opt_outfile != NULL) { + FILE *outf; + outf = fopen(opt_outfile, "w"); + if (outf == NULL) { + fprintf(stderr, "Error opening file '%s': %s\n", + opt_outfile, strerror(errno)); + return 2; + } + for (i=0; i < data_len; i++) + fprintf(outf, "%c", data[i]); + printf("Dumping (%i bytes) to file <%s>: <", data_len, opt_outfile); + for (i=0; i < data_len; i++) + printf(" %02X", data[i]); + printf(" >\n"); + fclose(outf); + } else { + printf("%s (%i bytes): <", kind, data_len); + for (i=0; i < data_len; i++) + printf(" %02X", data[i]); + printf(" >\n"); + } + printf(" >\n"); + return 0; +} + int read_certificate(void) { int r, i, count; @@ -197,6 +244,72 @@ int read_certificate(void) return 2; } +int read_data_object(void) +{ + int r, i, count; + struct sc_pkcs15_id id; + struct sc_pkcs15_object *objs[32]; + + id.len = SC_PKCS15_MAX_ID_SIZE; + sc_pkcs15_hex_string_to_id(opt_cert, &id); + + r = sc_pkcs15_get_objects(p15card, SC_PKCS15_TYPE_DATA_OBJECT, objs, 32); + if (r < 0) { + fprintf(stderr, "Data object enumeration failed: %s\n", sc_strerror(r)); + return 1; + } + count = r; + for (i = 0; i < count; i++) { + struct sc_pkcs15_data_info *cinfo = (struct sc_pkcs15_data_info *) objs[i]->data; + struct sc_pkcs15_data *data_object; + + if (sc_pkcs15_compare_id(&id, &cinfo->id) != 1) + continue; + + if (!quiet) + printf("Reading data object with ID '%s'\n", opt_cert); + r = sc_pkcs15_read_data_object(p15card, cinfo, &data_object); + if (r) { + fprintf(stderr, "Data object read failed: %s\n", sc_strerror(r)); + return 1; + } + r = print_data_object("Data Object", data_object->data, data_object->data_len); + sc_pkcs15_free_data_object(data_object); + return r; + } + fprintf(stderr, "Data object with ID '%s' not found.\n", opt_cert); + return 2; +} + +int list_data_objects(void) +{ + int r, i, count; + struct sc_pkcs15_id id; + struct sc_pkcs15_object *objs[32]; + id.len = SC_PKCS15_MAX_ID_SIZE; + + r = sc_pkcs15_get_objects(p15card, SC_PKCS15_TYPE_DATA_OBJECT, objs, 32); + if (r < 0) { + fprintf(stderr, "Data object enumeration failed: %s\n", sc_strerror(r)); + return 1; + } + count = r; + for (i = 0; i < count; i++) { + struct sc_pkcs15_data_info *cinfo = (struct sc_pkcs15_data_info *) objs[i]->data; + struct sc_pkcs15_data *data_object; + + printf("Reading data object <%i> ---------------------------\n", i); + r = sc_pkcs15_read_data_object(p15card, cinfo, &data_object); + if (r) { + fprintf(stderr, "Data object read failed: %s\n", sc_strerror(r)); + return 1; + } + r = list_data_object("Data Object", data_object->data, data_object->data_len); + sc_pkcs15_free_data_object(data_object); + } + return 0; +} + void print_prkey_info(const struct sc_pkcs15_object *obj) { unsigned int i; @@ -641,6 +754,8 @@ int main(int argc, char * const argv[]) int err = 0, r, c, long_optind = 0; int do_read_cert = 0; int do_list_certs = 0; + int do_read_data_object = 0; + int do_list_data_objects = 0; int do_list_pins = 0; int do_list_prkeys = 0; int do_list_pubkeys = 0; @@ -650,7 +765,7 @@ int main(int argc, char * const argv[]) int action_count = 0; while (1) { - c = getopt_long(argc, argv, "r:cko:qdp:L", options, &long_optind); + c = getopt_long(argc, argv, "r:cko:qdp:LR:C", options, &long_optind); if (c == -1) break; if (c == '?') @@ -665,6 +780,15 @@ int main(int argc, char * const argv[]) do_list_certs = 1; action_count++; break; + case 'R': + opt_cert = optarg; + do_read_data_object = 1; + action_count++; + break; + case 'C': + do_list_data_objects = 1; + action_count++; + break; case OPT_CHANGE_PIN: do_change_pin = 1; action_count++; @@ -776,6 +900,16 @@ int main(int argc, char * const argv[]) goto end; action_count--; } + if (do_list_data_objects) { + if ((err = list_data_objects())) + goto end; + action_count--; + } + if (do_read_data_object) { + if ((err = read_data_object())) + goto end; + action_count--; + } if (do_list_prkeys) { if ((err = list_private_keys())) goto end;