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.
|
/* Prepare the verification of the PIN for the key PRKDF by checking
|
||||||
|
* the AODF and selecting the key file. KEYREF is used for error
|
||||||
Create the signature and return the allocated result in OUTDATA.
|
* messages. */
|
||||||
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
|
static gpg_error_t
|
||||||
do_sign (app_t app, ctrl_t ctrl, const char *keyidstr, int hashalgo,
|
prepare_verify_pin (app_t app, const char *keyref,
|
||||||
gpg_error_t (*pincb)(void*, const char *, char **),
|
prkdf_object_t prkdf, aodf_object_t aodf)
|
||||||
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;
|
gpg_error_t err;
|
||||||
int i;
|
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)
|
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
|
/* 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);
|
err = select_ef_by_path (app, prkdf->path, prkdf->pathlen);
|
||||||
if (err)
|
if (err)
|
||||||
{
|
|
||||||
log_error ("p15: error selecting file for key %s: %s\n",
|
log_error ("p15: error selecting file for key %s: %s\n",
|
||||||
keyidstr, gpg_strerror (errno));
|
keyref, gpg_strerror (err));
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Due to the fact that the non-repudiation signature on a BELPIC
|
/* Given the private key object PRKDF and its authentication object
|
||||||
card requires a verify immediately before the DSO we set the
|
* AODF ask for the PIN and verify that PIN. */
|
||||||
MSE before we do the verification. Other cards might also allow
|
static gpg_error_t
|
||||||
this but I don't want to break anything, thus we do it only
|
verify_pin (app_t app,
|
||||||
for the BELPIC card here. */
|
gpg_error_t (*pincb)(void*, const char *, char **), void *pincb_arg,
|
||||||
if (app->app_local->card_type == CARD_TYPE_BELPIC)
|
prkdf_object_t prkdf, aodf_object_t aodf)
|
||||||
{
|
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
|
gpg_error_t err;
|
||||||
char *pinvalue;
|
char *pinvalue;
|
||||||
size_t pinvaluelen;
|
size_t pinvaluelen;
|
||||||
const char *errstr;
|
const char *errstr;
|
||||||
const char *s;
|
const char *s;
|
||||||
|
int i;
|
||||||
|
|
||||||
if (prkdf->usageflags.non_repudiation
|
if (prkdf->usageflags.non_repudiation
|
||||||
&& app->app_local->card_type == CARD_TYPE_BELPIC)
|
&& 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
|
/* We might need to cope with UTF8 things here. Not sure how
|
||||||
min_length etc. are exactly defined, for now we take them as
|
min_length etc. are exactly defined, for now we take them as
|
||||||
a plain octet count. */
|
a plain octet count. */
|
||||||
|
|
||||||
if (strlen (pinvalue) < aodf->min_length)
|
if (strlen (pinvalue) < aodf->min_length)
|
||||||
{
|
{
|
||||||
log_error ("p15: PIN is too short; minimum length is %lu\n",
|
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));
|
|((aodf->pad_char_valid?aodf->pad_char:0)&0x0f));
|
||||||
|
|
||||||
if (aodf->pinflags.needs_padding)
|
if (aodf->pinflags.needs_padding)
|
||||||
|
{
|
||||||
while (i < aodf->stored_length)
|
while (i < aodf->stored_length)
|
||||||
paddedpin[i++] = aodf->pad_char_valid? aodf->pad_char : 0;
|
paddedpin[i++] = aodf->pad_char_valid? aodf->pad_char : 0;
|
||||||
|
}
|
||||||
|
|
||||||
xfree (pinvalue);
|
xfree (pinvalue);
|
||||||
pinvalue = paddedpin;
|
pinvalue = paddedpin;
|
||||||
@ -3379,9 +3287,9 @@ do_sign (app_t app, ctrl_t ctrl, const char *keyidstr, int hashalgo,
|
|||||||
else
|
else
|
||||||
pinvaluelen = strlen (pinvalue);
|
pinvaluelen = strlen (pinvalue);
|
||||||
|
|
||||||
log_printhex (pinvalue, pinvaluelen,
|
/* log_printhex (pinvalue, pinvaluelen, */
|
||||||
"about to verify with ref %lu pin:",
|
/* "about to verify with ref %lu pin:", */
|
||||||
aodf->pin_reference_valid? aodf->pin_reference : 0);
|
/* aodf->pin_reference_valid? aodf->pin_reference : 0); */
|
||||||
err = iso7816_verify (app_get_slot (app),
|
err = iso7816_verify (app_get_slot (app),
|
||||||
aodf->pin_reference_valid? aodf->pin_reference : 0,
|
aodf->pin_reference_valid? aodf->pin_reference : 0,
|
||||||
pinvalue, pinvaluelen);
|
pinvalue, pinvaluelen);
|
||||||
@ -3393,8 +3301,132 @@ do_sign (app_t app, ctrl_t ctrl, const char *keyidstr, int hashalgo,
|
|||||||
}
|
}
|
||||||
if (opt.verbose)
|
if (opt.verbose)
|
||||||
log_info ("p15: PIN verification succeeded\n");
|
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. */
|
/* Prepare the DER object from INDATA. */
|
||||||
if (indatalen == 36)
|
if (indatalen == 36)
|
||||||
{
|
{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user