card: New command 'authenticate'.

* tools/card-tool-misc.c (hex_to_buffer): New.
* tools/gpg-card-tool.c (get_data_from_file): Change to allow returning
a string.
(cmd_authenticate): New.
(cmds): Add command "authenticate".

Signed-off-by: Werner Koch <wk@gnupg.org>
This commit is contained in:
Werner Koch 2019-01-31 16:06:47 +01:00
parent 1d57450f3e
commit da38325740
No known key found for this signature in database
GPG Key ID: E3FDFF218E45B72B
3 changed files with 118 additions and 6 deletions

View File

@ -42,3 +42,38 @@ find_kinfo (card_info_t info, const char *keyref)
return kinfo; return kinfo;
return NULL; return NULL;
} }
/* Convert STRING into a newly allocated buffer while translating the
* hex numbers. Blanks and colons are allowed to separate pairs of
* hex digits. Returns NULL on error or a newly malloced buffer and
* its length in LENGTH. */
void *
hex_to_buffer (const char *string, size_t *r_length)
{
unsigned char *buffer;
const char *s;
size_t n;
buffer = xtrymalloc (strlen (string)+1);
if (!buffer)
return NULL;
for (s=string, n=0; *s; s++)
{
if (ascii_isspace (*s) || *s == ':')
continue;
if (hexdigitp (s) && hexdigitp (s+1))
{
buffer[n++] = xtoi_2 (s);
s++;
}
else
{
xfree (buffer);
gpg_err_set_errno (EINVAL);
return NULL;
}
}
*r_length = n;
return buffer;
}

View File

@ -189,6 +189,7 @@ gpg_error_t test_get_matching_keys (const char *hexgrip);
/*-- card-tool-misc.c --*/ /*-- card-tool-misc.c --*/
key_info_t find_kinfo (card_info_t info, const char *keyref); key_info_t find_kinfo (card_info_t info, const char *keyref);
void *hex_to_buffer (const char *string, size_t *r_length);
/*-- card-call-scd.c --*/ /*-- card-call-scd.c --*/

View File

@ -326,8 +326,11 @@ main (int argc, char **argv)
/* Read data from file FNAME up to MAX_GET_DATA_FROM_FILE characters. /* Read data from file FNAME up to MAX_GET_DATA_FROM_FILE characters.
* On error return an error code and stores NULL at R_BUFFER; on * On error return an error code and stores NULL at R_BUFFER; on
* success returns 0, stpres the number of bytes read at R_BUFLEN and * success returns 0 and stores the number of bytes read at R_BUFLEN
* the address of a newly allocated buffer at R_BUFFER. */ * and the address of a newly allocated buffer at R_BUFFER. A
* complementary nul byte is always appended to the data but not
* counted; this allows to pass NULL for R-BUFFER and consider the
* returned data as a string. */
static gpg_error_t static gpg_error_t
get_data_from_file (const char *fname, char **r_buffer, size_t *r_buflen) get_data_from_file (const char *fname, char **r_buffer, size_t *r_buflen)
{ {
@ -337,7 +340,8 @@ get_data_from_file (const char *fname, char **r_buffer, size_t *r_buflen)
int n; int n;
*r_buffer = NULL; *r_buffer = NULL;
*r_buflen = 0; if (r_buflen)
*r_buflen = 0;
fp = es_fopen (fname, "rb"); fp = es_fopen (fname, "rb");
if (!fp) if (!fp)
@ -356,7 +360,7 @@ get_data_from_file (const char *fname, char **r_buffer, size_t *r_buflen)
return err; return err;
} }
n = es_fread (data, 1, MAX_GET_DATA_FROM_FILE, fp); n = es_fread (data, 1, MAX_GET_DATA_FROM_FILE - 1, fp);
es_fclose (fp); es_fclose (fp);
if (n < 0) if (n < 0)
{ {
@ -365,8 +369,11 @@ get_data_from_file (const char *fname, char **r_buffer, size_t *r_buflen)
xfree (data); xfree (data);
return err; return err;
} }
data[n] = 0;
*r_buffer = data; *r_buffer = data;
*r_buflen = n; if (r_buflen)
*r_buflen = n;
return 0; return 0;
} }
@ -951,6 +958,73 @@ cmd_verify (card_info_t info, char *argstr)
} }
static gpg_error_t
cmd_authenticate (card_info_t info, char *argstr)
{
gpg_error_t err;
int opt_setkey;
int opt_raw;
char *string = NULL;
char *key = NULL;
size_t keylen;
if (!info)
return print_help
("AUTHENTICATE [--setkey] [--raw] [< FILE]|KEY\n\n"
"Perform a mutual autentication either by reading the key\n"
"from FILE or by taking it from the command line. Without\n"
"the option --raw the key is expected to be hex encoded.\n"
"To install a new administration key --setkey is used; this\n"
"requires a prior authentication with the old key.",
APP_TYPE_PIV, 0);
if (info->apptype != APP_TYPE_PIV)
{
log_info ("Note: This is a PIV only command.\n");
return gpg_error (GPG_ERR_NOT_SUPPORTED);
}
opt_setkey = has_leading_option (argstr, "--setkey");
opt_raw = has_leading_option (argstr, "--raw");
argstr = skip_options (argstr);
if (*argstr == '<') /* Read key from a file. */
{
for (argstr++; spacep (argstr); argstr++)
;
err = get_data_from_file (argstr, &string, NULL);
if (err)
goto leave;
}
if (opt_raw)
{
key = string? string : xstrdup (argstr);
string = NULL;
keylen = strlen (key);
}
else
{
key = hex_to_buffer (string? string: argstr, &keylen);
if (!key)
{
err = gpg_error_from_syserror ();
goto leave;
}
}
err = scd_setattr (opt_setkey? "SET-ADM-KEY":"AUTH-ADM-KEY", key, keylen);
leave:
if (key)
{
wipememory (key, keylen);
xfree (key);
}
xfree (string);
return err;
}
/* Helper for cmd_name to qyery a part of name. */ /* Helper for cmd_name to qyery a part of name. */
static char * static char *
ask_one_name (const char *prompt) ask_one_name (const char *prompt)
@ -2610,7 +2684,7 @@ enum cmdids
cmdNAME, cmdURL, cmdFETCH, cmdLOGIN, cmdLANG, cmdSALUT, cmdCAFPR, cmdNAME, cmdURL, cmdFETCH, cmdLOGIN, cmdLANG, cmdSALUT, cmdCAFPR,
cmdFORCESIG, cmdGENERATE, cmdPASSWD, cmdPRIVATEDO, cmdWRITECERT, cmdFORCESIG, cmdGENERATE, cmdPASSWD, cmdPRIVATEDO, cmdWRITECERT,
cmdREADCERT, cmdUNBLOCK, cmdFACTORYRESET, cmdKDFSETUP, cmdREADCERT, cmdUNBLOCK, cmdFACTORYRESET, cmdKDFSETUP,
cmdKEYATTR, cmdUIF, cmdKEYATTR, cmdUIF, cmdAUTHENTICATE,
cmdINVCMD cmdINVCMD
}; };
@ -2641,6 +2715,7 @@ static struct
{ "passwd" , cmdPASSWD, 0, N_("menu to change or unblock the PIN")}, { "passwd" , cmdPASSWD, 0, N_("menu to change or unblock the PIN")},
{ "verify" , cmdVERIFY, 0, N_("verify the PIN and list all data")}, { "verify" , cmdVERIFY, 0, N_("verify the PIN and list all data")},
{ "unblock" , cmdUNBLOCK,0, N_("unblock the PIN using a Reset Code")}, { "unblock" , cmdUNBLOCK,0, N_("unblock the PIN using a Reset Code")},
{ "authenticate",cmdAUTHENTICATE, 0,N_("authenticate to the card")},
{ "reset" , cmdRESET, 0, N_("send a reset to the card daemon")}, { "reset" , cmdRESET, 0, N_("send a reset to the card daemon")},
{ "factory-reset", cmdFACTORYRESET, 1, N_("destroy all keys and data")}, { "factory-reset", cmdFACTORYRESET, 1, N_("destroy all keys and data")},
{ "kdf-setup", cmdKDFSETUP, 1, N_("setup KDF for PIN authentication")}, { "kdf-setup", cmdKDFSETUP, 1, N_("setup KDF for PIN authentication")},
@ -2871,6 +2946,7 @@ interactive_loop (void)
if (!err) if (!err)
redisplay = 1; redisplay = 1;
break; break;
case cmdAUTHENTICATE: err = cmd_authenticate (info, argstr); break;
case cmdNAME: err = cmd_name (info, argstr); break; case cmdNAME: err = cmd_name (info, argstr); break;
case cmdURL: err = cmd_url (info, argstr); break; case cmdURL: err = cmd_url (info, argstr); break;
case cmdFETCH: err = cmd_fetch (info); break; case cmdFETCH: err = cmd_fetch (info); break;