diff options
-rw-r--r-- | scd/app-p15.c | 238 |
1 files changed, 117 insertions, 121 deletions
diff --git a/scd/app-p15.c b/scd/app-p15.c index 642e4dab6..11dae2624 100644 --- a/scd/app-p15.c +++ b/scd/app-p15.c @@ -4891,32 +4891,20 @@ do_sign (app_t app, ctrl_t ctrl, const char *keyidstr, int hashalgo, 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). */ - const unsigned char *dataptr; + unsigned int digestlen; /* Length of the hash. */ int exmode, le_value; + unsigned char oidbuf[64]; + size_t oidbuflen; + size_t n; + unsigned char *indata_buffer = NULL; /* Malloced helper. */ (void)ctrl; - if (!keyidstr || !*keyidstr) + if (!keyidstr || !*keyidstr || !indatalen) return gpg_error (GPG_ERR_INV_VALUE); err = prkdf_object_from_keyidstr (app, keyidstr, &prkdf); @@ -4958,20 +4946,19 @@ do_sign (app_t app, ctrl_t ctrl, const char *keyidstr, int hashalgo, return err; } + + digestlen = gcry_md_get_algo_dlen (hashalgo); + /* We handle ECC separately from RSA so that we do not need to touch * working code. In particular we prepare the input data before the * verify and a possible MSE. */ if (prkdf->is_ecc) { - unsigned int digestlen; - unsigned char oidbuf[64]; - size_t oidbuflen; - - digestlen = gcry_md_get_algo_dlen (hashalgo); if (digestlen != 32 && digestlen != 48 && digestlen != 64) { log_error ("p15: ECC signing not possible: dlen=%u\n", digestlen); - return gpg_error (GPG_ERR_DIGEST_ALGO); + err = gpg_error (GPG_ERR_DIGEST_ALGO); + goto leave; } if (indatalen == digestlen) @@ -4983,15 +4970,17 @@ do_sign (app_t app, ctrl_t ctrl, const char *keyidstr, int hashalgo, err = gcry_md_get_asnoid (hashalgo, &oidbuf, &oidbuflen); if (err) { - log_debug ("p15: no OID for hash algo %d\n", hashalgo); - return gpg_error (GPG_ERR_INTERNAL); + log_error ("p15: no OID for hash algo %d\n", hashalgo); + err = gpg_error (GPG_ERR_INTERNAL); + goto leave; } if (indatalen != oidbuflen + digestlen || memcmp (indata, oidbuf, oidbuflen)) { log_error ("p15: input data too long for ECC: len=%zu\n", indatalen); - return gpg_error (GPG_ERR_INV_VALUE); + err = gpg_error (GPG_ERR_INV_VALUE); + goto leave; } indata = (const char*)indata + oidbuflen; indatalen -= oidbuflen; @@ -5000,15 +4989,105 @@ do_sign (app_t app, ctrl_t ctrl, const char *keyidstr, int hashalgo, { log_error ("p15: input data too short for ECC: len=%zu\n", indatalen); - return gpg_error (GPG_ERR_INV_VALUE); + err = gpg_error (GPG_ERR_INV_VALUE); + goto leave; } } - else /* Check for RSA. FIXME: We should rework the RSA part. */ + else /* Prepare RSA input. */ { - if (indatalen != 20 && indatalen != 16 - && indatalen != 35 && indatalen != 36 - && indatalen != (32+19)) - return gpg_error (GPG_ERR_INV_VALUE); + unsigned int framelen; + unsigned char *frame; + int i; + + framelen = (prkdf->keynbits+7) / 8; + if (!framelen) + { + log_error ("p15: key length unknown" + " - can't prepare PKCS#v1.5 frame\n"); + err = gpg_error (GPG_ERR_INV_VALUE); + goto leave; + } + + oidbuflen = sizeof oidbuf; + if (!hashalgo) + { + /* We assume that indata already has the required + * digestinfo; thus merely prepend the padding below. */ + } + else if ((err = gcry_md_get_asnoid (hashalgo, &oidbuf, &oidbuflen))) + { + log_debug ("p15: no OID for hash algo %d\n", hashalgo); + goto leave; + } + else + { + if (indatalen == digestlen) + { + /* Plain hash in INDATA; prepend the digestinfo. */ + indata_buffer = xtrymalloc (oidbuflen + indatalen); + if (!indata_buffer) + { + err = gpg_error_from_syserror (); + goto leave; + } + memcpy (indata_buffer, oidbuf, oidbuflen); + memcpy (indata_buffer+oidbuflen, indata, indatalen); + indata = indata_buffer; + indatalen = oidbuflen + indatalen; + } + else if (indatalen == oidbuflen + digestlen + && !memcmp (indata, oidbuf, oidbuflen)) + ; /* We already got the correct prefix. */ + else + { + err = gpg_error (GPG_ERR_INV_VALUE); + log_error ("p15: bad input for signing with RSA and hash %d\n", + hashalgo); + goto leave; + } + } + /* Now prepend the pkcs#v1.5 padding. We require at least 8 + * byte of padding and 3 extra bytes for the prefix and the + * delimiting nul. */ + if (!indatalen || indatalen + 8 + 4 > framelen) + { + err = gpg_error (GPG_ERR_INV_VALUE); + log_error ("p15: input does not fit into a %u bit PKCS#v1.5 frame\n", + 8*framelen); + goto leave; + } + frame = xtrymalloc (framelen); + if (!frame) + { + err = gpg_error_from_syserror (); + goto leave; + } + if (app->app_local->card_type == CARD_TYPE_BELPIC) + { + /* This card wants only the plain hash w/o any prefix. */ + /* FIXME: We may want to remove this code because it is unlikely + * that such cards are still in use. */ + memcpy (frame, indata, indatalen); + framelen = indatalen; + } + else + { + n = 0; + frame[n++] = 0; + frame[n++] = 1; /* Block type. */ + i = framelen - indatalen - 3 ; + memset (frame+n, 0xff, i); + n += i; + frame[n++] = 0; /* Delimiter. */ + memcpy (frame+n, indata, indatalen); + n += indatalen; + log_assert (n == framelen); + } + /* And now put it into the indata_buffer. */ + xfree (indata_buffer); + indata_buffer = frame; + indata = indata_buffer; + indatalen = framelen; } /* Prepare PIN verification. This is split so that we can do @@ -5022,7 +5101,8 @@ do_sign (app_t app, ctrl_t ctrl, const char *keyidstr, int hashalgo, 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. */ + for the BELPIC card here. + FIXME: see comment above about these cards. */ if (app->app_local->card_type == CARD_TYPE_BELPIC) { unsigned char mse[5]; @@ -5039,7 +5119,6 @@ do_sign (app_t app, ctrl_t ctrl, const char *keyidstr, int hashalgo, err = iso7816_manage_security_env (app_get_slot (app), 0x41, 0xB6, mse, sizeof mse); - no_data_padding = 1; mse_done = 1; } if (err) @@ -5054,76 +5133,6 @@ do_sign (app_t app, ctrl_t ctrl, const char *keyidstr, int hashalgo, if (err) return err; - /* Prepare the input data from INDATA. */ - if (prkdf->is_ecc) - { - /* Already checked. */ - datalen = indatalen; - } - else if (indatalen == 36) - { - /* No ASN.1 container used. */ - if (hashalgo != MD_USER_TLS_MD5SHA1) - return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM); - memcpy (data, indata, indatalen); - datalen = hashlen = 36; - } - else if (indatalen == 35) - { - /* Alright, the caller was so kind to send us an already - prepared DER object. Check that it is what we want and that - it matches the hash algorithm. */ - if (hashalgo == GCRY_MD_SHA1 && !memcmp (indata, sha1_prefix, 15)) - ; - else if (hashalgo == GCRY_MD_RMD160 - && !memcmp (indata, rmd160_prefix, 15)) - ; - else - return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM); - memcpy (data, indata, indatalen); - datalen = 35; - hashlen = 20; - } - else if (indatalen == 32 + 19) - { - /* Seems to be a prepared SHA256 DER object. */ - if (hashalgo == GCRY_MD_SHA256 && !memcmp (indata, sha256_prefix, 19)) - ; - else - return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM); - memcpy (data, indata, indatalen); - datalen = 51; - hashlen = 32; - } - else - { - /* Need to prepend the prefix. */ - if (hashalgo == GCRY_MD_SHA256) - { - memcpy (data, sha256_prefix, 19); - memcpy (data+19, indata, indatalen); - datalen = 51; - hashlen = 32; - } - else if (hashalgo == GCRY_MD_SHA1) - { - memcpy (data, sha1_prefix, 15); - memcpy (data+15, indata, indatalen); - datalen = 35; - hashlen = 20; - } - else if (hashalgo == GCRY_MD_RMD160) - { - memcpy (data, rmd160_prefix, 15); - memcpy (data+15, indata, indatalen); - datalen = 35; - hashlen = 20; - } - else - return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM); - } - - /* Manage security environment needs to be tweaked for certain cards. */ if (mse_done) err = 0; @@ -5157,21 +5166,6 @@ do_sign (app_t app, ctrl_t ctrl, const char *keyidstr, int hashalgo, return err; } - if (prkdf->is_ecc) - { - dataptr = indata; - datalen = indatalen; - } - else - { - dataptr = data; - if (no_data_padding) - { - dataptr += datalen - hashlen; - datalen = hashlen; - } - } - if (prkdf->keyalgo == GCRY_PK_RSA && prkdf->keynbits > 2048) { exmode = 1; @@ -5184,9 +5178,11 @@ do_sign (app_t app, ctrl_t ctrl, const char *keyidstr, int hashalgo, } err = iso7816_compute_ds (app_get_slot (app), - exmode, dataptr, datalen, + exmode, indata, indatalen, le_value, outdata, outdatalen); + leave: + xfree (indata_buffer); return err; } |