integrated SM into pace

git-svn-id: https://vsmartcard.svn.sourceforge.net/svnroot/vsmartcard@53 96b47cad-a561-4643-ad3b-153ac7d7599c
This commit is contained in:
frankmorgner
2010-04-01 05:52:37 +00:00
parent ae3e7ae862
commit 9d573d0398
4 changed files with 129 additions and 64 deletions

View File

@@ -1289,7 +1289,7 @@ int ccid_testpace()
}
if (sc_card_valid(card_in_slot[i])) {
return pace_test(ctx, card_in_slot[i]);
return pace_test(card_in_slot[i]);
}
}

View File

@@ -17,6 +17,7 @@
* ccid. If not, see <http://www.gnu.org/licenses/>.
*/
#include "pace.h"
#include "sm.h"
#include <opensc/log.h>
#include <openssl/asn1.h>
#include <openssl/asn1t.h>
@@ -135,16 +136,16 @@ IMPLEMENT_ASN1_FUNCTIONS(PACE_GEN_AUTH_R)
#ifdef NO_PACE
inline int GetReadersPACECapabilities(sc_context_t *ctx, sc_card_t *card,
inline int GetReadersPACECapabilities(sc_card_t *card,
const __u8 *in, __u8 **out, size_t *outlen) {
SC_FUNC_RETURN(ctx, SC_LOG_TYPE_DEBUG, SC_ERROR_NOT_SUPPORTED);
SC_FUNC_RETURN(card->ctx, SC_LOG_TYPE_DEBUG, SC_ERROR_NOT_SUPPORTED);
}
inline int EstablishPACEChannel(sc_context_t *ctx, sc_card_t *card,
const __u8 *in, __u8 **out, size_t *outlen) {
SC_FUNC_RETURN(ctx, SC_LOG_TYPE_DEBUG, 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);
}
int pace_test(sc_context_t *ctx, sc_card_t *card) {
SC_FUNC_RETURN(ctx, SC_LOG_TYPE_DEBUG, SC_ERROR_NOT_SUPPORTED);
int pace_test(sc_card_t *card) {
SC_FUNC_RETURN(card->ctx, SC_LOG_TYPE_DEBUG, SC_ERROR_NOT_SUPPORTED);
}
#else
@@ -173,14 +174,14 @@ void bin_log(sc_context_t *ctx, const char *label, const u8 *data, size_t len)
label, len, buf);
}
int GetReadersPACECapabilities(sc_context_t *ctx, sc_card_t *card,
int GetReadersPACECapabilities(sc_card_t *card,
const __u8 *in, __u8 **out, size_t *outlen) {
if (!out || !outlen)
SC_FUNC_RETURN(ctx, SC_LOG_TYPE_DEBUG, SC_ERROR_INVALID_ARGUMENTS);
SC_FUNC_RETURN(card->ctx, SC_LOG_TYPE_DEBUG, SC_ERROR_INVALID_ARGUMENTS);
__u8 *result = realloc(*out, 2);
if (!result)
SC_FUNC_RETURN(ctx, SC_LOG_TYPE_DEBUG, SC_ERROR_OUT_OF_MEMORY);
SC_FUNC_RETURN(card->ctx, SC_LOG_TYPE_DEBUG, SC_ERROR_OUT_OF_MEMORY);
*out = result;
*outlen = 2;
@@ -190,11 +191,11 @@ int GetReadersPACECapabilities(sc_context_t *ctx, sc_card_t *card,
/* BitMap */
*result = PACE_BITMAP_PACE|PACE_BITMAP_EID;
SC_FUNC_RETURN(ctx, SC_LOG_TYPE_DEBUG, SC_SUCCESS);
SC_FUNC_RETURN(card->ctx, SC_LOG_TYPE_DEBUG, SC_SUCCESS);
}
/** select and read EF.CardAccess */
int get_ef_card_access(sc_context_t *ctx, sc_card_t *card,
int get_ef_card_access(sc_card_t *card,
__u8 **ef_cardaccess, size_t *length_ef_cardaccess)
{
int r;
@@ -203,13 +204,13 @@ int get_ef_card_access(sc_context_t *ctx, sc_card_t *card,
__u8 *p;
memset(&path, 0, sizeof path);
SC_TEST_RET(ctx, sc_append_file_id(&path, FID_EF_CARDACCESS),
SC_TEST_RET(card->ctx, sc_append_file_id(&path, FID_EF_CARDACCESS),
"Could not create path object.");
SC_TEST_RET(ctx, sc_concatenate_path(&path, sc_get_mf_path(), &path),
SC_TEST_RET(card->ctx, sc_concatenate_path(&path, sc_get_mf_path(), &path),
"Could not create path object.");
memset(&file, 0, sizeof file);
SC_TEST_RET(ctx, sc_select_file(card, &path, &file),
SC_TEST_RET(card->ctx, sc_select_file(card, &path, &file),
"Could not select EF.CardAccess.");
ssc++;
*length_ef_cardaccess = 0;
@@ -217,7 +218,7 @@ int get_ef_card_access(sc_context_t *ctx, sc_card_t *card,
while(1) {
p = realloc(*ef_cardaccess, *length_ef_cardaccess + maxresp);
if (!p)
SC_FUNC_RETURN(ctx, SC_LOG_TYPE_DEBUG, SC_ERROR_OUT_OF_MEMORY);
SC_FUNC_RETURN(card->ctx, SC_LOG_TYPE_DEBUG, SC_ERROR_OUT_OF_MEMORY);
*ef_cardaccess = p;
r = sc_read_binary(card, *length_ef_cardaccess,
@@ -229,7 +230,7 @@ int get_ef_card_access(sc_context_t *ctx, sc_card_t *card,
break;
}
SC_TEST_RET(ctx, r, "Could not read EF.CardAccess.");
SC_TEST_RET(card->ctx, r, "Could not read EF.CardAccess.");
*length_ef_cardaccess += r;
}
@@ -237,12 +238,12 @@ int get_ef_card_access(sc_context_t *ctx, sc_card_t *card,
/* test cards only return an empty FCI template,
* so we can't determine any file proberties */
if (*length_ef_cardaccess < file->size)
SC_FUNC_RETURN(ctx, SC_LOG_TYPE_DEBUG, SC_ERROR_FILE_TOO_SMALL);
SC_FUNC_RETURN(card->ctx, SC_LOG_TYPE_DEBUG, SC_ERROR_FILE_TOO_SMALL);
SC_FUNC_RETURN(ctx, SC_LOG_TYPE_DEBUG, SC_SUCCESS);
SC_FUNC_RETURN(card->ctx, SC_LOG_TYPE_DEBUG, SC_SUCCESS);
}
int pace_mse_set_at(sc_context_t *ctx, sc_card_t *card,
int pace_mse_set_at(sc_card_t *card,
int protocol, int secret_key, int reference)
{
sc_apdu_t apdu;
@@ -286,10 +287,10 @@ int pace_mse_set_at(sc_context_t *ctx, sc_card_t *card,
/* The tag/length for the sequence (0x30) is omitted in the command apdu. */
/* FIXME is there a OpenSSL way to get the value only or even a define for
* the tag? */
apdu.data = sc_asn1_find_tag(ctx, d, r, 0x30, &apdu.datalen);
apdu.data = sc_asn1_find_tag(card->ctx, d, r, 0x30, &apdu.datalen);
apdu.lc = apdu.datalen;
bin_log(ctx, "MSE:Set AT command data", apdu.data, apdu.datalen);
bin_log(card->ctx, "MSE:Set AT command data", apdu.data, apdu.datalen);
r = sc_transmit_apdu(card, &apdu);
ssc++;
@@ -297,7 +298,7 @@ int pace_mse_set_at(sc_context_t *ctx, sc_card_t *card,
goto err;
if (apdu.resplen) {
sc_error(ctx, "MSE:Set AT response data should be empty");
sc_error(card->ctx, "MSE:Set AT response data should be empty");
r = SC_ERROR_UNKNOWN_DATA_RECEIVED;
goto err;
}
@@ -340,10 +341,10 @@ err:
if (apdu.resplen)
free(apdu.resp);
SC_FUNC_RETURN(ctx, SC_LOG_TYPE_DEBUG, r);
SC_FUNC_RETURN(card->ctx, SC_LOG_TYPE_DEBUG, r);
}
int pace_gen_auth(sc_context_t *ctx, sc_card_t *card,
int pace_gen_auth(sc_card_t *card,
int step, const u8 *in, size_t in_len, u8 **out, size_t *out_len)
{
sc_apdu_t apdu;
@@ -409,7 +410,7 @@ int pace_gen_auth(sc_context_t *ctx, sc_card_t *card,
apdu.datalen = r;
apdu.lc = r;
bin_log(ctx, "General authenticate command data", apdu.data, apdu.datalen);
bin_log(card->ctx, "General authenticate command data", apdu.data, apdu.datalen);
/* sanity checks in sc_transmit_apdu forbid case 4 apdus with le == 0 */
apdu.resplen = maxresp;
@@ -423,11 +424,11 @@ int pace_gen_auth(sc_context_t *ctx, sc_card_t *card,
if (r < 0)
goto err;
bin_log(ctx, "General authenticate response data", apdu.resp, apdu.resplen);
bin_log(card->ctx, "General authenticate response data", apdu.resp, apdu.resplen);
if (!d2i_PACE_GEN_AUTH_R(&r_data,
(const unsigned char **) &apdu.resp, apdu.resplen)) {
sc_error(ctx, "Could not parse general authenticate response data.");
sc_error(card->ctx, "Could not parse general authenticate response data.");
r = SC_ERROR_INTERNAL;
goto err;
}
@@ -438,7 +439,7 @@ int pace_gen_auth(sc_context_t *ctx, sc_card_t *card,
|| r_data->mapping_data
|| r_data->eph_pub_key
|| r_data->auth_token) {
sc_error(ctx, "Response data of general authenticate for "
sc_error(card->ctx, "Response data of general authenticate for "
"step %d should (only) contain the "
"encrypted nonce.", step);
r = SC_ERROR_UNKNOWN_DATA_RECEIVED;
@@ -452,7 +453,7 @@ int pace_gen_auth(sc_context_t *ctx, sc_card_t *card,
|| !r_data->mapping_data
|| r_data->eph_pub_key
|| r_data->auth_token) {
sc_error(ctx, "Response data of general authenticate for "
sc_error(card->ctx, "Response data of general authenticate for "
"step %d should (only) contain the "
"mapping data.", step);
r = SC_ERROR_UNKNOWN_DATA_RECEIVED;
@@ -466,7 +467,7 @@ int pace_gen_auth(sc_context_t *ctx, sc_card_t *card,
|| r_data->mapping_data
|| !r_data->eph_pub_key
|| r_data->auth_token) {
sc_error(ctx, "Response data of general authenticate for "
sc_error(card->ctx, "Response data of general authenticate for "
"step %d should (only) contain the "
"ephemeral public key.", step);
r = SC_ERROR_UNKNOWN_DATA_RECEIVED;
@@ -480,7 +481,7 @@ int pace_gen_auth(sc_context_t *ctx, sc_card_t *card,
|| r_data->mapping_data
|| r_data->eph_pub_key
|| !r_data->auth_token) {
sc_error(ctx, "Response data of general authenticate for "
sc_error(card->ctx, "Response data of general authenticate for "
"step %d should (only) contain the "
"authentication token.", step);
r = SC_ERROR_UNKNOWN_DATA_RECEIVED;
@@ -529,7 +530,7 @@ err:
//if (apdu.resplen)
//free(apdu.resp);
SC_FUNC_RETURN(ctx, SC_LOG_TYPE_DEBUG, r);
SC_FUNC_RETURN(card->ctx, SC_LOG_TYPE_DEBUG, r);
}
PACE_SEC *
@@ -585,12 +586,13 @@ void debug_ossl(sc_context_t *ctx) {
}
}
int EstablishPACEChannel(sc_context_t *ctx, 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 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;
@@ -602,7 +604,7 @@ int EstablishPACEChannel(sc_context_t *ctx, sc_card_t *card,
int r;
if (!in || !out || !outlen)
SC_FUNC_RETURN(ctx, SC_LOG_TYPE_DEBUG, SC_ERROR_INVALID_ARGUMENTS);
SC_FUNC_RETURN(card->ctx, SC_LOG_TYPE_DEBUG, SC_ERROR_INVALID_ARGUMENTS);
pin_id = *in;
in++;
@@ -624,42 +626,42 @@ int EstablishPACEChannel(sc_context_t *ctx, sc_card_t *card,
enc_nonce = BUF_MEM_new();
if (!enc_nonce) {
r = SC_ERROR_INTERNAL;
debug_ossl(ctx);
debug_ossl(card->ctx);
goto err;
}
r = get_ef_card_access(ctx, card, &ef_cardaccess, &length_ef_cardaccess);
r = get_ef_card_access(card, &ef_cardaccess, &length_ef_cardaccess);
if (r < 0) {
goto err;
}
bin_log(ctx, "EF.CardAccess", ef_cardaccess, length_ef_cardaccess);
bin_log(card->ctx, "EF.CardAccess", ef_cardaccess, length_ef_cardaccess);
if (!parse_ef_card_access(ef_cardaccess, length_ef_cardaccess,
&info, &static_dp)) {
r = SC_ERROR_INTERNAL;
debug_ossl(ctx);
debug_ossl(card->ctx);
goto err;
}
r = pace_mse_set_at(ctx, card, info->protocol, pin_id, 1);
r = pace_mse_set_at(card, info->protocol, pin_id, 1);
if (r < 0) {
goto err;
}
r = pace_gen_auth(ctx, card, 1, NULL, 0, (u8 **) &enc_nonce->data,
r = pace_gen_auth(card, 1, NULL, 0, (u8 **) &enc_nonce->data,
&enc_nonce->length);
if (r < 0) {
goto err;
}
bin_log(ctx, "Encrypted nonce from MRTD", (u8 *)enc_nonce->data, enc_nonce->length);
bin_log(card->ctx, "Encrypted nonce from MRTD", (u8 *)enc_nonce->data, enc_nonce->length);
enc_nonce->max = enc_nonce->length;
sec = get_psec(card, (char *) pin, length_pin, pin_id);
if (!sec) {
r = SC_ERROR_INTERNAL;
debug_ossl(ctx);
debug_ossl(card->ctx);
goto err;
}
pctx = PACE_CTX_new();
if (!pctx || !PACE_CTX_init(pctx, info)) {
r = SC_ERROR_INTERNAL;
debug_ossl(ctx);
debug_ossl(card->ctx);
goto err;
}
pctx->tr_version = PACE_TR_VERSION_2_01;
@@ -670,38 +672,38 @@ int EstablishPACEChannel(sc_context_t *ctx, sc_card_t *card,
mdata = PACE_STEP3A_generate_mapping_data(static_dp, pctx);
if (!nonce || !mdata || !mdata_opp) {
r = SC_ERROR_INTERNAL;
debug_ossl(ctx);
debug_ossl(card->ctx);
goto err;
}
r = pace_gen_auth(ctx, card, 2, (u8 *) mdata->data, mdata->length,
r = pace_gen_auth(card, 2, (u8 *) mdata->data, mdata->length,
(u8 **) &mdata_opp->data, &mdata_opp->length);
if (r < 0) {
goto err;
}
mdata_opp->max = mdata_opp->length;
bin_log(ctx, "Mapping data from MRTD", (u8 *) mdata_opp->data, mdata_opp->length);
bin_log(card->ctx, "Mapping data from MRTD", (u8 *) mdata_opp->data, mdata_opp->length);
eph_dp = PACE_STEP3A_map_dp(static_dp, pctx, nonce, mdata_opp);
pub = PACE_STEP3B_generate_ephemeral_key(eph_dp, pctx);
pub_opp = BUF_MEM_new();
if (!eph_dp || !pub || !pub_opp) {
r = SC_ERROR_INTERNAL;
debug_ossl(ctx);
debug_ossl(card->ctx);
goto err;
}
r = pace_gen_auth(ctx, card, 3, (u8 *) pub->data, pub->length,
r = pace_gen_auth(card, 3, (u8 *) pub->data, pub->length,
(u8 **) &pub_opp->data, &pub_opp->length);
if (r < 0) {
goto err;
}
pub_opp->max = pub_opp->length;
bin_log(ctx, "Public key from MRTD", (u8 *) pub_opp->data, pub_opp->length);
bin_log(card->ctx, "Public key from MRTD", (u8 *) pub_opp->data, pub_opp->length);
key = PACE_STEP3B_compute_ephemeral_key(eph_dp, pctx, pub_opp);
if (!key ||
!PACE_STEP3C_derive_keys(key, pctx, info, &k_mac, &k_enc)) {
r = SC_ERROR_INTERNAL;
debug_ossl(ctx);
debug_ossl(card->ctx);
goto err;
}
token = PACE_STEP3D_compute_authentication_token(pctx,
@@ -709,25 +711,49 @@ int EstablishPACEChannel(sc_context_t *ctx, sc_card_t *card,
token_opp = BUF_MEM_new();
if (!token || !token_opp) {
r = SC_ERROR_INTERNAL;
debug_ossl(ctx);
debug_ossl(card->ctx);
goto err;
}
r = pace_gen_auth(ctx, card, 4, (u8 *) token->data, token->length,
r = pace_gen_auth(card, 4, (u8 *) token->data, token->length,
(u8 **) &token_opp->data, &token_opp->length);
if (r < 0) {
goto err;
}
token_opp->max = token_opp->length;
bin_log(ctx, "Authentication token from MRTD", (u8 *) token_opp->data, 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)) {
r = SC_ERROR_INTERNAL;
debug_ossl(ctx);
debug_ossl(card->ctx);
goto err;
}
/* 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;
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;
err:
if (info)
@@ -771,14 +797,16 @@ err:
if (pctx)
PACE_CTX_clear_free(pctx);
SC_FUNC_RETURN(ctx, SC_LOG_TYPE_DEBUG, r);
SC_FUNC_RETURN(card->ctx, SC_LOG_TYPE_DEBUG, r);
}
int pace_test(sc_context_t *ctx, sc_card_t *card)
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));
in[0] = PACE_CAN; // pin_id
in[1] = 0; // length_chat
@@ -792,7 +820,8 @@ int pace_test(sc_context_t *ctx, sc_card_t *card)
in[9] = 0; // length_cert_desc
in[10]= 0; // length_cert_desc
return EstablishPACEChannel(ctx, card, in, &out, &outlen);
SC_FUNC_RETURN(card->ctx, SC_LOG_TYPE_ERROR,
EstablishPACEChannel(card, in, &out, &outlen, &sm));
}
#endif

View File

@@ -19,6 +19,7 @@
#ifndef _PACE_H
#define _PACE_H
#include "sm.h"
#include <linux/usb/ch9.h>
#include <opensc/opensc.h>
@@ -39,11 +40,11 @@ extern "C" {
#define MAX_EF_CARDACCESS 2048
int GetReadersPACECapabilities(sc_context_t *ctx, sc_card_t *card, const __u8
int GetReadersPACECapabilities(sc_card_t *card, const __u8
*in, __u8 **out, size_t *outlen);
int EstablishPACEChannel(sc_context_t *ctx, sc_card_t *card, const __u8 *in,
__u8 **out, size_t *outlen);
int pace_test(sc_context_t *ctx, sc_card_t *card);
int EstablishPACEChannel(sc_card_t *card, const __u8 *in,
__u8 **out, size_t *outlen, struct sm_ctx *sm_ctx);
int pace_test(sc_card_t *card);
#ifdef __cplusplus
}

View File

@@ -1,6 +1,31 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef _SM_H
#define _SM_H
#include <opensc/opensc.h>
#include <openssl/evp.h>
#ifdef __cplusplus
extern "C" {
#endif
#define SM_ISO_PADDING 0x01
#define SM_NO_PADDING 0x02
@@ -20,3 +45,13 @@ struct sm_ctx {
EVP_MD_CTX * md_ctx;
ENGINE *md_engine;
};
int sm_encrypt(const struct sm_ctx *ctx, sc_card_t *card,
const sc_apdu_t *apdu, sc_apdu_t *sm_apdu);
int sm_decrypt(const struct sm_ctx *ctx, sc_card_t *card,
const sc_apdu_t *sm_apdu, sc_apdu_t *apdu);
#ifdef __cplusplus
}
#endif
#endif