summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWerner Koch <wk@gnupg.org>2019-01-20 11:41:23 +0100
committerWerner Koch <wk@gnupg.org>2019-01-20 11:41:23 +0100
commit70bb5c7931598590b1acfae90bf4657f5911d2d3 (patch)
tree2528e900b7df2c1af710afb3a5bccc0e8e926e96
parentssh: Simplify the curve name lookup. (diff)
downloadgnupg2-70bb5c7931598590b1acfae90bf4657f5911d2d3.tar.xz
gnupg2-70bb5c7931598590b1acfae90bf4657f5911d2d3.zip
scd: One new and one improved 7816 function.
* scd/apdu.c (apdu_send_direct): New arg R_SW. * scd/command.c (cmd_apdu): Ditto. * scd/iso7816.c (iso7816_apdu_direct): New arg R_SW. (iso7816_general_authenticate): New. * scd/app-nks.c (get_chv_status, get_nks_version): Pass NULL for new arg. -- iso7816_general_authenticate will be used for the PIV card support. The new arg to iso7816_apdu_direct and apdu_send_direct allows to get the raw status word back without the need to handle an output buffer. Signed-off-by: Werner Koch <wk@gnupg.org>
-rw-r--r--scd/apdu.c30
-rw-r--r--scd/apdu.h2
-rw-r--r--scd/app-nks.c4
-rw-r--r--scd/command.c5
-rw-r--r--scd/iso7816.c67
-rw-r--r--scd/iso7816.h9
6 files changed, 90 insertions, 27 deletions
diff --git a/scd/apdu.c b/scd/apdu.c
index f3e2a12e7..816938ac5 100644
--- a/scd/apdu.c
+++ b/scd/apdu.c
@@ -3063,19 +3063,25 @@ apdu_send_simple (int slot, int extended_mode,
/* This is a more generic version of the apdu sending routine. It
- takes an already formatted APDU in APDUDATA or length APDUDATALEN
- and returns with an APDU including the status word. With
- HANDLE_MORE set to true this function will handle the MORE DATA
- status and return all APDUs concatenated with one status word at
- the end. If EXTENDED_LENGTH is != 0 extended lengths are allowed
- with a max. result data length of EXTENDED_LENGTH bytes. The
- function does not return a regular status word but 0 on success.
- If the slot is locked, the function returns immediately with an
- error. */
+ * takes an already formatted APDU in APDUDATA or length APDUDATALEN
+ * and returns with an APDU including the status word. With
+ * HANDLE_MORE set to true this function will handle the MORE DATA
+ * status and return all APDUs concatenated with one status word at
+ * the end. If EXTENDED_LENGTH is != 0 extended lengths are allowed
+ * with a max. result data length of EXTENDED_LENGTH bytes. The
+ * function does not return a regular status word but 0 on success.
+ * If the slot is locked, the function returns immediately with an
+ * error.
+ *
+ * Out of historical reasons the function returns 0 on success and
+ * outs the status word at the end of the result to be able to get the
+ * status word in the case of a not provided RETBUF, R_SW can be used
+ * to store the SW. But note that R_SW qill only be set if the
+ * function returns 0. */
int
apdu_send_direct (int slot, size_t extended_length,
const unsigned char *apdudata, size_t apdudatalen,
- int handle_more,
+ int handle_more, unsigned int *r_sw,
unsigned char **retbuf, size_t *retbuflen)
{
#define SHORT_RESULT_BUFFER_SIZE 258
@@ -3282,9 +3288,13 @@ apdu_send_direct (int slot, size_t extended_length,
(*retbuf)[(*retbuflen)++] = sw;
}
+ if (r_sw)
+ *r_sw = sw;
+
if (DBG_CARD_IO && retbuf)
log_printhex (*retbuf, *retbuflen, " dump: ");
+
return 0;
}
diff --git a/scd/apdu.h b/scd/apdu.h
index 8621ddc41..1392aab71 100644
--- a/scd/apdu.h
+++ b/scd/apdu.h
@@ -138,7 +138,7 @@ int apdu_send_le (int slot, int extended_mode,
unsigned char **retbuf, size_t *retbuflen);
int apdu_send_direct (int slot, size_t extended_length,
const unsigned char *apdudata, size_t apdudatalen,
- int handle_more,
+ int handle_more, unsigned int *r_sw,
unsigned char **retbuf, size_t *retbuflen);
const char *apdu_get_reader_name (int slot);
diff --git a/scd/app-nks.c b/scd/app-nks.c
index 9e720f0b0..801ab904a 100644
--- a/scd/app-nks.c
+++ b/scd/app-nks.c
@@ -273,7 +273,7 @@ get_chv_status (app_t app, int sigg, int pwid)
command[3] = pwid;
if (apdu_send_direct (app->slot, 0, (unsigned char *)command,
- 4, 0, &result, &resultlen))
+ 4, 0, NULL, &result, &resultlen))
rc = -1; /* Error. */
else if (resultlen < 2)
rc = -1; /* Error. */
@@ -1300,7 +1300,7 @@ get_nks_version (int slot)
int type;
if (iso7816_apdu_direct (slot, "\x80\xaa\x06\x00\x00", 5, 0,
- &result, &resultlen))
+ NULL, &result, &resultlen))
return 2; /* NKS 2 does not support this command. */
/* Example value: 04 11 19 22 21 6A 20 80 03 03 01 01 01 00 00 00
diff --git a/scd/command.c b/scd/command.c
index 9df26117c..ea4ccbcda 100644
--- a/scd/command.c
+++ b/scd/command.c
@@ -333,7 +333,7 @@ static const char hlp_learn[] =
"or a \"CANCEL\" to force the function to terminate with a Cancel\n"
"error message.\n"
"\n"
- "With the option --keypairinfo only KEYPARIINFO lstatus lines are\n"
+ "With the option --keypairinfo only KEYPARIINFO status lines are\n"
"returned.\n"
"\n"
"The response of this command is a list of status lines formatted as\n"
@@ -346,6 +346,7 @@ static const char hlp_learn[] =
" P15 = PKCS-15 structure used\n"
" DINSIG = DIN SIG\n"
" OPENPGP = OpenPGP card\n"
+ " PIV = PIV card\n"
" NKS = NetKey card\n"
"\n"
"are implemented. These strings are aliases for the AID\n"
@@ -1663,7 +1664,7 @@ cmd_apdu (assuan_context_t ctx, char *line)
rc = apdu_send_direct (app->slot, exlen,
apdu, apdulen, handle_more,
- &result, &resultlen);
+ NULL, &result, &resultlen);
if (rc)
log_error ("apdu_send_direct failed: %s\n", gpg_strerror (rc));
else
diff --git a/scd/iso7816.c b/scd/iso7816.c
index 43c0bcd8e..c8a2138cb 100644
--- a/scd/iso7816.c
+++ b/scd/iso7816.c
@@ -50,6 +50,7 @@
#define CMD_PUT_DATA 0xDA
#define CMD_MSE 0x22
#define CMD_PSO 0x2A
+#define CMD_GENERAL_AUTHENTICATE 0x87
#define CMD_INTERNAL_AUTHENTICATE 0x88
#define CMD_GENERATE_KEYPAIR 0x47
#define CMD_GET_CHALLENGE 0x84
@@ -225,24 +226,28 @@ iso7816_list_directory (int slot, int list_dirs,
internally. The return value is a gpg error code (i.e. a mapped
status word). This is basically the same as apdu_send_direct but
it maps the status word and does not return it in the result
- buffer. */
+ buffer. However, it R_SW is not NULL the status word is stored
+ R_SW for closer inspection. */
gpg_error_t
iso7816_apdu_direct (int slot, const void *apdudata, size_t apdudatalen,
- int handle_more,
+ int handle_more, unsigned int *r_sw,
unsigned char **result, size_t *resultlen)
{
- int sw;
+ int sw, sw2;
- if (!result || !resultlen)
- return gpg_error (GPG_ERR_INV_VALUE);
- *result = NULL;
- *resultlen = 0;
+ if (result)
+ {
+ *result = NULL;
+ *resultlen = 0;
+ }
sw = apdu_send_direct (slot, 0, apdudata, apdudatalen, handle_more,
- result, resultlen);
+ &sw2, result, resultlen);
if (!sw)
{
- if (*resultlen < 2)
+ if (!result)
+ sw = sw2;
+ else if (*resultlen < 2)
sw = SW_HOST_GENERAL_ERROR;
else
{
@@ -251,13 +256,15 @@ iso7816_apdu_direct (int slot, const void *apdudata, size_t apdudatalen,
(*resultlen)--;
}
}
- if (sw != SW_SUCCESS)
+ if (sw != SW_SUCCESS && result)
{
/* Make sure that pending buffers are released. */
xfree (*result);
*result = NULL;
*resultlen = 0;
}
+ if (r_sw)
+ *r_sw = sw;
return map_sw (sw);
}
@@ -621,7 +628,7 @@ iso7816_decipher (int slot, int extended_mode,
}
-/* For LE see do_generate_keypair. */
+/* For LE see do_generate_keypair. */
gpg_error_t
iso7816_internal_authenticate (int slot, int extended_mode,
const unsigned char *data, size_t datalen,
@@ -658,6 +665,44 @@ iso7816_internal_authenticate (int slot, int extended_mode,
}
+/* For LE see do_generate_keypair. */
+gpg_error_t
+iso7816_general_authenticate (int slot, int extended_mode,
+ int algoref, int keyref,
+ const unsigned char *data, size_t datalen,
+ int le,
+ unsigned char **result, size_t *resultlen)
+{
+ int sw;
+
+ if (!data || !datalen || !result || !resultlen)
+ return gpg_error (GPG_ERR_INV_VALUE);
+ *result = NULL;
+ *resultlen = 0;
+
+ if (!extended_mode)
+ le = 256; /* Ignore provided Le and use what apdu_send uses. */
+ else if (le >= 0 && le < 256)
+ le = 256;
+
+ sw = apdu_send_le (slot, extended_mode,
+ 0x00, CMD_GENERAL_AUTHENTICATE, algoref, keyref,
+ datalen, (const char*)data,
+ le,
+ result, resultlen);
+ if (sw != SW_SUCCESS)
+ {
+ /* Make sure that pending buffers are released. */
+ xfree (*result);
+ *result = NULL;
+ *resultlen = 0;
+ return map_sw (sw);
+ }
+
+ return 0;
+}
+
+
/* LE is the expected return length. This is usually 0 except if
extended length mode is used and more than 256 byte will be
returned. In that case a value of -1 uses a large default
diff --git a/scd/iso7816.h b/scd/iso7816.h
index 332fc0e81..4a366e6eb 100644
--- a/scd/iso7816.h
+++ b/scd/iso7816.h
@@ -63,7 +63,7 @@ gpg_error_t iso7816_list_directory (int slot, int list_dirs,
unsigned char **result, size_t *resultlen);
gpg_error_t iso7816_apdu_direct (int slot,
const void *apdudata, size_t apdudatalen,
- int handle_more,
+ int handle_more, unsigned int *r_sw,
unsigned char **result, size_t *resultlen);
gpg_error_t iso7816_check_pinpad (int slot, int command,
pininfo_t *pininfo);
@@ -104,6 +104,13 @@ gpg_error_t iso7816_internal_authenticate (int slot, int extended_mode,
const unsigned char *data, size_t datalen,
int le,
unsigned char **result, size_t *resultlen);
+gpg_error_t iso7816_general_authenticate (int slot, int extended_mode,
+ int algoref, int keyref,
+ const unsigned char *data,
+ size_t datalen,
+ int le,
+ unsigned char **result,
+ size_t *resultlen);
gpg_error_t iso7816_generate_keypair (int slot, int extended_mode,
const char *data, size_t datalen,
int le,