opensc/src/pkcs15init/pkcs15-jcop.c

358 lines
10 KiB
C
Raw Normal View History

/*
* JCOP specific operation for PKCS15 initialization
*
* Copyright 2003 Chaskiel Grundman <cg2v@andrew.cmu.edu>
* Copyright (C) 2002 Olaf Kirch <okir@suse.de>
*
* 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 "config.h"
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <stdarg.h>
#include "libopensc/opensc.h"
#include "libopensc/cardctl.h"
#include "libopensc/log.h"
#include "pkcs15-init.h"
#include "profile.h"
#define JCOP_MAX_PINS 3
/*
* Erase the card
*/
static int
jcop_erase_card(struct sc_profile *pro, sc_pkcs15_card_t *p15card) {
/* later */
return SC_ERROR_NOT_SUPPORTED;
}
static int
jcop_create_dir(sc_profile_t *profile, sc_pkcs15_card_t *p15card, sc_file_t *file)
{
return SC_ERROR_NOT_SUPPORTED;
};
/*
* Select a PIN reference
*/
static int
jcop_select_pin_reference(sc_profile_t *profile, sc_pkcs15_card_t *p15card,
sc_pkcs15_auth_info_t *auth_info) {
int preferred, current;
if (auth_info->auth_type != SC_PKCS15_PIN_AUTH_TYPE_PIN)
return SC_ERROR_OBJECT_NOT_VALID;
if ((current = auth_info->attrs.pin.reference) < 0)
current = 0;
if (auth_info->attrs.pin.flags & SC_PKCS15_PIN_FLAG_SO_PIN) {
preferred = 3;
} else {
preferred = current;
if (preferred < 1)
preferred=1;
if (preferred > 2)
return SC_ERROR_TOO_MANY_OBJECTS;
}
if (current > preferred)
return SC_ERROR_TOO_MANY_OBJECTS;
auth_info->attrs.pin.reference = preferred;
return 0;
}
/*
* Store a PIN
*/
static int
jcop_create_pin(sc_profile_t *profile, sc_pkcs15_card_t *p15card, sc_file_t *df,
sc_pkcs15_object_t *pin_obj,
const unsigned char *pin, size_t pin_len,
const unsigned char *puk, size_t puk_len)
{
sc_pkcs15_auth_info_t *auth_info = (sc_pkcs15_auth_info_t *) pin_obj->data;
struct sc_pkcs15_pin_attributes *pin_attrs = &auth_info->attrs.pin;
unsigned char nulpin[16];
unsigned char padpin[16];
int r;
if (auth_info->auth_type != SC_PKCS15_PIN_AUTH_TYPE_PIN)
return SC_ERROR_OBJECT_NOT_VALID;
if (pin_attrs->flags & SC_PKCS15_PIN_FLAG_SO_PIN) {
/* SO PIN reference must be 0 */
if (pin_attrs->reference != 3)
return SC_ERROR_INVALID_ARGUMENTS;
} else {
if (pin_attrs->reference >= 3)
return SC_ERROR_TOO_MANY_OBJECTS;
}
if (puk != NULL && puk_len > 0) {
return SC_ERROR_NOT_SUPPORTED;
}
r = sc_select_file(p15card->card, &df->path, NULL);
if (r < 0)
return r;
/* Current PIN is 00:00:00:00:00:00:00:00... */
memset(nulpin, 0, sizeof(nulpin));
memset(padpin, 0, sizeof(padpin));
memcpy(padpin, pin, pin_len);
r = sc_change_reference_data(p15card->card, SC_AC_CHV,
pin_attrs->reference,
nulpin, sizeof(nulpin),
padpin, sizeof(padpin), NULL);
if (r < 0)
return r;
pin_attrs->flags &= ~SC_PKCS15_PIN_FLAG_LOCAL;
return r;
}
/*
* Create a new key file
*/
static int
jcop_create_key(sc_profile_t *profile, sc_pkcs15_card_t *p15card, sc_pkcs15_object_t *obj)
{
sc_pkcs15_prkey_info_t *key_info = (sc_pkcs15_prkey_info_t *) obj->data;
sc_file_t *keyfile = NULL;
size_t bytes, mod_len, prv_len;
int r;
if (obj->type != SC_PKCS15_TYPE_PRKEY_RSA) {
2018-11-22 08:31:29 +00:00
sc_log(p15card->card->ctx, "JCOP supports only RSA keys.");
return SC_ERROR_NOT_SUPPORTED;
}
/* The caller is supposed to have chosen a key file path for us */
if (key_info->path.len == 0 || key_info->modulus_length == 0)
return SC_ERROR_INVALID_ARGUMENTS;
/* Get the file we're supposed to create */
r = sc_profile_get_file_by_path(profile, &key_info->path, &keyfile);
if (r < 0)
return r;
mod_len = key_info->modulus_length / 8;
bytes = mod_len / 2;
prv_len = 2 + 5 * bytes;
keyfile->size = prv_len;
/* Fix up PIN references in file ACL */
r = sc_pkcs15init_fixup_file(profile, p15card, keyfile);
if (r >= 0)
r = sc_pkcs15init_create_file(profile, p15card, keyfile);
sc_file_free(keyfile);
return r;
}
static void
jcop_bn2bin(unsigned char *dest, sc_pkcs15_bignum_t *bn, unsigned int size)
{
u8 *src;
unsigned int n;
assert(bn->len <= size);
memset(dest, 0, size);
for (n = size-bn->len, src = bn->data; n < size; n++,src++)
dest[n] = *src;
}
/*
* Store a private key
* Private key file formats: (transparent file)
* Non-CRT:
* byte 0 0x05
* byte 1 Modulus length (in byte/4)
* byte 2 Modulus (n)
* byte 2+x private exponent (d)
*
* CRT:
* byte 0 0x06
* byte 1 component length (in byte/2; component length is half
* of modulus length
* byte 2 Prime (p)
* byte 2+x Prime (q)
* byte 2+2*x Exponent 1 (d mod (p-1))
* byte 2+3*x Exponent 2 (d mod (q-1))
* byte 2+4*x Coefficient ((p ^ -1) mod q
*
* We use the CRT format, since that's what key generation does.
*
* Numbers are stored big endian.
*/
static int
jcop_store_key(sc_profile_t *profile, sc_pkcs15_card_t *p15card,
sc_pkcs15_object_t *obj,
sc_pkcs15_prkey_t *key)
{
sc_pkcs15_prkey_info_t *key_info = (sc_pkcs15_prkey_info_t *) obj->data;
sc_file_t *keyfile;
unsigned char keybuf[1024];
size_t size,base;
int r;
if (obj->type != SC_PKCS15_TYPE_PRKEY_RSA) {
2018-11-22 08:31:29 +00:00
sc_log(p15card->card->ctx, "JCOP supports only RSA keys.");
return SC_ERROR_NOT_SUPPORTED;
}
r = sc_profile_get_file_by_path(profile, &key_info->path, &keyfile);
if (r < 0)
return r;
base=key_info->modulus_length / 16;
size=2+5*base;
keybuf[0]=6;
keybuf[1]=base/4;
jcop_bn2bin(&keybuf[2 + 0 * base], &key->u.rsa.p, base);
jcop_bn2bin(&keybuf[2 + 1 * base], &key->u.rsa.q, base);
jcop_bn2bin(&keybuf[2 + 2 * base], &key->u.rsa.dmp1, base);
jcop_bn2bin(&keybuf[2 + 3 * base], &key->u.rsa.dmq1, base);
jcop_bn2bin(&keybuf[2 + 4 * base], &key->u.rsa.iqmp, base);
r = sc_pkcs15init_update_file(profile, p15card, keyfile, keybuf, size);
sc_file_free(keyfile);
return r;
}
/*
* Generate a key pair
*/
static int
jcop_generate_key(sc_profile_t *profile, sc_pkcs15_card_t *p15card,
sc_pkcs15_object_t *obj,
sc_pkcs15_pubkey_t *pubkey)
{
sc_pkcs15_prkey_info_t *key_info = (sc_pkcs15_prkey_info_t *) obj->data;
struct sc_cardctl_jcop_genkey args;
sc_file_t *temppubfile=NULL, *keyfile=NULL;
unsigned char *keybuf=NULL;
size_t mod_len, exp_len, pub_len, keybits;
int r,delete_ok=0;
if (obj->type != SC_PKCS15_TYPE_PRKEY_RSA) {
2018-11-22 08:31:29 +00:00
sc_log(p15card->card->ctx, "JCOP supports only RSA keys.");
return SC_ERROR_NOT_SUPPORTED;
}
r=sc_profile_get_file(profile, "temp-pubkey", &temppubfile);
if (r < 0)
goto out;
r = sc_select_file(p15card->card, &key_info->path, &keyfile);
if (r < 0)
goto out;
mod_len = key_info->modulus_length / 8;
exp_len = 4;
pub_len = 2 + mod_len + exp_len;
temppubfile->size = pub_len;
r = sc_pkcs15init_fixup_file(profile, p15card, temppubfile);
if (r < 0)
goto out;
r = sc_pkcs15init_create_file(profile, p15card, temppubfile);
if (r < 0)
goto out;
delete_ok=1;
r = sc_pkcs15init_authenticate(profile, p15card, temppubfile, SC_AC_OP_UPDATE);
if (r < 0)
goto out;
r = sc_pkcs15init_authenticate(profile, p15card, keyfile, SC_AC_OP_UPDATE);
if (r < 0)
goto out;
keybits = key_info->modulus_length;
/* generate key */
/* keysize is _not_ passed to the card at any point. it appears to
infer it from the file size */
memset(&args, 0, sizeof(args));
args.exponent = 0x10001;
sc_append_file_id(&args.pub_file_ref, temppubfile->id);
sc_append_file_id(&args.pri_file_ref, keyfile->id);
Do not cast the return value of malloc(3) and calloc(3) From http://en.wikipedia.org/wiki/Malloc#Casting_and_type_safety " Casting and type safety malloc returns a void pointer (void *), which indicates that it is a pointer to a region of unknown data type. One may "cast" (see type conversion) this pointer to a specific type, as in int *ptr = (int*)malloc(10 * sizeof (int)); When using C, this is considered bad practice; it is redundant under the C standard. Moreover, putting in a cast may mask failure to include the header stdlib.h, in which the prototype for malloc is found. In the absence of a prototype for malloc, the C compiler will assume that malloc returns an int, and will issue a warning in a context such as the above, provided the error is not masked by a cast. On certain architectures and data models (such as LP64 on 64 bit systems, where long and pointers are 64 bit and int is 32 bit), this error can actually result in undefined behavior, as the implicitly declared malloc returns a 32 bit value whereas the actually defined function returns a 64 bit value. Depending on calling conventions and memory layout, this may result in stack smashing. The returned pointer need not be explicitly cast to a more specific pointer type, since ANSI C defines an implicit conversion between the void pointer type and other pointers to objects. An explicit cast of malloc's return value is sometimes performed because malloc originally returned a char *, but this cast is unnecessary in standard C code.[4][5] Omitting the cast, however, creates an incompatibility with C++, which does require it. The lack of a specific pointer type returned from malloc is type-unsafe behaviour: malloc allocates based on byte count but not on type. This distinguishes it from the C++ new operator that returns a pointer whose type relies on the operand. (see C Type Safety). " See also http://www.opensc-project.org/pipermail/opensc-devel/2010-August/014586.html git-svn-id: https://www.opensc-project.org/svnp/opensc/trunk@4636 c6295689-39f2-0310-b995-f0e70906c6a9
2010-08-18 15:08:51 +00:00
keybuf = malloc(keybits / 8);
if (!keybuf) {
r=SC_ERROR_OUT_OF_MEMORY;
goto out;
}
args.pubkey = keybuf;
args.pubkey_len = keybits / 8;
r = sc_card_ctl(p15card->card, SC_CARDCTL_JCOP_GENERATE_KEY, (void *)&args);
if (r < 0)
goto out;
/* extract public key */
pubkey->algorithm = SC_ALGORITHM_RSA;
pubkey->u.rsa.modulus.len = keybits / 8;
pubkey->u.rsa.modulus.data = keybuf;
pubkey->u.rsa.exponent.len = 3;
Do not cast the return value of malloc(3) and calloc(3) From http://en.wikipedia.org/wiki/Malloc#Casting_and_type_safety " Casting and type safety malloc returns a void pointer (void *), which indicates that it is a pointer to a region of unknown data type. One may "cast" (see type conversion) this pointer to a specific type, as in int *ptr = (int*)malloc(10 * sizeof (int)); When using C, this is considered bad practice; it is redundant under the C standard. Moreover, putting in a cast may mask failure to include the header stdlib.h, in which the prototype for malloc is found. In the absence of a prototype for malloc, the C compiler will assume that malloc returns an int, and will issue a warning in a context such as the above, provided the error is not masked by a cast. On certain architectures and data models (such as LP64 on 64 bit systems, where long and pointers are 64 bit and int is 32 bit), this error can actually result in undefined behavior, as the implicitly declared malloc returns a 32 bit value whereas the actually defined function returns a 64 bit value. Depending on calling conventions and memory layout, this may result in stack smashing. The returned pointer need not be explicitly cast to a more specific pointer type, since ANSI C defines an implicit conversion between the void pointer type and other pointers to objects. An explicit cast of malloc's return value is sometimes performed because malloc originally returned a char *, but this cast is unnecessary in standard C code.[4][5] Omitting the cast, however, creates an incompatibility with C++, which does require it. The lack of a specific pointer type returned from malloc is type-unsafe behaviour: malloc allocates based on byte count but not on type. This distinguishes it from the C++ new operator that returns a pointer whose type relies on the operand. (see C Type Safety). " See also http://www.opensc-project.org/pipermail/opensc-devel/2010-August/014586.html git-svn-id: https://www.opensc-project.org/svnp/opensc/trunk@4636 c6295689-39f2-0310-b995-f0e70906c6a9
2010-08-18 15:08:51 +00:00
pubkey->u.rsa.exponent.data = malloc(3);
if (!pubkey->u.rsa.exponent.data) {
pubkey->u.rsa.modulus.data = NULL;
r=SC_ERROR_OUT_OF_MEMORY;
goto out;
}
memcpy(pubkey->u.rsa.exponent.data, "\x01\x00\x01", 3);
out:
if (r < 0 && keybuf)
free(keybuf);
if (delete_ok)
sc_pkcs15init_rmdir(p15card, profile, temppubfile);
sc_file_free(keyfile);
sc_file_free(temppubfile);
return r;
}
static struct sc_pkcs15init_operations sc_pkcs15init_jcop_operations = {
jcop_erase_card,
NULL, /* init_card */
jcop_create_dir,
NULL, /* create_domain */
jcop_select_pin_reference,
jcop_create_pin,
NULL, /* select_key_reference */
jcop_create_key,
jcop_store_key,
jcop_generate_key,
NULL, NULL, /* encode private/public key */
NULL, /* finalize_card */
NULL, /* delete_object */
NULL, NULL, NULL, NULL, NULL, /* pkcs15init emulation */
NULL /* sanity_check */
};
struct sc_pkcs15init_operations *sc_pkcs15init_get_jcop_ops(void)
{
return &sc_pkcs15init_jcop_operations;
}