- moved libsc to its own directory

- added non-working MIME plugin for "text/x-text-to-sign"
- added pseudo-random number generator support
- split hst-test.c into smaller files


git-svn-id: https://www.opensc-project.org/svnp/opensc/trunk@31 c6295689-39f2-0310-b995-f0e70906c6a9
This commit is contained in:
jey 2001-11-01 15:43:20 +00:00
parent aea833a5e8
commit c57e2e266d
25 changed files with 3887 additions and 123 deletions

389
src/libopensc/asn1.c Normal file
View File

@ -0,0 +1,389 @@
/* Copyright (C) 2001 Juha Yrjölä <juha.yrjola@iki.fi>
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
*/
#include "sc.h"
#include "sc-asn1.h"
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <assert.h>
const char *tag2str(int tag)
{
const static char *tags[] = {
"EOC", "BOOLEAN", "INTEGER", "BIT STRING", "OCTET STRING", /* 0-4 */
"NULL", "OBJECT", "OBJECT DESCRIPTOR", "EXTERNAL", "REAL", /* 5-9 */
"ENUMERATED", "<ASN1 11>", "UTF8STRING", "<ASN1 13>", /* 10-13 */
"<ASN1 14>", "<ASN1 15>", "SEQUENCE", "SET", /* 15-17 */
"NUMERICSTRING", "PRINTABLESTRING", "T61STRING", /* 18-20 */
"VIDEOTEXSTRING", "IA5STRING", "UTCTIME", "GENERALIZEDTIME", /* 21-24 */
"GRAPHICSTRING", "VISIBLESTRING", "GENERALSTRING", /* 25-27 */
"UNIVERSALSTRING", "<ASN1 29>", "BMPSTRING" /* 28-30 */
};
if (tag < 0 || tag > 30)
return "(unknown)";
return tags[tag];
}
static int read_tag(const u8 ** buf,
int buflen, int *cla_out, int *tag_out, int *taglen)
{
const u8 *p = *buf;
int left = buflen;
int cla, tag, len, i;
*buf = NULL;
if (*p == 0)
return 0;
cla = (*p & ASN1_TAG_CLASS) | (*p & ASN1_TAG_CONSTRUCTED);
tag = *p & ASN1_TAG_PRIMITIVE;
if (tag == ASN1_TAG_PRIMITIVE) { /* 0x1F */
fprintf(stderr, "Tag number >= 0x1F not supported!\n");
goto error;
}
p++;
if (--left == 0)
goto error;
len = *p & 0x7f;
if (*p++ & 0x80) {
int a = 0;
if (len > 4) {
fprintf(stderr, "ASN.1 tag too long!\n");
goto error;
}
for (i = 0; i < len; i++) {
a <<= 8;
a |= *p;
p++;
}
len = a;
}
*cla_out = cla;
*tag_out = tag;
*taglen = len;
*buf = p;
return 1;
error:
return -1;
}
static void sc_asn1_print_octet_string(const u8 * buf, int buflen)
{
int i;
for (i = 0; i < buflen; i++)
printf("%02X", buf[i]);
}
static void sc_asn1_print_utf8string(const u8 * buf, int buflen)
{
int i;
for (i = 0; i < buflen; i++)
printf("%c", buf[i]);
}
static void sc_asn1_print_integer(const u8 * buf, int buflen)
{
long long a = 0;
int i;
if (buflen > sizeof(a)) {
printf("too long");
return;
}
for (i = 0; i < buflen; i++) {
a <<= 8;
a |= buf[i];
}
printf("%lld", a);
}
static void sc_asn1_print_bit_string(const u8 * buf, int buflen)
{
unsigned long long a = 0;
int i, r;
if (buflen > sizeof(a) + 1) {
printf("too long");
return;
}
r = sc_asn1_decode_bit_string(buf, buflen, &a, sizeof(a));
if (r < 0) {
printf("decode error");
return;
}
for (i = r - 1; i >= 0; i--) {
printf("%c", ((a >> i) & 1) ? '1' : '0');
}
}
static void sc_asn1_print_object_id(const u8 * buf, int buflen)
{
int i = 0;
struct sc_object_id oid;
char sbuf[256];
if (sc_asn1_decode_object_id(buf, buflen, &oid)) {
printf("decode error");
return;
}
sbuf[0] = 0;
while (oid.value[i] >= 0) {
char tmp[12];
if (i)
strcat(sbuf, ".");
sprintf(tmp, "%d", oid.value[i]);
strcat(sbuf, tmp);
i++;
}
printf("%s", sbuf);
}
static void print_tags_recursive(const u8 * buf0,
const u8 * buf, int buflen, int depth)
{
int i, r, bytesleft = buflen;
const char *classes[4] = {
"Univ", "Appl", "Cntx", "Priv"
};
const u8 *p = buf;
while (bytesleft >= 2) {
int cla, tag, len, hlen;
const u8 *tagp = p;
r = read_tag(&tagp, bytesleft, &cla, &tag, &len);
if (r < 0) {
printf("Error in decoding.\n");
return;
}
hlen = tagp - p;
if (r == 0)
return;
if (cla == 0 && tag == 0) {
printf("Zero tag, finishing\n");
break;
}
for (i = 0; i < depth; i++) {
putchar(' ');
putchar(' ');
}
printf("%02X %s: tag 0x%02X, length %3d: ",
cla | tag, classes[cla >> 6], tag & 0x1f, len);
if (len + hlen > bytesleft) {
printf(" Illegal length!\n");
return;
}
p += hlen + len;
bytesleft -= hlen + len;
if ((cla & ASN1_TAG_CLASS) == ASN1_TAG_UNIVERSAL)
printf("%s", tag2str(tag));
if (cla & ASN1_TAG_CONSTRUCTED) {
putchar('\n');
print_tags_recursive(buf0, tagp, len, depth + 1);
continue;
}
if ((cla & ASN1_TAG_CLASS) == ASN1_TAG_UNIVERSAL) {
printf(" [");
switch (tag) {
case ASN1_BIT_STRING:
sc_asn1_print_bit_string(tagp, len);
break;
case ASN1_OCTET_STRING:
sc_asn1_print_octet_string(tagp, len);
break;
case ASN1_OBJECT:
sc_asn1_print_object_id(tagp, len);
break;
case ASN1_INTEGER:
case ASN1_ENUMERATED:
sc_asn1_print_integer(tagp, len);
break;
case ASN1_T61STRING:
case ASN1_PRINTABLESTRING:
case ASN1_UTF8STRING:
sc_asn1_print_utf8string(tagp, len);
break;
}
printf("]");
}
putchar('\n');
}
return;
}
void sc_asn1_print_tags(const u8 * buf, int buflen)
{
printf("Printing tags for buffer of length %d\n", buflen);
print_tags_recursive(buf, buf, buflen, 0);
}
const u8 *sc_asn1_find_tag(const u8 * buf, int buflen, int tag_in, int *taglen_in)
{
int left = buflen, cla, tag, taglen;
const u8 *p = buf;
*taglen_in = 0;
while (left >= 2) {
buf = p;
if (read_tag(&p, left, &cla, &tag, &taglen) != 1)
return NULL;
left -= (p - buf);
if ((tag | cla) == tag_in) {
if (taglen > left)
return NULL;
*taglen_in = taglen;
return p;
}
if ((cla | tag) == 0xF0) { /* skip 0xF0 foobar tags */
fprintf(stderr, "Foobar tag skipped\n");
taglen = 0;
}
left -= taglen;
p += taglen;
}
return NULL;
}
const u8 *sc_asn1_skip_tag(const u8 ** buf, int *buflen, int tag_in, int *taglen_out)
{
const u8 *p = *buf;
int len = *buflen, cla, tag, taglen;
if (read_tag((const u8 **) &p, len, &cla, &tag, &taglen) != 1)
return NULL;
if ((tag | cla) != tag_in)
return NULL;
len -= (p - *buf); /* header size */
if (taglen > len) {
fprintf(stderr, "skip_tag(): too long tag\n");
return NULL;
}
*buflen -= (p - *buf) + taglen;
*buf = p + taglen; /* point to next tag */
*taglen_out = taglen;
return p;
}
const u8 *sc_asn1_verify_tag(const u8 * buf, int buflen, int tag_in, int *taglen_out)
{
return sc_asn1_skip_tag(&buf, &buflen, tag_in, taglen_out);
}
static int decode_bit_string(const u8 * inbuf, int inlen, void *outbuf,
int outlen, int invert)
{
const u8 *in = inbuf;
u8 *out = (u8 *) outbuf;
int zero_bits = *in & 0x07;
int octets_left = inlen - 1;
int i, count = 0;
in++;
if (outlen < octets_left)
return SC_ERROR_INVALID_ARGUMENTS;
while (octets_left) {
/* 1st octet of input: ABCDEFGH, where A is the MSB */
/* 1st octet of output: HGFEDCBA, where A is the LSB */
/* first bit in bit string is the LSB in first resulting octet */
int bits_to_go;
*out = 0;
if (octets_left == 1)
bits_to_go = 8 - zero_bits;
else
bits_to_go = 8;
if (invert)
for (i = 0; i < bits_to_go; i++) {
*out |= ((*in >> (7 - i)) & 1) << i;
}
else {
*out = *in;
}
out++;
in++;
octets_left--;
count++;
}
return (count * 8) - zero_bits;
}
int sc_asn1_decode_bit_string(const u8 * inbuf,
int inlen, void *outbuf, int outlen)
{
return decode_bit_string(inbuf, inlen, outbuf, outlen, 1);
}
int sc_asn1_decode_bit_string_ni(const u8 * inbuf,
int inlen, void *outbuf, int outlen)
{
return decode_bit_string(inbuf, inlen, outbuf, outlen, 0);
}
int sc_asn1_decode_integer(const u8 * inbuf, int inlen, int *out)
{
int i, a = 0;
if (inlen > sizeof(int))
return SC_ERROR_INVALID_ASN1_OBJECT;
for (i = 0; i < inlen; i++) {
a <<= 8;
a |= *inbuf++;
}
*out = a;
return 0;
}
int sc_asn1_decode_object_id(const u8 * inbuf, int inlen,
struct sc_object_id *id)
{
int i, a;
const u8 *p = inbuf;
int *octet = id->value;
assert(id != NULL);
if (inlen < 1)
return SC_ERROR_INVALID_ASN1_OBJECT;
for (i = 0; i < SC_ASN1_MAX_OBJECT_ID_OCTETS; i++)
id->value[i] = -1;
a = *p;
*octet++ = a / 40;
*octet++ = a % 40;
inlen--;
while (inlen) {
p++;
a = *p & 0x7F;
inlen--;
while (inlen && *p & 0x80) {
p++;
a <<= 7;
a |= *p & 0x7F;
inlen--;
}
*octet++ = a;
if (octet - id->value >= SC_ASN1_MAX_OBJECT_ID_OCTETS-1)
return SC_ERROR_INVALID_ASN1_OBJECT;
};
return 0;
}

48
src/libopensc/asn1.h Normal file
View File

@ -0,0 +1,48 @@
/* Copyright (C) 2001 Juha Yrjölä <juha.yrjola@iki.fi>
* All rights reserved.
*/
#ifndef _SC_ASN1_H
#define _SC_ASN1_H
#define ASN1_TAG_CLASS 0xC0
#define ASN1_TAG_UNIVERSAL 0x00
#define ASN1_TAG_APPLICATION 0x40
#define ASN1_TAG_CONTEXT 0x80
#define ASN1_TAG_PRIVATE 0xC0
#define ASN1_TAG_CONSTRUCTED 0x20
#define ASN1_TAG_PRIMITIVE 0x1F
#define ASN1_EOC 0
#define ASN1_BOOLEAN 1 /**/
#define ASN1_INTEGER 2
#define ASN1_NEG_INTEGER (2 | ASN1_NEG)
#define ASN1_BIT_STRING 3
#define ASN1_OCTET_STRING 4
#define ASN1_NULL 5
#define ASN1_OBJECT 6
#define ASN1_OBJECT_DESCRIPTOR 7
#define ASN1_EXTERNAL 8
#define ASN1_REAL 9
#define ASN1_ENUMERATED 10
#define ASN1_NEG_ENUMERATED (10 | ASN1_NEG)
#define ASN1_UTF8STRING 12
#define ASN1_SEQUENCE 16
#define ASN1_SET 17
#define ASN1_NUMERICSTRING 18 /**/
#define ASN1_PRINTABLESTRING 19
#define ASN1_T61STRING 20
#define ASN1_TELETEXSTRING 20 /* alias */
#define ASN1_VIDEOTEXSTRING 21 /**/
#define ASN1_IA5STRING 22
#define ASN1_UTCTIME 23
#define ASN1_GENERALIZEDTIME 24 /**/
#define ASN1_GRAPHICSTRING 25 /**/
#define ASN1_ISO64STRING 26 /**/
#define ASN1_VISIBLESTRING 26 /* alias */
#define ASN1_GENERALSTRING 27 /**/
#define ASN1_UNIVERSALSTRING 28 /**/
#define ASN1_BMPSTRING 30
#endif

View File

@ -0,0 +1,187 @@
/* Copyright (C) 2001 Juha Yrjölä <juha.yrjola@iki.fi>
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
*/
#ifndef _SC_PKCS15_H
#define _SC_PKCS15_H
#include "sc.h"
#define SC_PKCS15_PIN_MAGIC 0x31415926
#define SC_PKCS15_MAX_PINS 2
#define SC_PKCS15_MAX_CERTS 3
#define SC_PKCS15_MAX_PRKEYS 2
#define SC_PKCS15_MAX_LABEL_SIZE 32
#define SC_PKCS15_MAX_ID_SIZE 16
struct sc_pkcs15_id {
u8 value[SC_PKCS15_MAX_ID_SIZE];
int len;
};
struct sc_pkcs15_common_obj_attr {
char label[SC_PKCS15_MAX_LABEL_SIZE]; /* zero terminated */
int flags;
struct sc_pkcs15_id auth_id;
int user_consent;
/* FIXME: add accessControlRules */
};
struct sc_pkcs15_pin_info {
struct sc_pkcs15_common_obj_attr com_attr;
struct sc_pkcs15_id auth_id;
int flags, type;
int min_length, stored_length;
u8 pad_char;
struct sc_path path;
int tries_left;
unsigned int magic;
};
#define SC_PKCS15_ALGO_OP_COMPUTE_CHECKSUM 0x01
#define SC_PKCS15_ALGO_OP_COMPUTE_SIGNATURE 0x02
#define SC_PKCS15_ALGO_OP_VERIFY_CHECKSUM 0x04
#define SC_PKCS15_ALGO_OP_VERIFY_SIGNATURE 0x08
#define SC_PKCS15_ALGO_OP_ENCIPHER 0x10
#define SC_PKCS15_ALGO_OP_DECIPHER 0x20
#define SC_PKCS15_ALGO_OP_HASH 0x40
#define SC_PKCS15_ALGO_OP_GENERATE_KEY 0x80
struct sc_pkcs15_algorithm_info {
int reference;
int algorithm, supported_operations;
};
struct sc_pkcs15_rsa_pubkey {
u8 *modulus;
int modulus_len;
unsigned int exponent;
};
struct sc_pkcs15_cert {
int version;
unsigned long long serial;
struct sc_pkcs15_rsa_pubkey key;
u8 *data; /* DER encoded raw cert */
int data_len;
};
struct sc_pkcs15_cert_info {
struct sc_pkcs15_common_obj_attr com_attr;
struct sc_pkcs15_id id; /* correlates to private RSA key id */
int authority; /* boolean */
/* identifiers [2] SEQUENCE OF CredentialIdentifier{{KeyIdentifiers}} */
struct sc_path path;
};
#define SC_PCKS15_PRKEY_USAGE_ENCRYPT 0x01
#define SC_PCKS15_PRKEY_USAGE_DECRYPT 0x02
#define SC_PCKS15_PRKEY_USAGE_SIGN 0x04
#define SC_PCKS15_PRKEY_USAGE_SIGNRECOVER 0x08
#define SC_PCKS15_PRKEY_USAGE_WRAP 0x10
#define SC_PCKS15_PRKEY_USAGE_UNWRAP 0x20
#define SC_PCKS15_PRKEY_USAGE_VERIFY 0x40
#define SC_PCKS15_PRKEY_USAGE_VERIFYRECOVER 0x80
#define SC_PCKS15_PRKEY_USAGE_DERIVE 0x100
#define SC_PCKS15_PRKEY_USAGE_NONREPUDIATION 0x200
#define SC_PKCS15_PRKEY_ACCESS_SENSITIVE 0x01
#define SC_PKCS15_PRKEY_ACCESS_EXTRACTABLE 0x02
#define SC_PKCS15_PRKEY_ACCESS_ALWAYSSENSITIVE 0x04
#define SC_PKCS15_PRKEY_ACCESS_NEVEREXTRACTABLE 0x08
#define SC_PKCS15_PRKEY_ACCESS_LOCAL 0x10
struct sc_pkcs15_prkey_info {
struct sc_pkcs15_common_obj_attr com_attr;
struct sc_pkcs15_id id; /* correlates to public certificate id */
int usage, access_flags;
int key_reference;
struct sc_path file_id;
int modulus_length;
};
struct sc_pkcs15_card {
struct sc_card *card;
char *label;
struct sc_file file_dir, file_ao1, file_app;
/* in app DF */
struct sc_file file_tokeninfo, file_odf;
struct sc_file file_prkdf;
struct sc_file file_aodf, file_ao2;
struct sc_file file_cdf1, file_cdf2, file_cdf3;
struct sc_file file_dodf;
/* fields from TokenInfo: */
int version;
char *serial_number, *manufacturer_id;
int flags;
struct sc_pkcs15_algorithm_info alg_info[1];
struct sc_pkcs15_cert_info cert_info[SC_PKCS15_MAX_CERTS];
int cert_count;
struct sc_pkcs15_prkey_info prkey_info[SC_PKCS15_MAX_PRKEYS];
int prkey_count;
struct sc_pkcs15_pin_info pin_info[SC_PKCS15_MAX_PINS];
int pin_count;
};
#define SC_PKCS15_CARD_FLAG_READONLY 0x01
#define SC_PKCS15_CARD_FLAG_LOGIN_REQUIRED 0x02
#define SC_PKCS15_CARD_FLAG_PRN_GENERATION 0x04
#define SC_PKCS15_CARD_FLAG_EID_COMPLIANT 0x08
int sc_pkcs15_init(struct sc_card *card,
struct sc_pkcs15_card **pkcs15_card);
int sc_pkcs15_destroy(struct sc_pkcs15_card *card);
void sc_pkcs15_print_card(const struct sc_pkcs15_card *card);
void sc_pkcs15_print_cert_info(const struct sc_pkcs15_cert_info *cert);
int sc_pkcs15_enum_certificates(struct sc_pkcs15_card *card);
int sc_pkcs15_read_certificate(struct sc_pkcs15_card *card,
const struct sc_pkcs15_cert_info *info,
struct sc_pkcs15_cert **cert);
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);
void sc_pkcs15_print_pin_info(const struct sc_pkcs15_pin_info *pin);
int sc_pkcs15_enum_pins(struct sc_pkcs15_card *card);
int sc_pkcs15_verify_pin(struct sc_pkcs15_card *card,
struct sc_pkcs15_pin_info *pin,
char *pincode, int pinlen);
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_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_parse_common_object_attr(struct sc_pkcs15_common_obj_attr *attr,
const u8 * buf, int buflen);
#endif

185
src/libopensc/opensc.h Normal file
View File

@ -0,0 +1,185 @@
/* Copyright (C) 2001 Juha Yrjölä <juha.yrjola@iki.fi>
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
*/
#ifndef _SC_H
#define _SC_H
#include <winscard.h>
#define SC_ERROR_MIN -1000
#define SC_ERROR_UNKNOWN -1000
#define SC_ERROR_CMD_TOO_SHORT -1001
#define SC_ERROR_CMD_TOO_LONG -1002
#define SC_ERROR_NOT_SUPPORTED -1003
#define SC_ERROR_TRANSMIT_FAILED -1004
#define SC_ERROR_FILE_NOT_FOUND -1005
#define SC_ERROR_INVALID_ARGUMENTS -1006
#define SC_ERROR_PKCS15_CARD_NOT_FOUND -1007
#define SC_ERROR_REQUIRED_PARAMETER_NOT_FOUND -1008
#define SC_ERROR_OUT_OF_MEMORY -1009
#define SC_ERROR_NO_READERS_FOUND -1010
#define SC_ERROR_OBJECT_NOT_VALID -1011
#define SC_ERROR_UNKNOWN_RESPONSE -1012
#define SC_ERROR_PIN_CODE_INCORRECT -1013
#define SC_ERROR_SECURITY_STATUS_NOT_SATISFIED -1014
#define SC_ERROR_CONNECTING_TO_RES_MGR -1015
#define SC_ERROR_INVALID_ASN1_OBJECT -1016
#define SC_APDU_CASE_NONE 0
#define SC_APDU_CASE_1 1
#define SC_APDU_CASE_2_SHORT 2
#define SC_APDU_CASE_3_SHORT 3
#define SC_APDU_CASE_4_SHORT 4
#define SC_APDU_CASE_2_EXT 5
#define SC_APDU_CASE_3_EXT 6
#define SC_APDU_CASE_4_EXT 7
#define SC_ISO7816_4_SELECT_FILE 0xA4
#define SC_ISO7816_4_GET_RESPONSE 0xC0
#define SC_ISO7616_4_READ_BINARY 0xB0
#define SC_ISO7616_4_VERIFY 0x20
#define SC_ISO7616_4_UPDATE_BINARY 0xD6
#define SC_ISO7616_4_ERASE_BINARY 0x0E
#define SC_SELECT_FILE_RECORD_FIRST 0x00
#define SC_SELECT_FILE_RECORD_LAST 0x01
#define SC_SELECT_FILE_RECORD_NEXT 0x02
#define SC_SELECT_FILE_RECORD_PREVIOUS 0x03
#define SC_SELECT_FILE_BY_FILE_ID 0x00
#define SC_SELECT_FILE_BY_DF_NAME 0x01
#define SC_SELECT_FILE_BY_PATH 0x02
#define SC_FILE_MAGIC 0x10203040
#define SC_FILE_TYPE_DF 0x07
#define SC_FILE_TYPE_INTERNAL_EF 0x01
#define SC_FILE_TYPE_WORKING_EF 0x00
#define SC_MAX_READERS 4
#define SC_MAX_PATH_SIZE 16
#define SC_MAX_PIN_SIZE 16
#define SC_ASN1_MAX_OBJECT_ID_OCTETS 16
typedef unsigned char u8;
struct sc_object_id {
int value[SC_ASN1_MAX_OBJECT_ID_OCTETS];
};
struct sc_path {
u8 value[SC_MAX_PATH_SIZE];
int len;
};
struct sc_file {
struct sc_path path;
u8 name[16];
int namelen;
int type;
int size, id;
unsigned int magic;
};
struct sc_card {
int class;
struct sc_context *context;
SCARDHANDLE pcsc_card;
};
struct sc_context {
SCARDCONTEXT pcsc_ctx;
char *readers[SC_MAX_READERS];
int reader_count;
};
struct sc_apdu {
int cse; /* APDU case */
u8 cla, ins, p1, p2;
int lc, le;
const u8 *data; /* C-APDU */
int datalen; /* length of C-APDU */
u8 *resp; /* R-APDU */
int resplen; /* length of R-APDU */
};
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;
int key_ref;
};
const u8 *sc_asn1_find_tag(const u8 * buf, int buflen, int tag, int *taglen);
const u8 *sc_asn1_verify_tag(const u8 * buf, int buflen, int tag, int *taglen);
const u8 *sc_asn1_skip_tag(const u8 ** buf, int *buflen, int tag, int *taglen);
void sc_asn1_print_tags(const u8 * buf, int buflen);
int sc_asn1_utf8string_to_ascii(const u8 * buf,
int buflen, u8 * outbuf, int outlen);
int sc_asn1_decode_bit_string(const u8 * inbuf,
int inlen, void *outbuf, int outlen);
/* non-inverting version */
int sc_asn1_decode_bit_string_ni(const u8 * inbuf,
int inlen, void *outbuf, int outlen);
int sc_asn1_decode_integer(const u8 * inbuf, int inlen, int *out);
int sc_asn1_decode_object_id(const u8 * inbuf, int inlen,
struct sc_object_id *id);
/* internal functions */
int sc_check_apdu(const struct sc_apdu *apdu);
int sc_transmit_apdu(struct sc_card *card, struct sc_apdu *apdu);
int sc_format_apdu(struct sc_card *card,
struct sc_apdu *apdu, u8 cse, u8 ins, u8 p1, u8 p2);
int sc_establish_context(struct sc_context **ctx);
int sc_destroy_context(struct sc_context *ctx);
int sc_connect_card(struct sc_context *ctx,
int reader, struct sc_card **card);
int sc_disconnect_card(struct sc_card *card);
int sc_detect_card(struct sc_context *ctx, int reader);
/* timeout of -1 means forever, reader of -1 means all readers */
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);
int sc_select_file(struct sc_card *card,
struct sc_file *file,
const struct sc_path *path, int pathtype);
int sc_read_binary(struct sc_card *card, int idx, u8 * buf, int count);
int sc_restore_security_env(struct sc_card *card, int se_num);
int sc_set_security_env(struct sc_card *card,
const struct sc_security_env *env);
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_get_random(struct sc_card *card, u8 * rndout, int len);
const char *sc_strerror(int error);
int sc_debug;
#endif

302
src/libopensc/pkcs15-cert.c Normal file
View File

@ -0,0 +1,302 @@
/* Copyright (C) 2001 Juha Yrjölä <juha.yrjola@iki.fi>
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
*/
#include "sc.h"
#include "sc-pkcs15.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <assert.h>
static int parse_rsa_pubkey(const u8 *buf, int buflen, struct sc_pkcs15_rsa_pubkey *key)
{
const u8 *tag;
int taglen;
buf = sc_asn1_verify_tag(buf, buflen, 0x30, &buflen);
if (buf == NULL)
return -1;
tag = sc_asn1_verify_tag(buf, buflen, 0x02, &taglen);
if (tag == NULL)
return -1;
key->modulus = malloc(taglen);
memcpy(key->modulus, tag, taglen);
key->modulus_len = taglen;
tag += taglen;
buflen -= tag - buf;
tag = sc_asn1_verify_tag(tag, buflen, 0x02, &taglen);
if (sc_asn1_decode_integer(tag, taglen, (int *) &key->exponent)) {
free(key->modulus);
return SC_ERROR_INVALID_ASN1_OBJECT;
}
return 0;
}
static int parse_cert(const u8 *buf, int buflen, struct sc_pkcs15_cert *cert)
{
const u8 *tag, *p;
u8 *tmpbuf;
int taglen, left, r;
struct sc_pkcs15_rsa_pubkey *key = &cert->key;
buf = sc_asn1_verify_tag(buf, buflen, 0x30, &buflen); /* SEQUENCE */
if (buf == NULL) /* Certificate */
return SC_ERROR_INVALID_ASN1_OBJECT;
p = sc_asn1_skip_tag(&buf, &buflen, 0x30, &left); /* SEQUENCE */
if (p == NULL) /* tbsCertificate */
return SC_ERROR_INVALID_ASN1_OBJECT;
cert->version = 0;
tag = sc_asn1_skip_tag(&p, &left, 0xA0, &taglen); /* Version */
if (tag != NULL) {
tag = sc_asn1_verify_tag(tag, taglen, 0x02, &taglen);
if (tag != NULL) {
sc_asn1_decode_integer(tag, taglen, &cert->version);
cert->version++;
}
}
tag = sc_asn1_skip_tag(&p, &left, 0x02, &taglen); /* INTEGER */
if (tag == NULL)
return SC_ERROR_INVALID_ASN1_OBJECT;
sc_asn1_decode_integer(tag, taglen, (int *) &cert->serial);
tag = sc_asn1_skip_tag(&p, &left, 0x30, &taglen); /* signatureId */
if (tag == NULL)
return SC_ERROR_INVALID_ASN1_OBJECT;
tag = sc_asn1_skip_tag(&p, &left, 0x30, &taglen); /* issuer */
if (tag == NULL)
return SC_ERROR_INVALID_ASN1_OBJECT;
tag = sc_asn1_skip_tag(&p, &left, 0x30, &taglen); /* validity */
if (tag == NULL)
return SC_ERROR_INVALID_ASN1_OBJECT;
tag = sc_asn1_skip_tag(&p, &left, 0x30, &taglen); /* subject */
if (tag == NULL)
return SC_ERROR_INVALID_ASN1_OBJECT;
tag = sc_asn1_skip_tag(&p, &left, 0x30, &taglen); /* subjectPKInfo */
if (tag == NULL)
return SC_ERROR_INVALID_ASN1_OBJECT;
/* FIXME: get the algorithm ID */
tag = sc_asn1_find_tag(tag, taglen, 0x03, &taglen); /* subjectPubKey */
if (tag == NULL)
return SC_ERROR_INVALID_ASN1_OBJECT;
tmpbuf = malloc(taglen-1);
r = sc_asn1_decode_bit_string_ni(tag, taglen, tmpbuf, taglen-1);
if (r < 0) {
free(tmpbuf);
return SC_ERROR_INVALID_ASN1_OBJECT;
}
r >>= 3;
r = parse_rsa_pubkey(tmpbuf, r, key);
free(tmpbuf);
if (r)
return SC_ERROR_INVALID_ASN1_OBJECT;
return 0;
}
int sc_pkcs15_read_certificate(struct sc_pkcs15_card *p15card,
const struct sc_pkcs15_cert_info *info,
struct sc_pkcs15_cert **cert_out)
{
int r, len;
struct sc_file file;
char *data;
struct sc_pkcs15_cert *cert;
char fname[50];
u8 buf[2048];
FILE *crtf;
int cert_found = 0;
assert(p15card != NULL && info != NULL && cert_out != NULL);
/* FIXME: Remove this kludge */
sprintf(fname, "/tmp/fineid-%02X.crt", info->id.value[0]);
crtf = fopen(fname, "r");
if (crtf != NULL) {
r = fread(buf, 1, sizeof(buf), crtf);
if (r > 0) {
data = malloc(r);
memcpy(data, buf, r);
len = r;
cert_found = 1;
}
fclose(crtf);
}
if (!cert_found) {
r = sc_select_file(p15card->card, &file, &info->path,
SC_SELECT_FILE_BY_PATH);
if (r)
return r;
data = malloc(file.size);
if (data == NULL)
return SC_ERROR_OUT_OF_MEMORY;
r = sc_read_binary(p15card->card, 0, data, file.size);
if (r < 0) {
free(data);
return r;
}
len = r;
/* FIXME: kludge! */
crtf = fopen(fname, "w");
if (crtf != NULL) {
fwrite(data, len, 1, crtf);
fclose(crtf);
}
}
cert = malloc(sizeof(struct sc_pkcs15_cert));
if (cert == NULL) {
free(data);
return SC_ERROR_OUT_OF_MEMORY;
}
memset(cert, 0, sizeof(struct sc_pkcs15_cert));
if (parse_cert(data, len, cert)) {
free(data);
free(cert);
return SC_ERROR_INVALID_ASN1_OBJECT;
}
cert->data = data;
cert->data_len = len;
*cert_out = cert;
return 0;
}
static int parse_x509_cert_info(struct sc_pkcs15_cert_info *cert,
const u8 * buf, int buflen)
{
const u8 *tag, *p;
int taglen, left;
tag = sc_asn1_skip_tag(&buf, &buflen, 0x30, &taglen); /* SEQUENCE */
if (tag == NULL)
return SC_ERROR_INVALID_ASN1_OBJECT;
sc_pkcs15_parse_common_object_attr(&cert->com_attr, tag, taglen);
p = sc_asn1_skip_tag(&buf, &buflen, 0x30, &left); /* SEQUENCE */
if (tag == NULL)
return SC_ERROR_INVALID_ASN1_OBJECT;
tag = sc_asn1_skip_tag(&p, &left, 0x04, &taglen); /* OCTET STRING */
if (tag == NULL)
return SC_ERROR_INVALID_ASN1_OBJECT;
memcpy(cert->id.value, tag, taglen);
cert->id.len = taglen;
tag = sc_asn1_find_tag(p, left, 0x01, &taglen); /* BOOLEAN */
if (tag != NULL && taglen > 0) {
if (tag[0])
cert->authority = 1;
else
cert->authority = 0;
} else
cert->authority = 0;
/* FIXME */
tag = sc_asn1_find_tag(buf, buflen, 0xA1, &taglen);
if (tag == NULL)
return SC_ERROR_INVALID_ASN1_OBJECT;
tag = sc_asn1_verify_tag(tag, taglen, 0x30, &taglen); /* SEQUENCE 1 */
if (tag == NULL)
return SC_ERROR_INVALID_ASN1_OBJECT;
tag = sc_asn1_verify_tag(tag, taglen, 0x30, &taglen); /* SEQUENCE 2 */
if (tag == NULL)
return SC_ERROR_INVALID_ASN1_OBJECT;
tag = sc_asn1_verify_tag(tag, taglen, 0x04, &taglen); /* OCTET STRING */
if (tag == NULL)
return SC_ERROR_INVALID_ASN1_OBJECT;
memcpy(cert->path.value, tag, taglen);
cert->path.len = taglen;
return 0;
}
void sc_pkcs15_print_cert_info(const struct sc_pkcs15_cert_info *cert)
{
int i;
printf("X.509 Certificate [%s]\n", cert->com_attr.label);
printf("\tFlags : %d\n", cert->com_attr.flags);
printf("\tTrustable: %s\n", cert->authority ? "yes" : "no");
printf("\tPath : ");
for (i = 0; i < cert->path.len; i++)
printf("%02X", cert->path.value[i]);
printf("\n");
printf("\tID : ");
sc_pkcs15_print_id(&cert->id);
printf("\n");
}
static int get_certs_from_file(struct sc_pkcs15_card *card,
struct sc_file *file)
{
int r, taglen, left;
u8 buf[MAX_BUFFER_SIZE];
const u8 *tag, *p;
int count = 0;
r = sc_select_file(card->card, file, &file->path,
SC_SELECT_FILE_BY_PATH);
if (r)
return r;
r = sc_read_binary(card->card, 0, buf, file->size);
if (r < 0)
return r;
left = r;
p = buf;
count = 0;
while (card->cert_count < SC_PKCS15_MAX_CERTS) {
tag = sc_asn1_skip_tag(&p, &left, 0x30, &taglen); /* SEQUENCE */
if (tag == NULL)
break;
if (parse_x509_cert_info
(&card->cert_info[card->cert_count], tag, taglen))
break;
card->cert_count++;
}
return 0;
}
int sc_pkcs15_enum_certificates(struct sc_pkcs15_card *card)
{
int r;
assert(card != NULL);
card->cert_count = 0;
r = get_certs_from_file(card, &card->file_cdf1);
if (r != 0)
return r;
if (card->file_cdf2.path.len) {
r = get_certs_from_file(card, &card->file_cdf2);
if (r != 0)
return r;
}
r = get_certs_from_file(card, &card->file_cdf3);
if (r != 0)
return r;
return card->cert_count;
}
void sc_pkcs15_free_certificate(struct sc_pkcs15_cert *cert)
{
assert(cert != NULL);
free(cert->data);
free(cert);
}

246
src/libopensc/pkcs15-pin.c Normal file
View File

@ -0,0 +1,246 @@
/* Copyright (C) 2001 Juha Yrjölä <juha.yrjola@iki.fi>
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
*/
#include "sc.h"
#include "sc-pkcs15.h"
#include <assert.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
static int decode_pin_info(const u8 *buf,
int buflen, struct sc_pkcs15_pin_info *pin)
{
const u8 *tag, *p = buf;
int taglen, left = buflen;
memset(pin, 0, sizeof(*pin));
tag = sc_asn1_skip_tag(&p, &left, 0x30, &taglen); /* SEQUENCE */
if (tag == NULL)
return SC_ERROR_REQUIRED_PARAMETER_NOT_FOUND;
sc_pkcs15_parse_common_object_attr(&pin->com_attr, tag, taglen);
tag = sc_asn1_skip_tag(&p, &left, 0x30, &taglen); /* SEQUENCE */
if (tag == NULL)
return SC_ERROR_REQUIRED_PARAMETER_NOT_FOUND;
tag = sc_asn1_verify_tag(tag, taglen, 0x04, &taglen); /* OCTET STRING */
if (tag == NULL || taglen == 0)
return SC_ERROR_REQUIRED_PARAMETER_NOT_FOUND;
if (taglen > SC_PKCS15_MAX_ID_SIZE)
taglen = SC_PKCS15_MAX_ID_SIZE;
memcpy(pin->auth_id.value, tag, taglen);
pin->auth_id.len = taglen;
p = sc_asn1_verify_tag(p, left, 0xA1, &left); /* CONS */
if (left == 0)
return SC_ERROR_REQUIRED_PARAMETER_NOT_FOUND;
p = sc_asn1_verify_tag(p, left, 0x30, &left);
if (left == 0)
return SC_ERROR_REQUIRED_PARAMETER_NOT_FOUND;
tag = sc_asn1_skip_tag(&p, &left, 0x03, &taglen);
if (taglen == 0)
return SC_ERROR_REQUIRED_PARAMETER_NOT_FOUND;
sc_asn1_decode_bit_string(tag, taglen, &pin->flags,
sizeof(pin->flags));
tag = sc_asn1_skip_tag(&p, &left, 0x0A, &taglen);
if (taglen == 0)
return SC_ERROR_REQUIRED_PARAMETER_NOT_FOUND;
pin->type = tag[0];
tag = sc_asn1_skip_tag(&p, &left, 0x02, &taglen);
if (taglen == 0)
return SC_ERROR_REQUIRED_PARAMETER_NOT_FOUND;
pin->min_length = tag[0];
tag = sc_asn1_skip_tag(&p, &left, 0x02, &taglen);
if (taglen == 0)
return SC_ERROR_REQUIRED_PARAMETER_NOT_FOUND;
pin->stored_length = tag[0];
tag = sc_asn1_find_tag(p, left, 0x04, &taglen);
if (taglen == 0)
return SC_ERROR_REQUIRED_PARAMETER_NOT_FOUND;
pin->pad_char = tag[0];
tag = sc_asn1_find_tag(p, left, 0x30, &taglen);
if (taglen != 0) {
tag = sc_asn1_find_tag(tag, taglen, 0x04, &taglen);
if (taglen >= 0) {
memcpy(pin->path.value, tag, taglen);
pin->path.len = taglen;
}
}
pin->magic = SC_PKCS15_PIN_MAGIC;
return 0;
}
void sc_pkcs15_print_pin_info(const struct sc_pkcs15_pin_info *pin)
{
char path[SC_MAX_PATH_SIZE * 2 + 1];
int i;
char *p;
p = path;
*p = 0;
for (i = 0; i < pin->path.len; i++) {
sprintf(p, "%02X", pin->path.value[i]);
p += 2;
}
printf("PIN number %d: %s, path %s, pad char 0x%02X\n",
pin->auth_id.value[0], pin->com_attr.label,
path, pin->pad_char);
}
int sc_pkcs15_enum_pins(struct sc_pkcs15_card *p15card)
{
int r, i;
u8 buf[MAX_BUFFER_SIZE];
const u8 *tag, *p;
int taglen, buflen;
assert(p15card != NULL);
r = sc_select_file(p15card->card, &p15card->file_aodf,
&p15card->file_aodf.path,
SC_SELECT_FILE_BY_PATH);
if (r)
return r;
r = sc_read_binary(p15card->card, 0, buf, p15card->file_aodf.size);
if (r < 0)
return r;
buflen = r;
p = buf;
i = 0;
p15card->pin_count = 0;
while ((tag = sc_asn1_skip_tag(&p, &buflen, 0x30, &taglen)) != NULL) {
r = decode_pin_info(tag, taglen,
&p15card->pin_info[p15card->
pin_count]);
if (r)
break;
p15card->pin_count++;
if (p15card->pin_count >= SC_PKCS15_MAX_PINS)
break;
}
return p15card->pin_count;
}
int sc_pkcs15_verify_pin(struct sc_pkcs15_card *p15card,
struct sc_pkcs15_pin_info *pin,
char *pincode, int pinlen)
{
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)
return SC_ERROR_OBJECT_NOT_VALID;
if (pinlen > pin->stored_length || pinlen < pin->min_length)
return SC_ERROR_INVALID_ARGUMENTS;
card = p15card->card;
r = sc_select_file(card, &file, &pin->path,
SC_SELECT_FILE_BY_PATH);
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);
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;
}
int sc_pkcs15_change_pin(struct sc_pkcs15_card *p15card,
struct sc_pkcs15_pin_info *pin,
char *oldpin,
int oldpinlen, char *newpin, int newpinlen)
{
int r;
struct sc_file file;
struct sc_apdu apdu;
struct sc_card *card;
char pinbuf[SC_MAX_PIN_SIZE * 2];
char resp[MAX_BUFFER_SIZE];
assert(p15card != NULL);
if (pin->magic != SC_PKCS15_PIN_MAGIC)
return SC_ERROR_OBJECT_NOT_VALID;
if ((oldpinlen > pin->stored_length)
|| (newpinlen > pin->stored_length))
return SC_ERROR_INVALID_ARGUMENTS;
if ((oldpinlen < pin->min_length) || (newpinlen < pin->min_length))
return SC_ERROR_INVALID_ARGUMENTS;
card = p15card->card;
r = sc_select_file(card, &file, &pin->path,
SC_SELECT_FILE_BY_PATH);
if (r)
return r;
sc_format_apdu(p15card->card, &apdu, SC_APDU_CASE_3_SHORT,
0x24, 0, pin->auth_id.value[0]);
apdu.lc = pin->stored_length * 2;
apdu.data = pinbuf;
apdu.datalen = pin->stored_length * 2;
apdu.resp = resp;
apdu.resplen = 2;
memset(pinbuf, pin->pad_char, pin->stored_length * 2);
memcpy(pinbuf, oldpin, oldpinlen);
memcpy(pinbuf + pin->stored_length, newpin, newpinlen);
r = sc_transmit_apdu(card, &apdu);
memset(pinbuf, 0, pin->stored_length * 2);
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;
}

View File

@ -0,0 +1,143 @@
/* Copyright (C) 2001 Juha Yrjölä <juha.yrjola@iki.fi>
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
*/
#include "sc.h"
#include "sc-pkcs15.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <assert.h>
void sc_pkcs15_print_prkey_info(const struct sc_pkcs15_prkey_info *prkey)
{
int i;
printf("Private RSA Key [%s]\n", prkey->com_attr.label);
printf("\tFlags : %X\n", prkey->com_attr.flags);
printf("\tUsage : %X\n", prkey->usage);
printf("\tAccessFlags : %X\n", prkey->access_flags);
printf("\tModLength : %d\n", prkey->modulus_length);
printf("\tKey ref : %d\n", prkey->key_reference);
printf("\tFile ID : ");
for (i = 0; i < prkey->file_id.len; i++)
printf("%02X", prkey->file_id.value[i]);
printf("\n");
printf("\tID : ");
sc_pkcs15_print_id(&prkey->id);
printf("\n");
}
static int parse_prkey_info(const u8 * buf,
int buflen, struct sc_pkcs15_prkey_info *prkey)
{
const u8 *tag, *p;
int taglen, left;
tag = sc_asn1_skip_tag(&buf, &buflen, 0x30, &taglen); /* SEQUENCE */
if (tag == NULL)
return SC_ERROR_REQUIRED_PARAMETER_NOT_FOUND;
sc_pkcs15_parse_common_object_attr(&prkey->com_attr, tag, taglen);
p = sc_asn1_skip_tag(&buf, &buflen, 0x30, &left); /* SEQUENCE */
if (tag == NULL)
return SC_ERROR_REQUIRED_PARAMETER_NOT_FOUND;
tag = sc_asn1_skip_tag(&p, &left, 0x04, &taglen); /* OCTET STRING */
if (tag == NULL)
return SC_ERROR_REQUIRED_PARAMETER_NOT_FOUND;
memcpy(prkey->id.value, tag, taglen);
prkey->id.len = taglen;
tag = sc_asn1_skip_tag(&p, &left, 0x03, &taglen); /* BIT STRING */
if (tag == NULL)
return SC_ERROR_REQUIRED_PARAMETER_NOT_FOUND;
sc_asn1_decode_bit_string(tag, taglen, &prkey->usage,
sizeof(prkey->usage));
tag = sc_asn1_skip_tag(&p, &left, 0x01, &taglen); /* BOOLEAN */
if (tag != NULL) {
/* FIXME */
}
tag = sc_asn1_skip_tag(&p, &left, 0x03, &taglen); /* BIT STRING */
if (tag != NULL) {
sc_asn1_decode_bit_string(tag, taglen,
&prkey->access_flags,
sizeof(prkey->access_flags));
} else
prkey->access_flags = 0;
tag = sc_asn1_skip_tag(&p, &left, 0x02, &taglen); /* INTEGER */
if (tag != NULL && taglen) {
prkey->key_reference = tag[0];
} else
prkey->key_reference = -1;
/* FIXME */
p = sc_asn1_find_tag(buf, buflen, 0xA1, &left);
if (p == NULL)
return SC_ERROR_REQUIRED_PARAMETER_NOT_FOUND;
p = sc_asn1_verify_tag(p, left, 0x30, &left); /* SEQUENCE 1 */
if (tag == NULL)
return SC_ERROR_REQUIRED_PARAMETER_NOT_FOUND;
tag = sc_asn1_skip_tag(&p, &left, 0x30, &taglen); /* SEQUENCE 2 */
if (tag == NULL)
return SC_ERROR_REQUIRED_PARAMETER_NOT_FOUND;
tag = sc_asn1_verify_tag(tag, taglen, 0x04, &taglen); /* OCTET STRING */
if (tag == NULL)
return SC_ERROR_REQUIRED_PARAMETER_NOT_FOUND;
memcpy(prkey->file_id.value, tag, taglen);
prkey->file_id.len = taglen;
tag = sc_asn1_skip_tag(&p, &left, 0x02, &taglen); /* INTEGER */
if (tag == NULL)
return SC_ERROR_REQUIRED_PARAMETER_NOT_FOUND;
sc_asn1_decode_integer(tag, taglen, &prkey->modulus_length);
return 0;
}
int sc_pkcs15_enum_private_keys(struct sc_pkcs15_card *card)
{
int r, left, taglen;
const u8 *p, *tag;
u8 buf[1024];
assert(card != NULL);
card->prkey_count = 0;
r = sc_select_file(card->card, &card->file_prkdf,
&card->file_prkdf.path, SC_SELECT_FILE_BY_PATH);
if (r)
return r;
r = sc_read_binary(card->card, 0, buf, card->file_prkdf.size);
if (r < 0)
return r;
left = r;
p = buf;
while ((tag = sc_asn1_skip_tag(&p, &left, 0x30, &taglen)) != NULL) {
struct sc_pkcs15_prkey_info *prkey =
&card->prkey_info[card->prkey_count];
if (parse_prkey_info(tag, taglen, prkey))
break;
card->prkey_count++;
}
return card->prkey_count;
}

111
src/libopensc/pkcs15-sec.c Normal file
View File

@ -0,0 +1,111 @@
/* Copyright (C) 2001 Juha Yrjölä <juha.yrjola@iki.fi>
* All rights reserved.
*/
#include "sc.h"
#include <assert.h>
#include <sys/mman.h>
#include <string.h>
#include <stdlib.h>
int sc_pkcs15_verify_pin(struct sc_pkcs15_card *p15card,
struct sc_pkcs15_pin_info *pin,
char *pincode, int pinlen)
{
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)
return SC_ERROR_OBJECT_NOT_VALID;
if (pinlen > pin->stored_length || pinlen < pin->min_length)
return SC_ERROR_INVALID_ARGUMENTS;
card = p15card->card;
r = sc_select_file(card, &file, &pin->path,
SC_SELECT_FILE_BY_PATH);
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);
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;
}
int sc_pkcs15_change_pin(struct sc_pkcs15_card *p15card,
struct sc_pkcs15_pin_info *pin,
char *oldpin,
int oldpinlen, char *newpin, int newpinlen)
{
int r;
struct sc_file file;
struct sc_apdu apdu;
struct sc_card *card;
char pinbuf[SC_MAX_PIN_SIZE * 2];
char resp[MAX_BUFFER_SIZE];
assert(p15card != NULL);
if (pin->magic != SC_PKCS15_PIN_MAGIC)
return SC_ERROR_OBJECT_NOT_VALID;
if ((oldpinlen > pin->stored_length)
|| (newpinlen > pin->stored_length))
return SC_ERROR_INVALID_ARGUMENTS;
if ((oldpinlen < pin->min_length) || (newpinlen < pin->min_length))
return SC_ERROR_INVALID_ARGUMENTS;
card = p15card->card;
r = sc_select_file(card, &file, &pin->path,
SC_SELECT_FILE_BY_PATH);
if (r)
return r;
sc_format_apdu(p15card->card, &apdu, SC_APDU_CASE_3_SHORT,
0x24, 0, pin->auth_id.value[0]);
apdu.lc = pin->stored_length * 2;
apdu.data = pinbuf;
apdu.datalen = pin->stored_length * 2;
apdu.resp = resp;
apdu.resplen = 2;
memset(pinbuf, pin->pad_char, pin->stored_length * 2);
memcpy(pinbuf, oldpin, oldpinlen);
memcpy(pinbuf + pin->stored_length, newpin, newpinlen);
r = sc_transmit_apdu(card, &apdu);
memset(pinbuf, 0, pin->stored_length * 2);
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;
}

354
src/libopensc/pkcs15.c Normal file
View File

@ -0,0 +1,354 @@
/* Copyright (C) 2001 Juha Yrjölä <juha.yrjola@iki.fi>
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
*/
#include "sc.h"
#include "sc-pkcs15.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <assert.h>
void sc_pkcs15_print_card(const struct sc_pkcs15_card *card)
{
const char *flags[] = {
"Read-only",
"Login required",
"PRN generation",
"EID compliant"
};
int i;
assert(card != NULL);
printf("PKCS#15 Card [%s]:\n", card->label);
printf("\tVersion : %d\n", card->version);
printf("\tSerial number : %s\n", card->serial_number);
printf("\tManufacturer ID: %s\n", card->manufacturer_id);
printf("\tFlags : ");
for (i = 0; i < 4; i++) {
int count = 0;
if ((card->flags >> i) & 1) {
if (count)
printf(", ");
printf("%s", flags[i]);
count++;
}
}
printf("\n");
}
static int extract_path(const u8 * buf, int buflen, struct sc_path *path)
{
const u8 *tag;
int taglen;
tag = sc_asn1_verify_tag(buf, buflen, 0x30, &taglen);
if (tag == NULL)
return -1;
tag = sc_asn1_verify_tag(tag, taglen, 0x04, &taglen); /* OCTET STRING */
if (tag == NULL)
return -1;
memcpy(path->value, tag, taglen);
path->len = taglen;
return 0;
}
void parse_tokeninfo(struct sc_pkcs15_card *card, const u8 * buf, int buflen)
{
const u8 *tag, *p = buf;
int i, taglen, left = buflen;
p = sc_asn1_verify_tag(buf, buflen, 0x30, &left); /* SEQUENCE */
if (p == NULL)
goto err;
tag = sc_asn1_skip_tag(&p, &left, 0x02, &taglen); /* INTEGER */
if (tag == NULL)
goto err;
card->version = tag[0] + 1;
tag = sc_asn1_skip_tag(&p, &left, 0x04, &taglen); /* OCTET STRING */
if (tag == NULL)
goto err;
card->serial_number = malloc(taglen * 2 + 1);
card->serial_number[0] = 0;
for (i = 0; i < taglen; i++) {
char byte[3];
sprintf(byte, "%02X", tag[i]);
strcat(card->serial_number, byte);
}
tag = sc_asn1_skip_tag(&p, &left, 0x0C, &taglen); /* UTF8 STRING */
if (tag == NULL)
goto err;
card->manufacturer_id = malloc(taglen + 1);
memcpy(card->manufacturer_id, tag, taglen);
card->manufacturer_id[taglen] = 0;
tag = sc_asn1_skip_tag(&p, &left, 0x80, &taglen); /* Label */
if (tag != NULL) { /* skip this tag */
}
tag = sc_asn1_skip_tag(&p, &left, 0x03, &taglen); /* BIT STRING */
if (tag == NULL)
goto err;
sc_asn1_decode_bit_string(tag, taglen, &card->flags,
sizeof(card->flags));
tag = sc_asn1_find_tag(p, left, 0xA2, &taglen); /* supportedAlgo */
if (tag == NULL)
goto err;
p = sc_asn1_skip_tag(&tag, &taglen, 0x30, &left); /* SEQUENCE */
if (p == NULL)
goto err;
tag = sc_asn1_skip_tag(&p, &left, 0x02, &taglen); /* INTEGER */
if (tag == NULL)
goto err;
card->alg_info[0].reference = tag[0];
tag = sc_asn1_skip_tag(&p, &left, 0x02, &taglen); /* INTEGER */
if (tag == NULL)
goto err;
card->alg_info[0].algorithm = tag[0];
tag = sc_asn1_find_tag(p, left, 0x03, &taglen); /* BIT STRING */ ;
if (tag == NULL)
goto err;
sc_asn1_decode_bit_string(tag, taglen,
&card->alg_info[0].supported_operations,
sizeof(card->alg_info[0].
supported_operations));
return;
err:
if (card->serial_number == NULL)
card->serial_number = strdup("(unknown)");
if (card->manufacturer_id == NULL)
card->manufacturer_id = strdup("(unknown)");
return;
}
static int parse_dir(const u8 * buf, int buflen, struct sc_pkcs15_card *card)
{
const u8 *tag;
int taglen;
const char *aid = "\xA0\x00\x00\x00\x63PKCS-15";
const int aidlen = 12;
buf = sc_asn1_verify_tag(buf, buflen, 0x61, &buflen);
if (buf == NULL)
return -1;
tag = sc_asn1_skip_tag(&buf, &buflen, 0x4F, &taglen);
if (taglen != aidlen || memcmp(aid, tag, aidlen) != 0)
return -1;
tag = sc_asn1_skip_tag(&buf, &buflen, 0x50, &taglen);
if (taglen > 0) {
card->label = malloc(taglen + 1);
if (card->label != NULL) {
memcpy(card->label, tag, taglen);
card->label[taglen] = 0;
}
} else
card->label = strdup("(unknown)");
tag = sc_asn1_skip_tag(&buf, &buflen, 0x51, &taglen);
if (tag == NULL)
return -1;
memcpy(card->file_app.path.value, tag, taglen);
card->file_app.path.len = taglen;
tag = sc_asn1_skip_tag(&buf, &buflen, 0x73, &taglen);
if (taglen > 2) {
/* FIXME: process DDO */
}
return 0;
}
static int parse_odf(const u8 * buf, int buflen, struct sc_pkcs15_card *card)
{
const u8 *tag;
int taglen;
/* authObjects */
if ((tag = sc_asn1_find_tag(buf, buflen, 0xA8, &taglen)) == NULL)
return -1;
if (extract_path(tag, taglen, &card->file_aodf.path))
return -1;
/* CDF #1 -- Card holder certificates */
if ((tag = sc_asn1_find_tag(buf, buflen, 0xA4, &taglen)) == NULL)
return -1;
if (extract_path(tag, taglen, &card->file_cdf1.path))
return -1;
/* CDF #2 -- New certificates */
tag += taglen;
taglen += 2;
if ((tag = sc_asn1_verify_tag(tag, taglen, 0xA4, &taglen)) == NULL)
return -1;
if (extract_path(tag, taglen, &card->file_cdf2.path))
return -1;
/* CDF #3 -- Trusted CA certificates */
if ((tag = sc_asn1_find_tag(buf, buflen, 0xA5, &taglen)) == NULL)
return -1;
if (extract_path(tag, taglen, &card->file_cdf3.path))
return -1;
/* PrKDF */
if ((tag = sc_asn1_find_tag(buf, buflen, 0xA0, &taglen)) == NULL)
return -1;
if (extract_path(tag, taglen, &card->file_prkdf.path))
return -1;
/* DODF */
if ((tag = sc_asn1_find_tag(buf, buflen, 0xA7, &taglen)) == NULL)
return -1;
if (extract_path(tag, taglen, &card->file_dodf.path))
return -1;
return 0;
};
int sc_pkcs15_init(struct sc_card *card,
struct sc_pkcs15_card **p15card_out)
{
unsigned char buf[MAX_BUFFER_SIZE];
int err, len;
struct sc_pkcs15_card *p15card = NULL;
struct sc_path tmppath;
assert(card != NULL && p15card_out != NULL);
p15card = malloc(sizeof(struct sc_pkcs15_card));
if (p15card == NULL)
return SC_ERROR_OUT_OF_MEMORY;
memset(p15card, 0, sizeof(struct sc_pkcs15_card));
p15card->card = card;
memcpy(tmppath.value, "\x2F\x00", 2);
tmppath.len = 2;
err =
sc_select_file(card, &p15card->file_dir, &tmppath,
SC_SELECT_FILE_BY_PATH);
if (err)
goto error;
err = sc_read_binary(card, 0, buf, p15card->file_dir.size);
if (err < 0)
goto error;
if (err <= 2) {
err = SC_ERROR_PKCS15_CARD_NOT_FOUND;
goto error;
}
len = err;
if (parse_dir(buf, len, p15card)) {
err = SC_ERROR_PKCS15_CARD_NOT_FOUND;
goto error;
}
memcpy(&tmppath, &p15card->file_app.path, sizeof(struct sc_path));
err =
sc_select_file(card, &p15card->file_app,
&p15card->file_app.path,
SC_SELECT_FILE_BY_PATH);
if (err)
goto error;
memcpy(tmppath.value + tmppath.len, "\x50\x31", 2);
tmppath.len += 2;
err =
sc_select_file(card, &p15card->file_odf, &tmppath,
SC_SELECT_FILE_BY_PATH);
if (err)
goto error;
err = sc_read_binary(card, 0, buf, p15card->file_odf.size);
if (err < 0)
goto error;
if (err < 2) {
err = SC_ERROR_PKCS15_CARD_NOT_FOUND;
goto error;
}
len = err;
if (parse_odf(buf, len, p15card)) {
err = SC_ERROR_PKCS15_CARD_NOT_FOUND;
goto error;
}
tmppath.len -= 2;
memcpy(tmppath.value + tmppath.len, "\x50\x32", 2);
tmppath.len += 2;
err =
sc_select_file(card, &p15card->file_tokeninfo, &tmppath,
SC_SELECT_FILE_BY_PATH);
if (err)
goto error;
err = sc_read_binary(card, 0, buf, p15card->file_tokeninfo.size);
if (err < 0)
goto error;
if (err <= 2) {
err = SC_ERROR_PKCS15_CARD_NOT_FOUND;
goto error;
}
parse_tokeninfo(p15card, buf, err);
*p15card_out = p15card;
return 0;
error:
free(p15card);
return err;
}
int sc_pkcs15_destroy(struct sc_pkcs15_card *p15card)
{
free(p15card->label);
free(p15card);
return 0;
}
int sc_pkcs15_parse_common_object_attr(struct sc_pkcs15_common_obj_attr *attr,
const u8 * buf, int buflen)
{
int taglen;
const u8 *tag;
tag = sc_asn1_find_tag(buf, buflen, 0x0C, &taglen); /* UTF8STRING */
if (tag != NULL && taglen < SC_PKCS15_MAX_LABEL_SIZE) {
memcpy(attr->label, tag, taglen);
attr->label[taglen] = 0;
} else
attr->label[0] = 0;
tag = sc_asn1_find_tag(buf, buflen, 0x03, &taglen); /* BIT STRING */
if (tag != NULL) {
if (sc_asn1_decode_bit_string(buf, buflen, &attr->flags,
sizeof(attr->flags)) < 0)
attr->flags = 0;
} else
attr->flags = 0;
tag = sc_asn1_find_tag(buf, buflen, 0x04, &taglen); /* OCTET STRING */
if (tag != NULL) {
memcpy(attr->auth_id.value, tag, taglen);
attr->auth_id.len = taglen;
} else
attr->auth_id.len = 0;
/* FIXME: parse rest */
attr->auth_id.len = 0;
attr->user_consent = 0;
return 0;
}
int sc_pkcs15_compare_id(const struct sc_pkcs15_id *id1,
const struct sc_pkcs15_id *id2)
{
assert(id1 != NULL && id2 != NULL);
if (id1->len != id2->len)
return 0;
return memcmp(id1->value, id2->value, id1->len) == 0;
}
void sc_pkcs15_print_id(const struct sc_pkcs15_id *id)
{
int i;
for (i = 0; i < id->len; i++)
printf("%02X", id->value[i]);
}

187
src/libopensc/pkcs15.h Normal file
View File

@ -0,0 +1,187 @@
/* Copyright (C) 2001 Juha Yrjölä <juha.yrjola@iki.fi>
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
*/
#ifndef _SC_PKCS15_H
#define _SC_PKCS15_H
#include "sc.h"
#define SC_PKCS15_PIN_MAGIC 0x31415926
#define SC_PKCS15_MAX_PINS 2
#define SC_PKCS15_MAX_CERTS 3
#define SC_PKCS15_MAX_PRKEYS 2
#define SC_PKCS15_MAX_LABEL_SIZE 32
#define SC_PKCS15_MAX_ID_SIZE 16
struct sc_pkcs15_id {
u8 value[SC_PKCS15_MAX_ID_SIZE];
int len;
};
struct sc_pkcs15_common_obj_attr {
char label[SC_PKCS15_MAX_LABEL_SIZE]; /* zero terminated */
int flags;
struct sc_pkcs15_id auth_id;
int user_consent;
/* FIXME: add accessControlRules */
};
struct sc_pkcs15_pin_info {
struct sc_pkcs15_common_obj_attr com_attr;
struct sc_pkcs15_id auth_id;
int flags, type;
int min_length, stored_length;
u8 pad_char;
struct sc_path path;
int tries_left;
unsigned int magic;
};
#define SC_PKCS15_ALGO_OP_COMPUTE_CHECKSUM 0x01
#define SC_PKCS15_ALGO_OP_COMPUTE_SIGNATURE 0x02
#define SC_PKCS15_ALGO_OP_VERIFY_CHECKSUM 0x04
#define SC_PKCS15_ALGO_OP_VERIFY_SIGNATURE 0x08
#define SC_PKCS15_ALGO_OP_ENCIPHER 0x10
#define SC_PKCS15_ALGO_OP_DECIPHER 0x20
#define SC_PKCS15_ALGO_OP_HASH 0x40
#define SC_PKCS15_ALGO_OP_GENERATE_KEY 0x80
struct sc_pkcs15_algorithm_info {
int reference;
int algorithm, supported_operations;
};
struct sc_pkcs15_rsa_pubkey {
u8 *modulus;
int modulus_len;
unsigned int exponent;
};
struct sc_pkcs15_cert {
int version;
unsigned long long serial;
struct sc_pkcs15_rsa_pubkey key;
u8 *data; /* DER encoded raw cert */
int data_len;
};
struct sc_pkcs15_cert_info {
struct sc_pkcs15_common_obj_attr com_attr;
struct sc_pkcs15_id id; /* correlates to private RSA key id */
int authority; /* boolean */
/* identifiers [2] SEQUENCE OF CredentialIdentifier{{KeyIdentifiers}} */
struct sc_path path;
};
#define SC_PCKS15_PRKEY_USAGE_ENCRYPT 0x01
#define SC_PCKS15_PRKEY_USAGE_DECRYPT 0x02
#define SC_PCKS15_PRKEY_USAGE_SIGN 0x04
#define SC_PCKS15_PRKEY_USAGE_SIGNRECOVER 0x08
#define SC_PCKS15_PRKEY_USAGE_WRAP 0x10
#define SC_PCKS15_PRKEY_USAGE_UNWRAP 0x20
#define SC_PCKS15_PRKEY_USAGE_VERIFY 0x40
#define SC_PCKS15_PRKEY_USAGE_VERIFYRECOVER 0x80
#define SC_PCKS15_PRKEY_USAGE_DERIVE 0x100
#define SC_PCKS15_PRKEY_USAGE_NONREPUDIATION 0x200
#define SC_PKCS15_PRKEY_ACCESS_SENSITIVE 0x01
#define SC_PKCS15_PRKEY_ACCESS_EXTRACTABLE 0x02
#define SC_PKCS15_PRKEY_ACCESS_ALWAYSSENSITIVE 0x04
#define SC_PKCS15_PRKEY_ACCESS_NEVEREXTRACTABLE 0x08
#define SC_PKCS15_PRKEY_ACCESS_LOCAL 0x10
struct sc_pkcs15_prkey_info {
struct sc_pkcs15_common_obj_attr com_attr;
struct sc_pkcs15_id id; /* correlates to public certificate id */
int usage, access_flags;
int key_reference;
struct sc_path file_id;
int modulus_length;
};
struct sc_pkcs15_card {
struct sc_card *card;
char *label;
struct sc_file file_dir, file_ao1, file_app;
/* in app DF */
struct sc_file file_tokeninfo, file_odf;
struct sc_file file_prkdf;
struct sc_file file_aodf, file_ao2;
struct sc_file file_cdf1, file_cdf2, file_cdf3;
struct sc_file file_dodf;
/* fields from TokenInfo: */
int version;
char *serial_number, *manufacturer_id;
int flags;
struct sc_pkcs15_algorithm_info alg_info[1];
struct sc_pkcs15_cert_info cert_info[SC_PKCS15_MAX_CERTS];
int cert_count;
struct sc_pkcs15_prkey_info prkey_info[SC_PKCS15_MAX_PRKEYS];
int prkey_count;
struct sc_pkcs15_pin_info pin_info[SC_PKCS15_MAX_PINS];
int pin_count;
};
#define SC_PKCS15_CARD_FLAG_READONLY 0x01
#define SC_PKCS15_CARD_FLAG_LOGIN_REQUIRED 0x02
#define SC_PKCS15_CARD_FLAG_PRN_GENERATION 0x04
#define SC_PKCS15_CARD_FLAG_EID_COMPLIANT 0x08
int sc_pkcs15_init(struct sc_card *card,
struct sc_pkcs15_card **pkcs15_card);
int sc_pkcs15_destroy(struct sc_pkcs15_card *card);
void sc_pkcs15_print_card(const struct sc_pkcs15_card *card);
void sc_pkcs15_print_cert_info(const struct sc_pkcs15_cert_info *cert);
int sc_pkcs15_enum_certificates(struct sc_pkcs15_card *card);
int sc_pkcs15_read_certificate(struct sc_pkcs15_card *card,
const struct sc_pkcs15_cert_info *info,
struct sc_pkcs15_cert **cert);
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);
void sc_pkcs15_print_pin_info(const struct sc_pkcs15_pin_info *pin);
int sc_pkcs15_enum_pins(struct sc_pkcs15_card *card);
int sc_pkcs15_verify_pin(struct sc_pkcs15_card *card,
struct sc_pkcs15_pin_info *pin,
char *pincode, int pinlen);
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_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_parse_common_object_attr(struct sc_pkcs15_common_obj_attr *attr,
const u8 * buf, int buflen);
#endif

48
src/libopensc/sc-asn1.h Normal file
View File

@ -0,0 +1,48 @@
/* Copyright (C) 2001 Juha Yrjölä <juha.yrjola@iki.fi>
* All rights reserved.
*/
#ifndef _SC_ASN1_H
#define _SC_ASN1_H
#define ASN1_TAG_CLASS 0xC0
#define ASN1_TAG_UNIVERSAL 0x00
#define ASN1_TAG_APPLICATION 0x40
#define ASN1_TAG_CONTEXT 0x80
#define ASN1_TAG_PRIVATE 0xC0
#define ASN1_TAG_CONSTRUCTED 0x20
#define ASN1_TAG_PRIMITIVE 0x1F
#define ASN1_EOC 0
#define ASN1_BOOLEAN 1 /**/
#define ASN1_INTEGER 2
#define ASN1_NEG_INTEGER (2 | ASN1_NEG)
#define ASN1_BIT_STRING 3
#define ASN1_OCTET_STRING 4
#define ASN1_NULL 5
#define ASN1_OBJECT 6
#define ASN1_OBJECT_DESCRIPTOR 7
#define ASN1_EXTERNAL 8
#define ASN1_REAL 9
#define ASN1_ENUMERATED 10
#define ASN1_NEG_ENUMERATED (10 | ASN1_NEG)
#define ASN1_UTF8STRING 12
#define ASN1_SEQUENCE 16
#define ASN1_SET 17
#define ASN1_NUMERICSTRING 18 /**/
#define ASN1_PRINTABLESTRING 19
#define ASN1_T61STRING 20
#define ASN1_TELETEXSTRING 20 /* alias */
#define ASN1_VIDEOTEXSTRING 21 /**/
#define ASN1_IA5STRING 22
#define ASN1_UTCTIME 23
#define ASN1_GENERALIZEDTIME 24 /**/
#define ASN1_GRAPHICSTRING 25 /**/
#define ASN1_ISO64STRING 26 /**/
#define ASN1_VISIBLESTRING 26 /* alias */
#define ASN1_GENERALSTRING 27 /**/
#define ASN1_UNIVERSALSTRING 28 /**/
#define ASN1_BMPSTRING 30
#endif

804
src/libopensc/sc.c Normal file
View File

@ -0,0 +1,804 @@
/* Copyright (C) 2001 Juha Yrjölä <juha.yrjola@iki.fi>
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
*/
#include "sc.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <ctype.h>
int sc_debug = 0;
static int convert_sw_to_errorcode(u8 * sw)
{
switch (sw[0]) {
case 0x69:
switch (sw[1]) {
case 0x82:
return SC_ERROR_SECURITY_STATUS_NOT_SATISFIED;
}
case 0x6A:
switch (sw[1]) {
case 0x81:
return SC_ERROR_NOT_SUPPORTED;
case 0x82:
case 0x83:
return SC_ERROR_FILE_NOT_FOUND;
case 0x86:
case 0x87:
return SC_ERROR_INVALID_ARGUMENTS;
}
}
return SC_ERROR_UNKNOWN;
}
static void sc_hex_dump(const unsigned char *buf, int count)
{
int i;
for (i = 0; i < count; i++) {
unsigned char c = buf[i];
int printch = 0;
if (!isalnum(c) && !ispunct(c) && !isspace(c))
printch = 0;
if (printch)
printf("%02X%c ", c, c);
else
printf("%02X ", c);
}
printf("\n");
fflush(stdout);
}
int sc_check_apdu(const struct sc_apdu *apdu)
{
switch (apdu->cse) {
case SC_APDU_CASE_1:
if (apdu->datalen)
return SC_ERROR_INVALID_ARGUMENTS;
break;
case SC_APDU_CASE_2_SHORT:
if (apdu->datalen)
return SC_ERROR_INVALID_ARGUMENTS;
if (apdu->resplen < apdu->le)
return SC_ERROR_INVALID_ARGUMENTS;
break;
case SC_APDU_CASE_3_SHORT:
if (apdu->datalen == 0 || apdu->data == NULL)
return SC_ERROR_INVALID_ARGUMENTS;
break;
case SC_APDU_CASE_4_SHORT:
if (apdu->datalen == 0 || apdu->data == NULL)
return SC_ERROR_INVALID_ARGUMENTS;
if (apdu->resplen < apdu->le)
return SC_ERROR_INVALID_ARGUMENTS;
break;
case SC_APDU_CASE_2_EXT:
case SC_APDU_CASE_3_EXT:
case SC_APDU_CASE_4_EXT:
return SC_ERROR_NOT_SUPPORTED;
}
return 0;
}
static int sc_transceive_t0(struct sc_card *card, struct sc_apdu *apdu)
{
SCARD_IO_REQUEST sSendPci, sRecvPci;
BYTE s[MAX_BUFFER_SIZE], r[MAX_BUFFER_SIZE];
DWORD dwSendLength, dwRecvLength;
LONG rv;
u8 *data = s;
int data_bytes = apdu->lc;
if (data_bytes == 0)
data_bytes = 256;
*data++ = apdu->cla;
*data++ = apdu->ins;
*data++ = apdu->p1;
*data++ = apdu->p2;
switch (apdu->cse) {
case SC_APDU_CASE_1:
break;
case SC_APDU_CASE_2_SHORT:
*data++ = apdu->le;
break;
case SC_APDU_CASE_2_EXT:
*data++ = 0;
*data++ = apdu->le >> 8;
*data++ = apdu->le & 0xFF;
break;
case SC_APDU_CASE_3_SHORT:
*data++ = apdu->lc;
if (apdu->datalen != data_bytes)
return SC_ERROR_INVALID_ARGUMENTS;
memcpy(data, apdu->data, data_bytes);
data += data_bytes;
break;
case SC_APDU_CASE_4_SHORT:
*data++ = apdu->lc;
if (apdu->datalen != data_bytes)
return SC_ERROR_INVALID_ARGUMENTS;
memcpy(data, apdu->data, data_bytes);
data += data_bytes;
*data++ = apdu->le;
break;
}
sSendPci.dwProtocol = SCARD_PROTOCOL_T0;
sSendPci.cbPciLength = 0;
sRecvPci.dwProtocol = SCARD_PROTOCOL_T0;
sRecvPci.cbPciLength = 0;
dwSendLength = data - s;
dwRecvLength = apdu->resplen;
if (sc_debug) {
printf("Sending: ");
sc_hex_dump(s, dwSendLength);
}
rv = SCardTransmit(card->pcsc_card, &sSendPci, s, dwSendLength,
&sRecvPci, r, &dwRecvLength);
if (rv != SCARD_S_SUCCESS) {
fprintf(stderr, "SCardTransmit failed with 0x%08x\n",
(int) rv);
return SC_ERROR_TRANSMIT_FAILED;
}
apdu->resplen = dwRecvLength;
memcpy(apdu->resp, r, dwRecvLength);
return 0;
}
int sc_transmit_apdu(struct sc_card *card, struct sc_apdu *apdu)
{
int r;
r = sc_check_apdu(apdu);
if (r)
return r;
r = sc_transceive_t0(card, apdu);
if (r)
return r;
if (sc_debug) {
printf("Received: ");
sc_hex_dump(apdu->resp, apdu->resplen);
}
if (apdu->resp[0] == 0x61 && apdu->resplen == 2) {
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];
rspapdu.resp = rsp;
rspapdu.resplen = apdu->resp[1] + 2;
if (sc_debug)
printf("Sending response request with %d bytes\n", rspapdu.resplen);
r = sc_transceive_t0(card, &rspapdu);
if (r) {
fprintf(stderr, "Error %d when getting response\n",
r);
return r;
}
if (sc_debug) {
printf("Response: ");
sc_hex_dump(rspapdu.resp, rspapdu.resplen);
}
memcpy(apdu->resp, rspapdu.resp, rspapdu.resplen);
apdu->resplen = rspapdu.resplen;
}
return 0;
}
static void sc_process_fci(struct sc_file *file,
const u8 *buf, int buflen)
{
int taglen, len = buflen;
const u8 *tag, *p = buf;
if (tag != NULL && taglen == 2) {
file->id = (tag[0] << 8) | tag[1];
if (sc_debug)
printf("File identifier: 0x%02X%02X\n", tag[0],
tag[1]);
}
tag = sc_asn1_find_tag(p, len, 0x81, &taglen);
if (tag != NULL && taglen >= 2) {
int bytes = (tag[0] << 8) + tag[1];
if (sc_debug)
printf("Bytes in file: %d\n", bytes);
file->size = bytes;
}
tag = sc_asn1_find_tag(p, len, 0x83, &taglen);
tag = sc_asn1_find_tag(p, len, 0x82, &taglen);
if (tag != NULL) {
if (taglen > 0) {
unsigned char byte = tag[0];
const char *type;
if (sc_debug)
printf("\tShareable: %s\n",
(byte & 0x40) ? "yes" : "no");
switch ((byte >> 3) & 7) {
case 0:
type = "working EF";
break;
case 1:
type = "internal EF";
break;
case 7:
type = "DF";
break;
default:
type = "unknown";
break;
}
file->type = (byte >> 3) & 7;
if (sc_debug) {
printf("\tType: %s\n", type);
printf("\tEF structure: %d\n",
byte & 0x07);
}
}
}
tag = sc_asn1_find_tag(p, len, 0x84, &taglen);
if (tag != NULL && taglen > 0 && taglen <= 16) {
char name[17];
int i;
memcpy(file->name, tag, taglen);
file->namelen = taglen;
for (i = 0; i < taglen; i++) {
if (isalnum(tag[i]) || ispunct(tag[i])
|| isspace(tag[i]))
name[i] = tag[i];
else
name[i] = '?';
}
name[taglen] = 0;
if (sc_debug)
printf("\tFile name: %s\n", name);
}
file->magic = SC_FILE_MAGIC;
}
int sc_select_file(struct sc_card *card,
struct sc_file *file,
const struct sc_path *in_path, int pathtype)
{
struct sc_context *ctx;
struct sc_apdu apdu;
char buf[MAX_BUFFER_SIZE], cmd[15];
u8 pathbuf[SC_MAX_PATH_SIZE], *path = pathbuf;
int r, pathlen;
assert(card != NULL && in_path != NULL);
ctx = card->context;
if (in_path->len > SC_MAX_PATH_SIZE)
return SC_ERROR_INVALID_ARGUMENTS;
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;
apdu.resp = buf;
apdu.resplen = 2;
memcpy(cmd, "\x00\xA4", 2);
switch (pathtype) {
case SC_SELECT_FILE_BY_FILE_ID:
apdu.p1 = 0;
break;
case SC_SELECT_FILE_BY_DF_NAME:
apdu.p1 = 4;
break;
case SC_SELECT_FILE_BY_PATH:
apdu.p1 = 8;
if (pathlen >= 2 && memcmp(path, "\x3F\x00", 2) == 0) {
if (pathlen == 2) { /* only 3F00 supplied */
apdu.p1 = 0;
break;
}
path += 2;
pathlen -= 2;
}
break;
default:
return SC_ERROR_INVALID_ARGUMENTS;
}
apdu.p2 = 0; /* record */
apdu.lc = pathlen;
apdu.data = path;
apdu.datalen = pathlen;
r = sc_transmit_apdu(card, &apdu);
if (r)
return r;
if (apdu.resplen < 2)
return SC_ERROR_UNKNOWN_RESPONSE;
switch (apdu.resp[0]) {
case 0x6A:
switch (apdu.resp[1]) {
case 0x82:
return SC_ERROR_FILE_NOT_FOUND;
default:
return SC_ERROR_UNKNOWN_RESPONSE;
}
case 0x6F:
break;
case 0x90:
return 0;
default:
fprintf(stderr,
"SELECT FILE returned SW1=%02X, SW2=%02X.\n",
apdu.resp[0], apdu.resp[1]);
return SC_ERROR_UNKNOWN_RESPONSE;
}
if (file == NULL)
return 0;
memset(file, 0, sizeof(*file));
if (pathtype == SC_SELECT_FILE_BY_PATH) {
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;
sc_process_fci(file, apdu.resp + 2, len);
}
return 0;
}
int sc_read_binary(struct sc_card *card,
int idx, unsigned char *buf, int count)
{
#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 > RB_BUF_SIZE) {
int bytes_read = 0;
unsigned char *p = buf;
while (count > 0) {
int n = count > RB_BUF_SIZE ? RB_BUF_SIZE : count;
r = sc_read_binary(card, idx, p, n);
if (r < 0)
return r;
p += r;
idx += r;
bytes_read += r;
count -= r;
if (r == 0)
return bytes_read;
}
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;
apdu.le = count;
apdu.resplen = count + 2;
apdu.resp = recvbuf;
r = sc_transmit_apdu(card, &apdu);
if (r)
return r;
if (apdu.resplen == 2) {
}
if (apdu.resplen == count + 2)
apdu.resplen = count;
memcpy(buf, recvbuf, apdu.resplen);
if (sc_debug == 2) {
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)
{
assert(card != NULL && apdu != NULL);
memset(apdu, 0, sizeof(*apdu));
apdu->cla = card->class;
apdu->cse = cse;
apdu->ins = ins;
apdu->p1 = p1;
apdu->p2 = p2;
return 0;
}
int sc_detect_card(struct sc_context *ctx, int reader)
{
LONG ret;
SCARD_READERSTATE_A rgReaderStates[SC_MAX_READERS];
assert(ctx != NULL);
if (reader >= ctx->reader_count || reader < 0)
return SC_ERROR_INVALID_ARGUMENTS;
rgReaderStates[0].szReader = ctx->readers[reader];
rgReaderStates[0].dwCurrentState = SCARD_STATE_EMPTY;
ret = SCardGetStatusChange(ctx->pcsc_ctx, 0, rgReaderStates, 1);
if (ret != 0)
return -1; /* FIXME */
if (rgReaderStates[0].dwEventState & SCARD_STATE_CHANGED)
return 1;
return 0;
}
int sc_wait_for_card(struct sc_context *ctx, int reader, int timeout)
{
LONG ret;
SCARD_READERSTATE_A rgReaderStates[SC_MAX_READERS];
int count = 0, i;
assert(ctx != NULL);
if (reader >= ctx->reader_count)
return SC_ERROR_INVALID_ARGUMENTS;
if (reader < 0) {
if (ctx->reader_count == 0)
return SC_ERROR_NO_READERS_FOUND;
for (i = 0; i < ctx->reader_count; i++) {
rgReaderStates[i].szReader = ctx->readers[i];
rgReaderStates[i].dwCurrentState =
SCARD_STATE_EMPTY;
}
count = ctx->reader_count;
} else {
rgReaderStates[0].szReader = ctx->readers[reader];
rgReaderStates[0].dwCurrentState = SCARD_STATE_EMPTY;
count = 1;
}
ret = SCardGetStatusChange(ctx->pcsc_ctx, timeout, rgReaderStates,
count);
if (ret != 0)
return -1; /* FIXME */
for (i = 0; i < count; i++) {
if (rgReaderStates[i].dwEventState & SCARD_STATE_CHANGED)
return 1;
}
return 0;
}
int sc_establish_context(struct sc_context **ctx_out)
{
struct sc_context *ctx;
LONG rv;
DWORD reader_buf_size;
char *reader_buf, *p;
LPCSTR mszGroups;
int i, reader_count;
assert(ctx_out != NULL);
ctx = malloc(sizeof(struct sc_context));
if (ctx == NULL)
return SC_ERROR_OUT_OF_MEMORY;
rv = SCardEstablishContext(SCARD_SCOPE_GLOBAL, "localhost", NULL,
&ctx->pcsc_ctx);
if (rv != SCARD_S_SUCCESS) {
fprintf(stderr,
"ERROR: Cannot connect to Resource Manager\n");
return SC_ERROR_CONNECTING_TO_RES_MGR;
}
SCardListReaders(ctx->pcsc_ctx, NULL, NULL,
(LPDWORD) & reader_buf_size);
if (reader_buf_size == 0) {
fprintf(stderr, "No readers found!\n");
free(ctx);
return SC_ERROR_NO_READERS_FOUND;
}
reader_buf = (char *) malloc(sizeof(char) * reader_buf_size);
SCardListReaders(ctx->pcsc_ctx, mszGroups, reader_buf,
(LPDWORD) & reader_buf_size);
p = reader_buf;
ctx->reader_count = 0;
do {
ctx->readers[ctx->reader_count] = strdup(p);
ctx->reader_count++;
while (*p++ != 0);
if (reader_count == SC_MAX_READERS)
break;
} while (p < (reader_buf + reader_buf_size - 1));
free(reader_buf);
for (i = 0; i < ctx->reader_count; i++)
printf("Found reader #%d - %s\n", i + 1, ctx->readers[i]);
*ctx_out = ctx;
return 0;
}
int sc_destroy_context(struct sc_context *ctx)
{
int i;
assert(ctx != NULL);
for (i = 0; i < ctx->reader_count; i++)
free(ctx->readers[i]);
free(ctx);
return 0;
}
int sc_connect_card(struct sc_context *ctx,
int reader, struct sc_card **card_out)
{
struct sc_card *card;
DWORD active_proto;
SCARDHANDLE card_handle;
LONG rv;
assert(card_out != NULL);
if (reader >= ctx->reader_count || reader < 0)
return SC_ERROR_INVALID_ARGUMENTS;
card = malloc(sizeof(struct sc_card));
if (card == NULL)
return SC_ERROR_OUT_OF_MEMORY;
memset(card, 0, sizeof(struct sc_card));
rv = SCardConnect(ctx->pcsc_ctx, ctx->readers[reader],
SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0,
&card_handle, &active_proto);
if (rv != 0) {
free(card);
return -1; /* FIXME */
}
card->pcsc_card = card_handle;
*card_out = card;
card->class = 0; /* FIXME */
return 0;
}
int sc_disconnect_card(struct sc_card *card)
{
assert(card != NULL);
SCardDisconnect(card->pcsc_card, SCARD_UNPOWER_CARD);
return 0;
}
const char *sc_strerror(int error)
{
const char *errors[] = {
"Unknown error",
"Command too short",
"Command too long",
"Not supported",
"Transmit failed",
"File not found",
"Invalid arguments",
"PKCS#15 compatible SmartCard not found",
"Required parameter not found on SmartCard",
"Out of memory",
"No readers found",
"Object not valid",
"Unknown response",
"PIN code incorrect",
"Security status not satisfied",
"Error connecting to Resource Manager",
};
int nr_errors = sizeof(errors) / sizeof(errors[0]);
error -= SC_ERROR_MIN;
if (error < 0)
error = -error;
if (error >= nr_errors)
return errors[0];
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) {
fprintf(stderr, "Set sec env: SWs=%02X%02X\n",
apdu.resp[0], apdu.resp[1]);
return -1;
}
return 0;
}
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;
}
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;
}
fprintf(stderr, "sc_compute_signature(): SW1=%02X, SW2=%02X\n",
p[0], p[1]);
return convert_sw_to_errorcode(p);
}
int sc_lock(struct sc_card *card)
{
long rv;
rv = SCardBeginTransaction(card->pcsc_card);
if (rv != SCARD_S_SUCCESS)
return -1;
return 0;
}
int sc_unlock(struct sc_card *card)
{
long rv;
rv = SCardEndTransaction(card->pcsc_card, SCARD_LEAVE_CARD);
if (rv != SCARD_S_SUCCESS)
return -1;
return 0;
}
int sc_get_random(struct sc_card *card, u8 *rnd, int len)
{
int r;
struct sc_apdu apdu;
u8 buf[8];
sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT,
0x84, 0x00, 0x00);
apdu.le = 8;
apdu.resp = buf;
apdu.resplen = 8;
while (len > 0) {
int n = len > 8 ? 8 : len;
r = sc_transmit_apdu(card, &apdu);
if (r)
return r;
if (apdu.resplen != 8) {
if (apdu.resplen == 2)
return convert_sw_to_errorcode(apdu.resp);
return SC_ERROR_UNKNOWN;
}
memcpy(rnd, apdu.resp, n);
len -= n;
rnd += n;
}
return 0;
}

40
src/libopensc/sec.c Normal file
View File

@ -0,0 +1,40 @@
/* Copyright (C) 2001 Juha Yrjölä <juha.yrjola@iki.fi>
* All rights reserved.
*/
#include "sc.h"
#include "sc-pkcs15.h"
#include <unistd.h>
#include <stdio.h>
#include <ctype.h>
int sc_sec_ask_pin_code(struct sc_pkcs15_pin_info *pin,
char *out, int outlen, const char *prompt)
{
char buf[80];
int i;
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;
}
return 0;
}

View File

@ -23,7 +23,7 @@
#include <winscard.h>
#include "sc-pkcs11.h"
#include "../sc.h"
#include <sc.h>
struct sc_context *ctx = NULL;
struct pkcs11_slot slot[PKCS11_MAX_SLOTS];

View File

@ -22,8 +22,8 @@
#include <winscard.h>
#include "pkcs11/pkcs11.h"
#include "../sc.h"
#include "../sc-pkcs15.h"
#include <sc.h>
#include <sc-pkcs15.h>
#define PKCS11_MAX_SLOTS 4
#define PKCS11_MAX_SESSIONS 8

29
src/signer/Makefile Normal file
View File

@ -0,0 +1,29 @@
PLUGIN_DEFINES=-DXP_UNIX -I/usr/include/mozilla -I/usr/include/mozilla/java
CC= gcc
OPTIMIZER= -g
CFLAGS=-Wall $(OPTIMIZER) $(PLUGIN_DEFINES)
SRC= UnixShell.c stubs.c
OBJ= UnixShell.o stubs.o
SHAREDTARGET=signer.so
default all: $(SHAREDTARGET)
$(SHAREDTARGET): $(OBJ)
$(CC) -shared -o $(SHAREDTARGET) $(OBJ) $(LDFLAGS)
UnixShell.o: UnixShell.c
$(CC) -c $(CFLAGS) UnixShell.c
stubs.o: stubs.c
$(CC) -c $(CFLAGS) stubs.c
clean:
$(RM) $(OBJ) $(SHAREDTARGET)
test:
.do cp $(SHAREDTARGET) /usr/lib/mozilla/plugins
.do cp $(SHAREDTARGET) /usr/lib/netscape/plugins-libc6

406
src/signer/npunix.c Normal file
View File

@ -0,0 +1,406 @@
/*
* npunix.c
*
* Netscape Client Plugin API
* - Wrapper function to interface with the Netscape Navigator
*
* dp Suresh <dp@netscape.com>
*
*----------------------------------------------------------------------
* PLUGIN DEVELOPERS:
* YOU WILL NOT NEED TO EDIT THIS FILE.
*----------------------------------------------------------------------
*/
#define XP_UNIX 1
#include <stdio.h>
#include "npapi.h"
#include "npupp.h"
/*
* Define PLUGIN_TRACE to have the wrapper functions print
* messages to stderr whenever they are called.
*/
#ifdef PLUGIN_TRACE
#include <stdio.h>
#define PLUGINDEBUGSTR(msg) fprintf(stderr, "%s\n", msg)
#else
#define PLUGINDEBUGSTR(msg)
#endif
/***********************************************************************
*
* Globals
*
***********************************************************************/
static NPNetscapeFuncs gNetscapeFuncs; /* Netscape Function table */
/***********************************************************************
*
* Wrapper functions : plugin calling Netscape Navigator
*
* These functions let the plugin developer just call the APIs
* as documented and defined in npapi.h, without needing to know
* about the function table and call macros in npupp.h.
*
***********************************************************************/
void
NPN_Version(int* plugin_major, int* plugin_minor,
int* netscape_major, int* netscape_minor)
{
*plugin_major = NP_VERSION_MAJOR;
*plugin_minor = NP_VERSION_MINOR;
/* Major version is in high byte */
*netscape_major = gNetscapeFuncs.version >> 8;
/* Minor version is in low byte */
*netscape_minor = gNetscapeFuncs.version & 0xFF;
}
NPError
NPN_GetValue(NPP instance, NPNVariable variable, void *r_value)
{
return CallNPN_GetValueProc(gNetscapeFuncs.getvalue,
instance, variable, r_value);
}
NPError
NPN_GetURL(NPP instance, const char* url, const char* window)
{
return CallNPN_GetURLProc(gNetscapeFuncs.geturl, instance, url, window);
}
NPError
NPN_PostURL(NPP instance, const char* url, const char* window,
uint32 len, const char* buf, NPBool file)
{
return CallNPN_PostURLProc(gNetscapeFuncs.posturl, instance,
url, window, len, buf, file);
}
NPError
NPN_RequestRead(NPStream* stream, NPByteRange* rangeList)
{
return CallNPN_RequestReadProc(gNetscapeFuncs.requestread,
stream, rangeList);
}
NPError
NPN_NewStream(NPP instance, NPMIMEType type, const char *window,
NPStream** stream_ptr)
{
return CallNPN_NewStreamProc(gNetscapeFuncs.newstream, instance,
type, window, stream_ptr);
}
int32
NPN_Write(NPP instance, NPStream* stream, int32 len, void* buffer)
{
return CallNPN_WriteProc(gNetscapeFuncs.write, instance,
stream, len, buffer);
}
NPError
NPN_DestroyStream(NPP instance, NPStream* stream, NPError reason)
{
return CallNPN_DestroyStreamProc(gNetscapeFuncs.destroystream,
instance, stream, reason);
}
void
NPN_Status(NPP instance, const char* message)
{
CallNPN_StatusProc(gNetscapeFuncs.status, instance, message);
}
const char*
NPN_UserAgent(NPP instance)
{
return CallNPN_UserAgentProc(gNetscapeFuncs.uagent, instance);
}
void*
NPN_MemAlloc(uint32 size)
{
return CallNPN_MemAllocProc(gNetscapeFuncs.memalloc, size);
}
void NPN_MemFree(void* ptr)
{
CallNPN_MemFreeProc(gNetscapeFuncs.memfree, ptr);
}
uint32 NPN_MemFlush(uint32 size)
{
return CallNPN_MemFlushProc(gNetscapeFuncs.memflush, size);
}
void NPN_ReloadPlugins(NPBool reloadPages)
{
CallNPN_ReloadPluginsProc(gNetscapeFuncs.reloadplugins, reloadPages);
}
JRIEnv* NPN_GetJavaEnv()
{
return CallNPN_GetJavaEnvProc(gNetscapeFuncs.getJavaEnv);
}
jref NPN_GetJavaPeer(NPP instance)
{
return CallNPN_GetJavaPeerProc(gNetscapeFuncs.getJavaPeer,
instance);
}
/***********************************************************************
*
* Wrapper functions : Netscape Navigator -> plugin
*
* These functions let the plugin developer just create the APIs
* as documented and defined in npapi.h, without needing to
* install those functions in the function table or worry about
* setting up globals for 68K plugins.
*
***********************************************************************/
NPError
Private_New(NPMIMEType pluginType, NPP instance, uint16 mode,
int16 argc, char* argn[], char* argv[], NPSavedData* saved)
{
NPError ret;
PLUGINDEBUGSTR("New");
ret = NPP_New(pluginType, instance, mode, argc, argn, argv, saved);
return ret;
}
NPError
Private_Destroy(NPP instance, NPSavedData** save)
{
PLUGINDEBUGSTR("Destroy");
return NPP_Destroy(instance, save);
}
NPError
Private_SetWindow(NPP instance, NPWindow* window)
{
NPError err;
PLUGINDEBUGSTR("SetWindow");
err = NPP_SetWindow(instance, window);
return err;
}
NPError
Private_NewStream(NPP instance, NPMIMEType type, NPStream* stream,
NPBool seekable, uint16* stype)
{
NPError err;
PLUGINDEBUGSTR("NewStream");
err = NPP_NewStream(instance, type, stream, seekable, stype);
return err;
}
int32
Private_WriteReady(NPP instance, NPStream* stream)
{
unsigned int result;
PLUGINDEBUGSTR("WriteReady");
result = NPP_WriteReady(instance, stream);
return result;
}
int32
Private_Write(NPP instance, NPStream* stream, int32 offset, int32 len,
void* buffer)
{
unsigned int result;
PLUGINDEBUGSTR("Write");
result = NPP_Write(instance, stream, offset, len, buffer);
return result;
}
void
Private_StreamAsFile(NPP instance, NPStream* stream, const char* fname)
{
PLUGINDEBUGSTR("StreamAsFile");
NPP_StreamAsFile(instance, stream, fname);
}
NPError
Private_DestroyStream(NPP instance, NPStream* stream, NPError reason)
{
NPError err;
PLUGINDEBUGSTR("DestroyStream");
err = NPP_DestroyStream(instance, stream, reason);
return err;
}
void
Private_Print(NPP instance, NPPrint* platformPrint)
{
PLUGINDEBUGSTR("Print");
NPP_Print(instance, platformPrint);
}
JRIGlobalRef
Private_GetJavaClass(void)
{
jref clazz = NPP_GetJavaClass();
if (clazz) {
JRIEnv* env = NPN_GetJavaEnv();
return JRI_NewGlobalRef(env, clazz);
}
return NULL;
}
/***********************************************************************
*
* These functions are located automagically by netscape.
*
***********************************************************************/
/*
* NP_GetMIMEDescription
* - Netscape needs to know about this symbol
* - Netscape uses the return value to identify when an object instance
* of this plugin should be created.
*/
char *
NP_GetMIMEDescription(void)
{
return NPP_GetMIMEDescription();
}
/*
* NP_GetValue [optional]
* - Netscape needs to know about this symbol.
* - Interfaces with plugin to get values for predefined variables
* that the navigator needs.
*/
NPError
NP_GetValue(void *future, NPPVariable variable, void *value)
{
return NPP_GetValue(future, variable, value);
}
/*
* NP_Initialize
* - Netscape needs to know about this symbol.
* - It calls this function after looking up its symbol before it
* is about to create the first ever object of this kind.
*
* PARAMETERS
* nsTable - The netscape function table. If developers just use these
* wrappers, they dont need to worry about all these function
* tables.
* RETURN
* pluginFuncs
* - This functions needs to fill the plugin function table
* pluginFuncs and return it. Netscape Navigator plugin
* library will use this function table to call the plugin.
*
*/
NPError
NP_Initialize(NPNetscapeFuncs* nsTable, NPPluginFuncs* pluginFuncs)
{
NPError err = NPERR_NO_ERROR;
PLUGINDEBUGSTR("NP_Initialize");
/* validate input parameters */
if ((nsTable == NULL) || (pluginFuncs == NULL))
err = NPERR_INVALID_FUNCTABLE_ERROR;
/*
* Check the major version passed in Netscape's function table.
* We won't load if the major version is newer than what we expect.
* Also check that the function tables passed in are big enough for
* all the functions we need (they could be bigger, if Netscape added
* new APIs, but that's OK with us -- we'll just ignore them).
*
*/
if (err == NPERR_NO_ERROR) {
if ((nsTable->version >> 8) > NP_VERSION_MAJOR)
err = NPERR_INCOMPATIBLE_VERSION_ERROR;
if (nsTable->size < sizeof(NPNetscapeFuncs))
err = NPERR_INVALID_FUNCTABLE_ERROR;
if (pluginFuncs->size < sizeof(NPPluginFuncs))
err = NPERR_INVALID_FUNCTABLE_ERROR;
}
if (err == NPERR_NO_ERROR) {
/*
* Copy all the fields of Netscape function table into our
* copy so we can call back into Netscape later. Note that
* we need to copy the fields one by one, rather than assigning
* the whole structure, because the Netscape function table
* could actually be bigger than what we expect.
*/
gNetscapeFuncs.version = nsTable->version;
gNetscapeFuncs.size = nsTable->size;
gNetscapeFuncs.posturl = nsTable->posturl;
gNetscapeFuncs.geturl = nsTable->geturl;
gNetscapeFuncs.requestread = nsTable->requestread;
gNetscapeFuncs.newstream = nsTable->newstream;
gNetscapeFuncs.write = nsTable->write;
gNetscapeFuncs.destroystream = nsTable->destroystream;
gNetscapeFuncs.status = nsTable->status;
gNetscapeFuncs.uagent = nsTable->uagent;
gNetscapeFuncs.memalloc = nsTable->memalloc;
gNetscapeFuncs.memfree = nsTable->memfree;
gNetscapeFuncs.memflush = nsTable->memflush;
gNetscapeFuncs.reloadplugins = nsTable->reloadplugins;
gNetscapeFuncs.getJavaEnv = nsTable->getJavaEnv;
gNetscapeFuncs.getJavaPeer = nsTable->getJavaPeer;
gNetscapeFuncs.getvalue = nsTable->getvalue;
/*
* Set up the plugin function table that Netscape will use to
* call us. Netscape needs to know about our version and size
* and have a UniversalProcPointer for every function we
* implement.
*/
pluginFuncs->version = (NP_VERSION_MAJOR << 8) + NP_VERSION_MINOR;
pluginFuncs->size = sizeof(NPPluginFuncs);
pluginFuncs->newp = NewNPP_NewProc(Private_New);
pluginFuncs->destroy = NewNPP_DestroyProc(Private_Destroy);
pluginFuncs->setwindow = NewNPP_SetWindowProc(Private_SetWindow);
pluginFuncs->newstream = NewNPP_NewStreamProc(Private_NewStream);
pluginFuncs->destroystream = NewNPP_DestroyStreamProc(Private_DestroyStream);
pluginFuncs->asfile = NewNPP_StreamAsFileProc(Private_StreamAsFile);
pluginFuncs->writeready = NewNPP_WriteReadyProc(Private_WriteReady);
pluginFuncs->write = NewNPP_WriteProc(Private_Write);
pluginFuncs->print = NewNPP_PrintProc(Private_Print);
pluginFuncs->event = NULL;
pluginFuncs->javaClass = Private_GetJavaClass();
err = NPP_Initialize();
}
return err;
}
/*
* NP_Shutdown [optional]
* - Netscape needs to know about this symbol.
* - It calls this function after looking up its symbol after
* the last object of this kind has been destroyed.
*
*/
NPError
NP_Shutdown(void)
{
PLUGINDEBUGSTR("NP_Shutdown");
NPP_Shutdown();
return NPERR_NO_ERROR;
}

14
src/signer/stubs.c Normal file
View File

@ -0,0 +1,14 @@
/* -*- Mode: C; tab-width: 4; -*- */
/*******************************************************************************
* Simple LiveConnect Sample Plugin
* Copyright (c) 1996 Netscape Communications. All rights reserved.
******************************************************************************/
/*
** Ok, so we don't usually include .c files (only .h files) but we're
** doing it here to avoid some fancy make rules. First pull in the common
** glue code:
*/
#ifdef XP_UNIX
#include "npunix.c"
#endif

View File

@ -8,23 +8,23 @@
#include <string.h>
#include "sc.h"
#include "sc-pkcs15.h"
#include "sc-test.h"
struct sc_context *ctx = NULL;
struct sc_card *card = NULL;
struct sc_pkcs15_card *p15_card = NULL;
#define DO_PRKEY_ENUM 1
#define DO_PIN_ENUM 1
#define DO_PIN_VERIFY 1
#define DO_DECIPHER 1
#define DO_SIGN 1
#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_CERT_ENUM 1
#define DO_CERT_READ 1
#define DO_TEST 0
struct sc_pkcs15_card *p15card;
int enum_private_keys()
{
int i;
i = sc_pkcs15_enum_private_keys(p15_card);
i = sc_pkcs15_enum_private_keys(p15card);
if (i < 0) {
fprintf(stderr, "Private key enumeration failed with %s\n",
sc_strerror(i));
@ -32,53 +32,8 @@ int enum_private_keys()
}
printf("%d private keys found!\n", i);
for (i = 0; i < p15_card->prkey_count; i++) {
sc_pkcs15_print_prkey_info(&p15_card->prkey_info[i]);
}
return 0;
}
int enum_pins()
{
int i, c;
c = sc_pkcs15_enum_pins(p15_card);
if (c < 0) {
fprintf(stderr, "Error enumerating PIN codes: %s\n",
sc_strerror(i));
return 1;
}
if (c == 0)
fprintf(stderr, "No PIN codes found!\n");
for (i = 0; i < c; i++) {
sc_pkcs15_print_pin_info(&p15_card->pin_info[i]);
}
return 0;
}
int ask_and_verify_pin(struct sc_pkcs15_pin_info *pin)
{
int i = 0;
char buf[32];
i = sc_sec_ask_pin_code(pin, buf, sizeof(buf),
"Please enter PIN code");
if (i == 0) {
i = sc_pkcs15_verify_pin(p15_card, pin, buf, strlen(buf));
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;
}
printf("PIN code correct.\n");
} else {
printf("\nNot verifying PIN code.\n");
for (i = 0; i < p15card->prkey_count; i++) {
sc_pkcs15_print_prkey_info(&p15card->prkey_info[i]);
}
return 0;
}
@ -89,74 +44,33 @@ int main(int argc, char **argv)
struct sc_security_env senv;
FILE *file;
struct sc_object_id oid;
struct timeval tv1, tv2;
int i, c;
sc_asn1_decode_object_id("\x2a\x86\x48\x86\xf7\x0d", 6, &oid);
i = sc_test_init(&argc, argv);
if (i != 0)
return 1;
i = sc_establish_context(&ctx);
if (i < 0) {
printf("sc_establish_context() failed (%d)\n", i);
return 1;
}
i = sc_detect_card(ctx, 0);
printf("Card %s.\n", i == 1 ? "present" : "absent");
if (i < 0) {
return 1;
}
if (i == 0) {
printf("Please insert a smart card.");
fflush(stdout);
i = sc_wait_for_card(ctx, -1, -1);
if (i != 1)
return 1;
c = -1;
for (i = 0; i < ctx->reader_count; i++) {
if (sc_detect_card(ctx, i) == 1) {
c = i;
break;
}
}
printf("\n");
} else
c = 0;
printf("Connecting... ");
fflush(stdout);
i = sc_connect_card(ctx, c, &card);
if (i != 0) {
printf("Connecting to card failed\n");
return 1;
}
printf("done.\n");
fflush(stdout);
i = sc_pkcs15_init(card, &p15_card);
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(p15_card);
sc_pkcs15_print_card(p15card);
#if DO_PRKEY_ENUM
if (enum_private_keys())
return 1;
#endif
#if DO_PIN_ENUM
if (enum_pins())
return 1;
#endif
#if DO_PIN_VERIFY
if (ask_and_verify_pin(&p15_card->pin_info[0]))
return 1;
#endif
#if DO_DECIPHER
senv.signature = 0;
senv.algorithm_ref = 0x02;
senv.key_ref = 0;
senv.key_file_id = p15_card->prkey_info[0].file_id;
senv.app_df_path = p15_card->file_app.path;
i = sc_set_security_env(p15_card->card, &senv);
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));
@ -188,9 +102,9 @@ int main(int argc, char **argv)
senv.signature = 1;
senv.algorithm_ref = 0x02;
senv.key_ref = 0;
senv.key_file_id = p15_card->prkey_info[0].file_id;
senv.app_df_path = p15_card->file_app.path;
i = sc_set_security_env(p15_card->card, &senv);
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));
@ -220,7 +134,7 @@ int main(int argc, char **argv)
}
#endif
#if DO_CERT_ENUM
i = sc_pkcs15_enum_certificates(p15_card);
i = sc_pkcs15_enum_certificates(p15card);
if (i < 0) {
fprintf(stderr, "Certificate enumeration failed: %s\n",
sc_strerror(i));
@ -229,23 +143,23 @@ int main(int argc, char **argv)
printf("%d certificates found.\n", i);
#endif
#if DO_CERT_READ
for (i = 0; i < p15_card->cert_count; i++) {
for (i = 0; i < p15card->cert_count; i++) {
char fname[16];
struct sc_pkcs15_cert *cert;
sc_pkcs15_print_cert_info(&p15_card->cert_info[i]);
sc_pkcs15_print_cert_info(&p15card->cert_info[i]);
strcpy(fname, "cert-");
sprintf(fname + 5, "%02X",
p15_card->cert_info[i].id.value[0]);
p15card->cert_info[i].id.value[0]);
file = fopen(fname, "w");
if (file != NULL) {
c = sc_pkcs15_read_certificate(p15_card,
&p15_card->cert_info[i],
c = sc_pkcs15_read_certificate(p15card,
&p15card->cert_info[i],
&cert);
if (c) {
fprintf(stderr,
"Certificate read failed.\n");
"Certificate read failed.\n ");
return 1;
}
printf("Dumping certificate to file '%s' (%d bytes)\n",
@ -257,9 +171,7 @@ int main(int argc, char **argv)
}
#endif
printf("Cleaning up...\n");
i = sc_pkcs15_destroy(p15_card);
sc_disconnect_card(card);
sc_destroy_context(ctx);
sc_test_cleanup();
return 0;
}

67
src/tests/lottery.c Normal file
View File

@ -0,0 +1,67 @@
/* Copyright (C) 2001 Juha Yrjölä <juha.yrjola@iki.fi>
* All rights reserved.
*/
#include "sc-test.h"
#include "sc.h"
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
int main(int argc, char *argv[])
{
int i, c;
int freq[39];
struct timeval tv1, tv2;
u8 buf[14];
i = sc_test_init(&argc, argv);
for (i = 0; i < 39; i++)
freq[i] = 0;
c = 0;
while (1) {
u8 alkiot[39];
for (i = 0; i < 39; i++) {
alkiot[i] = i + 1;
}
if (c == 0)
gettimeofday(&tv1, NULL);
if (sc_get_random(card, buf, 14) == 0) {
int i, jaljella = 39;
printf("Lottorivi: ");
for (i = 0; i < 7; i++) {
unsigned short s = buf[2*i] + (buf[2*i+1] << 8);
int lot = s % (jaljella+1);
int num = alkiot[lot];
alkiot[lot] = alkiot[jaljella-1];
jaljella--;
freq[num-1]++;
printf("%3d ", num);
}
printf("\n");
}
c++;
if (c == 50) {
unsigned long long foo, foo2;
gettimeofday(&tv2, NULL);
foo = tv2.tv_sec * 1000 + tv2.tv_usec / 1000;
foo2 = tv1.tv_sec * 1000 + tv1.tv_usec / 1000;
printf("Time per one: %lld ms\n", (foo - foo2)/50);
printf("Frequencies:\n");
for (i = 0; i < 39; i++) {
printf("%3d: %5d", i+1, freq[i]);
}
printf("\n");
c = 0;
}
}
}

81
src/tests/p15dump.c Normal file
View File

@ -0,0 +1,81 @@
/* Copyright (C) 2001 Juha Yrjölä <juha.yrjola@iki.fi>
* All rights reserved.
*
* PKCS#15 PIN code test
*/
#include "sc-test.h"
#include "sc.h"
#include "sc-pkcs15.h"
#include <stdio.h>
#include <stdlib.h>
struct sc_pkcs15_card *p15card;
int enum_pins()
{
int i, c;
c = sc_pkcs15_enum_pins(p15card);
if (c < 0) {
fprintf(stderr, "Error enumerating PIN codes: %s\n",
sc_strerror(i));
return 1;
}
if (c == 0)
fprintf(stderr, "No PIN codes found!\n");
for (i = 0; i < c; i++) {
sc_pkcs15_print_pin_info(&p15card->pin_info[i]);
}
return 0;
}
int main(int argc, char *argv[])
{
int i, c;
i = sc_test_init(&argc, argv);
if (i < 0)
return 1;
printf("Looking for a PKCS#15 compatible Smart Card... ");
fflush(stdout);
i = sc_pkcs15_init(card, &p15card);
if (i) {
fprintf(stderr, "failed: %s\n", sc_strerror(i));
return 1;
}
printf("found.\n");
sc_pkcs15_print_card(p15card);
printf("Enumerating PIN codes...\n");
i = enum_pins();
if (i)
return 1;
printf("Enumerating private keys... ");
fflush(stdout);
i = sc_pkcs15_enum_private_keys(p15card);
if (i < 0) {
fprintf(stderr, "failed: %s\n", sc_strerror(i));
return 1;
}
printf("done.\n");
for (c = 0; c < p15card->prkey_count; c++) {
sc_pkcs15_print_prkey_info(&p15card->prkey_info[c]);
}
printf("Enumerating certificates... ");
fflush(stdout);
i = sc_pkcs15_enum_certificates(p15card);
if (i < 0) {
fprintf(stderr, "failed: %s\n", sc_strerror(i));
return 1;
}
printf("done.\n");
for (c = 0; c < p15card->cert_count; c++) {
sc_pkcs15_print_cert_info(&p15card->cert_info[c]);
}
return 0;
}

85
src/tests/pintest.c Normal file
View File

@ -0,0 +1,85 @@
/* Copyright (C) 2001 Juha Yrjölä <juha.yrjola@iki.fi>
* All rights reserved.
*
* PKCS#15 PIN code test
*/
#include "sc-test.h"
#include "sc.h"
#include "sc-pkcs15.h"
#include <stdio.h>
#include <stdlib.h>
struct sc_pkcs15_card *p15card;
int enum_pins()
{
int i, c;
c = sc_pkcs15_enum_pins(p15card);
if (c < 0) {
fprintf(stderr, "Error enumerating PIN codes: %s\n",
sc_strerror(i));
return 1;
}
if (c == 0)
fprintf(stderr, "No PIN codes found!\n");
for (i = 0; i < c; i++) {
sc_pkcs15_print_pin_info(&p15card->pin_info[i]);
}
return 0;
}
int ask_and_verify_pin(struct sc_pkcs15_pin_info *pin)
{
int i = 0;
char buf[32];
i = sc_sec_ask_pin_code(pin, buf, sizeof(buf),
"Please enter PIN code");
if (i == 0) {
i = sc_pkcs15_verify_pin(p15card, pin, buf, strlen(buf));
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;
}
printf("PIN code correct.\n");
} else {
printf("\nNot verifying PIN code.\n");
}
return 0;
}
int main(int argc, char *argv[])
{
int i, c;
i = sc_test_init(&argc, argv);
if (i < 0)
return 1;
printf("Looking for a PKCS#15 compatible Smart Card... ");
fflush(stdout);
i = sc_pkcs15_init(card, &p15card);
if (i) {
fprintf(stderr, "failed: %s\n", sc_strerror(i));
return 1;
}
printf("found.\n");
printf("Enumerating PIN codes...\n");
i = enum_pins();
if (i)
return 1;
for (c = 0; c < p15card->pin_count; c++) {
ask_and_verify_pin(&p15card->pin_info[c]);
}
return 0;
}

54
src/tests/prngtest.c Normal file
View File

@ -0,0 +1,54 @@
/* Copyright (C) 2001 Juha Yrjölä <juha.yrjola@iki.fi>
* All rights reserved.
*
* Pseudo-random number generator test program
*/
#include "sc-test.h"
#include "sc.h"
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
int main(int argc, char *argv[])
{
int i, c;
int freq[256];
struct timeval tv1, tv2;
u8 buf[8];
i = sc_test_init(&argc, argv);
if (i < 0)
return 1;
for (i = 0; i < 256; i++)
freq[i] = 0;
c = 0;
while (1) {
if (c == 0)
gettimeofday(&tv1, NULL);
if (sc_get_random(card, buf, 8) != 0) {
printf("sc_get_random() failed.\n");
return 1;
}
for (i = 0; i < 8; i++)
freq[buf[i]]++;
c++;
if (c == 100) {
unsigned long long foo, foo2;
gettimeofday(&tv2, NULL);
foo = tv2.tv_sec * 1000 + tv2.tv_usec / 1000;
foo2 = tv1.tv_sec * 1000 + tv1.tv_usec / 1000;
printf("Time to generate 64 bits of randomness: %lld ms\n",
(foo - foo2)/100);
printf("Frequencies:\n");
for (i = 0; i < 256; i++) {
printf("%02X: %5d ", i, freq[i]);
}
printf("\n");
c = 0;
}
}
}

62
src/tests/sc-test.c Normal file
View File

@ -0,0 +1,62 @@
/* Copyright (C) 2001 Juha Yrjölä <juha.yrjola@iki.fi>
* All rights reserved.
*
* Pseudo-random number generator test program
*/
#include <stdio.h>
#include <stdlib.h>
#include "sc.h"
struct sc_context *ctx;
struct sc_card *card;
int sc_test_init(int *argc, char *argv[])
{
int i, c;
i = sc_establish_context(&ctx);
if (i < 0) {
printf("sc_establish_context() failed (%d)\n", i);
return i;
}
i = sc_detect_card(ctx, 0);
printf("Card %s.\n", i == 1 ? "present" : "absent");
if (i < 0) {
return i;
}
if (i == 0) {
printf("Please insert a smart card.");
fflush(stdout);
i = sc_wait_for_card(ctx, -1, -1);
if (i < 0)
return i;
if (i != 1)
return -1;
c = -1;
for (i = 0; i < ctx->reader_count; i++) {
if (sc_detect_card(ctx, i) == 1) {
c = i;
break;
}
}
printf("\n");
} else
c = 0;
printf("Connecting... ");
fflush(stdout);
i = sc_connect_card(ctx, c, &card);
if (i != 0) {
printf("Connecting to card failed\n");
return i;
}
printf("connected.\n");
fflush(stdout);
}
void sc_test_cleanup()
{
sc_disconnect_card(card);
sc_destroy_context(ctx);
}

10
src/tests/sc-test.h Normal file
View File

@ -0,0 +1,10 @@
#ifndef _SC_TEST_H
extern struct sc_context *ctx;
extern struct sc_card *card;
int sc_test_init(int *argc, char *argv[]);
void sc_test_cleanup();
#endif