891f98363b
the first usage is to update the public key PKCS#15 object attributes and to encode it's direct value. (support of the Oberthur's AuthentIC V3.2 card) git-svn-id: https://www.opensc-project.org/svnp/opensc/trunk@5001 c6295689-39f2-0310-b995-f0e70906c6a9
353 lines
7.5 KiB
C
353 lines
7.5 KiB
C
/*
|
|
* pkcs15-westcos.c: pkcs15 support for westcos card
|
|
*
|
|
* Copyright (C) 2009 francois.leblanc@cev-sa.com
|
|
*
|
|
* 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 <string.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
|
|
#ifdef ENABLE_OPENSSL
|
|
#include <openssl/opensslv.h>
|
|
#include <openssl/rsa.h>
|
|
#include <openssl/evp.h>
|
|
#include <openssl/pem.h>
|
|
#include <openssl/err.h>
|
|
#include <openssl/bio.h>
|
|
#endif
|
|
|
|
#include "libopensc/opensc.h"
|
|
#include "libopensc/cardctl.h"
|
|
#include "pkcs15-init.h"
|
|
#include "profile.h"
|
|
|
|
static int westcos_pkcs15init_init_card(sc_profile_t *profile,
|
|
sc_pkcs15_card_t *p15card)
|
|
{
|
|
int r;
|
|
struct sc_path path;
|
|
|
|
sc_format_path("3F00", &path);
|
|
r = sc_select_file(p15card->card, &path, NULL);
|
|
if(r) return (r);
|
|
|
|
return r;
|
|
}
|
|
|
|
static int westcos_pkcs15init_create_dir(sc_profile_t *profile,
|
|
sc_pkcs15_card_t *p15card,
|
|
sc_file_t *df)
|
|
{
|
|
int r;
|
|
|
|
/* Create the application DF */
|
|
r = sc_pkcs15init_create_file(profile, p15card, df);
|
|
|
|
r = sc_select_file(p15card->card, &df->path, NULL);
|
|
if(r) return r;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Select the PIN reference
|
|
*/
|
|
static int westcos_pkcs15_select_pin_reference(sc_profile_t *profile,
|
|
sc_pkcs15_card_t *p15card,
|
|
sc_pkcs15_pin_info_t *pin_info)
|
|
{
|
|
|
|
if (pin_info->flags & SC_PKCS15_PIN_FLAG_SO_PIN) {
|
|
pin_info->reference = 1;
|
|
} else {
|
|
pin_info->reference = 0;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Create a new PIN inside a DF
|
|
*/
|
|
static int westcos_pkcs15_create_pin(sc_profile_t *profile,
|
|
sc_pkcs15_card_t *p15card,
|
|
sc_file_t *df,
|
|
sc_pkcs15_object_t *pin_obj,
|
|
const u8 *pin, size_t pin_len,
|
|
const u8 *puk, size_t puk_len)
|
|
{
|
|
int r;
|
|
sc_file_t *pinfile = NULL;
|
|
|
|
if(pin_len>9 || puk_len>9)
|
|
return SC_ERROR_INVALID_ARGUMENTS;
|
|
|
|
r = sc_profile_get_file(profile, "PINFILE", &pinfile);
|
|
if(r < 0) return r;
|
|
|
|
r = sc_create_file(p15card->card, pinfile);
|
|
if(r)
|
|
{
|
|
if(r != SC_ERROR_FILE_ALREADY_EXISTS)
|
|
return (r);
|
|
|
|
r = sc_select_file(p15card->card, &pinfile->path, NULL);
|
|
if(r) return (r);
|
|
}
|
|
|
|
if(pinfile)
|
|
sc_file_free(pinfile);
|
|
|
|
if(pin != NULL)
|
|
{
|
|
sc_changekey_t ck;
|
|
struct sc_pin_cmd_pin pin_cmd;
|
|
int ret;
|
|
|
|
memset(&pin_cmd, 0, sizeof(pin_cmd));
|
|
memset(&ck, 0, sizeof(ck));
|
|
|
|
memcpy(ck.key_template, "\x1e\x00\x00\x10", 4);
|
|
|
|
pin_cmd.encoding = SC_PIN_ENCODING_GLP;
|
|
pin_cmd.len = pin_len;
|
|
pin_cmd.data = pin;
|
|
pin_cmd.max_length = 8;
|
|
|
|
ret = sc_build_pin(ck.new_key.key_value,
|
|
sizeof(ck.new_key.key_value), &pin_cmd, 1);
|
|
if(ret < 0)
|
|
return SC_ERROR_CARD_CMD_FAILED;
|
|
|
|
ck.new_key.key_len = ret;
|
|
r = sc_card_ctl(p15card->card, SC_CARDCTL_WESTCOS_CHANGE_KEY, &ck);
|
|
if(r) return r;
|
|
}
|
|
|
|
if(puk != NULL)
|
|
{
|
|
sc_changekey_t ck;
|
|
struct sc_pin_cmd_pin puk_cmd;
|
|
int ret;
|
|
|
|
memset(&puk_cmd, 0, sizeof(puk_cmd));
|
|
memset(&ck, 0, sizeof(ck));
|
|
|
|
memcpy(ck.key_template, "\x1e\x00\x00\x20", 4);
|
|
|
|
puk_cmd.encoding = SC_PIN_ENCODING_GLP;
|
|
puk_cmd.len = puk_len;
|
|
puk_cmd.data = puk;
|
|
puk_cmd.max_length = 8;
|
|
|
|
ret = sc_build_pin(ck.new_key.key_value,
|
|
sizeof(ck.new_key.key_value), &puk_cmd, 1);
|
|
if(ret < 0)
|
|
return SC_ERROR_CARD_CMD_FAILED;
|
|
|
|
ck.new_key.key_len = ret;
|
|
r = sc_card_ctl(p15card->card, SC_CARDCTL_WESTCOS_CHANGE_KEY, &ck);
|
|
if(r) return r;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Create a new key file
|
|
*/
|
|
static int westcos_pkcs15init_create_key(sc_profile_t *profile,
|
|
sc_pkcs15_card_t *p15card,
|
|
sc_pkcs15_object_t *obj)
|
|
{
|
|
|
|
if (obj->type != SC_PKCS15_TYPE_PRKEY_RSA) {
|
|
return SC_ERROR_NOT_SUPPORTED;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
* Store a private key
|
|
*/
|
|
static int westcos_pkcs15init_store_key(sc_profile_t *profile,
|
|
sc_pkcs15_card_t *p15card,
|
|
sc_pkcs15_object_t *obj,
|
|
sc_pkcs15_prkey_t *key)
|
|
{
|
|
return SC_ERROR_NOT_SUPPORTED;
|
|
}
|
|
|
|
/*
|
|
* Generate key
|
|
*/
|
|
static int westcos_pkcs15init_generate_key(sc_profile_t *profile,
|
|
sc_pkcs15_card_t *p15card,
|
|
sc_pkcs15_object_t *obj,
|
|
sc_pkcs15_pubkey_t *pubkey)
|
|
{
|
|
#ifndef ENABLE_OPENSSL
|
|
return SC_ERROR_NOT_SUPPORTED;
|
|
#else
|
|
int r = SC_ERROR_UNKNOWN;
|
|
long lg;
|
|
u8 *p;
|
|
sc_pkcs15_prkey_info_t *key_info = (sc_pkcs15_prkey_info_t *) obj->data;
|
|
RSA *rsa = NULL;
|
|
BIGNUM *bn = NULL;
|
|
BIO *mem = NULL;
|
|
|
|
sc_file_t *prkf = NULL;
|
|
|
|
if (obj->type != SC_PKCS15_TYPE_PRKEY_RSA) {
|
|
return SC_ERROR_NOT_SUPPORTED;
|
|
}
|
|
|
|
#if OPENSSL_VERSION_NUMBER>=0x00908000L
|
|
rsa = RSA_new();
|
|
bn = BN_new();
|
|
mem = BIO_new(BIO_s_mem());
|
|
|
|
if(rsa == NULL || bn == NULL || mem == NULL)
|
|
{
|
|
r = SC_ERROR_OUT_OF_MEMORY;
|
|
goto out;
|
|
}
|
|
|
|
if(!BN_set_word(bn, RSA_F4) ||
|
|
!RSA_generate_key_ex(rsa, key_info->modulus_length, bn, NULL))
|
|
#else
|
|
mem = BIO_new(BIO_s_mem());
|
|
|
|
if(mem == NULL)
|
|
{
|
|
r = SC_ERROR_OUT_OF_MEMORY;
|
|
goto out;
|
|
}
|
|
|
|
rsa = RSA_generate_key(key_info->modulus_length, RSA_F4, NULL, NULL);
|
|
if (!rsa)
|
|
#endif
|
|
{
|
|
r = SC_ERROR_UNKNOWN;
|
|
goto out;
|
|
}
|
|
|
|
rsa->meth = RSA_PKCS1_SSLeay();
|
|
|
|
if(pubkey != NULL)
|
|
{
|
|
if(!i2d_RSAPublicKey_bio(mem, rsa))
|
|
{
|
|
r = SC_ERROR_UNKNOWN;
|
|
goto out;
|
|
}
|
|
|
|
lg = BIO_get_mem_data(mem, &p);
|
|
|
|
pubkey->algorithm = SC_ALGORITHM_RSA;
|
|
|
|
r = sc_pkcs15_decode_pubkey(p15card->card->ctx, pubkey, p, lg);
|
|
}
|
|
|
|
(void) BIO_reset(mem);
|
|
|
|
if(!i2d_RSAPrivateKey_bio(mem, rsa))
|
|
{
|
|
r = SC_ERROR_UNKNOWN;
|
|
goto out;
|
|
}
|
|
|
|
lg = BIO_get_mem_data(mem, &p);
|
|
|
|
/* Get the private key file */
|
|
r = sc_profile_get_file_by_path(profile, &key_info->path, &prkf);
|
|
if (r < 0)
|
|
{
|
|
char pbuf[SC_MAX_PATH_STRING_SIZE];
|
|
|
|
r = sc_path_print(pbuf, sizeof(pbuf), &key_info->path);
|
|
if (r != SC_SUCCESS)
|
|
pbuf[0] = '\0';
|
|
|
|
goto out;
|
|
}
|
|
|
|
prkf->size = lg;
|
|
|
|
r = sc_pkcs15init_create_file(profile, p15card, prkf);
|
|
if(r) goto out;
|
|
|
|
r = sc_pkcs15init_update_file(profile, p15card, prkf, p, lg);
|
|
if(r) goto out;
|
|
|
|
out:
|
|
if(mem)
|
|
BIO_free(mem);
|
|
if(bn)
|
|
BN_free(bn);
|
|
if(rsa)
|
|
RSA_free(rsa);
|
|
if(prkf)
|
|
sc_file_free(prkf);
|
|
|
|
return r;
|
|
#endif
|
|
}
|
|
|
|
static int westcos_pkcs15init_finalize_card(sc_card_t *card)
|
|
{
|
|
int r;
|
|
|
|
/* be sure authentificate card */
|
|
r = sc_card_ctl(card, SC_CARDCTL_WESTCOS_AUT_KEY, NULL);
|
|
if(r) return (r);
|
|
|
|
return sc_pkcs15init_set_lifecycle(card, SC_CARDCTRL_LIFECYCLE_USER);
|
|
}
|
|
|
|
static struct sc_pkcs15init_operations sc_pkcs15init_westcos_operations = {
|
|
NULL, /* erase_card */
|
|
westcos_pkcs15init_init_card, /* init_card */
|
|
westcos_pkcs15init_create_dir, /* create_dir */
|
|
NULL, /* create_domain */
|
|
westcos_pkcs15_select_pin_reference, /* select_pin_reference */
|
|
westcos_pkcs15_create_pin, /* create_pin */
|
|
NULL, /* select_key_reference */
|
|
westcos_pkcs15init_create_key, /* create_key */
|
|
westcos_pkcs15init_store_key, /* store_key */
|
|
westcos_pkcs15init_generate_key, /* generate_key */
|
|
NULL, NULL, /* encode private/public key */
|
|
westcos_pkcs15init_finalize_card, /* finalize_card */
|
|
NULL, /* delete_object */
|
|
NULL, NULL, NULL, NULL, NULL, /* pkcs15init emulation */
|
|
NULL /* sanity_check */
|
|
};
|
|
|
|
struct sc_pkcs15init_operations* sc_pkcs15init_get_westcos_ops(void)
|
|
{
|
|
return &sc_pkcs15init_westcos_operations;
|
|
}
|
|
|
|
|
|
|