Very basic and untested oberthur driver. Could possibly work,
as only non-essential parts stripped (or at least that was the plan). Written by Viktor Tarasov of idealx. All bugs by Andreas Jellinghaus, please don't blame anyone else. git-svn-id: https://www.opensc-project.org/svnp/opensc/trunk@1793 c6295689-39f2-0310-b995-f0e70906c6a9
This commit is contained in:
parent
9b7cdbffad
commit
52c1b2d700
@ -27,6 +27,7 @@ libopensc_la_SOURCES = \
|
||||
card-setcos.c card-miocos.c card-flex.c card-gpk.c \
|
||||
card-etoken.c card-tcos.c card-emv.c card-default.c \
|
||||
card-mcrd.c card-starcos.c card-openpgp.c card-jcop.c\
|
||||
card-oberthur.c card-oberthur.h \
|
||||
\
|
||||
pkcs15-openpgp.c pkcs15-infocamere.c
|
||||
libopensc_la_LDFLAGS = -version-info @OPENSC_LT_CURRENT@:@OPENSC_LT_REVISION@:@OPENSC_LT_AGE@
|
||||
|
2318
src/libopensc/card-oberthur.c
Normal file
2318
src/libopensc/card-oberthur.c
Normal file
File diff suppressed because it is too large
Load Diff
70
src/libopensc/card-oberthur.h
Normal file
70
src/libopensc/card-oberthur.h
Normal file
@ -0,0 +1,70 @@
|
||||
#ifndef _OPENSC_CARD_OBERTHUR_H
|
||||
#define _OPENSC_CARD_OBERTHUR_H
|
||||
|
||||
#include <opensc/opensc.h>
|
||||
|
||||
#define AID_OBERTHUR_V2 0x201
|
||||
#define AID_OBERTHUR_V4 0x401
|
||||
#define AID_OBERTHUR_V5 0x501
|
||||
|
||||
#define ATR_OBERTHUR 0x0100
|
||||
#define ATR_OBERTHUR_32K 0x0110
|
||||
#define ATR_OBERTHUR_32K_BIO 0x0112
|
||||
#define ATR_OBERTHUR_64K 0x0120
|
||||
|
||||
#define FLAG_KEYGEN 0x0001
|
||||
|
||||
#define AUTH_PIN 1
|
||||
#define AUTH_PUK 2
|
||||
|
||||
#define PUBKEY_512_ASN1_SIZE 0x4A
|
||||
#define PUBKEY_1024_ASN1_SIZE 0x8C
|
||||
#define PUBKEY_2048_ASN1_SIZE 0x10E
|
||||
|
||||
#define SC_OBERTHUR_MAX_ATTR_SIZE 8
|
||||
|
||||
struct NTLV {
|
||||
char *name;
|
||||
unsigned int tag;
|
||||
int len;
|
||||
unsigned char *value;
|
||||
};
|
||||
typedef struct NTLV NTLV_t;
|
||||
|
||||
struct oberthur_atr {
|
||||
const char *atr;
|
||||
const char *name;
|
||||
unsigned int type;
|
||||
};
|
||||
|
||||
struct oberthur_aid {
|
||||
const char *aid;
|
||||
const char *name;
|
||||
unsigned int type;
|
||||
};
|
||||
typedef struct oberthur_aid oberthur_aid_t;
|
||||
|
||||
struct auth_application_id {
|
||||
unsigned int tag;
|
||||
u8 value[SC_MAX_AID_SIZE];
|
||||
int len;
|
||||
};
|
||||
typedef struct auth_application_id auth_application_id_t;
|
||||
|
||||
struct auth_senv {
|
||||
unsigned int algorithm;
|
||||
int key_file_id;
|
||||
size_t key_size;
|
||||
};
|
||||
typedef struct auth_senv auth_senv_t;
|
||||
|
||||
|
||||
struct auth_private_data {
|
||||
struct sc_pin_cmd_pin pin_info;
|
||||
long int sn;
|
||||
auth_application_id_t aid;
|
||||
auth_senv_t senv;
|
||||
};
|
||||
typedef struct auth_private_data auth_private_data_t;
|
||||
|
||||
#endif /* _OPENSC_CARD_OBERTHUR_H */
|
@ -85,6 +85,13 @@ enum {
|
||||
SC_CARDCTL_JCOP_LOCK,
|
||||
SC_CARDCTL_JCOP_GENERATE_KEY,
|
||||
|
||||
/*
|
||||
* Oberthur specific calls
|
||||
*/
|
||||
SC_CARDCTL_OBERTHUR_BASE = _CTL_PREFIX('O', 'B', 'R'),
|
||||
SC_CARDCTL_OBERTHUR_UPDATE_KEY,
|
||||
SC_CARDCTL_OBERTHUR_GENERATE_KEY,
|
||||
SC_CARDCTL_OBERTHUR_CREATE_PIN,
|
||||
};
|
||||
|
||||
enum {
|
||||
@ -234,6 +241,44 @@ struct sc_cardctl_jcop_genkey {
|
||||
unsigned int pubkey_len;
|
||||
};
|
||||
|
||||
/*
|
||||
* Oberthur ex_data stuff
|
||||
*/
|
||||
enum SC_CARDCTL_OBERTHUR_KEY_TYPE {
|
||||
SC_CARDCTL_OBERTHUR_KEY_DES = 0x80,
|
||||
|
||||
SC_CARDCTL_OBERTHUR_KEY_RSA_PUBLIC = 0xA1,
|
||||
SC_CARDCTL_OBERTHUR_KEY_RSA_SFM,
|
||||
SC_CARDCTL_OBERTHUR_KEY_RSA_CRT,
|
||||
SC_CARDCTL_OBERTHUR_KEY_DSA_PUBLIC,
|
||||
SC_CARDCTL_OBERTHUR_KEY_DSA_PRIVATE,
|
||||
};
|
||||
|
||||
struct sc_cardctl_oberthur_genkey_info {
|
||||
unsigned int id_prv, id_pub;
|
||||
unsigned int key_bits;
|
||||
unsigned long exponent;
|
||||
unsigned char * pubkey;
|
||||
unsigned int pubkey_len;
|
||||
};
|
||||
|
||||
struct sc_cardctl_oberthur_updatekey_info {
|
||||
enum SC_CARDCTL_OBERTHUR_KEY_TYPE type;
|
||||
unsigned int component;
|
||||
unsigned char *data;
|
||||
unsigned int len;
|
||||
};
|
||||
|
||||
struct sc_cardctl_oberthur_createpin_info {
|
||||
unsigned int type;
|
||||
unsigned int ref;
|
||||
unsigned char *pin;
|
||||
unsigned int pin_len;
|
||||
unsigned int pin_tries;
|
||||
unsigned char *puk;
|
||||
unsigned int puk_len;
|
||||
unsigned int puk_tries;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -69,6 +69,9 @@ static const struct _sc_driver_entry internal_card_drivers[] = {
|
||||
{ "tcos", (void *) sc_get_tcos_driver, NULL },
|
||||
{ "opengpg", (void *) sc_get_openpgp_driver, NULL },
|
||||
{ "jcop", (void *) sc_get_jcop_driver, NULL },
|
||||
#ifdef HAVE_OPENSSL
|
||||
{ "oberthur", (void *) sc_get_oberthur_driver, NULL },
|
||||
#endif
|
||||
/* The default driver should be last, as it handles all the
|
||||
* unrecognized cards. */
|
||||
{ "default", (void *) sc_get_default_driver, NULL },
|
||||
|
@ -539,6 +539,7 @@ struct sc_card_operations {
|
||||
* restore_security_env. */
|
||||
int (*decipher)(struct sc_card *card, const u8 * crgram,
|
||||
size_t crgram_len, u8 * out, size_t outlen);
|
||||
|
||||
/* compute_signature: Generates a digital signature on the card. Similiar
|
||||
* to the function decipher. */
|
||||
int (*compute_signature)(struct sc_card *card, const u8 * data,
|
||||
@ -579,9 +580,6 @@ struct sc_card_operations {
|
||||
int (*get_data)(sc_card_t *, unsigned int, u8 *, size_t);
|
||||
int (*put_data)(sc_card_t *, unsigned int, const u8 *, size_t);
|
||||
|
||||
/* FIXME
|
||||
* Any of ISO-7816s contains this function?
|
||||
*/
|
||||
int (*delete_record)(sc_card_t *card, unsigned int rec_nr);
|
||||
};
|
||||
|
||||
@ -874,6 +872,7 @@ extern struct sc_card_driver *sc_get_starcos_driver(void);
|
||||
extern struct sc_card_driver *sc_get_tcos_driver(void);
|
||||
extern struct sc_card_driver *sc_get_openpgp_driver(void);
|
||||
extern struct sc_card_driver *sc_get_jcop_driver(void);
|
||||
extern struct sc_card_driver *sc_get_oberthur_driver(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -14,6 +14,7 @@ PROFILES = \
|
||||
miocos.profile \
|
||||
etoken.profile \
|
||||
jcop.profile \
|
||||
oberthur.profile \
|
||||
starcos.profile \
|
||||
pkcs15.profile
|
||||
|
||||
@ -24,7 +25,9 @@ lib_LTLIBRARIES = libpkcs15init.la
|
||||
libpkcs15init_la_SOURCES = \
|
||||
pkcs15-lib.c profile.c keycache.c \
|
||||
pkcs15-gpk.c pkcs15-miocos.c pkcs15-cflex.c \
|
||||
pkcs15-etoken.c pkcs15-jcop.c pkcs15-starcos.c
|
||||
pkcs15-etoken.c pkcs15-jcop.c pkcs15-starcos.c \
|
||||
pkcs15-oberthur.c
|
||||
|
||||
libpkcs15init_la_LDFLAGS = -version-info @OPENSC_LT_CURRENT@:@OPENSC_LT_REVISION@:@OPENSC_LT_AGE@
|
||||
|
||||
include_HEADERS = pkcs15-init.h
|
||||
|
188
src/pkcs15init/oberthur.profile
Normal file
188
src/pkcs15init/oberthur.profile
Normal file
@ -0,0 +1,188 @@
|
||||
#
|
||||
# PKCS15 r/w profile for Oberthur cards
|
||||
#
|
||||
cardinfo {
|
||||
label = "S3M";
|
||||
manufacturer = "Oberthur/OpenSC";
|
||||
|
||||
max-pin-length = 64;
|
||||
min-pin-length = 4;
|
||||
pin-encoding = ascii-numeric;
|
||||
pin-pad-char = 0xFF;
|
||||
|
||||
# Delete or not the public key when inconporating the
|
||||
# corresponding certificate.
|
||||
keep-public-key = no; # yes/no
|
||||
|
||||
}
|
||||
|
||||
# Define reasonable limits for PINs and PUK
|
||||
# Note that we do not set a file path or reference
|
||||
# here; that is done dynamically.
|
||||
PIN user-pin {
|
||||
attempts = 5;
|
||||
max-length = 64;
|
||||
min-length = 4;
|
||||
flags = 0x32; # local, initialized, needs-padding
|
||||
reference = 1
|
||||
}
|
||||
PIN user-puk {
|
||||
attempts = 5;
|
||||
max-length = 16;
|
||||
min-length = 4;
|
||||
flags = 0x32; # local, initialized, needs-padding
|
||||
}
|
||||
PIN so-pin {
|
||||
auth-id = FF;
|
||||
attempts = 3;
|
||||
max-length = 64;
|
||||
min-length = 4;
|
||||
flags = 0xB2;
|
||||
reference = 2
|
||||
default-value = "31:32:33:34:35:36:37:38";
|
||||
}
|
||||
|
||||
# CHV3 used for Oberthur's specifique access condition "PIN or SOPIN"
|
||||
# Any value for this pin can given, when the OpenSC tools are asking for.
|
||||
|
||||
# Additional filesystem info.
|
||||
# This is added to the file system info specified in the
|
||||
# main profile.
|
||||
filesystem {
|
||||
DF MF {
|
||||
ACL = *=CHV2;
|
||||
|
||||
DF OberthurAWP-AppDF {
|
||||
ACL = *=NONE;
|
||||
ACL = CREATE=CHV2, CRYPTO=NEVER;
|
||||
file-id = 5011;
|
||||
size = 40;
|
||||
|
||||
DF private-DF {
|
||||
ACL = *=NEVER;
|
||||
ACL = CREATE=CHV1, CRYPTO=CHV1, FILES=NONE, DELETE=NONE;
|
||||
file-id = 9002;
|
||||
size = 40;
|
||||
|
||||
# Private RSA keys
|
||||
EF OberthurAWP-private-key-info {
|
||||
ACL = WRITE=CHV1, UPDATE=CHV1, READ=CHV1;
|
||||
}
|
||||
EF template-private-key {
|
||||
file-id = 3000;
|
||||
type = internal-ef;
|
||||
# READ acl used instead of DECRYPT/SIGN
|
||||
ACL = UPDATE=CHV1, READ=CHV1;
|
||||
}
|
||||
|
||||
# Private DES keys
|
||||
EF OberthurAWP-private-des-info {
|
||||
ACL = WRITE=CHV1, UPDATE=CHV1, READ=CHV1;
|
||||
}
|
||||
EF template-private-des {
|
||||
file-id = 4000;
|
||||
type = internal-ef;
|
||||
size = 24; # 192 bits
|
||||
# READ acl used insted of DECRYPT/ENCRYPT/CHECKSUM
|
||||
ACL = UPDATE=CHV1, READ=CHV1;
|
||||
}
|
||||
|
||||
# Private data
|
||||
EF OberthurAWP-private-data-info {
|
||||
ACL = WRITE=CHV1, UPDATE=CHV1, READ=CHV1;
|
||||
}
|
||||
EF template-private-data {
|
||||
file-id = 6000;
|
||||
ACL = WRITE=CHV1, UPDATE=CHV1, READ=CHV1;
|
||||
}
|
||||
}
|
||||
|
||||
DF public-DF {
|
||||
ACL = CREATE=NONE, CRYPTO=NONE, FILES=NONE, DELETE=NONE;
|
||||
file-id = 9001;
|
||||
size = 80;
|
||||
|
||||
# Certificate
|
||||
EF OberthurAWP-certificate-info {
|
||||
ACL = WRITE=NONE, UPDATE=NONE, READ=NONE, ERASE=NONE;
|
||||
}
|
||||
EF template-certificate {
|
||||
file-id = 2000;
|
||||
ACL = WRITE=NONE, UPDATE=NONE, READ=NONE, ERASE=NONE;
|
||||
}
|
||||
|
||||
#Public Key
|
||||
EF OberthurAWP-public-key-info {
|
||||
ACL = WRITE=NONE, UPDATE=NONE, READ=NONE, ERASE=NONE;
|
||||
}
|
||||
EF template-public-key {
|
||||
file-id = 1000;
|
||||
type = internal-ef;
|
||||
ACL = *=NONE;
|
||||
}
|
||||
|
||||
# Public DES keys
|
||||
EF OberthurAWP-public-des-info {
|
||||
ACL = WRITE=NONE, UPDATE=NONE, READ=NONE, ERASE=NONE;
|
||||
}
|
||||
EF template-public-des {
|
||||
file-id = 7000;
|
||||
type = internal-ef;
|
||||
size = 24; # 192 bits
|
||||
ACL = *=NONE;
|
||||
}
|
||||
|
||||
# Public data
|
||||
EF OberthurAWP-public-data-info {
|
||||
ACL = WRITE=NONE, UPDATE=NONE, READ=NONE, ERASE=NONE;
|
||||
}
|
||||
EF template-public-data {
|
||||
file-id = 5000;
|
||||
ACL = *=NONE;
|
||||
}
|
||||
}
|
||||
|
||||
EF OberthurAWP-token-info {
|
||||
file-id = 1000;
|
||||
size = 36;
|
||||
ACL = WRITE=CHV2, UPDATE=CHV2, READ=NONE, ERASE=NEVER;
|
||||
}
|
||||
|
||||
EF OberthurAWP-container-list {
|
||||
file-id = 3000;
|
||||
structure = linear-variable;
|
||||
size = 20;
|
||||
record-length = 141;
|
||||
ACL = WRITE=NONE, UPDATE=NONE, READ=NONE, ERASE=CHV3;
|
||||
}
|
||||
|
||||
EF OberthurAWP-public-list {
|
||||
file-id = 4000;
|
||||
size = 250;
|
||||
ACL = *=NONE, ERASE=NEVER;
|
||||
}
|
||||
|
||||
EF OberthurAWP-private-list {
|
||||
file-id = 5000;
|
||||
size = 125;
|
||||
ACL = WRITE=CHV1, UPDATE=CHV1, READ=NONE, ERASE=NEVER;
|
||||
}
|
||||
}
|
||||
|
||||
DF PKCS15-AppDF {
|
||||
ACL = *=CHV2, FILES=NONE;
|
||||
size = 20;
|
||||
|
||||
EF template-data-1 {
|
||||
file-id = 3301;
|
||||
ACL = *=CHV2, READ=NONE;
|
||||
}
|
||||
|
||||
EF template-data-2 {
|
||||
file-id = 3302;
|
||||
ACL = *=CHV2, READ=NONE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -365,6 +365,7 @@ extern struct sc_pkcs15init_operations *sc_pkcs15init_get_cyberflex_ops(void);
|
||||
extern struct sc_pkcs15init_operations *sc_pkcs15init_get_etoken_ops(void);
|
||||
extern struct sc_pkcs15init_operations *sc_pkcs15init_get_jcop_ops(void);
|
||||
extern struct sc_pkcs15init_operations *sc_pkcs15init_get_starcos_ops(void);
|
||||
extern struct sc_pkcs15init_operations *sc_pkcs15init_get_oberthur_ops(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -89,6 +89,9 @@ static int sc_pkcs15init_update_tokeninfo(struct sc_pkcs15_card *,
|
||||
struct sc_profile *profile);
|
||||
static int sc_pkcs15init_update_odf(struct sc_pkcs15_card *,
|
||||
struct sc_profile *profile);
|
||||
static int sc_pkcs15init_update_any_df(sc_pkcs15_card_t *p15card,
|
||||
sc_profile_t *profile,
|
||||
sc_pkcs15_df_t *df, int is_new);
|
||||
static sc_pkcs15_object_t *sc_pkcs15init_new_object(int type, const char *label,
|
||||
sc_pkcs15_id_t *auth_id, void *data);
|
||||
static int sc_pkcs15init_add_object(struct sc_pkcs15_card *,
|
||||
@ -138,6 +141,7 @@ static struct profile_operations {
|
||||
{ "etoken", (void *) sc_pkcs15init_get_etoken_ops },
|
||||
{ "jcop", (void *) sc_pkcs15init_get_jcop_ops },
|
||||
{ "starcos", (void *) sc_pkcs15init_get_starcos_ops },
|
||||
{ "oberthur", (void *) sc_pkcs15init_get_oberthur_ops },
|
||||
{ NULL, NULL },
|
||||
};
|
||||
|
||||
@ -454,6 +458,9 @@ sc_pkcs15init_add_app(struct sc_card *card, struct sc_profile *profile,
|
||||
|
||||
p15spec->card = card;
|
||||
|
||||
sc_profile_get_pin_info(profile, SC_PKCS15INIT_USER_PIN, &puk_info);
|
||||
sc_profile_get_pin_info(profile, SC_PKCS15INIT_USER_PUK, &puk_info);
|
||||
|
||||
/* Perform card-specific initialization */
|
||||
if (profile->ops->init_card
|
||||
&& (r = profile->ops->init_card(profile, card)) < 0) {
|
||||
@ -922,7 +929,7 @@ sc_pkcs15init_generate_key(struct sc_pkcs15_card *p15card,
|
||||
keybits, SC_ALGORITHM_ONBOARD_KEY_GEN))
|
||||
return SC_ERROR_NOT_SUPPORTED;
|
||||
|
||||
if (profile->ops->generate_key == NULL)
|
||||
if (profile->ops->generate_key == NULL && profile->ops->old_generate_key == NULL)
|
||||
return SC_ERROR_NOT_SUPPORTED;
|
||||
|
||||
/* Set the USER PIN reference from args */
|
||||
@ -1347,6 +1354,7 @@ sc_pkcs15init_store_certificate(struct sc_pkcs15_card *p15card,
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Store a data object
|
||||
*/
|
||||
@ -1407,6 +1415,7 @@ sc_pkcs15init_store_data(struct sc_pkcs15_card *p15card,
|
||||
{
|
||||
struct sc_file *file = NULL;
|
||||
int r;
|
||||
unsigned int index = -1;
|
||||
|
||||
/* Set the SO PIN reference from card */
|
||||
if ((r = set_so_pin_from_card(p15card, profile)) < 0)
|
||||
@ -1424,7 +1433,6 @@ sc_pkcs15init_store_data(struct sc_pkcs15_card *p15card,
|
||||
if (r < 0)
|
||||
return r;
|
||||
} else {
|
||||
unsigned int index;
|
||||
|
||||
/* Get the number of objects of this type already on this card */
|
||||
index = sc_pkcs15_get_objects(p15card,
|
||||
@ -1445,6 +1453,7 @@ sc_pkcs15init_store_data(struct sc_pkcs15_card *p15card,
|
||||
}
|
||||
r = sc_pkcs15init_update_file(profile, p15card->card,
|
||||
file, data->value, data->len);
|
||||
|
||||
*path = file->path;
|
||||
|
||||
done: if (file)
|
||||
@ -2114,12 +2123,6 @@ sc_pkcs15init_remove_object(sc_pkcs15_card_t *p15card,
|
||||
if ((df = obj->df) == NULL)
|
||||
return 0;
|
||||
|
||||
#ifdef notyet
|
||||
if (profile->ops->ext_remove_data
|
||||
&& (r = profile->ops->ext_remove_data(profile, card, obj)))
|
||||
return r;
|
||||
#endif
|
||||
|
||||
/* Unlink the object and update the DF */
|
||||
sc_pkcs15_remove_object(p15card, obj);
|
||||
if ((r = sc_pkcs15init_update_any_df(p15card, profile, df, 0)) < 0)
|
||||
@ -2261,7 +2264,7 @@ do_get_and_verify_secret(sc_profile_t *pro, sc_card_t *card,
|
||||
const char *ident, *label = NULL;
|
||||
int pin_id = -1;
|
||||
size_t defsize = 0;
|
||||
u8 defbuf[32];
|
||||
u8 defbuf[0x100];
|
||||
int r;
|
||||
|
||||
path = file? &file->path : NULL;
|
||||
@ -2398,7 +2401,7 @@ do_verify_pin(struct sc_profile *pro, struct sc_card *card, sc_file_t *file,
|
||||
unsigned int type, unsigned int reference)
|
||||
{
|
||||
size_t pinsize;
|
||||
u8 pinbuf[32];
|
||||
u8 pinbuf[0x100];
|
||||
|
||||
pinsize = sizeof(pinbuf);
|
||||
return do_get_and_verify_secret(pro, card, file, type, reference,
|
||||
|
718
src/pkcs15init/pkcs15-oberthur.c
Normal file
718
src/pkcs15init/pkcs15-oberthur.c
Normal file
@ -0,0 +1,718 @@
|
||||
/*
|
||||
* Oberthur specific operation for PKCS #15 initialization
|
||||
*
|
||||
* Copyright (C) 2002 Juha Yrjölä <juha.yrjola@iki.fi>
|
||||
* Copyright (C) 2003 Idealx <www.idealx.org>
|
||||
* Viktor Tarasov <vtarasov@idealx.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
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <ctype.h>
|
||||
#include <opensc/opensc.h>
|
||||
#include <opensc/cardctl.h>
|
||||
#include <opensc/log.h>
|
||||
#include "pkcs15-init.h"
|
||||
#include "profile.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../libopensc/card-oberthur.h"
|
||||
|
||||
#define COSM_TITLE "OberthurAWP"
|
||||
|
||||
#define COSM_TLV_TAG 0x00
|
||||
#define COSM_LIST_TAG 0xFF
|
||||
#define COSM_TAG_CONTAINER 0x0000
|
||||
#define COSM_TAG_CERT 0x0001
|
||||
#define COSM_TAG_PRVKEY_RSA 0x04B1
|
||||
#define COSM_TAG_PUBKEY_RSA 0x0349
|
||||
#define COSM_TAG_DES 0x0679
|
||||
#define COSM_TAG_DATA 0x0001
|
||||
#define COSM_IMPORTED 0x0000
|
||||
#define COSM_GENERATED 0x0004
|
||||
|
||||
#define TLV_TYPE_V 0
|
||||
#define TLV_TYPE_LV 1
|
||||
#define TLV_TYPE_TLV 2
|
||||
|
||||
// Should be greater then SC_PKCS15_TYPE_CLASS_MASK
|
||||
#define SC_DEVICE_SPECIFIC_TYPE 0x1000
|
||||
|
||||
#define COSM_PUBLIC_LIST (SC_DEVICE_SPECIFIC_TYPE | 0x02)
|
||||
#define COSM_PRIVATE_LIST (SC_DEVICE_SPECIFIC_TYPE | 0x03)
|
||||
#define COSM_CONTAINER_LIST (SC_DEVICE_SPECIFIC_TYPE | 0x04)
|
||||
#define COSM_TOKENINFO (SC_DEVICE_SPECIFIC_TYPE | 0x05)
|
||||
|
||||
#define COSM_TYPE_PRKEY_RSA (SC_DEVICE_SPECIFIC_TYPE | SC_PKCS15_TYPE_PRKEY_RSA)
|
||||
#define COSM_TYPE_PUBKEY_RSA (SC_DEVICE_SPECIFIC_TYPE | SC_PKCS15_TYPE_PUBKEY_RSA)
|
||||
|
||||
static int cosm_update_pin(struct sc_profile *profile, struct sc_card *card,
|
||||
struct sc_pkcs15_pin_info *info, const u8 *pin, size_t pin_len,
|
||||
const u8 *puk, size_t puk_len);
|
||||
|
||||
int cosm_delete_file(struct sc_card *card, struct sc_profile *profile,
|
||||
struct sc_file *df);
|
||||
|
||||
int cosm_delete_file(struct sc_card *card, struct sc_profile *profile,
|
||||
struct sc_file *df)
|
||||
{
|
||||
struct sc_path path;
|
||||
struct sc_file *parent;
|
||||
int rv = 0;
|
||||
|
||||
sc_debug(card->ctx, " id %04X\n", df->id);
|
||||
|
||||
if (df->type==SC_FILE_TYPE_DF) {
|
||||
rv = sc_pkcs15init_authenticate(profile, card, df, SC_AC_OP_DELETE);
|
||||
if (rv < 0)
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Select the parent DF */
|
||||
|
||||
path = df->path;
|
||||
path.len -= 2;
|
||||
|
||||
rv = sc_select_file(card, &path, &parent);
|
||||
if (rv < 0)
|
||||
goto done;
|
||||
|
||||
rv = sc_pkcs15init_authenticate(profile, card, parent, SC_AC_OP_DELETE);
|
||||
sc_file_free(parent);
|
||||
if (rv < 0)
|
||||
goto done;
|
||||
|
||||
memset(&path, 0, sizeof(path));
|
||||
path.type = SC_PATH_TYPE_FILE_ID;
|
||||
path.value[0] = df->id >> 8;
|
||||
path.value[1] = df->id & 0xFF;
|
||||
path.len = 2;
|
||||
|
||||
rv = sc_delete_file(card, &path);
|
||||
done:
|
||||
sc_debug(card->ctx, "return %i\n", rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Erase the card
|
||||
*/
|
||||
static int cosm_erase_card(struct sc_profile *profile, struct sc_card *card)
|
||||
{
|
||||
struct sc_file *df = profile->df_info->file, *dir;
|
||||
int r;
|
||||
|
||||
/* Delete EF(DIR). This may not be very nice
|
||||
* against other applications that use this file, but
|
||||
* extremely useful for testing :)
|
||||
* Note we need to delete if before the DF because we create
|
||||
* it *after* the DF.
|
||||
* */
|
||||
card->ctx->suppress_errors++;
|
||||
if (sc_profile_get_file(profile, "DIR", &dir) >= 0) {
|
||||
sc_debug(card->ctx, "erase file dir %04X\n",dir->id);
|
||||
r = cosm_delete_file(card, profile, dir);
|
||||
sc_file_free(dir);
|
||||
if (r < 0 && r != SC_ERROR_FILE_NOT_FOUND)
|
||||
goto done;
|
||||
}
|
||||
|
||||
sc_debug(card->ctx, "erase file ddf %04X\n",df->id);
|
||||
r=cosm_delete_file(card, profile, df);
|
||||
|
||||
if (sc_profile_get_file(profile, "private-DF", &dir) >= 0) {
|
||||
sc_debug(card->ctx, "erase file dir %04X\n",dir->id);
|
||||
r = cosm_delete_file(card, profile, dir);
|
||||
sc_file_free(dir);
|
||||
if (r < 0 && r != SC_ERROR_FILE_NOT_FOUND)
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (sc_profile_get_file(profile, "public-DF", &dir) >= 0) {
|
||||
sc_debug(card->ctx, "erase file dir %04X\n",dir->id);
|
||||
r = cosm_delete_file(card, profile, dir);
|
||||
sc_file_free(dir);
|
||||
if (r < 0 && r != SC_ERROR_FILE_NOT_FOUND)
|
||||
goto done;
|
||||
}
|
||||
|
||||
r = sc_profile_get_file(profile, COSM_TITLE"-AppDF", &dir);
|
||||
if (!r) {
|
||||
sc_debug(card->ctx, "delete %s; r %i\n", COSM_TITLE"-AppDF", r);
|
||||
r = cosm_delete_file(card, profile, dir);
|
||||
sc_file_free(dir);
|
||||
}
|
||||
|
||||
done:
|
||||
sc_keycache_forget_key(NULL, -1, -1);
|
||||
card->ctx->suppress_errors++;
|
||||
|
||||
if (r == SC_ERROR_FILE_NOT_FOUND)
|
||||
r=0;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Initialize the Application DF
|
||||
*/
|
||||
static int
|
||||
cosm_init_app(struct sc_profile *profile, struct sc_card *card,
|
||||
struct sc_pkcs15_pin_info *pinfo,
|
||||
const u8 *pin, size_t pin_len,
|
||||
const u8 *puk, size_t puk_len)
|
||||
{
|
||||
int r;
|
||||
struct sc_file *file = NULL;
|
||||
|
||||
sc_debug(card->ctx, "pin_len %i; puk_len %i\n", pin_len, puk_len);
|
||||
/* Create the application DF */
|
||||
r = sc_pkcs15init_create_file(profile, card, profile->df_info->file);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
/* Oberthur AWP file system is expected.*/
|
||||
/* Create private objects DF */
|
||||
if (sc_profile_get_file(profile, "private-DF", &file)) {
|
||||
sc_error(card->ctx, "Inconsistent profile: cannot find private-DF");
|
||||
return SC_ERROR_INCONSISTENT_PROFILE;
|
||||
}
|
||||
|
||||
r = sc_pkcs15init_create_file(profile, card, file);
|
||||
sc_file_free(file);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
/* Create public objects DF */
|
||||
if (sc_profile_get_file(profile, "public-DF", &file)) {
|
||||
sc_error(card->ctx, "Inconsistent profile: cannot find public-DF");
|
||||
return SC_ERROR_INCONSISTENT_PROFILE;
|
||||
}
|
||||
|
||||
r = sc_pkcs15init_create_file(profile, card, file);
|
||||
sc_file_free(file);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
/* Create Oberthur AWP application DF (5011),
|
||||
* and populate with Oberthur's xxDF files*/
|
||||
r = sc_profile_get_file(profile, COSM_TITLE"-AppDF", &file);
|
||||
sc_debug(card->ctx, "name %s; r %i\n", COSM_TITLE"-AppDF", r);
|
||||
if (r==SC_ERROR_FILE_NOT_FOUND) {
|
||||
sc_debug(card->ctx, "create file dir %04X\n", file->id);
|
||||
r = sc_pkcs15init_create_file(profile, card, file);
|
||||
sc_file_free(file);
|
||||
}
|
||||
if (r && r!=SC_ERROR_FILE_ALREADY_EXISTS)
|
||||
return(r);
|
||||
|
||||
sc_debug(card->ctx, "return OK\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cosm_create_reference_data(struct sc_profile *profile, struct sc_card *card,
|
||||
struct sc_pkcs15_pin_info *pinfo,
|
||||
const u8 *pin, size_t pin_len, const u8 *puk, size_t puk_len )
|
||||
{
|
||||
int rv;
|
||||
int puk_buff_len = 0;
|
||||
unsigned char *puk_buff = NULL;
|
||||
sc_pkcs15_pin_info_t profile_pin;
|
||||
sc_pkcs15_pin_info_t profile_puk;
|
||||
struct sc_cardctl_oberthur_createpin_info args;
|
||||
|
||||
sc_debug(card->ctx, "pin lens %i/%i\n", pin_len, puk_len);
|
||||
if (!pin || pin_len>0x40)
|
||||
return SC_ERROR_INVALID_ARGUMENTS;
|
||||
if (puk && !puk_len)
|
||||
return SC_ERROR_INVALID_ARGUMENTS;
|
||||
|
||||
rv = sc_select_file(card, &pinfo->path, NULL);
|
||||
if (rv)
|
||||
return rv;
|
||||
|
||||
sc_profile_get_pin_info(profile, SC_PKCS15INIT_USER_PIN, &profile_pin);
|
||||
if (profile_pin.max_length > 0x100)
|
||||
return SC_ERROR_INCONSISTENT_PROFILE;
|
||||
|
||||
if (puk) {
|
||||
int ii, jj;
|
||||
unsigned char *ptr = (unsigned char *)puk;
|
||||
|
||||
puk_buff = malloc(0x100);
|
||||
if (!puk_buff)
|
||||
goto done;
|
||||
|
||||
sc_profile_get_pin_info(profile, SC_PKCS15INIT_USER_PUK, &profile_puk);
|
||||
if (profile_puk.max_length > 0x100)
|
||||
return SC_ERROR_INCONSISTENT_PROFILE;
|
||||
memset(puk_buff, profile_puk.pad_char, 0x100);
|
||||
for (ii=0; ii<8 && (ptr-puk) < puk_len && (*ptr); ii++) {
|
||||
jj = 0;
|
||||
while (isalnum(*ptr) && jj<16) {
|
||||
*(puk_buff + ii*0x10 + jj++) = *ptr;
|
||||
++ptr;
|
||||
}
|
||||
while(!isalnum(*ptr) && (*ptr))
|
||||
++ptr;
|
||||
}
|
||||
|
||||
puk_buff_len = ii*0x10;
|
||||
}
|
||||
|
||||
sc_debug(card->ctx, "pinfo->reference %i; tries %i\n",
|
||||
pinfo->reference, profile_pin.tries_left);
|
||||
|
||||
sc_debug(card->ctx, "sc_card_ctl %s\n","SC_CARDCTL_OBERTHUR_CREATE_PIN");
|
||||
args.type = SC_AC_CHV;
|
||||
args.ref = pinfo->reference;
|
||||
args.pin = (u8 *)pin;
|
||||
args.pin_len = pin_len;
|
||||
args.pin_tries = profile_pin.tries_left;
|
||||
args.puk = puk_buff;
|
||||
args.puk_len = puk_buff_len;
|
||||
args.puk_tries = profile_puk.tries_left;
|
||||
|
||||
if ((rv = sc_card_ctl(card, SC_CARDCTL_OBERTHUR_CREATE_PIN, &args)) < 0)
|
||||
goto done;
|
||||
|
||||
done:
|
||||
if (puk_buff)
|
||||
free(puk_buff);
|
||||
|
||||
sc_debug(card->ctx, "return %i\n", rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
/*
|
||||
* Update PIN
|
||||
*/
|
||||
static int cosm_update_pin(struct sc_profile *profile, struct sc_card *card,
|
||||
struct sc_pkcs15_pin_info *pinfo, const u8 *pin, size_t pin_len,
|
||||
const u8 *puk, size_t puk_len )
|
||||
{
|
||||
int rv;
|
||||
int tries_left = -1;
|
||||
|
||||
sc_debug(card->ctx, "ref %i; flags %X\n", pinfo->reference, pinfo->flags);
|
||||
|
||||
if (pinfo->flags & SC_PKCS15_PIN_FLAG_SO_PIN) {
|
||||
sc_error(card->ctx,"Pin references should be only in the profile"
|
||||
"and in the card-oberthur.\n");
|
||||
if (pinfo->reference != 2)
|
||||
return SC_ERROR_INVALID_PIN_REFERENCE;
|
||||
|
||||
rv = sc_change_reference_data(card, SC_AC_CHV, pinfo->reference, puk, puk_len,
|
||||
pin, pin_len, &tries_left);
|
||||
sc_debug(card->ctx, "return value %X; tries left %i\n", rv, tries_left);
|
||||
if (tries_left != -1)
|
||||
sc_error(card->ctx, "Failed to change reference data for soPin: rv %X", rv);
|
||||
|
||||
}
|
||||
else {
|
||||
rv = cosm_create_reference_data(profile, card, pinfo,
|
||||
pin, pin_len, puk, puk_len);
|
||||
}
|
||||
|
||||
sc_debug(card->ctx, "return %i\n",rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
static int
|
||||
cosm_select_pin_reference(sc_profile_t *profile, sc_card_t *card,
|
||||
sc_pkcs15_pin_info_t *pin_info)
|
||||
{
|
||||
sc_file_t *pinfile;
|
||||
|
||||
sc_debug(card->ctx, "ref %i; flags %X\n", pin_info->reference, pin_info->flags);
|
||||
if (sc_profile_get_file(profile, COSM_TITLE "-AppDF", &pinfile) < 0) {
|
||||
sc_error(card->ctx, "Profile doesn't define \"%s\"", COSM_TITLE "-AppDF");
|
||||
return SC_ERROR_INCONSISTENT_PROFILE;
|
||||
}
|
||||
|
||||
pin_info->path = pinfile->path;
|
||||
sc_file_free(pinfile);
|
||||
|
||||
if (pin_info->flags & SC_PKCS15_PIN_FLAG_SO_PIN) {
|
||||
pin_info->reference = 2;
|
||||
}
|
||||
|
||||
if (pin_info->reference < 0 || pin_info->reference > 3)
|
||||
return SC_ERROR_INVALID_PIN_REFERENCE;
|
||||
|
||||
if (!(pin_info->flags & SC_PKCS15_PIN_FLAG_SO_PIN)) {
|
||||
if (pin_info->reference == 2)
|
||||
return SC_ERROR_INVALID_PIN_REFERENCE;
|
||||
else if (pin_info->reference == 0)
|
||||
pin_info->reference = 1;
|
||||
}
|
||||
sc_debug(card->ctx, "return %i\n",0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Store a PIN
|
||||
*/
|
||||
static int
|
||||
cosm_create_pin(sc_profile_t *profile, sc_card_t *card, 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_pin_info_t *pinfo = (sc_pkcs15_pin_info_t *) pin_obj->data;
|
||||
sc_file_t *pinfile;
|
||||
int r = 0, type;
|
||||
|
||||
sc_debug(card->ctx, "ref %i; flags %X\n", pinfo->reference, pinfo->flags);
|
||||
if (sc_profile_get_file(profile, COSM_TITLE "-AppDF", &pinfile) < 0) {
|
||||
sc_error(card->ctx, "Profile doesn't define \"%s\"", COSM_TITLE "-AppDF");
|
||||
return SC_ERROR_INCONSISTENT_PROFILE;
|
||||
}
|
||||
|
||||
pinfo->path = pinfile->path;
|
||||
sc_file_free(pinfile);
|
||||
|
||||
if (pinfo->flags & SC_PKCS15_PIN_FLAG_SO_PIN) {
|
||||
type = SC_PKCS15INIT_SO_PIN;
|
||||
|
||||
if (pinfo->reference != 2)
|
||||
return SC_ERROR_INVALID_ARGUMENTS;
|
||||
}
|
||||
else {
|
||||
type = SC_PKCS15INIT_USER_PIN;
|
||||
|
||||
if (pinfo->reference !=1)
|
||||
return SC_ERROR_INVALID_PIN_REFERENCE;
|
||||
}
|
||||
|
||||
if (pin && pin_len) {
|
||||
r = cosm_update_pin(profile, card, pinfo, pin, pin_len, puk, puk_len);
|
||||
}
|
||||
else {
|
||||
sc_debug(card->ctx, "User PIN not updated");
|
||||
}
|
||||
sc_debug(card->ctx, "return %i\n",r);
|
||||
|
||||
sc_keycache_set_pin_name(&pinfo->path, pinfo->reference, type);
|
||||
pinfo->flags &= ~SC_PKCS15_PIN_FLAG_LOCAL;
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Allocate a file
|
||||
*/
|
||||
static int
|
||||
cosm_new_file(struct sc_profile *profile, struct sc_card *card,
|
||||
unsigned int type, unsigned int num, struct sc_file **out)
|
||||
{
|
||||
struct sc_file *file;
|
||||
char *template = NULL, *desc = NULL;
|
||||
unsigned int structure = 0xFFFFFFFF;
|
||||
|
||||
sc_debug(card->ctx, "type %X; num %i\n",type, num);
|
||||
while (1) {
|
||||
switch (type) {
|
||||
case SC_PKCS15_TYPE_PRKEY_RSA:
|
||||
case COSM_TYPE_PRKEY_RSA:
|
||||
desc = "RSA private key";
|
||||
template = "template-private-key";
|
||||
structure = SC_CARDCTL_OBERTHUR_KEY_RSA_CRT;
|
||||
break;
|
||||
case SC_PKCS15_TYPE_PUBKEY_RSA:
|
||||
case COSM_TYPE_PUBKEY_RSA:
|
||||
desc = "RSA public key";
|
||||
template = "template-public-key";
|
||||
structure = SC_CARDCTL_OBERTHUR_KEY_RSA_PUBLIC;
|
||||
break;
|
||||
case SC_PKCS15_TYPE_PUBKEY_DSA:
|
||||
desc = "DSA public key";
|
||||
template = "template-public-key";
|
||||
break;
|
||||
case SC_PKCS15_TYPE_PRKEY:
|
||||
desc = "extractable private key";
|
||||
template = "template-extractable-key";
|
||||
break;
|
||||
case SC_PKCS15_TYPE_CERT:
|
||||
desc = "certificate";
|
||||
template = "template-certificate";
|
||||
break;
|
||||
case SC_PKCS15_TYPE_DATA_OBJECT:
|
||||
desc = "data object";
|
||||
template = "template-public-data";
|
||||
break;
|
||||
}
|
||||
if (template)
|
||||
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)) {
|
||||
sc_error(card->ctx, "File type %X not supported by card driver",
|
||||
type);
|
||||
return SC_ERROR_INVALID_ARGUMENTS;
|
||||
}
|
||||
type &= SC_PKCS15_TYPE_CLASS_MASK;
|
||||
}
|
||||
|
||||
sc_debug(card->ctx, "template %s; num %i\n",template, num);
|
||||
if (sc_profile_get_file(profile, template, &file) < 0) {
|
||||
sc_error(card->ctx, "Profile doesn't define %s template '%s'\n",
|
||||
desc, template);
|
||||
return SC_ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
file->id |= (num & 0xFF);
|
||||
file->path.value[file->path.len-1] |= (num & 0xFF);
|
||||
if (file->type == SC_FILE_TYPE_INTERNAL_EF) {
|
||||
file->ef_structure = structure;
|
||||
}
|
||||
|
||||
sc_debug(card->ctx, "file size %i; ef type %i/%i; id %04X\n",file->size,
|
||||
file->type, file->ef_structure, file->id);
|
||||
*out = file;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* RSA key generation
|
||||
*/
|
||||
static int
|
||||
cosm_old_generate_key(struct sc_profile *profile, struct sc_card *card,
|
||||
unsigned int index, unsigned int keybits,
|
||||
sc_pkcs15_pubkey_t *pubkey,
|
||||
struct sc_pkcs15_prkey_info *info)
|
||||
{
|
||||
struct sc_cardctl_oberthur_genkey_info args;
|
||||
struct sc_file *prkf = NULL, *tmpf = NULL;
|
||||
sc_path_t path;
|
||||
int rv;
|
||||
|
||||
sc_debug(card->ctx, "index %i; nn %i\n",index,keybits);
|
||||
if (keybits < 512 || keybits > 2048 || (keybits%0x20)) {
|
||||
sc_error(card->ctx, "Unsupported key size %u\n", keybits);
|
||||
return SC_ERROR_INVALID_ARGUMENTS;
|
||||
}
|
||||
|
||||
/* Get private key file from profile. */
|
||||
if ((rv = cosm_new_file(profile, card, SC_PKCS15_TYPE_PRKEY_RSA, index,
|
||||
&prkf)) < 0)
|
||||
goto failed;
|
||||
sc_debug(card->ctx, "prv ef type %i\n",prkf->ef_structure);
|
||||
prkf->size = keybits;
|
||||
|
||||
/* Access condition of private object DF. */
|
||||
path = prkf->path;
|
||||
path.len -= 2;
|
||||
if ((rv = sc_profile_get_file_by_path(profile, &path, &tmpf)))
|
||||
goto failed;
|
||||
else if ((rv = sc_pkcs15init_authenticate(profile, card, tmpf,
|
||||
SC_AC_OP_CRYPTO)) < 0)
|
||||
goto failed;
|
||||
else if ((rv = sc_pkcs15init_authenticate(profile, card, tmpf,
|
||||
SC_AC_OP_CREATE)) < 0)
|
||||
goto failed;
|
||||
else
|
||||
sc_file_free(tmpf);
|
||||
|
||||
/* In the private key DF create the temporary public RSA file. */
|
||||
sc_debug(card->ctx, "ready to create public key\n");
|
||||
sc_file_dup(&tmpf, prkf);
|
||||
tmpf->type = SC_FILE_TYPE_INTERNAL_EF;
|
||||
tmpf->ef_structure = SC_CARDCTL_OBERTHUR_KEY_RSA_PUBLIC;
|
||||
tmpf->id = 0x1012;
|
||||
tmpf->path.value[tmpf->path.len - 2] = 0x10;
|
||||
tmpf->path.value[tmpf->path.len - 1] = 0x12;
|
||||
|
||||
if ((rv = sc_pkcs15init_create_file(profile, card, prkf)))
|
||||
goto failed;
|
||||
else if ((rv = sc_pkcs15init_create_file(profile, card, tmpf)))
|
||||
goto failed;
|
||||
|
||||
memset(&args, 0, sizeof(args));
|
||||
args.id_prv = prkf->id;
|
||||
args.id_pub = tmpf->id;
|
||||
args.exponent = 0x10001;
|
||||
args.key_bits = keybits;
|
||||
args.pubkey_len = keybits/8;
|
||||
args.pubkey = malloc(keybits/8);
|
||||
if (!args.pubkey) {
|
||||
rv = SC_ERROR_OUT_OF_MEMORY;
|
||||
goto failed;
|
||||
}
|
||||
|
||||
sc_debug(card->ctx, "sc_card_ctl %s\n","SC_CARDCTL_OBERTHUR_GENERATE_KEY");
|
||||
if ((rv = sc_card_ctl(card, SC_CARDCTL_OBERTHUR_GENERATE_KEY, &args)) < 0)
|
||||
goto failed;
|
||||
|
||||
/* extract public key */
|
||||
pubkey->algorithm = SC_ALGORITHM_RSA;
|
||||
pubkey->u.rsa.modulus.len = keybits / 8;
|
||||
pubkey->u.rsa.modulus.data = (u8 *) malloc(keybits / 8);
|
||||
if (!pubkey->u.rsa.modulus.data) {
|
||||
rv = SC_ERROR_MEMORY_FAILURE;
|
||||
goto failed;
|
||||
}
|
||||
|
||||
//FIXME and if the exponent length is not 3?
|
||||
pubkey->u.rsa.exponent.len = 3;
|
||||
pubkey->u.rsa.exponent.data = (u8 *) malloc(3);
|
||||
if (!pubkey->u.rsa.exponent.data) {
|
||||
rv = SC_ERROR_MEMORY_FAILURE;
|
||||
goto failed;
|
||||
}
|
||||
memcpy(pubkey->u.rsa.exponent.data, "\x01\x00\x01", 3);
|
||||
memcpy(pubkey->u.rsa.modulus.data, args.pubkey, args.pubkey_len);
|
||||
|
||||
info->key_reference = 1;
|
||||
info->path = prkf->path;
|
||||
|
||||
sc_debug(card->ctx, "delete temporary public key\n");
|
||||
if ((rv = cosm_delete_file(card, profile, tmpf)))
|
||||
goto failed;
|
||||
|
||||
failed:
|
||||
if (tmpf) sc_file_free(tmpf);
|
||||
if (prkf) sc_file_free(prkf);
|
||||
sc_debug(card->ctx, "return %i\n",rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Store a private key
|
||||
*/
|
||||
static int
|
||||
cosm_new_key(struct sc_profile *profile, struct sc_card *card,
|
||||
struct sc_pkcs15_prkey *key, unsigned int index,
|
||||
struct sc_pkcs15_prkey_info *info)
|
||||
{
|
||||
struct sc_file *prvfile = NULL, *pubfile = NULL;
|
||||
struct sc_pkcs15_prkey_rsa *rsa = NULL;
|
||||
struct sc_pkcs15_bignum bn[6];
|
||||
u8 *buff;
|
||||
int rv, ii;
|
||||
|
||||
sc_debug(card->ctx, " index %i\n", index);
|
||||
if (key->algorithm != SC_ALGORITHM_RSA) {
|
||||
sc_error(card->ctx, "For a while supports only RSA keys.");
|
||||
return SC_ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
/* Create and populate the private part. */
|
||||
rv = cosm_new_file(profile, card, SC_PKCS15_TYPE_PRKEY_RSA, index,
|
||||
&prvfile);
|
||||
if (rv < 0)
|
||||
return SC_ERROR_SYNTAX_ERROR;
|
||||
|
||||
sc_debug(card->ctx, " prvfile->id %i; path=%s\n",
|
||||
prvfile->id, sc_print_path(&prvfile->path));
|
||||
|
||||
rsa = &key->u.rsa;
|
||||
|
||||
prvfile->size = rsa->modulus.len << 3;
|
||||
buff = malloc(rsa->modulus.len);
|
||||
if (!buff) {
|
||||
sc_error(card->ctx, "Memory allocation error.");
|
||||
return SC_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
rv = sc_select_file(card, &prvfile->path, NULL);
|
||||
if (rv==SC_ERROR_FILE_NOT_FOUND)
|
||||
rv = sc_pkcs15init_create_file(profile, card, prvfile);
|
||||
|
||||
if (rv <0)
|
||||
goto failed;
|
||||
|
||||
if ((rv = sc_pkcs15init_authenticate(profile, card, prvfile,
|
||||
SC_AC_OP_UPDATE)) <0)
|
||||
goto failed;
|
||||
|
||||
bn[0] = rsa->p;
|
||||
bn[1] = rsa->q;
|
||||
bn[2] = rsa->iqmp;
|
||||
bn[3] = rsa->dmp1;
|
||||
bn[4] = rsa->dmq1;
|
||||
for (ii=0;ii<5;ii++) {
|
||||
struct sc_cardctl_oberthur_updatekey_info args;
|
||||
|
||||
memset(&args, 0, sizeof(args));
|
||||
args.type = SC_CARDCTL_OBERTHUR_KEY_RSA_CRT;
|
||||
args.component = ii+1;
|
||||
args.data = bn[ii].data;
|
||||
args.len = bn[ii].len;
|
||||
rv = sc_card_ctl(card, SC_CARDCTL_OBERTHUR_UPDATE_KEY, &args);
|
||||
if (rv)
|
||||
goto failed;
|
||||
}
|
||||
|
||||
info->path = prvfile->path;
|
||||
info->modulus_length = rsa->modulus.len << 3;
|
||||
|
||||
failed:
|
||||
if (pubfile) sc_file_free(pubfile);
|
||||
if (prvfile) sc_file_free(prvfile);
|
||||
if (buff) free(buff);
|
||||
|
||||
sc_debug(card->ctx, "return %i\n", rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
struct sc_pkcs15init_operations sc_pkcs15init_oberthur_operations;
|
||||
|
||||
struct sc_pkcs15init_operations *
|
||||
sc_pkcs15init_get_oberthur_ops(void)
|
||||
{
|
||||
struct sc_pkcs15init_operations *ops = &sc_pkcs15init_oberthur_operations;
|
||||
|
||||
ops->erase_card = cosm_erase_card;
|
||||
|
||||
//NEW
|
||||
ops->create_dir = NULL;
|
||||
ops->create_domain = NULL;
|
||||
ops->select_pin_reference = cosm_select_pin_reference;
|
||||
ops->create_pin = cosm_create_pin;
|
||||
ops->select_key_reference = NULL;
|
||||
ops->create_key = NULL;
|
||||
ops->store_key = NULL;
|
||||
ops->generate_key = NULL;
|
||||
ops->encode_private_key = NULL;
|
||||
ops->encode_public_key = NULL;
|
||||
|
||||
//OLD
|
||||
ops->init_app = cosm_init_app;
|
||||
ops->new_pin = NULL;
|
||||
ops->new_key = cosm_new_key;
|
||||
ops->new_file = cosm_new_file;
|
||||
ops->old_generate_key = cosm_old_generate_key;
|
||||
|
||||
return ops;
|
||||
};
|
@ -72,6 +72,17 @@ option small {
|
||||
}
|
||||
}
|
||||
|
||||
option oberthur {
|
||||
macros {
|
||||
odf-size = 512;
|
||||
aodf-size = 512;
|
||||
cdf-size = 3072;
|
||||
prkdf-size = 1024;
|
||||
pukdf-size = 1024;
|
||||
dodf-size = 512;
|
||||
}
|
||||
}
|
||||
|
||||
# This option tells pkcs15-init to use the direct option
|
||||
# when storing certificates on the card (i.e. put the
|
||||
# certificates into the CDF itself, rather than a
|
||||
|
Loading…
Reference in New Issue
Block a user