#define __CWA14890_C__
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#if defined(ENABLE_OPENSSL) && defined(ENABLE_SM)
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "opensc.h"
#include "cardctl.h"
#include "internal.h"
#include <openssl/rsa.h>
#include <openssl/bn.h>
#include <openssl/x509.h>
#include <openssl/des.h>
#include <openssl/rand.h>
#include "cwa14890.h"
#include "cwa-dnie.h"
#define MAX_RESP_BUFFER_SIZE 2048
typedef struct cwa_tlv_st {
u8 *buf;
size_t buflen;
unsigned int tag;
size_t len;
u8 *data;
} cwa_tlv_t;
static void cwa_trace_apdu(sc_card_t * card, sc_apdu_t * apdu, int flag)
{
char buf[2048];
if (!card || !card->ctx || !apdu || card->ctx->debug < SC_LOG_DEBUG_NORMAL)
return;
if (flag == 0) {
if (apdu->datalen > 0) {
sc_hex_dump(apdu->data, apdu->datalen, buf, sizeof(buf));
sc_log(card->ctx,
"\nAPDU before encode: ==================================================\nCLA: %02X INS: %02X P1: %02X P2: %02X Lc: %02"SC_FORMAT_LEN_SIZE_T"X Le: %02"SC_FORMAT_LEN_SIZE_T"X DATA: [%5"SC_FORMAT_LEN_SIZE_T"u bytes]\n%s======================================================================\n",
apdu->cla, apdu->ins, apdu->p1, apdu->p2,
apdu->lc, apdu->le, apdu->datalen, buf);
} else {
sc_log(card->ctx,
"\nAPDU before encode: ==================================================\nCLA: %02X INS: %02X P1: %02X P2: %02X Lc: %02"SC_FORMAT_LEN_SIZE_T"X Le: %02"SC_FORMAT_LEN_SIZE_T"X (NO DATA)\n======================================================================\n",
apdu->cla, apdu->ins, apdu->p1, apdu->p2,
apdu->lc, apdu->le);
}
} else {
sc_hex_dump(apdu->resp, apdu->resplen, buf, sizeof(buf));
sc_log(card->ctx,
"\nAPDU response after decode: ==========================================\nSW1: %02X SW2: %02X RESP: [%5"SC_FORMAT_LEN_SIZE_T"u bytes]\n%s======================================================================\n",
apdu->sw1, apdu->sw2, apdu->resplen, buf);
}
}
static int cwa_increase_ssc(sc_card_t * card)
{
int n;
struct sm_cwa_session * sm = &card->sm_ctx.info.session.cwa;
if (!card || !card->ctx )
return SC_ERROR_INVALID_ARGUMENTS;
LOG_FUNC_CALLED(card->ctx);
sc_log(card->ctx, "Curr SSC: '%s'", sc_dump_hex(sm->ssc, 8));
for (n = 7; n >= 0; n--) {
sm->ssc[n]++;
if ((sm->ssc[n]) != 0x00)
break;
}
sc_log(card->ctx, "Next SSC: '%s'", sc_dump_hex(sm->ssc, 8));
LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
}
static void cwa_iso7816_padding(u8 * buf, size_t * buflen)
{
buf[*buflen] = 0x80;
(*buflen)++;
for (; *buflen & 0x07; (*buflen)++)
buf[*buflen] = 0x00;
}
static int cwa_compose_tlv(sc_card_t * card,
u8 tag,
size_t len, u8 * data, u8 ** out, size_t * outlen)
{
u8 *pt;
size_t size;
sc_context_t *ctx;
if (!card || !card->ctx || !out || !outlen)
return SC_ERROR_INVALID_ARGUMENTS;
ctx = card->ctx;
LOG_FUNC_CALLED(ctx);
pt = *out;
size = *outlen;
*(pt + size++) = tag;
if (len < 0x80) {
*(pt + size++) = len;
} else if (len < 0x00000100) {
*(pt + size++) = 0x81;
*(pt + size++) = 0xff & len;
} else if (len < 0x00010000) {
*(pt + size++) = 0x82;
*(pt + size++) = 0xff & (len >> 8);
*(pt + size++) = 0xff & len;
} else if (len < 0x01000000) {
*(pt + size++) = 0x83;
*(pt + size++) = 0xff & (len >> 16);
*(pt + size++) = 0xff & (len >> 8);
*(pt + size++) = 0xff & len;
} else {
LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS);
}
if (len != 0)
memcpy(pt + size, data, len);
size += len;
*outlen = size;
LOG_FUNC_RETURN(ctx, SC_SUCCESS);
}
static int cwa_parse_tlv(sc_card_t * card,
u8 * buffer, size_t datalen,
cwa_tlv_t tlv_array[]
)
{
size_t n = 0;
size_t next = 0;
sc_context_t *ctx = NULL;
if (!card || !card->ctx)
return SC_ERROR_INVALID_ARGUMENTS;
ctx = card->ctx;
LOG_FUNC_CALLED(ctx);
if (!tlv_array)
LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS);
for (n = 0; n < datalen; n += next) {
cwa_tlv_t *tlv = NULL;
size_t j = 2;
switch (*(buffer + n)) {
case CWA_SM_PLAIN_TAG:
tlv = &tlv_array[0];
break;
case CWA_SM_CRYPTO_TAG:
tlv = &tlv_array[1];
break;
case CWA_SM_MAC_TAG:
tlv = &tlv_array[2];
break;
case CWA_SM_STATUS_TAG:
tlv = &tlv_array[3];
break;
default:
sc_log(ctx, "Invalid TLV Tag type: '0x%02X'",
*(buffer + n));
LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_DATA);
}
tlv->buf = buffer + n;
tlv->tag = 0xff & *(buffer + n);
tlv->len = 0;
switch (0xff & *(buffer + n + 1)) {
case 0x84:
tlv->len = (0xff & *(buffer + n + j++));
case 0x83:
tlv->len =
(tlv->len << 8) + (0xff & *(buffer + n + j++));
case 0x82:
tlv->len =
(tlv->len << 8) + (0xff & *(buffer + n + j++));
case 0x81:
tlv->len =
(tlv->len << 8) + (0xff & *(buffer + n + j++));
break;
case 0x80:
tlv->len =
(tlv->len << 8) + (0xff & *(buffer + n + j++));
break;
default:
if ((*(buffer + n + 1) & 0xff) < 0x80) {
tlv->len = 0xff & *(buffer + n + 1);
} else {
sc_log(ctx, "Invalid tag length indicator: %d",
*(buffer + n + 1));
LOG_FUNC_RETURN(ctx, SC_ERROR_WRONG_LENGTH);
}
}
tlv->data = buffer + n + j;
tlv->buflen = j + tlv->len;;
sc_log(ctx, "Found Tag: '0x%02X': Length: '%"SC_FORMAT_LEN_SIZE_T"u' Value:\n%s",
tlv->tag, tlv->len, sc_dump_hex(tlv->data, tlv->len));
next = tlv->buflen;
}
LOG_FUNC_RETURN(ctx, SC_SUCCESS);
}
static int cwa_verify_icc_certificates(sc_card_t * card,
cwa_provider_t * provider,
X509 * sub_ca_cert, X509 * icc_cert)
{
char *msg = NULL;
int res = SC_SUCCESS;
EVP_PKEY *root_ca_key = NULL;
EVP_PKEY *sub_ca_key = NULL;
sc_context_t *ctx = NULL;
if (!card || !card->ctx || !provider)
return SC_ERROR_INVALID_ARGUMENTS;
ctx = card->ctx;
LOG_FUNC_CALLED(ctx);
if (!sub_ca_cert || !icc_cert)
LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS);
res = provider->cwa_get_root_ca_pubkey(card, &root_ca_key);
if (res != SC_SUCCESS) {
msg = "Cannot get root CA public key";
res = SC_ERROR_INTERNAL;
goto verify_icc_certificates_end;
}
res = X509_verify(sub_ca_cert, root_ca_key);
if (!res) {
msg = "Cannot verify icc Sub-CA certificate";
res = SC_ERROR_SM_AUTHENTICATION_FAILED;
goto verify_icc_certificates_end;
}
sub_ca_key = X509_get_pubkey(sub_ca_cert);
res = X509_verify(icc_cert, sub_ca_key);
if (!res) {
msg = "Cannot verify icc certificate";
res = SC_ERROR_SM_AUTHENTICATION_FAILED;
goto verify_icc_certificates_end;
}
res = SC_SUCCESS;
verify_icc_certificates_end:
if (root_ca_key)
EVP_PKEY_free(root_ca_key);
if (sub_ca_key)
EVP_PKEY_free(sub_ca_key);
if (res != SC_SUCCESS)
sc_log(ctx, "%s", msg);
LOG_FUNC_RETURN(ctx, res);
}
static int cwa_verify_cvc_certificate(sc_card_t * card,
const u8 * cert, size_t len)
{
sc_apdu_t apdu;
int result = SC_SUCCESS;
sc_context_t *ctx = NULL;
if (!card || !card->ctx)
return SC_ERROR_INVALID_ARGUMENTS;
ctx = card->ctx;
LOG_FUNC_CALLED(ctx);
if (!cert || (len <= 0))
LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS);
dnie_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x2A, 0x00, 0xAE, 0, len,
NULL, 0, cert, len);
result = sc_transmit_apdu(card, &apdu);
LOG_TEST_RET(ctx, result, "Verify CVC certificate failed");
result = sc_check_sw(card, apdu.sw1, apdu.sw2);
LOG_FUNC_RETURN(ctx, result);
}
static int cwa_set_security_env(sc_card_t * card,
u8 p1, u8 p2, u8 * buffer, size_t length)
{
sc_apdu_t apdu;
int result = SC_SUCCESS;
sc_context_t *ctx = NULL;
if (!card || !card->ctx)
return SC_ERROR_INVALID_ARGUMENTS;
ctx = card->ctx;
LOG_FUNC_CALLED(ctx);
if (!buffer || (length <= 0))
LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS);
dnie_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x22, p1, p2, 0, length,
NULL, 0, buffer, length);
result = sc_transmit_apdu(card, &apdu);
LOG_TEST_RET(ctx, result, "SM Set Security Environment failed");
result = sc_check_sw(card, apdu.sw1, apdu.sw2);
LOG_FUNC_RETURN(ctx, result);
}
static int cwa_internal_auth(sc_card_t * card, u8 * sig, size_t sig_len, u8 * data, size_t datalen)
{
sc_apdu_t apdu;
u8 rbuf[SC_MAX_APDU_BUFFER_SIZE];
int result = SC_SUCCESS;
sc_context_t *ctx = NULL;
if (!card || !card->ctx)
return SC_ERROR_INVALID_ARGUMENTS;
ctx = card->ctx;
LOG_FUNC_CALLED(ctx);
if (!data || (datalen <= 0))
LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS);
dnie_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0x88, 0x00, 0x00, 0x80, datalen,
rbuf, sizeof(rbuf), data, datalen);
result = sc_transmit_apdu(card, &apdu);
LOG_TEST_RET(ctx, result, "SM internal auth failed");
result = sc_check_sw(card, apdu.sw1, apdu.sw2);
LOG_TEST_RET(ctx, result, "SM internal auth invalid response");
if (apdu.resplen != sig_len)
LOG_FUNC_RETURN(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED);
memcpy(sig, apdu.resp, apdu.resplen);
LOG_FUNC_RETURN(ctx, SC_SUCCESS);
}
static int cwa_prepare_external_auth(sc_card_t * card,
RSA * icc_pubkey,
RSA * ifd_privkey,
u8 * sig,
size_t sig_len)
{
char *msg = NULL;
int res = SC_SUCCESS;
u8 *buf1;
u8 *buf2;
u8 *buf3;
int len1, len2, len3;
u8 *sha_buf;
u8 *sha_data;
BIGNUM *bn = NULL;
BIGNUM *bnsub = NULL;
BIGNUM *bnres = NULL;
sc_context_t *ctx = NULL;
const BIGNUM *ifd_privkey_n, *ifd_privkey_e, *ifd_privkey_d;
struct sm_cwa_session * sm = &card->sm_ctx.info.session.cwa;
if (!card || !card->ctx)
return SC_ERROR_INVALID_ARGUMENTS;
ctx = card->ctx;
LOG_FUNC_CALLED(ctx);
if (!icc_pubkey || !ifd_privkey || !sm)
LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS);
buf1 = calloc(128, sizeof(u8));
buf2 = calloc(128, sizeof(u8));
buf3 = calloc(128, sizeof(u8));
sha_buf = calloc(74 + 32 + 8 + 8, sizeof(u8));
sha_data = calloc(SHA_DIGEST_LENGTH, sizeof(u8));
if (!buf1 || !buf2 || !buf3 || !sha_buf || !sha_data) {
msg = "prepare external auth: calloc error";
res = SC_ERROR_OUT_OF_MEMORY;
goto prepare_external_auth_end;
}
buf3[0] = 0x6A;
RAND_bytes(buf3 + 1, 74);
RAND_bytes(sm->ifd.k, 32);
memcpy(buf3 + 1 + 74, sm->ifd.k, 32);
memcpy(sha_buf, buf3 + 1, 74);
memcpy(sha_buf + 74, buf3 + 1 + 74, 32);
memcpy(sha_buf + 74 + 32, sm->icc.rnd, 8);
memcpy(sha_buf + 74 + 32 + 8, sm->icc.sn, 8);
SHA1(sha_buf, 74 + 32 + 8 + 8, sha_data);
memcpy(buf3 + 1 + 74 + 32, sha_data, SHA_DIGEST_LENGTH);
buf3[127] = 0xBC;
len2 = RSA_private_decrypt(128, buf3, buf2, ifd_privkey, RSA_NO_PADDING);
if (len2 < 0) {
msg = "Prepare external auth: ifd_privk encrypt failed";
res = SC_ERROR_SM_ENCRYPT_FAILED;
goto prepare_external_auth_end;
}
bn = BN_bin2bn(buf2, len2, NULL);
bnsub = BN_new();
if (!bn || !bnsub) {
msg = "Prepare external auth: BN creation failed";
res = SC_ERROR_INTERNAL;
goto prepare_external_auth_end;
}
RSA_get0_key(ifd_privkey, &ifd_privkey_n, &ifd_privkey_e, &ifd_privkey_d);
res = BN_sub(bnsub, ifd_privkey_n, bn);
if (res == 0) {
msg = "Prepare external auth: BN sigmin evaluation failed";
res = SC_ERROR_INTERNAL;
goto prepare_external_auth_end;
}
bnres = (BN_cmp(bn, bnsub) < 0) ? bn : bnsub;
if (BN_num_bytes(bnres) > 128) {
msg = "Prepare external auth: BN sigmin result is too big";
res = SC_ERROR_INTERNAL;
goto prepare_external_auth_end;
}
len3 = BN_bn2bin(bnres, buf3);
if (len3 <= 0) {
msg = "Prepare external auth: BN to buffer conversion failed";
res = SC_ERROR_INTERNAL;
goto prepare_external_auth_end;
}
len1 = RSA_public_encrypt(len3, buf3, buf1, icc_pubkey, RSA_NO_PADDING);
if (len1 <= 0 || (size_t) len1 != sig_len) {
msg = "Prepare external auth: icc_pubk encrypt failed";
res = SC_ERROR_SM_ENCRYPT_FAILED;
goto prepare_external_auth_end;
}
memcpy(sig, buf1, len1);
res = SC_SUCCESS;
prepare_external_auth_end:
if (bn)
BN_free(bn);
if (bnsub)
BN_free(bnsub);
if (buf1) {
memset(buf1, 0, 128);
free(buf1);
}
if (buf2) {
memset(buf2, 0, 128);
free(buf2);
}
if (buf3) {
memset(buf3, 0, 128);
free(buf3);
}
if (sha_buf) {
memset(sha_buf, 0, 74 + 32 + 8 + 1 + 7);
free(sha_buf);
}
if (sha_data) {
memset(sha_data, 0, SHA_DIGEST_LENGTH);
free(sha_data);
}
if (res != SC_SUCCESS)
sc_log(ctx, "%s", msg);
LOG_FUNC_RETURN(ctx, res);
}
static int cwa_external_auth(sc_card_t * card, u8 * sig, size_t sig_len)
{
sc_apdu_t apdu;
int result = SC_SUCCESS;
sc_context_t *ctx = NULL;
if (!card || !card->ctx)
return SC_ERROR_INVALID_ARGUMENTS;
ctx = card->ctx;
LOG_FUNC_CALLED(ctx);
dnie_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x82, 0x00, 0x00, 0, sig_len,
NULL, 0, sig, sig_len);
result = sc_transmit_apdu(card, &apdu);
LOG_TEST_RET(ctx, result, "SM external auth failed");
result = sc_check_sw(card, apdu.sw1, apdu.sw2);
LOG_TEST_RET(ctx, result, "SM external auth invalid response");
LOG_FUNC_RETURN(ctx, SC_SUCCESS);
}
static int cwa_compute_session_keys(sc_card_t * card)
{
char *msg = NULL;
int n = 0;
int res = SC_SUCCESS;
u8 *kseed;
u8 *data;
u8 *sha_data;
u8 kenc[4] = { 0x00, 0x00, 0x00, 0x01 };
u8 kmac[4] = { 0x00, 0x00, 0x00, 0x02 };
sc_context_t *ctx = NULL;
struct sm_cwa_session * sm = &card->sm_ctx.info.session.cwa;
if (!card || !card->ctx)
return SC_ERROR_INVALID_ARGUMENTS;
ctx = card->ctx;
LOG_FUNC_CALLED(ctx);
kseed = calloc(32, sizeof(u8));
data = calloc(32 + 4, sizeof(u8));
sha_data = calloc(SHA_DIGEST_LENGTH, sizeof(u8));
if (!kseed || !data || !sha_data) {
msg = "Compute Session Keys: calloc() failed";
res = SC_ERROR_OUT_OF_MEMORY;
goto compute_session_keys_end;
}
for (n = 0; n < 32; n++)
*(kseed + n) = sm->icc.k[n] ^ sm->ifd.k[n];
memcpy(data, kseed, 32);
memcpy(data + 32, kenc, 4);
SHA1(data, 32 + 4, sha_data);
memcpy(sm->session_enc, sha_data, 16);
memset(data, 0, 32 + 4);
memset(sha_data, 0, SHA_DIGEST_LENGTH);
memcpy(data, kseed, 32);
memcpy(data + 32, kmac, 4);
SHA1(data, 32 + 4, sha_data);
memcpy(sm->session_mac, sha_data, 16);
memcpy(sm->ssc, sm->icc.rnd + 4, 4);
memcpy(sm->ssc + 4, sm->ifd.rnd + 4, 4);
res = SC_SUCCESS;
compute_session_keys_end:
if (kseed) {
memset(kseed, 0, 32);
free(kseed);
}
if (data) {
memset(data, 0, 32 + 4);
free(data);
}
if (sha_data) {
memset(sha_data, 0, SHA_DIGEST_LENGTH);
free(sha_data);
}
if (res != SC_SUCCESS)
sc_log(ctx, "%s", msg);
else {
sc_log(ctx, "Kenc: %s", sc_dump_hex(sm->session_enc, 16));
sc_log(ctx, "Kmac: %s", sc_dump_hex(sm->session_mac, 16));
sc_log(ctx, "SSC: %s", sc_dump_hex(sm->ssc, 8));
}
LOG_FUNC_RETURN(ctx, res);
}
static int cwa_compare_signature(u8 * data, size_t dlen, u8 * ifd_data)
{
u8 *buf = calloc(74 + 32 + 32, sizeof(u8));
u8 *sha = calloc(SHA_DIGEST_LENGTH, sizeof(u8));
int res = SC_SUCCESS;
if (!buf || !sha) {
res = SC_ERROR_OUT_OF_MEMORY;
goto compare_signature_end;
}
res = SC_ERROR_INVALID_DATA;
if (dlen != 128)
goto compare_signature_end;
if (data[0] != 0x6a)
goto compare_signature_end;
if (data[127] != 0xBC)
goto compare_signature_end;
memcpy(buf, data + 1, 74 + 32);
memcpy(buf + 74 + 32, ifd_data, 16);
SHA1(buf, 74 + 32 + 16, sha);
if (memcmp(data + 127 - SHA_DIGEST_LENGTH, sha, SHA_DIGEST_LENGTH) == 0)
res = SC_SUCCESS;
compare_signature_end:
if (buf)
free(buf);
if (sha)
free(sha);
return res;
}
static int cwa_verify_internal_auth(sc_card_t * card,
RSA * icc_pubkey,
RSA * ifd_privkey,
u8 * ifdbuf,
size_t ifdlen,
u8 * sig,
size_t sig_len)
{
int res = SC_SUCCESS;
char *msg = NULL;
u8 *buf1 = NULL;
u8 *buf2 = NULL;
u8 *buf3 = NULL;
int len1 = 0;
int len2 = 0;
int len3 = 0;
BIGNUM *bn = NULL;
BIGNUM *sigbn = NULL;
sc_context_t *ctx = NULL;
const BIGNUM *icc_pubkey_n, *icc_pubkey_e, *icc_pubkey_d;
struct sm_cwa_session * sm = &card->sm_ctx.info.session.cwa;
if (!card || !card->ctx)
return SC_ERROR_INVALID_ARGUMENTS;
ctx = card->ctx;
LOG_FUNC_CALLED(ctx);
if (!ifdbuf || (ifdlen != 16)) {
res = SC_ERROR_INVALID_ARGUMENTS;
msg = "Null buffers received as parameters";
goto verify_internal_done;
}
if (!icc_pubkey || !ifd_privkey) {
res = SC_ERROR_SM_NO_SESSION_KEYS;
msg = "Either provided icc_pubk or ifd_privk are null";
goto verify_internal_done;
}
buf1 = (u8 *) calloc(128, sizeof(u8));
buf2 = (u8 *) calloc(128, sizeof(u8));
buf3 = (u8 *) calloc(128, sizeof(u8));
if (!buf1 || !buf2 || !buf3) {
msg = "Verify Signature: calloc() error";
res = SC_ERROR_OUT_OF_MEMORY;
goto verify_internal_done;
}
len1 = RSA_private_decrypt(sig_len, sig, buf1, ifd_privkey, RSA_NO_PADDING);
if (len1 <= 0) {
msg = "Verify Signature: decrypt with ifd privk failed";
res = SC_ERROR_SM_ENCRYPT_FAILED;
goto verify_internal_done;
}
len3 = RSA_public_encrypt(len1, buf1, buf3, icc_pubkey, RSA_NO_PADDING);
if (len3 <= 0)
goto verify_nicc_sig;
res = cwa_compare_signature(buf3, len3, ifdbuf);
if (res == SC_SUCCESS)
goto verify_internal_ok;
verify_nicc_sig:
bn = BN_bin2bn(buf1, len1, NULL);
sigbn = BN_new();
if (!bn || !sigbn) {
msg = "Verify Signature: cannot bignums creation error";
res = SC_ERROR_OUT_OF_MEMORY;
goto verify_internal_done;
}
RSA_get0_key(icc_pubkey, &icc_pubkey_n, &icc_pubkey_e, &icc_pubkey_d);
res = BN_sub(sigbn, icc_pubkey_n, bn);
if (!res) {
msg = "Verify Signature: evaluation of N.ICC-SIG failed";
res = SC_ERROR_INTERNAL;
goto verify_internal_done;
}
len2 = BN_bn2bin(sigbn, buf2);
if (len2 <= 0) {
msg = "Verify Signature: cannot convert bignum to buffer";
res = SC_ERROR_INTERNAL;
goto verify_internal_done;
}
len3 = RSA_public_encrypt(len2, buf2, buf3, icc_pubkey, RSA_NO_PADDING);
if (len3 <= 0) {
msg = "Verify Signature: cannot get valid SIG data";
res = SC_ERROR_INVALID_DATA;
goto verify_internal_done;
}
res = cwa_compare_signature(buf3, len3, ifdbuf);
if (res != SC_SUCCESS) {
msg = "Verify Signature: cannot get valid SIG data";
res = SC_ERROR_INVALID_DATA;
goto verify_internal_done;
}
verify_internal_ok:
memcpy(sm->icc.k, buf3 + 1 + 74, 32);
res = SC_SUCCESS;
verify_internal_done:
if (buf1)
free(buf1);
if (buf2)
free(buf2);
if (buf3)
free(buf3);
if (bn)
BN_free(bn);
if (sigbn)
BN_free(sigbn);
if (res != SC_SUCCESS)
sc_log(ctx, "%s", msg);
LOG_FUNC_RETURN(ctx, res);
}
int cwa_create_secure_channel(sc_card_t * card,
cwa_provider_t * provider, int flag)
{
u8 *cert = NULL;
size_t certlen;
int res = SC_SUCCESS;
char *msg = "Success";
X509 *icc_cert = NULL;
X509 *ca_cert = NULL;
EVP_PKEY *icc_pubkey = NULL;
EVP_PKEY *ifd_privkey = NULL;
sc_context_t *ctx = NULL;
struct sm_cwa_session * sm = &card->sm_ctx.info.session.cwa;
u8 sig[128];
u8 *buffer = NULL;
size_t bufferlen;
u8 *tlv = NULL;
size_t tlvlen = 0;
u8 rndbuf[16];
if (!card || !card->ctx )
return SC_ERROR_INVALID_ARGUMENTS;
if (!provider)
return SC_ERROR_SM_NOT_INITIALIZED;
ctx = card->ctx;
LOG_FUNC_CALLED(ctx);
switch (flag) {
case CWA_SM_OFF:
card->sm_ctx.sm_mode = SM_MODE_NONE;
sc_log(ctx, "Setting CWA SM status to none");
LOG_FUNC_RETURN(ctx, SC_SUCCESS);
case CWA_SM_ON:
sc_log(ctx, "CWA SM initialization requested");
break;
default:
sc_log(ctx, "Invalid provided SM initialization flag");
LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS);
}
sc_log(ctx, "CreateSecureChannel pre-operations");
if (provider->cwa_create_pre_ops) {
res = provider->cwa_create_pre_ops(card, provider);
if (res != SC_SUCCESS) {
msg = "Create SM: provider pre_ops() failed";
sc_log(ctx, "%s", msg);
goto csc_end;
}
}
sc_log(ctx, "Retrieve ICC serial number");
if (provider->cwa_get_sn_icc) {
res = provider->cwa_get_sn_icc(card);
if (res != SC_SUCCESS) {
msg = "Retrieve ICC failed";
sc_log(ctx, "%s", msg);
goto csc_end;
}
} else {
msg = "Don't know how to obtain ICC serial number";
sc_log(ctx, "%s", msg);
res = SC_ERROR_INTERNAL;
goto csc_end;
}
if (!provider->cwa_get_icc_intermediate_ca_cert) {
sc_log(ctx,
"Step 8.4.1.6: Skip Retrieving ICC intermediate CA");
ca_cert = NULL;
} else {
sc_log(ctx, "Step 8.4.1.7: Retrieving ICC intermediate CA");
res =
provider->cwa_get_icc_intermediate_ca_cert(card, &ca_cert);
if (res != SC_SUCCESS) {
msg =
"Cannot get ICC intermediate CA certificate from provider";
goto csc_end;
}
}
sc_log(ctx, "Step 8.4.1.8: Retrieve ICC certificate");
res = provider->cwa_get_icc_cert(card, &icc_cert);
if (res != SC_SUCCESS) {
msg = "Cannot get ICC certificate from provider";
goto csc_end;
}
if (ca_cert) {
sc_log(ctx, "Verifying ICC certificate chain");
res =
cwa_verify_icc_certificates(card, provider, ca_cert,
icc_cert);
if (res != SC_SUCCESS) {
res = SC_ERROR_SM_AUTHENTICATION_FAILED;
msg = "Icc Certificates verification failed";
goto csc_end;
}
} else {
sc_log(ctx, "Cannot verify Certificate chain. skip step");
}
icc_pubkey = X509_get_pubkey(icc_cert);
sc_log(ctx,
"Step 8.4.1.2: Select Root CA in card for IFD cert verification");
res = provider->cwa_get_root_ca_pubkey_ref(card, &buffer, &bufferlen);
if (res != SC_SUCCESS) {
msg = "Cannot get Root CA key reference from provider";
goto csc_end;
}
tlvlen = 0;
tlv = calloc(10 + bufferlen, sizeof(u8));
if (!tlv) {
msg = "calloc error";
res = SC_ERROR_OUT_OF_MEMORY;
goto csc_end;
}
res = cwa_compose_tlv(card, 0x83, bufferlen, buffer, &tlv, &tlvlen);
if (res != SC_SUCCESS) {
msg = "Cannot compose tlv for setting Root CA key reference";
goto csc_end;
}
res = cwa_set_security_env(card, 0x81, 0xB6, tlv, tlvlen);
if (res != SC_SUCCESS) {
msg = "Select Root CA key ref failed";
goto csc_end;
}
sc_log(ctx,
"Step 8.4.1.3: Send CVC IFD intermediate CA Cert for ICC verification");
res = provider->cwa_get_cvc_ca_cert(card, &cert, &certlen);
if (res != SC_SUCCESS) {
msg = "Get CVC CA cert from provider failed";
goto csc_end;
}
res = cwa_verify_cvc_certificate(card, cert, certlen);
if (res != SC_SUCCESS) {
msg = "Verify CVC CA failed";
goto csc_end;
}
sc_log(ctx,
"Step 8.4.1.4: Select Intermediate CA pubkey ref for ICC verification");
res =
provider->cwa_get_intermediate_ca_pubkey_ref(card, &buffer,
&bufferlen);
if (res != SC_SUCCESS) {
msg = "Cannot get intermediate CA key reference from provider";
goto csc_end;
}
tlvlen = 0;
free(tlv);
tlv = calloc(10 + bufferlen, sizeof(u8));
if (!tlv) {
msg = "calloc error";
res = SC_ERROR_OUT_OF_MEMORY;
goto csc_end;
}
res = cwa_compose_tlv(card, 0x83, bufferlen, buffer, &tlv, &tlvlen);
if (res != SC_SUCCESS) {
msg =
"Cannot compose tlv for setting intermediate CA key reference";
goto csc_end;
}
res = cwa_set_security_env(card, 0x81, 0xB6, tlv, tlvlen);
if (res != SC_SUCCESS) {
msg = "Select CVC CA pubk failed";
goto csc_end;
}
sc_log(ctx,
"Step 8.4.1.5: Send CVC IFD Certificate for ICC verification");
res = provider->cwa_get_cvc_ifd_cert(card, &cert, &certlen);
if (res != SC_SUCCESS) {
msg = "Get CVC IFD cert from provider failed";
goto csc_end;
}
res = cwa_verify_cvc_certificate(card, cert, certlen);
if (res != SC_SUCCESS) {
msg = "Verify CVC IFD failed";
goto csc_end;
}
sc_log(ctx,
"Step 8.4.1.9: Send IFD pubk and ICC privk key references for Internal Auth");
res = provider->cwa_get_ifd_pubkey_ref(card, &buffer, &bufferlen);
if (res != SC_SUCCESS) {
msg = "Cannot get ifd public key reference from provider";
goto csc_end;
}
tlvlen = 0;
free(tlv);
tlv = calloc(10 + bufferlen, sizeof(u8));
if (!tlv) {
msg = "calloc error";
res = SC_ERROR_OUT_OF_MEMORY;
goto csc_end;
}
res = cwa_compose_tlv(card, 0x83, bufferlen, buffer, &tlv, &tlvlen);
if (res != SC_SUCCESS) {
msg = "Cannot compose tlv for setting ifd pubkey reference";
goto csc_end;
}
res = provider->cwa_get_icc_privkey_ref(card, &buffer, &bufferlen);
if (res != SC_SUCCESS) {
msg = "Cannot get icc private key reference from provider";
goto csc_end;
}
res = cwa_compose_tlv(card, 0x84, bufferlen, buffer, &tlv, &tlvlen);
if (res != SC_SUCCESS) {
msg = "Cannot compose tlv for setting ifd pubkey reference";
goto csc_end;
}
res = cwa_set_security_env(card, 0xC1, 0xA4, tlv, tlvlen);
if (res != SC_SUCCESS) {
msg = "Select CVC IFD pubk failed";
goto csc_end;
}
sc_log(ctx, "Step 8.4.1.10: Perform Internal authentication");
res = provider->cwa_get_sn_ifd(card);
if (res != SC_SUCCESS) {
msg = "Cannot get ifd serial number from provider";
goto csc_end;
}
RAND_bytes(sm->ifd.rnd, 8);
memcpy(rndbuf, sm->ifd.rnd, 8);
memcpy(rndbuf + 8, sm->ifd.sn, 8);
res = cwa_internal_auth(card, sig, 128, rndbuf, 16);
if (res != SC_SUCCESS) {
msg = "Internal auth cmd failed";
goto csc_end;
}
res = provider->cwa_get_ifd_privkey(card, &ifd_privkey);
if (res != SC_SUCCESS) {
msg = "Cannot retrieve IFD private key from provider";
res = SC_ERROR_SM_NO_SESSION_KEYS;
goto csc_end;
}
sc_log(ctx, "Verify Internal Auth command response");
res = cwa_verify_internal_auth(card, EVP_PKEY_get0_RSA(icc_pubkey),
EVP_PKEY_get0_RSA(ifd_privkey),
rndbuf,
16,
sig, 128
);
if (res != SC_SUCCESS) {
msg = "Internal Auth Verify failed";
goto csc_end;
}
sc_log(ctx, "Step 8.4.1.11: Prepare External Auth: Get Challenge");
res = sc_get_challenge(card, sm->icc.rnd, sizeof(sm->icc.rnd));
if (res != SC_SUCCESS) {
msg = "Get Challenge failed";
goto csc_end;
}
res = cwa_prepare_external_auth(card,
EVP_PKEY_get0_RSA(icc_pubkey),
EVP_PKEY_get0_RSA(ifd_privkey), sig, 128);
if (res != SC_SUCCESS) {
msg = "Prepare external auth failed";
goto csc_end;
}
sc_log(ctx, "Step 8.4.1.12: Perform External (IFD) Authentication");
res = cwa_external_auth(card, sig, 128);
if (res != SC_SUCCESS) {
msg = "External auth cmd failed";
goto csc_end;
}
sc_log(ctx, "Step 8.4.2: Compute Session Keys");
res = cwa_compute_session_keys(card);
if (res != SC_SUCCESS) {
msg = "Session Key generation failed";
goto csc_end;
}
sc_log(ctx, "CreateSecureChannel post-operations");
if (provider->cwa_create_post_ops) {
res = provider->cwa_create_post_ops(card, provider);
if (res != SC_SUCCESS) {
sc_log(ctx, "Create SM: provider post_ops() failed");
goto csc_end;
}
}
res = SC_SUCCESS;
csc_end:
free(tlv);
if (icc_cert)
X509_free(icc_cert);
if (ca_cert)
X509_free(ca_cert);
if (icc_pubkey)
EVP_PKEY_free(icc_pubkey);
if (ifd_privkey)
EVP_PKEY_free(ifd_privkey);
if (res != SC_SUCCESS) {
sc_log(ctx, "%s", msg);
card->sm_ctx.sm_mode = SM_MODE_NONE;
} else {
card->sm_ctx.sm_mode = SM_MODE_TRANSMIT;
}
LOG_FUNC_RETURN(ctx, res);
}
int cwa_encode_apdu(sc_card_t * card,
cwa_provider_t * provider, sc_apdu_t * from, sc_apdu_t * to)
{
u8 *apdubuf = NULL;
size_t apdulen, tlv_len;
u8 *ccbuf = NULL;
size_t cclen = 0;
u8 macbuf[8];
DES_key_schedule k1;
DES_key_schedule k2;
char *msg = NULL;
size_t i, j;
int res = SC_SUCCESS;
sc_context_t *ctx = NULL;
struct sm_cwa_session * sm_session = &card->sm_ctx.info.session.cwa;
u8 *msgbuf = NULL;
u8 *cryptbuf = NULL;
if (!card || !card->ctx || !provider)
return SC_ERROR_INVALID_ARGUMENTS;
ctx = card->ctx;
LOG_FUNC_CALLED(ctx);
if (!from || !to || !sm_session)
LOG_FUNC_RETURN(ctx, SC_ERROR_SM_NOT_INITIALIZED);
if (card->sm_ctx.sm_mode != SM_MODE_TRANSMIT)
LOG_FUNC_RETURN(ctx, SC_ERROR_SM_INVALID_LEVEL);
msgbuf = calloc(12 + from->lc, sizeof(u8));
cryptbuf = calloc(12 + from->lc, sizeof(u8));
if (!msgbuf || !cryptbuf) {
res = SC_ERROR_OUT_OF_MEMORY;
goto err;
}
if ((from->cla & 0x0C) != 0) {
memcpy(to, from, sizeof(sc_apdu_t));
res = SC_SUCCESS;
goto encode_end;
}
if (from->ins == 0xC0) {
memcpy(to, from, sizeof(sc_apdu_t));
res = SC_SUCCESS;
goto encode_end;
}
cwa_trace_apdu(card, from, 0);
apdubuf = calloc(MAX(SC_MAX_APDU_BUFFER_SIZE, 20 + from->datalen),
sizeof(u8));
ccbuf = calloc(MAX(SC_MAX_APDU_BUFFER_SIZE, 20 + from->datalen),
sizeof(u8));
to->resp = calloc(MAX_RESP_BUFFER_SIZE, sizeof(u8));
to->resplen = MAX_RESP_BUFFER_SIZE;
if (!apdubuf || !ccbuf || (!from->resp && !to->resp)) {
res = SC_ERROR_OUT_OF_MEMORY;
goto err;
}
to->cse = SC_APDU_CASE_4_SHORT;
to->cla = from->cla | 0x0C;
to->ins = from->ins;
to->p1 = from->p1;
to->p2 = from->p2;
to->le = from->le;
if (!to->le)
to->le = 255;
to->lc = 0;
*(ccbuf + cclen++) = to->cla;
*(ccbuf + cclen++) = to->ins;
*(ccbuf + cclen++) = to->p1;
*(ccbuf + cclen++) = to->p2;
cwa_iso7816_padding(ccbuf, &cclen);
if (from->lc != 0) {
size_t dlen = from->lc;
DES_cblock iv = { 0, 0, 0, 0, 0, 0, 0, 0 };
DES_set_key_unchecked((const_DES_cblock *) & (sm_session->session_enc[0]),
&k1);
DES_set_key_unchecked((const_DES_cblock *) & (sm_session->session_enc[8]),
&k2);
memcpy(msgbuf, from->data, dlen);
cwa_iso7816_padding(msgbuf, &dlen);
*cryptbuf = 0x01;
DES_ede3_cbc_encrypt(msgbuf, cryptbuf + 1, dlen, &k1, &k2, &k1,
&iv, DES_ENCRYPT);
res =
cwa_compose_tlv(card, 0x87, dlen + 1, cryptbuf, &ccbuf,
&cclen);
if (res != SC_SUCCESS) {
msg = "Error in compose tag 8x87 TLV";
goto encode_end;
}
} else if ((0xff & from->le) > 0) {
u8 le = 0xff & from->le;
res = cwa_compose_tlv(card, 0x97, 1, &le, &ccbuf, &cclen);
if (res != SC_SUCCESS) {
msg = "Encode APDU compose_tlv(0x97) failed";
goto encode_end;
}
}
memcpy(apdubuf, ccbuf + 8, cclen - 8);
apdulen = cclen - 8;
cwa_iso7816_padding(ccbuf, &cclen);
res = cwa_increase_ssc(card);
if (res != SC_SUCCESS) {
msg = "Error in computing SSC";
goto encode_end;
}
DES_set_key_unchecked((const_DES_cblock *) & (sm_session->session_mac[0]),&k1);
DES_set_key_unchecked((const_DES_cblock *) & (sm_session->session_mac[8]),&k2);
memcpy(macbuf, sm_session->ssc, 8);
for (i = 0; i < cclen; i += 8) {
DES_ecb_encrypt((const_DES_cblock *) macbuf,
(DES_cblock *) macbuf, &k1, DES_ENCRYPT);
for (j = 0; j < 8; j++)
macbuf[j] ^= ccbuf[i + j];
}
DES_ecb2_encrypt((const_DES_cblock *) macbuf, (DES_cblock *) macbuf,
&k1, &k2, DES_ENCRYPT);
tlv_len = (card->atr.value[15] >= DNIE_30_VERSION)? 8 : 4;
sc_log(ctx, "Using TLV length: %"SC_FORMAT_LEN_SIZE_T"u", tlv_len);
res = cwa_compose_tlv(card, 0x8E, tlv_len, macbuf, &apdubuf, &apdulen);
if (res != SC_SUCCESS) {
msg = "Encode APDU compose_tlv(0x87) failed";
goto encode_end;
}
to->lc = apdulen;
to->data = apdubuf;
to->datalen = apdulen;
res = SC_SUCCESS;
goto encode_end_apdu_valid;
err:
encode_end:
if (apdubuf)
free(apdubuf);
if (from->resp != to->resp)
free(to->resp);
encode_end_apdu_valid:
if (msg)
sc_log(ctx, "%s", msg);
free(msgbuf);
free(cryptbuf);
free(ccbuf);
LOG_FUNC_RETURN(ctx, res);
}
int cwa_decode_response(sc_card_t * card,
cwa_provider_t * provider,
sc_apdu_t * apdu)
{
size_t i, j, tlv_len;
cwa_tlv_t tlv_array[4];
cwa_tlv_t *p_tlv = &tlv_array[0];
cwa_tlv_t *e_tlv = &tlv_array[1];
cwa_tlv_t *m_tlv = &tlv_array[2];
cwa_tlv_t *s_tlv = &tlv_array[3];
u8 *buffer = NULL;
u8 *ccbuf = NULL;
size_t cclen = 0;
u8 macbuf[8];
size_t resplen = 0;
DES_key_schedule k1;
DES_key_schedule k2;
int res = SC_SUCCESS;
char *msg = NULL;
sc_context_t *ctx = NULL;
struct sm_cwa_session * sm_session = &card->sm_ctx.info.session.cwa;
if (!card || !card->ctx || !provider)
return SC_ERROR_INVALID_ARGUMENTS;
ctx = card->ctx;
LOG_FUNC_CALLED(ctx);
if ((apdu == NULL) || (sm_session == NULL))
LOG_FUNC_RETURN(ctx, SC_ERROR_SM_NOT_INITIALIZED);
if (card->sm_ctx.sm_mode != SM_MODE_TRANSMIT)
LOG_FUNC_RETURN(ctx, SC_ERROR_SM_INVALID_LEVEL);
if (apdu->sw1 == 0x69) {
if ((apdu->sw2 == 0x88) || (apdu->sw2 == 0x87)) {
msg = "SM related errors in APDU response";
cwa_create_secure_channel(card, provider, CWA_SM_OFF);
res = SC_ERROR_SECURITY_STATUS_NOT_SATISFIED;
goto response_decode_end;
}
}
if (!apdu->resp || (apdu->resplen == 0)) {
sc_log(ctx, "Empty APDU response: assume not cwa encoded");
return SC_SUCCESS;
}
switch (*apdu->resp) {
case CWA_SM_PLAIN_TAG:
case CWA_SM_CRYPTO_TAG:
case CWA_SM_MAC_TAG:
case CWA_SM_LE_TAG:
case CWA_SM_STATUS_TAG:
break;
default:
sc_log(card->ctx, "APDU Response seems not to be cwa encoded");
return SC_SUCCESS;
}
memset(tlv_array, 0, 4 * sizeof(cwa_tlv_t));
buffer = calloc(apdu->resplen, sizeof(u8));
if (!buffer) {
msg = "Cannot allocate space for response buffer";
res = SC_ERROR_OUT_OF_MEMORY;
goto response_decode_end;
}
memcpy(buffer, apdu->resp, apdu->resplen);
res = cwa_parse_tlv(card, buffer, apdu->resplen, tlv_array);
if (res != SC_SUCCESS) {
msg = "Error in TLV parsing";
goto response_decode_end;
}
if (p_tlv->buf && e_tlv->buf) {
msg =
"Plain and Encoded data are mutually exclusive in apdu response";
res = SC_ERROR_INVALID_DATA;
goto response_decode_end;
}
if (!m_tlv->buf) {
msg = "No MAC TAG found in apdu response";
res = SC_ERROR_INVALID_DATA;
goto response_decode_end;
}
tlv_len = (card->atr.value[15] >= DNIE_30_VERSION)? 8 : 4;
if (m_tlv->len != tlv_len) {
msg = "Invalid MAC TAG Length";
res = SC_ERROR_INVALID_DATA;
goto response_decode_end;
}
ccbuf =
calloc(e_tlv->buflen + s_tlv->buflen + p_tlv->buflen + 8,
sizeof(u8));
if (!ccbuf) {
msg = "Cannot allocate space for mac checking";
res = SC_ERROR_OUT_OF_MEMORY;
goto response_decode_end;
}
cclen = 0;
if (e_tlv->buf) {
memcpy(ccbuf, e_tlv->buf, e_tlv->buflen);
cclen = e_tlv->buflen;
}
if (p_tlv->buf) {
memcpy(ccbuf, p_tlv->buf, p_tlv->buflen);
cclen += p_tlv->buflen;
}
if (s_tlv->buf) {
if (s_tlv->len != 2) {
msg = "Invalid SW TAG length";
res = SC_ERROR_INVALID_DATA;
goto response_decode_end;
}
memcpy(ccbuf + cclen, s_tlv->buf, s_tlv->buflen);
cclen += s_tlv->buflen;
apdu->sw1 = s_tlv->data[0];
apdu->sw2 = s_tlv->data[1];
}
cwa_iso7816_padding(ccbuf, &cclen);
res = cwa_increase_ssc(card);
if (res != SC_SUCCESS) {
msg = "Error in computing SSC";
goto response_decode_end;
}
DES_set_key_unchecked((const_DES_cblock *) & (sm_session->session_mac[0]), &k1);
DES_set_key_unchecked((const_DES_cblock *) & (sm_session->session_mac[8]), &k2);
memcpy(macbuf, sm_session->ssc, 8);
for (i = 0; i < cclen; i += 8) {
DES_ecb_encrypt((const_DES_cblock *) macbuf,
(DES_cblock *) macbuf, &k1, DES_ENCRYPT);
for (j = 0; j < 8; j++)
macbuf[j] ^= ccbuf[i + j];
}
DES_ecb2_encrypt((const_DES_cblock *) macbuf, (DES_cblock *) macbuf,
&k1, &k2, DES_ENCRYPT);
res = memcmp(m_tlv->data, macbuf, 4);
if (res != 0) {
msg = "Error in MAC CC checking: value doesn't match";
res = SC_ERROR_SM_ENCRYPT_FAILED;
goto response_decode_end;
}
resplen = 10 + MAX(p_tlv->len, e_tlv->len);
if (apdu->resplen < resplen) {
msg = "Cannot allocate buffer to store response";
res = SC_ERROR_BUFFER_TOO_SMALL;
goto response_decode_end;
}
apdu->resplen = resplen;
if (p_tlv->buf) {
memcpy(apdu->resp, p_tlv->data, p_tlv->len);
apdu->resplen = p_tlv->len;
}
else if (e_tlv->buf) {
DES_cblock iv = { 0, 0, 0, 0, 0, 0, 0, 0 };
if ((e_tlv->len < 9) || ((e_tlv->len - 1) % 8) != 0) {
msg = "Invalid length for Encoded data TLV";
res = SC_ERROR_INVALID_DATA;
goto response_decode_end;
}
if (e_tlv->data[0] != 0x01) {
msg = "Encoded TLV: Invalid padding info value";
res = SC_ERROR_INVALID_DATA;
goto response_decode_end;
}
DES_set_key_unchecked((const_DES_cblock *) & (sm_session->session_enc[0]),
&k1);
DES_set_key_unchecked((const_DES_cblock *) & (sm_session->session_enc[8]),
&k2);
DES_ede3_cbc_encrypt(&e_tlv->data[1], apdu->resp, e_tlv->len - 1,
&k1, &k2, &k1, &iv, DES_DECRYPT);
apdu->resplen = e_tlv->len - 1;
for (; (apdu->resplen > 0) && *(apdu->resp + apdu->resplen - 1) == 0x00; apdu->resplen--) ;
if (*(apdu->resp + apdu->resplen - 1) != 0x80) {
msg =
"Decrypted TLV has no 0x80 iso padding indicator!";
res = SC_ERROR_INVALID_DATA;
goto response_decode_end;
}
apdu->resplen--;
}
else
apdu->resplen = 0;
res = SC_SUCCESS;
response_decode_end:
if (buffer)
free(buffer);
if (ccbuf)
free(ccbuf);
if (msg) {
sc_log(ctx, "%s", msg);
} else {
cwa_trace_apdu(card, apdu, 1);
}
LOG_FUNC_RETURN(ctx, res);
}
static int default_create_pre_ops(sc_card_t * card, cwa_provider_t * provider)
{
return SC_SUCCESS;
}
static int default_create_post_ops(sc_card_t * card, cwa_provider_t * provider)
{
return SC_SUCCESS;
}
static int default_get_root_ca_pubkey(sc_card_t * card, EVP_PKEY ** root_ca_key)
{
return SC_ERROR_NOT_SUPPORTED;
}
static int default_get_cvc_ca_cert(sc_card_t * card, u8 ** cert,
size_t * length)
{
return SC_ERROR_NOT_SUPPORTED;
}
static int default_get_cvc_ifd_cert(sc_card_t * card, u8 ** cert,
size_t * length)
{
return SC_ERROR_NOT_SUPPORTED;
}
static int default_get_ifd_privkey(sc_card_t * card, EVP_PKEY ** ifd_privkey)
{
return SC_ERROR_NOT_SUPPORTED;
}
static int default_get_icc_intermediate_ca_cert(sc_card_t * card, X509 ** cert)
{
return SC_ERROR_NOT_SUPPORTED;
}
static int default_get_icc_cert(sc_card_t * card, X509 ** cert)
{
return SC_ERROR_NOT_SUPPORTED;
}
static int default_get_root_ca_pubkey_ref(sc_card_t * card, u8 ** buf,
size_t * len)
{
return SC_ERROR_NOT_SUPPORTED;
}
static int default_get_intermediate_ca_pubkey_ref(sc_card_t * card, u8 ** buf,
size_t * len)
{
return SC_ERROR_NOT_SUPPORTED;
}
static int default_get_ifd_pubkey_ref(sc_card_t * card, u8 ** buf, size_t * len)
{
return SC_ERROR_NOT_SUPPORTED;
}
static int default_get_icc_privkey_ref(sc_card_t * card, u8 ** buf,
size_t * len)
{
return SC_ERROR_NOT_SUPPORTED;
}
static int default_get_sn_ifd(sc_card_t * card)
{
return SC_ERROR_NOT_SUPPORTED;
}
static int default_get_sn_icc(sc_card_t * card)
{
return SC_ERROR_NOT_SUPPORTED;
}
static cwa_provider_t default_cwa_provider = {
default_create_pre_ops,
default_create_post_ops,
default_get_icc_intermediate_ca_cert,
default_get_icc_cert,
default_get_root_ca_pubkey,
default_get_ifd_privkey,
default_get_cvc_ca_cert,
default_get_cvc_ifd_cert,
default_get_root_ca_pubkey_ref,
default_get_intermediate_ca_pubkey_ref,
default_get_ifd_pubkey_ref,
default_get_icc_privkey_ref,
default_get_sn_ifd,
default_get_sn_icc,
};
cwa_provider_t *cwa_get_default_provider(sc_card_t * card)
{
cwa_provider_t *res = NULL;
if (!card || !card->ctx)
return NULL;
LOG_FUNC_CALLED(card->ctx);
res = calloc(1, sizeof(cwa_provider_t));
if (!res) {
sc_log(card->ctx, "Cannot allocate space for cwa_provider");
return NULL;
}
memcpy(res, &default_cwa_provider, sizeof(cwa_provider_t));
return res;
}
#undef __CWA14890_C__
#endif