From 592f48011790e30d4bcfd9093eb58b786c8c9a8b Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Mon, 29 Mar 2021 20:36:01 +0200 Subject: [PATCH] scd:p15: Make RSA with SHA512 work with CardOS. * scd/app-p15.c (do_sign): Rewrite. -- This basically works now but for my test card I need to pass --cert-digest-algo-512 manually. Need to check this again and automate it. It will also be useful to take the NotBefore timestamp from the dummy X.509 certificate and use that for the PGP key creation time. Signed-off-by: Werner Koch --- scd/app-p15.c | 238 +++++++++++++++++++++++++------------------------- 1 file 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; }