|
PKCS15 Emulation Routine for use with GemSAFE GPK 1600 Windows Initilized C: msg#00281encryption.opensc.devel
Attached is a pkcs15 emulation routine that can be used with a Windows initialized GemSAFE GPK 1600 card along with mods to have this built with OpenSC. The certificate and private key are made available via PKCS#15. Thus when used with Heimdal Kerberos PKINIT modifications the card can be used to get a Kerberos ticket from Windows AD using the same cert and Key as would be used for Windows login. The intent is to use the same smartcard as used for login to Windows to login to other systems. The following files are included: ./src/gemsafe/Makefile.am ./src/gemsafe/pkcs15-gemsafe.c ./src/Makefile.am ./configure.in The last two are mods to build the gemsafe directory. The mods are against the opensc-20050330.tar.gz downloaded today. Comments: No code added to allow pin changes, as one could still use the GemSAFE windows code to do this. The cert is found in the GemSAFE control block by looking for a cert. The private key is assumed to be in file 0009, but as Nils pointed out on his card it is in file 000A. I need to match the RSA modulus in the cert with the ones in the multiple private key files to find a match. (I will work on this.) The pin padding has been moved to the pkcs15-gemsafe.c rather then being mods to card-gpk.c The lib is pkcs15emu_gemsafe.so, rather then pkcs15_emu_gemsafe.so as in yesterdays version. The changes create a pkcs15_emu_gemsafe.so library. This can be loaded using something like this in opensc.conf: app default { debug = 0; card_atr 3B:A7:00:40:18:80:65:A2:09:01:03:52 { name = "GemSAFE" ; pkcs15emu = "pkcs15emu_gemsafe"; } framework pkcs15 { try_emulation_first = yes; enable_builtin_emulation = yes; emulate pkcs15emu_gemsafe { module = /opt/opensc/lib/pkcs15emu_gemsafe.so; function = "sc_pkcs15emu_gemsafe_init_ex"; } } } -- Douglas E. Engert <DEEngert@xxxxxxx> Argonne National Laboratory 9700 South Cass Avenue Argonne, Illinois 60439 (630) 252-5444 --- ./src/gemsafe/,Makefile.am Mon Mar 28 12:47:47 2005 +++ ./src/gemsafe/Makefile.am Wed Mar 30 11:37:32 2005 @@ -0,0 +1,14 @@ +# Process this file with automake to create Makefile.in + +MAINTAINERCLEANFILES = Makefile.in + +lib_LTLIBRARIES = pkcs15emu_gemsafe.la + + + +pkcs15emu_gemsafe_la_SOURCES = \ + pkcs15-gemsafe.c +pkcs15emu_gemsafe_la_LDFLAGS = -module -version-info @OPENSC_LT_CURRENT@:@OPENSC_LT_REVISION@:@OPENSC_LT_AGE@ +pkcs15emu_gemsafe_la_LIBADD = @LIBOPENSC@ @LIBCRYPTO@ @LIBSCCONF@ + +noinst_HEADERS = --- ./src/gemsafe/,pkcs15-gemsafe.c Mon Mar 28 12:47:47 2005 +++ ./src/gemsafe/pkcs15-gemsafe.c Wed Mar 30 11:14:10 2005 @@ -0,0 +1,386 @@ +/* + * partial PKCS15 emulation for gemsafe GPK cards + * + * Copyright (C) 2004, Nils <larsch@xxxxxxxxxxxxxx> + * + * 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 <opensc/pkcs15.h> +#include <opensc/log.h> +#include <stdlib.h> +#include <string.h> +#include <stdio.h> + +#define MANU_ID "GemSAFE on GPK1600" + +int sc_pkcs15emu_gemsafe_init_ex(sc_pkcs15_card_t *, sc_pkcs15emu_opt_t *); + +static int (*pin_cmd_save)(struct sc_card *, struct sc_pin_cmd_data *, + int *tries_left); + +typedef struct cdata_st { + const char *label; + int authority; + const char *path; + const char *id; + int obj_flags; +} cdata; + +typedef struct pdata_st { + const char *id; + const char *label; + const char *path; + int ref; + int type; + unsigned int maxlen; + unsigned int minlen; + unsigned int storedlen; + int flags; + int tries_left; + const char pad_char; + int obj_flags; +} pindata; + +typedef struct prdata_st { + const char *id; + const char *label; + unsigned int modulus_len; + int usage; + const char *path; + int ref; + const char *auth_id; + int obj_flags; +} prdata; + +#define USAGE_NONREP SC_PKCS15_PRKEY_USAGE_NONREPUDIATION +#define USAGE_KE SC_PKCS15_PRKEY_USAGE_ENCRYPT | \ + SC_PKCS15_PRKEY_USAGE_DECRYPT | \ + SC_PKCS15_PRKEY_USAGE_WRAP | \ + SC_PKCS15_PRKEY_USAGE_UNWRAP +#define USAGE_AUT SC_PKCS15_PRKEY_USAGE_ENCRYPT | \ + SC_PKCS15_PRKEY_USAGE_DECRYPT | \ + SC_PKCS15_PRKEY_USAGE_WRAP | \ + SC_PKCS15_PRKEY_USAGE_UNWRAP | \ + SC_PKCS15_PRKEY_USAGE_SIGN + +static int my_pin_cmd(sc_card_t * card, struct sc_pin_cmd_data * data, + int *tries_left) +{ + /* GemSAFE pin uses a null terminated string with 0xFF */ + /* so we need to add the 0x00 to the pin then pad with 0xFF */ + + int r; + u8 *saved_data = NULL; + int saved_len; + char newpin[8]; + + SC_FUNC_CALLED(card->ctx, 2); + + memset(newpin, 0xff, sizeof(newpin)); + + if (data->pin1.data && data->pin1.len < 8 && data->pin1.len > 0) { + memcpy(newpin,data->pin1.data, data->pin1.len); + newpin[data->pin1.len] = 0x00; + + sc_debug(card->ctx, "pin len=%d", data->pin1.len); + + saved_data = data->pin1.data; + saved_len = data->pin1.len; + data->pin1.data = newpin; + data->pin1.len = sizeof(newpin); + } + + r = pin_cmd_save(card, data, tries_left); + + if (saved_data) { + data->pin1.data = saved_data; + data->pin1.len = saved_len; + } + + SC_FUNC_RETURN(card->ctx, 2, r); + + return r; + +} + + +static int is_seq(unsigned char * seq, int *seq_size, int *seq_len) +{ + int i,j,k; + + if (seq[0] != 0x30) + return 0; /* not a sequence */ + if (seq[1] & 0x80) { + i = seq[1] & 0x7f; + if (i > 2 || i == 0) + return 0; /* cert would be bigger then 65k or zero */ + if (seq[2] == 0) + return 0; /* DER would not have extra zero */ + k = 0; + for (j = 0; j < i; j++) { + k = (k << 8) + seq[j + 2]; + } + if (k < 128) + return 0; /* DER would have used single byte for len */ + } else { + i = 0; + k = seq[1]; + } + + *seq_size = i + 2; + *seq_len = k; + return 1; +} + +static int gemsafe_detect_card(sc_pkcs15_card_t *p15card) +{ + sc_card_t *card = p15card->card; + + SC_FUNC_CALLED(card->ctx, 1); + + +// if (strcmp(card->name, "Gemplus GPK")) +// return SC_ERROR_WRONG_CARD; + + /* DEE should check that we can get */ + /* "3F00a0000000180f000001530001" */ + /* and get the DF number from it. 0200 is assumed */ + /* This is on the GPK 1600 at least */ + /* Other GemSAFE cards may be detected in other ways */ + + return SC_SUCCESS; +} + +static int sc_pkcs15emu_gemsafe_init(sc_pkcs15_card_t *p15card) +{ + const cdata certs[] = { + {"User certificate",0, "","1", 0}, + {NULL, 0, NULL, 0, 0} + }; + + const pindata pins[] = { + { "1", "pin", "3F000200", 0x00, + SC_PKCS15_PIN_TYPE_ASCII_NUMERIC, + 8, 4, 8, SC_PKCS15_PIN_FLAG_NEEDS_PADDING | + SC_PKCS15_PIN_FLAG_LOCAL, -1, 0x00, + SC_PKCS15_CO_FLAG_PRIVATE }, + { NULL, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0} + }; + + const prdata prkeys[] = { + { "1", "AUTH key", 1024, USAGE_AUT, "3F0002000009", + 0x00, "1", SC_PKCS15_CO_FLAG_PRIVATE}, + { NULL, NULL, 0, 0, NULL, 0, NULL, 0} + }; + + int r, i; + sc_path_t path; + sc_file_t *file = NULL; + sc_card_t *card = p15card->card; + unsigned char *gsdata = NULL; + int idxlen, idx1, idx2, seq_len1, seq_len2, seq_size1, seq_size2; + + SC_FUNC_CALLED(card->ctx, 1); + + /* could read this off card if needed */ + + p15card->label = strdup("GemSAFE"); + p15card->manufacturer_id = strdup("gemsafe"); + p15card->serial_number = strdup("0000"); + + /* Get the gemsafe data with the cert */ + sc_format_path("3F000200004", &path); + + if (sc_select_file(card, &path, &file) < 0) { + return SC_ERROR_WRONG_CARD; + } + + /* the GemSAFE file has our cert, but we do not know the format */ + /* of the file. But we do know a cert has SEQ SEQ SEQOF INT 2 */ + /* so we will look for that. We assume cert is larger then 127 bytes */ + /* and less then 65K, and must be fit in the file->size */ + /* There is a chance that we might find something that is not */ + /* a cert, but the chances are low. If GemPlus ever publishes */ + /* the format of the file, we can used that instead. */ + + /* For performance reasons we will only */ + /* read part of the file , as it is about 6100 bytes */ + + gsdata = (unsigned char *) malloc(file->size); + + if (!gsdata) + return SC_ERROR_OUT_OF_MEMORY; + + /* set indcies of data in gsdata */ + idx1 = 0; /* start point */ + idx2 = 0; /* index of last data read so far */ + + + /* set certs We only have one we are interested in */ + /* but the read loop is set up to allow for more in future */ + + for (i = 0; certs[i].label; i++) { + struct sc_pkcs15_cert_info cert_info; + struct sc_pkcs15_object cert_obj; + + memset(&cert_info, 0, sizeof(cert_info)); + memset(&cert_obj, 0, sizeof(cert_obj)); + + sc_pkcs15_format_id(certs[i].id, &cert_info.id); + cert_info.authority = certs[i].authority; + sc_format_path(certs[i].path, &cert_info.path); + + strncpy(cert_obj.label, certs[i].label, SC_PKCS15_MAX_LABEL_SIZE - 1); + cert_obj.flags = certs[i].obj_flags; + + while (idx1 < file->size - 16) { /* actually 13 for all these tests */ + if (idx1 > idx2 - 16) { /* need more data in buff */ + idxlen = 248; /* read in next 248 bytes */ + if (idxlen > file->size - idx2) + idxlen = file->size - idx2; + r = sc_read_binary(card, idx2, gsdata + idx2, idxlen, 0); + if (r < 0) + break; + idx2 = idx2 + idxlen; + } + + if ( gsdata[idx1] == 0x30 && + is_seq(gsdata + idx1, &seq_size1, &seq_len1) && + is_seq(gsdata + idx1 + seq_size1, &seq_size2, &seq_len2) && + gsdata[idx1 + seq_size1 + seq_size2 + 0] == 0xa0 && + gsdata[idx1 + seq_size1 + seq_size2 + 1] == 0x03 && + gsdata[idx1 + seq_size1 + seq_size2 + 2] == 0x02 && + gsdata[idx1 + seq_size1 + seq_size2 + 3] == 0x01 && + gsdata[idx1 + seq_size1 + seq_size2 + 4] == 0x02 && + idx1 + 4 + seq_len1 < file->size) { + /* we have a cert (I hope) */ + /* read in rest if needed */ + idxlen = idx1 + seq_len1 + 4 - idx2; + if (idxlen > 0) { + idxlen = (idxlen + 3) & 0xfffffffc; + r = sc_read_binary(card, idx2, gsdata + idx2, idxlen, 0); + if (r < 0) + break; /* can not read cert */ + idx2 = idx2 + idxlen; + } + cert_info.value.len = seq_len1 + 4; + sc_debug(card->ctx, "Found cert at offset %d", idx1); + cert_info.value.value = (unsigned char *) + malloc(cert_info.value.len); + if (!cert_info.value.value) + return SC_ERROR_OUT_OF_MEMORY; + + memcpy(cert_info.value.value, gsdata + idx1, cert_info.value.len); + idx1 = idx1 + cert_info.value.len; + break; + } + idx1++; + } + + if (cert_info.value.value == NULL) + break; /* cert not found, no more certs */ + + r = sc_pkcs15emu_add_x509_cert(p15card, &cert_obj, &cert_info); + if (r < 0) + return SC_ERROR_INTERNAL; + } + + if (gsdata) + free(gsdata); + + /* set pins */ + + + /* GemSAFE uses different padding, so need to trap */ + /* the pin_cmd and reset the padding */ + + pin_cmd_save = card->ops->pin_cmd; + card->ops->pin_cmd = my_pin_cmd; + + for (i = 0; pins[i].label; i++) { + struct sc_pkcs15_pin_info pin_info; + struct sc_pkcs15_object pin_obj; + + memset(&pin_info, 0, sizeof(pin_info)); + memset(&pin_obj, 0, sizeof(pin_obj)); + + sc_pkcs15_format_id(pins[i].id, &pin_info.auth_id); + pin_info.reference = pins[i].ref; + pin_info.flags = pins[i].flags; + pin_info.type = pins[i].type; + pin_info.min_length = pins[i].minlen; + pin_info.stored_length = pins[i].storedlen; + pin_info.max_length = pins[i].maxlen; + pin_info.pad_char = pins[i].pad_char; + sc_format_path(pins[i].path, &pin_info.path); + pin_info.tries_left = -1; + + strncpy(pin_obj.label, pins[i].label, SC_PKCS15_MAX_LABEL_SIZE - 1); + pin_obj.flags = pins[i].obj_flags; + + r = sc_pkcs15emu_add_pin_obj(p15card, &pin_obj, &pin_info); + if (r < 0) + return SC_ERROR_INTERNAL; + } + + /* set private keys */ + for (i = 0; prkeys[i].label; i++) { + struct sc_pkcs15_prkey_info prkey_info; + struct sc_pkcs15_object prkey_obj; + + memset(&prkey_info, 0, sizeof(prkey_info)); + memset(&prkey_obj, 0, sizeof(prkey_obj)); + + sc_pkcs15_format_id(prkeys[i].id, &prkey_info.id); + prkey_info.usage = prkeys[i].usage; + prkey_info.native = 1; + prkey_info.key_reference = prkeys[i].ref; + prkey_info.modulus_length= prkeys[i].modulus_len; + sc_format_path(prkeys[i].path, &prkey_info.path); + + strncpy(prkey_obj.label, prkeys[i].label, SC_PKCS15_MAX_LABEL_SIZE - 1); + prkey_obj.flags = prkeys[i].obj_flags; + if (prkeys[i].auth_id) + sc_pkcs15_format_id(prkeys[i].auth_id, &prkey_obj.auth_id); + + r = sc_pkcs15emu_add_rsa_prkey(p15card, &prkey_obj, &prkey_info); + if (r < 0) + return SC_ERROR_INTERNAL; + } + + return SC_SUCCESS; +} + +int sc_pkcs15emu_gemsafe_init_ex(sc_pkcs15_card_t *p15card, + sc_pkcs15emu_opt_t *opts) +{ + sc_card_t *card = p15card->card; + sc_context_t *ctx = card->ctx; + + sc_debug(ctx, "Entering %s", __FUNCTION__); + + if (opts && opts->flags & SC_PKCS15EMU_FLAGS_NO_CHECK) + return sc_pkcs15emu_gemsafe_init(p15card); + else { + int r = gemsafe_detect_card(p15card); + if (r) + return SC_ERROR_WRONG_CARD; + return sc_pkcs15emu_gemsafe_init(p15card); + } +} + +/* since we are in our own shared lib, we need this entry */ +SC_IMPLEMENT_DRIVER_VERSION("0.9.4") --- ./src/,Makefile.am Wed Mar 2 02:11:47 2005 +++ ./src/Makefile.am Wed Mar 30 10:32:09 2005 @@ -6,4 +6,4 @@ # Order IS important SUBDIRS = common include scconf scdl scldap scrandom libopensc pkcs15init pkcs11 \ - tests tools openssh scam pam sia signer sslengines + tests tools openssh scam pam sia signer sslengines gemsafe --- ./,configure.in Tue Mar 29 15:11:56 2005 +++ ./configure.in Wed Mar 30 10:32:59 2005 @@ -994,6 +994,7 @@ src/signer/Makefile src/signer/npinclude/Makefile src/sslengines/Makefile +src/gemsafe/Makefile src/tests/Makefile src/tests/regression/Makefile src/tools/Makefile _______________________________________________ OpenSC-devel mailing list OpenSC-devel@xxxxxxxxxx http://www.opensc.org/cgi-bin/mailman/listinfo/opensc-devel |
|
| <Prev in Thread] | Current Thread | [Next in Thread> |
|---|---|---|
| Previous by Date: | Re: libopensc asn1 boolean handling: 00281, William Wanders |
|---|---|
| Next by Date: | Using openct-ifd.so in pcsc-lite: 00281, Marc Bevand |
| Previous by Thread: | Adding SC_FILE_STATUS_INITIALISATION status in sc_file_ti: 00281, Stef Hoeben |
| Next by Thread: | Using openct-ifd.so in pcsc-lite: 00281, Marc Bevand |
| Indexes: | [Date] [Thread] [Top] [All Lists] |
| News | FAQ | advertise |