- pkcs15 rewrite
git-svn-id: https://www.opensc-project.org/svnp/opensc/trunk@1508 c6295689-39f2-0310-b995-f0e70906c6a9
This commit is contained in:
parent
3d283fd925
commit
23c1e81512
@ -22,11 +22,11 @@ EXTRA_DIST = $(PROFILES) Makefile.mak
|
||||
lib_LTLIBRARIES = libpkcs15init.la
|
||||
|
||||
libpkcs15init_la_SOURCES = \
|
||||
pkcs15-lib.c profile.c \
|
||||
pkcs15-lib.c profile.c keycache.c \
|
||||
pkcs15-gpk.c pkcs15-miocos.c pkcs15-cflex.c \
|
||||
pkcs15-etoken.c
|
||||
libpkcs15init_la_LDFLAGS = -version-info @OPENSC_LT_CURRENT@:@OPENSC_LT_REVISION@:@OPENSC_LT_AGE@
|
||||
|
||||
include_HEADERS = pkcs15-init.h
|
||||
noinst_HEADERS = profile.h
|
||||
noinst_HEADERS = profile.h keycache.h
|
||||
pkgdata_DATA = $(PROFILES)
|
||||
|
@ -5,7 +5,7 @@ TARGET = pkcs15init.lib
|
||||
HEADERS = pkcs15-init.h
|
||||
HEADERSDIR = $(TOPDIR)\src\include\opensc
|
||||
|
||||
OBJECTS = profile.obj pkcs15-lib.obj \
|
||||
OBJECTS = profile.obj pkcs15-lib.obj keycache.obj \
|
||||
pkcs15-miocos.obj pkcs15-gpk.obj pkcs15-cflex.obj \
|
||||
pkcs15-etoken.obj
|
||||
|
||||
|
@ -8,8 +8,14 @@ cardinfo {
|
||||
}
|
||||
|
||||
# Define reasonable limits for PINs and PUK
|
||||
# Note that we do not set a file path or reference
|
||||
# here; that is done dynamically.
|
||||
# We set the reference for SO pin+puk here, because
|
||||
# those are hard-coded (if a PUK us assigned).
|
||||
PIN so-pin {
|
||||
reference = 0;
|
||||
}
|
||||
PIN so-puk {
|
||||
reference = 1;
|
||||
}
|
||||
PIN user-pin {
|
||||
attempts = 3;
|
||||
}
|
||||
@ -31,24 +37,66 @@ filesystem {
|
||||
size = 256;
|
||||
}
|
||||
|
||||
EF template-private-key {
|
||||
type = internal-ef;
|
||||
file-id = 4B01; # This is the base FileID
|
||||
size = 266; # 266 is enough for 1024-bit keys
|
||||
ACL = *=NEVER, UPDATE=$PIN, ERASE=$PIN;
|
||||
}
|
||||
EF template-public-key {
|
||||
file-id = 5501;
|
||||
ACL = *=NEVER, READ=NONE, UPDATE=$PIN, ERASE=$PIN;
|
||||
# This template defines files for keys, certificates etc.
|
||||
#
|
||||
# When instantiating the template, each file id will be
|
||||
# combined with the last octet of the object's pkcs15 id
|
||||
# to form a unique file ID.
|
||||
template key-domain {
|
||||
# This is a dummy entry - pkcs15-init insists that
|
||||
# this is present
|
||||
EF private-key {
|
||||
file-id = FFFF;
|
||||
}
|
||||
EF public-key {
|
||||
file-id = 3003;
|
||||
structure = transparent;
|
||||
ACL = *=NEVER,
|
||||
READ=NONE,
|
||||
UPDATE=$PIN,
|
||||
ERASE=$PIN;
|
||||
}
|
||||
|
||||
# Certificate template
|
||||
EF certificate {
|
||||
file-id = 3004;
|
||||
structure = transparent;
|
||||
ACL = *=NEVER,
|
||||
READ=NONE,
|
||||
UPDATE=$PIN,
|
||||
ERASE=$PIN;
|
||||
}
|
||||
|
||||
# Extractable private keys are stored in transparent EFs.
|
||||
# Encryption of the content is performed by libopensc.
|
||||
EF extractable-key {
|
||||
file-id = 3001;
|
||||
structure = transparent;
|
||||
ACL = *=NEVER,
|
||||
READ=$PIN,
|
||||
UPDATE=$PIN,
|
||||
ERASE=$PIN;
|
||||
}
|
||||
|
||||
# data objects are stored in transparent EFs.
|
||||
EF data {
|
||||
file-id = 3002;
|
||||
structure = transparent;
|
||||
ACL = *=NEVER,
|
||||
READ=NONE,
|
||||
UPDATE=$PIN,
|
||||
WRITE=$PIN;
|
||||
}
|
||||
|
||||
}
|
||||
EF template-certificate {
|
||||
file-id = 4301;
|
||||
ACL = *=NEVER, READ=NONE, UPDATE=$PIN, ERASE=$PIN;
|
||||
}
|
||||
EF template-extractable-key {
|
||||
file-id = 7000;
|
||||
ACL = *=NEVER, READ=$PIN, UPDATE=$PIN, ERASE=$PIN;
|
||||
}
|
||||
# EF template-private-key {
|
||||
# type = internal-ef;
|
||||
# file-id = 4B01; # This is the base FileID
|
||||
# size = 266; # 266 is enough for 1024-bit keys
|
||||
# ACL = *=NEVER, UPDATE=$PIN, ERASE=$PIN;
|
||||
# }
|
||||
|
||||
# This is needed when generating a key on-card.
|
||||
EF tempfile {
|
||||
file-id = 7EAD;
|
||||
structure = linear-variable-tlv;
|
||||
@ -58,10 +106,3 @@ filesystem {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Define an SO pin
|
||||
# This PIN is not used yet.
|
||||
#PIN sopin {
|
||||
# file = sopinfile;
|
||||
# reference = 0;
|
||||
#}
|
||||
|
@ -1,18 +1,24 @@
|
||||
#
|
||||
# PKCS15 r/w profile for Cryptoflex cards
|
||||
# General purpose PKCS15 profile for Cryptoflex cards
|
||||
#
|
||||
cardinfo {
|
||||
max-pin-length = 8;
|
||||
pin-encoding = ascii-numeric;
|
||||
pin-pad-char = 0x00;
|
||||
pin-domains = yes;
|
||||
|
||||
# This profile does not PIN-protect certificates
|
||||
# stored on the card. If you enable this, you MUST
|
||||
# adjust the sizes of the pin-domain and key-dir DFs
|
||||
# accordingly.
|
||||
protect-certificates = no;
|
||||
}
|
||||
|
||||
# Define reasonable limits for PINs and PUK
|
||||
# Note that we do not set a file path or reference
|
||||
# here; that is done dynamically.
|
||||
# The user pin must always be CHV1, otherwise things
|
||||
# won't work (crypto operations are protected by CHV1)
|
||||
PIN user-pin {
|
||||
attempts = 3;
|
||||
flags = 0x32; # local, initialized, needs-padding
|
||||
}
|
||||
PIN user-puk {
|
||||
attempts = 10;
|
||||
@ -22,70 +28,80 @@ PIN user-puk {
|
||||
# This is added to the file system info specified in the
|
||||
# main profile.
|
||||
filesystem {
|
||||
# Define default ACLs and file ids for CHV1/CHV2
|
||||
EF CHV1 {
|
||||
file-id = 0000;
|
||||
ACL = *=NEVER, UPDATE=CHV1;
|
||||
}
|
||||
EF CHV2 {
|
||||
file-id = 0100;
|
||||
ACL = *=NEVER, UPDATE=CHV2;
|
||||
}
|
||||
|
||||
DF MF {
|
||||
ACL = *=AUT1;
|
||||
|
||||
# The DELETE=NONE ACLs will go away once the code
|
||||
# works. It's here to make sure I can erase the card
|
||||
# even if I mess up big time.
|
||||
DF PKCS15-AppDF {
|
||||
ACL = *=AUT1, FILES=NONE;
|
||||
DF keydir-1 {
|
||||
ACL = *=AUT1, FILES=NONE;
|
||||
file-id = 4B01;
|
||||
size = 1370; # Sufficient for a 2048-bit key
|
||||
EF pinfile-1 {
|
||||
file-id = 0000;
|
||||
size = 23;
|
||||
ACL = *=NEVER, UPDATE=AUT1;
|
||||
}
|
||||
EF template-private-key-1 {
|
||||
file-id = 0012;
|
||||
ACL = *=NEVER, CRYPTO=$PIN, UPDATE=AUT1;
|
||||
ACL = *=$SOPIN, FILES=NONE, DELETE=NONE;
|
||||
size = 7500;
|
||||
|
||||
# This "pin-domain" DF is a template that is
|
||||
# instantiated for each PIN created on the card.
|
||||
#
|
||||
# When instantiating the template, each file id will be
|
||||
# combined with the last octet of the object's pkcs15 id
|
||||
# to form a unique file ID. That is, PIN 01 will reside
|
||||
# in 4b01, PIN 02 will reside in 4b02, etc.
|
||||
template pin-domain {
|
||||
DF pin-dir {
|
||||
ACL = *=$SOPIN, FILES=NONE, DELETE=NONE;
|
||||
file-id = 4B00;
|
||||
|
||||
# The minimum size for a 2048 bit key is 1396
|
||||
size = 1396;
|
||||
}
|
||||
EF template-extractable-key-1 {
|
||||
file-id = 7000;
|
||||
ACL = *=NEVER, READ=CHV1, UPDATE=AUT1;
|
||||
}
|
||||
}
|
||||
DF keydir-2 {
|
||||
ACL = *=AUT1, FILES=NONE;
|
||||
file-id = 4B02;
|
||||
size = 1370; # Sufficient for a 2048-bit key
|
||||
EF pinfile-2 {
|
||||
file-id = 0000;
|
||||
size = 23;
|
||||
ACL = *=NEVER, UPDATE=AUT1;
|
||||
}
|
||||
EF template-private-key-2 {
|
||||
file-id = 0012;
|
||||
ACL = *=NEVER, CRYPTO=CHV1, UPDATE=AUT1;
|
||||
}
|
||||
|
||||
# For PIN-protected files, instantiate this template
|
||||
# below the pin directory.
|
||||
# For unprotected objects, install within the application DF.
|
||||
#
|
||||
# When instantiating the template, each file id will be
|
||||
# combined with the last octet of the object's pkcs15 id
|
||||
# to form a unique file ID.
|
||||
template key-domain {
|
||||
# In order to support more than one key per PIN,
|
||||
# each key must be within its own subdirectory.
|
||||
DF key-directory {
|
||||
ACL = *=$PIN, FILES=NONE;
|
||||
file-id = 3000;
|
||||
size = 1332;
|
||||
|
||||
EF private-key {
|
||||
file-id = 0012;
|
||||
ACL = *=NEVER, CRYPTO=$PIN, UPDATE=$PIN;
|
||||
}
|
||||
EF internal-pubkey-file {
|
||||
file-id = 1012;
|
||||
ACL = *=$PIN, READ=NONE;
|
||||
}
|
||||
}
|
||||
EF template-extractable-key-2 {
|
||||
file-id = 7000;
|
||||
ACL = *=NEVER, READ=$PIN, UPDATE=AUT1;
|
||||
}
|
||||
}
|
||||
EF template-public-key-1 {
|
||||
file-id = 5201;
|
||||
ACL = *=AUT1, READ=NONE;
|
||||
}
|
||||
EF template-public-key-2 {
|
||||
file-id = 5202;
|
||||
ACL = *=AUT1, READ=NONE;
|
||||
}
|
||||
EF template-certificate-1 {
|
||||
file-id = 5501;
|
||||
ACL = *=AUT1, READ=NONE;
|
||||
}
|
||||
EF template-certificate-2 {
|
||||
file-id = 5502;
|
||||
ACL = *=AUT1, READ=NONE;
|
||||
}
|
||||
EF extractable-key {
|
||||
file-id = 4300;
|
||||
ACL = *=NEVER, READ=$PIN, UPDATE=$PIN;
|
||||
}
|
||||
EF public-key {
|
||||
file-id = 4400;
|
||||
ACL = *=$PIN, READ=NONE;
|
||||
}
|
||||
EF certificate {
|
||||
file-id = 4500;
|
||||
ACL = *=$PIN, READ=NONE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Define an SO pin
|
||||
# This PIN is not used yet.
|
||||
#PIN sopin {
|
||||
# file = sopinfile;
|
||||
# reference = 0;
|
||||
#}
|
||||
|
@ -7,12 +7,6 @@ cardinfo {
|
||||
pin-pad-char = 0x00;
|
||||
}
|
||||
|
||||
# Define reference for SO PIN
|
||||
PIN so-pin {
|
||||
file = pinfile;
|
||||
reference = 0x08;
|
||||
}
|
||||
|
||||
# Additional filesystem info.
|
||||
# This is added to the file system info specified in the
|
||||
# main profile.
|
||||
@ -37,53 +31,60 @@ filesystem {
|
||||
ACL = *=NEVER;
|
||||
}
|
||||
|
||||
# Private key files.
|
||||
# GPK private key files will never let you read the private key
|
||||
# part, so it's okay to set READ=NONE. What's more, we may need
|
||||
# read access so we're able to check the key size/type.
|
||||
EF template-private-key {
|
||||
file-id = 0006; # This is the base FileID
|
||||
structure = 0x2C; # GPK specific
|
||||
ACL = *=NEVER,
|
||||
READ=NONE,
|
||||
CRYPTO=$PIN,
|
||||
UPDATE=$PIN,
|
||||
WRITE=$PIN;
|
||||
}
|
||||
# This template defines files for keys, certificates etc.
|
||||
#
|
||||
# When instantiating the template, each file id will be
|
||||
# combined with the last octet of the object's pkcs15 id
|
||||
# to form a unique file ID.
|
||||
template key-domain {
|
||||
# Private key files.
|
||||
# GPK private key files will never let you read the private key
|
||||
# part, so it's okay to set READ=NONE. What's more, we may need
|
||||
# read access so we're able to check the key size/type.
|
||||
EF private-key {
|
||||
file-id = 3000; # This is the base FileID
|
||||
structure = 0x2C; # GPK specific
|
||||
ACL = *=NEVER,
|
||||
READ=NONE,
|
||||
CRYPTO=$PIN,
|
||||
UPDATE=$PIN,
|
||||
WRITE=$PIN;
|
||||
}
|
||||
|
||||
# Extractable private keys are stored in transparent EFs.
|
||||
# Encryption of the content is performed by libopensc.
|
||||
EF template-extractable-key {
|
||||
file-id = 7000;
|
||||
structure = transparent;
|
||||
ACL = *=NEVER,
|
||||
# Extractable private keys are stored in transparent EFs.
|
||||
# Encryption of the content is performed by libopensc.
|
||||
EF extractable-key {
|
||||
file-id = 3001;
|
||||
structure = transparent;
|
||||
ACL = *=NEVER,
|
||||
READ=$PIN,
|
||||
UPDATE=$PIN,
|
||||
WRITE=$PIN;
|
||||
}
|
||||
}
|
||||
|
||||
# data objects are stored in transparent EFs.
|
||||
EF template-data {
|
||||
file-id = 5000;
|
||||
structure = transparent;
|
||||
ACL = *=NEVER,
|
||||
# data objects are stored in transparent EFs.
|
||||
EF data {
|
||||
file-id = 3002;
|
||||
structure = transparent;
|
||||
ACL = *=NEVER,
|
||||
READ=NONE,
|
||||
UPDATE=$PIN,
|
||||
WRITE=$PIN;
|
||||
}
|
||||
}
|
||||
|
||||
EF template-public-key {
|
||||
file-id = 8000;
|
||||
structure = transparent;
|
||||
ACL = *=NONE;
|
||||
}
|
||||
EF public-key {
|
||||
file-id = 3003;
|
||||
structure = transparent;
|
||||
ACL = *=NONE;
|
||||
}
|
||||
|
||||
# Certificate template
|
||||
EF template-certificate {
|
||||
file-id = 9000;
|
||||
structure = transparent;
|
||||
ACL = *=NONE;
|
||||
}
|
||||
# Certificate template
|
||||
EF certificate {
|
||||
file-id = 3004;
|
||||
structure = transparent;
|
||||
ACL = *=NONE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
387
src/pkcs15init/keycache.c
Normal file
387
src/pkcs15init/keycache.c
Normal file
@ -0,0 +1,387 @@
|
||||
/*
|
||||
* Cache authentication info
|
||||
*
|
||||
* Copyright (C) 2003, Olaf Kirch <okir@lst.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
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
#ifdef HAVE_STRINGS_H
|
||||
#include <strings.h>
|
||||
#endif
|
||||
#include <assert.h>
|
||||
#include <opensc/pkcs15.h>
|
||||
#include "profile.h"
|
||||
#include "pkcs15-init.h"
|
||||
#include <opensc/cardctl.h>
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#undef KEYCACHE_DEBUG
|
||||
#define MAX_SECRET 32 /* sufficient for 128bit symmetric keys */
|
||||
|
||||
struct secret {
|
||||
struct secret * next;
|
||||
sc_path_t path;
|
||||
int type, ref, named_pin;
|
||||
size_t len;
|
||||
unsigned char value[MAX_SECRET];
|
||||
};
|
||||
|
||||
static struct secret * secret_cache = NULL;
|
||||
static struct secret * named_pin[SC_PKCS15INIT_NPINS];
|
||||
|
||||
#ifdef KEYCACHE_DEBUG
|
||||
static void sc_keycache_dump(void);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Check if a keycache entry matches the given type, reference
|
||||
* and path.
|
||||
*/
|
||||
static int
|
||||
__match_entry(struct secret *s, int type, int ref, const sc_path_t *path,
|
||||
int match_prefix)
|
||||
{
|
||||
if ((type != -1 && s->type != type)
|
||||
|| (ref != -1 && s->ref != ref))
|
||||
return 0;
|
||||
|
||||
/* Compare the two paths */
|
||||
if (match_prefix) {
|
||||
/* Prefix match - the path argument given by
|
||||
* the caller should be a prefix of the keycache
|
||||
* entry.
|
||||
*/
|
||||
/* If the path is a wildcard, it's a match */
|
||||
if (path == NULL)
|
||||
return 1;
|
||||
if (s->path.len > path->len)
|
||||
return 0;
|
||||
} else {
|
||||
/* Exact match - path names must patch exactly.
|
||||
* A NULL path argument is an empty path */
|
||||
if (path == 0)
|
||||
return (s->path.len == 0);
|
||||
if (s->path.len != path->len)
|
||||
return 0;
|
||||
}
|
||||
if (memcmp(s->path.value, path->value, s->path.len))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find the secret, given a path name, type and reference.
|
||||
* If none found, search for it in parent directories.
|
||||
*/
|
||||
static struct secret *
|
||||
find_entry(const sc_path_t *path, int type, int ref, int match_prefix)
|
||||
{
|
||||
struct secret *s;
|
||||
|
||||
if (type == SC_AC_SYMBOLIC) {
|
||||
if (0 <= ref && ref < SC_PKCS15INIT_NPINS
|
||||
&& (s = named_pin[ref]) != NULL
|
||||
&& __match_entry(s, SC_AC_CHV, -1, path, match_prefix))
|
||||
return s;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (s = secret_cache; s; s = s->next) {
|
||||
if (__match_entry(s, type, ref, path, match_prefix))
|
||||
break;
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find a key with matching type/reference. If a path is
|
||||
* given, find the entry with the longest matching prefix.
|
||||
*/
|
||||
static struct secret *
|
||||
search_key(const sc_path_t *path, int type, int ref)
|
||||
{
|
||||
struct secret *best = NULL, *s;
|
||||
|
||||
if (type == SC_AC_SYMBOLIC) {
|
||||
if (0 <= ref && ref < SC_PKCS15INIT_NPINS
|
||||
&& (s = named_pin[ref]) != NULL
|
||||
&& __match_entry(s, type, -1, path, 1))
|
||||
return s;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (s = secret_cache; s; s = s->next) {
|
||||
if (s->len != 0
|
||||
&& __match_entry(s, type, ref, path, 1)) {
|
||||
/* Ignore if path shorter than the longest
|
||||
* matched prefix.
|
||||
*/
|
||||
if (path == NULL || best == NULL
|
||||
|| best->path.len < path->len)
|
||||
best = s;
|
||||
}
|
||||
}
|
||||
|
||||
return best;
|
||||
}
|
||||
|
||||
/*
|
||||
* Store a secret in the cache
|
||||
*/
|
||||
struct secret *
|
||||
new_entry(const sc_path_t *path, int type, int ref)
|
||||
{
|
||||
struct secret *s;
|
||||
|
||||
s = (struct secret *) calloc(1, sizeof(*s));
|
||||
s->next = secret_cache;
|
||||
secret_cache = s;
|
||||
if (path)
|
||||
s->path = *path;
|
||||
if (type == SC_AC_SYMBOLIC) {
|
||||
s->type = SC_AC_CHV;
|
||||
s->ref = -1;
|
||||
s->named_pin = ref;
|
||||
} else {
|
||||
s->type = type;
|
||||
s->ref = ref;
|
||||
s->named_pin = -1;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
/*
|
||||
* Cache the given key
|
||||
*/
|
||||
int
|
||||
sc_keycache_put_key(const sc_path_t *path, int type, int ref,
|
||||
const unsigned char *secret, size_t len)
|
||||
{
|
||||
struct secret *s;
|
||||
|
||||
if (len > MAX_SECRET)
|
||||
return SC_ERROR_BUFFER_TOO_SMALL;
|
||||
|
||||
if (!(s = find_entry(path, type, ref, 0)))
|
||||
s = new_entry(path, type, ref);
|
||||
|
||||
memset(s->value, 0, sizeof(s->value));
|
||||
memcpy(s->value, secret, len);
|
||||
s->len = len;
|
||||
|
||||
#ifdef KEYCACHE_DEBUG
|
||||
sc_keycache_dump();
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
sc_keycache_put_pin(const sc_path_t *path, int ref, const char *pin)
|
||||
{
|
||||
return sc_keycache_put_key(path, SC_AC_CHV, ref, pin,
|
||||
pin? strlen(pin) : 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get a key/pin from the cache
|
||||
*/
|
||||
int
|
||||
sc_keycache_get_key(const sc_path_t *path, int type, int ref,
|
||||
unsigned char *key, size_t size)
|
||||
{
|
||||
struct secret *s;
|
||||
|
||||
if (!(s = search_key(path, type, ref)))
|
||||
return SC_ERROR_OBJECT_NOT_FOUND;
|
||||
|
||||
if (s->len > size)
|
||||
return SC_ERROR_BUFFER_TOO_SMALL;
|
||||
memcpy(key, s->value, s->len);
|
||||
return s->len;
|
||||
}
|
||||
|
||||
const char *
|
||||
sc_keycache_get_pin(const sc_path_t *path, int ref)
|
||||
{
|
||||
struct secret *s;
|
||||
|
||||
if (!(s = search_key(path, SC_AC_CHV, ref)))
|
||||
return NULL;
|
||||
|
||||
return s->len? s->value : NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Define a symbolic name for a PIN. This is used to define
|
||||
* what $PIN and $SOPIN mean in a given context.
|
||||
*/
|
||||
int
|
||||
sc_keycache_set_pin_name(const sc_path_t *path, int ref, int name)
|
||||
{
|
||||
struct secret *s, *old;
|
||||
|
||||
if (name < 0 || name >= SC_PKCS15INIT_NPINS)
|
||||
return SC_ERROR_INVALID_ARGUMENTS;
|
||||
|
||||
/* If we had previously marked a PIN with this name,
|
||||
* unlink it */
|
||||
if ((old = named_pin[name]) != NULL) {
|
||||
named_pin[name] = NULL;
|
||||
old->named_pin = -1;
|
||||
}
|
||||
|
||||
if (ref >= 0) {
|
||||
/* Create the named PIN if it doesn't exist */
|
||||
if (!(s = find_entry(path, SC_AC_CHV, ref, 0)))
|
||||
s = new_entry(path, SC_AC_CHV, ref);
|
||||
|
||||
/* Set the pin name */
|
||||
s->named_pin = name;
|
||||
|
||||
/* If the old SOPIN was just the name entry,
|
||||
* copy over the name to the new entry */
|
||||
if (old && old->ref == -1 && s->len == 0) {
|
||||
memcpy(s->value, old->value, old->len);
|
||||
s->len = old->len;
|
||||
}
|
||||
|
||||
named_pin[name] = s;
|
||||
}
|
||||
|
||||
#ifdef KEYCACHE_DEBUG
|
||||
sc_keycache_dump();
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the symbolic name of a PIN, if any
|
||||
*/
|
||||
int
|
||||
sc_keycache_get_pin_name(const sc_path_t *path, int ref)
|
||||
{
|
||||
struct secret *s;
|
||||
|
||||
#ifdef KEYCACHE_DEBUG
|
||||
printf("sc_keycache_get_pin_name(%s, %d)\n",
|
||||
path? sc_print_path(path) : "any", ref);
|
||||
#endif
|
||||
|
||||
if (!(s = find_entry(path, SC_AC_CHV, ref, 1)))
|
||||
return -1;
|
||||
return s->named_pin;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get path and reference of symbolic PIN
|
||||
*/
|
||||
int
|
||||
sc_keycache_find_named_pin(const sc_path_t *path, int name)
|
||||
{
|
||||
struct secret *s;
|
||||
|
||||
if (name < 0 || name >= SC_PKCS15INIT_NPINS
|
||||
|| (s = named_pin[name]) == NULL
|
||||
|| !__match_entry(s, SC_AC_CHV, -1, path, 1))
|
||||
return -1;
|
||||
|
||||
return s->ref;
|
||||
}
|
||||
|
||||
/*
|
||||
* Zap one or more keys from the cache
|
||||
*/
|
||||
void
|
||||
sc_keycache_forget_key(const sc_path_t *path, int type, int ref)
|
||||
{
|
||||
struct secret *s, **prev;
|
||||
|
||||
prev = &secret_cache;
|
||||
while ((s = *prev) != NULL) {
|
||||
if (__match_entry(s, type, ref, path, 1)) {
|
||||
*prev = s->next;
|
||||
memset(s, 0, sizeof(*s));
|
||||
free(s);
|
||||
} else {
|
||||
prev = &s->next;
|
||||
}
|
||||
}
|
||||
#ifdef KEYCACHE_DEBUG
|
||||
sc_keycache_dump();
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Dump the keycache
|
||||
*/
|
||||
#ifdef KEYCACHE_DEBUG
|
||||
void
|
||||
sc_keycache_dump(void)
|
||||
{
|
||||
struct secret *s;
|
||||
int j;
|
||||
|
||||
printf("== Keycache ==\n");
|
||||
for (s = secret_cache; s; s = s->next) {
|
||||
char buf[32];
|
||||
|
||||
switch (s->type) {
|
||||
case SC_AC_CHV: printf("CHV"); break;
|
||||
case SC_AC_AUT: printf("AUT"); break;
|
||||
case SC_AC_PRO: printf("PRO"); break;
|
||||
default: printf("%d/", s->type);
|
||||
}
|
||||
printf("%d %-16s\t", s->ref, sc_print_path(&s->path));
|
||||
sc_bin_to_hex(s->value, s->len, buf, sizeof(buf), ':');
|
||||
printf("key=%s", buf);
|
||||
|
||||
switch (s->named_pin) {
|
||||
case SC_PKCS15INIT_SO_PIN:
|
||||
printf(", SO PIN"); break;
|
||||
case SC_PKCS15INIT_SO_PUK:
|
||||
printf(", SO PUK"); break;
|
||||
case SC_PKCS15INIT_USER_PIN:
|
||||
printf(", USER PIN"); break;
|
||||
case SC_PKCS15INIT_USER_PUK:
|
||||
printf(", USER PUK"); break;
|
||||
}
|
||||
|
||||
if (s->named_pin >= 0
|
||||
&& named_pin[s->named_pin] != s)
|
||||
printf(" [PTR MISMATCH!]");
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
for (j = 0; j < SC_PKCS15INIT_NPINS; j++) {
|
||||
if ((s = named_pin[j]) == NULL)
|
||||
continue;
|
||||
if (s->named_pin != j)
|
||||
printf(" named_pin[%d] MISMATCH: name=%d\n",
|
||||
j, s->named_pin);
|
||||
}
|
||||
}
|
||||
#endif
|
34
src/pkcs15init/keycache.h
Normal file
34
src/pkcs15init/keycache.h
Normal file
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Cache authentication info
|
||||
*
|
||||
* Copyright (C) 2003, Olaf Kirch <okir@lst.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
|
||||
*/
|
||||
|
||||
#ifndef _PKCS15INIT_KEYCACHE_H
|
||||
#define _PKCS15INIT_KEYCACHE_H
|
||||
|
||||
extern int sc_keycache_put_key(const sc_path_t *, int, int,
|
||||
const unsigned char *, size_t);
|
||||
extern int sc_keycache_put_pin(const sc_path_t *, int, const char *);
|
||||
extern int sc_keycache_set_pin_name(const sc_path_t *, int, int);
|
||||
extern int sc_keycache_get_pin_name(const sc_path_t *, int);
|
||||
extern int sc_keycache_find_named_pin(const sc_path_t *, int);
|
||||
extern int sc_keycache_get_key(const sc_path_t *, int, int, unsigned char *, size_t);
|
||||
extern const char *sc_keycache_get_pin(const sc_path_t *, int);
|
||||
extern void sc_keycache_forget_key(const sc_path_t *, int, int);
|
||||
|
||||
#endif /* _PKCS15INIT_KEYCACHE_H */
|
File diff suppressed because it is too large
Load Diff
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* eToken PRO specific operation for PKCS15 initialization
|
||||
* CardOS specific operation for PKCS15 initialization
|
||||
*
|
||||
* Copyright (C) 2002 Olaf Kirch <okir@lst.de>
|
||||
*
|
||||
@ -54,9 +54,19 @@ struct rsakey {
|
||||
/*
|
||||
* Local functions
|
||||
*/
|
||||
static int etoken_store_pin(sc_profile_t *profile, sc_card_t *card,
|
||||
sc_pkcs15_pin_info_t *pin_info, int puk_id,
|
||||
const u8 *pin, size_t pin_len);
|
||||
static int etoken_create_sec_env(sc_profile_t *, sc_card_t *,
|
||||
unsigned int, unsigned int);
|
||||
static int etoken_new_file(struct sc_profile *, struct sc_card *,
|
||||
unsigned int, unsigned int,
|
||||
struct sc_file **);
|
||||
static int etoken_put_key(struct sc_profile *, struct sc_card *,
|
||||
int, unsigned int, struct sc_pkcs15_prkey_rsa *);
|
||||
static int etoken_key_algorithm(unsigned int, int *);
|
||||
static int etoken_extract_pubkey(sc_card_t *, int,
|
||||
u8, sc_pkcs15_bignum_t *);
|
||||
static void error(struct sc_profile *, const char *, ...);
|
||||
|
||||
/* Object IDs for PIN objects.
|
||||
@ -123,20 +133,273 @@ etoken_erase(struct sc_profile *profile, struct sc_card *card)
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize pin file
|
||||
* Create the Application DF
|
||||
*/
|
||||
static int
|
||||
etoken_store_pin(struct sc_profile *profile, struct sc_card *card,
|
||||
int pin_type, unsigned int pin_id, unsigned int puk_id,
|
||||
etoken_create_dir(sc_profile_t *profile, sc_card_t *card, sc_file_t *df)
|
||||
{
|
||||
int r;
|
||||
|
||||
/* Create the application DF */
|
||||
if ((r = sc_pkcs15init_create_file(profile, card, df)) < 0)
|
||||
return r;
|
||||
|
||||
if ((r = sc_select_file(card, &df->path, NULL)) < 0)
|
||||
return r;
|
||||
|
||||
/* Create a default security environment for this DF.
|
||||
* This SE autometically becomes the current SE when the
|
||||
* DF is selected. */
|
||||
if ((r = etoken_create_sec_env(profile, card, 0x01, 0x00)) < 0)
|
||||
return r;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Caller passes in a suggested PIN reference.
|
||||
* See if it's good, and if it isn't, propose something better
|
||||
*/
|
||||
static int
|
||||
etoken_select_pin_reference(sc_profile_t *profile, sc_card_t *card,
|
||||
sc_pkcs15_pin_info_t *pin_info)
|
||||
{
|
||||
int preferred, current;
|
||||
|
||||
if ((current = pin_info->reference) < 0)
|
||||
current = 1;
|
||||
|
||||
if (pin_info->flags & SC_PKCS15_PIN_FLAG_SO_PIN) {
|
||||
preferred = 1;
|
||||
} else {
|
||||
preferred = current;
|
||||
/* PINs are even numbered, PUKs are odd */
|
||||
if (!(preferred & 1))
|
||||
preferred++;
|
||||
if (preferred >= 126)
|
||||
return SC_ERROR_TOO_MANY_OBJECTS;
|
||||
}
|
||||
|
||||
if (current > preferred)
|
||||
return SC_ERROR_TOO_MANY_OBJECTS;
|
||||
pin_info->reference = preferred;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Store a PIN
|
||||
*/
|
||||
static int
|
||||
etoken_create_pin(sc_profile_t *profile, sc_card_t *card, sc_file_t *df,
|
||||
sc_pkcs15_pin_info_t *pin_info,
|
||||
const u8 *pin, size_t pin_len,
|
||||
const u8 *puk, size_t puk_len)
|
||||
{
|
||||
unsigned int puk_id = ETOKEN_AC_NEVER;
|
||||
int r;
|
||||
|
||||
if (!pin || !pin_len)
|
||||
return SC_ERROR_INVALID_ARGUMENTS;
|
||||
|
||||
r = sc_select_file(card, &df->path, NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (puk && puk_len) {
|
||||
struct sc_pkcs15_pin_info puk_info;
|
||||
|
||||
sc_profile_get_pin_info(profile,
|
||||
SC_PKCS15INIT_USER_PUK, &puk_info);
|
||||
puk_info.reference = puk_id = pin_info->reference + 1;
|
||||
r = etoken_store_pin(profile, card,
|
||||
&puk_info, ETOKEN_AC_NEVER,
|
||||
puk, puk_len);
|
||||
}
|
||||
|
||||
if (r >= 0) {
|
||||
r = etoken_store_pin(profile, card,
|
||||
pin_info, puk_id,
|
||||
pin, pin_len);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* Select a key reference
|
||||
*/
|
||||
static int
|
||||
etoken_select_key_reference(sc_profile_t *profile, sc_card_t *card,
|
||||
sc_pkcs15_prkey_info_t *key_info)
|
||||
{
|
||||
struct sc_file *df = profile->df_info->file;
|
||||
|
||||
if (key_info->key_reference > 255)
|
||||
return SC_ERROR_TOO_MANY_OBJECTS;
|
||||
|
||||
key_info->path = df->path;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a private key object.
|
||||
* This is a no-op.
|
||||
*/
|
||||
static int
|
||||
etoken_create_key(sc_profile_t *profile, sc_card_t *card,
|
||||
sc_pkcs15_object_t *obj)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Store a private key object.
|
||||
*/
|
||||
static int
|
||||
etoken_store_key(sc_profile_t *profile, sc_card_t *card,
|
||||
sc_pkcs15_object_t *obj,
|
||||
sc_pkcs15_prkey_t *key)
|
||||
{
|
||||
sc_pkcs15_prkey_info_t *key_info = (sc_pkcs15_prkey_info_t *) obj->data;
|
||||
int algorithm, r;
|
||||
|
||||
if (obj->type != SC_PKCS15_TYPE_PRKEY_RSA) {
|
||||
error(profile, "CardOS supports RSA keys only.\n");
|
||||
return SC_ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
if (etoken_key_algorithm(key_info->usage, &algorithm) < 0) {
|
||||
error(profile, "CardOS does not support keys "
|
||||
"that can both sign _and_ decrypt.");
|
||||
return SC_ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
r = etoken_put_key(profile, card, algorithm,
|
||||
key_info->key_reference,
|
||||
&key->u.rsa);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* Key generation
|
||||
*/
|
||||
static int
|
||||
etoken_generate_key(sc_profile_t *profile, sc_card_t *card,
|
||||
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_pkcs15_prkey_rsa key_obj;
|
||||
struct sc_cardctl_etoken_genkey_info args;
|
||||
struct sc_file *temp;
|
||||
u8 abignum[RSAKEY_MAX_SIZE];
|
||||
u8 randbuf[64];
|
||||
unsigned int keybits;
|
||||
int algorithm, r, delete_it = 0;
|
||||
|
||||
if (obj->type != SC_PKCS15_TYPE_PRKEY_RSA) {
|
||||
error(profile, "CardOS supports only RSA keys.");
|
||||
return SC_ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
if (etoken_key_algorithm(key_info->usage, &algorithm) < 0) {
|
||||
error(profile, "CardOS does not support keys "
|
||||
"that can both sign _and_ decrypt.");
|
||||
return SC_ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
keybits = key_info->modulus_length & ~7UL;
|
||||
if (keybits > RSAKEY_MAX_BITS) {
|
||||
error(profile, "Unable to generate key, max size is %d\n",
|
||||
RSAKEY_MAX_BITS);
|
||||
return SC_ERROR_INVALID_ARGUMENTS;
|
||||
}
|
||||
|
||||
if (sc_profile_get_file(profile, "tempfile", &temp) < 0) {
|
||||
error(profile, "Profile doesn't define temporary file "
|
||||
"for key generation.\n");
|
||||
return SC_ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
memset(pubkey, 0, sizeof(*pubkey));
|
||||
|
||||
if ((r = sc_pkcs15init_create_file(profile, card, temp)) < 0)
|
||||
goto out;
|
||||
delete_it = 1;
|
||||
|
||||
/* Create a key object, initializing components to 0xff */
|
||||
memset(&key_obj, 0, sizeof(key_obj));
|
||||
memset(abignum, 0xFF, sizeof(abignum));
|
||||
key_obj.modulus.data = abignum;
|
||||
key_obj.modulus.len = keybits >> 3;
|
||||
key_obj.d.data = abignum;
|
||||
key_obj.d.len = keybits >> 3;
|
||||
r = etoken_put_key(profile, card, algorithm,
|
||||
key_info->key_reference, &key_obj);
|
||||
if (r < 0)
|
||||
goto out;
|
||||
|
||||
memset(&args, 0, sizeof(args));
|
||||
#ifdef notyet
|
||||
if ((r = scrandom_get_data(randbuf, sizeof(randbuf))) < 0)
|
||||
goto out;
|
||||
|
||||
/* For now, we have to rely on the card's internal number
|
||||
* generator because libscrandom is static, which causes
|
||||
* all sorts of headaches when linking against it
|
||||
* (some platforms don't allow non-PIC code in a shared lib,
|
||||
* such as ia64).
|
||||
*/
|
||||
args.random_data = randbuf;
|
||||
args.random_len = sizeof(randbuf);
|
||||
#endif
|
||||
args.key_id = key_info->key_reference;
|
||||
args.key_bits = keybits;
|
||||
args.fid = temp->id;
|
||||
r = sc_card_ctl(card, SC_CARDCTL_ETOKEN_GENERATE_KEY, &args);
|
||||
memset(randbuf, 0, sizeof(randbuf));
|
||||
if (r < 0)
|
||||
goto out;
|
||||
|
||||
/* extract public key from file and delete it */
|
||||
if ((r = sc_select_file(card, &temp->path, NULL)) < 0)
|
||||
goto out;
|
||||
r = etoken_extract_pubkey(card, 1, 0x10, &pubkey->u.rsa.modulus);
|
||||
if (r < 0)
|
||||
goto out;
|
||||
r = etoken_extract_pubkey(card, 2, 0x11, &pubkey->u.rsa.exponent);
|
||||
if (r < 0)
|
||||
goto out;
|
||||
pubkey->algorithm = SC_ALGORITHM_RSA;
|
||||
|
||||
out: if (delete_it) {
|
||||
sc_pkcs15init_rmdir(card, profile, temp);
|
||||
}
|
||||
sc_file_free(temp);
|
||||
if (r < 0) {
|
||||
if (pubkey->u.rsa.modulus.data)
|
||||
free (pubkey->u.rsa.modulus.data);
|
||||
if (pubkey->u.rsa.exponent.data)
|
||||
free (pubkey->u.rsa.exponent.data);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* Store a PIN or PUK
|
||||
*/
|
||||
static int
|
||||
etoken_store_pin(sc_profile_t *profile, sc_card_t *card,
|
||||
sc_pkcs15_pin_info_t *pin_info, int puk_id,
|
||||
const u8 *pin, size_t pin_len)
|
||||
{
|
||||
struct sc_pkcs15_pin_info params;
|
||||
struct sc_cardctl_etoken_obj_info args;
|
||||
unsigned char buffer[256];
|
||||
unsigned char pinpadded[16];
|
||||
struct tlv tlv;
|
||||
unsigned int attempts, minlen, maxlen;
|
||||
|
||||
printf("etoken_store_pin(ref=%d, puk=%d\n", pin_info->reference, puk_id);
|
||||
/* We need to do padding because pkcs15-lib.c does it.
|
||||
* Would be nice to have a flag in the profile that says
|
||||
* "no padding required". */
|
||||
@ -148,21 +411,15 @@ etoken_store_pin(struct sc_profile *profile, struct sc_card *card,
|
||||
pinpadded[pin_len++] = profile->pin_pad_char;
|
||||
pin = pinpadded;
|
||||
|
||||
sc_profile_get_pin_info(profile, pin_type, ¶ms);
|
||||
attempts = params.tries_left;
|
||||
minlen = params.min_length;
|
||||
|
||||
/* Set the profile's PIN reference */
|
||||
params.reference = pin_id;
|
||||
params.path = profile->df_info->file->path;
|
||||
sc_profile_set_pin_info(profile, pin_type, ¶ms);
|
||||
attempts = pin_info->tries_left;
|
||||
minlen = pin_info->min_length;
|
||||
|
||||
tlv_init(&tlv, buffer, sizeof(buffer));
|
||||
|
||||
/* object address: class, id */
|
||||
tlv_next(&tlv, 0x83);
|
||||
tlv_add(&tlv, 0x00); /* class byte: usage TEST, k=0 */
|
||||
tlv_add(&tlv, pin_id);
|
||||
tlv_add(&tlv, pin_info->reference);
|
||||
|
||||
/* parameters */
|
||||
tlv_next(&tlv, 0x85);
|
||||
@ -181,16 +438,16 @@ etoken_store_pin(struct sc_profile *profile, struct sc_card *card,
|
||||
/* DEK: not documented, no idea what it means */
|
||||
tlv_add(&tlv, 0x00);
|
||||
|
||||
/* ARA counter: not documented, no idea what it means */
|
||||
/* ARA counter: Nils says this is the userConsent field */
|
||||
tlv_add(&tlv, 0x00);
|
||||
|
||||
tlv_add(&tlv, minlen); /* minlen */
|
||||
tlv_add(&tlv, minlen); /* minlen */
|
||||
|
||||
/* AC conditions */
|
||||
tlv_next(&tlv, 0x86);
|
||||
tlv_add(&tlv, 0x00); /* use: always */
|
||||
tlv_add(&tlv, pin_id); /* change: PIN */
|
||||
tlv_add(&tlv, puk_id); /* unblock: PUK */
|
||||
tlv_add(&tlv, 0x00); /* use: always */
|
||||
tlv_add(&tlv, pin_info->reference); /* change: PIN */
|
||||
tlv_add(&tlv, puk_id); /* unblock: PUK */
|
||||
|
||||
/* data: PIN */
|
||||
tlv_next(&tlv, 0x8f);
|
||||
@ -235,11 +492,13 @@ etoken_create_sec_env(struct sc_profile *profile, struct sc_card *card,
|
||||
return sc_card_ctl(card, SC_CARDCTL_ETOKEN_PUT_DATA_SECI, &args);
|
||||
}
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* Initialize the Application DF and pin file
|
||||
*/
|
||||
static int
|
||||
etoken_init_app(struct sc_profile *profile, struct sc_card *card,
|
||||
struct sc_pkcs15_pin_info *pin_info,
|
||||
const unsigned char *pin, size_t pin_len,
|
||||
const unsigned char *puk, size_t puk_len)
|
||||
{
|
||||
@ -259,16 +518,20 @@ etoken_init_app(struct sc_profile *profile, struct sc_card *card,
|
||||
u8 puk_id = ETOKEN_AC_NEVER;
|
||||
|
||||
if (r >= 0 && puk && puk_len) {
|
||||
puk_id = ETOKEN_PUK_ID(0);
|
||||
struct sc_pkcs15_pin_info puk_info;
|
||||
|
||||
sc_profile_get_pin_info(profile,
|
||||
SC_PKCS15INIT_SO_PUK, &puk_info);
|
||||
|
||||
puk_id = puk_info.reference;
|
||||
r = etoken_store_pin(profile, card,
|
||||
SC_PKCS15INIT_SO_PUK,
|
||||
puk_id, ETOKEN_AC_NEVER,
|
||||
&puk_info, ETOKEN_AC_NEVER,
|
||||
puk, puk_len);
|
||||
}
|
||||
if (r >= 0) {
|
||||
pin_info->path = df->path;
|
||||
r = etoken_store_pin(profile, card,
|
||||
SC_PKCS15INIT_SO_PIN,
|
||||
ETOKEN_PIN_ID(0), puk_id,
|
||||
pin_info, puk_id,
|
||||
pin, pin_len);
|
||||
}
|
||||
}
|
||||
@ -281,50 +544,7 @@ etoken_init_app(struct sc_profile *profile, struct sc_card *card,
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* Store a PIN
|
||||
*/
|
||||
static int
|
||||
etoken_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)
|
||||
{
|
||||
struct sc_file *df = profile->df_info->file;
|
||||
unsigned int puk_id = ETOKEN_AC_NEVER, pin_id;
|
||||
int r;
|
||||
|
||||
if (!pin || !pin_len)
|
||||
return SC_ERROR_INVALID_ARGUMENTS;
|
||||
|
||||
r = sc_select_file(card, &df->path, NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (index >= ETOKEN_MAX_PINS)
|
||||
return SC_ERROR_TOO_MANY_OBJECTS;
|
||||
|
||||
if (puk && puk_len) {
|
||||
puk_id = ETOKEN_PUK_ID(index);
|
||||
r = etoken_store_pin(profile, card,
|
||||
SC_PKCS15INIT_USER_PUK,
|
||||
puk_id, ETOKEN_AC_NEVER,
|
||||
puk, puk_len);
|
||||
}
|
||||
|
||||
if (r >= 0) {
|
||||
pin_id = ETOKEN_PIN_ID(index);
|
||||
r = etoken_store_pin(profile, card,
|
||||
SC_PKCS15INIT_USER_PIN,
|
||||
pin_id, puk_id,
|
||||
pin, pin_len);
|
||||
info->reference = pin_id;
|
||||
info->path = df->path;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Determine the key algorithm based on the intended usage
|
||||
@ -419,7 +639,7 @@ etoken_store_key_component(struct sc_card *card,
|
||||
}
|
||||
|
||||
static int
|
||||
etoken_store_key(struct sc_profile *profile, struct sc_card *card,
|
||||
etoken_put_key(struct sc_profile *profile, struct sc_card *card,
|
||||
int algorithm, unsigned int key_id,
|
||||
struct sc_pkcs15_prkey_rsa *key)
|
||||
{
|
||||
@ -440,38 +660,6 @@ etoken_store_key(struct sc_profile *profile, struct sc_card *card,
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* Store a private key
|
||||
*/
|
||||
static int
|
||||
etoken_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_pkcs15_prkey_rsa *rsa;
|
||||
int algorithm, key_id, r;
|
||||
|
||||
if (key->algorithm != SC_ALGORITHM_RSA) {
|
||||
error(profile, "eToken supports RSA keys only.\n");
|
||||
return SC_ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
if (etoken_key_algorithm(info->usage, &algorithm) < 0) {
|
||||
error(profile, "eToken does not support keys "
|
||||
"that can both sign _and_ decrypt.");
|
||||
return SC_ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
rsa = &key->u.rsa;
|
||||
key_id = ETOKEN_KEY_ID(index);
|
||||
r = etoken_store_key(profile, card, algorithm, key_id, rsa);
|
||||
if (r >= 0) {
|
||||
info->path = profile->df_info->file->path;
|
||||
info->key_reference = key_id;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate a file
|
||||
*/
|
||||
@ -574,107 +762,6 @@ etoken_extract_pubkey(struct sc_card *card, int nr, u8 tag,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Key generation
|
||||
*/
|
||||
static int
|
||||
etoken_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_pkcs15_prkey_rsa key_obj;
|
||||
struct sc_cardctl_etoken_genkey_info args;
|
||||
struct sc_file *temp;
|
||||
u8 abignum[RSAKEY_MAX_SIZE];
|
||||
u8 randbuf[64], key_id;
|
||||
int algorithm, r, delete_it = 0;
|
||||
|
||||
keybits &= ~7UL;
|
||||
if (keybits > RSAKEY_MAX_BITS) {
|
||||
error(profile, "Unable to generate key, max size is %d\n",
|
||||
RSAKEY_MAX_BITS);
|
||||
return SC_ERROR_INVALID_ARGUMENTS;
|
||||
}
|
||||
|
||||
if (etoken_key_algorithm(info->usage, &algorithm) < 0) {
|
||||
error(profile, "eToken does not support keys "
|
||||
"that can both sign _and_ decrypt.");
|
||||
return SC_ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
if (sc_profile_get_file(profile, "tempfile", &temp) < 0) {
|
||||
error(profile, "Profile doesn't define temporary file "
|
||||
"for key generation.\n");
|
||||
return SC_ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
memset(pubkey, 0, sizeof(*pubkey));
|
||||
|
||||
if ((r = sc_pkcs15init_create_file(profile, card, temp)) < 0)
|
||||
goto out;
|
||||
delete_it = 1;
|
||||
|
||||
key_id = ETOKEN_KEY_ID(index);
|
||||
|
||||
/* Create a key object, initializing components to 0xff */
|
||||
memset(&key_obj, 0, sizeof(key_obj));
|
||||
memset(abignum, 0xFF, sizeof(abignum));
|
||||
key_obj.modulus.data = abignum;
|
||||
key_obj.modulus.len = keybits >> 3;
|
||||
key_obj.d.data = abignum;
|
||||
key_obj.d.len = keybits >> 3;
|
||||
r = etoken_store_key(profile, card, algorithm, key_id, &key_obj);
|
||||
if (r < 0)
|
||||
goto out;
|
||||
|
||||
memset(&args, 0, sizeof(args));
|
||||
#ifdef notyet
|
||||
if ((r = scrandom_get_data(randbuf, sizeof(randbuf))) < 0)
|
||||
goto out;
|
||||
|
||||
/* For now, we have to rely on the card's internal number
|
||||
* generator because libscrandom is static, which causes
|
||||
* all sorts of headaches when linking against it
|
||||
* (some platforms don't allow non-PIC code in a shared lib,
|
||||
* such as ia64).
|
||||
*/
|
||||
args.random_data = randbuf;
|
||||
args.random_len = sizeof(randbuf);
|
||||
#endif
|
||||
args.key_id = key_id;
|
||||
args.key_bits = keybits;
|
||||
args.fid = temp->id;
|
||||
r = sc_card_ctl(card, SC_CARDCTL_ETOKEN_GENERATE_KEY, &args);
|
||||
memset(randbuf, 0, sizeof(randbuf));
|
||||
if (r < 0)
|
||||
goto out;
|
||||
|
||||
/* extract public key from file and delete it */
|
||||
if ((r = sc_select_file(card, &temp->path, NULL)) < 0)
|
||||
goto out;
|
||||
r = etoken_extract_pubkey(card, 1, 0x10, &pubkey->u.rsa.modulus);
|
||||
if (r < 0)
|
||||
goto out;
|
||||
r = etoken_extract_pubkey(card, 2, 0x11, &pubkey->u.rsa.exponent);
|
||||
if (r < 0)
|
||||
goto out;
|
||||
pubkey->algorithm = SC_ALGORITHM_RSA;
|
||||
info->key_reference = key_id;
|
||||
info->path = profile->df_info->file->path;
|
||||
|
||||
out: if (delete_it) {
|
||||
sc_pkcs15init_rmdir(card, profile, temp);
|
||||
}
|
||||
sc_file_free(temp);
|
||||
if (r < 0) {
|
||||
if (pubkey->u.rsa.modulus.data)
|
||||
free (pubkey->u.rsa.modulus.data);
|
||||
if (pubkey->u.rsa.exponent.data)
|
||||
free (pubkey->u.rsa.exponent.data);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
static void
|
||||
error(struct sc_profile *profile, const char *fmt, ...)
|
||||
{
|
||||
@ -689,10 +776,15 @@ error(struct sc_profile *profile, const char *fmt, ...)
|
||||
}
|
||||
|
||||
struct sc_pkcs15init_operations sc_pkcs15init_etoken_operations = {
|
||||
etoken_erase,
|
||||
etoken_init_app,
|
||||
etoken_new_pin,
|
||||
etoken_new_key,
|
||||
etoken_new_file,
|
||||
etoken_generate_key
|
||||
.erase_card = etoken_erase,
|
||||
.create_dir = etoken_create_dir,
|
||||
.select_pin_reference = etoken_select_pin_reference,
|
||||
.create_pin = etoken_create_pin,
|
||||
.select_key_reference = etoken_select_key_reference,
|
||||
.create_key = etoken_create_key,
|
||||
.store_key = etoken_store_key,
|
||||
//.new_pin = etoken_new_pin,
|
||||
//.new_key = etoken_new_key,
|
||||
.generate_key = etoken_generate_key
|
||||
//.new_file = etoken_new_file,
|
||||
};
|
||||
|
@ -32,6 +32,7 @@
|
||||
#include "profile.h"
|
||||
|
||||
#define GPK_MAX_PINS 8
|
||||
#define GPK_PIN_SCOPE 8
|
||||
#define GPK_FTYPE_SECRET_CODE 0x21
|
||||
#define GPK_FTYPE_PUBLIC_KEY 0x2C
|
||||
|
||||
@ -60,13 +61,7 @@ struct pkdata {
|
||||
/*
|
||||
* Local functions
|
||||
*/
|
||||
static int gpk_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);
|
||||
static int gpk_new_file(struct sc_profile *, struct sc_card *,
|
||||
unsigned int, unsigned int,
|
||||
struct sc_file **);
|
||||
static int gpk_pkfile_create(sc_profile_t *, sc_card_t *, sc_file_t *);
|
||||
static int gpk_encode_rsa_key(struct sc_profile *,
|
||||
struct sc_pkcs15_prkey_rsa *, struct pkdata *,
|
||||
struct sc_pkcs15_prkey_info *);
|
||||
@ -75,6 +70,7 @@ static int gpk_encode_dsa_key(struct sc_profile *,
|
||||
struct sc_pkcs15_prkey_info *);
|
||||
static int gpk_store_pk(struct sc_profile *, struct sc_card *,
|
||||
struct sc_file *, struct pkdata *);
|
||||
static int gpk_init_pinfile(sc_profile_t *, sc_card_t *, sc_file_t *);
|
||||
static void error(struct sc_profile *, const char *, ...);
|
||||
static void debug(struct sc_profile *, const char *, ...);
|
||||
|
||||
@ -97,6 +93,152 @@ gpk_erase_card(struct sc_profile *pro, struct sc_card *card)
|
||||
return sc_card_ctl(card, SC_CARDCTL_ERASE_CARD, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a new DF
|
||||
* This will usually be the application DF
|
||||
*/
|
||||
static int
|
||||
gpk_create_dir(sc_profile_t *profile, sc_card_t *card, sc_file_t *df)
|
||||
{
|
||||
struct sc_file *pinfile;
|
||||
int r, locked, i;
|
||||
|
||||
if (sc_card_ctl(card, SC_CARDCTL_GPK_IS_LOCKED, &locked) == 0
|
||||
&& locked) {
|
||||
error(profile,
|
||||
"This card is already personalized, unable to "
|
||||
"create PKCS#15 structure.");
|
||||
return SC_ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
/* Create the DF. */
|
||||
r = sc_pkcs15init_create_file(profile, card, df);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* See if there's a file called "pinfile" that resides within
|
||||
* this DF. If so, create it */
|
||||
if (sc_profile_get_file(profile, "pinfile", &pinfile) >= 0) {
|
||||
/* Build the pin file's path from the DF path + its
|
||||
* file ID */
|
||||
pinfile->path = df->path;
|
||||
sc_append_file_id(&pinfile->path, pinfile->id);
|
||||
|
||||
r = gpk_init_pinfile(profile, card, pinfile);
|
||||
sc_file_free(pinfile);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
for (i = 0; i < GPK_MAX_PINS; i++)
|
||||
sc_keycache_put_pin(&df->path, GPK_PIN_SCOPE|i, " ");
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* Select a PIN reference
|
||||
*/
|
||||
static int
|
||||
gpk_select_pin_reference(sc_profile_t *profile, sc_card_t *card,
|
||||
sc_pkcs15_pin_info_t *pin_info)
|
||||
{
|
||||
int preferred, current;
|
||||
|
||||
if ((current = pin_info->reference) < 0)
|
||||
current = 0;
|
||||
|
||||
if (pin_info->flags & SC_PKCS15_PIN_FLAG_SO_PIN) {
|
||||
preferred = GPK_PIN_SCOPE | 0;
|
||||
} else {
|
||||
preferred = current | GPK_PIN_SCOPE;
|
||||
|
||||
if (preferred & 1)
|
||||
preferred++;
|
||||
if (preferred < (GPK_PIN_SCOPE | 2))
|
||||
preferred = GPK_PIN_SCOPE | 2;
|
||||
if (preferred > 15)
|
||||
return SC_ERROR_TOO_MANY_OBJECTS;
|
||||
}
|
||||
|
||||
if (current > preferred)
|
||||
return SC_ERROR_TOO_MANY_OBJECTS;
|
||||
pin_info->reference = preferred;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Store a PIN
|
||||
*/
|
||||
static int
|
||||
gpk_create_pin(sc_profile_t *profile, sc_card_t *card, sc_file_t *df,
|
||||
sc_pkcs15_pin_info_t *pin_info,
|
||||
const unsigned char *pin, size_t pin_len,
|
||||
const unsigned char *puk, size_t puk_len)
|
||||
{
|
||||
unsigned char nulpin[8];
|
||||
int r, type;
|
||||
|
||||
if (pin_info->flags & SC_PKCS15_PIN_FLAG_SO_PIN) {
|
||||
type = SC_PKCS15INIT_SO_PIN;
|
||||
|
||||
/* SO PIN reference must be 0 */
|
||||
if (pin_info->reference != (GPK_PIN_SCOPE | 0))
|
||||
return SC_ERROR_INVALID_ARGUMENTS;
|
||||
} else {
|
||||
type = SC_PKCS15INIT_USER_PIN;
|
||||
|
||||
/* PIN references must be even numbers
|
||||
* (the odd numbered PIN entries contain the
|
||||
* PUKs).
|
||||
* Returning SC_ERROR_INVALID_PIN_REFERENCE will
|
||||
* tell the caller to pick a different value.
|
||||
*/
|
||||
if ((pin_info->reference & 1) || !(pin_info->reference & GPK_PIN_SCOPE))
|
||||
return SC_ERROR_INVALID_PIN_REFERENCE;
|
||||
if (pin_info->reference >= (GPK_PIN_SCOPE + GPK_MAX_PINS))
|
||||
return SC_ERROR_TOO_MANY_OBJECTS;
|
||||
}
|
||||
|
||||
/* No PUK given, but the PIN file specifies an unblock
|
||||
* PIN for every PIN.
|
||||
* Use the same value for the PUK for now.
|
||||
* Alternatively, we could leave the unblock PIN at the default
|
||||
* value, but deliberately block it. */
|
||||
if (puk == NULL || puk_len == 0) {
|
||||
puk = pin;
|
||||
puk_len = pin_len;
|
||||
}
|
||||
|
||||
r = sc_select_file(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));
|
||||
r = sc_change_reference_data(card, SC_AC_CHV,
|
||||
pin_info->reference,
|
||||
nulpin, sizeof(nulpin),
|
||||
pin, pin_len, NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* Current PUK is 00:00:00:00:00:00:00:00 */
|
||||
r = sc_change_reference_data(card, SC_AC_CHV,
|
||||
pin_info->reference + 1,
|
||||
nulpin, sizeof(nulpin),
|
||||
puk, puk_len, NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
sc_keycache_set_pin_name(&df->path,
|
||||
pin_info->reference,
|
||||
type);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Lock a file operation
|
||||
*/
|
||||
@ -146,7 +288,6 @@ static int
|
||||
gpk_init_pinfile(struct sc_profile *profile, struct sc_card *card,
|
||||
struct sc_file *file)
|
||||
{
|
||||
struct sc_pkcs15_pin_info sopin_info, pin_info;
|
||||
const struct sc_acl_entry *acl;
|
||||
unsigned char buffer[GPK_MAX_PINS * 8], *blk;
|
||||
struct sc_file *pinfile;
|
||||
@ -155,14 +296,10 @@ gpk_init_pinfile(struct sc_profile *profile, struct sc_card *card,
|
||||
int r;
|
||||
|
||||
/* Set defaults */
|
||||
sc_profile_get_pin_info(profile, SC_PKCS15INIT_SO_PIN, &sopin_info);
|
||||
so_attempts[0] = sopin_info.tries_left;
|
||||
sc_profile_get_pin_info(profile, SC_PKCS15INIT_SO_PUK, &pin_info);
|
||||
so_attempts[1] = pin_info.tries_left;
|
||||
sc_profile_get_pin_info(profile, SC_PKCS15INIT_USER_PIN, &pin_info);
|
||||
user_attempts[0] = pin_info.tries_left;
|
||||
sc_profile_get_pin_info(profile, SC_PKCS15INIT_USER_PUK, &pin_info);
|
||||
user_attempts[1] = pin_info.tries_left;
|
||||
so_attempts[0] = sc_profile_get_pin_retries(profile, SC_PKCS15INIT_SO_PIN);
|
||||
so_attempts[1] = sc_profile_get_pin_retries(profile, SC_PKCS15INIT_SO_PUK);
|
||||
user_attempts[0] = sc_profile_get_pin_retries(profile, SC_PKCS15INIT_USER_PIN);
|
||||
user_attempts[1] = sc_profile_get_pin_retries(profile, SC_PKCS15INIT_USER_PUK);
|
||||
|
||||
sc_file_dup(&pinfile, file);
|
||||
|
||||
@ -199,7 +336,7 @@ gpk_init_pinfile(struct sc_profile *profile, struct sc_card *card,
|
||||
* the next will be a PUK so take note of the
|
||||
* unlock code */
|
||||
if (i + 1 < npins)
|
||||
blk[2] = 0x8 | (i + 1);
|
||||
blk[2] = GPK_PIN_SCOPE | (i + 1);
|
||||
}
|
||||
|
||||
/* Compute the CKS */
|
||||
@ -217,100 +354,54 @@ out: sc_file_free(pinfile);
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize the Application DF and pin file
|
||||
* Create a key file
|
||||
*/
|
||||
static int
|
||||
gpk_init_app(struct sc_profile *profile, struct sc_card *card,
|
||||
const unsigned char *pin, size_t pin_len,
|
||||
const unsigned char *puk, size_t puk_len)
|
||||
gpk_create_key(sc_profile_t *profile, sc_card_t *card, sc_pkcs15_object_t *obj)
|
||||
{
|
||||
struct sc_pkcs15_pin_info sopin_info;
|
||||
struct sc_file *pinfile;
|
||||
int r, locked;
|
||||
|
||||
if (sc_card_ctl(card, SC_CARDCTL_GPK_IS_LOCKED, &locked) == 0
|
||||
&& locked) {
|
||||
error(profile,
|
||||
"This card is already personalized, unable to "
|
||||
"create PKCS#15 structure.");
|
||||
return SC_ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
/* Profile must define a "pinfile" */
|
||||
if (sc_profile_get_file(profile, "pinfile", &pinfile) < 0) {
|
||||
error(profile, "Profile doesn't define a \"pinfile\"");
|
||||
return SC_ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
/* Create the application DF */
|
||||
r = sc_pkcs15init_create_file(profile, card, profile->df_info->file);
|
||||
|
||||
/* Create the PIN file */
|
||||
if (r >= 0)
|
||||
r = gpk_init_pinfile(profile, card, pinfile);
|
||||
|
||||
sc_profile_get_pin_info(profile, SC_PKCS15INIT_SO_PIN, &sopin_info);
|
||||
if (r >= 0 && pin_len) {
|
||||
r = gpk_new_pin(profile, card, &sopin_info, 0,
|
||||
pin, pin_len,
|
||||
puk, puk_len);
|
||||
if (r >= 0)
|
||||
sc_profile_set_pin_info(profile, SC_PKCS15INIT_SO_PIN,
|
||||
&sopin_info);
|
||||
}
|
||||
|
||||
sc_file_free(pinfile);
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* Store a PIN
|
||||
*/
|
||||
static int
|
||||
gpk_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)
|
||||
{
|
||||
unsigned char nulpin[8];
|
||||
sc_pkcs15_prkey_info_t *key_info = (sc_pkcs15_prkey_info_t *) obj->data;
|
||||
struct sc_file *keyfile = NULL;
|
||||
size_t bytes, mod_len, exp_len, prv_len, pub_len;
|
||||
int r;
|
||||
|
||||
/* Profile must define a "pinfile" */
|
||||
if (sc_profile_get_path(profile, "pinfile", &info->path) < 0) {
|
||||
error(profile, "Profile doesn't define a \"pinfile\"");
|
||||
/* 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;
|
||||
}
|
||||
if (info->path.len > 2)
|
||||
info->path.len -= 2;
|
||||
|
||||
r = sc_select_file(card, &info->path, NULL);
|
||||
/* 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;
|
||||
|
||||
index <<= 2;
|
||||
if (index >= GPK_MAX_PINS)
|
||||
return SC_ERROR_TOO_MANY_OBJECTS;
|
||||
if (puk == NULL || puk_len == 0) {
|
||||
puk = pin;
|
||||
puk_len = pin_len;
|
||||
/* Compute the file size.
|
||||
* We assume private keys are stored as CRT elements.
|
||||
* - 512, 768 bit keys: all CRT elements fit into one record
|
||||
* - >= 1024: each CRT element into a record of its own
|
||||
*
|
||||
* We also assume the public exponent is 32bit max
|
||||
*
|
||||
* Rules
|
||||
* - private key records must have a length divisible by 8
|
||||
*/
|
||||
mod_len = key_info->modulus_length / 8;
|
||||
exp_len = 4;
|
||||
bytes = mod_len / 2;
|
||||
pub_len = 8 + ((3 + mod_len + 3 + exp_len + 3) & ~3UL);
|
||||
if (5 * bytes < 256) {
|
||||
prv_len = 8 + ((3 + 5 * bytes + 7) & ~7UL);
|
||||
} else {
|
||||
prv_len = 8 + 5 * ((3 + bytes + 7) & ~7UL);
|
||||
}
|
||||
keyfile->size = pub_len + prv_len;
|
||||
|
||||
/* Current PIN is 00:00:00:00:00:00:00:00 */
|
||||
memset(nulpin, 0, sizeof(nulpin));
|
||||
r = sc_change_reference_data(card, SC_AC_CHV,
|
||||
0x8 | index,
|
||||
nulpin, sizeof(nulpin),
|
||||
pin, pin_len, NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
/* Fix up PIN references in file ACL */
|
||||
r = sc_pkcs15init_fixup_file(profile, keyfile);
|
||||
|
||||
/* Current PUK is 00:00:00:00:00:00:00:00 */
|
||||
r = sc_change_reference_data(card, SC_AC_CHV,
|
||||
0x8 | (index + 1),
|
||||
nulpin, sizeof(nulpin),
|
||||
puk, puk_len, NULL);
|
||||
if (r >= 0)
|
||||
r = gpk_pkfile_create(profile, card, keyfile);
|
||||
|
||||
info->reference = 0x8 | index;
|
||||
if (keyfile)
|
||||
sc_file_free(keyfile);
|
||||
return r;
|
||||
}
|
||||
|
||||
@ -318,6 +409,50 @@ gpk_new_pin(struct sc_profile *profile, struct sc_card *card,
|
||||
* Store a private key
|
||||
*/
|
||||
static int
|
||||
gpk_store_key(sc_profile_t *profile, sc_card_t *card,
|
||||
sc_pkcs15_object_t *obj, struct sc_pkcs15_prkey *key)
|
||||
{
|
||||
sc_pkcs15_prkey_info_t *key_info = (sc_pkcs15_prkey_info_t *) obj->data;
|
||||
struct sc_file *keyfile = NULL;
|
||||
struct pkdata data;
|
||||
int r;
|
||||
|
||||
/* 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_select_file(card, &key_info->path, &keyfile);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
switch (key->algorithm) {
|
||||
case SC_ALGORITHM_RSA:
|
||||
r = gpk_encode_rsa_key(profile, &key->u.rsa,
|
||||
&data, key_info);
|
||||
break;
|
||||
|
||||
case SC_ALGORITHM_DSA:
|
||||
r = gpk_encode_dsa_key(profile, &key->u.dsa,
|
||||
&data, key_info);
|
||||
break;
|
||||
default:
|
||||
return SC_ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
if (r >= 0)
|
||||
r = gpk_store_pk(profile, card, keyfile, &data);
|
||||
|
||||
if (keyfile)
|
||||
sc_file_free(keyfile);
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* Store a private key
|
||||
*/
|
||||
#if 0
|
||||
static int
|
||||
gpk_new_key(struct sc_profile *profile, struct sc_card *card,
|
||||
struct sc_pkcs15_prkey *key, unsigned int index,
|
||||
struct sc_pkcs15_prkey_info *info)
|
||||
@ -439,6 +574,7 @@ gpk_new_file(struct sc_profile *profile, struct sc_card *card,
|
||||
*out = file;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* GPK public/private key file handling is hideous.
|
||||
@ -449,8 +585,7 @@ gpk_new_file(struct sc_profile *profile, struct sc_card *card,
|
||||
* XXX: Handle the UPDATE ACL = NEVER case just like for EFsc files
|
||||
*/
|
||||
static int
|
||||
gpk_pkfile_create(struct sc_profile *profile, struct sc_card *card,
|
||||
struct sc_file *file)
|
||||
gpk_pkfile_create(sc_profile_t *profile, sc_card_t *card, sc_file_t *file)
|
||||
{
|
||||
struct sc_file *found = NULL;
|
||||
int r;
|
||||
@ -500,12 +635,12 @@ gpk_pkfile_keyalgo(unsigned int algo, unsigned char *p)
|
||||
* Set up the public key record for a signature only public key
|
||||
*/
|
||||
static int
|
||||
gpk_pkfile_init_public(struct sc_profile *profile,
|
||||
struct sc_card *card, struct sc_file *file,
|
||||
gpk_pkfile_init_public(sc_profile_t *profile, sc_card_t *card, sc_file_t *file,
|
||||
unsigned int algo, unsigned int bits,
|
||||
unsigned int usage)
|
||||
{
|
||||
const struct sc_acl_entry *acl;
|
||||
sc_file_t *tmp = NULL;
|
||||
u8 sysrec[7], buffer[256];
|
||||
unsigned int n, npins;
|
||||
int r, gpkclass;
|
||||
@ -531,8 +666,17 @@ gpk_pkfile_init_public(struct sc_profile *profile,
|
||||
|| (r = gpk_pkfile_keyalgo(algo, &sysrec[5])) < 0)
|
||||
return r;
|
||||
|
||||
/* Set PIN protection if requested. */
|
||||
acl = sc_file_get_acl_entry(file, SC_AC_OP_CRYPTO);
|
||||
/* Set PIN protection if requested.
|
||||
* As the crypto ACLs are stored inside the file,
|
||||
* we have to get them from the profile here. */
|
||||
r = sc_profile_get_file_by_path(profile, &file->path, &tmp);
|
||||
if (r < 0)
|
||||
return r;
|
||||
/* Fix up PIN references in file ACL */
|
||||
if ((r = sc_pkcs15init_fixup_file(profile, tmp)) < 0)
|
||||
goto out;
|
||||
|
||||
acl = sc_file_get_acl_entry(tmp, SC_AC_OP_CRYPTO);
|
||||
for (npins = 0; acl; acl = acl->next) {
|
||||
if (acl->method == SC_AC_NONE
|
||||
|| acl->method == SC_AC_NEVER)
|
||||
@ -540,11 +684,13 @@ gpk_pkfile_init_public(struct sc_profile *profile,
|
||||
if (acl->method != SC_AC_CHV) {
|
||||
error(profile, "Authentication method not "
|
||||
"supported for private key files.\n");
|
||||
return SC_ERROR_NOT_SUPPORTED;
|
||||
r = SC_ERROR_NOT_SUPPORTED;
|
||||
goto out;
|
||||
}
|
||||
if (++npins >= 2) {
|
||||
error(profile, "Too many pins for PrKEY file!\n");
|
||||
return SC_ERROR_NOT_SUPPORTED;
|
||||
r = SC_ERROR_NOT_SUPPORTED;
|
||||
goto out;
|
||||
}
|
||||
sysrec[2] += 0x40;
|
||||
sysrec[3] >>= 4;
|
||||
@ -578,6 +724,9 @@ gpk_pkfile_init_public(struct sc_profile *profile,
|
||||
} else {
|
||||
r = sc_append_record(card, sysrec, sizeof(sysrec), 0);
|
||||
}
|
||||
|
||||
out: if (tmp)
|
||||
sc_file_free(tmp);
|
||||
return r;
|
||||
}
|
||||
|
||||
@ -673,24 +822,12 @@ gpk_pkfile_update_private(struct sc_profile *profile,
|
||||
{
|
||||
unsigned int m, size, nb, cks;
|
||||
struct pkcomp *pe;
|
||||
u8 keybuf[32], data[256];
|
||||
size_t keysize;
|
||||
u8 data[256];
|
||||
int r = 0;
|
||||
|
||||
if (card->ctx->debug > 1)
|
||||
debug(profile, "Updating private key elements\n");
|
||||
|
||||
/* We must set a secure messaging key before each Load Private Key
|
||||
* command. Any key will do...
|
||||
* The GPK _is_ weird. */
|
||||
keysize = sizeof(keybuf);
|
||||
r = sc_pkcs15init_get_secret(profile, card,
|
||||
SC_AC_PRO, 1, keybuf, &keysize);
|
||||
if (r < 0) {
|
||||
error(profile, "No secure messaging key defined by profile");
|
||||
return SC_ERROR_SECURITY_STATUS_NOT_SATISFIED;
|
||||
}
|
||||
|
||||
for (m = 0; m < part->count; m++) {
|
||||
pe = part->components + m;
|
||||
|
||||
@ -699,7 +836,10 @@ gpk_pkfile_update_private(struct sc_profile *profile,
|
||||
memcpy(data, pe->data, pe->size);
|
||||
size = pe->size;
|
||||
|
||||
r = sc_verify(card, SC_AC_PRO, 1, keybuf, keysize, NULL);
|
||||
/* We must set a secure messaging key before each
|
||||
* Load Private Key command. Any key will do...
|
||||
* The GPK _is_ weird. */
|
||||
r = sc_pkcs15init_verify_key(profile, card, NULL, SC_AC_PRO, 1);
|
||||
if (r < 0)
|
||||
break;
|
||||
|
||||
@ -912,6 +1052,7 @@ static int
|
||||
gpk_store_pk(struct sc_profile *profile, struct sc_card *card,
|
||||
struct sc_file *file, struct pkdata *p)
|
||||
{
|
||||
size_t fsize;
|
||||
int r;
|
||||
|
||||
/* Compute length of private/public key parts */
|
||||
@ -923,10 +1064,9 @@ gpk_store_pk(struct sc_profile *profile, struct sc_card *card,
|
||||
"Storing pk: %u bits, pub %u bytes, priv %u bytes\n",
|
||||
p->bits, p->_public.size, p->_private.size);
|
||||
|
||||
file->size = p->_public.size + p->_private.size;
|
||||
r = gpk_pkfile_create(profile, card, file);
|
||||
if (r < 0)
|
||||
return r;
|
||||
fsize = p->_public.size + p->_private.size;
|
||||
if (fsize > file->size)
|
||||
return SC_ERROR_FILE_TOO_SMALL;
|
||||
|
||||
/* Put the system record */
|
||||
r = gpk_pkfile_init_public(profile, card, file, p->algo,
|
||||
@ -973,14 +1113,17 @@ debug(struct sc_profile *profile, const char *fmt, ...)
|
||||
vsnprintf(buffer, sizeof(buffer), fmt, ap);
|
||||
va_end(ap);
|
||||
if (profile->cbs && profile->cbs->debug)
|
||||
profile->cbs->debug("%s", buffer);
|
||||
profile->cbs->debug(2, "%s", buffer);
|
||||
printf("%s", buffer); /* XXX */
|
||||
}
|
||||
|
||||
struct sc_pkcs15init_operations sc_pkcs15init_gpk_operations = {
|
||||
gpk_erase_card,
|
||||
gpk_init_app,
|
||||
gpk_new_pin,
|
||||
gpk_new_key,
|
||||
gpk_new_file,
|
||||
.erase_card = gpk_erase_card,
|
||||
.create_dir = gpk_create_dir,
|
||||
.select_pin_reference = gpk_select_pin_reference,
|
||||
.create_pin = gpk_create_pin,
|
||||
.create_key = gpk_create_key,
|
||||
.store_key = gpk_store_key,
|
||||
// .new_key = gpk_new_key,
|
||||
// .new_file = gpk_new_file,
|
||||
};
|
||||
|
@ -13,19 +13,85 @@ extern "C" {
|
||||
|
||||
#include <opensc/pkcs15.h>
|
||||
|
||||
struct sc_profile; /* opaque type */
|
||||
typedef struct sc_profile sc_profile_t; /* opaque type */
|
||||
|
||||
struct sc_pkcs15init_operations {
|
||||
/*
|
||||
* Erase everything that's on the card
|
||||
* So far, only the GPK supports this
|
||||
*/
|
||||
* So far, only the GPK supports this */
|
||||
int (*erase_card)(struct sc_profile *, struct sc_card *);
|
||||
|
||||
/*
|
||||
* New style API
|
||||
*/
|
||||
|
||||
/*
|
||||
* Create a DF
|
||||
*/
|
||||
int (*create_dir)(sc_profile_t *, sc_card_t *, sc_file_t *);
|
||||
|
||||
/*
|
||||
* Create a "pin domain". This is for cards such as
|
||||
* the cryptoflex that need to put their pins into
|
||||
* separate directories
|
||||
*/
|
||||
int (*create_domain)(sc_profile_t *, sc_card_t *,
|
||||
const sc_pkcs15_id_t *, sc_file_t **);
|
||||
|
||||
/*
|
||||
* Select a PIN reference
|
||||
*/
|
||||
int (*select_pin_reference)(sc_profile_t *, sc_card_t *,
|
||||
sc_pkcs15_pin_info_t *);
|
||||
|
||||
/*
|
||||
* Create a PIN object within the given DF.
|
||||
*
|
||||
* The pin_info object is completely filled in by the caller.
|
||||
* The card driver can reject the pin reference; in this case
|
||||
* the caller needs to adjust it.
|
||||
*/
|
||||
int (*create_pin)(sc_profile_t *, sc_card_t *, sc_file_t *,
|
||||
struct sc_pkcs15_pin_info *,
|
||||
const unsigned char *pin, size_t pin_len,
|
||||
const unsigned char *puk, size_t puk_len);
|
||||
|
||||
/*
|
||||
* Select a reference for a private key object
|
||||
*/
|
||||
int (*select_key_reference)(sc_profile_t *, sc_card_t *,
|
||||
sc_pkcs15_prkey_info_t *);
|
||||
|
||||
/*
|
||||
* Create an empty key object.
|
||||
* @index is the number key objects already on the card.
|
||||
* @pin_info contains information on the PIN protecting
|
||||
* the key. NULL if the key should be
|
||||
* unprotected.
|
||||
* @key_info should be filled in by the function
|
||||
*/
|
||||
int (*create_key)(sc_profile_t *, sc_card_t *,
|
||||
sc_pkcs15_object_t *o);
|
||||
|
||||
/*
|
||||
* Store a key on the card
|
||||
*/
|
||||
int (*store_key)(sc_profile_t *, sc_card_t *,
|
||||
sc_pkcs15_object_t *,
|
||||
sc_pkcs15_prkey_t *);
|
||||
|
||||
/*
|
||||
* Generate key
|
||||
*/
|
||||
int (*generate_key)(sc_profile_t *, sc_card_t *,
|
||||
sc_pkcs15_object_t *,
|
||||
sc_pkcs15_pubkey_t *);
|
||||
|
||||
/*
|
||||
* Initialize application, and optionally set a SO pin
|
||||
*/
|
||||
int (*init_app)(struct sc_profile *, struct sc_card *,
|
||||
struct sc_pkcs15_pin_info *,
|
||||
const unsigned char *pin, size_t pin_len,
|
||||
const unsigned char *puk, size_t puk_len);
|
||||
|
||||
@ -58,7 +124,7 @@ struct sc_pkcs15init_operations {
|
||||
/*
|
||||
* Generate a new key pair
|
||||
*/
|
||||
int (*generate_key)(struct sc_profile *, struct sc_card *,
|
||||
int (*old_generate_key)(struct sc_profile *, struct sc_card *,
|
||||
unsigned int index, unsigned int keybits,
|
||||
sc_pkcs15_pubkey_t *pubkey_res,
|
||||
struct sc_pkcs15_prkey_info *);
|
||||
@ -75,7 +141,7 @@ struct sc_pkcs15init_operations {
|
||||
struct sc_pkcs15init_callbacks {
|
||||
/* Error and debug output */
|
||||
void (*error)(const char *, ...);
|
||||
void (*debug)(const char *, ...);
|
||||
void (*debug)(int level, const char *, ...);
|
||||
|
||||
/*
|
||||
* Get a PIN from the front-end. The first argument is
|
||||
@ -100,6 +166,7 @@ struct sc_pkcs15init_initargs {
|
||||
size_t so_pin_len;
|
||||
const u8 * so_puk;
|
||||
size_t so_puk_len;
|
||||
const char * so_pin_label;
|
||||
const char * label;
|
||||
const char * serial;
|
||||
};
|
||||
@ -220,8 +287,6 @@ extern int sc_pkcs15init_update_file(struct sc_profile *,
|
||||
struct sc_card *, struct sc_file *, void *, unsigned int);
|
||||
extern int sc_pkcs15init_authenticate(struct sc_profile *,
|
||||
struct sc_card *, struct sc_file *, int);
|
||||
extern int sc_pkcs15init_present_pin(struct sc_profile *,
|
||||
struct sc_card *, unsigned int);
|
||||
extern int sc_pkcs15init_fixup_file(struct sc_profile *, struct sc_file *);
|
||||
extern int sc_pkcs15init_fixup_acls(struct sc_profile *,
|
||||
struct sc_file *,
|
||||
@ -229,18 +294,17 @@ extern int sc_pkcs15init_fixup_acls(struct sc_profile *,
|
||||
struct sc_acl_entry *);
|
||||
extern int sc_pkcs15init_get_pin_info(struct sc_profile *, unsigned int,
|
||||
struct sc_pkcs15_pin_info *);
|
||||
extern int sc_profile_get_pin_retries(sc_profile_t *, unsigned int);
|
||||
extern int sc_pkcs15init_get_manufacturer(struct sc_profile *,
|
||||
const char **);
|
||||
extern int sc_pkcs15init_get_serial(struct sc_profile *, const char **);
|
||||
extern int sc_pkcs15init_set_serial(struct sc_profile *, const char *);
|
||||
extern int sc_pkcs15init_get_label(struct sc_profile *, const char **);
|
||||
|
||||
extern void sc_pkcs15init_set_pin_data(struct sc_profile *, int,
|
||||
const void *, size_t);
|
||||
extern void sc_pkcs15init_set_secret(struct sc_profile *,
|
||||
int, int, u8 *, size_t);
|
||||
extern int sc_pkcs15init_get_secret(struct sc_profile *,
|
||||
struct sc_card *, int, int, u8 *, size_t *);
|
||||
extern int sc_pkcs15init_verify_key(struct sc_profile *, struct sc_card *,
|
||||
sc_file_t *, unsigned int, unsigned int);
|
||||
|
||||
/* Erasing the card structure via rm -rf */
|
||||
extern int sc_pkcs15init_erase_card_recursively(struct sc_card *,
|
||||
@ -254,6 +318,9 @@ extern int sc_pkcs15init_requires_restrictive_usage(
|
||||
struct sc_pkcs15init_prkeyargs *,
|
||||
unsigned int);
|
||||
|
||||
extern int sc_pkcs15_create_pin_domain(sc_profile_t *, sc_card_t *,
|
||||
const sc_pkcs15_id_t *, sc_file_t **);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -32,6 +32,7 @@
|
||||
* Initialize the Application DF
|
||||
*/
|
||||
static int miocos_init_app(struct sc_profile *profile, struct sc_card *card,
|
||||
struct sc_pkcs15_pin_info *pin_info,
|
||||
const u8 *pin, size_t pin_len, const u8 *puk, size_t puk_len)
|
||||
{
|
||||
/* Create the application DF */
|
||||
@ -200,8 +201,8 @@ miocos_new_key(struct sc_profile *profile, struct sc_card *card,
|
||||
|
||||
struct sc_pkcs15init_operations sc_pkcs15init_miocos_operations = {
|
||||
NULL,
|
||||
miocos_init_app,
|
||||
miocos_new_pin,
|
||||
miocos_new_key,
|
||||
miocos_new_file,
|
||||
.init_app = miocos_init_app,
|
||||
.new_pin = miocos_new_pin,
|
||||
.new_key = miocos_new_key,
|
||||
.new_file = miocos_new_file,
|
||||
};
|
||||
|
@ -11,11 +11,40 @@ cardinfo {
|
||||
max-pin-length = 8;
|
||||
}
|
||||
|
||||
# Default settings.
|
||||
# This option block will always be processed.
|
||||
option default {
|
||||
macros {
|
||||
protected = *=$SOPIN, READ=NONE;
|
||||
unprotected = *=NONE;
|
||||
so-pin-flags = local, initialized, needs-padding, soPin;
|
||||
default-df-size = 256;
|
||||
}
|
||||
}
|
||||
|
||||
# This option sets up the card so that a single
|
||||
# user PIN protects all files
|
||||
option onepin {
|
||||
macros {
|
||||
protected = *=$PIN, READ=NONE;
|
||||
unprotected = *=NONE;
|
||||
so-pin-flags = local, initialized, needs-padding;
|
||||
}
|
||||
}
|
||||
|
||||
# This option is for cards with very little memory
|
||||
option small {
|
||||
macros {
|
||||
default-df-size = 128;
|
||||
}
|
||||
}
|
||||
|
||||
# Define reasonable limits for PINs and PUK
|
||||
# Note that we do not set a file path or reference
|
||||
# for the user pin; that is done dynamically.
|
||||
PIN user-pin {
|
||||
attempts = 3;
|
||||
flags = local, initialized, needs-padding;
|
||||
}
|
||||
PIN user-puk {
|
||||
attempts = 7;
|
||||
@ -24,7 +53,7 @@ PIN so-pin {
|
||||
auth-id = FF;
|
||||
attempts = 2;
|
||||
min-length = 6;
|
||||
flags = 0x32;
|
||||
flags = $so-pin-flags;
|
||||
}
|
||||
PIN so-puk {
|
||||
attempts = 4;
|
||||
@ -54,43 +83,43 @@ filesystem {
|
||||
|
||||
EF PKCS15-ODF {
|
||||
file-id = 5031;
|
||||
size = 256;
|
||||
ACL = *=NONE;
|
||||
size = $default-df-size;
|
||||
ACL = $unprotected;
|
||||
}
|
||||
|
||||
EF PKCS15-TokenInfo {
|
||||
file-id = 5032;
|
||||
ACL = *=NONE;
|
||||
ACL = $unprotected;
|
||||
}
|
||||
|
||||
EF PKCS15-AODF {
|
||||
file-id = 4401;
|
||||
size = 256;
|
||||
ACL = *=$SOPIN, READ=NONE;
|
||||
size = $default-df-size;
|
||||
ACL = $protected;
|
||||
}
|
||||
|
||||
EF PKCS15-PrKDF {
|
||||
file-id = 4402;
|
||||
size = 256;
|
||||
acl = *=$SOPIN, READ=NONE;
|
||||
size = $default-df-size;
|
||||
acl = $protected;
|
||||
}
|
||||
|
||||
EF PKCS15-PuKDF {
|
||||
file-id = 4403;
|
||||
size = 256;
|
||||
acl = *=$SOPIN, READ=NONE;
|
||||
size = $default-df-size;
|
||||
acl = $protected;
|
||||
}
|
||||
|
||||
EF PKCS15-CDF {
|
||||
file-id = 4404;
|
||||
size = 512;
|
||||
acl = *=$SOPIN, READ=NONE;
|
||||
size = "2 * $default-df-size";
|
||||
acl = $protected;
|
||||
}
|
||||
|
||||
EF PKCS15-DODF {
|
||||
file-id = 4405;
|
||||
size = 256;
|
||||
ACL = *=NONE;
|
||||
size = $default-df-size;
|
||||
ACL = $protected;
|
||||
}
|
||||
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -12,6 +12,7 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
#include <opensc/pkcs15.h>
|
||||
#include "keycache.h"
|
||||
|
||||
#ifndef SC_PKCS15_PROFILE_DIRECTORY
|
||||
#define SC_PKCS15_PROFILE_DIRECTORY "/usr/lib/opensc/profiles"
|
||||
@ -20,6 +21,7 @@ extern "C" {
|
||||
#define SC_PKCS15_PROFILE_SUFFIX "profile"
|
||||
#endif
|
||||
|
||||
/* Obsolete */
|
||||
struct auth_info {
|
||||
struct auth_info * next;
|
||||
unsigned int type; /* CHV, AUT, PRO */
|
||||
@ -34,6 +36,12 @@ struct file_info {
|
||||
struct sc_file * file;
|
||||
unsigned int dont_free;
|
||||
struct file_info * parent;
|
||||
|
||||
/* Template support */
|
||||
struct file_info * instance;
|
||||
struct sc_profile * base_template;
|
||||
unsigned int inst_index;
|
||||
sc_path_t inst_path;
|
||||
};
|
||||
|
||||
/* For now, we assume the PUK always resides
|
||||
@ -42,13 +50,33 @@ struct file_info {
|
||||
struct pin_info {
|
||||
unsigned int id;
|
||||
struct pin_info * next;
|
||||
char * file_name;
|
||||
unsigned int file_offset;
|
||||
struct file_info * file;
|
||||
char * file_name; /* obsolete */
|
||||
unsigned int file_offset; /* obsolete */
|
||||
struct file_info * file; /* obsolete */
|
||||
|
||||
struct sc_pkcs15_pin_info pin;
|
||||
sc_pkcs15_pin_info_t pin;
|
||||
};
|
||||
|
||||
typedef struct sc_macro {
|
||||
char * name;
|
||||
struct sc_macro * next;
|
||||
scconf_list * value;
|
||||
} sc_macro_t;
|
||||
|
||||
/* Template support.
|
||||
*
|
||||
* Templates are EFs or entire hierarchies of DFs/EFs.
|
||||
* When instantiating a template, the file IDs of the
|
||||
* EFs and DFs are combined from the value given in the
|
||||
* profile, and the last octet of the pkcs15 ID.
|
||||
*/
|
||||
typedef struct sc_template {
|
||||
char * name;
|
||||
struct sc_template * next;
|
||||
struct sc_profile * data;
|
||||
struct file_info * file;
|
||||
} sc_template_t;
|
||||
|
||||
struct sc_profile {
|
||||
char * driver;
|
||||
struct sc_pkcs15init_operations *ops;
|
||||
@ -61,7 +89,10 @@ struct sc_profile {
|
||||
|
||||
struct pin_info * pin_list;
|
||||
struct auth_info * auth_list;
|
||||
sc_template_t * template_list;
|
||||
sc_macro_t * macro_list;
|
||||
|
||||
unsigned int pin_domains;
|
||||
unsigned int pin_maxlen;
|
||||
unsigned int pin_minlen;
|
||||
unsigned int pin_pad_char;
|
||||
@ -70,36 +101,36 @@ struct sc_profile {
|
||||
unsigned int puk_attempts;
|
||||
unsigned int rsa_access_flags;
|
||||
unsigned int dsa_access_flags;
|
||||
unsigned int protect_certificates;
|
||||
|
||||
/* PKCS15 information */
|
||||
struct sc_pkcs15_card * p15_card;
|
||||
};
|
||||
|
||||
struct sc_profile *sc_profile_new();
|
||||
int sc_profile_load(struct sc_profile *, const char *);
|
||||
int sc_profile_load(struct sc_profile *, const char *,
|
||||
const char *);
|
||||
int sc_profile_finish(struct sc_profile *);
|
||||
void sc_profile_free(struct sc_profile *);
|
||||
int sc_profile_build_pkcs15(struct sc_profile *);
|
||||
void sc_profile_set_so_pin(struct sc_profile *, const char *);
|
||||
void sc_profile_set_user_pin(struct sc_profile *, const char *);
|
||||
void sc_profile_set_secret(struct sc_profile *,
|
||||
unsigned int, unsigned int, const u8 *, size_t);
|
||||
int sc_profile_get_secret(struct sc_profile *,
|
||||
unsigned int, unsigned int, u8 *, size_t *);
|
||||
void sc_profile_forget_secrets(struct sc_profile *,
|
||||
unsigned int, int);
|
||||
void sc_profile_get_pin_info(struct sc_profile *,
|
||||
unsigned int, struct sc_pkcs15_pin_info *);
|
||||
int sc_profile_get_pin_id(struct sc_profile *,
|
||||
unsigned int, unsigned int *);
|
||||
void sc_profile_set_pin_info(struct sc_profile *,
|
||||
unsigned int, const struct sc_pkcs15_pin_info *);
|
||||
int sc_profile_get_file(struct sc_profile *, const char *,
|
||||
struct sc_file **);
|
||||
int sc_profile_get_file_by_path(struct sc_profile *,
|
||||
const struct sc_path *, struct sc_file **);
|
||||
int sc_profile_get_path(struct sc_profile *,
|
||||
const char *, struct sc_path *);
|
||||
int sc_profile_get_file_in(struct sc_profile *,
|
||||
const sc_path_t *, const char *, sc_file_t **);
|
||||
int sc_profile_instantiate_template(struct sc_profile *,
|
||||
const char *, const sc_path_t *,
|
||||
const char *, const sc_pkcs15_id_t *,
|
||||
sc_file_t **);
|
||||
int sc_profile_add_file(struct sc_profile *,
|
||||
const char *, sc_file_t *);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -47,6 +47,7 @@
|
||||
#include <opensc/cardctl.h>
|
||||
#include <opensc/pkcs15.h>
|
||||
#include <opensc/pkcs15-init.h>
|
||||
#include <opensc/log.h>
|
||||
#include "util.h"
|
||||
|
||||
|
||||
@ -95,6 +96,7 @@ static int do_read_certificate(const char *, const char *, X509 **);
|
||||
static void parse_commandline(int argc, char **argv);
|
||||
static void read_options_file(const char *);
|
||||
static void ossl_print_errors(void);
|
||||
static void p15init_debug(int, const char *, ...);
|
||||
|
||||
|
||||
enum {
|
||||
@ -199,7 +201,7 @@ const char * option_help[] = {
|
||||
"Do not prompt the user, except for PINs",
|
||||
|
||||
"Specify the general profile to use",
|
||||
"Specify the card profile option to use",
|
||||
"Specify the card profile to use",
|
||||
"Read additional command line options from file",
|
||||
"Wait for card insertion",
|
||||
"Enable debugging output",
|
||||
@ -286,7 +288,7 @@ static unsigned int opt_secret_count;
|
||||
|
||||
static struct sc_pkcs15init_callbacks callbacks = {
|
||||
error, /* error() */
|
||||
NULL, /* debug() */
|
||||
p15init_debug, /* debug() */
|
||||
get_pin_callback, /* get_pin() */
|
||||
get_key_callback, /* get_key() */
|
||||
};
|
||||
@ -517,7 +519,7 @@ do_init_app(struct sc_profile *profile)
|
||||
args.so_puk_len = strlen((char *) args.so_puk);
|
||||
args.serial = (const char *) opt_serial;
|
||||
args.label = opt_label;
|
||||
|
||||
|
||||
return sc_pkcs15init_add_app(card, profile, &args);
|
||||
|
||||
failed:
|
||||
@ -699,6 +701,7 @@ static int
|
||||
do_store_public_key(struct sc_profile *profile, EVP_PKEY *pkey)
|
||||
{
|
||||
struct sc_pkcs15init_pubkeyargs args;
|
||||
sc_pkcs15_object_t *dummy;
|
||||
int r = 0;
|
||||
|
||||
memset(&args, 0, sizeof(args));
|
||||
@ -712,7 +715,7 @@ do_store_public_key(struct sc_profile *profile, EVP_PKEY *pkey)
|
||||
r = do_convert_public_key(&args.key, pkey);
|
||||
if (r >= 0)
|
||||
r = sc_pkcs15init_store_public_key(p15card, profile,
|
||||
&args, NULL);
|
||||
&args, &dummy);
|
||||
|
||||
return r;
|
||||
}
|
||||
@ -1935,3 +1938,22 @@ ossl_print_errors()
|
||||
while ((err = ERR_get_error()) != 0)
|
||||
fprintf(stderr, "%s\n", ERR_error_string(err, NULL));
|
||||
}
|
||||
|
||||
/*
|
||||
* Debug helper function
|
||||
*/
|
||||
void
|
||||
p15init_debug(int level, const char *fmt, ...)
|
||||
{
|
||||
char buffer[128];
|
||||
va_list ap;
|
||||
|
||||
if (ctx->debug < level)
|
||||
return;
|
||||
|
||||
va_start(ap, fmt);
|
||||
vsnprintf(buffer, sizeof(buffer), fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
sc_debug(ctx, "%s", buffer);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user