diff --git a/ccid/Makefile b/ccid/Makefile
index 9cca3c7..36bc8ea 100644
--- a/ccid/Makefile
+++ b/ccid/Makefile
@@ -21,14 +21,20 @@ INSTALL_PROGRAM = $(INSTALL)
TARGETS = ccid
+CCID_SRC = ccid.h ccid.c \
+ sm.c sm.h \
+ pace.h pace.c pace_lib.c \
+ apdu.h apdu.c \
+ usbstring.c usbstring.h usb.c
+
# top-level rule
all: $(TARGETS)
-ccid: ccid.h ccid.c pace.h pace.c sm.c sm.h utils.h utils.c apdu.h apdu.c usbstring.c usbstring.h usb.c
+ccid: $(CCID_SRC)
$(CC) $(LIBPCSCLITE_CFLAGS) $(OPENSC_CFLAGS) $(OPENSSL_CFLAGS) \
$(PTHREAD_CFLAGS) $(CFLAGS) $(EXTRA_CFLAGS) \
- usbstring.c ccid.c pace.c sm.c utils.c apdu.c usb.c -o $@
+ $(filter %.c, $(CCID_SRC)) -o $@
install: $(TARGETS) installdirs
diff --git a/ccid/apdu.h b/ccid/apdu.h
index c81f692..178c978 100644
--- a/ccid/apdu.h
+++ b/ccid/apdu.h
@@ -1,5 +1,5 @@
-#ifndef _APDU_H
-#define _APDU_H
+#ifndef _CCID_APDU_H
+#define _CCID_APDU_H
#ifdef __cplusplus
extern "C" {
diff --git a/ccid/ccid.c b/ccid/ccid.c
index 85232aa..02592da 100644
--- a/ccid/ccid.c
+++ b/ccid/ccid.c
@@ -178,7 +178,7 @@ int build_apdu(const __u8 *buf, size_t len, sc_apdu_t *apdu)
len0 = len;
if (len < 4) {
- sc_debug(ctx, "APDU too short (must be at least 4 bytes)");
+ sc_error(ctx, "APDU too short (must be at least 4 bytes)");
SC_FUNC_RETURN(ctx, SC_LOG_TYPE_VERBOSE, SC_ERROR_INVALID_DATA);
}
@@ -195,7 +195,7 @@ int build_apdu(const __u8 *buf, size_t len, sc_apdu_t *apdu)
apdu->data = p;
apdu->datalen = apdu->lc;
if (len < apdu->lc) {
- sc_debug(ctx, "APDU too short (need %lu bytes)\n",
+ sc_error(ctx, "APDU too short (need %lu bytes)\n",
(unsigned long) apdu->lc - len);
SC_FUNC_RETURN(ctx, SC_LOG_TYPE_VERBOSE, SC_ERROR_INVALID_DATA);
}
@@ -211,7 +211,7 @@ int build_apdu(const __u8 *buf, size_t len, sc_apdu_t *apdu)
apdu->cse = SC_APDU_CASE_3_SHORT;
}
if (len) {
- sc_debug(ctx, "APDU too long (%lu bytes extra)\n",
+ sc_error(ctx, "APDU too long (%lu bytes extra)\n",
(unsigned long) len);
SC_FUNC_RETURN(ctx, SC_LOG_TYPE_VERBOSE, SC_ERROR_INVALID_DATA);
}
@@ -227,7 +227,7 @@ int build_apdu(const __u8 *buf, size_t len, sc_apdu_t *apdu)
apdu->flags = SC_APDU_FLAGS_NO_GET_RESP|SC_APDU_FLAGS_NO_RETRY_WL;
- sc_debug(ctx, "APDU, %d byte(s):\tins=%02x p1=%02x p2=%02x",
+ sc_error(ctx, "APDU, %d byte(s):\tins=%02x p1=%02x p2=%02x",
(unsigned int) len0, apdu->ins, apdu->p1, apdu->p2);
SC_FUNC_RETURN(ctx, SC_LOG_TYPE_VERBOSE, SC_SUCCESS);
@@ -347,6 +347,8 @@ __u8 get_bStatus(int sc_result, __u8 bSlot)
}
} else {
debug_sc_result(flags);
+ sc_error(ctx, "Could not detect card presence."
+ " Falling back to default (bStatus=0x%02X).", result);
}
return result;
@@ -461,10 +463,14 @@ perform_PC_to_RDR_IccPowerOn(const __u8 *in, __u8 **out, size_t *outlen)
result->dwLength = __cpu_to_le32(card_in_slot[request->bSlot]->atr_len);
} else {
debug_sc_result(SC_ERROR_OUT_OF_MEMORY);
+ sc_error(ctx, "Could not get memory for ATR."
+ " Returning package without payload.");
*outlen = sizeof *result;
}
} else {
debug_sc_result(sc_result);
+ sc_error(ctx, "Could not connect to card in slot %d."
+ " Returning default status package.", request->bSlot);
*outlen = sizeof *result;
}
@@ -551,6 +557,8 @@ perform_PC_to_RDR_XfrBlock(const u8 *in, __u8** out, size_t *outlen)
} else {
*outlen = sizeof *result;
debug_sc_result(sc_result);
+ sc_error(ctx, "Could not get memory for response apdu."
+ " Returning package without payload.");
}
result->bError = get_bError(sc_result);
result->bStatus = get_bStatus(sc_result, request->bSlot);
@@ -1028,6 +1036,8 @@ err:
} else {
*outlen = sizeof *result;
debug_sc_result(sc_result);
+ sc_error(ctx, "Could not get memory for response apdu."
+ " Returning package without payload.");
}
result->bError = get_bError(sc_result);
result->bStatus = get_bStatus(sc_result, request->bSlot);
@@ -1068,6 +1078,8 @@ get_RDR_to_PC_NotifySlotChange(RDR_to_PC_NotifySlotChange_t **out)
sc_result = detect_card_presence(i);
if (sc_result < 0) {
debug_sc_result(sc_result);
+ sc_error(ctx, "Could not detect card presence, skipping slot %d.",
+ i);
continue;
}
@@ -1121,7 +1133,8 @@ perform_unknown(const __u8 *in, __u8 **out, size_t *outlen)
result->bMessageType = 0x84;
break;
default:
- sc_debug(ctx, "unknown message type");
+ sc_debug(ctx, "Unknown message type in request. "
+ "Using bMessageType=0x%2x for output.", 0);
result->bMessageType = 0;
}
result->dwLength = __constant_cpu_to_le32(0);
@@ -1177,7 +1190,8 @@ int ccid_parse_bulkin(const __u8* inbuf, __u8** outbuf)
break;
default:
- sc_debug(ctx, "unknown ccid bulk-in message");
+ sc_debug(ctx, "Unknown ccid bulk-in message. "
+ "Starting default handler.");
sc_result = perform_unknown(inbuf, outbuf, &outlen);
}
@@ -1248,7 +1262,7 @@ int ccid_parse_control(struct usb_ctrlrequest *setup, __u8 **outbuf)
break;
default:
- sc_debug(ctx, "unknown ccid control command");
+ sc_error(ctx, "Unknown ccid control command.");
result = SC_ERROR_NOT_SUPPORTED;
}
diff --git a/ccid/ccid.h b/ccid/ccid.h
index 104d03e..1700bcf 100644
--- a/ccid/ccid.h
+++ b/ccid/ccid.h
@@ -16,8 +16,8 @@
* You should have received a copy of the GNU General Public License along with
* ccid. If not, see .
*/
-#ifndef _VPCD_H
-#define _VPCD_H
+#ifndef _CCID_H
+#define _CCID_H
#include
diff --git a/ccid/pace.c b/ccid/pace.c
index eef2c91..ea4d1a9 100644
--- a/ccid/pace.c
+++ b/ccid/pace.c
@@ -19,6 +19,7 @@
#include "pace.h"
#include "sm.h"
#include
+#include
#include
#include
@@ -138,14 +139,24 @@ IMPLEMENT_ASN1_FUNCTIONS(PACE_GEN_AUTH_R)
#ifdef NO_PACE
inline int GetReadersPACECapabilities(sc_card_t *card,
const __u8 *in, __u8 **out, size_t *outlen) {
- SC_FUNC_RETURN(card->ctx, SC_LOG_TYPE_DEBUG, SC_ERROR_NOT_SUPPORTED);
+ SC_FUNC_RETURN(card->ctx, SC_LOG_TYPE_ERROR, SC_ERROR_NOT_SUPPORTED);
}
inline int EstablishPACEChannel(sc_card_t *card, const __u8 *in,
__u8 **out, size_t *outlen, struct sm_ctx *sm_ctx) {
- SC_FUNC_RETURN(card->ctx, SC_LOG_TYPE_DEBUG, SC_ERROR_NOT_SUPPORTED);
+ SC_FUNC_RETURN(card->ctx, SC_LOG_TYPE_ERROR, SC_ERROR_NOT_SUPPORTED);
}
int pace_test(sc_card_t *card) {
- SC_FUNC_RETURN(card->ctx, SC_LOG_TYPE_DEBUG, SC_ERROR_NOT_SUPPORTED);
+ SC_FUNC_RETURN(card->ctx, SC_LOG_TYPE_ERROR, SC_ERROR_NOT_SUPPORTED);
+}
+int pace_sm_encrypt(sc_card_t *card, struct *sm_ctx,
+ const u8 *data, size_t datalen, u8 **enc)
+{
+ SC_FUNC_RETURN(card->ctx, SC_LOG_TYPE_ERROR, SC_ERROR_NOT_SUPPORTED);
+}
+int pace_sm_decrypt(sc_card_t *card, struct *sm_ctx,
+ const u8 *enc, size_t enclen, u8 **data)
+{
+ SC_FUNC_RETURN(card->ctx, SC_LOG_TYPE_ERROR, SC_ERROR_NOT_SUPPORTED);
}
#else
@@ -164,16 +175,6 @@ int pace_test(sc_card_t *card) {
const size_t maxresp = SC_MAX_APDU_BUFFER_SIZE - 2;
uint16_t ssc = 0;
-void bin_log(sc_context_t *ctx, const char *label, const u8 *data, size_t len)
-{
- char buf[1024];
-
- sc_hex_dump(ctx, data, len, buf, sizeof buf);
- sc_debug(ctx, "%s (%u bytes):\n%s"
- "======================================================================",
- label, len, buf);
-}
-
int GetReadersPACECapabilities(sc_card_t *card,
const __u8 *in, __u8 **out, size_t *outlen) {
if (!out || !outlen)
@@ -366,7 +367,7 @@ int pace_gen_auth(sc_card_t *card,
r = SC_ERROR_OUT_OF_MEMORY;
goto err;
}
- switch(step) {
+ switch (step) {
case 1:
break;
case 2:
@@ -547,7 +548,7 @@ get_psec(sc_card_t *card, const char *pin, size_t length_pin, u8 pin_id)
memset(&hints, 0, sizeof(hints));
hints.dialog_name = "ccid.PACE";
hints.card = card;
- switch(pin_id) {
+ switch (pin_id) {
case PACE_MRZ:
hints.prompt = "Enter MRZ";
break;
@@ -587,12 +588,11 @@ void debug_ossl(sc_context_t *ctx) {
}
int EstablishPACEChannel(sc_card_t *card, const __u8 *in,
- __u8 **out, size_t *outlen, struct sm_ctx *sm_ctx)
+ __u8 **out, size_t *outlen, struct sm_ctx *sctx)
{
__u8 pin_id;
size_t length_chat, length_pin, length_cert_desc, length_ef_cardaccess;
const __u8 *chat, *pin, *certificate_description;
- u8 *buf;
__u8 *ef_cardaccess = NULL;
PACEInfo *info = NULL;
PACEDomainParameterInfo *static_dp = NULL, *eph_dp = NULL;
@@ -631,6 +631,7 @@ int EstablishPACEChannel(sc_card_t *card, const __u8 *in,
}
r = get_ef_card_access(card, &ef_cardaccess, &length_ef_cardaccess);
if (r < 0) {
+ sc_error(card->ctx, "Could not get EF.CardAccess.");
goto err;
}
bin_log(card->ctx, "EF.CardAccess", ef_cardaccess, length_ef_cardaccess);
@@ -638,15 +639,20 @@ int EstablishPACEChannel(sc_card_t *card, const __u8 *in,
&info, &static_dp)) {
r = SC_ERROR_INTERNAL;
debug_ossl(card->ctx);
+ sc_error(card->ctx, "Could not parse EF.CardAccess.");
goto err;
}
r = pace_mse_set_at(card, info->protocol, pin_id, 1);
if (r < 0) {
+ sc_error(card->ctx, "Could not select protocol proberties "
+ "(MSE: Set AT).");
goto err;
}
r = pace_gen_auth(card, 1, NULL, 0, (u8 **) &enc_nonce->data,
&enc_nonce->length);
if (r < 0) {
+ sc_error(card->ctx, "Could not get encrypted nonce from card "
+ "(General Authenticate step 1 failed).");
goto err;
}
bin_log(card->ctx, "Encrypted nonce from MRTD", (u8 *)enc_nonce->data, enc_nonce->length);
@@ -678,6 +684,8 @@ int EstablishPACEChannel(sc_card_t *card, const __u8 *in,
r = pace_gen_auth(card, 2, (u8 *) mdata->data, mdata->length,
(u8 **) &mdata_opp->data, &mdata_opp->length);
if (r < 0) {
+ sc_error(card->ctx, "Could not exchange mapping data with card "
+ "(General Authenticate step 2 failed).");
goto err;
}
mdata_opp->max = mdata_opp->length;
@@ -694,6 +702,8 @@ int EstablishPACEChannel(sc_card_t *card, const __u8 *in,
r = pace_gen_auth(card, 3, (u8 *) pub->data, pub->length,
(u8 **) &pub_opp->data, &pub_opp->length);
if (r < 0) {
+ sc_error(card->ctx, "Could not exchange ephemeral public key with card "
+ "(General Authenticate step 3 failed).");
goto err;
}
pub_opp->max = pub_opp->length;
@@ -717,10 +727,11 @@ int EstablishPACEChannel(sc_card_t *card, const __u8 *in,
r = pace_gen_auth(card, 4, (u8 *) token->data, token->length,
(u8 **) &token_opp->data, &token_opp->length);
if (r < 0) {
+ sc_error(card->ctx, "Could not exchange authentication token with card "
+ "(General Authenticate step 4 failed).");
goto err;
}
token_opp->max = token_opp->length;
- bin_log(card->ctx, "Authentication token from MRTD", (u8 *) token_opp->data, token_opp->length);
if (!PACE_STEP3D_verify_authentication_token(pctx,
eph_dp, info, k_mac, token_opp)) {
@@ -730,30 +741,19 @@ int EstablishPACEChannel(sc_card_t *card, const __u8 *in,
}
/* XXX parse CHAT to check role of terminal */
- buf = realloc(sm_ctx->key_mac, k_mac->length);
- if (!buf) {
- r = SC_ERROR_OUT_OF_MEMORY;
+
+ sctx->authentication_ctx = pace_sm_ctx_create(info->protocol, k_mac,
+ k_enc, pctx);
+ if (!sctx->authentication_ctx) {
+ r = SC_ERROR_INTERNAL;
goto err;
}
- sm_ctx->key_mac = buf;
- memcpy(sm_ctx->key_mac, k_mac->data, k_mac->length);
- sm_ctx->key_mac_len = k_mac->length;
-
- buf = realloc(sm_ctx->key_enc, k_enc->length);
- if (!buf) {
- r = SC_ERROR_OUT_OF_MEMORY;
- goto err;
- }
- sm_ctx->key_enc = buf;
- memcpy(sm_ctx->key_enc, k_enc->data, k_enc->length);
- sm_ctx->key_enc_len = k_enc->length;
-
- sm_ctx->cipher = pctx->cipher;
- sm_ctx->cipher_ctx = pctx->cipher_ctx;
- sm_ctx->cipher_engine = pctx->cipher_engine;
- sm_ctx->md = pctx->md;
- sm_ctx->md_ctx = pctx->md_ctx;
- sm_ctx->md_engine = pctx->md_engine;
+ sctx->authenticate = pace_sm_authenticate;
+ sctx->cipher_ctx = sctx->authenticate;
+ sctx->encrypt = pace_sm_encrypt;
+ sctx->decrypt = pace_sm_decrypt;
+ sctx->padding_indicator = SM_ISO_PADDING;
+ sctx->block_length = EVP_CIPHER_block_size(pctx->cipher);
err:
if (info)
@@ -772,14 +772,6 @@ err:
BUF_MEM_free(mdata);
if (mdata_opp)
BUF_MEM_free(mdata_opp);
- if (k_enc) {
- OPENSSL_cleanse(k_enc->data, k_enc->length);
- BUF_MEM_free(k_enc);
- }
- if (k_mac) {
- OPENSSL_cleanse(k_mac->data, k_mac->length);
- BUF_MEM_free(k_mac);
- }
if (token_opp)
BUF_MEM_free(token_opp);
if (token)
@@ -794,8 +786,21 @@ err:
}
if (sec)
PACE_SEC_clean_free(sec);
- if (pctx)
- PACE_CTX_clear_free(pctx);
+
+ if (r < 0) {
+ if (k_enc) {
+ OPENSSL_cleanse(k_enc->data, k_enc->length);
+ BUF_MEM_free(k_enc);
+ }
+ if (k_mac) {
+ OPENSSL_cleanse(k_mac->data, k_mac->length);
+ BUF_MEM_free(k_mac);
+ }
+ if (pctx)
+ PACE_CTX_clear_free(pctx);
+ if (sctx->authentication_ctx)
+ pace_sm_ctx_free(sctx->authentication_ctx);
+ }
SC_FUNC_RETURN(card->ctx, SC_LOG_TYPE_DEBUG, r);
}
@@ -805,8 +810,12 @@ int pace_test(sc_card_t *card)
__u8 in[16];
__u8 *out = NULL;
size_t outlen;
- struct sm_ctx sm;
- memset(&sm, 0, sizeof(sm));
+ struct sm_ctx sctx;
+ sc_apdu_t sm_apdu;
+ sc_apdu_t apdu;
+
+ memset(&sctx, 0, sizeof(sctx));
+ memset(&apdu, 0, sizeof(apdu));
in[0] = PACE_CAN; // pin_id
in[1] = 0; // length_chat
@@ -820,8 +829,287 @@ int pace_test(sc_card_t *card)
in[9] = 0; // length_cert_desc
in[10]= 0; // length_cert_desc
- SC_FUNC_RETURN(card->ctx, SC_LOG_TYPE_ERROR,
- EstablishPACEChannel(card, in, &out, &outlen, &sm));
+ SC_TEST_RET(card->ctx, SC_LOG_TYPE_ERROR,
+ EstablishPACEChannel(card, in, &out, &outlen, &sctx));
+
+ /* select CardSecurity */
+ in[0] = 0x00;
+ in[1] = 0xA4;
+ apdu.p1 = 0x08;
+ apdu.p2 = 0x00;
+ apdu.lc = 0x02;
+ in[0] = 0x01;
+ in[1] = 0x1D;
+ apdu.data = in;
+ apdu.datalen = 2;
+ apdu.le = 0x00;
+ apdu.lc = SC_APDU_CASE_4_SHORT;
+
+ sm_encrypt(&sctx, card, &apdu, &sm_apdu);
+ SC_TEST_RET(card->ctx, SC_LOG_TYPE_ERROR,
+ my_transmit_apdu(card, &sm_apdu));
+ sm_decrypt(&sctx, card, &sm_apdu, &apdu);
+
+ return SC_SUCCESS;
+}
+
+BUF_MEM *
+encoded_ssc(const uint16_t ssc, const PACE_CTX *ctx)
+{
+ BUF_MEM * out = NULL;
+ size_t len;
+
+ if (!ctx)
+ goto err;
+
+ len = EVP_CIPHER_block_size(ctx->cipher);
+ out = BUF_MEM_create(len);
+ if (!out || len < sizeof ssc)
+ goto err;
+
+ /* Copy SSC to the end of buffer and fill the rest with 0 */
+ memset(out->data, 0, len);
+ memcpy(out->data + len - sizeof ssc, &ssc, sizeof ssc);
+
+ return out;
+
+err:
+ if (out)
+ BUF_MEM_free(out);
+
+ return NULL;
+}
+
+int
+update_iv(struct sm_ctx *ctx)
+{
+ if (!ctx || !ctx->cipher_ctx)
+ return SC_ERROR_INVALID_ARGUMENTS;
+
+ BUF_MEM *sscbuf = NULL, *ivbuf = NULL;
+ unsigned char *p;
+ struct pace_sm_ctx *psmctx = ctx->cipher_ctx;
+ int r;
+
+ switch (psmctx->protocol) {
+ case NID_id_PACE_DH_GM_AES_CBC_CMAC_128:
+ case NID_id_PACE_DH_GM_AES_CBC_CMAC_192:
+ case NID_id_PACE_DH_GM_AES_CBC_CMAC_256:
+ case NID_id_PACE_DH_IM_AES_CBC_CMAC_128:
+ case NID_id_PACE_DH_IM_AES_CBC_CMAC_192:
+ case NID_id_PACE_DH_IM_AES_CBC_CMAC_256:
+ case NID_id_PACE_ECDH_GM_AES_CBC_CMAC_128:
+ case NID_id_PACE_ECDH_GM_AES_CBC_CMAC_192:
+ case NID_id_PACE_ECDH_GM_AES_CBC_CMAC_256:
+ case NID_id_PACE_ECDH_IM_AES_CBC_CMAC_128:
+ case NID_id_PACE_ECDH_IM_AES_CBC_CMAC_192:
+ case NID_id_PACE_ECDH_IM_AES_CBC_CMAC_256:
+ /* For AES decryption the IV is not needed,
+ * so we always set it to the encryption IV=E(K_Enc, SSC) */
+ sscbuf = encoded_ssc(psmctx->ssc, psmctx->ctx);
+ ivbuf = PACE_encrypt(psmctx->ctx, psmctx->key_enc, sscbuf);
+ if (!ivbuf) {
+ r = SC_ERROR_INTERNAL;
+ goto err;
+ }
+ p = realloc(psmctx->ctx->iv, ivbuf->length);
+ if (!p) {
+ r = SC_ERROR_OUT_OF_MEMORY;
+ goto err;
+ }
+ memcpy(p, ivbuf->data, ivbuf->length);
+ psmctx->ctx->iv = p;
+ break;
+ case NID_id_PACE_DH_GM_3DES_CBC_CBC:
+ case NID_id_PACE_DH_IM_3DES_CBC_CBC:
+ case NID_id_PACE_ECDH_GM_3DES_CBC_CBC:
+ case NID_id_PACE_ECDH_IM_3DES_CBC_CBC:
+ /* For 3DES encryption or decryption the IV is always NULL */
+ free(psmctx->ctx->iv);
+ psmctx->ctx->iv = NULL;
+ break;
+ default:
+ break;
+ }
+
+ r = SC_SUCCESS;
+
+err:
+ if (sscbuf)
+ BUF_MEM_free(sscbuf);
+ if (ivbuf)
+ BUF_MEM_free(ivbuf);
+
+ return r;
+}
+
+int
+increment_ssc(struct sm_ctx *ctx)
+{
+ if (!ctx || !ctx->cipher_ctx)
+ return SC_ERROR_INVALID_ARGUMENTS;
+
+ struct pace_sm_ctx *psmctx = ctx->cipher_ctx;
+
+ if (psmctx->ssc == 0) {
+ psmctx->ssc = 2;
+ } else {
+ psmctx->ssc++;
+ }
+
+ update_iv(ctx);
+
+ return SC_SUCCESS;
+}
+
+int
+reset_ssc(struct sm_ctx *ctx)
+{
+ if (!ctx || !ctx->cipher_ctx)
+ return SC_ERROR_INVALID_ARGUMENTS;
+
+ struct pace_sm_ctx *psmctx = ctx->cipher_ctx;
+ psmctx->ssc = 0;
+
+ return SC_SUCCESS;
+}
+
+int pace_sm_encrypt(sc_card_t *card, const struct sm_ctx *ctx,
+ const u8 *data, size_t datalen, u8 **enc)
+{
+ BUF_MEM *encbuf = NULL, *databuf = NULL;
+ u8 *p = NULL;
+ int r;
+
+ if (!ctx || !enc || !ctx->cipher_ctx) {
+ r = SC_ERROR_INVALID_ARGUMENTS;
+ goto err;
+ }
+ struct pace_sm_ctx *psmctx = ctx->cipher_ctx;
+
+ /* The send sequence counter is extended to the block length of the cipher,
+ * so it is no problem that we get padded data */
+ databuf = BUF_MEM_create_init(data, datalen);
+ encbuf = PACE_encrypt(psmctx->ctx, psmctx->key_enc, databuf);
+ if (!databuf || !encbuf) {
+ r = SC_ERROR_INTERNAL;
+ goto err;
+ }
+
+ if (!encbuf) {
+ r = SC_ERROR_INTERNAL;
+ goto err;
+ }
+
+ p = realloc(*enc, encbuf->length);
+ if (!p) {
+ r = SC_ERROR_OUT_OF_MEMORY;
+ goto err;
+ }
+ memcpy(p, encbuf->data, encbuf->length);
+
+ *enc = p;
+ r = encbuf->length;
+
+err:
+ if (databuf) {
+ OPENSSL_cleanse(databuf->data, databuf->max);
+ BUF_MEM_free(databuf);
+ }
+ if (encbuf)
+ BUF_MEM_free(encbuf);
+
+ SC_FUNC_RETURN(card->ctx, SC_LOG_TYPE_ERROR, r);
+}
+
+int pace_sm_decrypt(sc_card_t *card, const struct sm_ctx *ctx,
+ const u8 *enc, size_t enclen, u8 **data)
+{
+ BUF_MEM *encbuf = NULL, *databuf = NULL;
+ u8 *p = NULL;
+ int r;
+
+ if (!ctx || !enc || !ctx->cipher_ctx) {
+ r = SC_ERROR_INVALID_ARGUMENTS;
+ goto err;
+ }
+ struct pace_sm_ctx *psmctx = ctx->cipher_ctx;
+
+ encbuf = BUF_MEM_create_init(enc, enclen);
+ databuf = PACE_decrypt(psmctx->ctx, psmctx->key_enc, encbuf);
+ if (!encbuf || !databuf) {
+ r = SC_ERROR_INTERNAL;
+ goto err;
+ }
+
+ p = realloc(*data, databuf->length);
+ if (!p) {
+ r = SC_ERROR_OUT_OF_MEMORY;
+ goto err;
+ }
+ memcpy(p, databuf->data, databuf->length);
+
+ *data = p;
+ r = databuf->length;
+
+err:
+ if (databuf) {
+ OPENSSL_cleanse(databuf->data, databuf->max);
+ BUF_MEM_free(databuf);
+ }
+ if (encbuf)
+ BUF_MEM_free(encbuf);
+
+ SC_FUNC_RETURN(card->ctx, SC_LOG_TYPE_ERROR, r);
+}
+
+int pace_sm_authenticate(sc_card_t *card, const struct sm_ctx *ctx,
+ const u8 *data, size_t datalen, u8 **macdata)
+{
+ BUF_MEM *databuf = NULL, *macbuf = NULL;
+ u8 *p = NULL;
+ int r;
+
+ if (!ctx || !ctx->cipher_ctx) {
+ r = SC_ERROR_INVALID_ARGUMENTS;
+ goto err;
+ }
+ struct pace_sm_ctx *psmctx = ctx->cipher_ctx;
+
+ databuf = encoded_ssc(psmctx->ssc, psmctx->ctx);
+ if (!databuf ||
+ !BUF_MEM_grow(databuf, databuf->length + datalen)) {
+ r = SC_ERROR_INTERNAL;
+ goto err;
+ }
+ memcpy(databuf->data + databuf->length, data, datalen);
+
+ macbuf = PACE_authenticate(psmctx->ctx, psmctx->protocol,
+ psmctx->key_mac, databuf);
+ if (!macbuf) {
+ r = SC_ERROR_INTERNAL;
+ goto err;
+ }
+
+ p = realloc(*macdata, macbuf->length);
+ if (!p) {
+ r = SC_ERROR_OUT_OF_MEMORY;
+ goto err;
+ }
+ memcpy(p, macbuf->data, macbuf->length);
+
+ *macdata = p;
+ r = macbuf->length;
+
+err:
+ if (databuf) {
+ OPENSSL_cleanse(databuf->data, databuf->max);
+ BUF_MEM_free(databuf);
+ }
+ if (macbuf)
+ BUF_MEM_free(macbuf);
+
+ SC_FUNC_RETURN(card->ctx, SC_LOG_TYPE_ERROR, r);
}
#endif
diff --git a/ccid/pace.h b/ccid/pace.h
index 51b4d61..88d600f 100644
--- a/ccid/pace.h
+++ b/ccid/pace.h
@@ -16,12 +16,13 @@
* You should have received a copy of the GNU General Public License along with
* ccid. If not, see .
*/
-#ifndef _PACE_H
-#define _PACE_H
+#ifndef _CCID_PACE_H
+#define _CCID_PACE_H
#include "sm.h"
#include
#include
+#include
#ifdef __cplusplus
extern "C" {
@@ -40,10 +41,34 @@ extern "C" {
#define MAX_EF_CARDACCESS 2048
+struct pace_sm_ctx {
+ int protocol;
+ /* XXX SSC is up to 16 Bytes long, not only 16 Bits */
+ uint16_t ssc;
+ const BUF_MEM *key_mac;
+ const BUF_MEM *key_enc;
+ PACE_CTX *ctx;
+};
+
+struct pace_sm_ctx *
+pace_sm_ctx_create(int protocol, const BUF_MEM *key_mac,
+ const BUF_MEM *key_enc, PACE_CTX *ctx);
+void
+pace_sm_ctx_free(struct pace_sm_ctx *ctx);
+void
+pace_sm_ctx_clear_free(struct pace_sm_ctx *ctx);
+
+int pace_sm_encrypt(sc_card_t *card, const struct sm_ctx *ctx,
+ const u8 *data, size_t datalen, u8 **enc);
+int pace_sm_decrypt(sc_card_t *card, const struct sm_ctx *ctx,
+ const u8 *enc, size_t enclen, u8 **data);
+int pace_sm_authenticate(sc_card_t *card, const struct sm_ctx *ctx,
+ const u8 *data, size_t datalen, u8 **outdata);
+
int GetReadersPACECapabilities(sc_card_t *card, const __u8
*in, __u8 **out, size_t *outlen);
int EstablishPACEChannel(sc_card_t *card, const __u8 *in,
- __u8 **out, size_t *outlen, struct sm_ctx *sm_ctx);
+ __u8 **out, size_t *outlen, struct sm_ctx *ctx);
int pace_test(sc_card_t *card);
#ifdef __cplusplus
diff --git a/ccid/pace_lib.c b/ccid/pace_lib.c
new file mode 100644
index 0000000..b9f259f
--- /dev/null
+++ b/ccid/pace_lib.c
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2010 Frank Morgner
+ *
+ * This file is part of ccid.
+ *
+ * ccid is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later
+ * version.
+ *
+ * ccid 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 General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * ccid. If not, see .
+ */
+#include "pace.h"
+#include
+#include
+
+struct pace_sm_ctx *
+pace_sm_ctx_create(int protocol, const BUF_MEM *key_mac,
+ const BUF_MEM *key_enc, PACE_CTX *ctx)
+{
+ struct pace_sm_ctx *out = malloc(sizeof *out);
+ if (!out)
+ return NULL;
+
+ out->key_enc = key_enc;
+ out->key_mac = key_mac;
+ out->protocol = protocol;
+ out->ctx = ctx;
+
+ return out;
+}
+
+void
+pace_sm_ctx_free(struct pace_sm_ctx *ctx)
+{
+ if (ctx) {
+ free(ctx);
+ }
+}
+
+void
+pace_sm_ctx_clear_free(struct pace_sm_ctx *ctx)
+{
+ if (ctx) {
+ if (ctx->key_mac) {
+ OPENSSL_cleanse(ctx->key_mac->data, ctx->key_mac->max);
+ BUF_MEM_free((BUF_MEM *) ctx->key_mac);
+ }
+ if (ctx->key_enc) {
+ OPENSSL_cleanse(ctx->key_enc->data, ctx->key_enc->max);
+ BUF_MEM_free((BUF_MEM *) ctx->key_enc);
+ }
+ PACE_CTX_clear_free(ctx->ctx);
+ pace_sm_ctx_free(ctx);
+ }
+}
diff --git a/ccid/sm.c b/ccid/sm.c
index de610b4..183bc4a 100644
--- a/ccid/sm.c
+++ b/ccid/sm.c
@@ -1,29 +1,89 @@
+/*
+ * Copyright (C) 2010 Frank Morgner
+ *
+ * This file is part of ccid.
+ *
+ * ccid is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later
+ * version.
+ *
+ * ccid 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 General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * ccid. If not, see .
+ */
#include "sm.h"
-#include "utils.h"
+#include
#include
#include
+#include
#include
static const struct sc_asn1_entry c_sm_capdu[] = {
{ "Padding-content indicator followed by cryptogram",
- SC_ASN1_INTEGER , 0x87, SC_ASN1_OPTIONAL|SC_ASN1_UNSIGNED, NULL, NULL },
+ SC_ASN1_OCTET_STRING, SC_ASN1_CTX|0x07, SC_ASN1_OPTIONAL , NULL, NULL },
{ "Protected Le",
- SC_ASN1_INTEGER , 0x97, SC_ASN1_OPTIONAL|SC_ASN1_UNSIGNED, NULL, NULL },
+ SC_ASN1_INTEGER , SC_ASN1_CTX|0x17, SC_ASN1_OPTIONAL|SC_ASN1_UNSIGNED, NULL, NULL },
{ "Cryptographic Checksum",
- SC_ASN1_OCTET_STRING, 0x8E, 0, NULL, NULL },
+ SC_ASN1_OCTET_STRING, SC_ASN1_CTX|0x0E, SC_ASN1_OPTIONAL , NULL, NULL },
{ NULL , 0 , 0 , 0 , NULL , NULL }
};
static const struct sc_asn1_entry c_sm_rapdu[] = {
{ "Padding-content indicator followed by cryptogram" ,
- SC_ASN1_INTEGER , 0x87, SC_ASN1_OPTIONAL|SC_ASN1_UNSIGNED, NULL, NULL },
+ SC_ASN1_OCTET_STRING, SC_ASN1_CTX|0x07, SC_ASN1_OPTIONAL , NULL, NULL },
{ "Processing Status",
- SC_ASN1_INTEGER , 0x99, SC_ASN1_OPTIONAL|SC_ASN1_UNSIGNED, NULL, NULL },
+ SC_ASN1_INTEGER , SC_ASN1_CTX|0x19, SC_ASN1_OPTIONAL|SC_ASN1_UNSIGNED, NULL, NULL },
{ "Cryptographic Checksum",
- SC_ASN1_OCTET_STRING, 0x8E, 0, NULL, NULL },
+ SC_ASN1_OCTET_STRING, SC_ASN1_CTX|0x0E, SC_ASN1_OPTIONAL , NULL, NULL },
{ NULL, 0, 0, 0, NULL, NULL }
};
+void bin_log(sc_context_t *ctx, const char *label, const u8 *data, size_t len)
+{
+ char buf[1024];
+
+ sc_hex_dump(ctx, data, len, buf, sizeof buf);
+ sc_debug(ctx, "%s (%u bytes):\n%s"
+ "======================================================================",
+ label, len, buf);
+}
+
+BUF_MEM *
+add_iso_pad(const BUF_MEM * m, int block_size)
+{
+ BUF_MEM * out = NULL;
+ int p_len;
+
+ if (!m)
+ goto err;
+
+ /* calculate length of padded message */
+ p_len = (m->length / block_size) * block_size + block_size;
+
+ out = BUF_MEM_create(p_len);
+ if (!out)
+ goto err;
+
+ memcpy(out->data, m->data, m->length);
+
+ /* now add iso padding */
+ memset(out->data + m->length, 0x80, 1);
+ memset(out->data + m->length + 1, 0, p_len - m->length - 1);
+
+ return out;
+
+err:
+ if (out)
+ BUF_MEM_free(out);
+
+ return NULL;
+}
+
BUF_MEM * add_padding(const struct sm_ctx *ctx, const char *data, size_t datalen)
{
BUF_MEM *tmp = BUF_MEM_create_init(data, datalen);
@@ -35,21 +95,20 @@ BUF_MEM * add_padding(const struct sm_ctx *ctx, const char *data, size_t datalen
tmp = NULL;
break;
case SM_ISO_PADDING:
- padded = add_iso_pad(tmp, EVP_CIPHER_block_size(ctx->cipher));
+ padded = add_iso_pad(tmp, ctx->block_length);
+ /* fall through */
+ default:
if (tmp) {
- OPENSSL_cleanse(tmp->data, tmp->max);
+ sc_mem_clear(tmp->data, tmp->max);
BUF_MEM_free(tmp);
}
break;
- default:
- return NULL;
}
return padded;
}
-int no_padding(u8 padding_indicator, const char *data, size_t datalen,
- size_t *raw_len)
+int no_padding(u8 padding_indicator, const u8 *data, size_t datalen)
{
if (!datalen || !data)
return SC_ERROR_INVALID_ARGUMENTS;
@@ -72,9 +131,7 @@ int no_padding(u8 padding_indicator, const char *data, size_t datalen,
return SC_ERROR_NOT_SUPPORTED;
}
- *raw_len = len;
-
- return SC_SUCCESS;
+ return len;
}
u8 * format_le(size_t le_len, size_t le, struct sc_asn1_entry *le_entry)
@@ -117,29 +174,36 @@ BUF_MEM * prefix_buf(u8 prefix, BUF_MEM *buf)
return cat;
}
-BUF_MEM * format_data(const struct sm_ctx *ctx, const u8 *data, size_t datalen,
+BUF_MEM * format_data(sc_card_t *card, const struct sm_ctx *ctx, const u8 *data, size_t datalen,
struct sc_asn1_entry *formatted_encrypted_data_entry)
{
+ int r;
+
+ if (!ctx)
+ return NULL;
BUF_MEM *pad_data = add_padding(ctx, (char *) data, datalen);
- BUF_MEM *enc_data = cipher(ctx->cipher_ctx, ctx->cipher,
- ctx->cipher_engine, ctx->key_enc, ctx->iv, 1, pad_data);
+ BUF_MEM *enc_data = BUF_MEM_new();
+ if (!pad_data || !enc_data)
+ return NULL;
- if (pad_data) {
- OPENSSL_cleanse(pad_data->data, pad_data->max);
- BUF_MEM_free(pad_data);
- }
+ r = ctx->encrypt(card, ctx, (u8 *) pad_data->data, pad_data->length,
+ (u8 **) &enc_data->data);
+ if (r < 0)
+ return NULL;
+ enc_data->length = r;
BUF_MEM *indicator_encdata = prefix_buf(ctx->padding_indicator, enc_data);
- if (enc_data) {
- BUF_MEM_free(enc_data);
- }
+ sc_mem_clear(pad_data->data, pad_data->max);
+ BUF_MEM_free(pad_data);
+ BUF_MEM_free(enc_data);
if (indicator_encdata)
sc_format_asn1_entry(formatted_encrypted_data_entry,
- indicator_encdata->data, &(indicator_encdata->length),
+ indicator_encdata->data, &indicator_encdata->length,
SC_ASN1_PRESENT);
+
return indicator_encdata;
}
@@ -173,6 +237,7 @@ int sm_encrypt(const struct sm_ctx *ctx, sc_card_t *card,
mac_data = format_head(ctx, apdu);
if (!mac_data) {
+ sc_error(card->ctx, "Could not format header of SM apdu.");
r = SC_ERROR_WRONG_PADDING;
goto err;
}
@@ -184,6 +249,7 @@ int sm_encrypt(const struct sm_ctx *ctx, sc_card_t *card,
case SC_APDU_CASE_2_SHORT:
le = format_le(1, apdu->le, sm_capdu + 1);
if (!le) {
+ sc_error(card->ctx, "Could not format Le of SM apdu.");
r = SC_ERROR_WRONG_LENGTH;
goto err;
}
@@ -193,6 +259,7 @@ int sm_encrypt(const struct sm_ctx *ctx, sc_card_t *card,
/* T0 extended APDUs look just like short APDUs */
le = format_le(1, apdu->le, sm_capdu + 1);
if (!le) {
+ sc_error(card->ctx, "Could not format Le of SM apdu.");
r = SC_ERROR_WRONG_LENGTH;
goto err;
}
@@ -200,6 +267,7 @@ int sm_encrypt(const struct sm_ctx *ctx, sc_card_t *card,
/* in case of T1 always use 3 bytes for length */
le = format_le(3, apdu->le, sm_capdu + 1);
if (!le) {
+ sc_error(card->ctx, "Could not format Le of SM apdu.");
r = SC_ERROR_WRONG_LENGTH;
goto err;
}
@@ -207,9 +275,10 @@ int sm_encrypt(const struct sm_ctx *ctx, sc_card_t *card,
break;
case SC_APDU_CASE_3_SHORT:
case SC_APDU_CASE_3_EXT:
- fdata = format_data(ctx, apdu->data, apdu->datalen,
+ fdata = format_data(card, ctx, apdu->data, apdu->datalen,
sm_capdu + 0);
if (!fdata) {
+ sc_error(card->ctx, "Could not format data of SM apdu.");
r = SC_ERROR_OUT_OF_MEMORY;
goto err;
}
@@ -219,14 +288,16 @@ int sm_encrypt(const struct sm_ctx *ctx, sc_card_t *card,
if (card->slot->active_protocol != SC_PROTO_T0) {
le = format_le(1, apdu->le, sm_capdu + 1);
if (!le) {
+ sc_error(card->ctx, "Could not format Le of SM apdu.");
r = SC_ERROR_WRONG_LENGTH;
goto err;
}
}
- fdata = format_data(ctx, apdu->data, apdu->datalen,
+ fdata = format_data(card, ctx, apdu->data, apdu->datalen,
sm_capdu + 0);
if (!fdata) {
+ sc_error(card->ctx, "Could not format data of SM apdu.");
r = SC_ERROR_OUT_OF_MEMORY;
goto err;
}
@@ -241,19 +312,22 @@ int sm_encrypt(const struct sm_ctx *ctx, sc_card_t *card,
* expected data */
le = format_le(2, apdu->le, sm_capdu + 1);
if (!le) {
+ sc_error(card->ctx, "Could not format Le of SM apdu.");
r = SC_ERROR_WRONG_LENGTH;
goto err;
}
}
- fdata = format_data(ctx, apdu->data, apdu->datalen,
+ fdata = format_data(card, ctx, apdu->data, apdu->datalen,
sm_capdu + 0);
if (!fdata) {
+ sc_error(card->ctx, "Could not format data of SM apdu.");
r = SC_ERROR_OUT_OF_MEMORY;
goto err;
}
break;
default:
+ sc_error(card->ctx, "Unhandled apdu case.");
r = SC_ERROR_INVALID_DATA;
goto err;
}
@@ -273,20 +347,24 @@ int sm_encrypt(const struct sm_ctx *ctx, sc_card_t *card,
memcpy(mac_data->data + oldlen, tmp->data, tmp->length);
BUF_MEM_free(tmp);
tmp = add_padding(ctx, mac_data->data, mac_data->length);
- BUF_MEM_free(mac_data);
- mac_data = hash(ctx->md, ctx->md_ctx, ctx->md_engine, tmp);
- mac = cipher(ctx->cipher_ctx, ctx->cipher, ctx->cipher_engine,
- ctx->key_mac, ctx->iv, 1, mac_data);
+ mac = BUF_MEM_new();
if (!mac) {
- r = SC_ERROR_INTERNAL;
+ r = SC_ERROR_OUT_OF_MEMORY;
goto err;
}
- sc_format_asn1_entry(sm_capdu + 2, mac->data, &(mac->length),
+ r = ctx->authenticate(card, ctx, (u8 *) tmp->data, tmp->length,
+ (u8 **) &mac->data);
+ if (r < 0) {
+ sc_error(card->ctx, "Could not get authentication code");
+ goto err;
+ }
+ mac->length = r;
+ bin_log(card->ctx, "mac", (u8 *)mac->data, mac->length);
+ sc_format_asn1_entry(sm_capdu + 2, mac->data, &mac->length,
SC_ASN1_PRESENT);
/* format SM apdu */
- BUF_MEM_free(sm_data);
sm_data = BUF_MEM_new();
if (!sm_data) {
r = SC_ERROR_OUT_OF_MEMORY;
@@ -296,6 +374,7 @@ int sm_encrypt(const struct sm_ctx *ctx, sc_card_t *card,
if (r < 0)
goto err;
memcpy(sm_apdu, apdu, sizeof *sm_apdu);
+ sm_apdu->cla = 0x0C;
sm_apdu->data = (u8 *) sm_data->data;
sm_apdu->lc = sm_data->length;
sm_apdu->le = 0;
@@ -335,12 +414,13 @@ int sm_decrypt(const struct sm_ctx *ctx, sc_card_t *card,
{
int r;
struct sc_asn1_entry sm_rapdu[4];
- u8 sw[2], mac[EVP_CIPHER_block_size(ctx->cipher)], fdata[1024];
+ struct sc_asn1_entry my_sm_rapdu[4];
+ u8 sw[2], mac[256], fdata[1024];
size_t sw_len = sizeof sw, mac_len = sizeof mac, fdata_len = sizeof fdata,
- buf_len, oldlen;
+ buf_len;
const u8 *buf;
- BUF_MEM *mac_data = NULL, *tmp = NULL, *my_mac = NULL, *data = NULL,
- enc_data;
+ u8 *data;
+ BUF_MEM *mac_data = NULL, *tmp = NULL, *my_mac = NULL;
sc_copy_asn1_entry(c_sm_rapdu, sm_rapdu);
sc_format_asn1_entry(sm_rapdu + 0, fdata, &fdata_len, 0);
@@ -352,71 +432,61 @@ int sm_decrypt(const struct sm_ctx *ctx, sc_card_t *card,
if (r < 0)
goto err;
if (buf_len > 0) {
- r = SC_ERROR_TOO_MANY_OBJECTS;
+ r = SC_ERROR_UNKNOWN_DATA_RECEIVED;
goto err;
}
+ if (sm_rapdu[2].flags & SC_ASN1_PRESENT) {
+ sc_copy_asn1_entry(sm_rapdu, my_sm_rapdu);
+
+ tmp = BUF_MEM_new();
+ if (!tmp) {
+ r = SC_ERROR_OUT_OF_MEMORY;
+ goto err;
+ }
+ sc_format_asn1_entry(my_sm_rapdu + 2, NULL, NULL, 0);
+ r = sc_asn1_encode(card->ctx, my_sm_rapdu, (u8 **) &tmp->data, &tmp->length);
+ if (r < 0)
+ goto err;
+ mac_data = add_padding(ctx, tmp->data, tmp->length);
+ if (!mac_data) {
+ r = SC_ERROR_INTERNAL;
+ goto err;
+ }
+
+ r = ctx->verify_authentication(card, ctx, mac, mac_len,
+ (u8 *) mac_data->data, mac_data->length);
+ if (r < 0)
+ goto err;
+ }
+
+
+
+
if (sm_rapdu[0].flags & SC_ASN1_PRESENT) {
if (ctx->padding_indicator != fdata[0]) {
- r = SC_ERROR_DECRYPT_FAILED;
+ r = SC_ERROR_UNKNOWN_DATA_RECEIVED;
goto err;
}
- enc_data.data = (char *) fdata + 1;
- enc_data.length = fdata_len - 1;
- enc_data.max = enc_data.length;
+ r = ctx->decrypt(card, ctx, fdata + 1, fdata_len - 1, &data);
+ if (r < 0)
+ goto err;
+ buf_len = r;
+
+ r = no_padding(ctx->padding_indicator, data, buf_len);
+ if (r < 0)
+ goto err;
+
+ memcpy(apdu, sm_apdu, sizeof *apdu);
+ apdu->resp = data;
+ apdu->resplen = r;
+ } else {
+ apdu->resplen = r;
}
- mac_data = format_head(ctx, sm_apdu);
-
- tmp = BUF_MEM_new();
- if (!tmp) {
- r = SC_ERROR_OUT_OF_MEMORY;
- goto err;
- }
- sc_format_asn1_entry(sm_rapdu + 2, NULL, NULL, 0);
- r = sc_asn1_encode(card->ctx, sm_rapdu, (u8 **) &tmp->data, &tmp->length);
- if (r < 0)
- goto err;
- oldlen = mac_data->length;
- BUF_MEM_grow(mac_data, oldlen + tmp->length);
- memcpy(mac_data->data + oldlen, tmp->data, tmp->length);
- free(tmp->data);
- tmp = add_padding(ctx, mac_data->data, mac_data->length);
- BUF_MEM_free(mac_data);
- mac_data = hash(ctx->md, ctx->md_ctx, ctx->md_engine, tmp);
- my_mac = cipher(ctx->cipher_ctx, ctx->cipher, ctx->cipher_engine,
- ctx->key_mac, ctx->iv, 1, mac_data);
- if (!my_mac) {
- r = SC_ERROR_INTERNAL;
- goto err;
- }
-
- if (my_mac->length != mac_len ||
- memcmp(my_mac->data, mac, mac_len) != 0) {
- r = SC_ERROR_DECRYPT_FAILED;
- goto err;
- }
-
-
- data = cipher(ctx->cipher_ctx, ctx->cipher, ctx->cipher_engine,
- ctx->key_enc, ctx->iv, 0, &enc_data);
- r = no_padding(ctx->padding_indicator, data->data, data->length,
- &data->length);
- if (r < 0)
- goto err;
-
-
- memcpy(apdu, sm_apdu, sizeof *apdu);
- apdu->resp = (u8 *) data->data;
- apdu->resplen = data->length;
-
-
- /* BUF_MEM_free must not free data->data */
- data->data = NULL;
- data->length = 0;
- data->max = 0;
+ r = SC_SUCCESS;
err:
if (tmp) {
@@ -428,9 +498,6 @@ err:
if (my_mac) {
BUF_MEM_free(my_mac);
}
- if (data) {
- BUF_MEM_free(data);
- }
SC_FUNC_RETURN(card->ctx, SC_LOG_TYPE_ERROR, r);
}
diff --git a/ccid/sm.h b/ccid/sm.h
index 4c09857..073649a 100644
--- a/ccid/sm.h
+++ b/ccid/sm.h
@@ -16,11 +16,11 @@
* You should have received a copy of the GNU General Public License along with
* ccid. If not, see .
*/
-#ifndef _SM_H
-#define _SM_H
+#ifndef _CCID_SM_H
+#define _CCID_SM_H
#include
-#include
+#include
#ifdef __cplusplus
extern "C" {
@@ -31,19 +31,21 @@ extern "C" {
struct sm_ctx {
u8 padding_indicator;
- u8 *key_mac;
- size_t key_mac_len;
- u8 *key_enc;
- size_t key_enc_len;
+ size_t block_length;
- const EVP_CIPHER *cipher;
- EVP_CIPHER_CTX *cipher_ctx;
- ENGINE *cipher_engine;
- unsigned char *iv;
- const EVP_MD * md;
- EVP_MD_CTX * md_ctx;
- ENGINE *md_engine;
+ void *authentication_ctx;
+ int (*authenticate)(sc_card_t *card, const struct sm_ctx *ctx,
+ const u8 *data, size_t datalen, u8 **outdata);
+ int (*verify_authentication)(sc_card_t *card, const struct sm_ctx *ctx,
+ const u8 *mac, size_t maclen,
+ const u8 *macdata, size_t macdatalen);
+
+ void *cipher_ctx;
+ int (*encrypt)(sc_card_t *card, const struct sm_ctx *ctx,
+ const u8 *data, size_t datalen, u8 **enc);
+ int (*decrypt)(sc_card_t *card, const struct sm_ctx *ctx,
+ const u8 *enc, size_t enclen, u8 **data);
};
int sm_encrypt(const struct sm_ctx *ctx, sc_card_t *card,
@@ -51,6 +53,11 @@ int sm_encrypt(const struct sm_ctx *ctx, sc_card_t *card,
int sm_decrypt(const struct sm_ctx *ctx, sc_card_t *card,
const sc_apdu_t *sm_apdu, sc_apdu_t *apdu);
+BUF_MEM * add_iso_pad(const BUF_MEM * m, int block_size);
+BUF_MEM * add_padding(const struct sm_ctx *ctx, const char *data, size_t datalen);
+
+void bin_log(sc_context_t *ctx, const char *label, const u8 *data, size_t len);
+
#ifdef __cplusplus
}
#endif
diff --git a/ccid/utils.c b/ccid/utils.c
deleted file mode 100644
index 4a9bfd7..0000000
--- a/ccid/utils.c
+++ /dev/null
@@ -1,278 +0,0 @@
-/**
- * @date 2009-11-30
- * @version 0.1
- * @author Frank Morgner
- * @author Dominik Oepen
- */
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include "utils.h"
-
-BUF_MEM *
-hash(const EVP_MD * md, EVP_MD_CTX * ctx, ENGINE * impl, const BUF_MEM * in)
-{
- BUF_MEM * out = NULL;
- EVP_MD_CTX * tmp_ctx = NULL;
- unsigned int tmp_len;
-
- if (!md || !in)
- goto err;
-
- if (ctx)
- tmp_ctx = ctx;
- else {
- tmp_ctx = EVP_MD_CTX_create();
- if (!tmp_ctx)
- goto err;
- }
-
- tmp_len = EVP_MD_size(md);
- out = BUF_MEM_create(tmp_len);
- if (!out || !EVP_DigestInit_ex(tmp_ctx, md, impl) ||
- !EVP_DigestUpdate(tmp_ctx, in->data, in->length) ||
- !EVP_DigestFinal_ex(tmp_ctx, (unsigned char *) out->data,
- &tmp_len))
- goto err;
- out->length = tmp_len;
-
- if (!ctx)
- EVP_MD_CTX_destroy(tmp_ctx);
-
- return out;
-
-err:
- if (out)
- BUF_MEM_free(out);
- if (tmp_ctx && !ctx)
- EVP_MD_CTX_destroy(tmp_ctx);
-
- return NULL;
-}
-
-BUF_MEM *
-cipher(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *type, ENGINE *impl,
- unsigned char *key, unsigned char *iv, int enc, const BUF_MEM * in)
-{
- BUF_MEM * out = NULL;
- EVP_CIPHER_CTX * tmp_ctx = NULL;
- int i;
-
- if (!in)
- goto err;
-
- if (ctx)
- tmp_ctx = ctx;
- else {
- tmp_ctx = EVP_CIPHER_CTX_new();
- if (!tmp_ctx)
- goto err;
- EVP_CIPHER_CTX_init(tmp_ctx);
- }
-
- if (tmp_ctx->flags & EVP_CIPH_NO_PADDING) {
- i = in->length;
- if (in->length % EVP_CIPHER_block_size(type) != 0) {
- printf("Input length is not a multiple of block length\n");
- goto err;
- }
- } else
- i = in->length + EVP_CIPHER_block_size(type);
-
- out = BUF_MEM_create(i);
- if (!out)
- goto err;
-
- /* get cipher */
- if (!EVP_CipherInit_ex(tmp_ctx, type, impl, key, iv, enc)
- || !EVP_CIPHER_CTX_set_padding(tmp_ctx, 0))
- goto err;
-
- if (!EVP_CipherUpdate(tmp_ctx, (unsigned char *) out->data, &i,
- (unsigned char *) in->data, in->length))
- goto err;
- out->length = i;
-
- if (!EVP_CipherFinal_ex(tmp_ctx, (unsigned char *) (out->data + out->length),
- &i))
- goto err;
-
- if (!(tmp_ctx->flags & EVP_CIPH_NO_PADDING))
- out->length += i;
-
- if (!ctx) {
- EVP_CIPHER_CTX_cleanup(tmp_ctx);
- EVP_CIPHER_CTX_free(tmp_ctx);
- }
-
- return out;
-
-err:
-
- if (out)
- BUF_MEM_free(out);
- if (!ctx && tmp_ctx) {
- EVP_CIPHER_CTX_cleanup(tmp_ctx);
- EVP_CIPHER_CTX_free(tmp_ctx);
- }
-
- return NULL;
-}
-
-
-BUF_MEM *
-add_iso_pad(const BUF_MEM * m, int block_size)
-{
- BUF_MEM * out = NULL;
- int p_len;
-
- if (!m)
- goto err;
-
- /* calculate length of padded message */
- p_len = (m->length / block_size) * block_size + block_size;
-
- out = BUF_MEM_create(p_len);
- if (!out)
- goto err;
-
- memcpy(out->data, m->data, m->length);
-
- /* now add iso padding */
- memset(out->data + m->length, 0x80, 1);
- memset(out->data + m->length + 1, 0, p_len - m->length - 1);
-
- return out;
-
-err:
- if (out)
- BUF_MEM_free(out);
-
- return NULL;
-}
-
-BUF_MEM *
-encoded_ssc(const uint16_t ssc, const PACE_CTX *ctx)
-{
- BUF_MEM * out = NULL;
- size_t len;
-
- if (!ctx)
- goto err;
-
- len = EVP_CIPHER_block_size(ctx->cipher);
- out = BUF_MEM_create(len);
- if (!out || len < sizeof ssc)
- goto err;
-
- /* Copy SSC to the end of buffer and fill the rest with 0 */
- memset(out->data, 0, len);
- memcpy(out->data + len - sizeof ssc, &ssc, sizeof ssc);
-
- return out;
-
-err:
- if (out)
- BUF_MEM_free(out);
-
- return NULL;
-}
-
-BUF_MEM *
-BUF_MEM_create(size_t len)
-{
- BUF_MEM *out = BUF_MEM_new();
- if (!out)
- return NULL;
-
- if (!BUF_MEM_grow(out, len)) {
- BUF_MEM_free(out);
- return NULL;
- }
-
- return out;
-}
-
-BUF_MEM *
-BUF_MEM_create_init(const void *buf, size_t len)
-{
- BUF_MEM *out;
-
- if (!buf)
- return NULL;
-
- out = BUF_MEM_create(len);
- if (!out)
- return NULL;
-
- memcpy(out->data, buf, len);
-
- return out;
-}
-
-BUF_MEM *
-point2buf(const EC_KEY * ecdh, BN_CTX * bn_ctx, const EC_POINT * ecp)
-{
- size_t len;
- BUF_MEM * out;
-
- len = EC_POINT_point2oct(EC_KEY_get0_group(ecdh), ecp,
- EC_KEY_get_conv_form(ecdh), NULL, 0, bn_ctx);
- if (len == 0)
- return NULL;
-
- out = BUF_MEM_create(len);
- if (!out)
- return NULL;
-
- out->length = EC_POINT_point2oct(EC_KEY_get0_group(ecdh), ecp,
- EC_KEY_get_conv_form(ecdh), (unsigned char *) out->data, out->max,
- bn_ctx);
-
- return out;
-}
-
-BUF_MEM *
-bn2buf(const BIGNUM *bn)
-{
- BUF_MEM * out;
-
- if (!bn)
- return NULL;
-
- out = BUF_MEM_create(BN_num_bytes(bn));
- if (!out)
- return NULL;
-
- out->length = BN_bn2bin(bn, (unsigned char *) out->data);
-
- return out;
-}
-
-BUF_MEM *
-BUF_MEM_dup(const BUF_MEM * in)
-{
- BUF_MEM * out = NULL;
-
- if (!in)
- return NULL;
-
- out = BUF_MEM_create(in->length);
- if (!out)
- goto err;
-
- memcpy(out->data, in->data, in->length);
- out->max = in->max;
-
- return out;
-
-err:
- if (out)
- BUF_MEM_free(out);
-
- return NULL;
-}
diff --git a/ccid/utils.h b/ccid/utils.h
deleted file mode 100644
index 8a75266..0000000
--- a/ccid/utils.h
+++ /dev/null
@@ -1,119 +0,0 @@
-#ifndef _UTIL_H_
-#define _UTIL_H_
-/**
- * @date 2009-11-30
- * @version 0.1
- * @author Frank Morgner
- * @author Dominik Oepen
- */
-
-#include
-#include
-#include
-#include
-#include
-
-/**
- * @brief Wrapper for the OpenSSL hash functions.
- *
- * @param md
- * @param ctx (optional)
- * @param impl (optional)
- * @param in
- *
- * @return message digest or NULL if an error occurred
- */
-BUF_MEM *
-hash(const EVP_MD * md, EVP_MD_CTX * ctx, ENGINE * impl, const BUF_MEM * in);
-/**
- * @brief Wrapper to the OpenSSL encryption functions.
- *
- * @param ctx (optional)
- * @param type
- * @param impl only evaluated if init is 1. (optional)
- * @param key only evaluated if init is 1.
- * @param iv only evaluated if init is 1. (optional)
- * @param enc only evaluated if init is 1.
- * @param in
- *
- * @return cipher of in or NULL if an error occurred
- *
- * @note automatic padding is disabled
- */
-BUF_MEM *
-cipher(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *type, ENGINE *impl,
- unsigned char *key, unsigned char *iv, int enc, const BUF_MEM * in);
-/**
- * @brief Padds a buffer using ISO/IEC 9797-1 padding method 2.
- *
- * @param m buffer to padd
- * @param block_size pad to this block size
- *
- * @return new buffer with the padded input or NULL if an error occurred
- */
-BUF_MEM *
-add_iso_pad(const BUF_MEM * m, int block_size);
-/**
- * @brief Encodes a send sequence counter according to TR-3110 F.3
- *
- * @param ssc Send sequence counter to encode (Formatted in big endian)
- * @param ctx PACE_CTX object
- *
- * @return BUF_MEM object containing the send sequence counter or NULL if an error occurred
- *
- * @note This function is automatically called during PACE, normally you should not need to use it.
- */
-BUF_MEM * encoded_ssc(const uint16_t ssc, const PACE_CTX *ctx);
-
-#include
-#include
-
-/**
- * @brief Creates a BUF_MEM object
- *
- * @param len required length of the buffer
- *
- * @return Initialized BUF_MEM object or NULL if an error occurred
- */
-BUF_MEM *
-BUF_MEM_create(size_t len);
-/**
- * @brief Creates and initializes a BUF_MEM object
- *
- * @param buf Initial data
- * @param len Length of buf
- *
- * @return Initialized BUF_MEM object or NULL if an error occurred
- */
-BUF_MEM *
-BUF_MEM_create_init(const void *buf, size_t len);
-/**
- * @brief converts an EC_POINT object to a BUF_MEM object
- *
- * @param ecdh EC_KEY object
- * @param bn_ctx object (optional)
- * @param ecp elliptic curve point to convert
- *
- * @return converted elliptic curve point or NULL if an error occurred
- */
-BUF_MEM *
-point2buf(const EC_KEY * ecdh, BN_CTX * bn_ctx, const EC_POINT * ecp);
-/**
- * @brief converts an BIGNUM object to a BUF_MEM object
- *
- * @param bn bignumber to convert
- *
- * @return converted bignumber or NULL if an error occurred
- */
-BUF_MEM *
-bn2buf(const BIGNUM *bn);
-/**
- * @brief duplicates a BUF_MEM structure
- *
- * @param in BUF_MEM to duplicate
- *
- * @return pointer to the new BUF_MEM or NULL in case of error
- */
-BUF_MEM *
-BUF_MEM_dup(const BUF_MEM * in);
-#endif