opensc/src/tools/cryptoflex-tool.c

1394 lines
30 KiB
C

/*
* cryptoflex-tool.c: Tool for doing various Cryptoflex related stuff
*
* Copyright (C) 2001 Juha Yrjölä <juha.yrjola@iki.fi>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "util.h"
#include <opensc-pkcs15.h>
#include <openssl/bn.h>
#include <openssl/rsa.h>
#include <openssl/x509.h>
#include <openssl/pem.h>
#include <openssl/err.h>
int opt_reader = 0, opt_debug = 0;
int opt_key_num = 1, opt_pin_num = -1;
int quiet = 0;
int opt_exponent = 3;
int opt_mod_length = 1024;
int opt_key_count = 1;
int opt_pin_attempts = 10;
int opt_puk_attempts = 10;
const char *opt_appdf = NULL, *opt_prkeyf = NULL, *opt_pubkeyf = NULL;
u8 *pincode = NULL;
const struct option options[] = {
{ "create-pkcs15", 0, 0, 'C' },
{ "list-keys", 0, 0, 'l' },
{ "create-key-files", 1, 0, 'c' },
{ "create-pin-file", 1, 0, 'P' },
{ "generate-key", 0, 0, 'g' },
{ "read-key", 0, 0, 'R' },
{ "verify-pin", 0, 0, 'v' },
{ "key-num", 1, 0, 'k' },
{ "app-df", 1, 0, 'a' },
{ "prkey-file", 1, 0, 'p' },
{ "pubkey-file", 1, 0, 'u' },
{ "exponent", 1, 0, 'e' },
{ "modulus-length", 1, 0, 'm' },
{ "reader", 1, 0, 'r' },
{ "quiet", 0, 0, 'q' },
{ "debug", 0, 0, 'd' },
{ 0, 0, 0, 0 }
};
const char *option_help[] = {
"Creates a new PKCS #15 structure",
"Lists all keys in a public key file",
"Creates new RSA key files for <arg> keys",
"Creates a new CHV<arg> file",
"Generates a new RSA key pair",
"Reads a public key from the card",
"Verifies CHV1 before issuing commands",
"Selects which key number to operate on [1]",
"Selects the DF to operate in",
"Private key file",
"Public key file",
"The RSA exponent to use in key generation [3]",
"Modulus length to use in key generation [1024]",
"Uses reader number <arg> [0]",
"Quiet operation",
"Debug output -- may be supplied several times",
};
struct sc_context *ctx = NULL;
struct sc_card *card = NULL;
char *getpin(const char *prompt)
{
char *buf, pass[20];
int i;
printf("%s", prompt);
fflush(stdout);
if (fgets(pass, 20, stdin) == NULL)
return NULL;
for (i = 0; i < 20; i++)
if (pass[i] == '\n')
pass[i] = 0;
if (strlen(pass) == 0)
return NULL;
buf = malloc(8);
if (buf == NULL)
return NULL;
if (strlen(pass) > 8) {
fprintf(stderr, "PIN code too long.\n");
return NULL;
}
memset(buf, 0, 8);
strncpy(buf, pass, 8);
memset(pass, 0, strlen(pass));
return buf;
}
int verify_pin(int pin)
{
char prompt[50];
int r, type, tries_left = -1;
if (pincode == NULL) {
sprintf(prompt, "Please enter CHV%d: ", pin);
pincode = (u8 *) getpin(prompt);
if (pincode == NULL || strlen((char *) pincode) == 0)
return -1;
}
if (pin == 1)
type = SC_AC_CHV1;
else if (pin == 2)
type = SC_AC_CHV2;
else
return -3;
r = sc_verify(card, type, pin, pincode, 8, &tries_left);
if (r) {
memset(pincode, 0, 8);
free(pincode);
pincode = NULL;
fprintf(stderr, "PIN code verification failed: %s\n", sc_strerror(r));
return -1;
}
return 0;
}
int select_app_df(void)
{
struct sc_path path;
struct sc_file file;
char str[80];
int r;
strcpy(str, "3F00");
if (opt_appdf != NULL)
strcat(str, opt_appdf);
sc_format_path(str, &path);
r = sc_select_file(card, &path, &file);
if (r) {
fprintf(stderr, "Unable to select application DF: %s\n", sc_strerror(r));
return -1;
}
if (file.type != SC_FILE_TYPE_DF) {
fprintf(stderr, "Selected application DF is not a DF.\n");
return -1;
}
if (opt_pin_num >= 0)
return verify_pin(opt_pin_num);
else
return 0;
}
void invert_buf(u8 *dest, const u8 *src, size_t c)
{
int i;
for (i = 0; i < c; i++)
dest[i] = src[c-1-i];
}
BIGNUM * cf2bn(const u8 *buf, size_t bufsize, BIGNUM *num)
{
u8 tmp[512];
invert_buf(tmp, buf, bufsize);
return BN_bin2bn(tmp, bufsize, num);
}
int bn2cf(const BIGNUM *num, u8 *buf)
{
u8 tmp[512];
int r;
r = BN_bn2bin(num, tmp);
if (r <= 0)
return r;
invert_buf(buf, tmp, r);
return r;
}
#if 0
int mont(RSA *rsa, u8 *j0)
{
BIGNUM Ri, RR, Ni;
BN_CTX *bn_ctx = BN_CTX_new();
int num_bits = BN_num_bits(rsa->n);
u8 tmp[512];
BN_init(&Ri);
BN_init(&RR);
BN_init(&Ni);
BN_zero(&RR);
BN_set_bit(&RR, num_bits);
if ((BN_mod_inverse(&Ri, &RR, rsa->n, bn_ctx)) == NULL) {
fprintf(stderr, "BN_mod_inverse() failed.\n");
return -1;
}
BN_lshift(&Ri, &Ri, num_bits);
BN_sub_word(&Ri, 1);
BN_div(&Ni, NULL, &Ri, rsa->n, bn_ctx);
bn2cf(&Ni, tmp);
memcpy(j0, tmp, BN_num_bytes(&Ni)/2);
printf("Ni from SSL:\n");
hex_dump_asc(stdout, tmp, BN_num_bytes(&Ni), -1);
BN_free(&Ri);
BN_free(&RR);
BN_free(&Ni);
return 0;
}
#endif
int parse_public_key(const u8 *key, size_t keysize, RSA *rsa)
{
const u8 *p = key;
BIGNUM *n, *e;
int base;
base = (keysize - 7) / 5;
if (base != 32 && base != 48 && base != 64 && base != 128) {
fprintf(stderr, "Invalid public key.\n");
return -1;
}
p += 3;
n = BN_new();
if (n == NULL)
return -1;
cf2bn(p, 2 * base, n);
p += 2 * base;
p += base;
p += 2 * base;
e = BN_new();
if (e == NULL)
return -1;
cf2bn(p, 4, e);
rsa->n = n;
rsa->e = e;
return 0;
}
int gen_d(RSA *rsa)
{
BN_CTX *ctx, *ctx2;
BIGNUM *r0, *r1, *r2;
ctx = BN_CTX_new();
ctx2 = BN_CTX_new();
BN_CTX_start(ctx);
r0 = BN_CTX_get(ctx);
r1 = BN_CTX_get(ctx);
r2 = BN_CTX_get(ctx);
BN_sub(r1, rsa->p, BN_value_one());
BN_sub(r2, rsa->q, BN_value_one());
BN_mul(r0, r1, r2, ctx);
if ((rsa->d = BN_mod_inverse(NULL, rsa->e, r0, ctx2)) == NULL) {
fprintf(stderr, "BN_mod_inverse() failed.\n");
return -1;
}
BN_CTX_end(ctx);
BN_CTX_free(ctx);
BN_CTX_free(ctx2);
return 0;
}
int parse_private_key(const u8 *key, size_t keysize, RSA *rsa)
{
const u8 *p = key;
BIGNUM *bn_p, *q, *dmp1, *dmq1, *iqmp;
int base;
base = (keysize - 3) / 5;
if (base != 32 && base != 48 && base != 64 && base != 128) {
fprintf(stderr, "Invalid private key.\n");
return -1;
}
p += 3;
bn_p = BN_new();
if (bn_p == NULL)
return -1;
cf2bn(p, base, bn_p);
p += base;
q = BN_new();
if (q == NULL)
return -1;
cf2bn(p, base, q);
p += base;
iqmp = BN_new();
if (iqmp == NULL)
return -1;
cf2bn(p, base, iqmp);
p += base;
dmp1 = BN_new();
if (dmp1 == NULL)
return -1;
cf2bn(p, base, dmp1);
p += base;
dmq1 = BN_new();
if (dmq1 == NULL)
return -1;
cf2bn(p, base, dmq1);
p += base;
rsa->p = bn_p;
rsa->q = q;
rsa->dmp1 = dmp1;
rsa->dmq1 = dmq1;
rsa->iqmp = iqmp;
if (gen_d(rsa))
return -1;
return 0;
}
int read_public_key(RSA *rsa)
{
int r;
struct sc_path path;
struct sc_file file;
u8 buf[2048], *p = buf;
size_t bufsize, keysize;
r = select_app_df();
if (r)
return 1;
sc_format_path("I1012", &path);
r = sc_select_file(card, &path, &file);
if (r) {
fprintf(stderr, "Unable to select public key file: %s\n", sc_strerror(r));
return 2;
}
bufsize = file.size;
r = sc_read_binary(card, 0, buf, bufsize, 0);
if (r < 0) {
fprintf(stderr, "Unable to read public key file: %s\n", sc_strerror(r));
return 2;
}
bufsize = r;
do {
if (bufsize < 4)
return 3;
keysize = (p[0] << 8) | p[1];
if (keysize == 0)
break;
if (keysize < 3)
return 3;
if (p[2] == opt_key_num)
break;
p += keysize;
bufsize -= keysize;
} while (1);
if (keysize == 0) {
printf("Key number %d not found.\n", opt_key_num);
return 2;
}
return parse_public_key(p, keysize, rsa);
}
int read_private_key(RSA *rsa)
{
int r;
struct sc_path path;
struct sc_file file;
u8 buf[2048], *p = buf;
size_t bufsize, keysize;
r = select_app_df();
if (r)
return 1;
sc_format_path("I0012", &path);
r = sc_select_file(card, &path, &file);
if (r) {
fprintf(stderr, "Unable to select private key file: %s\n", sc_strerror(r));
return 2;
}
if (file.acl[SC_AC_OP_READ] == SC_AC_NEVER)
return 10;
bufsize = file.size;
r = sc_read_binary(card, 0, buf, bufsize, 0);
if (r < 0) {
fprintf(stderr, "Unable to read private key file: %s\n", sc_strerror(r));
return 2;
}
bufsize = r;
do {
if (bufsize < 4)
return 3;
keysize = (p[0] << 8) | p[1];
if (keysize == 0)
break;
if (keysize < 3)
return 3;
if (p[2] == opt_key_num)
break;
p += keysize;
bufsize -= keysize;
} while (1);
if (keysize == 0) {
printf("Key number %d not found.\n", opt_key_num);
return 2;
}
return parse_private_key(p, keysize, rsa);
}
int read_key(void)
{
RSA *rsa = RSA_new();
u8 buf[1024], *p = buf;
u8 b64buf[2048];
int r;
if (rsa == NULL)
return -1;
r = read_public_key(rsa);
if (r)
return r;
r = i2d_RSA_PUBKEY(rsa, &p);
if (r <= 0) {
fprintf(stderr, "Error encoding public key.\n");
return -1;
}
r = sc_base64_encode(buf, r, b64buf, sizeof(b64buf), 64);
if (r < 0) {
fprintf(stderr, "Error in Base64 encoding: %s\n", sc_strerror(r));
return -1;
}
printf("-----BEGIN PUBLIC KEY-----\n%s-----END PUBLIC KEY-----\n", b64buf);
r = read_private_key(rsa);
if (r == 10)
return 0;
else if (r)
return r;
p = buf;
r = i2d_RSAPrivateKey(rsa, &p);
if (r <= 0) {
fprintf(stderr, "Error encoding private key.\n");
return -1;
}
r = sc_base64_encode(buf, r, b64buf, sizeof(b64buf), 64);
if (r < 0) {
fprintf(stderr, "Error in Base64 encoding: %s\n", sc_strerror(r));
return -1;
}
printf("-----BEGIN RSA PRIVATE KEY-----\n%s-----END RSA PRIVATE KEY-----\n", b64buf);
return 0;
}
int list_keys(void)
{
int r, i, idx = 0;
struct sc_path path;
struct sc_file file;
u8 buf[2048], *p = buf;
size_t keysize;
int mod_lens[] = { 512, 768, 1024, 2048 };
int sizes[] = { 167, 247, 327, 647 };
r = select_app_df();
if (r)
return 1;
sc_format_path("I1012", &path);
r = sc_select_file(card, &path, &file);
if (r) {
fprintf(stderr, "Unable to select public key file: %s\n", sc_strerror(r));
return 2;
}
do {
int mod_len = -1;
r = sc_read_binary(card, idx, buf, 3, 0);
if (r < 0) {
fprintf(stderr, "Unable to read public key file: %s\n", sc_strerror(r));
return 2;
}
keysize = (p[0] << 8) | p[1];
if (keysize == 0)
break;
idx += keysize;
for (i = 0; i < sizeof(sizes)/sizeof(int); i++)
if (sizes[i] == keysize)
mod_len = mod_lens[i];
if (mod_len < 0)
printf("Key %d -- unknown modulus length\n", p[2] & 0x0F);
else
printf("Key %d -- Modulus length %d\n", p[2] & 0x0F, mod_len);
} while (1);
return 0;
}
int generate_key(void)
{
struct sc_apdu apdu;
u8 sbuf[4];
u8 p2;
int r;
switch (opt_mod_length) {
case 512:
p2 = 0x40;
break;
case 768:
p2 = 0x60;
break;
case 1024:
p2 = 0x80;
break;
case 2048:
p2 = 0x00;
break;
default:
fprintf(stderr, "Invalid modulus length.\n");
return 2;
}
sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x46, (u8) opt_key_num-1, p2);
apdu.cla = 0xF0;
apdu.lc = 4;
apdu.datalen = 4;
apdu.data = sbuf;
sbuf[0] = opt_exponent & 0xFF;
sbuf[1] = (opt_exponent >> 8) & 0xFF;
sbuf[2] = (opt_exponent >> 16) & 0xFF;
sbuf[3] = (opt_exponent >> 24) & 0xFF;
r = select_app_df();
if (r)
return 1;
if (!quiet)
printf("Generating key...\n");
r = sc_transmit_apdu(card, &apdu);
if (r) {
fprintf(stderr, "APDU transmit failed: %s\n", sc_strerror(r));
if (r == SC_ERROR_TRANSMIT_FAILED)
fprintf(stderr, "Reader has timed out. It is still possible that the key generation has\n"
"succeeded.\n");
return 1;
}
if (apdu.sw1 == 0x90 && apdu.sw2 == 0x00) {
printf("Key generation successful.\n");
return 0;
}
if (apdu.sw1 == 0x69 && apdu.sw2 == 0x82)
fprintf(stderr, "CHV1 not verified or invalid exponent value.\n");
else
fprintf(stderr, "Card returned SW1=%02X, SW2=%02X.\n", apdu.sw1, apdu.sw2);
return 1;
}
int create_key_files(void)
{
struct sc_file file;
int mod_lens[] = { 512, 768, 1024, 2048 };
int sizes[] = { 163, 243, 323, 643 };
int size = -1;
int i, r;
for (i = 0; i < sizeof(mod_lens) / sizeof(int); i++)
if (mod_lens[i] == opt_mod_length) {
size = sizes[i];
break;
}
if (size == -1) {
fprintf(stderr, "Invalid modulus length.\n");
return 1;
}
if (!quiet)
printf("Creating key files for %d keys.\n", opt_key_count);
memset(&file, 0, sizeof(file));
for (i = 0; i < SC_MAX_AC_OPS; i++)
file.acl[i] = SC_AC_NONE;
file.type = SC_FILE_TYPE_WORKING_EF;
file.ef_structure = SC_FILE_EF_TRANSPARENT;
file.id = 0x0012;
file.size = opt_key_count * size + 3;
file.acl[SC_AC_OP_READ] = SC_AC_NEVER;
file.acl[SC_AC_OP_UPDATE] = SC_AC_CHV1;
file.acl[SC_AC_OP_INVALIDATE] = SC_AC_CHV1;
file.acl[SC_AC_OP_REHABILITATE] = SC_AC_CHV1;
if (select_app_df())
return 1;
r = sc_create_file(card, &file);
if (r) {
fprintf(stderr, "Unable to create private key file: %s\n", sc_strerror(r));
return 1;
}
file.id = 0x1012;
file.size = opt_key_count * (size + 4) + 3;
file.acl[SC_AC_OP_READ] = SC_AC_NONE;
file.acl[SC_AC_OP_UPDATE] = SC_AC_CHV1;
file.acl[SC_AC_OP_INVALIDATE] = SC_AC_CHV1;
file.acl[SC_AC_OP_REHABILITATE] = SC_AC_CHV1;
if (select_app_df())
return 1;
r = sc_create_file(card, &file);
if (r) {
fprintf(stderr, "Unable to create public key file: %s\n", sc_strerror(r));
return 1;
}
if (!quiet)
printf("Key files generated successfully.\n");
return 0;
}
int read_rsa_privkey(RSA **rsa_out)
{
RSA *rsa = NULL;
BIO *in = NULL;
int r;
in = BIO_new(BIO_s_file());
if (opt_prkeyf == NULL) {
fprintf(stderr, "Private key file must be set.\n");
return 2;
}
r = BIO_read_filename(in, opt_prkeyf);
if (r <= 0) {
perror(opt_prkeyf);
return 2;
}
rsa = PEM_read_bio_RSAPrivateKey(in, NULL, NULL, NULL);
if (rsa == NULL) {
fprintf(stderr, "Unable to load private key.\n");
return 2;
}
BIO_free(in);
*rsa_out = rsa;
return 0;
}
int encode_private_key(RSA *rsa, u8 *key, size_t *keysize)
{
u8 buf[512], *p = buf;
u8 bnbuf[256];
int base = 0;
int r;
switch (BN_num_bits(rsa->n)) {
case 512:
base = 32;
break;
case 768:
base = 48;
break;
case 1024:
base = 64;
break;
case 2048:
base = 128;
break;
}
if (base == 0) {
fprintf(stderr, "Key length invalid.\n");
return 2;
}
*p++ = (5 * base + 3) >> 8;
*p++ = (5 * base + 3) & 0xFF;
*p++ = opt_key_num;
r = bn2cf(rsa->p, bnbuf);
if (r != base) {
fprintf(stderr, "Invalid private key.\n");
return 2;
}
memcpy(p, bnbuf, base);
p += base;
r = bn2cf(rsa->q, bnbuf);
if (r != base) {
fprintf(stderr, "Invalid private key.\n");
return 2;
}
memcpy(p, bnbuf, base);
p += base;
r = bn2cf(rsa->iqmp, bnbuf);
if (r != base) {
fprintf(stderr, "Invalid private key.\n");
return 2;
}
memcpy(p, bnbuf, base);
p += base;
r = bn2cf(rsa->dmp1, bnbuf);
if (r != base) {
fprintf(stderr, "Invalid private key.\n");
return 2;
}
memcpy(p, bnbuf, base);
p += base;
r = bn2cf(rsa->dmq1, bnbuf);
if (r != base) {
fprintf(stderr, "Invalid private key.\n");
return 2;
}
memcpy(p, bnbuf, base);
p += base;
memcpy(key, buf, p - buf);
*keysize = p - buf;
return 0;
}
int encode_public_key(RSA *rsa, u8 *key, size_t *keysize)
{
u8 buf[512], *p = buf;
u8 bnbuf[256];
int base = 0;
int r;
switch (BN_num_bits(rsa->n)) {
case 512:
base = 32;
break;
case 768:
base = 48;
break;
case 1024:
base = 64;
break;
case 2048:
base = 128;
break;
}
if (base == 0) {
fprintf(stderr, "Key length invalid.\n");
return 2;
}
*p++ = (5 * base + 7) >> 8;
*p++ = (5 * base + 7) & 0xFF;
*p++ = opt_key_num;
r = bn2cf(rsa->n, bnbuf);
if (r != 2*base) {
fprintf(stderr, "Invalid public key.\n");
return 2;
}
memcpy(p, bnbuf, 2*base);
p += 2*base;
#if 0
mont(rsa, p); /* j0 */
#else
memset(p, 0, base);
#endif
p += base;
memset(bnbuf, 0, 2*base);
memcpy(p, bnbuf, 2*base);
p += 2*base;
r = bn2cf(rsa->e, bnbuf);
memcpy(p, bnbuf, 4);
p += 4;
memcpy(key, buf, p - buf);
*keysize = p - buf;
return 0;
}
int update_public_key(const u8 *key, size_t keysize)
{
int r, idx = 0;
struct sc_path path;
struct sc_file file;
r = select_app_df();
if (r)
return 1;
sc_format_path("I1012", &path);
r = sc_select_file(card, &path, &file);
if (r) {
fprintf(stderr, "Unable to select public key file: %s\n", sc_strerror(r));
return 2;
}
idx = keysize * (opt_key_num-1);
r = sc_update_binary(card, idx, key, keysize, 0);
if (r < 0) {
fprintf(stderr, "Unable to write public key: %s\n", sc_strerror(r));
return 2;
}
return 0;
}
int update_private_key(const u8 *key, size_t keysize)
{
int r, idx = 0;
struct sc_path path;
struct sc_file file;
r = select_app_df();
if (r)
return 1;
sc_format_path("I0012", &path);
r = sc_select_file(card, &path, &file);
if (r) {
fprintf(stderr, "Unable to select private key file: %s\n", sc_strerror(r));
return 2;
}
idx = keysize * (opt_key_num-1);
r = sc_update_binary(card, idx, key, keysize, 0);
if (r < 0) {
fprintf(stderr, "Unable to write private key: %s\n", sc_strerror(r));
return 2;
}
return 0;
}
int store_key(void)
{
u8 prv[1024], pub[1024];
size_t prvsize, pubsize;
int r;
RSA *rsa;
r = read_rsa_privkey(&rsa);
if (r)
return r;
r = encode_private_key(rsa, prv, &prvsize);
if (r)
return r;
r = encode_public_key(rsa, pub, &pubsize);
if (r)
return r;
if (!quiet)
printf("Storing private key...\n");
r = select_app_df();
if (r)
return r;
r = update_private_key(prv, prvsize);
if (r)
return r;
if (!quiet)
printf("Storing public key...\n");
r = select_app_df();
if (r)
return r;
r = update_public_key(pub, pubsize);
if (r)
return r;
return 0;
}
int create_file(struct sc_file *file)
{
struct sc_path path;
int r;
path = file->path;
if (path.len < 2)
return SC_ERROR_INVALID_ARGUMENTS;
ctx->log_errors = 0;
r = sc_select_file(card, &path, NULL);
ctx->log_errors = 1;
if (r == 0)
return 0; /* File already exists */
path.len -= 2;
r = sc_select_file(card, &path, NULL);
if (r) {
fprintf(stderr, "Unable to select parent DF: %s", sc_strerror(r));
return r;
}
file->id = (path.value[path.len] << 8) | (path.value[path.len+1] & 0xFF);
r = sc_create_file(card, file);
if (r)
return r;
r = sc_select_file(card, &file->path, NULL);
if (r) {
fprintf(stderr, "Unable to select created file: %s\n", sc_strerror(r));
return r;
}
return 0;
}
int create_app_df(struct sc_path *path, size_t size)
{
struct sc_file file;
int i;
memset(&file, 0, sizeof(file));
file.type = SC_FILE_TYPE_DF;
file.size = size;
file.path = *path;
for (i = 0; i < SC_MAX_AC_OPS; i++)
file.acl[i] = SC_AC_NONE;
file.acl[SC_AC_OP_CREATE] = SC_AC_CHV2;
file.acl[SC_AC_OP_DELETE] = SC_AC_CHV2;
file.status = SC_FILE_STATUS_ACTIVATED;
return create_file(&file);
}
int new_pkcs15_df(struct sc_pkcs15_card *p15card, int df_type, struct sc_file *file)
{
struct sc_pkcs15_df *df = &p15card->df[df_type];
struct sc_file *newfile;
int c = df->count;
if (c >= SC_PKCS15_MAX_DFS)
return -1;
file->acl[SC_AC_OP_UPDATE] = SC_AC_CHV2;
file->acl[SC_AC_OP_INVALIDATE] = SC_AC_NEVER;
file->acl[SC_AC_OP_REHABILITATE] = SC_AC_NEVER;
newfile = malloc(sizeof(struct sc_file));
if (newfile == NULL)
return -1;
df->file[c] = newfile;
memcpy(newfile, file, sizeof(struct sc_file));
df->count++;
return c;
}
int create_pin_file(const struct sc_path *inpath, int chv, const char *key_id)
{
char prompt[40], *pin, *puk;
char buf[30], *p = buf;
struct sc_path file_id, path;
struct sc_file file;
size_t len;
int r, i;
file_id = *inpath;
if (file_id.len < 2)
return -1;
if (chv == 1)
sc_format_path("I0000", &file_id);
else if (chv == 2)
sc_format_path("I0100", &file_id);
else
return -1;
r = sc_select_file(card, inpath, NULL);
if (r)
return -1;
ctx->log_errors = 0;
r = sc_select_file(card, &file_id, NULL);
ctx->log_errors = 1;
if (r == 0)
return 0;
for (;;) {
#if 0
char *tmp = NULL;
#endif
sprintf(prompt, "Please enter CHV%d%s: ", chv, key_id);
pin = getpin(prompt);
if (pin == NULL)
return -1;
#if 0
sprintf(prompt, "Please enter CHV%d%s again: ", chv, key_id);
tmp = getpin(prompt);
if (tmp == NULL)
return -1;
if (memcmp(pin, tmp, 8) != 0) {
free(pin);
free(tmp);
continue;
}
free(tmp);
#endif
break;
}
for (;;) {
#if 0
char *tmp = NULL;
#endif
sprintf(prompt, "Please enter PUK for CHV%d%s: ", chv, key_id);
puk = getpin(prompt);
if (puk == NULL)
return -1;
#if 0
sprintf(prompt, "Please enter PUK for CHV%d%s again: ", chv, key_id);
tmp = getpin(prompt);
if (tmp == NULL)
return -1;
if (memcmp(puk, tmp, 8) != 0) {
free(puk);
free(tmp);
continue;
}
free(tmp);
#endif
break;
}
memset(p, 0xFF, 3);
p += 3;
memcpy(p, pin, 8);
p += 8;
*p++ = opt_pin_attempts;
*p++ = opt_pin_attempts;
memcpy(p, puk, 8);
p += 8;
*p++ = opt_puk_attempts;
*p++ = opt_puk_attempts;
len = p - buf;
file.type = SC_FILE_TYPE_WORKING_EF;
file.ef_structure = SC_FILE_EF_TRANSPARENT;
for (i = 0; i < SC_MAX_AC_OPS; i++)
file.acl[i] = SC_AC_NONE;
file.acl[SC_AC_OP_READ] = SC_AC_NEVER;
if (inpath->len == 2 && inpath->value[0] == 0x3F &&
inpath->value[1] == 0x00)
file.acl[SC_AC_OP_UPDATE] = SC_AC_AUT | SC_AC_KEY_NUM_1;
else
file.acl[SC_AC_OP_UPDATE] = SC_AC_CHV2;
file.acl[SC_AC_OP_INVALIDATE] = SC_AC_AUT | SC_AC_KEY_NUM_1;
file.acl[SC_AC_OP_REHABILITATE] = SC_AC_AUT | SC_AC_KEY_NUM_1;
file.size = len;
file.id = (file_id.value[0] << 8) | file_id.value[1];
r = sc_create_file(card, &file);
if (r) {
fprintf(stderr, "PIN file creation failed: %s\n", sc_strerror(r));
return r;
}
path = *inpath;
sc_append_path(&path, &file_id);
r = sc_select_file(card, &path, NULL);
if (r) {
fprintf(stderr, "Unable to select created PIN file: %s\n", sc_strerror(r));
return r;
}
r = sc_update_binary(card, 0, (const u8 *) buf, len, 0);
if (r < 0) {
fprintf(stderr, "Unable to update created PIN file: %s\n", sc_strerror(r));
return r;
}
return 0;
}
int add_object(struct sc_pkcs15_card *p15card,
struct sc_pkcs15_df *df, int file_nr,
unsigned int type, void *data, size_t datalen)
{
struct sc_pkcs15_object *obj;
obj = malloc(sizeof(*obj));
if (obj == NULL)
return -1;
obj->type = type;
obj->data = malloc(datalen);
if (obj->data == NULL) {
free(obj);
return -1;
}
memcpy(obj->data, data, datalen);
return sc_pkcs15_add_object(p15card, df, file_nr, obj);
}
int create_pkcs15()
{
struct sc_pkcs15_card *p15card;
struct sc_file file;
struct sc_path path;
struct sc_pkcs15_cert_info cert;
struct sc_pkcs15_pin_info pin;
struct sc_pkcs15_prkey_info prkey;
int i, r, file_no;
p15card = sc_pkcs15_card_new();
if (p15card == NULL)
return 1;
p15card->label = strdup("OpenSC Test Card");
p15card->manufacturer_id = strdup("OpenSC Project");
p15card->serial_number = strdup("1234");
p15card->flags = SC_PKCS15_CARD_FLAG_EID_COMPLIANT;
p15card->version = 1;
sc_format_path("3F005015", &p15card->file_app.path);
p15card->card = card;
memset(&file, 0, sizeof(file));
for (i = 0; i < SC_MAX_AC_OPS; i++)
file.acl[i] = SC_AC_NONE;
file.size = 32;
sc_format_path("3F0050155031", &file.path);
p15card->file_tokeninfo = file;
sc_format_path("3F0050155031", &file.path);
p15card->file_odf = file;
sc_format_path("3F0050154403", &file.path);
file_no = new_pkcs15_df(p15card, SC_PKCS15_CDF, &file);
if (file_no < 0)
return 1;
sc_format_path("3F0050154402", &file.path);
file_no = new_pkcs15_df(p15card, SC_PKCS15_PRKDF, &file);
if (file_no < 0)
return 1;
sc_format_path("3F0050154401", &file.path);
file_no = new_pkcs15_df(p15card, SC_PKCS15_AODF, &file);
if (file_no < 0)
return 1;
memset(&cert, 0, sizeof(cert));
strcpy(cert.com_attr.label, "Authentication certificate");
sc_pkcs15_format_id("45", &cert.id);
sc_format_path("3F0050154301", &cert.path);
add_object(p15card, &p15card->df[SC_PKCS15_CDF], file_no,
SC_PKCS15_TYPE_CERT_X509, &cert, sizeof(cert)),
strcpy(cert.com_attr.label, "Non-repudiation certificate");
sc_pkcs15_format_id("46", &cert.id);
sc_format_path("3F0050154302", &cert.path);
add_object(p15card, &p15card->df[SC_PKCS15_CDF], file_no,
SC_PKCS15_TYPE_CERT_X509, &cert, sizeof(cert)),
memset(&prkey, 0, sizeof(prkey));
prkey.modulus_length = opt_mod_length;
prkey.com_attr.flags = 1;
prkey.native = 1;
strcpy(prkey.com_attr.label, "Authentication key");
sc_pkcs15_format_id("45", &prkey.id);
sc_pkcs15_format_id("01", &prkey.com_attr.auth_id);
sc_format_path("0012", &prkey.path);
prkey.key_reference = 0;
prkey.usage = SC_PKCS15_PRKEY_USAGE_SIGN;
prkey.access_flags = 0x1D;
add_object(p15card, &p15card->df[SC_PKCS15_PRKDF], file_no,
SC_PKCS15_TYPE_PRKEY_RSA, &prkey, sizeof(prkey)),
strcpy(prkey.com_attr.label, "Non-repudiation key");
sc_pkcs15_format_id("46", &prkey.id);
sc_pkcs15_format_id("02", &prkey.com_attr.auth_id);
sc_format_path("3F004B020012", &prkey.path);
prkey.key_reference = 0;
prkey.usage = SC_PKCS15_PRKEY_USAGE_NONREPUDIATION;
prkey.access_flags = 0x1D;
add_object(p15card, &p15card->df[SC_PKCS15_PRKDF], file_no,
SC_PKCS15_TYPE_PRKEY_RSA, &prkey, sizeof(prkey)),
memset(&pin, 0, sizeof(pin));
pin.com_attr.flags = 0x03;
pin.magic = SC_PKCS15_PIN_MAGIC;
strcpy(pin.com_attr.label, "Authentication PIN");
sc_pkcs15_format_id("01", &pin.auth_id);
sc_format_path("3F005015", &pin.path);
pin.reference = 1;
pin.flags = 0x32;
pin.min_length = 4;
pin.stored_length = 8;
pin.pad_char = 0x00;
pin.type = 1;
add_object(p15card, &p15card->df[SC_PKCS15_AODF], file_no,
SC_PKCS15_TYPE_AUTH_PIN, &pin, sizeof(pin)),
strcpy(pin.com_attr.label, "Non-repuditiation PIN");
sc_pkcs15_format_id("02", &pin.auth_id);
sc_format_path("3F004B02", &pin.path);
pin.reference = 1;
pin.flags = 0x32;
pin.min_length = 4;
pin.stored_length = 8;
pin.pad_char = 0x00;
pin.type = 1;
add_object(p15card, &p15card->df[SC_PKCS15_AODF], file_no,
SC_PKCS15_TYPE_AUTH_PIN, &pin, sizeof(pin)),
r = create_app_df(&p15card->file_app.path, 5000);
if (r) {
fprintf(stderr, "Unable to create app DF: %s\n", sc_strerror(r));
return 1;
}
r = create_pin_file(&p15card->file_app.path, 1, " (key 1)");
if (r)
return 1;
sc_format_path("3F004B02", &path);
r = create_app_df(&path, 1000);
if (r) {
fprintf(stderr, "Unable to create DF for key 2: %s\n", sc_strerror(r));
return 1;
}
r = create_pin_file(&path, 1, " (key 2)");
if (r)
return 1;
r = sc_pkcs15_create(p15card, card);
sc_pkcs15_card_free(p15card);
if (r) {
fprintf(stderr, "PKCS #15 structure creation failed: %s\n", sc_strerror(r));
return 1;
}
return 0;
}
int create_pin()
{
struct sc_path path;
char buf[80];
if (opt_pin_num != 1 && opt_pin_num != 2) {
fprintf(stderr, "Invalid PIN number. Possible values: 1, 2.\n");
return 2;
}
strcpy(buf, "3F00");
if (opt_appdf != NULL)
strcat(buf, opt_appdf);
sc_format_path(buf, &path);
return create_pin_file(&path, opt_pin_num, "");
}
int main(int argc, char * const argv[])
{
int err = 0, r, c, long_optind = 0;
int action_count = 0;
int do_read_key = 0;
int do_generate_key = 0;
int do_create_key_files = 0;
int do_list_keys = 0;
int do_store_key = 0;
int do_create_pin_file = 0;
int do_create_pkcs15 = 0;
while (1) {
c = getopt_long(argc, argv, "P:Cvslgc:Rk:r:p:u:e:m:dqa:", options, &long_optind);
if (c == -1)
break;
if (c == '?')
print_usage_and_die("cryptoflex-tool");
switch (c) {
case 'C':
do_create_pkcs15 = 1;
action_count++;
break;
case 'l':
do_list_keys = 1;
action_count++;
break;
case 'P':
do_create_pin_file = 1;
opt_pin_num = atoi(optarg);
action_count++;
break;
case 'R':
do_read_key = 1;
action_count++;
break;
case 'g':
do_generate_key = 1;
action_count++;
break;
case 'c':
do_create_key_files = 1;
opt_key_count = atoi(optarg);
action_count++;
break;
case 's':
do_store_key = 1;
action_count++;
break;
case 'k':
opt_key_num = atoi(optarg);
if (opt_key_num < 1 || opt_key_num > 15) {
fprintf(stderr, "Key number invalid.\n");
exit(2);
}
break;
case 'v':
opt_pin_num = 1;
break;
case 'e':
opt_exponent = atoi(optarg);
break;
case 'm':
opt_mod_length = atoi(optarg);
break;
case 'p':
opt_prkeyf = optarg;
break;
case 'u':
opt_pubkeyf = optarg;
break;
case 'r':
opt_reader = atoi(optarg);
break;
case 'q':
quiet++;
break;
case 'd':
opt_debug++;
break;
case 'a':
opt_appdf = optarg;
break;
}
}
if (action_count == 0)
print_usage_and_die("cryptoflex-tool");
r = sc_establish_context(&ctx);
if (r) {
fprintf(stderr, "Failed to establish context: %s\n", sc_strerror(r));
return 1;
}
ctx->error_file = stderr;
ctx->debug_file = stdout;
ctx->debug = opt_debug;
if (opt_reader >= ctx->reader_count || opt_reader < 0) {
fprintf(stderr, "Illegal reader number. Only %d reader(s) configured.\n", ctx->reader_count);
err = 1;
goto end;
}
if (sc_detect_card(ctx, opt_reader) != 1) {
fprintf(stderr, "Card not present.\n");
err = 3;
goto end;
}
if (!quiet)
fprintf(stderr, "Connecting to card in reader %s...\n", ctx->readers[opt_reader]);
r = sc_connect_card(ctx, opt_reader, &card);
if (r) {
fprintf(stderr, "Failed to connect to card: %s\n", sc_strerror(r));
err = 1;
goto end;
}
printf("Using card driver: %s\n", card->driver->name);
r = sc_lock(card);
if (r) {
fprintf(stderr, "Unable to lock card: %s\n", sc_strerror(r));
err = 1;
goto end;
}
if (do_create_pkcs15) {
if ((err = create_pkcs15()) != 0)
goto end;
action_count--;
}
if (do_create_pin_file) {
if ((err = create_pin()) != 0)
goto end;
action_count--;
}
if (do_create_key_files) {
if ((err = create_key_files()) != 0)
goto end;
action_count--;
}
if (do_generate_key) {
if ((err = generate_key()) != 0)
goto end;
action_count--;
}
if (do_store_key) {
if ((err = store_key()) != 0)
goto end;
action_count--;
}
if (do_list_keys) {
if ((err = list_keys()) != 0)
goto end;
action_count--;
}
if (do_read_key) {
if ((err = read_key()) != 0)
goto end;
action_count--;
}
if (pincode != NULL) {
memset(pincode, 0, 8);
free(pincode);
}
end:
if (card) {
sc_unlock(card);
sc_disconnect_card(card);
}
if (ctx)
sc_destroy_context(ctx);
return err;
}