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
This commit is contained in:
aj 2007-03-10 10:46:32 +00:00
parent 7d00cf350f
commit c6954a9c33
10 changed files with 1144 additions and 436 deletions

View File

@ -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

View File

@ -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

View File

@ -4,6 +4,7 @@
*
* Copyright (C) 2001, 2002 Juha Yrjölä <juha.yrjola@iki.fi>
* Copyright (C) 2005, Douglas E. Engert <deengert@anl.gov>
* Copyright (C) 2006, Identity Alliance, Thomas Harning <thomas.harning@identityalliance.com>
*
* 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 <openssl/rsa.h>
#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;

176
src/libopensc/compression.c Normal file
View File

@ -0,0 +1,176 @@
/*
* compression.c: Generic wrapper for compression of data
*
* Copyright (C) 2006, Identity Alliance, Thomas Harning <thomas.harning@identityalliance.com>
*
* 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 <zlib.h>
#include <memory.h>
#include <malloc.h>
#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 */

View File

@ -0,0 +1,35 @@
/*
* compression.h: Generic wrapper for compression of data
*
* Copyright (C) 2006, Identity Alliance, Thomas Harning <thomas.harning@identityalliance.com>
*
* 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

View File

@ -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 <thomas.harning@identityalliance.com>
*
* 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 <opensc/opensc.h>
#include <opensc/types.h>
#include <opensc/log.h>
#include <opensc/pkcs15.h>
#include <memory.h>
#include <malloc.h>
#include <openssl/bio.h>
#include <openssl/rsa.h>
#include <openssl/x509.h>
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;
}

View File

@ -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 <thomas.harning@identityalliance.com>
*
* 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 <opensc/pkcs15.h>
#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

View File

@ -5,6 +5,9 @@
* Copyright (C) 2005, Douglas E. Engert <deengert@anl.gov>
* 2004, Nils Larsch <larsch@trustcenter.de>
*
* Copyright (C) 2006, Identity Alliance,
* Thomas Harning <thomas.harning@identityalliance.com>
*
* 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 <stdlib.h>
#include <string.h>
@ -33,88 +35,12 @@
#include <openssl/rsa.h>
#include <openssl/pem.h>
#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);
}

View File

@ -41,7 +41,7 @@
#include <openssl/pem.h>
#include <openssl/err.h>
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 <ref>:<alg> 9A:06 on card, and output pubkey",
"Load the AUTH cert onto card from file <arg>",
"Load a cert <ref> where <ref> is 9A,9B,9C or 9D",
"Load a cert that has been gziped <ref>",
"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--;
}

View File

@ -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