From 594e125f06e1bf7c818d1690de25dfb51d8a351c Mon Sep 17 00:00:00 2001 From: Frank Morgner Date: Fri, 15 Sep 2017 11:47:10 +0200 Subject: [PATCH] Added PKCS#15 emulator for DIN 66291 profile --- src/libopensc/Makefile.am | 2 +- src/libopensc/Makefile.mak | 2 +- src/libopensc/pkcs15-din-66291.c | 277 +++++++++++++++++++++++++++++++ src/libopensc/pkcs15-syn.c | 1 + src/libopensc/pkcs15-syn.h | 1 + src/libopensc/pkcs15.c | 62 ++++--- src/libopensc/pkcs15.h | 2 + 7 files changed, 320 insertions(+), 27 deletions(-) create mode 100644 src/libopensc/pkcs15-din-66291.c diff --git a/src/libopensc/Makefile.am b/src/libopensc/Makefile.am index 0f92feea..a71256b0 100644 --- a/src/libopensc/Makefile.am +++ b/src/libopensc/Makefile.am @@ -52,7 +52,7 @@ libopensc_la_SOURCES_BASE = \ pkcs15-actalis.c pkcs15-atrust-acos.c pkcs15-tccardos.c pkcs15-piv.c \ pkcs15-cac.c pkcs15-esinit.c pkcs15-westcos.c pkcs15-pteid.c \ pkcs15-oberthur.c pkcs15-itacns.c pkcs15-gemsafeV1.c pkcs15-sc-hsm.c \ - pkcs15-coolkey.c \ + pkcs15-coolkey.c pkcs15-din-66291.c \ pkcs15-dnie.c pkcs15-gids.c pkcs15-iasecc.c pkcs15-jpki.c \ compression.c p15card-helper.c sm.c \ aux-data.c diff --git a/src/libopensc/Makefile.mak b/src/libopensc/Makefile.mak index bfee45f8..ac1564d3 100644 --- a/src/libopensc/Makefile.mak +++ b/src/libopensc/Makefile.mak @@ -32,7 +32,7 @@ OBJECTS = \ pkcs15-openpgp.obj pkcs15-infocamere.obj pkcs15-starcert.obj \ pkcs15-tcos.obj pkcs15-esteid.obj pkcs15-postecert.obj pkcs15-gemsafeGPK.obj \ pkcs15-actalis.obj pkcs15-atrust-acos.obj pkcs15-tccardos.obj pkcs15-piv.obj \ - pkcs15-cac.obj pkcs15-esinit.obj pkcs15-westcos.obj pkcs15-pteid.obj \ + pkcs15-cac.obj pkcs15-esinit.obj pkcs15-westcos.obj pkcs15-pteid.obj pkcs15-din-66291.obj \ pkcs15-oberthur.obj pkcs15-itacns.obj pkcs15-gemsafeV1.obj pkcs15-sc-hsm.obj \ pkcs15-dnie.obj pkcs15-gids.obj pkcs15-iasecc.obj pkcs15-jpki.obj \ compression.obj p15card-helper.obj sm.obj \ diff --git a/src/libopensc/pkcs15-din-66291.c b/src/libopensc/pkcs15-din-66291.c new file mode 100644 index 00000000..31894d5d --- /dev/null +++ b/src/libopensc/pkcs15-din-66291.c @@ -0,0 +1,277 @@ +/* + * PKCS15 emulation layer for DIN 66291–4 profile. + * + * Copyright (C) 2017, Frank Morgner + * + * 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 + */ + + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "common/compat_strlcpy.h" +#include "log.h" +#include "pkcs15.h" +#include +#include + +static const unsigned char aid_CIA[] = {0xE8, 0x28, 0xBD, 0x08, 0x0F, + 0xA0, 0x00, 0x00, 0x01, 0x67, 0x45, 0x53, 0x49, 0x47, 0x4E}; +static const unsigned char aid_ESIGN[] = {0xA0, 0x00, 0x00, 0x01, 0x67, + 0x45, 0x53, 0x49, 0x47, 0x4E}; + +int din_66291_match_p15card(sc_pkcs15_card_t *p15card, struct sc_aid *aid) +{ + int ok = 0, r; + sc_path_t path; + unsigned char *tokeninfo_content = NULL; + struct sc_file *file_tokeninfo = NULL; + struct sc_pkcs15_tokeninfo *tokeninfo = sc_pkcs15_tokeninfo_new(); + + if (!p15card || !tokeninfo + || (aid && (aid->len != sizeof aid_CIA + || 0 != memcmp(aid->value, aid_CIA, sizeof aid_CIA)))) + goto err; + + if (p15card->tokeninfo + && p15card->tokeninfo->profile_indication.name + && 0 == strcmp("DIN V 66291", + p15card->tokeninfo->profile_indication.name)) { + ok = 1; + goto err; + } + + /* it is possible that p15card->tokeninfo has not been touched yet */ + sc_path_set(&path, SC_PATH_TYPE_DF_NAME, aid_CIA, sizeof aid_CIA, 0, 0); + if (SC_SUCCESS != sc_select_file(p15card->card, &path, NULL)) + goto err; + + sc_format_path("5032", &path); + if (SC_SUCCESS != sc_select_file(p15card->card, &path, &file_tokeninfo)) + goto err; + + tokeninfo_content = malloc(file_tokeninfo->size); + if (!tokeninfo_content) + goto err; + r = sc_read_binary(p15card->card, 0, tokeninfo_content, file_tokeninfo->size, 0); + if (r < 0) + goto err; + r = sc_pkcs15_parse_tokeninfo(p15card->card->ctx, tokeninfo, tokeninfo_content, r); + if (r != SC_SUCCESS) + goto err; + + if (tokeninfo->profile_indication.name + && 0 == strcmp("DIN V 66291", + tokeninfo->profile_indication.name)) { + ok = 1; + /* save tokeninfo and file_tokeninfo */ + sc_pkcs15_free_tokeninfo(p15card->tokeninfo); + sc_file_free(p15card->file_tokeninfo); + p15card->tokeninfo = tokeninfo; + p15card->file_tokeninfo = file_tokeninfo; + tokeninfo = NULL; + file_tokeninfo = NULL; + } + +err: + sc_pkcs15_free_tokeninfo(tokeninfo); + sc_file_free(file_tokeninfo); + free(tokeninfo_content); + + return ok; +} + + static int +sc_pkcs15emu_din_66291_init(sc_pkcs15_card_t *p15card) +{ + /* EF.C.CH.AUT + * fileIdentifier ´C5 00´ + * shortFileIdentifier ´01´= 1 + * PrK.CH.AUT + * keyIdentifier ´02´ = 2 + * privateKey …, Moduluslänge 2048 Bit + * + * EF.C.CH.ENC + * fileIdentifier ´C2 00´ + * shortFileIdentifier ´02´= 2 + * PrK.CH.ENC + * keyIdentifier ´03´ = 3 + * privateKey …, Moduluslänge 2048 Bit + */ + sc_path_t path; + size_t i; + struct sc_pin_cmd_data data; + const unsigned char user_pin_ref = 0x02; + sc_serial_number_t serial; + + sc_path_set(&path, SC_PATH_TYPE_DF_NAME, aid_ESIGN, sizeof aid_ESIGN, 0, 0); + if (SC_SUCCESS != sc_select_file(p15card->card, &path, NULL)) + return SC_ERROR_WRONG_CARD; + + memset(&data, 0, sizeof(data)); + data.cmd = SC_PIN_CMD_GET_INFO; + data.pin_type = SC_AC_CHV; + data.pin_reference = user_pin_ref; + + if (SC_SUCCESS == sc_pin_cmd(p15card->card, &data, NULL)) { + const unsigned char user_pin_id = 1; + + for (i = 0; i < 2; i++) { + const char *pin_names[3] = { "PIN", "PUK" }; + const int pin_min[] = {6, 10}; + const int pin_max[] = {8, 8}; + const unsigned char user_puk_id = 2; + const int pin_id[] = {user_pin_id, user_puk_id}; + const int pin_flags[] = {SC_PKCS15_PIN_FLAG_INITIALIZED, + SC_PKCS15_PIN_FLAG_UNBLOCKING_PIN|SC_PKCS15_PIN_FLAG_UNBLOCK_DISABLED}; + const int max_tries[] = {3, 10}; + struct sc_pkcs15_auth_info pin_info; + struct sc_pkcs15_object pin_obj; + + memset(&pin_info, 0, sizeof(pin_info)); + memset(&pin_obj, 0, sizeof(pin_obj)); + + pin_info.auth_id.value[0] = pin_id[i]; + pin_info.auth_id.len = 1; + pin_info.auth_type = SC_PKCS15_PIN_AUTH_TYPE_PIN; + pin_info.attrs.pin.flags = pin_flags[i]; + pin_info.attrs.pin.type = SC_PKCS15_PIN_TYPE_ASCII_NUMERIC; + pin_info.attrs.pin.min_length = pin_min[i]; + pin_info.attrs.pin.stored_length = pin_max[i]; + pin_info.attrs.pin.max_length = pin_max[i]; + pin_info.max_tries = max_tries[i]; + + strlcpy(pin_obj.label, pin_names[i], sizeof(pin_obj.label)); + + /* catch the differences between PIN and PUK */ + if (pin_flags[i] & SC_PKCS15_PIN_FLAG_UNBLOCKING_PIN) { + pin_info.tries_left = max_tries[i]; + } else { + pin_info.attrs.pin.reference = user_pin_ref; + pin_info.tries_left = data.pin1.tries_left; + pin_info.logged_in = data.pin1.logged_in; + pin_obj.auth_id.value[0] = user_puk_id; + pin_obj.auth_id.len = 1; + } + + if (0 > sc_pkcs15emu_add_pin_obj(p15card, &pin_obj, &pin_info)) + return SC_ERROR_INTERNAL; + } + + for (i = 0; i < 2; i++) { + struct sc_aid aid; + const char *din_66291_cert_fids[] = { "C500", "C200"}; + const char prk_id[] = { 0x10, 0x11,}; + struct sc_pkcs15_cert_info cert_info; + struct sc_pkcs15_object cert_obj; + struct sc_pkcs15_prkey_info prkey_info; + struct sc_pkcs15_object prkey_obj; + const int prk_usage[2] = { + SC_PKCS15_PRKEY_USAGE_ENCRYPT + | SC_PKCS15_PRKEY_USAGE_DECRYPT + | SC_PKCS15_PRKEY_USAGE_SIGN, + SC_PKCS15_PRKEY_USAGE_NONREPUDIATION}; + + memcpy(aid.value, aid_CIA, sizeof aid_CIA); + aid.len = sizeof aid_CIA; + + memset(&prkey_info, 0, sizeof(prkey_info)); + memset(&prkey_obj, 0, sizeof(prkey_obj)); + memset(&cert_info, 0, sizeof(cert_info)); + memset(&cert_obj, 0, sizeof(cert_obj)); + + + sc_format_path(din_66291_cert_fids[i], &cert_info.path); + if (SC_SUCCESS != sc_select_file(p15card->card, &cert_info.path, NULL)) + continue; + cert_info.path.aid = aid; + + cert_info.id.value[0] = prk_id[i]; + cert_info.id.len = 1; + + if (0 > sc_pkcs15emu_add_x509_cert(p15card, &cert_obj, &cert_info)) + continue; + + if (i == 0) { + sc_pkcs15_cert_t *cert; + if (SC_SUCCESS == sc_pkcs15_read_certificate(p15card, &cert_info, &cert)) { + static const struct sc_object_id cn_oid = {{ 2, 5, 4, 3, -1 }}; + u8 *cn_name = NULL; + size_t cn_len = 0; + sc_pkcs15_get_name_from_dn(p15card->card->ctx, cert->subject, + cert->subject_len, &cn_oid, &cn_name, &cn_len); + if (cn_len > 0) { + char *token_name = malloc(cn_len+1); + if (token_name) { + memcpy(token_name, cn_name, cn_len); + token_name[cn_len] = '\0'; + free(p15card->tokeninfo->label); + p15card->tokeninfo->label = token_name; + } + } + free(cn_name); + sc_pkcs15_free_certificate(cert); + } + } + + memset(&prkey_info, 0, sizeof(prkey_info)); + memset(&prkey_obj, 0, sizeof(prkey_obj)); + + prkey_info.id.value[0] = prk_id[i]; + prkey_info.id.len = 1; + prkey_info.usage = prk_usage[i]; + prkey_info.native = 1; + prkey_info.key_reference = prk_id[i]; + prkey_info.modulus_length = 2048; + prkey_obj.auth_id.value[0] = user_pin_id; + prkey_obj.auth_id.len = 1; + prkey_obj.user_consent = 0; + prkey_obj.flags = SC_PKCS15_CO_FLAG_PRIVATE; + + if (0 > sc_pkcs15emu_add_rsa_prkey(p15card, &prkey_obj, &prkey_info)) + continue; + } + } + + /* get the card serial number */ + if (!p15card->tokeninfo->serial_number + && SC_SUCCESS == sc_card_ctl(p15card->card, SC_CARDCTL_GET_SERIALNR, &serial)) { + char serial_hex[SC_MAX_SERIALNR*2+2]; + sc_bin_to_hex(serial.value, serial.len , serial_hex, sizeof serial_hex - 1, 0); + p15card->tokeninfo->serial_number = strdup(serial_hex); + } + + return SC_SUCCESS; +} + +int sc_pkcs15emu_din_66291_init_ex(sc_pkcs15_card_t *p15card, struct sc_aid *aid, + sc_pkcs15emu_opt_t *opts) +{ + if (!p15card || ! p15card->card) + return SC_ERROR_INVALID_ARGUMENTS; + + SC_FUNC_CALLED(p15card->card->ctx, 1); + + /* Check card */ + if (!(opts && opts->flags & SC_PKCS15EMU_FLAGS_NO_CHECK)) { + if (!din_66291_match_p15card(p15card, aid)) + return SC_ERROR_WRONG_CARD; + } + + /* Init card */ + return sc_pkcs15emu_din_66291_init(p15card); +} diff --git a/src/libopensc/pkcs15-syn.c b/src/libopensc/pkcs15-syn.c index d72fc313..4f2932e4 100644 --- a/src/libopensc/pkcs15-syn.c +++ b/src/libopensc/pkcs15-syn.c @@ -59,6 +59,7 @@ struct sc_pkcs15_emulator_handler builtin_emulators[] = { { "iasecc", sc_pkcs15emu_iasecc_init_ex }, { "jpki", sc_pkcs15emu_jpki_init_ex }, { "coolkey", sc_pkcs15emu_coolkey_init_ex }, + { "din66291", sc_pkcs15emu_din_66291_init_ex }, { NULL, NULL } }; diff --git a/src/libopensc/pkcs15-syn.h b/src/libopensc/pkcs15-syn.h index 22db061b..202711d0 100644 --- a/src/libopensc/pkcs15-syn.h +++ b/src/libopensc/pkcs15-syn.h @@ -53,6 +53,7 @@ int sc_pkcs15emu_gids_init_ex(sc_pkcs15_card_t *, struct sc_aid *, sc_pkcs15emu_ int sc_pkcs15emu_iasecc_init_ex(sc_pkcs15_card_t *, struct sc_aid *, sc_pkcs15emu_opt_t *); int sc_pkcs15emu_jpki_init_ex(sc_pkcs15_card_t *, struct sc_aid *, sc_pkcs15emu_opt_t *); int sc_pkcs15emu_coolkey_init_ex(sc_pkcs15_card_t *p15card, struct sc_aid *, sc_pkcs15emu_opt_t *opts); +int sc_pkcs15emu_din_66291_init_ex(sc_pkcs15_card_t *p15card, struct sc_aid *, sc_pkcs15emu_opt_t *opts); struct sc_pkcs15_emulator_handler { const char *name; diff --git a/src/libopensc/pkcs15.c b/src/libopensc/pkcs15.c index ba99c8af..d136021b 100644 --- a/src/libopensc/pkcs15.c +++ b/src/libopensc/pkcs15.c @@ -738,40 +738,52 @@ sc_pkcs15_card_new(void) return NULL; } - sc_init_oid(&p15card->tokeninfo->profile_indication.oid); - p15card->magic = SC_PKCS15_CARD_MAGIC; return p15card; } -void -sc_pkcs15_free_tokeninfo(struct sc_pkcs15_card *p15card) +struct sc_pkcs15_tokeninfo * +sc_pkcs15_tokeninfo_new(void) { - if (!p15card || !p15card->tokeninfo) + struct sc_pkcs15_tokeninfo *tokeninfo; + + tokeninfo = calloc(1, sizeof(struct sc_pkcs15_tokeninfo)); + if (tokeninfo == NULL) { + return NULL; + } + + sc_init_oid(&tokeninfo->profile_indication.oid); + + return tokeninfo; +} + + +void +sc_pkcs15_free_tokeninfo(struct sc_pkcs15_tokeninfo *tokeninfo) +{ + if (!tokeninfo) return; - if (p15card->tokeninfo->label != NULL) - free(p15card->tokeninfo->label); - if (p15card->tokeninfo->serial_number != NULL) - free(p15card->tokeninfo->serial_number); - if (p15card->tokeninfo->manufacturer_id != NULL) - free(p15card->tokeninfo->manufacturer_id); - if (p15card->tokeninfo->last_update.gtime != NULL) - free(p15card->tokeninfo->last_update.gtime); - if (p15card->tokeninfo->preferred_language != NULL) - free(p15card->tokeninfo->preferred_language); - if (p15card->tokeninfo->profile_indication.name != NULL) - free(p15card->tokeninfo->profile_indication.name); - if (p15card->tokeninfo->seInfo != NULL) { + if (tokeninfo->label != NULL) + free(tokeninfo->label); + if (tokeninfo->serial_number != NULL) + free(tokeninfo->serial_number); + if (tokeninfo->manufacturer_id != NULL) + free(tokeninfo->manufacturer_id); + if (tokeninfo->last_update.gtime != NULL) + free(tokeninfo->last_update.gtime); + if (tokeninfo->preferred_language != NULL) + free(tokeninfo->preferred_language); + if (tokeninfo->profile_indication.name != NULL) + free(tokeninfo->profile_indication.name); + if (tokeninfo->seInfo != NULL) { unsigned i; - for (i = 0; i < p15card->tokeninfo->num_seInfo; i++) - free(p15card->tokeninfo->seInfo[i]); - free(p15card->tokeninfo->seInfo); + for (i = 0; i < tokeninfo->num_seInfo; i++) + free(tokeninfo->seInfo[i]); + free(tokeninfo->seInfo); } - free(p15card->tokeninfo); - - p15card->tokeninfo = NULL; + free(tokeninfo); } @@ -815,7 +827,7 @@ sc_pkcs15_card_free(struct sc_pkcs15_card *p15card) sc_file_free(p15card->file_unusedspace); p15card->magic = 0; - sc_pkcs15_free_tokeninfo(p15card); + sc_pkcs15_free_tokeninfo(p15card->tokeninfo); sc_pkcs15_free_app(p15card); free(p15card); } diff --git a/src/libopensc/pkcs15.h b/src/libopensc/pkcs15.h index b6a2dd34..6ba61c21 100644 --- a/src/libopensc/pkcs15.h +++ b/src/libopensc/pkcs15.h @@ -647,6 +647,8 @@ int sc_pkcs15_find_object_by_id(struct sc_pkcs15_card *, unsigned int, struct sc_pkcs15_card * sc_pkcs15_card_new(void); void sc_pkcs15_card_free(struct sc_pkcs15_card *p15card); void sc_pkcs15_card_clear(struct sc_pkcs15_card *p15card); +struct sc_pkcs15_tokeninfo * sc_pkcs15_tokeninfo_new(void); +void sc_pkcs15_free_tokeninfo(struct sc_pkcs15_tokeninfo *tokeninfo); int sc_pkcs15_decipher(struct sc_pkcs15_card *p15card, const struct sc_pkcs15_object *prkey_obj,