- 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:
parent
aea833a5e8
commit
c57e2e266d
389
src/libopensc/asn1.c
Normal file
389
src/libopensc/asn1.c
Normal 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
48
src/libopensc/asn1.h
Normal 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
|
187
src/libopensc/opensc-pkcs15.h
Normal file
187
src/libopensc/opensc-pkcs15.h
Normal 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
185
src/libopensc/opensc.h
Normal 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
302
src/libopensc/pkcs15-cert.c
Normal 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
246
src/libopensc/pkcs15-pin.c
Normal 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;
|
||||
}
|
143
src/libopensc/pkcs15-prkey.c
Normal file
143
src/libopensc/pkcs15-prkey.c
Normal 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
111
src/libopensc/pkcs15-sec.c
Normal 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
354
src/libopensc/pkcs15.c
Normal 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
187
src/libopensc/pkcs15.h
Normal 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
48
src/libopensc/sc-asn1.h
Normal 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
804
src/libopensc/sc.c
Normal 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
40
src/libopensc/sec.c
Normal 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;
|
||||
}
|
@ -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];
|
||||
|
@ -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
29
src/signer/Makefile
Normal 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
406
src/signer/npunix.c
Normal 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
14
src/signer/stubs.c
Normal 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
|
@ -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
67
src/tests/lottery.c
Normal 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
81
src/tests/p15dump.c
Normal 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
85
src/tests/pintest.c
Normal 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
54
src/tests/prngtest.c
Normal 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
62
src/tests/sc-test.c
Normal 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
10
src/tests/sc-test.h
Normal 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
|
Loading…
Reference in New Issue
Block a user