handling certificate description and chat in libnpa instead of ccid-emulator
git-svn-id: https://vsmartcard.svn.sourceforge.net/svnroot/vsmartcard@534 96b47cad-a561-4643-ad3b-153ac7d7599c
This commit is contained in:
@@ -34,10 +34,7 @@
|
|||||||
#include <npa/npa.h>
|
#include <npa/npa.h>
|
||||||
#include <npa/sm.h>
|
#include <npa/sm.h>
|
||||||
#include <npa/scutil.h>
|
#include <npa/scutil.h>
|
||||||
#include <openssl/cv_cert.h>
|
|
||||||
|
|
||||||
static char *certificate_description = NULL;
|
|
||||||
static size_t certificate_description_length = 0;
|
|
||||||
static struct sm_ctx sctx;
|
static struct sm_ctx sctx;
|
||||||
#ifdef BUERGERCLIENT_WORKAROUND
|
#ifdef BUERGERCLIENT_WORKAROUND
|
||||||
static char *ef_cardaccess = NULL;
|
static char *ef_cardaccess = NULL;
|
||||||
@@ -168,9 +165,6 @@ void ccid_shutdown()
|
|||||||
#ifdef WITH_PACE
|
#ifdef WITH_PACE
|
||||||
sm_ctx_clear_free(&sctx);
|
sm_ctx_clear_free(&sctx);
|
||||||
memset(&sctx, 0, sizeof(sctx));
|
memset(&sctx, 0, sizeof(sctx));
|
||||||
free(certificate_description);
|
|
||||||
certificate_description = NULL;
|
|
||||||
certificate_description_length = 0;
|
|
||||||
#ifdef BUERGERCLIENT_WORKAROUND
|
#ifdef BUERGERCLIENT_WORKAROUND
|
||||||
free(ef_cardaccess);
|
free(ef_cardaccess);
|
||||||
ef_cardaccess = NULL;
|
ef_cardaccess = NULL;
|
||||||
@@ -571,26 +565,6 @@ perform_PC_to_RDR_XfrBlock(const u8 *in, size_t inlen, __u8** out, size_t *outle
|
|||||||
else
|
else
|
||||||
bin_log(ctx, SC_LOG_DEBUG_VERBOSE, "Invalid APDU", abDataIn,
|
bin_log(ctx, SC_LOG_DEBUG_VERBOSE, "Invalid APDU", abDataIn,
|
||||||
__le32_to_cpu(request->dwLength));
|
__le32_to_cpu(request->dwLength));
|
||||||
|
|
||||||
#ifdef WITH_PACE
|
|
||||||
/* Note that this is only an approximation to find out if we
|
|
||||||
* have a nPA */
|
|
||||||
if (sctx.active) {
|
|
||||||
if (apdu.ins == 0x2a && apdu.p1 == 0x00 && apdu.p2 == 0xbe) {
|
|
||||||
/* PSO:Verify Certificate
|
|
||||||
* check certificate description to match given certificate */
|
|
||||||
CVC_CERT *cvc_cert = NULL;
|
|
||||||
|
|
||||||
cvc_cert = CVC_d2i_CVC_CERT(NULL, &apdu.data, apdu.datalen);
|
|
||||||
if (!cvc_cert
|
|
||||||
|| !CVC_check_cert(cvc_cert, certificate_description,
|
|
||||||
certificate_description_length)) {
|
|
||||||
sc_debug(ctx, SC_LOG_DEBUG_VERBOSE, "Certificate Description doesn't match Certificate");
|
|
||||||
SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_INVALID_DATA);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sc_result = get_RDR_to_PC_DataBlock(request->bSeq, sc_result,
|
sc_result = get_RDR_to_PC_DataBlock(request->bSeq, sc_result,
|
||||||
@@ -894,9 +868,6 @@ perform_PC_to_RDR_Secure_EstablishPACEChannel(sc_card_t *card,
|
|||||||
__le16 word;
|
__le16 word;
|
||||||
__le32 dword;
|
__le32 dword;
|
||||||
__u8 *p;
|
__u8 *p;
|
||||||
BIO *bio_stdout = NULL;
|
|
||||||
CVC_CERTIFICATE_DESCRIPTION *desc = NULL;
|
|
||||||
CVC_CHAT *chat = NULL;
|
|
||||||
|
|
||||||
memset(&pace_input, 0, sizeof pace_input);
|
memset(&pace_input, 0, sizeof pace_input);
|
||||||
memset(&pace_output, 0, sizeof pace_output);
|
memset(&pace_output, 0, sizeof pace_output);
|
||||||
@@ -911,13 +882,6 @@ perform_PC_to_RDR_Secure_EstablishPACEChannel(sc_card_t *card,
|
|||||||
bin_log(ctx, SC_LOG_DEBUG_VERBOSE, "EstablishPACEChannel InBuffer",
|
bin_log(ctx, SC_LOG_DEBUG_VERBOSE, "EstablishPACEChannel InBuffer",
|
||||||
abData, abDatalen);
|
abData, abDatalen);
|
||||||
|
|
||||||
bio_stdout = BIO_new_fp(stdout, BIO_NOCLOSE);
|
|
||||||
if (!bio_stdout) {
|
|
||||||
sc_debug(ctx, SC_LOG_DEBUG_VERBOSE, "Could not get output buffer");
|
|
||||||
sc_result = SC_ERROR_INTERNAL;
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (abDatalen < parsed+1) {
|
if (abDatalen < parsed+1) {
|
||||||
sc_debug(ctx, SC_LOG_DEBUG_VERBOSE, "Buffer too small, could not get PinID");
|
sc_debug(ctx, SC_LOG_DEBUG_VERBOSE, "Buffer too small, could not get PinID");
|
||||||
sc_result = SC_ERROR_INVALID_ARGUMENTS;
|
sc_result = SC_ERROR_INVALID_ARGUMENTS;
|
||||||
@@ -945,21 +909,6 @@ perform_PC_to_RDR_Secure_EstablishPACEChannel(sc_card_t *card,
|
|||||||
if (pace_input.chat_length) {
|
if (pace_input.chat_length) {
|
||||||
bin_log(ctx, SC_LOG_DEBUG_VERBOSE, "Card holder authorization template",
|
bin_log(ctx, SC_LOG_DEBUG_VERBOSE, "Card holder authorization template",
|
||||||
pace_input.chat, pace_input.chat_length);
|
pace_input.chat, pace_input.chat_length);
|
||||||
|
|
||||||
chat = d2i_CVC_CHAT(NULL,
|
|
||||||
&pace_input.chat,
|
|
||||||
pace_input.chat_length);
|
|
||||||
if (!chat) {
|
|
||||||
sc_debug(ctx, SC_LOG_DEBUG_VERBOSE, "Could not parse CHAT");
|
|
||||||
sc_result = SC_ERROR_INTERNAL;
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!cvc_chat_print(bio_stdout, chat, 4)) {
|
|
||||||
sc_debug(ctx, SC_LOG_DEBUG_VERBOSE, "Could not print CHAT");
|
|
||||||
sc_result = SC_ERROR_INTERNAL;
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -997,35 +946,10 @@ perform_PC_to_RDR_Secure_EstablishPACEChannel(sc_card_t *card,
|
|||||||
}
|
}
|
||||||
pace_input.certificate_description = &abData[parsed];
|
pace_input.certificate_description = &abData[parsed];
|
||||||
parsed += pace_input.certificate_description_length;
|
parsed += pace_input.certificate_description_length;
|
||||||
p = realloc(certificate_description,
|
|
||||||
pace_input.certificate_description_length);
|
|
||||||
if (!p) {
|
|
||||||
sc_result = SC_ERROR_OUT_OF_MEMORY;
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
certificate_description = p;
|
|
||||||
certificate_description_length = pace_input.certificate_description_length;
|
|
||||||
memcpy(certificate_description, pace_input.certificate_description,
|
|
||||||
pace_input.certificate_description_length);
|
|
||||||
if (pace_input.certificate_description_length) {
|
if (pace_input.certificate_description_length) {
|
||||||
bin_log(ctx, SC_LOG_DEBUG_VERBOSE, "Certificate description",
|
bin_log(ctx, SC_LOG_DEBUG_VERBOSE, "Certificate description",
|
||||||
pace_input.certificate_description,
|
pace_input.certificate_description,
|
||||||
pace_input.certificate_description_length);
|
pace_input.certificate_description_length);
|
||||||
|
|
||||||
desc = d2i_CVC_CERTIFICATE_DESCRIPTION(NULL,
|
|
||||||
&pace_input.certificate_description,
|
|
||||||
pace_input.certificate_description_length);
|
|
||||||
if (!desc) {
|
|
||||||
sc_debug(ctx, SC_LOG_DEBUG_VERBOSE, "Could not parse Certificate Description");
|
|
||||||
sc_result = SC_ERROR_INTERNAL;
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!certificate_description_print(bio_stdout, desc, 4)) {
|
|
||||||
sc_debug(ctx, SC_LOG_DEBUG_VERBOSE, "Could not print Certificate Description");
|
|
||||||
sc_result = SC_ERROR_INTERNAL;
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1165,12 +1089,6 @@ err:
|
|||||||
free(pace_output.previous_car);
|
free(pace_output.previous_car);
|
||||||
free(pace_output.id_icc);
|
free(pace_output.id_icc);
|
||||||
free(pace_output.id_pcd);
|
free(pace_output.id_pcd);
|
||||||
if (bio_stdout)
|
|
||||||
BIO_free_all(bio_stdout);
|
|
||||||
if (desc)
|
|
||||||
CVC_CERTIFICATE_DESCRIPTION_free(desc);
|
|
||||||
if (chat)
|
|
||||||
CVC_CHAT_free(chat);
|
|
||||||
|
|
||||||
return sc_result;
|
return sc_result;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,12 +27,11 @@
|
|||||||
#include <openssl/bio.h>
|
#include <openssl/bio.h>
|
||||||
#include <openssl/buffer.h>
|
#include <openssl/buffer.h>
|
||||||
#include <openssl/cv_cert.h>
|
#include <openssl/cv_cert.h>
|
||||||
|
#include <openssl/eac.h>
|
||||||
#include <openssl/err.h>
|
#include <openssl/err.h>
|
||||||
#include <openssl/evp.h>
|
#include <openssl/evp.h>
|
||||||
#include <openssl/objects.h>
|
#include <openssl/objects.h>
|
||||||
#include <openssl/eac.h>
|
|
||||||
#include <openssl/pace.h>
|
#include <openssl/pace.h>
|
||||||
#include <openssl/cv_cert.h>
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
|
||||||
@@ -157,6 +156,10 @@ struct npa_sm_ctx {
|
|||||||
BIGNUM *ssc;
|
BIGNUM *ssc;
|
||||||
/** EAC context */
|
/** EAC context */
|
||||||
EAC_CTX *ctx;
|
EAC_CTX *ctx;
|
||||||
|
/** Certificate Description given on initialization of PACE */
|
||||||
|
unsigned char *certificate_description;
|
||||||
|
/** length of \a certificate_description */
|
||||||
|
size_t certificate_description_length;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int npa_sm_encrypt(sc_card_t *card, const struct sm_ctx *ctx,
|
static int npa_sm_encrypt(sc_card_t *card, const struct sm_ctx *ctx,
|
||||||
@@ -179,7 +182,8 @@ static int decrement_ssc(struct npa_sm_ctx *eacsmctx);
|
|||||||
static int reset_ssc(struct npa_sm_ctx *eacsmctx);
|
static int reset_ssc(struct npa_sm_ctx *eacsmctx);
|
||||||
|
|
||||||
static struct npa_sm_ctx *
|
static struct npa_sm_ctx *
|
||||||
npa_sm_ctx_create(EAC_CTX *ctx)
|
npa_sm_ctx_create(EAC_CTX *ctx, const unsigned char *certificate_description,
|
||||||
|
size_t certificate_description_length)
|
||||||
{
|
{
|
||||||
struct npa_sm_ctx *out = malloc(sizeof *out);
|
struct npa_sm_ctx *out = malloc(sizeof *out);
|
||||||
if (!out)
|
if (!out)
|
||||||
@@ -191,6 +195,13 @@ npa_sm_ctx_create(EAC_CTX *ctx)
|
|||||||
|
|
||||||
out->ctx = ctx;
|
out->ctx = ctx;
|
||||||
|
|
||||||
|
out->certificate_description = realloc(NULL,
|
||||||
|
certificate_description_length);
|
||||||
|
if (!out->certificate_description)
|
||||||
|
goto err;
|
||||||
|
out->certificate_description_length = certificate_description_length;
|
||||||
|
memcpy(out->certificate_description, certificate_description,
|
||||||
|
certificate_description_length);
|
||||||
|
|
||||||
return out;
|
return out;
|
||||||
|
|
||||||
@@ -1206,7 +1217,9 @@ int EstablishPACEChannel(struct sm_ctx *oldnpactx, sc_card_t *card,
|
|||||||
bin_log(card->ctx, SC_LOG_DEBUG_NORMAL, "ID PCD", pace_output->id_pcd,
|
bin_log(card->ctx, SC_LOG_DEBUG_NORMAL, "ID PCD", pace_output->id_pcd,
|
||||||
pace_output->id_pcd_length);
|
pace_output->id_pcd_length);
|
||||||
|
|
||||||
sctx->priv_data = npa_sm_ctx_create(eac_ctx);
|
sctx->priv_data = npa_sm_ctx_create(eac_ctx,
|
||||||
|
pace_input.certificate_description,
|
||||||
|
pace_input.certificate_description_length);
|
||||||
if (!sctx->priv_data) {
|
if (!sctx->priv_data) {
|
||||||
r = SC_ERROR_OUT_OF_MEMORY;
|
r = SC_ERROR_OUT_OF_MEMORY;
|
||||||
goto err;
|
goto err;
|
||||||
@@ -1489,6 +1502,21 @@ static int
|
|||||||
npa_sm_pre_transmit(sc_card_t *card, const struct sm_ctx *ctx,
|
npa_sm_pre_transmit(sc_card_t *card, const struct sm_ctx *ctx,
|
||||||
sc_apdu_t *apdu)
|
sc_apdu_t *apdu)
|
||||||
{
|
{
|
||||||
|
if (apdu && apdu->ins == 0x2a && apdu->p1 == 0x00 && apdu->p2 == 0xbe) {
|
||||||
|
/* PSO:Verify Certificate
|
||||||
|
* check certificate description to match given certificate */
|
||||||
|
CVC_CERT *cvc_cert = NULL;
|
||||||
|
struct npa_sm_ctx *eacsmctx = ctx->priv_data;
|
||||||
|
|
||||||
|
cvc_cert = CVC_d2i_CVC_CERT(NULL, &apdu->data, apdu->datalen);
|
||||||
|
if (!eacsmctx || !cvc_cert
|
||||||
|
|| !CVC_check_cert(cvc_cert, eacsmctx->certificate_description,
|
||||||
|
eacsmctx->certificate_description_length)) {
|
||||||
|
sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Certificate Description doesn't match Certificate");
|
||||||
|
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_INVALID_DATA);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL,
|
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL,
|
||||||
increment_ssc(ctx->priv_data));
|
increment_ssc(ctx->priv_data));
|
||||||
}
|
}
|
||||||
@@ -1509,6 +1537,7 @@ npa_sm_clear_free(const struct sm_ctx *ctx)
|
|||||||
EAC_CTX_clear_free(eacsmctx->ctx);
|
EAC_CTX_clear_free(eacsmctx->ctx);
|
||||||
if (eacsmctx->ssc)
|
if (eacsmctx->ssc)
|
||||||
BN_clear_free(eacsmctx->ssc);
|
BN_clear_free(eacsmctx->ssc);
|
||||||
|
free(eacsmctx->certificate_description);
|
||||||
free(eacsmctx);
|
free(eacsmctx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user