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:
parent
7d00cf350f
commit
c6954a9c33
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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,7 +556,7 @@ 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];
|
||||
@ -600,6 +654,97 @@ 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,39 +856,20 @@ static int piv_put_data(sc_card_t *card, unsigned int tag,
|
||||
SC_FUNC_RETURN(card->ctx, 1, 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
|
||||
*/
|
||||
|
||||
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;
|
||||
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_FUNC_CALLED(card->ctx,1);
|
||||
|
||||
if (priv->selected_obj < 0)
|
||||
SC_FUNC_RETURN(card->ctx, 1, SC_ERROR_INTERNAL);
|
||||
if (idx != 0)
|
||||
SC_FUNC_RETURN(card->ctx, 1, SC_ERROR_NO_CARD_SUPPORT);
|
||||
|
||||
switch (piv_objects[priv->selected_obj].enumtag) {
|
||||
case PIV_OBJ_X509_PIV_AUTH:
|
||||
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);
|
||||
+ put_tag_and_len(0x71, 1, NULL)
|
||||
+ put_tag_and_len(0xFE, 0, NULL);
|
||||
|
||||
sbuflen = put_tag_and_len(0x53, taglen, NULL);
|
||||
|
||||
@ -766,23 +883,48 @@ static int piv_write_binary(sc_card_t *card, unsigned int idx,
|
||||
memcpy(p, buf, count);
|
||||
p += count;
|
||||
put_tag_and_len(0x71, 1, &p);
|
||||
*p++ = 0x00; /* certinfo, i.e. not gziped */
|
||||
*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);
|
||||
break;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (r == 0)
|
||||
r = piv_put_data(card, priv->selected_obj, sbuf, sbuflen);
|
||||
if (sbuf)
|
||||
free(sbuf);
|
||||
|
||||
SC_FUNC_RETURN(card->ctx, 1, r);
|
||||
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)
|
||||
{
|
||||
piv_private_data_t * priv = PIV_DATA(card);
|
||||
/* TODO: Add cache hooks */
|
||||
SC_FUNC_CALLED(card->ctx,1);
|
||||
|
||||
if (priv->selected_obj < 0)
|
||||
SC_FUNC_RETURN(card->ctx, 1, SC_ERROR_INTERNAL);
|
||||
if (idx != 0)
|
||||
SC_FUNC_RETURN(card->ctx, 1, SC_ERROR_NO_CARD_SUPPORT);
|
||||
|
||||
switch (piv_objects[priv->selected_obj].enumtag) {
|
||||
case PIV_OBJ_X509_PIV_AUTH:
|
||||
case PIV_OBJ_X509_DS:
|
||||
case PIV_OBJ_X509_KM:
|
||||
case PIV_OBJ_X509_CARD_AUTH:
|
||||
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);
|
||||
SC_FUNC_RETURN(card->ctx, 1, SC_ERROR_NOT_SUPPORTED);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@ -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,6 +1398,12 @@ 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) {
|
||||
@ -1267,7 +1416,12 @@ static int piv_select_file(sc_card_t *card, const sc_path_t *in_path,
|
||||
file->type = SC_FILE_TYPE_DF;
|
||||
file->shareable = 0;
|
||||
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;
|
||||
@ -1340,6 +1508,9 @@ static int piv_init(sc_card_t *card)
|
||||
|
||||
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;
|
||||
SC_FUNC_RETURN(card->ctx, 1, r);
|
||||
|
176
src/libopensc/compression.c
Normal file
176
src/libopensc/compression.c
Normal 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 */
|
35
src/libopensc/compression.h
Normal file
35
src/libopensc/compression.h
Normal 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
|
||||
|
342
src/libopensc/p15card-helper.c
Normal file
342
src/libopensc/p15card-helper.c
Normal 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;
|
||||
}
|
137
src/libopensc/p15card-helper.h
Normal file
137
src/libopensc/p15card-helper.h
Normal 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
|
||||
|
@ -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,42 +52,40 @@ static int piv_detect_card(sc_pkcs15_card_t *p15card)
|
||||
return SC_SUCCESS;
|
||||
}
|
||||
|
||||
static int sc_pkcs15emu_piv_init(sc_pkcs15_card_t *p15card)
|
||||
{
|
||||
const objdata objects[] = {
|
||||
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",
|
||||
{"3", "Card Holder Fingerprints",
|
||||
"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",
|
||||
{"4", "Printed Information",
|
||||
"2.16.840.1.101.3.7.2.48.1", 0, "3001", SC_PKCS15_CO_FLAG_PRIVATE},
|
||||
{"6", "Card Holder Facial Image",
|
||||
{"5", "Card Holder Facial Image",
|
||||
"2.16.840.1.101.3.7.2.96.48", 0, "6030", SC_PKCS15_CO_FLAG_PRIVATE},
|
||||
{"7", "Security Object",
|
||||
{"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[] = {
|
||||
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[] = {
|
||||
const pindata pins[] = {
|
||||
{ "1", "PIV Card Holder pin", "", 0x80,
|
||||
SC_PKCS15_PIN_TYPE_ASCII_NUMERIC,
|
||||
8, 4, 8,
|
||||
@ -180,44 +104,85 @@ static int sc_pkcs15emu_piv_init(sc_pkcs15_card_t *p15card)
|
||||
/* 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[] = {
|
||||
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},
|
||||
0x9E, "1", 0},
|
||||
{ "4", "ADMIN pubkey", 1024, USAGE_AUT, "9B06",
|
||||
0x9B, "1", 0},
|
||||
{ NULL, NULL, 0, 0, NULL, 0, NULL, 0}
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
const prdata prkeys[] = {
|
||||
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, "",
|
||||
{ "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, "",
|
||||
0x9D, "1", 0},
|
||||
0x9B, "1", 0},
|
||||
{ NULL, NULL, 0, 0, NULL, 0, NULL, 0}
|
||||
};
|
||||
};
|
||||
|
||||
int r, i;
|
||||
/* 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)
|
||||
{
|
||||
int r;
|
||||
sc_card_t *card = p15card->card;
|
||||
int exposed_cert[4] = {1, 0, 0, 0};
|
||||
|
||||
SC_FUNC_CALLED(card->ctx, 1);
|
||||
|
||||
@ -239,160 +204,7 @@ static int sc_pkcs15emu_piv_init(sc_pkcs15_card_t *p15card)
|
||||
|
||||
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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
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);
|
||||
fclose(fp);
|
||||
if(cert == NULL){
|
||||
printf("file %s does not conatin PEM-encoded certificate\n",
|
||||
cert_file);
|
||||
return-1 ;
|
||||
return -1 ;
|
||||
}
|
||||
|
||||
derlen = i2d_X509(cert, NULL);
|
||||
der = (u8 *) malloc(derlen);
|
||||
p = der;
|
||||
i2d_X509(cert, &p);
|
||||
|
||||
}
|
||||
fclose(fp);
|
||||
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--;
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user