diff options
Diffstat (limited to 'sm')
-rw-r--r-- | sm/call-agent.c | 2 | ||||
-rw-r--r-- | sm/call-dirmngr.c | 36 | ||||
-rw-r--r-- | sm/certchain.c | 3 | ||||
-rw-r--r-- | sm/certdump.c | 9 | ||||
-rw-r--r-- | sm/certlist.c | 6 | ||||
-rw-r--r-- | sm/decrypt.c | 8 | ||||
-rw-r--r-- | sm/gpgsm.c | 17 | ||||
-rw-r--r-- | sm/gpgsm.h | 8 | ||||
-rw-r--r-- | sm/keydb.c | 28 | ||||
-rw-r--r-- | sm/sign.c | 272 | ||||
-rw-r--r-- | sm/verify.c | 10 |
11 files changed, 362 insertions, 37 deletions
diff --git a/sm/call-agent.c b/sm/call-agent.c index 06319cf62..698039504 100644 --- a/sm/call-agent.c +++ b/sm/call-agent.c @@ -890,6 +890,8 @@ istrusted_status_cb (void *opaque, const char *line) flags->chain_model = 1; else if (has_leading_keyword (line, "qual")) flags->qualified = 1; + else if (has_leading_keyword (line, "de-vs")) + flags->de_vs = 1; } return 0; } diff --git a/sm/call-dirmngr.c b/sm/call-dirmngr.c index cc958ccf8..86beeedc1 100644 --- a/sm/call-dirmngr.c +++ b/sm/call-dirmngr.c @@ -362,7 +362,7 @@ inq_certificate (void *opaque, const char *line) } else { - log_error ("unsupported inquiry '%s'\n", line); + log_error ("unsupported certificate inquiry '%s'\n", line); return gpg_error (GPG_ERR_ASS_UNKNOWN_INQUIRE); } @@ -386,8 +386,8 @@ inq_certificate (void *opaque, const char *line) int err; ksba_cert_t cert; - - err = gpgsm_find_cert (parm->ctrl, line, ski, &cert, 1); + err = gpgsm_find_cert (parm->ctrl, line, ski, &cert, + FIND_CERT_ALLOW_AMBIG|FIND_CERT_WITH_EPHEM); if (err) { log_error ("certificate not found: %s\n", gpg_strerror (err)); @@ -521,6 +521,7 @@ isvalid_status_cb (void *opaque, const char *line) GPG_ERR_CERTIFICATE_REVOKED GPG_ERR_NO_CRL_KNOWN + GPG_ERR_INV_CRL_OBJ GPG_ERR_CRL_TOO_OLD Values for USE_OCSP: @@ -1014,7 +1015,8 @@ run_command_inq_cb (void *opaque, const char *line) if (!*line) return gpg_error (GPG_ERR_ASS_PARAMETER); - err = gpgsm_find_cert (parm->ctrl, line, NULL, &cert, 1); + err = gpgsm_find_cert (parm->ctrl, line, NULL, &cert, + FIND_CERT_ALLOW_AMBIG); if (err) { log_error ("certificate not found: %s\n", gpg_strerror (err)); @@ -1035,9 +1037,33 @@ run_command_inq_cb (void *opaque, const char *line) line = s; log_info ("dirmngr: %s\n", line); } + else if ((s = has_leading_keyword (line, "ISTRUSTED"))) + { + /* The server is asking us whether the certificate is a trusted + root certificate. */ + char fpr[41]; + struct rootca_flags_s rootca_flags; + int n; + + line = s; + + for (s=line,n=0; hexdigitp (s); s++, n++) + ; + if (*s || n != 40) + return gpg_error (GPG_ERR_ASS_PARAMETER); + for (s=line, n=0; n < 40; s++, n++) + fpr[n] = (*s >= 'a')? (*s & 0xdf): *s; + fpr[n] = 0; + + if (!gpgsm_agent_istrusted (parm->ctrl, NULL, fpr, &rootca_flags)) + rc = assuan_send_data (parm->ctx, "1", 1); + else + rc = 0; + return rc; + } else { - log_error ("unsupported inquiry '%s'\n", line); + log_error ("unsupported command inquiry '%s'\n", line); rc = gpg_error (GPG_ERR_ASS_UNKNOWN_INQUIRE); } diff --git a/sm/certchain.c b/sm/certchain.c index cbb6e1127..7b782190b 100644 --- a/sm/certchain.c +++ b/sm/certchain.c @@ -122,6 +122,7 @@ do_list (int is_error, int listmode, estream_t fp, const char *format, ...) } else { + es_fflush (es_stdout); log_logv (is_error? GPGRT_LOGLVL_ERROR: GPGRT_LOGLVL_INFO, format, arg_ptr); log_printf ("\n"); @@ -1480,6 +1481,7 @@ ask_marktrusted (ctrl_t ctrl, ksba_cert_t cert, int listmode) int success = 0; fpr = gpgsm_get_fingerprint_string (cert, GCRY_MD_SHA1); + es_fflush (es_stdout); log_info (_("fingerprint=%s\n"), fpr? fpr : "?"); xfree (fpr); @@ -2277,6 +2279,7 @@ gpgsm_basic_cert_check (ctrl_t ctrl, ksba_cert_t cert) { if (!opt.quiet) { + es_fflush (es_stdout); log_info ("issuer certificate (#/"); gpgsm_dump_string (issuer); log_printf (") not found\n"); diff --git a/sm/certdump.c b/sm/certdump.c index 3ad0edbe3..03bfd4106 100644 --- a/sm/certdump.c +++ b/sm/certdump.c @@ -728,7 +728,14 @@ gpgsm_es_print_name2 (estream_t fp, const char *name, int translate) void gpgsm_es_print_name (estream_t fp, const char *name) { - gpgsm_es_print_name2 (fp, name, 1); + if (opt.no_pretty_dn) + { + if (!name) + name = "[error]"; + es_write_sanitized (fp, name, strlen (name), NULL, NULL); + } + else + gpgsm_es_print_name2 (fp, name, 1); } diff --git a/sm/certlist.c b/sm/certlist.c index b5f9f7874..fdf31a198 100644 --- a/sm/certlist.c +++ b/sm/certlist.c @@ -508,11 +508,12 @@ gpgsm_release_certlist (certlist_t list) int gpgsm_find_cert (ctrl_t ctrl, const char *name, ksba_sexp_t keyid, ksba_cert_t *r_cert, - int allow_ambiguous) + unsigned int flags) { int rc; KEYDB_SEARCH_DESC desc; KEYDB_HANDLE kh = NULL; + int allow_ambiguous = (flags & FIND_CERT_ALLOW_AMBIG); *r_cert = NULL; rc = classify_user_id (name, &desc, 0); @@ -523,6 +524,9 @@ gpgsm_find_cert (ctrl_t ctrl, rc = gpg_error (GPG_ERR_ENOMEM); else { + if ((flags & FIND_CERT_WITH_EPHEM)) + keydb_set_ephemeral (kh, 1); + nextone: rc = keydb_search (ctrl, kh, &desc, 1); if (!rc) diff --git a/sm/decrypt.c b/sm/decrypt.c index 3702cd893..68b362b45 100644 --- a/sm/decrypt.c +++ b/sm/decrypt.c @@ -37,14 +37,6 @@ #include "../common/tlv.h" #include "../common/compliance.h" -/* We can provide an enum value which is only availabale with KSBA - * 1.6.0 so that we can compile even against older versions. Some - * calls will of course return an error in this case. This value is - * currently not used because the cipher mode is sufficient here. */ -/* #if KSBA_VERSION_NUMBER < 0x010600 /\* 1.6.0 *\/ */ -/* # define KSBA_CT_AUTHENVELOPED_DATA 10 */ -/* #endif */ - struct decrypt_filter_parm_s { diff --git a/sm/gpgsm.c b/sm/gpgsm.c index f8b3856c2..aeb6ad7a9 100644 --- a/sm/gpgsm.c +++ b/sm/gpgsm.c @@ -114,6 +114,7 @@ enum cmd_and_opt_values { oNoLogFile, oAuditLog, oHtmlAuditLog, + oLogTime, oEnableSpecialFilenames, @@ -169,6 +170,7 @@ enum cmd_and_opt_values { oWithKeyScreening, oAnswerYes, oAnswerNo, + oNoPrettyDN, oKeyring, oDefaultKey, oDefRecipient, @@ -288,6 +290,7 @@ static gpgrt_opt_t opts[] = { N_("|FILE|write server mode logs to FILE")), ARGPARSE_s_n (oNoLogFile, "no-log-file", "@"), ARGPARSE_s_i (oLoggerFD, "logger-fd", "@"), + ARGPARSE_s_n (oLogTime, "log-time", "@"), ARGPARSE_s_n (oNoSecmemWarn, "no-secmem-warning", "@"), @@ -383,7 +386,7 @@ static gpgrt_opt_t opts[] = { ARGPARSE_s_n (oWithKeygrip, "with-keygrip", "@"), ARGPARSE_s_n (oWithSecret, "with-secret", "@"), ARGPARSE_s_n (oWithKeyScreening,"with-key-screening", "@"), - + ARGPARSE_s_n (oNoPrettyDN, "no-pretty-dn", "@"), ARGPARSE_header ("Security", N_("Options controlling the security")), @@ -499,6 +502,9 @@ static int maybe_setuid = 1; static const char *debug_level; static unsigned int debug_value; +/* Helper for --log-time; */ +static int opt_log_time; + /* Default value for include-certs. We need an extra macro for gpgconf-list because the variable will be changed by the command line option. @@ -1247,6 +1253,7 @@ main ( int argc, char **argv) case oLogFile: logfile = pargs.r.ret_str; break; case oNoLogFile: logfile = NULL; break; + case oLogTime: opt_log_time = 1; break; case oAuditLog: auditlog = pargs.r.ret_str; break; case oHtmlAuditLog: htmlauditlog = pargs.r.ret_str; break; @@ -1312,6 +1319,10 @@ main ( int argc, char **argv) opt.with_key_screening = 1; break; + case oNoPrettyDN: + opt.no_pretty_dn = 1; + break; + case oHomedir: gnupg_set_homedir (pargs.r.ret_str); break; case oChUid: break; /* Command line only (see above). */ case oAgentProgram: opt.agent_program = pargs.r.ret_str; break; @@ -1579,6 +1590,10 @@ main ( int argc, char **argv) log_set_file (logfile); log_set_prefix (NULL, GPGRT_LOG_WITH_PREFIX | GPGRT_LOG_WITH_TIME | GPGRT_LOG_WITH_PID); } + else if (opt_log_time) + log_set_prefix (NULL, (GPGRT_LOG_WITH_PREFIX|GPGRT_LOG_NO_REGISTRY + |GPGRT_LOG_WITH_TIME)); + if (gnupg_faked_time_p ()) { diff --git a/sm/gpgsm.h b/sm/gpgsm.h index ced2d679f..cef39ff2a 100644 --- a/sm/gpgsm.h +++ b/sm/gpgsm.h @@ -85,6 +85,8 @@ struct int with_key_screening; /* Option --with-key-screening active. */ + int no_pretty_dn; /* Option --no-pretty-dn */ + int pinentry_mode; int request_origin; @@ -293,6 +295,7 @@ struct rootca_flags_s unsigned int relax:1; /* Relax checking of root certificates. */ unsigned int chain_model:1; /* Root requires the use of the chain model. */ unsigned int qualified:1; /* Root CA used for qualfied signatures. */ + unsigned int de_vs:1; /* Root CA is de-vs compliant. */ }; @@ -404,8 +407,11 @@ int gpgsm_add_cert_to_certlist (ctrl_t ctrl, ksba_cert_t cert, int gpgsm_add_to_certlist (ctrl_t ctrl, const char *name, int secret, certlist_t *listaddr, int is_encrypt_to); void gpgsm_release_certlist (certlist_t list); + +#define FIND_CERT_ALLOW_AMBIG 1 +#define FIND_CERT_WITH_EPHEM 2 int gpgsm_find_cert (ctrl_t ctrl, const char *name, ksba_sexp_t keyid, - ksba_cert_t *r_cert, int allow_ambiguous); + ksba_cert_t *r_cert, unsigned int flags); /*-- keylist.c --*/ gpg_error_t gpgsm_list_keys (ctrl_t ctrl, strlist_t names, diff --git a/sm/keydb.c b/sm/keydb.c index fbe28f2b9..a12dba19f 100644 --- a/sm/keydb.c +++ b/sm/keydb.c @@ -33,6 +33,7 @@ #include "keydb.h" #include "../common/i18n.h" #include "../common/asshelp.h" +#include "../common/comopt.h" #include "../kbx/kbx-client-util.h" @@ -242,8 +243,23 @@ maybe_create_keybox (char *filename, int force, int *r_created) *last_slash_in_filename = save_slash; goto leave; } + *last_slash_in_filename = save_slash; + + if (!opt.use_keyboxd + && !parse_comopt (GNUPG_MODULE_NAME_GPG, 0) + && comopt.use_keyboxd) + { + /* The above try_make_homedir created a new default hoemdir + * and also wrote a new common.conf. Thus we now see that + * use-keyboxd has been set. Let's set this option and + * return a dedicated error code. */ + opt.use_keyboxd = comopt.use_keyboxd; + rc = gpg_error (GPG_ERR_TRUE); + goto leave; + } } - *last_slash_in_filename = save_slash; + else + *last_slash_in_filename = save_slash; /* To avoid races with other instances of gpg trying to create or update the keybox (it is removed during an update for a short @@ -459,9 +475,13 @@ keydb_add_resource (ctrl_t ctrl, const char *url, int force, int *auto_created) leave: if (err) { - log_error ("keyblock resource '%s': %s\n", filename, gpg_strerror (err)); - gpgsm_status_with_error (ctrl, STATUS_ERROR, - "add_keyblock_resource", err); + if (gpg_err_code (err) != GPG_ERR_TRUE) + { + log_error ("keyblock resource '%s': %s\n", + filename, gpg_strerror (err)); + gpgsm_status_with_error (ctrl, STATUS_ERROR, + "add_keyblock_resource", err); + } } else any_registered = 1; @@ -1,6 +1,8 @@ /* sign.c - Sign a message * Copyright (C) 2001, 2002, 2003, 2008, * 2010 Free Software Foundation, Inc. + * Copyright (C) 2003-2012, 2016-2017, 2019, + * 2020, 2022-2023 g10 Code GmbH * * This file is part of GnuPG. * @@ -16,6 +18,7 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, see <https://www.gnu.org/licenses/>. + * SPDX-License-Identifier: GPL-3.0-or-later */ #include <config.h> @@ -32,6 +35,7 @@ #include "keydb.h" #include "../common/i18n.h" +#include "../common/tlv.h" /* Hash the data and return if something was hashed. Return -1 on error. */ @@ -300,7 +304,6 @@ 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) { @@ -378,7 +381,12 @@ add_signed_attribute (ksba_cms_t cms, const char *attrstr) } /* Store the data in the CMS object for all signers. */ +#if 0 err = ksba_cms_add_attribute (cms, -1, fields[0], 0, der, derlen); +#else + (void)cms; + err = gpg_error (GPG_ERR_NOT_IMPLEMENTED); +#endif if (err) { log_error ("invalid attribute specification '%s': %s\n", @@ -391,7 +399,218 @@ add_signed_attribute (ksba_cms_t cms, const char *attrstr) xfree (fields); return err; } -#endif /*ksba >= 1.4.0 */ + + + +/* This function takes a binary detached signature in (BLOB,BLOBLEN) + * and writes it to OUT_FP. The core of the function is to replace + * NDEF length sequences in the input to those with fixed inputs. + * This helps certain other implementations to properly verify + * detached signature. Moreover, it allows our own trailing zero + * stripping code - which we need for PDF signatures - to work + * correctly. + * + * Example start of a detached signature as created by us: + * 0 NDEF: SEQUENCE { -- 1st sequence + * 2 9: OBJECT IDENTIFIER signedData (1 2 840 113549 1 7 2) + * 13 NDEF: [0] { -- 2nd sequence + * 15 NDEF: SEQUENCE { -- 3rd sequence + * 17 1: INTEGER 1 -- version + * 20 15: SET { -- set of algorithms + * 22 13: SEQUENCE { + * 24 9: OBJECT IDENTIFIER sha-256 (2 16 840 1 101 3 4 2 1) + * 35 0: NULL + * : } + * : } + * 37 NDEF: SEQUENCE { -- 4th pretty short sequence + * 39 9: OBJECT IDENTIFIER data (1 2 840 113549 1 7 1) + * : } + * 52 869: [0] { + * Our goal is to replace the NDEF by fixed length tags. + */ +static gpg_error_t +write_detached_signature (ctrl_t ctrl, const void *blob, size_t bloblen, + estream_t out_fp) +{ + gpg_error_t err; + const unsigned char *p; + size_t n, objlen, hdrlen; + int class, tag, cons, ndef; + const unsigned char *p_ctoid, *p_version, *p_algoset, *p_dataoid; + size_t n_ctoid, n_version, n_algoset, n_dataoid; + const unsigned char *p_certset, *p_signerinfos; + size_t n_certset, n_signerinfos; + int i; + ksba_der_t dbld; + unsigned char *finalder = NULL; + size_t finalderlen; + + (void)ctrl; + + p = blob; + n = bloblen; + if ((err=parse_ber_header (&p,&n,&class,&tag,&cons,&ndef,&objlen,&hdrlen))) + return err; + if (!(class == CLASS_UNIVERSAL && tag == TAG_SEQUENCE && cons)) + return gpg_error (GPG_ERR_INV_CMS_OBJ); /* No 1st sequence. */ + + if ((err=parse_ber_header (&p,&n,&class,&tag,&cons,&ndef,&objlen,&hdrlen))) + return err; + if (!(class == CLASS_UNIVERSAL && tag == TAG_OBJECT_ID && !cons)) + return gpg_error (GPG_ERR_INV_CMS_OBJ); /* No signedData OID. */ + if (objlen > n) + return gpg_error (GPG_ERR_BAD_BER); /* Object larger than data. */ + p_ctoid = p; + n_ctoid = objlen; + p += objlen; + n -= objlen; + + if ((err=parse_ber_header (&p,&n,&class,&tag,&cons,&ndef,&objlen,&hdrlen))) + return err; + if (!(class == CLASS_CONTEXT && tag == 0 && cons)) + return gpg_error (GPG_ERR_INV_CMS_OBJ); /* No 2nd sequence. */ + + if ((err=parse_ber_header (&p,&n,&class,&tag,&cons,&ndef,&objlen,&hdrlen))) + return err; + if (!(class == CLASS_UNIVERSAL && tag == TAG_SEQUENCE && cons)) + return gpg_error (GPG_ERR_INV_CMS_OBJ); /* No 3rd sequence. */ + + if ((err=parse_ber_header (&p,&n,&class,&tag,&cons,&ndef,&objlen,&hdrlen))) + return err; + if (!(class == CLASS_UNIVERSAL && tag == TAG_INTEGER)) + return gpg_error (GPG_ERR_INV_CMS_OBJ); /* No version. */ + if (objlen > n) + return gpg_error (GPG_ERR_BAD_BER); /* Object larger than data. */ + p_version = p; + n_version = objlen; + p += objlen; + n -= objlen; + + p_algoset = p; + if ((err=parse_ber_header (&p,&n,&class,&tag,&cons,&ndef,&objlen,&hdrlen))) + return err; + if (!(class == CLASS_UNIVERSAL && tag == TAG_SET && cons && !ndef)) + return gpg_error (GPG_ERR_INV_CMS_OBJ); /* No set of algorithms. */ + if (objlen > n) + return gpg_error (GPG_ERR_BAD_BER); /* Object larger than data. */ + n_algoset = hdrlen + objlen; + p += objlen; + n -= objlen; + + if ((err=parse_ber_header (&p,&n,&class,&tag,&cons,&ndef,&objlen,&hdrlen))) + return err; + if (!(class == CLASS_UNIVERSAL && tag == TAG_SEQUENCE && cons)) + return gpg_error (GPG_ERR_INV_CMS_OBJ); /* No 4th sequence. */ + + if ((err=parse_ber_header (&p,&n,&class,&tag,&cons,&ndef,&objlen,&hdrlen))) + return err; + if (!(class == CLASS_UNIVERSAL && tag == TAG_OBJECT_ID && !cons)) + return gpg_error (GPG_ERR_INV_CMS_OBJ); /* No data OID. */ + if (objlen > n) + return gpg_error (GPG_ERR_BAD_BER); /* Object larger than data. */ + p_dataoid = p; + n_dataoid = objlen; + p += objlen; + n -= objlen; + + if ((err=parse_ber_header (&p,&n,&class,&tag,&cons,&ndef,&objlen,&hdrlen))) + return err; + if (!(class == CLASS_UNIVERSAL && tag == TAG_NONE && !cons && !objlen)) + return gpg_error (GPG_ERR_INV_CMS_OBJ); /* No End tag. */ + + /* certificates [0] IMPLICIT CertificateSet OPTIONAL, + * Note: We ignore the following + * crls [1] IMPLICIT CertificateRevocationLists OPTIONAL + * because gpgsm does not create them. */ + if ((err=parse_ber_header (&p,&n,&class,&tag,&cons,&ndef,&objlen,&hdrlen))) + return err; + if (class == CLASS_CONTEXT && tag == 0 && cons) + { + if (objlen > n) + return gpg_error (GPG_ERR_BAD_BER); /* Object larger than data. */ + p_certset = p; + n_certset = objlen; + p += objlen; + n -= objlen; + if ((err=parse_ber_header (&p,&n,&class,&tag,&cons,&ndef, + &objlen,&hdrlen))) + return err; + } + else + { + p_certset = NULL; + n_certset = 0; + } + + /* SignerInfos ::= SET OF SignerInfo */ + if (!(class == CLASS_UNIVERSAL && tag == TAG_SET && cons && !ndef)) + return gpg_error (GPG_ERR_INV_CMS_OBJ); /* No set of signerInfos. */ + if (objlen > n) + return gpg_error (GPG_ERR_BAD_BER); /* Object larger than data. */ + p_signerinfos = p; + n_signerinfos = objlen; + p += objlen; + n -= objlen; + + /* For the fun of it check the 3 end tags. */ + for (i=0; i < 3; i++) + { + if ((err=parse_ber_header (&p,&n,&class,&tag,&cons,&ndef, + &objlen,&hdrlen))) + return err; + if (!(class == CLASS_UNIVERSAL && tag == TAG_NONE && !cons && !objlen)) + return gpg_error (GPG_ERR_INV_CMS_OBJ); /* No End tag. */ + } + if (n) + return gpg_error (GPG_ERR_INV_CMS_OBJ); /* Garbage */ + + /*---- From here on we jump to leave on error. ----*/ + + /* Now create a new object from the collected data. */ + dbld = ksba_der_builder_new (16); /* (pre-allocate 16 items) */ + if (!dbld) + { + err = gpg_error_from_syserror (); + goto leave; + } + ksba_der_add_tag (dbld, 0, KSBA_TYPE_SEQUENCE); + ksba_der_add_val ( dbld, 0, KSBA_TYPE_OBJECT_ID, p_ctoid, n_ctoid); + ksba_der_add_tag ( dbld, KSBA_CLASS_CONTEXT, 0); + ksba_der_add_tag ( dbld, 0, KSBA_TYPE_SEQUENCE); + ksba_der_add_val ( dbld, 0, KSBA_TYPE_INTEGER, p_version, n_version); + ksba_der_add_der ( dbld, p_algoset, n_algoset); + ksba_der_add_tag ( dbld, 0, KSBA_TYPE_SEQUENCE); + ksba_der_add_val ( dbld, 0, KSBA_TYPE_OBJECT_ID, p_dataoid, n_dataoid); + ksba_der_add_end ( dbld); + if (p_certset) + { + ksba_der_add_tag ( dbld, KSBA_CLASS_CONTEXT, 0); + ksba_der_add_der ( dbld, p_certset, n_certset); + ksba_der_add_end ( dbld); + } + ksba_der_add_tag ( dbld, 0, KSBA_TYPE_SET); + ksba_der_add_der ( dbld, p_signerinfos, n_signerinfos); + ksba_der_add_end ( dbld); + ksba_der_add_end ( dbld); + ksba_der_add_end ( dbld); + ksba_der_add_end (dbld); + + err = ksba_der_builder_get (dbld, &finalder, &finalderlen); + if (err) + goto leave; + + if (es_fwrite (finalder, finalderlen, 1, out_fp) != 1) + { + err = gpg_error_from_syserror (); + goto leave; + } + + + leave: + ksba_der_release (dbld); + ksba_free (finalder); + return err; +} @@ -409,6 +628,7 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist, gpg_error_t err; gnupg_ksba_io_t b64writer = NULL; ksba_writer_t writer; + estream_t sig_fp = NULL; /* Used for detached signatures. */ ksba_cms_t cms = NULL; ksba_stop_reason_t stopreason; KEYDB_HANDLE kh = NULL; @@ -419,6 +639,7 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist, ksba_isotime_t signed_at; certlist_t cl; int release_signerlist = 0; + int binary_detached = detached && !ctrl->create_pem && !ctrl->create_base64; audit_set_type (ctrl->audit, AUDIT_TYPE_SIGN); @@ -441,11 +662,25 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist, goto leave; } + /* Note that in detached mode the b64 write is actually a binary + * writer because we need to fixup the created signature later. + * Note that we do this only for binary output because we have no + * PEM writer interface outside of the ksba create writer code. */ ctrl->pem_name = "SIGNED MESSAGE"; - rc = gnupg_ksba_create_writer - (&b64writer, ((ctrl->create_pem? GNUPG_KSBA_IO_PEM : 0) - | (ctrl->create_base64? GNUPG_KSBA_IO_BASE64 : 0)), - ctrl->pem_name, out_fp, &writer); + if (binary_detached) + { + sig_fp = es_fopenmem (0, "w+"); + rc = sig_fp? 0 : gpg_error_from_syserror (); + if (!rc) + rc = gnupg_ksba_create_writer (&b64writer, 0, NULL, sig_fp, &writer); + } + else + { + rc = gnupg_ksba_create_writer + (&b64writer, ((ctrl->create_pem? GNUPG_KSBA_IO_PEM : 0) + | (ctrl->create_base64? GNUPG_KSBA_IO_BASE64 : 0)), + ctrl->pem_name, out_fp, &writer); + } if (rc) { log_error ("can't create writer: %s\n", gpg_strerror (rc)); @@ -474,9 +709,7 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist, if (!err) 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) @@ -758,8 +991,6 @@ 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; @@ -767,10 +998,6 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist, if ((err = add_signed_attribute (cms, sl->d))) goto leave; } -#else - if (opt.attributes) - 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 @@ -949,6 +1176,22 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist, goto leave; } + if (binary_detached) + { + void *blob = NULL; + size_t bloblen; + + rc = es_fclose_snatch (sig_fp, &blob, &bloblen); + sig_fp = NULL; + if (rc) + goto leave; + rc = write_detached_signature (ctrl, blob, bloblen, out_fp); + xfree (blob); + if (rc) + goto leave; + } + + audit_log (ctrl->audit, AUDIT_SIGNING_DONE); log_info ("signature created\n"); @@ -962,5 +1205,6 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist, gnupg_ksba_destroy_writer (b64writer); keydb_release (kh); gcry_md_close (data_md); + es_fclose (sig_fp); return rc; } diff --git a/sm/verify.c b/sm/verify.c index 9f1216f83..a07d1c9c7 100644 --- a/sm/verify.c +++ b/sm/verify.c @@ -105,12 +105,17 @@ gpgsm_verify (ctrl_t ctrl, int in_fd, int data_fd, estream_t out_fp) int signer; const char *algoid; int algo; - int is_detached; + int is_detached, maybe_detached; estream_t in_fp = NULL; char *p; audit_set_type (ctrl->audit, AUDIT_TYPE_VERIFY); + /* Although we detect detached signatures during the parsing phase, + * we need to know it earlier and thus accept the caller idea of + * what to verify. */ + maybe_detached = (data_fd != -1); + kh = keydb_new (ctrl); if (!kh) { @@ -131,7 +136,8 @@ gpgsm_verify (ctrl_t ctrl, int in_fd, int data_fd, estream_t out_fp) rc = gnupg_ksba_create_reader (&b64reader, ((ctrl->is_pem? GNUPG_KSBA_IO_PEM : 0) | (ctrl->is_base64? GNUPG_KSBA_IO_BASE64 : 0) - | (ctrl->autodetect_encoding? GNUPG_KSBA_IO_AUTODETECT : 0)), + | (ctrl->autodetect_encoding? GNUPG_KSBA_IO_AUTODETECT : 0) + | (maybe_detached? GNUPG_KSBA_IO_STRIP : 0)), in_fp, &reader); if (rc) { |