2006-02-14 22:09:10 +00:00
|
|
|
/*
|
|
|
|
* partial PKCS15 emulation for PIV-II cards
|
|
|
|
* only minimal use of the authentication cert and key
|
|
|
|
*
|
Douglas E. Engert: major update for the PIV smartcard.
The major issue is with getting the length of an object or the cert
contained in an object. The PIV card does not have a directory on the card,
So the previous version tried to put off as long as possible the reading
of objects for performance so as to avoid having to read objects that would
not be used. The first standard, NIST 800-73, set maximum sizes for objects.
800-73-2 removed this for certificates.
A certificate object can contain a certificate which might be compressed.
The only way to get the length of the compressed certificate is to decompress
it. Thus the decompressed certificate could be larger then the container object,
so even if the PIV card had a directory, one would still need to decompress
the certificate to find its length.
OpenSC sc_read_binary will use the length obtained by using
sc_select_file(...,&file_out), and thus the lengths must be determined
in sc_select_file.
Change are to card-piv.c and pkcs15-piv.c and include:
* The old cache code which was not working was removed.
* New cache code was added which caches all object read from the card
* If an object has a cert, the cert is decompressed and also cached.
* As part of reading an object the first 8 bytes are read
and this is then used to allocate a large buffer to read in the
object.
* If pkcs15 or pkcs11 asks about a certificate, the cert object
will be read, and the cert decompressed, to get the actual length.
* If piv_select_file is called with the file_out != NULL the object
will be read to get the length If called with NULL it will not be read.
* The enumeration of the objects now starts with 0.
* sc_ctx_suppress_errors_on and off are used to avoid file not found
messages which are are a by product of not having a directory.
* "Unsigned Card Holder Unique Identifier" object in card-piv and pkcs15-piv.c
had conflicting paths, as NIST 800-72-1 had two tables with different
paths. The enumtag for it in card-piv.c was also wrong.
git-svn-id: https://www.opensc-project.org/svnp/opensc/trunk@3710 c6295689-39f2-0310-b995-f0e70906c6a9
2009-07-22 10:09:21 +00:00
|
|
|
* Copyright (C) 2005,2006,2007,2008,2009 Douglas E. Engert <deengert@anl.gov>
|
2006-02-14 22:09:10 +00:00
|
|
|
* 2004, Nils Larsch <larsch@trustcenter.de>
|
2007-03-10 10:46:32 +00:00
|
|
|
* Copyright (C) 2006, Identity Alliance,
|
|
|
|
* Thomas Harning <thomas.harning@identityalliance.com>
|
2007-06-21 07:07:49 +00:00
|
|
|
* Copyright (C) 2007, EMC, Russell Larner <rlarner@rsa.com>
|
2007-03-10 10:46:32 +00:00
|
|
|
*
|
2006-02-14 22:09:10 +00:00
|
|
|
* 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
|
|
|
|
*/
|
|
|
|
|
2008-03-06 16:06:59 +00:00
|
|
|
#include "internal.h"
|
2006-02-14 22:09:10 +00:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <ctype.h>
|
2008-04-01 12:35:08 +00:00
|
|
|
#include "pkcs15.h"
|
|
|
|
#include "cardctl.h"
|
2006-02-14 22:09:10 +00:00
|
|
|
|
|
|
|
#define MANU_ID "piv_II "
|
|
|
|
|
|
|
|
int sc_pkcs15emu_piv_init_ex(sc_pkcs15_card_t *, sc_pkcs15emu_opt_t *);
|
|
|
|
|
2007-06-21 07:07:49 +00:00
|
|
|
|
|
|
|
typedef struct objdata_st {
|
|
|
|
const char *id;
|
|
|
|
const char *label;
|
|
|
|
const char *aoid;
|
|
|
|
const char *auth_id;
|
|
|
|
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;
|
|
|
|
int found;
|
|
|
|
} 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;
|
|
|
|
int found;
|
|
|
|
} 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;
|
|
|
|
|
|
|
|
|
2006-02-14 22:09:10 +00:00
|
|
|
static int piv_detect_card(sc_pkcs15_card_t *p15card)
|
|
|
|
{
|
|
|
|
sc_card_t *card = p15card->card;
|
|
|
|
|
|
|
|
SC_FUNC_CALLED(card->ctx, 1);
|
|
|
|
if (card->type < SC_CARD_TYPE_PIV_II_GENERIC
|
|
|
|
|| card->type >= SC_CARD_TYPE_PIV_II_GENERIC+1000)
|
|
|
|
return SC_ERROR_INVALID_CARD;
|
|
|
|
return SC_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2007-06-21 07:07:49 +00:00
|
|
|
static int sc_pkcs15emu_piv_init(sc_pkcs15_card_t *p15card)
|
|
|
|
{
|
|
|
|
|
2007-11-09 08:35:23 +00:00
|
|
|
/* The cert objects will return all the data */
|
2007-03-10 10:46:32 +00:00
|
|
|
const objdata objects[] = {
|
|
|
|
{"1", "Card Capability Container",
|
2007-06-21 11:07:00 +00:00
|
|
|
"2.16.840.1.101.3.7.1.219.0", NULL, "DB00", 0},
|
2007-03-10 10:46:32 +00:00
|
|
|
{"2", "Card Holder Unique Identifier",
|
2007-06-21 11:07:00 +00:00
|
|
|
"2.16.840.1.101.3.7.2.48.0", NULL, "3000", 0},
|
2007-11-09 08:35:23 +00:00
|
|
|
{"3", "Unsigned Card Holder Unique Identifier",
|
Douglas E. Engert: major update for the PIV smartcard.
The major issue is with getting the length of an object or the cert
contained in an object. The PIV card does not have a directory on the card,
So the previous version tried to put off as long as possible the reading
of objects for performance so as to avoid having to read objects that would
not be used. The first standard, NIST 800-73, set maximum sizes for objects.
800-73-2 removed this for certificates.
A certificate object can contain a certificate which might be compressed.
The only way to get the length of the compressed certificate is to decompress
it. Thus the decompressed certificate could be larger then the container object,
so even if the PIV card had a directory, one would still need to decompress
the certificate to find its length.
OpenSC sc_read_binary will use the length obtained by using
sc_select_file(...,&file_out), and thus the lengths must be determined
in sc_select_file.
Change are to card-piv.c and pkcs15-piv.c and include:
* The old cache code which was not working was removed.
* New cache code was added which caches all object read from the card
* If an object has a cert, the cert is decompressed and also cached.
* As part of reading an object the first 8 bytes are read
and this is then used to allocate a large buffer to read in the
object.
* If pkcs15 or pkcs11 asks about a certificate, the cert object
will be read, and the cert decompressed, to get the actual length.
* If piv_select_file is called with the file_out != NULL the object
will be read to get the length If called with NULL it will not be read.
* The enumeration of the objects now starts with 0.
* sc_ctx_suppress_errors_on and off are used to avoid file not found
messages which are are a by product of not having a directory.
* "Unsigned Card Holder Unique Identifier" object in card-piv and pkcs15-piv.c
had conflicting paths, as NIST 800-72-1 had two tables with different
paths. The enumtag for it in card-piv.c was also wrong.
git-svn-id: https://www.opensc-project.org/svnp/opensc/trunk@3710 c6295689-39f2-0310-b995-f0e70906c6a9
2009-07-22 10:09:21 +00:00
|
|
|
"2.16.840.1.101.3.7.2.48.2", NULL, "3010", 0},
|
2007-11-09 08:35:23 +00:00
|
|
|
{"4", "X.509 Certificate for PIV Authentication",
|
|
|
|
"2.16.840.1.101.3.7.2.1.1", NULL, "0101", 0},
|
|
|
|
{"5", "Card Holder Fingerprints",
|
2007-06-21 07:07:49 +00:00
|
|
|
"2.16.840.1.101.3.7.2.96.16", "1", "6010", SC_PKCS15_CO_FLAG_PRIVATE},
|
2007-11-09 08:35:23 +00:00
|
|
|
{"6", "Printed Information",
|
2007-06-21 07:07:49 +00:00
|
|
|
"2.16.840.1.101.3.7.2.48.1", "1", "3001", SC_PKCS15_CO_FLAG_PRIVATE},
|
2007-11-09 08:35:23 +00:00
|
|
|
{"7", "Card Holder Facial Image",
|
2007-06-21 07:07:49 +00:00
|
|
|
"2.16.840.1.101.3.7.2.96.48", "1", "6030", SC_PKCS15_CO_FLAG_PRIVATE},
|
2007-11-09 08:35:23 +00:00
|
|
|
{"8", "X.509 Certificate for Digital Signature",
|
|
|
|
"2.16.840.1.101.3.7.2.1.0", NULL, "0100", 0},
|
|
|
|
{"9", "X.509 Certificate for Key Management",
|
|
|
|
"2.16.840.1.101.3.7.2.1.2", NULL, "0102", 0},
|
|
|
|
{"10","X.509 Certificate for Card Authentication",
|
|
|
|
"2.16.840.1.101.3.7.2.5.0", NULL, "0500", 0},
|
|
|
|
{"11", "Security Object",
|
2007-06-21 11:07:00 +00:00
|
|
|
"2.16.840.1.101.3.7.2.144.0", NULL, "9000", 0},
|
2007-06-21 12:01:39 +00:00
|
|
|
{NULL, NULL, NULL, NULL, NULL, 0}
|
2007-03-10 10:46:32 +00:00
|
|
|
};
|
2007-06-21 07:07:49 +00:00
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*/
|
2007-11-09 08:35:23 +00:00
|
|
|
/* certs will be pulled out from the cert objects */
|
2007-06-21 07:07:49 +00:00
|
|
|
cdata certs[] = {
|
2007-11-09 08:35:23 +00:00
|
|
|
{"1", "Certificate for PIV Authentication", 0, "0101cece", 0, 0},
|
|
|
|
|
|
|
|
{"2", "Certificate for Digital Signature", 0, "0100cece", 0, 0},
|
|
|
|
{"3", "Certificate for Key Management", 0, "0102cece", 0, 0},
|
|
|
|
{"4", "Certificate for Card Authentication", 0, "0500cece", 0, 0},
|
2007-06-21 07:07:49 +00:00
|
|
|
{NULL, NULL, 0, NULL, 0, 0}
|
|
|
|
};
|
2007-03-10 10:46:32 +00:00
|
|
|
|
2007-06-21 07:07:49 +00:00
|
|
|
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}
|
|
|
|
};
|
2006-02-14 22:09:10 +00:00
|
|
|
|
|
|
|
|
2007-06-21 07:07:49 +00:00
|
|
|
/*
|
|
|
|
* The size of the key or the algid is not really known
|
|
|
|
* but can be derived from the certificates.
|
|
|
|
* the cert, pubkey and privkey are a set.
|
|
|
|
* Key usages bits taken from pkcs15v1_1 Table 2
|
|
|
|
*/
|
|
|
|
pubdata pubkeys[] = {
|
2007-03-10 10:46:32 +00:00
|
|
|
|
2007-06-21 07:07:49 +00:00
|
|
|
{ "1", "PIV AUTH pubkey", 0000,
|
|
|
|
SC_PKCS15_PRKEY_USAGE_ENCRYPT |
|
|
|
|
SC_PKCS15_PRKEY_USAGE_WRAP |
|
|
|
|
SC_PKCS15_PRKEY_USAGE_VERIFY |
|
|
|
|
SC_PKCS15_PRKEY_USAGE_VERIFYRECOVER,
|
2007-07-15 15:29:40 +00:00
|
|
|
"9A06", 0x9A, "1", 0, 0},
|
2007-06-21 07:07:49 +00:00
|
|
|
{ "2", "SIGN pubkey", 0000,
|
|
|
|
SC_PKCS15_PRKEY_USAGE_ENCRYPT |
|
|
|
|
SC_PKCS15_PRKEY_USAGE_VERIFY |
|
|
|
|
SC_PKCS15_PRKEY_USAGE_VERIFYRECOVER |
|
|
|
|
SC_PKCS15_PRKEY_USAGE_NONREPUDIATION,
|
2007-07-15 15:29:40 +00:00
|
|
|
"9C06", 0x9C, "1", 0, 0},
|
2007-06-21 07:07:49 +00:00
|
|
|
{ "3", "KEY MAN pubkey", 0000,
|
|
|
|
SC_PKCS15_PRKEY_USAGE_WRAP,
|
2007-07-15 15:29:40 +00:00
|
|
|
"9D06", 0x9D, "1", 0, 0},
|
2007-06-21 07:07:49 +00:00
|
|
|
{ "4", "CARD AUTH pubkey", 0000,
|
|
|
|
SC_PKCS15_PRKEY_USAGE_VERIFY |
|
|
|
|
SC_PKCS15_PRKEY_USAGE_VERIFYRECOVER,
|
|
|
|
"9E06", 0x9E, "0", 0, 0}, /* no pin, and avail in contactless */
|
|
|
|
{ NULL, NULL, 0, 0, NULL, 0, NULL, 0, 0}
|
|
|
|
|
|
|
|
};
|
2006-02-14 22:09:10 +00:00
|
|
|
|
2007-06-21 07:07:49 +00:00
|
|
|
prdata prkeys[] = {
|
|
|
|
{ "1", "PIV AUTH key", 0000,
|
|
|
|
SC_PKCS15_PRKEY_USAGE_DECRYPT |
|
|
|
|
SC_PKCS15_PRKEY_USAGE_UNWRAP |
|
|
|
|
SC_PKCS15_PRKEY_USAGE_SIGN |
|
|
|
|
SC_PKCS15_PRKEY_USAGE_SIGNRECOVER,
|
2007-07-15 15:29:40 +00:00
|
|
|
"", 0x9A, "1", 0},
|
2007-06-21 07:07:49 +00:00
|
|
|
{ "2", "SIGN key", 0000,
|
|
|
|
SC_PKCS15_PRKEY_USAGE_DECRYPT |
|
|
|
|
SC_PKCS15_PRKEY_USAGE_SIGN |
|
|
|
|
SC_PKCS15_PRKEY_USAGE_SIGNRECOVER |
|
|
|
|
SC_PKCS15_PRKEY_USAGE_NONREPUDIATION,
|
2007-07-15 15:29:40 +00:00
|
|
|
"", 0x9C, "1", 0},
|
2007-06-21 07:07:49 +00:00
|
|
|
{ "3", "KEY MAN key", 0000,
|
|
|
|
SC_PKCS15_PRKEY_USAGE_UNWRAP,
|
2007-07-15 15:29:40 +00:00
|
|
|
"", 0x9D, "1", 0},
|
2007-06-21 07:07:49 +00:00
|
|
|
{ "4", "CARD AUTH key", 0000,
|
|
|
|
SC_PKCS15_PRKEY_USAGE_SIGN |
|
|
|
|
SC_PKCS15_PRKEY_USAGE_SIGNRECOVER,
|
2007-06-21 11:07:00 +00:00
|
|
|
"", 0x9E, NULL, 0}, /* no PIN needed, works with wireless */
|
2007-06-21 07:07:49 +00:00
|
|
|
{ NULL, NULL, 0, 0, NULL, 0, NULL, 0}
|
|
|
|
};
|
2006-02-14 22:09:10 +00:00
|
|
|
|
2007-06-21 07:07:49 +00:00
|
|
|
int r, i;
|
2006-02-14 22:09:10 +00:00
|
|
|
sc_card_t *card = p15card->card;
|
Douglas E. Engert: major update for the PIV smartcard.
The major issue is with getting the length of an object or the cert
contained in an object. The PIV card does not have a directory on the card,
So the previous version tried to put off as long as possible the reading
of objects for performance so as to avoid having to read objects that would
not be used. The first standard, NIST 800-73, set maximum sizes for objects.
800-73-2 removed this for certificates.
A certificate object can contain a certificate which might be compressed.
The only way to get the length of the compressed certificate is to decompress
it. Thus the decompressed certificate could be larger then the container object,
so even if the PIV card had a directory, one would still need to decompress
the certificate to find its length.
OpenSC sc_read_binary will use the length obtained by using
sc_select_file(...,&file_out), and thus the lengths must be determined
in sc_select_file.
Change are to card-piv.c and pkcs15-piv.c and include:
* The old cache code which was not working was removed.
* New cache code was added which caches all object read from the card
* If an object has a cert, the cert is decompressed and also cached.
* As part of reading an object the first 8 bytes are read
and this is then used to allocate a large buffer to read in the
object.
* If pkcs15 or pkcs11 asks about a certificate, the cert object
will be read, and the cert decompressed, to get the actual length.
* If piv_select_file is called with the file_out != NULL the object
will be read to get the length If called with NULL it will not be read.
* The enumeration of the objects now starts with 0.
* sc_ctx_suppress_errors_on and off are used to avoid file not found
messages which are are a by product of not having a directory.
* "Unsigned Card Holder Unique Identifier" object in card-piv and pkcs15-piv.c
had conflicting paths, as NIST 800-72-1 had two tables with different
paths. The enumtag for it in card-piv.c was also wrong.
git-svn-id: https://www.opensc-project.org/svnp/opensc/trunk@3710 c6295689-39f2-0310-b995-f0e70906c6a9
2009-07-22 10:09:21 +00:00
|
|
|
sc_file_t *file_out = NULL;
|
2007-06-21 07:07:49 +00:00
|
|
|
int exposed_cert[4] = {1, 0, 0, 0};
|
|
|
|
sc_serial_number_t serial;
|
|
|
|
char buf[SC_MAX_SERIALNR * 2 + 1];
|
2006-02-14 22:09:10 +00:00
|
|
|
|
|
|
|
SC_FUNC_CALLED(card->ctx, 1);
|
|
|
|
|
|
|
|
/* could read this off card if needed */
|
|
|
|
|
|
|
|
/* CSP does not like a - in the name */
|
|
|
|
p15card->label = strdup("PIV_II");
|
|
|
|
p15card->manufacturer_id = strdup(MANU_ID);
|
2007-06-21 07:07:49 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* get serial number
|
|
|
|
* We will use the FASC-N from the CHUID
|
|
|
|
* Note we are not verifying CHUID, belongs to this card
|
|
|
|
* but need serial number for Mac tokend
|
|
|
|
*/
|
|
|
|
|
2006-02-22 20:35:57 +00:00
|
|
|
r = sc_card_ctl(card, SC_CARDCTL_GET_SERIALNR, &serial);
|
2007-06-21 07:07:49 +00:00
|
|
|
if (r < 0) {
|
|
|
|
sc_debug(card->ctx,"sc_card_ctl rc=%d",r);
|
|
|
|
p15card->serial_number = strdup("00000000");
|
|
|
|
} else {
|
|
|
|
sc_bin_to_hex(serial.value, serial.len, buf, sizeof(buf), 0);
|
|
|
|
p15card->serial_number = strdup(buf);
|
|
|
|
}
|
2006-02-14 22:09:10 +00:00
|
|
|
|
|
|
|
sc_debug(card->ctx, "PIV-II adding objects...");
|
2007-06-21 07:07:49 +00:00
|
|
|
|
|
|
|
/* 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);
|
Douglas E. Engert: major update for the PIV smartcard.
The major issue is with getting the length of an object or the cert
contained in an object. The PIV card does not have a directory on the card,
So the previous version tried to put off as long as possible the reading
of objects for performance so as to avoid having to read objects that would
not be used. The first standard, NIST 800-73, set maximum sizes for objects.
800-73-2 removed this for certificates.
A certificate object can contain a certificate which might be compressed.
The only way to get the length of the compressed certificate is to decompress
it. Thus the decompressed certificate could be larger then the container object,
so even if the PIV card had a directory, one would still need to decompress
the certificate to find its length.
OpenSC sc_read_binary will use the length obtained by using
sc_select_file(...,&file_out), and thus the lengths must be determined
in sc_select_file.
Change are to card-piv.c and pkcs15-piv.c and include:
* The old cache code which was not working was removed.
* New cache code was added which caches all object read from the card
* If an object has a cert, the cert is decompressed and also cached.
* As part of reading an object the first 8 bytes are read
and this is then used to allocate a large buffer to read in the
object.
* If pkcs15 or pkcs11 asks about a certificate, the cert object
will be read, and the cert decompressed, to get the actual length.
* If piv_select_file is called with the file_out != NULL the object
will be read to get the length If called with NULL it will not be read.
* The enumeration of the objects now starts with 0.
* sc_ctx_suppress_errors_on and off are used to avoid file not found
messages which are are a by product of not having a directory.
* "Unsigned Card Holder Unique Identifier" object in card-piv and pkcs15-piv.c
had conflicting paths, as NIST 800-72-1 had two tables with different
paths. The enumtag for it in card-piv.c was also wrong.
git-svn-id: https://www.opensc-project.org/svnp/opensc/trunk@3710 c6295689-39f2-0310-b995-f0e70906c6a9
2009-07-22 10:09:21 +00:00
|
|
|
|
|
|
|
/* We could make sure the object is on the card */
|
|
|
|
/* But really don't need to do this now */
|
2009-09-14 08:46:59 +00:00
|
|
|
/* r = sc_select_file(card, &obj_info.path, NULL);
|
|
|
|
if (r == SC_ERROR_FILE_NOT_FOUND)
|
|
|
|
continue;
|
|
|
|
*/
|
2007-06-21 07:07:49 +00:00
|
|
|
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;
|
|
|
|
|
|
|
|
if (objects[i].auth_id)
|
|
|
|
sc_pkcs15_format_id(objects[i].auth_id, &obj_obj.auth_id);
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* certs, pubkeys and priv keys are related and we assume
|
|
|
|
* they are in order
|
|
|
|
* We need to read the cert, get modulus and keylen
|
|
|
|
* We use those for the pubkey, and priv key objects.
|
|
|
|
* If no cert, then see if pubkey (i.e. we are initilizing,
|
|
|
|
* and the pubkey is in a file,) then add pubkey and privkey
|
|
|
|
* If no cert and no pubkey, skip adding them.
|
|
|
|
|
|
|
|
*/
|
|
|
|
/* set certs */
|
|
|
|
sc_debug(card->ctx, "PIV-II adding certs...");
|
|
|
|
for (i = 0; certs[i].label; i++) {
|
|
|
|
struct sc_pkcs15_cert_info cert_info;
|
|
|
|
struct sc_pkcs15_object cert_obj;
|
|
|
|
sc_pkcs15_der_t cert_der;
|
|
|
|
sc_pkcs15_cert_t *cert_out;
|
|
|
|
|
|
|
|
if ((card->flags & 0x20) && (exposed_cert[i] == 0))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
memset(&cert_info, 0, sizeof(cert_info));
|
|
|
|
memset(&cert_obj, 0, sizeof(cert_obj));
|
2006-02-14 22:09:10 +00:00
|
|
|
|
2007-06-21 07:07:49 +00:00
|
|
|
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;
|
|
|
|
|
|
|
|
/* see if we have a cert */
|
|
|
|
|
Douglas E. Engert: major update for the PIV smartcard.
The major issue is with getting the length of an object or the cert
contained in an object. The PIV card does not have a directory on the card,
So the previous version tried to put off as long as possible the reading
of objects for performance so as to avoid having to read objects that would
not be used. The first standard, NIST 800-73, set maximum sizes for objects.
800-73-2 removed this for certificates.
A certificate object can contain a certificate which might be compressed.
The only way to get the length of the compressed certificate is to decompress
it. Thus the decompressed certificate could be larger then the container object,
so even if the PIV card had a directory, one would still need to decompress
the certificate to find its length.
OpenSC sc_read_binary will use the length obtained by using
sc_select_file(...,&file_out), and thus the lengths must be determined
in sc_select_file.
Change are to card-piv.c and pkcs15-piv.c and include:
* The old cache code which was not working was removed.
* New cache code was added which caches all object read from the card
* If an object has a cert, the cert is decompressed and also cached.
* As part of reading an object the first 8 bytes are read
and this is then used to allocate a large buffer to read in the
object.
* If pkcs15 or pkcs11 asks about a certificate, the cert object
will be read, and the cert decompressed, to get the actual length.
* If piv_select_file is called with the file_out != NULL the object
will be read to get the length If called with NULL it will not be read.
* The enumeration of the objects now starts with 0.
* sc_ctx_suppress_errors_on and off are used to avoid file not found
messages which are are a by product of not having a directory.
* "Unsigned Card Holder Unique Identifier" object in card-piv and pkcs15-piv.c
had conflicting paths, as NIST 800-72-1 had two tables with different
paths. The enumtag for it in card-piv.c was also wrong.
git-svn-id: https://www.opensc-project.org/svnp/opensc/trunk@3710 c6295689-39f2-0310-b995-f0e70906c6a9
2009-07-22 10:09:21 +00:00
|
|
|
/* use a &file_out so card-piv will read cert if present */
|
|
|
|
r = sc_pkcs15_read_file(p15card, &cert_info.path,
|
|
|
|
&cert_der.value, &cert_der.len, &file_out);
|
|
|
|
if (file_out) {
|
|
|
|
sc_file_free(file_out);
|
|
|
|
file_out = NULL;
|
|
|
|
}
|
2007-06-21 07:07:49 +00:00
|
|
|
|
|
|
|
if (r) {
|
|
|
|
sc_debug(card->ctx, "No cert found,i=%d", i);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
certs[i].found = 1;
|
|
|
|
/* cache it using the PKCS15 emulation objects */
|
|
|
|
/* as it does not change */
|
|
|
|
if (cert_der.value) {
|
|
|
|
cert_info.value.value = cert_der.value;
|
|
|
|
cert_info.value.len = cert_der.len;
|
|
|
|
cert_info.path.len = 0; /* use in mem cert from now on */
|
|
|
|
}
|
|
|
|
/* following will find the cached cert in cert_info */
|
|
|
|
r = sc_pkcs15_read_certificate(p15card, &cert_info, &cert_out);
|
|
|
|
if (r < 0) {
|
Douglas E. Engert: major update for the PIV smartcard.
The major issue is with getting the length of an object or the cert
contained in an object. The PIV card does not have a directory on the card,
So the previous version tried to put off as long as possible the reading
of objects for performance so as to avoid having to read objects that would
not be used. The first standard, NIST 800-73, set maximum sizes for objects.
800-73-2 removed this for certificates.
A certificate object can contain a certificate which might be compressed.
The only way to get the length of the compressed certificate is to decompress
it. Thus the decompressed certificate could be larger then the container object,
so even if the PIV card had a directory, one would still need to decompress
the certificate to find its length.
OpenSC sc_read_binary will use the length obtained by using
sc_select_file(...,&file_out), and thus the lengths must be determined
in sc_select_file.
Change are to card-piv.c and pkcs15-piv.c and include:
* The old cache code which was not working was removed.
* New cache code was added which caches all object read from the card
* If an object has a cert, the cert is decompressed and also cached.
* As part of reading an object the first 8 bytes are read
and this is then used to allocate a large buffer to read in the
object.
* If pkcs15 or pkcs11 asks about a certificate, the cert object
will be read, and the cert decompressed, to get the actual length.
* If piv_select_file is called with the file_out != NULL the object
will be read to get the length If called with NULL it will not be read.
* The enumeration of the objects now starts with 0.
* sc_ctx_suppress_errors_on and off are used to avoid file not found
messages which are are a by product of not having a directory.
* "Unsigned Card Holder Unique Identifier" object in card-piv and pkcs15-piv.c
had conflicting paths, as NIST 800-72-1 had two tables with different
paths. The enumtag for it in card-piv.c was also wrong.
git-svn-id: https://www.opensc-project.org/svnp/opensc/trunk@3710 c6295689-39f2-0310-b995-f0e70906c6a9
2009-07-22 10:09:21 +00:00
|
|
|
sc_debug(card->ctx, "Failed to read/parse the certificate r=%d",r);
|
2007-06-21 07:07:49 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
/* TODO support DSA keys */
|
|
|
|
if (cert_out->key.algorithm == SC_ALGORITHM_RSA) {
|
|
|
|
/* save modulus_len in pub and priv */
|
|
|
|
pubkeys[i].modulus_len = cert_out->key.u.rsa.modulus.len * 8;
|
|
|
|
prkeys[i].modulus_len = cert_out->key.u.rsa.modulus.len * 8;
|
|
|
|
}
|
|
|
|
sc_pkcs15_free_certificate(cert_out);
|
|
|
|
|
|
|
|
r = sc_pkcs15emu_add_x509_cert(p15card, &cert_obj, &cert_info);
|
|
|
|
if (r < 0) {
|
2009-09-14 08:46:59 +00:00
|
|
|
sc_debug(card->ctx, " Failed to add cert obj r=%d",r);
|
2007-06-21 07:07:49 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* set pins */
|
|
|
|
sc_debug(card->ctx, "PIV-II adding 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;
|
|
|
|
|
|
|
|
strncpy(pin_obj.label, pins[i].label, SC_PKCS15_MAX_LABEL_SIZE - 1);
|
|
|
|
pin_obj.flags = pins[i].obj_flags;
|
|
|
|
|
|
|
|
r = sc_pkcs15emu_add_pin_obj(p15card, &pin_obj, &pin_info);
|
|
|
|
if (r < 0)
|
|
|
|
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
|
|
|
|
*/
|
|
|
|
sc_debug(card->ctx, "PIV-II adding pub keys...");
|
|
|
|
for (i = 0; pubkeys[i].label; i++) {
|
|
|
|
struct sc_pkcs15_pubkey_info pubkey_info;
|
|
|
|
struct sc_pkcs15_object pubkey_obj;
|
|
|
|
struct sc_pkcs15_pubkey *p15_key;
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
sc_format_path(pubkeys[i].path, &pubkey_info.path);
|
|
|
|
|
|
|
|
strncpy(pubkey_obj.label, pubkeys[i].label, SC_PKCS15_MAX_LABEL_SIZE - 1);
|
|
|
|
|
|
|
|
pubkey_obj.flags = pubkeys[i].obj_flags;
|
|
|
|
|
|
|
|
|
|
|
|
if (pubkeys[i].auth_id)
|
|
|
|
sc_pkcs15_format_id(pubkeys[i].auth_id, &pubkey_obj.auth_id);
|
|
|
|
|
|
|
|
if (certs[i].found == 0) { /* no cert found */
|
|
|
|
sc_debug(card->ctx,"No cert for this pub key i=%d",i);
|
|
|
|
/* TODO DSA */
|
|
|
|
pubkey_obj.type = SC_PKCS15_TYPE_PUBKEY_RSA;
|
|
|
|
pubkey_obj.data = &pubkey_info;
|
|
|
|
r = sc_pkcs15_read_pubkey(p15card, &pubkey_obj, &p15_key);
|
|
|
|
pubkey_obj.data = NULL;
|
|
|
|
sc_debug(card->ctx," READING PUB KEY r=%d",r);
|
|
|
|
if (r < 0 ) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
/* Only get here if no cert, and the card-piv.c found
|
|
|
|
* there is a pub key file. This only happens when trying
|
|
|
|
* initializing a card and have set env to point at file
|
|
|
|
*/
|
|
|
|
if (p15_key->algorithm == SC_ALGORITHM_RSA) {
|
|
|
|
/* save modulus_len in pub and priv */
|
|
|
|
pubkeys[i].modulus_len = p15_key->u.rsa.modulus.len * 8;
|
|
|
|
prkeys[i].modulus_len = p15_key->u.rsa.modulus.len * 8;
|
|
|
|
pubkeys[i].found = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
pubkey_info.modulus_length = pubkeys[i].modulus_len;
|
|
|
|
strncpy(pubkey_obj.label, pubkeys[i].label, SC_PKCS15_MAX_LABEL_SIZE - 1);
|
|
|
|
|
|
|
|
/* TODO DSA keys */
|
|
|
|
r = sc_pkcs15emu_add_rsa_pubkey(p15card, &pubkey_obj, &pubkey_info);
|
|
|
|
if (r < 0)
|
|
|
|
SC_FUNC_RETURN(card->ctx, 1, r); /* should not fail */
|
|
|
|
|
|
|
|
pubkeys[i].found = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* set private keys */
|
|
|
|
sc_debug(card->ctx, "PIV-II adding 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));
|
|
|
|
|
|
|
|
if (certs[i].found == 0 && pubkeys[i].found == 0)
|
|
|
|
continue; /* i.e. no cert or pubkey */
|
|
|
|
|
|
|
|
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;
|
|
|
|
/* The cert or pubkey should have filled modulus_len */
|
|
|
|
/* TODO DSA keys */
|
|
|
|
sc_format_path(prkeys[i].path, &prkey_info.path);
|
|
|
|
|
|
|
|
strncpy(prkey_obj.label, prkeys[i].label, SC_PKCS15_MAX_LABEL_SIZE - 1);
|
|
|
|
|
|
|
|
prkey_obj.flags = prkeys[i].obj_flags;
|
|
|
|
|
|
|
|
if (prkeys[i].auth_id)
|
|
|
|
sc_pkcs15_format_id(prkeys[i].auth_id, &prkey_obj.auth_id);
|
|
|
|
|
|
|
|
r = sc_pkcs15emu_add_rsa_prkey(p15card, &prkey_obj, &prkey_info);
|
|
|
|
if (r < 0)
|
|
|
|
SC_FUNC_RETURN(card->ctx, 1, r);
|
|
|
|
}
|
2006-02-14 22:09:10 +00:00
|
|
|
|
|
|
|
SC_FUNC_RETURN(card->ctx, 1, SC_SUCCESS);
|
|
|
|
}
|
|
|
|
|
|
|
|
int sc_pkcs15emu_piv_init_ex(sc_pkcs15_card_t *p15card,
|
|
|
|
sc_pkcs15emu_opt_t *opts)
|
|
|
|
{
|
|
|
|
sc_card_t *card = p15card->card;
|
|
|
|
sc_context_t *ctx = card->ctx;
|
|
|
|
|
|
|
|
SC_FUNC_CALLED(ctx, 1);
|
|
|
|
|
|
|
|
if (opts && opts->flags & SC_PKCS15EMU_FLAGS_NO_CHECK)
|
|
|
|
return sc_pkcs15emu_piv_init(p15card);
|
|
|
|
else {
|
|
|
|
int r = piv_detect_card(p15card);
|
|
|
|
if (r)
|
|
|
|
return SC_ERROR_WRONG_CARD;
|
|
|
|
return sc_pkcs15emu_piv_init(p15card);
|
|
|
|
}
|
|
|
|
}
|