From c6954a9c333087034c94d3ef460487eecb90160c Mon Sep 17 00:00:00 2001 From: aj Date: Sat, 10 Mar 2007 10:46:32 +0000 Subject: [PATCH] full piv update by Thomas harning Jr. and David E. Engert, adding compression etc. Also enables opensc to be compiled with and without zlib support. git-svn-id: https://www.opensc-project.org/svnp/opensc/trunk@3125 c6295689-39f2-0310-b995-f0e70906c6a9 --- src/libopensc/Makefile.am | 5 +- src/libopensc/Makefile.mak | 3 +- src/libopensc/card-piv.c | 355 +++++++++++++++++++------- src/libopensc/compression.c | 176 +++++++++++++ src/libopensc/compression.h | 35 +++ src/libopensc/p15card-helper.c | 342 +++++++++++++++++++++++++ src/libopensc/p15card-helper.h | 137 ++++++++++ src/libopensc/pkcs15-piv.c | 454 ++++++++++----------------------- src/tools/piv-tool.c | 59 +++-- win32/Make.rules.mak | 14 +- 10 files changed, 1144 insertions(+), 436 deletions(-) create mode 100644 src/libopensc/compression.c create mode 100644 src/libopensc/compression.h create mode 100644 src/libopensc/p15card-helper.c create mode 100644 src/libopensc/p15card-helper.h diff --git a/src/libopensc/Makefile.am b/src/libopensc/Makefile.am index 564a49a8..5728df11 100644 --- a/src/libopensc/Makefile.am +++ b/src/libopensc/Makefile.am @@ -33,14 +33,15 @@ libopensc_la_SOURCES = \ \ pkcs15-openpgp.c pkcs15-infocamere.c pkcs15-starcert.c \ pkcs15-tcos.c pkcs15-esteid.c pkcs15-postecert.c pkcs15-gemsafe.c \ - pkcs15-actalis.c pkcs15-atrust-acos.c pkcs15-tccardos.c pkcs15-piv.c + pkcs15-actalis.c pkcs15-atrust-acos.c pkcs15-tccardos.c pkcs15-piv.c \ + compression.c p15card-helper.c libopensc_la_LDFLAGS = -version-info @OPENSC_LT_CURRENT@:@OPENSC_LT_REVISION@:@OPENSC_LT_AGE@ libopensc_la_LIBADD = @LIBSCCONF@ $(OPENSSL_LIBS) $(OPENCT_LIBS) $(PCSC_LIBS) $(LTLIBLTDL) include_HEADERS = \ opensc.h pkcs15.h emv.h \ cardctl.h asn1.h log.h ui.h \ - errors.h types.h + errors.h types.h compression.h noinst_HEADERS = cards.h ctbcs.h internal.h esteid.h muscle.h muscle-filesystem.h part10.h diff --git a/src/libopensc/Makefile.mak b/src/libopensc/Makefile.mak index 34a6b316..fedbaed0 100644 --- a/src/libopensc/Makefile.mak +++ b/src/libopensc/Makefile.mak @@ -29,6 +29,7 @@ OBJECTS = \ card-oberthur.obj card-belpic.obj card-atrust-acos.obj \ card-incrypto34.obj card-piv.obj\ muscle.obj card-muscle.obj muscle-filesystem.obj \ + compression.obj p15card-helper.obj \ \ pkcs15-openpgp.obj pkcs15-infocamere.obj pkcs15-starcert.obj \ pkcs15-tcos.obj pkcs15-esteid.obj pkcs15-postecert.obj \ @@ -43,5 +44,5 @@ all: install-headers $(TARGET) $(TARGET): $(OBJECTS) ..\scconf\scconf.lib ..\common\common.lib perl $(TOPDIR)\win32\makedef.pl $*.def $* $(OBJECTS) - link $(LINKFLAGS) /dll /def:$*.def /implib:$*.lib /out:$(TARGET) $(OBJECTS) ..\scconf\scconf.lib ..\common\common.lib winscard.lib $(OPENSSL_LIB) gdi32.lib $(LIBLTDL_LIB) advapi32.lib ws2_32.lib + link $(LINKFLAGS) /dll /def:$*.def /implib:$*.lib /out:$(TARGET) $(OBJECTS) ..\scconf\scconf.lib ..\common\common.lib winscard.lib $(OPENSSL_LIB) $(ZLIB_LIB) gdi32.lib $(LIBLTDL_LIB) advapi32.lib ws2_32.lib if EXIST $(TARGET).manifest mt -manifest $(TARGET).manifest -outputresource:$(TARGET);2 diff --git a/src/libopensc/card-piv.c b/src/libopensc/card-piv.c index 27e72cbe..09ecc547 100644 --- a/src/libopensc/card-piv.c +++ b/src/libopensc/card-piv.c @@ -4,6 +4,7 @@ * * Copyright (C) 2001, 2002 Juha Yrjölä * Copyright (C) 2005, Douglas E. Engert + * Copyright (C) 2006, Identity Alliance, Thomas Harning * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -29,8 +30,17 @@ #include #include "asn1.h" #include "cardctl.h" +#ifdef HAVE_ZLIB_H +#include "compression.h" +#endif -struct piv_private_data { +typedef struct { + u8* data; + size_t length; + int enumtag; +} piv_cache_item; + +typedef struct piv_private_data { struct sc_pin_cmd_pin pin_info; sc_file_t *aid_file; int enumtag; @@ -39,8 +49,53 @@ struct piv_private_data { size_t max_recv_size; /* saved size, need to lie to pkcs15_read_file */ size_t max_send_size; int key_ref; /* saved from set_security_env and */ - int alg_id; /* used in decrypy, signature */ -}; + int alg_id; /* used in decrypt, signature */ + piv_cache_item* cache; + int cacheLen; + piv_cache_item* current_item; +} piv_private_data_t; + +#define PIV_DATA(card) ((piv_private_data_t*)card->drv_data) + +static int add_cache_item(piv_private_data_t* priv, int enumtag, u8* data, size_t length) { + int idx, len = priv->cacheLen; + piv_cache_item* cache = priv->cache; + for(idx = 0; idx < len; idx++) { + if(!cache[idx].data) + break; + if(cache[idx].enumtag == enumtag) /* Found matching tag */ + break; + } + if(idx == len) + return -1; /* FAILED NO FREE ROOM */ + if(cache[idx].data) + free(cache[idx].data); + cache[idx].data = data; + cache[idx].length = length; + cache[idx].enumtag = enumtag; + return 0; +} + +static piv_cache_item* get_cache_item(piv_private_data_t* priv, int enumtag) { + int idx, len = priv->cacheLen; + piv_cache_item* cache = priv->cache; + for(idx = 0; idx < len; idx++) { + if(cache[idx].enumtag == enumtag) + return &cache[idx]; + } + return NULL; +} + +static void free_cache_items(piv_private_data_t* priv) { + int idx, len = priv->cacheLen; + piv_cache_item* cache = priv->cache; + for(idx = 0; idx < len; idx++) { + if(cache[idx].data) { + free(cache[idx].data); + cache[idx].data = NULL; + } + } +} struct piv_aid { int enumtag; @@ -71,7 +126,8 @@ enum { PIV_OBJ_X509_CARD_AUTH, PIV_OBJ_SEC_OBJ, PIV_OBJ_9B03, - PIV_OBJ_9A06 + PIV_OBJ_9A06, + PIV_CACHE_SIZE }; struct piv_object { @@ -88,14 +144,12 @@ static struct piv_object piv_objects[] = { { PIV_OBJ_CCC, "Card Capability Container", "2.16.840.1.101.3.7.1.219.0", 3, "\x5F\xC1\x07", "\xDB\x00", 266}, { PIV_OBJ_CHUI, "Card Holder Unique Identifier", - "2.16.840.1.101.3.7.2.48.0", 3, "\x5F\xC1\x02", "\x30\x00", 3377}, + "2.16.840.1.101.3.7.2.48.0", 3, "\x5F\xC1\x02", "\x30\x00", 3379}, /* Updated per SP800-73-1 Errata */ { PIV_OBJ_X509_PIV_AUTH, "X.509 Certificate for PIV Authentication", "2.16.840.1.101.3.7.2.1.1", 3, "\x5F\xC1\x05", "\x01\x01", 1856+4+400} , /* extra 400 is hack for MultOS card which returns 2200 bytes */ - { PIV_OBJ_CHF1, "Card Holder Fingerprint I", - "2.16.840.1.101.3.7.2.96.16", 3, "\x5F\xC1\x03", "\x60\x01", 7768}, - { PIV_OBJ_CHF2, "Card Holder Fingerprint II", - "2.16.840.1.101.3.7.2.96.17", 3, "\x5F\xC1\x04", "\x60\x11", 7768}, + { PIV_OBJ_CHF1, "Card Holder Fingerprints", + "2.16.840.1.101.3.7.2.96.16", 3, "\x5F\xC1\x03", "\x60\x10", 7768}, { PIV_OBJ_PI, "Printed Information", "2.16.840.1.101.3.7.2.48.1", 3, "\x5F\xC1\x09", "\x30\x01", 106}, { PIV_OBJ_CHFI, "Card Holder Facial Image", @@ -184,7 +238,7 @@ static int piv_general_io(sc_card_t *card, int ins, int p1, int p2, const u8 * sendbuf, size_t sendbuflen, u8 ** recvbuf, size_t * recvbuflen) { - struct piv_private_data * priv = (struct piv_private_data *) card->drv_data; + piv_private_data_t * priv = PIV_DATA(card); int r; sc_apdu_t apdu; u8 rbufinitbuf[20000]; /* crude way to do this see above comments */ @@ -502,12 +556,12 @@ static int piv_find_aid(sc_card_t * card, sc_file_t *aid_file) static int piv_get_data(sc_card_t * card, unsigned int enumtag, u8 **buf, size_t *buf_len) { - struct piv_private_data * priv = (struct piv_private_data *) card->drv_data; + piv_private_data_t * priv = PIV_DATA(card); u8 *p; int r = 0; u8 tagbuf[8]; size_t tag_len; - + SC_FUNC_CALLED(card->ctx,1); sc_debug(card->ctx, "get_data: tag=%d \n", enumtag); @@ -599,7 +653,98 @@ err: SC_FUNC_RETURN(card->ctx, 1, r); } - + + +static int piv_handle_certificate_data(sc_card_t *card, + int enumtag, + unsigned idx, u8* buf, size_t count, + u8* data, size_t length) { + piv_private_data_t * priv = PIV_DATA(card); + u8* tag; + size_t taglen; + int compressed = 0; + piv_cache_item* item; + /* get the certificate out */ + tag = (u8 *) sc_asn1_find_tag(card->ctx, data, length, 0x71, &taglen); + if (tag && (((*tag) & 0x80) || ((*tag) & 0x01))) { + compressed = 1; + } + tag = (u8 *) sc_asn1_find_tag(card->ctx, data, length, 0x70, &taglen); + if (tag == NULL) { + return SC_ERROR_OBJECT_NOT_VALID; + } + /* Potential truncation */ + if(compressed) { +#ifdef HAVE_ZLIB_H + size_t len = count; + u8* newBuf = NULL; + if(SC_SUCCESS != do_decompress_alloc(&newBuf, &len, tag, taglen, COMPRESSION_AUTO)) { + return SC_ERROR_OBJECT_NOT_VALID; + } else { + if(len < count + idx) + count = len - idx; + if(count <= 0) + return 0; + memcpy(buf, newBuf + idx, count); + if(0 != add_cache_item(priv, enumtag, newBuf, len)) { + /* Failed to cache item */ + free(newBuf); + } + } + return count; +#else + sc_error(card->ctx,"PIV compression not supported, no zlib"); + return SC_ERROR_NOT_SUPPORTED; +#endif + } + if(taglen < count + idx) + count = taglen - idx; + if(count <= 0) + return 0; + memcpy(buf, tag, count); + if(0 == add_cache_item(priv, enumtag, NULL, 0)) { + /* Space available in the cache array, use it */ + item = get_cache_item(priv, enumtag); + if(item) { + item->data = malloc(taglen); + if(item->data) { + item->length = taglen; + memcpy(item->data, tag, taglen); + } + } + } + return count; +} + +static int piv_handle_data(sc_card_t *card, int enumtag, + unsigned idx, u8* buf, size_t count, u8* data, size_t length) { + /* For now get the first tag, and return the data */ + piv_private_data_t * priv = PIV_DATA(card); + u8* tag; + size_t taglen; + piv_cache_item* item; + + tag = (u8 *) sc_asn1_find_tag(card->ctx, data, length, *data, &taglen); + if (tag == NULL) { + return SC_ERROR_OBJECT_NOT_VALID; + } + if(taglen < count + idx) + count = taglen - idx; + if(count <= 0) + return 0; + memcpy(buf, tag + idx, count); + if(0 == add_cache_item(priv, enumtag, NULL, 0)) { + item = get_cache_item(priv, enumtag); + if(item) { + item->data = malloc(taglen); + if(item->data) { + item->length = taglen; + memcpy(item->data, tag, taglen); + } + } + } + return count; +} /* * Callers of this are expecting a file without tags, * So we need to know what type of file this is, so we can get the @@ -609,18 +754,31 @@ err: static int piv_read_binary(sc_card_t *card, unsigned int idx, unsigned char *buf, size_t count, unsigned long flags) { - struct piv_private_data * priv = (struct piv_private_data *) card->drv_data; + piv_private_data_t * priv = PIV_DATA(card); + piv_cache_item* item = NULL; + int enumtag; int r; u8 *rbuf = NULL; size_t rbuflen = 0; - u8 *tag; - size_t taglen; u8 *body; size_t bodylen; SC_FUNC_CALLED(card->ctx,1); if (priv->selected_obj < 0) SC_FUNC_RETURN(card->ctx, 1, SC_ERROR_INTERNAL); + enumtag = piv_objects[priv->selected_obj].enumtag; + + /* Hit the cache */ + if(priv->current_item) { + item = priv->current_item; + if(idx + count > item->length) { + count = item->length - idx; + } + if(count <= 0) + return 0; + memcpy(buf, item->data + idx, count); + return count; + } if (priv->eof == 1) return 0; @@ -629,7 +787,7 @@ static int piv_read_binary(sc_card_t *card, unsigned int idx, if (r >=0) { /* if tag is 0, assume card is telling us no object on card */ - if (rbuf[0] == '0') { + if (!rbuf || rbuf[0] == '0') { r = SC_ERROR_FILE_NOT_FOUND; goto err; } @@ -639,40 +797,18 @@ static int piv_read_binary(sc_card_t *card, unsigned int idx, /* if missing, assume its the body */ /* DEE bug in the beta card */ sc_debug(card->ctx," ***** tag 0x53 MISSING \n"); - body = rbuf; - bodylen = rbuflen; -#if 0 r = SC_ERROR_INVALID_DATA; goto err; -#endif } - switch (piv_objects[priv->selected_obj].enumtag) { + switch (enumtag) { case PIV_OBJ_X509_PIV_AUTH: case PIV_OBJ_X509_DS: case PIV_OBJ_X509_KM: case PIV_OBJ_X509_CARD_AUTH: - /* get the certificate out */ - tag = (u8 *) sc_asn1_find_tag(card->ctx, body, bodylen, 0x70, &taglen); - if (tag == NULL) { - r = SC_ERROR_OBJECT_NOT_VALID; - break; - } - memcpy(buf, tag, taglen); /*DEE should check lengths */ - r = taglen; - tag = (u8 *) sc_asn1_find_tag(card->ctx, body, bodylen, 0x71, &taglen); - if (tag && ((*tag) & 0x80)) { - sc_debug(card->ctx,0,"Cert is gziped! %0x2.2x\n",*tag); - } + r = piv_handle_certificate_data(card, enumtag, idx, buf, count, body, bodylen); break; default: - /* For now get the first tag, and return the data */ - tag = (u8 *) sc_asn1_find_tag(card->ctx, body, bodylen, *body, &taglen); - if (tag == NULL) { - r = SC_ERROR_OBJECT_NOT_VALID; - break; - } - memcpy(buf, tag, taglen); /*DEE should check lengths */ - r = taglen; + r = piv_handle_data(card, enumtag, idx, buf, count, body, bodylen); break; } } @@ -720,23 +856,57 @@ static int piv_put_data(sc_card_t *card, unsigned int tag, SC_FUNC_RETURN(card->ctx, 1, r); } +static int piv_write_certificate(sc_card_t *card, + unsigned idx, const u8* buf, size_t count, + unsigned long flags) { + piv_private_data_t * priv = PIV_DATA(card); + int r = SC_SUCCESS; + u8 *sbuf = NULL; + u8 *p; + size_t sbuflen; + size_t taglen; + sc_debug(card->ctx,"DEE cert len=%d",count); + taglen = put_tag_and_len(0x70, count, NULL) + + put_tag_and_len(0x71, 1, NULL) + + put_tag_and_len(0xFE, 0, NULL); + + sbuflen = put_tag_and_len(0x53, taglen, NULL); + + sbuf = (u8*) malloc(sbuflen); + if (sbuf == NULL) + SC_FUNC_RETURN(card->ctx, 1, SC_ERROR_OUT_OF_MEMORY); + p = sbuf; + put_tag_and_len(0x53, taglen, &p); + + put_tag_and_len(0x70, count, &p); + memcpy(p, buf, count); + p += count; + put_tag_and_len(0x71, 1, &p); + *p++ = (flags && 1)? 0x80:0x00; /* certinfo, i.e. gziped? */ + put_tag_and_len(0xFE,0,&p); /* LRC tag */ + + sc_debug(card->ctx,"DEE buf %p len %d %d", sbuf, p -sbuf, sbuflen); + + r = piv_put_data(card, priv->selected_obj, sbuf, sbuflen); + if (sbuf) + free(sbuf); + + return r; +} /* * We need to add the 0x53 tag and other specific tags, * and call the piv_put_data * Note: the select file will have saved the object type for us + * Write is only used by piv-tool, so we will use flags==1 + * to indicate we are writing a compressed cert. */ static int piv_write_binary(sc_card_t *card, unsigned int idx, const u8 *buf, size_t count, unsigned long flags) { - struct piv_private_data * priv = (struct piv_private_data *) card->drv_data; - int r = 0; - u8 *sbuf = NULL; - u8 *p; - size_t sbuflen; - size_t taglen; - + piv_private_data_t * priv = PIV_DATA(card); + /* TODO: Add cache hooks */ SC_FUNC_CALLED(card->ctx,1); if (priv->selected_obj < 0) @@ -749,40 +919,12 @@ static int piv_write_binary(sc_card_t *card, unsigned int idx, case PIV_OBJ_X509_DS: case PIV_OBJ_X509_KM: case PIV_OBJ_X509_CARD_AUTH: - sc_debug(card->ctx,"DEE cert len=%d",count); - - taglen = put_tag_and_len(0x70, count, NULL) - + put_tag_and_len(0x71, 1, NULL); - - sbuflen = put_tag_and_len(0x53, taglen, NULL); - - sbuf = (u8*) malloc(sbuflen); - if (sbuf == NULL) - SC_FUNC_RETURN(card->ctx, 1, SC_ERROR_OUT_OF_MEMORY); - p = sbuf; - put_tag_and_len(0x53, taglen, &p); - - put_tag_and_len(0x70, count, &p); - memcpy(p, buf, count); - p += count; - put_tag_and_len(0x71, 1, &p); - *p++ = 0x00; /* certinfo, i.e. not gziped */ - sc_debug(card->ctx,"DEE buf %p len %d %d", sbuf, p -sbuf, sbuflen); - break; - + SC_FUNC_RETURN(card->ctx, 1, piv_write_certificate(card, idx, buf, count, flags)); default: sc_debug(card->ctx, "Don't know how to write object %s\n", piv_objects[priv->selected_obj].name); - r = SC_ERROR_NOT_SUPPORTED; - break; + SC_FUNC_RETURN(card->ctx, 1, SC_ERROR_NOT_SUPPORTED); } - - if (r == 0) - r = piv_put_data(card, priv->selected_obj, sbuf, sbuflen); - if (sbuf) - free(sbuf); - - SC_FUNC_RETURN(card->ctx, 1, r); } /* @@ -954,7 +1096,7 @@ err: static int piv_general_external_authenticate(sc_card_t *card, unsigned int key_ref, unsigned int alg_id) { - struct piv_private_data * priv = (struct piv_private_data *) card->drv_data; + piv_private_data_t * priv = PIV_DATA(card); int r, outl; u8 *rbuf = NULL; size_t rbuflen; @@ -1109,7 +1251,7 @@ static int piv_set_security_env(sc_card_t *card, const sc_security_env_t *env, int se_num) { - struct piv_private_data * priv = (struct piv_private_data *) card->drv_data; + piv_private_data_t * priv = PIV_DATA(card); SC_FUNC_CALLED(card->ctx,1); @@ -1139,7 +1281,7 @@ static int piv_validate_general_authentication(sc_card_t *card, const u8 * data, size_t datalen, u8 * out, size_t outlen) { - struct piv_private_data * priv = (struct piv_private_data *) card->drv_data; + piv_private_data_t * priv = PIV_DATA(card); int r; u8 *p; u8 *tag; @@ -1228,7 +1370,8 @@ static int piv_find_obj_by_containerid(sc_card_t *card, const u8 * str) static int piv_select_file(sc_card_t *card, const sc_path_t *in_path, sc_file_t **file_out) { - struct piv_private_data * priv = (struct piv_private_data *) card->drv_data; + piv_private_data_t * priv = PIV_DATA(card); + piv_cache_item* item = NULL; int i; const u8 *path; int pathlen; @@ -1255,8 +1398,14 @@ static int piv_select_file(sc_card_t *card, const sc_path_t *in_path, priv->selected_obj = i; priv->eof = 0; + /* check out the cache */ + item = get_cache_item(priv, i); + if(item) { + priv->current_item = item; + } + /* make it look like the file was found. We don't want to read it now,. */ - + if (file_out) { file = sc_file_new(); if (file == NULL) @@ -1266,8 +1415,13 @@ static int piv_select_file(sc_card_t *card, const sc_path_t *in_path, /* this could be like the FCI */ file->type = SC_FILE_TYPE_DF; file->shareable = 0; - file->ef_structure = 0; - file->size = piv_objects[i].maxlen; + file->ef_structure = 0; + if(item) { + file->size = item->length; + } else { + file->size = piv_objects[i].maxlen; + } + file->id = (piv_objects[i].containerid[0]<<8) + piv_objects[i].containerid[1]; *file_out = file; @@ -1280,12 +1434,16 @@ static int piv_select_file(sc_card_t *card, const sc_path_t *in_path, static int piv_finish(sc_card_t *card) { - struct piv_private_data * priv = (struct piv_private_data *) card->drv_data; + piv_private_data_t * priv = PIV_DATA(card); SC_FUNC_CALLED(card->ctx,1); if (priv) { if (priv->aid_file) sc_file_free(priv->aid_file); + if(priv->cache) { + free_cache_items(priv); + free(priv->cache); + } free(priv); } return 0; @@ -1294,9 +1452,18 @@ static int piv_finish(sc_card_t *card) static int piv_match_card(sc_card_t *card) { + int i; + sc_file_t aidfile; SC_FUNC_CALLED(card->ctx,1); - /* dee need to look at AID */ - return 0; /* never match */ + /* Since we send an APDU, the card's logout function may be called... + * however it may be in dirty memory */ + card->ops->logout = NULL; + + /* Detect by selecting applet */ + sc_ctx_suppress_errors_on(card->ctx); + i = !(piv_find_aid(card, &aidfile)); + sc_ctx_suppress_errors_off(card->ctx); + return i; /* never match */ } @@ -1304,16 +1471,17 @@ static int piv_init(sc_card_t *card) { int r; unsigned long flags; - struct piv_private_data *priv; + piv_private_data_t *priv; SC_FUNC_CALLED(card->ctx,1); - priv = (struct piv_private_data *) calloc(1, sizeof(struct piv_private_data)); + priv = (piv_private_data_t *) calloc(1, sizeof(piv_private_data_t)); if (!priv) return SC_ERROR_OUT_OF_MEMORY; priv->aid_file = sc_file_new(); priv->selected_obj = -1; - priv->max_recv_size = card->max_recv_size; + priv->max_recv_size = 256; + //priv->max_recv_size = card->max_recv_size; priv->max_send_size = card->max_send_size; card->max_recv_size = 0xffff; /* must force pkcs15 read_binary in one call */ card->max_send_size = 0xffff; @@ -1339,6 +1507,9 @@ static int piv_init(sc_card_t *card) _sc_card_add_rsa_alg(card, 3072, flags, 0); /* optional */ card->caps |= SC_CARD_CAP_RNG; + + priv->cache = calloc(PIV_CACHE_SIZE, sizeof(piv_cache_item)); + priv->cacheLen = PIV_CACHE_SIZE; if (r > 0) r = 0; diff --git a/src/libopensc/compression.c b/src/libopensc/compression.c new file mode 100644 index 00000000..e18f991e --- /dev/null +++ b/src/libopensc/compression.c @@ -0,0 +1,176 @@ +/* + * compression.c: Generic wrapper for compression of data + * + * Copyright (C) 2006, Identity Alliance, Thomas Harning + * + * 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" +#ifdef HAVE_ZLIB_H +#include "compression.h" + +#include +#include +#include +#include "errors.h" + +static int zerr_to_opensc(int err) { + switch(err) { + case Z_OK: + case Z_STREAM_END: + return SC_SUCCESS; + case Z_UNKNOWN: + return SC_ERROR_UNKNOWN; + case Z_BUF_ERROR: + case Z_MEM_ERROR: + return SC_ERROR_MEMORY_FAILURE; + case Z_VERSION_ERROR: + case Z_DATA_ERROR: + case Z_STREAM_ERROR: + //case Z_NEED_DICT: + default: + return SC_ERROR_INTERNAL; + } +} +static int detect_method(const u8* in, size_t inLen) { + if(inLen > 2 && in[0] == 0x1f && in[1] == 0x8b) { /* GZIP */ + return COMPRESSION_GZIP; + } else if(inLen > 1 /*&& (in[0] & 0x10) == Z_DEFLATED*/) { + /* REALLY SIMPLE ZLIB TEST -- + * Check for the compression method to be set to 8... + * many things can spoof this, but this is ok for now + * */ + return COMPRESSION_ZLIB; + } else { + return COMPRESSION_UNKNOWN; + } +} + +static int do_decompress_gzip(u8* out, size_t* outLen, const u8* in, size_t inLen) { + /* Since uncompress does not offer a way to make it uncompress gzip... manually set it up */ + z_stream gz; + int err; + int window_size = 15 + 0x20; + memset(&gz, 0, sizeof(gz)); + + gz.next_in = (u8*)in; + gz.avail_in = inLen; + gz.next_out = out; + gz.avail_out = *outLen; + + err = inflateInit2(&gz, window_size); + if(err != Z_OK) return zerr_to_opensc(err); + err = inflate(&gz, Z_FINISH); + if(err != Z_STREAM_END) { + inflateEnd(&gz); + return zerr_to_opensc(err); + } + *outLen = gz.total_out; + + err = inflateEnd(&gz); + return zerr_to_opensc(err); +} + +int do_decompress(u8* out, size_t* outLen, const u8* in, size_t inLen, int method) { + if(method == COMPRESSION_AUTO) { + method = detect_method(in, inLen); + if(method == COMPRESSION_UNKNOWN) { + return SC_ERROR_UNKNOWN_DATA_RECEIVED; + } + } + switch(method) { + case COMPRESSION_ZLIB: + return zerr_to_opensc(uncompress(out, outLen, in, inLen)); + case COMPRESSION_GZIP: + return do_decompress_gzip(out, outLen, in, inLen); + default: + return SC_ERROR_INVALID_ARGUMENTS; + } +} + +static int do_decompress_zlib_alloc(u8** out, size_t* outLen, const u8* in, size_t inLen, int gzip) { + /* Since uncompress does not offer a way to make it uncompress gzip... manually set it up */ + z_stream gz; + int err; + int window_size = 15; + const int startSize = inLen < 1024 ? 2048 : inLen * 2; + const int blockSize = inLen < 1024 ? 512 : inLen / 2; + int bufferSize = startSize; + if(gzip) + window_size += 0x20; + memset(&gz, 0, sizeof(gz)); + + gz.next_in = (u8*)in; + gz.avail_in = inLen; + + err = inflateInit2(&gz, window_size); + if(err != Z_OK) return zerr_to_opensc(err); + + *outLen = 0; + + while(1) { + /* Setup buffer... */ + int num; + u8* buf = realloc(*out, bufferSize); + if(!buf) { + if(*out) + free(*out); + *out = NULL; + return Z_MEM_ERROR; + } + *out = buf; + gz.next_out = buf + *outLen; + gz.avail_out = bufferSize - *outLen; + + err = inflate(&gz, Z_FULL_FLUSH); + if(err != Z_STREAM_END && err != Z_OK) { + if(*out) + free(*out); + *out = NULL; + break; + } + num = bufferSize - *outLen - gz.avail_out; + if(num > 0) { + *outLen += num; + bufferSize += num + blockSize; + } + if(err == Z_STREAM_END) { + buf = realloc(buf, *outLen); /* Shrink it down, if it fails, just use old data */ + if(buf) { + *out = buf; + } + break; + } + } + inflateEnd(&gz); + return zerr_to_opensc(err); +} +int do_decompress_alloc(u8** out, size_t* outLen, const u8* in, size_t inLen, int method) { + if(method == COMPRESSION_AUTO) { + method = detect_method(in, inLen); + if(method == COMPRESSION_UNKNOWN) { + return SC_ERROR_UNKNOWN_DATA_RECEIVED; + } + } + switch(method) { + case COMPRESSION_ZLIB: + return do_decompress_zlib_alloc(out, outLen, in, inLen, 0); + case COMPRESSION_GZIP: + return do_decompress_zlib_alloc(out, outLen, in, inLen, 1); + default: + return SC_ERROR_INVALID_ARGUMENTS; + } +} +#endif /* HAVE_ZLIB_H */ diff --git a/src/libopensc/compression.h b/src/libopensc/compression.h new file mode 100644 index 00000000..4b95c990 --- /dev/null +++ b/src/libopensc/compression.h @@ -0,0 +1,35 @@ +/* + * compression.h: Generic wrapper for compression of data + * + * Copyright (C) 2006, Identity Alliance, Thomas Harning + * + * 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 + */ +#ifndef COMPRESSION_H +#define COMPRESSION_H + +#include "opensc.h" +#include "types.h" + +#define COMPRESSION_AUTO 0 +#define COMPRESSION_ZLIB 1 +#define COMPRESSION_GZIP 2 +#define COMPRESSION_UNKNOWN (-1) + +int do_decompress_alloc(u8** out, size_t* outLen, const u8* in, size_t inLen, int method); +int do_decompress(u8* out, size_t* outLen, const u8* in, size_t inLen, int method); + +#endif + diff --git a/src/libopensc/p15card-helper.c b/src/libopensc/p15card-helper.c new file mode 100644 index 00000000..b58f37bd --- /dev/null +++ b/src/libopensc/p15card-helper.c @@ -0,0 +1,342 @@ +/* + * p15card-helper.c: Utility library to assist in PKCS#15 emulation on Non-filesystem cards + * + * Copyright (C) 2006, Identity Alliance, Thomas Harning + * + * 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 "p15card-helper.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int initialize_objects(sc_pkcs15_card_t *p15card, p15data_items *items) { + sc_card_t* card = p15card->card; + const objdata* objects = items->objects; + int i, r; + if(!objects) return SC_SUCCESS; + for (i = 0; objects[i].label; i++) { + struct sc_pkcs15_data_info obj_info; + struct sc_pkcs15_object obj_obj; + + memset(&obj_info, 0, sizeof(obj_info)); + memset(&obj_obj, 0, sizeof(obj_obj)); + sc_pkcs15_format_id(objects[i].id, &obj_info.id); + sc_format_path(objects[i].path, &obj_info.path); + strncpy(obj_info.app_label, objects[i].label, SC_PKCS15_MAX_LABEL_SIZE - 1); + r = sc_format_oid(&obj_info.app_oid, objects[i].aoid); + if (r != SC_SUCCESS) + return r; + + strncpy(obj_obj.label, objects[i].label, SC_PKCS15_MAX_LABEL_SIZE - 1); + obj_obj.flags = objects[i].obj_flags; + + r = sc_pkcs15emu_object_add(p15card, SC_PKCS15_TYPE_DATA_OBJECT, + &obj_obj, &obj_info); + if (r < 0) + SC_FUNC_RETURN(card->ctx, 1, r); + } + return SC_SUCCESS; +} + +static const prdata* get_prkey_by_cert(p15data_items* items, const cdata* cert) { + const prdata* keys; + if(!items->private_keys) + return NULL; + for(keys = items->private_keys; keys->id; keys++) { + if(0 == strcmp(cert->id, keys->id)) + return keys; + } + return NULL; +} + +static int add_private_key(sc_pkcs15_card_t *p15card, const prdata* key, int usage, int modulus_length) { + 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(key->id, &prkey_info.id); + + prkey_info.native = 1; + prkey_info.key_reference = key->ref; + + if(!modulus_length) modulus_length = key->modulus_len; + prkey_info.modulus_length= modulus_length; + + sc_format_path(key->path, &prkey_info.path); + + strncpy(prkey_obj.label, key->label, SC_PKCS15_MAX_LABEL_SIZE - 1); + + prkey_obj.flags = key->obj_flags; + + /* Setup key usage */ + if(!usage) usage = key->usage; + prkey_info.usage = usage; + + if (key->auth_id) + sc_pkcs15_format_id(key->auth_id, &prkey_obj.auth_id); + + return sc_pkcs15emu_add_rsa_prkey(p15card, &prkey_obj, &prkey_info); +} + +static int add_public_key(sc_pkcs15_card_t *p15card, const pubdata *key, int usage, int modulus_length) { + struct sc_pkcs15_pubkey_info pubkey_info; + struct sc_pkcs15_object pubkey_obj; + + memset(&pubkey_info, 0, sizeof(pubkey_info)); + memset(&pubkey_obj, 0, sizeof(pubkey_obj)); + + sc_pkcs15_format_id(key->id, &pubkey_info.id); + if(!usage) usage = key->usage; + pubkey_info.usage = usage; + pubkey_info.native = 1; + pubkey_info.key_reference = key->ref; + if(!modulus_length) modulus_length = key->modulus_len; + pubkey_info.modulus_length= modulus_length; + /* we really don't know how many bits or module length, + * we will assume 1024 for now + */ + sc_format_path(key->path, &pubkey_info.path); + + strncpy(pubkey_obj.label, key->label, SC_PKCS15_MAX_LABEL_SIZE - 1); + + pubkey_obj.flags = key->obj_flags; + + if (key->auth_id) + sc_pkcs15_format_id(key->auth_id, &pubkey_obj.auth_id); + + return sc_pkcs15emu_add_rsa_pubkey(p15card, &pubkey_obj, &pubkey_info); +} + +//int default_cert_handle(sc_pkcs15_card_t *p15card, p15data_items* items, cdata* cert, u8* data, size_t length) { +CERT_HANDLE_FUNCTION(default_cert_handle) { + /* Certificate data exists, parse it */ + int r; + X509 *cert_data = NULL; + EVP_PKEY *pkey = NULL; + int certtype = 0; + int modulus_len = 0; + const prdata* key = get_prkey_by_cert(items, cert); + if(!key) { + sc_error(p15card->card->ctx, "Error: No key for this certificate"); + return SC_ERROR_INTERNAL; + } + + if(!d2i_X509(&cert_data, (const u8**)&data, length)) { + sc_error(p15card->card->ctx, "Error converting certificate"); + return SC_ERROR_INTERNAL; + } + + pkey = X509_get_pubkey(cert_data); + + if(pkey == NULL) { + sc_error(p15card->card->ctx, "Error: no public key associated with the certificate"); + r = SC_ERROR_INTERNAL; + goto err; + } + if(! EVP_PK_RSA & (certtype = X509_certificate_type(cert_data, pkey))) { + sc_error(p15card->card->ctx, "Error: certificate is not for an RSA key"); + r = SC_ERROR_INTERNAL; + goto err; + } + if(pkey->pkey.rsa->n == NULL) { + sc_error(p15card->card->ctx, "Error: no modulus associated with the certificate"); + r = SC_ERROR_INTERNAL; + goto err; + } + + modulus_len = 8 * BN_num_bytes(pkey->pkey.rsa->n); /* converting to bits */ + //printf("Key Size: %d bits\n\n", modulus_len); + //cached_cert->modulusLength = modulus_len; + + if(key->label) { + int usage = 0; + if (certtype & EVP_PKT_SIGN) { + usage |= SC_PKCS15_PRKEY_USAGE_SIGN; + usage |= SC_PKCS15_PRKEY_USAGE_NONREPUDIATION; + } + + if (certtype & EVP_PKT_ENC) { + usage |= SC_PKCS15_PRKEY_USAGE_ENCRYPT; + usage |= SC_PKCS15_PRKEY_USAGE_DECRYPT; + } + if (certtype & EVP_PKT_EXCH) { + usage |= SC_PKCS15_PRKEY_USAGE_WRAP; + usage |= SC_PKCS15_PRKEY_USAGE_UNWRAP; + } + r = add_private_key(p15card, key, usage, modulus_len); + if (r < 0) + goto err; + } + r = SC_SUCCESS; +err: + if(pkey) { + EVP_PKEY_free(pkey); + pkey = NULL; + } + if(cert_data) { + X509_free(cert_data); + cert_data = NULL; + } + SC_FUNC_RETURN(p15card->card->ctx, 1, r); +} + +int initialize_certificates(sc_pkcs15_card_t *p15card, p15data_items* items) { + /* set certs */ + sc_card_t* card = p15card->card; + const cdata* certs = items->certs; + int onFailResume = items->cert_continue; + int i, r; + if(!certs) return SC_SUCCESS; + 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)); + + r = SC_SUCCESS; + + 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; + + if(items->cert_load) { + u8* cert_buffer = NULL; + size_t cert_length = 0; + int should_free = 0; + if(SC_SUCCESS != (r = sc_select_file(card, &cert_info.path, NULL))) { + if(onFailResume) + continue; + else + break; + } + if(SC_SUCCESS != (r = items->cert_load(card, &cert_buffer, &cert_length, &should_free))) { + if(onFailResume) + continue; + else + break; + } + /* Handle cert */ + /* If no cert handler, add.. if cert handler succeeds.. add */ + if(!items->cert_handle || SC_SUCCESS == (r = items->cert_handle(p15card, items, &certs[i], cert_buffer, cert_length))) { + r = sc_pkcs15emu_add_x509_cert(p15card, &cert_obj, &cert_info); + } + if(should_free) + free(cert_buffer); + if(SC_SUCCESS != r) { + if(onFailResume) + continue; + else + break; + } + } else { /* Automatically add */ + if(SC_SUCCESS != (r = sc_pkcs15emu_add_x509_cert(p15card, &cert_obj, &cert_info))) { + if(onFailResume) + continue; + else + break; + } + } + } + return SC_SUCCESS; +} + +int initialize_pins(sc_pkcs15_card_t *p15card, p15data_items* items) { + /* set pins */ + int i,r; + const pindata* pins = items->pins; + if(!pins) return SC_SUCCESS; + 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; + + if(0 > (r = sc_pkcs15emu_add_pin_obj(p15card, &pin_obj, &pin_info))) + SC_FUNC_RETURN(p15card->card->ctx, 1, r); + } + return SC_SUCCESS; +} + +int initialize_private_keys(sc_pkcs15_card_t *p15card, p15data_items* items) { + const prdata *prkeys = items->private_keys; + int i, r; + if(!prkeys) return SC_SUCCESS; + /* set private keys */ + for (i = 0; prkeys[i].label; i++) { + r = add_private_key(p15card, &prkeys[i], 0, 0); + if (r < 0) + SC_FUNC_RETURN(p15card->card->ctx, 1, r); + } + return SC_SUCCESS; +} + +int initialize_public_keys(sc_pkcs15_card_t *p15card, p15data_items *items) { + const pubdata *keys = items->public_keys; + int i, r; + if(!keys) return SC_SUCCESS; + /* set public keys */ + for (i = 0; keys[i].label; i++) { + r = add_public_key(p15card, &keys[i], 0, 0); + if (r < 0) + SC_FUNC_RETURN(p15card->card->ctx, 1, r); + } + return SC_SUCCESS; + +} + +int initialize_all(sc_pkcs15_card_t *p15card, p15data_items* items) { + int r; + if(SC_SUCCESS != (r = initialize_objects(p15card, items))) + return r; + if(SC_SUCCESS != (r = initialize_certificates(p15card, items))) + return r; + if(SC_SUCCESS != (r = initialize_pins(p15card, items))) + return r; + + if(items->forced_private && (SC_SUCCESS != (r = initialize_private_keys(p15card, items)))) + return r; + if(items->forced_public && (SC_SUCCESS != (r = initialize_public_keys(p15card, items)))) + return r; + return SC_SUCCESS; +} diff --git a/src/libopensc/p15card-helper.h b/src/libopensc/p15card-helper.h new file mode 100644 index 00000000..433b6a72 --- /dev/null +++ b/src/libopensc/p15card-helper.h @@ -0,0 +1,137 @@ +/* + * p15card-helper.h: Utility library to assist in PKCS#15 emulation on Non-filesystem cards + * + * Copyright (C) 2006, Identity Alliance, Thomas Harning + * + * 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 + */ + +#ifndef P15CARD_HELPER_H +#define P15CARD_HELPER_H + +#include + + +#define USAGE_NONREP SC_PKCS15_PRKEY_USAGE_NONREPUDIATION | \ + SC_PKCS15_PRKEY_USAGE_SIGN +#define USAGE_DS SC_PKCS15_PRKEY_USAGE_SIGN +#define USAGE_CRYPTO SC_PKCS15_PRKEY_USAGE_ENCRYPT | \ + SC_PKCS15_PRKEY_USAGE_DECRYPT | \ + SC_PKCS15_PRKEY_USAGE_WRAP | \ + SC_PKCS15_PRKEY_USAGE_UNWRAP +#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 + + +typedef struct objdata_st { + const char *id; + const char *label; + const char *aoid; + int authority; + const char *path; + int obj_flags; +} objdata; + +typedef struct cdata_st { + const char *id; + const char *label; + int authority; + const char *path; + 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 pubdata_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; +} pubdata; + +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; + +typedef struct p15data_items p15data_items; + +typedef int (*cert_load_function)(sc_card_t *card, u8** data, size_t* length, int* shouldFree); +#define CERT_LOAD_FUNCTION(x) int x(sc_card_t *card, u8** data, size_t*length, int *shouldFree) +typedef int (*cert_handle_function)(sc_pkcs15_card_t *p15card, p15data_items* items, const cdata* cert, u8* data, size_t length); +#define CERT_HANDLE_FUNCTION(x) int x(sc_pkcs15_card_t *p15card, p15data_items* items, const cdata* cert, u8* data, size_t length) + +struct p15data_items { + const objdata* objects; + const cdata* certs; + const pindata* pins; + const pubdata* public_keys; + const prdata* private_keys; + + cert_load_function cert_load; + cert_handle_function cert_handle; + int cert_continue; /* Continue after cert failure */ + int forced_private; /* Should add all private keys w/o cert-management */ + int forced_public; /* Should add public keys (generally not needed..) */ +}; + +CERT_HANDLE_FUNCTION(default_cert_handle); + +int initialize_objects(sc_pkcs15_card_t *p15card, p15data_items* items); +int initialize_certificates(sc_pkcs15_card_t *p15card, p15data_items* items); +int initialize_pins(sc_pkcs15_card_t *p15card, p15data_items *items); +int initialize_private_keys(sc_pkcs15_card_t *p15card, p15data_items *items); +int initialize_public_keys(sc_pkcs15_card_t *p15card, p15data_items *items); +int initialize_all(sc_pkcs15_card_t *p15card, p15data_items *items); + +#endif + diff --git a/src/libopensc/pkcs15-piv.c b/src/libopensc/pkcs15-piv.c index 735da44b..cabdcb50 100644 --- a/src/libopensc/pkcs15-piv.c +++ b/src/libopensc/pkcs15-piv.c @@ -5,6 +5,9 @@ * Copyright (C) 2005, Douglas E. Engert * 2004, Nils Larsch * + * Copyright (C) 2006, Identity Alliance, + * Thomas Harning + * * 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 @@ -19,7 +22,6 @@ * 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 #include @@ -33,88 +35,12 @@ #include #include #include "strlcpy.h" +#include "p15card-helper.h" #define MANU_ID "piv_II " int sc_pkcs15emu_piv_init_ex(sc_pkcs15_card_t *, sc_pkcs15emu_opt_t *); - -typedef struct objdata_st { - const char *id; - const char *label; - const char *aoid; - int authority; - const char *path; - int obj_flags; -} objdata; - -typedef struct cdata_st { - const char *id; - const char *label; - int authority; - const char *path; - 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 pubdata_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; -} pubdata; - -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 int piv_detect_card(sc_pkcs15_card_t *p15card) { sc_card_t *card = p15card->card; @@ -126,98 +52,137 @@ static int piv_detect_card(sc_pkcs15_card_t *p15card) return SC_SUCCESS; } +const objdata objects[] = { + {"1", "Card Capability Container", + "2.16.840.1.101.3.7.1.219.0", 0, "DB00", 0}, + {"2", "Card Holder Unique Identifier", + "2.16.840.1.101.3.7.2.48.0", 0 , "3000", 0}, + {"3", "Card Holder Fingerprints", + "2.16.840.1.101.3.7.2.96.16", 0, "6010", SC_PKCS15_CO_FLAG_PRIVATE}, + {"4", "Printed Information", + "2.16.840.1.101.3.7.2.48.1", 0, "3001", SC_PKCS15_CO_FLAG_PRIVATE}, + {"5", "Card Holder Facial Image", + "2.16.840.1.101.3.7.2.96.48", 0, "6030", SC_PKCS15_CO_FLAG_PRIVATE}, + {"6", "Security Object", + "2.16.840.1.101.3.7.2.144.0", 0, "9000", 0}, + {NULL, NULL, NULL, 0, NULL, 0} +}; + +/* + * NIST 800-73-1 is proposing to lift the restriction on + * requering pin protected certs. Thus the default will be to + * not require this. But there are a number of test cards + * that do enforce it. Code later on will allow SC_PKCS15_CO_FLAG_PRIVATE + * to be set. + */ +const cdata certs[] = { + {"1", "Certificate for PIV Authentication", 0, "0101", 0}, + {"2", "Certificate for Digital Signature", 0, "0100", 0}, + {"3", "Certificate for Key Management", 0, "0102", 0}, +#if 0 /* Strange break */ + {"4", "Certificate for Card Authentication", 0, "0500", 0}, +#endif + {NULL, NULL, 0, NULL, 0} +}; + +const pindata pins[] = { + { "1", "PIV Card Holder pin", "", 0x80, + SC_PKCS15_PIN_TYPE_ASCII_NUMERIC, + 8, 4, 8, + SC_PKCS15_PIN_FLAG_NEEDS_PADDING | + SC_PKCS15_PIN_FLAG_LOCAL, + -1, 0xFF, + SC_PKCS15_CO_FLAG_PRIVATE }, + { "2", "PIV PUK", "", 0x81, + SC_PKCS15_PIN_TYPE_ASCII_NUMERIC, + 8, 4, 8, + SC_PKCS15_PIN_FLAG_NEEDS_PADDING | + SC_PKCS15_PIN_FLAG_LOCAL | SC_PKCS15_PIN_FLAG_SO_PIN | + SC_PKCS15_PIN_FLAG_UNBLOCKING_PIN, + -1, 0xFF, + SC_PKCS15_CO_FLAG_PRIVATE }, + /* there are some more key, but dont need for now */ + /* The admin 9b might fall in here */ + { NULL, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0} +}; + + +/* + * The size of the key or the algid is not really known + * but can be derived from the certificates. + * DEE need to fix - We will still refer to the "key files" as 06 even of not. + * 07 is 2048, 05 is 3072. + */ +const pubdata pubkeys[] = { + + { "1", "AUTH pubkey", 1024, USAGE_AUT, "9A06", + 0x9A, "1", 0}, + { "2", "SIGN pubkey", 1024, USAGE_AUT, "9C06", + 0x9C, "1", 0}, + { "3", "KEY MAN pubkey", 1024, USAGE_AUT, "9D06", + 0x9E, "1", 0}, + { "4", "ADMIN pubkey", 1024, USAGE_AUT, "9B06", + 0x9B, "1", 0}, + { NULL, NULL, 0, 0, NULL, 0, NULL, 0} + +}; + +const prdata prkeys[] = { + { "1", "AUTH key", 1024, USAGE_AUT, "", + 0x9A, "1", 0}, + { "2", "SIGN key", 1024, USAGE_AUT, "", + 0x9C, "1", 0}, + { "3", "KEY MAN key", 1024, USAGE_AUT, "", + 0x9E, "1", 0}, + { "4", "ADMIN key", 1024, USAGE_AUT, "", + 0x9B, "1", 0}, + { NULL, NULL, 0, 0, NULL, 0, NULL, 0} +}; + +/* TEMPORARY: Should hook into card-piv ... */ +static int piv_load_cached_cert(sc_card_t *card, u8** buf, size_t* count, int* should_free) { + /* File already selected.. just read... */ + int r; + u8* out = malloc(4096*2); + r = sc_read_binary(card, 0, out, 4096*2, 0); + if(r < 0) { + free(out); + *buf = NULL; + *count = 0; + return r; + } + *count = r; + *buf = out; + *should_free = 1; + return SC_SUCCESS; +} + +#define CHECK_CERTIFICATES 1 +static p15data_items items = { + objects, + certs, + pins, + NULL, + prkeys, +#ifdef CHECK_CERTIFICATES + piv_load_cached_cert, +#else + NULL, +#endif + default_cert_handle, + 1, +#ifdef CHECK_CERTIFICATES + 0, +#else + 1, +#endif + 0 +}; + static int sc_pkcs15emu_piv_init(sc_pkcs15_card_t *p15card) { - const objdata objects[] = { - {"1", "Card Capability Container", - "2.16.840.1.101.3.7.1.219.0", 0, "DB00", 0}, - {"2", "Card Holder Unique Identifier", - "2.16.840.1.101.3.7.2.48.0", 0 , "3000", 0}, - {"3", "Card Holder Fingerprint I", - "2.16.840.1.101.3.7.2.96.16", 0, "6010", SC_PKCS15_CO_FLAG_PRIVATE}, - {"4", "Card Holder Fingerprint II", - "2.16.840.1.101.3.7.2.96.17", 0, "6011", SC_PKCS15_CO_FLAG_PRIVATE}, - {"5", "Printed Information", - "2.16.840.1.101.3.7.2.48.1", 0, "3001", SC_PKCS15_CO_FLAG_PRIVATE}, - {"6", "Card Holder Facial Image", - "2.16.840.1.101.3.7.2.96.48", 0, "6030", SC_PKCS15_CO_FLAG_PRIVATE}, - {"7", "Security Object", - "2.16.840.1.101.3.7.2.144.0", 0, "9000", 0}, - {NULL, NULL, NULL, 0, NULL, 0} - }; - - /* - * NIST 800-73-1 is proposing to lift the restriction on - * requering pin protected certs. Thus the default will be to - * not require this. But there are a number of test cards - * that do enforce it. Code later on will allow SC_PKCS15_CO_FLAG_PRIVATE - * to be set. - */ - const cdata certs[] = { - {"1", "Certificate for PIV Authentication", 0, "0101", 0}, - {"2", "Certificate for Digital Signature", 0, "0100", 0}, - {"3", "Certificate for Key Management", 0, "0102", 0}, - {"4", "Certificate for Card Authentication", 0, "0500", 0}, - {NULL, NULL, 0, NULL, 0} - }; - - const pindata pins[] = { - { "1", "PIV Card Holder pin", "", 0x80, - SC_PKCS15_PIN_TYPE_ASCII_NUMERIC, - 8, 4, 8, - SC_PKCS15_PIN_FLAG_NEEDS_PADDING | - SC_PKCS15_PIN_FLAG_LOCAL, - -1, 0xFF, - SC_PKCS15_CO_FLAG_PRIVATE }, - { "2", "PIV PUK", "", 0x81, - SC_PKCS15_PIN_TYPE_ASCII_NUMERIC, - 8, 4, 8, - SC_PKCS15_PIN_FLAG_NEEDS_PADDING | - SC_PKCS15_PIN_FLAG_LOCAL | SC_PKCS15_PIN_FLAG_SO_PIN | - SC_PKCS15_PIN_FLAG_UNBLOCKING_PIN, - -1, 0xFF, - SC_PKCS15_CO_FLAG_PRIVATE }, - /* there are some more key, but dont need for now */ - /* The admin 9b might fall in here */ - { NULL, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0} - }; - - - /* - * The size of the key or the algid is not really known - * but can be derived from the certificates. - * DEE need to fix - We will still refer to the "key files" as 06 even of not. - * 07 is 2048, 05 is 3072. - */ - const pubdata pubkeys[] = { - - { "1", "AUTH pubkey", 1024, USAGE_AUT, "9A06", - 0x9A, "1", 0}, - { "2", "SIGN pubkey", 1024, USAGE_AUT, "9C06", - 0x9C, "1", 0}, - { "3", "KEY MAN pubkey", 1024, USAGE_AUT, "9D06", - 0x9D, "1", 0}, - { "4", "ADMIN pubkey", 1024, USAGE_AUT, "9B06", - 0x9B, "1", 0}, - { NULL, NULL, 0, 0, NULL, 0, NULL, 0} - - }; - - const prdata prkeys[] = { - { "1", "AUTH key", 1024, USAGE_AUT, "", - 0x9A, "1", 0}, - { "2", " SIGN key", 1024, USAGE_AUT, "", - 0x9B, "1", 0}, - { "3", "KEY MAN key", 1024, USAGE_AUT, "", - 0x9C, "1", 0}, - { "4", "ADMIN key", 1024, USAGE_AUT, "", - 0x9D, "1", 0}, - { NULL, NULL, 0, 0, NULL, 0, NULL, 0} - }; - - int r, i; + int r; sc_card_t *card = p15card->card; - int exposed_cert[4] = {1, 0, 0, 0}; SC_FUNC_CALLED(card->ctx, 1); @@ -238,161 +203,8 @@ static int sc_pkcs15emu_piv_init(sc_pkcs15_card_t *p15card) p15card->serial_number = strdup("9876543210"); sc_debug(card->ctx, "PIV-II adding objects..."); - - /* set other objects */ - for (i = 0; objects[i].label; i++) { - struct sc_pkcs15_data_info obj_info; - struct sc_pkcs15_object obj_obj; - - memset(&obj_info, 0, sizeof(obj_info)); - memset(&obj_obj, 0, sizeof(obj_obj)); - sc_pkcs15_format_id(objects[i].id, &obj_info.id); - sc_format_path(objects[i].path, &obj_info.path); - strlcpy(obj_info.app_label, objects[i].label, sizeof(obj_info.app_label)); - r = sc_format_oid(&obj_info.app_oid, objects[i].aoid); - if (r != SC_SUCCESS) - return r; - - strlcpy(obj_obj.label, objects[i].label, sizeof(obj_obj.label)); - obj_obj.flags = objects[i].obj_flags; - - r = sc_pkcs15emu_object_add(p15card, SC_PKCS15_TYPE_DATA_OBJECT, - &obj_obj, &obj_info); - if (r < 0) - SC_FUNC_RETURN(card->ctx, 1, r); - } - - /* set certs */ - for (i = 0; certs[i].label; i++) { - struct sc_pkcs15_cert_info cert_info; - struct sc_pkcs15_object cert_obj; - - if ((card->flags & 0x20) && (exposed_cert[i] == 0)) - continue; - - 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); - - strlcpy(cert_obj.label, certs[i].label, sizeof(cert_obj.label)); - cert_obj.flags = certs[i].obj_flags; - - /* Cards based on NIST 800-73 may enforce pin protected certs */ - /* But this is being dropped in 800-73-1 */ - if (card->flags & 0x10) { - cert_obj.flags |= SC_PKCS15_CO_FLAG_PRIVATE; - } - - r = sc_pkcs15emu_add_x509_cert(p15card, &cert_obj, &cert_info); - if (r < 0) - SC_FUNC_RETURN(card->ctx, 1, r); - } - - - /* set pins */ - - 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; - - strlcpy(pin_obj.label, pins[i].label, sizeof(pin_obj.label)); - pin_obj.flags = pins[i].obj_flags; - - r = sc_pkcs15emu_add_pin_obj(p15card, &pin_obj, &pin_info); - if (r < 0) - SC_FUNC_RETURN(card->ctx, 1, r); - } - - - - /* set public keys */ - /* We may only need this during initialzation when genkey - * gets the pubkey, but it can not be read from the card - * at a later time. The piv-tool can stach in file - */ - - for (i = 0; pubkeys[i].label; i++) { - struct sc_pkcs15_pubkey_info pubkey_info; - struct sc_pkcs15_object pubkey_obj; - - if ((card->flags & 0x20) && (exposed_cert[i] == 0)) - continue; - - memset(&pubkey_info, 0, sizeof(pubkey_info)); - memset(&pubkey_obj, 0, sizeof(pubkey_obj)); - - sc_pkcs15_format_id(pubkeys[i].id, &pubkey_info.id); - pubkey_info.usage = pubkeys[i].usage; - pubkey_info.native = 1; - pubkey_info.key_reference = pubkeys[i].ref; - pubkey_info.modulus_length= pubkeys[i].modulus_len; - /* we really don't know how many bits or module length, - * we will assume 1024 for now - */ - sc_format_path(pubkeys[i].path, &pubkey_info.path); - - strlcpy(pubkey_obj.label, pubkeys[i].label, sizeof(pubkey_obj.label)); - - pubkey_obj.flags = pubkeys[i].obj_flags; - - if (pubkeys[i].auth_id) - sc_pkcs15_format_id(pubkeys[i].auth_id, &pubkey_obj.auth_id); - - r = sc_pkcs15emu_add_rsa_pubkey(p15card, &pubkey_obj, &pubkey_info); - if (r < 0) - SC_FUNC_RETURN(card->ctx, 1, r); - } - - - /* set private keys */ - for (i = 0; prkeys[i].label; i++) { - struct sc_pkcs15_prkey_info prkey_info; - struct sc_pkcs15_object prkey_obj; - - if ((card->flags & 0x20) && (exposed_cert[i] == 0)) - continue; - - 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; - /* we really don't know how many bits or module length, - * we will assume 1024 for now - */ - sc_format_path(prkeys[i].path, &prkey_info.path); - - strlcpy(prkey_obj.label, prkeys[i].label, sizeof(prkey_obj.label)); - - 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) - SC_FUNC_RETURN(card->ctx, 1, r); - } + r = initialize_all(p15card, &items); SC_FUNC_RETURN(card->ctx, 1, SC_SUCCESS); } diff --git a/src/tools/piv-tool.c b/src/tools/piv-tool.c index 43b1fda5..8baff899 100644 --- a/src/tools/piv-tool.c +++ b/src/tools/piv-tool.c @@ -41,7 +41,7 @@ #include #include -const char *app_name = "opensc-tool"; +const char *app_name = "piv-tool"; static int opt_reader = -1, opt_wait = 0; @@ -60,6 +60,7 @@ const struct option options[] = { { "usepin", 0, 0, 'P' }, /* some beta cards want user pin for put_data */ { "genkey", 0, 0, 'G' }, { "cert", 0, 0, 'C' }, + { "compresscert", 0, 0, 'Z' }, { "req", 0, 0, 'R' }, { "out", 0, 0, 'o' }, { "in", 0, 0, 'o' }, @@ -77,7 +78,8 @@ const char *option_help[] = { "authenticate using default 3des key", "authenticate using user pin", "Generate key : 9A:06 on card, and output pubkey", - "Load the AUTH cert onto card from file ", + "Load a cert where is 9A,9B,9C or 9D", + "Load a cert that has been gziped ", "Generate a cert req", "Output file for cert or key or req", "Inout file for cert", @@ -94,7 +96,8 @@ BIO * bp = NULL; RSA * newkey = NULL; -static int load_cert(const char * cert_id, const char * cert_file) +static int load_cert(const char * cert_id, const char * cert_file, + int compress) { X509 * cert = NULL; FILE *fp; @@ -106,25 +109,39 @@ static int load_cert(const char * cert_id, const char * cert_file) size_t derlen; int r; - if((fp=fopen(cert_file, "r"))==NULL){ printf("Cannot open cert file, %s %s\n", cert_file, strerror(errno)); return -1; } - cert = PEM_read_X509(fp, &cert, NULL, NULL); + if (compress) { /* file is gziped already */ + struct stat stat_buf; + + stat(cert_file, &stat_buf); + derlen = stat_buf.st_size; + der = malloc(derlen); + if (der == NULL) { + printf("file %s is too big, %d\n", cert_file, derlen); + return-1 ; + } + if (1 != fread(der, derlen, 1, fp)) { + printf("unable to read file %s\n",cert_file); + return -1; + } + } else { + cert = PEM_read_X509(fp, &cert, NULL, NULL); + if(cert == NULL){ + printf("file %s does not conatin PEM-encoded certificate\n", + cert_file); + return -1 ; + } + + derlen = i2d_X509(cert, NULL); + der = (u8 *) malloc(derlen); + p = der; + i2d_X509(cert, &p); + } fclose(fp); - if(cert == NULL){ - printf("file %s does not conatin PEM-encoded certificate\n", - cert_file); - return-1 ; - } - - derlen = i2d_X509(cert, NULL); - der = (u8 *) malloc(derlen); - p = der; - i2d_X509(cert, &p); - sc_hex_to_bin(cert_id, buf,&buflen); switch (buf[0]) { @@ -142,7 +159,8 @@ static int load_cert(const char * cert_id, const char * cert_file) fprintf(stderr, "select file failed\n"); return -1; } - r = sc_write_binary(card, 0, der, derlen, 0); + /* we pass compress as the flag to card-piv.c write_binary */ + r = sc_write_binary(card, 0, der, derlen, compress); return r; @@ -340,6 +358,7 @@ int main(int argc, char * const argv[]) int do_admin_mode = 0; int do_gen_key = 0; int do_load_cert = 0; + int compress_cert = 0; int do_req = 0; int do_print_serial = 0; int do_print_name = 0; @@ -355,7 +374,7 @@ int main(int argc, char * const argv[]) setbuf(stdout, NULL); while (1) { - c = getopt_long(argc, argv, "nA:G:C:Ri:o:fvs:c:w", options, &long_optind); + c = getopt_long(argc, argv, "nA:G:Z:C:Ri:o:fvs:c:w", options, &long_optind); if (c == -1) break; if (c == '?') @@ -384,6 +403,8 @@ int main(int argc, char * const argv[]) key_info = optarg; action_count++; break; + case 'Z': + compress_cert = 1; case 'C': do_load_cert = 1; cert_id = optarg; @@ -469,7 +490,7 @@ int main(int argc, char * const argv[]) action_count--; } if (do_load_cert) { - if ((err = load_cert(cert_id, in_file))) + if ((err = load_cert(cert_id, in_file, compress_cert))) goto end; action_count--; } diff --git a/win32/Make.rules.mak b/win32/Make.rules.mak index 8374fbcd..a474d1a1 100644 --- a/win32/Make.rules.mak +++ b/win32/Make.rules.mak @@ -21,7 +21,19 @@ OPENSSL_LIB = C:\openssl\out32dll\libeay32.lib PROGRAMS_OPENSSL = pkcs15-init.exe cryptoflex-tool.exe netkey-tool.exe !ENDIF -COPTS = /D_CRT_SECURE_NO_DEPRECATE /Zi /MD /nologo /DHAVE_CONFIG_H /I$(TOPDIR)\src\include /I$(TOPDIR)\src\include\opensc /I$(TOPDIR)\src\common $(OPENSSL_INCL_DIR) $(LIBLTDL_INCL) /D_WIN32_WINNT=0x0400 $(OPENSSL_DEF) +# If you want support for zlib (Used for PIV, infocamere and actalis: +# - Download zlib and build +# - uncomment the line starting with ZLIB_DEF +# - set the ZLIB_INCL_DIR below to the zlib include lib proceeded by "/I" +# - set the ZLIB_LIB below to your zlib lib file +#ZLIB_DEF = /DHAVE_ZLIB_H +!IF "$(ZLIB_DEF)" == "/DHAVE_ZLIB_H" +ZLIB_INCL_DIR = /IC:\ZLIB\INCLUDE +ZLIB_LIB = C:\ZLIB\LIB\zlib.lib +!ENDIF + + +COPTS = /D_CRT_SECURE_NO_DEPRECATE /Zi /MD /nologo /DHAVE_CONFIG_H /I$(TOPDIR)\src\include /I$(TOPDIR)\src\include\opensc /I$(TOPDIR)\src\common $(OPENSSL_INCL_DIR) $(ZLIB_INCL_DIR) $(LIBLTDL_INCL) /D_WIN32_WINNT=0x0400 $(OPENSSL_DEF) $(ZLIB_DEF) LINKFLAGS = /DEBUG /NOLOGO /INCREMENTAL:NO /MACHINE:IX86