- 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:
parent
e5cf39b2eb
commit
ea594e3e50
|
@ -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 }
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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.
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue