Apply security fix.

git-svn-id: https://www.opensc-project.org/svnp/opensc/trunk@3552 c6295689-39f2-0310-b995-f0e70906c6a9
This commit is contained in:
aj 2008-07-31 13:25:16 +00:00
parent 1b1ae308e0
commit 07247596d6
3 changed files with 244 additions and 3 deletions

2
NEWS
View File

@ -7,6 +7,8 @@ Also see the svn changelog using svn command
or doc/nonpersistent/ChangeLog.
New in 0.11.5; 2008-07-31; Andreas Jellinghaus
* Apply security fix for cardos driver and extend pkcs15-tool to
test cards for the security vulnerability and update them.
* Build system rewritten (NOTICE: configure options was modified).
The build system can produce outputs for *NIX, cygwin and native
windows (using mingw).

View File

@ -389,7 +389,7 @@ static const int df_acl[9] = {
SC_AC_OP_REHABILITATE, /* DF */
SC_AC_OP_DELETE, /* DF */
-1, /* ADMIN DF */
SC_AC_OP_UPDATE, /* ADMIN DF */
SC_AC_OP_CREATE, /* Files */
-1 /* Reserved */
};
@ -404,7 +404,7 @@ static const int ef_acl[9] = {
/* XXX: ADMIN should be an ACL type of its own, or mapped
* to erase */
-1, /* ADMIN EF (modify meta information?) */
SC_AC_OP_UPDATE, /* ADMIN EF (modify meta information?) */
-1, /* INC (-> cylic fixed files) */
-1 /* DEC */
};

View File

@ -2,6 +2,7 @@
* pkcs15-tool.c: Tool for poking with PKCS #15 smart cards
*
* Copyright (C) 2001 Juha Yrjölä <juha.yrjola@iki.fi>
* Copyright (C) 2008 Andreas Jellinghaus <aj@dungeon.inka.de>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@ -91,6 +92,8 @@ static const struct option options[] = {
#if defined(ENABLE_OPENSSL) && (defined(_WIN32) || defined(HAVE_INTTYPES_H))
{ "read-ssh-key", required_argument, NULL, OPT_READ_SSH },
#endif
{ "test-update", no_argument, NULL, 'T' },
{ "update", no_argument, NULL, 'U' },
{ "reader", required_argument, NULL, OPT_READER },
{ "pin", required_argument, NULL, OPT_PIN },
{ "new-pin", required_argument, NULL, OPT_NEWPIN },
@ -117,6 +120,8 @@ static const char *option_help[] = {
"Lists public keys",
"Reads public key with ID <arg>",
"Reads public key with ID <arg>, outputs ssh format",
"Test if the card needs a security update",
"Update the card with a security update",
"Uses reader number <arg>",
"Specify PIN",
"Specify New PIN (when changing or unblocking)",
@ -1177,6 +1182,218 @@ static int learn_card(void)
return 0;
}
static int test_update(sc_card_t *in_card)
{
sc_apdu_t apdu;
static u8 cmd1[2] = { 0x50, 0x15};
u8 rbuf[258];
int rc;
int r;
static u8 fci_bad[] = { 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
static u8 fci_good[] = { 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00 };
if (strcmp("cardos",in_card->driver->short_name) != 0) {
printf("not using the cardos driver, card is fine.");
rc = 0;
goto end;
}
if (strcmp("OpenSC Card",p15card->label) != 0) {
printf("not initialized by opensc, card is fine.");
rc = 0;
goto end;
}
/* first select file on 5015 and get fci */
sc_format_apdu(in_card, &apdu, SC_APDU_CASE_4_SHORT, 0xa4, 0x08, 0x00);
apdu.lc = sizeof(cmd1);
apdu.datalen = sizeof(cmd1);
apdu.data = cmd1;
apdu.le = 256;
apdu.resp = rbuf;
apdu.resplen = sizeof(rbuf);
r = sc_transmit_apdu(card, &apdu);
if (r < 0) {
printf("selecting folder failed: %s\n", sc_strerror(r));
rc = 2;
goto end;
}
if (apdu.sw1 != 0x90) {
printf("apdu command select file failed: card returned %02X %02X\n",
apdu.sw1, apdu.sw2);
rc = 2;
goto end;
}
if (apdu.resplen < 6) {
printf("select file did not return enough data (length %d)\n",
(int) apdu.resplen);
goto bad_fci;
}
if (rbuf[0] != 0x6f) {
printf("select file did not return the information we need\n");
goto bad_fci;
}
if (rbuf[1] != apdu.resplen -2) {
printf("select file returned inconsistent information\n");
goto bad_fci;
}
{
int i=0;
while(i < rbuf[1]) {
if (rbuf[2+i] == 0x86) { /* found our buffer */
break;
}
/* other tag */
i += 2 + rbuf[2+i+1]; /* length of this tag*/
}
if (rbuf[2+i+1] < 9 || 2+i+2+9 > apdu.resplen) {
printf("select file returned short fci\n");
goto bad_fci;
}
if (memcmp(&rbuf[2+i+2],fci_good,sizeof(fci_good)) == 0) {
printf("fci is up-to-date, card is fine\n");
rc = 0;
goto end;
}
if (memcmp(&rbuf[2+i+2],fci_bad,sizeof(fci_bad)) == 0) {
printf("fci is out-of-date, card is vulnerable\n");
rc = 1;
goto end;
}
printf("select file returned fci with unknown data\n");
goto bad_fci;
}
end:
/* 0 = card ok, 1 = card vulnerable, 2 = problem! */
return rc;
bad_fci:
util_hex_dump(stdout,rbuf,apdu.resplen," ");
printf("\n");
return 2;
}
static int update(sc_card_t *in_card)
{
sc_apdu_t apdu;
u8 rbuf[258];
static u8 cmd1[2] = { 0x50, 0x15};
static u8 cmd3[11] = { 0x86, 0x09, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00,
0xff, 0x00, 0x00};
int r;
/* first select file on 5015 */
sc_format_apdu(in_card, &apdu, SC_APDU_CASE_3_SHORT, 0xa4, 0x08, 0x00);
apdu.lc = sizeof(cmd1);
apdu.datalen = sizeof(cmd1);
apdu.data = cmd1;
r = sc_transmit_apdu(card, &apdu);
if (r < 0) {
printf("selecting folder failed: %s\n", sc_strerror(r));
goto end;
}
if (apdu.sw1 != 0x90) {
printf("apdu command select file: card returned %02X %02X\n",
apdu.sw1, apdu.sw2);
goto end;
}
/* next get lifecycle */
memset(&apdu, 0, sizeof(apdu));
sc_format_apdu(in_card, &apdu, SC_APDU_CASE_2, 0xca, 0x01, 0x83);
apdu.cla = 0x00;
apdu.le = 256;
apdu.resp = rbuf;
apdu.resplen = sizeof(rbuf);
r = sc_transmit_apdu(card, &apdu);
if (r < 0) {
printf("get lifecycle failed: %s\n", sc_strerror(r));
goto end;
}
if (apdu.sw1 != 0x90) {
printf("get lifecycle failed: card returned %02X %02X\n",
apdu.sw1, apdu.sw2);
goto end;
}
if (apdu.resplen < 1) {
printf("get lifecycle failed: lifecycle byte not in response\n");
goto end;
}
if (rbuf[0] != 0x10 && rbuf[0] != 0x20) {
printf("lifecycle neither user nor admin, can't proceed\n");
goto end;
}
if (rbuf[0] == 0x20)
goto skip_change_lifecycle;
/* next phase control / change lifecycle to operational */
memset(&apdu, 0, sizeof(apdu));
sc_format_apdu(in_card, &apdu, SC_APDU_CASE_1, 0x10, 0x00, 0x00);
apdu.cla = 0x80;
r = sc_transmit_apdu(card, &apdu);
if (r < 0) {
printf("change lifecycle failed: %s\n", sc_strerror(r));
goto end;
}
if (apdu.sw1 != 0x90) {
printf("apdu command change lifecycle failed: card returned %02X %02X\n",
apdu.sw1, apdu.sw2);
goto end;
}
skip_change_lifecycle:
/* last update AC */
memset(&apdu, 0, sizeof(apdu));
sc_format_apdu(in_card, &apdu, SC_APDU_CASE_3_SHORT, 0xda, 0x01, 0x6f);
apdu.lc = sizeof(cmd3);
apdu.datalen = sizeof(cmd3);
apdu.data = cmd3;
apdu.le = 0;
apdu.resplen = 0;
apdu.resp = NULL;
r = sc_transmit_apdu(card, &apdu);
if (r < 0) {
printf("update fci failed: %s\n", sc_strerror(r));
goto end;
}
if (apdu.sw1 != 0x90) {
printf("apdu command update fci failed: card returned %02X %02X\n",
apdu.sw1, apdu.sw2);
goto end;
}
printf("security update applied successfully.\n");
end:
return 0;
}
int main(int argc, char * const argv[])
{
int err = 0, r, c, long_optind = 0;
@ -1195,11 +1412,13 @@ int main(int argc, char * const argv[])
int do_change_pin = 0;
int do_unblock_pin = 0;
int do_learn_card = 0;
int do_test_update = 0;
int do_update = 0;
int action_count = 0;
sc_context_param_t ctx_param;
while (1) {
c = getopt_long(argc, argv, "r:cuko:va:LR:CwD", options, &long_optind);
c = getopt_long(argc, argv, "r:cuko:va:LR:CwDTU", options, &long_optind);
if (c == -1)
break;
if (c == '?')
@ -1263,6 +1482,14 @@ int main(int argc, char * const argv[])
do_learn_card = 1;
action_count++;
break;
case 'T':
do_test_update = 1;
action_count++;
break;
case 'U':
do_update = 1;
action_count++;
break;
case OPT_READER:
opt_reader = atoi(optarg);
break;
@ -1390,6 +1617,18 @@ int main(int argc, char * const argv[])
goto end;
action_count--;
}
if (do_test_update || do_update) {
err = test_update(card);
action_count--;
if (err == 2) { /* problem */
err =1;
goto end;
}
if (do_update && err == 1) { /* card vulnerable */
if ((err = update(card)))
goto end;
}
}
end:
if (p15card)
sc_pkcs15_unbind(p15card);