|
| <prev next> |
PKCS15 Emulation Routine for use with GemSAFE GPK 1600 Windows Initilized C: msg#00286encryption.opensc.devel
Attached is a new version of 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 GemSAFE applications directory is searched for by name rather then assuming it is a 3F000200. Since the card may have more then one key file, the files from 0007 to 000F are searched to see if they are key files and the modulus size and modulus is read. Later after a certificate is found, its modulus is compared to ones found in the keyfiles, and the key file id is set to match the certificate. This should address Nils' comment about on his card the key files was 000A, rather then 0009. -- 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 Thu Mar 31 16:21:30 2005 @@ -0,0 +1,506 @@ +/* + * 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; + +typedef struct keyinfo_st { + int fileid; + sc_pkcs15_id_t id; + unsigned int modulus_len; + u8 modulus[1024/8]; +} keyinfo; + +#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 const u8 gemsafe_aid[] = {0xA0, 0x00, 0x00, 0x00, 0x18, + 0x0F, 0x00, 0x00, 0x01, 0x63, 0x00, 0x01}; + +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 = 0; + 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; + + 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, j; + int dfpath; + 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; + + u8 sysrec[7]; + int num_keyinfo = 0; + keyinfo keyinfo[8]; /* will loook for 8 keys */ + u8 modulus_buf[ 1 + 1024 / 8]; /* tag+modulus */ + u8 *cp; + + 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"); + + /* test if we have a gemsafe app df */ + memset(&path, 0, sizeof(path)); + memcpy(path.value, gemsafe_aid, sizeof(gemsafe_aid)); + path.len = sizeof(gemsafe_aid); + path.type = SC_PATH_TYPE_DF_NAME; + r = sc_select_file(card, &path, &file); + if (r < 0) + return SC_ERROR_WRONG_CARD; + + /* we will use dfpath in all other references */ + dfpath = file->id; + free(file); + file = NULL; + +sc_debug(card->ctx, "GemSafe file found, id=%d",dfpath); + + /* There may be more then one key in the directory. */ + /* we need to find them so we can associate them with the */ + /* the certificate. The files are 0007 to 000f */ + + for (i = 7; i < 16; i++) { + path.value[0] = 0x00; + path.value[1] = i; + path.len = 2; + path.type = SC_PATH_TYPE_FILE_ID; + card->ctx->suppress_errors++; /* file may not exist, and not an error */ + r = sc_select_file(card, &path, NULL); + card->ctx->suppress_errors--; + if (r < 0) + continue; + card->ctx->suppress_errors++; + r = sc_read_record(card, 1, sysrec, sizeof(sysrec), SC_RECORD_BY_REC_NR); + card->ctx->suppress_errors--; + if (r != 7 || sysrec[0] != 0) { + continue; + } + if (sysrec[5] != 0x00) { + continue; + } + + switch (sysrec[1]) { + case 0x00: keyinfo[num_keyinfo].modulus_len = 512 / 8; break; + case 0x10: keyinfo[num_keyinfo].modulus_len = 768 / 8; break; + case 0x11: keyinfo[num_keyinfo].modulus_len = 1024 / 8; break; + default: + sc_error(card->ctx, "Unsupported modulus length"); + continue; + } + + keyinfo[num_keyinfo].fileid = i; + sc_pkcs15_format_id("NONE", &keyinfo[num_keyinfo].id); + + sc_debug(card->ctx,"reading modulus"); + r = sc_read_record(card, 2, modulus_buf, + keyinfo[num_keyinfo].modulus_len+1, SC_RECORD_BY_REC_NR); + if (r < 0) + continue; + + /* need to reverse the modulus skiping the tag */ + j = keyinfo[num_keyinfo].modulus_len; + cp = keyinfo[num_keyinfo].modulus; + while (j--) + *cp++ = modulus_buf[j + 1]; + num_keyinfo++; + } + + /* Get the gemsafe data with the cert */ + sc_format_path("3F000200004", &path); + + /* file.id has the real DF of the GemSAFE file from above*/ + path.value[2] = dfpath >> 8; + path.value[3] = dfpath & 0xff; + + 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; + sc_pkcs15_cert_t *cert_out; + + 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; + + /* now lets see if we have a matching key for this cert */ + + r = sc_pkcs15_read_certificate(p15card, &cert_info, &cert_out); + if (r < 0) + return SC_ERROR_INTERNAL; + + for (j = 0; j < num_keyinfo; j++) { + if (cert_out->key.u.rsa.modulus.len == keyinfo[j].modulus_len && + memcmp(cert_out->key.u.rsa.modulus.data, + &keyinfo[j].modulus, cert_out->key.u.rsa.modulus.len) == 0) { + memcpy(&keyinfo[j].id, &cert_info.id, sizeof(sc_pkcs15_id_t)); + sc_debug(card->ctx, "found match"); + } + } + sc_pkcs15_free_certificate(cert_out); + } + + 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.path.value[2] = dfpath >> 8; + pin_info.path.value[3] = dfpath & 0xff; + 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; + } + +/* needs work, as we may want to add more then one key */ +/* but not sure what the other keys do */ + + /* 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); + +/*DEE need to look for them by reading and checking mudulus vs cert */ + + prkey_info.path.value[2] = dfpath >> 8; + prkey_info.path.value[3] = dfpath & 0xff; + + /* will use the default path, unless we found a key with */ + /* the same modulus as the cert(s) we already added */ + /* This allows us to have a card with a key but no cert */ + + for (j = 0; j < num_keyinfo; j++) { + if (sc_pkcs15_compare_id(&keyinfo[j].id, &prkey_info.id)) { + sc_debug(card->ctx, "found key in file %d for id %d", + keyinfo[j].fileid, prkey_info.id); + prkey_info.path.value[4] = keyinfo[j].fileid >> 8; + prkey_info.path.value[5] = keyinfo[j].fileid & 0xff; + break; + } + } + + 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: ePass2000 usb: 00286, Justin Karneges |
|---|---|
| Previous by Thread: | Using openct-ifd.so in pcsc-litei: 00286, Marc Bevand |
| Indexes: | [Date] [Thread] [Top] [All Lists] |
| News | FAQ | advertise |