SM: move SM APDU procedures to dedicated source file
new SM errors: 'session-already-opened' and 'invalid-checksum' declare typed data for DH SM session
This commit is contained in:
parent
4c1c39f3e4
commit
8d7c773561
@ -46,7 +46,7 @@ libopensc_la_SOURCES = \
|
|||||||
pkcs15-actalis.c pkcs15-atrust-acos.c pkcs15-tccardos.c pkcs15-piv.c \
|
pkcs15-actalis.c pkcs15-atrust-acos.c pkcs15-tccardos.c pkcs15-piv.c \
|
||||||
pkcs15-esinit.c pkcs15-westcos.c pkcs15-pteid.c pkcs15-oberthur.c \
|
pkcs15-esinit.c pkcs15-westcos.c pkcs15-pteid.c pkcs15-oberthur.c \
|
||||||
pkcs15-itacns.c pkcs15-gemsafeV1.c pkcs15-sc-hsm.c \
|
pkcs15-itacns.c pkcs15-gemsafeV1.c pkcs15-sc-hsm.c \
|
||||||
compression.c p15card-helper.c \
|
compression.c p15card-helper.c sm.c \
|
||||||
libopensc.exports
|
libopensc.exports
|
||||||
if WIN32
|
if WIN32
|
||||||
libopensc_la_SOURCES += $(top_builddir)/win32/versioninfo.rc
|
libopensc_la_SOURCES += $(top_builddir)/win32/versioninfo.rc
|
||||||
|
@ -30,7 +30,7 @@ OBJECTS = \
|
|||||||
pkcs15-actalis.obj pkcs15-atrust-acos.obj pkcs15-tccardos.obj pkcs15-piv.obj \
|
pkcs15-actalis.obj pkcs15-atrust-acos.obj pkcs15-tccardos.obj pkcs15-piv.obj \
|
||||||
pkcs15-esinit.obj pkcs15-westcos.obj pkcs15-pteid.obj pkcs15-oberthur.obj \
|
pkcs15-esinit.obj pkcs15-westcos.obj pkcs15-pteid.obj pkcs15-oberthur.obj \
|
||||||
pkcs15-itacns.obj pkcs15-gemsafeV1.obj pkcs15-sc-hsm.obj \
|
pkcs15-itacns.obj pkcs15-gemsafeV1.obj pkcs15-sc-hsm.obj \
|
||||||
compression.obj p15card-helper.obj \
|
compression.obj p15card-helper.obj sm.obj \
|
||||||
$(TOPDIR)\win32\versioninfo.res
|
$(TOPDIR)\win32\versioninfo.res
|
||||||
|
|
||||||
all: $(TOPDIR)\win32\versioninfo.res $(TARGET)
|
all: $(TOPDIR)\win32\versioninfo.res $(TARGET)
|
||||||
|
@ -234,95 +234,6 @@ int sc_apdu_set_resp(sc_context_t *ctx, sc_apdu_t *apdu, const u8 *buf,
|
|||||||
return SC_SUCCESS;
|
return SC_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef ENABLE_SM
|
|
||||||
static const struct sc_asn1_entry c_asn1_sm_response[4] = {
|
|
||||||
{ "encryptedData", SC_ASN1_OCTET_STRING, SC_ASN1_CTX | 7, SC_ASN1_OPTIONAL, NULL, NULL },
|
|
||||||
{ "statusWord", SC_ASN1_OCTET_STRING, SC_ASN1_CTX | 0x19, 0, NULL, NULL },
|
|
||||||
{ "mac", SC_ASN1_OCTET_STRING, SC_ASN1_CTX | 0x0E, 0, NULL, NULL },
|
|
||||||
{ NULL, 0, 0, 0, NULL, NULL }
|
|
||||||
};
|
|
||||||
static int
|
|
||||||
sc_sm_parse_answer(struct sc_context *ctx, unsigned char *resp_data, size_t resp_len,
|
|
||||||
struct sm_card_response *out)
|
|
||||||
{
|
|
||||||
struct sc_asn1_entry asn1_sm_response[4];
|
|
||||||
unsigned char data[SC_MAX_APDU_BUFFER_SIZE];
|
|
||||||
size_t data_len = sizeof(data);
|
|
||||||
unsigned char status[2] = {0, 0};
|
|
||||||
size_t status_len = sizeof(status);
|
|
||||||
unsigned char mac[8];
|
|
||||||
size_t mac_len = sizeof(mac);
|
|
||||||
int r;
|
|
||||||
|
|
||||||
if (!resp_data || !resp_len || !out)
|
|
||||||
return SC_ERROR_INVALID_ARGUMENTS;
|
|
||||||
|
|
||||||
sc_copy_asn1_entry(c_asn1_sm_response, asn1_sm_response);
|
|
||||||
|
|
||||||
sc_format_asn1_entry(asn1_sm_response + 0, data, &data_len, 0);
|
|
||||||
sc_format_asn1_entry(asn1_sm_response + 1, status, &status_len, 0);
|
|
||||||
sc_format_asn1_entry(asn1_sm_response + 2, mac, &mac_len, 0);
|
|
||||||
|
|
||||||
r = sc_asn1_decode(ctx, asn1_sm_response, resp_data, resp_len, NULL, NULL);
|
|
||||||
if (r)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
if (asn1_sm_response[1].flags & SC_ASN1_PRESENT) {
|
|
||||||
out->sw1 = status[0];
|
|
||||||
out->sw2 = status[1];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (asn1_sm_response[2].flags & SC_ASN1_PRESENT) {
|
|
||||||
memcpy(out->mac, mac, mac_len);
|
|
||||||
out->mac_len = mac_len;
|
|
||||||
}
|
|
||||||
/* TODO: to be continued ... */
|
|
||||||
|
|
||||||
return SC_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** parse answer of SM protected APDU returned by APDU or by 'GET RESPONSE'
|
|
||||||
* @param card 'sc_card' smartcard object
|
|
||||||
* @param resp_data 'raw data returned by SM protected APDU
|
|
||||||
* @param resp_len 'length of raw data returned by SM protected APDU
|
|
||||||
* @param ref_rv 'status word returned by APDU or 'GET RESPONSE' (can be different from status word encoded into SM response date)
|
|
||||||
* @param apdu 'sc_apdu' object to update
|
|
||||||
* @return SC_SUCCESS on success and an error code otherwise
|
|
||||||
*/
|
|
||||||
static int
|
|
||||||
sc_sm_update_apdu_response(struct sc_card *card, unsigned char *resp_data, size_t resp_len, int ref_rv,
|
|
||||||
struct sc_apdu *apdu)
|
|
||||||
{
|
|
||||||
struct sm_card_response sm_resp;
|
|
||||||
int r;
|
|
||||||
|
|
||||||
if (!apdu)
|
|
||||||
return SC_ERROR_INVALID_ARGUMENTS;
|
|
||||||
else if (!resp_data || !resp_len)
|
|
||||||
return SC_SUCCESS;
|
|
||||||
|
|
||||||
memset(&sm_resp, 0, sizeof(sm_resp));
|
|
||||||
r = sc_sm_parse_answer(card->ctx, resp_data, resp_len, &sm_resp);
|
|
||||||
if (r)
|
|
||||||
return r;
|
|
||||||
else if (!sm_resp.sw1 && !sm_resp.sw2)
|
|
||||||
return SC_ERROR_INVALID_DATA;
|
|
||||||
else if (ref_rv != sc_check_sw(card, sm_resp.sw1, sm_resp.sw2))
|
|
||||||
return SC_ERROR_INVALID_DATA;
|
|
||||||
|
|
||||||
if (sm_resp.mac_len) {
|
|
||||||
if (sm_resp.mac_len > sizeof(apdu->mac))
|
|
||||||
return SC_ERROR_INVALID_DATA;
|
|
||||||
memcpy(apdu->mac, sm_resp.mac, sm_resp.mac_len);
|
|
||||||
apdu->mac_len = sm_resp.mac_len;
|
|
||||||
}
|
|
||||||
|
|
||||||
apdu->sw1 = sm_resp.sw1;
|
|
||||||
apdu->sw2 = sm_resp.sw2;
|
|
||||||
|
|
||||||
return SC_SUCCESS;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*********************************************************************/
|
/*********************************************************************/
|
||||||
/* higher level APDU transfer handling functions */
|
/* higher level APDU transfer handling functions */
|
||||||
@ -354,7 +265,8 @@ sc_sm_update_apdu_response(struct sc_card *card, unsigned char *resp_data, size_
|
|||||||
* @param apdu sc_apdu_t object to check
|
* @param apdu sc_apdu_t object to check
|
||||||
* @return SC_SUCCESS on success and an error code otherwise
|
* @return SC_SUCCESS on success and an error code otherwise
|
||||||
*/
|
*/
|
||||||
static int sc_check_apdu(sc_card_t *card, const sc_apdu_t *apdu)
|
int
|
||||||
|
sc_check_apdu(sc_card_t *card, const sc_apdu_t *apdu)
|
||||||
{
|
{
|
||||||
if ((apdu->cse & ~SC_APDU_SHORT_MASK) == 0) {
|
if ((apdu->cse & ~SC_APDU_SHORT_MASK) == 0) {
|
||||||
/* length check for short APDU */
|
/* length check for short APDU */
|
||||||
@ -441,7 +353,8 @@ error:
|
|||||||
* APDU if one of the SC_APDU_CASE_? types is used.
|
* APDU if one of the SC_APDU_CASE_? types is used.
|
||||||
* @param apdu APDU object
|
* @param apdu APDU object
|
||||||
*/
|
*/
|
||||||
static void sc_detect_apdu_cse(const sc_card_t *card, sc_apdu_t *apdu)
|
static void
|
||||||
|
sc_detect_apdu_cse(const sc_card_t *card, sc_apdu_t *apdu)
|
||||||
{
|
{
|
||||||
if (apdu->cse == SC_APDU_CASE_2 || apdu->cse == SC_APDU_CASE_3 ||
|
if (apdu->cse == SC_APDU_CASE_2 || apdu->cse == SC_APDU_CASE_3 ||
|
||||||
apdu->cse == SC_APDU_CASE_4) {
|
apdu->cse == SC_APDU_CASE_4) {
|
||||||
@ -458,48 +371,6 @@ static void sc_detect_apdu_cse(const sc_card_t *card, sc_apdu_t *apdu)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef ENABLE_SM
|
|
||||||
static int
|
|
||||||
sc_single_sm_transmit(struct sc_card *card, struct sc_apdu *apdu)
|
|
||||||
{
|
|
||||||
struct sc_context *ctx = card->ctx;
|
|
||||||
struct sc_apdu *sm_apdu = NULL;
|
|
||||||
int rv;
|
|
||||||
|
|
||||||
LOG_FUNC_CALLED(ctx);
|
|
||||||
sc_log(ctx, "SM_MODE:%X", card->sm_ctx.sm_mode);
|
|
||||||
if (!card->sm_ctx.ops.get_sm_apdu || !card->sm_ctx.ops.free_sm_apdu)
|
|
||||||
LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_SUPPORTED);
|
|
||||||
|
|
||||||
/* get SM encoded APDU */
|
|
||||||
rv = card->sm_ctx.ops.get_sm_apdu(card, apdu, &sm_apdu);
|
|
||||||
if (rv == SC_ERROR_SM_NOT_APPLIED) {
|
|
||||||
/* SM wrap of this APDU is ignored by card driver.
|
|
||||||
* Send plain APDU to the reader driver */
|
|
||||||
rv = card->reader->ops->transmit(card->reader, apdu);
|
|
||||||
LOG_FUNC_RETURN(ctx, rv);
|
|
||||||
}
|
|
||||||
LOG_TEST_RET(ctx, rv, "get SM APDU error");
|
|
||||||
|
|
||||||
/* check if SM APDU is still valid */
|
|
||||||
rv = sc_check_apdu(card, sm_apdu);
|
|
||||||
if (rv < 0) {
|
|
||||||
card->sm_ctx.ops.free_sm_apdu(card, apdu, &sm_apdu);
|
|
||||||
LOG_TEST_RET(ctx, rv, "cannot validate SM encoded APDU");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* send APDU to the reader driver */
|
|
||||||
rv = card->reader->ops->transmit(card->reader, sm_apdu);
|
|
||||||
LOG_TEST_RET(ctx, rv, "unable to transmit APDU");
|
|
||||||
|
|
||||||
/* decode SM answer and free temporary SM related data */
|
|
||||||
rv = card->sm_ctx.ops.free_sm_apdu(card, apdu, &sm_apdu);
|
|
||||||
|
|
||||||
LOG_FUNC_RETURN(ctx, rv);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
sc_single_transmit(struct sc_card *card, struct sc_apdu *apdu)
|
sc_single_transmit(struct sc_card *card, struct sc_apdu *apdu)
|
||||||
{
|
{
|
||||||
@ -514,7 +385,7 @@ sc_single_transmit(struct sc_card *card, struct sc_apdu *apdu)
|
|||||||
apdu->cla, apdu->ins, apdu->p1, apdu->p2, apdu->datalen, apdu->data);
|
apdu->cla, apdu->ins, apdu->p1, apdu->p2, apdu->datalen, apdu->data);
|
||||||
#ifdef ENABLE_SM
|
#ifdef ENABLE_SM
|
||||||
if (card->sm_ctx.sm_mode == SM_MODE_TRANSMIT)
|
if (card->sm_ctx.sm_mode == SM_MODE_TRANSMIT)
|
||||||
return sc_single_sm_transmit(card, apdu);
|
return sc_sm_single_transmit(card, apdu);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* send APDU to the reader driver */
|
/* send APDU to the reader driver */
|
||||||
@ -524,6 +395,7 @@ sc_single_transmit(struct sc_card *card, struct sc_apdu *apdu)
|
|||||||
LOG_FUNC_RETURN(ctx, rv);
|
LOG_FUNC_RETURN(ctx, rv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
sc_set_le_and_transmit(struct sc_card *card, struct sc_apdu *apdu, size_t olen)
|
sc_set_le_and_transmit(struct sc_card *card, struct sc_apdu *apdu, size_t olen)
|
||||||
{
|
{
|
||||||
|
@ -120,7 +120,6 @@ const char *sc_strerror(int error)
|
|||||||
};
|
};
|
||||||
const int p15i_base = -SC_ERROR_PKCS15INIT;
|
const int p15i_base = -SC_ERROR_PKCS15INIT;
|
||||||
|
|
||||||
const int sm_base = -SC_ERROR_SM;
|
|
||||||
const char *sm_errors[] = {
|
const char *sm_errors[] = {
|
||||||
"Generic Secure Messaging error",
|
"Generic Secure Messaging error",
|
||||||
"Data enciphering error",
|
"Data enciphering error",
|
||||||
@ -131,9 +130,12 @@ const char *sc_strerror(int error)
|
|||||||
"Cannot authenticate card",
|
"Cannot authenticate card",
|
||||||
"Random generation error",
|
"Random generation error",
|
||||||
"Secure messaging keyset not found",
|
"Secure messaging keyset not found",
|
||||||
"IFD data missing"
|
"IFD data missing",
|
||||||
|
"SM not applied",
|
||||||
|
"SM session already active",
|
||||||
|
"Invalid checksum"
|
||||||
};
|
};
|
||||||
|
const int sm_base = -SC_ERROR_SM;
|
||||||
|
|
||||||
const char *misc_errors[] = {
|
const char *misc_errors[] = {
|
||||||
"Unknown error",
|
"Unknown error",
|
||||||
|
@ -110,17 +110,19 @@ extern "C" {
|
|||||||
#define SC_ERROR_FILE_TOO_SMALL -1510
|
#define SC_ERROR_FILE_TOO_SMALL -1510
|
||||||
|
|
||||||
/* Related to secure messaging */
|
/* Related to secure messaging */
|
||||||
#define SC_ERROR_SM -1600
|
#define SC_ERROR_SM -1600
|
||||||
#define SC_ERROR_SM_ENCRYPT_FAILED -1601
|
#define SC_ERROR_SM_ENCRYPT_FAILED -1601
|
||||||
#define SC_ERROR_SM_INVALID_LEVEL -1602
|
#define SC_ERROR_SM_INVALID_LEVEL -1602
|
||||||
#define SC_ERROR_SM_NO_SESSION_KEYS -1603
|
#define SC_ERROR_SM_NO_SESSION_KEYS -1603
|
||||||
#define SC_ERROR_SM_INVALID_SESSION_KEY -1604
|
#define SC_ERROR_SM_INVALID_SESSION_KEY -1604
|
||||||
#define SC_ERROR_SM_NOT_INITIALIZED -1605
|
#define SC_ERROR_SM_NOT_INITIALIZED -1605
|
||||||
#define SC_ERROR_SM_AUTHENTICATION_FAILED -1606
|
#define SC_ERROR_SM_AUTHENTICATION_FAILED -1606
|
||||||
#define SC_ERROR_SM_RAND_FAILED -1607
|
#define SC_ERROR_SM_RAND_FAILED -1607
|
||||||
#define SC_ERROR_SM_KEYSET_NOT_FOUND -1608
|
#define SC_ERROR_SM_KEYSET_NOT_FOUND -1608
|
||||||
#define SC_ERROR_SM_IFD_DATA_MISSING -1609
|
#define SC_ERROR_SM_IFD_DATA_MISSING -1609
|
||||||
#define SC_ERROR_SM_NOT_APPLIED -1610
|
#define SC_ERROR_SM_NOT_APPLIED -1610
|
||||||
|
#define SC_ERROR_SM_SESSION_ALREADY_ACTIVE -1611
|
||||||
|
#define SC_ERROR_SM_INVALID_CHECKSUM -1612
|
||||||
|
|
||||||
|
|
||||||
/* Errors that do not fit the categories above */
|
/* Errors that do not fit the categories above */
|
||||||
|
@ -306,6 +306,9 @@ sc_remote_data_init
|
|||||||
sc_crc32
|
sc_crc32
|
||||||
sc_pkcs15_convert_prkey
|
sc_pkcs15_convert_prkey
|
||||||
sc_pkcs15_convert_pubkey
|
sc_pkcs15_convert_pubkey
|
||||||
|
sc_sm_parse_answer
|
||||||
|
sc_sm_update_apdu_response
|
||||||
|
sc_sm_single_transmit
|
||||||
iasecc_sdo_encode_update_field
|
iasecc_sdo_encode_update_field
|
||||||
iasecc_sm_create_file
|
iasecc_sm_create_file
|
||||||
iasecc_sm_delete_file
|
iasecc_sm_delete_file
|
||||||
|
179
src/libopensc/sm.c
Normal file
179
src/libopensc/sm.c
Normal file
@ -0,0 +1,179 @@
|
|||||||
|
/*
|
||||||
|
* sm.c: Secure Messaging helper functions
|
||||||
|
*
|
||||||
|
* Copyright (C) 2013 Viktor Tarasov <viktor.tarasov@gmail.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
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "internal.h"
|
||||||
|
#include "asn1.h"
|
||||||
|
|
||||||
|
static const struct sc_asn1_entry c_asn1_sm_response[4] = {
|
||||||
|
{ "encryptedData", SC_ASN1_OCTET_STRING, SC_ASN1_CTX | 7, SC_ASN1_OPTIONAL, NULL, NULL },
|
||||||
|
{ "statusWord", SC_ASN1_OCTET_STRING, SC_ASN1_CTX | 0x19, 0, NULL, NULL },
|
||||||
|
{ "mac", SC_ASN1_OCTET_STRING, SC_ASN1_CTX | 0x0E, 0, NULL, NULL },
|
||||||
|
{ NULL, 0, 0, 0, NULL, NULL }
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef ENABLE_SM
|
||||||
|
int
|
||||||
|
sc_sm_parse_answer(struct sc_card *card, unsigned char *resp_data, size_t resp_len,
|
||||||
|
struct sm_card_response *out)
|
||||||
|
{
|
||||||
|
struct sc_asn1_entry asn1_sm_response[4];
|
||||||
|
unsigned char data[SC_MAX_APDU_BUFFER_SIZE];
|
||||||
|
size_t data_len = sizeof(data);
|
||||||
|
unsigned char status[2] = {0, 0};
|
||||||
|
size_t status_len = sizeof(status);
|
||||||
|
unsigned char mac[8];
|
||||||
|
size_t mac_len = sizeof(mac);
|
||||||
|
int rv;
|
||||||
|
|
||||||
|
if (!resp_data || !resp_len || !out)
|
||||||
|
return SC_ERROR_INVALID_ARGUMENTS;
|
||||||
|
|
||||||
|
sc_copy_asn1_entry(c_asn1_sm_response, asn1_sm_response);
|
||||||
|
|
||||||
|
sc_format_asn1_entry(asn1_sm_response + 0, data, &data_len, 0);
|
||||||
|
sc_format_asn1_entry(asn1_sm_response + 1, status, &status_len, 0);
|
||||||
|
sc_format_asn1_entry(asn1_sm_response + 2, mac, &mac_len, 0);
|
||||||
|
|
||||||
|
rv = sc_asn1_decode(card->ctx, asn1_sm_response, resp_data, resp_len, NULL, NULL);
|
||||||
|
if (rv)
|
||||||
|
return rv;
|
||||||
|
|
||||||
|
if (asn1_sm_response[0].flags & SC_ASN1_PRESENT) {
|
||||||
|
if (data_len > sizeof(out->data))
|
||||||
|
return SC_ERROR_BUFFER_TOO_SMALL;
|
||||||
|
memcpy(out->data, data, data_len);
|
||||||
|
out->data_len = data_len;
|
||||||
|
}
|
||||||
|
if (asn1_sm_response[1].flags & SC_ASN1_PRESENT) {
|
||||||
|
if (!status[0])
|
||||||
|
return SC_ERROR_INVALID_DATA;
|
||||||
|
out->sw1 = status[0];
|
||||||
|
out->sw2 = status[1];
|
||||||
|
}
|
||||||
|
if (asn1_sm_response[2].flags & SC_ASN1_PRESENT) {
|
||||||
|
memcpy(out->mac, mac, mac_len);
|
||||||
|
out->mac_len = mac_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SC_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** parse answer of SM protected APDU returned by APDU or by 'GET RESPONSE'
|
||||||
|
* @param card 'sc_card' smartcard object
|
||||||
|
* @param resp_data 'raw data returned by SM protected APDU
|
||||||
|
* @param resp_len 'length of raw data returned by SM protected APDU
|
||||||
|
* @param ref_rv 'status word returned by APDU or 'GET RESPONSE' (can be different from status word encoded into SM response date)
|
||||||
|
* @param apdu 'sc_apdu' object to update
|
||||||
|
* @return SC_SUCCESS on success and an error code otherwise
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
sc_sm_update_apdu_response(struct sc_card *card, unsigned char *resp_data, size_t resp_len,
|
||||||
|
int ref_rv, struct sc_apdu *apdu)
|
||||||
|
{
|
||||||
|
struct sm_card_response sm_resp;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
if (!apdu)
|
||||||
|
return SC_ERROR_INVALID_ARGUMENTS;
|
||||||
|
else if (!resp_data || !resp_len)
|
||||||
|
return SC_SUCCESS;
|
||||||
|
|
||||||
|
memset(&sm_resp, 0, sizeof(sm_resp));
|
||||||
|
r = sc_sm_parse_answer(card, resp_data, resp_len, &sm_resp);
|
||||||
|
if (r)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
if (sm_resp.mac_len) {
|
||||||
|
if (sm_resp.mac_len > sizeof(apdu->mac))
|
||||||
|
return SC_ERROR_INVALID_DATA;
|
||||||
|
memcpy(apdu->mac, sm_resp.mac, sm_resp.mac_len);
|
||||||
|
apdu->mac_len = sm_resp.mac_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
apdu->sw1 = sm_resp.sw1;
|
||||||
|
apdu->sw2 = sm_resp.sw2;
|
||||||
|
|
||||||
|
return SC_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
sc_sm_single_transmit(struct sc_card *card, struct sc_apdu *apdu)
|
||||||
|
{
|
||||||
|
struct sc_context *ctx = card->ctx;
|
||||||
|
struct sc_apdu *sm_apdu = NULL;
|
||||||
|
int rv;
|
||||||
|
|
||||||
|
LOG_FUNC_CALLED(ctx);
|
||||||
|
sc_log(ctx, "SM_MODE:%X", card->sm_ctx.sm_mode);
|
||||||
|
if (!card->sm_ctx.ops.get_sm_apdu || !card->sm_ctx.ops.free_sm_apdu)
|
||||||
|
LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_SUPPORTED);
|
||||||
|
|
||||||
|
/* get SM encoded APDU */
|
||||||
|
rv = card->sm_ctx.ops.get_sm_apdu(card, apdu, &sm_apdu);
|
||||||
|
if (rv == SC_ERROR_SM_NOT_APPLIED) {
|
||||||
|
/* SM wrap of this APDU is ignored by card driver.
|
||||||
|
* Send plain APDU to the reader driver */
|
||||||
|
rv = card->reader->ops->transmit(card->reader, apdu);
|
||||||
|
LOG_FUNC_RETURN(ctx, rv);
|
||||||
|
}
|
||||||
|
LOG_TEST_RET(ctx, rv, "get SM APDU error");
|
||||||
|
|
||||||
|
/* check if SM APDU is still valid */
|
||||||
|
rv = sc_check_apdu(card, sm_apdu);
|
||||||
|
if (rv < 0) {
|
||||||
|
card->sm_ctx.ops.free_sm_apdu(card, apdu, &sm_apdu);
|
||||||
|
LOG_TEST_RET(ctx, rv, "cannot validate SM encoded APDU");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* send APDU to the reader driver */
|
||||||
|
rv = card->reader->ops->transmit(card->reader, sm_apdu);
|
||||||
|
LOG_TEST_RET(ctx, rv, "unable to transmit APDU");
|
||||||
|
|
||||||
|
/* decode SM answer and free temporary SM related data */
|
||||||
|
rv = card->sm_ctx.ops.free_sm_apdu(card, apdu, &sm_apdu);
|
||||||
|
|
||||||
|
LOG_FUNC_RETURN(ctx, rv);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
int
|
||||||
|
sc_sm_parse_answer(struct sc_context *ctx, unsigned char *resp_data, size_t resp_len,
|
||||||
|
struct sm_card_response *out)
|
||||||
|
{
|
||||||
|
return SC_ERROR_NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
int
|
||||||
|
sc_sm_update_apdu_response(struct sc_card *card, unsigned char *resp_data, size_t resp_len, int ref_rv,
|
||||||
|
struct sc_apdu *apdu)
|
||||||
|
{
|
||||||
|
return SC_ERROR_NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
int
|
||||||
|
sc_sm_single_transmit(struct sc_card *card, struct sc_apdu *apdu)
|
||||||
|
{
|
||||||
|
return SC_ERROR_NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
#endif
|
@ -43,21 +43,22 @@ extern "C" {
|
|||||||
|
|
||||||
#define SM_TYPE_GP_SCP01 0x100
|
#define SM_TYPE_GP_SCP01 0x100
|
||||||
#define SM_TYPE_CWA14890 0x400
|
#define SM_TYPE_CWA14890 0x400
|
||||||
|
#define SM_TYPE_DH_RSA 0x500
|
||||||
|
|
||||||
#define SM_MODE_NONE 0x0
|
#define SM_MODE_NONE 0x0
|
||||||
#define SM_MODE_ACL 0x100
|
#define SM_MODE_ACL 0x100
|
||||||
#define SM_MODE_TRANSMIT 0x200
|
#define SM_MODE_TRANSMIT 0x200
|
||||||
|
|
||||||
#define SM_CMD_INITIALIZE 0x10
|
#define SM_CMD_INITIALIZE 0x10
|
||||||
#define SM_CMD_MUTUAL_AUTHENTICATION 0x20
|
#define SM_CMD_MUTUAL_AUTHENTICATION 0x20
|
||||||
#define SM_CMD_RSA 0x100
|
#define SM_CMD_RSA 0x100
|
||||||
#define SM_CMD_RSA_GENERATE 0x101
|
#define SM_CMD_RSA_GENERATE 0x101
|
||||||
#define SM_CMD_RSA_UPDATE 0x102
|
#define SM_CMD_RSA_UPDATE 0x102
|
||||||
#define SM_CMD_RSA_READ_PUBLIC 0x103
|
#define SM_CMD_RSA_READ_PUBLIC 0x103
|
||||||
#define SM_CMD_FILE 0x200
|
#define SM_CMD_FILE 0x200
|
||||||
#define SM_CMD_FILE_READ 0x201
|
#define SM_CMD_FILE_READ 0x201
|
||||||
#define SM_CMD_FILE_UPDATE 0x202
|
#define SM_CMD_FILE_UPDATE 0x202
|
||||||
#define SM_CMD_FILE_CREATE 0x203
|
#define SM_CMD_FILE_CREATE 0x203
|
||||||
#define SM_CMD_FILE_DELETE 0x204
|
#define SM_CMD_FILE_DELETE 0x204
|
||||||
#define SM_CMD_PIN 0x300
|
#define SM_CMD_PIN 0x300
|
||||||
#define SM_CMD_PIN_VERIFY 0x301
|
#define SM_CMD_PIN_VERIFY 0x301
|
||||||
@ -200,6 +201,26 @@ struct sm_cwa_session {
|
|||||||
size_t mdata_len;
|
size_t mdata_len;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @struct sm_dh_session
|
||||||
|
* DH SM session data:
|
||||||
|
*/
|
||||||
|
struct sm_dh_session {
|
||||||
|
struct sc_tlv_data g;
|
||||||
|
struct sc_tlv_data N;
|
||||||
|
struct sc_tlv_data ifd_p;
|
||||||
|
struct sc_tlv_data ifd_y;
|
||||||
|
struct sc_tlv_data icc_p;
|
||||||
|
struct sc_tlv_data shared_secret;
|
||||||
|
|
||||||
|
unsigned char session_enc[16];
|
||||||
|
unsigned char session_mac[16];
|
||||||
|
|
||||||
|
unsigned char card_challenge[32];
|
||||||
|
|
||||||
|
unsigned char ssc[8];
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @struct sc_info is the
|
* @struct sc_info is the
|
||||||
* placehold for the secure messaging working data:
|
* placehold for the secure messaging working data:
|
||||||
@ -219,6 +240,7 @@ struct sm_info {
|
|||||||
union {
|
union {
|
||||||
struct sm_gp_session gp;
|
struct sm_gp_session gp;
|
||||||
struct sm_cwa_session cwa;
|
struct sm_cwa_session cwa;
|
||||||
|
struct sm_dh_session dh;
|
||||||
} session;
|
} session;
|
||||||
|
|
||||||
struct sc_serial_number serialnr;
|
struct sc_serial_number serialnr;
|
||||||
@ -329,6 +351,10 @@ typedef struct sm_context {
|
|||||||
|
|
||||||
int iasecc_sm_external_authentication(struct sc_card *, unsigned, int *);
|
int iasecc_sm_external_authentication(struct sc_card *, unsigned, int *);
|
||||||
|
|
||||||
|
int sc_sm_parse_answer(struct sc_card *, unsigned char *, size_t, struct sm_card_response *);
|
||||||
|
int sc_sm_update_apdu_response(struct sc_card *, unsigned char *, size_t, int, struct sc_apdu *);
|
||||||
|
int sc_sm_single_transmit(struct sc_card *, struct sc_apdu *);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user