diff --git a/g10/sig-check.c b/g10/sig-check.c index e7f97de65..4c172d692 100644 --- a/g10/sig-check.c +++ b/g10/sig-check.c @@ -1076,7 +1076,7 @@ check_signature_over_key_or_uid (ctrl_t ctrl, PKT_public_key *signer, * signature packet's data structure. * * TODO: add r_revoked here as well. It has the same problems as - * r_expiredate and r_expired and the cache. */ + * r_expiredate and r_expired and the cache [nw]. Which problems [wk]? */ int check_key_signature2 (ctrl_t ctrl, kbnode_t root, kbnode_t node, PKT_public_key *check_pk, diff --git a/sm/gpgsm.c b/sm/gpgsm.c index 020072a50..b9694b2e9 100644 --- a/sm/gpgsm.c +++ b/sm/gpgsm.c @@ -192,6 +192,8 @@ enum cmd_and_opt_values { oNoRandomSeedFile, oNoCommonCertsImport, oIgnoreCertExtension, + oAuthenticode, + oAttribute, oNoAutostart }; @@ -402,6 +404,8 @@ static ARGPARSE_OPTS opts[] = { ARGPARSE_s_n (oNoCommonCertsImport, "no-common-certs-import", "@"), ARGPARSE_s_s (oIgnoreCertExtension, "ignore-cert-extension", "@"), ARGPARSE_s_n (oNoAutostart, "no-autostart", "@"), + ARGPARSE_s_n (oAuthenticode, "authenticode", "@"), + ARGPARSE_s_s (oAttribute, "attribute", "@"), /* Command aliases. */ ARGPARSE_c (aListKeys, "list-key", "@"), @@ -1460,6 +1464,12 @@ main ( int argc, char **argv) add_to_strlist (&opt.ignored_cert_extensions, pargs.r.ret_str); break; + case oAuthenticode: opt.authenticode = 1; break; + + case oAttribute: + add_to_strlist (&opt.attributes, pargs.r.ret_str); + break; + case oNoAutostart: opt.autostart = 0; break; case oCompliance: diff --git a/sm/gpgsm.h b/sm/gpgsm.h index 7a5e4917d..c15d8dc4f 100644 --- a/sm/gpgsm.h +++ b/sm/gpgsm.h @@ -149,6 +149,21 @@ struct strlist_t ignored_cert_extensions; enum gnupg_compliance_mode compliance; + + /* Enable creation of authenticode signatures. */ + int authenticode; + + /* A list of extra attributes put into a signed data object. For a + * signed each attribute each string has the format: + * :s: + * and for an unsigned attribute + * :u: + * The OID is in the usual dotted decimal for. The HEX_OR_FILENAME + * is either a list of hex digits or a filename with the DER encoded + * value. A filename is detected by the presence of a slash in the + * HEX_OR_FILENAME. The actual value needs to be encoded as a SET OF + * attribute values. */ + strlist_t attributes; } opt; /* Debug values and macros. */ diff --git a/sm/sign.c b/sm/sign.c index 24ecad3d7..0604642b4 100644 --- a/sm/sign.c +++ b/sm/sign.c @@ -302,6 +302,99 @@ add_certificate_list (ctrl_t ctrl, ksba_cms_t cms, ksba_cert_t cert) } +#if KSBA_VERSION_NUMBER >= 0x010400 && 0 /* 1.4.0 */ +static gpg_error_t +add_signed_attribute (ksba_cms_t cms, const char *attrstr) +{ + gpg_error_t err; + char **fields = NULL; + const char *s; + int i; + unsigned char *der = NULL; + size_t derlen; + + fields = strtokenize (attrstr, ":"); + if (!fields) + { + err = gpg_error_from_syserror (); + log_error ("strtokenize failed: %s\n", gpg_strerror (err)); + goto leave; + } + + for (i=0; fields[i]; i++) + ; + if (i != 3) + { + err = gpg_error (GPG_ERR_SYNTAX); + log_error ("invalid attribute specification '%s': %s\n", + attrstr, i < 3 ? "not enough fields":"too many fields"); + goto leave; + } + if (!ascii_strcasecmp (fields[1], "u")) + { + err = 0; + goto leave; /* Skip unsigned attruibutes. */ + } + if (ascii_strcasecmp (fields[1], "s")) + { + err = gpg_error (GPG_ERR_SYNTAX); + log_error ("invalid attribute specification '%s': %s\n", + attrstr, "type is not 's' or 'u'"); + goto leave; + } + /* Check that the OID is valid. */ + err = ksba_oid_from_str (fields[0], &der, &derlen); + if (err) + { + log_error ("invalid attribute specification '%s': %s\n", + attrstr, gpg_strerror (err)); + goto leave; + } + xfree (der); + der = NULL; + + if (strchr (fields[2], '/')) + { + /* FIXME: read from file. */ + } + else /* Directly given in hex. */ + { + for (i=0, s = fields[2]; hexdigitp (s); s++, i++) + ; + if (*s || !i || (i&1)) + { + log_error ("invalid attribute specification '%s': %s\n", + attrstr, "invalid hex encoding of the data"); + err = gpg_error (GPG_ERR_SYNTAX); + goto leave; + } + der = xtrystrdup (fields[2]); + if (!der) + { + err = gpg_error_from_syserror (); + log_error ("malloc failed: %s\n", gpg_strerror (err)); + goto leave; + } + for (s=fields[2], derlen=0; s[0] && s[1]; s += 2) + der[derlen++] = xtoi_2 (s); + } + + /* Store the data in the CMS object for all signers. */ + err = ksba_cms_add_attribute (cms, -1, fields[0], 0, der, derlen); + if (err) + { + log_error ("invalid attribute specification '%s': %s\n", + attrstr, gpg_strerror (err)); + goto leave; + } + + leave: + xfree (der); + xfree (fields); + return err; +} +#endif /*ksba >= 1.4.0 */ + /* Perform a sign operation. @@ -377,10 +470,17 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist, goto leave; } - /* We are going to create signed data with data as encap. content */ + /* We are going to create signed data with data as encap. content. + * In authenticode mode we use spcIndirectDataContext instead. */ err = ksba_cms_set_content_type (cms, 0, KSBA_CT_SIGNED_DATA); if (!err) - err = ksba_cms_set_content_type (cms, 1, KSBA_CT_DATA); + err = ksba_cms_set_content_type + (cms, 1, +#if KSBA_VERSION_NUMBER >= 0x010400 && 0 + opt.authenticode? KSBA_CT_SPC_IND_DATA_CTX : +#endif + KSBA_CT_DATA + ); if (err) { log_debug ("ksba_cms_set_content_type failed: %s\n", @@ -643,6 +743,20 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist, } } + /* We can add signed attributes only when build against libksba 1.4. */ +#if KSBA_VERSION_NUMBER >= 0x010400 && 0 /* 1.4.0 */ + { + strlist_t sl; + + for (sl = opt.attributes; sl; sl = sl->next) + if ((err = add_signed_attribute (cms, sl->d))) + goto leave; + } +#else + log_info ("Note: option --attribute is ignored by this version\n"); +#endif /*ksba >= 1.4.0 */ + + /* We need to write at least a minimal list of our capabilities to try to convince some MUAs to use 3DES and not the crippled RC2. Our list is: