2001-11-06 18:34:19 +00:00
|
|
|
/*
|
2001-12-22 20:43:09 +00:00
|
|
|
* sc.c: General functions
|
2001-11-01 15:43:20 +00:00
|
|
|
*
|
2006-12-19 21:31:17 +00:00
|
|
|
* Copyright (C) 2001, 2002 Juha Yrjölä <juha.yrjola@iki.fi>
|
2001-11-06 18:34:19 +00:00
|
|
|
*
|
|
|
|
* 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,
|
2001-11-01 15:43:20 +00:00
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
2001-11-06 18:34:19 +00:00
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Lesser General Public License for more details.
|
2001-11-01 15:43:20 +00:00
|
|
|
*
|
2001-11-06 18:34:19 +00:00
|
|
|
* 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
|
2001-11-01 15:43:20 +00:00
|
|
|
*/
|
|
|
|
|
2010-03-04 08:14:36 +00:00
|
|
|
#include "config.h"
|
2005-10-09 22:15:35 +00:00
|
|
|
|
2001-11-01 15:43:20 +00:00
|
|
|
#include <stdio.h>
|
2005-10-30 18:05:30 +00:00
|
|
|
#include <ctype.h>
|
2001-11-01 15:43:20 +00:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <assert.h>
|
2010-03-04 08:14:36 +00:00
|
|
|
#ifdef HAVE_SYS_MMAN_H
|
|
|
|
#include <sys/mman.h>
|
|
|
|
#endif
|
|
|
|
#ifdef ENABLE_OPENSSL
|
|
|
|
#include <openssl/crypto.h> /* for OPENSSL_cleanse */
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include "internal.h"
|
2001-11-01 15:43:20 +00:00
|
|
|
|
2008-04-16 04:32:56 +00:00
|
|
|
#ifdef PACKAGE_VERSION
|
|
|
|
static const char *sc_version = PACKAGE_VERSION;
|
2001-11-26 20:14:48 +00:00
|
|
|
#else
|
2007-06-21 10:07:01 +00:00
|
|
|
static const char *sc_version = "(undef)";
|
2001-11-26 20:14:48 +00:00
|
|
|
#endif
|
2001-11-01 15:43:20 +00:00
|
|
|
|
2002-06-14 12:52:56 +00:00
|
|
|
const char *sc_get_version(void)
|
|
|
|
{
|
|
|
|
return sc_version;
|
|
|
|
}
|
|
|
|
|
2001-12-22 13:38:25 +00:00
|
|
|
int sc_hex_to_bin(const char *in, u8 *out, size_t *outlen)
|
2001-11-20 22:21:58 +00:00
|
|
|
{
|
2001-12-22 13:38:25 +00:00
|
|
|
int err = 0;
|
2002-12-04 15:36:33 +00:00
|
|
|
size_t left, count = 0;
|
2001-11-20 22:21:58 +00:00
|
|
|
|
|
|
|
assert(in != NULL && out != NULL && outlen != NULL);
|
|
|
|
left = *outlen;
|
|
|
|
|
2002-12-04 15:36:33 +00:00
|
|
|
while (*in != '\0') {
|
|
|
|
int byte = 0, nybbles = 2;
|
|
|
|
|
2011-02-06 22:43:12 +00:00
|
|
|
while (nybbles-- && *in && *in != ':' && *in != ' ') {
|
2005-12-05 21:36:55 +00:00
|
|
|
char c;
|
2002-12-04 15:36:33 +00:00
|
|
|
byte <<= 4;
|
|
|
|
c = *in++;
|
|
|
|
if ('0' <= c && c <= '9')
|
|
|
|
c -= '0';
|
|
|
|
else
|
|
|
|
if ('a' <= c && c <= 'f')
|
|
|
|
c = c - 'a' + 10;
|
|
|
|
else
|
|
|
|
if ('A' <= c && c <= 'F')
|
|
|
|
c = c - 'A' + 10;
|
|
|
|
else {
|
|
|
|
err = SC_ERROR_INVALID_ARGUMENTS;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
byte |= c;
|
2001-11-20 22:21:58 +00:00
|
|
|
}
|
2011-02-06 22:43:12 +00:00
|
|
|
if (*in == ':' || *in == ' ')
|
2001-11-20 22:21:58 +00:00
|
|
|
in++;
|
|
|
|
if (left <= 0) {
|
|
|
|
err = SC_ERROR_BUFFER_TOO_SMALL;
|
|
|
|
break;
|
|
|
|
}
|
2002-12-04 15:36:33 +00:00
|
|
|
out[count++] = (u8) byte;
|
2001-11-20 22:21:58 +00:00
|
|
|
left--;
|
|
|
|
}
|
2002-12-04 15:36:33 +00:00
|
|
|
|
|
|
|
out:
|
|
|
|
*outlen = count;
|
2001-11-20 22:21:58 +00:00
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2002-12-10 14:44:42 +00:00
|
|
|
int sc_bin_to_hex(const u8 *in, size_t in_len, char *out, size_t out_len,
|
2005-08-03 18:43:40 +00:00
|
|
|
int in_sep)
|
2002-12-06 12:49:19 +00:00
|
|
|
{
|
2002-12-10 14:44:42 +00:00
|
|
|
unsigned int n, sep_len;
|
2005-08-03 18:43:40 +00:00
|
|
|
char *pos, *end, sep;
|
2002-12-06 12:49:19 +00:00
|
|
|
|
2005-08-03 18:43:40 +00:00
|
|
|
sep = (char)in_sep;
|
2002-12-10 14:44:42 +00:00
|
|
|
sep_len = sep > 0 ? 1 : 0;
|
2002-12-06 12:49:19 +00:00
|
|
|
pos = out;
|
2002-12-10 13:26:31 +00:00
|
|
|
end = out + out_len;
|
2002-12-06 12:49:19 +00:00
|
|
|
for (n = 0; n < in_len; n++) {
|
2002-12-10 14:44:42 +00:00
|
|
|
if (pos + 3 + sep_len >= end)
|
2002-12-06 12:49:19 +00:00
|
|
|
return SC_ERROR_BUFFER_TOO_SMALL;
|
2002-12-10 14:44:42 +00:00
|
|
|
if (n && sep_len)
|
|
|
|
*pos++ = sep;
|
2002-12-06 12:49:19 +00:00
|
|
|
sprintf(pos, "%02x", in[n]);
|
|
|
|
pos += 2;
|
|
|
|
}
|
|
|
|
*pos = '\0';
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-05-23 17:33:45 +00:00
|
|
|
u8 *ulong2bebytes(u8 *buf, unsigned long x)
|
2006-06-27 17:49:19 +00:00
|
|
|
{
|
2011-05-23 17:33:45 +00:00
|
|
|
if (buf != NULL) {
|
|
|
|
buf[3] = (u8) (x & 0xff);
|
|
|
|
buf[2] = (u8) ((x >> 8) & 0xff);
|
|
|
|
buf[1] = (u8) ((x >> 16) & 0xff);
|
|
|
|
buf[0] = (u8) ((x >> 24) & 0xff);
|
|
|
|
}
|
|
|
|
return buf;
|
2006-06-27 17:49:19 +00:00
|
|
|
}
|
|
|
|
|
2011-05-23 17:33:45 +00:00
|
|
|
u8 *ushort2bebytes(u8 *buf, unsigned short x)
|
2006-06-27 17:49:19 +00:00
|
|
|
{
|
2011-05-23 17:33:45 +00:00
|
|
|
if (buf != NULL) {
|
|
|
|
buf[1] = (u8) (x & 0xff);
|
|
|
|
buf[0] = (u8) ((x >> 8) & 0xff);
|
|
|
|
}
|
|
|
|
return buf;
|
2006-06-27 17:49:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
unsigned long bebytes2ulong(const u8 *buf)
|
|
|
|
{
|
2011-05-23 17:33:45 +00:00
|
|
|
if (buf == NULL)
|
|
|
|
return 0UL;
|
|
|
|
return (unsigned long) (buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3]);
|
2006-06-27 17:49:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
unsigned short bebytes2ushort(const u8 *buf)
|
|
|
|
{
|
2011-05-23 17:33:45 +00:00
|
|
|
if (buf == NULL)
|
|
|
|
return 0U;
|
|
|
|
return (unsigned short) (buf[0] << 8 | buf[1]);
|
2006-06-27 17:49:19 +00:00
|
|
|
}
|
|
|
|
|
2005-10-30 18:05:30 +00:00
|
|
|
int sc_format_oid(struct sc_object_id *oid, const char *in)
|
|
|
|
{
|
2006-07-13 20:40:50 +00:00
|
|
|
int ii;
|
2005-10-30 18:05:30 +00:00
|
|
|
const char *p;
|
|
|
|
char *q;
|
|
|
|
|
|
|
|
if (oid == NULL || in == NULL)
|
2006-07-13 20:40:50 +00:00
|
|
|
return SC_ERROR_INVALID_ARGUMENTS;
|
2005-10-30 18:05:30 +00:00
|
|
|
/* init oid */
|
|
|
|
for (ii=0; ii<SC_MAX_OBJECT_ID_OCTETS; ii++)
|
|
|
|
oid->value[ii] = -1;
|
|
|
|
|
|
|
|
p = in;
|
2012-02-17 09:06:57 +00:00
|
|
|
|
2005-10-30 18:05:30 +00:00
|
|
|
for (ii=0; ii < SC_MAX_OBJECT_ID_OCTETS; ii++) {
|
|
|
|
oid->value[ii] = strtol(p, &q, 10);
|
|
|
|
if (!*q)
|
|
|
|
break;
|
|
|
|
if (!(q[0] == '.' && isdigit(q[1]))) {
|
2006-07-13 20:40:50 +00:00
|
|
|
return SC_ERROR_INVALID_ARGUMENTS;
|
2005-10-30 18:05:30 +00:00
|
|
|
}
|
|
|
|
p = q + 1;
|
|
|
|
}
|
|
|
|
|
2006-07-13 20:40:50 +00:00
|
|
|
if (ii == 1)
|
|
|
|
/* reject too short OIDs */
|
|
|
|
return SC_ERROR_INVALID_ARGUMENTS;
|
|
|
|
|
2005-10-30 18:05:30 +00:00
|
|
|
return SC_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2005-08-03 09:00:00 +00:00
|
|
|
int sc_compare_oid(const struct sc_object_id *oid1, const struct sc_object_id *oid2)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
assert(oid1 != NULL && oid2 != NULL);
|
|
|
|
for (i = 0; i < SC_MAX_OBJECT_ID_OCTETS; i++) {
|
|
|
|
if (oid1->value[i] != oid2->value[i])
|
|
|
|
return 0;
|
|
|
|
if (oid1->value[i] < 0)
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2010-01-24 15:25:08 +00:00
|
|
|
int sc_detect_card_presence(sc_reader_t *reader)
|
2002-02-24 19:32:14 +00:00
|
|
|
{
|
|
|
|
int r;
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_FUNC_CALLED(reader->ctx, SC_LOG_DEBUG_VERBOSE);
|
2002-02-24 19:32:14 +00:00
|
|
|
if (reader->ops->detect_card_presence == NULL)
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_FUNC_RETURN(reader->ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_NOT_SUPPORTED);
|
2005-02-06 19:40:40 +00:00
|
|
|
|
2010-01-24 15:25:08 +00:00
|
|
|
r = reader->ops->detect_card_presence(reader);
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_FUNC_RETURN(reader->ctx, SC_LOG_DEBUG_NORMAL, r);
|
2001-11-01 15:43:20 +00:00
|
|
|
}
|
|
|
|
|
2012-02-17 09:06:57 +00:00
|
|
|
int sc_path_set(sc_path_t *path, int type, const u8 *id, size_t id_len,
|
2006-10-30 18:51:48 +00:00
|
|
|
int idx, int count)
|
|
|
|
{
|
|
|
|
if (path == NULL || id == NULL || id_len == 0 || id_len > SC_MAX_PATH_SIZE)
|
|
|
|
return SC_ERROR_INVALID_ARGUMENTS;
|
2011-01-09 08:49:15 +00:00
|
|
|
|
|
|
|
memset(path, 0, sizeof(*path));
|
2006-10-30 18:51:48 +00:00
|
|
|
memcpy(path->value, id, id_len);
|
|
|
|
path->len = id_len;
|
|
|
|
path->type = type;
|
|
|
|
path->index = idx;
|
|
|
|
path->count = count;
|
2012-02-17 09:06:57 +00:00
|
|
|
|
2006-10-30 18:51:48 +00:00
|
|
|
return SC_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2005-03-08 20:59:35 +00:00
|
|
|
void sc_format_path(const char *str, sc_path_t *path)
|
2001-11-17 14:55:41 +00:00
|
|
|
{
|
2001-12-25 20:45:48 +00:00
|
|
|
int type = SC_PATH_TYPE_PATH;
|
2001-11-17 14:55:41 +00:00
|
|
|
|
2002-12-04 15:36:33 +00:00
|
|
|
memset(path, 0, sizeof(*path));
|
2002-01-01 17:25:10 +00:00
|
|
|
if (*str == 'i' || *str == 'I') {
|
2001-12-25 20:45:48 +00:00
|
|
|
type = SC_PATH_TYPE_FILE_ID;
|
2002-01-01 17:25:10 +00:00
|
|
|
str++;
|
2001-12-25 20:45:48 +00:00
|
|
|
}
|
2002-12-04 15:36:33 +00:00
|
|
|
path->len = sizeof(path->value);
|
|
|
|
if (sc_hex_to_bin(str, path->value, &path->len) >= 0) {
|
|
|
|
path->type = type;
|
2001-11-17 14:55:41 +00:00
|
|
|
}
|
2003-11-20 15:40:01 +00:00
|
|
|
path->count = -1;
|
2001-12-22 20:43:09 +00:00
|
|
|
return;
|
2001-11-01 15:43:20 +00:00
|
|
|
}
|
|
|
|
|
2005-03-08 20:59:35 +00:00
|
|
|
int sc_append_path(sc_path_t *dest, const sc_path_t *src)
|
2002-01-21 12:49:00 +00:00
|
|
|
{
|
2006-01-01 23:11:00 +00:00
|
|
|
return sc_concatenate_path(dest, dest, src);
|
2002-01-21 12:49:00 +00:00
|
|
|
}
|
|
|
|
|
2005-03-08 20:59:35 +00:00
|
|
|
int sc_append_path_id(sc_path_t *dest, const u8 *id, size_t idlen)
|
2002-01-21 12:49:00 +00:00
|
|
|
{
|
|
|
|
if (dest->len + idlen > SC_MAX_PATH_SIZE)
|
|
|
|
return SC_ERROR_INVALID_ARGUMENTS;
|
|
|
|
memcpy(dest->value + dest->len, id, idlen);
|
|
|
|
dest->len += idlen;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-03-08 20:59:35 +00:00
|
|
|
int sc_append_file_id(sc_path_t *dest, unsigned int fid)
|
2003-10-13 14:34:18 +00:00
|
|
|
{
|
|
|
|
u8 id[2] = { fid >> 8, fid & 0xff };
|
|
|
|
|
|
|
|
return sc_append_path_id(dest, id, 2);
|
|
|
|
}
|
|
|
|
|
2006-01-01 23:11:00 +00:00
|
|
|
int sc_concatenate_path(sc_path_t *d, const sc_path_t *p1, const sc_path_t *p2)
|
|
|
|
{
|
|
|
|
sc_path_t tpath;
|
|
|
|
|
|
|
|
if (d == NULL || p1 == NULL || p2 == NULL)
|
|
|
|
return SC_ERROR_INVALID_ARGUMENTS;
|
|
|
|
|
2006-11-11 11:47:48 +00:00
|
|
|
if (p1->type == SC_PATH_TYPE_DF_NAME || p2->type == SC_PATH_TYPE_DF_NAME)
|
2006-11-11 11:09:57 +00:00
|
|
|
/* we do not support concatenation of AIDs at the moment */
|
|
|
|
return SC_ERROR_NOT_SUPPORTED;
|
|
|
|
|
2006-01-01 23:11:00 +00:00
|
|
|
if (p1->len + p2->len > SC_MAX_PATH_SIZE)
|
|
|
|
return SC_ERROR_INVALID_ARGUMENTS;
|
|
|
|
|
|
|
|
memset(&tpath, 0, sizeof(sc_path_t));
|
|
|
|
memcpy(tpath.value, p1->value, p1->len);
|
|
|
|
memcpy(tpath.value + p1->len, p2->value, p2->len);
|
|
|
|
tpath.len = p1->len + p2->len;
|
|
|
|
tpath.type = SC_PATH_TYPE_PATH;
|
2006-09-24 12:50:41 +00:00
|
|
|
/* use 'index' and 'count' entry of the second path object */
|
|
|
|
tpath.index = p2->index;
|
|
|
|
tpath.count = p2->count;
|
2006-11-11 11:09:57 +00:00
|
|
|
/* the result is currently always as path */
|
|
|
|
tpath.type = SC_PATH_TYPE_PATH;
|
2006-01-01 23:11:00 +00:00
|
|
|
|
|
|
|
*d = tpath;
|
|
|
|
|
|
|
|
return SC_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2003-08-29 12:55:30 +00:00
|
|
|
const char *sc_print_path(const sc_path_t *path)
|
|
|
|
{
|
2011-01-09 17:17:01 +00:00
|
|
|
static char buffer[SC_MAX_PATH_STRING_SIZE + SC_MAX_AID_STRING_SIZE];
|
2003-08-29 12:55:30 +00:00
|
|
|
|
2006-01-11 23:41:17 +00:00
|
|
|
if (sc_path_print(buffer, sizeof(buffer), path) != SC_SUCCESS)
|
|
|
|
buffer[0] = '\0';
|
2003-08-29 12:55:30 +00:00
|
|
|
|
|
|
|
return buffer;
|
|
|
|
}
|
|
|
|
|
2006-01-11 23:41:17 +00:00
|
|
|
int sc_path_print(char *buf, size_t buflen, const sc_path_t *path)
|
|
|
|
{
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
if (buf == NULL || path == NULL)
|
|
|
|
return SC_ERROR_INVALID_ARGUMENTS;
|
|
|
|
|
2011-01-09 17:17:01 +00:00
|
|
|
if (buflen < path->len * 2 + path->aid.len * 2 + 1)
|
2006-01-11 23:41:17 +00:00
|
|
|
return SC_ERROR_BUFFER_TOO_SMALL;
|
|
|
|
|
|
|
|
buf[0] = '\0';
|
2011-01-09 17:17:01 +00:00
|
|
|
if (path->aid.len) {
|
|
|
|
for (i = 0; i < path->aid.len; i++)
|
|
|
|
snprintf(buf + strlen(buf), buflen - strlen(buf), "%02x", path->aid.value[i]);
|
|
|
|
snprintf(buf + strlen(buf), buflen - strlen(buf), "::");
|
|
|
|
}
|
2011-01-11 10:46:09 +00:00
|
|
|
|
2006-01-11 23:41:17 +00:00
|
|
|
for (i = 0; i < path->len; i++)
|
2011-01-09 17:17:01 +00:00
|
|
|
snprintf(buf + strlen(buf), buflen - strlen(buf), "%02x", path->value[i]);
|
2011-01-12 17:41:10 +00:00
|
|
|
if (!path->aid.len && path->type == SC_PATH_TYPE_DF_NAME)
|
2011-01-11 10:46:09 +00:00
|
|
|
snprintf(buf + strlen(buf), buflen - strlen(buf), "::");
|
2006-01-11 23:41:17 +00:00
|
|
|
|
|
|
|
return SC_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2003-10-13 14:34:18 +00:00
|
|
|
int sc_compare_path(const sc_path_t *path1, const sc_path_t *path2)
|
|
|
|
{
|
|
|
|
return path1->len == path2->len
|
|
|
|
&& !memcmp(path1->value, path2->value, path1->len);
|
|
|
|
}
|
|
|
|
|
2006-01-01 23:11:00 +00:00
|
|
|
int sc_compare_path_prefix(const sc_path_t *prefix, const sc_path_t *path)
|
|
|
|
{
|
|
|
|
sc_path_t tpath;
|
|
|
|
|
|
|
|
if (prefix->len > path->len)
|
|
|
|
return 0;
|
|
|
|
|
2006-08-01 18:49:08 +00:00
|
|
|
tpath = *path;
|
|
|
|
tpath.len = prefix->len;
|
2006-01-01 23:11:00 +00:00
|
|
|
|
|
|
|
return sc_compare_path(&tpath, prefix);
|
|
|
|
}
|
|
|
|
|
|
|
|
const sc_path_t *sc_get_mf_path(void)
|
|
|
|
{
|
2012-02-17 09:06:57 +00:00
|
|
|
static const sc_path_t mf_path = {
|
|
|
|
{0x3f, 0x00, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 2,
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
SC_PATH_TYPE_PATH,
|
2011-01-09 08:49:15 +00:00
|
|
|
{{0},0}
|
|
|
|
};
|
2006-01-01 23:11:00 +00:00
|
|
|
return &mf_path;
|
|
|
|
}
|
|
|
|
|
2005-03-08 20:59:35 +00:00
|
|
|
int sc_file_add_acl_entry(sc_file_t *file, unsigned int operation,
|
2002-02-20 09:56:47 +00:00
|
|
|
unsigned int method, unsigned long key_ref)
|
|
|
|
{
|
2005-03-08 20:59:35 +00:00
|
|
|
sc_acl_entry_t *p, *_new;
|
2002-02-20 09:56:47 +00:00
|
|
|
|
|
|
|
assert(file != NULL);
|
|
|
|
assert(operation < SC_MAX_AC_OPS);
|
|
|
|
|
|
|
|
switch (method) {
|
|
|
|
case SC_AC_NEVER:
|
|
|
|
sc_file_clear_acl_entries(file, operation);
|
2005-03-08 20:59:35 +00:00
|
|
|
file->acl[operation] = (sc_acl_entry_t *) 1;
|
2002-02-20 09:56:47 +00:00
|
|
|
return 0;
|
|
|
|
case SC_AC_NONE:
|
|
|
|
sc_file_clear_acl_entries(file, operation);
|
2005-03-08 20:59:35 +00:00
|
|
|
file->acl[operation] = (sc_acl_entry_t *) 2;
|
2002-02-20 09:56:47 +00:00
|
|
|
return 0;
|
|
|
|
case SC_AC_UNKNOWN:
|
|
|
|
sc_file_clear_acl_entries(file, operation);
|
2005-03-08 20:59:35 +00:00
|
|
|
file->acl[operation] = (sc_acl_entry_t *) 3;
|
2002-02-20 09:56:47 +00:00
|
|
|
return 0;
|
2002-02-21 18:53:23 +00:00
|
|
|
default:
|
|
|
|
/* NONE and UNKNOWN get zapped when a new AC is added.
|
|
|
|
* If the ACL is NEVER, additional entries will be
|
|
|
|
* dropped silently. */
|
2005-03-08 20:59:35 +00:00
|
|
|
if (file->acl[operation] == (sc_acl_entry_t *) 1)
|
2002-02-21 18:53:23 +00:00
|
|
|
return 0;
|
2005-03-08 20:59:35 +00:00
|
|
|
if (file->acl[operation] == (sc_acl_entry_t *) 2
|
|
|
|
|| file->acl[operation] == (sc_acl_entry_t *) 3)
|
2002-02-21 18:53:23 +00:00
|
|
|
file->acl[operation] = NULL;
|
2002-02-20 09:56:47 +00:00
|
|
|
}
|
2005-02-06 19:40:40 +00:00
|
|
|
|
2005-03-26 19:48:28 +00:00
|
|
|
/* If the entry is already present (e.g. due to the mapping)
|
|
|
|
* of the card's AC with OpenSC's), don't add it again. */
|
|
|
|
for (p = file->acl[operation]; p != NULL; p = p->next) {
|
|
|
|
if ((p->method == method) && (p->key_ref == key_ref))
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
Do not cast the return value of malloc(3) and calloc(3)
From http://en.wikipedia.org/wiki/Malloc#Casting_and_type_safety
" Casting and type safety
malloc returns a void pointer (void *), which indicates that it is a
pointer to a region of unknown data type. One may "cast" (see type
conversion) this pointer to a specific type, as in
int *ptr = (int*)malloc(10 * sizeof (int));
When using C, this is considered bad practice; it is redundant under the
C standard. Moreover, putting in a cast may mask failure to include the
header stdlib.h, in which the prototype for malloc is found. In the
absence of a prototype for malloc, the C compiler will assume that
malloc returns an int, and will issue a warning in a context such as the
above, provided the error is not masked by a cast. On certain
architectures and data models (such as LP64 on 64 bit systems, where
long and pointers are 64 bit and int is 32 bit), this error can actually
result in undefined behavior, as the implicitly declared malloc returns
a 32 bit value whereas the actually defined function returns a 64 bit
value. Depending on calling conventions and memory layout, this may
result in stack smashing.
The returned pointer need not be explicitly cast to a more specific
pointer type, since ANSI C defines an implicit conversion between the
void pointer type and other pointers to objects. An explicit cast of
malloc's return value is sometimes performed because malloc originally
returned a char *, but this cast is unnecessary in standard C
code.[4][5] Omitting the cast, however, creates an incompatibility with
C++, which does require it.
The lack of a specific pointer type returned from malloc is type-unsafe
behaviour: malloc allocates based on byte count but not on type. This
distinguishes it from the C++ new operator that returns a pointer whose
type relies on the operand. (see C Type Safety). "
See also
http://www.opensc-project.org/pipermail/opensc-devel/2010-August/014586.html
git-svn-id: https://www.opensc-project.org/svnp/opensc/trunk@4636 c6295689-39f2-0310-b995-f0e70906c6a9
2010-08-18 15:08:51 +00:00
|
|
|
_new = malloc(sizeof(sc_acl_entry_t));
|
2002-04-19 14:23:31 +00:00
|
|
|
if (_new == NULL)
|
2002-02-20 09:56:47 +00:00
|
|
|
return SC_ERROR_OUT_OF_MEMORY;
|
2002-04-19 14:23:31 +00:00
|
|
|
_new->method = method;
|
|
|
|
_new->key_ref = key_ref;
|
|
|
|
_new->next = NULL;
|
2002-02-20 09:56:47 +00:00
|
|
|
|
|
|
|
p = file->acl[operation];
|
|
|
|
if (p == NULL) {
|
2002-04-19 14:23:31 +00:00
|
|
|
file->acl[operation] = _new;
|
2002-02-20 09:56:47 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
while (p->next != NULL)
|
|
|
|
p = p->next;
|
2002-04-19 14:23:31 +00:00
|
|
|
p->next = _new;
|
2002-02-20 09:56:47 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-03-08 20:59:35 +00:00
|
|
|
const sc_acl_entry_t * sc_file_get_acl_entry(const sc_file_t *file,
|
2002-02-20 09:56:47 +00:00
|
|
|
unsigned int operation)
|
|
|
|
{
|
2005-03-08 20:59:35 +00:00
|
|
|
sc_acl_entry_t *p;
|
|
|
|
static const sc_acl_entry_t e_never = {
|
2011-02-05 17:16:54 +00:00
|
|
|
SC_AC_NEVER, SC_AC_KEY_REF_NONE, {{0, 0, 0, {0}}}, NULL
|
2002-02-20 09:56:47 +00:00
|
|
|
};
|
2005-03-08 20:59:35 +00:00
|
|
|
static const sc_acl_entry_t e_none = {
|
2011-02-05 17:16:54 +00:00
|
|
|
SC_AC_NONE, SC_AC_KEY_REF_NONE, {{0, 0, 0, {0}}}, NULL
|
2002-02-20 09:56:47 +00:00
|
|
|
};
|
2005-03-08 20:59:35 +00:00
|
|
|
static const sc_acl_entry_t e_unknown = {
|
2011-02-05 17:16:54 +00:00
|
|
|
SC_AC_UNKNOWN, SC_AC_KEY_REF_NONE, {{0, 0, 0, {0}}}, NULL
|
2002-02-20 09:56:47 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
assert(file != NULL);
|
|
|
|
assert(operation < SC_MAX_AC_OPS);
|
|
|
|
|
|
|
|
p = file->acl[operation];
|
2005-03-08 20:59:35 +00:00
|
|
|
if (p == (sc_acl_entry_t *) 1)
|
2002-02-20 09:56:47 +00:00
|
|
|
return &e_never;
|
2005-03-08 20:59:35 +00:00
|
|
|
if (p == (sc_acl_entry_t *) 2)
|
2002-02-20 09:56:47 +00:00
|
|
|
return &e_none;
|
2005-03-08 20:59:35 +00:00
|
|
|
if (p == (sc_acl_entry_t *) 3)
|
2002-02-20 09:56:47 +00:00
|
|
|
return &e_unknown;
|
|
|
|
|
|
|
|
return file->acl[operation];
|
|
|
|
}
|
|
|
|
|
2005-03-08 20:59:35 +00:00
|
|
|
void sc_file_clear_acl_entries(sc_file_t *file, unsigned int operation)
|
2002-02-20 09:56:47 +00:00
|
|
|
{
|
2005-03-08 20:59:35 +00:00
|
|
|
sc_acl_entry_t *e;
|
2005-02-06 19:40:40 +00:00
|
|
|
|
2002-02-20 09:56:47 +00:00
|
|
|
assert(file != NULL);
|
|
|
|
assert(operation < SC_MAX_AC_OPS);
|
|
|
|
|
|
|
|
e = file->acl[operation];
|
2005-03-08 20:59:35 +00:00
|
|
|
if (e == (sc_acl_entry_t *) 1 ||
|
|
|
|
e == (sc_acl_entry_t *) 2 ||
|
|
|
|
e == (sc_acl_entry_t *) 3) {
|
2002-02-20 09:56:47 +00:00
|
|
|
file->acl[operation] = NULL;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (e != NULL) {
|
2005-03-08 20:59:35 +00:00
|
|
|
sc_acl_entry_t *tmp = e->next;
|
2002-02-20 09:56:47 +00:00
|
|
|
free(e);
|
|
|
|
e = tmp;
|
|
|
|
}
|
|
|
|
file->acl[operation] = NULL;
|
|
|
|
}
|
|
|
|
|
2007-06-21 10:07:01 +00:00
|
|
|
sc_file_t * sc_file_new(void)
|
2002-02-20 09:56:47 +00:00
|
|
|
{
|
2005-08-18 22:43:01 +00:00
|
|
|
sc_file_t *file = (sc_file_t *)calloc(1, sizeof(sc_file_t));
|
2002-02-20 09:56:47 +00:00
|
|
|
if (file == NULL)
|
|
|
|
return NULL;
|
2005-08-18 22:43:01 +00:00
|
|
|
|
2002-02-20 09:56:47 +00:00
|
|
|
file->magic = SC_FILE_MAGIC;
|
|
|
|
return file;
|
|
|
|
}
|
|
|
|
|
2005-03-08 20:59:35 +00:00
|
|
|
void sc_file_free(sc_file_t *file)
|
2002-02-20 09:56:47 +00:00
|
|
|
{
|
2004-10-17 16:20:46 +00:00
|
|
|
unsigned int i;
|
2002-02-20 09:56:47 +00:00
|
|
|
assert(sc_file_valid(file));
|
|
|
|
file->magic = 0;
|
|
|
|
for (i = 0; i < SC_MAX_AC_OPS; i++)
|
|
|
|
sc_file_clear_acl_entries(file, i);
|
2002-03-28 14:13:36 +00:00
|
|
|
if (file->sec_attr)
|
|
|
|
free(file->sec_attr);
|
|
|
|
if (file->prop_attr)
|
|
|
|
free(file->prop_attr);
|
2002-04-17 13:36:35 +00:00
|
|
|
if (file->type_attr)
|
|
|
|
free(file->type_attr);
|
2002-02-20 09:56:47 +00:00
|
|
|
free(file);
|
|
|
|
}
|
|
|
|
|
2005-03-08 20:59:35 +00:00
|
|
|
void sc_file_dup(sc_file_t **dest, const sc_file_t *src)
|
2002-02-20 09:56:47 +00:00
|
|
|
{
|
2005-03-08 20:59:35 +00:00
|
|
|
sc_file_t *newf;
|
|
|
|
const sc_acl_entry_t *e;
|
2004-10-17 16:20:46 +00:00
|
|
|
unsigned int op;
|
2005-02-06 19:40:40 +00:00
|
|
|
|
2002-02-20 09:56:47 +00:00
|
|
|
assert(sc_file_valid(src));
|
|
|
|
*dest = NULL;
|
|
|
|
newf = sc_file_new();
|
|
|
|
if (newf == NULL)
|
|
|
|
return;
|
|
|
|
*dest = newf;
|
2005-02-06 19:40:40 +00:00
|
|
|
|
2005-08-19 06:39:16 +00:00
|
|
|
memcpy(&newf->path, &src->path, sizeof(struct sc_path));
|
|
|
|
memcpy(&newf->name, &src->name, sizeof(src->name));
|
|
|
|
newf->namelen = src->namelen;
|
|
|
|
newf->type = src->type;
|
|
|
|
newf->shareable = src->shareable;
|
|
|
|
newf->ef_structure = src->ef_structure;
|
|
|
|
newf->size = src->size;
|
|
|
|
newf->id = src->id;
|
|
|
|
newf->status = src->status;
|
2002-02-20 09:56:47 +00:00
|
|
|
for (op = 0; op < SC_MAX_AC_OPS; op++) {
|
|
|
|
newf->acl[op] = NULL;
|
|
|
|
e = sc_file_get_acl_entry(src, op);
|
2005-08-19 06:39:16 +00:00
|
|
|
if (e != NULL) {
|
|
|
|
if (sc_file_add_acl_entry(newf, op, e->method, e->key_ref) < 0)
|
|
|
|
goto err;
|
|
|
|
}
|
2002-02-20 09:56:47 +00:00
|
|
|
}
|
2005-08-19 06:39:16 +00:00
|
|
|
newf->record_length = src->record_length;
|
|
|
|
newf->record_count = src->record_count;
|
|
|
|
|
|
|
|
if (sc_file_set_sec_attr(newf, src->sec_attr, src->sec_attr_len) < 0)
|
|
|
|
goto err;
|
|
|
|
if (sc_file_set_prop_attr(newf, src->prop_attr, src->prop_attr_len) < 0)
|
|
|
|
goto err;
|
|
|
|
if (sc_file_set_type_attr(newf, src->type_attr, src->type_attr_len) < 0)
|
|
|
|
goto err;
|
|
|
|
return;
|
|
|
|
err:
|
|
|
|
if (newf != NULL)
|
|
|
|
sc_file_free(newf);
|
|
|
|
*dest = NULL;
|
2002-02-20 09:56:47 +00:00
|
|
|
}
|
|
|
|
|
2005-03-08 20:59:35 +00:00
|
|
|
int sc_file_set_sec_attr(sc_file_t *file, const u8 *sec_attr,
|
2002-03-28 14:13:36 +00:00
|
|
|
size_t sec_attr_len)
|
|
|
|
{
|
2004-04-21 18:10:58 +00:00
|
|
|
u8 *tmp;
|
2002-03-28 14:13:36 +00:00
|
|
|
assert(sc_file_valid(file));
|
|
|
|
|
|
|
|
if (sec_attr == NULL) {
|
|
|
|
if (file->sec_attr != NULL)
|
|
|
|
free(file->sec_attr);
|
|
|
|
file->sec_attr = NULL;
|
|
|
|
file->sec_attr_len = 0;
|
|
|
|
return 0;
|
|
|
|
}
|
2004-04-21 18:10:58 +00:00
|
|
|
tmp = (u8 *) realloc(file->sec_attr, sec_attr_len);
|
|
|
|
if (!tmp) {
|
|
|
|
if (file->sec_attr)
|
|
|
|
free(file->sec_attr);
|
|
|
|
file->sec_attr = NULL;
|
2002-03-28 14:13:36 +00:00
|
|
|
file->sec_attr_len = 0;
|
|
|
|
return SC_ERROR_OUT_OF_MEMORY;
|
|
|
|
}
|
2004-04-21 18:10:58 +00:00
|
|
|
file->sec_attr = tmp;
|
2002-03-28 14:13:36 +00:00
|
|
|
memcpy(file->sec_attr, sec_attr, sec_attr_len);
|
|
|
|
file->sec_attr_len = sec_attr_len;
|
|
|
|
|
|
|
|
return 0;
|
2005-02-06 19:40:40 +00:00
|
|
|
}
|
2002-03-28 14:13:36 +00:00
|
|
|
|
2005-03-08 20:59:35 +00:00
|
|
|
int sc_file_set_prop_attr(sc_file_t *file, const u8 *prop_attr,
|
2002-03-28 14:13:36 +00:00
|
|
|
size_t prop_attr_len)
|
|
|
|
{
|
2004-04-21 18:10:58 +00:00
|
|
|
u8 *tmp;
|
2002-03-28 14:13:36 +00:00
|
|
|
assert(sc_file_valid(file));
|
|
|
|
|
|
|
|
if (prop_attr == NULL) {
|
|
|
|
if (file->prop_attr != NULL)
|
|
|
|
free(file->prop_attr);
|
|
|
|
file->prop_attr = NULL;
|
|
|
|
file->prop_attr_len = 0;
|
|
|
|
return 0;
|
|
|
|
}
|
2004-04-21 18:10:58 +00:00
|
|
|
tmp = (u8 *) realloc(file->prop_attr, prop_attr_len);
|
|
|
|
if (!tmp) {
|
|
|
|
if (file->prop_attr)
|
|
|
|
free(file->prop_attr);
|
|
|
|
file->prop_attr = NULL;
|
2002-03-28 14:13:36 +00:00
|
|
|
file->prop_attr_len = 0;
|
|
|
|
return SC_ERROR_OUT_OF_MEMORY;
|
|
|
|
}
|
2004-04-21 18:10:58 +00:00
|
|
|
file->prop_attr = tmp;
|
2002-03-28 14:13:36 +00:00
|
|
|
memcpy(file->prop_attr, prop_attr, prop_attr_len);
|
|
|
|
file->prop_attr_len = prop_attr_len;
|
|
|
|
|
|
|
|
return 0;
|
2005-02-06 19:40:40 +00:00
|
|
|
}
|
2002-03-28 14:13:36 +00:00
|
|
|
|
2005-03-08 20:59:35 +00:00
|
|
|
int sc_file_set_type_attr(sc_file_t *file, const u8 *type_attr,
|
2002-04-17 13:36:35 +00:00
|
|
|
size_t type_attr_len)
|
|
|
|
{
|
2004-04-21 18:10:58 +00:00
|
|
|
u8 *tmp;
|
2002-04-17 13:36:35 +00:00
|
|
|
assert(sc_file_valid(file));
|
|
|
|
|
|
|
|
if (type_attr == NULL) {
|
|
|
|
if (file->type_attr != NULL)
|
|
|
|
free(file->type_attr);
|
|
|
|
file->type_attr = NULL;
|
|
|
|
file->type_attr_len = 0;
|
|
|
|
return 0;
|
|
|
|
}
|
2004-04-21 18:10:58 +00:00
|
|
|
tmp = (u8 *) realloc(file->type_attr, type_attr_len);
|
|
|
|
if (!tmp) {
|
|
|
|
if (file->type_attr)
|
|
|
|
free(file->type_attr);
|
|
|
|
file->type_attr = NULL;
|
2002-04-17 13:36:35 +00:00
|
|
|
file->type_attr_len = 0;
|
|
|
|
return SC_ERROR_OUT_OF_MEMORY;
|
|
|
|
}
|
2004-04-21 18:10:58 +00:00
|
|
|
file->type_attr = tmp;
|
2002-04-17 13:36:35 +00:00
|
|
|
memcpy(file->type_attr, type_attr, type_attr_len);
|
|
|
|
file->type_attr_len = type_attr_len;
|
|
|
|
|
|
|
|
return 0;
|
2005-02-06 19:40:40 +00:00
|
|
|
}
|
2002-04-17 13:36:35 +00:00
|
|
|
|
2007-06-21 10:07:01 +00:00
|
|
|
int sc_file_valid(const sc_file_t *file) {
|
2001-12-25 20:45:48 +00:00
|
|
|
#ifndef NDEBUG
|
|
|
|
assert(file != NULL);
|
|
|
|
#endif
|
|
|
|
return file->magic == SC_FILE_MAGIC;
|
|
|
|
}
|
2002-03-26 11:38:40 +00:00
|
|
|
|
2010-01-24 15:25:08 +00:00
|
|
|
int _sc_parse_atr(sc_reader_t *reader)
|
2002-03-26 11:38:40 +00:00
|
|
|
{
|
2011-01-07 17:18:58 +00:00
|
|
|
u8 *p = reader->atr.value;
|
|
|
|
int atr_len = (int) reader->atr.len;
|
2002-03-26 11:38:40 +00:00
|
|
|
int n_hist, x;
|
2011-02-05 20:59:28 +00:00
|
|
|
int tx[4] = {-1, -1, -1, -1};
|
2002-03-26 11:38:40 +00:00
|
|
|
int i, FI, DI;
|
|
|
|
const int Fi_table[] = {
|
|
|
|
372, 372, 558, 744, 1116, 1488, 1860, -1,
|
|
|
|
-1, 512, 768, 1024, 1536, 2048, -1, -1 };
|
|
|
|
const int f_table[] = {
|
|
|
|
40, 50, 60, 80, 120, 160, 200, -1,
|
|
|
|
-1, 50, 75, 100, 150, 200, -1, -1 };
|
|
|
|
const int Di_table[] = {
|
|
|
|
-1, 1, 2, 4, 8, 16, 32, -1,
|
|
|
|
12, 20, -1, -1, -1, -1, -1, -1 };
|
2002-12-05 09:34:24 +00:00
|
|
|
|
2010-01-24 15:25:08 +00:00
|
|
|
reader->atr_info.hist_bytes_len = 0;
|
|
|
|
reader->atr_info.hist_bytes = NULL;
|
2002-12-05 09:34:24 +00:00
|
|
|
|
|
|
|
if (atr_len == 0) {
|
2010-03-15 12:17:13 +00:00
|
|
|
sc_debug(reader->ctx, SC_LOG_DEBUG_NORMAL, "empty ATR - card not present?\n");
|
2002-12-05 09:34:24 +00:00
|
|
|
return SC_ERROR_INTERNAL;
|
|
|
|
}
|
|
|
|
|
2002-03-26 11:38:40 +00:00
|
|
|
if (p[0] != 0x3B && p[0] != 0x3F) {
|
2010-03-15 12:17:13 +00:00
|
|
|
sc_debug(reader->ctx, SC_LOG_DEBUG_NORMAL, "invalid sync byte in ATR: 0x%02X\n", p[0]);
|
2002-03-26 11:38:40 +00:00
|
|
|
return SC_ERROR_INTERNAL;
|
|
|
|
}
|
|
|
|
n_hist = p[1] & 0x0F;
|
|
|
|
x = p[1] >> 4;
|
|
|
|
p += 2;
|
|
|
|
atr_len -= 2;
|
|
|
|
for (i = 0; i < 4 && atr_len > 0; i++) {
|
|
|
|
if (x & (1 << i)) {
|
|
|
|
tx[i] = *p;
|
|
|
|
p++;
|
|
|
|
atr_len--;
|
|
|
|
} else
|
|
|
|
tx[i] = -1;
|
|
|
|
}
|
|
|
|
if (tx[0] >= 0) {
|
2010-01-24 15:25:08 +00:00
|
|
|
reader->atr_info.FI = FI = tx[0] >> 4;
|
|
|
|
reader->atr_info.DI = DI = tx[0] & 0x0F;
|
|
|
|
reader->atr_info.Fi = Fi_table[FI];
|
|
|
|
reader->atr_info.f = f_table[FI];
|
|
|
|
reader->atr_info.Di = Di_table[DI];
|
2002-03-26 11:38:40 +00:00
|
|
|
} else {
|
2010-01-24 15:25:08 +00:00
|
|
|
reader->atr_info.Fi = -1;
|
|
|
|
reader->atr_info.f = -1;
|
|
|
|
reader->atr_info.Di = -1;
|
2002-03-26 11:38:40 +00:00
|
|
|
}
|
|
|
|
if (tx[2] >= 0)
|
2010-01-24 15:25:08 +00:00
|
|
|
reader->atr_info.N = tx[3];
|
2002-03-26 11:38:40 +00:00
|
|
|
else
|
2010-01-24 15:25:08 +00:00
|
|
|
reader->atr_info.N = -1;
|
2002-03-26 11:38:40 +00:00
|
|
|
while (tx[3] > 0 && tx[3] & 0xF0 && atr_len > 0) {
|
|
|
|
x = tx[3] >> 4;
|
|
|
|
for (i = 0; i < 4 && atr_len > 0; i++) {
|
|
|
|
if (x & (1 << i)) {
|
|
|
|
tx[i] = *p;
|
|
|
|
p++;
|
|
|
|
atr_len--;
|
|
|
|
} else
|
|
|
|
tx[i] = -1;
|
2012-02-17 09:06:57 +00:00
|
|
|
}
|
2002-03-26 11:38:40 +00:00
|
|
|
}
|
|
|
|
if (atr_len <= 0)
|
|
|
|
return 0;
|
|
|
|
if (n_hist > atr_len)
|
|
|
|
n_hist = atr_len;
|
2010-01-24 15:25:08 +00:00
|
|
|
reader->atr_info.hist_bytes_len = n_hist;
|
|
|
|
reader->atr_info.hist_bytes = p;
|
2002-03-26 11:38:40 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2005-09-17 10:44:45 +00:00
|
|
|
|
2011-10-05 09:20:04 +00:00
|
|
|
void *sc_mem_alloc_secure(sc_context_t *ctx, size_t len)
|
2009-10-22 08:59:59 +00:00
|
|
|
{
|
|
|
|
void *pointer;
|
2011-12-14 12:14:14 +00:00
|
|
|
int locked = 0;
|
|
|
|
|
2009-10-22 08:59:59 +00:00
|
|
|
pointer = calloc(len, sizeof(unsigned char));
|
|
|
|
if (!pointer)
|
|
|
|
return NULL;
|
|
|
|
#ifdef HAVE_SYS_MMAN_H
|
|
|
|
/* TODO Windows support and mprotect too */
|
|
|
|
/* Do not swap the memory */
|
2011-12-14 12:14:14 +00:00
|
|
|
if (mlock(pointer, len) >= 0)
|
|
|
|
locked = 1;
|
2009-10-22 08:59:59 +00:00
|
|
|
#endif
|
2011-12-14 12:14:14 +00:00
|
|
|
if (!locked) {
|
|
|
|
if (ctx->paranoid_memory) {
|
|
|
|
sc_do_log (ctx, 0, NULL, 0, NULL, "cannot lock memory, failing allocation because paranoid set");
|
|
|
|
free (pointer);
|
|
|
|
pointer = NULL;
|
|
|
|
} else {
|
|
|
|
sc_do_log (ctx, 0, NULL, 0, NULL, "cannot lock memory, sensitive data may be paged to disk");
|
|
|
|
}
|
|
|
|
}
|
2009-10-22 08:59:59 +00:00
|
|
|
return pointer;
|
|
|
|
}
|
|
|
|
|
2005-09-17 10:44:45 +00:00
|
|
|
void sc_mem_clear(void *ptr, size_t len)
|
|
|
|
{
|
2008-03-06 16:06:59 +00:00
|
|
|
#ifdef ENABLE_OPENSSL
|
2010-01-23 06:28:35 +00:00
|
|
|
/* FIXME: Bug in 1.0.0-beta series crashes with 0 length */
|
|
|
|
if (len > 0)
|
|
|
|
OPENSSL_cleanse(ptr, len);
|
2005-09-17 10:44:45 +00:00
|
|
|
#else
|
|
|
|
memset(ptr, 0, len);
|
|
|
|
#endif
|
|
|
|
}
|
2006-02-01 22:59:42 +00:00
|
|
|
|
2011-05-29 17:47:54 +00:00
|
|
|
int sc_mem_reverse(unsigned char *buf, size_t len)
|
|
|
|
{
|
|
|
|
unsigned char ch;
|
|
|
|
size_t ii;
|
|
|
|
|
|
|
|
if (!buf || !len)
|
|
|
|
return SC_ERROR_INVALID_ARGUMENTS;
|
|
|
|
|
|
|
|
for (ii = 0; ii < len / 2; ii++) {
|
|
|
|
ch = *(buf + ii);
|
|
|
|
*(buf + ii) = *(buf + len - 1 - ii);
|
|
|
|
*(buf + len - 1 - ii) = ch;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-02-17 09:06:57 +00:00
|
|
|
static int
|
|
|
|
sc_remote_apdu_allocate(struct sc_remote_data *rdata,
|
2011-05-13 12:44:31 +00:00
|
|
|
struct sc_remote_apdu **new_rapdu)
|
|
|
|
{
|
|
|
|
struct sc_remote_apdu *rapdu = NULL, *rr;
|
|
|
|
|
|
|
|
if (!rdata)
|
|
|
|
return SC_ERROR_INVALID_ARGUMENTS;
|
|
|
|
|
|
|
|
rapdu = calloc(1, sizeof(struct sc_remote_apdu));
|
|
|
|
if (rapdu == NULL)
|
|
|
|
return SC_ERROR_OUT_OF_MEMORY;
|
|
|
|
|
|
|
|
rapdu->apdu.data = &rapdu->sbuf[0];
|
|
|
|
rapdu->apdu.resp = &rapdu->rbuf[0];
|
|
|
|
rapdu->apdu.resplen = sizeof(rapdu->rbuf);
|
|
|
|
|
|
|
|
if (new_rapdu)
|
|
|
|
*new_rapdu = rapdu;
|
|
|
|
|
|
|
|
if (rdata->data == NULL) {
|
|
|
|
rdata->data = rapdu;
|
|
|
|
rdata->length = 1;
|
|
|
|
return SC_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (rr = rdata->data; rr->next; rr = rr->next)
|
|
|
|
;
|
|
|
|
rr->next = rapdu;
|
|
|
|
rdata->length++;
|
|
|
|
|
|
|
|
return SC_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2012-02-17 09:06:57 +00:00
|
|
|
static void
|
2011-05-13 12:44:31 +00:00
|
|
|
sc_remote_apdu_free (struct sc_remote_data *rdata)
|
|
|
|
{
|
|
|
|
struct sc_remote_apdu *rapdu = NULL;
|
|
|
|
|
|
|
|
if (!rdata)
|
|
|
|
return;
|
|
|
|
|
|
|
|
rapdu = rdata->data;
|
|
|
|
while(rapdu) {
|
|
|
|
struct sc_remote_apdu *rr = rapdu->next;
|
|
|
|
|
|
|
|
free(rapdu);
|
|
|
|
rapdu = rr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void sc_remote_data_init(struct sc_remote_data *rdata)
|
|
|
|
{
|
|
|
|
if (!rdata)
|
|
|
|
return;
|
|
|
|
memset(rdata, 0, sizeof(struct sc_remote_data));
|
|
|
|
|
|
|
|
rdata->alloc = sc_remote_apdu_allocate;
|
|
|
|
rdata->free = sc_remote_apdu_free;
|
|
|
|
}
|
|
|
|
|
2012-05-29 09:29:44 +00:00
|
|
|
static unsigned long sc_CRC_tab32[256];
|
|
|
|
static int sc_CRC_tab32_initialized = 0;
|
|
|
|
unsigned sc_crc32(unsigned char *value, size_t len)
|
|
|
|
{
|
|
|
|
size_t ii, jj;
|
|
|
|
unsigned long crc;
|
|
|
|
unsigned long index, long_c;
|
|
|
|
|
|
|
|
if (!sc_CRC_tab32_initialized) {
|
|
|
|
for (ii=0; ii<256; ii++) {
|
|
|
|
crc = (unsigned long) ii;
|
|
|
|
for (jj=0; jj<8; jj++) {
|
|
|
|
if ( crc & 0x00000001L )
|
|
|
|
crc = ( crc >> 1 ) ^ 0xEDB88320l;
|
|
|
|
else
|
|
|
|
crc = crc >> 1;
|
|
|
|
}
|
|
|
|
sc_CRC_tab32[ii] = crc;
|
|
|
|
}
|
|
|
|
sc_CRC_tab32_initialized = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
crc = 0xffffffffL;
|
|
|
|
for (ii=0; ii<len; ii++) {
|
|
|
|
long_c = 0x000000ffL & (unsigned long) (*(value + ii));
|
|
|
|
index = crc ^ long_c;
|
|
|
|
crc = (crc >> 8) ^ sc_CRC_tab32[ index & 0xff ];
|
|
|
|
}
|
|
|
|
|
|
|
|
crc ^= 0xffffffff;
|
|
|
|
return crc%0xffff;
|
|
|
|
}
|
|
|
|
|
2006-02-01 22:59:42 +00:00
|
|
|
/**************************** mutex functions ************************/
|
|
|
|
|
|
|
|
int sc_mutex_create(const sc_context_t *ctx, void **mutex)
|
|
|
|
{
|
|
|
|
if (ctx == NULL)
|
|
|
|
return SC_ERROR_INVALID_ARGUMENTS;
|
|
|
|
if (ctx->thread_ctx != NULL && ctx->thread_ctx->create_mutex != NULL)
|
|
|
|
return ctx->thread_ctx->create_mutex(mutex);
|
|
|
|
else
|
|
|
|
return SC_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
int sc_mutex_lock(const sc_context_t *ctx, void *mutex)
|
|
|
|
{
|
|
|
|
if (ctx == NULL)
|
|
|
|
return SC_ERROR_INVALID_ARGUMENTS;
|
|
|
|
if (ctx->thread_ctx != NULL && ctx->thread_ctx->lock_mutex != NULL)
|
|
|
|
return ctx->thread_ctx->lock_mutex(mutex);
|
|
|
|
else
|
|
|
|
return SC_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
int sc_mutex_unlock(const sc_context_t *ctx, void *mutex)
|
|
|
|
{
|
|
|
|
if (ctx == NULL)
|
|
|
|
return SC_ERROR_INVALID_ARGUMENTS;
|
|
|
|
if (ctx->thread_ctx != NULL && ctx->thread_ctx->unlock_mutex != NULL)
|
|
|
|
return ctx->thread_ctx->unlock_mutex(mutex);
|
|
|
|
else
|
|
|
|
return SC_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2006-02-05 19:35:55 +00:00
|
|
|
int sc_mutex_destroy(const sc_context_t *ctx, void *mutex)
|
2006-02-01 22:59:42 +00:00
|
|
|
{
|
2006-02-05 19:35:55 +00:00
|
|
|
if (ctx == NULL)
|
|
|
|
return SC_ERROR_INVALID_ARGUMENTS;
|
|
|
|
if (ctx->thread_ctx != NULL && ctx->thread_ctx->destroy_mutex != NULL)
|
|
|
|
return ctx->thread_ctx->destroy_mutex(mutex);
|
|
|
|
else
|
|
|
|
return SC_SUCCESS;
|
2006-02-01 22:59:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
unsigned long sc_thread_id(const sc_context_t *ctx)
|
|
|
|
{
|
2012-02-17 09:06:57 +00:00
|
|
|
if (ctx == NULL || ctx->thread_ctx == NULL ||
|
2006-02-01 22:59:42 +00:00
|
|
|
ctx->thread_ctx->thread_id == NULL)
|
|
|
|
return 0UL;
|
|
|
|
else
|
|
|
|
return ctx->thread_ctx->thread_id();
|
|
|
|
}
|