summaryrefslogtreecommitdiffstats
path: root/sm/sign.c
diff options
context:
space:
mode:
Diffstat (limited to 'sm/sign.c')
-rw-r--r--sm/sign.c478
1 files changed, 369 insertions, 109 deletions
diff --git a/sm/sign.c b/sm/sign.c
index dd7612f..4f60334 100644
--- a/sm/sign.c
+++ b/sm/sign.c
@@ -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;
}