refactored sc_get_challenge

Let sc_get_challenge() do sc_lock() and loop through the card driver's
get_challenge() until enough bytes were collected. The card driver's
get_challenge() now returns the number of bytes collected (less or equal
than requested) or an error code.

- Allow more code re-use.
- PIV driver now uses ASN.1 parser for reading the random bytes
This commit is contained in:
Frank Morgner 2018-01-23 13:53:23 +01:00
parent 91812cf40f
commit 410cdf0dcc
15 changed files with 151 additions and 265 deletions

View File

@ -1664,40 +1664,27 @@ authentic_get_serialnr(struct sc_card *card, struct sc_serial_number *serial)
}
/* 'GET CHALLENGE' returns always 24 bytes */
static int
authentic_get_challenge(struct sc_card *card, unsigned char *rnd, size_t len)
{
struct sc_context *ctx = card->ctx;
struct sc_apdu apdu;
/* 'GET CHALLENGE' returns always 24 bytes */
unsigned char rbuf[0x18];
int rv, nn;
size_t out_len;
int r;
LOG_FUNC_CALLED(ctx);
if (!rnd && len)
return SC_ERROR_INVALID_ARGUMENTS;
LOG_FUNC_CALLED(card->ctx);
sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0x84, 0x00, 0x00);
apdu.resp = rbuf;
apdu.resplen = sizeof(rbuf);
apdu.le = sizeof(rbuf);
r = iso_ops->get_challenge(card, rnd, sizeof rbuf);
LOG_TEST_RET(card->ctx, r, "GET CHALLENGE cmd failed");
while (len > 0) {
rv = sc_transmit_apdu(card, &apdu);
SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, rv, "APDU transmit failed");
rv = sc_check_sw(card, apdu.sw1, apdu.sw2);
LOG_TEST_RET(ctx, rv, "PIN cmd failed");
if (apdu.resplen != sizeof(rbuf))
return sc_check_sw(card, apdu.sw1, apdu.sw2);
nn = len > apdu.resplen ? apdu.resplen : len;
memcpy(rnd, apdu.resp, nn);
len -= nn;
rnd += nn;
if (len < (size_t) r) {
out_len = len;
} else {
out_len = (size_t) r;
}
memcpy(rnd, rbuf, out_len);
LOG_FUNC_RETURN(ctx, SC_SUCCESS);
LOG_FUNC_RETURN(card->ctx, out_len);
}

View File

@ -849,42 +849,22 @@ static int cac_card_ctl(sc_card_t *card, unsigned long cmd, void *ptr)
static int cac_get_challenge(sc_card_t *card, u8 *rnd, size_t len)
{
/* CAC requires 8 byte response */
u8 rbuf[8];
u8 *rbufp = NULL;
size_t rbuflen = 0;
size_t out_len = sizeof rbuf;
int r;
SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
LOG_FUNC_CALLED(card->ctx);
sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL,
"challenge len=%"SC_FORMAT_LEN_SIZE_T"u", len);
r = cac_apdu_io(card, 0x84, 0x00, 0x00, NULL, 0, (u8 **) &rbuf, &out_len);
LOG_TEST_RET(card->ctx, r, "Could not get challenge");
r = sc_lock(card);
if (r != SC_SUCCESS)
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, r);
/* CAC requires 8 byte response */
while (len > 0) {
size_t n;
rbufp = &rbuf[0];
rbuflen = sizeof(rbuf);
r = cac_apdu_io(card, 0x84, 0x00, 0x00, NULL, 0, &rbufp, &rbuflen);
if (r < 0) {
sc_unlock(card);
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, r);
}
n = len > rbuflen ? rbuflen : len;
memcpy(rnd, rbufp, n);
len -= n;
rnd += n;
if (len < out_len) {
out_len = len;
}
memcpy(rnd, rbuf, out_len);
r = sc_unlock(card);
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, r);
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, (int) out_len);
}
static int cac_set_security_env(sc_card_t *card, const sc_security_env_t *env, int se_num)

View File

@ -1610,40 +1610,17 @@ static int coolkey_card_ctl(sc_card_t *card, unsigned long cmd, void *ptr)
static int coolkey_get_challenge(sc_card_t *card, u8 *rnd, size_t len)
{
size_t rbuflen = 0;
int r;
LOG_FUNC_CALLED(card->ctx);
SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
if (len > COOLKEY_MAX_CHUNK_SIZE)
len = COOLKEY_MAX_CHUNK_SIZE;
sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL,
"challenge len=%"SC_FORMAT_LEN_SIZE_T"u", len);
r = sc_lock(card);
if (r != SC_SUCCESS)
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, r);
for(; len >= COOLKEY_MAX_CHUNK_SIZE; len -= COOLKEY_MAX_CHUNK_SIZE,
rnd += COOLKEY_MAX_CHUNK_SIZE) {
rbuflen = COOLKEY_MAX_CHUNK_SIZE;
r = coolkey_apdu_io(card, COOLKEY_CLASS, COOLKEY_INS_GET_RANDOM,
0, 0, NULL, 0, &rnd, &rbuflen, NULL, 0);
if (r != COOLKEY_MAX_CHUNK_SIZE) {
len = 0;
break;
}
}
if (len) {
r = coolkey_apdu_io(card, COOLKEY_CLASS, COOLKEY_INS_GET_RANDOM,
0, 0, NULL, 0, &rnd, &len, NULL, 0);
}
sc_unlock(card);
if (r > 0) {
r= SC_SUCCESS;
}
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, r);
LOG_TEST_RET(card->ctx,
coolkey_apdu_io(card, COOLKEY_CLASS, COOLKEY_INS_GET_RANDOM, 0, 0,
NULL, 0, &rnd, &len, NULL, 0),
"Could not get challenge");
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, (int) len);
}
static int coolkey_set_security_env(sc_card_t *card, const sc_security_env_t *env, int se_num)

View File

@ -1340,51 +1340,27 @@ static int dnie_select_file(struct sc_card *card,
* @param len requested challenge length
* @return SC_SUCCESS if OK; else error code
*/
#define BUFFER_SIZE 8
static int dnie_get_challenge(struct sc_card *card, u8 * rnd, size_t len)
{
sc_apdu_t apdu;
u8 buf[MAX_RESP_BUFFER_SIZE];
int result = SC_SUCCESS;
if ((card == NULL) || (card->ctx == NULL))
return SC_ERROR_INVALID_ARGUMENTS;
LOG_FUNC_CALLED(card->ctx);
/* just a copy of iso7816::get_challenge() but call dnie_check_sw to
* look for extra error codes */
if ( (rnd==NULL) || (len==0) ) {
/* no valid buffer provided */
result = SC_ERROR_INVALID_ARGUMENTS;
goto dnie_get_challenge_error;
}
dnie_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0x84, 0x00, 0x00, BUFFER_SIZE, 0,
buf, MAX_RESP_BUFFER_SIZE, NULL, 0);
/* As DNIe cannot handle other data length than 0x08 and 0x14 */
u8 rbuf[8];
size_t out_len;
int r;
/*
* As DNIe cannot handle other data length than 0x08 and 0x14,
* perform consecutive reads of 8 bytes until retrieve requested length
*/
while (len > 0) {
size_t n = len > BUFFER_SIZE ? BUFFER_SIZE : len;
sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0x84, 0x00, 0x00);
apdu.le = BUFFER_SIZE;
apdu.resp = buf;
apdu.resplen = MAX_RESP_BUFFER_SIZE; /* include SW's */
result = sc_transmit_apdu(card, &apdu);
if (result != SC_SUCCESS) {
LOG_TEST_RET(card->ctx, result, "APDU transmit failed");
}
if (apdu.resplen != BUFFER_SIZE) {
result = sc_check_sw(card, apdu.sw1, apdu.sw2);
goto dnie_get_challenge_error;
}
memcpy(rnd, apdu.resp, n);
len -= n;
rnd += n;
LOG_FUNC_CALLED(card->ctx);
r = iso_ops->get_challenge(card, rbuf, sizeof rbuf);
LOG_TEST_RET(card->ctx, r, "GET CHALLENGE cmd failed");
if (len < (size_t) r) {
out_len = len;
} else {
out_len = (size_t) r;
}
result = SC_SUCCESS;
dnie_get_challenge_error:
LOG_FUNC_RETURN(card->ctx, result);
memcpy(rnd, rbuf, out_len);
LOG_FUNC_RETURN(card->ctx, (int) out_len);
}
/*

View File

@ -2573,34 +2573,26 @@ get_external_key_retries(struct sc_card *card, unsigned char kid, unsigned char
return r;
}
static int
epass2003_get_challenge(sc_card_t *card, u8 *rnd, size_t count)
static int
epass2003_get_challenge(sc_card_t *card, u8 *rnd, size_t len)
{
sc_apdu_t apdu;
u8 rbuf[16];
size_t n;
int ret = SC_SUCCESS; /* if count == 0 */
size_t out_len;
int r;
SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0x84, 0x00, 0x00);
apdu.le = sizeof(rbuf);
apdu.resp = rbuf;
apdu.resplen = sizeof(rbuf);
LOG_FUNC_CALLED(card->ctx);
while (count > 0)
{
ret = sc_transmit_apdu(card, &apdu);
SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, ret, "APDU transmit failed");
ret = sc_check_sw(card, apdu.sw1, apdu.sw2);
SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, ret, "Get challenge failed");
if (apdu.resplen != sizeof(rbuf))
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_UNKNOWN);
n = count < sizeof(rbuf) ? count : sizeof(rbuf);
memcpy(rnd, rbuf, n);
count -= n;
rnd += n;
r = iso_ops->get_challenge(card, rnd, sizeof rbuf);
LOG_TEST_RET(card->ctx, r, "GET CHALLENGE cmd failed");
if (len < (size_t) r) {
out_len = len;
} else {
out_len = (size_t) r;
}
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, ret);
memcpy(rnd, rbuf, out_len);
LOG_FUNC_RETURN(card->ctx, (int) out_len);
}

View File

@ -1211,17 +1211,17 @@ isoApplet_compute_signature(struct sc_card *card,
static int
isoApplet_get_challenge(struct sc_card *card, u8 *rnd, size_t len)
{
struct sc_context *ctx = card->ctx;
int r;
LOG_FUNC_CALLED(ctx);
LOG_FUNC_CALLED(card->ctx);
if(card->caps & SC_CARD_CAP_RNG) {
if(card->caps & SC_CARD_CAP_RNG) {
r = iso_ops->get_challenge(card, rnd, len);
} else {
r = SC_ERROR_NOT_SUPPORTED;
}
LOG_FUNC_RETURN(ctx, r);
LOG_FUNC_RETURN(card->ctx, r);
}
static int isoApplet_card_reader_lock_obtained(sc_card_t *card, int was_reset)

View File

@ -775,8 +775,12 @@ static int muscle_get_challenge(sc_card_t *card, u8 *rnd, size_t len)
{
if (len == 0)
return SC_SUCCESS;
else
return msc_get_challenge(card, len, 0, NULL, rnd);
else {
SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL,
msc_get_challenge(card, len, 0, NULL, rnd),
"GET CHALLENGE cmd failed");
return (int) len;
}
}
static int muscle_check_sw(sc_card_t * card, unsigned int sw1, unsigned int sw2) {

View File

@ -1222,16 +1222,17 @@ pgp_list_files(sc_card_t *card, u8 *buf, size_t buflen)
static int
pgp_get_challenge(struct sc_card *card, u8 *rnd, size_t len)
{
struct pgp_priv_data *priv = DRVDATA(card);
struct pgp_priv_data *priv;
LOG_FUNC_CALLED(card->ctx);
priv = DRVDATA(card);
if (0 == (priv->ext_caps & EXT_CAP_GET_CHALLENGE)) {
LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED);
}
if (priv->max_challenge_size > 0 && len > priv->max_challenge_size) {
LOG_FUNC_RETURN(card->ctx, SC_ERROR_WRONG_LENGTH);
len = priv->max_challenge_size;
}
LOG_FUNC_RETURN(card->ctx, iso_ops->get_challenge(card, rnd, len));

View File

@ -2229,54 +2229,41 @@ static int piv_card_ctl(sc_card_t *card, unsigned long cmd, void *ptr)
static int piv_get_challenge(sc_card_t *card, u8 *rnd, size_t len)
{
u8 sbuf[16];
/* Dynamic Authentication Template (Challenge) */
u8 sbuf[] = {0x7c, 0x02, 0x81, 0x00};
u8 *rbuf = NULL;
size_t rbuflen = 0;
u8 *p, *q;
const u8 *p;
size_t rbuf_len = 0, out_len = 0;
int r;
unsigned int tag, cla;
SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
LOG_FUNC_CALLED(card->ctx);
sc_log(card->ctx, "challenge len=%"SC_FORMAT_LEN_SIZE_T"u", len);
/* NIST 800-73-3 says use 9B, previous verisons used 00 */
r = piv_general_io(card, 0x87, 0x00, 0x9B, sbuf, sizeof sbuf, &rbuf, &rbuf_len);
LOG_TEST_GOTO_ERR(card->ctx, r, "GENERAL AUTHENTICATE failed");
r = sc_lock(card);
if (r != SC_SUCCESS)
LOG_FUNC_RETURN(card->ctx, r);
p = sbuf;
*p++ = 0x7c;
*p++ = 0x02;
*p++ = 0x81;
*p++ = 0x00;
/* assuming 8 byte response ? */
/* should take what the card returns */
while (len > 0) {
size_t n = len > 8 ? 8 : len;
/* NIST 800-73-3 says use 9B, previous versions used 00 */
r = piv_general_io(card, 0x87, 0x00, 0x9B, sbuf, p - sbuf, &rbuf, &rbuflen);
if (r < 0) {
sc_unlock(card);
LOG_FUNC_RETURN(card->ctx, r);
}
q = rbuf;
if ( (*q++ != 0x7C)
|| (*q++ != rbuflen - 2)
|| (*q++ != 0x81)
|| (*q++ != rbuflen - 4)) {
r = SC_ERROR_INVALID_DATA;
sc_unlock(card);
LOG_FUNC_RETURN(card->ctx, r);
}
memcpy(rnd, q, n);
len -= n;
rnd += n;
free(rbuf);
rbuf = NULL;
p = rbuf;
r = sc_asn1_read_tag(&p, rbuf_len, &cla, &tag, &out_len);
if (r < 0 || (cla|tag) != 0x7C) {
LOG_TEST_GOTO_ERR(card->ctx, SC_ERROR_INVALID_DATA, "Can't find Dynamic Authentication Template");
}
r = sc_unlock(card);
rbuf_len = out_len;
r = sc_asn1_read_tag(&p, rbuf_len, &cla, &tag, &out_len);
if (r < 0 || (cla|tag) != 0x81) {
LOG_TEST_GOTO_ERR(card->ctx, SC_ERROR_INVALID_DATA, "Can't find Challenge");
}
if (len < out_len) {
out_len = len;
}
memcpy(rnd, p, out_len);
r = (int) out_len;
err:
free(rbuf);
LOG_FUNC_RETURN(card->ctx, r);

View File

@ -1137,33 +1137,25 @@ static int rutoken_compute_signature(struct sc_card *card,
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, ret);
}
static int rutoken_get_challenge(sc_card_t *card, u8 *rnd, size_t count)
static int rutoken_get_challenge(sc_card_t *card, u8 *rnd, size_t len)
{
sc_apdu_t apdu;
u8 rbuf[32];
size_t n;
int ret = SC_SUCCESS; /* if count == 0 */
unsigned char rbuf[32];
size_t out_len;
int r;
SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0x84, 0x00, 0x00);
apdu.le = sizeof(rbuf);
apdu.resp = rbuf;
apdu.resplen = sizeof(rbuf);
LOG_FUNC_CALLED(card->ctx);
while (count > 0)
{
ret = sc_transmit_apdu(card, &apdu);
SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, ret, "APDU transmit failed");
ret = sc_check_sw(card, apdu.sw1, apdu.sw2);
SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, ret, "Get challenge failed");
if (apdu.resplen != sizeof(rbuf))
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_UNKNOWN);
n = count < sizeof(rbuf) ? count : sizeof(rbuf);
memcpy(rnd, rbuf, n);
count -= n;
rnd += n;
r = iso_ops->get_challenge(card, rnd, sizeof rbuf);
LOG_TEST_RET(card->ctx, r, "GET CHALLENGE cmd failed");
if (len < (size_t) r) {
out_len = len;
} else {
out_len = (size_t) r;
}
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, ret);
memcpy(rnd, rbuf, out_len);
LOG_FUNC_RETURN(card->ctx, out_len);
}
static int rutoken_get_serial(sc_card_t *card, sc_serial_number_t *serial)

View File

@ -805,16 +805,36 @@ int sc_get_challenge(sc_card_t *card, u8 *rnd, size_t len)
{
int r;
if (card == NULL) {
if (len == 0)
return SC_SUCCESS;
if (card == NULL || rnd == NULL) {
return SC_ERROR_INVALID_ARGUMENTS;
}
LOG_FUNC_CALLED(card->ctx);
if (card->ops->get_challenge == NULL)
if (card->ops == NULL || card->ops->get_challenge == NULL)
LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED);
r = card->ops->get_challenge(card, rnd, len);
LOG_FUNC_RETURN(card->ctx, r);
r = sc_lock(card);
if (r != SC_SUCCESS)
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, r);
while (len > 0) {
r = card->ops->get_challenge(card, rnd, len);
if (r < 0) {
sc_unlock(card);
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, r);
}
rnd += (size_t) r;
len -= (size_t) r;
}
sc_unlock(card);
LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
}
int sc_read_record(sc_card_t *card, unsigned int rec_nr, u8 *buf,

View File

@ -260,31 +260,6 @@ iasecc_sm_se_mutual_authentication(struct sc_card *card, unsigned se_num)
LOG_FUNC_RETURN(ctx, rv);
}
static int
iasecc_sm_get_challenge(struct sc_card *card, unsigned char *out, size_t len)
{
struct sc_context *ctx = card->ctx;
struct sc_apdu apdu;
unsigned char rbuf[SC_MAX_APDU_BUFFER_SIZE];
int rv;
sc_log(ctx, "SM get challenge: length %"SC_FORMAT_LEN_SIZE_T"u", len);
sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0x84, 0, 0);
apdu.le = len;
apdu.resplen = len;
apdu.resp = rbuf;
rv = sc_transmit_apdu(card, &apdu);
LOG_TEST_RET(ctx, rv, "APDU transmit failed");
rv = sc_check_sw(card, apdu.sw1, apdu.sw2);
LOG_TEST_RET(ctx, rv, "Command failed");
memcpy(out, rbuf, apdu.resplen);
LOG_FUNC_RETURN(ctx, apdu.resplen);
}
#endif
@ -309,7 +284,7 @@ iasecc_sm_initialize(struct sc_card *card, unsigned se_num, unsigned cmd)
rv = iasecc_sm_se_mutual_authentication(card, se_num);
LOG_TEST_RET(ctx, rv, "iasecc_sm_initialize() MUTUAL AUTHENTICATION failed");
rv = iasecc_sm_get_challenge(card, cwa_session->card_challenge, SM_SMALL_CHALLENGE_LEN);
rv = sc_get_challenge(card, cwa_session->card_challenge, SM_SMALL_CHALLENGE_LEN);
LOG_TEST_RET(ctx, rv, "iasecc_sm_initialize() GET CHALLENGE failed");
sc_remote_data_init(&rdata);

View File

@ -621,12 +621,6 @@ iso7816_get_challenge(struct sc_card *card, u8 *rnd, size_t len)
int r;
struct sc_apdu apdu;
if (len == 0)
return SC_SUCCESS;
if (!rnd)
return SC_ERROR_INVALID_ARGUMENTS;
sc_format_apdu(card, &apdu, SC_APDU_CASE_2, 0x84, 0x00, 0x00);
apdu.le = len;
apdu.resp = rnd;
@ -635,14 +629,14 @@ iso7816_get_challenge(struct sc_card *card, u8 *rnd, size_t len)
r = sc_transmit_apdu(card, &apdu);
LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
if (apdu.resplen != len) {
r = sc_check_sw(card, apdu.sw1, apdu.sw2);
if (r == SC_SUCCESS) {
r = SC_ERROR_WRONG_LENGTH;
}
}
r = sc_check_sw(card, apdu.sw1, apdu.sw2);
LOG_TEST_RET(card->ctx, r, "GET CHALLENGE failed");
return r;
if (len < apdu.resplen) {
return (int) len;
}
return (int) apdu.resplen;
}

View File

@ -3665,7 +3665,7 @@ DWORD WINAPI CardGetChallenge(__in PCARD_DATA pCardData,
}
rv = sc_get_challenge(vs->p15card->card, *ppbChallengeData, 8);
if (rv) {
if (rv < 0) {
logprintf(pCardData, 1, "Get challenge failed: %s\n", sc_strerror(rv));
pCardData->pfnCspFree(*ppbChallengeData);
*ppbChallengeData = NULL;

View File

@ -1609,7 +1609,8 @@ static int do_random(int argc, char **argv)
count = atoi(argv[0]);
if (count < 0 || (size_t) count > sizeof buffer) {
printf("Number must be in range 0..256\n");
printf("Number must be in range 0..%"SC_FORMAT_LEN_SIZE_T"u\n",
sizeof buffer);
return -1;
}