mirror of
git://git.gnupg.org/gnupg.git
synced 2025-01-18 14:17:03 +01:00
scd:p15: Factor PIN verification out to a new function.
* scd/app-p15.c (do_sign): Factor code out to ... (prepare_verify_pin, verify_pin): new functions. -- Signed-off-by: Werner Koch <wk@gnupg.org>
This commit is contained in:
parent
c7ff8c59b9
commit
375b145487
258
scd/app-p15.c
258
scd/app-p15.c
@ -3094,82 +3094,15 @@ micardo_mse (app_t app, unsigned short fid)
|
||||
|
||||
|
||||
|
||||
/* Handler for the PKSIGN command.
|
||||
|
||||
Create the signature and return the allocated result in OUTDATA.
|
||||
If a PIN is required, the PINCB will be used to ask for the PIN;
|
||||
that callback should return the PIN in an allocated buffer and
|
||||
store that as the 3rd argument. */
|
||||
/* Prepare the verification of the PIN for the key PRKDF by checking
|
||||
* the AODF and selecting the key file. KEYREF is used for error
|
||||
* messages. */
|
||||
static gpg_error_t
|
||||
do_sign (app_t app, ctrl_t ctrl, const char *keyidstr, int hashalgo,
|
||||
gpg_error_t (*pincb)(void*, const char *, char **),
|
||||
void *pincb_arg,
|
||||
const void *indata, size_t indatalen,
|
||||
unsigned char **outdata, size_t *outdatalen )
|
||||
prepare_verify_pin (app_t app, const char *keyref,
|
||||
prkdf_object_t prkdf, aodf_object_t aodf)
|
||||
{
|
||||
static unsigned char sha256_prefix[19] = /* OID: 2.16.840.1.101.3.4.2.1 */
|
||||
{ 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48,
|
||||
0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20 };
|
||||
static unsigned char sha1_prefix[15] = /* Object ID is 1.3.14.3.2.26 */
|
||||
{ 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03,
|
||||
0x02, 0x1a, 0x05, 0x00, 0x04, 0x14 };
|
||||
static unsigned char rmd160_prefix[15] = /* Object ID is 1.3.36.3.2.1 */
|
||||
{ 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x24, 0x03,
|
||||
0x02, 0x01, 0x05, 0x00, 0x04, 0x14 };
|
||||
|
||||
gpg_error_t err;
|
||||
int i;
|
||||
unsigned char data[32+19]; /* Must be large enough for a SHA-256 digest
|
||||
* + the largest OID prefix above and also
|
||||
* fit the 36 bytes of md5sha1. */
|
||||
prkdf_object_t prkdf; /* The private key object. */
|
||||
aodf_object_t aodf; /* The associated authentication object. */
|
||||
int no_data_padding = 0; /* True if the card want the data without padding.*/
|
||||
int mse_done = 0; /* Set to true if the MSE has been done. */
|
||||
unsigned int hashlen; /* Length of the hash. */
|
||||
unsigned int datalen; /* Length of the data to sign (prefix+hash). */
|
||||
unsigned char *dataptr;
|
||||
int exmode, le_value;
|
||||
|
||||
(void)ctrl;
|
||||
|
||||
log_debug ("p15:sign: keyidstr='%s' indatalen=%zu\n", keyidstr, indatalen);
|
||||
if (!keyidstr || !*keyidstr)
|
||||
return gpg_error (GPG_ERR_INV_VALUE);
|
||||
if (indatalen != 20 && indatalen != 16
|
||||
&& indatalen != 35 && indatalen != 36
|
||||
&& indatalen != (32+19))
|
||||
return gpg_error (GPG_ERR_INV_VALUE);
|
||||
|
||||
err = prkdf_object_from_keyidstr (app, keyidstr, &prkdf);
|
||||
if (err)
|
||||
return err;
|
||||
if (!(prkdf->usageflags.sign || prkdf->usageflags.sign_recover
|
||||
||prkdf->usageflags.non_repudiation))
|
||||
{
|
||||
log_error ("p15: key %s may not be used for signing\n", keyidstr);
|
||||
return gpg_error (GPG_ERR_WRONG_KEY_USAGE);
|
||||
}
|
||||
|
||||
if (!prkdf->authid)
|
||||
{
|
||||
log_error ("p15: no authentication object defined for %s\n", keyidstr);
|
||||
/* fixme: we might want to go ahead and do without PIN
|
||||
verification. */
|
||||
return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
|
||||
}
|
||||
|
||||
/* Find the authentication object to this private key object. */
|
||||
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)
|
||||
{
|
||||
log_error ("p15: authentication object for %s missing\n", keyidstr);
|
||||
return gpg_error (GPG_ERR_INV_CARD);
|
||||
}
|
||||
|
||||
|
||||
if (opt.verbose)
|
||||
{
|
||||
@ -3197,55 +3130,29 @@ do_sign (app_t app, ctrl_t ctrl, const char *keyidstr, int hashalgo,
|
||||
}
|
||||
|
||||
/* Select the key file. Note that this may change the security
|
||||
environment thus we do it before PIN verification. */
|
||||
* environment thus we need to do it before PIN verification. */
|
||||
err = select_ef_by_path (app, prkdf->path, prkdf->pathlen);
|
||||
if (err)
|
||||
{
|
||||
log_error ("p15: error selecting file for key %s: %s\n",
|
||||
keyidstr, gpg_strerror (errno));
|
||||
keyref, gpg_strerror (err));
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
/* Due to the fact that the non-repudiation signature on a BELPIC
|
||||
card requires a verify immediately before the DSO we set the
|
||||
MSE before we do the verification. Other cards might also allow
|
||||
this but I don't want to break anything, thus we do it only
|
||||
for the BELPIC card here. */
|
||||
if (app->app_local->card_type == CARD_TYPE_BELPIC)
|
||||
{
|
||||
unsigned char mse[5];
|
||||
|
||||
mse[0] = 4; /* Length of the template. */
|
||||
mse[1] = 0x80; /* Algorithm reference tag. */
|
||||
if (hashalgo == MD_USER_TLS_MD5SHA1)
|
||||
mse[2] = 0x01; /* Let card do pkcs#1 0xFF padding. */
|
||||
else
|
||||
mse[2] = 0x02; /* RSASSA-PKCS1-v1.5 using SHA1. */
|
||||
mse[3] = 0x84; /* Private key reference tag. */
|
||||
mse[4] = prkdf->key_reference_valid? prkdf->key_reference : 0x82;
|
||||
|
||||
err = iso7816_manage_security_env (app_get_slot (app),
|
||||
0x41, 0xB6,
|
||||
mse, sizeof mse);
|
||||
no_data_padding = 1;
|
||||
mse_done = 1;
|
||||
}
|
||||
if (err)
|
||||
{
|
||||
log_error ("p15: MSE failed: %s\n", gpg_strerror (err));
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
/* Now that we have all the information available, prepare and run
|
||||
the PIN verification.*/
|
||||
if (1)
|
||||
/* Given the private key object PRKDF and its authentication object
|
||||
* AODF ask for the PIN and verify that PIN. */
|
||||
static gpg_error_t
|
||||
verify_pin (app_t app,
|
||||
gpg_error_t (*pincb)(void*, const char *, char **), void *pincb_arg,
|
||||
prkdf_object_t prkdf, aodf_object_t aodf)
|
||||
{
|
||||
gpg_error_t err;
|
||||
char *pinvalue;
|
||||
size_t pinvaluelen;
|
||||
const char *errstr;
|
||||
const char *s;
|
||||
int i;
|
||||
|
||||
if (prkdf->usageflags.non_repudiation
|
||||
&& app->app_local->card_type == CARD_TYPE_BELPIC)
|
||||
@ -3262,7 +3169,6 @@ do_sign (app_t app, ctrl_t ctrl, const char *keyidstr, int hashalgo,
|
||||
/* We might need to cope with UTF8 things here. Not sure how
|
||||
min_length etc. are exactly defined, for now we take them as
|
||||
a plain octet count. */
|
||||
|
||||
if (strlen (pinvalue) < aodf->min_length)
|
||||
{
|
||||
log_error ("p15: PIN is too short; minimum length is %lu\n",
|
||||
@ -3347,8 +3253,10 @@ do_sign (app_t app, ctrl_t ctrl, const char *keyidstr, int hashalgo,
|
||||
|((aodf->pad_char_valid?aodf->pad_char:0)&0x0f));
|
||||
|
||||
if (aodf->pinflags.needs_padding)
|
||||
{
|
||||
while (i < aodf->stored_length)
|
||||
paddedpin[i++] = aodf->pad_char_valid? aodf->pad_char : 0;
|
||||
}
|
||||
|
||||
xfree (pinvalue);
|
||||
pinvalue = paddedpin;
|
||||
@ -3379,9 +3287,9 @@ do_sign (app_t app, ctrl_t ctrl, const char *keyidstr, int hashalgo,
|
||||
else
|
||||
pinvaluelen = strlen (pinvalue);
|
||||
|
||||
log_printhex (pinvalue, pinvaluelen,
|
||||
"about to verify with ref %lu pin:",
|
||||
aodf->pin_reference_valid? aodf->pin_reference : 0);
|
||||
/* log_printhex (pinvalue, pinvaluelen, */
|
||||
/* "about to verify with ref %lu pin:", */
|
||||
/* aodf->pin_reference_valid? aodf->pin_reference : 0); */
|
||||
err = iso7816_verify (app_get_slot (app),
|
||||
aodf->pin_reference_valid? aodf->pin_reference : 0,
|
||||
pinvalue, pinvaluelen);
|
||||
@ -3393,8 +3301,132 @@ do_sign (app_t app, ctrl_t ctrl, const char *keyidstr, int hashalgo,
|
||||
}
|
||||
if (opt.verbose)
|
||||
log_info ("p15: PIN verification succeeded\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* Handler for the PKSIGN command.
|
||||
|
||||
Create the signature and return the allocated result in OUTDATA.
|
||||
If a PIN is required, the PINCB will be used to ask for the PIN;
|
||||
that callback should return the PIN in an allocated buffer and
|
||||
store that as the 3rd argument. */
|
||||
static gpg_error_t
|
||||
do_sign (app_t app, ctrl_t ctrl, const char *keyidstr, int hashalgo,
|
||||
gpg_error_t (*pincb)(void*, const char *, char **),
|
||||
void *pincb_arg,
|
||||
const void *indata, size_t indatalen,
|
||||
unsigned char **outdata, size_t *outdatalen )
|
||||
{
|
||||
static unsigned char sha256_prefix[19] = /* OID: 2.16.840.1.101.3.4.2.1 */
|
||||
{ 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48,
|
||||
0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20 };
|
||||
static unsigned char sha1_prefix[15] = /* Object ID is 1.3.14.3.2.26 */
|
||||
{ 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03,
|
||||
0x02, 0x1a, 0x05, 0x00, 0x04, 0x14 };
|
||||
static unsigned char rmd160_prefix[15] = /* Object ID is 1.3.36.3.2.1 */
|
||||
{ 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x24, 0x03,
|
||||
0x02, 0x01, 0x05, 0x00, 0x04, 0x14 };
|
||||
|
||||
gpg_error_t err;
|
||||
unsigned char data[32+19]; /* Must be large enough for a SHA-256 digest
|
||||
* + the largest OID prefix above and also
|
||||
* fit the 36 bytes of md5sha1. */
|
||||
prkdf_object_t prkdf; /* The private key object. */
|
||||
aodf_object_t aodf; /* The associated authentication object. */
|
||||
int no_data_padding = 0; /* True if the card want the data without padding.*/
|
||||
int mse_done = 0; /* Set to true if the MSE has been done. */
|
||||
unsigned int hashlen; /* Length of the hash. */
|
||||
unsigned int datalen; /* Length of the data to sign (prefix+hash). */
|
||||
unsigned char *dataptr;
|
||||
int exmode, le_value;
|
||||
|
||||
(void)ctrl;
|
||||
|
||||
if (!keyidstr || !*keyidstr)
|
||||
return gpg_error (GPG_ERR_INV_VALUE);
|
||||
if (indatalen != 20 && indatalen != 16
|
||||
&& indatalen != 35 && indatalen != 36
|
||||
&& indatalen != (32+19))
|
||||
return gpg_error (GPG_ERR_INV_VALUE);
|
||||
|
||||
err = prkdf_object_from_keyidstr (app, keyidstr, &prkdf);
|
||||
if (err)
|
||||
return err;
|
||||
if (!(prkdf->usageflags.sign || prkdf->usageflags.sign_recover
|
||||
||prkdf->usageflags.non_repudiation))
|
||||
{
|
||||
log_error ("p15: key %s may not be used for signing\n", keyidstr);
|
||||
return gpg_error (GPG_ERR_WRONG_KEY_USAGE);
|
||||
}
|
||||
|
||||
if (!prkdf->authid)
|
||||
{
|
||||
log_error ("p15: no authentication object defined for %s\n", keyidstr);
|
||||
/* fixme: we might want to go ahead and do without PIN
|
||||
verification. */
|
||||
return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
|
||||
}
|
||||
|
||||
/* Find the authentication object to this private key object. */
|
||||
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)
|
||||
{
|
||||
log_error ("p15: authentication object for %s missing\n", keyidstr);
|
||||
return gpg_error (GPG_ERR_INV_CARD);
|
||||
}
|
||||
|
||||
|
||||
/* Prepare PIN verification. This is split so that we can do
|
||||
* MSE operation for some task after having selected the key file but
|
||||
* before sending the verify APDU. */
|
||||
err = prepare_verify_pin (app, keyidstr, prkdf, aodf);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* Due to the fact that the non-repudiation signature on a BELPIC
|
||||
card requires a verify immediately before the DSO we set the
|
||||
MSE before we do the verification. Other cards might also allow
|
||||
this but I don't want to break anything, thus we do it only
|
||||
for the BELPIC card here. */
|
||||
if (app->app_local->card_type == CARD_TYPE_BELPIC)
|
||||
{
|
||||
unsigned char mse[5];
|
||||
|
||||
mse[0] = 4; /* Length of the template. */
|
||||
mse[1] = 0x80; /* Algorithm reference tag. */
|
||||
if (hashalgo == MD_USER_TLS_MD5SHA1)
|
||||
mse[2] = 0x01; /* Let card do pkcs#1 0xFF padding. */
|
||||
else
|
||||
mse[2] = 0x02; /* RSASSA-PKCS1-v1.5 using SHA1. */
|
||||
mse[3] = 0x84; /* Private key reference tag. */
|
||||
mse[4] = prkdf->key_reference_valid? prkdf->key_reference : 0x82;
|
||||
|
||||
err = iso7816_manage_security_env (app_get_slot (app),
|
||||
0x41, 0xB6,
|
||||
mse, sizeof mse);
|
||||
no_data_padding = 1;
|
||||
mse_done = 1;
|
||||
}
|
||||
if (err)
|
||||
{
|
||||
log_error ("p15: MSE failed: %s\n", gpg_strerror (err));
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Now that we have all the information available run the actual PIN
|
||||
* verification.*/
|
||||
err = verify_pin (app, pincb, pincb_arg, prkdf, aodf);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
|
||||
/* Prepare the DER object from INDATA. */
|
||||
if (indatalen == 36)
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user