patch from Douglas E. Engert for bug #165

git-svn-id: https://www.opensc-project.org/svnp/opensc/trunk@3292 c6295689-39f2-0310-b995-f0e70906c6a9
This commit is contained in:
ludovic.rousseau 2007-11-09 08:35:23 +00:00
parent caf4207090
commit ca92ec661f
2 changed files with 149 additions and 52 deletions

View File

@ -47,6 +47,7 @@ typedef struct piv_private_data {
sc_file_t *aid_file;
int enumtag;
int selected_obj; /* The index into the piv_objects last selected */
int return_only_cert; /* return the cert from the object */
int eof;
size_t max_recv_size; /* saved size, need to lie to pkcs15_read_file */
size_t max_send_size;
@ -118,19 +119,23 @@ struct piv_aid {
/* The Generic entry should be the "A0 00 00 03 08 00 00 01 00 "
* NIST published this on 10/6/2005
* 800-73-2 is due for release 11/2007.
* 800-73-2 Part 1 now refers to version "02 00"
* i.e. "A0 00 00 03 08 00 00 01 00 02 00".
* but we dont need the version number. but could get it from the PIX.
*/
static struct piv_aid piv_aids[] = {
{SC_CARD_TYPE_PIV_II_GENERIC,
9, 11, (u8 *) "\xA0\x00\x00\x03\x08\x00\x00\x10\x00\x01\x00" },
9, 9, (u8 *) "\xA0\x00\x00\x03\x08\x00\x00\x10\x00" },
{0, 9, 0, NULL }
};
enum {
PIV_OBJ_CCC = 1,
PIV_OBJ_CHUI,
PIV_OBJ_UCHUI, /* new with 800-73-2 */
PIV_OBJ_X509_PIV_AUTH,
PIV_OBJ_CHF1,
PIV_OBJ_CHF2,
PIV_OBJ_CHF,
PIV_OBJ_PI,
PIV_OBJ_CHFI,
PIV_OBJ_X509_DS,
@ -155,28 +160,31 @@ struct piv_object {
size_t maxlen; /* advisory, used with select_file, but we can read larger */
};
/* maxlen values are advisory only, we can read larger if needed. */
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},
"2.16.840.1.101.3.7.1.219.0", 3, "\x5F\xC1\x07", "\xDB\x00", 266+30+3},
{ PIV_OBJ_CHUI, "Card Holder Unique Identifier",
"2.16.840.1.101.3.7.2.48.0", 3, "\x5F\xC1\x02", "\x30\x00", 3379}, /* Updated per SP800-73-1 Errata */
"2.16.840.1.101.3.7.2.48.0", 3, "\x5F\xC1\x02", "\x30\x00", 3392+20+4},
{ PIV_OBJ_CHUI, "Unsigned Card Holder Unique Identifier",
"2.16.840.1.101.3.7.2.48.1", 3, "\x5F\xC1\x04", "\x30\x10", 67+14+4},
{ 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} ,
"2.16.840.1.101.3.7.2.1.1", 3, "\x5F\xC1\x05", "\x01\x01", 1895+9+4+400} ,
/* extra 400 is hack for MultOS card which returns 2200 bytes */
{ 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_CHF, "Card Holder Fingerprints",
"2.16.840.1.101.3.7.2.96.16", 3, "\x5F\xC1\x03", "\x60\x10", 4000+4+4},
{ PIV_OBJ_PI, "Printed Information",
"2.16.840.1.101.3.7.2.48.1", 3, "\x5F\xC1\x09", "\x30\x01", 106},
"2.16.840.1.101.3.7.2.48.1", 3, "\x5F\xC1\x09", "\x30\x01", 146+18+3},
{ PIV_OBJ_CHFI, "Card Holder Facial Image",
"2.16.840.1.101.3.7.2.96.48", 3, "\x5F\xC1\x08", "\x60\x30", 12704},
"2.16.840.1.101.3.7.2.96.48", 3, "\x5F\xC1\x08", "\x60\x30", 12704+5+4},
{ PIV_OBJ_X509_DS, "X.509 Certificate for Digital Signature",
"2.16.840.1.101.3.7.2.1.0", 3, "\x5F\xC1\x0A", "\x01\x00", 1856+4},
"2.16.840.1.101.3.7.2.1.0", 3, "\x5F\xC1\x0A", "\x01\x00", 1895+9+4+400},
{ PIV_OBJ_X509_KM, "X.509 Certificate for Key Management",
"2.16.840.1.101.3.7.2.1.2", 3, "\x5F\xC1\x0B", "\x01\x02", 1856+4},
"2.16.840.1.101.3.7.2.1.2", 3, "\x5F\xC1\x0B", "\x01\x02", 1895+9+4+400},
{ PIV_OBJ_X509_CARD_AUTH, "X.509 Certificate for Card Authentication",
"2.16.840.1.101.3.7.2.5.0", 3, "\x5F\xC1\x01", "\x05\x00", 1856+4},
"2.16.840.1.101.3.7.2.5.0", 3, "\x5F\xC1\x01", "\x05\x00", 1895+9+4+400},
{ PIV_OBJ_SEC_OBJ, "Security Object",
"2.16.840.1.101.3.7.2.144.0", 3, "\x5F\xC1\x06", "\x90\x00", 1000},
"2.16.840.1.101.3.7.2.144.0", 3, "\x5F\xC1\x06", "\x90\x00", 1000+30+4+4},
/* following not standard , to be used by piv-tool only for testing */
{ PIV_OBJ_9B03, "3DES-ECB ADM",
"2.16.840.1.101.3.7.2.9999.3", 2, "\x9B\x03", "\x9B\x03", 24},
@ -186,13 +194,13 @@ static struct piv_object piv_objects[] = {
* but still use the "9x06" name.
*/
{ PIV_OBJ_9A06, "RSA 9A Pub key from last genkey",
"2.16.840.1.101.3.7.2.9999.20", 2, "\x9A\x06", "\x9A\x06", 512},
"2.16.840.1.101.3.7.2.9999.20", 2, "\x9A\x06", "\x9A\x06", 2048},
{ PIV_OBJ_9C06, "Pub 9C key from last genkey",
"2.16.840.1.101.3.7.2.9999.21", 2, "\x9C\x06", "\x9C\x06", 512},
"2.16.840.1.101.3.7.2.9999.21", 2, "\x9C\x06", "\x9C\x06", 2048},
{ PIV_OBJ_9D06, "Pub 9D key from last genkey",
"2.16.840.1.101.3.7.2.9999.22", 2, "\x9D\x06", "\x9D\x06", 512},
"2.16.840.1.101.3.7.2.9999.22", 2, "\x9D\x06", "\x9D\x06", 2048},
{ PIV_OBJ_9E06, "Pub 9E key from last genkey",
"2.16.840.1.101.3.7.2.9999.23", 2, "\x9E\x06", "\x9E\x06", 512},
"2.16.840.1.101.3.7.2.9999.23", 2, "\x9E\x06", "\x9E\x06", 2048},
{ 0, "", "", 0, "", "", 0}
};
@ -525,8 +533,9 @@ static int piv_find_aid(sc_card_t * card, sc_file_t *aid_file)
sc_debug(card->ctx,"found PIX");
/* early cards returned full AID, rather then just the pix */
for (i = 0; piv_aids[i].len_short != 0; i++) {
if ((pixlen >= 6 && memcmp(pix, piv_aids[i].value + 5, 6) == 0)
for (i = 0; piv_aids[i].len_long != 0; i++) {
if ((pixlen >= 6 && memcmp(pix, piv_aids[i].value + 5,
piv_aids[i].len_long - 5 ) == 0)
|| ((pixlen >= piv_aids[i].len_short &&
memcmp(pix, piv_aids[i].value,
piv_aids[i].len_short) == 0))) {
@ -619,10 +628,10 @@ static int piv_get_data(sc_card_t * card, unsigned int enumtag,
* the PIV card will only recover the public key during a generate
* key operation. If the piv-tool was used it would save this
* as an OpenSSL EVP_KEY PEM using the -o parameter
* we will look to see there as a file and load it
* we will look to see if there is a file then load it
* this is ugly, and maybe the pkcs15 cache would work
* but we only need it to get the OpenSSL req with engine to work.
* Each of the 3 keys with certs has its own file.
* Each of the 4 keys with certs has its own file.
*/
switch (piv_objects[enumtag].enumtag) {
@ -723,6 +732,7 @@ static int piv_handle_certificate_data(sc_card_t *card,
piv_cache_item* item;
/* get the certificate out */
tag = (u8 *) sc_asn1_find_tag(card->ctx, data, length, 0x71, &taglen);
/* 800-72-1 not clear if this is 80 or 01 Sent comment to NIST for 800-72-2 */
if (tag && (((*tag) & 0x80) || ((*tag) & 0x01))) {
compressed = 1;
}
@ -880,7 +890,10 @@ static int piv_read_binary(sc_card_t *card, unsigned int idx,
case PIV_OBJ_X509_DS:
case PIV_OBJ_X509_KM:
case PIV_OBJ_X509_CARD_AUTH:
r = piv_handle_certificate_data(card, enumtag, idx, buf, count, body, bodylen);
if (priv->return_only_cert)
r = piv_handle_certificate_data(card, enumtag, idx, buf, count, body, bodylen);
else
r = piv_handle_data(card, enumtag, idx, buf, count, rbuf, rbuflen);
break;
case PIV_OBJ_9A06:
case PIV_OBJ_9C06:
@ -1075,25 +1088,37 @@ err:
/*
* will only deal with 3des for now
* assumptions include:
* size of encrypted data is same as unencrypted
* challenges, nonces etc from card are less then 114 (keeps tags simple)
*/
static int piv_general_mutual_authenticate(sc_card_t *card,
unsigned int key_ref, unsigned int alg_id)
{
int r;
size_t N;
int locked = 0, outl;
int N;
int locked = 0, outl, outl2;
u8 *rbuf = NULL;
size_t rbuflen;
u8 nonce[8] = {0xDE, 0xE0, 0xDE, 0xE1, 0xDE, 0xE2, 0xDE, 0xE3};
u8 sbuf[255], key[24];
u8 *p, *q;
EVP_CIPHER_CTX ctx;
const EVP_CIPHER *cipher;
SC_FUNC_CALLED(card->ctx,1);
EVP_CIPHER_CTX_init(&ctx);
switch (alg_id) {
case 1: cipher=EVP_des_ede3_ecb(); break;
case 2: cipher=EVP_des_ede3_cbc(); break;
case 3: cipher=EVP_des_ede3_ecb(); break;
case 4: cipher=EVP_des_ede3_cbc(); break;
default: cipher=EVP_des_ede3_ecb(); break;
}
r = piv_get_3des_key(card, key);
if (r != SC_SUCCESS)
goto err;
@ -1123,18 +1148,32 @@ static int piv_general_mutual_authenticate(sc_card_t *card,
r = SC_ERROR_INVALID_DATA;
goto err;
}
N = *(rbuf + 3); /* assuming 2 * N + 6 < 128 and N = 8 */
N = *(rbuf + 3); /* assuming N + sizeof(nonce) + 6 < 128 */
/* needs work, as challenge may be other then 8 bytes */
/* prepare the response */
p = sbuf;
*p++ = 0x7c;
*p++ = 2 * N + 4;
*p++ = N + sizeof(nonce)+ 4;
*p++ = 0x80;
*p++ = (u8)N;
EVP_DecryptInit_ex(&ctx, EVP_des_ede3(), NULL, key, NULL);
if (!EVP_DecryptUpdate(&ctx, p, &outl, q, 8)) {
/* decrypt the data from the card */
if (!EVP_DecryptInit(&ctx, cipher, key, NULL)) {
/* may fail if des parity of key is wrong. depends on OpenSSL options */
r = SC_ERROR_INTERNAL;
goto err;
}
EVP_CIPHER_CTX_set_padding(&ctx,0);
if (!EVP_DecryptUpdate(&ctx, p, &outl, q, N)) {
r = SC_ERROR_INTERNAL;
goto err;
}
if(!EVP_DecryptFinal(&ctx, p+outl, &outl2)) {
r = SC_ERROR_INTERNAL;
goto err;
}
if (outl+outl2 != N) {
r = SC_ERROR_INTERNAL;
goto err;
}
@ -1142,9 +1181,9 @@ static int piv_general_mutual_authenticate(sc_card_t *card,
p += N;
*p++ = 0x81;
*p++ = N;
memcpy(p, &nonce, N); /* we use a fixed nonce for now */
p += N;
*p++ = sizeof(nonce);
memcpy(p, &nonce, sizeof(nonce)); /* we use a fixed nonce for now */
p += sizeof(nonce);
free(rbuf);
rbuf = NULL;
@ -1159,14 +1198,28 @@ static int piv_general_mutual_authenticate(sc_card_t *card,
r = SC_ERROR_INVALID_DATA;
goto err;
}
N = *(rbuf + 3);
p = sbuf;
if (!EVP_DecryptUpdate(&ctx, p, &outl, q, 8)) {
EVP_CIPHER_CTX_cleanup(&ctx);
EVP_CIPHER_CTX_init(&ctx);
if (!EVP_DecryptInit(&ctx, cipher, key, NULL)) {
r = SC_ERROR_INTERNAL;
goto err;
}
EVP_CIPHER_CTX_set_padding(&ctx,0);
if (!EVP_DecryptUpdate(&ctx, p, &outl, q, N)) {
r = SC_ERROR_INTERNAL;
goto err;
}
if(!EVP_DecryptFinal(&ctx, p+outl, &outl2)) {
r = SC_ERROR_INTERNAL;
goto err;
}
if (memcmp(nonce, p, N) != 0) {
if (outl+outl2 != sizeof(nonce) || memcmp(nonce, p, sizeof(nonce)) != 0) {
sc_debug(card->ctx, "mutual authentication failed, card returned wrong value");
r = SC_ERROR_DECRYPT_FAILED;
goto err;
@ -1187,17 +1240,28 @@ static int piv_general_external_authenticate(sc_card_t *card,
unsigned int key_ref, unsigned int alg_id)
{
/* unused: piv_private_data_t * priv = PIV_DATA(card); */
int r, outl;
int r, outl, outl2;
int N;
int locked = 0;
u8 *rbuf = NULL;
size_t rbuflen;
u8 sbuf[255], key[24];
u8 *p, *q;
EVP_CIPHER_CTX ctx;
const EVP_CIPHER *cipher;
SC_FUNC_CALLED(card->ctx,1);
EVP_CIPHER_CTX_init(&ctx);
switch (alg_id) {
case 1: cipher=EVP_des_ede3_ecb(); break;
case 2: cipher=EVP_des_ede3_cbc(); break;
case 3: cipher=EVP_des_ede3_ecb(); break;
case 4: cipher=EVP_des_ede3_cbc(); break;
default: cipher=EVP_des_ede3_ecb(); break;
}
r = piv_get_3des_key(card, key);
if (r != SC_SUCCESS)
goto err;
@ -1205,6 +1269,7 @@ static int piv_general_external_authenticate(sc_card_t *card,
r = sc_lock(card);
if (r != SC_SUCCESS)
goto err;
locked = 1;
p = sbuf;
q = rbuf;
@ -1227,25 +1292,38 @@ static int piv_general_external_authenticate(sc_card_t *card,
goto err;
}
/* needs work, as challenge may be other then 8 bytes */
/* assuming challenge and response are same size i.e. des3 */
p = sbuf;
*p++ = 0x7c;
*p++ = *(rbuf + 1);
*p++ = 0x82;
*p++ = *(rbuf + 3);
N = *(rbuf + 3); /* assuming 2 * N + 6 < 128 */
EVP_EncryptInit_ex(&ctx, EVP_des_ede3(), NULL, key, NULL);
if (!EVP_EncryptUpdate(&ctx, p, &outl, q, 8)) {
if (!EVP_EncryptInit(&ctx, cipher, key, NULL)) {
r = SC_ERROR_INTERNAL;
goto err;
}
EVP_CIPHER_CTX_set_padding(&ctx,0);
if (!EVP_EncryptUpdate(&ctx, p, &outl, q, N)) {
r = SC_ERROR_INTERNAL;
goto err;
}
p += *(rbuf + 3);
if(!EVP_EncryptFinal(&ctx, p+outl, &outl2)) {
r = SC_ERROR_INTERNAL;
goto err;
}
if (outl+outl2 != N) {
r = SC_ERROR_INTERNAL;
goto err;
}
p += N;
r = piv_general_io(card, 0x87, alg_id, key_ref, sbuf, p - sbuf, NULL, NULL);
sc_unlock(card);
err:
if (locked)
sc_unlock(card);
EVP_CIPHER_CTX_cleanup(&ctx);
sc_mem_clear(key, sizeof(key));
if (rbuf)
@ -1535,13 +1613,19 @@ static int piv_select_file(sc_card_t *card, const sc_path_t *in_path,
path += 2;
pathlen -= 2;
}
if (pathlen != 2)
SC_FUNC_RETURN(card->ctx, 1, SC_ERROR_INVALID_ARGUMENTS);
i = piv_find_obj_by_containerid(card, path);
if (i< 0)
SC_FUNC_RETURN(card->ctx, 1, SC_ERROR_FILE_NOT_FOUND);
/*
* pkcs15 will use a 2 byte path or a 4 byte path
* with cece added to path to request only the cert from the cert obj
* PIV "Container ID" is used as the path, and are two bytes long
*/
priv->return_only_cert = (pathlen == 4 && path[2] == 0xce && path[3] == 0xce);
priv->selected_obj = i;
priv->eof = 0;

View File

@ -111,18 +111,29 @@ static int piv_detect_card(sc_pkcs15_card_t *p15card)
static int sc_pkcs15emu_piv_init(sc_pkcs15_card_t *p15card)
{
/* The cert objects will return all the data */
const objdata objects[] = {
{"1", "Card Capability Container",
"2.16.840.1.101.3.7.1.219.0", NULL, "DB00", 0},
{"2", "Card Holder Unique Identifier",
"2.16.840.1.101.3.7.2.48.0", NULL, "3000", 0},
{"3", "Card Holder Fingerprints",
{"3", "Unsigned Card Holder Unique Identifier",
"2.16.840.1.101.3.7.2.48.2", NULL, "3002", 0},
{"4", "X.509 Certificate for PIV Authentication",
"2.16.840.1.101.3.7.2.1.1", NULL, "0101", 0},
{"5", "Card Holder Fingerprints",
"2.16.840.1.101.3.7.2.96.16", "1", "6010", SC_PKCS15_CO_FLAG_PRIVATE},
{"4", "Printed Information",
{"6", "Printed Information",
"2.16.840.1.101.3.7.2.48.1", "1", "3001", SC_PKCS15_CO_FLAG_PRIVATE},
{"5", "Card Holder Facial Image",
{"7", "Card Holder Facial Image",
"2.16.840.1.101.3.7.2.96.48", "1", "6030", SC_PKCS15_CO_FLAG_PRIVATE},
{"6", "Security Object",
{"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",
"2.16.840.1.101.3.7.2.144.0", NULL, "9000", 0},
{NULL, NULL, NULL, NULL, NULL, 0}
};
@ -133,11 +144,13 @@ const objdata objects[] = {
* that do enforce it. Code later on will allow SC_PKCS15_CO_FLAG_PRIVATE
* to be set.
*/
/* certs will be pulled out from the cert objects */
cdata certs[] = {
{"1", "Certificate for PIV Authentication", 0, "0101", 0, 0},
{"2", "Certificate for Digital Signature", 0, "0100", 0, 0},
{"3", "Certificate for Key Management", 0, "0102", 0, 0},
{"4", "Certificate for Card Authentication", 0, "0500", 0, 0},
{"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},
{NULL, NULL, 0, NULL, 0, 0}
};