- added very partial SSH support

- rearranged some functions
- added several new functions
- fixed handling of SW's


git-svn-id: https://www.opensc-project.org/svnp/opensc/trunk@47 c6295689-39f2-0310-b995-f0e70906c6a9
This commit is contained in:
jey 2001-11-20 22:21:58 +00:00
parent e5cf39b2eb
commit ea594e3e50
18 changed files with 1490 additions and 572 deletions

View File

@ -129,7 +129,16 @@ static int fineid_pkcs15_defaults(void *arg)
return 0; return 0;
} }
static int multiflex_defaults(void *arg)
{
struct sc_card *card = (struct sc_card *) arg;
card->class = 0xC0;
return 0;
}
const struct sc_defaults sc_card_table[] = { const struct sc_defaults sc_card_table[] = {
{ "3B:9F:94:40:1E:00:67:11:43:46:49:53:45:10:52:66:FF:81:90:00", fineid_defaults, fineid_pkcs15_defaults }, { "3B:9F:94:40:1E:00:67:11:43:46:49:53:45:10:52:66:FF:81:90:00", fineid_defaults, fineid_pkcs15_defaults },
{ "3B:19:14:55:90:01:02:02:00:05:04:B0", multiflex_defaults, NULL },
{ NULL, NULL, NULL } { NULL, NULL, NULL }
}; };

View File

@ -158,6 +158,11 @@ struct sc_pkcs15_card {
int sc_pkcs15_init(struct sc_card *card, int sc_pkcs15_init(struct sc_card *card,
struct sc_pkcs15_card **pkcs15_card); struct sc_pkcs15_card **pkcs15_card);
int sc_pkcs15_destroy(struct sc_pkcs15_card *card); int sc_pkcs15_destroy(struct sc_pkcs15_card *card);
int sc_pkcs15_decipher(struct sc_pkcs15_card *p15card,
const struct sc_pkcs15_prkey_info *prkey,
const u8 * in, int inlen, u8 *out, int outlen);
void sc_pkcs15_print_card(const struct sc_pkcs15_card *card); void sc_pkcs15_print_card(const struct sc_pkcs15_card *card);
void sc_pkcs15_print_cert_info(const struct sc_pkcs15_cert_info *cert); void sc_pkcs15_print_cert_info(const struct sc_pkcs15_cert_info *cert);
@ -169,6 +174,9 @@ void sc_pkcs15_free_certificate(struct sc_pkcs15_cert *cert);
void sc_pkcs15_print_prkey_info(const struct sc_pkcs15_prkey_info *prkey); void sc_pkcs15_print_prkey_info(const struct sc_pkcs15_prkey_info *prkey);
int sc_pkcs15_enum_private_keys(struct sc_pkcs15_card *card); int sc_pkcs15_enum_private_keys(struct sc_pkcs15_card *card);
int sc_pkcs15_find_prkey_by_id(struct sc_pkcs15_card *card,
const struct sc_pkcs15_id *id,
struct sc_pkcs15_prkey_info **out);
void sc_pkcs15_print_pin_info(const struct sc_pkcs15_pin_info *pin); void sc_pkcs15_print_pin_info(const struct sc_pkcs15_pin_info *pin);
int sc_pkcs15_enum_pins(struct sc_pkcs15_card *card); int sc_pkcs15_enum_pins(struct sc_pkcs15_card *card);
@ -179,13 +187,14 @@ int sc_pkcs15_change_pin(struct sc_pkcs15_card *card,
struct sc_pkcs15_pin_info *pin, struct sc_pkcs15_pin_info *pin,
char *oldpincode, char *oldpincode,
int oldpinlen, char *newpincode, int newpinlen); int oldpinlen, char *newpincode, int newpinlen);
int sc_pkcs15_find_pin_by_auth_id(struct sc_pkcs15_card *card,
const struct sc_pkcs15_id *id,
struct sc_pkcs15_pin_info **out);
int sc_pkcs15_compare_id(const struct sc_pkcs15_id *id1, int sc_pkcs15_compare_id(const struct sc_pkcs15_id *id1,
const struct sc_pkcs15_id *id2); const struct sc_pkcs15_id *id2);
void sc_pkcs15_print_id(const struct sc_pkcs15_id *id); void sc_pkcs15_print_id(const struct sc_pkcs15_id *id);
int sc_pkcs15_hex_string_to_id(const char *in, struct sc_pkcs15_id *out);
int sc_sec_ask_pin_code(struct sc_pkcs15_pin_info *pin,
char *out, int outlen, const char *prompt);
int sc_pkcs15_parse_common_object_attr(struct sc_pkcs15_common_obj_attr *attr, int sc_pkcs15_parse_common_object_attr(struct sc_pkcs15_common_obj_attr *attr,
const u8 * buf, int buflen); const u8 * buf, int buflen);

View File

@ -21,6 +21,7 @@
#ifndef _SC_H #ifndef _SC_H
#define _SC_H #define _SC_H
#include <pthread.h>
#include <winscard.h> #include <winscard.h>
#define SC_ERROR_MIN -1000 #define SC_ERROR_MIN -1000
@ -46,6 +47,9 @@
#define SC_ERROR_RESOURCE_MANAGER -1019 #define SC_ERROR_RESOURCE_MANAGER -1019
#define SC_ERROR_CARD_REMOVED -1020 #define SC_ERROR_CARD_REMOVED -1020
#define SC_ERROR_INVALID_PIN_LENGTH -1021 #define SC_ERROR_INVALID_PIN_LENGTH -1021
#define SC_ERROR_UNKNOWN_SMARTCARD -1022
#define SC_ERROR_UNKNOWN_REPLY -1023
#define SC_ERROR_OBJECT_NOT_FOUND -1024
#define SC_APDU_CASE_NONE 0 #define SC_APDU_CASE_NONE 0
#define SC_APDU_CASE_1 1 #define SC_APDU_CASE_1 1
@ -126,6 +130,7 @@ struct sc_card {
int atr_len; int atr_len;
const struct sc_defaults *defaults; const struct sc_defaults *defaults;
pthread_mutex_t mutex;
}; };
struct sc_context { struct sc_context {
@ -142,11 +147,13 @@ struct sc_apdu {
int datalen; /* length of C-APDU */ int datalen; /* length of C-APDU */
u8 *resp; /* R-APDU */ u8 *resp; /* R-APDU */
int resplen; /* length of R-APDU */ int resplen; /* length of R-APDU */
int no_response; /* No response required */
int sw1, sw2;
}; };
struct sc_security_env { struct sc_security_env {
int algorithm_ref; int algorithm_ref;
struct sc_path app_df_path;
struct sc_path key_file_id; struct sc_path key_file_id;
/* signature=1 ==> digital signing, signature=0 ==> authentication */ /* signature=1 ==> digital signing, signature=0 ==> authentication */
int signature; int signature;
@ -187,6 +194,7 @@ int sc_wait_for_card(struct sc_context *ctx, int reader, int timeout);
int sc_lock(struct sc_card *card); int sc_lock(struct sc_card *card);
int sc_unlock(struct sc_card *card); int sc_unlock(struct sc_card *card);
/* ISO 7816-4 related functions */ /* ISO 7816-4 related functions */
int sc_select_file(struct sc_card *card, struct sc_file *file, int sc_select_file(struct sc_card *card, struct sc_file *file,
const struct sc_path *path, int pathtype); const struct sc_path *path, int pathtype);
@ -201,6 +209,12 @@ int sc_decipher(struct sc_card *card, const u8 * crgram, int crgram_len,
u8 * out, int outlen); u8 * out, int outlen);
int sc_compute_signature(struct sc_card *card, const u8 * data, int sc_compute_signature(struct sc_card *card, const u8 * data,
int data_len, u8 * out, int outlen); int data_len, u8 * out, int outlen);
int sc_verify(struct sc_card *card, int ref, const u8 *buf, int buflen,
int *tries_left);
int sc_change_reference_data(struct sc_card *card, int ref, const u8 *old,
int oldlen, const u8 *new, int newlen);
int sc_reset_retry_counter(struct sc_card *card, int ref, const u8 *puk,
int puklen, const u8 *new, int newlen);
/* ISO 7816-9 */ /* ISO 7816-9 */
int sc_create_file(struct sc_card *card, const struct sc_file *file); int sc_create_file(struct sc_card *card, const struct sc_file *file);
@ -209,10 +223,14 @@ int sc_delete_file(struct sc_card *card, int file_id);
/* Possibly only on Setec cards */ /* Possibly only on Setec cards */
int sc_list_files(struct sc_card *card, u8 * buf, int buflen); int sc_list_files(struct sc_card *card, u8 * buf, int buflen);
int sc_file_valid(const struct sc_file *file);
const char *sc_strerror(int error); const char *sc_strerror(int error);
/* Internal use only */
int sc_file_valid(const struct sc_file *file);
void sc_hex_dump(const u8 *buf, int len); void sc_hex_dump(const u8 *buf, int len);
void sc_print_binary(const u8 *buf, int len); void sc_print_binary(const u8 *buf, int len);
int sc_hex_to_bin(const char *in, u8 *out, int *outlen);
int _sc_sw_to_errorcode(int sw1, int sw2);
extern int sc_debug; extern int sc_debug;
extern const char *sc_version; extern const char *sc_version;

View File

@ -169,10 +169,8 @@ int sc_pkcs15_verify_pin(struct sc_pkcs15_card *p15card,
{ {
int r; int r;
struct sc_file file; struct sc_file file;
struct sc_apdu apdu;
struct sc_card *card; struct sc_card *card;
char pinbuf[SC_MAX_PIN_SIZE]; char pinbuf[SC_MAX_PIN_SIZE];
char resp[MAX_BUFFER_SIZE];
assert(p15card != NULL); assert(p15card != NULL);
if (pin->magic != SC_PKCS15_PIN_MAGIC) if (pin->magic != SC_PKCS15_PIN_MAGIC)
@ -185,30 +183,15 @@ int sc_pkcs15_verify_pin(struct sc_pkcs15_card *p15card,
if (r) if (r)
return r; return r;
sc_format_apdu(p15card->card, &apdu, SC_APDU_CASE_3_SHORT,
0x20, 0, pin->auth_id.value[0]);
apdu.lc = pin->stored_length;
apdu.data = pinbuf;
apdu.datalen = pin->stored_length;
apdu.resp = resp;
apdu.resplen = 2;
memset(pinbuf, pin->pad_char, pin->stored_length); memset(pinbuf, pin->pad_char, pin->stored_length);
memcpy(pinbuf, pincode, pinlen); memcpy(pinbuf, pincode, pinlen);
r = sc_transmit_apdu(card, &apdu); r = sc_verify(card, pin->auth_id.value[0],
pinbuf, pin->stored_length, &pin->tries_left);
memset(pinbuf, 0, pinlen); memset(pinbuf, 0, pinlen);
if (r) if (r)
return r; return r;
if (apdu.resplen == 2) {
if (apdu.resp[0] == 0x90 && apdu.resp[1] == 0x00)
return 0; return 0;
if (apdu.resp[0] == 0x63 && (apdu.resp[1] & 0xF0) == 0xC0) {
pin->tries_left = apdu.resp[1] & 0x0F;
return SC_ERROR_PIN_CODE_INCORRECT;
}
}
return -1;
} }
int sc_pkcs15_change_pin(struct sc_pkcs15_card *p15card, int sc_pkcs15_change_pin(struct sc_pkcs15_card *p15card,
@ -263,3 +246,22 @@ int sc_pkcs15_change_pin(struct sc_pkcs15_card *p15card,
} }
return -1; return -1;
} }
int sc_pkcs15_find_pin_by_auth_id(struct sc_pkcs15_card *card,
const struct sc_pkcs15_id *id,
struct sc_pkcs15_pin_info **pin_out)
{
int r, i;
r = sc_pkcs15_enum_pins(card);
if (r < 0)
return r;
for (i = 0; i < card->pin_count; i++) {
struct sc_pkcs15_pin_info *pin = &card->pin_info[i];
if (sc_pkcs15_compare_id(&pin->auth_id, id) == 1) {
*pin_out = pin;
return 0;
}
}
return SC_ERROR_OBJECT_NOT_FOUND;
}

View File

@ -39,6 +39,9 @@ void sc_pkcs15_print_prkey_info(const struct sc_pkcs15_prkey_info *prkey)
for (i = 0; i < prkey->file_id.len; i++) for (i = 0; i < prkey->file_id.len; i++)
printf("%02X", prkey->file_id.value[i]); printf("%02X", prkey->file_id.value[i]);
printf("\n"); printf("\n");
printf("\tAuth ID : ");
sc_pkcs15_print_id(&prkey->com_attr.auth_id);
printf("\n");
printf("\tID : "); printf("\tID : ");
sc_pkcs15_print_id(&prkey->id); sc_pkcs15_print_id(&prkey->id);
printf("\n"); printf("\n");
@ -146,3 +149,22 @@ int sc_pkcs15_enum_private_keys(struct sc_pkcs15_card *card)
} }
return card->prkey_count; return card->prkey_count;
} }
int sc_pkcs15_find_prkey_by_id(struct sc_pkcs15_card *card,
const struct sc_pkcs15_id *id,
struct sc_pkcs15_prkey_info **key_out)
{
int r, i;
r = sc_pkcs15_enum_private_keys(card);
if (r < 0)
return r;
for (i = 0; i < card->prkey_count; i++) {
struct sc_pkcs15_prkey_info *key = &card->prkey_info[i];
if (sc_pkcs15_compare_id(&key->id, id) == 1) {
*key_out = key;
return 0;
}
}
return SC_ERROR_OBJECT_NOT_FOUND;
}

View File

@ -0,0 +1,56 @@
/*
* sc-pkcs15-sec.c: PKCS#15 cryptography functions
*
* Copyright (C) 2001 Juha Yrjölä <juha.yrjola@iki.fi>
*
* 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 "sc.h"
#include "sc-pkcs15.h"
#include <assert.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
int sc_pkcs15_decipher(struct sc_pkcs15_card *p15card,
const struct sc_pkcs15_prkey_info *prkey,
const u8 * in, int inlen, u8 *out, int outlen)
{
int r;
struct sc_security_env senv;
senv.algorithm_ref = 0x02;
senv.key_file_id = prkey->file_id;
senv.signature = 0;
senv.key_ref = prkey->key_reference;
r = sc_select_file(p15card->card, &p15card->file_app,
&p15card->file_app.path, SC_SELECT_FILE_BY_PATH);
if (r)
return r;
r = sc_restore_security_env(p15card->card, 0); /* empty SE */
if (r)
return r;
r = sc_set_security_env(p15card->card, &senv);
if (r)
return r;
r = sc_decipher(p15card->card, in, inlen, out, outlen);
if (r)
return r;
return 0;
}

View File

@ -230,7 +230,9 @@ int sc_pkcs15_init(struct sc_card *card,
memset(p15card, 0, sizeof(struct sc_pkcs15_card)); memset(p15card, 0, sizeof(struct sc_pkcs15_card));
p15card->card = card; p15card->card = card;
if (card->defaults != NULL && card->defaults->pkcs15_defaults_func != NULL) { if (card->defaults != NULL && card->defaults->pkcs15_defaults_func == NULL)
return SC_ERROR_NOT_SUPPORTED;
if (card->defaults != NULL) {
card->defaults->pkcs15_defaults_func(p15card); card->defaults->pkcs15_defaults_func(p15card);
err = sc_select_file(card, &p15card->file_tokeninfo, err = sc_select_file(card, &p15card->file_tokeninfo,
&p15card->file_tokeninfo.path, &p15card->file_tokeninfo.path,
@ -369,3 +371,9 @@ void sc_pkcs15_print_id(const struct sc_pkcs15_id *id)
for (i = 0; i < id->len; i++) for (i = 0; i < id->len; i++)
printf("%02X", id->value[i]); printf("%02X", id->value[i]);
} }
int sc_pkcs15_hex_string_to_id(const char *in, struct sc_pkcs15_id *out)
{
out->len = sizeof(out->value);
return sc_hex_to_bin(in, out->value, &out->len);
}

View File

@ -158,6 +158,11 @@ struct sc_pkcs15_card {
int sc_pkcs15_init(struct sc_card *card, int sc_pkcs15_init(struct sc_card *card,
struct sc_pkcs15_card **pkcs15_card); struct sc_pkcs15_card **pkcs15_card);
int sc_pkcs15_destroy(struct sc_pkcs15_card *card); int sc_pkcs15_destroy(struct sc_pkcs15_card *card);
int sc_pkcs15_decipher(struct sc_pkcs15_card *p15card,
const struct sc_pkcs15_prkey_info *prkey,
const u8 * in, int inlen, u8 *out, int outlen);
void sc_pkcs15_print_card(const struct sc_pkcs15_card *card); void sc_pkcs15_print_card(const struct sc_pkcs15_card *card);
void sc_pkcs15_print_cert_info(const struct sc_pkcs15_cert_info *cert); void sc_pkcs15_print_cert_info(const struct sc_pkcs15_cert_info *cert);
@ -169,6 +174,9 @@ void sc_pkcs15_free_certificate(struct sc_pkcs15_cert *cert);
void sc_pkcs15_print_prkey_info(const struct sc_pkcs15_prkey_info *prkey); void sc_pkcs15_print_prkey_info(const struct sc_pkcs15_prkey_info *prkey);
int sc_pkcs15_enum_private_keys(struct sc_pkcs15_card *card); int sc_pkcs15_enum_private_keys(struct sc_pkcs15_card *card);
int sc_pkcs15_find_prkey_by_id(struct sc_pkcs15_card *card,
const struct sc_pkcs15_id *id,
struct sc_pkcs15_prkey_info **out);
void sc_pkcs15_print_pin_info(const struct sc_pkcs15_pin_info *pin); void sc_pkcs15_print_pin_info(const struct sc_pkcs15_pin_info *pin);
int sc_pkcs15_enum_pins(struct sc_pkcs15_card *card); int sc_pkcs15_enum_pins(struct sc_pkcs15_card *card);
@ -179,13 +187,14 @@ int sc_pkcs15_change_pin(struct sc_pkcs15_card *card,
struct sc_pkcs15_pin_info *pin, struct sc_pkcs15_pin_info *pin,
char *oldpincode, char *oldpincode,
int oldpinlen, char *newpincode, int newpinlen); int oldpinlen, char *newpincode, int newpinlen);
int sc_pkcs15_find_pin_by_auth_id(struct sc_pkcs15_card *card,
const struct sc_pkcs15_id *id,
struct sc_pkcs15_pin_info **out);
int sc_pkcs15_compare_id(const struct sc_pkcs15_id *id1, int sc_pkcs15_compare_id(const struct sc_pkcs15_id *id1,
const struct sc_pkcs15_id *id2); const struct sc_pkcs15_id *id2);
void sc_pkcs15_print_id(const struct sc_pkcs15_id *id); void sc_pkcs15_print_id(const struct sc_pkcs15_id *id);
int sc_pkcs15_hex_string_to_id(const char *in, struct sc_pkcs15_id *out);
int sc_sec_ask_pin_code(struct sc_pkcs15_pin_info *pin,
char *out, int outlen, const char *prompt);
int sc_pkcs15_parse_common_object_attr(struct sc_pkcs15_common_obj_attr *attr, int sc_pkcs15_parse_common_object_attr(struct sc_pkcs15_common_obj_attr *attr,
const u8 * buf, int buflen); const u8 * buf, int buflen);

View File

@ -29,18 +29,18 @@
const char *sc_version = LIBSC_VERSION; const char *sc_version = LIBSC_VERSION;
int sc_debug = 1; int sc_debug = 1;
static int convert_sw_to_errorcode(u8 * sw) int _sc_sw_to_errorcode(int sw1, int sw2)
{ {
switch (sw[0]) { switch (sw1) {
case 0x69: case 0x69:
switch (sw[1]) { switch (sw2) {
case 0x82: case 0x82:
return SC_ERROR_SECURITY_STATUS_NOT_SATISFIED; return SC_ERROR_SECURITY_STATUS_NOT_SATISFIED;
default: default:
return SC_ERROR_UNKNOWN; return SC_ERROR_UNKNOWN_REPLY;
} }
case 0x6A: case 0x6A:
switch (sw[1]) { switch (sw2) {
case 0x81: case 0x81:
return SC_ERROR_NOT_SUPPORTED; return SC_ERROR_NOT_SUPPORTED;
case 0x82: case 0x82:
@ -50,15 +50,18 @@ static int convert_sw_to_errorcode(u8 * sw)
case 0x87: case 0x87:
return SC_ERROR_INVALID_ARGUMENTS; return SC_ERROR_INVALID_ARGUMENTS;
default: default:
return SC_ERROR_UNKNOWN; return SC_ERROR_UNKNOWN_REPLY;
} }
case 0x6D: case 0x6D:
return SC_ERROR_NOT_SUPPORTED; return SC_ERROR_NOT_SUPPORTED;
case 0x6E:
return SC_ERROR_UNKNOWN_SMARTCARD;
case 0x90: case 0x90:
if (sw[1] == 0) if (sw2 == 0)
return 0; return 0;
return SC_ERROR_UNKNOWN_REPLY;
} }
return SC_ERROR_UNKNOWN; return SC_ERROR_UNKNOWN_REPLY;
} }
void sc_hex_dump(const u8 *buf, int count) void sc_hex_dump(const u8 *buf, int count)
@ -90,6 +93,35 @@ void sc_print_binary(const u8 *buf, int count)
fflush(stdout); fflush(stdout);
} }
int sc_hex_to_bin(const char *in, u8 *out, int *outlen)
{
int c = 0, err = 0, left;
assert(in != NULL && out != NULL && outlen != NULL);
left = *outlen;
while (*in) {
int byte;
if (sscanf(in, "%02X", &byte) != 1) {
err = SC_ERROR_INVALID_ARGUMENTS;
break;
}
in += 2;
if (*in == ':')
in++;
if (left <= 0) {
err = SC_ERROR_BUFFER_TOO_SMALL;
break;
}
*out++ = byte;
left--;
c++;
}
*outlen = c;
return err;
}
int sc_check_apdu(const struct sc_apdu *apdu) int sc_check_apdu(const struct sc_apdu *apdu)
{ {
switch (apdu->cse) { switch (apdu->cse) {
@ -170,7 +202,7 @@ static int sc_transceive_t0(struct sc_card *card, struct sc_apdu *apdu)
sRecvPci.cbPciLength = 0; sRecvPci.cbPciLength = 0;
dwSendLength = data - s; dwSendLength = data - s;
dwRecvLength = apdu->resplen; dwRecvLength = apdu->resplen + 2;
if (sc_debug > 2) { if (sc_debug > 2) {
printf("Sending: "); printf("Sending: ");
sc_hex_dump(s, dwSendLength); sc_hex_dump(s, dwSendLength);
@ -192,7 +224,13 @@ static int sc_transceive_t0(struct sc_card *card, struct sc_apdu *apdu)
} }
} }
} }
if (dwRecvLength < 2)
return SC_ERROR_UNKNOWN_RESPONSE;
apdu->sw1 = r[dwRecvLength-2];
apdu->sw2 = r[dwRecvLength-1];
dwRecvLength -= 2;
apdu->resplen = dwRecvLength; apdu->resplen = dwRecvLength;
if (dwRecvLength)
memcpy(apdu->resp, r, dwRecvLength); memcpy(apdu->resp, r, dwRecvLength);
return 0; return 0;
@ -209,20 +247,25 @@ int sc_transmit_apdu(struct sc_card *card, struct sc_apdu *apdu)
if (r) if (r)
return r; return r;
if (sc_debug > 2) { if (sc_debug > 2) {
printf("Received: "); printf("Received (SW1=%02X SW2=%02X)", apdu->sw1, apdu->sw2);
if (apdu->resplen) {
printf(": ");
sc_hex_dump(apdu->resp, apdu->resplen); sc_hex_dump(apdu->resp, apdu->resplen);
} else
printf("\n");
} }
if (apdu->resp[0] == 0x61 && apdu->resplen == 2) { if (apdu->sw1 == 0x61 && apdu->resplen == 0) {
struct sc_apdu rspapdu; struct sc_apdu rspapdu;
BYTE rsp[MAX_BUFFER_SIZE]; BYTE rsp[MAX_BUFFER_SIZE];
rspapdu.cla = apdu->cla; if (apdu->no_response)
rspapdu.cse = SC_APDU_CASE_2_SHORT; return 0;
rspapdu.ins = 0xC0;
rspapdu.p1 = rspapdu.p2 = 0; sc_format_apdu(card, &rspapdu, SC_APDU_CASE_2_SHORT,
rspapdu.le = apdu->resp[1]; 0xC0, 0, 0);
rspapdu.le = apdu->sw2;
rspapdu.resp = rsp; rspapdu.resp = rsp;
rspapdu.resplen = apdu->resp[1] + 2; rspapdu.resplen = apdu->sw2;
r = sc_transceive_t0(card, &rspapdu); r = sc_transceive_t0(card, &rspapdu);
if (r) { if (r) {
fprintf(stderr, "Error %d when getting response\n", fprintf(stderr, "Error %d when getting response\n",
@ -230,11 +273,15 @@ int sc_transmit_apdu(struct sc_card *card, struct sc_apdu *apdu)
return r; return r;
} }
if (sc_debug > 2) { if (sc_debug > 2) {
printf("Response: "); printf("Response (SW1=%02X SW2=%02X): ", rspapdu.sw1,
rspapdu.sw2);
sc_hex_dump(rspapdu.resp, rspapdu.resplen); sc_hex_dump(rspapdu.resp, rspapdu.resplen);
} }
/* FIXME: Check apdu->resplen */
memcpy(apdu->resp, rspapdu.resp, rspapdu.resplen); memcpy(apdu->resp, rspapdu.resp, rspapdu.resplen);
apdu->resplen = rspapdu.resplen; apdu->resplen = rspapdu.resplen;
apdu->sw1 = rspapdu.sw1;
apdu->sw2 = rspapdu.sw2;
} }
return 0; return 0;
} }
@ -333,7 +380,7 @@ int sc_select_file(struct sc_card *card,
{ {
struct sc_context *ctx; struct sc_context *ctx;
struct sc_apdu apdu; struct sc_apdu apdu;
char buf[MAX_BUFFER_SIZE], cmd[15]; char buf[MAX_BUFFER_SIZE];
u8 pathbuf[SC_MAX_PATH_SIZE], *path = pathbuf; u8 pathbuf[SC_MAX_PATH_SIZE], *path = pathbuf;
int r, pathlen; int r, pathlen;
@ -345,12 +392,10 @@ int sc_select_file(struct sc_card *card,
memcpy(path, in_path->value, in_path->len); memcpy(path, in_path->value, in_path->len);
pathlen = in_path->len; pathlen = in_path->len;
apdu.cse = SC_APDU_CASE_3_SHORT; sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xA4, 0, 0);
apdu.cla = card->class;
apdu.ins = 0xA4;
apdu.resp = buf; apdu.resp = buf;
apdu.resplen = 2; apdu.resplen = 0;
memcpy(cmd, "\x00\xA4", 2);
switch (pathtype) { switch (pathtype) {
case SC_SELECT_FILE_BY_FILE_ID: case SC_SELECT_FILE_BY_FILE_ID:
apdu.p1 = 0; apdu.p1 = 0;
@ -376,47 +421,37 @@ int sc_select_file(struct sc_card *card,
apdu.lc = pathlen; apdu.lc = pathlen;
apdu.data = path; apdu.data = path;
apdu.datalen = pathlen; apdu.datalen = pathlen;
#if 0
/* FIXME: Some smarter way to do this... */ if (file != NULL) {
if (file == NULL || sc_file_valid(file)) {
r = sc_transceive_t0(card, &apdu); /* we don't need the response */
if (apdu.resplen == 2 && apdu.resp[0] == 0x61) {
apdu.resp[0] = 0x90;
apdu.resp[1] = 0;
}
} else {
#endif
if (file != NULL)
memset(file, 0, sizeof(*file)); memset(file, 0, sizeof(*file));
r = sc_transmit_apdu(card, &apdu);
#if 0
}
#endif
if (r)
return r;
if (apdu.resplen < 2)
return SC_ERROR_UNKNOWN_RESPONSE;
switch (apdu.resp[0]) {
case 0x6F:
break;
case 0x90:
case 0x00: /* proprietary coding */
return 0;
default:
return convert_sw_to_errorcode(apdu.resp);
}
if (file == NULL)
return 0;
if (pathtype == SC_SELECT_FILE_BY_PATH) {
memcpy(&file->path.value, path, pathlen); memcpy(&file->path.value, path, pathlen);
file->path.len = pathlen; file->path.len = pathlen;
} }
if (apdu.resp[0] == 0x6F) { if (file == NULL || sc_file_valid(file))
// int l1 = apdu.resplen - 2, l2 = apdu.resp[1]; apdu.no_response = 1;
int l1 = apdu.resplen, l2 = apdu.resp[1]; r = sc_transmit_apdu(card, &apdu);
int len = l1 > l2 ? l2 : l1; if (r)
return r;
process_fci(file, apdu.resp + 2, len); if (apdu.no_response) {
if (apdu.sw1 == 0x61)
return 0;
return _sc_sw_to_errorcode(apdu.sw1, apdu.sw2);
}
r = _sc_sw_to_errorcode(apdu.sw1, apdu.sw2);
if (r)
return r;
switch (apdu.resp[0]) {
case 0x6F:
if (file != NULL && apdu.resp[1] <= apdu.resplen)
process_fci(file, apdu.resp+2, apdu.resp[1]);
break;
case 0x00: /* proprietary coding */
return 0;
default:
return SC_ERROR_UNKNOWN_RESPONSE;
} }
return 0; return 0;
} }
@ -426,14 +461,12 @@ int sc_read_binary(struct sc_card *card,
{ {
#define RB_BUF_SIZE 250 #define RB_BUF_SIZE 250
struct sc_apdu apdu; struct sc_apdu apdu;
struct sc_context *ctx;
u8 recvbuf[MAX_BUFFER_SIZE]; u8 recvbuf[MAX_BUFFER_SIZE];
int r; int r;
assert(card != NULL && buf != NULL); assert(card != NULL && buf != NULL);
ctx = card->context; if (count == 0)
return 0;
memset(&apdu, 0, sizeof(apdu));
if (count > RB_BUF_SIZE) { if (count > RB_BUF_SIZE) {
int bytes_read = 0; int bytes_read = 0;
unsigned char *p = buf; unsigned char *p = buf;
@ -452,38 +485,25 @@ int sc_read_binary(struct sc_card *card,
} }
return bytes_read; return bytes_read;
} }
apdu.cse = SC_APDU_CASE_2_SHORT; sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xB0,
apdu.cla = 0; (idx >> 8) & 0x7F, idx & 0xFF);
apdu.ins = 0xB0;
apdu.p1 = (idx >> 8) & 0x7f;
apdu.p2 = idx & 0xFF;
apdu.le = count; apdu.le = count;
apdu.resplen = count + 2; apdu.resplen = count;
apdu.resp = recvbuf; apdu.resp = recvbuf;
r = sc_transmit_apdu(card, &apdu); r = sc_transmit_apdu(card, &apdu);
if (r) if (r)
return r; return r;
if (apdu.resplen == 2) { if (apdu.resplen == 0)
return convert_sw_to_errorcode(apdu.resp); return _sc_sw_to_errorcode(apdu.sw1, apdu.sw2);
}
if (apdu.resplen == count + 2)
apdu.resplen = count;
memcpy(buf, recvbuf, apdu.resplen); memcpy(buf, recvbuf, apdu.resplen);
if (sc_debug > 3) {
FILE *file = fopen("sc_recv", "w");
if (file != NULL) {
fwrite(buf, apdu.resplen, 1, file);
fclose(file);
}
}
return apdu.resplen; return apdu.resplen;
} }
int sc_format_apdu(struct sc_card *card, int sc_format_apdu(struct sc_card *card, struct sc_apdu *apdu,
struct sc_apdu *apdu, unsigned char cse, unsigned char ins,
unsigned char cse, unsigned char p1, unsigned char p2)
unsigned char ins, unsigned char p1, unsigned char p2)
{ {
assert(card != NULL && apdu != NULL); assert(card != NULL && apdu != NULL);
memset(apdu, 0, sizeof(*apdu)); memset(apdu, 0, sizeof(*apdu));
@ -492,6 +512,8 @@ int sc_format_apdu(struct sc_card *card,
apdu->ins = ins; apdu->ins = ins;
apdu->p1 = p1; apdu->p1 = p1;
apdu->p2 = p2; apdu->p2 = p2;
apdu->no_response = 0;
return 0; return 0;
} }
@ -691,6 +713,7 @@ int sc_connect_card(struct sc_context *ctx,
} else { } else {
card->class = 0; /* FIXME */ card->class = 0; /* FIXME */
} }
pthread_mutex_init(&card->mutex, NULL);
*card_out = card; *card_out = card;
return 0; return 0;
@ -700,6 +723,7 @@ int sc_disconnect_card(struct sc_card *card)
{ {
assert(card != NULL); assert(card != NULL);
SCardDisconnect(card->pcsc_card, SCARD_LEAVE_CARD); SCardDisconnect(card->pcsc_card, SCARD_LEAVE_CARD);
pthread_mutex_destroy(&card->mutex);
return 0; return 0;
} }
@ -727,7 +751,10 @@ const char *sc_strerror(int error)
"Card not present", "Card not present",
"Error with Resource Manager", "Error with Resource Manager",
"Card removed", "Card removed",
"Invalid PIN length" "Invalid PIN length",
"Unknown SmartCard",
"Unknown reply from SmartCard",
"Requested object not found",
}; };
int nr_errors = sizeof(errors) / sizeof(errors[0]); int nr_errors = sizeof(errors) / sizeof(errors[0]);
@ -740,156 +767,7 @@ const char *sc_strerror(int error)
return errors[error]; return errors[error];
} }
int sc_set_security_env(struct sc_card *card, int _sc_lock_int(struct sc_card *card)
const struct sc_security_env *env)
{
struct sc_apdu apdu;
u8 recv[MAX_BUFFER_SIZE], send[MAX_BUFFER_SIZE];
u8 *p;
int r;
struct sc_file file;
assert(card != NULL && env != NULL);
r = sc_select_file(card, &file, &env->app_df_path,
SC_SELECT_FILE_BY_PATH);
if (r)
return r;
apdu.cla = card->class;
apdu.cse = SC_APDU_CASE_3_SHORT;
apdu.ins = 0x22;
if (env->signature) {
apdu.p1 = 0x81;
apdu.p2 = 0xB6;
} else {
apdu.p1 = 0x41;
apdu.p2 = 0xB8;
}
apdu.le = 0;
p = send;
*p++ = 0x80; /* algorithm reference */
*p++ = 1;
*p++ = env->algorithm_ref;
*p++ = 0x81;
*p++ = env->key_file_id.len;
memcpy(p, env->key_file_id.value, env->key_file_id.len);
p += env->key_file_id.len;
*p++ = 0x84;
*p++ = 1;
*p++ = env->key_ref;
r = p - send;
apdu.lc = r;
apdu.datalen = r;
apdu.data = send;
apdu.resplen = 2;
apdu.resp = recv;
r = sc_transmit_apdu(card, &apdu);
if (r)
return r;
if (apdu.resp[0] != 0x90) {
if (sc_debug)
fprintf(stderr, "Set sec env: SWs=%02X%02X\n",
apdu.resp[0], apdu.resp[1]);
return -1;
}
return 0;
}
int sc_restore_security_env(struct sc_card *card, int num)
{
struct sc_apdu apdu;
int r;
u8 rbuf[2];
assert(card != NULL);
sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0x22, 0xF3, num);
apdu.resp = rbuf;
apdu.resplen = 2;
r = sc_transmit_apdu(card, &apdu);
if (r)
return r;
if (apdu.resplen != 2)
return -1;
return convert_sw_to_errorcode(apdu.resp);
}
int sc_decipher(struct sc_card *card,
const u8 * crgram, int crgram_len, u8 * out, int outlen)
{
int r;
struct sc_apdu apdu;
u8 recv[MAX_BUFFER_SIZE];
u8 send[MAX_BUFFER_SIZE], *p;
assert(card != NULL && crgram != NULL && out != NULL);
if (crgram_len > 255)
return SC_ERROR_INVALID_ARGUMENTS;
sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x2A, 0x80,
0x86);
apdu.resp = recv;
apdu.resplen = 2;
send[0] = 0; /* padding indicator byte */ ;
memcpy(send + 1, crgram, crgram_len);
apdu.data = send;
apdu.lc = crgram_len + 1;
apdu.datalen = crgram_len + 1;
r = sc_transmit_apdu(card, &apdu);
if (r)
return r;
p = apdu.resp + apdu.resplen - 2;
if (p[0] == 0x90 && p[1] == 0x00) { /* FIXME */
int l1 = apdu.resplen - 2, l2 = outlen;
int len = l1 > l2 ? l2 : l1;
memcpy(out, apdu.resp, len);
return len;
}
if (sc_debug)
fprintf(stderr, "sc_decipher(): SW1=%02X, SW2=%02X\n", p[0], p[1]);
return convert_sw_to_errorcode(p);
}
int sc_compute_signature(struct sc_card *card,
const u8 * data,
int datalen, u8 * out, int outlen)
{
int r;
struct sc_apdu apdu;
u8 recv[MAX_BUFFER_SIZE], *p;
u8 send[MAX_BUFFER_SIZE];
assert(card != NULL && data != NULL && out != NULL);
if (datalen > 255)
return SC_ERROR_INVALID_ARGUMENTS;
sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x2A, 0x9E,
0x9A);
apdu.resp = recv;
apdu.resplen = 2;
memcpy(send, data, datalen);
apdu.data = send;
apdu.lc = datalen;
apdu.datalen = datalen;
r = sc_transmit_apdu(card, &apdu);
if (r)
return r;
p = apdu.resp + apdu.resplen - 2;
if (p[0] == 0x90 && p[1] == 0x00) { /* FIXME */
int l1 = apdu.resplen - 2, l2 = outlen;
int len = l1 > l2 ? l2 : l1;
memcpy(out, apdu.resp, len);
return len;
}
if (sc_debug)
fprintf(stderr, "sc_compute_signature(): SW1=%02X, SW2=%02X\n",
p[0], p[1]);
return convert_sw_to_errorcode(p);
}
int sc_lock(struct sc_card *card)
{ {
long rv; long rv;
@ -901,7 +779,13 @@ int sc_lock(struct sc_card *card)
return 0; return 0;
} }
int sc_unlock(struct sc_card *card) int sc_lock(struct sc_card *card)
{
pthread_mutex_lock(&card->mutex);
return _sc_lock_int(card);
}
int _sc_unlock_int(struct sc_card *card)
{ {
long rv; long rv;
@ -911,6 +795,12 @@ int sc_unlock(struct sc_card *card)
return 0; return 0;
} }
int sc_unlock(struct sc_card *card)
{
pthread_mutex_unlock(&card->mutex);
return _sc_unlock_int(card);
}
int sc_get_random(struct sc_card *card, u8 *rnd, int len) int sc_get_random(struct sc_card *card, u8 *rnd, int len)
{ {
int r; int r;
@ -921,7 +811,7 @@ int sc_get_random(struct sc_card *card, u8 *rnd, int len)
0x84, 0x00, 0x00); 0x84, 0x00, 0x00);
apdu.le = 8; apdu.le = 8;
apdu.resp = buf; apdu.resp = buf;
apdu.resplen = 10; /* include SW's */ apdu.resplen = 8; /* include SW's */
while (len > 0) { while (len > 0) {
int n = len > 8 ? 8 : len; int n = len > 8 ? 8 : len;
@ -929,11 +819,8 @@ int sc_get_random(struct sc_card *card, u8 *rnd, int len)
r = sc_transmit_apdu(card, &apdu); r = sc_transmit_apdu(card, &apdu);
if (r) if (r)
return r; return r;
if (apdu.resplen != 10) { if (apdu.resplen != 8)
if (apdu.resplen == 2) return _sc_sw_to_errorcode(apdu.sw1, apdu.sw2);
return convert_sw_to_errorcode(apdu.resp);
return SC_ERROR_UNKNOWN;
}
memcpy(rnd, apdu.resp, n); memcpy(rnd, apdu.resp, n);
len -= n; len -= n;
rnd += n; rnd += n;
@ -953,12 +840,8 @@ int sc_list_files(struct sc_card *card, u8 *buf, int buflen)
r = sc_transmit_apdu(card, &apdu); r = sc_transmit_apdu(card, &apdu);
if (r) if (r)
return r; return r;
if (apdu.resplen < 2) if (apdu.resplen == 0)
return -1; /* FIXME */ return _sc_sw_to_errorcode(apdu.sw1, apdu.sw2);
if (apdu.resplen == 2)
return convert_sw_to_errorcode(apdu.resp);
apdu.resplen -= 2;
return apdu.resplen; return apdu.resplen;
} }
@ -1018,11 +901,7 @@ int sc_create_file(struct sc_card *card, const struct sc_file *file)
r = sc_transmit_apdu(card, &apdu); r = sc_transmit_apdu(card, &apdu);
if (r) if (r)
return r; return r;
if (apdu.resplen != 2) return _sc_sw_to_errorcode(apdu.sw1, apdu.sw2);
return -1;
if (apdu.resp[0] == 0x90 && apdu.resp[1] == 0x00)
return 0;
return convert_sw_to_errorcode(apdu.resp);
} }
int sc_delete_file(struct sc_card *card, int file_id) int sc_delete_file(struct sc_card *card, int file_id)
@ -1046,9 +925,7 @@ int sc_delete_file(struct sc_card *card, int file_id)
return r; return r;
if (apdu.resplen != 2) if (apdu.resplen != 2)
return -1; return -1;
if (apdu.resp[0] == 0x90 && apdu.resp[1] == 0x00) return _sc_sw_to_errorcode(apdu.sw1, apdu.sw2);
return 0;
return convert_sw_to_errorcode(apdu.resp);
} }
int sc_file_valid(const struct sc_file *file) int sc_file_valid(const struct sc_file *file)

View File

@ -1,40 +1,240 @@
/*
/* Copyright (C) 2001 Juha Yrjölä <juha.yrjola@iki.fi> * sc-sec.c: Cryptography and security (ISO7816-8) functions
* All rights reserved. *
* Copyright (C) 2001 Juha Yrjölä <juha.yrjola@iki.fi>
*
* 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 "sc.h" #include "sc.h"
#include "sc-pkcs15.h"
#include <unistd.h> #include <unistd.h>
#include <stdio.h> #include <stdio.h>
#include <ctype.h> #include <assert.h>
int sc_sec_ask_pin_code(struct sc_pkcs15_pin_info *pin, int sc_set_security_env(struct sc_card *card,
char *out, int outlen, const char *prompt) const struct sc_security_env *env)
{ {
char buf[80]; struct sc_apdu apdu;
int i; u8 sbuf[MAX_BUFFER_SIZE];
u8 *p;
int r;
while (1) { assert(card != NULL && env != NULL);
printf("%s [%s]: ", prompt, pin->com_attr.label); sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x22, 0, 0);
fflush(stdin); if (env->signature) {
memset(buf, 0, sizeof(buf)); apdu.p1 = 0x81;
if (fgets(buf, 80, stdin) == NULL) apdu.p2 = 0xB6;
return -1; } else {
i = 0; apdu.p1 = 0x41;
while (isdigit(buf[i])) { apdu.p2 = 0xB8;
out[i] = buf[i];
i++;
if (i >= outlen)
continue;
} }
out[i] = 0; apdu.le = 0;
if (i < pin->min_length) p = sbuf;
continue; *p++ = 0x80; /* algorithm reference */
if (i > pin->stored_length) *p++ = 1;
continue; *p++ = env->algorithm_ref;
memset(buf, 0, sizeof(buf)); *p++ = 0x81;
break; *p++ = env->key_file_id.len;
} memcpy(p, env->key_file_id.value, env->key_file_id.len);
return 0; p += env->key_file_id.len;
*p++ = 0x84;
*p++ = 1;
*p++ = env->key_ref;
r = p - sbuf;
apdu.lc = r;
apdu.datalen = r;
apdu.data = sbuf;
apdu.resplen = 0;
r = sc_transmit_apdu(card, &apdu);
if (r)
return r;
return _sc_sw_to_errorcode(apdu.sw1, apdu.sw2);
}
int sc_restore_security_env(struct sc_card *card, int num)
{
struct sc_apdu apdu;
int r;
assert(card != NULL);
sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0x22, 0xF3, num);
apdu.resplen = 0;
r = sc_transmit_apdu(card, &apdu);
if (r)
return r;
return _sc_sw_to_errorcode(apdu.sw1, apdu.sw2);
}
int sc_decipher(struct sc_card *card,
const u8 * crgram, int crgram_len, u8 * out, int outlen)
{
int r;
struct sc_apdu apdu;
u8 rbuf[MAX_BUFFER_SIZE];
u8 sbuf[MAX_BUFFER_SIZE];
assert(card != NULL && crgram != NULL && out != NULL);
if (crgram_len > 255)
return SC_ERROR_INVALID_ARGUMENTS;
sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x2A, 0x80, 0x86);
apdu.resp = rbuf;
apdu.resplen = 2; /* FIXME */
sbuf[0] = 0; /* padding indicator byte */ ;
memcpy(sbuf + 1, crgram, crgram_len);
apdu.data = sbuf;
apdu.lc = crgram_len + 1;
apdu.datalen = crgram_len + 1;
r = sc_transmit_apdu(card, &apdu);
if (r)
return r;
if (apdu.sw1 == 0x90 && apdu.sw2 == 0x00) {
int len = apdu.resplen > outlen ? outlen : apdu.resplen;
memcpy(out, apdu.resp, len);
return len;
}
if (sc_debug)
fprintf(stderr, "sc_decipher(): SW1=%02X, SW2=%02X\n",
apdu.sw1, apdu.sw2);
return _sc_sw_to_errorcode(apdu.sw1, apdu.sw2);
}
int sc_compute_signature(struct sc_card *card,
const u8 * data,
int datalen, u8 * out, int outlen)
{
int r;
struct sc_apdu apdu;
u8 rbuf[MAX_BUFFER_SIZE];
u8 sbuf[MAX_BUFFER_SIZE];
assert(card != NULL && data != NULL && out != NULL);
if (datalen > 255)
return SC_ERROR_INVALID_ARGUMENTS;
sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x2A, 0x9E,
0x9A);
apdu.resp = rbuf;
apdu.resplen = 2; /* FIXME */
memcpy(sbuf, data, datalen);
apdu.data = sbuf;
apdu.lc = datalen;
apdu.datalen = datalen;
r = sc_transmit_apdu(card, &apdu);
if (r)
return r;
if (apdu.sw1 == 0x90 && apdu.sw2 == 0x00) {
int len = apdu.resplen > outlen ? outlen : apdu.resplen;
memcpy(out, apdu.resp, len);
return len;
}
if (sc_debug)
fprintf(stderr, "sc_compute_signature(): SW1=%02X, SW2=%02X\n",
apdu.sw1, apdu.sw2);
return _sc_sw_to_errorcode(apdu.sw1, apdu.sw2);
}
int sc_verify(struct sc_card *card, int ref, const u8 *pin, int pinlen,
int *tries_left)
{
struct sc_apdu apdu;
u8 sbuf[MAX_BUFFER_SIZE];
int r;
if (pinlen >= MAX_BUFFER_SIZE)
return SC_ERROR_INVALID_ARGUMENTS;
sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x20, 0, ref);
memcpy(sbuf, pin, pinlen);
apdu.lc = pinlen;
apdu.datalen = pinlen;
apdu.data = sbuf;
apdu.resplen = 0;
r = sc_transmit_apdu(card, &apdu);
memset(sbuf, 0, pinlen);
if (r)
return r;
if (apdu.sw1 == 0x63 && (apdu.sw2 && 0xF0) == 0xC0) {
if (tries_left != NULL)
*tries_left = apdu.sw2 & 0x0F;
return SC_ERROR_PIN_CODE_INCORRECT;
}
return _sc_sw_to_errorcode(apdu.sw1, apdu.sw2);
}
int sc_change_reference_data(struct sc_card *card, int ref, const u8 *old,
int oldlen, const u8 *new, int newlen)
{
struct sc_apdu apdu;
u8 sbuf[MAX_BUFFER_SIZE];
int r, p1 = 0, len = oldlen + newlen;
if (len >= MAX_BUFFER_SIZE)
return SC_ERROR_INVALID_ARGUMENTS;
if (oldlen == 0)
p1 = 1;
sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x24, p1, ref);
memcpy(sbuf, old, oldlen);
memcpy(sbuf + oldlen, new, newlen);
apdu.lc = len;
apdu.datalen = len;
apdu.data = sbuf;
apdu.resplen = 0;
r = sc_transmit_apdu(card, &apdu);
memset(sbuf, 0, len);
if (r)
return r;
return _sc_sw_to_errorcode(apdu.sw1, apdu.sw2);
}
int sc_reset_retry_counter(struct sc_card *card, int ref, const u8 *puk,
int puklen, const u8 *new, int newlen)
{
struct sc_apdu apdu;
u8 sbuf[MAX_BUFFER_SIZE];
int r, p1 = 0, len = puklen + newlen;
if (len >= MAX_BUFFER_SIZE)
return SC_ERROR_INVALID_ARGUMENTS;
if (puklen == 0) {
if (newlen == 0)
p1 = 3;
else
p1 = 2;
} else {
if (newlen == 0)
p1 = 1;
else
p1 = 0;
}
sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x2C, p1, ref);
memcpy(sbuf, puk, puklen);
memcpy(sbuf + puklen, new, newlen);
apdu.lc = len;
apdu.datalen = len;
apdu.data = sbuf;
apdu.resplen = 0;
r = sc_transmit_apdu(card, &apdu);
memset(sbuf, 0, len);
if (r)
return r;
return _sc_sw_to_errorcode(apdu.sw1, apdu.sw2);
} }

315
src/openssh/opensc-ssh.c Normal file
View File

@ -0,0 +1,315 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <getopt.h>
#include <openssl/x509.h>
#include <openssl/evp.h>
#include <openssl/rsa.h>
#include <sc.h>
#include <sc-pkcs15.h>
int quiet = 0;
char *opt_outfile = NULL;
char *opt_cert = NULL;
const struct option options[] = {
{ "extract-key", 0, 0, 'k' },
{ "certificate-id", 1, 0, 'c' },
{ "reader", 1, 0, 'r' },
{ "output", 1, 0, 'o' },
{ "quiet", 0, 0, 'q' },
{ 0, 0, 0, 0 }
};
const char *option_help[] = {
"Extracts the public key from a certificate",
"Uses certificate with ID <arg>",
"Uses reader number <arg>",
"Outputs to file <arg>",
"Quiet operation",
};
struct sc_context *ctx = NULL;
struct sc_card *card = NULL;
struct sc_pkcs15_card *p15card = NULL;
void print_usage_and_die()
{
int i = 0;
printf("Usage: sc-ssh [OPTIONS]\nOptions:\n");
while (options[i].name) {
char buf[40], tmp[5];
const char *arg_str;
if (options[i].val > 0 && options[i].val < 128)
sprintf(tmp, ", -%c", options[i].val);
else
tmp[0] = 0;
switch (options[i].has_arg) {
case 1:
arg_str = " <arg>";
break;
case 2:
arg_str = " [arg]";
break;
default:
arg_str = "";
break;
}
sprintf(buf, "--%s%s%s", options[i].name, tmp, arg_str);
printf(" %-30s%s\n", buf, option_help[i]);
i++;
}
exit(2);
}
u8 * bignum_to_buf(BIGNUM *value, int *length, int *skip)
{
/* Function ripped from bufaux.c in OpenSSH
* Compliments to Tatu Ylönen */
int bytes = BN_num_bytes(value) + 1;
u8 *buf = malloc(bytes);
int oi;
int hasnohigh = 0;
buf[0] = '\0';
if (buf == NULL)
return NULL;
/* Get the value of in binary */
oi = BN_bn2bin(value, buf+1);
if (oi != bytes-1)
return NULL;
hasnohigh = (buf[1] & 0x80) ? 0 : 1;
if (value->neg) {
/**XXX should be two's-complement */
int i, carry;
u_char *uc = buf;
for(i = bytes-1, carry = 1; i>=0; i--) {
uc[i] ^= 0xff;
if(carry)
carry = !++uc[i];
}
}
*skip = hasnohigh;
*length = bytes;
return buf;
}
int put_string(const u8 *in, int inlen, u8 *out, int outlen, int *skip)
{
u8 *out0 = out;
if (outlen < 4 + inlen)
return -1;
*out++ = (inlen >> 24) & 0xFF;
*out++ = (inlen >> 16) & 0xFF;
*out++ = (inlen >> 8) & 0xFF;
*out++ = (inlen) & 0xFF;
memcpy(out, in, inlen);
out += inlen;
*skip = out - out0;
return 0;
}
int write_ssh_key(struct sc_pkcs15_cert_info *cinfo, RSA *rsa)
{
u8 *buf = malloc(10240), *p = buf, *num;
int r, len, skip, left = 10240;
if (buf == NULL)
return 1;
put_string("ssh-rsa", 7, p, left, &skip);
left -= skip;
p += skip;
num = bignum_to_buf(rsa->e, &len, &skip);
if (num == NULL)
return 1;
put_string(num+skip, len-skip, p, left, &skip);
left -= skip;
p += skip;
free(num);
num = bignum_to_buf(rsa->n, &len, &skip);
if (num == NULL)
return 1;
put_string(num+skip, len-skip, p, left, &skip);
left -= skip;
p += skip;
free(num);
len = p - buf;
p = malloc(len*5/3);
r = sc_base64_encode(buf, len, p, len*5/3, 0);
if (r) {
fprintf(stderr, "Base64 encoding failed: %s\n", sc_strerror(r));
return 1;
}
printf("ssh-rsa %s libsc-cert-%02X\n", p, cinfo->id.value[0]);
free(p),
free(buf);
return 0;
}
int extract_key()
{
int r, i;
struct sc_pkcs15_id id;
u8 *p = id.value;
char *certp = opt_cert;
struct sc_pkcs15_cert_info *cinfo;
struct sc_pkcs15_cert *cert;
X509 *x509;
EVP_PKEY *pubkey;
if (opt_cert) {
if (strlen(opt_cert)/2 >= SC_PKCS15_MAX_ID_SIZE) {
fprintf(stderr, "Certificate id too long.\n");
return 2;
}
id.len = 0;
while (*certp) {
int byte;
if (sscanf(certp, "%02X", &byte) != 1)
break;
certp += 2;
*p = byte;
p++;
id.len++;
}
}
r = sc_pkcs15_enum_certificates(p15card);
if (r < 0) {
fprintf(stderr, "Certificate enumeration failed: %s\n", sc_strerror(r));
return 1;
}
if (opt_cert) {
for (i = 0; i < p15card->cert_count; i++) {
cinfo = &p15card->cert_info[i];
if (sc_pkcs15_compare_id(&id, &cinfo->id) == 1)
break;
}
if (i == p15card->cert_count) {
fprintf(stderr, "Certificate with ID '%s' not found.\n", opt_cert);
return 2;
}
} else {
cinfo = &p15card->cert_info[0];
}
if (!quiet)
fprintf(stderr, "Using certificate '%s'.\n", cinfo->com_attr.label);
r = sc_pkcs15_read_certificate(p15card, cinfo, &cert);
if (r) {
fprintf(stderr, "Certificate read failed: %s\n", sc_strerror(r));
return 1;
}
x509 = X509_new();
p = cert->data;
if (!d2i_X509(&x509, &p, cert->data_len)) {
fprintf(stderr, "Unable to parse X.509 certificate.\n");
return 1;
}
pubkey = X509_get_pubkey(x509);
if (pubkey->type != EVP_PKEY_RSA) {
fprintf(stderr, "Public key is of unknown type.\n");
return 1;
}
r = write_ssh_key(cinfo, pubkey->pkey.rsa);
EVP_PKEY_free(pubkey);
X509_free(x509);
return r;
}
int main(int argc, char *const argv[])
{
int err = 0, r, c, long_optind = 0;
int action_count = 0, do_extract_key = 0;
int opt_reader = 0;
while (1) {
c = getopt_long(argc, argv, "r:o:qkc:", options, &long_optind);
if (c == -1)
break;
if (c == '?')
continue;
switch (c) {
case 'k':
do_extract_key = 1;
action_count++;
break;
case 'c':
opt_cert = optarg;
break;
case 'r':
opt_reader = atoi(optarg);
break;
case 'o':
opt_outfile = optarg;
break;
case 'q':
quiet++;
break;
}
}
if (action_count == 0)
print_usage_and_die();
r = sc_establish_context(&ctx);
if (r) {
fprintf(stderr, "Failed to establish context: %s\n", sc_strerror(r));
return 1;
}
if (opt_reader >= ctx->reader_count || opt_reader < 0) {
fprintf(stderr, "Illegal reader number. Only %d reader(s) configured.\n", ctx->reader_count);
err = 1;
goto end;
}
if (sc_detect_card(ctx, opt_reader) != 1) {
fprintf(stderr, "Card not present.\n");
return 3;
}
if (!quiet)
fprintf(stderr, "Connecting to card in reader %s...\n", ctx->readers[opt_reader]);
r = sc_connect_card(ctx, opt_reader, &card);
if (r) {
fprintf(stderr, "Failed to connect to card: %s\n", sc_strerror(r));
err = 1;
goto end;
}
sc_lock(card);
if (!quiet)
fprintf(stderr, "Trying to find a PKCS#15 compatible card...\n");
r = sc_pkcs15_init(card, &p15card);
if (r) {
fprintf(stderr, "PKCS#15 initialization failed: %s\n", sc_strerror(r));
err = 1;
goto end;
}
if (!quiet)
fprintf(stderr, "Found %s!\n", p15card->label);
if (do_extract_key) {
if ((err = extract_key()))
goto end;
action_count--;
}
end:
if (p15card)
sc_pkcs15_destroy(p15card);
if (card) {
sc_unlock(card);
sc_disconnect_card(card);
}
if (ctx)
sc_destroy_context(ctx);
return err;
}

View File

@ -1,14 +1,16 @@
Steps required to make the PAM module work: Steps required to make the PAM module work:
1. Compile and link the pam_pkcs15.so shared library. 1. Compile and link the pam_pkcs15.so shared library (type 'make').
2. Copy pam_pkcs.so to /lib/security. 2. Copy pam_pkcs.so to /lib/security.
3. Edit /etc/pam.d/login file. Add the following line before the 3. Edit /etc/pam.d/login file. Add the following line before the
pam_unix.so (on Debian) or pam_pwdb.so (on Red Hat) entry: pam_unix.so (Debian) or pam_pwdb.so (Red Hat) entry:
auth sufficient /lib/security/pam_pkcs15.so auth sufficient /lib/security/pam_pkcs15.so
4. Copy your PEM encoded certificate to a file in your home directory 4. Copy your PEM encoded certificate to a file in your home directory
called '.eid/authorized_certificates'. called '.eid/authorized_certificates'.
NOTE: You can use the 'certtest' program to get the PEM encoded NOTE: You can use the 'sc-tool -r <ID> -o ~/.eid/authorized_certificates'
certificate. command to get the PEM encoded certificate. Find the ID by saying
'sc-tool -c'. FINEID card owners should use 45 for the ID.
5. Try to login with your card in the reader. 5. Try to login with your card in the reader.
If it doesn't work, remove -DNDEBUG from the CFLAGS line in Makefile,
recompile and try again.

View File

@ -34,8 +34,6 @@ static const char *auth_cert_file = "authorized_certificates";
static int pamdebug = 1; static int pamdebug = 1;
static const struct pam_message msg_pin =
{ PAM_PROMPT_ECHO_OFF, "Enter PIN 1: " };
static int format_eid_dir_path(const char *user, char **buf) static int format_eid_dir_path(const char *user, char **buf)
{ {
@ -133,23 +131,31 @@ static int get_random(u8 *buf, int len)
} }
#ifndef TEST #ifndef TEST
static int get_password(pam_handle_t * pamh, char **password) static int get_password(pam_handle_t * pamh, char **password, const char *pinname)
{ {
int r; int r;
DBG(printf("Trying to get AUTHTOK...\n")); DBG(printf("Trying to get AUTHTOK...\n"));
r = pam_get_item(pamh, PAM_AUTHTOK, (void *) password); r = pam_get_item(pamh, PAM_AUTHTOK, (void *) password);
if (!*password) { if (!*password) {
const struct pam_message *msg[1] = { &msg_pin }; char buf[50];
struct pam_message msg_template =
{ PAM_PROMPT_ECHO_OFF, buf };
const struct pam_message *pin_msg[1] = { &msg_template };
struct pam_response *resp; struct pam_response *resp;
struct pam_conv *conv; struct pam_conv *conv;
char tmp[30];
strncpy(tmp, pinname, sizeof(tmp)-1);
tmp[sizeof(tmp)-1] = 0;
sprintf(buf, "Enter PIN [%s]: ", tmp);
DBG(printf("failed; Trying to get CONV object...\n")); DBG(printf("failed; Trying to get CONV object...\n"));
r = pam_get_item(pamh, PAM_CONV, (const void **) &conv); r = pam_get_item(pamh, PAM_CONV, (const void **) &conv);
if (r != PAM_SUCCESS) if (r != PAM_SUCCESS)
return r; return r;
DBG(printf("Conversing...\n")); DBG(printf("Conversing...\n"));
r = conv->conv(1, msg, &resp, conv->appdata_ptr); r = conv->conv(1, pin_msg, &resp, conv->appdata_ptr);
if (r != PAM_SUCCESS) if (r != PAM_SUCCESS)
return r; return r;
if (resp) { if (resp) {
@ -164,23 +170,6 @@ static int get_password(pam_handle_t * pamh, char **password)
} }
#endif #endif
static int set_sec_env(struct sc_card *card, const struct sc_pkcs15_card *p15card,
const struct sc_pkcs15_prkey_info *prkinfo)
{
struct sc_security_env senv;
int r;
senv.signature = 0;
senv.algorithm_ref = 0x02;
senv.key_ref = 0;
senv.key_file_id = prkinfo->file_id;
senv.app_df_path = p15card->file_app.path;
r = sc_set_security_env(p15card->card, &senv);
if (r)
return PAM_AUTH_ERR;
return PAM_SUCCESS;
}
#ifdef TEST #ifdef TEST
int main(int argc, const char **argv) int main(int argc, const char **argv)
#else #else
@ -194,6 +183,7 @@ PAM_EXTERN int pam_sm_authenticate(pam_handle_t * pamh, int flags, int argc, con
EVP_PKEY *pubkey = NULL; EVP_PKEY *pubkey = NULL;
struct sc_pkcs15_cert_info *cinfo; struct sc_pkcs15_cert_info *cinfo;
struct sc_pkcs15_prkey_info *prkinfo = NULL; struct sc_pkcs15_prkey_info *prkinfo = NULL;
struct sc_pkcs15_pin_info *pinfo = NULL;
u8 random_data[117]; u8 random_data[117];
u8 chg[128]; u8 chg[128];
@ -272,38 +262,27 @@ PAM_EXTERN int pam_sm_authenticate(pam_handle_t * pamh, int flags, int argc, con
for (i = 0; i < p15card->cert_count; i++) { for (i = 0; i < p15card->cert_count; i++) {
} }
cinfo = &p15card->cert_info[0]; /* FIXME */ cinfo = &p15card->cert_info[0]; /* FIXME */
DBG(printf("Enumerating private keys...\n")); DBG(printf("Finding private key...\n"));
r = sc_pkcs15_enum_private_keys(p15card); r = sc_pkcs15_find_prkey_by_id(p15card, &cinfo->id, &prkinfo);
if (r <= 0)
goto end;
for (i = 0; i < p15card->prkey_count; i++) {
struct sc_pkcs15_prkey_info *tmp = &p15card->prkey_info[i];
if (sc_pkcs15_compare_id(&tmp->id, &cinfo->id)) {
prkinfo = tmp;
break;
}
}
if (prkinfo == NULL)
goto end;
/* FIXME: Determine if PIN code needed */
DBG(printf("Enumerating PIN codes...\n"));
r = sc_pkcs15_enum_pins(p15card);
if (r < 0) if (r < 0)
goto end; goto end;
DBG(printf("Asking for PIN code...\n")); DBG(printf("Finding PIN code...\n"));
r = sc_pkcs15_find_pin_by_auth_id(p15card, &prkinfo->com_attr.auth_id, &pinfo);
if (r < 0)
goto end;
DBG(printf("Asking for PIN code '%s'...\n", pinfo->com_attr.label));
#ifdef TEST #ifdef TEST
password = strdup(getpass("Enter PIN1: ")); password = strdup(getpass("Enter PIN1: "));
r = 0; r = 0;
#else #else
r = get_password(pamh, &password); r = get_password(pamh, &password, pinfo->com_attr.label);
#endif #endif
if (r) { if (r) {
err = r; err = r;
goto end; goto end;
} }
DBG(printf("Verifying PIN code...\n")); DBG(printf("Verifying PIN code...\n"));
r = sc_pkcs15_verify_pin(p15card, &p15card->pin_info[0], password, strlen(password)); r = sc_pkcs15_verify_pin(p15card, pinfo, password, strlen(password));
if (r) { if (r) {
DBG(printf("PIN code verification failed: %s\n", sc_strerror(r))); DBG(printf("PIN code verification failed: %s\n", sc_strerror(r)));
if (r == SC_ERROR_CARD_REMOVED) if (r == SC_ERROR_CARD_REMOVED)
@ -312,26 +291,19 @@ PAM_EXTERN int pam_sm_authenticate(pam_handle_t * pamh, int flags, int argc, con
} }
DBG(printf("Awright! PIN code correct!\n")); DBG(printf("Awright! PIN code correct!\n"));
/* FIXME: clear password? */ /* FIXME: clear password? */
#if 0 DBG(printf("Deciphering...\n"));
r = sc_restore_security_env(card, 0); /* empty SE */ r = sc_pkcs15_decipher(p15card, prkinfo, chg, sizeof(chg), plain_text, sizeof(plain_text));
if (r) if (r <= 0) {
goto end; DBG(printf("Decipher failed: %s\n", sc_strerror(r)));
#endif
r = set_sec_env(card, p15card, prkinfo);
if (r != PAM_SUCCESS) {
err = r;
goto end; goto end;
} }
DBG(printf("Deciphering...\n"));
r = sc_decipher(card, chg, sizeof(chg), plain_text, sizeof(plain_text));
if (r <= 0)
goto end;
if (r != sizeof(random_data)) if (r != sizeof(random_data))
goto end; goto end;
if (memcmp(random_data, plain_text, sizeof(random_data)) != 0) if (memcmp(random_data, plain_text, sizeof(random_data)) != 0) {
DBG(printf("No luck this time.\n"));
goto end; goto end;
}
DBG(printf("Cool, dude! You're in!\n")); DBG(printf("You're in!\n"));
err = PAM_SUCCESS; err = PAM_SUCCESS;
end: end:
if (locked) if (locked)

View File

@ -5,8 +5,8 @@ CC= gcc
OPTIMIZER= -g OPTIMIZER= -g
CFLAGS=-Wall $(OPTIMIZER) $(PLUGIN_DEFINES) CFLAGS=-Wall $(OPTIMIZER) $(PLUGIN_DEFINES)
SRC= UnixShell.c stubs.c SRC= signer.c stubs.c
OBJ= UnixShell.o stubs.o OBJ= signer.o stubs.o
SHAREDTARGET=signer.so SHAREDTARGET=signer.so
@ -15,8 +15,8 @@ default all: $(SHAREDTARGET)
$(SHAREDTARGET): $(OBJ) $(SHAREDTARGET): $(OBJ)
$(CC) -shared -o $(SHAREDTARGET) $(OBJ) $(LDFLAGS) $(CC) -shared -o $(SHAREDTARGET) $(OBJ) $(LDFLAGS)
UnixShell.o: UnixShell.c signer.o: signer.c
$(CC) -c $(CFLAGS) UnixShell.c $(CC) -c $(CFLAGS) signer.c
stubs.o: stubs.c stubs.o: stubs.c
$(CC) -c $(CFLAGS) stubs.c $(CC) -c $(CFLAGS) stubs.c

333
src/signer/signer.c Normal file
View File

@ -0,0 +1,333 @@
/* -*- Mode: C; tab-width: 4; -*- */
/******************************************************************************
* Copyright (c) 1996 Netscape Communications. All rights reserved.
******************************************************************************/
/*
* UnixShell.c
*
* Netscape Client Plugin API
* - Function that need to be implemented by plugin developers
*
* This file defines a "Template" plugin that plugin developers can use
* as the basis for a real plugin. This shell just provides empty
* implementations of all functions that the plugin can implement
* that will be called by Netscape (the NPP_xxx methods defined in
* npapi.h).
*
* dp Suresh <dp@netscape.com>
*
*/
#include <stdio.h>
#include "npapi.h"
/***********************************************************************
* Instance state information about the plugin.
*
* PLUGIN DEVELOPERS:
* Use this struct to hold per-instance information that you'll
* need in the various functions in this file.
***********************************************************************/
typedef struct _PluginInstance
{
int nothing;
} PluginInstance;
/***********************************************************************
*
* Empty implementations of plugin API functions
*
* PLUGIN DEVELOPERS:
* You will need to implement these functions as required by your
* plugin.
*
***********************************************************************/
char*
NPP_GetMIMEDescription(void)
{
return("text/x-text-to-sign:sample:Text to be signed");
}
NPError
NPP_GetValue(NPP instance, NPPVariable variable, void *value)
{
NPError err = NPERR_NO_ERROR;
switch (variable) {
case NPPVpluginNameString:
*((char **)value) = "Template plugin";
break;
case NPPVpluginDescriptionString:
*((char **)value) =
"This plugins handles nothing. This is only"
" a template.";
break;
default:
err = NPERR_GENERIC_ERROR;
}
return err;
}
NPError
NPP_Initialize(void)
{
printf("NPP_Initialize()\n");
return NPERR_NO_ERROR;
}
jref
NPP_GetJavaClass()
{
return NULL;
}
void
NPP_Shutdown(void)
{
}
NPError
NPP_New(NPMIMEType pluginType,
NPP instance,
uint16 mode,
int16 argc,
char* argn[],
char* argv[],
NPSavedData* saved)
{
PluginInstance* This;
int i;
printf("NPP_New() called, attributes:\n");
for (i = 0; i < argc; i++) {
printf("'%s' = '%s'\n", argn[i], argv[i]);
}
if (instance == NULL)
return NPERR_INVALID_INSTANCE_ERROR;
instance->pdata = NPN_MemAlloc(sizeof(PluginInstance));
This = (PluginInstance*) instance->pdata;
if (This != NULL)
return NPERR_NO_ERROR;
else
return NPERR_OUT_OF_MEMORY_ERROR;
}
NPError
NPP_Destroy(NPP instance, NPSavedData** save)
{
PluginInstance* This;
if (instance == NULL)
return NPERR_INVALID_INSTANCE_ERROR;
This = (PluginInstance*) instance->pdata;
/* PLUGIN DEVELOPERS:
* If desired, call NP_MemAlloc to create a
* NPSavedDate structure containing any state information
* that you want restored if this plugin instance is later
* recreated.
*/
if (This != NULL) {
NPN_MemFree(instance->pdata);
instance->pdata = NULL;
}
return NPERR_NO_ERROR;
}
NPError
NPP_SetWindow(NPP instance, NPWindow* window)
{
PluginInstance* This;
printf("NPP_SetWindow()\n");
if (instance == NULL)
return NPERR_INVALID_INSTANCE_ERROR;
if (window == NULL)
return NPERR_NO_ERROR;
This = (PluginInstance*) instance->pdata;
/*
* PLUGIN DEVELOPERS:
* Before setting window to point to the
* new window, you may wish to compare the new window
* info to the previous window (if any) to note window
* size changes, etc.
*/
return NPERR_NO_ERROR;
}
NPError
NPP_NewStream(NPP instance,
NPMIMEType type,
NPStream *stream,
NPBool seekable,
uint16 *stype)
{
NPByteRange range;
PluginInstance* This;
printf("NPP_NewStream()\n");
if (instance == NULL)
return NPERR_INVALID_INSTANCE_ERROR;
This = (PluginInstance*) instance->pdata;
return NPERR_NO_ERROR;
}
/* PLUGIN DEVELOPERS:
* These next 2 functions are directly relevant in a plug-in which
* handles the data in a streaming manner. If you want zero bytes
* because no buffer space is YET available, return 0. As long as
* the stream has not been written to the plugin, Navigator will
* continue trying to send bytes. If the plugin doesn't want them,
* just return some large number from NPP_WriteReady(), and
* ignore them in NPP_Write(). For a NP_ASFILE stream, they are
* still called but can safely be ignored using this strategy.
*/
int32 STREAMBUFSIZE = 0X0FFFFFFF; /* If we are reading from a file in NPAsFile
* mode so we can take any size stream in our
* write call (since we ignore it) */
int32
NPP_WriteReady(NPP instance, NPStream *stream)
{
PluginInstance* This;
if (instance != NULL)
This = (PluginInstance*) instance->pdata;
printf("NPP_WriteReady()\n");
return STREAMBUFSIZE;
}
int32
NPP_Write(NPP instance, NPStream *stream, int32 offset, int32 len, void *buffer)
{
if (instance != NULL)
{
PluginInstance* This = (PluginInstance*) instance->pdata;
}
printf("NPP_Write(offset %d, len %d)\n", offset, len);
return len; /* The number of bytes accepted */
}
NPError
NPP_DestroyStream(NPP instance, NPStream *stream, NPError reason)
{
PluginInstance* This;
if (instance == NULL)
return NPERR_INVALID_INSTANCE_ERROR;
This = (PluginInstance*) instance->pdata;
printf("NPP_DestroyStream()\n");
return NPERR_NO_ERROR;
}
void
NPP_StreamAsFile(NPP instance, NPStream *stream, const char* fname)
{
PluginInstance* This;
FILE *inf, *outf;
unsigned char buf[1024];
int i;
if (instance != NULL)
This = (PluginInstance*) instance->pdata;
printf("NPP_StreamAsFile('%s')\n", fname);
inf = fopen(fname, "r");
if (inf == NULL)
return; /* FIXME */
i = 0;
outf = fopen("/tmp/empty.sgn", "w");
if (outf == NULL) {
fclose(inf);
return;
}
while ((i = fread(buf, 1, 1024, inf)) > 0) {
fwrite(buf, 1, i, outf);
}
fclose(outf);
fclose(inf);
}
void
NPP_Print(NPP instance, NPPrint* printInfo)
{
if(printInfo == NULL)
return;
if (instance != NULL) {
PluginInstance* This = (PluginInstance*) instance->pdata;
if (printInfo->mode == NP_FULL) {
/*
* PLUGIN DEVELOPERS:
* If your plugin would like to take over
* printing completely when it is in full-screen mode,
* set printInfo->pluginPrinted to TRUE and print your
* plugin as you see fit. If your plugin wants Netscape
* to handle printing in this case, set
* printInfo->pluginPrinted to FALSE (the default) and
* do nothing. If you do want to handle printing
* yourself, printOne is true if the print button
* (as opposed to the print menu) was clicked.
* On the Macintosh, platformPrint is a THPrint; on
* Windows, platformPrint is a structure
* (defined in npapi.h) containing the printer name, port,
* etc.
*/
void* platformPrint =
printInfo->print.fullPrint.platformPrint;
NPBool printOne =
printInfo->print.fullPrint.printOne;
/* Do the default*/
printInfo->print.fullPrint.pluginPrinted = FALSE;
}
else { /* If not fullscreen, we must be embedded */
/*
* PLUGIN DEVELOPERS:
* If your plugin is embedded, or is full-screen
* but you returned false in pluginPrinted above, NPP_Print
* will be called with mode == NP_EMBED. The NPWindow
* in the printInfo gives the location and dimensions of
* the embedded plugin on the printed page. On the
* Macintosh, platformPrint is the printer port; on
* Windows, platformPrint is the handle to the printing
* device context.
*/
NPWindow* printWindow =
&(printInfo->print.embedPrint.window);
void* platformPrint =
printInfo->print.embedPrint.platformPrint;
}
}
}

View File

@ -11,40 +11,19 @@
#include <sc-asn1.h> #include <sc-asn1.h>
#include "sc-test.h" #include "sc-test.h"
#define DO_PRKEY_ENUM 0
#define DO_PIN_ENUM 0
#define DO_PIN_VERIFY 0
#define DO_DECIPHER 0
#define DO_SIGN 0
#define DO_TEST 0
struct sc_pkcs15_card *p15card; struct sc_pkcs15_card *p15card;
int enum_private_keys()
{
int i;
i = sc_pkcs15_enum_private_keys(p15card);
if (i < 0) {
fprintf(stderr, "Private key enumeration failed with %s\n",
sc_strerror(i));
return 1;
}
printf("%d private keys found!\n", i);
for (i = 0; i < p15card->prkey_count; i++) {
sc_pkcs15_print_prkey_info(&p15card->prkey_info[i]);
}
return 0;
}
int test() int test()
{ {
struct sc_file file; struct sc_file file;
struct sc_path path; struct sc_path path;
struct sc_apdu apdu;
u8 rbuf[MAX_BUFFER_SIZE], sbuf[MAX_BUFFER_SIZE];
int r; int r;
sc_lock(card); sc_lock(card);
#if 1 #if 1
r = sc_pkcs15_init(card, &p15card); r = sc_pkcs15_init(card, &p15card);
if (r < 0) { if (r < 0) {
@ -56,18 +35,33 @@ int test()
fprintf(stderr, "PIN code enum failed: %s\n", sc_strerror(r)); fprintf(stderr, "PIN code enum failed: %s\n", sc_strerror(r));
goto err; goto err;
} }
memcpy(path.value, "\x51\x10", 2);
path.len = 2;
sc_debug = 3;
r = sc_select_file(card, &file, &path, SC_SELECT_FILE_BY_PATH);
sc_debug = 0;
if (r) {
fprintf(stderr, "sc_select_file failed: %s\n", sc_strerror(r));
goto err;
}
r = sc_pkcs15_verify_pin(p15card, &p15card->pin_info[0], "\x31\x32\x33\x34", 4); r = sc_pkcs15_verify_pin(p15card, &p15card->pin_info[0], "\x31\x32\x33\x34", 4);
if (r) { if (r) {
fprintf(stderr, "PIN code verification failed: %s\n", sc_strerror(r)); fprintf(stderr, "PIN code verification failed: %s\n", sc_strerror(r));
goto err; goto err;
} }
#endif #endif
memcpy(path.value, "\x3f\x00", 2); sc_debug = 3;
path.len = 2;
sc_debug = 1; sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x20, 0, 1);
r = sc_select_file(card, &file, &path, SC_SELECT_FILE_BY_PATH); apdu.lc = 8;
apdu.data = sbuf;
apdu.datalen = 8;
apdu.resp = rbuf;
apdu.resplen = sizeof(rbuf);
memcpy(sbuf, "\x31\x32\x33\x34\x00\x00\x00\x00", 8);
r = sc_transmit_apdu(card, &apdu);
if (r) { if (r) {
fprintf(stderr, "sc_select_file failed: %s\n", sc_strerror(r)); fprintf(stderr, "transmit failed: %s\n", sc_strerror(r));
goto err; goto err;
} }
r = sc_delete_file(card, 0x5110); r = sc_delete_file(card, 0x5110);
@ -75,6 +69,7 @@ int test()
fprintf(stderr, "fail: %s\n", sc_strerror(r)); fprintf(stderr, "fail: %s\n", sc_strerror(r));
goto err; goto err;
} }
return 0; return 0;
memset(&file, 0, sizeof(file)); memset(&file, 0, sizeof(file));
@ -95,6 +90,67 @@ err:
return r; return r;
} }
int test2()
{
int r;
struct sc_path path;
struct sc_file file;
memcpy(path.value, "\x3F\x00", 2);
path.len = 2;
sc_debug = 3;
r = sc_select_file(card, &file, &path, SC_SELECT_FILE_BY_PATH);
if (r) {
fprintf(stderr, "SELECT FILE failed: %s\n", sc_strerror(r));
return r;
}
return 0;
}
int test3()
{
FILE *inf;
u8 buf[256], txt[256];
int len, r;
struct sc_pkcs15_pin_info *pin;
struct sc_pkcs15_prkey_info *key;
r = sc_pkcs15_init(card, &p15card);
if (r) {
fprintf(stderr, "pkcs15 init failed: %s\n", sc_strerror(r));
return -1;
}
r = sc_pkcs15_enum_private_keys(p15card);
if (r < 0) {
fprintf(stderr, "pkcs15 enum prk: %s\n", sc_strerror(r));
return -1;
}
key = &p15card->prkey_info[0];
r = sc_pkcs15_enum_pins(p15card);
if (r < 0) {
fprintf(stderr, "pkcs15 enum pins: %s\n", sc_strerror(r));
return -1;
}
pin = &p15card->pin_info[0];
inf = fopen("crypt.dat", "r");
if (inf == NULL)
return -1;
len = fread(buf, 1, sizeof(buf), inf);
r = sc_pkcs15_verify_pin(p15card, pin, "\x31\x32\x33\x34", 4);
if (r) {
fprintf(stderr, "PIN code verification failed: %s\n", sc_strerror(r));
return -1;
}
r = sc_pkcs15_decipher(p15card, key, buf, len, txt, sizeof(txt));
if (r < 0) {
fprintf(stderr, "decipher failed: %s\n", sc_strerror(r));
return -1;
}
return 0;
}
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
int i; int i;
@ -103,93 +159,10 @@ int main(int argc, char **argv)
if (i != 0) if (i != 0)
return 1; return 1;
if (test()) sc_debug = 3;
if (test3())
return 1; return 1;
return 0;
i = sc_pkcs15_init(card, &p15card);
if (i != 0) {
fprintf(stderr, "PKCS#15 card init failed: %s\n",
sc_strerror(i));
return 1;
}
sc_pkcs15_print_card(p15card);
#if DO_PRKEY_ENUM
if (enum_private_keys())
return 1;
#endif
#if DO_DECIPHER
senv.signature = 0;
senv.algorithm_ref = 0x02;
senv.key_ref = 0;
senv.key_file_id = p15card->prkey_info[0].file_id;
senv.app_df_path = p15card->file_app.path;
i = sc_set_security_env(p15card->card, &senv);
if (i) {
fprintf(stderr, "Security environment set failed: %s\n",
sc_strerror(i));
return 1;
}
file = fopen("cryptogram", "r");
if (file != NULL) {
i = fread(buf, 1, sizeof(buf), file);
c = sc_decipher(card, buf, i, buf2, sizeof(buf2));
if (c < 0) {
fprintf(stderr, "Decipher failed: (%d) %s\n", c,
sc_strerror(c));
} else {
printf("Decrypted payload: ");
for (i = 0; i < c; i++) {
printf("%02X ", buf2[i]);
}
printf("\n");
fclose(file);
file = fopen("decrypted.dat", "w");
fwrite(buf2, c, 1, file);
fclose(file);
}
} else {
printf("File 'cryptogram' not found, not decrypting.\n");
}
#endif
#if DO_SIGN
senv.signature = 1;
senv.algorithm_ref = 0x02;
senv.key_ref = 0;
senv.key_file_id = p15card->prkey_info[0].file_id;
senv.app_df_path = p15card->file_app.path;
i = sc_set_security_env(p15card->card, &senv);
if (i) {
fprintf(stderr, "Security environment set failed: %s\n",
sc_strerror(i));
return 1;
}
file = fopen("input", "r");
if (file != NULL) {
i = fread(buf, 1, sizeof(buf), file);
SCardSetTimeout(ctx->pcsc_ctx, 15000);
c = sc_compute_signature(card, buf, i, buf2, sizeof(buf2));
if (c < 0) {
fprintf(stderr, "Signing failed: (%d) %s\n", c,
sc_strerror(c));
} else {
printf("Signed payload: ");
for (i = 0; i < c; i++) {
printf("%02X ", buf2[i]);
}
printf("\n");
fclose(file);
file = fopen("signed.dat", "w");
fwrite(buf2, c, 1, file);
fclose(file);
}
} else {
printf("File 'input' not found, not signing.\n");
}
#endif
printf("Cleaning up...\n");
sc_test_cleanup(); sc_test_cleanup();
return 0; return 0;

View File

@ -10,6 +10,7 @@
#include "sc-pkcs15.h" #include "sc-pkcs15.h"
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h>
struct sc_pkcs15_card *p15card; struct sc_pkcs15_card *p15card;
@ -35,13 +36,26 @@ int enum_pins()
int ask_and_verify_pin(struct sc_pkcs15_pin_info *pin) int ask_and_verify_pin(struct sc_pkcs15_pin_info *pin)
{ {
int i = 0; int i = 0;
char buf[32]; char prompt[80];
char *pass;
while (1) {
sprintf(prompt, "Please enter PIN code [%s]: ", pin->com_attr.label);
pass = getpass(prompt);
if (strlen(pass) == 0) {
printf("Not verifying PIN code.\n");
return -1;
}
if (strlen(pass) < pin->min_length)
break;
if (strlen(pass) > pin->stored_length)
break;
break;
}
i = sc_sec_ask_pin_code(pin, buf, sizeof(buf),
"Please enter PIN code");
if (i == 0) {
sc_lock(card); sc_lock(card);
i = sc_pkcs15_verify_pin(p15card, pin, buf, strlen(buf)); i = sc_pkcs15_verify_pin(p15card, pin, pass, strlen(pass));
sc_unlock(card); sc_unlock(card);
if (i) { if (i) {
if (i == SC_ERROR_PIN_CODE_INCORRECT) if (i == SC_ERROR_PIN_CODE_INCORRECT)
@ -53,11 +67,9 @@ int ask_and_verify_pin(struct sc_pkcs15_pin_info *pin)
"PIN verifying failed: %s\n", "PIN verifying failed: %s\n",
sc_strerror(i)); sc_strerror(i));
return 1; return 1;
} } else
printf("PIN code correct.\n"); printf("PIN code correct.\n");
} else {
printf("\nNot verifying PIN code.\n");
}
return 0; return 0;
} }

View File

@ -17,18 +17,22 @@ char * opt_cert = NULL;
char * opt_outfile = NULL; char * opt_outfile = NULL;
char * opt_pincode = NULL; char * opt_pincode = NULL;
char * opt_newpin = NULL; char * opt_newpin = NULL;
char * opt_apdu = NULL;
int quiet = 0; int quiet = 0;
const struct option options[] = { const struct option options[] = {
{ "list-readers", 0, 0, 'l' }, { "list-readers", 0, 0, 'l' },
{ "list-files", 0, 0, 'f' }, { "list-files", 0, 0, 'f' },
{ "send-apdu", 1, 0, 's' },
{ "read-certificate", 1, 0, 'r' }, { "read-certificate", 1, 0, 'r' },
{ "list-certificates", 0, 0, 'c' }, { "list-certificates", 0, 0, 'c' },
{ "list-pins", 0, 0, OPT_LIST_PINS }, { "list-pins", 0, 0, OPT_LIST_PINS },
{ "change-pin", 2, 0, OPT_CHANGE_PIN }, { "change-pin", 2, 0, OPT_CHANGE_PIN },
{ "list-private-keys", 0, 0, 'k' },
{ "reader", 1, 0, OPT_READER }, { "reader", 1, 0, OPT_READER },
{ "output", 1, 0, 'o' }, { "output", 1, 0, 'o' },
{ "quiet", 0, 0, 'q' }, { "quiet", 0, 0, 'q' },
{ "debug", 0, 0, 'd' },
{ "pin", 1, 0, 'p' }, { "pin", 1, 0, 'p' },
{ "pin-id", 1, &opt_pin, 0 }, { "pin-id", 1, &opt_pin, 0 },
{ 0, 0, 0, 0 } { 0, 0, 0, 0 }
@ -37,15 +41,18 @@ const struct option options[] = {
const char *option_help[] = { const char *option_help[] = {
"Lists all configured readers", "Lists all configured readers",
"Recursively lists files stored on card", "Recursively lists files stored on card",
"Read certificate with ID <arg>", "Sends an APDU in format AA:BB:CC:DD:EE:FF...",
"Lists certificates", "Reads certificate with ID <arg> [P15]",
"Lists PIN codes", "Lists certificates [P15]",
"Changes the PIN code to <arg>", "Lists PIN codes [P15]",
"Changes the PIN code to <arg> [P15]",
"Lists private keys [P15]",
"Uses reader number <arg>", "Uses reader number <arg>",
"Outputs to file <arg>", "Outputs to file <arg>",
"Quiet operation", "Quiet operation",
"Uses PIN <arg>; if not supplied, asks the user", "Debug output -- may be supplied several timeso"
"Choose which PIN to use", "Uses password (PIN) <arg>",
"The auth ID of the PIN to use [P15]",
}; };
struct sc_context *ctx = NULL; struct sc_context *ctx = NULL;
@ -113,52 +120,14 @@ int list_certificates()
return 0; return 0;
} }
int read_certificate() int print_pem_certificate(struct sc_pkcs15_cert *cert)
{ {
int r, i; int r;
struct sc_pkcs15_id id; u8 buf[2048];
u8 *p = id.value;
char *certp = opt_cert;
FILE *outf; FILE *outf;
if (strlen(opt_cert)/2 >= SC_PKCS15_MAX_ID_SIZE) {
fprintf(stderr, "Certificate id too long.\n");
return 2;
}
if (!quiet)
printf("Reading certificate with ID '%s'\n", opt_cert);
id.len = 0;
while (*certp) {
int byte;
if (sscanf(certp, "%02X", &byte) != 1)
break;
certp += 2;
*p = byte;
p++;
id.len++;
}
r = sc_pkcs15_enum_certificates(p15card);
if (r < 0) {
fprintf(stderr, "Certificate enumeration failed: %s\n", sc_strerror(r));
return 1;
}
for (i = 0; i < p15card->cert_count; i++) {
struct sc_pkcs15_cert_info *cinfo = &p15card->cert_info[i];
struct sc_pkcs15_cert *cert;
u8 buf[2048];
if (sc_pkcs15_compare_id(&id, &cinfo->id) != 1)
continue;
r = sc_pkcs15_read_certificate(p15card, cinfo, &cert);
if (r) {
fprintf(stderr, "Certificate read failed: %s\n", sc_strerror(r));
return 1;
}
r = sc_base64_encode(cert->data, cert->data_len, buf, r = sc_base64_encode(cert->data, cert->data_len, buf,
sizeof(buf), 64); sizeof(buf), 64);
sc_pkcs15_free_certificate(cert);
if (r) { if (r) {
fprintf(stderr, "Base64 encoding failed: %s\n", sc_strerror(r)); fprintf(stderr, "Base64 encoding failed: %s\n", sc_strerror(r));
return 1; return 1;
@ -176,6 +145,60 @@ int read_certificate()
buf); buf);
if (outf != stdout) if (outf != stdout)
fclose(outf); fclose(outf);
return 0;
}
int read_certificate()
{
int r, i;
struct sc_pkcs15_id id;
id.len = SC_PKCS15_MAX_ID_SIZE;
sc_pkcs15_hex_string_to_id(opt_cert, &id);
r = sc_pkcs15_enum_certificates(p15card);
if (r < 0) {
fprintf(stderr, "Certificate enumeration failed: %s\n", sc_strerror(r));
return 1;
}
for (i = 0; i < p15card->cert_count; i++) {
struct sc_pkcs15_cert_info *cinfo = &p15card->cert_info[i];
struct sc_pkcs15_cert *cert;
if (sc_pkcs15_compare_id(&id, &cinfo->id) != 1)
continue;
if (!quiet)
printf("Reading certificate with ID '%s'\n", opt_cert);
r = sc_pkcs15_read_certificate(p15card, cinfo, &cert);
if (r) {
fprintf(stderr, "Certificate read failed: %s\n", sc_strerror(r));
return 1;
}
r = print_pem_certificate(cert);
sc_pkcs15_free_certificate(cert);
return r;
}
fprintf(stderr, "Certificate with ID '%s' not found.\n", opt_cert);
return 2;
}
int list_private_keys()
{
int r, i;
r = sc_pkcs15_enum_private_keys(p15card);
if (r < 0) {
fprintf(stderr, "Private key enumeration failed: %s\n", sc_strerror(r));
return 1;
}
if (!quiet)
printf("Card has %d private key(s).\n\n", p15card->prkey_count);
for (i = 0; i < p15card->prkey_count; i++) {
struct sc_pkcs15_prkey_info *pinfo = &p15card->prkey_info[i];
sc_pkcs15_print_prkey_info(pinfo);
printf("\n");
} }
return 0; return 0;
} }
@ -343,6 +366,60 @@ int list_files()
return r; return r;
} }
int send_apdu()
{
struct sc_apdu apdu;
u8 buf[MAX_BUFFER_SIZE], sbuf[MAX_BUFFER_SIZE],
rbuf[MAX_BUFFER_SIZE], *p = buf;
int len = sizeof(buf), r;
sc_hex_to_bin(opt_apdu, buf, &len);
if (len < 5) {
fprintf(stderr, "APDU too short (must be at least 5 bytes).\n");
return 2;
}
apdu.cla = *p++;
apdu.ins = *p++;
apdu.p1 = *p++;
apdu.p2 = *p++;
apdu.resp = rbuf;
apdu.resplen = sizeof(rbuf);
len -= 4;
if (len > 1) {
apdu.lc = *p++;
len--;
memcpy(sbuf, p, apdu.lc);
apdu.data = sbuf;
apdu.datalen = apdu.lc;
len -= apdu.lc;
if (len) {
apdu.le = *p++;
len--;
apdu.cse = SC_APDU_CASE_4_SHORT;
} else
apdu.cse = SC_APDU_CASE_3_SHORT;
if (len) {
fprintf(stderr, "APDU too long (%d bytes extra).\n", len);
return 2;
}
} else if (len == 1) {
apdu.le = *p++;
len--;
apdu.cse = SC_APDU_CASE_2_SHORT;
} else
apdu.cse = SC_APDU_CASE_1;
sc_debug = 3;
r = sc_transmit_apdu(card, &apdu);
sc_debug = 0;
if (r) {
fprintf(stderr, "APDU transmit failed: %s\n", sc_strerror(r));
return 1;
}
return 0;
}
int main(int argc, char * const argv[]) int main(int argc, char * const argv[])
{ {
int err = 0, r, c, long_optind = 0; int err = 0, r, c, long_optind = 0;
@ -351,11 +428,13 @@ int main(int argc, char * const argv[])
int do_list_certs = 0; int do_list_certs = 0;
int do_list_pins = 0; int do_list_pins = 0;
int do_list_files = 0; int do_list_files = 0;
int do_list_prkeys = 0;
int do_change_pin = 0; int do_change_pin = 0;
int do_send_apdu = 0;
int action_count = 0; int action_count = 0;
while (1) { while (1) {
c = getopt_long(argc, argv, "lfr:coqp:", options, &long_optind); c = getopt_long(argc, argv, "lfr:kco:qdp:s:", options, &long_optind);
if (c == -1) if (c == -1)
break; break;
if (c == '?') if (c == '?')
@ -378,6 +457,11 @@ int main(int argc, char * const argv[])
do_list_certs = 1; do_list_certs = 1;
action_count++; action_count++;
break; break;
case 's':
opt_apdu = optarg;
do_send_apdu++;
action_count++;
break;
case OPT_CHANGE_PIN: case OPT_CHANGE_PIN:
do_change_pin = 1; do_change_pin = 1;
action_count++; action_count++;
@ -386,6 +470,10 @@ int main(int argc, char * const argv[])
do_list_pins = 1; do_list_pins = 1;
action_count++; action_count++;
break; break;
case 'k':
do_list_prkeys = 1;
action_count++;
break;
case OPT_READER: case OPT_READER:
opt_reader = atoi(optarg); opt_reader = atoi(optarg);
break; break;
@ -395,6 +483,9 @@ int main(int argc, char * const argv[])
case 'q': case 'q':
quiet++; quiet++;
break; break;
case 'd':
sc_debug++;
break;
case 'p': case 'p':
if (optarg == NULL && opt_pincode == NULL) if (optarg == NULL && opt_pincode == NULL)
opt_pincode = getpass("Enter PIN code: "); opt_pincode = getpass("Enter PIN code: ");
@ -437,12 +528,17 @@ int main(int argc, char * const argv[])
sc_lock(card); sc_lock(card);
if (do_send_apdu) {
if ((err = send_apdu()))
goto end;
action_count--;
}
if (do_list_files) { if (do_list_files) {
if ((err = list_files())) if ((err = list_files()))
goto end; goto end;
action_count--; action_count--;
} }
/* Here go the actions that do not require PKCS#15 */
if (action_count <= 0) if (action_count <= 0)
goto end; goto end;
@ -466,6 +562,11 @@ int main(int argc, char * const argv[])
goto end; goto end;
action_count--; action_count--;
} }
if (do_list_prkeys) {
if ((err = list_private_keys()))
goto end;
action_count--;
}
if (do_list_pins) { if (do_list_pins) {
if ((err = list_pins())) if ((err = list_pins()))
goto end; goto end;