- rewrite of the pkcs15-init stuff
git-svn-id: https://www.opensc-project.org/svnp/opensc/trunk@415 c6295689-39f2-0310-b995-f0e70906c6a9
This commit is contained in:
parent
4c48335672
commit
b6bf368fd2
19
src/pkcs15init/Makefile.am
Normal file
19
src/pkcs15init/Makefile.am
Normal file
@ -0,0 +1,19 @@
|
||||
# Process this file with automake to create Makefile.in
|
||||
|
||||
INCLUDES = @CFLAGS_OPENSC@ -DSC_PKCS15_PROFILE_DIRECTORY=\"$(pkgdatadir)\"
|
||||
LDFLAGS = @LDFLAGS@ @LIBOPENSC@ @LIBCRYPTO@
|
||||
|
||||
EXTRA_DIST = flex.profile gpk.profile miocos.profile pkcs15.profile
|
||||
|
||||
if HAVE_SSL
|
||||
lib_LTLIBRARIES = libpkcs15init.la
|
||||
endif
|
||||
|
||||
libpkcs15init_la_SOURCES = \
|
||||
pkcs15-lib.c profile.c \
|
||||
pkcs15-gpk.c
|
||||
# pkcs15-miocos.c pkcs15-cflex.c
|
||||
|
||||
include_HEADERS = pkcs15-init.h
|
||||
noinst_HEADERS = profile.h
|
||||
pkgdata_DATA = flex.profile gpk.profile miocos.profile pkcs15.profile
|
18
src/pkcs15init/README
Normal file
18
src/pkcs15init/README
Normal file
@ -0,0 +1,18 @@
|
||||
|
||||
|
||||
Very brief instructions
|
||||
|
||||
To init card:
|
||||
|
||||
Erase card and create pkcs15 dir
|
||||
./pkcs15-init -EC
|
||||
|
||||
Store a PIN on the card, using ID 01
|
||||
./pkcs15-init -P --auth-id 01 --pin aaaa --puk bbbb --label "My PIN"
|
||||
|
||||
Generate a 512 bit RSA key and store on card, protected by the above PIN
|
||||
./pkcs15-init -G rsa/512 --auth-id 01
|
||||
|
||||
Or, store a pkcs12 key/certificate pair
|
||||
./pkcs15-init --auth-id 01 -f pkcs12 -S mycert.p12
|
||||
|
3
src/pkcs15init/TODO
Normal file
3
src/pkcs15init/TODO
Normal file
@ -0,0 +1,3 @@
|
||||
|
||||
- Support settting an SO pin (during pre-personalization)
|
||||
|
111
src/pkcs15init/flex.profile
Normal file
111
src/pkcs15init/flex.profile
Normal file
@ -0,0 +1,111 @@
|
||||
#
|
||||
# PKCS15 r/w profile for Cryptoflex cards
|
||||
#
|
||||
CardInfo
|
||||
Label "OpenSC Card"
|
||||
Manufacturer "OpenSC Project"
|
||||
MinPinLength 1
|
||||
MaxPinLength 8
|
||||
PinEncoding ascii-numeric
|
||||
PinPadChar 0x00
|
||||
PrKeyAccessFlags RSA 0x1D
|
||||
|
||||
# This is the AAK (ie. transport key) required for
|
||||
# creating files in the MF
|
||||
Key AUT1 0x0001 "=Muscle00"
|
||||
|
||||
DF MF
|
||||
Path 3F00
|
||||
ACL *=AUT1
|
||||
|
||||
DF key1df
|
||||
Parent PKCS15-AppDF
|
||||
FileID 4B01
|
||||
Size 750 # Sufficient for a 1024-bit key
|
||||
ACL *=AUT1 FILES=NONE
|
||||
|
||||
DF key2df
|
||||
Parent PKCS15-AppDF
|
||||
FileID 4B02
|
||||
Size 750 # Sufficient for a 1024-bit key
|
||||
ACL *=AUT1 FILES=NONE
|
||||
|
||||
EF pinfile-chv1
|
||||
Parent key1df
|
||||
FileID 0000
|
||||
Structure transparent
|
||||
Size 23
|
||||
ACL *=NEVER UPDATE=AUT1
|
||||
|
||||
EF pinfile-chv2
|
||||
Parent key2df
|
||||
FileID 0000
|
||||
Structure transparent
|
||||
Size 23
|
||||
ACL *=NEVER UPDATE=AUT1
|
||||
|
||||
EF template-private-key-1
|
||||
Parent key1df
|
||||
FileID 0012
|
||||
Structure transparent
|
||||
Size 330
|
||||
ACL *=AUT1 READ=NEVER
|
||||
|
||||
EF template-private-key-2
|
||||
Parent key2df
|
||||
FileID 0012
|
||||
Structure transparent
|
||||
Size 330
|
||||
ACL *=AUT1 READ=NEVER
|
||||
|
||||
EF template-public-key-1
|
||||
Parent PKCS15-AppDF
|
||||
FileID 5201
|
||||
Structure transparent
|
||||
ACL *=AUT1 READ=NONE
|
||||
|
||||
EF template-public-key-2
|
||||
Parent PKCS15-AppDF
|
||||
FileID 5202
|
||||
Structure transparent
|
||||
ACL *=AUT1 READ=NONE
|
||||
|
||||
EF PKCS15-DIR
|
||||
ACL *=NEVER READ=NONE UPDATE=AUT1
|
||||
|
||||
EF PKCS15-ODF
|
||||
ACL *=NEVER READ=NONE UPDATE=AUT1
|
||||
|
||||
EF PKCS15-AODF
|
||||
ACL *=NEVER READ=NONE UPDATE=AUT1
|
||||
|
||||
EF PKCS15-PrKDF
|
||||
ACL *=NEVER READ=NONE UPDATE=AUT1
|
||||
|
||||
EF PKCS15-PuKDF
|
||||
ACL *=NEVER READ=NONE UPDATE=AUT1
|
||||
|
||||
EF PKCS15-CDF
|
||||
ACL *=NEVER READ=NONE UPDATE=AUT1
|
||||
|
||||
# CHV1. 3 attempts for the PIN, and 10 for the PUK
|
||||
PIN CHV1
|
||||
File pinfile-chv1
|
||||
Reference 0x01
|
||||
Attempts 3 10
|
||||
|
||||
# CHV2. 3 attempts for the PIN, and 10 for the PUK
|
||||
PIN CHV2
|
||||
File pinfile-chv2
|
||||
Reference 0x01
|
||||
Attempts 3 10
|
||||
|
||||
PrivateKey AuthKey
|
||||
Reference 0x00
|
||||
Index 1
|
||||
File template-private-key-1
|
||||
|
||||
PrivateKey SignKey
|
||||
Reference 0x00
|
||||
Index 1
|
||||
File template-private-key-2
|
60
src/pkcs15init/gpk.profile
Normal file
60
src/pkcs15init/gpk.profile
Normal file
@ -0,0 +1,60 @@
|
||||
#
|
||||
# PKCS15 r/w profile for GPK cards
|
||||
#
|
||||
CardInfo
|
||||
Label "OpenSC Card (GPK)"
|
||||
Manufacturer "OpenSC Project"
|
||||
MinPinLength 1
|
||||
MaxPinLength 8
|
||||
PinEncoding BCD
|
||||
PrKeyAccessFlags RSA 0x1D
|
||||
PrKeyAccessFlags DSA 0x12
|
||||
|
||||
# This is the secure messaging key required for
|
||||
# creating files in the MF
|
||||
Key PRO1 "=TEST KEYTEST KEY"
|
||||
|
||||
# The PIN file.
|
||||
# The GPK supports just one PIN file per DF, and the file can hold
|
||||
# up to 8 pins (or 4 PIN/PUK pairs).
|
||||
#
|
||||
# Note1: many commands use the short file ID (i.e. the lower 5 bits
|
||||
# of the FID) so you must be careful when picking FIDs for the
|
||||
# public key and PIN files.
|
||||
|
||||
EF pinfile
|
||||
Parent PKCS15-AppDF
|
||||
FileID 0000
|
||||
Structure 0x21 # GPK specific
|
||||
RecordLength 8
|
||||
Size 64 # room for 8 pins
|
||||
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
|
||||
Parent PKCS15-AppDF
|
||||
FileID 0006 # This is the base FileID
|
||||
Structure 0x2C # GPK specific
|
||||
ACL *=NEVER READ=NONE CRYPTO=$PIN UPDATE=$PIN WRITE=$PIN
|
||||
|
||||
EF template-public-key
|
||||
Parent PKCS15-AppDF
|
||||
FileID 8000
|
||||
Structure transparent
|
||||
ACL *=NONE
|
||||
|
||||
# Certificate template
|
||||
EF template-certificate
|
||||
Parent PKCS15-AppDF
|
||||
FileID 9000
|
||||
Structure transparent
|
||||
ACL *=NONE
|
||||
|
||||
# Define an SO pin
|
||||
# This PIN is not used yet
|
||||
#PIN sopin
|
||||
# File sopinfile
|
||||
# Reference 0
|
87
src/pkcs15init/miocos.profile
Normal file
87
src/pkcs15init/miocos.profile
Normal file
@ -0,0 +1,87 @@
|
||||
#
|
||||
# PKCS15 r/w profile for MioCOS cards
|
||||
#
|
||||
CardInfo
|
||||
Label "OpenSC Card"
|
||||
Manufacturer "OpenSC Project"
|
||||
MinPinLength 1
|
||||
MaxPinLength 8
|
||||
PinEncoding ascii-numeric
|
||||
PinPadChar 0x00
|
||||
PrKeyAccessFlags RSA 0x1D
|
||||
|
||||
EF pinfile-chv1
|
||||
Path 3F000000
|
||||
Structure transparent
|
||||
Size 20
|
||||
ACL *=NONE
|
||||
|
||||
EF pinfile-chv2
|
||||
Parent PKCS15-AppDF
|
||||
FileID 5002
|
||||
Size 23
|
||||
ACL *=NONE
|
||||
|
||||
EF template-private-key-1
|
||||
Parent PKCS15-AppDF
|
||||
FileID 4B01
|
||||
Size 330
|
||||
ACL *=NONE CRYPTO=CHV1
|
||||
|
||||
EF template-private-key-2
|
||||
Parent PKCS15-AppDF
|
||||
FileID 4B02
|
||||
Size 330
|
||||
ACL *=NONE CRYPTO=CHV2
|
||||
|
||||
EF template-public-key-1
|
||||
Parent PKCS15-AppDF
|
||||
FileID 5201
|
||||
Structure transparent
|
||||
ACL *=NONE READ=NONE
|
||||
|
||||
EF template-public-key-2
|
||||
Parent PKCS15-AppDF
|
||||
FileID 5202
|
||||
Structure transparent
|
||||
ACL *=NONE READ=NONE
|
||||
|
||||
EF PKCS15-DIR
|
||||
ACL *=NEVER READ=NONE UPDATE=CHV1
|
||||
|
||||
EF PKCS15-ODF
|
||||
ACL *=NEVER READ=NONE UPDATE=CHV1
|
||||
|
||||
EF PKCS15-AODF
|
||||
ACL *=NEVER READ=NONE UPDATE=CHV1
|
||||
|
||||
EF PKCS15-PrKDF
|
||||
ACL *=NEVER READ=NONE UPDATE=CHV1
|
||||
|
||||
EF PKCS15-PuKDF
|
||||
ACL *=NEVER READ=NONE UPDATE=CHV1
|
||||
|
||||
EF PKCS15-CDF
|
||||
ACL *=NEVER READ=NONE UPDATE=CHV1
|
||||
|
||||
# CHV1. 3 attempts for the PIN, and 10 for the PUK
|
||||
PIN CHV1
|
||||
File pinfile-chv1
|
||||
Reference 0x01
|
||||
Attempts 3 10
|
||||
|
||||
# CHV2. 3 attempts for the PIN, and 10 for the PUK
|
||||
PIN CHV2
|
||||
File pinfile-chv2
|
||||
Reference 0x02
|
||||
Attempts 3 10
|
||||
|
||||
PrivateKey AuthKey
|
||||
Reference 0x01
|
||||
Index 1
|
||||
File template-private-key-1
|
||||
|
||||
PrivateKey SignKey
|
||||
Reference 0x02
|
||||
Index 1
|
||||
File template-private-key-2
|
423
src/pkcs15init/pkcs15-cflex.c
Normal file
423
src/pkcs15init/pkcs15-cflex.c
Normal file
@ -0,0 +1,423 @@
|
||||
/*
|
||||
* Cryptoflex specific operation for PKCS #15 initialization
|
||||
*
|
||||
* Copyright (C) 2002 Juha Yrjölä <juha.yrjola@iki.fi>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
#include <sys/types.h>
|
||||
#include <string.h>
|
||||
#include <openssl/bn.h>
|
||||
#include "opensc.h"
|
||||
#include "cardctl.h"
|
||||
#include "pkcs15-init.h"
|
||||
#include "util.h"
|
||||
|
||||
/*
|
||||
* Update the contents of a PIN file
|
||||
*/
|
||||
static int cflex_update_pin(struct sc_card *card, struct pin_info *info)
|
||||
{
|
||||
u8 buffer[23], *p = buffer;
|
||||
int r;
|
||||
size_t len;
|
||||
|
||||
if (!info->puk.tries_left) {
|
||||
error("Cryptoflex needs a PUK code");
|
||||
return SC_ERROR_INVALID_ARGUMENTS;
|
||||
}
|
||||
|
||||
memset(p, 0xFF, 3);
|
||||
p += 3;
|
||||
memset(p, info->pin.pad_char, 8);
|
||||
strncpy((char *) p, info->secret[0], 8);
|
||||
p += 8;
|
||||
*p++ = info->pin.tries_left;
|
||||
*p++ = info->pin.tries_left;
|
||||
memset(p, info->puk.pad_char, 8);
|
||||
strncpy((char *) p, info->secret[1], 8);
|
||||
p += 8;
|
||||
*p++ = info->puk.tries_left;
|
||||
*p++ = info->puk.tries_left;
|
||||
len = 23;
|
||||
|
||||
r = sc_update_binary(card, 0, buffer, len, 0);
|
||||
if (r < 0)
|
||||
return r;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create the PIN file and write the PINs
|
||||
*/
|
||||
static int cflex_store_pin(struct sc_profile *profile, struct sc_card *card,
|
||||
struct pin_info *info)
|
||||
{
|
||||
struct sc_file *pinfile;
|
||||
int r;
|
||||
|
||||
sc_file_dup(&pinfile, info->file->file);
|
||||
|
||||
card->ctx->log_errors = 0;
|
||||
r = sc_select_file(card, &pinfile->path, NULL);
|
||||
card->ctx->log_errors = 1;
|
||||
if (r == SC_ERROR_FILE_NOT_FOUND) {
|
||||
/* Now create the file */
|
||||
if ((r = sc_pkcs15init_create_file(profile, card, pinfile)) < 0)
|
||||
goto out;
|
||||
/* The PIN EF is automatically selected */
|
||||
} else if (r < 0)
|
||||
goto out;
|
||||
|
||||
/* If messing with the PIN file requires any sort of
|
||||
* authentication, send it to the card now */
|
||||
r = sc_pkcs15init_authenticate(profile, card, pinfile, SC_AC_OP_UPDATE);
|
||||
if (r < 0)
|
||||
goto out;
|
||||
|
||||
r = cflex_update_pin(card, info);
|
||||
|
||||
out: sc_file_free(pinfile);
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize the Application DF and store the PINs
|
||||
*
|
||||
*/
|
||||
static int cflex_init_app(struct sc_profile *profile, struct sc_card *card)
|
||||
{
|
||||
struct pin_info *pin1, *pin2, *pin3;
|
||||
int r;
|
||||
|
||||
pin1 = sc_profile_find_pin(profile, "CHV1");
|
||||
pin2 = sc_profile_find_pin(profile, "CHV2");
|
||||
pin3 = sc_profile_find_pin(profile, "CHV3");
|
||||
if (pin1 == NULL) {
|
||||
fprintf(stderr, "No CHV1 defined\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
card->ctx->log_errors = 0;
|
||||
r = sc_select_file(card, &profile->df_info.file->path, NULL);
|
||||
card->ctx->log_errors = 1;
|
||||
if (r == SC_ERROR_FILE_NOT_FOUND) {
|
||||
/* Create the application DF */
|
||||
if (sc_pkcs15init_create_file(profile, card, profile->df_info.file))
|
||||
return 1;
|
||||
} else if (r < 0) {
|
||||
fprintf(stderr, "Unable to select application DF: %s\n",
|
||||
sc_strerror(r));
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Store CHV3 (ie. SO PIN) */
|
||||
if (pin3) {
|
||||
if (cflex_store_pin(profile, card, pin3))
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Store CHV1 */
|
||||
if (cflex_store_pin(profile, card, pin1))
|
||||
return 1;
|
||||
|
||||
/* Store CHV2 */
|
||||
if (pin2) {
|
||||
if (cflex_store_pin(profile, card, pin2))
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate a file
|
||||
*/
|
||||
static int cflex_allocate_file(struct sc_profile *profile, struct sc_card *card,
|
||||
unsigned int type, unsigned int num,
|
||||
struct sc_file **out)
|
||||
{
|
||||
char name[64], *tag, *desc;
|
||||
|
||||
desc = tag = NULL;
|
||||
while (1) {
|
||||
switch (type) {
|
||||
case SC_PKCS15_TYPE_PRKEY_RSA:
|
||||
desc = "RSA private key";
|
||||
tag = "private-key";
|
||||
break;
|
||||
case SC_PKCS15_TYPE_PUBKEY_RSA:
|
||||
desc = "RSA public key";
|
||||
tag = "public-key";
|
||||
break;
|
||||
case SC_PKCS15_TYPE_CERT:
|
||||
desc = "certificate";
|
||||
tag = "data";
|
||||
break;
|
||||
case SC_PKCS15_TYPE_DATA_OBJECT:
|
||||
desc = "data object";
|
||||
tag = "data";
|
||||
break;
|
||||
}
|
||||
if (tag)
|
||||
break;
|
||||
/* If this is a specific type such as
|
||||
* SC_PKCS15_TYPE_CERT_FOOBAR, fall back to
|
||||
* the generic class (SC_PKCS15_TYPE_CERT)
|
||||
*/
|
||||
if (!(type & ~SC_PKCS15_TYPE_CLASS_MASK)) {
|
||||
error("File type not supported by card driver");
|
||||
return SC_ERROR_INVALID_ARGUMENTS;
|
||||
}
|
||||
type &= SC_PKCS15_TYPE_CLASS_MASK;
|
||||
}
|
||||
|
||||
snprintf(name, sizeof(name), "template-%s-%d", tag, num + 1);
|
||||
if (sc_profile_get_file(profile, name, out) < 0) {
|
||||
error("Profile doesn't define %s template (%s)",
|
||||
desc, name);
|
||||
return SC_ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void invert_buf(u8 *dest, const u8 *src, size_t c)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < c; i++)
|
||||
dest[i] = src[c-1-i];
|
||||
}
|
||||
|
||||
static int bn2cf(const BIGNUM *num, u8 *buf)
|
||||
{
|
||||
u8 tmp[512];
|
||||
int r;
|
||||
|
||||
r = BN_bn2bin(num, tmp);
|
||||
if (r <= 0)
|
||||
return r;
|
||||
invert_buf(buf, tmp, r);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static int gen_d(RSA *rsa)
|
||||
{
|
||||
BN_CTX *ctx, *ctx2;
|
||||
BIGNUM *r0, *r1, *r2;
|
||||
|
||||
ctx = BN_CTX_new();
|
||||
ctx2 = BN_CTX_new();
|
||||
BN_CTX_start(ctx);
|
||||
r0 = BN_CTX_get(ctx);
|
||||
r1 = BN_CTX_get(ctx);
|
||||
r2 = BN_CTX_get(ctx);
|
||||
BN_sub(r1, rsa->p, BN_value_one());
|
||||
BN_sub(r2, rsa->q, BN_value_one());
|
||||
BN_mul(r0, r1, r2, ctx);
|
||||
if ((rsa->d = BN_mod_inverse(NULL, rsa->e, r0, ctx2)) == NULL) {
|
||||
fprintf(stderr, "BN_mod_inverse() failed.\n");
|
||||
return -1;
|
||||
}
|
||||
BN_CTX_end(ctx);
|
||||
BN_CTX_free(ctx);
|
||||
BN_CTX_free(ctx2);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int cflex_encode_private_key(RSA *rsa, u8 *key, size_t *keysize, int key_num)
|
||||
{
|
||||
u8 buf[512], *p = buf;
|
||||
u8 bnbuf[256];
|
||||
int base = 0;
|
||||
int r;
|
||||
|
||||
switch (BN_num_bits(rsa->n)) {
|
||||
case 512:
|
||||
base = 32;
|
||||
break;
|
||||
case 768:
|
||||
base = 48;
|
||||
break;
|
||||
case 1024:
|
||||
base = 64;
|
||||
break;
|
||||
case 2048:
|
||||
base = 128;
|
||||
break;
|
||||
}
|
||||
if (base == 0) {
|
||||
fprintf(stderr, "Key length invalid.\n");
|
||||
return 2;
|
||||
}
|
||||
*p++ = (5 * base + 3) >> 8;
|
||||
*p++ = (5 * base + 3) & 0xFF;
|
||||
*p++ = key_num;
|
||||
r = bn2cf(rsa->p, bnbuf);
|
||||
if (r != base) {
|
||||
fprintf(stderr, "Invalid private key.\n");
|
||||
return 2;
|
||||
}
|
||||
memcpy(p, bnbuf, base);
|
||||
p += base;
|
||||
|
||||
r = bn2cf(rsa->q, bnbuf);
|
||||
if (r != base) {
|
||||
fprintf(stderr, "Invalid private key.\n");
|
||||
return 2;
|
||||
}
|
||||
memcpy(p, bnbuf, base);
|
||||
p += base;
|
||||
|
||||
r = bn2cf(rsa->iqmp, bnbuf);
|
||||
if (r != base) {
|
||||
fprintf(stderr, "Invalid private key.\n");
|
||||
return 2;
|
||||
}
|
||||
memcpy(p, bnbuf, base);
|
||||
p += base;
|
||||
|
||||
r = bn2cf(rsa->dmp1, bnbuf);
|
||||
if (r != base) {
|
||||
fprintf(stderr, "Invalid private key.\n");
|
||||
return 2;
|
||||
}
|
||||
memcpy(p, bnbuf, base);
|
||||
p += base;
|
||||
|
||||
r = bn2cf(rsa->dmq1, bnbuf);
|
||||
if (r != base) {
|
||||
fprintf(stderr, "Invalid private key.\n");
|
||||
return 2;
|
||||
}
|
||||
memcpy(p, bnbuf, base);
|
||||
p += base;
|
||||
*p++ = 0;
|
||||
*p++ = 0;
|
||||
*p++ = 0;
|
||||
|
||||
memcpy(key, buf, p - buf);
|
||||
*keysize = p - buf;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cflex_encode_public_key(RSA *rsa, u8 *key, size_t *keysize, int key_num)
|
||||
{
|
||||
u8 buf[512], *p = buf;
|
||||
u8 bnbuf[256];
|
||||
int base = 0;
|
||||
int r;
|
||||
|
||||
switch (BN_num_bits(rsa->n)) {
|
||||
case 512:
|
||||
base = 32;
|
||||
break;
|
||||
case 768:
|
||||
base = 48;
|
||||
break;
|
||||
case 1024:
|
||||
base = 64;
|
||||
break;
|
||||
case 2048:
|
||||
base = 128;
|
||||
break;
|
||||
}
|
||||
if (base == 0) {
|
||||
fprintf(stderr, "Key length invalid.\n");
|
||||
return 2;
|
||||
}
|
||||
*p++ = (5 * base + 7) >> 8;
|
||||
*p++ = (5 * base + 7) & 0xFF;
|
||||
*p++ = key_num;
|
||||
r = bn2cf(rsa->n, bnbuf);
|
||||
if (r != 2*base) {
|
||||
fprintf(stderr, "Invalid public key.\n");
|
||||
return 2;
|
||||
}
|
||||
memcpy(p, bnbuf, 2*base);
|
||||
p += 2*base;
|
||||
|
||||
memset(p, 0, base);
|
||||
p += base;
|
||||
|
||||
memset(bnbuf, 0, 2*base);
|
||||
memcpy(p, bnbuf, 2*base);
|
||||
p += 2*base;
|
||||
r = bn2cf(rsa->e, bnbuf);
|
||||
memcpy(p, bnbuf, 4);
|
||||
p += 4;
|
||||
*p++ = 0;
|
||||
*p++ = 0;
|
||||
*p++ = 0;
|
||||
|
||||
memcpy(key, buf, p - buf);
|
||||
*keysize = p - buf;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Store a RSA key on the card
|
||||
*/
|
||||
static int cflex_store_rsa_key(struct sc_profile *profile, struct sc_card *card,
|
||||
struct sc_key_template *info, RSA *rsa)
|
||||
{
|
||||
u8 prv[1024], pub[1024];
|
||||
size_t prvsize, pubsize;
|
||||
struct sc_file *tmpfile;
|
||||
int r;
|
||||
|
||||
r = cflex_encode_private_key(rsa, prv, &prvsize, 1);
|
||||
if (r)
|
||||
return -1;
|
||||
r = cflex_encode_public_key(rsa, pub, &pubsize, 1);
|
||||
if (r)
|
||||
return -1;
|
||||
info->file->size = prvsize;
|
||||
printf("Updating RSA private key...\n");
|
||||
r = sc_pkcs15init_update_file(profile, card, info->file, prv, prvsize);
|
||||
if (r < 0)
|
||||
return r;
|
||||
sc_file_dup(&tmpfile, info->file);
|
||||
sc_file_clear_acl_entries(tmpfile, SC_AC_OP_READ);
|
||||
sc_file_add_acl_entry(tmpfile, SC_AC_OP_READ, SC_AC_NONE, SC_AC_KEY_REF_NONE);
|
||||
tmpfile->path.len -= 2;
|
||||
sc_append_path_id(&tmpfile->path, (const u8 *) "\x10\x12", 2);
|
||||
tmpfile->id = 0x1012;
|
||||
tmpfile->size = pubsize;
|
||||
printf("Updating RSA public key...\n");
|
||||
r = sc_pkcs15init_update_file(profile, card, tmpfile, pub, pubsize);
|
||||
sc_file_free(tmpfile);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void bind_cflex_operations(struct pkcs15_init_operations *ops)
|
||||
{
|
||||
ops->init_app = cflex_init_app;
|
||||
ops->allocate_file = cflex_allocate_file;
|
||||
ops->store_rsa = cflex_store_rsa_key;
|
||||
}
|
943
src/pkcs15init/pkcs15-gpk.c
Normal file
943
src/pkcs15init/pkcs15-gpk.c
Normal file
@ -0,0 +1,943 @@
|
||||
/*
|
||||
* GPK specific operation for PKCS15 initialization
|
||||
*
|
||||
* Copyright (C) 2002 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 <sys/types.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <stdarg.h>
|
||||
#include <openssl/bn.h>
|
||||
#include "opensc.h"
|
||||
#include "cardctl.h"
|
||||
#include "pkcs15-init.h"
|
||||
#include "profile.h"
|
||||
|
||||
#define GPK_MAX_PINS 8
|
||||
#define GPK_FTYPE_SECRET_CODE 0x21
|
||||
#define GPK_FTYPE_PUBLIC_KEY 0x2C
|
||||
|
||||
/*
|
||||
* Key components (for storing private keys)
|
||||
*/
|
||||
struct pkcomp {
|
||||
unsigned char tag;
|
||||
u8 * data;
|
||||
unsigned int size;
|
||||
};
|
||||
struct pkdata {
|
||||
unsigned int algo;
|
||||
unsigned int usage;
|
||||
struct pkpart {
|
||||
struct pkcomp components[7];
|
||||
unsigned int count;
|
||||
unsigned int size;
|
||||
} public, private;
|
||||
unsigned int bits, bytes;
|
||||
};
|
||||
|
||||
/*
|
||||
* Local functions
|
||||
*/
|
||||
static int gpk_new_file(struct sc_profile *, struct sc_card *,
|
||||
unsigned int, unsigned int,
|
||||
struct sc_file **);
|
||||
static int gpk_encode_rsa_key(struct sc_profile *,
|
||||
RSA *, struct pkdata *,
|
||||
struct sc_pkcs15_prkey_info *);
|
||||
static int gpk_encode_dsa_key(struct sc_profile *,
|
||||
DSA *, struct pkdata *,
|
||||
struct sc_pkcs15_prkey_info *);
|
||||
static int gpk_store_pk(struct sc_profile *, struct sc_card *,
|
||||
struct sc_file *, struct pkdata *);
|
||||
static void error(struct sc_profile *, const char *, ...);
|
||||
|
||||
/*
|
||||
* Erase the card
|
||||
*/
|
||||
static int
|
||||
gpk_erase_card(struct sc_profile *pro, struct sc_card *card)
|
||||
{
|
||||
return sc_card_ctl(card, SC_CARDCTL_ERASE_CARD, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Lock a file operation
|
||||
*/
|
||||
static int
|
||||
gpk_lock(struct sc_card *card, struct sc_file *file, unsigned int op)
|
||||
{
|
||||
struct sc_cardctl_gpk_lock args;
|
||||
|
||||
args.file = file;
|
||||
args.operation = op;
|
||||
return sc_card_ctl(card, SC_CARDCTL_GPK_LOCK, &args);
|
||||
}
|
||||
|
||||
/*
|
||||
* Lock the pin file
|
||||
*/
|
||||
static int
|
||||
gpk_lock_pinfile(struct sc_profile *profile, struct sc_card *card,
|
||||
struct sc_file *pinfile)
|
||||
{
|
||||
struct sc_path path;
|
||||
struct sc_file *parent = NULL;
|
||||
int r;
|
||||
|
||||
/* Select the parent DF */
|
||||
path = pinfile->path;
|
||||
if (path.len >= 2)
|
||||
path.len -= 2;
|
||||
if (path.len == 0)
|
||||
sc_format_path("3F00", &path);
|
||||
if ((r = sc_select_file(card, &path, &parent)) < 0)
|
||||
return r;
|
||||
|
||||
/* Present PINs etc as necessary */
|
||||
r = sc_pkcs15init_authenticate(profile, card, parent, SC_AC_OP_LOCK);
|
||||
if (r >= 0)
|
||||
r = gpk_lock(card, pinfile, SC_AC_OP_WRITE);
|
||||
|
||||
sc_file_free(parent);
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize pin file
|
||||
*/
|
||||
static int
|
||||
gpk_init_pinfile(struct sc_profile *profile, struct sc_card *card,
|
||||
struct sc_file *file)
|
||||
{
|
||||
const struct sc_acl_entry *acl;
|
||||
unsigned char buffer[GPK_MAX_PINS * 8], *blk;
|
||||
struct sc_file *pinfile;
|
||||
unsigned int pin_attempts, puk_attempts;
|
||||
unsigned int npins, i, j, cks;
|
||||
int r;
|
||||
|
||||
/* Set defaults */
|
||||
if ((pin_attempts = profile->pin_attempts) == 0)
|
||||
pin_attempts = 7;
|
||||
if ((puk_attempts = profile->puk_attempts) == 0)
|
||||
puk_attempts = 3;
|
||||
|
||||
sc_file_dup(&pinfile, file);
|
||||
|
||||
/* Create the PIN file. */
|
||||
acl = sc_file_get_acl_entry(pinfile, SC_AC_OP_WRITE);
|
||||
if (acl->method != SC_AC_NEVER) {
|
||||
error(profile, "PIN file most be protected by WRITE=NEVER");
|
||||
return SC_ERROR_INVALID_ARGUMENTS;
|
||||
}
|
||||
sc_file_add_acl_entry(pinfile, SC_AC_OP_WRITE, SC_AC_NONE, 0);
|
||||
|
||||
if (pinfile->size == 0)
|
||||
pinfile->size = GPK_MAX_PINS * 8;
|
||||
|
||||
/* Now create the file */
|
||||
if ((r = sc_pkcs15init_create_file(profile, card, pinfile)) < 0
|
||||
|| (r = sc_select_file(card, &pinfile->path, NULL)) < 0)
|
||||
goto out;
|
||||
|
||||
/* Set up the PIN file contents.
|
||||
* We assume the file will contain pairs of PINs/PUKs */
|
||||
npins = pinfile->size / 8;
|
||||
memset(buffer, 0, sizeof(buffer));
|
||||
for (i = 0, blk = buffer; i < npins; blk += 8, i += 1) {
|
||||
if ((i % 1) == 0) {
|
||||
/* This is a PIN. If there's room in the file,
|
||||
* the next will be a PUK so take note of the
|
||||
* unlonk code */
|
||||
blk[0] = pin_attempts;
|
||||
if (i + 1 < npins)
|
||||
blk[2] = 0x8 | (i + 1);
|
||||
} else {
|
||||
/* This is the PUK */
|
||||
blk[0] = puk_attempts;
|
||||
}
|
||||
|
||||
/* Compute the CKS */
|
||||
for (j = 0, cks = 0; j < 8; j++)
|
||||
cks ^= blk[j];
|
||||
blk[3] = ~cks;
|
||||
}
|
||||
|
||||
r = sc_write_binary(card, 0, buffer, npins * 8, 0);
|
||||
if (r >= 0)
|
||||
r = gpk_lock_pinfile(profile, card, pinfile);
|
||||
|
||||
out: sc_file_free(pinfile);
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize the Application DF and pin file
|
||||
*/
|
||||
static int
|
||||
gpk_init_app(struct sc_profile *profile, struct sc_card *card)
|
||||
{
|
||||
struct sc_file *pinfile;
|
||||
int r;
|
||||
|
||||
/* 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_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];
|
||||
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\"");
|
||||
return SC_ERROR_INVALID_ARGUMENTS;
|
||||
}
|
||||
if (info->path.len > 2)
|
||||
info->path.len -= 2;
|
||||
|
||||
r = sc_select_file(card, &info->path, NULL);
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
|
||||
/* 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);
|
||||
|
||||
info->reference = 0x8 | index;
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* Store a private key
|
||||
*/
|
||||
static int
|
||||
gpk_new_key(struct sc_profile *profile, struct sc_card *card,
|
||||
EVP_PKEY *key, unsigned int index,
|
||||
struct sc_pkcs15_prkey_info *info)
|
||||
{
|
||||
struct sc_file *keyfile;
|
||||
struct pkdata data;
|
||||
int r;
|
||||
RSA *rsa;
|
||||
DSA *dsa;
|
||||
|
||||
switch (key->type) {
|
||||
case EVP_PKEY_RSA:
|
||||
r = gpk_new_file(profile, card,
|
||||
SC_PKCS15_TYPE_PRKEY_RSA, index,
|
||||
&keyfile);
|
||||
if (r >= 0) {
|
||||
rsa = EVP_PKEY_get1_RSA(key);
|
||||
r = gpk_encode_rsa_key(profile, rsa, &data, info);
|
||||
info->modulus_length = 8 * RSA_size(rsa);
|
||||
RSA_free(rsa);
|
||||
}
|
||||
break;
|
||||
|
||||
case EVP_PKEY_DSA:
|
||||
r = gpk_new_file(profile, card,
|
||||
SC_PKCS15_TYPE_PRKEY_DSA, index,
|
||||
&keyfile);
|
||||
if (r >= 0) {
|
||||
dsa = EVP_PKEY_get1_DSA(key);
|
||||
r = gpk_encode_dsa_key(profile, dsa, &data, info);
|
||||
info->modulus_length = 8 * DSA_size(dsa);
|
||||
DSA_free(dsa);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return SC_ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
/* Fix up PIN references in file ACL */
|
||||
if (r >= 0)
|
||||
r = sc_pkcs15init_fixup_file(profile, keyfile);
|
||||
|
||||
if (r >= 0)
|
||||
r = gpk_store_pk(profile, card, keyfile, &data);
|
||||
|
||||
info->path = keyfile->path;
|
||||
sc_file_free(keyfile);
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate a file
|
||||
*/
|
||||
static int
|
||||
gpk_new_file(struct sc_profile *profile, struct sc_card *card,
|
||||
unsigned int type, unsigned int num,
|
||||
struct sc_file **out)
|
||||
{
|
||||
struct sc_file *file;
|
||||
struct sc_path *p;
|
||||
char name[64], *tag, *desc;
|
||||
|
||||
desc = tag = NULL;
|
||||
while (1) {
|
||||
switch (type) {
|
||||
case SC_PKCS15_TYPE_PRKEY_RSA:
|
||||
desc = "RSA private key";
|
||||
tag = "private-key";
|
||||
break;
|
||||
case SC_PKCS15_TYPE_PUBKEY_RSA:
|
||||
desc = "RSA public key";
|
||||
tag = "public-key";
|
||||
break;
|
||||
#ifdef SC_PKCS15_TYPE_PRKEY_DSA
|
||||
case SC_PKCS15_TYPE_PRKEY_DSA:
|
||||
desc = "DSA private key";
|
||||
tag = "data";
|
||||
break;
|
||||
case SC_PKCS15_TYPE_PUBKEY_DSA:
|
||||
desc = "DSA public key";
|
||||
tag = "data";
|
||||
break;
|
||||
#endif
|
||||
case SC_PKCS15_TYPE_CERT:
|
||||
desc = "certificate";
|
||||
tag = "certificate";
|
||||
break;
|
||||
case SC_PKCS15_TYPE_DATA_OBJECT:
|
||||
desc = "data object";
|
||||
tag = "data";
|
||||
break;
|
||||
}
|
||||
if (tag)
|
||||
break;
|
||||
/* If this is a specific type such as
|
||||
* SC_PKCS15_TYPE_CERT_FOOBAR, fall back to
|
||||
* the generic class (SC_PKCS15_TYPE_CERT)
|
||||
*/
|
||||
if (!(type & ~SC_PKCS15_TYPE_CLASS_MASK)) {
|
||||
error(profile, "File type not supported by card driver");
|
||||
return SC_ERROR_INVALID_ARGUMENTS;
|
||||
}
|
||||
type &= SC_PKCS15_TYPE_CLASS_MASK;
|
||||
}
|
||||
|
||||
snprintf(name, sizeof(name), "template-%s", tag);
|
||||
if (sc_profile_get_file(profile, name, &file) < 0) {
|
||||
error(profile, "Profile doesn't define %s template (%s)\n",
|
||||
desc, name);
|
||||
return SC_ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
/* Now construct file from template */
|
||||
file->id += num;
|
||||
|
||||
p = &file->path;
|
||||
*p = profile->df_info.file->path;
|
||||
p->value[p->len++] = file->id >> 8;
|
||||
p->value[p->len++] = file->id;
|
||||
|
||||
*out = file;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* GPK public/private key file handling is hideous.
|
||||
* 600 lines of coke sweat and tears...
|
||||
*/
|
||||
/*
|
||||
* Create the PK file
|
||||
* 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)
|
||||
{
|
||||
struct sc_file *found = NULL;
|
||||
int r;
|
||||
|
||||
card->ctx->log_errors = 0;
|
||||
r = sc_select_file(card, &file->path, &found);
|
||||
card->ctx->log_errors = 1;
|
||||
if (r == SC_ERROR_FILE_NOT_FOUND) {
|
||||
r = sc_pkcs15init_create_file(profile, card, file);
|
||||
if (r >= 0)
|
||||
r = sc_select_file(card, &file->path, &found);
|
||||
} else {
|
||||
/* XXX: make sure the file has correct type and size? */
|
||||
}
|
||||
|
||||
if (r >= 0)
|
||||
r = sc_pkcs15init_authenticate(profile, card,
|
||||
file, SC_AC_OP_UPDATE);
|
||||
if (found)
|
||||
sc_file_free(found);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int
|
||||
gpk_pkfile_keybits(unsigned int bits, unsigned char *p)
|
||||
{
|
||||
switch (bits) {
|
||||
case 512: *p = 0x00; return 0;
|
||||
case 768: *p = 0x10; return 0;
|
||||
case 1024: *p = 0x11; return 0;
|
||||
}
|
||||
return SC_ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
static int
|
||||
gpk_pkfile_keyalgo(unsigned int algo, unsigned char *p)
|
||||
{
|
||||
switch (algo) {
|
||||
case SC_ALGORITHM_RSA: *p = 0x00; return 0;
|
||||
case SC_ALGORITHM_DSA: *p = 0x01; return 0;
|
||||
}
|
||||
return SC_ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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,
|
||||
unsigned int algo, unsigned int bits,
|
||||
unsigned int usage)
|
||||
{
|
||||
const struct sc_acl_entry *acl;
|
||||
u8 sysrec[7], buffer[256];
|
||||
unsigned int n, npins;
|
||||
int r;
|
||||
|
||||
/* Set up the system record */
|
||||
memset(sysrec, 0, sizeof(sysrec));
|
||||
|
||||
/* XXX: How to map keyUsage to sysrec[2]?
|
||||
* 0x00 sign & unwrap
|
||||
* 0x10 sign only
|
||||
* 0x20 unwrap only
|
||||
* 0x30 CA key
|
||||
* Which PKCS15 key usage values map to which flag?
|
||||
*/
|
||||
sysrec[2] = 0x00; /* no restriction for now */
|
||||
|
||||
/* Set the key type and algorithm */
|
||||
if ((r = gpk_pkfile_keybits(bits, &sysrec[1])) < 0
|
||||
|| (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);
|
||||
for (npins = 0; acl; acl = acl->next) {
|
||||
if (acl->method == SC_AC_NONE
|
||||
|| acl->method == SC_AC_NEVER)
|
||||
continue;
|
||||
if (acl->method != SC_AC_CHV) {
|
||||
error(profile, "Authentication method not "
|
||||
"supported for private key files.\n");
|
||||
return SC_ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
if (++npins >= 2) {
|
||||
error(profile, "Too many pins for PrKEY file!\n");
|
||||
return SC_ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
sysrec[2] += 0x40;
|
||||
sysrec[3] >>= 4;
|
||||
sysrec[3] |= acl->key_ref << 4;
|
||||
}
|
||||
|
||||
/* compute checksum - yet another slightly different
|
||||
* checksum algorithm courtesy of Gemplus */
|
||||
/* XXX: This is different from what the GPK reference
|
||||
* manual says which tells you to start with 0xA5 -- but
|
||||
* maybe that's just for the GPK8000 */
|
||||
for (sysrec[6] = 0xFF, n = 0; n < 6; n++)
|
||||
sysrec[6] ^= sysrec[n];
|
||||
|
||||
card->ctx->log_errors = 0;
|
||||
r = sc_read_record(card, 1, buffer, sizeof(buffer),
|
||||
SC_RECORD_BY_REC_NR);
|
||||
card->ctx->log_errors = 1;
|
||||
if (r >= 0) {
|
||||
if (r != 7 || buffer[0] != 0) {
|
||||
error(profile, "first record of public key file is not Lsys0");
|
||||
return SC_ERROR_OBJECT_NOT_VALID;
|
||||
}
|
||||
|
||||
r = sc_update_record(card, 1, sysrec, sizeof(sysrec),
|
||||
SC_RECORD_BY_REC_NR);
|
||||
} else {
|
||||
r = sc_append_record(card, sysrec, sizeof(sysrec), 0);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
static int
|
||||
gpk_pkfile_update_public(struct sc_profile *profile,
|
||||
struct sc_card *card, struct pkpart *part)
|
||||
{
|
||||
struct pkcomp *pe;
|
||||
unsigned char buffer[256];
|
||||
unsigned int m, n, tag;
|
||||
int r = 0, found;
|
||||
|
||||
if (card->ctx->debug > 1)
|
||||
printf("Updating public key elements\n");
|
||||
|
||||
/* If we've been given a key with public parts, write them now */
|
||||
for (n = 2; n < 256; n++) {
|
||||
card->ctx->log_errors = 0;
|
||||
r = sc_read_record(card, n, buffer, sizeof(buffer),
|
||||
SC_RECORD_BY_REC_NR);
|
||||
card->ctx->log_errors = 1;
|
||||
if (r < 0) {
|
||||
r = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Check for bad record */
|
||||
if (r < 2) {
|
||||
error(profile, "key file format error: "
|
||||
"record %u too small (%u bytes)\n",
|
||||
n, r);
|
||||
return SC_ERROR_OBJECT_NOT_VALID;
|
||||
}
|
||||
|
||||
tag = buffer[0];
|
||||
|
||||
for (m = 0, found = 0; m < part->count; m++) {
|
||||
pe = part->components + m;
|
||||
if (pe->tag == tag) {
|
||||
r = sc_update_record(card, n,
|
||||
pe->data, pe->size,
|
||||
SC_RECORD_BY_REC_NR);
|
||||
if (r < 0)
|
||||
return r;
|
||||
pe->tag = 0; /* mark as stored */
|
||||
found++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found && card->ctx->debug)
|
||||
printf("GPK unknown PK tag %u\n", tag);
|
||||
}
|
||||
|
||||
/* Write all remaining elements */
|
||||
for (m = 0; r >= 0 && m < part->count; m++) {
|
||||
pe = part->components + m;
|
||||
if (pe->tag != 0)
|
||||
r = sc_append_record(card, pe->data, pe->size, 0);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int
|
||||
gpk_pkfile_init_private(struct sc_card *card,
|
||||
struct sc_file *file, unsigned int privlen)
|
||||
{
|
||||
struct sc_cardctl_gpk_pkinit args;
|
||||
|
||||
if (card->ctx->debug > 1)
|
||||
printf("Initializing private key portion of file\n");
|
||||
args.file = file;
|
||||
args.privlen = privlen;
|
||||
return sc_card_ctl(card, SC_CARDCTL_GPK_PKINIT, &args);
|
||||
}
|
||||
|
||||
static int
|
||||
gpk_pkfile_load_private(struct sc_card *card, struct sc_file *file,
|
||||
u8 *data, unsigned int len, unsigned int datalen)
|
||||
{
|
||||
struct sc_cardctl_gpk_pkload args;
|
||||
|
||||
args.file = file;
|
||||
args.data = data;
|
||||
args.len = len;
|
||||
args.datalen = datalen;
|
||||
return sc_card_ctl(card, SC_CARDCTL_GPK_PKLOAD, &args);
|
||||
}
|
||||
|
||||
static int
|
||||
gpk_pkfile_update_private(struct sc_profile *profile,
|
||||
struct sc_card *card, struct sc_file *file,
|
||||
struct pkpart *part)
|
||||
{
|
||||
unsigned int m, size, nb, cks;
|
||||
struct pkcomp *pe;
|
||||
u8 keybuf[32], data[256];
|
||||
size_t keysize;
|
||||
int r = 0;
|
||||
|
||||
if (card->ctx->debug > 1)
|
||||
printf("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_profile_get_secret(profile, SC_AC_PRO, 0, 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;
|
||||
|
||||
if (pe->size + 8 > sizeof(data))
|
||||
return SC_ERROR_BUFFER_TOO_SMALL;
|
||||
memcpy(data, pe->data, pe->size);
|
||||
size = pe->size;
|
||||
|
||||
r = sc_verify(card, SC_AC_PRO, 0, keybuf, keysize, NULL);
|
||||
if (r < 0)
|
||||
break;
|
||||
|
||||
/* Pad out data to a multiple of 8 and checksum.
|
||||
* The GPK manual is a bit unclear about whether you
|
||||
* checksum first and then pad, or vice versa.
|
||||
* The following code does seem to work though: */
|
||||
for (nb = 0, cks = 0xff; nb < size; nb++)
|
||||
cks ^= data[nb];
|
||||
data[nb++] = cks;
|
||||
while (nb & 7)
|
||||
data[nb++] = 0;
|
||||
|
||||
r = gpk_pkfile_load_private(card, file, data, size, nb);
|
||||
if (r < 0)
|
||||
break;
|
||||
pe++;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Sum up the size of the public key elements
|
||||
* Each element is type + tag + bignum
|
||||
*/
|
||||
static void
|
||||
gpk_compute_publen(struct pkpart *part)
|
||||
{
|
||||
unsigned int n, publen = 8; /* length of sysrec0 */
|
||||
|
||||
for (n = 0; n < part->count; n++)
|
||||
publen += 2 + part->components[n].size;
|
||||
part->size = (publen + 3) & ~3UL;
|
||||
}
|
||||
|
||||
/* Sum up the size of the private key elements
|
||||
* Each element is type + tag + bignum + checksum, padded to a multiple
|
||||
* of eight
|
||||
*/
|
||||
static void
|
||||
gpk_compute_privlen(struct pkpart *part)
|
||||
{
|
||||
unsigned int n, privlen = 8;
|
||||
|
||||
for (n = 0; n < part->count; n++)
|
||||
privlen += (3 + part->components[n].size + 7) & ~7UL;
|
||||
part->size = privlen;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert BIGNUM to GPK representation, optionally zero padding to size.
|
||||
* Note OpenSSL stores BIGNUMs big endian while the GPK wants them
|
||||
* little endian
|
||||
*/
|
||||
static void
|
||||
gpk_bn2bin(const BIGNUM *bn, unsigned char *dest, unsigned int size)
|
||||
{
|
||||
u8 temp[256], *src;
|
||||
unsigned int n, len;
|
||||
|
||||
assert(BN_num_bytes(bn) <= sizeof(temp));
|
||||
len = BN_bn2bin(bn, temp);
|
||||
|
||||
assert(len <= size);
|
||||
for (n = 0, src = temp + len - 1; n < len; n++)
|
||||
dest[n] = *src--;
|
||||
for (; n < size; n++)
|
||||
dest[n] = '\0';
|
||||
}
|
||||
|
||||
/*
|
||||
* Add a BIGNUM component, optionally padding out the number to size bytes
|
||||
*/
|
||||
static void
|
||||
gpk_add_bignum(struct pkpart *part, unsigned int tag, BIGNUM *bn, size_t size)
|
||||
{
|
||||
struct pkcomp *comp;
|
||||
|
||||
if (size == 0)
|
||||
size = BN_num_bytes(bn);
|
||||
|
||||
comp = &part->components[part->count++];
|
||||
memset(comp, 0, sizeof(*comp));
|
||||
comp->tag = tag;
|
||||
comp->size = size + 1;
|
||||
comp->data = malloc(size + 1);
|
||||
|
||||
/* Add the tag */
|
||||
comp->data[0] = tag;
|
||||
|
||||
/* Add the BIGNUM */
|
||||
gpk_bn2bin(bn, comp->data + 1, size);
|
||||
|
||||
/* printf("TAG 0x%02x, len=%u\n", tag, comp->size); */
|
||||
}
|
||||
|
||||
int
|
||||
gpk_encode_rsa_key(struct sc_profile *profile,
|
||||
RSA *rsa, struct pkdata *p,
|
||||
struct sc_pkcs15_prkey_info *info)
|
||||
{
|
||||
if (!rsa->n || !rsa->e) {
|
||||
error(profile, "incomplete RSA public key");
|
||||
return SC_ERROR_INVALID_ARGUMENTS;
|
||||
}
|
||||
|
||||
/* Make sure the exponent is 0x10001 because that's
|
||||
* the only exponent supported by GPK4000 and GPK8000 */
|
||||
if (!BN_is_word(rsa->e, RSA_F4)) {
|
||||
error(profile, "unsupported RSA exponent");
|
||||
return SC_ERROR_INVALID_ARGUMENTS;
|
||||
}
|
||||
|
||||
memset(p, 0, sizeof(*p));
|
||||
p->algo = SC_ALGORITHM_RSA;
|
||||
p->usage = info->usage;
|
||||
p->bits = BN_num_bits(rsa->n);
|
||||
p->bytes = BN_num_bytes(rsa->n);
|
||||
|
||||
/* Set up the list of public elements */
|
||||
gpk_add_bignum(&p->public, 0x01, rsa->n, 0);
|
||||
gpk_add_bignum(&p->public, 0x07, rsa->e, 0);
|
||||
|
||||
/* Set up the list of private elements */
|
||||
if (!rsa->p || !rsa->q || !rsa->dmp1 || !rsa->dmq1 || !rsa->iqmp) {
|
||||
/* No or incomplete CRT information */
|
||||
if (!rsa->d) {
|
||||
error(profile, "incomplete RSA private key");
|
||||
return SC_ERROR_INVALID_ARGUMENTS;
|
||||
}
|
||||
gpk_add_bignum(&p->private, 0x04, rsa->d, 0);
|
||||
} else if (5 * (p->bytes / 2) < 256) {
|
||||
/* All CRT elements are stored in one record */
|
||||
struct pkcomp *comp;
|
||||
unsigned int K = p->bytes / 2;
|
||||
u8 *crtbuf;
|
||||
|
||||
crtbuf = malloc(5 * K + 1);
|
||||
|
||||
crtbuf[0] = 0x05;
|
||||
gpk_bn2bin(rsa->p, crtbuf + 1, K);
|
||||
gpk_bn2bin(rsa->q, crtbuf + 1 + 1 * K, K);
|
||||
gpk_bn2bin(rsa->iqmp, crtbuf + 1 + 2 * K, K);
|
||||
gpk_bn2bin(rsa->dmp1, crtbuf + 1 + 3 * K, K);
|
||||
gpk_bn2bin(rsa->dmq1, crtbuf + 1 + 4 * K, K);
|
||||
|
||||
comp = &p->private.components[p->private.count++];
|
||||
comp->tag = 0x05;
|
||||
comp->size = 5 * K + 1;
|
||||
comp->data = crtbuf;
|
||||
} else {
|
||||
/* CRT elements stored in individual records.
|
||||
* Make sure they're all fixed length even if they're
|
||||
* shorter */
|
||||
gpk_add_bignum(&p->private, 0x51, rsa->p, p->bytes/2);
|
||||
gpk_add_bignum(&p->private, 0x52, rsa->q, p->bytes/2);
|
||||
gpk_add_bignum(&p->private, 0x53, rsa->iqmp, p->bytes/2);
|
||||
gpk_add_bignum(&p->private, 0x54, rsa->dmp1, p->bytes/2);
|
||||
gpk_add_bignum(&p->private, 0x55, rsa->dmq1, p->bytes/2);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Encode a DSA key.
|
||||
* Confusingly, the GPK manual says that the GPK8000 can handle
|
||||
* DSA with 512 as well as 1024 bits, but all byte sizes shown
|
||||
* in the tables are 512 bits only...
|
||||
*/
|
||||
int
|
||||
gpk_encode_dsa_key(struct sc_profile *profile,
|
||||
DSA *dsa, struct pkdata *p,
|
||||
struct sc_pkcs15_prkey_info *info)
|
||||
{
|
||||
if (!dsa->p || !dsa->q || !dsa->g || !dsa->pub_key || !dsa->priv_key) {
|
||||
error(profile, "incomplete DSA public key");
|
||||
return SC_ERROR_INVALID_ARGUMENTS;
|
||||
}
|
||||
|
||||
memset(p, 0, sizeof(*p));
|
||||
p->algo = SC_ALGORITHM_RSA;
|
||||
p->usage = info->usage;
|
||||
p->bits = BN_num_bits(dsa->p);
|
||||
p->bytes = BN_num_bytes(dsa->p);
|
||||
|
||||
/* Make sure the key is either 512 or 1024 bits */
|
||||
if (p->bytes <= 64) {
|
||||
p->bits = 512;
|
||||
p->bytes = 64;
|
||||
} else if (p->bytes <= 128) {
|
||||
p->bits = 1024;
|
||||
p->bytes = 128;
|
||||
} else {
|
||||
error(profile, "incompatible DSA key size (%u bits)", p->bits);
|
||||
return SC_ERROR_INVALID_ARGUMENTS;
|
||||
}
|
||||
|
||||
/* Set up the list of public elements */
|
||||
gpk_add_bignum(&p->public, 0x09, dsa->p, 0);
|
||||
gpk_add_bignum(&p->public, 0x0a, dsa->q, 0);
|
||||
gpk_add_bignum(&p->public, 0x0b, dsa->g, 0);
|
||||
gpk_add_bignum(&p->public, 0x0c, dsa->pub_key, 0);
|
||||
|
||||
/* Set up the list of private elements */
|
||||
gpk_add_bignum(&p->private, 0x0d, dsa->priv_key, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
gpk_store_pk(struct sc_profile *profile, struct sc_card *card,
|
||||
struct sc_file *file, struct pkdata *p)
|
||||
{
|
||||
int r;
|
||||
|
||||
/* Compute length of private/public key parts */
|
||||
gpk_compute_publen(&p->public);
|
||||
gpk_compute_privlen(&p->private);
|
||||
|
||||
if (card->ctx->debug)
|
||||
printf("Storing pk: %u bits, pub %u bytes, priv %u bytes\n",
|
||||
p->bits, p->bytes, p->private.size);
|
||||
|
||||
/* Strange, strange, strange... when I create the public part with
|
||||
* the exact size of 8 + PK elements, the card refuses to store
|
||||
* the last record even though there's enough room in the file.
|
||||
* XXX: Check why */
|
||||
file->size = p->public.size + 8 + p->private.size + 8;
|
||||
r = gpk_pkfile_create(profile, card, file);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* Put the system record */
|
||||
r = gpk_pkfile_init_public(profile, card, file, p->algo,
|
||||
p->bits, p->usage);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* Put the public key elements */
|
||||
r = gpk_pkfile_update_public(profile, card, &p->public);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* Create the private key part */
|
||||
r = gpk_pkfile_init_private(card, file, p->private.size);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* Now store the private key elements */
|
||||
r = gpk_pkfile_update_private(profile, card, file, &p->private);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
#ifdef notdef
|
||||
static int
|
||||
gpk_bin2bn(const unsigned char *src, unsigned int len, BIGNUM **bn)
|
||||
{
|
||||
unsigned char num[1024];
|
||||
unsigned int n;
|
||||
|
||||
if (len > sizeof(num)) {
|
||||
error(profile, "number too big (%u bits)?", len * 8);
|
||||
return SC_ERROR_INVALID_ARGUMENTS;
|
||||
}
|
||||
for (n = 0; n < len; n++)
|
||||
num[n] = src[len-1-n];
|
||||
|
||||
*bn = BN_bin2bn(num, len, *bn);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
error(struct sc_profile *profile, const char *fmt, ...)
|
||||
{
|
||||
char buffer[256];
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
vsnprintf(buffer, sizeof(buffer), fmt, ap);
|
||||
va_end(ap);
|
||||
if (profile->cbs)
|
||||
profile->cbs->error("%s", buffer);
|
||||
}
|
||||
|
||||
struct sc_pkcs15init_operations sc_pkcs15init_gpk_operations = {
|
||||
gpk_erase_card,
|
||||
gpk_init_app,
|
||||
gpk_new_pin,
|
||||
gpk_new_key,
|
||||
gpk_new_file,
|
||||
};
|
143
src/pkcs15init/pkcs15-init.h
Normal file
143
src/pkcs15init/pkcs15-init.h
Normal file
@ -0,0 +1,143 @@
|
||||
/*
|
||||
* Function prototypes for pkcs15-init
|
||||
*
|
||||
* Copyright (C) 2002 Olaf Kirch <okir@lst.de>
|
||||
*/
|
||||
|
||||
#ifndef PKCS15_INIT_H
|
||||
#define PKCS15_INIT_H
|
||||
|
||||
#include <opensc-pkcs15.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/x509.h>
|
||||
|
||||
struct sc_profile; /* opaque type */
|
||||
|
||||
struct sc_pkcs15init_operations {
|
||||
/*
|
||||
* Erase everything that's on the card
|
||||
* So far, only the GPK supports this
|
||||
*/
|
||||
int (*erase_card)(struct sc_profile *, struct sc_card *);
|
||||
|
||||
/*
|
||||
* Initialize application
|
||||
*/
|
||||
int (*init_app)(struct sc_profile *, struct sc_card *);
|
||||
|
||||
/*
|
||||
* Store a new PIN
|
||||
* On some cards (such as the CryptoFlex) this will create
|
||||
* a new subdirectory of the AppDF.
|
||||
* Index is the number of the PIN in the AODF (this should
|
||||
* help the card driver to pick the right file ID/directory ID/
|
||||
* pin file index.
|
||||
*/
|
||||
int (*new_pin)(struct sc_profile *, struct sc_card *,
|
||||
struct sc_pkcs15_pin_info *, unsigned int index,
|
||||
const unsigned char *pin, size_t pin_len,
|
||||
const unsigned char *puk, size_t puk_len);
|
||||
|
||||
/*
|
||||
* Store a key on the card
|
||||
*/
|
||||
int (*new_key)(struct sc_profile *, struct sc_card *,
|
||||
EVP_PKEY *key, unsigned int index,
|
||||
struct sc_pkcs15_prkey_info *);
|
||||
|
||||
/*
|
||||
* Create a file based on a PKCS15_TYPE_xxx
|
||||
*/
|
||||
int (*new_file)(struct sc_profile *, struct sc_card *,
|
||||
unsigned int, unsigned int, struct sc_file **out);
|
||||
};
|
||||
|
||||
#define SC_PKCS15INIT_SO_PIN 0
|
||||
#define SC_PKCS15INIT_SO_PUK 1
|
||||
#define SC_PKCS15INIT_USER_PIN 2
|
||||
#define SC_PKCS15INIT_USER_PUK 3
|
||||
#define SC_PKCS15INIT_NPINS 4
|
||||
|
||||
struct sc_pkcs15init_callbacks {
|
||||
/* Error and debug output */
|
||||
void (*error)(const char *, ...);
|
||||
void (*debug)(const char *, ...);
|
||||
|
||||
/*
|
||||
* Get a PIN from the front-end. The first argument is
|
||||
* one if the SC_PKCS15INIT_XXX_PIN/PUK macros.
|
||||
*/
|
||||
int (*get_pin)(struct sc_profile *, int,
|
||||
const struct sc_pkcs15_pin_info *,
|
||||
u8 *, size_t *);
|
||||
int (*get_key)(struct sc_profile *,
|
||||
const char *prompt, u8 *, size_t *);
|
||||
};
|
||||
|
||||
struct sc_pkcs15init_pinargs {
|
||||
struct sc_pkcs15_id auth_id;
|
||||
const char * label;
|
||||
const u8 * pin;
|
||||
size_t pin_len;
|
||||
const u8 * puk;
|
||||
size_t puk_len;
|
||||
};
|
||||
|
||||
struct sc_pkcs15init_keyargs {
|
||||
struct sc_pkcs15_id id;
|
||||
struct sc_pkcs15_id auth_id;
|
||||
const char * label;
|
||||
const char * template_name;
|
||||
unsigned long usage;
|
||||
|
||||
/* For key generation */
|
||||
unsigned char onboard_keygen;
|
||||
unsigned int algorithm;
|
||||
unsigned int keybits;
|
||||
|
||||
EVP_PKEY * pkey;
|
||||
X509 * cert;
|
||||
};
|
||||
|
||||
struct sc_pkcs15init_certargs {
|
||||
struct sc_pkcs15_id id;
|
||||
const char * label;
|
||||
const char * template_name;
|
||||
|
||||
X509 * cert;
|
||||
};
|
||||
|
||||
extern void sc_pkcs15init_set_callbacks(struct sc_pkcs15init_callbacks *);
|
||||
extern int sc_pkcs15init_bind(struct sc_profile *,
|
||||
struct sc_card *, const char *);
|
||||
extern int sc_pkcs15init_add_app(struct sc_card *,
|
||||
struct sc_profile *);
|
||||
extern int sc_pkcs15init_store_pin(struct sc_pkcs15_card *,
|
||||
struct sc_profile *,
|
||||
struct sc_pkcs15init_pinargs *);
|
||||
extern int sc_pkcs15init_generate_key(struct sc_pkcs15_card *,
|
||||
struct sc_profile *,
|
||||
struct sc_pkcs15init_keyargs *);
|
||||
extern int sc_pkcs15init_store_private_key(struct sc_pkcs15_card *,
|
||||
struct sc_profile *,
|
||||
struct sc_pkcs15init_keyargs *);
|
||||
extern int sc_pkcs15init_store_public_key(struct sc_pkcs15_card *,
|
||||
struct sc_profile *,
|
||||
struct sc_pkcs15init_keyargs *);
|
||||
extern int sc_pkcs15init_store_certificate(struct sc_pkcs15_card *,
|
||||
struct sc_profile *,
|
||||
struct sc_pkcs15init_certargs *);
|
||||
|
||||
extern int sc_pkcs15init_create_file(struct sc_profile *,
|
||||
struct sc_card *, struct sc_file *);
|
||||
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_fixup_file(struct sc_profile *, struct sc_file *);
|
||||
extern int sc_pkcs15init_fixup_acls(struct sc_profile *,
|
||||
struct sc_file *,
|
||||
struct sc_acl_entry *,
|
||||
struct sc_acl_entry *);
|
||||
|
||||
#endif /* PKCS15_INIT_H */
|
1069
src/pkcs15init/pkcs15-lib.c
Normal file
1069
src/pkcs15init/pkcs15-lib.c
Normal file
File diff suppressed because it is too large
Load Diff
138
src/pkcs15init/pkcs15-miocos.c
Normal file
138
src/pkcs15init/pkcs15-miocos.c
Normal file
@ -0,0 +1,138 @@
|
||||
/*
|
||||
* MioCOS specific operation for PKCS15 initialization
|
||||
*
|
||||
* Copyright (C) 2002 Juha Yrjölä <juha.yrjola@iki.fi>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
#include <sys/types.h>
|
||||
#include <string.h>
|
||||
#include <openssl/bn.h>
|
||||
#include "opensc.h"
|
||||
#include "pkcs15-init.h"
|
||||
#include "util.h"
|
||||
|
||||
static int miocos_update_pin(struct sc_card *card, struct pin_info *info)
|
||||
{
|
||||
u8 buffer[20], *p = buffer;
|
||||
int r;
|
||||
size_t len;
|
||||
|
||||
if (!info->puk.tries_left) {
|
||||
error("PUK code needed.");
|
||||
return SC_ERROR_INVALID_ARGUMENTS;
|
||||
}
|
||||
info->pin.tries_left &= 0x0f;
|
||||
*p++ = (info->pin.tries_left << 8) | info->pin.tries_left;
|
||||
*p++ = 0xFF;
|
||||
memset(p, info->pin.pad_char, 8);
|
||||
strncpy((char *) p, info->secret[0], 8);
|
||||
p += 8;
|
||||
info->puk.tries_left &= 0x0f;
|
||||
*p++ = (info->puk.tries_left << 8) | info->puk.tries_left;
|
||||
*p++ = 0xFF;
|
||||
strncpy((char *) p, info->secret[1], 8);
|
||||
p += 8;
|
||||
len = 20;
|
||||
|
||||
r = sc_update_binary(card, 0, buffer, len, 0);
|
||||
if (r < 0)
|
||||
return r;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int miocos_store_pin(struct sc_profile *profile, struct sc_card *card,
|
||||
struct pin_info *info)
|
||||
{
|
||||
struct sc_file *pinfile;
|
||||
int r;
|
||||
|
||||
sc_file_dup(&pinfile, info->file->file);
|
||||
|
||||
card->ctx->log_errors = 0;
|
||||
r = sc_select_file(card, &pinfile->path, NULL);
|
||||
card->ctx->log_errors = 1;
|
||||
pinfile->type = SC_FILE_TYPE_INTERNAL_EF;
|
||||
pinfile->ef_structure = 0;
|
||||
if (r == SC_ERROR_FILE_NOT_FOUND) {
|
||||
/* Now create the file */
|
||||
r = sc_pkcs15init_create_file(profile, card, pinfile);
|
||||
if (r < 0)
|
||||
goto out;
|
||||
/* The PIN EF is automatically selected */
|
||||
} else if (r < 0)
|
||||
goto out;
|
||||
|
||||
/* If messing with the PIN file requires any sort of
|
||||
* authentication, send it to the card now */
|
||||
r = sc_pkcs15init_authenticate(profile, card, pinfile, SC_AC_OP_UPDATE);
|
||||
if (r < 0)
|
||||
goto out;
|
||||
|
||||
r = miocos_update_pin(card, info);
|
||||
|
||||
out: sc_file_free(pinfile);
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize the Application DF and store the PINs
|
||||
*/
|
||||
static int miocos_init_app(struct sc_profile *profile, struct sc_card *card)
|
||||
{
|
||||
struct pin_info *pin1, *pin2;
|
||||
|
||||
pin1 = sc_profile_find_pin(profile, "CHV1");
|
||||
pin2 = sc_profile_find_pin(profile, "CHV2");
|
||||
if (pin1 == NULL) {
|
||||
fprintf(stderr, "No CHV1 defined\n");
|
||||
return 1;
|
||||
}
|
||||
/* Create the application DF */
|
||||
if (sc_pkcs15init_create_file(profile, card, profile->df_info.file))
|
||||
return 1;
|
||||
|
||||
if (pin2) {
|
||||
if (miocos_store_pin(profile, card, pin2))
|
||||
return 1;
|
||||
}
|
||||
if (miocos_store_pin(profile, card, pin1))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Store a RSA key on the card
|
||||
*/
|
||||
static int miocos_store_rsa_key(struct sc_profile *profile,
|
||||
struct sc_card *card,
|
||||
struct sc_key_template *info,
|
||||
RSA *rsa)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void bind_miocos_operations(struct pkcs15_init_operations *ops)
|
||||
{
|
||||
ops->erase_card = NULL;
|
||||
ops->init_app = miocos_init_app;
|
||||
ops->store_rsa = miocos_store_rsa_key;
|
||||
ops->store_dsa = NULL;
|
||||
}
|
51
src/pkcs15init/pkcs15.profile
Normal file
51
src/pkcs15init/pkcs15.profile
Normal file
@ -0,0 +1,51 @@
|
||||
#
|
||||
# PKCS15 profile, generic information.
|
||||
# This profile is loaded before any card specific profile.
|
||||
#
|
||||
|
||||
# This is the DIR file
|
||||
EF PKCS15-DIR
|
||||
Path 3F002F00
|
||||
Size 128
|
||||
ACL *=NONE
|
||||
|
||||
# This is the application DF
|
||||
DF PKCS15-AppDF
|
||||
Path 3F005015
|
||||
AID A0:00:00:00:63:50:4B:43:53:2D:31:35
|
||||
ACL *=NONE
|
||||
|
||||
EF PKCS15-ODF
|
||||
Parent PKCS15-AppDF
|
||||
FileID 5031
|
||||
Size 128
|
||||
ACL *=NONE
|
||||
|
||||
EF PKCS15-TokenInfo
|
||||
Parent PKCS15-AppDF
|
||||
FileID 5032
|
||||
ACL *=NONE
|
||||
|
||||
EF PKCS15-AODF
|
||||
Parent PKCS15-AppDF
|
||||
FileID 4401
|
||||
Size 128
|
||||
ACL *=NEVER READ=NONE UPDATE=$SOPIN
|
||||
|
||||
EF PKCS15-PrKDF
|
||||
Parent PKCS15-AppDF
|
||||
FileID 4402
|
||||
Size 128
|
||||
ACL *=NEVER READ=NONE UPDATE=$SOPIN
|
||||
|
||||
EF PKCS15-PuKDF
|
||||
Parent PKCS15-AppDF
|
||||
FileID 4403
|
||||
Size 128
|
||||
ACL *=NEVER READ=NONE UPDATE=$SOPIN
|
||||
|
||||
EF PKCS15-CDF
|
||||
Parent PKCS15-AppDF
|
||||
FileID 4404
|
||||
Size 128
|
||||
ACL *=NEVER READ=NONE UPDATE=$SOPIN
|
1523
src/pkcs15init/profile.c
Normal file
1523
src/pkcs15init/profile.c
Normal file
File diff suppressed because it is too large
Load Diff
136
src/pkcs15init/profile.h
Normal file
136
src/pkcs15init/profile.h
Normal file
@ -0,0 +1,136 @@
|
||||
/*
|
||||
* Card profile information (internal)
|
||||
*
|
||||
* Copyright (C) 2002 Olaf Kirch <okir@lst.de>
|
||||
*/
|
||||
|
||||
#ifndef _OPENSC_PROFILE_H
|
||||
#define _OPENSC_PROFILE_H
|
||||
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/dsa.h>
|
||||
#include "opensc-pkcs15.h"
|
||||
|
||||
#ifndef SC_PKCS15_PROFILE_DIRECTORY
|
||||
#define SC_PKCS15_PROFILE_DIRECTORY "/usr/lib/opensc/profiles"
|
||||
#endif
|
||||
#ifndef SC_PKCS15_PROFILE_SUFFIX
|
||||
#define SC_PKCS15_PROFILE_SUFFIX "profile"
|
||||
#endif
|
||||
|
||||
struct auth_info {
|
||||
struct auth_info * next;
|
||||
unsigned int type; /* CHV, AUT, PRO */
|
||||
unsigned int ref;
|
||||
size_t key_len;
|
||||
u8 key[32];
|
||||
};
|
||||
|
||||
struct file_info {
|
||||
char * ident;
|
||||
struct file_info * next;
|
||||
struct sc_file * file;
|
||||
struct file_info * parent;
|
||||
|
||||
/* PKCS15 book-keeping info */
|
||||
/*
|
||||
struct {
|
||||
unsigned int fileno;
|
||||
unsigned int type;
|
||||
} pkcs15;
|
||||
*/
|
||||
};
|
||||
|
||||
/* For now, we assume the PUK always resides
|
||||
* in the same file as the PIN
|
||||
*/
|
||||
struct pin_info {
|
||||
unsigned int id;
|
||||
struct pin_info * next;
|
||||
struct file_info * file;
|
||||
unsigned int file_offset;
|
||||
|
||||
struct sc_pkcs15_pin_info pin;
|
||||
};
|
||||
|
||||
/* OBSOLESCENT */
|
||||
struct sc_key_template {
|
||||
char * ident;
|
||||
struct sc_key_template *next;
|
||||
struct sc_file * file;
|
||||
unsigned int index; /* translates to file offset */
|
||||
struct sc_acl_entry * key_acl;/* PINs for key usage */
|
||||
|
||||
struct sc_pkcs15_object pkcs15_obj;
|
||||
union {
|
||||
struct sc_pkcs15_prkey_info priv;
|
||||
struct sc_pkcs15_pubkey_info pub;
|
||||
} pkcs15;
|
||||
};
|
||||
|
||||
/* OBSOLESCENT */
|
||||
struct sc_cert_template {
|
||||
char * ident;
|
||||
struct sc_cert_template *next;
|
||||
struct sc_file * file;
|
||||
struct sc_pkcs15_object pkcs15_obj;
|
||||
struct sc_pkcs15_cert_info pkcs15;
|
||||
};
|
||||
|
||||
struct sc_profile {
|
||||
char * driver;
|
||||
struct sc_pkcs15init_operations *ops;
|
||||
struct sc_pkcs15init_callbacks *cbs;
|
||||
|
||||
struct file_info mf_info;
|
||||
struct file_info df_info;
|
||||
struct file_info * ef_list;
|
||||
struct sc_file * df[SC_PKCS15_DF_TYPE_COUNT];
|
||||
|
||||
struct pin_info * pin_list;
|
||||
struct auth_info * auth_list;
|
||||
struct sc_key_template *prkey_list;
|
||||
struct sc_key_template *pubkey_list;
|
||||
struct sc_cert_template *cert_list;
|
||||
|
||||
unsigned int pin_maxlen;
|
||||
unsigned int pin_minlen;
|
||||
unsigned int pin_pad_char;
|
||||
unsigned int pin_encoding;
|
||||
unsigned int pin_attempts;
|
||||
unsigned int puk_attempts;
|
||||
unsigned int rsa_access_flags;
|
||||
unsigned int dsa_access_flags;
|
||||
|
||||
/* PKCS15 information */
|
||||
struct sc_pkcs15_card * p15_card;
|
||||
char * p15_label;
|
||||
char * p15_manufacturer;
|
||||
char * p15_serial;
|
||||
};
|
||||
|
||||
void sc_profile_init(struct sc_profile *);
|
||||
int sc_profile_load(struct sc_profile *, const char *);
|
||||
int sc_profile_finish(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_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 *);
|
||||
|
||||
|
||||
#endif /* _OPENSC_PROFILE_H */
|
Loading…
Reference in New Issue
Block a user