- 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;
}
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[] = {
{ "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 }
};

View File

@ -158,6 +158,11 @@ struct sc_pkcs15_card {
int sc_pkcs15_init(struct sc_card *card,
struct sc_pkcs15_card **pkcs15_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_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);
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);
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,
char *oldpincode,
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,
const struct sc_pkcs15_id *id2);
void sc_pkcs15_print_id(const struct sc_pkcs15_id *id);
int sc_sec_ask_pin_code(struct sc_pkcs15_pin_info *pin,
char *out, int outlen, const char *prompt);
int sc_pkcs15_hex_string_to_id(const char *in, struct sc_pkcs15_id *out);
int sc_pkcs15_parse_common_object_attr(struct sc_pkcs15_common_obj_attr *attr,
const u8 * buf, int buflen);

View File

@ -21,6 +21,7 @@
#ifndef _SC_H
#define _SC_H
#include <pthread.h>
#include <winscard.h>
#define SC_ERROR_MIN -1000
@ -46,6 +47,9 @@
#define SC_ERROR_RESOURCE_MANAGER -1019
#define SC_ERROR_CARD_REMOVED -1020
#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_1 1
@ -126,6 +130,7 @@ struct sc_card {
int atr_len;
const struct sc_defaults *defaults;
pthread_mutex_t mutex;
};
struct sc_context {
@ -142,11 +147,13 @@ struct sc_apdu {
int datalen; /* length of C-APDU */
u8 *resp; /* R-APDU */
int resplen; /* length of R-APDU */
int no_response; /* No response required */
int sw1, sw2;
};
struct sc_security_env {
int algorithm_ref;
struct sc_path app_df_path;
struct sc_path key_file_id;
/* signature=1 ==> digital signing, signature=0 ==> authentication */
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_unlock(struct sc_card *card);
/* ISO 7816-4 related functions */
int sc_select_file(struct sc_card *card, struct sc_file *file,
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);
int sc_compute_signature(struct sc_card *card, const u8 * data,
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 */
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 */
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);
/* Internal use only */
int sc_file_valid(const struct sc_file *file);
void sc_hex_dump(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 const char *sc_version;

View File

@ -169,10 +169,8 @@ int sc_pkcs15_verify_pin(struct sc_pkcs15_card *p15card,
{
int r;
struct sc_file file;
struct sc_apdu apdu;
struct sc_card *card;
char pinbuf[SC_MAX_PIN_SIZE];
char resp[MAX_BUFFER_SIZE];
assert(p15card != NULL);
if (pin->magic != SC_PKCS15_PIN_MAGIC)
@ -185,30 +183,15 @@ int sc_pkcs15_verify_pin(struct sc_pkcs15_card *p15card,
if (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);
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);
if (r)
return r;
if (apdu.resplen == 2) {
if (apdu.resp[0] == 0x90 && apdu.resp[1] == 0x00)
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;
return 0;
}
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;
}
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++)
printf("%02X", prkey->file_id.value[i]);
printf("\n");
printf("\tAuth ID : ");
sc_pkcs15_print_id(&prkey->com_attr.auth_id);
printf("\n");
printf("\tID : ");
sc_pkcs15_print_id(&prkey->id);
printf("\n");
@ -146,3 +149,22 @@ int sc_pkcs15_enum_private_keys(struct sc_pkcs15_card *card)
}
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

@ -229,8 +229,10 @@ int sc_pkcs15_init(struct sc_card *card,
return SC_ERROR_OUT_OF_MEMORY;
memset(p15card, 0, sizeof(struct sc_pkcs15_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);
err = sc_select_file(card, &p15card->file_tokeninfo,
&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++)
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,
struct sc_pkcs15_card **pkcs15_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_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);
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);
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,
char *oldpincode,
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,
const struct sc_pkcs15_id *id2);
void sc_pkcs15_print_id(const struct sc_pkcs15_id *id);
int sc_sec_ask_pin_code(struct sc_pkcs15_pin_info *pin,
char *out, int outlen, const char *prompt);
int sc_pkcs15_hex_string_to_id(const char *in, struct sc_pkcs15_id *out);
int sc_pkcs15_parse_common_object_attr(struct sc_pkcs15_common_obj_attr *attr,
const u8 * buf, int buflen);

View File

@ -29,18 +29,18 @@
const char *sc_version = LIBSC_VERSION;
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:
switch (sw[1]) {
switch (sw2) {
case 0x82:
return SC_ERROR_SECURITY_STATUS_NOT_SATISFIED;
default:
return SC_ERROR_UNKNOWN;
return SC_ERROR_UNKNOWN_REPLY;
}
case 0x6A:
switch (sw[1]) {
switch (sw2) {
case 0x81:
return SC_ERROR_NOT_SUPPORTED;
case 0x82:
@ -50,15 +50,18 @@ static int convert_sw_to_errorcode(u8 * sw)
case 0x87:
return SC_ERROR_INVALID_ARGUMENTS;
default:
return SC_ERROR_UNKNOWN;
return SC_ERROR_UNKNOWN_REPLY;
}
case 0x6D:
return SC_ERROR_NOT_SUPPORTED;
case 0x6E:
return SC_ERROR_UNKNOWN_SMARTCARD;
case 0x90:
if (sw[1] == 0)
if (sw2 == 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)
@ -90,6 +93,35 @@ void sc_print_binary(const u8 *buf, int count)
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)
{
switch (apdu->cse) {
@ -170,7 +202,7 @@ static int sc_transceive_t0(struct sc_card *card, struct sc_apdu *apdu)
sRecvPci.cbPciLength = 0;
dwSendLength = data - s;
dwRecvLength = apdu->resplen;
dwRecvLength = apdu->resplen + 2;
if (sc_debug > 2) {
printf("Sending: ");
sc_hex_dump(s, dwSendLength);
@ -192,8 +224,14 @@ 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;
memcpy(apdu->resp, r, dwRecvLength);
if (dwRecvLength)
memcpy(apdu->resp, r, dwRecvLength);
return 0;
}
@ -209,20 +247,25 @@ int sc_transmit_apdu(struct sc_card *card, struct sc_apdu *apdu)
if (r)
return r;
if (sc_debug > 2) {
printf("Received: ");
sc_hex_dump(apdu->resp, apdu->resplen);
printf("Received (SW1=%02X SW2=%02X)", apdu->sw1, apdu->sw2);
if (apdu->resplen) {
printf(": ");
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;
BYTE rsp[MAX_BUFFER_SIZE];
rspapdu.cla = apdu->cla;
rspapdu.cse = SC_APDU_CASE_2_SHORT;
rspapdu.ins = 0xC0;
rspapdu.p1 = rspapdu.p2 = 0;
rspapdu.le = apdu->resp[1];
if (apdu->no_response)
return 0;
sc_format_apdu(card, &rspapdu, SC_APDU_CASE_2_SHORT,
0xC0, 0, 0);
rspapdu.le = apdu->sw2;
rspapdu.resp = rsp;
rspapdu.resplen = apdu->resp[1] + 2;
rspapdu.resplen = apdu->sw2;
r = sc_transceive_t0(card, &rspapdu);
if (r) {
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;
}
if (sc_debug > 2) {
printf("Response: ");
printf("Response (SW1=%02X SW2=%02X): ", rspapdu.sw1,
rspapdu.sw2);
sc_hex_dump(rspapdu.resp, rspapdu.resplen);
}
/* FIXME: Check apdu->resplen */
memcpy(apdu->resp, rspapdu.resp, rspapdu.resplen);
apdu->resplen = rspapdu.resplen;
apdu->sw1 = rspapdu.sw1;
apdu->sw2 = rspapdu.sw2;
}
return 0;
}
@ -333,7 +380,7 @@ int sc_select_file(struct sc_card *card,
{
struct sc_context *ctx;
struct sc_apdu apdu;
char buf[MAX_BUFFER_SIZE], cmd[15];
char buf[MAX_BUFFER_SIZE];
u8 pathbuf[SC_MAX_PATH_SIZE], *path = pathbuf;
int r, pathlen;
@ -345,12 +392,10 @@ int sc_select_file(struct sc_card *card,
memcpy(path, in_path->value, in_path->len);
pathlen = in_path->len;
apdu.cse = SC_APDU_CASE_3_SHORT;
apdu.cla = card->class;
apdu.ins = 0xA4;
sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xA4, 0, 0);
apdu.resp = buf;
apdu.resplen = 2;
memcpy(cmd, "\x00\xA4", 2);
apdu.resplen = 0;
switch (pathtype) {
case SC_SELECT_FILE_BY_FILE_ID:
apdu.p1 = 0;
@ -376,47 +421,37 @@ int sc_select_file(struct sc_card *card,
apdu.lc = pathlen;
apdu.data = path;
apdu.datalen = pathlen;
#if 0
/* FIXME: Some smarter way to do this... */
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));
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) {
if (file != NULL) {
memset(file, 0, sizeof(*file));
memcpy(&file->path.value, path, pathlen);
file->path.len = pathlen;
}
if (apdu.resp[0] == 0x6F) {
// int l1 = apdu.resplen - 2, l2 = apdu.resp[1];
int l1 = apdu.resplen, l2 = apdu.resp[1];
int len = l1 > l2 ? l2 : l1;
if (file == NULL || sc_file_valid(file))
apdu.no_response = 1;
r = sc_transmit_apdu(card, &apdu);
if (r)
return r;
if (apdu.no_response) {
if (apdu.sw1 == 0x61)
return 0;
return _sc_sw_to_errorcode(apdu.sw1, apdu.sw2);
}
process_fci(file, apdu.resp + 2, len);
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;
}
@ -426,14 +461,12 @@ int sc_read_binary(struct sc_card *card,
{
#define RB_BUF_SIZE 250
struct sc_apdu apdu;
struct sc_context *ctx;
u8 recvbuf[MAX_BUFFER_SIZE];
int r;
assert(card != NULL && buf != NULL);
ctx = card->context;
memset(&apdu, 0, sizeof(apdu));
if (count == 0)
return 0;
if (count > RB_BUF_SIZE) {
int bytes_read = 0;
unsigned char *p = buf;
@ -452,38 +485,25 @@ int sc_read_binary(struct sc_card *card,
}
return bytes_read;
}
apdu.cse = SC_APDU_CASE_2_SHORT;
apdu.cla = 0;
apdu.ins = 0xB0;
apdu.p1 = (idx >> 8) & 0x7f;
apdu.p2 = idx & 0xFF;
sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xB0,
(idx >> 8) & 0x7F, idx & 0xFF);
apdu.le = count;
apdu.resplen = count + 2;
apdu.resplen = count;
apdu.resp = recvbuf;
r = sc_transmit_apdu(card, &apdu);
if (r)
return r;
if (apdu.resplen == 2) {
return convert_sw_to_errorcode(apdu.resp);
}
if (apdu.resplen == count + 2)
apdu.resplen = count;
if (apdu.resplen == 0)
return _sc_sw_to_errorcode(apdu.sw1, apdu.sw2);
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;
}
int sc_format_apdu(struct sc_card *card,
struct sc_apdu *apdu,
unsigned char cse,
unsigned char ins, unsigned char p1, unsigned char p2)
int sc_format_apdu(struct sc_card *card, struct sc_apdu *apdu,
unsigned char cse, unsigned char ins,
unsigned char p1, unsigned char p2)
{
assert(card != NULL && apdu != NULL);
memset(apdu, 0, sizeof(*apdu));
@ -492,6 +512,8 @@ int sc_format_apdu(struct sc_card *card,
apdu->ins = ins;
apdu->p1 = p1;
apdu->p2 = p2;
apdu->no_response = 0;
return 0;
}
@ -691,6 +713,7 @@ int sc_connect_card(struct sc_context *ctx,
} else {
card->class = 0; /* FIXME */
}
pthread_mutex_init(&card->mutex, NULL);
*card_out = card;
return 0;
@ -700,6 +723,7 @@ int sc_disconnect_card(struct sc_card *card)
{
assert(card != NULL);
SCardDisconnect(card->pcsc_card, SCARD_LEAVE_CARD);
pthread_mutex_destroy(&card->mutex);
return 0;
}
@ -727,7 +751,10 @@ const char *sc_strerror(int error)
"Card not present",
"Error with Resource Manager",
"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]);
@ -740,159 +767,10 @@ const char *sc_strerror(int error)
return errors[error];
}
int sc_set_security_env(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)
int _sc_lock_int(struct sc_card *card)
{
long rv;
rv = SCardBeginTransaction(card->pcsc_card);
if (rv != SCARD_S_SUCCESS)
@ -901,7 +779,13 @@ int sc_lock(struct sc_card *card)
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;
@ -911,6 +795,12 @@ int sc_unlock(struct sc_card *card)
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 r;
@ -921,7 +811,7 @@ int sc_get_random(struct sc_card *card, u8 *rnd, int len)
0x84, 0x00, 0x00);
apdu.le = 8;
apdu.resp = buf;
apdu.resplen = 10; /* include SW's */
apdu.resplen = 8; /* include SW's */
while (len > 0) {
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);
if (r)
return r;
if (apdu.resplen != 10) {
if (apdu.resplen == 2)
return convert_sw_to_errorcode(apdu.resp);
return SC_ERROR_UNKNOWN;
}
if (apdu.resplen != 8)
return _sc_sw_to_errorcode(apdu.sw1, apdu.sw2);
memcpy(rnd, apdu.resp, n);
len -= 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);
if (r)
return r;
if (apdu.resplen < 2)
return -1; /* FIXME */
if (apdu.resplen == 2)
return convert_sw_to_errorcode(apdu.resp);
apdu.resplen -= 2;
if (apdu.resplen == 0)
return _sc_sw_to_errorcode(apdu.sw1, apdu.sw2);
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);
if (r)
return r;
if (apdu.resplen != 2)
return -1;
if (apdu.resp[0] == 0x90 && apdu.resp[1] == 0x00)
return 0;
return convert_sw_to_errorcode(apdu.resp);
return _sc_sw_to_errorcode(apdu.sw1, apdu.sw2);
}
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;
if (apdu.resplen != 2)
return -1;
if (apdu.resp[0] == 0x90 && apdu.resp[1] == 0x00)
return 0;
return convert_sw_to_errorcode(apdu.resp);
return _sc_sw_to_errorcode(apdu.sw1, apdu.sw2);
}
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>
* All rights reserved.
/*
* sc-sec.c: Cryptography and security (ISO7816-8) 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 <unistd.h>
#include <stdio.h>
#include <ctype.h>
#include <assert.h>
int sc_sec_ask_pin_code(struct sc_pkcs15_pin_info *pin,
char *out, int outlen, const char *prompt)
int sc_set_security_env(struct sc_card *card,
const struct sc_security_env *env)
{
char buf[80];
int i;
struct sc_apdu apdu;
u8 sbuf[MAX_BUFFER_SIZE];
u8 *p;
int r;
while (1) {
printf("%s [%s]: ", prompt, pin->com_attr.label);
fflush(stdin);
memset(buf, 0, sizeof(buf));
if (fgets(buf, 80, stdin) == NULL)
return -1;
i = 0;
while (isdigit(buf[i])) {
out[i] = buf[i];
i++;
if (i >= outlen)
continue;
}
out[i] = 0;
if (i < pin->min_length)
continue;
if (i > pin->stored_length)
continue;
memset(buf, 0, sizeof(buf));
break;
assert(card != NULL && env != NULL);
sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x22, 0, 0);
if (env->signature) {
apdu.p1 = 0x81;
apdu.p2 = 0xB6;
} else {
apdu.p1 = 0x41;
apdu.p2 = 0xB8;
}
return 0;
apdu.le = 0;
p = sbuf;
*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 - 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:
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.
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
4. Copy your PEM encoded certificate to a file in your home directory
called '.eid/authorized_certificates'.
NOTE: You can use the 'certtest' program to get the PEM encoded
certificate.
NOTE: You can use the 'sc-tool -r <ID> -o ~/.eid/authorized_certificates'
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.
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 const struct pam_message msg_pin =
{ PAM_PROMPT_ECHO_OFF, "Enter PIN 1: " };
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
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;
DBG(printf("Trying to get AUTHTOK...\n"));
r = pam_get_item(pamh, PAM_AUTHTOK, (void *) 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_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"));
r = pam_get_item(pamh, PAM_CONV, (const void **) &conv);
if (r != PAM_SUCCESS)
return r;
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)
return r;
if (resp) {
@ -164,23 +170,6 @@ static int get_password(pam_handle_t * pamh, char **password)
}
#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
int main(int argc, const char **argv)
#else
@ -194,7 +183,8 @@ PAM_EXTERN int pam_sm_authenticate(pam_handle_t * pamh, int flags, int argc, con
EVP_PKEY *pubkey = NULL;
struct sc_pkcs15_cert_info *cinfo;
struct sc_pkcs15_prkey_info *prkinfo = NULL;
struct sc_pkcs15_pin_info *pinfo = NULL;
u8 random_data[117];
u8 chg[128];
u8 plain_text[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++) {
}
cinfo = &p15card->cert_info[0]; /* FIXME */
DBG(printf("Enumerating private keys...\n"));
r = sc_pkcs15_enum_private_keys(p15card);
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);
DBG(printf("Finding private key...\n"));
r = sc_pkcs15_find_prkey_by_id(p15card, &cinfo->id, &prkinfo);
if (r < 0)
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
password = strdup(getpass("Enter PIN1: "));
r = 0;
#else
r = get_password(pamh, &password);
r = get_password(pamh, &password, pinfo->com_attr.label);
#endif
if (r) {
err = r;
goto end;
}
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) {
DBG(printf("PIN code verification failed: %s\n", sc_strerror(r)));
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"));
/* FIXME: clear password? */
#if 0
r = sc_restore_security_env(card, 0); /* empty SE */
if (r)
goto end;
#endif
r = set_sec_env(card, p15card, prkinfo);
if (r != PAM_SUCCESS) {
err = r;
DBG(printf("Deciphering...\n"));
r = sc_pkcs15_decipher(p15card, prkinfo, chg, sizeof(chg), plain_text, sizeof(plain_text));
if (r <= 0) {
DBG(printf("Decipher failed: %s\n", sc_strerror(r)));
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))
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;
DBG(printf("Cool, dude! You're in!\n"));
}
DBG(printf("You're in!\n"));
err = PAM_SUCCESS;
end:
if (locked)

View File

@ -5,8 +5,8 @@ CC= gcc
OPTIMIZER= -g
CFLAGS=-Wall $(OPTIMIZER) $(PLUGIN_DEFINES)
SRC= UnixShell.c stubs.c
OBJ= UnixShell.o stubs.o
SRC= signer.c stubs.c
OBJ= signer.o stubs.o
SHAREDTARGET=signer.so
@ -15,8 +15,8 @@ default all: $(SHAREDTARGET)
$(SHAREDTARGET): $(OBJ)
$(CC) -shared -o $(SHAREDTARGET) $(OBJ) $(LDFLAGS)
UnixShell.o: UnixShell.c
$(CC) -c $(CFLAGS) UnixShell.c
signer.o: signer.c
$(CC) -c $(CFLAGS) signer.c
stubs.o: 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-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;
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()
{
struct sc_file file;
struct sc_path path;
struct sc_apdu apdu;
u8 rbuf[MAX_BUFFER_SIZE], sbuf[MAX_BUFFER_SIZE];
int r;
sc_lock(card);
#if 1
r = sc_pkcs15_init(card, &p15card);
if (r < 0) {
@ -56,18 +35,33 @@ int test()
fprintf(stderr, "PIN code enum failed: %s\n", sc_strerror(r));
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);
if (r) {
fprintf(stderr, "PIN code verification failed: %s\n", sc_strerror(r));
goto err;
}
#endif
memcpy(path.value, "\x3f\x00", 2);
path.len = 2;
sc_debug = 1;
r = sc_select_file(card, &file, &path, SC_SELECT_FILE_BY_PATH);
sc_debug = 3;
sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x20, 0, 1);
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) {
fprintf(stderr, "sc_select_file failed: %s\n", sc_strerror(r));
fprintf(stderr, "transmit failed: %s\n", sc_strerror(r));
goto err;
}
r = sc_delete_file(card, 0x5110);
@ -75,6 +69,7 @@ int test()
fprintf(stderr, "fail: %s\n", sc_strerror(r));
goto err;
}
return 0;
memset(&file, 0, sizeof(file));
@ -95,6 +90,67 @@ err:
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 i;
@ -102,94 +158,11 @@ int main(int argc, char **argv)
i = sc_test_init(&argc, argv);
if (i != 0)
return 1;
if (test())
sc_debug = 3;
if (test3())
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();
return 0;

View File

@ -10,6 +10,7 @@
#include "sc-pkcs15.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
struct sc_pkcs15_card *p15card;
@ -35,29 +36,40 @@ int enum_pins()
int ask_and_verify_pin(struct sc_pkcs15_pin_info *pin)
{
int i = 0;
char buf[32];
char prompt[80];
char *pass;
i = sc_sec_ask_pin_code(pin, buf, sizeof(buf),
"Please enter PIN code");
if (i == 0) {
sc_lock(card);
i = sc_pkcs15_verify_pin(p15card, pin, buf, strlen(buf));
sc_unlock(card);
if (i) {
if (i == SC_ERROR_PIN_CODE_INCORRECT)
fprintf(stderr,
"Incorrect PIN code (%d tries left)\n",
pin->tries_left);
else
fprintf(stderr,
"PIN verifying failed: %s\n",
sc_strerror(i));
return 1;
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;
}
printf("PIN code correct.\n");
} else {
printf("\nNot verifying PIN code.\n");
if (strlen(pass) < pin->min_length)
break;
if (strlen(pass) > pin->stored_length)
break;
break;
}
sc_lock(card);
i = sc_pkcs15_verify_pin(p15card, pin, pass, strlen(pass));
sc_unlock(card);
if (i) {
if (i == SC_ERROR_PIN_CODE_INCORRECT)
fprintf(stderr,
"Incorrect PIN code (%d tries left)\n",
pin->tries_left);
else
fprintf(stderr,
"PIN verifying failed: %s\n",
sc_strerror(i));
return 1;
} else
printf("PIN code correct.\n");
return 0;
}

View File

@ -17,18 +17,22 @@ char * opt_cert = NULL;
char * opt_outfile = NULL;
char * opt_pincode = NULL;
char * opt_newpin = NULL;
char * opt_apdu = NULL;
int quiet = 0;
const struct option options[] = {
{ "list-readers", 0, 0, 'l' },
{ "list-files", 0, 0, 'f' },
{ "send-apdu", 1, 0, 's' },
{ "read-certificate", 1, 0, 'r' },
{ "list-certificates", 0, 0, 'c' },
{ "list-pins", 0, 0, OPT_LIST_PINS },
{ "change-pin", 2, 0, OPT_CHANGE_PIN },
{ "list-private-keys", 0, 0, 'k' },
{ "reader", 1, 0, OPT_READER },
{ "output", 1, 0, 'o' },
{ "quiet", 0, 0, 'q' },
{ "debug", 0, 0, 'd' },
{ "pin", 1, 0, 'p' },
{ "pin-id", 1, &opt_pin, 0 },
{ 0, 0, 0, 0 }
@ -37,15 +41,18 @@ const struct option options[] = {
const char *option_help[] = {
"Lists all configured readers",
"Recursively lists files stored on card",
"Read certificate with ID <arg>",
"Lists certificates",
"Lists PIN codes",
"Changes the PIN code to <arg>",
"Sends an APDU in format AA:BB:CC:DD:EE:FF...",
"Reads certificate with ID <arg> [P15]",
"Lists certificates [P15]",
"Lists PIN codes [P15]",
"Changes the PIN code to <arg> [P15]",
"Lists private keys [P15]",
"Uses reader number <arg>",
"Outputs to file <arg>",
"Quiet operation",
"Uses PIN <arg>; if not supplied, asks the user",
"Choose which PIN to use",
"Debug output -- may be supplied several timeso"
"Uses password (PIN) <arg>",
"The auth ID of the PIN to use [P15]",
};
struct sc_context *ctx = NULL;
@ -113,69 +120,85 @@ int list_certificates()
return 0;
}
int print_pem_certificate(struct sc_pkcs15_cert *cert)
{
int r;
u8 buf[2048];
FILE *outf;
r = sc_base64_encode(cert->data, cert->data_len, buf,
sizeof(buf), 64);
if (r) {
fprintf(stderr, "Base64 encoding failed: %s\n", sc_strerror(r));
return 1;
}
if (opt_outfile != NULL) {
outf = fopen(opt_outfile, "w");
if (outf == NULL) {
fprintf(stderr, "Error opening file '%s': %s\n",
opt_outfile, strerror(errno));
return 2;
}
} else
outf = stdout;
fprintf(outf, "-----BEGIN CERTIFICATE-----\n%s-----END CERTIFICATE-----\n",
buf);
if (outf != stdout)
fclose(outf);
return 0;
}
int read_certificate()
{
int r, i;
struct sc_pkcs15_id id;
u8 *p = id.value;
char *certp = opt_cert;
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;
id.len = SC_PKCS15_MAX_ID_SIZE;
sc_pkcs15_hex_string_to_id(opt_cert, &id);
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;
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 = sc_base64_encode(cert->data, cert->data_len, buf,
sizeof(buf), 64);
r = print_pem_certificate(cert);
sc_pkcs15_free_certificate(cert);
if (r) {
fprintf(stderr, "Base64 encoding failed: %s\n", sc_strerror(r));
return 1;
}
if (opt_outfile != NULL) {
outf = fopen(opt_outfile, "w");
if (outf == NULL) {
fprintf(stderr, "Error opening file '%s': %s\n",
opt_outfile, strerror(errno));
return 2;
}
} else
outf = stdout;
fprintf(outf, "-----BEGIN CERTIFICATE-----\n%s-----END CERTIFICATE-----\n",
buf);
if (outf != stdout)
fclose(outf);
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;
}
@ -343,6 +366,60 @@ int list_files()
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 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_pins = 0;
int do_list_files = 0;
int do_list_prkeys = 0;
int do_change_pin = 0;
int do_send_apdu = 0;
int action_count = 0;
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)
break;
if (c == '?')
@ -378,6 +457,11 @@ int main(int argc, char * const argv[])
do_list_certs = 1;
action_count++;
break;
case 's':
opt_apdu = optarg;
do_send_apdu++;
action_count++;
break;
case OPT_CHANGE_PIN:
do_change_pin = 1;
action_count++;
@ -386,6 +470,10 @@ int main(int argc, char * const argv[])
do_list_pins = 1;
action_count++;
break;
case 'k':
do_list_prkeys = 1;
action_count++;
break;
case OPT_READER:
opt_reader = atoi(optarg);
break;
@ -395,6 +483,9 @@ int main(int argc, char * const argv[])
case 'q':
quiet++;
break;
case 'd':
sc_debug++;
break;
case 'p':
if (optarg == NULL && opt_pincode == NULL)
opt_pincode = getpass("Enter PIN code: ");
@ -437,12 +528,17 @@ int main(int argc, char * const argv[])
sc_lock(card);
if (do_send_apdu) {
if ((err = send_apdu()))
goto end;
action_count--;
}
if (do_list_files) {
if ((err = list_files()))
goto end;
action_count--;
}
/* Here go the actions that do not require PKCS#15 */
if (action_count <= 0)
goto end;
@ -466,6 +562,11 @@ int main(int argc, char * const argv[])
goto end;
action_count--;
}
if (do_list_prkeys) {
if ((err = list_private_keys()))
goto end;
action_count--;
}
if (do_list_pins) {
if ((err = list_pins()))
goto end;