Start support of TCOS 3 cards.

Support restriction attribute.
Fix utf-8 printing problems.
Use AES by default.
This commit is contained in:
Werner Koch 2008-06-26 19:09:07 +00:00
parent b60bfbe25c
commit a6a9181818
14 changed files with 318 additions and 73 deletions

2
NEWS
View File

@ -25,6 +25,8 @@ Noteworthy changes in version 2.0.10 (unreleased)
* New control statement %ask-passphrase for the unattended key * New control statement %ask-passphrase for the unattended key
generation of gpg2. generation of gpg2.
* gpgsm now uses AES by default.
Noteworthy changes in version 2.0.9 (2008-03-26) Noteworthy changes in version 2.0.9 (2008-03-26)
------------------------------------------------ ------------------------------------------------

3
TODO
View File

@ -66,7 +66,8 @@
We should check the card status in open-card to make this smoother. 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 Needs to be integrated with the status file update, though. It is
not a real problem because application will get a card removed 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. ** Add a regression test to check the extkeyusage.

View File

@ -1,3 +1,9 @@
2008-06-26 Werner Koch <wk@g10code.com>
* 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 <marcus@g10code.de> 2008-06-25 Marcus Brinkmann <marcus@g10code.de>
Revert last three changes related to handle translation. Revert last three changes related to handle translation.

View File

@ -3074,7 +3074,7 @@ es_write_sanitized (estream_t ES__RESTRICT stream,
for (; length; length--, p++, count++) for (; length; length--, p++, count++)
{ {
if (*p < 0x20 if (*p < 0x20
|| (*p >= 0x7f && *p < 0xa0) || *p == 0x7f
|| (delimiters || (delimiters
&& (strchr (delimiters, *p) || *p == '\\'))) && (strchr (delimiters, *p) || *p == '\\')))
{ {

View File

@ -1,3 +1,9 @@
2008-06-26 Werner Koch <wk@g10code.com>
* 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 <wk@g10code.com> 2008-06-13 Werner Koch <wk@g10code.com>
* dotlock.c: Reformat code and implement locking for W32. * dotlock.c: Reformat code and implement locking for W32.

View File

@ -406,9 +406,8 @@ print_sanitized_buffer2 (FILE *fp, const void *buffer, size_t length,
for (; length; length--, p++, count++) for (; length; length--, p++, count++)
{ {
/* Fixme: Check whether *p < 0xa0 is correct for utf8 encoding. */
if (*p < 0x20 if (*p < 0x20
|| (*p >= 0x7f && *p < 0xa0) || *p == 0x7f
|| *p == delim || *p == delim
|| *p == delim2 || *p == delim2
|| ((delim || delim2) && *p=='\\')) || ((delim || delim2) && *p=='\\'))

View File

@ -1,3 +1,7 @@
2008-06-25 Werner Koch <wk@g10code.com>
* app-dinsig.c (do_sign): Allow for SHA256.
2008-06-24 Werner Koch <wk@g10code.com> 2008-06-24 Werner Koch <wk@g10code.com>
* app-common.h (app_ctx_s): Renamed reset_mode parameter of * app-common.h (app_ctx_s): Renamed reset_mode parameter of

View File

@ -1,5 +1,5 @@
/* app-dinsig.c - The DINSIG (DIN V 66291-1) card application. /* 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. * 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 */ static unsigned char rmd160_prefix[15] = /* Object ID is 1.3.36.3.2.1 */
{ 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x24, 0x03, { 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x24, 0x03,
0x02, 0x01, 0x05, 0x00, 0x04, 0x14 }; 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 rc;
int fid; int fid;
unsigned char data[35]; /* Must be large enough for a SHA-1 digest unsigned char data[19+32]; /* Must be large enough for a SHA-256 digest
+ the largest OID _prefix above. */ + the largest OID _prefix above. */
int datalen;
if (!keyidstr || !*keyidstr) if (!keyidstr || !*keyidstr)
return gpg_error (GPG_ERR_INV_VALUE); 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); return gpg_error (GPG_ERR_INV_VALUE);
/* Check that the provided ID is vaid. This is not really needed /* 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); return gpg_error (GPG_ERR_NOT_FOUND);
/* Prepare the DER object from INDATA. */ /* 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 /* Alright, the caller was so kind to send us an already
prepared DER object. Check that it is what we want and that 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); return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM);
memcpy (data, indata, indatalen); memcpy (data, indata, indatalen);
} }
else else if (indatalen == 19+32)
{ {
if (hashalgo == GCRY_MD_SHA1) /* Alright, the caller was so kind to send us an already
memcpy (data, sha1_prefix, 15); prepared DER object. Check that it is what we want and that
else if (hashalgo == GCRY_MD_RMD160) it matches the hash algorithm. */
memcpy (data, rmd160_prefix, 15); 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 else
return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM); 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); rc = verify_pin (app, pincb, pincb_arg);
if (!rc) if (!rc)
rc = iso7816_compute_ds (app->slot, data, 35, outdata, outdatalen); rc = iso7816_compute_ds (app->slot, data, datalen, outdata, outdatalen);
return rc; 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 /* Select the DINSIG application on the card in SLOT. This function
must be used before any other DINSIG application functions. */ 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.sign = do_sign;
app->fnc.auth = NULL; app->fnc.auth = NULL;
app->fnc.decipher = NULL; app->fnc.decipher = NULL;
app->fnc.change_pin = NULL; app->fnc.change_pin = NULL /*do_change_pin*/;
app->fnc.check_pin = NULL; app->fnc.check_pin = NULL;
app->force_chv1 = 1; app->force_chv1 = 1;

View File

@ -1,3 +1,16 @@
2008-06-25 Werner Koch <wk@g10code.com>
* 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 <wk@g10code.com> 2008-06-23 Werner Koch <wk@g10code.com>
* encrypt.c (encode_session_key): Replace xmalloc by xtrymalloc. * encrypt.c (encode_session_key): Replace xmalloc by xtrymalloc.

View File

@ -987,7 +987,7 @@ main ( int argc, char **argv)
create_dotlock (NULL); /* register locking cleanup */ create_dotlock (NULL); /* register locking cleanup */
i18n_init(); i18n_init();
opt.def_cipher_algoid = "3DES"; /*des-EDE3-CBC*/ opt.def_cipher_algoid = "AES"; /*des-EDE3-CBC*/
opt.homedir = default_homedir (); opt.homedir = default_homedir ();

View File

@ -207,6 +207,8 @@ struct certlist_s
ksba_cert_t cert; ksba_cert_t cert;
int is_encrypt_to; /* True if the certificate has been set through int is_encrypt_to; /* True if the certificate has been set through
the --encrypto-to option. */ 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; typedef struct certlist_s *certlist_t;

View File

@ -1,6 +1,6 @@
/* keylist.c - Print certificates in various formats. /* keylist.c - Print certificates in various formats.
* Copyright (C) 1998, 1999, 2000, 2001, 2003, * 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. * This file is part of GnuPG.
* *
@ -35,6 +35,7 @@
#include "keydb.h" #include "keydb.h"
#include "../kbx/keybox.h" /* for KEYBOX_FLAG_* */ #include "../kbx/keybox.h" /* for KEYBOX_FLAG_* */
#include "i18n.h" #include "i18n.h"
#include "tlv.h"
struct list_external_parm_s 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. */ /* A table mapping OIDs to a descriptive string. */
static struct static struct
{ {
char *oid; char *oid;
char *name; char *name;
unsigned int flag; unsigned int flag; /* A flag as described above. */
} oidtranstbl[] = { } oidtranstbl[] = {
/* Algorithms. */ /* Algorithms. */
@ -115,6 +122,10 @@ static struct
{ "0.2.262.1.10.12.4", "telesecCRLFilteredExt" }, { "0.2.262.1.10.12.4", "telesecCRLFilteredExt" },
{ "0.2.262.1.10.12.5", "telesecCRLFilterExt"}, { "0.2.262.1.10.12.5", "telesecCRLFilterExt"},
{ "0.2.262.1.10.12.6", "telesecNamingAuthorityExt" }, { "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. */ /* PKIX private extensions. */
{ "1.3.6.1.5.5.7.1.1", "authorityInfoAccess" }, { "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" }, { "1.3.6.1.5.5.7.48.5", "caRepository" },
/* X.509 id-ce */ /* X.509 id-ce */
{ "2.5.29.14", "subjectKeyIdentifier", 1}, { "2.5.29.14", "subjectKeyIdentifier", OID_FLAG_SKIP},
{ "2.5.29.15", "keyUsage", 1 }, { "2.5.29.15", "keyUsage", OID_FLAG_SKIP},
{ "2.5.29.16", "privateKeyUsagePeriod" }, { "2.5.29.16", "privateKeyUsagePeriod" },
{ "2.5.29.17", "subjectAltName", 1 }, { "2.5.29.17", "subjectAltName", OID_FLAG_SKIP},
{ "2.5.29.18", "issuerAltName", 1 }, { "2.5.29.18", "issuerAltName", OID_FLAG_SKIP},
{ "2.5.29.19", "basicConstraints", 1}, { "2.5.29.19", "basicConstraints", OID_FLAG_SKIP},
{ "2.5.29.20", "cRLNumber" }, { "2.5.29.20", "cRLNumber" },
{ "2.5.29.21", "cRLReason" }, { "2.5.29.21", "cRLReason" },
{ "2.5.29.22", "expirationDate" }, { "2.5.29.22", "expirationDate" },
@ -150,13 +161,13 @@ static struct
{ "2.5.29.28", "issuingDistributionPoint" }, { "2.5.29.28", "issuingDistributionPoint" },
{ "2.5.29.29", "certificateIssuer" }, { "2.5.29.29", "certificateIssuer" },
{ "2.5.29.30", "nameConstraints" }, { "2.5.29.30", "nameConstraints" },
{ "2.5.29.31", "cRLDistributionPoints", 1 }, { "2.5.29.31", "cRLDistributionPoints", OID_FLAG_SKIP},
{ "2.5.29.32", "certificatePolicies", 1 }, { "2.5.29.32", "certificatePolicies", OID_FLAG_SKIP},
{ "2.5.29.32.0", "anyPolicy" }, { "2.5.29.32.0", "anyPolicy" },
{ "2.5.29.33", "policyMappings" }, { "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.36", "policyConstraints" },
{ "2.5.29.37", "extKeyUsage", 1 }, { "2.5.29.37", "extKeyUsage", OID_FLAG_SKIP},
{ "2.5.29.46", "freshestCRL" }, { "2.5.29.46", "freshestCRL" },
{ "2.5.29.54", "inhibitAnyPolicy" }, { "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 /* List one certificate in raw mode useful to have a closer look at
the certificate. This one does no beautification and only minimal the certificate. This one does no beautification and only minimal
output sanitation. It is mainly useful for debugging. */ 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; const char *oid, *s;
ksba_name_t name, name2; ksba_name_t name, name2;
unsigned int reason; unsigned int reason;
const unsigned char *cert_der = NULL;
es_fprintf (fp, " ID: 0x%08lX\n", es_fprintf (fp, " ID: 0x%08lX\n",
gpgsm_get_short_fingerprint (cert)); gpgsm_get_short_fingerprint (cert));
@ -892,11 +957,19 @@ list_cert_raw (ctrl_t ctrl, KEYDB_HANDLE hd,
unsigned int flag; unsigned int flag;
s = get_oid_desc (oid, &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",
es_fprintf (fp, " %s: %s%s%s%s [%d octets]\n", i? "critExtn":" extn",
i? "critExtn":" extn", oid, s?" (":"", s?s:"", s?")":"", (int)len);
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; int is_ca, chainlen;
unsigned int kusage; unsigned int kusage;
char *string, *p, *pend; char *string, *p, *pend;
size_t off, len;
const char *oid;
const unsigned char *cert_der = NULL;
es_fprintf (fp, " ID: 0x%08lX\n", es_fprintf (fp, " ID: 0x%08lX\n",
gpgsm_get_short_fingerprint (cert)); 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); 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); err = ksba_cert_get_cert_policies (cert, &string);
if (gpg_err_code (err) != GPG_ERR_NO_DATA) if (gpg_err_code (err) != GPG_ERR_NO_DATA)
{ {

View File

@ -215,7 +215,6 @@ gpgsm_qualified_consent (ctrl_t ctrl, ksba_cert_t cert)
err = 0; err = 0;
i18n_switchback (orig_codeset); i18n_switchback (orig_codeset);
xfree (orig_codeset);
xfree (subject); xfree (subject);
if (err) if (err)

113
sm/sign.c
View File

@ -1,5 +1,5 @@
/* sign.c - Sign a message /* 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. * This file is part of GnuPG.
* *
@ -396,6 +396,44 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist,
release_signerlist = 1; 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. */ /* Gather certificates of signers and store them in the CMS object. */
for (cl=signerlist; cl; cl = cl->next) for (cl=signerlist; cl; cl = cl->next)
@ -419,7 +457,7 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist,
goto leave; goto leave;
} }
/* Set the hash algorithm we are going to use */ /* 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) if (err)
{ {
log_debug ("ksba_cms_add_digest_algo failed: %s\n", 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); rc = gcry_md_open (&data_md, 0, 0);
if (rc) if (rc)
{ {
@ -474,10 +513,6 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist,
if (!algo) if (!algo)
{ {
log_error ("unknown hash algorithm `%s'\n", algoid? algoid:"?"); 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); rc = gpg_error (GPG_ERR_BUG);
goto leave; goto leave;
} }
@ -485,26 +520,23 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist,
} }
if (detached) 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 digest. ksba_cms_build() takes this as an flag that detached
data is expected. */ data is expected. */
unsigned char *digest; unsigned char *digest;
size_t digest_len; 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); 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++) 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); err = ksba_cms_set_message_digest (cms, signer, digest, digest_len);
if (err) if (err)
{ {
@ -559,30 +591,26 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist,
} }
if (stopreason == KSBA_SR_BEGIN_DATA) 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; unsigned char *digest;
size_t digest_len; size_t digest_len;
assert (!detached); 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); rc = hash_and_copy_data (data_fd, data_md, writer);
if (rc) if (rc)
goto leave; 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++) 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, err = ksba_cms_set_message_digest (cms, signer,
digest, digest_len); digest, digest_len);
if (err) if (err)
@ -595,11 +623,11 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist,
} }
} }
else if (stopreason == KSBA_SR_NEED_SIG) else if (stopreason == KSBA_SR_NEED_SIG)
{ /* calculate the signature for all signers */ {
/* Compute the signature for all signers. */
gcry_md_hd_t md; gcry_md_hd_t md;
algo = GCRY_MD_SHA1; rc = gcry_md_open (&md, 0, 0);
rc = gcry_md_open (&md, algo, 0);
if (rc) if (rc)
{ {
log_error ("md_open failed: %s\n", gpg_strerror (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) if (signer)
gcry_md_reset (md); 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); rc = ksba_cms_hash_signed_attrs (cms, signer);
if (rc) if (rc)
{ {
@ -625,7 +660,7 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist,
} }
rc = gpgsm_create_cms_signature (ctrl, cl->cert, rc = gpgsm_create_cms_signature (ctrl, cl->cert,
md, algo, &sigval); md, cl->hash_algo, &sigval);
if (rc) if (rc)
{ {
gcry_md_close (md); 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", rc = asprintf (&buf, "%c %d %d 00 %s %s",
detached? 'D':'S', detached? 'D':'S',
pkalgo, pkalgo,
algo, cl->hash_algo,
signed_at, signed_at,
fpr); fpr);
} }