diff --git a/NEWS b/NEWS index ec7e2358d..8108d5f49 100644 --- a/NEWS +++ b/NEWS @@ -25,6 +25,8 @@ Noteworthy changes in version 2.0.10 (unreleased) * New control statement %ask-passphrase for the unattended key generation of gpg2. + * gpgsm now uses AES by default. + Noteworthy changes in version 2.0.9 (2008-03-26) ------------------------------------------------ diff --git a/TODO b/TODO index f10297f5e..139b90d74 100644 --- a/TODO +++ b/TODO @@ -66,7 +66,8 @@ We should check the card status in open-card to make this smoother. Needs to be integrated with the status file update, though. It is not a real problem because application will get a card removed - status and should the send a reset to try solving the problem. + status and should then send a reset to try solving the problem. +** Resolve fixme in do_sign of app-dinsig. ** Add a regression test to check the extkeyusage. diff --git a/common/ChangeLog b/common/ChangeLog index 3840eaacd..dcee95bbf 100644 --- a/common/ChangeLog +++ b/common/ChangeLog @@ -1,3 +1,9 @@ +2008-06-26 Werner Koch + + * estream.c (es_write_sanitized): Loose check for control + characters to better cope with utf-8. The range 0x80..0x9f is + nowadays not anymore accidently used for control charaters. + 2008-06-25 Marcus Brinkmann Revert last three changes related to handle translation. diff --git a/common/estream.c b/common/estream.c index e712e85cd..254fab93a 100644 --- a/common/estream.c +++ b/common/estream.c @@ -3074,7 +3074,7 @@ es_write_sanitized (estream_t ES__RESTRICT stream, for (; length; length--, p++, count++) { if (*p < 0x20 - || (*p >= 0x7f && *p < 0xa0) + || *p == 0x7f || (delimiters && (strchr (delimiters, *p) || *p == '\\'))) { diff --git a/jnlib/ChangeLog b/jnlib/ChangeLog index d09834419..c7bef6086 100644 --- a/jnlib/ChangeLog +++ b/jnlib/ChangeLog @@ -1,3 +1,9 @@ +2008-06-26 Werner Koch + + * stringhelp.c (print_sanitized_buffer2): Loose check for control + characters to better cope with utf-8. The range 0x80..0x9f is + nowadays not anymore accidently used for control charaters. + 2008-06-13 Werner Koch * dotlock.c: Reformat code and implement locking for W32. diff --git a/jnlib/stringhelp.c b/jnlib/stringhelp.c index 028750528..50e869cea 100644 --- a/jnlib/stringhelp.c +++ b/jnlib/stringhelp.c @@ -406,9 +406,8 @@ print_sanitized_buffer2 (FILE *fp, const void *buffer, size_t length, for (; length; length--, p++, count++) { - /* Fixme: Check whether *p < 0xa0 is correct for utf8 encoding. */ if (*p < 0x20 - || (*p >= 0x7f && *p < 0xa0) + || *p == 0x7f || *p == delim || *p == delim2 || ((delim || delim2) && *p=='\\')) diff --git a/scd/ChangeLog b/scd/ChangeLog index 60c139c40..3cd6eb0c2 100644 --- a/scd/ChangeLog +++ b/scd/ChangeLog @@ -1,3 +1,7 @@ +2008-06-25 Werner Koch + + * app-dinsig.c (do_sign): Allow for SHA256. + 2008-06-24 Werner Koch * app-common.h (app_ctx_s): Renamed reset_mode parameter of diff --git a/scd/app-dinsig.c b/scd/app-dinsig.c index 54b54b150..cd6c3d096 100644 --- a/scd/app-dinsig.c +++ b/scd/app-dinsig.c @@ -1,5 +1,5 @@ /* app-dinsig.c - The DINSIG (DIN V 66291-1) card application. - * Copyright (C) 2002, 2004, 2005, 2007 Free Software Foundation, Inc. + * Copyright (C) 2002, 2004, 2005, 2007, 2008 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -397,14 +397,20 @@ do_sign (app_t app, const char *keyidstr, int hashalgo, 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 }; + static unsigned char sha256_prefix[19] = /* OID is 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 }; int rc; int fid; - unsigned char data[35]; /* Must be large enough for a SHA-1 digest - + the largest OID _prefix above. */ + unsigned char data[19+32]; /* Must be large enough for a SHA-256 digest + + the largest OID _prefix above. */ + int datalen; if (!keyidstr || !*keyidstr) return gpg_error (GPG_ERR_INV_VALUE); - if (indatalen != 20 && indatalen != 16 && indatalen != 35) + if (indatalen != 20 && indatalen != 16 && indatalen != 32 + && indatalen != (15+20) && indatalen != (19+32)) return gpg_error (GPG_ERR_INV_VALUE); /* Check that the provided ID is vaid. This is not really needed @@ -421,7 +427,8 @@ do_sign (app_t app, const char *keyidstr, int hashalgo, return gpg_error (GPG_ERR_NOT_FOUND); /* Prepare the DER object from INDATA. */ - if (indatalen == 35) + datalen = 35; + if (indatalen == 15+20) { /* Alright, the caller was so kind to send us an already prepared DER object. Check that it is what we want and that @@ -434,24 +441,103 @@ do_sign (app_t app, const char *keyidstr, int hashalgo, return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM); memcpy (data, indata, indatalen); } - else + else if (indatalen == 19+32) { - if (hashalgo == GCRY_MD_SHA1) - memcpy (data, sha1_prefix, 15); - else if (hashalgo == GCRY_MD_RMD160) - memcpy (data, rmd160_prefix, 15); + /* 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. */ + datalen = indatalen; + if (hashalgo == GCRY_MD_SHA256 && !memcmp (indata, sha256_prefix, 19)) + ; + else if (hashalgo == GCRY_MD_SHA1 && !memcmp (indata, sha256_prefix, 19)) + { + /* Fixme: This is a kludge. A better solution is not to use + SHA1 as default but use an autodetection. However this + needs changes in all app-*.c */ + hashalgo = GCRY_MD_SHA256; + datalen = indatalen; + } else return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM); - memcpy (data+15, indata, indatalen); + memcpy (data, indata, indatalen); + } + else + { + int len = 15; + if (hashalgo == GCRY_MD_SHA1) + memcpy (data, sha1_prefix, len); + else if (hashalgo == GCRY_MD_RMD160) + memcpy (data, rmd160_prefix, len); + else if (hashalgo == GCRY_MD_SHA256) + { + len = 19; + datalen = len + indatalen; + memcpy (data, sha256_prefix, len); + } + else + return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM); + memcpy (data+len, indata, indatalen); } rc = verify_pin (app, pincb, pincb_arg); if (!rc) - rc = iso7816_compute_ds (app->slot, data, 35, outdata, outdatalen); + rc = iso7816_compute_ds (app->slot, data, datalen, outdata, outdatalen); return rc; } +#if 0 +#warning test function - works but may brick your card +/* Handle the PASSWD command. CHVNOSTR is currently ignored; we + always use VHV0. RESET_MODE is not yet implemented. */ +static gpg_error_t +do_change_pin (app_t app, ctrl_t ctrl, const char *chvnostr, + unsigned int flags, + gpg_error_t (*pincb)(void*, const char *, char **), + void *pincb_arg) +{ + gpg_error_t err; + char *pinvalue; + const char *oldpin; + size_t oldpinlen; + + if ((flags & APP_CHANGE_FLAG_RESET)) + return gpg_error (GPG_ERR_NOT_IMPLEMENTED); + + if ((flags & APP_CHANGE_FLAG_NULLPIN)) + { + /* With the nullpin flag, we do not verify the PIN - it would fail + if the Nullpin is still set. */ + oldpin = "\0\0\0\0\0"; + oldpinlen = 6; + } + else + { + err = verify_pin (app, pincb, pincb_arg); + if (err) + return err; + oldpin = NULL; + oldpinlen = 0; + } + + /* TRANSLATORS: Do not translate the "|*|" prefixes but + keep it at the start of the string. We need this elsewhere + to get some infos on the string. */ + err = pincb (pincb_arg, _("|N|Initial New PIN"), &pinvalue); + if (err) + { + log_error (_("error getting new PIN: %s\n"), gpg_strerror (err)); + return err; + } + + err = iso7816_change_reference_data (app->slot, 0x81, + oldpin, oldpinlen, + pinvalue, strlen (pinvalue)); + xfree (pinvalue); + return err; +} + + /* Select the DINSIG application on the card in SLOT. This function must be used before any other DINSIG application functions. */ @@ -475,7 +561,7 @@ app_select_dinsig (app_t app) app->fnc.sign = do_sign; app->fnc.auth = NULL; app->fnc.decipher = NULL; - app->fnc.change_pin = NULL; + app->fnc.change_pin = NULL /*do_change_pin*/; app->fnc.check_pin = NULL; app->force_chv1 = 1; diff --git a/sm/ChangeLog b/sm/ChangeLog index 20ab48302..a6a584b38 100644 --- a/sm/ChangeLog +++ b/sm/ChangeLog @@ -1,3 +1,16 @@ +2008-06-25 Werner Koch + + * sign.c (gpgsm_sign): Revamp the hash algorithm selection. + * gpgsm.h (struct certlist_s): Add field HASH_ALGO and HASH_ALGO_OID. + + * qualified.c (gpgsm_qualified_consent): Fix double free. + + * gpgsm.c (main): Change default cipher algo to AES. + + * keylist.c (print_utf8_extn_raw, print_utf8_extn): New. + (list_cert_raw, list_cert_std): Print the TeleSec restriction + extension. + 2008-06-23 Werner Koch * encrypt.c (encode_session_key): Replace xmalloc by xtrymalloc. diff --git a/sm/gpgsm.c b/sm/gpgsm.c index 50ffb84d2..dfbe82675 100644 --- a/sm/gpgsm.c +++ b/sm/gpgsm.c @@ -987,7 +987,7 @@ main ( int argc, char **argv) create_dotlock (NULL); /* register locking cleanup */ i18n_init(); - opt.def_cipher_algoid = "3DES"; /*des-EDE3-CBC*/ + opt.def_cipher_algoid = "AES"; /*des-EDE3-CBC*/ opt.homedir = default_homedir (); diff --git a/sm/gpgsm.h b/sm/gpgsm.h index acc53b574..2cd177504 100644 --- a/sm/gpgsm.h +++ b/sm/gpgsm.h @@ -207,6 +207,8 @@ struct certlist_s ksba_cert_t cert; int is_encrypt_to; /* True if the certificate has been set through the --encrypto-to option. */ + int hash_algo; /* Used to track the hash algorithm to use. */ + const char *hash_algo_oid; /* And the corresponding OID. */ }; typedef struct certlist_s *certlist_t; diff --git a/sm/keylist.c b/sm/keylist.c index 870ddf46d..6dcdc8d4d 100644 --- a/sm/keylist.c +++ b/sm/keylist.c @@ -1,6 +1,6 @@ /* keylist.c - Print certificates in various formats. * Copyright (C) 1998, 1999, 2000, 2001, 2003, - * 2004, 2005 Free Software Foundation, Inc. + * 2004, 2005, 2008 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -35,6 +35,7 @@ #include "keydb.h" #include "../kbx/keybox.h" /* for KEYBOX_FLAG_* */ #include "i18n.h" +#include "tlv.h" struct list_external_parm_s { @@ -77,12 +78,18 @@ struct }; +/* Do not print this extension in the list of extensions. This is set + for oids which are already available via ksba fucntions. */ +#define OID_FLAG_SKIP 1 +/* The extension is a simple UTF8String and should be printed. */ +#define OID_FLAG_UTF8 2 + /* A table mapping OIDs to a descriptive string. */ static struct { char *oid; char *name; - unsigned int flag; + unsigned int flag; /* A flag as described above. */ } oidtranstbl[] = { /* Algorithms. */ @@ -115,6 +122,10 @@ static struct { "0.2.262.1.10.12.4", "telesecCRLFilteredExt" }, { "0.2.262.1.10.12.5", "telesecCRLFilterExt"}, { "0.2.262.1.10.12.6", "telesecNamingAuthorityExt" }, +#define OIDSTR_restriction \ + "1.3.36.8.3.8" + { OIDSTR_restriction, "restriction", OID_FLAG_UTF8 }, + /* PKIX private extensions. */ { "1.3.6.1.5.5.7.1.1", "authorityInfoAccess" }, @@ -135,12 +146,12 @@ static struct { "1.3.6.1.5.5.7.48.5", "caRepository" }, /* X.509 id-ce */ - { "2.5.29.14", "subjectKeyIdentifier", 1}, - { "2.5.29.15", "keyUsage", 1 }, + { "2.5.29.14", "subjectKeyIdentifier", OID_FLAG_SKIP}, + { "2.5.29.15", "keyUsage", OID_FLAG_SKIP}, { "2.5.29.16", "privateKeyUsagePeriod" }, - { "2.5.29.17", "subjectAltName", 1 }, - { "2.5.29.18", "issuerAltName", 1 }, - { "2.5.29.19", "basicConstraints", 1}, + { "2.5.29.17", "subjectAltName", OID_FLAG_SKIP}, + { "2.5.29.18", "issuerAltName", OID_FLAG_SKIP}, + { "2.5.29.19", "basicConstraints", OID_FLAG_SKIP}, { "2.5.29.20", "cRLNumber" }, { "2.5.29.21", "cRLReason" }, { "2.5.29.22", "expirationDate" }, @@ -150,13 +161,13 @@ static struct { "2.5.29.28", "issuingDistributionPoint" }, { "2.5.29.29", "certificateIssuer" }, { "2.5.29.30", "nameConstraints" }, - { "2.5.29.31", "cRLDistributionPoints", 1 }, - { "2.5.29.32", "certificatePolicies", 1 }, + { "2.5.29.31", "cRLDistributionPoints", OID_FLAG_SKIP}, + { "2.5.29.32", "certificatePolicies", OID_FLAG_SKIP}, { "2.5.29.32.0", "anyPolicy" }, { "2.5.29.33", "policyMappings" }, - { "2.5.29.35", "authorityKeyIdentifier", 1 }, + { "2.5.29.35", "authorityKeyIdentifier", OID_FLAG_SKIP}, { "2.5.29.36", "policyConstraints" }, - { "2.5.29.37", "extKeyUsage", 1 }, + { "2.5.29.37", "extKeyUsage", OID_FLAG_SKIP}, { "2.5.29.46", "freshestCRL" }, { "2.5.29.54", "inhibitAnyPolicy" }, @@ -561,6 +572,59 @@ print_names_raw (estream_t fp, int indent, ksba_name_t name) } +static void +print_utf8_extn_raw (estream_t fp, int indent, + const unsigned char *der, size_t derlen) +{ + gpg_error_t err; + int class, tag, constructed, ndef; + size_t objlen, hdrlen; + + if (indent < 0) + indent = - indent; + + err = parse_ber_header (&der, &derlen, &class, &tag, &constructed, + &ndef, &objlen, &hdrlen); + if (!err && (objlen > derlen || tag != TAG_UTF8_STRING)) + err = gpg_error (GPG_ERR_INV_OBJ); + if (err) + { + es_fprintf (fp, "%*s[%s]\n", indent, "", gpg_strerror (err)); + return; + } + es_fprintf (fp, "%*s(%.*s)\n", indent, "", objlen, der); +} + + +static void +print_utf8_extn (estream_t fp, int indent, + const unsigned char *der, size_t derlen) +{ + gpg_error_t err; + int class, tag, constructed, ndef; + size_t objlen, hdrlen; + int indent_all; + + if ((indent_all = (indent < 0))) + indent = - indent; + + err = parse_ber_header (&der, &derlen, &class, &tag, &constructed, + &ndef, &objlen, &hdrlen); + if (!err && (objlen > derlen || tag != TAG_UTF8_STRING)) + err = gpg_error (GPG_ERR_INV_OBJ); + if (err) + { + es_fprintf (fp, "%*s[Error - %s]\n", + indent_all? indent:0, "", gpg_strerror (err)); + return; + } + es_fprintf (fp, "%*s\"", indent_all? indent:0, ""); + /* Fixme: we should implement word wrapping */ + es_write_sanitized (fp, der, objlen, "\"", NULL); + es_fputs ("\"\n", fp); +} + + /* List one certificate in raw mode useful to have a closer look at the certificate. This one does no beautification and only minimal output sanitation. It is mainly useful for debugging. */ @@ -581,6 +645,7 @@ list_cert_raw (ctrl_t ctrl, KEYDB_HANDLE hd, const char *oid, *s; ksba_name_t name, name2; unsigned int reason; + const unsigned char *cert_der = NULL; es_fprintf (fp, " ID: 0x%08lX\n", gpgsm_get_short_fingerprint (cert)); @@ -892,11 +957,19 @@ list_cert_raw (ctrl_t ctrl, KEYDB_HANDLE hd, unsigned int flag; s = get_oid_desc (oid, &flag); + if ((flag & OID_FLAG_SKIP)) + continue; - if (!(flag & 1)) - es_fprintf (fp, " %s: %s%s%s%s [%d octets]\n", - i? "critExtn":" extn", - oid, s?" (":"", s?s:"", s?")":"", (int)len); + es_fprintf (fp, " %s: %s%s%s%s [%d octets]\n", + i? "critExtn":" extn", + oid, s?" (":"", s?s:"", s?")":"", (int)len); + if ((flag & OID_FLAG_UTF8)) + { + if (!cert_der) + cert_der = ksba_cert_get_image (cert, NULL); + assert (cert_der); + print_utf8_extn_raw (fp, -15, cert_der+off, len); + } } @@ -938,6 +1011,10 @@ list_cert_std (ctrl_t ctrl, ksba_cert_t cert, estream_t fp, int have_secret, int is_ca, chainlen; unsigned int kusage; char *string, *p, *pend; + size_t off, len; + const char *oid; + const unsigned char *cert_der = NULL; + es_fprintf (fp, " ID: 0x%08lX\n", gpgsm_get_short_fingerprint (cert)); @@ -1053,6 +1130,21 @@ list_cert_std (ctrl_t ctrl, ksba_cert_t cert, estream_t fp, int have_secret, es_putc ('\n', fp); } + /* Print restrictions. */ + for (idx=0; !(err=ksba_cert_get_extension (cert, idx, + &oid, NULL, &off, &len));idx++) + { + if (!strcmp (oid, OIDSTR_restriction) ) + { + if (!cert_der) + cert_der = ksba_cert_get_image (cert, NULL); + assert (cert_der); + es_fputs (" restriction: ", fp); + print_utf8_extn (fp, 15, cert_der+off, len); + } + } + + /* Print policies. */ err = ksba_cert_get_cert_policies (cert, &string); if (gpg_err_code (err) != GPG_ERR_NO_DATA) { diff --git a/sm/qualified.c b/sm/qualified.c index 507c1517f..d90272804 100644 --- a/sm/qualified.c +++ b/sm/qualified.c @@ -215,7 +215,6 @@ gpgsm_qualified_consent (ctrl_t ctrl, ksba_cert_t cert) err = 0; i18n_switchback (orig_codeset); - xfree (orig_codeset); xfree (subject); if (err) diff --git a/sm/sign.c b/sm/sign.c index a6d02e929..fadd66469 100644 --- a/sm/sign.c +++ b/sm/sign.c @@ -1,5 +1,5 @@ /* sign.c - Sign a message - * Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc. + * Copyright (C) 2001, 2002, 2003, 2008 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -396,6 +396,44 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist, release_signerlist = 1; } + /* Figure out the hash algorithm to use. We do not want to use the + one for the certificate but if possible an OID for the plain + algorithm. */ + for (i=0, cl=signerlist; cl; cl = cl->next, i++) + { + const char *oid = ksba_cert_get_digest_algo (cl->cert); + + cl->hash_algo = oid ? gcry_md_map_name (oid) : 0; + switch (cl->hash_algo) + { + case GCRY_MD_SHA1: oid = "1.3.14.3.2.26"; break; + case GCRY_MD_RMD160: oid = "1.3.36.3.2.1"; break; + case GCRY_MD_SHA224: oid = "2.16.840.1.101.3.4.2.4"; break; + case GCRY_MD_SHA256: oid = "2.16.840.1.101.3.4.2.1"; break; + case GCRY_MD_SHA384: oid = "2.16.840.1.101.3.4.2.2"; break; + case GCRY_MD_SHA512: oid = "2.16.840.1.101.3.4.2.3"; break; +/* case GCRY_MD_WHIRLPOOL: oid = "No OID yet"; break; */ + + case GCRY_MD_MD5: /* We don't want to use MD5. */ + case 0: /* No algorithm found in cert. */ + default: /* Other algorithms. */ + log_info (_("hash algorithm %d (%s) for signer %d not supported;" + " using %s\n"), + cl->hash_algo, oid? oid: "?", i, + gcry_md_algo_name (GCRY_MD_SHA1)); + cl->hash_algo = GCRY_MD_SHA1; + oid = "1.3.14.3.2.26"; + break; + } + cl->hash_algo_oid = oid; + } + if (opt.verbose) + { + for (i=0, cl=signerlist; cl; cl = cl->next, i++) + log_info (_("hash algorithm used for signer %d: %s (%s)\n"), + i, gcry_md_algo_name (cl->hash_algo), cl->hash_algo_oid); + } + /* Gather certificates of signers and store them in the CMS object. */ for (cl=signerlist; cl; cl = cl->next) @@ -419,7 +457,7 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist, goto leave; } /* Set the hash algorithm we are going to use */ - err = ksba_cms_add_digest_algo (cms, "1.3.14.3.2.26" /*SHA-1*/); + err = ksba_cms_add_digest_algo (cms, cl->hash_algo_oid); if (err) { log_debug ("ksba_cms_add_digest_algo failed: %s\n", @@ -458,7 +496,8 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist, } } - /* Prepare hashing (actually we are figuring out what we have set above)*/ + /* Prepare hashing (actually we are figuring out what we have set + above). */ rc = gcry_md_open (&data_md, 0, 0); if (rc) { @@ -474,10 +513,6 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist, if (!algo) { log_error ("unknown hash algorithm `%s'\n", algoid? algoid:"?"); - if (algoid - && ( !strcmp (algoid, "1.2.840.113549.1.1.2") - ||!strcmp (algoid, "1.2.840.113549.2.2"))) - log_info (_("(this is the MD2 algorithm)\n")); rc = gpg_error (GPG_ERR_BUG); goto leave; } @@ -485,26 +520,23 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist, } if (detached) - { /* we hash the data right now so that we can store the message + { /* We hash the data right now so that we can store the message digest. ksba_cms_build() takes this as an flag that detached data is expected. */ unsigned char *digest; size_t digest_len; - /* Fixme do this for all signers and get the algo to use from - the signer's certificate - does not make much sense, but we - should do this consistent as we have already done it above. */ - algo = GCRY_MD_SHA1; + hash_data (data_fd, data_md); - digest = gcry_md_read (data_md, algo); - digest_len = gcry_md_get_algo_dlen (algo); - if ( !digest || !digest_len) - { - log_error ("problem getting the hash of the data\n"); - rc = gpg_error (GPG_ERR_BUG); - goto leave; - } for (cl=signerlist,signer=0; cl; cl = cl->next, signer++) { + digest = gcry_md_read (data_md, cl->hash_algo); + digest_len = gcry_md_get_algo_dlen (cl->hash_algo); + if ( !digest || !digest_len ) + { + log_error ("problem getting the hash of the data\n"); + rc = gpg_error (GPG_ERR_BUG); + goto leave; + } err = ksba_cms_set_message_digest (cms, signer, digest, digest_len); if (err) { @@ -559,30 +591,26 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist, } if (stopreason == KSBA_SR_BEGIN_DATA) - { /* hash the data and store the message digest */ + { + /* Hash the data and store the message digest. */ unsigned char *digest; size_t digest_len; assert (!detached); - /* Fixme: get the algo to use from the signer's certificate - - does not make much sense, but we should do this - consistent as we have already done it above. Code is - mostly duplicated above. */ - algo = GCRY_MD_SHA1; rc = hash_and_copy_data (data_fd, data_md, writer); if (rc) goto leave; - digest = gcry_md_read (data_md, algo); - digest_len = gcry_md_get_algo_dlen (algo); - if ( !digest || !digest_len) - { - log_error ("problem getting the hash of the data\n"); - rc = gpg_error (GPG_ERR_BUG); - goto leave; - } for (cl=signerlist,signer=0; cl; cl = cl->next, signer++) { + digest = gcry_md_read (data_md, cl->hash_algo); + digest_len = gcry_md_get_algo_dlen (cl->hash_algo); + if ( !digest || !digest_len ) + { + log_error ("problem getting the hash of the data\n"); + rc = gpg_error (GPG_ERR_BUG); + goto leave; + } err = ksba_cms_set_message_digest (cms, signer, digest, digest_len); if (err) @@ -595,11 +623,11 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist, } } else if (stopreason == KSBA_SR_NEED_SIG) - { /* calculate the signature for all signers */ + { + /* Compute the signature for all signers. */ gcry_md_hd_t md; - algo = GCRY_MD_SHA1; - rc = gcry_md_open (&md, algo, 0); + rc = gcry_md_open (&md, 0, 0); if (rc) { log_error ("md_open failed: %s\n", gpg_strerror (rc)); @@ -615,6 +643,13 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist, if (signer) gcry_md_reset (md); + { + certlist_t cl_tmp; + + for (cl_tmp=signerlist; cl_tmp; cl_tmp = cl_tmp->next) + gcry_md_enable (md, cl_tmp->hash_algo); + } + rc = ksba_cms_hash_signed_attrs (cms, signer); if (rc) { @@ -625,7 +660,7 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist, } rc = gpgsm_create_cms_signature (ctrl, cl->cert, - md, algo, &sigval); + md, cl->hash_algo, &sigval); if (rc) { gcry_md_close (md); @@ -656,7 +691,7 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist, rc = asprintf (&buf, "%c %d %d 00 %s %s", detached? 'D':'S', pkalgo, - algo, + cl->hash_algo, signed_at, fpr); }