opensc/src/minidriver/minidriver.c

3701 lines
112 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* minidriver.c: OpenSC minidriver
*
* Copyright (C) 2009,2010 francois.leblanc@cev-sa.com
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* This module requires "cardmod.h" from CNG SDK or platform SDK to build.
*/
#include "config.h"
#ifdef ENABLE_MINIDRIVER
#ifdef _MANAGED
#pragma managed(push, off)
#endif
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <windows.h>
#include "cardmod.h"
#include "libopensc/asn1.h"
#include "libopensc/cardctl.h"
#include "libopensc/opensc.h"
#include "libopensc/pkcs15.h"
#include "libopensc/log.h"
#include "libopensc/internal.h"
#include "pkcs15init/pkcs15-init.h"
#ifdef ENABLE_OPENSSL
#include <openssl/opensslv.h>
#if OPENSSL_VERSION_NUMBER >= 0x10000000L
#include <openssl/pem.h>
#endif
#endif
#if defined(__MINGW32__)
/* Part of the build svn project in the include directory */
#include "cardmod-mingw-compat.h"
#endif
#define MD_MINIMUM_VERSION_SUPPORTED 4
#define MD_CURRENT_VERSION_SUPPORTED 7
#define NULLSTR(a) (a == NULL ? "<NULL>" : a)
#define NULLWSTR(a) (a == NULL ? L"<NULL>" : a)
#define MD_MAX_KEY_CONTAINERS 12
#define MD_CARDID_SIZE 16
#define MD_UTC_TIME_LENGTH_MAX 16
#define MD_CARDCF_LENGTH (sizeof(CARD_CACHE_FILE_FORMAT))
#define MD_DATA_APPLICAITON_NAME "CSP"
#define MD_DATA_DEFAULT_CONT_LABEL "Default Key Container"
#define MD_KEY_USAGE_KEYEXCHANGE \
SC_PKCS15INIT_X509_KEY_ENCIPHERMENT | \
SC_PKCS15INIT_X509_DATA_ENCIPHERMENT | \
SC_PKCS15INIT_X509_DIGITAL_SIGNATURE
#define MD_KEY_USAGE_SIGNATURE \
SC_PKCS15INIT_X509_DIGITAL_SIGNATURE | \
SC_PKCS15INIT_X509_KEY_CERT_SIGN | \
SC_PKCS15INIT_X509_CRL_SIGN
#define MD_KEY_ACCESS \
SC_PKCS15_PRKEY_ACCESS_SENSITIVE | \
SC_PKCS15_PRKEY_ACCESS_ALWAYSSENSITIVE | \
SC_PKCS15_PRKEY_ACCESS_NEVEREXTRACTABLE | \
SC_PKCS15_PRKEY_ACCESS_LOCAL
/* copied from pkcs15-cardos.c */
#define USAGE_ANY_SIGN (SC_PKCS15_PRKEY_USAGE_SIGN | SC_PKCS15_PRKEY_USAGE_NONREPUDIATION)
#define USAGE_ANY_DECIPHER (SC_PKCS15_PRKEY_USAGE_DECRYPT | SC_PKCS15_PRKEY_USAGE_UNWRAP)
/* if use of internal-winscard.h */
#ifndef SCARD_E_INVALID_PARAMETER
#define SCARD_E_INVALID_PARAMETER 0x80100004L
#define SCARD_E_UNSUPPORTED_FEATURE 0x80100022L
#define SCARD_E_NO_MEMORY 0x80100006L
#define SCARD_W_WRONG_CHV 0x8010006BL
#define SCARD_E_FILE_NOT_FOUND 0x80100024L
#define SCARD_E_UNKNOWN_CARD 0x8010000DL
#define SCARD_F_UNKNOWN_ERROR 0x80100014L
#endif
struct md_directory {
unsigned char parent[9];
unsigned char name[9];
CARD_DIRECTORY_ACCESS_CONDITION acl;
struct md_file *files;
struct md_directory *subdirs;
struct md_directory *next;
};
struct md_file {
unsigned char parent[9];
unsigned char name[9];
CARD_FILE_ACCESS_CONDITION acl;
unsigned char *blob;
size_t size;
struct md_file *next;
};
struct md_pkcs15_container {
int index;
struct sc_pkcs15_id id;
char guid[MAX_CONTAINER_NAME_LEN + 1];
unsigned flags;
unsigned size_key_exchange, size_sign;
struct sc_pkcs15_object *cert_obj, *prkey_obj, *pubkey_obj;
};
typedef struct _VENDOR_SPECIFIC
{
struct sc_pkcs15_object *obj_user_pin, *obj_sopin;
struct sc_context *ctx;
struct sc_reader *reader;
struct sc_card *card;
struct sc_pkcs15_card *p15card;
struct md_pkcs15_container p15_containers[MD_MAX_KEY_CONTAINERS];
struct md_directory root;
SCARDCONTEXT hSCardCtx;
SCARDHANDLE hScard;
/* These will be used in CardAuthenticateEx to display a dialog box when doing
* external PIN verification.
*/
HWND hwndParent;
LPWSTR wszPinContext;
}VENDOR_SPECIFIC;
/*
* Windows (ex. Vista) may access the card from more the one thread.
* The following data type and static data is an attemt to resolve
* some of the encountered multi-thread issues of OpenSC
* on the minidriver side.
*
* TODO: resolve multi-thread issues on the OpenSC side
*/
#define MD_STATIC_FLAG_READ_ONLY 1
#define MD_STATIC_FLAG_SUPPORTS_X509_ENROLLMENT 2
#define MD_STATIC_FLAG_CONTEXT_DELETED 4
#define MD_STATIC_PROCESS_ATTACHED 0xA11AC4EDL
struct md_opensc_static_data {
unsigned flags, flags_checked;
unsigned long attach_check;
};
static struct md_opensc_static_data md_static_data;
#define C_ASN1_MD_CONTAINER_ATTRS_SIZE 7
static const struct sc_asn1_entry c_asn1_md_container_attrs[C_ASN1_MD_CONTAINER_ATTRS_SIZE] = {
{ "index", SC_ASN1_INTEGER, SC_ASN1_TAG_INTEGER, 0, NULL, NULL },
{ "id", SC_ASN1_PKCS15_ID, SC_ASN1_TAG_OCTET_STRING, SC_ASN1_EMPTY_ALLOWED, NULL, NULL },
{ "guid", SC_ASN1_UTF8STRING, SC_ASN1_TAG_UTF8STRING, SC_ASN1_EMPTY_ALLOWED, NULL, NULL },
{ "flags", SC_ASN1_BIT_FIELD, SC_ASN1_TAG_BIT_STRING, 0, NULL, NULL },
{ "sizeKeyExchange", SC_ASN1_INTEGER, SC_ASN1_TAG_INTEGER, 0, NULL, NULL },
{ "sizeSign", SC_ASN1_INTEGER, SC_ASN1_TAG_INTEGER, 0, NULL, NULL },
{ NULL, 0, 0, 0, NULL, NULL }
};
#define C_ASN1_MD_CONTAINER_SIZE 2
static const struct sc_asn1_entry c_asn1_md_container[C_ASN1_MD_CONTAINER_SIZE] = {
{ "mdContainer", SC_ASN1_STRUCT, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, 0, NULL, NULL },
{ NULL, 0, 0, 0, NULL, NULL }
};
static int associate_card(PCARD_DATA pCardData);
static int disassociate_card(PCARD_DATA pCardData);
static DWORD md_get_cardcf(PCARD_DATA pCardData, CARD_CACHE_FILE_FORMAT **out);
static DWORD md_pkcs15_delete_object(PCARD_DATA pCardData, struct sc_pkcs15_object *obj);
static DWORD md_fs_init(PCARD_DATA pCardData);
static void logprintf(PCARD_DATA pCardData, int level, const char* format, ...)
{
va_list arg;
VENDOR_SPECIFIC *vs;
#define CARDMOD_LOW_LEVEL_DEBUG 1
#ifdef CARDMOD_LOW_LEVEL_DEBUG
/* Use a simplied log to get all messages including messages
* before opensc is loaded. The file must be modifiable by all
* users as we maybe called under lsa or user. Note data from
* multiple process and threads may get intermingled.
* flush to get last message before ann crash
* close so as the file is not left open during any wait.
*/
{
FILE* lldebugfp = NULL;
lldebugfp = fopen("C:\\tmp\\md.log","a+");
if (lldebugfp) {
va_start(arg, format);
vfprintf(lldebugfp, format, arg);
va_end(arg);
fflush(lldebugfp);
fclose(lldebugfp);
lldebugfp = NULL;
}
}
#endif
va_start(arg, format);
if(pCardData != NULL) {
vs = (VENDOR_SPECIFIC*)(pCardData->pvVendorSpecific);
if(vs != NULL && vs->ctx != NULL) {
#ifdef _MSC_VER
sc_do_log_noframe(vs->ctx, level, format, arg);
#else
/* FIXME: trouble in vsprintf with %S arg under mingw32 */
if(vs->ctx->debug>=level) {
vfprintf(vs->ctx->debug_file, format, arg);
}
#endif
}
}
va_end(arg);
}
static void loghex(PCARD_DATA pCardData, int level, PBYTE data, int len)
{
char line[74];
char *c;
int i, a;
unsigned char * p;
logprintf(pCardData, level, "--- %p:%d\n", data, len);
if (data == NULL || len <= 0) return;
p = data;
c = line;
i = 0;
a = 0;
memset(line, 0, sizeof(line));
while(i < len) {
sprintf(c,"%02X", *p);
p++;
c += 2;
i++;
if (i%32 == 0) {
logprintf(pCardData, level, " %04X %s\n", a, line);
a +=32;
memset(line, 0, sizeof(line));
c = line;
} else {
if (i%4 == 0) *(c++) = ' ';
if (i%16 == 0) *(c++) = ' ';
}
}
if (i%32 != 0)
logprintf(pCardData, level, " %04X %s\n", a, line);
}
static void print_werror(PCARD_DATA pCardData, char *str)
{
void *buf;
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, GetLastError(), 0, (LPTSTR) &buf, 0, NULL);
logprintf(pCardData, 0, "%s%s\n", str, buf);
LocalFree(buf);
}
/*
* check if the card has been removed, or the
* caller has changed the handles.
* if so, then free up all previous card info
* and reestablish
*/
static int
check_reader_status(PCARD_DATA pCardData)
{
int r;
VENDOR_SPECIFIC *vs = NULL;
logprintf(pCardData, 4, "check_reader_status\n");
if(!pCardData)
return SCARD_E_INVALID_PARAMETER;
vs = (VENDOR_SPECIFIC*)(pCardData->pvVendorSpecific);
if(!vs)
return SCARD_E_INVALID_PARAMETER;
logprintf(pCardData, 7, "pCardData->hSCardCtx:0x%08X hScard:0x%08X\n",
pCardData->hSCardCtx, pCardData->hScard);
if (pCardData->hSCardCtx != vs->hSCardCtx || pCardData->hScard != vs->hScard) {
logprintf (pCardData, 1, "HANDLES CHANGED from 0x%08X 0x%08X\n", vs->hSCardCtx, vs->hScard);
// Basically a mini AcquireContext
r = disassociate_card(pCardData);
logprintf(pCardData, 1, "disassociate_card r = 0x%08X\n", r);
r = associate_card(pCardData); /* need to check return codes */
logprintf(pCardData, 1, "associate_card r = 0x%08X\n", r);
// Rebuild 'soft' fs - in case changed
r = md_fs_init(pCardData);
logprintf(pCardData, 1, "md_fs_init r = 0x%08X\n", r);
}
else if (vs->reader) {
/* This should always work, as BaseCSP should be checking for removal too */
r = sc_detect_card_presence(vs->reader);
logprintf(pCardData, 2, "check_reader_status r=%d flags 0x%08X\n", r, vs->reader->flags);
}
return SCARD_S_SUCCESS;
}
static DWORD
md_get_pin_by_role(PCARD_DATA pCardData, PIN_ID role, struct sc_pkcs15_object **ret_obj)
{
VENDOR_SPECIFIC *vs;
int rv = SC_SUCCESS;
if (!pCardData)
return SCARD_E_INVALID_PARAMETER;
vs = (VENDOR_SPECIFIC*)(pCardData->pvVendorSpecific);
if (!ret_obj)
return SCARD_E_INVALID_PARAMETER;
*ret_obj = NULL;
if (role == ROLE_USER) {
if (!vs->obj_user_pin) {
/* Get 'global' User PIN; if no, get the 'local' one */
rv = sc_pkcs15_find_pin_by_flags(vs->p15card, SC_PKCS15_PIN_TYPE_FLAGS_PIN_GLOBAL,
SC_PKCS15_PIN_TYPE_FLAGS_MASK, NULL, &vs->obj_user_pin);
if (rv)
rv = sc_pkcs15_find_pin_by_flags(vs->p15card, SC_PKCS15_PIN_TYPE_FLAGS_PIN_LOCAL,
SC_PKCS15_PIN_TYPE_FLAGS_MASK, NULL, &vs->obj_user_pin);
}
*ret_obj = vs->obj_user_pin;
}
else if (role == ROLE_ADMIN) {
/* Get SO PIN; if no, get the 'global' PUK; if no get the 'local' one */
if (!vs->obj_sopin) {
rv = sc_pkcs15_find_pin_by_flags(vs->p15card, SC_PKCS15_PIN_TYPE_FLAGS_SOPIN,
SC_PKCS15_PIN_TYPE_FLAGS_SOPIN, NULL, &vs->obj_sopin);
if (rv)
rv = sc_pkcs15_find_pin_by_flags(vs->p15card, SC_PKCS15_PIN_TYPE_FLAGS_PUK_GLOBAL,
SC_PKCS15_PIN_TYPE_FLAGS_MASK, NULL, &vs->obj_sopin);
if (rv)
rv = sc_pkcs15_find_pin_by_flags(vs->p15card, SC_PKCS15_PIN_TYPE_FLAGS_PUK_LOCAL,
SC_PKCS15_PIN_TYPE_FLAGS_MASK, NULL, &vs->obj_sopin);
}
*ret_obj = vs->obj_sopin;
}
else {
logprintf(pCardData, 2, "cannot get PIN object: unsupported role\n");
return SCARD_E_UNSUPPORTED_FEATURE;
}
return (rv == SC_SUCCESS) ? SCARD_S_SUCCESS : SCARD_E_UNSUPPORTED_FEATURE;
}
/* 'Write' mode can be enabled from the OpenSC configuration file*/
static BOOL
md_is_read_only(PCARD_DATA pCardData)
{
VENDOR_SPECIFIC *vs;
BOOL ret = TRUE;
if (!pCardData)
return TRUE;
logprintf(pCardData, 2, "Is read-only?\n");
if (md_static_data.flags_checked & MD_STATIC_FLAG_READ_ONLY) {
ret = (md_static_data.flags & MD_STATIC_FLAG_READ_ONLY) ? TRUE : FALSE;
logprintf(pCardData, 2, "Returns checked flag: %s\n", ret ? "TRUE" : "FALSE");
return ret;
}
vs = pCardData->pvVendorSpecific;
if (vs->ctx && vs->reader) {
/* TODO: use atr from pCardData */
scconf_block *atrblock = _sc_match_atr_block(vs->ctx, NULL, &vs->reader->atr);
logprintf(pCardData, 2, "Match ATR:\n", atrblock);
loghex(pCardData, 3, vs->reader->atr.value, vs->reader->atr.len);
if (atrblock)
if (scconf_get_bool(atrblock, "md_read_only", 1) == 0)
ret = FALSE;
}
md_static_data.flags_checked |= MD_STATIC_FLAG_READ_ONLY;
if (ret == TRUE)
md_static_data.flags |= MD_STATIC_FLAG_READ_ONLY;
else
md_static_data.flags &= ~MD_STATIC_FLAG_READ_ONLY;
logprintf(pCardData, 2, "Returns read-only flag '%s', static flags %X/%X\n",
ret ? "TRUE" : "FALSE",
md_static_data.flags, md_static_data.flags_checked);
return ret;
}
/* 'Write' mode can be enabled from the OpenSC configuration file*/
static BOOL
md_is_supports_X509_enrollment(PCARD_DATA pCardData)
{
VENDOR_SPECIFIC *vs;
BOOL ret = FALSE;
if (!pCardData)
return FALSE;
logprintf(pCardData, 2, "Is supports X509 enrollment?\n");
if (md_static_data.flags_checked & MD_STATIC_FLAG_SUPPORTS_X509_ENROLLMENT) {
ret = (md_static_data.flags & MD_STATIC_FLAG_SUPPORTS_X509_ENROLLMENT) ? TRUE : FALSE;
logprintf(pCardData, 2, "Returns checked flag: %s\n", ret ? "TRUE" : "FALSE");
return ret;
}
vs = pCardData->pvVendorSpecific;
if (vs->ctx && vs->reader) {
/* TODO: use atr from pCardData */
scconf_block *atrblock = _sc_match_atr_block(vs->ctx, NULL, &vs->reader->atr);
logprintf(pCardData, 2, "Match ATR:\n");
loghex(pCardData, 3, vs->reader->atr.value, vs->reader->atr.len);
if (atrblock)
if (scconf_get_bool(atrblock, "md_supports_X509_enrollment", 0))
ret = TRUE;
}
md_static_data.flags_checked |= MD_STATIC_FLAG_SUPPORTS_X509_ENROLLMENT;
if (ret == TRUE)
md_static_data.flags |= MD_STATIC_FLAG_SUPPORTS_X509_ENROLLMENT;
else
md_static_data.flags &= ~MD_STATIC_FLAG_SUPPORTS_X509_ENROLLMENT;
logprintf(pCardData, 2, "Returns x509-enrollment flag '%s', static flags %X/%X\n",
ret ? "TRUE" : "FALSE",
md_static_data.flags, md_static_data.flags_checked);
return ret;
}
/* Check if specified PIN has been verified */
static BOOL
md_is_pin_set(PCARD_DATA pCardData, DWORD role)
{
VENDOR_SPECIFIC *vs;
CARD_CACHE_FILE_FORMAT *cardcf = NULL;
if (!pCardData)
return FALSE;
vs = pCardData->pvVendorSpecific;
if (md_get_cardcf(pCardData, &cardcf) != SCARD_S_SUCCESS)
return FALSE;
return IS_PIN_SET(cardcf->bPinsFreshness, role);
}
/* Search directory by name and optionally by name of it's parent */
static DWORD
md_fs_find_directory(PCARD_DATA pCardData, struct md_directory *parent, char *name, struct md_directory **out)
{
VENDOR_SPECIFIC *vs;
struct md_directory *dir = NULL;
if (out)
*out = NULL;
if (!pCardData)
return SCARD_E_INVALID_PARAMETER;
vs = pCardData->pvVendorSpecific;
if (!parent)
parent = &vs->root;
if (!name) {
dir = parent;
}
else {
dir = parent->subdirs;
while(dir) {
if (!strcmp(dir->name, name))
break;
dir = dir->next;
}
}
if (!dir)
return SCARD_E_DIR_NOT_FOUND;
if (out)
*out = dir;
logprintf(pCardData, 3, "MD virtual file system: found '%s' directory\n", name);
return SCARD_S_SUCCESS;
}
static DWORD
md_fs_add_directory(PCARD_DATA pCardData, struct md_directory **head, char *name,
CARD_FILE_ACCESS_CONDITION acl,
struct md_directory **out)
{
struct md_directory *new_dir = NULL;
if (!pCardData || !head || !name)
return SCARD_E_INVALID_PARAMETER;
new_dir = pCardData->pfnCspAlloc(sizeof(struct md_directory));
if (!new_dir)
return SCARD_E_NO_MEMORY;
memset(new_dir, 0, sizeof(struct md_directory));
strncpy(new_dir->name, name, sizeof(new_dir->name) - 1);
new_dir->acl = acl;
if (*head == NULL) {
*head = new_dir;
}
else {
struct md_directory *last = *head;
while (last->next)
last = last->next;
last->next = new_dir;
}
if (out)
*out = new_dir;
logprintf(pCardData, 3, "MD virtual file system: directory '%s' added\n", name);
return SCARD_S_SUCCESS;
}
static DWORD
md_fs_find_file(PCARD_DATA pCardData, char *parent, char *name, struct md_file **out)
{
VENDOR_SPECIFIC *vs;
struct md_file *file = NULL;
struct md_directory *dir = NULL;
DWORD dwret;
if (out)
*out = NULL;
if (!pCardData || !name)
return SCARD_E_INVALID_PARAMETER;
vs = pCardData->pvVendorSpecific;
dwret = md_fs_find_directory(pCardData, NULL, parent, &dir);
if (dwret != SCARD_S_SUCCESS) {
logprintf(pCardData, 2, "find directory '%s' error: %X\n", parent ? parent : "<null>", dwret);
return dwret;
}
else if (!dir) {
logprintf(pCardData, 2, "directory '%s' not found\n", parent ? parent : "<null>");
return SCARD_E_INVALID_PARAMETER;
}
for (file = dir->files; file!=NULL;) {
if (!strcmp(file->name, name))
break;
file = file->next;
}
if (!file)
return SCARD_E_FILE_NOT_FOUND;
if (out)
*out = file;
logprintf(pCardData, 3, "MD virtual file system: found '%s' file\n", name);
return SCARD_S_SUCCESS;
}
static DWORD
md_fs_add_file(PCARD_DATA pCardData, struct md_file **head, char *name, CARD_FILE_ACCESS_CONDITION acl,
unsigned char *blob, size_t size, struct md_file **out)
{
struct md_file *new_file = NULL;
if (!pCardData || !head || !name)
return SCARD_E_INVALID_PARAMETER;
new_file = pCardData->pfnCspAlloc(sizeof(struct md_file));
if (!new_file)
return SCARD_E_NO_MEMORY;
memset(new_file, 0, sizeof(struct md_file));
strncpy(new_file->name, name, sizeof(new_file->name) - 1);
new_file->size = size;
new_file->acl = acl;
if (size) {
new_file->blob = pCardData->pfnCspAlloc(size);
if (!new_file->blob) {
pCardData->pfnCspFree(new_file);
return SCARD_E_NO_MEMORY;
}
if (blob)
CopyMemory(new_file->blob, blob, size);
else
memset(new_file->blob, 0, size);
}
if (*head == NULL) {
*head = new_file;
}
else {
struct md_file *last = *head;
while (last->next)
last = last->next;
last->next = new_file;
}
if (out)
*out = new_file;
logprintf(pCardData, 3, "MD virtual file system: file '%s' added\n", name);
return SCARD_S_SUCCESS;
}
static void
md_fs_free_file(PCARD_DATA pCardData, struct md_file *file)
{
if (!file)
return;
if (file->blob)
pCardData->pfnCspFree(file->blob);
file->blob = NULL;
file->size = 0;
}
static DWORD
md_fs_delete_file(PCARD_DATA pCardData, char *parent, char *name)
{
VENDOR_SPECIFIC *vs;
struct md_file *file = NULL, *file_to_rm = NULL;
struct md_directory *dir = NULL;
int deleted = 0;
DWORD dwret;
if (!pCardData || !name)
return SCARD_E_INVALID_PARAMETER;
vs = pCardData->pvVendorSpecific;
dwret = md_fs_find_directory(pCardData, NULL, parent, &dir);
if (dwret != SCARD_S_SUCCESS) {
logprintf(pCardData, 2, "find directory '%s' error: %X\n", parent ? parent : "<null>", dwret);
return dwret;
}
else if (!dir) {
logprintf(pCardData, 2, "directory '%s' not found\n", parent ? parent : "<null>");
return SCARD_E_INVALID_PARAMETER;
}
else if (!dir->files) {
logprintf(pCardData, 2, "no files in '%s' directory\n", parent ? parent : "<null>");
return SCARD_E_FILE_NOT_FOUND;
}
if (!strcmp(dir->files->name, name)) {
file_to_rm = dir->files;
dir->files = dir->files->next;
md_fs_free_file(pCardData, file_to_rm);
dwret = SCARD_S_SUCCESS;
}
else {
for (file = dir->files; file!=NULL; file = file->next) {
if (!file->next)
break;
if (!strcmp(file->next->name, name)) {
file_to_rm = file->next;
file->next = file->next->next;
md_fs_free_file(pCardData, file_to_rm);
deleted = 1;
break;
}
}
dwret = deleted ? SCARD_S_SUCCESS : SCARD_E_FILE_NOT_FOUND;
}
if (!strcmp(parent, "mscp")) {
int idx = -1;
if(sscanf(name, "ksc%d", &idx) > 0) {
}
else if(sscanf(name, "kxc%d", &idx) > 0) {
}
if (idx >= 0 && idx < MD_MAX_KEY_CONTAINERS) {
dwret = md_pkcs15_delete_object(pCardData, vs->p15_containers[idx].cert_obj);
vs->p15_containers[idx].cert_obj = NULL;
if(dwret != SCARD_S_SUCCESS)
logprintf(pCardData, 2, "Cannot delete certificate PKCS#15 object #%i: dwret 0x%X\n", idx, dwret);
}
}
return dwret;
}
static DWORD
md_pkcs15_encode_cardcf(PCARD_DATA pCardData, unsigned char *in, size_t in_size,
unsigned char *out, size_t *out_size)
{
VENDOR_SPECIFIC *vs;
char *last_update = NULL;
if (!pCardData || !in || in_size < MD_CARDCF_LENGTH
|| !out || !out_size || *out_size < MD_CARDCF_LENGTH)
return SCARD_E_INVALID_PARAMETER;
vs = pCardData->pvVendorSpecific;
memcpy(out, in, MD_CARDCF_LENGTH);
/* write down 'cardcf' with cleared PinsFreshness */
((CARD_CACHE_FILE_FORMAT *)out)->bPinsFreshness = PIN_SET_NONE;
last_update = sc_pkcs15_get_lastupdate(vs->p15card);
if (!last_update || (*out_size < MD_CARDCF_LENGTH + MD_UTC_TIME_LENGTH_MAX)) {
*out_size = MD_CARDCF_LENGTH;
}
else {
size_t lu_size = strlen(last_update);
if (lu_size > MD_UTC_TIME_LENGTH_MAX)
lu_size = MD_UTC_TIME_LENGTH_MAX;
memcpy(out + MD_CARDCF_LENGTH, last_update, lu_size);
if (lu_size < MD_UTC_TIME_LENGTH_MAX)
memset(out + MD_CARDCF_LENGTH + lu_size, 0, MD_UTC_TIME_LENGTH_MAX - lu_size);
*out_size = MD_CARDCF_LENGTH + MD_UTC_TIME_LENGTH_MAX;
}
return SCARD_S_SUCCESS;
}
static DWORD
md_pkcs15_encode_cmapfile(PCARD_DATA pCardData, unsigned char **out, size_t *out_len)
{
VENDOR_SPECIFIC *vs;
unsigned char *encoded, *ret, *p;
size_t guid_len, encoded_len, flags_len, ret_len;
int idx;
if (!pCardData || !out || !out_len)
return SCARD_E_INVALID_PARAMETER;
vs = pCardData->pvVendorSpecific;
logprintf(pCardData, 2, "encode P15 'cmapfile'\n");
ret = NULL, ret_len = 0;
for (idx=0; idx<MD_MAX_KEY_CONTAINERS; idx++) {
struct sc_asn1_entry asn1_md_container_attrs[C_ASN1_MD_CONTAINER_ATTRS_SIZE];
struct sc_asn1_entry asn1_md_container[C_ASN1_MD_CONTAINER_SIZE];
struct md_pkcs15_container cont = vs->p15_containers[idx];
int rv;
if (!cont.id.len && !strlen(cont.guid))
continue;
sc_copy_asn1_entry(c_asn1_md_container_attrs, asn1_md_container_attrs);
sc_copy_asn1_entry(c_asn1_md_container, asn1_md_container);
guid_len = strlen(cont.guid);
flags_len = sizeof(size_t);
sc_format_asn1_entry(asn1_md_container_attrs + 0, &cont.index, NULL, 1);
sc_format_asn1_entry(asn1_md_container_attrs + 1, &cont.id, NULL, 1);
sc_format_asn1_entry(asn1_md_container_attrs + 2, cont.guid, &guid_len, 1);
sc_format_asn1_entry(asn1_md_container_attrs + 3, &cont.flags, &flags_len, 1);
sc_format_asn1_entry(asn1_md_container_attrs + 4, &cont.size_key_exchange, NULL, 1);
sc_format_asn1_entry(asn1_md_container_attrs + 5, &cont.size_sign, NULL, 1);
sc_format_asn1_entry(asn1_md_container + 0, asn1_md_container_attrs, NULL, 1);
rv = sc_asn1_encode(vs->ctx, asn1_md_container, &encoded, &encoded_len);
if (rv < 0) {
logprintf(pCardData, 3, "MdEncodeCMapFile(): ASN1 encode error(%i): %s\n", rv, sc_strerror(rv));
return SCARD_F_INTERNAL_ERROR;
}
p = realloc(ret, ret_len + encoded_len);
if (!p) {
logprintf(pCardData, 3, "MdEncodeCMapFile(): realloc failed\n");
free(ret);
return SCARD_E_NO_MEMORY;
}
ret = p;
memcpy(ret + ret_len, encoded, encoded_len);
free(encoded);
ret_len += encoded_len;
}
logprintf(pCardData, 3, "encoded P15 'cmapfile':\n");
loghex(pCardData, 3, ret, ret_len);
*out = ret;
*out_len = ret_len;
return SCARD_S_SUCCESS;
}
/*
* Update 'soft' containers.
* Called each time when 'WriteFile' is called for 'cmapfile'.
*/
static DWORD
md_pkcs15_update_containers(PCARD_DATA pCardData, unsigned char *blob, size_t size)
{
VENDOR_SPECIFIC *vs;
CONTAINER_MAP_RECORD *pp;
DWORD dwret = SCARD_F_INTERNAL_ERROR;
int nn_records, idx;
if (!pCardData || !blob || size < sizeof(CONTAINER_MAP_RECORD))
return SCARD_E_INVALID_PARAMETER;
vs = pCardData->pvVendorSpecific;
nn_records = size/sizeof(CONTAINER_MAP_RECORD);
if (nn_records > MD_MAX_KEY_CONTAINERS)
nn_records = MD_MAX_KEY_CONTAINERS;
for (idx=0, pp = (CONTAINER_MAP_RECORD *)blob; idx<nn_records; idx++, pp++) {
struct md_pkcs15_container *cont = &(vs->p15_containers[idx]);
size_t count;
count = wcstombs(cont->guid, pp->wszGuid, sizeof(cont->guid));
if (!count) {
memset(cont, 0, sizeof(CONTAINER_MAP_RECORD));
}
else {
cont->index = idx;
cont->flags = pp->bFlags;
cont->size_sign = pp->wSigKeySizeBits;
cont->size_key_exchange = pp->wKeyExchangeKeySizeBits;
logprintf(pCardData, 3, "update P15 containers: touch container (idx:%i,id:%s,guid:%s,flags:%X)\n",
idx, sc_pkcs15_print_id(&cont->id),cont->guid,cont->flags);
}
}
return SCARD_S_SUCCESS;
}
static DWORD
md_pkcs15_update_container_from_do(PCARD_DATA pCardData, struct sc_pkcs15_object *dobj)
{
VENDOR_SPECIFIC *vs;
DWORD dwret = SCARD_F_INTERNAL_ERROR;
struct sc_pkcs15_data *ddata = NULL;
struct sc_pkcs15_id id;
int rv, offs, idx;
unsigned flags;
if (!pCardData || !dobj)
return SCARD_E_INVALID_PARAMETER;
vs = pCardData->pvVendorSpecific;
rv = sc_pkcs15_read_data_object(vs->p15card, (struct sc_pkcs15_data_info *)dobj->data, &ddata);
if (rv) {
logprintf(pCardData, 2, "sc_pkcs15_read_data_object('%s') returned %i\n", dobj->label, rv);
return SCARD_F_INTERNAL_ERROR;
}
offs = 0;
if (*(ddata->data + offs++) != 0x01) {
sc_pkcs15_free_data_object(ddata);
return SCARD_E_INVALID_VALUE;
}
id.len = *(ddata->data + offs++);
memcpy(id.value, ddata->data + offs, id.len);
offs += id.len;
if (*(ddata->data + offs++) != 0x02) {
sc_pkcs15_free_data_object(ddata);
return SCARD_E_INVALID_VALUE;
}
if (*(ddata->data + offs++) != 0x01) {
sc_pkcs15_free_data_object(ddata);
return SCARD_E_INVALID_VALUE;
}
flags = *(ddata->data + offs);
for (idx=0; idx<MD_MAX_KEY_CONTAINERS && vs->p15_containers[idx].prkey_obj; idx++) {
if (sc_pkcs15_compare_id(&id, &vs->p15_containers[idx].id)) {
snprintf(vs->p15_containers[idx].guid, sizeof(vs->p15_containers[idx].guid),
"%s", dobj->label);
vs->p15_containers[idx].flags = flags;
logprintf(pCardData, 2, "Set container's guid to '%s' and flags to 0x%X\n",
vs->p15_containers[idx].guid, flags);
break;
}
}
sc_pkcs15_free_data_object(ddata);
return SCARD_S_SUCCESS;
}
static DWORD
md_pkcs15_default_container_from_do(PCARD_DATA pCardData, struct sc_pkcs15_object *dobj)
{
VENDOR_SPECIFIC *vs;
struct sc_pkcs15_data *ddata = NULL;
DWORD dwret = SCARD_F_INTERNAL_ERROR;
int rv, idx;
char guid[MAX_CONTAINER_NAME_LEN + 1];
if (!pCardData || !dobj)
return SCARD_E_INVALID_PARAMETER;
vs = pCardData->pvVendorSpecific;
rv = sc_pkcs15_read_data_object(vs->p15card, (struct sc_pkcs15_data_info *)dobj->data, &ddata);
if (rv) {
logprintf(pCardData, 2, "sc_pkcs15_read_data_object('%s') returned %i\n", dobj->label, rv);
return SCARD_F_INTERNAL_ERROR;
}
if (ddata->data_len > MAX_CONTAINER_NAME_LEN || ddata->data_len < 32) {
logprintf(pCardData, 2, "Invalid container name length %i\n", ddata->data_len);
return SCARD_E_INVALID_VALUE;
}
memset(guid, 0, sizeof(guid));
memcpy(&guid[0] , ddata->data, ddata->data_len);
logprintf(pCardData, 2, "Search container '%s' to set it as default\n", guid);
for (idx=0; idx<MD_MAX_KEY_CONTAINERS && vs->p15_containers[idx].prkey_obj; idx++) {
if (strstr(vs->p15_containers[idx].guid, guid)) {
vs->p15_containers[idx].flags |= CONTAINER_MAP_DEFAULT_CONTAINER;
logprintf(pCardData, 2, "Default container is '%s'\n", vs->p15_containers[idx].guid);
break;
}
}
sc_pkcs15_free_data_object(ddata);
return SCARD_S_SUCCESS;
}
static DWORD
md_pkcs15_delete_object(PCARD_DATA pCardData, struct sc_pkcs15_object *obj)
{
VENDOR_SPECIFIC *vs;
struct sc_profile *profile = NULL;
struct sc_card *card = NULL;
struct sc_app_info *app_info = NULL;
DWORD dwret = SCARD_F_INTERNAL_ERROR;
int rv;
if (!pCardData)
return SCARD_E_INVALID_PARAMETER;
vs = pCardData->pvVendorSpecific;
card = vs->p15card->card;
if (!obj)
return SCARD_S_SUCCESS;
logprintf(pCardData, 3, "MdDeleteObject('%s',type:0x%X) called\n", obj->label, obj->type);
rv = sc_lock(card);
if (rv) {
logprintf(pCardData, 3, "MdDeleteObject(): cannot lock card\n");
return SCARD_F_INTERNAL_ERROR;
}
app_info = vs->p15card->app;
rv = sc_pkcs15init_bind(card, "pkcs15", NULL, app_info, &profile);
if (rv) {
logprintf(pCardData, 3, "MdDeleteObject(): PKCS#15 bind failed\n");
sc_unlock(card);
return SCARD_F_INTERNAL_ERROR;
}
rv = sc_pkcs15init_finalize_profile(card, profile, app_info ? &app_info->aid : NULL);
if (rv) {
logprintf(pCardData, 3, "MdDeleteObject(): cannot finalize profile\n");
goto done;
}
sc_pkcs15init_set_p15card(profile, vs->p15card);
rv = sc_pkcs15init_delete_object(vs->p15card, profile, obj);
if (rv) {
logprintf(pCardData, 2, "MdDeleteObject(): pkcs15init delete object failed %d\n", rv);
goto done;
}
dwret = SCARD_S_SUCCESS;
logprintf(pCardData, 3, "MdDeleteObject() returns OK\n");
done:
sc_pkcs15init_unbind(profile);
sc_unlock(card);
return dwret;
}
/* Set 'soft' file contents,
* and update data associated to 'cardcf' and 'cmapfile'.
*/
static DWORD
md_fs_set_content(PCARD_DATA pCardData, struct md_file *file, unsigned char *blob, size_t size)
{
if (!pCardData || !file)
return SCARD_E_INVALID_PARAMETER;
if (file->blob)
pCardData->pfnCspFree(file->blob);
file->blob = pCardData->pfnCspAlloc(size);
if (!file->blob)
return SCARD_E_NO_MEMORY;
CopyMemory(file->blob, blob, size);
file->size = size;
if (!strcmp(file->name, "cmapfile"))
return md_pkcs15_update_containers(pCardData, blob, size);
return SCARD_S_SUCCESS;
}
/*
* Set 'cardid' from the 'serialNumber' attribute of the 'tokenInfo'
*/
static DWORD
md_set_cardid(PCARD_DATA pCardData, struct md_file *file)
{
VENDOR_SPECIFIC *vs;
DWORD dwret;
if (!pCardData || !file)
return SCARD_E_INVALID_PARAMETER;
vs = pCardData->pvVendorSpecific;
if (vs->p15card->tokeninfo && vs->p15card->tokeninfo->serial_number) {
unsigned char sn_bin[SC_MAX_SERIALNR];
unsigned char cardid_bin[MD_CARDID_SIZE];
size_t offs, wr, sn_len = sizeof(sn_bin);
int rv;
rv = sc_hex_to_bin(vs->p15card->tokeninfo->serial_number, sn_bin, &sn_len);
if (rv) {
sn_len = strlen(vs->p15card->tokeninfo->serial_number);
if (sn_len > SC_MAX_SERIALNR) {
sn_len = SC_MAX_SERIALNR;
}
memcpy(sn_bin, vs->p15card->tokeninfo->serial_number, sn_len);
}
for (offs=0; offs < MD_CARDID_SIZE; ) {
wr = MD_CARDID_SIZE - offs;
if (wr > sn_len)
wr = sn_len;
memcpy(cardid_bin + offs, sn_bin, wr);
offs += wr;
}
dwret = md_fs_set_content(pCardData, file, cardid_bin, MD_CARDID_SIZE);
if (dwret != SCARD_S_SUCCESS)
return dwret;
}
logprintf(pCardData, 3, "cardid(%i)\n", file->size);
loghex(pCardData, 3, file->blob, file->size);
return SCARD_S_SUCCESS;
}
/*
* Return content of the 'soft' file.
*/
static void
md_fs_read_content(PCARD_DATA pCardData, char *parent, struct md_file *file)
{
VENDOR_SPECIFIC *vs;
struct md_directory *dir = NULL;
DWORD dwret;
if (!pCardData || !file)
return;
vs = pCardData->pvVendorSpecific;
dwret = md_fs_find_directory(pCardData, NULL, parent, &dir);
if (dwret != SCARD_S_SUCCESS) {
logprintf(pCardData, 2, "find directory '%s' error: %X\n", parent ? parent : "<null>", dwret);
return;
}
else if (!dir) {
logprintf(pCardData, 2, "directory '%s' not found\n", parent ? parent : "<null>");
return;
}
if (!strcmp(dir->name, "mscp")) {
int idx, rv;
if(sscanf(file->name, "ksc%d", &idx) > 0) {
}
else if(sscanf(file->name, "kxc%d", &idx) > 0) {
}
else {
idx = -1;
}
if (idx >=0 && idx < MD_MAX_KEY_CONTAINERS && vs->p15_containers[idx].cert_obj) {
struct sc_pkcs15_cert *cert = NULL;
struct sc_pkcs15_object *cert_obj = vs->p15_containers[idx].cert_obj;
struct sc_pkcs15_cert_info *cert_info = (struct sc_pkcs15_cert_info *)cert_obj->data;
rv = sc_pkcs15_read_certificate(vs->p15card, cert_info, &cert);
if(rv) {
logprintf(pCardData, 2, "Cannot read certificate idx:%i: sc-error %d\n", idx, rv);
logprintf(pCardData, 2, "set cardcf from 'DATA' pkcs#15 object\n");
return;
}
file->size = cert->data.len;
file->blob = pCardData->pfnCspAlloc(cert->data.len);
CopyMemory(file->blob, cert->data.value, cert->data.len);
sc_pkcs15_free_certificate(cert);
}
}
else {
return;
}
}
/*
* Set content of 'cardcf',
* for that look for the possible source in the following order:
* - data from the dedicated PKCS#15 'DATA' object;
* - 'lastUpdate' attribute of tokenInfo;
* - random data.
*/
static DWORD
md_set_cardcf(PCARD_DATA pCardData, struct md_file *file)
{
VENDOR_SPECIFIC *vs;
char *last_update = NULL;
CARD_CACHE_FILE_FORMAT empty;
size_t empty_len = sizeof(empty);
DWORD dwret;
if (!pCardData || !file)
return SCARD_E_INVALID_PARAMETER;
vs = pCardData->pvVendorSpecific;
memset(&empty, 0, sizeof(empty));
empty.bVersion = CARD_CACHE_FILE_CURRENT_VERSION;
last_update = sc_pkcs15_get_lastupdate(vs->p15card);
if (last_update) {
unsigned crc32 = sc_crc32(last_update, strlen(last_update));
logprintf(pCardData, 2, "Set 'cardcf' using lastUpdate '%s'; CRC32 %X\n", last_update, crc32);
empty.wContainersFreshness = crc32;
empty.wFilesFreshness = crc32;
}
else {
logprintf(pCardData, 2, "Set 'cardcf' using random value\n");
srand((unsigned)time(NULL));
empty.wContainersFreshness = rand()%30000;
empty.wFilesFreshness = rand()%30000;
}
dwret = md_fs_set_content(pCardData, file, (unsigned char *)(&empty), MD_CARDCF_LENGTH);
if (dwret != SCARD_S_SUCCESS)
return dwret;
logprintf(pCardData, 3, "'cardcf' content(%i)\n", file->size);
loghex(pCardData, 3, file->blob, file->size);
return SCARD_S_SUCCESS;
}
/*
* Return content of the 'soft' 'cardcf' file
*/
static DWORD
md_get_cardcf(PCARD_DATA pCardData, CARD_CACHE_FILE_FORMAT **out)
{
struct md_file *file = NULL;
if (!pCardData)
return SCARD_E_INVALID_PARAMETER;
md_fs_find_file(pCardData, NULL, "cardcf", &file);
if (!file) {
logprintf(pCardData, 2, "file 'cardcf' not found\n");
return SCARD_E_FILE_NOT_FOUND;
}
if (!file->blob || file->size < MD_CARDCF_LENGTH)
return SCARD_E_INVALID_VALUE;
if (out)
*out = (CARD_CACHE_FILE_FORMAT *)file->blob;
return SCARD_S_SUCCESS;
}
static DWORD
md_set_cardapps(PCARD_DATA pCardData, struct md_file *file)
{
DWORD dwret;
unsigned char mscp[8] = {'m','s','c','p',0,0,0,0};
if (!pCardData || !file)
return SCARD_E_INVALID_PARAMETER;
dwret = md_fs_set_content(pCardData, file, mscp, sizeof(mscp));
if (dwret != SCARD_S_SUCCESS)
return dwret;
logprintf(pCardData, 3, "mscp(%i)\n", file->size);
loghex(pCardData, 3, file->blob, file->size);
return SCARD_S_SUCCESS;
}
/*
* Set the content of the 'soft' 'cmapfile':
* 1. Initialize internal p15_contaniers with the existing private keys PKCS#15 objects;
* 2. Try to read the content of the PKCS#15 'DATA' object 'CSP':'cmapfile',
* If some record from the 'DATA' object references an existing key:
* 2a. Update the non-pkcs#15 attributes of the corresponding internal p15_container;
* 2b. Change the index of internal p15_container according to the index from 'DATA' file.
* Records from 'DATA' file are ignored is they do not have
* the corresponding PKCS#15 private key object.
* 3. Initalize the content of the 'soft' 'cmapfile' from the inernal p15-containers.
*/
static DWORD
md_set_cmapfile(PCARD_DATA pCardData, struct md_file *file)
{
VENDOR_SPECIFIC *vs;
PCONTAINER_MAP_RECORD p;
sc_pkcs15_pubkey_t *pubkey = NULL;
unsigned char *cmap_buf = NULL;
size_t cmap_len;
DWORD dwret;
int ii, rv, conts_num, found_default = 0;
/* struct sc_pkcs15_data *data_object; */
struct sc_pkcs15_object *prkey_objs[MD_MAX_KEY_CONTAINERS];
if (!pCardData || !file)
return SCARD_E_INVALID_PARAMETER;
logprintf(pCardData, 0, "set 'cmapfile'\n");
vs = pCardData->pvVendorSpecific;
cmap_len = MD_MAX_KEY_CONTAINERS*sizeof(CONTAINER_MAP_RECORD);
cmap_buf = pCardData->pfnCspAlloc(cmap_len);
if(!cmap_buf)
return SCARD_E_NO_MEMORY;
memset(cmap_buf, 0, cmap_len);
rv = sc_pkcs15_get_objects(vs->p15card, SC_PKCS15_TYPE_PRKEY_RSA, prkey_objs, MD_MAX_KEY_CONTAINERS);
if (rv < 0) {
logprintf(pCardData, 0, "Private key enumeration failed: %s\n", sc_strerror(rv));
return SCARD_F_UNKNOWN_ERROR;
}
conts_num = rv;
logprintf(pCardData, 2, "Found %d private key(s) in the card.\n", conts_num);
/* Initialize the P15 container array with the existing keys */
for(ii = 0; ii < conts_num; ii++) {
struct sc_pkcs15_object *key_obj = prkey_objs[ii], *cert_obj = NULL;
struct sc_pkcs15_prkey_info *prkey_info = (struct sc_pkcs15_prkey_info *)key_obj->data;
struct md_pkcs15_container *cont = &vs->p15_containers[ii];
if(key_obj->type != SC_PKCS15_TYPE_PRKEY_RSA) {
logprintf(pCardData, 7, "Non 'RSA' key (type:%X) are ignored\n", key_obj->type);
continue;
}
rv = sc_pkcs15_get_guid(vs->p15card, key_obj, 0, cont->guid, sizeof(cont->guid));
if (rv) {
logprintf(pCardData, 2, "sc_pkcs15_get_guid() error %d\n", rv);
return SCARD_F_INTERNAL_ERROR;
}
logprintf(pCardData, 7, "Container[%i]'s guid=%s\n", ii, cont->guid);
cont->flags = CONTAINER_MAP_VALID_CONTAINER;
/* AT_KEYEXCHANGE is more general key usage,
* it allows 'decryption' as well as 'signature' key usage.
* AT_SIGNATURE allows only 'signature' usage.
*/
cont->size_key_exchange = cont->size_sign = 0;
if (prkey_info->usage & USAGE_ANY_DECIPHER)
cont->size_key_exchange = prkey_info->modulus_length;
else if (prkey_info->usage & USAGE_ANY_SIGN)
cont->size_sign = prkey_info->modulus_length;
else
cont->size_key_exchange = prkey_info->modulus_length;
logprintf(pCardData, 7, "Container[%i]'s key-exchange:%i, sign:%i\n", ii, cont->size_key_exchange, cont->size_sign);
cont->id = prkey_info->id;
cont->prkey_obj = prkey_objs[ii];
/* Try to find the friend objects: certficate and public key */
if (!sc_pkcs15_find_cert_by_id(vs->p15card, &cont->id, &cont->cert_obj))
logprintf(pCardData, 2, "found certificate friend '%s'\n", cont->cert_obj->label);
if (!sc_pkcs15_find_pubkey_by_id(vs->p15card, &cont->id, &cont->pubkey_obj))
logprintf(pCardData, 2, "found public key friend '%s'\n", cont->pubkey_obj->label);
}
if (conts_num) {
/* Read 'CMAPFILE' and update the attributes of P15 containers */
struct sc_pkcs15_object *dobjs[MD_MAX_KEY_CONTAINERS + 1], *default_cont = NULL;
int num_dobjs = MD_MAX_KEY_CONTAINERS + 1;
rv = sc_pkcs15_get_objects(vs->p15card, SC_PKCS15_TYPE_DATA_OBJECT, dobjs, num_dobjs);
if (rv < 0) {
logprintf(pCardData, 0, "'DATA' object enumeration failed: %s\n", sc_strerror(rv));
return SCARD_F_UNKNOWN_ERROR;
}
num_dobjs = rv;
logprintf(pCardData, 2, "Found %d 'DATA' objects.\n", num_dobjs);
for (ii=0;ii<num_dobjs;ii++) {
struct sc_pkcs15_data_info *dinfo = (struct sc_pkcs15_data_info *)dobjs[ii]->data;
if (strcmp(dinfo->app_label, MD_DATA_APPLICAITON_NAME))
continue;
logprintf(pCardData, 2, "Found 'DATA' object '%s'\n", dobjs[ii]->label);
if (!strcmp(dobjs[ii]->label, MD_DATA_DEFAULT_CONT_LABEL)) {
default_cont = dobjs[ii];
continue;
}
dwret = md_pkcs15_update_container_from_do(pCardData, dobjs[ii]);
if (dwret != SCARD_S_SUCCESS) {
logprintf(pCardData, 2, "Cannot update container from DO: %li", dwret);
return dwret;
}
}
if (default_cont) {
dwret = md_pkcs15_default_container_from_do(pCardData, default_cont);
if (dwret != SCARD_S_SUCCESS) {
logprintf(pCardData, 2, "Cannot set default container from DO: %li", dwret);
return dwret;
}
}
/* Initialize 'CMAPFILE' content from the P15 containers */
p = (PCONTAINER_MAP_RECORD)cmap_buf;
for (ii=0; ii<MD_MAX_KEY_CONTAINERS; ii++) {
struct sc_pkcs15_object *cert_obj = NULL;
if (!(vs->p15_containers[ii].flags & CONTAINER_MAP_VALID_CONTAINER))
continue;
if (!found_default) {
vs->p15_containers[ii].flags |= CONTAINER_MAP_DEFAULT_CONTAINER;
found_default = 1;
}
mbstowcs((p+ii)->wszGuid, vs->p15_containers[ii].guid, MAX_CONTAINER_NAME_LEN + 1);
(p+ii)->bFlags = vs->p15_containers[ii].flags;
(p+ii)->wSigKeySizeBits = vs->p15_containers[ii].size_sign;
(p+ii)->wKeyExchangeKeySizeBits = vs->p15_containers[ii].size_key_exchange;
if (vs->p15_containers[ii].cert_obj) {
char k_name[6];
if (vs->p15_containers[ii].size_key_exchange) {
snprintf((char *)k_name, sizeof(k_name), "kxc%02i", ii);
dwret = md_fs_add_file(pCardData, &(file->next), k_name, file->acl, NULL, 0, NULL);
if (dwret != SCARD_S_SUCCESS)
return dwret;
}
if (vs->p15_containers[ii].size_sign) {
snprintf((char *)k_name, sizeof(k_name), "ksc%02i", ii);
dwret = md_fs_add_file(pCardData, &(file->next), k_name, file->acl, NULL, 0, NULL);
if (dwret != SCARD_S_SUCCESS)
return dwret;
}
}
logprintf(pCardData, 7, "cmapfile entry(%d) '%s' ",ii, vs->p15_containers[ii].guid);
loghex(pCardData, 7, (PBYTE) (p+ii), sizeof(CONTAINER_MAP_RECORD));
}
}
dwret = md_fs_set_content(pCardData, file, cmap_buf, cmap_len);
pCardData->pfnCspFree(cmap_buf);
if (dwret != SCARD_S_SUCCESS)
return dwret;
logprintf(pCardData, 3, "cmap(%i)\n", file->size);
loghex(pCardData, 3, file->blob, file->size);
return SCARD_S_SUCCESS;
}
/*
* Initialize internal 'soft' file system
*/
static DWORD
md_fs_init(PCARD_DATA pCardData)
{
VENDOR_SPECIFIC *vs;
DWORD dwret;
struct md_file *cardid, *cardcf, *cardapps, *cmapfile;
struct md_directory *mscp;
if (!pCardData || !pCardData->pvVendorSpecific)
return SCARD_E_INVALID_PARAMETER;
vs = pCardData->pvVendorSpecific;
dwret = md_fs_add_file(pCardData, &(vs->root.files), "cardid", EveryoneReadAdminWriteAc, NULL, 0, &cardid);
if (dwret != SCARD_S_SUCCESS)
return dwret;
dwret = md_set_cardid(pCardData, cardid);
if (dwret != SCARD_S_SUCCESS)
return dwret;
dwret = md_fs_add_file(pCardData, &(vs->root.files), "cardcf", EveryoneReadUserWriteAc, NULL, 0, &cardcf);
if (dwret != SCARD_S_SUCCESS)
return dwret;
dwret = md_set_cardcf(pCardData, cardcf);
if (dwret != SCARD_S_SUCCESS)
return dwret;
dwret = md_fs_add_file(pCardData, &(vs->root.files), "cardapps", EveryoneReadAdminWriteAc, NULL, 0, &cardapps);
if (dwret != SCARD_S_SUCCESS)
return dwret;
dwret = md_set_cardapps(pCardData, cardapps);
if (dwret != SCARD_S_SUCCESS)
return dwret;
dwret = md_fs_add_directory(pCardData, &(vs->root.subdirs), "mscp", UserCreateDeleteDirAc, &mscp);
if (dwret != SCARD_S_SUCCESS)
return dwret;
dwret = md_fs_add_file(pCardData, &(mscp->files), "cmapfile", EveryoneReadUserWriteAc, NULL, 0, &cmapfile);
if (dwret != SCARD_S_SUCCESS)
return dwret;
dwret = md_set_cmapfile(pCardData, cmapfile);
if (dwret != SCARD_S_SUCCESS)
return dwret;
logprintf(pCardData, 3, "MD virtual file system initialized\n");
return SCARD_S_SUCCESS;
}
/* Create SC context */
static DWORD
md_create_context(PCARD_DATA pCardData, VENDOR_SPECIFIC *vs)
{
sc_context_param_t ctx_param;
int r;
if (!pCardData)
return SCARD_E_INVALID_PARAMETER;
logprintf(pCardData, 3, "create sc ccontext\n");
vs->ctx = NULL;
memset(&ctx_param, 0, sizeof(ctx_param));
ctx_param.ver = 1;
ctx_param.app_name = "cardmod";
r = sc_context_create(&(vs->ctx), &ctx_param);
if (r) {
logprintf(pCardData, 0, "Failed to establish context: %s\n", sc_strerror(r));
return SCARD_F_UNKNOWN_ERROR;
}
logprintf(pCardData, 3, "sc context created\n");
return SCARD_S_SUCCESS;
}
static DWORD
md_card_capabilities(PCARD_CAPABILITIES pCardCapabilities)
{
if (!pCardCapabilities)
return SCARD_E_INVALID_PARAMETER;
if (pCardCapabilities->dwVersion != CARD_CAPABILITIES_CURRENT_VERSION && pCardCapabilities->dwVersion != 0)
return ERROR_REVISION_MISMATCH;
pCardCapabilities->dwVersion = CARD_CAPABILITIES_CURRENT_VERSION;
pCardCapabilities->fCertificateCompression = TRUE;
pCardCapabilities->fKeyGen = TRUE;
return SCARD_S_SUCCESS;
}
static DWORD
md_free_space(PCARD_DATA pCardData, PCARD_FREE_SPACE_INFO pCardFreeSpaceInfo)
{
VENDOR_SPECIFIC *vs;
int count, idx;
if (!pCardData || !pCardFreeSpaceInfo)
return SCARD_E_INVALID_PARAMETER;
if (pCardFreeSpaceInfo->dwVersion > CARD_FREE_SPACE_INFO_CURRENT_VERSION )
return ERROR_REVISION_MISMATCH;
vs = (VENDOR_SPECIFIC*)(pCardData->pvVendorSpecific);
/* Count free containers */
for (idx=0, count=0; idx<MD_MAX_KEY_CONTAINERS; idx++)
if (!vs->p15_containers[idx].prkey_obj)
count++;
pCardFreeSpaceInfo->dwVersion = CARD_FREE_SPACE_INFO_CURRENT_VERSION;
pCardFreeSpaceInfo->dwBytesAvailable = CARD_DATA_VALUE_UNKNOWN;
pCardFreeSpaceInfo->dwKeyContainersAvailable = count;
pCardFreeSpaceInfo->dwMaxKeyContainers = MD_MAX_KEY_CONTAINERS;
return SCARD_S_SUCCESS;
}
/* Check the new key to be created for the compatibility with card:
* - for the key to be generated the card needs to support the mechanism and size;
* - for the key to be imported checked also the validity of supplied key blob.
*/
static DWORD
md_check_key_compatibility(PCARD_DATA pCardData, DWORD flags, DWORD key_type,
DWORD key_size, BYTE *pbKeyData)
{
VENDOR_SPECIFIC *vs;
struct sc_algorithm_info *algo_info;
unsigned int count, key_algo;
if (!pCardData)
return SCARD_E_INVALID_PARAMETER;
if (key_type == AT_SIGNATURE || key_type == AT_KEYEXCHANGE) {
key_algo = SC_ALGORITHM_RSA;
}
else {
logprintf(pCardData, 3, "Unsupported key type: 0x%X\n", key_type);
return SCARD_E_UNSUPPORTED_FEATURE;
}
vs = (VENDOR_SPECIFIC*)(pCardData->pvVendorSpecific);
if (flags & CARD_CREATE_CONTAINER_KEY_IMPORT) {
PUBLICKEYSTRUC *pub_struc = (PUBLICKEYSTRUC *)pbKeyData;
RSAPUBKEY *pub_rsa = (RSAPUBKEY *)(pbKeyData + sizeof(PUBLICKEYSTRUC));
if (!pub_struc) {
logprintf(pCardData, 3, "No data for the key import operation\n");
return SCARD_E_INVALID_PARAMETER;
}
else if (pub_struc->bType != PRIVATEKEYBLOB) {
logprintf(pCardData, 3, "Invalid blob data for the key import operation\n");
return SCARD_E_INVALID_PARAMETER;
}
else if ((key_type == AT_KEYEXCHANGE) && (pub_struc->aiKeyAlg != CALG_RSA_KEYX)) {
logprintf(pCardData, 3, "Expected KEYEXCHANGE type of blob\n");
return SCARD_E_INVALID_PARAMETER;
}
else if ((key_type == AT_SIGNATURE) && (pub_struc->aiKeyAlg != CALG_RSA_SIGN)) {
logprintf(pCardData, 3, "Expected KEYSIGN type of blob\n");
return SCARD_E_INVALID_PARAMETER;
}
if (pub_rsa->magic == 0x31415352 || pub_rsa->magic == 0x32415352) {
key_size = pub_rsa->bitlen;
}
else {
logprintf(pCardData, 3, "'Magic' control failed\n");
return SCARD_E_INVALID_PARAMETER;
}
logprintf(pCardData, 3, "Set key size to %i\n", key_size);
}
count = vs->p15card->card->algorithm_count;
for (algo_info = vs->p15card->card->algorithms; count--; algo_info++) {
if (algo_info->algorithm != key_algo || algo_info->key_length != key_size)
continue;
logprintf(pCardData, 3, "Key compatible with the card capabilities\n");
return SCARD_S_SUCCESS;
}
logprintf(pCardData, 3, "No card support for key(type:0x%X,size:0x%X)\n", key_type, key_size);
return SCARD_E_UNSUPPORTED_FEATURE;
}
static DWORD
md_pkcs15_generate_key(PCARD_DATA pCardData, DWORD idx, DWORD key_type, DWORD key_size)
{
VENDOR_SPECIFIC *vs;
struct sc_card *card = NULL;
struct sc_profile *profile = NULL;
struct sc_pkcs15_object *pin_obj = NULL;
struct sc_pkcs15_auth_info *auth_info = NULL;
struct sc_app_info *app_info = NULL;
struct sc_pkcs15init_keygen_args keygen_args;
struct sc_pkcs15init_pubkeyargs pub_args;
struct md_pkcs15_container *cont = NULL;
int rv;
DWORD dw, dwret = SCARD_F_INTERNAL_ERROR;
if (!pCardData)
return SCARD_E_INVALID_PARAMETER;
vs = (VENDOR_SPECIFIC*)(pCardData->pvVendorSpecific);
card = vs->p15card->card;
memset(&pub_args, 0, sizeof(pub_args));
memset(&keygen_args, 0, sizeof(keygen_args));
keygen_args.prkey_args.label = keygen_args.pubkey_label = "TODO: key label";
if (key_type == AT_SIGNATURE) {
keygen_args.prkey_args.key.algorithm = SC_ALGORITHM_RSA;
pub_args.key.algorithm = SC_ALGORITHM_RSA;
keygen_args.prkey_args.x509_usage = MD_KEY_USAGE_SIGNATURE;
}
else if (key_type == AT_KEYEXCHANGE) {
keygen_args.prkey_args.key.algorithm = SC_ALGORITHM_RSA;
pub_args.key.algorithm = SC_ALGORITHM_RSA;
keygen_args.prkey_args.x509_usage = MD_KEY_USAGE_KEYEXCHANGE;
}
else {
logprintf(pCardData, 3, "MdGenerateKey(): unsupported key type: 0x%X\n", key_type);
return SCARD_E_INVALID_PARAMETER;
}
keygen_args.prkey_args.access_flags = MD_KEY_ACCESS;
dw = md_get_pin_by_role(pCardData, ROLE_USER, &pin_obj);
if (dw != SCARD_S_SUCCESS) {
logprintf(pCardData, 2, "MdGenerateKey(): cannot get User PIN object");
return dw;
}
auth_info = (struct sc_pkcs15_auth_info *) pin_obj->data;
keygen_args.prkey_args.auth_id = pub_args.auth_id = auth_info->auth_id;
rv = sc_lock(card);
if (rv) {
logprintf(pCardData, 3, "MdGenerateKey(): cannot lock card\n");
return SCARD_F_INTERNAL_ERROR;
}
app_info = vs->p15card->app;
rv = sc_pkcs15init_bind(card, "pkcs15", NULL, app_info, &profile);
if (rv) {
logprintf(pCardData, 3, "MdGenerateKey(): PKCS#15 bind failed\n");
sc_unlock(card);
return SCARD_F_INTERNAL_ERROR;
}
rv = sc_pkcs15init_finalize_profile(card, profile, app_info ? &app_info->aid : NULL);
if (rv) {
logprintf(pCardData, 3, "MdGenerateKey(): cannot finalize profile\n");
goto done;
}
sc_pkcs15init_set_p15card(profile, vs->p15card);
cont = &(vs->p15_containers[idx]);
if (strlen(cont->guid))
keygen_args.prkey_args.guid = cont->guid;
rv = sc_pkcs15init_generate_key(vs->p15card, profile, &keygen_args, key_size, &cont->prkey_obj);
if (rv < 0) {
logprintf(pCardData, 3, "MdGenerateKey(): key generation failed: sc-error %i\n", rv);
goto done;
}
cont->id = ((struct sc_pkcs15_prkey_info *)cont->prkey_obj->data)->id;
cont->index = idx;
cont->flags = CONTAINER_MAP_VALID_CONTAINER;
logprintf(pCardData, 3, "MdGenerateKey(): generated key(idx:%i,id:%s,guid:%s)\n",
idx, sc_pkcs15_print_id(&cont->id),cont->guid);
dwret = SCARD_S_SUCCESS;
done:
sc_pkcs15init_unbind(profile);
sc_unlock(card);
return dwret;
}
static DWORD
md_pkcs15_store_key(PCARD_DATA pCardData, DWORD idx, DWORD key_type, BYTE *blob, DWORD blob_size)
{
#if OPENSSL_VERSION_NUMBER >= 0x10000000L
VENDOR_SPECIFIC *vs;
struct sc_card *card = NULL;
struct sc_profile *profile = NULL;
struct sc_pkcs15_object *pin_obj = NULL;
struct sc_app_info *app_info = NULL;
struct md_pkcs15_container *cont = NULL;
struct sc_pkcs15init_prkeyargs prkey_args;
struct sc_pkcs15init_pubkeyargs pubkey_args;
BYTE *ptr = blob;
EVP_PKEY *pkey=NULL;
int rv;
DWORD dw, dwret = SCARD_F_INTERNAL_ERROR;
if (!pCardData)
return SCARD_E_INVALID_PARAMETER;
vs = (VENDOR_SPECIFIC*)(pCardData->pvVendorSpecific);
card = vs->p15card->card;
pkey = b2i_PrivateKey(&ptr, blob_size);
if (!pkey) {
logprintf(pCardData, 1, "MdStoreKey() MSBLOB key parse error");
return SCARD_E_INVALID_PARAMETER;
}
memset(&prkey_args, 0, sizeof(prkey_args));
rv = sc_pkcs15_convert_prkey(&prkey_args.key, pkey);
if (rv) {
logprintf(pCardData, 1, "MdStoreKey() cannot convert private key");
return SCARD_E_INVALID_PARAMETER;
}
memset(&pubkey_args, 0, sizeof(pubkey_args));
rv = sc_pkcs15_convert_pubkey(&pubkey_args.key, pkey);
if (rv) {
logprintf(pCardData, 1, "MdStoreKey() cannot convert public key");
return SCARD_E_INVALID_PARAMETER;
}
if (key_type == AT_SIGNATURE) {
prkey_args.x509_usage = MD_KEY_USAGE_SIGNATURE;
pubkey_args.x509_usage = MD_KEY_USAGE_SIGNATURE;
}
else if (key_type == AT_KEYEXCHANGE) {
prkey_args.x509_usage = MD_KEY_USAGE_KEYEXCHANGE;
pubkey_args.x509_usage = MD_KEY_USAGE_KEYEXCHANGE;
}
else {
logprintf(pCardData, 3, "MdStoreKey(): unsupported key type: 0x%X\n", key_type);
return SCARD_E_INVALID_PARAMETER;
}
prkey_args.access_flags = MD_KEY_ACCESS;
dw = md_get_pin_by_role(pCardData, ROLE_USER, &pin_obj);
if (dw != SCARD_S_SUCCESS) {
logprintf(pCardData, 2, "MdStoreKey(): cannot get User PIN object");
return dw;
}
prkey_args.auth_id = ((struct sc_pkcs15_auth_info *) pin_obj->data)->auth_id;
rv = sc_lock(card);
if (rv) {
logprintf(pCardData, 3, "MdStoreKey(): cannot lock card\n");
return SCARD_F_INTERNAL_ERROR;
}
app_info = vs->p15card->app;
rv = sc_pkcs15init_bind(card, "pkcs15", NULL, app_info, &profile);
if (rv) {
logprintf(pCardData, 3, "MdStoreKey(): PKCS#15 bind failed\n");
sc_unlock(card);
return SCARD_F_INTERNAL_ERROR;
}
rv = sc_pkcs15init_finalize_profile(card, profile, app_info ? &app_info->aid : NULL);
if (rv) {
logprintf(pCardData, 3, "MdStoreKey(): cannot finalize profile\n");
goto done;
}
sc_pkcs15init_set_p15card(profile, vs->p15card);
cont = &(vs->p15_containers[idx]);
if (strlen(cont->guid))
prkey_args.guid = cont->guid;
rv = sc_pkcs15init_store_private_key(vs->p15card, profile, &prkey_args, &cont->prkey_obj);
if (rv < 0) {
logprintf(pCardData, 3, "MdStoreKey(): private key store failed: sc-error %i\n", rv);
goto done;
}
rv = sc_pkcs15init_store_public_key(vs->p15card, profile, &pubkey_args, &cont->pubkey_obj);
if (rv < 0) {
logprintf(pCardData, 3, "MdStoreKey(): public key store failed: sc-error %i\n", rv);
goto done;
}
cont->id = ((struct sc_pkcs15_prkey_info *)cont->prkey_obj->data)->id;
cont->index = idx;
cont->flags |= CONTAINER_MAP_VALID_CONTAINER;
logprintf(pCardData, 3, "MdStoreKey(): stored key(idx:%i,id:%s,guid:%s)\n", idx, sc_pkcs15_print_id(&cont->id),cont->guid);
dwret = SCARD_S_SUCCESS;
done:
sc_pkcs15init_unbind(profile);
sc_unlock(card);
return dwret;
#else
logprintf(pCardData, 1, "MD store key not supported\n");
return SCARD_E_UNSUPPORTED_FEATURE;
#endif
}
static DWORD
md_pkcs15_store_certificate(PCARD_DATA pCardData, char *file_name, unsigned char *blob, size_t len)
{
VENDOR_SPECIFIC *vs;
struct sc_card *card = NULL;
struct sc_profile *profile = NULL;
struct sc_app_info *app_info = NULL;
struct sc_pkcs15_object *cert_obj;
struct sc_pkcs15init_certargs args;
int rv;
DWORD dwret = SCARD_F_INTERNAL_ERROR;
if (!pCardData)
return SCARD_E_INVALID_PARAMETER;
vs = (VENDOR_SPECIFIC*)(pCardData->pvVendorSpecific);
card = vs->p15card->card;
memset(&args, 0, sizeof(args));
args.der_encoded.value = blob;
args.der_encoded.len = len;
rv = sc_lock(card);
if (rv) {
logprintf(pCardData, 3, "MdStoreCert(): cannot lock card\n");
return SCARD_F_INTERNAL_ERROR;
}
app_info = vs->p15card->app;
rv = sc_pkcs15init_bind(card, "pkcs15", NULL, app_info, &profile);
if (rv) {
logprintf(pCardData, 3, "MdStoreCert(): PKCS#15 bind failed\n");
sc_unlock(card);
return SCARD_F_INTERNAL_ERROR;
}
rv = sc_pkcs15init_finalize_profile(card, profile, app_info ? &app_info->aid : NULL);
if (rv) {
logprintf(pCardData, 3, "MdStoreCert(): cannot finalize profile\n");
goto done;
}
sc_pkcs15init_set_p15card(profile, vs->p15card);
rv = sc_pkcs15init_store_certificate(vs->p15card, profile, &args, &cert_obj);
if (rv < 0) {
logprintf(pCardData, 3, "MdStoreCert(): cannot store certificate: sc-error %i\n", rv);
goto done;
}
dwret = SCARD_S_SUCCESS;
done:
sc_pkcs15init_unbind(profile);
sc_unlock(card);
return dwret;
}
static DWORD
md_query_key_sizes(CARD_KEY_SIZES *pKeySizes)
{
if (!pKeySizes)
return SCARD_E_INVALID_PARAMETER;
if (pKeySizes->dwVersion != CARD_KEY_SIZES_CURRENT_VERSION && pKeySizes->dwVersion != 0)
return ERROR_REVISION_MISMATCH;
pKeySizes->dwVersion = CARD_KEY_SIZES_CURRENT_VERSION;
pKeySizes->dwMinimumBitlen = 1024;
pKeySizes->dwDefaultBitlen = 2048;
pKeySizes->dwMaximumBitlen = 2048;
pKeySizes->dwIncrementalBitlen = 1024;
return SCARD_S_SUCCESS;
}
DWORD WINAPI CardDeleteContext(__inout PCARD_DATA pCardData)
{
VENDOR_SPECIFIC *vs = NULL;
if (md_static_data.attach_check != MD_STATIC_PROCESS_ATTACHED)
return SCARD_S_SUCCESS;
if(!pCardData)
return SCARD_E_INVALID_PARAMETER;
logprintf(pCardData, 1, "\nP:%d T:%d pCardData:%p hScard=0x%08X hSCardCtx=0x%08X CardDeleteContext\n",
GetCurrentProcessId(), GetCurrentThreadId(), pCardData, pCardData->hScard, pCardData->hSCardCtx);
vs = (VENDOR_SPECIFIC*)(pCardData->pvVendorSpecific);
if(!vs)
return SCARD_E_INVALID_PARAMETER;
disassociate_card(pCardData);
if(vs->ctx) {
logprintf(pCardData, 6, "release context\n");
sc_release_context(vs->ctx);
md_static_data.flags |= MD_STATIC_FLAG_CONTEXT_DELETED;
vs->ctx = NULL;
}
logprintf(pCardData, 1, "**********************************************************************\n");
pCardData->pfnCspFree(pCardData->pvVendorSpecific);
pCardData->pvVendorSpecific = NULL;
return SCARD_S_SUCCESS;
}
DWORD WINAPI CardQueryCapabilities(__in PCARD_DATA pCardData,
__in PCARD_CAPABILITIES pCardCapabilities)
{
DWORD dwret;
logprintf(pCardData, 1, "\nP:%d T:%d pCardData:%p ",GetCurrentProcessId(), GetCurrentThreadId(), pCardData);
logprintf(pCardData, 1, "pCardCapabilities=%X\n", pCardCapabilities);
if (!pCardData || !pCardCapabilities)
return SCARD_E_INVALID_PARAMETER;
dwret = md_card_capabilities(pCardCapabilities);
if (dwret != SCARD_S_SUCCESS)
return dwret;
check_reader_status(pCardData);
return SCARD_S_SUCCESS;
}
DWORD WINAPI CardDeleteContainer(__in PCARD_DATA pCardData,
__in BYTE bContainerIndex,
__in DWORD dwReserved)
{
logprintf(pCardData, 1, "\nP:%d T:%d pCardData:%p ",GetCurrentProcessId(), GetCurrentThreadId(), pCardData);
logprintf(pCardData, 1, "CardDeleteContainer(idx:%i)\n", bContainerIndex);
logprintf(pCardData, 1, "CardDeleteContainer() not supported\n");
return SCARD_E_UNSUPPORTED_FEATURE;
}
DWORD WINAPI CardCreateContainer(__in PCARD_DATA pCardData,
__in BYTE bContainerIndex,
__in DWORD dwFlags,
__in DWORD dwKeySpec,
__in DWORD dwKeySize,
__in PBYTE pbKeyData)
{
VENDOR_SPECIFIC *vs = NULL;
DWORD dwret;
if (!pCardData)
return SCARD_E_INVALID_PARAMETER;
vs = (VENDOR_SPECIFIC*)(pCardData->pvVendorSpecific);
logprintf(pCardData, 1, "\nP:%d T:%d pCardData:%p ",GetCurrentProcessId(), GetCurrentThreadId(), pCardData);
logprintf(pCardData, 1, "CardCreateContainer(idx:%i,flags:%X,type:%X,size:%i,data:%p)\n",
bContainerIndex, dwFlags, dwKeySpec, dwKeySize, pbKeyData);
if (pbKeyData) {
logprintf(pCardData, 7, "Key data\n");
loghex(pCardData, 7, pbKeyData, dwKeySize);
}
dwret = md_check_key_compatibility(pCardData, dwFlags, dwKeySpec, dwKeySize, pbKeyData);
if (dwret != SCARD_S_SUCCESS) {
logprintf(pCardData, 1, "check key compatibility failed");
return dwret;
}
if (dwFlags & CARD_CREATE_CONTAINER_KEY_GEN) {
dwret = md_pkcs15_generate_key(pCardData, bContainerIndex, dwKeySpec, dwKeySize);
if (dwret != SCARD_S_SUCCESS) {
logprintf(pCardData, 1, "key generation failed");
return dwret;
}
logprintf(pCardData, 1, "key generated");
}
else if ((dwFlags & CARD_CREATE_CONTAINER_KEY_IMPORT) && (pbKeyData != NULL)) {
dwret = md_pkcs15_store_key(pCardData, bContainerIndex, dwKeySpec, pbKeyData, dwKeySize);
if (dwret != SCARD_S_SUCCESS) {
logprintf(pCardData, 1, "key store failed");
return dwret;
}
logprintf(pCardData, 1, "key imported");
}
else {
logprintf(pCardData, 1, "Invalid dwFlags value: 0x%X", dwFlags);
return SCARD_E_INVALID_PARAMETER;
}
return SCARD_S_SUCCESS;
}
typedef struct {
PUBLICKEYSTRUC publickeystruc;
RSAPUBKEY rsapubkey;
} PUBKEYSTRUCT_BASE;
DWORD WINAPI CardGetContainerInfo(__in PCARD_DATA pCardData, __in BYTE bContainerIndex, __in DWORD dwFlags,
__in PCONTAINER_INFO pContainerInfo)
{
VENDOR_SPECIFIC *vs = NULL;
DWORD sz = 0;
DWORD ret = SCARD_F_UNKNOWN_ERROR;
struct md_pkcs15_container *cont = NULL;
struct sc_pkcs15_der pubkey_der;
int rv;
if(!pCardData)
return SCARD_E_INVALID_PARAMETER;
if (!pContainerInfo)
return SCARD_E_INVALID_PARAMETER;
logprintf(pCardData, 1, "\nP:%d T:%d pCardData:%p ",GetCurrentProcessId(), GetCurrentThreadId(), pCardData);
logprintf(pCardData, 1, "CardGetContainerInfo bContainerIndex=%u, dwFlags=0x%08X, " \
"dwVersion=%u, cbSigPublicKey=%u, cbKeyExPublicKey=%u\n", \
bContainerIndex, dwFlags, pContainerInfo->dwVersion, \
pContainerInfo->cbSigPublicKey, pContainerInfo->cbKeyExPublicKey);
if (dwFlags)
return SCARD_E_INVALID_PARAMETER;
if (bContainerIndex >= MD_MAX_KEY_CONTAINERS)
return SCARD_E_NO_KEY_CONTAINER;
if (pContainerInfo->dwVersion < 0 || pContainerInfo->dwVersion > CONTAINER_INFO_CURRENT_VERSION)
return ERROR_REVISION_MISMATCH;
pContainerInfo->dwVersion = CONTAINER_INFO_CURRENT_VERSION;
vs = (VENDOR_SPECIFIC*)(pCardData->pvVendorSpecific);
cont = &vs->p15_containers[bContainerIndex];
if (!cont->prkey_obj) {
logprintf(pCardData, 7, "Container %i is empty\n", bContainerIndex);
return SCARD_E_NO_KEY_CONTAINER;
}
check_reader_status(pCardData);
pubkey_der.value = NULL;
pubkey_der.len = 0;
if ((cont->prkey_obj->content.value != NULL) && (cont->prkey_obj->content.len > 0)) {
sc_der_copy(&pubkey_der, &cont->prkey_obj->content);
ret = SCARD_S_SUCCESS;
}
if (!pubkey_der.value && cont->pubkey_obj) {
struct sc_pkcs15_pubkey *pubkey = NULL;
logprintf(pCardData, 1, "now read public key '%s'\n", cont->pubkey_obj->label);
rv = sc_pkcs15_read_pubkey(vs->p15card, cont->pubkey_obj, &pubkey);
if (!rv) {
if(pubkey->algorithm == SC_ALGORITHM_RSA) {
sc_der_copy(&pubkey_der, &pubkey->data);
ret = SCARD_S_SUCCESS;
}
else {
ret = SCARD_E_UNSUPPORTED_FEATURE;
}
sc_pkcs15_free_pubkey(pubkey);
}
else {
logprintf(pCardData, 1, "public key read error %d\n", rv);
ret = SCARD_E_FILE_NOT_FOUND;
}
}
if (!pubkey_der.value && cont->cert_obj) {
struct sc_pkcs15_cert *cert = NULL;
logprintf(pCardData, 1, "now read certificate '%s'\n", cont->cert_obj->label);
rv = sc_pkcs15_read_certificate(vs->p15card, (struct sc_pkcs15_cert_info *)(cont->cert_obj->data), &cert);
if(!rv) {
if(cert->key->algorithm == SC_ALGORITHM_RSA) {
sc_der_copy(&pubkey_der, &cert->key->data);
ret = SCARD_S_SUCCESS;
}
else {
ret = SCARD_E_UNSUPPORTED_FEATURE;
}
sc_pkcs15_free_certificate(cert);
}
else {
logprintf(pCardData, 1, "certificate '%d' read error %d\n", bContainerIndex, rv);
ret = SCARD_E_FILE_NOT_FOUND;
}
}
if (!pubkey_der.value && (cont->size_sign || cont->size_key_exchange)) {
logprintf(pCardData, 2, "cannot find public key\n");
return SCARD_F_INTERNAL_ERROR;
}
if (ret != SCARD_S_SUCCESS) {
logprintf(pCardData, 7, "GetContainerInfo(idx:%i) failed; error %X", bContainerIndex, ret);
return ret;
}
logprintf(pCardData, 7, "SubjectPublicKeyInfo:\n");
loghex(pCardData, 7, pubkey_der.value, pubkey_der.len);
if (pubkey_der.len && pubkey_der.value) {
sz = 0; /* get size */
CryptDecodeObject(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, RSA_CSP_PUBLICKEYBLOB,
pubkey_der.value, pubkey_der.len, 0, NULL, &sz);
if (cont->size_sign) {
PUBKEYSTRUCT_BASE *oh = (PUBKEYSTRUCT_BASE *)pCardData->pfnCspAlloc(sz);
if (!oh)
return SCARD_E_NO_MEMORY;
CryptDecodeObject(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, RSA_CSP_PUBLICKEYBLOB,
pubkey_der.value, pubkey_der.len, 0, oh, &sz);
oh->publickeystruc.aiKeyAlg = CALG_RSA_SIGN;
pContainerInfo->cbSigPublicKey = sz;
pContainerInfo->pbSigPublicKey = (PBYTE)oh;
logprintf(pCardData, 3, "return info on SIGN_CONTAINER_INDEX %i\n", bContainerIndex);
}
if (cont->size_key_exchange) {
PUBKEYSTRUCT_BASE *oh = (PUBKEYSTRUCT_BASE*)pCardData->pfnCspAlloc(sz);
if (!oh)
return SCARD_E_NO_MEMORY;
CryptDecodeObject(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, RSA_CSP_PUBLICKEYBLOB,
pubkey_der.value, pubkey_der.len, 0, oh, &sz);
oh->publickeystruc.aiKeyAlg = CALG_RSA_KEYX;
pContainerInfo->cbKeyExPublicKey = sz;
pContainerInfo->pbKeyExPublicKey = (PBYTE)oh;
logprintf(pCardData, 3, "return info on KEYX_CONTAINER_INDEX %i\n", bContainerIndex);
}
}
logprintf(pCardData, 7, "returns container(idx:%i) info", bContainerIndex);
return SCARD_S_SUCCESS;
}
DWORD WINAPI CardAuthenticatePin(__in PCARD_DATA pCardData,
__in LPWSTR pwszUserId,
__in PBYTE pbPin,
__in DWORD cbPin,
__out_opt PDWORD pcAttemptsRemaining)
{
int r, tries_left;
sc_pkcs15_object_t *pin_obj;
char type[256];
VENDOR_SPECIFIC *vs;
struct md_file *cardcf_file = NULL;
CARD_CACHE_FILE_FORMAT *cardcf = NULL;
DWORD dwret;
if(!pCardData)
return SCARD_E_INVALID_PARAMETER;
vs = (VENDOR_SPECIFIC*)(pCardData->pvVendorSpecific);
logprintf(pCardData, 1, "\nP:%d T:%d pCardData:%p ",GetCurrentProcessId(), GetCurrentThreadId(), pCardData);
logprintf(pCardData, 1, "CardAuthenticatePin '%S':%d\n", NULLWSTR(pwszUserId), cbPin);
check_reader_status(pCardData);
dwret = md_get_cardcf(pCardData, &cardcf);
if (dwret != SCARD_S_SUCCESS)
return dwret;
if (NULL == pwszUserId)
return SCARD_E_INVALID_PARAMETER;
if (wcscmp(wszCARD_USER_USER,pwszUserId) != 0 && wcscmp(wszCARD_USER_ADMIN,pwszUserId) != 0)
return SCARD_E_INVALID_PARAMETER;
if (NULL == pbPin)
return SCARD_E_INVALID_PARAMETER;
if (cbPin < 4 || cbPin > 12)
return SCARD_W_WRONG_CHV;
if (wcscmp(wszCARD_USER_ADMIN,pwszUserId) == 0)
return SCARD_W_WRONG_CHV;
wcstombs(type, pwszUserId, 100);
type[10] = 0;
logprintf(pCardData, 1, "CardAuthenticatePin %.20s, %d, %d\n", NULLSTR(type),
cbPin, (pcAttemptsRemaining==NULL?-2:*pcAttemptsRemaining));
r = md_get_pin_by_role(pCardData, ROLE_USER, &pin_obj);
if (r != SCARD_S_SUCCESS) {
logprintf(pCardData, 2, "Cannot get User PIN object");
return r;
}
r = sc_pkcs15_verify_pin(vs->p15card, pin_obj, (const u8 *) pbPin, cbPin);
if (r) {
logprintf(pCardData, 1, "PIN code verification failed: %s\n", sc_strerror(r));
tries_left = ((struct sc_pkcs15_auth_info *)pin_obj->data)->tries_left;
if (r == SC_ERROR_AUTH_METHOD_BLOCKED)
return SCARD_W_CHV_BLOCKED;
if(pcAttemptsRemaining)
(*pcAttemptsRemaining) = tries_left;
return SCARD_W_WRONG_CHV;
}
logprintf(pCardData, 3, "Pin code correct.\n");
SET_PIN(cardcf->bPinsFreshness, ROLE_USER);
logprintf(pCardData, 3, "PinsFreshness = %d\n", cardcf->bPinsFreshness);
return SCARD_S_SUCCESS;
}
DWORD WINAPI CardGetChallenge(__in PCARD_DATA pCardData,
__deref_out_bcount(*pcbChallengeData) PBYTE *ppbChallengeData,
__out PDWORD pcbChallengeData)
{
logprintf(pCardData, 1, "\nP:%d T:%d pCardData:%p ",GetCurrentProcessId(), GetCurrentThreadId(), pCardData);
logprintf(pCardData, 1, "CardGetChallenge - unsupported\n");
return SCARD_E_UNSUPPORTED_FEATURE;
}
DWORD WINAPI CardAuthenticateChallenge(__in PCARD_DATA pCardData,
__in_bcount(cbResponseData) PBYTE pbResponseData,
__in DWORD cbResponseData,
__out_opt PDWORD pcAttemptsRemaining)
{
logprintf(pCardData, 1, "\nP:%d T:%d pCardData:%p ",GetCurrentProcessId(), GetCurrentThreadId(), pCardData);
logprintf(pCardData, 1, "CardAuthenticateChallenge - unsupported\n");
return SCARD_E_UNSUPPORTED_FEATURE;
}
DWORD WINAPI CardUnblockPin(__in PCARD_DATA pCardData,
__in LPWSTR pwszUserId,
__in_bcount(cbAuthenticationData) PBYTE pbAuthenticationData,
__in DWORD cbAuthenticationData,
__in_bcount(cbNewPinData) PBYTE pbNewPinData,
__in DWORD cbNewPinData,
__in DWORD cRetryCount,
__in DWORD dwFlags)
{
logprintf(pCardData, 1, "\nP:%d T:%d pCardData:%p ",GetCurrentProcessId(), GetCurrentThreadId(), pCardData);
logprintf(pCardData, 1, "CardUnblockPin - unsupported\n");
return SCARD_E_UNSUPPORTED_FEATURE;
}
DWORD WINAPI CardChangeAuthenticator(__in PCARD_DATA pCardData,
__in LPWSTR pwszUserId,
__in_bcount(cbCurrentAuthenticator) PBYTE pbCurrentAuthenticator,
__in DWORD cbCurrentAuthenticator,
__in_bcount(cbNewAuthenticator) PBYTE pbNewAuthenticator,
__in DWORD cbNewAuthenticator,
__in DWORD cRetryCount,
__in DWORD dwFlags,
__out_opt PDWORD pcAttemptsRemaining)
{
logprintf(pCardData, 1, "\nP:%d T:%d pCardData:%p ",GetCurrentProcessId(), GetCurrentThreadId(), pCardData);
logprintf(pCardData, 1, "CardChangeAuthenticator - unsupported\n");
return SCARD_E_UNSUPPORTED_FEATURE;
}
DWORD WINAPI CardDeauthenticate(__in PCARD_DATA pCardData,
__in LPWSTR pwszUserId,
__in DWORD dwFlags)
{
VENDOR_SPECIFIC *vs;
CARD_CACHE_FILE_FORMAT *cardcf = NULL;
struct md_file *cmapfile = NULL;
DWORD dwret;
logprintf(pCardData, 1, "\nP:%d T:%d pCardData:%p ",GetCurrentProcessId(), GetCurrentThreadId(), pCardData);
logprintf(pCardData, 1, "CardDeauthenticate(%S) %d\n", NULLWSTR(pwszUserId), dwFlags);
if(!pCardData)
return SCARD_E_INVALID_PARAMETER;
vs = (VENDOR_SPECIFIC*)(pCardData->pvVendorSpecific);
check_reader_status(pCardData);
dwret = md_get_cardcf(pCardData, &cardcf);
if (dwret != SCARD_S_SUCCESS)
return dwret;
logprintf(pCardData, 1, "CardDeauthenticate bPinsFreshness:%d\n", cardcf->bPinsFreshness);
if (!wcscmp(pwszUserId, wszCARD_USER_USER))
CLEAR_PIN(cardcf->bPinsFreshness, ROLE_USER);
else if (!wcscmp(pwszUserId, wszCARD_USER_ADMIN))
CLEAR_PIN(cardcf->bPinsFreshness, ROLE_ADMIN);
else
return SCARD_E_INVALID_PARAMETER;
logprintf(pCardData, 5, "PinsFreshness = %d\n", cardcf->bPinsFreshness);
/* TODO Reset PKCS#15 PIN object 'validated' flag */
return SCARD_S_SUCCESS;
}
DWORD WINAPI CardCreateDirectory(__in PCARD_DATA pCardData,
__in LPSTR pszDirectoryName,
__in CARD_DIRECTORY_ACCESS_CONDITION AccessCondition)
{
logprintf(pCardData, 1, "\nP:%d T:%d pCardData:%p ",GetCurrentProcessId(), GetCurrentThreadId(), pCardData);
logprintf(pCardData, 1, "CardCreateDirectory - unsupported\n");
return SCARD_E_UNSUPPORTED_FEATURE;
}
DWORD WINAPI CardDeleteDirectory(__in PCARD_DATA pCardData,
__in LPSTR pszDirectoryName)
{
logprintf(pCardData, 1, "\nP:%d T:%d pCardData:%p ",GetCurrentProcessId(), GetCurrentThreadId(), pCardData);
logprintf(pCardData, 1, "CardDeleteDirectory(%s) - unsupported\n", NULLSTR(pszDirectoryName));
return SCARD_E_UNSUPPORTED_FEATURE;
}
DWORD WINAPI CardCreateFile(__in PCARD_DATA pCardData,
__in LPSTR pszDirectoryName,
__in LPSTR pszFileName,
__in DWORD cbInitialCreationSize,
__in CARD_FILE_ACCESS_CONDITION AccessCondition)
{
struct md_directory *dir = NULL;
DWORD dwret;
logprintf(pCardData, 1, "\nP:%d T:%d pCardData:%p ",GetCurrentProcessId(), GetCurrentThreadId(), pCardData);
logprintf(pCardData, 1, "CardCreateFile(%s::%s, size %i, acl:0x%X) called\n",
NULLSTR(pszDirectoryName), NULLSTR(pszFileName), cbInitialCreationSize, AccessCondition);
dwret = md_fs_find_directory(pCardData, NULL, pszDirectoryName, &dir);
if (dwret != SCARD_S_SUCCESS) {
logprintf(pCardData, 1, "CardCreateFile() cannot find parent directory '%s'", NULLSTR(pszDirectoryName));
return dwret;
}
dwret = md_fs_add_file(pCardData, &dir->files, pszFileName, AccessCondition, NULL, cbInitialCreationSize, NULL);
if (dwret != SCARD_S_SUCCESS)
return dwret;
return SCARD_S_SUCCESS;
}
DWORD WINAPI CardReadFile(__in PCARD_DATA pCardData,
__in LPSTR pszDirectoryName,
__in LPSTR pszFileName,
__in DWORD dwFlags,
__deref_out_bcount(*pcbData) PBYTE *ppbData,
__out PDWORD pcbData)
{
VENDOR_SPECIFIC *vs;
struct md_directory *dir = NULL;
struct md_file *file = NULL;
logprintf(pCardData, 1, "\nP:%d T:%d pCardData:%p ",GetCurrentProcessId(), GetCurrentThreadId(), pCardData);
logprintf(pCardData, 1, "CardReadFile\n");
if(!pCardData)
return SCARD_E_INVALID_PARAMETER;
if (!ppbData || !pcbData)
return SCARD_E_INVALID_PARAMETER;
vs = (VENDOR_SPECIFIC*)(pCardData->pvVendorSpecific);
logprintf(pCardData, 2, "pszDirectoryName = %s, pszFileName = %s, dwFlags = %X, pcbData=%d, *ppbData=%X\n",
NULLSTR(pszDirectoryName), NULLSTR(pszFileName), dwFlags, *pcbData, *ppbData);
if (!pszFileName || !strlen(pszFileName))
return SCARD_E_INVALID_PARAMETER;
if (dwFlags)
return SCARD_E_INVALID_PARAMETER;
check_reader_status(pCardData);
md_fs_find_file(pCardData, pszDirectoryName, pszFileName, &file);
if (!file) {
logprintf(pCardData, 2, "CardReadFile(): file '%s' not found in '%s'\n", NULLSTR(pszFileName), NULLSTR(pszDirectoryName));
return SCARD_E_FILE_NOT_FOUND;
}
if (!file->blob)
md_fs_read_content(pCardData, pszDirectoryName, file);
*ppbData = pCardData->pfnCspAlloc(file->size);
if(!*ppbData)
return SCARD_E_NO_MEMORY;
*pcbData = file->size;
memcpy(*ppbData, file->blob, file->size);
logprintf(pCardData, 7, "returns '%s' content:\n", NULLSTR(pszFileName));
loghex(pCardData, 7, *ppbData, *pcbData);
return SCARD_S_SUCCESS;
}
DWORD WINAPI CardWriteFile(__in PCARD_DATA pCardData,
__in LPSTR pszDirectoryName,
__in LPSTR pszFileName,
__in DWORD dwFlags,
__in_bcount(cbData) PBYTE pbData,
__in DWORD cbData)
{
struct md_file *file = NULL;
DWORD dwret;
if(!pCardData)
return SCARD_E_INVALID_PARAMETER;
logprintf(pCardData, 1, "\nP:%d T:%d pCardData:%p ",GetCurrentProcessId(), GetCurrentThreadId(), pCardData);
logprintf(pCardData, 1, "CardWriteFile() dirName:'%s', fileName:'%s' \n", NULLSTR(pszDirectoryName), NULLSTR(pszFileName));
check_reader_status(pCardData);
if (pbData && cbData) {
logprintf(pCardData, 1, "CardWriteFile try to write (%i):\n", cbData);
loghex(pCardData, 2, pbData, cbData);
}
md_fs_find_file(pCardData, pszDirectoryName, pszFileName, &file);
if (!file) {
logprintf(pCardData, 2, "CardWriteFile(): file '%s' not found in '%s'\n", NULLSTR(pszFileName), NULLSTR(pszDirectoryName));
return SCARD_E_FILE_NOT_FOUND;
}
logprintf(pCardData, 7, "set content of '%s' to:\n", NULLSTR(pszFileName));
loghex(pCardData, 7, pbData, cbData);
dwret = md_fs_set_content(pCardData, file, pbData, cbData);
if (dwret != SCARD_S_SUCCESS) {
logprintf(pCardData, 1, "cannot set file content: %li\n", dwret);
return dwret;
}
if (pszDirectoryName && !strcmp(pszDirectoryName, "mscp")) {
if (strlen(pszFileName) == 5 &&
(strstr(pszFileName, "kxc") == pszFileName || strstr(pszFileName, "ksc") == pszFileName)) {
dwret = md_pkcs15_store_certificate(pCardData, pszFileName, pbData, cbData);
if (dwret != SCARD_S_SUCCESS)
return dwret;
logprintf(pCardData, 2, "md_pkcs15_store_certificate() OK\n");
}
}
logprintf(pCardData, 2, "write '%s' ok.\n", NULLSTR(pszFileName));
return SCARD_S_SUCCESS;
}
DWORD WINAPI CardDeleteFile(__in PCARD_DATA pCardData,
__in LPSTR pszDirectoryName,
__in LPSTR pszFileName,
__in DWORD dwFlags)
{
struct md_file *file = NULL;
DWORD dwret;
logprintf(pCardData, 1, "\nP:%d T:%d pCardData:%p ",GetCurrentProcessId(), GetCurrentThreadId(), pCardData);
logprintf(pCardData, 1, "CardDeleteFile(%s, %s) called\n", NULLSTR(pszDirectoryName), NULLSTR(pszFileName));
if(!pCardData)
return SCARD_E_INVALID_PARAMETER;
check_reader_status(pCardData);
dwret = md_fs_delete_file(pCardData, pszDirectoryName, pszFileName);
if (dwret != SCARD_S_SUCCESS) {
logprintf(pCardData, 2, "CardDeleteFile(): delete file error: %X\n", dwret);
return dwret;
}
return SCARD_S_SUCCESS;
}
DWORD WINAPI CardEnumFiles(__in PCARD_DATA pCardData,
__in LPSTR pszDirectoryName,
__out_ecount(*pdwcbFileName) LPSTR *pmszFileNames,
__out LPDWORD pdwcbFileName,
__in DWORD dwFlags)
{
VENDOR_SPECIFIC *vs = NULL;
char mstr[0x100];
struct md_directory *dir = NULL;
struct md_file *file = NULL;
size_t offs;
logprintf(pCardData, 1, "\nP:%d T:%d pCardData:%p ",GetCurrentProcessId(), GetCurrentThreadId(), pCardData);
logprintf(pCardData, 1, "CardEnumFiles() directory '%s'\n", NULLSTR(pszDirectoryName));
if (!pCardData)
return SCARD_E_INVALID_PARAMETER;
if (!pmszFileNames || !pdwcbFileName)
return SCARD_E_INVALID_PARAMETER;
if (dwFlags) {
logprintf(pCardData, 1, "CardEnumFiles() dwFlags not 'zero' -- %X\n", dwFlags);
return SCARD_E_INVALID_PARAMETER;
}
vs = (VENDOR_SPECIFIC*)(pCardData->pvVendorSpecific);
memset(mstr, 0, sizeof(mstr));
if (!pszDirectoryName || !strlen(pszDirectoryName))
dir = &vs->root;
else
md_fs_find_directory(pCardData, NULL, pszDirectoryName, &dir);
if (!dir) {
logprintf(pCardData, 2, "enum files() failed: directory '%s' not found\n", NULLSTR(pszDirectoryName));
return SCARD_E_FILE_NOT_FOUND;
}
file = dir->files;
for (offs = 0; file != NULL && offs < sizeof(mstr) - 10;) {
logprintf(pCardData, 2, "enum files(): file name '%s'\n", file->name);
strcpy(mstr+offs, file->name);
offs += strlen(file->name) + 1;
file = file->next;
}
offs += 1;
*pmszFileNames = (LPSTR)(*pCardData->pfnCspAlloc)(offs);
if (*pmszFileNames == NULL)
return SCARD_E_NO_MEMORY;
CopyMemory(*pmszFileNames, mstr, offs);
*pdwcbFileName = offs;
return SCARD_S_SUCCESS;
}
DWORD WINAPI CardGetFileInfo(__in PCARD_DATA pCardData,
__in LPSTR pszDirectoryName,
__in LPSTR pszFileName,
__in PCARD_FILE_INFO pCardFileInfo)
{
VENDOR_SPECIFIC *vs = NULL;
struct md_directory *dir = NULL;
struct md_file *file = NULL;
logprintf(pCardData, 1, "\nP:%d T:%d pCardData:%p ",GetCurrentProcessId(), GetCurrentThreadId(), pCardData);
logprintf(pCardData, 1, "CardGetFileInfo(dirName:'%s',fileName:'%s', out %p)\n", NULLSTR(pszDirectoryName), NULLSTR(pszFileName), pCardFileInfo);
vs = (VENDOR_SPECIFIC*)(pCardData->pvVendorSpecific);
md_fs_find_file(pCardData, pszDirectoryName, pszFileName, &file);
if (!file) {
logprintf(pCardData, 2, "CardWriteFile(): file '%s' not found in '%s'\n", NULLSTR(pszFileName), NULLSTR(pszDirectoryName));
return SCARD_E_FILE_NOT_FOUND;
}
pCardFileInfo->dwVersion = CARD_FILE_INFO_CURRENT_VERSION;
pCardFileInfo->cbFileSize = file->size;
pCardFileInfo->AccessCondition = file->acl;
return SCARD_S_SUCCESS;
}
DWORD WINAPI CardQueryFreeSpace(__in PCARD_DATA pCardData, __in DWORD dwFlags,
__in PCARD_FREE_SPACE_INFO pCardFreeSpaceInfo)
{
VENDOR_SPECIFIC *vs;
DWORD dwret;
logprintf(pCardData, 1, "\nP:%d T:%d pCardData:%p ",GetCurrentProcessId(), GetCurrentThreadId(), pCardData);
logprintf(pCardData, 1, "CardQueryFreeSpace %p, dwFlags=%X, version=%X\n",
pCardFreeSpaceInfo, dwFlags, pCardFreeSpaceInfo->dwVersion);
if (!pCardData)
return SCARD_E_INVALID_PARAMETER;
vs = (VENDOR_SPECIFIC*)(pCardData->pvVendorSpecific);
check_reader_status(pCardData);
dwret = md_free_space(pCardData, pCardFreeSpaceInfo);
if (dwret != SCARD_S_SUCCESS) {
logprintf(pCardData, 1, "CardQueryFreeSpace() md free space error");
return dwret;
}
logprintf(pCardData, 7, "FreeSpace:\n");
loghex(pCardData, 7, (BYTE *)pCardFreeSpaceInfo, sizeof(*pCardFreeSpaceInfo));
return SCARD_S_SUCCESS;
}
DWORD WINAPI CardQueryKeySizes(__in PCARD_DATA pCardData,
__in DWORD dwKeySpec,
__in DWORD dwFlags,
__out PCARD_KEY_SIZES pKeySizes)
{
DWORD dwret;
logprintf(pCardData, 1, "\nP:%d T:%d pCardData:%p ",GetCurrentProcessId(), GetCurrentThreadId(), pCardData);
logprintf(pCardData, 1, "CardQueryKeySizes dwKeySpec=%X, dwFlags=%X, version=%X\n", dwKeySpec, dwFlags, pKeySizes->dwVersion);
if (!pCardData)
return SCARD_E_INVALID_PARAMETER;
dwret = md_query_key_sizes(pKeySizes);
if (dwret != SCARD_S_SUCCESS)
return dwret;
logprintf(pCardData, 7, "pKeySizes:\n");
loghex(pCardData, 7, (BYTE *)pKeySizes, sizeof(*pKeySizes));
return SCARD_S_SUCCESS;
}
DWORD WINAPI CardRSADecrypt(__in PCARD_DATA pCardData,
__inout PCARD_RSA_DECRYPT_INFO pInfo)
{
int r, opt_crypt_flags = 0;
unsigned ui;
VENDOR_SPECIFIC *vs;
struct sc_pkcs15_prkey_info *prkey_info;
BYTE *pbuf = NULL, *pbuf2 = NULL;
DWORD lg= 0, lg2 = 0;
struct sc_pkcs15_object *pkey = NULL;
struct sc_algorithm_info *alg_info = NULL;
logprintf(pCardData, 1, "\nP:%d T:%d pCardData:%p ",GetCurrentProcessId(), GetCurrentThreadId(), pCardData);
logprintf(pCardData, 1, "CardRSADecrypt\n");
if (!pCardData)
return SCARD_E_INVALID_PARAMETER;
if (!pInfo)
return SCARD_E_INVALID_PARAMETER;
vs = (VENDOR_SPECIFIC*)(pCardData->pvVendorSpecific);
check_reader_status(pCardData);
logprintf(pCardData, 2, "CardRSADecrypt dwVersion=%u, bContainerIndex=%u,dwKeySpec=%u pbData=%p, cbData=%u\n",
pInfo->dwVersion,pInfo->bContainerIndex ,pInfo->dwKeySpec, pInfo->pbData, pInfo->cbData);
if (pInfo->dwVersion >= CARD_RSA_KEY_DECRYPT_INFO_VERSION_TWO)
logprintf(pCardData, 2, " pPaddingInfo=%p dwPaddingType=0x%08X\n", pInfo->pPaddingInfo, pInfo->dwPaddingType);
pkey = vs->p15_containers[pInfo->bContainerIndex].prkey_obj;
if (!pkey) {
logprintf(pCardData, 2, "CardRSADecrypt prkey not found\n");
return SCARD_E_INVALID_PARAMETER;
}
/* input and output buffers are always the same size */
pbuf = pCardData->pfnCspAlloc(pInfo->cbData);
if (!pbuf)
return SCARD_E_NO_MEMORY;
lg2 = pInfo->cbData;
pbuf2 = pCardData->pfnCspAlloc(pInfo->cbData);
if (!pbuf2)
return SCARD_E_NO_MEMORY;
/*inversion donnees*/
for(ui = 0; ui < pInfo->cbData; ui++)
pbuf[ui] = pInfo->pbData[pInfo->cbData-ui-1];
logprintf(pCardData, 2, "Data to be decrypted (inverted):\n");
loghex(pCardData, 7, pbuf, pInfo->cbData);
prkey_info = (struct sc_pkcs15_prkey_info *)(pkey->data);
alg_info = sc_card_find_rsa_alg(vs->p15card->card, prkey_info->modulus_length);
if (!alg_info) {
logprintf(pCardData, 2, "Cannot get appropriate RSA card algorithm for key size %i\n", prkey_info->modulus_length);
return SCARD_F_INTERNAL_ERROR;
}
if (alg_info->flags & SC_ALGORITHM_RSA_RAW) {
logprintf(pCardData, 2, "sc_pkcs15_decipher: using RSA-RAW mechanism\n");
r = sc_pkcs15_decipher(vs->p15card, pkey, opt_crypt_flags, pbuf, pInfo->cbData, pbuf2, pInfo->cbData);
if (r < 0) {
logprintf(pCardData, 2, "PKCS#15 decipher failed: %i\n", r);
return SCARD_F_INTERNAL_ERROR;
}
logprintf(pCardData, 2, "sc_pkcs15_decipher returned %d\n", r);
// Need to handle padding
if (pInfo->dwVersion >= CARD_RSA_KEY_DECRYPT_INFO_VERSION_TWO) {
logprintf(pCardData, 2, "sc_pkcs15_decipher: DECRYPT-INFO dwVersion=%u\n", pInfo->dwVersion);
if (pInfo->dwPaddingType == CARD_PADDING_PKCS1) {
logprintf(pCardData, 2, "sc_pkcs15_decipher: stripping PKCS1 padding\n");
r = sc_pkcs1_strip_02_padding(vs->ctx, pbuf2, pInfo->cbData, pbuf2, &pInfo->cbData);
if (r < 0) {
logprintf(pCardData, 2, "Cannot strip PKCS1 padding: %i\n", r);
return SCARD_F_INTERNAL_ERROR;
}
}
else if (pInfo->dwPaddingType == CARD_PADDING_OAEP) {
/* TODO: Handle OAEP padding if present - can call PFN_CSP_UNPAD_DATA */
logprintf(pCardData, 2, "OAEP padding not implemented\n");
return SCARD_F_INTERNAL_ERROR;
}
}
}
else if (alg_info->flags & SC_ALGORITHM_RSA_PAD_PKCS1) {
logprintf(pCardData, 2, "sc_pkcs15_decipher: using RSA_PAD_PKCS1 mechanism\n");
r = sc_pkcs15_decipher(vs->p15card, pkey, opt_crypt_flags | SC_ALGORITHM_RSA_PAD_PKCS1,
pbuf, pInfo->cbData, pbuf2, pInfo->cbData);
logprintf(pCardData, 2, "sc_pkcs15_decipher returned %d\n", r);
if (r > 0) {
// No padding info, or padding info none
if ((pInfo->dwVersion < CARD_RSA_KEY_DECRYPT_INFO_VERSION_TWO) ||
((pInfo->dwVersion >= CARD_RSA_KEY_DECRYPT_INFO_VERSION_TWO) &&
(pInfo->dwPaddingType == CARD_PADDING_NONE))) {
if ((unsigned)r <= pInfo->cbData - 9) {
/* add pkcs1 02 padding */
logprintf(pCardData, 2, "Add '%s' to the output data", "PKCS#1 BT02 padding");
memset(pbuf, 0x30, pInfo->cbData);
*(pbuf + 0) = 0;
*(pbuf + 1) = 2;
memcpy(pbuf + pInfo->cbData - r, pbuf2, r);
*(pbuf + pInfo->cbData - r - 1) = 0;
memcpy(pbuf2, pbuf, pInfo->cbData);
}
}
else if (pInfo->dwPaddingType == CARD_PADDING_PKCS1) {
// PKCS1 padding is already handled by the card...
pInfo->cbData = r;
}
/* TODO: Handle OAEP padding if present - can call PFN_CSP_UNPAD_DATA */
}
}
else {
logprintf(pCardData, 2, "CardRSADecrypt: no usable RSA algorithm\n");
return SCARD_E_INVALID_PARAMETER;
}
if ( r < 0) {
logprintf(pCardData, 2, "sc_pkcs15_decipher error(%i): %s\n", r, sc_strerror(r));
return SCARD_E_INVALID_VALUE;
}
logprintf(pCardData, 2, "decrypted data(%i):\n", pInfo->cbData);
loghex(pCardData, 7, pbuf2, pInfo->cbData);
/*inversion donnees */
for(ui = 0; ui < pInfo->cbData; ui++)
pInfo->pbData[ui] = pbuf2[pInfo->cbData-ui-1];
pCardData->pfnCspFree(pbuf);
pCardData->pfnCspFree(pbuf2);
return SCARD_S_SUCCESS;
}
DWORD WINAPI CardSignData(__in PCARD_DATA pCardData, __in PCARD_SIGNING_INFO pInfo)
{
VENDOR_SPECIFIC *vs;
ALG_ID hashAlg;
sc_pkcs15_prkey_info_t *prkey_info;
BYTE dataToSign[0x200];
int r, opt_crypt_flags = 0, opt_hash_flags = 0;
size_t dataToSignLen = sizeof(dataToSign);
sc_pkcs15_object_t *pkey;
logprintf(pCardData, 1, "\nP:%d T:%d pCardData:%p ",GetCurrentProcessId(), GetCurrentThreadId(), pCardData);
logprintf(pCardData, 1, "CardSignData\n");
if (!pCardData || !pInfo)
return SCARD_E_INVALID_PARAMETER;
logprintf(pCardData, 2, "CardSignData dwVersion=%u, bContainerIndex=%u, dwKeySpec=%u, dwSigningFlags=0x%08X, aiHashAlg=0x%08X\n",
pInfo->dwVersion,pInfo->bContainerIndex ,pInfo->dwKeySpec, pInfo->dwSigningFlags, pInfo->aiHashAlg);
logprintf(pCardData, 7, "pInfo->pbData(%i) ", pInfo->cbData);
loghex(pCardData, 7, pInfo->pbData, pInfo->cbData);
hashAlg = pInfo->aiHashAlg;
vs = (VENDOR_SPECIFIC*)(pCardData->pvVendorSpecific);
if (pInfo->bContainerIndex >= MD_MAX_KEY_CONTAINERS)
return SCARD_E_NO_KEY_CONTAINER;
pkey = vs->p15_containers[pInfo->bContainerIndex].prkey_obj;
if (!pkey)
return SCARD_E_NO_KEY_CONTAINER;
prkey_info = (struct sc_pkcs15_prkey_info *)(pkey->data);
check_reader_status(pCardData);
logprintf(pCardData, 2, "pInfo->dwVersion = %d\n", pInfo->dwVersion);
if (dataToSignLen < pInfo->cbData)
return SCARD_E_INSUFFICIENT_BUFFER;
memcpy(dataToSign, pInfo->pbData, pInfo->cbData);
dataToSignLen = pInfo->cbData;
if (CARD_PADDING_INFO_PRESENT & pInfo->dwSigningFlags) {
BCRYPT_PKCS1_PADDING_INFO *pinf = (BCRYPT_PKCS1_PADDING_INFO *)pInfo->pPaddingInfo;
if (CARD_PADDING_PKCS1 != pInfo->dwPaddingType) {
logprintf(pCardData, 0, "unsupported paddingtype\n");
return SCARD_E_UNSUPPORTED_FEATURE;
}
if (!pinf->pszAlgId) {
/* hashAlg = CALG_SSL3_SHAMD5; */
logprintf(pCardData, 3, "Using CALG_SSL3_SHAMD5 hashAlg\n");
opt_hash_flags = SC_ALGORITHM_RSA_HASH_MD5_SHA1;
}
else {
if (wcscmp(pinf->pszAlgId, L"MD5") == 0)
opt_hash_flags = SC_ALGORITHM_RSA_HASH_MD5;
else if (wcscmp(pinf->pszAlgId, L"SHA1") == 0)
opt_hash_flags = SC_ALGORITHM_RSA_HASH_SHA1;
else if (wcscmp(pinf->pszAlgId, L"SHAMD5") == 0)
opt_hash_flags = SC_ALGORITHM_RSA_HASH_MD5_SHA1;
else if (wcscmp(pinf->pszAlgId, L"SHA256") == 0)
opt_hash_flags = SC_ALGORITHM_RSA_HASH_SHA256;
else
{
logprintf(pCardData, 0,"unknown AlgId %S\n",NULLWSTR(pinf->pszAlgId));
return SCARD_E_UNSUPPORTED_FEATURE;
}
}
}
else {
logprintf(pCardData, 3, "CARD_PADDING_INFO_PRESENT not set\n");
if (GET_ALG_CLASS(hashAlg) != ALG_CLASS_HASH) {
logprintf(pCardData, 0, "bogus aiHashAlg\n");
return SCARD_E_INVALID_PARAMETER;
}
if (hashAlg == CALG_MD5)
opt_hash_flags = SC_ALGORITHM_RSA_HASH_MD5;
else if (hashAlg == CALG_SHA1)
opt_hash_flags = SC_ALGORITHM_RSA_HASH_SHA1;
else if (hashAlg == CALG_SSL3_SHAMD5)
opt_hash_flags = SC_ALGORITHM_RSA_HASH_MD5_SHA1;
else if (hashAlg == CALG_SHA_256)
opt_hash_flags = SC_ALGORITHM_RSA_HASH_SHA256;
else if (hashAlg !=0)
return SCARD_E_UNSUPPORTED_FEATURE;
}
/* From sc-minidriver_specs_v7.docx pp.76:
* 'The Base CSP/KSP performs the hashing operation on the data before passing it
* to CardSignData for signature.'
* So, the SC_ALGORITHM_RSA_HASH_* flags should not be passed to pkcs15 library
* when calculating the signature .
*
* From sc-minidriver_specs_v7.docx pp.76:
* 'If the aiHashAlg member is nonzero, it specifies the hash algorithms object identifier (OID)
* that is encoded in the PKCS padding.'
* So, the digest info has be included into the data to be signed.
* */
if (opt_hash_flags) {
logprintf(pCardData, 2, "include digest info of the algorithm 0x%08X\n", opt_hash_flags);
dataToSignLen = sizeof(dataToSign);
r = sc_pkcs1_encode(vs->ctx, opt_hash_flags, pInfo->pbData, pInfo->cbData, dataToSign, &dataToSignLen, 0);
if (r) {
logprintf(pCardData, 2, "PKCS#1 encode error %s\n", sc_strerror(r));
return SCARD_E_INVALID_VALUE;
}
}
opt_crypt_flags = SC_ALGORITHM_RSA_PAD_PKCS1 | SC_ALGORITHM_RSA_HASH_NONE;
pInfo->cbSignedData = prkey_info->modulus_length / 8;
logprintf(pCardData, 3, "pInfo->cbSignedData = %d\n", pInfo->cbSignedData);
if(!(pInfo->dwSigningFlags&CARD_BUFFER_SIZE_ONLY)) {
int r,i;
BYTE *pbuf = NULL;
DWORD lg;
lg = pInfo->cbSignedData;
logprintf(pCardData, 3, "lg = %d\n", lg);
pbuf = pCardData->pfnCspAlloc(lg);
if (!pbuf)
return SCARD_E_NO_MEMORY;
logprintf(pCardData, 7, "Data to sign: ");
loghex(pCardData, 7, dataToSign, dataToSignLen);
pInfo->pbSignedData = pCardData->pfnCspAlloc(pInfo->cbSignedData);
if (!pInfo->pbSignedData) {
pCardData->pfnCspFree(pbuf);
return SCARD_E_NO_MEMORY;
}
r = sc_pkcs15_compute_signature(vs->p15card, pkey, opt_crypt_flags, dataToSign, dataToSignLen, pbuf, lg);
logprintf(pCardData, 2, "sc_pkcs15_compute_signature return %d\n", r);
if(r < 0) {
logprintf(pCardData, 2, "sc_pkcs15_compute_signature erreur %s\n", sc_strerror(r));
return SCARD_F_INTERNAL_ERROR;
}
pInfo->cbSignedData = r;
/*inversion donnees*/
for(i = 0; i < r; i++)
pInfo->pbSignedData[i] = pbuf[r-i-1];
pCardData->pfnCspFree(pbuf);
logprintf(pCardData, 7, "Signature (inverted): ");
loghex(pCardData, 7, pInfo->pbSignedData, pInfo->cbSignedData);
}
logprintf(pCardData, 3, "CardSignData, dwVersion=%u, name=%S, hScard=0x%08X, hSCardCtx=0x%08X\n",
pCardData->dwVersion, NULLWSTR(pCardData->pwszCardName),pCardData->hScard, pCardData->hSCardCtx);
return SCARD_S_SUCCESS;
}
DWORD WINAPI CardConstructDHAgreement(__in PCARD_DATA pCardData,
__in PCARD_DH_AGREEMENT_INFO pAgreementInfo)
{
logprintf(pCardData, 1, "\nP:%d T:%d pCardData:%p ",GetCurrentProcessId(), GetCurrentThreadId(), pCardData);
logprintf(pCardData, 1, "CardConstructDHAgreement - unsupported\n");
return SCARD_E_UNSUPPORTED_FEATURE;
}
DWORD WINAPI CardDeriveKey(__in PCARD_DATA pCardData,
__in PCARD_DERIVE_KEY pAgreementInfo)
{
logprintf(pCardData, 1, "\nP:%d T:%d pCardData:%p ",GetCurrentProcessId(), GetCurrentThreadId(), pCardData);
logprintf(pCardData, 1, "CardDeriveKey - unsupported\n");
return SCARD_E_UNSUPPORTED_FEATURE;
}
DWORD WINAPI CardDestroyDHAgreement(
__in PCARD_DATA pCardData,
__in BYTE bSecretAgreementIndex,
__in DWORD dwFlags)
{
logprintf(pCardData, 1, "CardDestroyDHAgreement - unsupported\n");
return SCARD_E_UNSUPPORTED_FEATURE;
}
DWORD WINAPI CspGetDHAgreement(__in PCARD_DATA pCardData,
__in PVOID hSecretAgreement,
__out BYTE* pbSecretAgreementIndex,
__in DWORD dwFlags)
{
logprintf(pCardData, 1, "\nP:%d T:%d pCardData:%p ",GetCurrentProcessId(), GetCurrentThreadId(), pCardData);
logprintf(pCardData, 1, "CspGetDHAgreement - unsupported\n");
return SCARD_E_UNSUPPORTED_FEATURE;
}
DWORD WINAPI CardGetChallengeEx(__in PCARD_DATA pCardData,
__in PIN_ID PinId,
__deref_out_bcount(*pcbChallengeData) PBYTE *ppbChallengeData,
__out PDWORD pcbChallengeData,
__in DWORD dwFlags)
{
logprintf(pCardData, 1, "\nP:%d T:%d pCardData:%p ",GetCurrentProcessId(), GetCurrentThreadId(), pCardData);
logprintf(pCardData, 1, "CardGetChallengeEx - unsupported\n");
return SCARD_E_UNSUPPORTED_FEATURE;
}
DWORD WINAPI CardAuthenticateEx(__in PCARD_DATA pCardData,
__in PIN_ID PinId,
__in DWORD dwFlags,
__in PBYTE pbPinData,
__in DWORD cbPinData,
__deref_out_bcount_opt(*pcbSessionPin) PBYTE *ppbSessionPin,
__out_opt PDWORD pcbSessionPin,
__out_opt PDWORD pcAttemptsRemaining)
{
int r, tries_left;
VENDOR_SPECIFIC *vs;
CARD_CACHE_FILE_FORMAT *cardcf = NULL;
DWORD dwret;
sc_pkcs15_object_t *pin_obj = NULL;
logprintf(pCardData, 1, "\nP:%d T:%d pCardData:%p ",GetCurrentProcessId(), GetCurrentThreadId(), pCardData);
logprintf(pCardData, 1, "CardAuthenticateEx\n");
if (!pCardData)
return SCARD_E_INVALID_PARAMETER;
logprintf(pCardData, 2, "CardAuthenticateEx: PinId=%u, dwFlags=0x%08X, cbPinData=%u, Attempts %s\n",
PinId,dwFlags,cbPinData,pcAttemptsRemaining ? "YES" : "NO");
vs = (VENDOR_SPECIFIC*)(pCardData->pvVendorSpecific);
check_reader_status(pCardData);
if (dwFlags == CARD_AUTHENTICATE_GENERATE_SESSION_PIN || dwFlags == CARD_AUTHENTICATE_SESSION_PIN) {
if (! (vs->reader->capabilities & SC_READER_CAP_PIN_PAD))
return SCARD_E_UNSUPPORTED_FEATURE;
}
if (dwFlags && (dwFlags & CARD_PIN_SILENT_CONTEXT) && NULL == pbPinData)
return SCARD_E_INVALID_PARAMETER;
if (!(vs->reader->capabilities & SC_READER_CAP_PIN_PAD) && NULL == pbPinData)
return SCARD_E_INVALID_PARAMETER;
if (PinId != ROLE_USER)
return SCARD_E_INVALID_PARAMETER;
r = md_get_pin_by_role(pCardData, PinId, &pin_obj);
if (r != SCARD_S_SUCCESS) {
logprintf(pCardData, 2, "Cannot get User PIN object");
return r;
}
/* Do we need to display a prompt to enter PIN on pin pad? */
logprintf(pCardData, 7, "PIN pad=%s, pbPinData=%p, hwndParent=%d\n",
vs->reader->capabilities & SC_READER_CAP_PIN_PAD ? "yes" : "no", pbPinData, vs->hwndParent);
if ((vs->reader->capabilities & SC_READER_CAP_PIN_PAD) && NULL == pbPinData) {
char buf[200];
snprintf(buf, sizeof(buf), "Please enter PIN %s",
NULL == vs->wszPinContext ? "on reader pinpad." : vs->wszPinContext);
logprintf(pCardData, 7, "About to display message box for external PIN verification\n");
/* @TODO: Ideally, this should probably be a non-modal dialog with just a cancel button
* that goes away as soon as a key is pressed on the pinpad.
*/
r = MessageBox(vs->hwndParent, buf, "PIN Entry Required",
MB_OKCANCEL | MB_ICONINFORMATION);
if (IDCANCEL == r) {
logprintf(pCardData, 2, "User canceled PIN verification\n");
/* @TODO: is this the right code to return? */
return SCARD_E_INVALID_PARAMETER;
}
}
r = sc_pkcs15_verify_pin(vs->p15card, pin_obj, (const u8 *) pbPinData, cbPinData);
if (r) {
logprintf(pCardData, 2, "PIN code verification failed: %s\n", sc_strerror(r));
tries_left = ((struct sc_pkcs15_auth_info *)pin_obj->data)->tries_left;
logprintf(pCardData, 7, "PIN retries left: %i\n", tries_left);
if (r == SC_ERROR_AUTH_METHOD_BLOCKED)
return SCARD_W_CHV_BLOCKED;
if(pcAttemptsRemaining)
(*pcAttemptsRemaining) = tries_left;
return SCARD_W_WRONG_CHV;
}
logprintf(pCardData, 2, "Pin code correct.\n");
dwret = md_get_cardcf(pCardData, &cardcf);
if (dwret != SCARD_S_SUCCESS)
return dwret;
SET_PIN(cardcf->bPinsFreshness, PinId);
logprintf(pCardData, 7, "PinsFreshness = %d\n", cardcf->bPinsFreshness);
return SCARD_S_SUCCESS;
}
DWORD WINAPI CardChangeAuthenticatorEx(__in PCARD_DATA pCardData,
__in DWORD dwFlags,
__in PIN_ID dwAuthenticatingPinId,
__in_bcount(cbAuthenticatingPinData) PBYTE pbAuthenticatingPinData,
__in DWORD cbAuthenticatingPinData,
__in PIN_ID dwTargetPinId,
__in_bcount(cbTargetData) PBYTE pbTargetData,
__in DWORD cbTargetData,
__in DWORD cRetryCount,
__out_opt PDWORD pcAttemptsRemaining)
{
logprintf(pCardData, 1, "\nP:%d T:%d pCardData:%p ",GetCurrentProcessId(), GetCurrentThreadId(), pCardData);
logprintf(pCardData, 1, "CardChangeAuthenticatorEx - unsupported\n");
return SCARD_E_UNSUPPORTED_FEATURE;
}
DWORD WINAPI CardDeauthenticateEx(__in PCARD_DATA pCardData,
__in PIN_SET PinId,
__in DWORD dwFlags)
{
VENDOR_SPECIFIC *vs;
CARD_CACHE_FILE_FORMAT *cardcf = NULL;
struct md_file *cmapfile = NULL;
DWORD dwret;
logprintf(pCardData, 1, "\nP:%d T:%d pCardData:%p ",GetCurrentProcessId(), GetCurrentThreadId(), pCardData);
logprintf(pCardData, 1, "CardDeauthenticateEx PinId=%d dwFlags=0x%08X\n",PinId, dwFlags);
if (!pCardData) return SCARD_E_INVALID_PARAMETER;
vs = (VENDOR_SPECIFIC*)(pCardData->pvVendorSpecific);
check_reader_status(pCardData);
dwret = md_get_cardcf(pCardData, &cardcf);
if (dwret != SCARD_S_SUCCESS)
return dwret;
CLEAR_PIN(cardcf->bPinsFreshness, PinId);
logprintf(pCardData, 1, "CardDeauthenticateEx bPinsFreshness:%d\n", cardcf->bPinsFreshness);
/* TODO Reset PKCS#15 PIN object 'validated' flag */
return SCARD_S_SUCCESS;
}
DWORD WINAPI CardGetContainerProperty(__in PCARD_DATA pCardData,
__in BYTE bContainerIndex,
__in LPCWSTR wszProperty,
__out_bcount_part_opt(cbData, *pdwDataLen) PBYTE pbData,
__in DWORD cbData,
__out PDWORD pdwDataLen,
__in DWORD dwFlags)
{
logprintf(pCardData, 1, "\nP:%d T:%d pCardData:%p ",GetCurrentProcessId(), GetCurrentThreadId(), pCardData);
logprintf(pCardData, 1, "CardGetContainerProperty\n");
check_reader_status(pCardData);
if (!pCardData) return SCARD_E_INVALID_PARAMETER;
logprintf(pCardData, 2, "CardGetContainerProperty bContainerIndex=%u, wszProperty=%S," \
"cbData=%u, dwFlags=0x%08X\n",bContainerIndex,NULLWSTR(wszProperty),cbData,dwFlags);
if (!wszProperty)
return SCARD_E_INVALID_PARAMETER;
if (dwFlags)
return SCARD_E_INVALID_PARAMETER;
if (!pbData || !pdwDataLen)
return SCARD_E_INVALID_PARAMETER;
if (wcscmp(CCP_CONTAINER_INFO,wszProperty) == 0) {
PCONTAINER_INFO p = (PCONTAINER_INFO) pbData;
if (pdwDataLen) *pdwDataLen = sizeof(*p);
if (cbData >= sizeof(DWORD))
if (p->dwVersion != CONTAINER_INFO_CURRENT_VERSION && p->dwVersion != 0 )
return ERROR_REVISION_MISMATCH;
if (cbData < sizeof(*p))
return ERROR_INSUFFICIENT_BUFFER;
return CardGetContainerInfo(pCardData,bContainerIndex,0,p);
}
if (wcscmp(CCP_PIN_IDENTIFIER,wszProperty) == 0) {
PPIN_ID p = (PPIN_ID) pbData;
if (pdwDataLen)
*pdwDataLen = sizeof(*p);
if (cbData < sizeof(*p))
return ERROR_INSUFFICIENT_BUFFER;
*p = ROLE_USER;
logprintf(pCardData, 2,"Return Pin id %u\n",*p);
return SCARD_S_SUCCESS;
}
return SCARD_E_INVALID_PARAMETER;
}
DWORD WINAPI CardSetContainerProperty(__in PCARD_DATA pCardData,
__in BYTE bContainerIndex,
__in LPCWSTR wszProperty,
__in_bcount(cbDataLen) PBYTE pbData,
__in DWORD cbDataLen,
__in DWORD dwFlags)
{
logprintf(pCardData, 1, "\nP:%d T:%d pCardData:%p ",GetCurrentProcessId(), GetCurrentThreadId(), pCardData);
logprintf(pCardData, 1, "CardSetContainerProperty - unsupported\n");
return SCARD_E_UNSUPPORTED_FEATURE;
}
DWORD WINAPI CardGetProperty(__in PCARD_DATA pCardData,
__in LPCWSTR wszProperty,
__out_bcount_part_opt(cbData, *pdwDataLen) PBYTE pbData,
__in DWORD cbData,
__out PDWORD pdwDataLen,
__in DWORD dwFlags)
{
VENDOR_SPECIFIC *vs;
DWORD dwret;
logprintf(pCardData, 1, "\nP:%d T:%d pCardData:%p ",GetCurrentProcessId(), GetCurrentThreadId(), pCardData);
logprintf(pCardData, 2, "CardGetProperty('%S',cbData=%u,dwFlags=%u) called\n", NULLWSTR(wszProperty),cbData,dwFlags);
if (!pCardData || !wszProperty)
return SCARD_E_INVALID_PARAMETER;
if (!pbData || !pdwDataLen)
return SCARD_E_INVALID_PARAMETER;
vs = (VENDOR_SPECIFIC*)(pCardData->pvVendorSpecific);
check_reader_status(pCardData);
if (wcscmp(CP_CARD_FREE_SPACE,wszProperty) == 0) {
PCARD_FREE_SPACE_INFO pCardFreeSpaceInfo = (PCARD_FREE_SPACE_INFO )pbData;
if (pdwDataLen)
*pdwDataLen = sizeof(*pCardFreeSpaceInfo);
if (cbData < sizeof(*pCardFreeSpaceInfo))
return SCARD_E_NO_MEMORY;
dwret = md_free_space(pCardData, pCardFreeSpaceInfo);
if (dwret != SCARD_S_SUCCESS) {
logprintf(pCardData, 1, "Get free space error");
return dwret;
}
}
else if (wcscmp(CP_CARD_CAPABILITIES, wszProperty) == 0) {
PCARD_CAPABILITIES pCardCapabilities = (PCARD_CAPABILITIES )pbData;
if (pdwDataLen)
*pdwDataLen = sizeof(*pCardCapabilities);
if (cbData < sizeof(*pCardCapabilities))
return ERROR_INSUFFICIENT_BUFFER;
dwret = md_card_capabilities(pCardCapabilities);
if (dwret != SCARD_S_SUCCESS)
return dwret;
}
else if (wcscmp(CP_CARD_KEYSIZES,wszProperty) == 0) {
PCARD_KEY_SIZES pKeySizes = (PCARD_KEY_SIZES )pbData;
if (pdwDataLen)
*pdwDataLen = sizeof(*pKeySizes);
if (cbData < sizeof(*pKeySizes))
return ERROR_INSUFFICIENT_BUFFER;
dwret = md_query_key_sizes(pKeySizes);
if (dwret != SCARD_S_SUCCESS)
return dwret;
}
else if (wcscmp(CP_CARD_READ_ONLY, wszProperty) == 0) {
BOOL *p = (BOOL *)pbData;
if (pdwDataLen)
*pdwDataLen = sizeof(*p);
if (cbData < sizeof(*p))
return ERROR_INSUFFICIENT_BUFFER;
*p = md_is_read_only(pCardData);
}
else if (wcscmp(CP_CARD_CACHE_MODE, wszProperty) == 0) {
DWORD *p = (DWORD *)pbData;
if (pdwDataLen)
*pdwDataLen = sizeof(*p);
if (cbData < sizeof(*p))
return ERROR_INSUFFICIENT_BUFFER;
*p = CP_CACHE_MODE_NO_CACHE;
}
else if (wcscmp(CP_SUPPORTS_WIN_X509_ENROLLMENT, wszProperty) == 0) {
BOOL *p = (BOOL *)pbData;
if (pdwDataLen)
*pdwDataLen = sizeof(*p);
if (cbData < sizeof(*p))
return ERROR_INSUFFICIENT_BUFFER;
*p = md_is_supports_X509_enrollment(pCardData);
}
else if (wcscmp(CP_CARD_GUID, wszProperty) == 0) {
struct md_file *cardid = NULL;
md_fs_find_file(pCardData, NULL, "cardid", &cardid);
if (!cardid) {
logprintf(pCardData, 2, "file 'cardid' not found\n");
return SCARD_E_FILE_NOT_FOUND;
}
if (pdwDataLen)
*pdwDataLen = cardid->size;
if (cbData < cardid->size)
return ERROR_INSUFFICIENT_BUFFER;
CopyMemory(pbData, cardid->blob, cardid->size);
}
else if (wcscmp(CP_CARD_SERIAL_NO, wszProperty) == 0) {
unsigned char buf[64];
size_t buf_len = sizeof(buf);
size_t sn_len = strlen(vs->p15card->tokeninfo->serial_number)/2;
if (sc_hex_to_bin(vs->p15card->tokeninfo->serial_number, buf, &buf_len)) {
buf_len = strlen(vs->p15card->tokeninfo->serial_number);
if (buf_len > SC_MAX_SERIALNR) {
buf_len = SC_MAX_SERIALNR;
}
memcpy(buf, vs->p15card->tokeninfo->serial_number, buf_len);
}
if (pdwDataLen)
*pdwDataLen = buf_len;
if (cbData < buf_len)
return ERROR_INSUFFICIENT_BUFFER;
CopyMemory(pbData, buf, buf_len);
}
else if (wcscmp(CP_CARD_PIN_INFO,wszProperty) == 0) {
PPIN_INFO p = (PPIN_INFO) pbData;
if (pdwDataLen) *pdwDataLen = sizeof(*p);
if (cbData < sizeof(*p)) return ERROR_INSUFFICIENT_BUFFER;
if (p->dwVersion != PIN_INFO_CURRENT_VERSION) return ERROR_REVISION_MISMATCH;
p->PinType = vs->reader->capabilities & SC_READER_CAP_PIN_PAD ? ExternalPinType : AlphaNumericPinType;
p->dwFlags = 0;
switch (dwFlags) {
case ROLE_USER:
logprintf(pCardData, 2,"returning info on PIN ROLE_USER ( Auth ) [%u]\n",dwFlags);
p->PinPurpose = DigitalSignaturePin;
p->PinCachePolicy.dwVersion = PIN_CACHE_POLICY_CURRENT_VERSION;
p->PinCachePolicy.dwPinCachePolicyInfo = 0;
p->PinCachePolicy.PinCachePolicyType = PinCacheNormal;
p->dwChangePermission = CREATE_PIN_SET(ROLE_USER);
p->dwUnblockPermission = CREATE_PIN_SET(ROLE_ADMIN);
break;
case ROLE_ADMIN:
logprintf(pCardData, 2,"returning info on PIN ROLE_ADMIN ( Unblock ) [%u]\n",dwFlags);
p->PinPurpose = UnblockOnlyPin;
p->PinCachePolicy.dwVersion = PIN_CACHE_POLICY_CURRENT_VERSION;
p->PinCachePolicy.dwPinCachePolicyInfo = 0;
p->PinCachePolicy.PinCachePolicyType = PinCacheNormal;
p->dwChangePermission = CREATE_PIN_SET(ROLE_ADMIN);
p->dwUnblockPermission = 0;
break;
default:
logprintf(pCardData, 0,"Invalid Pin number %u requested\n",dwFlags);
return SCARD_E_INVALID_PARAMETER;
}
}
else if (wcscmp(CP_CARD_LIST_PINS,wszProperty) == 0) {
PPIN_SET p = (PPIN_SET) pbData;
if (pdwDataLen)
*pdwDataLen = sizeof(*p);
if (cbData < sizeof(*p))
return ERROR_INSUFFICIENT_BUFFER;
SET_PIN(*p, ROLE_USER);
}
else if (wcscmp(CP_CARD_AUTHENTICATED_STATE,wszProperty) == 0) {
PPIN_SET p = (PPIN_SET) pbData;
if (pdwDataLen)
*pdwDataLen = sizeof(*p);
if (cbData < sizeof(*p))
return ERROR_INSUFFICIENT_BUFFER;
logprintf(pCardData, 7, "CARD_AUTHENTICATED_STATE invalid\n");
return SCARD_E_INVALID_PARAMETER;
}
else if (wcscmp(CP_CARD_PIN_STRENGTH_VERIFY,wszProperty) == 0) {
DWORD *p = (DWORD *)pbData;
if (dwFlags != ROLE_USER)
return SCARD_E_INVALID_PARAMETER;
if (pdwDataLen)
*pdwDataLen = sizeof(*p);
if (cbData < sizeof(*p))
return ERROR_INSUFFICIENT_BUFFER;
*p = CARD_PIN_STRENGTH_PLAINTEXT;
}
else {
logprintf(pCardData, 3, "Unsupported property '%S'\n", wszProperty);
return SCARD_E_INVALID_PARAMETER;
}
logprintf(pCardData, 7, "returns '%S' ", wszProperty);
loghex(pCardData, 7, pbData, *pdwDataLen);
return SCARD_S_SUCCESS;
}
DWORD WINAPI CardSetProperty(__in PCARD_DATA pCardData,
__in LPCWSTR wszProperty,
__in_bcount(cbDataLen) PBYTE pbData,
__in DWORD cbDataLen,
__in DWORD dwFlags)
{
VENDOR_SPECIFIC *vs;
logprintf(pCardData, 1, "\nP:%d T:%d pCardData:%p ",GetCurrentProcessId(), GetCurrentThreadId(), pCardData);
logprintf(pCardData, 1, "CardSetProperty\n");
if (!pCardData)
return SCARD_E_INVALID_PARAMETER;
logprintf(pCardData, 2, "CardSetProperty wszProperty=%S, pbData=%p, cbDataLen=%u, dwFlags=%u",\
NULLWSTR(wszProperty),pbData,cbDataLen,dwFlags);
vs = (VENDOR_SPECIFIC*)(pCardData->pvVendorSpecific);
if (!wszProperty)
return SCARD_E_INVALID_PARAMETER;
if (wcscmp(CP_CARD_PIN_STRENGTH_VERIFY, wszProperty) == 0 ||
wcscmp(CP_CARD_PIN_INFO, wszProperty) == 0)
return SCARD_E_INVALID_PARAMETER;
if (dwFlags)
return SCARD_E_INVALID_PARAMETER;
if (wcscmp(CP_PIN_CONTEXT_STRING, wszProperty) == 0) {
vs->wszPinContext = (LPWSTR) pbData;
logprintf(pCardData, 3, "Saved PIN context string: %S\n", pbData);
return SCARD_S_SUCCESS;
}
if (wcscmp(CP_CARD_CACHE_MODE, wszProperty) == 0 ||
wcscmp(CP_SUPPORTS_WIN_X509_ENROLLMENT, wszProperty) == 0 ||
wcscmp(CP_CARD_GUID, wszProperty) == 0 ||
wcscmp(CP_CARD_SERIAL_NO, wszProperty) == 0) {
return SCARD_E_INVALID_PARAMETER;
}
if (!pbData || !cbDataLen)
return SCARD_E_INVALID_PARAMETER;
/* This property and CP_PIN_CONTEXT_STRING are set just prior to a call to
* CardAuthenticateEx if the PIN required is declared of type ExternalPinType.
*/
if (wcscmp(CP_PARENT_WINDOW, wszProperty) == 0) {
if (cbDataLen != sizeof(HWND)) {
return SCARD_E_INVALID_PARAMETER;
}
else {
HWND cp = *((HWND *) pbData);
if (cp!=0 && !IsWindow(cp))
return SCARD_E_INVALID_PARAMETER;
vs->hwndParent = cp;
}
logprintf(pCardData, 3, "Saved parent window (%u)\n", vs->hwndParent);
return SCARD_S_SUCCESS;
}
logprintf(pCardData, 3, "INVALID PARAMETER\n");
return SCARD_E_INVALID_PARAMETER;
}
DWORD WINAPI CardAcquireContext(IN PCARD_DATA pCardData, __in DWORD dwFlags)
{
VENDOR_SPECIFIC *vs;
DWORD dwret, suppliedVersion = 0;
if (!pCardData)
return SCARD_E_INVALID_PARAMETER;
if (dwFlags)
return SCARD_E_INVALID_PARAMETER;
suppliedVersion = pCardData->dwVersion;
/* VENDOR SPECIFIC */
vs = pCardData->pvVendorSpecific = pCardData->pfnCspAlloc(sizeof(VENDOR_SPECIFIC));
memset(vs, 0, sizeof(VENDOR_SPECIFIC));
logprintf(pCardData, 1, "==================================================================\n");
logprintf(pCardData, 1, "\nP:%d T:%d pCardData:%p ",GetCurrentProcessId(), GetCurrentThreadId(), pCardData);
logprintf(pCardData, 1, "CardAcquireContext, dwVersion=%u, name=%S,hScard=0x%08X, hSCardCtx=0x%08X\n",
pCardData->dwVersion, NULLWSTR(pCardData->pwszCardName),pCardData->hScard, pCardData->hSCardCtx);
vs->hScard = pCardData->hScard;
vs->hSCardCtx = pCardData->hSCardCtx;
/* The lowest supported version is 4. */
if (pCardData->dwVersion < MD_MINIMUM_VERSION_SUPPORTED)
return (DWORD) ERROR_REVISION_MISMATCH;
if( pCardData->hScard == 0) {
logprintf(pCardData, 0, "Invalide handle.\n");
return SCARD_E_INVALID_HANDLE;
}
logprintf(pCardData, 2, "request version pCardData->dwVersion = %d\n", pCardData->dwVersion);
pCardData->dwVersion = min(pCardData->dwVersion, MD_CURRENT_VERSION_SUPPORTED);
logprintf(pCardData, 2, "pCardData->dwVersion = %d\n", pCardData->dwVersion);
dwret = md_create_context(pCardData, vs);
if (dwret != SCARD_S_SUCCESS)
return dwret;
md_static_data.flags &= ~MD_STATIC_FLAG_CONTEXT_DELETED;
pCardData->pfnCardDeleteContext = CardDeleteContext;
pCardData->pfnCardQueryCapabilities = CardQueryCapabilities;
pCardData->pfnCardDeleteContainer = CardDeleteContainer;
pCardData->pfnCardCreateContainer = CardCreateContainer;
pCardData->pfnCardGetContainerInfo = CardGetContainerInfo;
pCardData->pfnCardAuthenticatePin = CardAuthenticatePin;
pCardData->pfnCardGetChallenge = CardGetChallenge;
pCardData->pfnCardAuthenticateChallenge = CardAuthenticateChallenge;
pCardData->pfnCardUnblockPin = CardUnblockPin;
pCardData->pfnCardChangeAuthenticator = CardChangeAuthenticator;
pCardData->pfnCardDeauthenticate = CardDeauthenticate; /* NULL */
pCardData->pfnCardCreateDirectory = CardCreateDirectory;
pCardData->pfnCardDeleteDirectory = CardDeleteDirectory;
pCardData->pvUnused3 = NULL;
pCardData->pvUnused4 = NULL;
pCardData->pfnCardCreateFile = CardCreateFile;
pCardData->pfnCardReadFile = CardReadFile;
pCardData->pfnCardWriteFile = CardWriteFile;
pCardData->pfnCardDeleteFile = CardDeleteFile;
pCardData->pfnCardEnumFiles = CardEnumFiles;
pCardData->pfnCardGetFileInfo = CardGetFileInfo;
pCardData->pfnCardQueryFreeSpace = CardQueryFreeSpace;
pCardData->pfnCardQueryKeySizes = CardQueryKeySizes;
pCardData->pfnCardSignData = CardSignData;
pCardData->pfnCardRSADecrypt = CardRSADecrypt;
pCardData->pfnCardConstructDHAgreement = CardConstructDHAgreement;
dwret = associate_card(pCardData);
if (dwret != SCARD_S_SUCCESS)
return dwret;
dwret = md_fs_init(pCardData);
if (dwret != SCARD_S_SUCCESS)
return dwret;
logprintf(pCardData, 1, "OpenSC init done.\n");
if (suppliedVersion > 4) {
pCardData->pfnCardDeriveKey = CardDeriveKey;
pCardData->pfnCardDestroyDHAgreement = CardDestroyDHAgreement;
pCardData->pfnCspGetDHAgreement = CspGetDHAgreement;
if (suppliedVersion > 5 ) {
pCardData->pfnCardGetChallengeEx = CardGetChallengeEx;
pCardData->pfnCardAuthenticateEx = CardAuthenticateEx;
pCardData->pfnCardChangeAuthenticatorEx = CardChangeAuthenticatorEx;
pCardData->pfnCardDeauthenticateEx = CardDeauthenticateEx;
pCardData->pfnCardGetContainerProperty = CardGetContainerProperty;
pCardData->pfnCardSetContainerProperty = CardSetContainerProperty;
pCardData->pfnCardGetProperty = CardGetProperty;
pCardData->pfnCardSetProperty = CardSetProperty;
}
}
return SCARD_S_SUCCESS;
}
static int associate_card(PCARD_DATA pCardData)
{
VENDOR_SPECIFIC *vs;
DWORD dw;
int r;
logprintf(pCardData, 1, "associate_card\n");
if (!pCardData)
return SCARD_E_INVALID_PARAMETER;
vs = (VENDOR_SPECIFIC*)(pCardData->pvVendorSpecific);
/*
* set the addresses of the reader and card handles
* Our cardmod pcsc code will use these when we call sc_ctx_use_reader
* We use the address of the handles as provided in the pCardData
*/
vs->hSCardCtx = pCardData->hSCardCtx;
vs->hScard = pCardData->hScard;
/**
* Check if a linked context has been deleted - if so, repair shared data.
* Multithreaded issue - TODO: proper multithreaded handling
*/
if (md_static_data.flags & MD_STATIC_FLAG_CONTEXT_DELETED)
{
r = sc_context_repair(&(vs->ctx));
logprintf(pCardData, 2, "sc_context_repair called - result = %d, %s\n", r, sc_strerror(r));
md_static_data.flags &= ~MD_STATIC_FLAG_CONTEXT_DELETED;
}
/* set the provided reader and card handles into ctx */
logprintf(pCardData, 5, "cardmod_use_handles %d\n", sc_ctx_use_reader(vs->ctx, &vs->hSCardCtx, &vs->hScard));
/* should be only one reader */
logprintf(pCardData, 5, "sc_ctx_get_reader_count(ctx): %d\n", sc_ctx_get_reader_count(vs->ctx));
vs->reader = sc_ctx_get_reader(vs->ctx, 0);
if(vs->reader) {
struct sc_app_info *app_generic = NULL;
struct sc_aid *aid = NULL;
r = sc_connect_card(vs->reader, &(vs->card));
if(r) {
logprintf(pCardData, 0, "Cannot connect card in reader '%s'\n", NULLSTR(vs->reader->name));
return SCARD_E_UNKNOWN_CARD;
}
logprintf(pCardData, 3, "Connected card in '%s'\n", NULLSTR(vs->reader->name));
app_generic = sc_pkcs15_get_application_by_type(vs->card, "generic");
if (app_generic)
logprintf(pCardData, 3, "Use generic application '%s'\n", app_generic->label);
aid = app_generic ? &app_generic->aid : NULL;
r = sc_pkcs15_bind(vs->card, aid, &(vs->p15card));
logprintf(pCardData, 2, "PKCS#15 initialization result: %d, %s\n", r, sc_strerror(r));
}
if(vs->card == NULL || vs->p15card == NULL) {
logprintf(pCardData, 0, "Card unknown.\n");
return SCARD_E_UNKNOWN_CARD;
}
dw = md_get_pin_by_role(pCardData, ROLE_USER, &vs->obj_user_pin);
if (dw != SCARD_S_SUCCESS) {
logprintf(pCardData, 2, "Cannot get User PIN object");
return dw;
}
dw = md_get_pin_by_role(pCardData, ROLE_USER, &vs->obj_sopin);
if (dw != SCARD_S_SUCCESS)
logprintf(pCardData, 2, "Cannot get ADMIN PIN object -- ignored");
return SCARD_S_SUCCESS;
}
static int disassociate_card(PCARD_DATA pCardData)
{
VENDOR_SPECIFIC *vs;
logprintf(pCardData, 1, "disassociate_card\n");
if (!pCardData)
return SCARD_E_INVALID_PARAMETER;
vs = (VENDOR_SPECIFIC*)(pCardData->pvVendorSpecific);
vs->obj_user_pin = NULL;
vs->obj_sopin = NULL;
if(vs->p15card) {
logprintf(pCardData, 6, "sc_pkcs15_unbind\n");
sc_pkcs15_unbind(vs->p15card);
vs->p15card = NULL;
}
if(vs->card) {
logprintf(pCardData, 6, "sc_disconnect_card\n");
sc_disconnect_card(vs->card);
vs->card = NULL;
}
vs->reader = NULL;
vs->hSCardCtx = -1;
vs->hScard = -1;
return SCARD_S_SUCCESS;
}
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
#ifdef CARDMOD_LOW_LEVEL_DEBUG
CHAR name[MAX_PATH + 1] = "\0";
char *reason = "";
GetModuleFileName(GetModuleHandle(NULL),name,MAX_PATH);
switch (ul_reason_for_call) {
case DLL_PROCESS_ATTACH:
reason = "Attach Process";
break;
case DLL_THREAD_ATTACH:
reason = "Attach Thread";
break;
case DLL_THREAD_DETACH:
reason = "Detach Thread";
break;
case DLL_PROCESS_DETACH:
reason = "Detach Process";
break;
}
logprintf(NULL,8,"\n********** DllMain Module(handle:0x%X) '%s'; reason='%s'; Reserved=%p; P:%d; T:%d\n",
hModule, name, reason, lpReserved, GetCurrentProcessId(), GetCurrentThreadId());
#endif
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
md_static_data.attach_check = MD_STATIC_PROCESS_ATTACHED;
break;
case DLL_PROCESS_DETACH:
md_static_data.attach_check = 0;
break;
}
return TRUE;
}
#ifdef _MANAGED
#pragma managed(pop)
#endif
#endif