summaryrefslogtreecommitdiffstats
path: root/sm
diff options
context:
space:
mode:
authorWerner Koch <wk@gnupg.org>2008-06-26 21:09:07 +0200
committerWerner Koch <wk@gnupg.org>2008-06-26 21:09:07 +0200
commita6a9181818d86219da202137c1697b826a3ea151 (patch)
treeeeaf866d273a9308bf19091b06cd248333cc058a /sm
parentg10/ (diff)
downloadgnupg2-a6a9181818d86219da202137c1697b826a3ea151.tar.xz
gnupg2-a6a9181818d86219da202137c1697b826a3ea151.zip
Start support of TCOS 3 cards.
Support restriction attribute. Fix utf-8 printing problems. Use AES by default.
Diffstat (limited to 'sm')
-rw-r--r--sm/ChangeLog13
-rw-r--r--sm/gpgsm.c2
-rw-r--r--sm/gpgsm.h2
-rw-r--r--sm/keylist.c122
-rw-r--r--sm/qualified.c1
-rw-r--r--sm/sign.c113
6 files changed, 197 insertions, 56 deletions
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 <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>
* 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);
}