scd:p15: Implement CHV-STATUS attribute

* scd/command.c (send_status_direct): Return an error.
* scd/app-p15.c (do_learn_status): Emit CHV-STATUS.
(compare_aodf_objid): New.
(do_getattr): Implement CHV-STATUS.
This commit is contained in:
Werner Koch 2021-03-16 18:52:38 +01:00
parent e4c2d7be22
commit bf1d7bc369
No known key found for this signature in database
GPG Key ID: E3FDFF218E45B72B
3 changed files with 119 additions and 8 deletions

View File

@ -3885,6 +3885,10 @@ do_learn_status (app_t app, ctrl_t ctrl, unsigned int flags)
if (!err)
err = send_keypairinfo (app, ctrl, app->app_local->private_key_info);
if (!err)
err = do_getattr (app, ctrl, "CHV-STATUS");
return err;
}
@ -4068,6 +4072,27 @@ do_readcert (app_t app, const char *certid,
}
/* Sort helper for an array of authentication objects. */
static int
compare_aodf_objid (const void *arg_a, const void *arg_b)
{
const aodf_object_t a = *(const aodf_object_t *)arg_a;
const aodf_object_t b = *(const aodf_object_t *)arg_b;
int rc;
rc = memcmp (a->objid, b->objid,
a->objidlen < b->objidlen? a->objidlen : b->objidlen);
if (!rc)
{
if (a->objidlen < b->objidlen)
rc = -1;
else if (a->objidlen > b->objidlen)
rc = 1;
}
return rc;
}
/* Implement the GETATTR command. This is similar to the LEARN
command but returns just one value via the status interface. */
@ -4195,6 +4220,46 @@ do_getattr (app_t app, ctrl_t ctrl, const char *name)
else
return 0;
}
else if (!strcmp (name, "CHV-STATUS"))
{
aodf_object_t aodf;
aodf_object_t aodfarray[16];
int naodf = 0;
membuf_t mb;
char *p;
int i;
/* Put the AODFs into an array for easier sorting. Note that we
* handle onl the first 16 encountrer which should be more than
* enough. */
for (aodf = app->app_local->auth_object_info;
aodf && naodf < DIM(aodfarray); aodf = aodf->next)
if (aodf->objidlen && aodf->pin_reference_valid)
aodfarray[naodf++] = aodf;
qsort (aodfarray, naodf, sizeof *aodfarray, compare_aodf_objid);
init_membuf (&mb, 256);
for (i = 0; i < naodf; i++)
{
/* int j; */
/* log_debug ("p15: AODF[%d] pinref=%lu id=", */
/* i, aodfarray[i]->pin_reference); */
/* for (j=0; j < aodfarray[i]->objidlen; j++) */
/* log_printf ("%02X", aodfarray[i]->objid[j]); */
put_membuf_printf
(&mb, "%s%d", i? " ":"",
iso7816_verify_status (app_get_slot (app),
aodfarray[i]->pin_reference));
}
put_membuf( &mb, "", 1);
p = get_membuf (&mb, NULL);
if (!p)
return gpg_error_from_syserror ();
err = send_status_direct (ctrl, "CHV-STATUS", p);
xfree (p);
return err;
}
return gpg_error (GPG_ERR_INV_NAME);
}
@ -4463,7 +4528,7 @@ make_pin_prompt (app_t app, int remaining, const char *firstline,
/* Given the private key object PRKDF and its authentication object
* AODF ask for the PIN and verify that PIN. IF AODF is NULL, no
* AODF ask for the PIN and verify that PIN. If AODF is NULL, no
* authentication is done. */
static gpg_error_t
verify_pin (app_t app,
@ -4985,7 +5050,7 @@ do_decipher (app_t app, ctrl_t ctrl, const char *keyidstr,
return err;
if (!(prkdf->usageflags.decrypt || prkdf->usageflags.unwrap))
{
log_error ("p15: key %s may not be used for decruption\n", keyidstr);
log_error ("p15: key %s may not be used for decryption\n", keyidstr);
return gpg_error (GPG_ERR_WRONG_KEY_USAGE);
}
@ -5082,6 +5147,49 @@ do_decipher (app_t app, ctrl_t ctrl, const char *keyidstr,
}
/* Perform a simple verify operation for the PIN specified by
* KEYIDSTR. Note that we require a key reference which is then used
* to select the authentication object. Return GPG_ERR_NO_PIN if a
* PIN is not required for using the private key KEYIDSTR. */
static gpg_error_t
do_check_pin (app_t app, ctrl_t ctrl, const char *keyidstr,
gpg_error_t (*pincb)(void*, const char *, char **),
void *pincb_arg)
{
gpg_error_t err;
prkdf_object_t prkdf; /* The private key object. */
aodf_object_t aodf; /* The associated authentication object. */
(void)ctrl;
if (!keyidstr || !*keyidstr)
return gpg_error (GPG_ERR_INV_VALUE);
err = prkdf_object_from_keyidstr (app, keyidstr, &prkdf);
if (err)
return err;
/* Find the authentication object to this private key object. */
if (!prkdf->authid)
{
log_error ("p15: no authentication object defined for %s\n", keyidstr);
return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
}
for (aodf = app->app_local->auth_object_info; aodf; aodf = aodf->next)
if (aodf->objidlen == prkdf->authidlen
&& !memcmp (aodf->objid, prkdf->authid, prkdf->authidlen))
break;
if (!aodf) /* None found. */
return gpg_error (GPG_ERR_NO_PIN);
err = prepare_verify_pin (app, keyidstr, prkdf, aodf);
if (!err)
err = verify_pin (app, pincb, pincb_arg, prkdf, aodf);
return err;
}
/* Process the various keygrip based info requests. */
static gpg_error_t
do_with_keygrip (app_t app, ctrl_t ctrl, int action,
@ -5404,7 +5512,7 @@ app_select_p15 (app_t app)
app->fnc.auth = do_auth;
app->fnc.decipher = do_decipher;
app->fnc.change_pin = NULL;
app->fnc.check_pin = NULL;
app->fnc.check_pin = do_check_pin;
app->fnc.with_keygrip = do_with_keygrip;
leave:

View File

@ -2458,15 +2458,17 @@ send_status_info (ctrl_t ctrl, const char *keyword, ...)
/* Send a ready formatted status line via assuan. */
void
gpg_error_t
send_status_direct (ctrl_t ctrl, const char *keyword, const char *args)
{
assuan_context_t ctx = ctrl->server_local->assuan_ctx;
if (strchr (args, '\n'))
log_error ("error: LF detected in status line - not sending\n");
else
assuan_write_status (ctx, keyword, args);
{
log_error ("error: LF detected in status line - not sending\n");
return gpg_error (GPG_ERR_INTERNAL);
}
return assuan_write_status (ctx, keyword, args);
}

View File

@ -133,7 +133,8 @@ gpg_error_t initialize_module_command (void);
int scd_command_handler (ctrl_t, int);
void send_status_info (ctrl_t ctrl, const char *keyword, ...)
GPGRT_ATTR_SENTINEL(1);
void send_status_direct (ctrl_t ctrl, const char *keyword, const char *args);
gpg_error_t send_status_direct (ctrl_t ctrl,
const char *keyword, const char *args);
gpg_error_t send_status_printf (ctrl_t ctrl, const char *keyword,
const char *format, ...) GPGRT_ATTR_PRINTF(3,4);
void send_keyinfo (ctrl_t ctrl, int data, const char *keygrip_str,