2001-11-20 22:21:58 +00:00
|
|
|
/*
|
2002-01-10 12:33:56 +00:00
|
|
|
* sec.c: Cryptography and security (ISO7816-8) functions
|
2001-11-20 22:21:58 +00:00
|
|
|
*
|
2006-12-19 21:31:17 +00:00
|
|
|
* Copyright (C) 2001, 2002 Juha Yrjölä <juha.yrjola@iki.fi>
|
2001-11-20 22:21:58 +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,
|
|
|
|
* 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
|
2001-11-01 15:43:20 +00:00
|
|
|
*/
|
|
|
|
|
2015-04-22 21:55:33 +00:00
|
|
|
#if HAVE_CONFIG_H
|
2010-03-04 08:14:36 +00:00
|
|
|
#include "config.h"
|
2015-04-22 21:55:33 +00:00
|
|
|
#endif
|
2010-03-04 08:14:36 +00:00
|
|
|
|
2001-11-01 15:43:20 +00:00
|
|
|
#include <stdio.h>
|
2003-01-06 23:46:24 +00:00
|
|
|
#include <string.h>
|
2001-11-20 22:21:58 +00:00
|
|
|
#include <assert.h>
|
2017-09-20 11:32:29 +00:00
|
|
|
#include <ctype.h>
|
2010-03-04 08:14:36 +00:00
|
|
|
#ifdef HAVE_UNISTD_H
|
|
|
|
#include <unistd.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include "internal.h"
|
2001-11-20 22:21:58 +00:00
|
|
|
|
2005-03-08 20:59:35 +00:00
|
|
|
int sc_decipher(sc_card_t *card,
|
2001-12-22 13:38:25 +00:00
|
|
|
const u8 * crgram, size_t crgram_len, u8 * out, size_t outlen)
|
2001-11-01 15:43:20 +00:00
|
|
|
{
|
2001-11-20 22:21:58 +00:00
|
|
|
int r;
|
|
|
|
|
2017-02-22 08:32:18 +00:00
|
|
|
if (card == NULL || crgram == NULL || out == NULL) {
|
2020-02-24 17:23:23 +00:00
|
|
|
LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);
|
2017-02-22 08:32:18 +00:00
|
|
|
}
|
2018-11-22 08:14:50 +00:00
|
|
|
LOG_FUNC_CALLED(card->ctx);
|
2002-03-15 09:42:07 +00:00
|
|
|
if (card->ops->decipher == NULL)
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_NOT_SUPPORTED);
|
2002-03-15 09:42:07 +00:00
|
|
|
r = card->ops->decipher(card, crgram, crgram_len, out, outlen);
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r);
|
2001-11-20 22:21:58 +00:00
|
|
|
}
|
|
|
|
|
2005-03-08 20:59:35 +00:00
|
|
|
int sc_compute_signature(sc_card_t *card,
|
2001-12-22 13:38:25 +00:00
|
|
|
const u8 * data, size_t datalen,
|
|
|
|
u8 * out, size_t outlen)
|
2001-11-20 22:21:58 +00:00
|
|
|
{
|
|
|
|
int r;
|
|
|
|
|
2017-02-22 08:32:18 +00:00
|
|
|
if (card == NULL) {
|
|
|
|
return SC_ERROR_INVALID_ARGUMENTS;
|
|
|
|
}
|
2018-11-22 08:14:50 +00:00
|
|
|
LOG_FUNC_CALLED(card->ctx);
|
2002-01-20 21:20:09 +00:00
|
|
|
if (card->ops->compute_signature == NULL)
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_NOT_SUPPORTED);
|
2002-01-20 21:20:09 +00:00
|
|
|
r = card->ops->compute_signature(card, data, datalen, out, outlen);
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r);
|
2001-11-20 22:21:58 +00:00
|
|
|
}
|
|
|
|
|
2017-09-22 12:03:31 +00:00
|
|
|
int sc_unwrap(sc_card_t *card,
|
|
|
|
const u8 * crgram, size_t crgram_len, u8 * out, size_t outlen)
|
|
|
|
{
|
|
|
|
int r;
|
|
|
|
|
|
|
|
if (card == NULL || crgram == NULL) {
|
|
|
|
return SC_ERROR_INVALID_ARGUMENTS;
|
|
|
|
}
|
2018-11-22 08:14:50 +00:00
|
|
|
LOG_FUNC_CALLED(card->ctx);
|
2017-09-22 12:03:31 +00:00
|
|
|
if (card->ops->unwrap == NULL)
|
|
|
|
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_NOT_SUPPORTED);
|
|
|
|
r = card->ops->unwrap(card, crgram, crgram_len);
|
|
|
|
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r);
|
|
|
|
}
|
|
|
|
|
2017-11-17 14:15:12 +00:00
|
|
|
int sc_wrap(sc_card_t *card,
|
|
|
|
const u8 * crgram, size_t crgram_len, u8 * out, size_t outlen)
|
|
|
|
{
|
|
|
|
int r;
|
|
|
|
|
|
|
|
if (card == NULL) {
|
|
|
|
return SC_ERROR_INVALID_ARGUMENTS;
|
|
|
|
}
|
2018-11-22 08:14:50 +00:00
|
|
|
LOG_FUNC_CALLED(card->ctx);
|
2017-11-17 14:15:12 +00:00
|
|
|
if (card->ops->wrap == NULL)
|
|
|
|
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_NOT_SUPPORTED);
|
|
|
|
r = card->ops->wrap(card, out, outlen);
|
|
|
|
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r);
|
|
|
|
}
|
|
|
|
|
2005-03-08 20:59:35 +00:00
|
|
|
int sc_set_security_env(sc_card_t *card,
|
|
|
|
const sc_security_env_t *env,
|
2002-01-16 23:59:18 +00:00
|
|
|
int se_num)
|
|
|
|
{
|
|
|
|
int r;
|
|
|
|
|
2017-02-22 08:32:18 +00:00
|
|
|
if (card == NULL) {
|
|
|
|
return SC_ERROR_INVALID_ARGUMENTS;
|
|
|
|
}
|
2018-11-22 08:14:50 +00:00
|
|
|
LOG_FUNC_CALLED(card->ctx);
|
2002-01-16 23:59:18 +00:00
|
|
|
if (card->ops->set_security_env == NULL)
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_NOT_SUPPORTED);
|
2002-01-16 23:59:18 +00:00
|
|
|
r = card->ops->set_security_env(card, env, se_num);
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r);
|
2002-01-16 23:59:18 +00:00
|
|
|
}
|
|
|
|
|
2005-03-08 20:59:35 +00:00
|
|
|
int sc_restore_security_env(sc_card_t *card, int se_num)
|
2002-01-16 23:59:18 +00:00
|
|
|
{
|
|
|
|
int r;
|
|
|
|
|
2017-02-22 08:32:18 +00:00
|
|
|
if (card == NULL) {
|
|
|
|
return SC_ERROR_INVALID_ARGUMENTS;
|
|
|
|
}
|
2018-11-22 08:14:50 +00:00
|
|
|
LOG_FUNC_CALLED(card->ctx);
|
2002-01-16 23:59:18 +00:00
|
|
|
if (card->ops->restore_security_env == NULL)
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_NOT_SUPPORTED);
|
2002-01-16 23:59:18 +00:00
|
|
|
r = card->ops->restore_security_env(card, se_num);
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r);
|
2002-01-16 23:59:18 +00:00
|
|
|
}
|
|
|
|
|
2005-03-08 20:59:35 +00:00
|
|
|
int sc_verify(sc_card_t *card, unsigned int type, int ref,
|
2002-01-10 23:02:48 +00:00
|
|
|
const u8 *pin, size_t pinlen, int *tries_left)
|
2001-11-20 22:21:58 +00:00
|
|
|
{
|
2002-12-23 18:47:27 +00:00
|
|
|
struct sc_pin_cmd_data data;
|
2002-01-10 23:02:48 +00:00
|
|
|
|
2002-12-23 18:47:27 +00:00
|
|
|
memset(&data, 0, sizeof(data));
|
|
|
|
data.cmd = SC_PIN_CMD_VERIFY;
|
|
|
|
data.pin_type = type;
|
|
|
|
data.pin_reference = ref;
|
|
|
|
data.pin1.data = pin;
|
|
|
|
data.pin1.len = pinlen;
|
|
|
|
|
|
|
|
return sc_pin_cmd(card, &data, tries_left);
|
2001-11-20 22:21:58 +00:00
|
|
|
}
|
|
|
|
|
2005-03-08 20:59:35 +00:00
|
|
|
int sc_logout(sc_card_t *card)
|
2003-05-20 08:30:46 +00:00
|
|
|
{
|
|
|
|
if (card->ops->logout == NULL)
|
2006-06-17 12:24:04 +00:00
|
|
|
return SC_ERROR_NOT_SUPPORTED;
|
|
|
|
return card->ops->logout(card);
|
2003-05-20 08:30:46 +00:00
|
|
|
}
|
|
|
|
|
2005-03-08 20:59:35 +00:00
|
|
|
int sc_change_reference_data(sc_card_t *card, unsigned int type,
|
2002-02-10 18:04:03 +00:00
|
|
|
int ref, const u8 *old, size_t oldlen,
|
|
|
|
const u8 *newref, size_t newlen,
|
2001-12-02 19:21:46 +00:00
|
|
|
int *tries_left)
|
2001-11-20 22:21:58 +00:00
|
|
|
{
|
2002-12-23 18:47:27 +00:00
|
|
|
struct sc_pin_cmd_data data;
|
2001-11-20 22:21:58 +00:00
|
|
|
|
2002-12-23 18:47:27 +00:00
|
|
|
memset(&data, 0, sizeof(data));
|
|
|
|
data.cmd = SC_PIN_CMD_CHANGE;
|
|
|
|
data.pin_type = type;
|
|
|
|
data.pin_reference = ref;
|
|
|
|
data.pin1.data = old;
|
|
|
|
data.pin1.len = oldlen;
|
|
|
|
data.pin2.data = newref;
|
|
|
|
data.pin2.len = newlen;
|
|
|
|
|
|
|
|
return sc_pin_cmd(card, &data, tries_left);
|
2001-11-20 22:21:58 +00:00
|
|
|
}
|
|
|
|
|
2005-03-08 20:59:35 +00:00
|
|
|
int sc_reset_retry_counter(sc_card_t *card, unsigned int type, int ref,
|
2002-02-10 18:04:03 +00:00
|
|
|
const u8 *puk, size_t puklen, const u8 *newref,
|
|
|
|
size_t newlen)
|
2002-12-23 18:47:27 +00:00
|
|
|
{
|
|
|
|
struct sc_pin_cmd_data data;
|
|
|
|
|
|
|
|
memset(&data, 0, sizeof(data));
|
|
|
|
data.cmd = SC_PIN_CMD_UNBLOCK;
|
|
|
|
data.pin_type = type;
|
|
|
|
data.pin_reference = ref;
|
|
|
|
data.pin1.data = puk;
|
|
|
|
data.pin1.len = puklen;
|
|
|
|
data.pin2.data = newref;
|
|
|
|
data.pin2.len = newlen;
|
|
|
|
|
|
|
|
return sc_pin_cmd(card, &data, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This is the new style pin command, which takes care of all PIN
|
|
|
|
* operations.
|
|
|
|
* If a PIN was given by the application, the card driver should
|
|
|
|
* send this PIN to the card. If no PIN was given, the driver should
|
|
|
|
* ask the reader to obtain the pin(s) via the pin pad
|
|
|
|
*/
|
2005-03-08 20:59:35 +00:00
|
|
|
int sc_pin_cmd(sc_card_t *card, struct sc_pin_cmd_data *data,
|
2002-12-23 18:47:27 +00:00
|
|
|
int *tries_left)
|
2001-11-20 22:21:58 +00:00
|
|
|
{
|
2020-03-05 21:15:27 +00:00
|
|
|
int r, debug;
|
2002-02-10 18:04:03 +00:00
|
|
|
|
2017-02-22 08:32:18 +00:00
|
|
|
if (card == NULL) {
|
|
|
|
return SC_ERROR_INVALID_ARGUMENTS;
|
|
|
|
}
|
2018-11-22 08:14:50 +00:00
|
|
|
LOG_FUNC_CALLED(card->ctx);
|
2020-03-05 21:15:27 +00:00
|
|
|
|
|
|
|
debug = card->ctx->debug;
|
|
|
|
if (data->cmd != SC_PIN_CMD_GET_INFO
|
|
|
|
&& card->ctx->debug < SC_LOG_DEBUG_PIN) {
|
|
|
|
card->ctx->debug = 0;
|
|
|
|
}
|
|
|
|
|
2002-12-23 18:47:27 +00:00
|
|
|
if (card->ops->pin_cmd) {
|
|
|
|
r = card->ops->pin_cmd(card, data, tries_left);
|
|
|
|
} else if (!(data->flags & SC_PIN_CMD_USE_PINPAD)) {
|
|
|
|
/* Card driver doesn't support new style pin_cmd, fall
|
|
|
|
* back to old interface */
|
|
|
|
|
|
|
|
r = SC_ERROR_NOT_SUPPORTED;
|
|
|
|
switch (data->cmd) {
|
|
|
|
case SC_PIN_CMD_VERIFY:
|
|
|
|
if (card->ops->verify != NULL)
|
|
|
|
r = card->ops->verify(card,
|
|
|
|
data->pin_type,
|
|
|
|
data->pin_reference,
|
|
|
|
data->pin1.data,
|
2004-10-17 20:40:58 +00:00
|
|
|
(size_t) data->pin1.len,
|
2002-12-23 18:47:27 +00:00
|
|
|
tries_left);
|
|
|
|
break;
|
|
|
|
case SC_PIN_CMD_CHANGE:
|
|
|
|
if (card->ops->change_reference_data != NULL)
|
|
|
|
r = card->ops->change_reference_data(card,
|
|
|
|
data->pin_type,
|
|
|
|
data->pin_reference,
|
|
|
|
data->pin1.data,
|
2004-10-17 20:40:58 +00:00
|
|
|
(size_t) data->pin1.len,
|
2002-12-23 18:47:27 +00:00
|
|
|
data->pin2.data,
|
2004-10-17 20:40:58 +00:00
|
|
|
(size_t) data->pin2.len,
|
2002-12-23 18:47:27 +00:00
|
|
|
tries_left);
|
|
|
|
break;
|
|
|
|
case SC_PIN_CMD_UNBLOCK:
|
|
|
|
if (card->ops->reset_retry_counter != NULL)
|
|
|
|
r = card->ops->reset_retry_counter(card,
|
|
|
|
data->pin_type,
|
|
|
|
data->pin_reference,
|
|
|
|
data->pin1.data,
|
2004-10-17 20:40:58 +00:00
|
|
|
(size_t) data->pin1.len,
|
2002-12-23 18:47:27 +00:00
|
|
|
data->pin2.data,
|
2004-10-17 20:40:58 +00:00
|
|
|
(size_t) data->pin2.len);
|
2002-12-23 18:47:27 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (r == SC_ERROR_NOT_SUPPORTED)
|
2018-11-22 08:31:29 +00:00
|
|
|
sc_log(card->ctx, "unsupported PIN operation (%d)",
|
2002-12-23 18:47:27 +00:00
|
|
|
data->cmd);
|
|
|
|
} else {
|
2018-11-22 08:31:29 +00:00
|
|
|
sc_log(card->ctx, "Use of pin pad not supported by card driver");
|
2002-12-23 18:47:27 +00:00
|
|
|
r = SC_ERROR_NOT_SUPPORTED;
|
|
|
|
}
|
2020-03-05 21:15:27 +00:00
|
|
|
card->ctx->debug = debug;
|
|
|
|
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r);
|
2002-12-23 18:47:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This function will copy a PIN, convert and pad it as required
|
2003-07-14 13:20:49 +00:00
|
|
|
*
|
|
|
|
* Note about the SC_PIN_ENCODING_GLP encoding:
|
2018-04-14 17:38:34 +00:00
|
|
|
* PIN buffers are always 16 nibbles (8 bytes) and look like this:
|
2003-07-14 13:20:49 +00:00
|
|
|
* 0x2 + len + pin_in_BCD + paddingnibbles
|
|
|
|
* in which the paddingnibble = 0xF
|
2017-09-20 11:32:29 +00:00
|
|
|
* E.g. if PIN = 12345, then sbuf = {0x25, 0x12, 0x34, 0x5F, 0xFF, 0xFF, 0xFF, 0xFF}
|
2003-07-14 13:20:49 +00:00
|
|
|
* E.g. if PIN = 123456789012, then sbuf = {0x2C, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0xFF}
|
|
|
|
* Reference: Global Platform - Card Specification - version 2.0.1' - April 7, 2000
|
2002-12-23 18:47:27 +00:00
|
|
|
*/
|
|
|
|
int sc_build_pin(u8 *buf, size_t buflen, struct sc_pin_cmd_pin *pin, int pad)
|
|
|
|
{
|
2005-01-18 21:42:00 +00:00
|
|
|
size_t i = 0, j, pin_len = pin->len;
|
2002-12-23 18:47:27 +00:00
|
|
|
|
|
|
|
if (pin->max_length && pin_len > pin->max_length)
|
|
|
|
return SC_ERROR_INVALID_ARGUMENTS;
|
|
|
|
|
2003-07-14 13:20:49 +00:00
|
|
|
if (pin->encoding == SC_PIN_ENCODING_GLP) {
|
2003-08-14 07:13:44 +00:00
|
|
|
while (pin_len > 0 && pin->data[pin_len - 1] == 0xFF)
|
|
|
|
pin_len--;
|
2003-07-14 13:20:49 +00:00
|
|
|
if (pin_len > 12)
|
|
|
|
return SC_ERROR_INVALID_ARGUMENTS;
|
2003-08-14 07:13:44 +00:00
|
|
|
for (i = 0; i < pin_len; i++) {
|
|
|
|
if (pin->data[i] < '0' || pin->data[i] > '9')
|
|
|
|
return SC_ERROR_INVALID_ARGUMENTS;
|
|
|
|
}
|
2017-08-02 21:12:58 +00:00
|
|
|
buf[0] = 0x20 | (u8) pin_len;
|
2003-07-14 13:20:49 +00:00
|
|
|
buf++;
|
|
|
|
buflen--;
|
|
|
|
}
|
|
|
|
|
2002-12-23 18:47:27 +00:00
|
|
|
/* PIN given by application, encode if required */
|
|
|
|
if (pin->encoding == SC_PIN_ENCODING_ASCII) {
|
|
|
|
if (pin_len > buflen)
|
|
|
|
return SC_ERROR_BUFFER_TOO_SMALL;
|
|
|
|
memcpy(buf, pin->data, pin_len);
|
|
|
|
i = pin_len;
|
2003-07-14 13:20:49 +00:00
|
|
|
} else if (pin->encoding == SC_PIN_ENCODING_BCD || pin->encoding == SC_PIN_ENCODING_GLP) {
|
2002-12-23 18:47:27 +00:00
|
|
|
if (pin_len > 2 * buflen)
|
|
|
|
return SC_ERROR_BUFFER_TOO_SMALL;
|
|
|
|
for (i = j = 0; j < pin_len; j++) {
|
2017-09-20 08:13:26 +00:00
|
|
|
if (!isdigit(pin->data[j])) {
|
|
|
|
return SC_ERROR_INVALID_DATA;
|
|
|
|
}
|
2002-12-23 18:47:27 +00:00
|
|
|
buf[i] <<= 4;
|
|
|
|
buf[i] |= pin->data[j] & 0xf;
|
|
|
|
if (j & 1)
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
if (j & 1) {
|
|
|
|
buf[i] <<= 4;
|
|
|
|
buf[i] |= pin->pad_char & 0xf;
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Pad to maximum PIN length if requested */
|
2003-07-14 13:20:49 +00:00
|
|
|
if (pad || pin->encoding == SC_PIN_ENCODING_GLP) {
|
2005-01-18 21:42:00 +00:00
|
|
|
size_t pad_length = pin->pad_length;
|
|
|
|
u8 pad_char = pin->encoding == SC_PIN_ENCODING_GLP ? 0xFF : pin->pad_char;
|
|
|
|
|
2002-12-23 18:47:27 +00:00
|
|
|
if (pin->encoding == SC_PIN_ENCODING_BCD)
|
|
|
|
pad_length >>= 1;
|
2003-07-14 13:20:49 +00:00
|
|
|
if (pin->encoding == SC_PIN_ENCODING_GLP)
|
|
|
|
pad_length = 8;
|
2002-12-23 18:47:27 +00:00
|
|
|
|
2005-01-18 21:42:00 +00:00
|
|
|
if (pad_length > buflen)
|
|
|
|
return SC_ERROR_BUFFER_TOO_SMALL;
|
2002-12-23 18:47:27 +00:00
|
|
|
|
2005-01-18 21:42:00 +00:00
|
|
|
if (pad_length && i < pad_length) {
|
|
|
|
memset(buf + i, pad_char, pad_length - i);
|
|
|
|
i = pad_length;
|
|
|
|
}
|
2002-12-23 18:47:27 +00:00
|
|
|
}
|
2005-01-18 21:42:00 +00:00
|
|
|
|
2002-12-23 18:47:27 +00:00
|
|
|
return i;
|
2001-11-01 15:43:20 +00:00
|
|
|
}
|