diff options
Diffstat (limited to 'sm')
-rw-r--r-- | sm/certcheck.c | 31 | ||||
-rw-r--r-- | sm/certlist.c | 45 | ||||
-rw-r--r-- | sm/certreqgen-ui.c | 4 | ||||
-rw-r--r-- | sm/certreqgen.c | 233 | ||||
-rw-r--r-- | sm/decrypt.c | 376 | ||||
-rw-r--r-- | sm/encrypt.c | 321 | ||||
-rw-r--r-- | sm/fingerprint.c | 42 | ||||
-rw-r--r-- | sm/gpgsm.c | 6 | ||||
-rw-r--r-- | sm/gpgsm.h | 9 | ||||
-rw-r--r-- | sm/keylist.c | 31 | ||||
-rw-r--r-- | sm/misc.c | 109 | ||||
-rw-r--r-- | sm/sign.c | 102 | ||||
-rw-r--r-- | sm/verify.c | 4 |
13 files changed, 1137 insertions, 176 deletions
diff --git a/sm/certcheck.c b/sm/certcheck.c index d6b967c8a..534f47c1b 100644 --- a/sm/certcheck.c +++ b/sm/certcheck.c @@ -74,14 +74,17 @@ do_encode_md (gcry_md_hd_t md, int algo, int pkalgo, unsigned int nbits, size_t nframe; unsigned char *frame; - if (pkalgo == GCRY_PK_DSA || pkalgo == GCRY_PK_ECDSA) + if (pkalgo == GCRY_PK_DSA || pkalgo == GCRY_PK_ECC) { - unsigned int qbits; + unsigned int qbits0, qbits; - if ( pkalgo == GCRY_PK_ECDSA ) - qbits = gcry_pk_get_nbits (pkey); + if ( pkalgo == GCRY_PK_ECC ) + { + qbits0 = gcry_pk_get_nbits (pkey); + qbits = qbits0 == 521? 512 : qbits0; + } else - qbits = get_dsa_qbits (pkey); + qbits0 = qbits = get_dsa_qbits (pkey); if ( (qbits%8) ) { @@ -98,7 +101,7 @@ do_encode_md (gcry_md_hd_t md, int algo, int pkalgo, unsigned int nbits, if (qbits < 160) { log_error (_("%s key uses an unsafe (%u bit) hash\n"), - gcry_pk_algo_name (pkalgo), qbits); + gcry_pk_algo_name (pkalgo), qbits0); return gpg_error (GPG_ERR_INTERNAL); } @@ -109,7 +112,7 @@ do_encode_md (gcry_md_hd_t md, int algo, int pkalgo, unsigned int nbits, { log_error (_("a %u bit hash is not valid for a %u bit %s key\n"), (unsigned int)nframe*8, - gcry_pk_get_nbits (pkey), + qbits0, gcry_pk_algo_name (pkalgo)); /* FIXME: we need to check the requirements for ECDSA. */ if (nframe < 20 || pkalgo == GCRY_PK_DSA ) @@ -210,10 +213,8 @@ pk_algo_from_sexp (gcry_sexp_t pkey) algo = GCRY_PK_RSA; else if (n==3 && !memcmp (name, "dsa", 3)) algo = GCRY_PK_DSA; - /* Because this function is called only for verification we can - assume that ECC actually means ECDSA. */ else if (n==3 && !memcmp (name, "ecc", 3)) - algo = GCRY_PK_ECDSA; + algo = GCRY_PK_ECC; else if (n==13 && !memcmp (name, "ambiguous-rsa", 13)) algo = GCRY_PK_RSA; else @@ -357,9 +358,19 @@ gpgsm_check_cert_sig (ksba_cert_t issuer_cert, ksba_cert_t cert) int use_pss = 0; unsigned int saltlen; + /* Note that we map the 4 algos which current Libgcrypt versions are + * not aware of the OID. */ algo = gcry_md_map_name ( (algoid=ksba_cert_get_digest_algo (cert))); if (!algo && algoid && !strcmp (algoid, "1.2.840.113549.1.1.10")) use_pss = 1; + else if (!algo && algoid && !strcmp (algoid, "1.2.840.10045.4.3.1")) + algo = GCRY_MD_SHA224; /* ecdsa-with-sha224 */ + else if (!algo && algoid && !strcmp (algoid, "1.2.840.10045.4.3.2")) + algo = GCRY_MD_SHA256; /* ecdsa-with-sha256 */ + else if (!algo && algoid && !strcmp (algoid, "1.2.840.10045.4.3.3")) + algo = GCRY_MD_SHA384; /* ecdsa-with-sha384 */ + else if (!algo && algoid && !strcmp (algoid, "1.2.840.10045.4.3.4")) + algo = GCRY_MD_SHA512; /* ecdsa-with-sha512 */ else if (!algo) { log_error ("unknown digest algorithm '%s' used certificate\n", diff --git a/sm/certlist.c b/sm/certlist.c index b1ae58c52..94f85d2b2 100644 --- a/sm/certlist.c +++ b/sm/certlist.c @@ -34,7 +34,16 @@ #include "keydb.h" #include "../common/i18n.h" - +/* Mode values for cert_usage_p. + * Take care: the values have a semantic. */ +#define USE_MODE_SIGN 0 +#define USE_MODE_ENCR 1 +#define USE_MODE_VRFY 2 +#define USE_MODE_DECR 3 +#define USE_MODE_CERT 4 +#define USE_MODE_OCSP 5 + +/* OIDs we use here. */ static const char oid_kp_serverAuth[] = "1.3.6.1.5.5.7.3.1"; static const char oid_kp_clientAuth[] = "1.3.6.1.5.5.7.3.2"; static const char oid_kp_codeSigning[] = "1.3.6.1.5.5.7.3.3"; @@ -42,6 +51,7 @@ static const char oid_kp_emailProtection[]= "1.3.6.1.5.5.7.3.4"; static const char oid_kp_timeStamping[] = "1.3.6.1.5.5.7.3.8"; static const char oid_kp_ocspSigning[] = "1.3.6.1.5.5.7.3.9"; + /* Return 0 if the cert is usable for encryption. A MODE of 0 checks for signing a MODE of 1 checks for encryption, a MODE of 2 checks for verification and a MODE of 3 for decryption (just for @@ -120,7 +130,7 @@ cert_usage_p (ksba_cert_t cert, int mode, int silent) if (gpg_err_code (err) == GPG_ERR_NO_DATA) { err = 0; - if (opt.verbose && mode < 2 && !silent) + if (opt.verbose && mode < USE_MODE_VRFY && !silent) log_info (_("no key usage specified - assuming all usages\n")); use = ~0; } @@ -137,7 +147,7 @@ cert_usage_p (ksba_cert_t cert, int mode, int silent) return err; } - if (mode == 4) + if (mode == USE_MODE_CERT) { if ((use & (KSBA_KEYUSAGE_KEY_CERT_SIGN))) return 0; @@ -147,7 +157,7 @@ cert_usage_p (ksba_cert_t cert, int mode, int silent) return gpg_error (GPG_ERR_WRONG_KEY_USAGE); } - if (mode == 5) + if (mode == USE_MODE_OCSP) { if (use != ~0 && (have_ocsp_signing @@ -161,7 +171,8 @@ cert_usage_p (ksba_cert_t cert, int mode, int silent) } encr_bits = (KSBA_KEYUSAGE_KEY_ENCIPHERMENT|KSBA_KEYUSAGE_DATA_ENCIPHERMENT); - if ((opt.compat_flags & COMPAT_ALLOW_KA_TO_ENCR)) + if ((opt.compat_flags & COMPAT_ALLOW_KA_TO_ENCR) + || gpgsm_is_ecc_key (cert)) encr_bits |= KSBA_KEYUSAGE_KEY_AGREEMENT; sign_bits = (KSBA_KEYUSAGE_DIGITAL_SIGNATURE|KSBA_KEYUSAGE_NON_REPUDIATION); @@ -170,11 +181,13 @@ cert_usage_p (ksba_cert_t cert, int mode, int silent) return 0; if (!silent) - log_info - (mode==3? _("certificate should not have been used for encryption\n"): - mode==2? _("certificate should not have been used for signing\n"): - mode==1? _("certificate is not usable for encryption\n"): - /**/ _("certificate is not usable for signing\n")); + log_info (mode == USE_MODE_DECR? + _("certificate should not have been used for encryption\n") : + mode == USE_MODE_VRFY? + _("certificate should not have been used for signing\n") : + mode == USE_MODE_ENCR? + _("certificate is not usable for encryption\n") : + _("certificate is not usable for signing\n")); return gpg_error (GPG_ERR_WRONG_KEY_USAGE); } @@ -184,7 +197,7 @@ cert_usage_p (ksba_cert_t cert, int mode, int silent) int gpgsm_cert_use_sign_p (ksba_cert_t cert, int silent) { - return cert_usage_p (cert, 0, silent); + return cert_usage_p (cert, USE_MODE_SIGN, silent); } @@ -192,31 +205,31 @@ gpgsm_cert_use_sign_p (ksba_cert_t cert, int silent) int gpgsm_cert_use_encrypt_p (ksba_cert_t cert) { - return cert_usage_p (cert, 1, 0); + return cert_usage_p (cert, USE_MODE_ENCR, 0); } int gpgsm_cert_use_verify_p (ksba_cert_t cert) { - return cert_usage_p (cert, 2, 0); + return cert_usage_p (cert, USE_MODE_VRFY, 0); } int gpgsm_cert_use_decrypt_p (ksba_cert_t cert) { - return cert_usage_p (cert, 3, 0); + return cert_usage_p (cert, USE_MODE_DECR, 0); } int gpgsm_cert_use_cert_p (ksba_cert_t cert) { - return cert_usage_p (cert, 4, 0); + return cert_usage_p (cert, USE_MODE_CERT, 0); } int gpgsm_cert_use_ocsp_p (ksba_cert_t cert) { - return cert_usage_p (cert, 5, 0); + return cert_usage_p (cert, USE_MODE_OCSP, 0); } diff --git a/sm/certreqgen-ui.c b/sm/certreqgen-ui.c index d75b017c7..fbfaa8a8f 100644 --- a/sm/certreqgen-ui.c +++ b/sm/certreqgen-ui.c @@ -113,7 +113,9 @@ check_keygrip (ctrl_t ctrl, const char *hexgrip) case GCRY_PK_RSA: return "RSA"; case GCRY_PK_DSA: return "DSA"; case GCRY_PK_ELG: return "ELG"; - case GCRY_PK_EDDSA: return "ECDSA"; + case GCRY_PK_ECC: return "ECC"; + case GCRY_PK_ECDSA: return "ECDSA"; + case GCRY_PK_EDDSA: return "EdDSA"; default: return NULL; } } diff --git a/sm/certreqgen.c b/sm/certreqgen.c index 92d6ffe05..73ca7d2ea 100644 --- a/sm/certreqgen.c +++ b/sm/certreqgen.c @@ -67,6 +67,7 @@ #include "keydb.h" #include "../common/i18n.h" +#include "../common/membuf.h" enum para_name @@ -74,6 +75,7 @@ enum para_name pKEYTYPE, pKEYLENGTH, pKEYGRIP, + pKEYCURVE, pKEYUSAGE, pNAMEDN, pNAMEEMAIL, @@ -236,6 +238,7 @@ read_parameters (ctrl_t ctrl, estream_t fp, estream_t out_fp) { "Key-Type", pKEYTYPE}, { "Key-Length", pKEYLENGTH }, { "Key-Grip", pKEYGRIP }, + { "Key-Curve", pKEYCURVE }, { "Key-Usage", pKEYUSAGE }, { "Name-DN", pNAMEDN }, { "Name-Email", pNAMEEMAIL, 1 }, @@ -433,6 +436,7 @@ proc_parameters (ctrl_t ctrl, struct para_data_s *para, struct para_data_s *r; const char *s, *string; int i; + int algo; unsigned int nbits; char numbuf[20]; unsigned char keyparms[100]; @@ -446,30 +450,30 @@ proc_parameters (ctrl_t ctrl, struct para_data_s *para, /* Check that we have all required parameters; */ assert (get_parameter (para, pKEYTYPE, 0)); - /* We can only use RSA for now. There is a problem with pkcs-10 on - how to use ElGamal because it is expected that a PK algorithm can - always be used for signing. Another problem is that on-card - generated encryption keys may not be used for signing. */ - i = get_parameter_algo (para, pKEYTYPE); - if (!i && (s = get_parameter_value (para, pKEYTYPE, 0)) && *s) + /* There is a problem with pkcs-10 on how to use ElGamal because it + is expected that a PK algorithm can always be used for + signing. Another problem is that on-card generated encryption + keys may not be used for signing. */ + algo = get_parameter_algo (para, pKEYTYPE); + if (!algo && (s = get_parameter_value (para, pKEYTYPE, 0)) && *s) { /* Hack to allow creation of certificates directly from a smart card. For example: "Key-Type: card:OPENPGP.3". */ if (!strncmp (s, "card:", 5) && s[5]) cardkeyid = xtrystrdup (s+5); } - if ( (i < 1 || i != GCRY_PK_RSA) && !cardkeyid ) + if (algo < 1 && !cardkeyid) { r = get_parameter (para, pKEYTYPE, 0); if (r) - log_error (_("line %d: invalid algorithm\n"), r?r->lnr:0); + log_error (_("line %d: invalid algorithm\n"), r->lnr); else log_error ("No Key-Type specified\n"); return gpg_error (GPG_ERR_INV_PARAMETER); } /* Check the keylength. NOTE: If you change this make sure that it - macthes the gpgconflist item in gpgsm.c */ + matches the gpgconflist item in gpgsm.c */ if (!get_parameter (para, pKEYLENGTH, 0)) nbits = 3072; else @@ -626,7 +630,7 @@ proc_parameters (ctrl_t ctrl, struct para_data_s *para, /* Check the optional AuthorityKeyId. */ string = get_parameter_value (para, pAUTHKEYID, 0); - if (string) + if (string && strcmp (string, "none")) { for (s=string, i=0; hexdigitp (s); s++, i++) ; @@ -641,7 +645,7 @@ proc_parameters (ctrl_t ctrl, struct para_data_s *para, /* Check the optional SubjectKeyId. */ string = get_parameter_value (para, pSUBJKEYID, 0); - if (string) + if (string && strcmp (string, "none")) { for (s=string, i=0; hexdigitp (s); s++, i++) ; @@ -721,10 +725,37 @@ proc_parameters (ctrl_t ctrl, struct para_data_s *para, } else if (!outctrl->dryrun) /* Generate new key. */ { - sprintf (numbuf, "%u", nbits); - snprintf ((char*)keyparms, DIM (keyparms), - "(6:genkey(3:rsa(5:nbits%d:%s)))", - (int)strlen (numbuf), numbuf); + if (algo == GCRY_PK_RSA) + { + sprintf (numbuf, "%u", nbits); + snprintf ((char*)keyparms, DIM (keyparms), + "(6:genkey(3:rsa(5:nbits%d:%s)))", + (int)strlen (numbuf), numbuf); + } + else if (algo == GCRY_PK_ECC || algo == GCRY_PK_EDDSA) + { + const char *curve = get_parameter_value (para, pKEYCURVE, 0); + const char *flags; + + if (algo == GCRY_PK_EDDSA) + flags = "(flags eddsa)"; + else if (!strcmp (curve, "Curve25519")) + flags = "(flags djb-tweak)"; + else + flags = ""; + + snprintf ((char*)keyparms, DIM (keyparms), + "(genkey(ecc(curve %zu:%s)%s))", + strlen (curve), curve, flags); + } + else + { + r = get_parameter (para, pKEYTYPE, 0); + log_error (_("line %d: invalid algorithm\n"), r->lnr); + xfree (sigkey); + xfree (cardkeyid); + return gpg_error (GPG_ERR_INV_PARAMETER); + } rc = gpgsm_agent_genkey (ctrl, keyparms, &public); if (rc) { @@ -805,16 +836,40 @@ create_request (ctrl_t ctrl, ksba_isotime_t atime; int certmode = 0; int mdalgo; + membuf_t tbsbuffer; + membuf_t *tbsmb = NULL; + size_t publiclen; + size_t sigkeylen; + int publicpkalgo; /* The gcrypt public key algo of the public key. */ + int sigkeypkalgo; /* The gcrypt public key algo of the signing key. */ err = ksba_certreq_new (&cr); if (err) return err; - string = get_parameter_value (para, pHASHALGO, 0); - if (string) - mdalgo = gcry_md_map_name (string); + publiclen = gcry_sexp_canon_len (public, 0, NULL, NULL); + sigkeylen = sigkey? gcry_sexp_canon_len (sigkey, 0, NULL, NULL) : 0; + + publicpkalgo = get_pk_algo_from_canon_sexp (public, publiclen); + sigkeypkalgo = sigkey? get_pk_algo_from_canon_sexp (public, publiclen) : 0; + + if (publicpkalgo == GCRY_PK_EDDSA) + { + mdalgo = GCRY_MD_SHA512; + md = NULL; /* We sign the data and not a hash. */ + init_membuf (&tbsbuffer, 2048); + tbsmb = &tbsbuffer; + ksba_certreq_set_hash_function + (cr, (void (*)(void *, const void*,size_t))put_membuf, tbsmb); + } else - mdalgo = GCRY_MD_SHA256; + { + string = get_parameter_value (para, pHASHALGO, 0); + if (string) + mdalgo = gcry_md_map_name (string); + else + mdalgo = GCRY_MD_SHA256; + } rc = gcry_md_open (&md, mdalgo, 0); if (rc) { @@ -912,12 +967,10 @@ create_request (ctrl_t ctrl, } } - err = ksba_certreq_set_public_key (cr, public); if (err) { - log_error ("error setting the public key: %s\n", - gpg_strerror (err)); + log_error ("error setting the public key: %s\n", gpg_strerror (err)); rc = err; goto leave; } @@ -1113,14 +1166,17 @@ create_request (ctrl_t ctrl, given we set it to the public key to create a self-signed certificate. */ if (!sigkey) - sigkey = public; + { + sigkey = public; + sigkeylen = publiclen; + sigkeypkalgo = publicpkalgo; + } + /* Set the the digestinfo aka siginfo. */ { unsigned char *siginfo; - err = transform_sigval (sigkey, - gcry_sexp_canon_len (sigkey, 0, NULL, NULL), - mdalgo, &siginfo, NULL); + err = transform_sigval (sigkey, sigkeylen, mdalgo, &siginfo, NULL); if (!err) { err = ksba_certreq_set_siginfo (cr, siginfo); @@ -1135,9 +1191,12 @@ create_request (ctrl_t ctrl, } } + /* Insert the AuthorityKeyId. */ string = get_parameter_value (para, pAUTHKEYID, 0); - if (string) + if (string && !strcmp (string, "none")) + ; /* Do not issue an AKI. */ + else if (string) { char *hexbuf; @@ -1163,20 +1222,69 @@ create_request (ctrl_t ctrl, hexbuf[2] = 0x80; /* Context tag for an implicit Octet string. */ hexbuf[3] = len; err = ksba_certreq_add_extension (cr, oidstr_authorityKeyIdentifier, - 0, - hexbuf, 4+len); + 0, hexbuf, 4+len); xfree (hexbuf); if (err) { - log_error ("error setting the authority-key-id: %s\n", + log_error ("error setting the AKI: %s\n", gpg_strerror (err)); + goto leave; + } + } + else if (publicpkalgo == GCRY_PK_EDDSA || publicpkalgo == GCRY_PK_ECC) + { + /* For EdDSA and ECC we add the public key as default identifier. */ + const unsigned char *q; + size_t qlen, derlen; + unsigned char *der; + + err = get_ecc_q_from_canon_sexp (public, publiclen, &q, &qlen); + if (err) + { + log_error ("error getting Q from public key: %s\n", gpg_strerror (err)); goto leave; } + if (publicpkalgo == GCRY_PK_EDDSA && qlen>32 && (qlen&1) && *q==0x40) + { + /* Skip our optional native encoding octet. */ + q++; + qlen--; + } + /* FIXME: For plain ECC we should better use a compressed + * point. That requires an updated Libgcrypt. Without that + * using nistp521 won't work due to the length check below. */ + if (qlen > 125) + { + err = gpg_error (GPG_ERR_TOO_LARGE); + goto leave; + } + derlen = 4 + qlen; + der = xtrymalloc (derlen); + if (!der) + { + err = gpg_error_from_syserror (); + goto leave; + } + der[0] = 0x30; /* Sequence */ + der[1] = qlen + 2; + der[2] = 0x80; /* Context tag for an implict Octet String. */ + der[3] = qlen; + memcpy (der+4, q, qlen); + err = ksba_certreq_add_extension (cr, oidstr_authorityKeyIdentifier, + 0, der, derlen); + xfree (der); + if (err) + { + log_error ("error setting the AKI: %s\n", gpg_strerror (err)); + goto leave; + } } /* Insert the SubjectKeyId. */ string = get_parameter_value (para, pSUBJKEYID, 0); - if (string) + if (string && !strcmp (string, "none")) + ; /* Do not issue an SKI. */ + else if (string) { char *hexbuf; @@ -1204,10 +1312,53 @@ create_request (ctrl_t ctrl, xfree (hexbuf); if (err) { - log_error ("error setting the subject-key-id: %s\n", + log_error ("error setting SKI: %s\n", gpg_strerror (err)); + goto leave; + } + } + else if (sigkeypkalgo == GCRY_PK_EDDSA || sigkeypkalgo == GCRY_PK_ECC) + { + /* For EdDSA and ECC we add the public key as default identifier. */ + const unsigned char *q; + size_t qlen, derlen; + unsigned char *der; + + err = get_ecc_q_from_canon_sexp (sigkey, sigkeylen, &q, &qlen); + if (err) + { + log_error ("error getting Q from signature key: %s\n", gpg_strerror (err)); goto leave; } + if (sigkeypkalgo == GCRY_PK_EDDSA && qlen>32 && (qlen&1) && *q==0x40) + { + /* Skip our optional native encoding octet. */ + q++; + qlen--; + } + if (qlen > 127) + { + err = gpg_error (GPG_ERR_TOO_LARGE); + goto leave; + } + derlen = 2 + qlen; + der = xtrymalloc (derlen); + if (!der) + { + err = gpg_error_from_syserror (); + goto leave; + } + der[0] = 0x04; /* Octet String */ + der[1] = qlen; + memcpy (der+2, q, qlen); + err = ksba_certreq_add_extension (cr, oidstr_subjectKeyIdentifier, 0, + der, derlen); + xfree (der); + if (err) + { + log_error ("error setting the SKI: %s\n", gpg_strerror (err)); + goto leave; + } } /* Insert additional extensions. */ @@ -1283,20 +1434,12 @@ create_request (ctrl_t ctrl, if (stopreason == KSBA_SR_NEED_SIG) { gcry_sexp_t s_pkey; - size_t n; unsigned char grip[20]; char hexgrip[41]; unsigned char *sigval, *newsigval; size_t siglen; - n = gcry_sexp_canon_len (sigkey, 0, NULL, NULL); - if (!n) - { - log_error ("libksba did not return a proper S-Exp\n"); - rc = gpg_error (GPG_ERR_BUG); - goto leave; - } - rc = gcry_sexp_sscan (&s_pkey, NULL, (const char*)sigkey, n); + rc = gcry_sexp_sscan (&s_pkey, NULL, (const char*)sigkey, sigkeylen); if (rc) { log_error ("gcry_sexp_scan failed: %s\n", gpg_strerror (rc)); @@ -1312,8 +1455,9 @@ create_request (ctrl_t ctrl, gcry_sexp_release (s_pkey); bin2hex (grip, 20, hexgrip); - log_info ("about to sign the %s for key: &%s\n", - certmode? "certificate":"CSR", hexgrip); + if (!opt.quiet) + log_info ("about to sign the %s for key: &%s\n", + certmode? "certificate":"CSR", hexgrip); if (carddirect && !certmode) rc = gpgsm_scd_pksign (ctrl, carddirect, NULL, @@ -1345,8 +1489,7 @@ create_request (ctrl_t ctrl, goto leave; } - err = transform_sigval (sigval, siglen, mdalgo, - &newsigval, NULL); + err = transform_sigval (sigval, siglen, mdalgo, &newsigval, NULL); xfree (sigval); if (!err) { diff --git a/sm/decrypt.c b/sm/decrypt.c index 2aa716f5b..01260f599 100644 --- a/sm/decrypt.c +++ b/sm/decrypt.c @@ -1,7 +1,7 @@ /* decrypt.c - Decrypt a message * Copyright (C) 2001, 2003, 2010 Free Software Foundation, Inc. * Copyright (C) 2001-2019 Werner Koch - * Copyright (C) 2015-2021 g10 Code GmbH + * Copyright (C) 2015-2020 g10 Code GmbH * * This file is part of GnuPG. * @@ -82,6 +82,335 @@ string_from_gcry_buffer (gcry_buffer_t *buffer) } +/* Helper to construct and hash the + * ECC-CMS-SharedInfo ::= SEQUENCE { + * keyInfo AlgorithmIdentifier, + * entityUInfo [0] EXPLICIT OCTET STRING OPTIONAL, + * suppPubInfo [2] EXPLICIT OCTET STRING } + * as described in RFC-5753, 7.2. */ +gpg_error_t +hash_ecc_cms_shared_info (gcry_md_hd_t hash_hd, const char *wrap_algo_str, + unsigned int keylen, + const void *ukm, unsigned int ukmlen) +{ + gpg_error_t err; + void *p; + unsigned char *oid; + size_t n, oidlen, toidlen, tkeyinfo, tukmlen, tsupppubinfo; + unsigned char keylenbuf[6]; + membuf_t mb = MEMBUF_ZERO; + + err = ksba_oid_from_str (wrap_algo_str, &oid, &oidlen); + if (err) + return err; + toidlen = get_tlv_length (CLASS_UNIVERSAL, TAG_OBJECT_ID, 0, oidlen); + tkeyinfo = get_tlv_length (CLASS_UNIVERSAL, TAG_SEQUENCE, 1, toidlen); + + tukmlen = ukm? get_tlv_length (CLASS_CONTEXT, 0, 1, ukmlen) : 0; + + keylen *= 8; + keylenbuf[0] = TAG_OCTET_STRING; + keylenbuf[1] = 4; + keylenbuf[2] = (keylen >> 24); + keylenbuf[3] = (keylen >> 16); + keylenbuf[4] = (keylen >> 8); + keylenbuf[5] = keylen; + + tsupppubinfo = get_tlv_length (CLASS_CONTEXT, 2, 1, sizeof keylenbuf); + + put_tlv_to_membuf (&mb, CLASS_UNIVERSAL, TAG_SEQUENCE, 1, + tkeyinfo + tukmlen + tsupppubinfo); + put_tlv_to_membuf (&mb, CLASS_UNIVERSAL, TAG_SEQUENCE, 1, + toidlen); + put_tlv_to_membuf (&mb, CLASS_UNIVERSAL, TAG_OBJECT_ID, 0, oidlen); + put_membuf (&mb, oid, oidlen); + ksba_free (oid); + + if (ukm) + { + put_tlv_to_membuf (&mb, CLASS_CONTEXT, 0, 1, ukmlen); + put_membuf (&mb, ukm, ukmlen); + } + + put_tlv_to_membuf (&mb, CLASS_CONTEXT, 2, 1, sizeof keylenbuf); + put_membuf (&mb, keylenbuf, sizeof keylenbuf); + + p = get_membuf (&mb, &n); + if (!p) + return gpg_error_from_syserror (); + + gcry_md_write (hash_hd, p, n); + xfree (p); + return 0; +} + + + +/* Derive a KEK (key wrapping key) using (SECRET,SECRETLEN), an + * optional (UKM,ULMLEN), the wrap algorithm WRAP_ALGO_STR in decimal + * dotted form, and the hash algorithm HASH_ALGO. On success a key of + * length KEYLEN is stored at KEY. */ +gpg_error_t +ecdh_derive_kek (unsigned char *key, unsigned int keylen, + int hash_algo, const char *wrap_algo_str, + const void *secret, unsigned int secretlen, + const void *ukm, unsigned int ukmlen) +{ + gpg_error_t err = 0; + unsigned int hashlen; + gcry_md_hd_t hash_hd; + unsigned char counter; + unsigned int n, ncopy; + + hashlen = gcry_md_get_algo_dlen (hash_algo); + if (!hashlen) + return gpg_error (GPG_ERR_INV_ARG); + + err = gcry_md_open (&hash_hd, hash_algo, 0); + if (err) + return err; + + /* According to SEC1 3.6.1 we should check that + * SECRETLEN + UKMLEN + 4 < maxhashlen + * However, we have no practical limit on the hash length and thus + * there is no point in checking this. The second check that + * KEYLEN < hashlen*(2^32-1) + * is obviously also not needed. + */ + for (n=0, counter=1; n < keylen; counter++) + { + if (counter > 1) + gcry_md_reset (hash_hd); + gcry_md_write (hash_hd, secret, secretlen); + gcry_md_write (hash_hd, "\x00\x00\x00", 3); /* MSBs of counter */ + gcry_md_write (hash_hd, &counter, 1); + err = hash_ecc_cms_shared_info (hash_hd, wrap_algo_str, keylen, + ukm, ukmlen); + if (err) + break; + gcry_md_final (hash_hd); + if (n + hashlen > keylen) + ncopy = keylen - n; + else + ncopy = hashlen; + memcpy (key+n, gcry_md_read (hash_hd, 0), ncopy); + n += ncopy; + } + + gcry_md_close (hash_hd); + return err; +} + + +/* This function will modify SECRET. NBITS is the size of the curve + * which which we took from the certificate. */ +static gpg_error_t +ecdh_decrypt (unsigned char *secret, size_t secretlen, + unsigned int nbits, gcry_sexp_t enc_val, + unsigned char **r_result, unsigned int *r_resultlen) +{ + gpg_error_t err; + gcry_buffer_t ioarray[4] = { {0}, {0}, {0}, {0} }; + char *encr_algo_str = NULL; + char *wrap_algo_str = NULL; + int hash_algo, cipher_algo; + const unsigned char *ukm; /* Alias for ioarray[2]. */ + unsigned int ukmlen; + const unsigned char *data; /* Alias for ioarray[3]. */ + unsigned int datalen; + unsigned int keylen; + unsigned char key[32]; + gcry_cipher_hd_t cipher_hd = NULL; + unsigned char *result = NULL; + unsigned int resultlen; + + *r_resultlen = 0; + *r_result = NULL; + + /* Extract X from SECRET; this is the actual secret. Unless a + * smartcard diretcly returns X, it must be in the format of: + * + * 04 || X || Y + * 40 || X + * 41 || X + */ + if (secretlen < 2) + return gpg_error (GPG_ERR_BAD_DATA); + if (secretlen == (nbits+7)/8) + ; /* Matches curve length - this is already the X coordinate. */ + else if (*secret == 0x04) + { + secretlen--; + memmove (secret, secret+1, secretlen); + if ((secretlen & 1)) + return gpg_error (GPG_ERR_BAD_DATA); + secretlen /= 2; + } + else if (*secret == 0x40 || *secret == 0x41) + { + secretlen--; + memmove (secret, secret+1, secretlen); + } + else + return gpg_error (GPG_ERR_BAD_DATA); + if (!secretlen) + return gpg_error (GPG_ERR_BAD_DATA); + + if (DBG_CRYPTO) + log_printhex (secret, secretlen, "ECDH X ..:"); + + /* We have now the shared secret bytes in (SECRET,SECRETLEN). Now + * we will compute the KEK using a value dervied from the secret + * bytes. */ + err = gcry_sexp_extract_param (enc_val, "enc-val", + "&'encr-algo''wrap-algo''ukm'?s", + ioarray+0, ioarray+1, + ioarray+2, ioarray+3, NULL); + if (err) + { + log_error ("extracting ECDH parameter failed: %s\n", gpg_strerror (err)); + goto leave; + } + encr_algo_str = string_from_gcry_buffer (ioarray); + if (!encr_algo_str) + { + err = gpg_error_from_syserror (); + goto leave; + } + wrap_algo_str = string_from_gcry_buffer (ioarray+1); + if (!wrap_algo_str) + { + err = gpg_error_from_syserror (); + goto leave; + } + ukm = ioarray[2].data; + ukmlen = ioarray[2].len; + data = ioarray[3].data; + datalen = ioarray[3].len; + + /* Check parameters. */ + if (DBG_CRYPTO) + { + log_debug ("encr_algo: %s\n", encr_algo_str); + log_debug ("wrap_algo: %s\n", wrap_algo_str); + log_printhex (ukm, ukmlen, "ukm .....:"); + log_printhex (data, datalen, "data ....:"); + } + + if (!strcmp (encr_algo_str, "1.3.132.1.11.1")) + { + /* dhSinglePass-stdDH-sha256kdf-scheme */ + hash_algo = GCRY_MD_SHA256; + } + else if (!strcmp (encr_algo_str, "1.3.132.1.11.2")) + { + /* dhSinglePass-stdDH-sha384kdf-scheme */ + hash_algo = GCRY_MD_SHA384; + } + else if (!strcmp (encr_algo_str, "1.3.132.1.11.3")) + { + /* dhSinglePass-stdDH-sha512kdf-scheme */ + hash_algo = GCRY_MD_SHA512; + } + else if (!strcmp (encr_algo_str, "1.3.133.16.840.63.0.2")) + { + /* dhSinglePass-stdDH-sha1kdf-scheme */ + hash_algo = GCRY_MD_SHA1; + } + else + { + err = gpg_error (GPG_ERR_PUBKEY_ALGO); + goto leave; + } + + if (!strcmp (wrap_algo_str, "2.16.840.1.101.3.4.1.5")) + { + cipher_algo = GCRY_CIPHER_AES128; + keylen = 16; + } + else if (!strcmp (wrap_algo_str, "2.16.840.1.101.3.4.1.25")) + { + cipher_algo = GCRY_CIPHER_AES192; + keylen = 24; + } + else if (!strcmp (wrap_algo_str, "2.16.840.1.101.3.4.1.45")) + { + cipher_algo = GCRY_CIPHER_AES256; + keylen = 32; + } + else + { + err = gpg_error (GPG_ERR_PUBKEY_ALGO); + goto leave; + } + + err = ecdh_derive_kek (key, keylen, hash_algo, wrap_algo_str, + secret, secretlen, ukm, ukmlen); + if (err) + goto leave; + + if (DBG_CRYPTO) + log_printhex (key, keylen, "KEK .....:"); + + /* Unwrap the key. */ + if ((datalen % 8) || datalen < 16) + { + log_error ("can't use a shared secret of %u bytes for ecdh\n", datalen); + err = gpg_error (GPG_ERR_BAD_DATA); + goto leave; + } + + resultlen = datalen - 8; + result = xtrymalloc_secure (resultlen); + if (!result) + { + err = gpg_error_from_syserror (); + goto leave; + } + + err = gcry_cipher_open (&cipher_hd, cipher_algo, GCRY_CIPHER_MODE_AESWRAP, 0); + if (err) + { + log_error ("ecdh failed to initialize AESWRAP: %s\n", gpg_strerror (err)); + goto leave; + } + + err = gcry_cipher_setkey (cipher_hd, key, keylen); + wipememory (key, sizeof key); + if (err) + { + log_error ("ecdh failed in gcry_cipher_setkey: %s\n", gpg_strerror (err)); + goto leave; + } + + err = gcry_cipher_decrypt (cipher_hd, result, resultlen, data, datalen); + if (err) + { + log_error ("ecdh failed in gcry_cipher_decrypt: %s\n",gpg_strerror (err)); + goto leave; + } + + *r_resultlen = resultlen; + *r_result = result; + result = NULL; + + leave: + if (result) + { + wipememory (result, resultlen); + xfree (result); + } + gcry_cipher_close (cipher_hd); + xfree (encr_algo_str); + xfree (wrap_algo_str); + xfree (ioarray[0].data); + xfree (ioarray[1].data); + xfree (ioarray[2].data); + xfree (ioarray[3].data); + return err; +} + + /* Helper for pwri_decrypt to parse the derive info. * Example data for (DER,DERLEN): * SEQUENCE { @@ -447,13 +776,14 @@ pwri_decrypt (ctrl_t ctrl, gcry_sexp_t enc_val, /* Decrypt the session key and fill in the parm structure. The algo and the IV is expected to be already in PARM. */ static int -prepare_decryption (ctrl_t ctrl, const char *hexkeygrip, const char *desc, +prepare_decryption (ctrl_t ctrl, const char *hexkeygrip, + int pk_algo, unsigned int nbits, const char *desc, ksba_const_sexp_t enc_val, struct decrypt_filter_parm_s *parm) { char *seskey = NULL; size_t n, seskeylen; - int pwri = !hexkeygrip; + int pwri = !hexkeygrip && !pk_algo; int rc; if (DBG_CRYPTO) @@ -468,6 +798,9 @@ prepare_decryption (ctrl_t ctrl, const char *hexkeygrip, const char *desc, log_error ("error decrypting session key: %s\n", gpg_strerror (rc)); goto leave; } + + if (DBG_CRYPTO) + log_printhex (seskey, seskeylen, "DEK frame:"); } n=0; @@ -490,6 +823,27 @@ prepare_decryption (ctrl_t ctrl, const char *hexkeygrip, const char *desc, seskey = decrypted; seskeylen = decryptedlen; } + else if (pk_algo == GCRY_PK_ECC) + { + gcry_sexp_t s_enc_val; + unsigned char *decrypted; + unsigned int decryptedlen; + + rc = gcry_sexp_sscan (&s_enc_val, NULL, enc_val, + gcry_sexp_canon_len (enc_val, 0, NULL, NULL)); + if (rc) + goto leave; + + rc = ecdh_decrypt (seskey, seskeylen, nbits, s_enc_val, + &decrypted, &decryptedlen); + gcry_sexp_release (s_enc_val); + if (rc) + goto leave; + xfree (seskey); + seskey = decrypted; + seskeylen = decryptedlen; + + } else if (seskeylen == 32 || seskeylen == 24 || seskeylen == 16) { /* Smells like an AES-128, 3-DES, or AES-256 key. This might @@ -530,7 +884,10 @@ prepare_decryption (ctrl_t ctrl, const char *hexkeygrip, const char *desc, } if (DBG_CRYPTO) - log_printhex (seskey+n, seskeylen-n, "session key:"); + { + log_printhex (seskey+n, seskeylen-n, "CEK .......:"); + log_printhex (parm->iv, parm->ivlen, "IV ........:"); + } if (opt.verbose) log_info (_("%s.%s encrypted data\n"), @@ -839,7 +1196,10 @@ gpgsm_decrypt (ctrl_t ctrl, int in_fd, estream_t out_fp) dfparm.mode = mode; dfparm.blklen = gcry_cipher_get_algo_blklen (algo); if (dfparm.blklen > sizeof (dfparm.helpblock)) - return gpg_error (GPG_ERR_BUG); + { + rc = gpg_error (GPG_ERR_BUG); + goto leave; + } rc = ksba_cms_get_content_enc_iv (cms, dfparm.iv, @@ -951,6 +1311,7 @@ gpgsm_decrypt (ctrl_t ctrl, int in_fd, estream_t out_fp) hexkeygrip = gpgsm_get_keygrip_hexstring (cert); desc = gpgsm_format_keydesc (cert); + pkfpr = gpgsm_get_fingerprint_hexstring (cert, GCRY_MD_SHA1); pkalgostr = gpgsm_pubkey_algo_string (cert, NULL); pk_algo = gpgsm_get_key_algo_info (cert, &nbits); @@ -1006,7 +1367,7 @@ gpgsm_decrypt (ctrl_t ctrl, int in_fd, estream_t out_fp) if (maybe_pwri && opt.verbose) log_info ("recp %d - KEKRI or PWRI\n", recp); - rc = prepare_decryption (ctrl, hexkeygrip, + rc = prepare_decryption (ctrl, hexkeygrip, pk_algo, nbits, desc, enc_val, &dfparm); xfree (enc_val); if (rc) @@ -1076,7 +1437,8 @@ gpgsm_decrypt (ctrl_t ctrl, int in_fd, estream_t out_fp) if (!any_key) { - rc = gpg_error (GPG_ERR_NO_SECKEY); + if (!rc) + rc = gpg_error (GPG_ERR_NO_SECKEY); goto leave; } } diff --git a/sm/encrypt.c b/sm/encrypt.c index 587b568c6..fb36977af 100644 --- a/sm/encrypt.c +++ b/sm/encrypt.c @@ -1,6 +1,8 @@ /* encrypt.c - Encrypt a message * Copyright (C) 2001, 2003, 2004, 2007, 2008, * 2010 Free Software Foundation, Inc. + * Copyright (C) 2001-2019 Werner Koch + * Copyright (C) 2015-2020 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> @@ -144,7 +147,7 @@ init_dek (DEK dek) return 0; } - +/* Encrypt an RSA session key. */ static int encode_session_key (DEK dek, gcry_sexp_t * r_data) { @@ -165,10 +168,282 @@ encode_session_key (DEK dek, gcry_sexp_t * r_data) } +/* Encrypt DEK using ECDH. S_PKEY is the public key. On success the + * result is stored at R_ENCVAL. Example of a public key: + * + * (public-key (ecc (curve "1.3.132.0.34") (q #04B0[...]B8#))) + * + */ +static gpg_error_t +ecdh_encrypt (DEK dek, gcry_sexp_t s_pkey, gcry_sexp_t *r_encval) +{ + gpg_error_t err; + gcry_sexp_t l1; + char *curvebuf = NULL; + const char *curve; + unsigned int curvebits; + const char *encr_algo_str; + const char *wrap_algo_str; + int hash_algo, cipher_algo; + unsigned int keylen, hashlen; + unsigned char key[32]; + gcry_sexp_t s_data = NULL; + gcry_sexp_t s_encr = NULL; + gcry_buffer_t ioarray[2] = { {0}, {0} }; + unsigned char *secret; /* Alias for ioarray[0]. */ + unsigned int secretlen; + unsigned char *pubkey; /* Alias for ioarray[1]. */ + unsigned int pubkeylen; + gcry_cipher_hd_t cipher_hd = NULL; + unsigned char *result = NULL; + unsigned int resultlen; + + *r_encval = NULL; + + /* Figure out the encryption and wrap algo OIDs. */ + /* Get the curve name if any, */ + l1 = gcry_sexp_find_token (s_pkey, "curve", 0); + if (l1) + { + curvebuf = gcry_sexp_nth_string (l1, 1); + gcry_sexp_release (l1); + } + if (!curvebuf) + { + err = gpg_error (GPG_ERR_INV_CURVE); + log_error ("%s: invalid public key: no curve\n", __func__); + goto leave; + } + + /* We need to use our OpenPGP mapping to turn a curve name into its + * canonical numerical OID. We also use this to get the size of the + * curve which we need to figure out a suitable hash algo. We + * should have a Libgcrypt function to do this; see bug report #4926. */ + curve = openpgp_curve_to_oid (curvebuf, &curvebits, NULL); + if (!curve) + { + err = gpg_error (GPG_ERR_UNKNOWN_CURVE); + log_error ("%s: invalid public key: %s\n", __func__, gpg_strerror (err)); + goto leave; + } + xfree (curvebuf); + curvebuf = NULL; + + /* Our mapping matches the recommended algorithms from RFC-5753 but + * not supporing the short curves which would require 3DES. */ + if (curvebits < 255) + { + err = gpg_error (GPG_ERR_UNKNOWN_CURVE); + log_error ("%s: curve '%s' is not supported\n", __func__, curve); + goto leave; + } + else if (curvebits <= 256) + { + /* dhSinglePass-stdDH-sha256kdf-scheme */ + encr_algo_str = "1.3.132.1.11.1"; + wrap_algo_str = "2.16.840.1.101.3.4.1.5"; + hash_algo = GCRY_MD_SHA256; + hashlen = 32; + cipher_algo = GCRY_CIPHER_AES128; + keylen = 16; + } + else if (curvebits <= 384) + { + /* dhSinglePass-stdDH-sha384kdf-scheme */ + encr_algo_str = "1.3.132.1.11.2"; + wrap_algo_str = "2.16.840.1.101.3.4.1.25"; + hash_algo = GCRY_MD_SHA384; + hashlen = 48; + cipher_algo = GCRY_CIPHER_AES256; + keylen = 24; + } + else + { + /* dhSinglePass-stdDH-sha512kdf-scheme*/ + encr_algo_str = "1.3.132.1.11.3"; + wrap_algo_str = "2.16.840.1.101.3.4.1.45"; + hash_algo = GCRY_MD_SHA512; + hashlen = 64; + cipher_algo = GCRY_CIPHER_AES256; + keylen = 32; + } + + + /* Create a secret and an ephemeral key. */ + { + char *k; + k = gcry_random_bytes_secure ((curvebits+7)/8, GCRY_STRONG_RANDOM); + if (DBG_CRYPTO) + log_printhex (k, (curvebits+7)/8, "ephm. k .:"); + err = gcry_sexp_build (&s_data, NULL, "%b", (int)(curvebits+7)/8, k); + xfree (k); + } + if (err) + { + log_error ("%s: error building ephemeral secret: %s\n", + __func__, gpg_strerror (err)); + goto leave; + } + + err = gcry_pk_encrypt (&s_encr, s_data, s_pkey); + if (err) + { + log_error ("%s: error encrypting ephemeral secret: %s\n", + __func__, gpg_strerror (err)); + goto leave; + } + err = gcry_sexp_extract_param (s_encr, NULL, "&se", + &ioarray+0, ioarray+1, NULL); + if (err) + { + log_error ("%s: error extracting ephemeral key and secret: %s\n", + __func__, gpg_strerror (err)); + goto leave; + } + secret = ioarray[0].data; + secretlen = ioarray[0].len; + pubkey = ioarray[1].data; + pubkeylen = ioarray[1].len; + + if (DBG_CRYPTO) + { + log_printhex (pubkey, pubkeylen, "pubkey ..:"); + log_printhex (secret, secretlen, "secret ..:"); + } + + /* Extract X coordinate from SECRET. */ + if (secretlen < 5) /* 5 because N could be reduced to (n-1)/2. */ + err = gpg_error (GPG_ERR_BAD_DATA); + else if (*secret == 0x04) + { + secretlen--; + memmove (secret, secret+1, secretlen); + if ((secretlen & 1)) + { + err = gpg_error (GPG_ERR_BAD_DATA); + goto leave; + } + secretlen /= 2; + } + else if (*secret == 0x40 || *secret == 0x41) + { + secretlen--; + memmove (secret, secret+1, secretlen); + } + else + err = gpg_error (GPG_ERR_BAD_DATA); + if (err) + goto leave; + + if (DBG_CRYPTO) + log_printhex (secret, secretlen, "ECDH X ..:"); + + /* Derive a KEK (key wrapping key) using MESSAGE and SECRET_X. + * According to SEC1 3.6.1 we should check that + * SECRETLEN + UKMLEN + 4 < maxhashlen + * However, we have no practical limit on the hash length and thus + * there is no point in checking this. The second check that + * KEYLEN < hashlen*(2^32-1) + * is obviously also not needed. Because with our allowed + * parameters KEYLEN is always less or equal to HASHLEN so that we + * do not need to iterate at all. + */ + log_assert (gcry_md_get_algo_dlen (hash_algo) == hashlen); + { + gcry_md_hd_t hash_hd; + err = gcry_md_open (&hash_hd, hash_algo, 0); + if (err) + goto leave; + gcry_md_write(hash_hd, secret, secretlen); + gcry_md_write(hash_hd, "\x00\x00\x00\x01", 4); /* counter */ + err = hash_ecc_cms_shared_info (hash_hd, wrap_algo_str, keylen, NULL, 0); + gcry_md_final (hash_hd); + log_assert (keylen <= sizeof key && keylen <= hashlen); + memcpy (key, gcry_md_read (hash_hd, 0), keylen); + gcry_md_close (hash_hd); + if (err) + goto leave; + } + + if (DBG_CRYPTO) + log_printhex (key, keylen, "KEK .....:"); + + /* Wrap the key. */ + if ((dek->keylen % 8) || dek->keylen < 16) + { + log_error ("%s: can't use a session key of %u bytes\n", + __func__, dek->keylen); + err = gpg_error (GPG_ERR_BAD_DATA); + goto leave; + } + + resultlen = dek->keylen + 8; + result = xtrymalloc_secure (resultlen); + if (!result) + { + err = gpg_error_from_syserror (); + goto leave; + } + + err = gcry_cipher_open (&cipher_hd, cipher_algo, GCRY_CIPHER_MODE_AESWRAP, 0); + if (err) + { + log_error ("%s: failed to initialize AESWRAP: %s\n", + __func__, gpg_strerror (err)); + goto leave; + } + + err = gcry_cipher_setkey (cipher_hd, key, keylen); + wipememory (key, sizeof key); + if (err) + { + log_error ("%s: failed in gcry_cipher_setkey: %s\n", + __func__, gpg_strerror (err)); + goto leave; + } + + err = gcry_cipher_encrypt (cipher_hd, result, resultlen, + dek->key, dek->keylen); + if (err) + { + log_error ("%s: failed in gcry_cipher_encrypt: %s\n", + __func__, gpg_strerror (err)); + goto leave; + } + + if (DBG_CRYPTO) + log_printhex (result, resultlen, "w(CEK) ..:"); + + err = gcry_sexp_build (r_encval, NULL, + "(enc-val(ecdh(e%b)(s%b)(encr-algo%s)(wrap-algo%s)))", + (int)pubkeylen, pubkey, + (int)resultlen, result, + encr_algo_str, + wrap_algo_str, + NULL); + if (err) + log_error ("%s: failed building final S-exp: %s\n", + __func__, gpg_strerror (err)); + + leave: + gcry_cipher_close (cipher_hd); + wipememory (key, sizeof key); + xfree (result); + xfree (ioarray[0].data); + xfree (ioarray[1].data); + gcry_sexp_release (s_data); + gcry_sexp_release (s_encr); + xfree (curvebuf); + return err; +} + + /* Encrypt the DEK under the key contained in CERT and return it as a - canonical S-Exp in encval. */ + * canonical S-expressions at ENCVAL. PK_ALGO is the public key + * algorithm which the caller has already retrieved from CERT. */ static int -encrypt_dek (const DEK dek, ksba_cert_t cert, unsigned char **encval) +encrypt_dek (const DEK dek, ksba_cert_t cert, int pk_algo, + unsigned char **encval) { gcry_sexp_t s_ciph, s_data, s_pkey; int rc; @@ -198,21 +473,41 @@ encrypt_dek (const DEK dek, ksba_cert_t cert, unsigned char **encval) return rc; } + if (DBG_CRYPTO) + { + log_printsexp (" pubkey:", s_pkey); + log_printhex (dek->key, dek->keylen, "CEK .....:"); + } + /* Put the encoded cleartext into a simple list. */ s_data = NULL; /* (avoid compiler warning) */ - rc = encode_session_key (dek, &s_data); - if (rc) + if (pk_algo == GCRY_PK_ECC) { - gcry_sexp_release (s_pkey); - log_error ("encode_session_key failed: %s\n", gpg_strerror (rc)); - return rc; + if (!(opt.compat_flags & COMPAT_ALLOW_ECC_ENCR)) + rc = gpg_error (GPG_ERR_NOT_SUPPORTED); + else + rc = ecdh_encrypt (dek, s_pkey, &s_ciph); } + else + { + rc = encode_session_key (dek, &s_data); + if (rc) + { + log_error ("encode_session_key failed: %s\n", gpg_strerror (rc)); + return rc; + } + if (DBG_CRYPTO) + log_printsexp (" data:", s_data); - /* pass it to libgcrypt */ - rc = gcry_pk_encrypt (&s_ciph, s_data, s_pkey); + /* pass it to libgcrypt */ + rc = gcry_pk_encrypt (&s_ciph, s_data, s_pkey); + } gcry_sexp_release (s_data); gcry_sexp_release (s_pkey); + if (DBG_CRYPTO) + log_printsexp ("enc-val:", s_ciph); + /* Reformat it. */ if (!rc) { @@ -387,7 +682,7 @@ gpgsm_encrypt (ctrl_t ctrl, certlist_t recplist, int data_fd, estream_t out_fp) err = ksba_cms_set_reader_writer (cms, reader, writer); if (err) { - log_debug ("ksba_cms_set_reader_writer failed: %s\n", + log_error ("ksba_cms_set_reader_writer failed: %s\n", gpg_strerror (err)); rc = err; goto leave; @@ -402,7 +697,7 @@ gpgsm_encrypt (ctrl_t ctrl, certlist_t recplist, int data_fd, estream_t out_fp) err = ksba_cms_set_content_type (cms, 1, KSBA_CT_DATA); if (err) { - log_debug ("ksba_cms_set_content_type failed: %s\n", + log_error ("ksba_cms_set_content_type failed: %s\n", gpg_strerror (err)); rc = err; goto leave; @@ -500,7 +795,7 @@ gpgsm_encrypt (ctrl_t ctrl, certlist_t recplist, int data_fd, estream_t out_fp) && !gnupg_pk_is_compliant (CO_DE_VS, pk_algo, 0, NULL, nbits, NULL)) compliant = 0; - rc = encrypt_dek (dek, cl->cert, &encval); + rc = encrypt_dek (dek, cl->cert, pk_algo, &encval); if (rc) { audit_log_cert (ctrl->audit, AUDIT_ENCRYPTED_TO, cl->cert, rc); diff --git a/sm/fingerprint.c b/sm/fingerprint.c index 2e01cf1c0..ce0830e29 100644 --- a/sm/fingerprint.c +++ b/sm/fingerprint.c @@ -219,20 +219,25 @@ gpgsm_get_keygrip_hexstring (ksba_cert_t cert) /* Return the PK algorithm used by CERT as well as the length in bits - of the public key at NBITS. */ + * of the public key at NBITS. If R_CURVE is not NULL and an ECC + * algorithm is used the name or OID of the curve is stored there; the + * caller needs to free this value. */ int -gpgsm_get_key_algo_info (ksba_cert_t cert, unsigned int *nbits) +gpgsm_get_key_algo_info2 (ksba_cert_t cert, unsigned int *nbits, char **r_curve) { gcry_sexp_t s_pkey; int rc; ksba_sexp_t p; size_t n; gcry_sexp_t l1, l2; + const char *curve; const char *name; char namebuf[128]; if (nbits) *nbits = 0; + if (r_curve) + *r_curve = NULL; p = ksba_cert_get_public_key (cert); if (!p) @@ -258,6 +263,24 @@ gpgsm_get_key_algo_info (ksba_cert_t cert, unsigned int *nbits) gcry_sexp_release (s_pkey); return 0; } + + if (r_curve) + { + curve = gcry_pk_get_curve (l1, 0, NULL); + if (curve) + { + name = openpgp_oid_to_curve (openpgp_curve_to_oid (curve, + NULL, NULL), 0); + *r_curve = xtrystrdup (name? name : curve); + if (!*r_curve) + { + gcry_sexp_release (l1); + gcry_sexp_release (s_pkey); + return 0; /* Out of core. */ + } + } + } + l2 = gcry_sexp_cadr (l1); gcry_sexp_release (l1); l1 = l2; @@ -277,6 +300,21 @@ gpgsm_get_key_algo_info (ksba_cert_t cert, unsigned int *nbits) } +int +gpgsm_get_key_algo_info (ksba_cert_t cert, unsigned int *nbits) +{ + return gpgsm_get_key_algo_info2 (cert, nbits, NULL); +} + + +/* Return true if CERT is an ECC key. */ +int +gpgsm_is_ecc_key (ksba_cert_t cert) +{ + return GCRY_PK_ECC == gpgsm_get_key_algo_info2 (cert, NULL, NULL); +} + + /* This is a wrapper around pubkey_algo_string which takes a KSBA * certificate instead of a Gcrypt public key. Note that this * function may return NULL on error. */ diff --git a/sm/gpgsm.c b/sm/gpgsm.c index 27168904c..473ef5e09 100644 --- a/sm/gpgsm.c +++ b/sm/gpgsm.c @@ -463,6 +463,7 @@ static struct debug_flags_s debug_flags [] = static struct compatibility_flags_s compatibility_flags [] = { { COMPAT_ALLOW_KA_TO_ENCR, "allow-ka-to-encr" }, + { COMPAT_ALLOW_ECC_ENCR, "allow-ecc-encr" }, { 0, NULL } }; @@ -494,7 +495,7 @@ static int default_include_certs = DEFAULT_INCLUDE_CERTS; static int default_validation_model; /* The default cipher algo. */ -#define DEFAULT_CIPHER_ALGO "AES" +#define DEFAULT_CIPHER_ALGO "AES256" static char *build_list (const char *text, @@ -515,6 +516,7 @@ our_pk_test_algo (int algo) { case GCRY_PK_RSA: case GCRY_PK_ECDSA: + case GCRY_PK_EDDSA: return gcry_pk_test_algo (algo); default: return 1; @@ -1530,7 +1532,7 @@ main ( int argc, char **argv) set_debug (); if (opt.verbose) /* Print the compatibility flags. */ parse_compatibility_flags (NULL, &opt.compat_flags, compatibility_flags); - gnupg_set_compliance_extra_info (opt.min_rsa_length); + gnupg_set_compliance_extra_info (CO_EXTRA_INFO_MIN_RSA, opt.min_rsa_length); /* Although we always use gpgsm_exit, we better install a regualr exit handler so that at least the secure memory gets wiped diff --git a/sm/gpgsm.h b/sm/gpgsm.h index 53ef165a1..0735fcb22 100644 --- a/sm/gpgsm.h +++ b/sm/gpgsm.h @@ -181,6 +181,7 @@ struct * policies: 1.3.6.1.4.1.7924.1.1:N: */ #define COMPAT_ALLOW_KA_TO_ENCR 1 +#define COMPAT_ALLOW_ECC_ENCR 2 /* Forward declaration for an object defined in server.c */ @@ -236,6 +237,7 @@ struct certlist_s ksba_cert_t cert; int is_encrypt_to; /* True if the certificate has been set through the --encrypto-to option. */ + int pk_algo; /* The PK_ALGO from CERT or 0 if not yet known. */ int hash_algo; /* Used to track the hash algorithm to use. */ const char *hash_algo_oid; /* And the corresponding OID. */ }; @@ -281,6 +283,9 @@ unsigned long gpgsm_get_short_fingerprint (ksba_cert_t cert, unsigned char *gpgsm_get_keygrip (ksba_cert_t cert, unsigned char *array); char *gpgsm_get_keygrip_hexstring (ksba_cert_t cert); int gpgsm_get_key_algo_info (ksba_cert_t cert, unsigned int *nbits); +int gpgsm_get_key_algo_info2 (ksba_cert_t cert, unsigned int *nbits, + char **r_curve); +int gpgsm_is_ecc_key (ksba_cert_t cert); char *gpgsm_pubkey_algo_string (ksba_cert_t cert, int *r_algoid); char *gpgsm_get_certid (ksba_cert_t cert); @@ -387,6 +392,10 @@ int gpgsm_encrypt (ctrl_t ctrl, certlist_t recplist, int in_fd, estream_t out_fp); /*-- decrypt.c --*/ +gpg_error_t hash_ecc_cms_shared_info (gcry_md_hd_t hash_hd, + const char *wrap_algo_str, + unsigned int keylen, + const void *ukm, unsigned int ukmlen); int gpgsm_decrypt (ctrl_t ctrl, int in_fd, estream_t out_fp); /*-- certreqgen.c --*/ diff --git a/sm/keylist.c b/sm/keylist.c index 2d51aa74d..19e7a76c8 100644 --- a/sm/keylist.c +++ b/sm/keylist.c @@ -247,7 +247,7 @@ print_key_data (ksba_cert_t cert, estream_t fp) } static void -print_capabilities (ksba_cert_t cert, estream_t fp) +print_capabilities (ksba_cert_t cert, int algo, estream_t fp) { gpg_error_t err; unsigned int use; @@ -299,7 +299,7 @@ print_capabilities (ksba_cert_t cert, estream_t fp) /* We need to returned the faked key usage to frontends so that they * can select the right key. Note that we don't do this for the * human readable keyUsage. */ - if ((opt.compat_flags & COMPAT_ALLOW_KA_TO_ENCR) + if ((algo == GCRY_PK_ECC || (opt.compat_flags & COMPAT_ALLOW_KA_TO_ENCR)) && (use & KSBA_KEYUSAGE_KEY_AGREEMENT)) is_encr = 1; @@ -408,6 +408,7 @@ list_cert_colon (ctrl_t ctrl, ksba_cert_t cert, unsigned int validity, gpg_error_t valerr; int algo; unsigned int nbits; + char *curve = NULL; const char *chain_id; char *chain_id_buffer = NULL; int is_root = 0; @@ -499,7 +500,7 @@ list_cert_colon (ctrl_t ctrl, ksba_cert_t cert, unsigned int validity, if (*truststring) es_fputs (truststring, fp); - algo = gpgsm_get_key_algo_info (cert, &nbits); + algo = gpgsm_get_key_algo_info2 (cert, &nbits, &curve); es_fprintf (fp, ":%u:%d:%s:", nbits, algo, fpr+24); ksba_cert_get_validity (cert, 0, t); @@ -538,7 +539,7 @@ list_cert_colon (ctrl_t ctrl, ksba_cert_t cert, unsigned int validity, /* Field 11, signature class - not used */ es_putc (':', fp); /* Field 12, capabilities: */ - print_capabilities (cert, fp); + print_capabilities (cert, algo, fp); es_putc (':', fp); /* Field 13, not used: */ es_putc (':', fp); @@ -563,6 +564,8 @@ list_cert_colon (ctrl_t ctrl, ksba_cert_t cert, unsigned int validity, } es_putc (':', fp); /* End of field 15. */ es_putc (':', fp); /* End of field 16. */ + if (curve) + es_fputs (curve, fp); es_putc (':', fp); /* End of field 17. */ print_compliance_flags (cert, algo, nbits, fp); es_putc (':', fp); /* End of field 18. */ @@ -626,6 +629,7 @@ list_cert_colon (ctrl_t ctrl, ksba_cert_t cert, unsigned int validity, xfree (p); } xfree (kludge_uid); + xfree (curve); } @@ -829,12 +833,11 @@ list_cert_raw (ctrl_t ctrl, KEYDB_HANDLE hd, es_fprintf (fp, " hashAlgo: %s%s%s%s\n", oid, s?" (":"",s?s:"",s?")":""); { - const char *algoname; - unsigned int nbits; + char *algostr; - algoname = gcry_pk_algo_name (gpgsm_get_key_algo_info (cert, &nbits)); - es_fprintf (fp, " keyType: %u bit %s\n", - nbits, algoname? algoname:"?"); + algostr = gpgsm_pubkey_algo_string (cert, NULL); + es_fprintf (fp, " keyType: %s\n", algostr? algostr : "[error]"); + xfree (algostr); } /* subjectKeyIdentifier */ @@ -1192,15 +1195,13 @@ list_cert_std (ctrl_t ctrl, ksba_cert_t cert, estream_t fp, int have_secret, { - const char *algoname; - unsigned int nbits; + char *algostr; - algoname = gcry_pk_algo_name (gpgsm_get_key_algo_info (cert, &nbits)); - es_fprintf (fp, " key type: %u bit %s\n", - nbits, algoname? algoname:"?"); + algostr = gpgsm_pubkey_algo_string (cert, NULL); + es_fprintf (fp, " key type: %s\n", algostr? algostr : "[error]"); + xfree (algostr); } - err = ksba_cert_get_key_usage (cert, &kusage); if (gpg_err_code (err) != GPG_ERR_NO_DATA) { @@ -101,7 +101,7 @@ setup_pinentry_env (void) function ignores missing parameters so that it can also be used to create an siginfo value as expected by ksba_certreq_set_siginfo. To create a siginfo s-expression a public-key s-expression may be - used instead of a sig-val. We only support RSA for now. */ + used instead of a sig-val. */ gpg_error_t transform_sigval (const unsigned char *sigval, size_t sigvallen, int mdalgo, unsigned char **r_newsigval, size_t *r_newsigvallen) @@ -111,11 +111,15 @@ transform_sigval (const unsigned char *sigval, size_t sigvallen, int mdalgo, size_t buflen, toklen; int depth, last_depth1, last_depth2; int is_pubkey = 0; - const unsigned char *rsa_s = NULL; - size_t rsa_s_len = 0; + int pkalgo; + const unsigned char *rsa_s, *ecc_r, *ecc_s; + size_t rsa_s_len, ecc_r_len, ecc_s_len; const char *oid; gcry_sexp_t sexp; + rsa_s = ecc_r = ecc_s = NULL; + rsa_s_len = ecc_r_len = ecc_s_len = 0; + *r_newsigval = NULL; if (r_newsigvallen) *r_newsigvallen = 0; @@ -137,7 +141,15 @@ transform_sigval (const unsigned char *sigval, size_t sigvallen, int mdalgo, return err; if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen))) return err; - if (!tok || toklen != 3 || memcmp ("rsa", tok, toklen)) + if (!tok) + return gpg_error (GPG_ERR_WRONG_PUBKEY_ALGO); + if (toklen == 3 && !memcmp ("rsa", tok, 3)) + pkalgo = GCRY_PK_RSA; + else if (toklen == 3 && !memcmp ("ecc", tok, 3)) + pkalgo = GCRY_PK_ECC; + else if (toklen == 5 && !memcmp ("ecdsa", tok, 5)) + pkalgo = GCRY_PK_ECC; + else return gpg_error (GPG_ERR_WRONG_PUBKEY_ALGO); last_depth1 = depth; @@ -150,8 +162,8 @@ transform_sigval (const unsigned char *sigval, size_t sigvallen, int mdalgo, return err; if (tok && toklen == 1) { - const unsigned char **mpi; - size_t *mpi_len; + const unsigned char **mpi = NULL; + size_t *mpi_len = NULL; switch (*tok) { @@ -161,6 +173,25 @@ transform_sigval (const unsigned char *sigval, size_t sigvallen, int mdalgo, if (mpi && *mpi) return gpg_error (GPG_ERR_DUP_VALUE); + switch (*tok) + { + case 's': + if (pkalgo == GCRY_PK_RSA) + { + mpi = &rsa_s; + mpi_len = &rsa_s_len; + } + else if (pkalgo == GCRY_PK_ECC || pkalgo == GCRY_PK_EDDSA) + { + mpi = &ecc_s; + mpi_len = &ecc_s_len; + } + break; + + case 'r': mpi = &ecc_r; mpi_len = &ecc_r_len; break; + default: mpi = NULL; mpi_len = NULL; break; + } + if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen))) return err; if (tok && mpi) @@ -181,34 +212,62 @@ transform_sigval (const unsigned char *sigval, size_t sigvallen, int mdalgo, if (err) return err; - /* Map the hash algorithm to an OID. */ - switch (mdalgo) + if (0) + ; /* Just to align it with the code in 2.3. */ + else { - case GCRY_MD_SHA1: - oid = "1.2.840.113549.1.1.5"; /* sha1WithRSAEncryption */ - break; + /* Map the hash algorithm to an OID. */ + if (mdalgo < 0 || mdalgo > (1<<15) || pkalgo < 0 || pkalgo > (1<<15)) + return gpg_error (GPG_ERR_DIGEST_ALGO); + + switch (mdalgo | (pkalgo << 16)) + { + case GCRY_MD_SHA1 | (GCRY_PK_RSA << 16): + oid = "1.2.840.113549.1.1.5"; /* sha1WithRSAEncryption */ + break; + + case GCRY_MD_SHA256 | (GCRY_PK_RSA << 16): + oid = "1.2.840.113549.1.1.11"; /* sha256WithRSAEncryption */ + break; + + case GCRY_MD_SHA384 | (GCRY_PK_RSA << 16): + oid = "1.2.840.113549.1.1.12"; /* sha384WithRSAEncryption */ + break; + + case GCRY_MD_SHA512 | (GCRY_PK_RSA << 16): + oid = "1.2.840.113549.1.1.13"; /* sha512WithRSAEncryption */ + break; + + case GCRY_MD_SHA224 | (GCRY_PK_ECC << 16): + oid = "1.2.840.10045.4.3.1"; /* ecdsa-with-sha224 */ + break; - case GCRY_MD_SHA256: - oid = "1.2.840.113549.1.1.11"; /* sha256WithRSAEncryption */ - break; + case GCRY_MD_SHA256 | (GCRY_PK_ECC << 16): + oid = "1.2.840.10045.4.3.2"; /* ecdsa-with-sha256 */ + break; - case GCRY_MD_SHA384: - oid = "1.2.840.113549.1.1.12"; /* sha384WithRSAEncryption */ - break; + case GCRY_MD_SHA384 | (GCRY_PK_ECC << 16): + oid = "1.2.840.10045.4.3.3"; /* ecdsa-with-sha384 */ + break; - case GCRY_MD_SHA512: - oid = "1.2.840.113549.1.1.13"; /* sha512WithRSAEncryption */ - break; + case GCRY_MD_SHA512 | (GCRY_PK_ECC << 16): + oid = "1.2.840.10045.4.3.4"; /* ecdsa-with-sha512 */ + break; - default: - return gpg_error (GPG_ERR_DIGEST_ALGO); + default: + return gpg_error (GPG_ERR_DIGEST_ALGO); + } } - if (rsa_s && !is_pubkey) + if (is_pubkey) + err = gcry_sexp_build (&sexp, NULL, "(sig-val(%s))", oid); + else if (pkalgo == GCRY_PK_RSA) err = gcry_sexp_build (&sexp, NULL, "(sig-val(%s(s%b)))", oid, (int)rsa_s_len, rsa_s); - else - err = gcry_sexp_build (&sexp, NULL, "(sig-val(%s))", oid); + else if (pkalgo == GCRY_PK_ECC || pkalgo == GCRY_PK_EDDSA) + err = gcry_sexp_build (&sexp, NULL, "(sig-val(%s(r%b)(s%b)))", oid, + (int)ecc_r_len, ecc_r, (int)ecc_s_len, ecc_s); + if (err) return err; err = make_canon_sexp (sexp, r_newsigval, r_newsigvallen); @@ -430,6 +430,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 +439,11 @@ 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; + + pk_algo = gpgsm_get_key_algo_info (cl->cert, &nbits); + cl->pk_algo = pk_algo; if (opt.forced_digest_algo) { @@ -446,7 +452,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 +477,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 +501,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, 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 (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"), @@ -644,13 +658,16 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist, } /* 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) @@ -777,17 +794,23 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist, 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) + rc = gpg_error_from_syserror (); xfree (fpr); if (rc) { @@ -813,7 +836,6 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist, audit_log (ctrl->audit, AUDIT_SIGNING_DONE); log_info ("signature created\n"); - leave: if (rc) log_error ("error creating signature: %s <%s>\n", diff --git a/sm/verify.c b/sm/verify.c index 5510f42cb..ea2192440 100644 --- a/sm/verify.c +++ b/sm/verify.c @@ -459,6 +459,10 @@ gpgsm_verify (ctrl_t ctrl, int in_fd, int data_fd, estream_t out_fp) pkfpr = gpgsm_get_fingerprint_hexstring (cert, GCRY_MD_SHA1); pkalgostr = gpgsm_pubkey_algo_string (cert, NULL); pkalgo = gpgsm_get_key_algo_info (cert, &nbits); + /* Remap the ECC algo to the algo we use. Note that EdDSA has + * already been mapped. */ + if (pkalgo == GCRY_PK_ECC) + pkalgo = GCRY_PK_ECDSA; log_info (_("Signature made ")); if (*sigtime) |