2002-04-02 13:26:42 +00:00
|
|
|
|
/*
|
|
|
|
|
* Cryptoflex specific operation for PKCS #15 initialization
|
|
|
|
|
*
|
|
|
|
|
* Copyright (C) 2002 Juha Yrj<EFBFBD>l<EFBFBD> <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
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
|
#include <config.h>
|
|
|
|
|
#endif
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <openssl/bn.h>
|
|
|
|
|
#include "opensc.h"
|
|
|
|
|
#include "pkcs15-init.h"
|
2002-04-04 22:10:36 +00:00
|
|
|
|
#include "profile.h"
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Initialize the Application DF
|
|
|
|
|
*/
|
|
|
|
|
static int cflex_init_app(struct sc_profile *profile, struct sc_card *card,
|
|
|
|
|
const u8 *pin, size_t pin_len, const u8 *puk, size_t puk_len)
|
|
|
|
|
{
|
|
|
|
|
/* Create the application DF */
|
|
|
|
|
if (sc_pkcs15init_create_file(profile, card, profile->df_info->file))
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2002-04-02 13:26:42 +00:00
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Update the contents of a PIN file
|
|
|
|
|
*/
|
2002-04-04 22:10:36 +00:00
|
|
|
|
static int cflex_update_pin(struct sc_profile *profile, struct sc_card *card,
|
|
|
|
|
sc_file_t *file,
|
|
|
|
|
const u8 *pin, size_t pin_len, int pin_tries,
|
|
|
|
|
const u8 *puk, size_t puk_len, int puk_tries)
|
2002-04-02 13:26:42 +00:00
|
|
|
|
{
|
|
|
|
|
u8 buffer[23], *p = buffer;
|
|
|
|
|
int r;
|
|
|
|
|
size_t len;
|
|
|
|
|
|
|
|
|
|
memset(p, 0xFF, 3);
|
|
|
|
|
p += 3;
|
2002-04-04 22:10:36 +00:00
|
|
|
|
memset(p, profile->pin_pad_char, 8);
|
|
|
|
|
strncpy((char *) p, pin, pin_len);
|
2002-04-02 13:26:42 +00:00
|
|
|
|
p += 8;
|
2002-04-04 22:10:36 +00:00
|
|
|
|
*p++ = pin_tries;
|
|
|
|
|
*p++ = pin_tries;
|
|
|
|
|
memset(p, profile->pin_pad_char, 8);
|
|
|
|
|
strncpy((char *) p, puk, puk_len);
|
2002-04-02 13:26:42 +00:00
|
|
|
|
p += 8;
|
2002-04-04 22:10:36 +00:00
|
|
|
|
*p++ = puk_tries;
|
|
|
|
|
*p++ = puk_tries;
|
2002-04-02 13:26:42 +00:00
|
|
|
|
len = 23;
|
|
|
|
|
|
2002-04-04 22:10:36 +00:00
|
|
|
|
r = sc_pkcs15init_update_file(profile, card, file, buffer, len);
|
2002-04-02 13:26:42 +00:00
|
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
2002-04-04 22:10:36 +00:00
|
|
|
|
* Store a PIN
|
2002-04-02 13:26:42 +00:00
|
|
|
|
*/
|
2002-04-04 22:10:36 +00:00
|
|
|
|
static int
|
|
|
|
|
cflex_new_pin(struct sc_profile *profile, struct sc_card *card,
|
|
|
|
|
struct sc_pkcs15_pin_info *info, unsigned int index,
|
|
|
|
|
const u8 *pin, size_t pin_len,
|
|
|
|
|
const u8 *puk, size_t puk_len)
|
2002-04-02 13:26:42 +00:00
|
|
|
|
{
|
2002-04-04 22:10:36 +00:00
|
|
|
|
sc_file_t *pinfile;
|
|
|
|
|
struct sc_pkcs15_pin_info tmpinfo;
|
|
|
|
|
char template[30];
|
|
|
|
|
int pin_tries, puk_tries;
|
2002-04-02 13:26:42 +00:00
|
|
|
|
int r;
|
|
|
|
|
|
2002-04-04 22:10:36 +00:00
|
|
|
|
index++;
|
|
|
|
|
sprintf(template, "pinfile-%d", index);
|
|
|
|
|
/* Profile must define a "pinfile" for each PIN */
|
|
|
|
|
if (sc_profile_get_file(profile, template, &pinfile) < 0) {
|
|
|
|
|
profile->cbs->error("Profile doesn't define \"%s\"", template);
|
|
|
|
|
return SC_ERROR_INVALID_ARGUMENTS;
|
2002-04-02 13:26:42 +00:00
|
|
|
|
}
|
2002-04-04 22:10:36 +00:00
|
|
|
|
info->path = pinfile->path;
|
|
|
|
|
if (info->path.len > 2)
|
|
|
|
|
info->path.len -= 2;
|
|
|
|
|
info->reference = 1;
|
|
|
|
|
if (pin_len > 8)
|
|
|
|
|
pin_len = 8;
|
|
|
|
|
if (puk_len > 8)
|
|
|
|
|
puk_len = 8;
|
|
|
|
|
sc_profile_get_pin_info(profile, SC_PKCS15INIT_USER_PIN, &tmpinfo);
|
|
|
|
|
pin_tries = tmpinfo.tries_left;
|
|
|
|
|
sc_profile_get_pin_info(profile, SC_PKCS15INIT_USER_PUK, &tmpinfo);
|
|
|
|
|
puk_tries = tmpinfo.tries_left;
|
2002-04-02 13:26:42 +00:00
|
|
|
|
|
2002-04-04 22:10:36 +00:00
|
|
|
|
r = cflex_update_pin(profile, card, pinfile, pin, pin_len, pin_tries,
|
|
|
|
|
puk, puk_len, puk_tries);
|
|
|
|
|
sc_file_free(pinfile);
|
|
|
|
|
return r;
|
2002-04-02 13:26:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Allocate a file
|
|
|
|
|
*/
|
2002-04-04 22:10:36 +00:00
|
|
|
|
static int
|
|
|
|
|
cflex_new_file(struct sc_profile *profile, struct sc_card *card,
|
2002-04-02 13:26:42 +00:00
|
|
|
|
unsigned int type, unsigned int num,
|
|
|
|
|
struct sc_file **out)
|
|
|
|
|
{
|
2002-04-04 22:10:36 +00:00
|
|
|
|
struct sc_file *file;
|
|
|
|
|
char name[64], *tag, *desc;
|
2002-04-02 13:26:42 +00:00
|
|
|
|
|
|
|
|
|
desc = tag = NULL;
|
|
|
|
|
while (1) {
|
|
|
|
|
switch (type) {
|
|
|
|
|
case SC_PKCS15_TYPE_PRKEY_RSA:
|
|
|
|
|
desc = "RSA private key";
|
|
|
|
|
tag = "private-key";
|
|
|
|
|
break;
|
|
|
|
|
case SC_PKCS15_TYPE_PUBKEY_RSA:
|
|
|
|
|
desc = "RSA public key";
|
|
|
|
|
tag = "public-key";
|
|
|
|
|
break;
|
|
|
|
|
case SC_PKCS15_TYPE_CERT:
|
|
|
|
|
desc = "certificate";
|
2002-04-04 22:10:36 +00:00
|
|
|
|
tag = "certificate";
|
2002-04-02 13:26:42 +00:00
|
|
|
|
break;
|
|
|
|
|
case SC_PKCS15_TYPE_DATA_OBJECT:
|
|
|
|
|
desc = "data object";
|
|
|
|
|
tag = "data";
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (tag)
|
|
|
|
|
break;
|
|
|
|
|
/* If this is a specific type such as
|
|
|
|
|
* SC_PKCS15_TYPE_CERT_FOOBAR, fall back to
|
|
|
|
|
* the generic class (SC_PKCS15_TYPE_CERT)
|
|
|
|
|
*/
|
|
|
|
|
if (!(type & ~SC_PKCS15_TYPE_CLASS_MASK)) {
|
2002-04-04 22:10:36 +00:00
|
|
|
|
profile->cbs->error("File type not supported by card driver");
|
2002-04-02 13:26:42 +00:00
|
|
|
|
return SC_ERROR_INVALID_ARGUMENTS;
|
|
|
|
|
}
|
|
|
|
|
type &= SC_PKCS15_TYPE_CLASS_MASK;
|
|
|
|
|
}
|
|
|
|
|
|
2002-04-04 22:10:36 +00:00
|
|
|
|
snprintf(name, sizeof(name), "template-%s-%d", tag, num+1);
|
|
|
|
|
if (sc_profile_get_file(profile, name, &file) < 0) {
|
|
|
|
|
profile->cbs->error("Profile doesn't define %s template '%s'\n",
|
2002-04-02 13:26:42 +00:00
|
|
|
|
desc, name);
|
|
|
|
|
return SC_ERROR_NOT_SUPPORTED;
|
|
|
|
|
}
|
|
|
|
|
|
2002-04-04 22:10:36 +00:00
|
|
|
|
*out = file;
|
2002-04-02 13:26:42 +00:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static 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];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static 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
|
|
|
|
|
static 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;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
static int cflex_encode_private_key(RSA *rsa, u8 *key, size_t *keysize, int key_num)
|
|
|
|
|
{
|
|
|
|
|
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++ = 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;
|
|
|
|
|
*p++ = 0;
|
|
|
|
|
*p++ = 0;
|
|
|
|
|
*p++ = 0;
|
|
|
|
|
|
|
|
|
|
memcpy(key, buf, p - buf);
|
|
|
|
|
*keysize = p - buf;
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int cflex_encode_public_key(RSA *rsa, u8 *key, size_t *keysize, int key_num)
|
|
|
|
|
{
|
|
|
|
|
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++ = 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;
|
|
|
|
|
|
|
|
|
|
memset(p, 0, base);
|
|
|
|
|
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;
|
|
|
|
|
*p++ = 0;
|
|
|
|
|
*p++ = 0;
|
|
|
|
|
*p++ = 0;
|
|
|
|
|
|
|
|
|
|
memcpy(key, buf, p - buf);
|
|
|
|
|
*keysize = p - buf;
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
2002-04-04 22:10:36 +00:00
|
|
|
|
* Store a private key
|
2002-04-02 13:26:42 +00:00
|
|
|
|
*/
|
2002-04-04 22:10:36 +00:00
|
|
|
|
static int
|
|
|
|
|
cflex_new_key(struct sc_profile *profile, struct sc_card *card,
|
|
|
|
|
EVP_PKEY *key, unsigned int index,
|
|
|
|
|
struct sc_pkcs15_prkey_info *info)
|
2002-04-02 13:26:42 +00:00
|
|
|
|
{
|
|
|
|
|
u8 prv[1024], pub[1024];
|
|
|
|
|
size_t prvsize, pubsize;
|
2002-04-04 22:10:36 +00:00
|
|
|
|
struct sc_file *keyfile = NULL, *tmpfile = NULL;
|
|
|
|
|
RSA *rsa = NULL;
|
2002-04-02 13:26:42 +00:00
|
|
|
|
int r;
|
|
|
|
|
|
2002-04-04 22:10:36 +00:00
|
|
|
|
if (key->type != EVP_PKEY_RSA) {
|
|
|
|
|
profile->cbs->error("Cryptoflex supports only RSA keys.");
|
|
|
|
|
return SC_ERROR_NOT_SUPPORTED;
|
|
|
|
|
}
|
|
|
|
|
rsa = EVP_PKEY_get1_RSA(key);
|
2002-04-02 13:26:42 +00:00
|
|
|
|
r = cflex_encode_private_key(rsa, prv, &prvsize, 1);
|
|
|
|
|
if (r)
|
2002-04-04 22:10:36 +00:00
|
|
|
|
goto err;
|
2002-04-02 13:26:42 +00:00
|
|
|
|
r = cflex_encode_public_key(rsa, pub, &pubsize, 1);
|
|
|
|
|
if (r)
|
2002-04-04 22:10:36 +00:00
|
|
|
|
goto err;
|
2002-04-02 13:26:42 +00:00
|
|
|
|
printf("Updating RSA private key...\n");
|
2002-04-04 22:10:36 +00:00
|
|
|
|
r = cflex_new_file(profile, card, SC_PKCS15_TYPE_PRKEY_RSA, index,
|
|
|
|
|
&keyfile);
|
2002-04-02 13:26:42 +00:00
|
|
|
|
if (r < 0)
|
2002-04-04 22:10:36 +00:00
|
|
|
|
goto err;
|
|
|
|
|
keyfile->size = prvsize;
|
|
|
|
|
r = sc_pkcs15init_update_file(profile, card, keyfile, prv, prvsize);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
goto err;
|
|
|
|
|
info->path = keyfile->path;
|
|
|
|
|
info->modulus_length = RSA_size(rsa)*8;
|
|
|
|
|
sc_file_dup(&tmpfile, keyfile);
|
2002-04-02 13:26:42 +00:00
|
|
|
|
sc_file_clear_acl_entries(tmpfile, SC_AC_OP_READ);
|
|
|
|
|
sc_file_add_acl_entry(tmpfile, SC_AC_OP_READ, SC_AC_NONE, SC_AC_KEY_REF_NONE);
|
|
|
|
|
tmpfile->path.len -= 2;
|
|
|
|
|
sc_append_path_id(&tmpfile->path, (const u8 *) "\x10\x12", 2);
|
|
|
|
|
tmpfile->id = 0x1012;
|
|
|
|
|
tmpfile->size = pubsize;
|
|
|
|
|
printf("Updating RSA public key...\n");
|
|
|
|
|
r = sc_pkcs15init_update_file(profile, card, tmpfile, pub, pubsize);
|
2002-04-04 22:10:36 +00:00
|
|
|
|
err:
|
|
|
|
|
if (rsa)
|
|
|
|
|
RSA_free(rsa);
|
|
|
|
|
if (tmpfile)
|
|
|
|
|
sc_file_free(tmpfile);
|
|
|
|
|
return r;
|
2002-04-02 13:26:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
2002-04-04 22:10:36 +00:00
|
|
|
|
struct sc_pkcs15init_operations sc_pkcs15init_cflex_operations = {
|
|
|
|
|
NULL,
|
|
|
|
|
cflex_init_app,
|
|
|
|
|
cflex_new_pin,
|
|
|
|
|
cflex_new_key,
|
|
|
|
|
cflex_new_file,
|
|
|
|
|
};
|