diff options
Diffstat (limited to 'sm/sign.c')
-rw-r--r-- | sm/sign.c | 478 |
1 files changed, 369 insertions, 109 deletions
@@ -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> @@ -33,6 +36,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. */ @@ -293,7 +297,7 @@ add_certificate_list (ctrl_t ctrl, ksba_cms_t cms, ksba_cert_t cert) } ksba_cert_release (cert); - return rc == -1? 0: rc; + return gpg_err_code (rc) == GPG_ERR_NOT_FOUND? 0 : rc; ksba_failure: ksba_cert_release (cert); @@ -304,6 +308,215 @@ add_certificate_list (ctrl_t ctrl, ksba_cms_t cms, ksba_cert_t cert) +/* 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 (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; + + 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; +} + + + /* Perform a sign operation. Sign the data received on DATA-FD in embedded mode or in detached @@ -314,10 +527,11 @@ int gpgsm_sign (ctrl_t ctrl, certlist_t signerlist, int data_fd, int detached, estream_t out_fp) { - int i, rc; gpg_error_t err; + int i; 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; @@ -328,6 +542,8 @@ 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; + char *curve = NULL; audit_set_type (ctrl->audit, AUDIT_TYPE_SIGN); @@ -335,45 +551,59 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist, if (!kh) { log_error (_("failed to allocate keyDB handle\n")); - rc = gpg_error (GPG_ERR_GENERAL); + err = gpg_error (GPG_ERR_GENERAL); goto leave; } if (!gnupg_rng_is_compliant (opt.compliance)) { - rc = gpg_error (GPG_ERR_FORBIDDEN); + err = gpg_error (GPG_ERR_FORBIDDEN); log_error (_("%s is not compliant with %s mode\n"), "RNG", gnupg_compliance_option_string (opt.compliance)); gpgsm_status_with_error (ctrl, STATUS_ERROR, - "random-compliance", rc); + "random-compliance", err); 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 (rc) + if (binary_detached) { - log_error ("can't create writer: %s\n", gpg_strerror (rc)); - goto leave; + sig_fp = es_fopenmem (0, "w+"); + err = sig_fp? 0 : gpg_error_from_syserror (); + if (!err) + err = gnupg_ksba_create_writer (&b64writer, 0, NULL, sig_fp, &writer); + } + else + { + err = 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); } - - err = ksba_cms_new (&cms); if (err) { - rc = err; + log_error ("can't create writer: %s\n", gpg_strerror (err)); goto leave; } + gnupg_ksba_set_progress_cb (b64writer, gpgsm_progress_cb, ctrl); + if (ctrl->input_size_hint) + gnupg_ksba_set_total (b64writer, ctrl->input_size_hint); + + err = ksba_cms_new (&cms); + if (err) + goto leave; + err = ksba_cms_set_reader_writer (cms, NULL, writer); if (err) { log_debug ("ksba_cms_set_reader_writer failed: %s\n", gpg_strerror (err)); - rc = err; goto leave; } @@ -385,7 +615,6 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist, { log_debug ("ksba_cms_set_content_type failed: %s\n", gpg_strerror (err)); - rc = err; goto leave; } @@ -398,22 +627,23 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist, log_error ("no default signer found\n"); gpgsm_status2 (ctrl, STATUS_INV_SGNR, get_inv_recpsgnr_code (GPG_ERR_NO_SECKEY), NULL); - rc = gpg_error (GPG_ERR_GENERAL); + err = gpg_error (GPG_ERR_GENERAL); goto leave; } /* Although we don't check for ambiguous specification we will check that the signer's certificate is usable and valid. */ - rc = gpgsm_cert_use_sign_p (cert, 0); - if (!rc) - rc = gpgsm_validate_chain (ctrl, cert, "", NULL, 0, NULL, 0, NULL); - if (rc) + err = gpgsm_cert_use_sign_p (cert, 0); + if (!err) + err = gpgsm_validate_chain (ctrl, cert, + GNUPG_ISOTIME_NONE, NULL, 0, NULL, 0, NULL); + if (err) { char *tmpfpr; tmpfpr = gpgsm_get_fingerprint_hexstring (cert, 0); gpgsm_status2 (ctrl, STATUS_INV_SGNR, - get_inv_recpsgnr_code (rc), tmpfpr, NULL); + get_inv_recpsgnr_code (err), tmpfpr, NULL); xfree (tmpfpr); goto leave; } @@ -422,7 +652,7 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist, signerlist = xtrycalloc (1, sizeof *signerlist); if (!signerlist) { - rc = out_of_core (); + err = gpg_error_from_syserror (); ksba_cert_release (cert); goto leave; } @@ -430,6 +660,7 @@ 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. */ @@ -438,6 +669,12 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist, for (i=0, cl=signerlist; cl; cl = cl->next, i++) { const char *oid; + unsigned int nbits; + int pk_algo; + + xfree (curve); + pk_algo = gpgsm_get_key_algo_info (cl->cert, &nbits, &curve); + cl->pk_algo = pk_algo; if (opt.forced_digest_algo) { @@ -446,7 +683,21 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist, } else { - oid = ksba_cert_get_digest_algo (cl->cert); + if (pk_algo == GCRY_PK_ECC) + { + /* Map the Curve to a corresponding hash algo. */ + if (nbits <= 256) + oid = "2.16.840.1.101.3.4.2.1"; /* sha256 */ + else if (nbits <= 384) + oid = "2.16.840.1.101.3.4.2.2"; /* sha384 */ + else + oid = "2.16.840.1.101.3.4.2.3"; /* sha512 */ + } + else + { + /* For RSA we reuse the hash algo used by the certificate. */ + oid = ksba_cert_get_digest_algo (cl->cert); + } cl->hash_algo = oid ? gcry_md_map_name (oid) : 0; } switch (cl->hash_algo) @@ -457,7 +708,6 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist, 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. */ @@ -482,27 +732,22 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist, goto leave; } - { - unsigned int nbits; - int pk_algo = gpgsm_get_key_algo_info (cl->cert, &nbits); - - if (! gnupg_pk_is_allowed (opt.compliance, PK_USE_SIGNING, pk_algo, 0, - NULL, nbits, NULL)) - { - char kidstr[10+1]; - - snprintf (kidstr, sizeof kidstr, "0x%08lX", - gpgsm_get_short_fingerprint (cl->cert, NULL)); - log_error (_("key %s may not be used for signing in %s mode\n"), - kidstr, - gnupg_compliance_option_string (opt.compliance)); - err = gpg_error (GPG_ERR_PUBKEY_ALGO); - goto leave; - } - } + if (!gnupg_pk_is_allowed (opt.compliance, PK_USE_SIGNING, pk_algo, + PK_ALGO_FLAG_ECC18, NULL, nbits, curve)) + { + char kidstr[10+1]; + + snprintf (kidstr, sizeof kidstr, "0x%08lX", + gpgsm_get_short_fingerprint (cl->cert, NULL)); + log_error (_("key %s may not be used for signing in %s mode\n"), + kidstr, + gnupg_compliance_option_string (opt.compliance)); + err = gpg_error (GPG_ERR_PUBKEY_ALGO); + goto leave; + } } - if (opt.verbose) + if (opt.verbose > 1 || opt.debug) { for (i=0, cl=signerlist; cl; cl = cl->next, i++) log_info (_("hash algorithm used for signer %d: %s (%s)\n"), @@ -513,22 +758,21 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist, /* Gather certificates of signers and store them in the CMS object. */ for (cl=signerlist; cl; cl = cl->next) { - rc = gpgsm_cert_use_sign_p (cl->cert, 0); - if (rc) + err = gpgsm_cert_use_sign_p (cl->cert, 0); + if (err) goto leave; err = ksba_cms_add_signer (cms, cl->cert); if (err) { log_error ("ksba_cms_add_signer failed: %s\n", gpg_strerror (err)); - rc = err; goto leave; } - rc = add_certificate_list (ctrl, cms, cl->cert); - if (rc) + err = add_certificate_list (ctrl, cms, cl->cert); + if (err) { log_error ("failed to store list of certificates: %s\n", - gpg_strerror(rc)); + gpg_strerror (err)); goto leave; } /* Set the hash algorithm we are going to use */ @@ -537,7 +781,6 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist, { log_debug ("ksba_cms_add_digest_algo failed: %s\n", gpg_strerror (err)); - rc = err; goto leave; } } @@ -559,7 +802,6 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist, { log_error (_("checking for qualified certificate failed: %s\n"), gpg_strerror (err)); - rc = err; goto leave; } if (*buffer) @@ -567,19 +809,16 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist, else err = gpgsm_not_qualified_warning (ctrl, cl->cert); if (err) - { - rc = err; - goto leave; - } + goto leave; } } /* Prepare hashing (actually we are figuring out what we have set above). */ - rc = gcry_md_open (&data_md, 0, 0); - if (rc) + err = gcry_md_open (&data_md, 0, 0); + if (err) { - log_error ("md_open failed: %s\n", gpg_strerror (rc)); + log_error ("md_open failed: %s\n", gpg_strerror (err)); goto leave; } if (DBG_HASHING) @@ -591,7 +830,7 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist, if (!algo) { log_error ("unknown hash algorithm '%s'\n", algoid? algoid:"?"); - rc = gpg_error (GPG_ERR_BUG); + err = gpg_error (GPG_ERR_BUG); goto leave; } gcry_md_enable (data_md, algo); @@ -616,7 +855,7 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist, if ( !digest || !digest_len ) { log_error ("problem getting the hash of the data\n"); - rc = gpg_error (GPG_ERR_BUG); + err = gpg_error (GPG_ERR_BUG); goto leave; } err = ksba_cms_set_message_digest (cms, signer, digest, digest_len); @@ -624,7 +863,6 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist, { log_error ("ksba_cms_set_message_digest failed: %s\n", gpg_strerror (err)); - rc = err; goto leave; } } @@ -638,19 +876,21 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist, { log_error ("ksba_cms_set_signing_time failed: %s\n", gpg_strerror (err)); - rc = err; goto leave; } } /* 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: - - aes128-CBC - des-EDE3-CBC - */ - err = ksba_cms_add_smime_capability (cms, "2.16.840.1.101.3.4.1.2", NULL, 0); + * try to convince some MUAs to use 3DES and not the crippled + * RC2. Our list is: + * + * aes256-CBC + * aes128-CBC + * des-EDE3-CBC + */ + err = ksba_cms_add_smime_capability (cms, "2.16.840.1.101.3.4.1.42", NULL,0); + if (!err) + err = ksba_cms_add_smime_capability (cms, "2.16.840.1.101.3.4.1.2", NULL,0); if (!err) err = ksba_cms_add_smime_capability (cms, "1.2.840.113549.3.7", NULL, 0); if (err) @@ -667,8 +907,7 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist, err = ksba_cms_build (cms, &stopreason); if (err) { - log_debug ("ksba_cms_build failed: %s\n", gpg_strerror (err)); - rc = err; + log_error ("creating CMS object failed: %s\n", gpg_strerror (err)); goto leave; } @@ -680,8 +919,8 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist, assert (!detached); - rc = hash_and_copy_data (data_fd, data_md, writer); - if (rc) + err = hash_and_copy_data (data_fd, data_md, writer); + if (err) goto leave; audit_log (ctrl->audit, AUDIT_GOT_DATA); for (cl=signerlist,signer=0; cl; cl = cl->next, signer++) @@ -691,7 +930,7 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist, if ( !digest || !digest_len ) { log_error ("problem getting the hash of the data\n"); - rc = gpg_error (GPG_ERR_BUG); + err = gpg_error (GPG_ERR_BUG); goto leave; } err = ksba_cms_set_message_digest (cms, signer, @@ -700,7 +939,6 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist, { log_error ("ksba_cms_set_message_digest failed: %s\n", gpg_strerror (err)); - rc = err; goto leave; } } @@ -710,10 +948,10 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist, /* Compute the signature for all signers. */ gcry_md_hd_t md; - rc = gcry_md_open (&md, 0, 0); - if (rc) + err = gcry_md_open (&md, 0, 0); + if (err) { - log_error ("md_open failed: %s\n", gpg_strerror (rc)); + log_error ("md_open failed: %s\n", gpg_strerror (err)); goto leave; } if (DBG_HASHING) @@ -738,20 +976,20 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist, } } - rc = ksba_cms_hash_signed_attrs (cms, signer); - if (rc) + err = ksba_cms_hash_signed_attrs (cms, signer); + if (err) { log_debug ("hashing signed attrs failed: %s\n", - gpg_strerror (rc)); + gpg_strerror (err)); gcry_md_close (md); goto leave; } - rc = gpgsm_create_cms_signature (ctrl, cl->cert, - md, cl->hash_algo, &sigval); - if (rc) + err = gpgsm_create_cms_signature (ctrl, cl->cert, + md, cl->hash_algo, &sigval); + if (err) { - audit_log_cert (ctrl->audit, AUDIT_SIGNED_BY, cl->cert, rc); + audit_log_cert (ctrl->audit, AUDIT_SIGNED_BY, cl->cert, err); gcry_md_close (md); goto leave; } @@ -763,7 +1001,6 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist, audit_log_cert (ctrl->audit, AUDIT_SIGNED_BY, cl->cert, err); log_error ("failed to store the signature: %s\n", gpg_strerror (err)); - rc = err; gcry_md_close (md); goto leave; } @@ -772,24 +1009,29 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist, fpr = gpgsm_get_fingerprint_hexstring (cl->cert, GCRY_MD_SHA1); if (!fpr) { - rc = gpg_error (GPG_ERR_ENOMEM); + err = gpg_error (GPG_ERR_ENOMEM); gcry_md_close (md); goto leave; } - rc = 0; - { - int pkalgo = gpgsm_get_key_algo_info (cl->cert, NULL); - buf = xtryasprintf ("%c %d %d 00 %s %s", - detached? 'D':'S', - pkalgo, - cl->hash_algo, - signed_at, - fpr); - if (!buf) - rc = gpg_error_from_syserror (); - } + if (opt.verbose) + { + char *pkalgostr = gpgsm_pubkey_algo_string (cl->cert, NULL); + log_info (_("%s/%s signature using %s key %s\n"), + pubkey_algo_to_string (cl->pk_algo), + gcry_md_algo_name (cl->hash_algo), + pkalgostr, fpr); + xfree (pkalgostr); + } + buf = xtryasprintf ("%c %d %d 00 %s %s", + detached? 'D':'S', + cl->pk_algo, + cl->hash_algo, + signed_at, + fpr); + if (!buf) + err = gpg_error_from_syserror (); xfree (fpr); - if (rc) + if (err) { gcry_md_close (md); goto leave; @@ -803,26 +1045,44 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist, } while (stopreason != KSBA_SR_READY); - rc = gnupg_ksba_finish_writer (b64writer); - if (rc) + err = gnupg_ksba_finish_writer (b64writer); + if (err) { - log_error ("write failed: %s\n", gpg_strerror (rc)); + log_error ("write failed: %s\n", gpg_strerror (err)); goto leave; } + if (binary_detached) + { + void *blob = NULL; + size_t bloblen; + + err = (es_fclose_snatch (sig_fp, &blob, &bloblen)? + gpg_error_from_syserror () : 0); + sig_fp = NULL; + if (err) + goto leave; + err = write_detached_signature (blob, bloblen, out_fp); + xfree (blob); + if (err) + goto leave; + } + + audit_log (ctrl->audit, AUDIT_SIGNING_DONE); log_info ("signature created\n"); - leave: - if (rc) + if (err) log_error ("error creating signature: %s <%s>\n", - gpg_strerror (rc), gpg_strsource (rc) ); + gpg_strerror (err), gpg_strsource (err) ); if (release_signerlist) gpgsm_release_certlist (signerlist); + xfree (curve); ksba_cms_release (cms); gnupg_ksba_destroy_writer (b64writer); keydb_release (kh); gcry_md_close (data_md); - return rc; + es_fclose (sig_fp); + return err; } |