2012-09-27 13:50:15 +00:00
|
|
|
/*
|
|
|
|
* pkcs15-sc-hsm.c : PKCS#15 emulation for write support
|
|
|
|
*
|
|
|
|
* Copyright (C) 2012 Andreas Schwier, CardContact, Minden, Germany
|
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
* License along with this library; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
#include <config.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <ctype.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
|
|
|
|
#include "../libopensc/opensc.h"
|
|
|
|
#include "../libopensc/cardctl.h"
|
|
|
|
#include "../libopensc/log.h"
|
|
|
|
#include "../libopensc/pkcs15.h"
|
|
|
|
#include "../libopensc/cards.h"
|
|
|
|
#include "../libopensc/card-sc-hsm.h"
|
|
|
|
#include "../libopensc/asn1.h"
|
|
|
|
#include "../libopensc/pkcs15.h"
|
|
|
|
|
|
|
|
#include "pkcs15-init.h"
|
|
|
|
#include "profile.h"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static u8 pubexp[] = { 0x01, 0x00, 0x01 };
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int sc_hsm_delete_ef(sc_pkcs15_card_t *p15card, u8 prefix, u8 id)
|
|
|
|
{
|
|
|
|
sc_card_t *card = p15card->card;
|
|
|
|
sc_path_t path;
|
|
|
|
u8 fid[2];
|
|
|
|
int r;
|
|
|
|
|
|
|
|
fid[0] = prefix;
|
|
|
|
fid[1] = id;
|
|
|
|
|
|
|
|
sc_path_set(&path, SC_PATH_TYPE_FILE_ID, fid, 2, 0, -1);
|
|
|
|
|
|
|
|
r = sc_delete_file(card, &path);
|
|
|
|
LOG_TEST_RET(card->ctx, r, "Could not delete file");
|
|
|
|
|
|
|
|
LOG_FUNC_RETURN(card->ctx, r);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int sc_hsm_update_ef(sc_pkcs15_card_t *p15card, u8 prefix, u8 id, int erase, u8 *buf, size_t buflen)
|
|
|
|
{
|
|
|
|
sc_card_t *card = p15card->card;
|
|
|
|
sc_file_t *file = NULL;
|
|
|
|
sc_path_t path;
|
|
|
|
u8 fid[2];
|
|
|
|
int r;
|
|
|
|
|
|
|
|
fid[0] = prefix;
|
|
|
|
fid[1] = id;
|
|
|
|
|
|
|
|
sc_path_set(&path, SC_PATH_TYPE_FILE_ID, fid, 2, 0, -1);
|
|
|
|
|
|
|
|
r = sc_select_file(card, &path, NULL);
|
|
|
|
|
|
|
|
if ((r == SC_SUCCESS) && erase) {
|
|
|
|
r = sc_delete_file(card, &path);
|
|
|
|
LOG_TEST_RET(card->ctx, r, "Could not delete file");
|
|
|
|
r = SC_ERROR_FILE_NOT_FOUND;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (r == SC_ERROR_FILE_NOT_FOUND) {
|
|
|
|
file = sc_file_new();
|
|
|
|
file->id = (path.value[0] << 8) | path.value[1];
|
|
|
|
file->type = SC_FILE_TYPE_WORKING_EF;
|
|
|
|
file->ef_structure = SC_FILE_EF_TRANSPARENT;
|
|
|
|
file->size = (size_t) 0;
|
|
|
|
file->status = SC_FILE_STATUS_ACTIVATED;
|
|
|
|
r = sc_create_file(card, file);
|
|
|
|
sc_file_free(file);
|
2012-10-14 12:35:46 +00:00
|
|
|
LOG_TEST_RET(card->ctx, r, "Could not create file");
|
2012-09-27 13:50:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
r = sc_update_binary(card, 0, buf, buflen, 0);
|
|
|
|
LOG_FUNC_RETURN(card->ctx, r);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int sc_hsm_create_key(sc_profile_t *profile, sc_pkcs15_card_t *p15card,
|
|
|
|
sc_pkcs15_object_t *obj)
|
|
|
|
{
|
|
|
|
// Keys are automatically generated in GENERATE ASYMMETRIC KEY PAIR command
|
|
|
|
LOG_FUNC_CALLED(p15card->card->ctx);
|
|
|
|
LOG_FUNC_RETURN(p15card->card->ctx, SC_SUCCESS);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2014-07-13 10:13:04 +00:00
|
|
|
static int sc_hsm_store_key(sc_profile_t *profile, sc_pkcs15_card_t *p15card,
|
2014-09-03 15:16:59 +00:00
|
|
|
sc_pkcs15_object_t *obj, sc_pkcs15_prkey_t *key)
|
2014-07-13 10:13:04 +00:00
|
|
|
{
|
|
|
|
LOG_FUNC_CALLED(p15card->card->ctx);
|
|
|
|
LOG_FUNC_RETURN(p15card->card->ctx, SC_ERROR_NOT_SUPPORTED);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2012-09-27 13:50:15 +00:00
|
|
|
static int sc_hsm_determine_free_id(struct sc_pkcs15_card *p15card, u8 range)
|
|
|
|
{
|
|
|
|
struct sc_card *card = p15card->card;
|
|
|
|
u8 filelist[MAX_EXT_APDU_LENGTH];
|
|
|
|
int filelistlength, i, j;
|
|
|
|
|
|
|
|
LOG_FUNC_CALLED(p15card->card->ctx);
|
|
|
|
|
|
|
|
filelistlength = sc_list_files(card, filelist, sizeof(filelist));
|
|
|
|
LOG_TEST_RET(card->ctx, filelistlength, "Could not enumerate file and key identifier");
|
|
|
|
|
|
|
|
for (j = 0; j < 256; j++) {
|
|
|
|
for (i = 0; i < filelistlength; i += 2) {
|
|
|
|
if ((filelist[i] == range) && (filelist[i + 1] == j)) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (i >= filelistlength) {
|
|
|
|
LOG_FUNC_RETURN(p15card->card->ctx, j);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
LOG_FUNC_RETURN(p15card->card->ctx, SC_ERROR_NOT_ENOUGH_MEMORY);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int sc_hsm_encode_gakp_rsa(struct sc_pkcs15_card *p15card, sc_cvc_t *cvc, int keysize) {
|
|
|
|
struct sc_object_id rsa15withSHA256 = { { 0,4,0,127,0,7,2,2,2,1,2,-1 } };
|
|
|
|
|
|
|
|
LOG_FUNC_CALLED(p15card->card->ctx);
|
|
|
|
|
|
|
|
cvc->coefficientAorExponentlen = sizeof(pubexp);
|
|
|
|
cvc->coefficientAorExponent = malloc(sizeof(pubexp));
|
|
|
|
if (!cvc->coefficientAorExponent) {
|
|
|
|
LOG_FUNC_RETURN(p15card->card->ctx, SC_ERROR_OUT_OF_MEMORY);
|
|
|
|
}
|
|
|
|
memcpy(cvc->coefficientAorExponent, pubexp, sizeof(pubexp));
|
|
|
|
|
|
|
|
cvc->pukoid = rsa15withSHA256;
|
|
|
|
cvc->modulusSize = keysize;
|
|
|
|
|
|
|
|
LOG_FUNC_RETURN(p15card->card->ctx, SC_SUCCESS);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int sc_hsm_encode_gakp_ec(struct sc_pkcs15_card *p15card, sc_cvc_t *cvc, struct sc_pkcs15_prkey_info *key_info) {
|
|
|
|
struct sc_object_id ecdsaWithSHA256 = { { 0,4,0,127,0,7,2,2,2,2,3,-1 } };
|
2015-02-14 16:47:59 +00:00
|
|
|
struct sc_ec_parameters *ecparams = (struct sc_ec_parameters *)key_info->params.data;
|
2013-05-25 02:22:28 +00:00
|
|
|
struct ec_curve *curve = NULL;
|
2012-09-27 13:50:15 +00:00
|
|
|
u8 *curveoid;
|
2014-11-04 16:11:34 +00:00
|
|
|
int curveoidlen,r;
|
2012-09-27 13:50:15 +00:00
|
|
|
|
|
|
|
LOG_FUNC_CALLED(p15card->card->ctx);
|
|
|
|
|
|
|
|
curveoid = ecparams->der.value;
|
|
|
|
if ((ecparams->der.len < 3) || (*curveoid++ != 0x06)) {
|
|
|
|
sc_log(p15card->card->ctx, "EC_PARAMS does not contain curve object identifier");
|
|
|
|
LOG_FUNC_RETURN(p15card->card->ctx, SC_ERROR_INVALID_DATA);
|
|
|
|
}
|
|
|
|
|
|
|
|
curveoidlen = *curveoid++;
|
|
|
|
|
2014-11-04 16:11:34 +00:00
|
|
|
r = sc_pkcs15emu_sc_hsm_get_curve(&curve, curveoid, curveoidlen);
|
|
|
|
LOG_TEST_RET(p15card->card->ctx, r, "Unsupported named curve");
|
2012-09-27 13:50:15 +00:00
|
|
|
|
|
|
|
cvc->primeOrModuluslen = curve->prime.len;
|
|
|
|
cvc->primeOrModulus = malloc(cvc->primeOrModuluslen);
|
|
|
|
if (!cvc->primeOrModulus) {
|
|
|
|
LOG_FUNC_RETURN(p15card->card->ctx, SC_ERROR_OUT_OF_MEMORY);
|
|
|
|
}
|
|
|
|
memcpy(cvc->primeOrModulus, curve->prime.value, cvc->primeOrModuluslen);
|
|
|
|
|
|
|
|
cvc->coefficientAorExponentlen = curve->coefficientA.len;
|
|
|
|
cvc->coefficientAorExponent = malloc(cvc->coefficientAorExponentlen);
|
|
|
|
if (!cvc->coefficientAorExponent) {
|
|
|
|
LOG_FUNC_RETURN(p15card->card->ctx, SC_ERROR_OUT_OF_MEMORY);
|
|
|
|
}
|
|
|
|
memcpy(cvc->coefficientAorExponent, curve->coefficientA.value, cvc->coefficientAorExponentlen);
|
|
|
|
|
|
|
|
cvc->coefficientBlen = curve->coefficientB.len;
|
|
|
|
cvc->coefficientB = malloc(cvc->coefficientBlen);
|
|
|
|
if (!cvc->coefficientB) {
|
|
|
|
LOG_FUNC_RETURN(p15card->card->ctx, SC_ERROR_OUT_OF_MEMORY);
|
|
|
|
}
|
|
|
|
memcpy(cvc->coefficientB, curve->coefficientB.value, cvc->coefficientBlen);
|
|
|
|
|
|
|
|
cvc->basePointGlen = curve->basePointG.len;
|
|
|
|
cvc->basePointG = malloc(cvc->basePointGlen);
|
|
|
|
if (!cvc->basePointG) {
|
|
|
|
LOG_FUNC_RETURN(p15card->card->ctx, SC_ERROR_OUT_OF_MEMORY);
|
|
|
|
}
|
|
|
|
memcpy(cvc->basePointG, curve->basePointG.value, cvc->basePointGlen);
|
|
|
|
|
|
|
|
cvc->orderlen = curve->order.len;
|
|
|
|
cvc->order = malloc(cvc->orderlen);
|
|
|
|
if (!cvc->order) {
|
|
|
|
LOG_FUNC_RETURN(p15card->card->ctx, SC_ERROR_OUT_OF_MEMORY);
|
|
|
|
}
|
|
|
|
memcpy(cvc->order, curve->order.value, cvc->orderlen);
|
|
|
|
|
|
|
|
cvc->cofactorlen = curve->coFactor.len;
|
|
|
|
cvc->cofactor = malloc(cvc->cofactorlen);
|
|
|
|
if (!cvc->cofactor) {
|
|
|
|
LOG_FUNC_RETURN(p15card->card->ctx, SC_ERROR_OUT_OF_MEMORY);
|
|
|
|
}
|
|
|
|
memcpy(cvc->cofactor, curve->coFactor.value, cvc->cofactorlen);
|
|
|
|
|
|
|
|
cvc->pukoid = ecdsaWithSHA256;
|
|
|
|
|
|
|
|
LOG_FUNC_RETURN(p15card->card->ctx, SC_SUCCESS);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int sc_hsm_generate_key(struct sc_profile *profile, struct sc_pkcs15_card *p15card,
|
|
|
|
struct sc_pkcs15_object *object,
|
|
|
|
struct sc_pkcs15_pubkey *pubkey)
|
|
|
|
{
|
|
|
|
struct sc_card *card = p15card->card;
|
|
|
|
struct sc_pkcs15_prkey_info *key_info = (struct sc_pkcs15_prkey_info *)object->data;
|
|
|
|
sc_cardctl_sc_hsm_keygen_info_t sc_hsm_keyinfo;
|
|
|
|
sc_cvc_t cvc;
|
|
|
|
u8 *cvcbin, *cvcpo;
|
|
|
|
unsigned int cla,tag;
|
|
|
|
size_t taglen, cvclen;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
LOG_FUNC_CALLED(p15card->card->ctx);
|
|
|
|
|
|
|
|
key_info->key_reference = sc_hsm_determine_free_id(p15card, KEY_PREFIX);
|
|
|
|
LOG_TEST_RET(card->ctx, key_info->key_reference, "Could not determine key reference");
|
|
|
|
|
|
|
|
memset(&cvc, 0, sizeof(cvc));
|
|
|
|
|
2015-10-04 15:53:51 +00:00
|
|
|
strlcpy(cvc.car, "UTCA00001", sizeof cvc.car);
|
|
|
|
strlcpy(cvc.chr, "UTTM00001", sizeof cvc.chr);
|
2012-09-27 13:50:15 +00:00
|
|
|
|
|
|
|
switch(object->type) {
|
|
|
|
case SC_PKCS15_TYPE_PRKEY_RSA:
|
|
|
|
r = sc_hsm_encode_gakp_rsa(p15card, &cvc, key_info->modulus_length);
|
|
|
|
break;
|
|
|
|
case SC_PKCS15_TYPE_PRKEY_EC:
|
|
|
|
r = sc_hsm_encode_gakp_ec(p15card, &cvc, key_info);
|
|
|
|
break;
|
|
|
|
default:
|
2015-01-28 04:47:20 +00:00
|
|
|
r = SC_ERROR_NOT_IMPLEMENTED;
|
2012-09-27 13:50:15 +00:00
|
|
|
break;
|
|
|
|
}
|
2015-01-28 04:47:20 +00:00
|
|
|
LOG_TEST_RET(p15card->card->ctx, r, "Could not encode GAKP cdata");
|
2012-09-27 13:50:15 +00:00
|
|
|
|
|
|
|
r = sc_pkcs15emu_sc_hsm_encode_cvc(p15card, &cvc, &cvcbin, &cvclen);
|
|
|
|
sc_pkcs15emu_sc_hsm_free_cvc(&cvc);
|
|
|
|
LOG_TEST_RET(p15card->card->ctx, r, "Could not encode GAKP cdata");
|
|
|
|
|
|
|
|
|
|
|
|
cvcpo = cvcbin;
|
2012-10-14 12:35:46 +00:00
|
|
|
sc_asn1_read_tag((const u8 **)&cvcpo, cvclen, &cla, &tag, &taglen);
|
|
|
|
sc_asn1_read_tag((const u8 **)&cvcpo, cvclen, &cla, &tag, &taglen);
|
2012-09-27 13:50:15 +00:00
|
|
|
|
|
|
|
sc_hsm_keyinfo.key_id = key_info->key_reference;
|
|
|
|
sc_hsm_keyinfo.auth_key_id = 0;
|
|
|
|
sc_hsm_keyinfo.gakprequest = cvcpo;
|
|
|
|
sc_hsm_keyinfo.gakprequest_len = taglen;
|
|
|
|
sc_hsm_keyinfo.gakpresponse = NULL;
|
|
|
|
sc_hsm_keyinfo.gakpresponse_len = 0;
|
|
|
|
|
|
|
|
r = sc_card_ctl(card, SC_CARDCTL_SC_HSM_GENERATE_KEY, &sc_hsm_keyinfo);
|
|
|
|
if (r < 0)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
|
|
|
|
cvcpo = sc_hsm_keyinfo.gakpresponse;
|
|
|
|
cvclen = sc_hsm_keyinfo.gakpresponse_len;
|
|
|
|
|
|
|
|
r = sc_pkcs15emu_sc_hsm_decode_cvc(p15card, (const u8 **)&cvcpo, &cvclen, &cvc);
|
|
|
|
if (r < 0) {
|
|
|
|
sc_log(p15card->card->ctx, "Could not decode GAKP rdata");
|
|
|
|
r = SC_ERROR_OBJECT_NOT_VALID;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2012-11-12 15:52:48 +00:00
|
|
|
r = sc_hsm_update_ef(p15card, EE_CERTIFICATE_PREFIX, key_info->key_reference, 1, sc_hsm_keyinfo.gakpresponse, sc_hsm_keyinfo.gakpresponse_len);
|
|
|
|
if (r < 0) {
|
|
|
|
sc_log(p15card->card->ctx, "Could not save certificate signing request");
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2012-09-27 13:50:15 +00:00
|
|
|
if (pubkey != NULL) {
|
2014-02-02 20:03:04 +00:00
|
|
|
r = sc_pkcs15emu_sc_hsm_get_public_key(p15card->card->ctx, &cvc, pubkey);
|
2012-09-27 13:50:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
out:
|
|
|
|
|
|
|
|
sc_pkcs15emu_sc_hsm_free_cvc(&cvc);
|
|
|
|
|
|
|
|
if (cvcbin) {
|
|
|
|
free(cvcbin);
|
|
|
|
}
|
|
|
|
if (sc_hsm_keyinfo.gakpresponse) {
|
|
|
|
free(sc_hsm_keyinfo.gakpresponse);
|
|
|
|
}
|
|
|
|
LOG_FUNC_RETURN(p15card->card->ctx, r);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Certificates with a related private key are stored in the fid range CE00 - CEFF. The
|
|
|
|
* second byte in the fid matches the key id.
|
|
|
|
* Certificates without a related private key (e.g. CA certificates) are stored in the fid range
|
|
|
|
* CA00 - CAFF. The second byte is a free selected id.
|
|
|
|
*/
|
|
|
|
static int sc_hsm_emu_store_cert(struct sc_pkcs15_card *p15card, struct sc_profile *profile,
|
|
|
|
struct sc_pkcs15_object *object,
|
|
|
|
struct sc_pkcs15_der *data)
|
|
|
|
|
|
|
|
{
|
|
|
|
struct sc_pkcs15_cert_info *cert_info = (struct sc_pkcs15_cert_info *) object->data;
|
|
|
|
struct sc_pkcs15_object *prkey;
|
|
|
|
sc_path_t path;
|
|
|
|
u8 id[2];
|
|
|
|
int r;
|
|
|
|
|
|
|
|
r = sc_pkcs15_find_object_by_id(p15card, SC_PKCS15_TYPE_PRKEY, &cert_info->id , &prkey);
|
|
|
|
|
|
|
|
if (r == SC_ERROR_OBJECT_NOT_FOUND) {
|
|
|
|
r = sc_hsm_determine_free_id(p15card, CA_CERTIFICATE_PREFIX);
|
|
|
|
LOG_TEST_RET(p15card->card->ctx, r, "Out of identifier to store certificate description");
|
|
|
|
|
|
|
|
id[0] = CA_CERTIFICATE_PREFIX;
|
|
|
|
id[1] = r;
|
|
|
|
} else {
|
|
|
|
LOG_TEST_RET(p15card->card->ctx, r, "Error locating matching private key");
|
|
|
|
|
|
|
|
id[0] = EE_CERTIFICATE_PREFIX;
|
|
|
|
id[1] = ((struct sc_pkcs15_prkey_info *)prkey->data)->key_reference;
|
|
|
|
}
|
|
|
|
|
|
|
|
sc_path_set(&path, SC_PATH_TYPE_FILE_ID, id, 2, 0, -1);
|
|
|
|
cert_info->path = path;
|
|
|
|
|
|
|
|
r = sc_hsm_update_ef(p15card, id[0], id[1], 1, data->value, data->len);
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int sc_hsm_emu_delete_cert(struct sc_pkcs15_card *p15card, struct sc_profile *profile,
|
|
|
|
struct sc_pkcs15_object *object)
|
|
|
|
|
|
|
|
{
|
|
|
|
struct sc_pkcs15_cert_info *cert_info = (struct sc_pkcs15_cert_info *) object->data;
|
|
|
|
|
2014-09-03 15:16:59 +00:00
|
|
|
return sc_hsm_delete_ef(p15card, cert_info->path.value[0], cert_info->path.value[1]);
|
2012-09-27 13:50:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int sc_hsm_emu_store_binary(struct sc_pkcs15_card *p15card, struct sc_profile *profile,
|
|
|
|
struct sc_pkcs15_object *object,
|
|
|
|
struct sc_pkcs15_der *data)
|
|
|
|
|
|
|
|
{
|
|
|
|
struct sc_pkcs15_data_info *data_info = (struct sc_pkcs15_data_info *) object->data;
|
|
|
|
sc_path_t path;
|
|
|
|
u8 id[2];
|
|
|
|
int r;
|
|
|
|
|
|
|
|
r = sc_hsm_determine_free_id(p15card, DCOD_PREFIX);
|
|
|
|
LOG_TEST_RET(p15card->card->ctx, r, "Out of identifier to store data description");
|
|
|
|
|
|
|
|
if (object->flags & SC_PKCS15_CO_FLAG_PRIVATE) {
|
|
|
|
id[0] = PROT_DATA_PREFIX;
|
|
|
|
} else {
|
|
|
|
id[0] = DATA_PREFIX;
|
|
|
|
}
|
|
|
|
id[1] = r;
|
|
|
|
|
|
|
|
sc_path_set(&path, SC_PATH_TYPE_FILE_ID, id, 2, 0, -1);
|
|
|
|
data_info->path = path;
|
|
|
|
|
|
|
|
r = sc_hsm_update_ef(p15card, id[0], id[1], 1, data->value, data->len);
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int sc_hsm_emu_store_data(struct sc_pkcs15_card *p15card, struct sc_profile *profile,
|
|
|
|
struct sc_pkcs15_object *object,
|
|
|
|
struct sc_pkcs15_der *data, struct sc_path *path)
|
|
|
|
|
|
|
|
{
|
|
|
|
struct sc_context *ctx = p15card->card->ctx;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
LOG_FUNC_CALLED(ctx);
|
|
|
|
|
|
|
|
switch (object->type & SC_PKCS15_TYPE_CLASS_MASK) {
|
|
|
|
case SC_PKCS15_TYPE_PRKEY:
|
|
|
|
case SC_PKCS15_TYPE_PUBKEY:
|
|
|
|
r = SC_SUCCESS;
|
|
|
|
break;
|
|
|
|
case SC_PKCS15_TYPE_CERT:
|
|
|
|
r = sc_hsm_emu_store_cert(p15card, profile, object, data);
|
|
|
|
break;
|
|
|
|
case SC_PKCS15_TYPE_DATA_OBJECT:
|
|
|
|
r = sc_hsm_emu_store_binary(p15card, profile, object, data);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
r = SC_ERROR_NOT_IMPLEMENTED;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
LOG_FUNC_RETURN(ctx, r);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int sc_hsm_emu_delete_object(struct sc_profile *profile, struct sc_pkcs15_card *p15card,
|
|
|
|
struct sc_pkcs15_object *object, const struct sc_path *path)
|
|
|
|
{
|
|
|
|
struct sc_context *ctx = p15card->card->ctx;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
LOG_FUNC_CALLED(ctx);
|
|
|
|
|
|
|
|
switch (object->type & SC_PKCS15_TYPE_CLASS_MASK) {
|
|
|
|
case SC_PKCS15_TYPE_PRKEY:
|
|
|
|
r = sc_hsm_delete_ef(p15card, KEY_PREFIX, ((struct sc_pkcs15_prkey_info *)object->data)->key_reference);
|
|
|
|
break;
|
|
|
|
case SC_PKCS15_TYPE_CERT:
|
|
|
|
r = sc_hsm_emu_delete_cert(p15card, profile, object);
|
|
|
|
break;
|
|
|
|
case SC_PKCS15_TYPE_DATA_OBJECT:
|
|
|
|
r = sc_delete_file(p15card->card, path);
|
|
|
|
break;
|
|
|
|
case SC_PKCS15_TYPE_PUBKEY:
|
|
|
|
r = SC_SUCCESS;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
r = SC_ERROR_NOT_IMPLEMENTED;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
LOG_FUNC_RETURN(ctx, r);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int sc_hsm_emu_update_prkd(struct sc_profile *profile, struct sc_pkcs15_card *p15card,
|
|
|
|
struct sc_pkcs15_object *object)
|
|
|
|
{
|
|
|
|
struct sc_pkcs15_prkey_info *key_info = (struct sc_pkcs15_prkey_info *)object->data;
|
|
|
|
u8 *buf;
|
|
|
|
size_t buflen;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
r = sc_pkcs15_encode_prkdf_entry(p15card->card->ctx, object, &buf, &buflen);
|
|
|
|
LOG_TEST_RET(p15card->card->ctx, r, "Error encoding PRKD entry");
|
|
|
|
|
|
|
|
r = sc_hsm_update_ef(p15card, PRKD_PREFIX, key_info->key_reference, 0, buf, buflen);
|
|
|
|
free(buf);
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int sc_hsm_emu_update_dcod(struct sc_profile *profile, struct sc_pkcs15_card *p15card,
|
|
|
|
struct sc_pkcs15_object *object)
|
|
|
|
{
|
|
|
|
struct sc_pkcs15_data_info *data_info = (struct sc_pkcs15_data_info *) object->data;
|
|
|
|
u8 *buf;
|
|
|
|
size_t buflen;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
r = sc_pkcs15_encode_dodf_entry(p15card->card->ctx, object, &buf, &buflen);
|
|
|
|
LOG_TEST_RET(p15card->card->ctx, r, "Error encoding DCOD entry");
|
|
|
|
|
2013-02-15 14:02:28 +00:00
|
|
|
r = sc_hsm_update_ef(p15card, DCOD_PREFIX, data_info->path.value[data_info->path.len - 1], 0, buf, buflen);
|
2012-09-27 13:50:15 +00:00
|
|
|
free(buf);
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int sc_hsm_emu_update_cd(struct sc_profile *profile, struct sc_pkcs15_card *p15card,
|
|
|
|
struct sc_pkcs15_object *object)
|
|
|
|
{
|
|
|
|
struct sc_pkcs15_cert_info *cert_info = (struct sc_pkcs15_cert_info *) object->data;
|
|
|
|
u8 *buf;
|
|
|
|
size_t buflen;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
if ((cert_info->path.len < 2) ||
|
|
|
|
((cert_info->path.value[cert_info->path.len - 2]) != CA_CERTIFICATE_PREFIX)) {
|
|
|
|
// Certificates associated with stored private keys don't get a separate CD entry
|
|
|
|
return SC_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sc_pkcs15_encode_cdf_entry(p15card->card->ctx, object, &buf, &buflen);
|
|
|
|
LOG_TEST_RET(p15card->card->ctx, r, "Error encoding CD entry");
|
|
|
|
|
2013-02-15 14:02:28 +00:00
|
|
|
r = sc_hsm_update_ef(p15card, CD_PREFIX, cert_info->path.value[cert_info->path.len - 1], 0, buf, buflen);
|
2012-09-27 13:50:15 +00:00
|
|
|
free(buf);
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int sc_hsm_emu_delete_cd(struct sc_profile *profile, struct sc_pkcs15_card *p15card,
|
|
|
|
struct sc_pkcs15_object *object)
|
|
|
|
{
|
|
|
|
struct sc_pkcs15_cert_info *cert_info = (struct sc_pkcs15_cert_info *) object->data;
|
|
|
|
|
|
|
|
if ((cert_info->path.len < 2) ||
|
|
|
|
((cert_info->path.value[cert_info->path.len - 2]) != CA_CERTIFICATE_PREFIX)) {
|
|
|
|
// Certificates associated with stored private keys don't get a separate CD entry
|
|
|
|
return SC_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2013-02-15 14:02:28 +00:00
|
|
|
return sc_hsm_delete_ef(p15card, CD_PREFIX, cert_info->path.value[cert_info->path.len - 1]);
|
2012-09-27 13:50:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int sc_hsm_emu_update_any_df(struct sc_profile *profile, struct sc_pkcs15_card *p15card,
|
|
|
|
unsigned op, struct sc_pkcs15_object *object)
|
|
|
|
{
|
|
|
|
struct sc_context *ctx = p15card->card->ctx;
|
|
|
|
int rv = SC_ERROR_NOT_SUPPORTED;
|
|
|
|
|
|
|
|
SC_FUNC_CALLED(ctx, 1);
|
|
|
|
switch(op) {
|
|
|
|
case SC_AC_OP_ERASE:
|
|
|
|
sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "Update DF; erase object('%s',type:%X)", object->label, object->type);
|
|
|
|
switch(object->type & SC_PKCS15_TYPE_CLASS_MASK) {
|
|
|
|
case SC_PKCS15_TYPE_PRKEY:
|
|
|
|
rv = sc_hsm_delete_ef(p15card, PRKD_PREFIX, ((struct sc_pkcs15_prkey_info *)object->data)->key_reference);
|
|
|
|
break;
|
|
|
|
case SC_PKCS15_TYPE_PUBKEY:
|
|
|
|
rv = SC_SUCCESS;
|
|
|
|
break;
|
|
|
|
case SC_PKCS15_TYPE_CERT:
|
|
|
|
rv = sc_hsm_emu_delete_cd(profile, p15card, object);
|
|
|
|
break;
|
|
|
|
case SC_PKCS15_TYPE_DATA_OBJECT:
|
|
|
|
rv = sc_hsm_delete_ef(p15card, DCOD_PREFIX, ((struct sc_pkcs15_data_info *)object->data)->path.value[1]);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case SC_AC_OP_UPDATE:
|
|
|
|
case SC_AC_OP_CREATE:
|
|
|
|
sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "Update DF; create object('%s',type:%X)", object->label, object->type);
|
|
|
|
switch(object->type & SC_PKCS15_TYPE_CLASS_MASK) {
|
|
|
|
case SC_PKCS15_TYPE_PUBKEY:
|
|
|
|
rv = SC_SUCCESS;
|
|
|
|
break;
|
|
|
|
case SC_PKCS15_TYPE_PRKEY:
|
|
|
|
rv = sc_hsm_emu_update_prkd(profile, p15card, object);
|
|
|
|
break;
|
|
|
|
case SC_PKCS15_TYPE_CERT:
|
|
|
|
rv = sc_hsm_emu_update_cd(profile, p15card, object);
|
|
|
|
break;
|
|
|
|
case SC_PKCS15_TYPE_DATA_OBJECT:
|
|
|
|
rv = sc_hsm_emu_update_dcod(profile, p15card, object);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
SC_FUNC_RETURN(ctx, 1, rv);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static struct sc_pkcs15init_operations
|
|
|
|
sc_pkcs15init_sc_hsm_operations = {
|
|
|
|
NULL, /* erase_card */
|
|
|
|
NULL, /* init_card */
|
|
|
|
NULL, /* create_dir */
|
|
|
|
NULL, /* create_domain */
|
|
|
|
NULL, /* select_pin_reference */
|
|
|
|
NULL, /* create_pin */
|
|
|
|
NULL, /* select key reference */
|
|
|
|
sc_hsm_create_key,
|
2014-07-13 10:13:04 +00:00
|
|
|
sc_hsm_store_key,
|
2012-09-27 13:50:15 +00:00
|
|
|
sc_hsm_generate_key,
|
|
|
|
NULL, /* encode private key */
|
|
|
|
NULL, /* encode public key */
|
|
|
|
NULL, /* finalize_card */
|
|
|
|
sc_hsm_emu_delete_object, /* delete object */
|
|
|
|
NULL, /* pkcs15init emulation update_dir */
|
|
|
|
sc_hsm_emu_update_any_df, /* pkcs15init emulation update_any_df */
|
|
|
|
NULL, /* pkcs15init emulation update_tokeninfo */
|
|
|
|
NULL, /* pkcs15init emulation write_info */
|
|
|
|
sc_hsm_emu_store_data,
|
|
|
|
NULL, /* sanity_check */
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
struct sc_pkcs15init_operations *
|
|
|
|
sc_pkcs15init_get_sc_hsm_ops(void)
|
|
|
|
{
|
|
|
|
return &sc_pkcs15init_sc_hsm_operations;
|
|
|
|
}
|
|
|
|
|