/* * PKCS15 emulation layer for 1202 and 1203 Infocamere card. * To see how this works, run p15dump on your Infocamere card. * * Copyright (C) 2004, Antonino Iacono * Copyright (C) 2003, Olaf Kirch * * 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 #include #include static int (*set_security_env)(sc_card_t *, const struct sc_security_env *, int); static int (*compute_signature)(sc_card_t *, const u8 *, size_t, u8 *, size_t); static int set_sec_env(sc_card_t *card, const struct sc_security_env *env, int se_num) { struct sc_security_env tenv = *env; if (tenv.operation == SC_SEC_OPERATION_SIGN) tenv.operation = SC_SEC_OPERATION_DECIPHER; return set_security_env(card, &tenv, se_num); } static int do_sign(sc_card_t *card, const u8 *in, size_t inlen, u8 *out, size_t outlen) { return card->ops->decipher(card, in, inlen, out, outlen); } static void set_string(char **strp, const char *value) { if (*strp) free(strp); *strp = value? strdup(value) : NULL; } int sc_pkcs15emu_infocamere_init(sc_pkcs15_card_t *p15card) { const int prkey_usage = SC_PKCS15_PRKEY_USAGE_NONREPUDIATION; const int authprkey_usage = SC_PKCS15_PRKEY_USAGE_SIGN | SC_PKCS15_PRKEY_USAGE_SIGNRECOVER | SC_PKCS15_PRKEY_USAGE_ENCRYPT | SC_PKCS15_PRKEY_USAGE_DECRYPT; sc_card_t *card = p15card->card; sc_path_t path; struct sc_file *file; sc_pkcs15_id_t id, auth_id; unsigned char buffer[256]; unsigned char ef_gdo[256]; char serial[256]; unsigned char certlen[2]; int authority, change_sign = 0; const char *label = "User Non-repudiation Certificate"; const char *calabel = "CA Certificate"; const char *authlabel = "User Authentication Certificate"; const char *infocamere_cert_path [2] = { "DF01C000", "3F00000011111A02" }; const char *infocamere_auth_certpath [2] = { "11111A02", "000011111B02" }; const char *infocamere_cacert_path [2] = { "DF01C008", "000011114101" }; const char *infocamere_auth_path [2] = { "3F001111", "3F0000001111" }; const char *infocamere_nrepud_path [2] = { "3F00DF01", "3F0000001111" }; const int infocamere_idpin_auth_obj [2] = { 0x95, 0x81 }; const int infocamere_idpin_nrepud_obj [2] = { 0x99, 0x81 }; const int infocamere_idprkey_auth_obj [2] = { 0x9B, 0x01 }; const int infocamere_idprkey_nrepud_obj [2] = { 0x84, 0x01 }; const char *authPIN = "Authentication PIN"; const char *nonrepPIN = "Non-repudiation PIN"; const char *authPRKEY = "Authentication Key"; const char *nonrepPRKEY = "Non repudiation Key"; const int flags = SC_PKCS15_PIN_FLAG_CASE_SENSITIVE | SC_PKCS15_PIN_FLAG_INITIALIZED | SC_PKCS15_PIN_FLAG_NEEDS_PADDING; int r, len_iccsn, len_chn; sc_format_path("3F002F02", &path); r = sc_select_file(card, &path, &file); if (r < 0 || file->size > 255) { /* Not EF.GDO */ r = SC_ERROR_WRONG_CARD; goto failed; } sc_read_binary(card, 0, ef_gdo, file->size, 0); if (ef_gdo[0]!=0x5A || file->size < 3) { /* Not EF.GDO */ r = SC_ERROR_WRONG_CARD; goto failed; } len_iccsn = ef_gdo[1]; memcpy(buffer,ef_gdo+2,len_iccsn); sc_bin_to_hex(buffer, len_iccsn , serial, sizeof(serial), 0); if (file->size < (size_t)(len_iccsn + 5)) { /* Not CHN */ r = SC_ERROR_WRONG_CARD; goto failed; } if (!(ef_gdo[len_iccsn+2]==0x5F && ef_gdo[len_iccsn+3]==0x20)) { /* Not CHN */ r = SC_ERROR_WRONG_CARD; goto failed; } len_chn = ef_gdo[len_iccsn+4]; if (len_chn < 2 || len_chn > 8) { /* Length CHN incorrect */ r = SC_ERROR_WRONG_CARD; goto failed; } if (!(ef_gdo[len_iccsn+5]==0x12 && (ef_gdo[len_iccsn+6]==0x02 || ef_gdo[len_iccsn+6]==0x03))) { /* Not Infocamere Card*/ r = SC_ERROR_WRONG_CARD; goto failed; } set_string(&p15card->serial_number, serial); if (ef_gdo[len_iccsn+6]==0x02) set_string(&p15card->label, "Infocamere 1202 Card"); else { set_string(&p15card->label, "Infocamere 1203 Card"); change_sign = 1; } set_string(&p15card->manufacturer_id, "Infocamere"); authority = 0; /* Get the authentication certificate length */ sc_format_path(infocamere_auth_certpath[ef_gdo[len_iccsn+6]-2], &path); if (sc_select_file(card, &path, NULL) >= 0) { sc_read_binary(card, 0, certlen, 2, 0); /* Now set the certificate offset/len */ path.index = 2; path.count = (certlen[1] << 8) + certlen[0]; id.value[0] = 1; id.len = 1; sc_pkcs15emu_add_cert(p15card, SC_PKCS15_TYPE_CERT_X509, authority, &path, &id, authlabel, SC_PKCS15_CO_FLAG_MODIFIABLE); /* add authentication PIN */ sc_format_path(infocamere_auth_path[ef_gdo[len_iccsn+6]-2], &path); sc_pkcs15emu_add_pin(p15card, &id, authPIN, &path, infocamere_idpin_auth_obj[ef_gdo[len_iccsn+6]-2], SC_PKCS15_PIN_TYPE_ASCII_NUMERIC, 5, 8, flags, 3, 0, SC_PKCS15_CO_FLAG_MODIFIABLE | SC_PKCS15_CO_FLAG_PRIVATE); /* add authentication private key */ auth_id.value[0] = 1; auth_id.len = 1; sc_pkcs15emu_add_prkey(p15card, &id, authPRKEY, SC_PKCS15_TYPE_PRKEY_RSA, 1024, authprkey_usage, &path, infocamere_idprkey_auth_obj[ef_gdo[len_iccsn+6]-2], &auth_id, SC_PKCS15_CO_FLAG_PRIVATE); } /* Get the non-repudiation certificate length */ sc_format_path(infocamere_cert_path[ef_gdo[len_iccsn+6]-2], &path); if (sc_select_file(card, &path, NULL) < 0) { r = SC_ERROR_INTERNAL; goto failed; } sc_read_binary(card, 0, certlen, 2, 0); /* Now set the certificate offset/len */ path.index = 2; path.count = (certlen[1] << 8) + certlen[0]; id.value[0] = 2; id.len = 1; sc_pkcs15emu_add_cert(p15card, SC_PKCS15_TYPE_CERT_X509, authority, &path, &id, label, SC_PKCS15_CO_FLAG_MODIFIABLE); /* Get the CA certificate length */ authority = 1; sc_format_path(infocamere_cacert_path[ef_gdo[len_iccsn+6]-2], &path); if (sc_select_file(card, &path, NULL) >= 0) { sc_read_binary(card, 0, certlen, 2, 0); /* Now set the certificate offset/len */ path.index = 2; path.count = (certlen[1] << 8) + certlen[0]; id.value[0] = 3; sc_pkcs15emu_add_cert(p15card, SC_PKCS15_TYPE_CERT_X509, authority, &path, &id, calabel, SC_PKCS15_CO_FLAG_MODIFIABLE); } /* add non repudiation PIN */ sc_format_path(infocamere_nrepud_path[ef_gdo[len_iccsn+6]-2], &path); id.value[0] = 2; sc_pkcs15emu_add_pin(p15card, &id, nonrepPIN, &path, infocamere_idpin_nrepud_obj[ef_gdo[len_iccsn+6]-2], SC_PKCS15_PIN_TYPE_ASCII_NUMERIC, 5, 8, flags, 3, 0, SC_PKCS15_CO_FLAG_MODIFIABLE | SC_PKCS15_CO_FLAG_PRIVATE); /* add non repudiation private key */ auth_id.value[0] = 2; auth_id.len = 1; sc_pkcs15emu_add_prkey(p15card, &id, nonrepPRKEY, SC_PKCS15_TYPE_PRKEY_RSA, 1024, prkey_usage, &path, infocamere_idprkey_nrepud_obj[ef_gdo[len_iccsn+6]-2], &auth_id, SC_PKCS15_CO_FLAG_PRIVATE); /* return to MF */ sc_format_path("3F00", &path); r = sc_select_file(card, &path, NULL); if (change_sign) { struct sc_card_operations *new_ops; new_ops = (struct sc_card_operations *) calloc(1, sizeof(*new_ops)); if (!new_ops) return SC_ERROR_OUT_OF_MEMORY; /* copy normal cardos card ops */ *new_ops = *card->ops; /* save old signature funcs */ set_security_env = new_ops->set_security_env; compute_signature = new_ops->compute_signature; /* set new one */ new_ops->set_security_env = set_sec_env; new_ops->compute_signature = do_sign; /* use new ops */ card->ops = new_ops; } return 0; failed: sc_error(card->ctx, "Failed to initialize Infocamere emulation: %s\n", sc_strerror(r)); return r; } static int infocamere_detect_card(sc_pkcs15_card_t *p15card) { sc_card_t *card = p15card->card; /* check if we have the correct card OS */ if (strcmp(card->name, "STARCOS SPK 2.3") && strcmp(card->name, "CardOS M4")) return SC_ERROR_WRONG_CARD; return SC_SUCCESS; } int sc_pkcs15emu_infocamere_init_ex(sc_pkcs15_card_t *p15card, sc_pkcs15emu_opt_t *opts) { if (opts && opts->flags & SC_PKCS15EMU_FLAGS_NO_CHECK) return sc_pkcs15emu_infocamere_init(p15card); else { int r = infocamere_detect_card(p15card); if (r) return SC_ERROR_WRONG_CARD; return sc_pkcs15emu_infocamere_init(p15card); } }