diff --git a/sm/call-agent.c b/sm/call-agent.c index 5f4236b69..ec8020517 100644 --- a/sm/call-agent.c +++ b/sm/call-agent.c @@ -76,6 +76,13 @@ struct import_key_parm_s size_t keylen; }; +struct sethash_inq_parm_s +{ + assuan_context_t ctx; + const void *data; + size_t datalen; +}; + struct default_inq_parm_s { ctrl_t ctrl; @@ -257,8 +264,29 @@ default_inq_cb (void *opaque, const char *line) +/* This is the inquiry callback required by the SETHASH command. */ +static gpg_error_t +sethash_inq_cb (void *opaque, const char *line) +{ + gpg_error_t err = 0; + struct sethash_inq_parm_s *parm = opaque; + + if (has_leading_keyword (line, "TBSDATA")) + { + err = assuan_send_data (parm->ctx, parm->data, parm->datalen); + } + else + log_error ("ignoring gpg-agent inquiry '%s'\n", line); + + return err; +} + + /* Call the agent to do a sign operation using the key identified by - the hex string KEYGRIP. */ + * the hex string KEYGRIP. If DIGESTALGO is given (DIGEST,DIGESTLEN) + * gives the to be signed hash created using the given algo. If + * DIGESTALGO is not given (i.e. zero) (DIGEST,DIGESTALGO) give the + * entire data to-be-signed. */ int gpgsm_agent_pksign (ctrl_t ctrl, const char *keygrip, const char *desc, unsigned char *digest, size_t digestlen, int digestalgo, @@ -277,7 +305,7 @@ gpgsm_agent_pksign (ctrl_t ctrl, const char *keygrip, const char *desc, inq_parm.ctrl = ctrl; inq_parm.ctx = agent_ctx; - if (digestlen*2 + 50 > DIM(line)) + if (digestalgo && digestlen*2 + 50 > DIM(line)) return gpg_error (GPG_ERR_GENERAL); rc = assuan_transact (agent_ctx, "RESET", NULL, NULL, NULL, NULL, NULL, NULL); @@ -298,11 +326,26 @@ gpgsm_agent_pksign (ctrl_t ctrl, const char *keygrip, const char *desc, return rc; } - sprintf (line, "SETHASH %d ", digestalgo); - p = line + strlen (line); - for (i=0; i < digestlen ; i++, p += 2 ) - sprintf (p, "%02X", digest[i]); - rc = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL); + if (!digestalgo) + { + struct sethash_inq_parm_s sethash_inq_parm; + + sethash_inq_parm.ctx = agent_ctx; + sethash_inq_parm.data = digest; + sethash_inq_parm.datalen = digestlen; + rc = assuan_transact (agent_ctx, "SETHASH --inquire", + NULL, NULL, sethash_inq_cb, &sethash_inq_parm, + NULL, NULL); + } + else + { + snprintf (line, sizeof line, "SETHASH %d ", digestalgo); + p = line + strlen (line); + for (i=0; i < digestlen ; i++, p += 2 ) + sprintf (p, "%02X", digest[i]); + rc = assuan_transact (agent_ctx, line, + NULL, NULL, NULL, NULL, NULL, NULL); + } if (rc) return rc; diff --git a/sm/certcheck.c b/sm/certcheck.c index 3dcac2ffa..3604ac788 100644 --- a/sm/certcheck.c +++ b/sm/certcheck.c @@ -360,6 +360,8 @@ gpgsm_check_cert_sig (ksba_cert_t issuer_cert, ksba_cert_t cert) int use_eddsa = 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; @@ -367,6 +369,14 @@ gpgsm_check_cert_sig (ksba_cert_t issuer_cert, ksba_cert_t cert) use_eddsa = 1; else if (algoid && !strcmp (algoid, "1.3.101.113")) use_eddsa = 2; + 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 in certificate\n", diff --git a/sm/certreqgen.c b/sm/certreqgen.c index 3fbab2d50..e54569ac8 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 @@ -835,6 +836,8 @@ create_request (ctrl_t ctrl, ksba_isotime_t atime; int certmode = 0; int mdalgo; + membuf_t tbsbuffer; + membuf_t *tbsmb = NULL; err = ksba_certreq_new (&cr); if (err) @@ -842,21 +845,31 @@ create_request (ctrl_t ctrl, len = gcry_sexp_canon_len (public, 0, NULL, NULL); if (get_pk_algo_from_canon_sexp (public, len) == GCRY_PK_EDDSA) - mdalgo = GCRY_MD_SHA512; - else if ((string = get_parameter_value (para, pHASHALGO, 0))) - mdalgo = gcry_md_map_name (string); - else - mdalgo = GCRY_MD_SHA256; - rc = gcry_md_open (&md, mdalgo, 0); - if (rc) { - log_error ("md_open failed: %s\n", gpg_strerror (rc)); - goto leave; + 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 + { + if ((string = get_parameter_value (para, pHASHALGO, 0))) + mdalgo = gcry_md_map_name (string); + else + mdalgo = GCRY_MD_SHA256; + rc = gcry_md_open (&md, mdalgo, 0); + if (rc) + { + log_error ("md_open failed: %s\n", gpg_strerror (rc)); + goto leave; + } + if (DBG_HASHING) + gcry_md_debug (md, "cr.cri"); + ksba_certreq_set_hash_function (cr, HASH_FNC, md); } - if (DBG_HASHING) - gcry_md_debug (md, "cr.cri"); - ksba_certreq_set_hash_function (cr, HASH_FNC, md); ksba_certreq_set_writer (cr, writer); err = ksba_certreq_add_subject (cr, get_parameter_value (para, pNAMEDN, 0)); @@ -1150,6 +1163,7 @@ create_request (ctrl_t ctrl, { unsigned char *siginfo; + err = transform_sigval (sigkey, gcry_sexp_canon_len (sigkey, 0, NULL, NULL), mdalgo, &siginfo, NULL); @@ -1320,6 +1334,8 @@ create_request (ctrl_t ctrl, char hexgrip[41]; unsigned char *sigval, *newsigval; size_t siglen; + void *tbsdata; + size_t tbsdatalen; n = gcry_sexp_canon_len (sigkey, 0, NULL, NULL); if (!n) @@ -1348,11 +1364,26 @@ create_request (ctrl_t ctrl, certmode? "certificate":"CSR", hexgrip); if (carddirect && !certmode) - rc = gpgsm_scd_pksign (ctrl, carddirect, NULL, - gcry_md_read (md, mdalgo), - gcry_md_get_algo_dlen (mdalgo), - mdalgo, - &sigval, &siglen); + { + if (tbsmb) + { + tbsdata = get_membuf (tbsmb, &tbsdatalen); + tbsmb = NULL; + if (!tbsdata) + rc = gpg_error_from_syserror (); + else + rc = gpgsm_scd_pksign (ctrl, carddirect, NULL, + tbsdata, tbsdatalen, 0, + &sigval, &siglen); + xfree (tbsdata); + } + else + rc = gpgsm_scd_pksign (ctrl, carddirect, NULL, + gcry_md_read (md, mdalgo), + gcry_md_get_algo_dlen (mdalgo), + mdalgo, + &sigval, &siglen); + } else { char *orig_codeset; @@ -1364,11 +1395,25 @@ create_request (ctrl_t ctrl, " the passphrase for the key you just created once" " more.\n")); i18n_switchback (orig_codeset); - rc = gpgsm_agent_pksign (ctrl, hexgrip, desc, - gcry_md_read(md, mdalgo), - gcry_md_get_algo_dlen (mdalgo), - mdalgo, - &sigval, &siglen); + if (tbsmb) + { + tbsdata = get_membuf (tbsmb, &tbsdatalen); + tbsmb = NULL; + if (!tbsdata) + rc = gpg_error_from_syserror (); + else + rc = gpgsm_agent_pksign (ctrl, hexgrip, desc, + tbsdata, tbsdatalen, 0, + + &sigval, &siglen); + xfree (tbsdata); + } + else + rc = gpgsm_agent_pksign (ctrl, hexgrip, desc, + gcry_md_read(md, mdalgo), + gcry_md_get_algo_dlen (mdalgo), + mdalgo, + &sigval, &siglen); xfree (desc); } if (rc) @@ -1398,6 +1443,8 @@ create_request (ctrl_t ctrl, leave: + if (tbsmb) + xfree (get_membuf (tbsmb, NULL)); gcry_md_close (md); ksba_certreq_release (cr); return rc; diff --git a/sm/misc.c b/sm/misc.c index 954529390..99f6da63c 100644 --- a/sm/misc.c +++ b/sm/misc.c @@ -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) @@ -115,6 +115,7 @@ transform_sigval (const unsigned char *sigval, size_t sigvallen, int mdalgo, size_t rsa_s_len, ecc_r_len, ecc_s_len; const char *oid; gcry_sexp_t sexp; + const char *eddsa_curve = NULL; rsa_s = ecc_r = ecc_s = NULL; rsa_s_len = ecc_r_len = ecc_s_len = 0; @@ -144,6 +145,8 @@ transform_sigval (const unsigned char *sigval, size_t sigvallen, int mdalgo, 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 if (toklen == 5 && !memcmp ("eddsa", tok, 5)) @@ -191,6 +194,18 @@ transform_sigval (const unsigned char *sigval, size_t sigvallen, int mdalgo, *mpi_len = toklen; } } + else if (toklen == 5 && !memcmp (tok, "curve", 5)) + { + if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen))) + return err; + if ((toklen == 7 && !memcmp (tok, "Ed25519", 7)) + || (toklen == 22 && !memcmp (tok, "1.3.6.1.4.1.11591.15.1", 22)) + || (toklen == 11 && !memcmp (tok, "1.3.101.112", 11))) + eddsa_curve = "1.3.101.112"; + else if ((toklen == 5 && !memcmp (tok, "Ed448", 5)) + || (toklen == 11 && !memcmp (tok, "1.3.101.113", 11))) + eddsa_curve = "1.3.101.113"; + } /* Skip to the end of the list. */ last_depth2 = depth; @@ -203,50 +218,55 @@ transform_sigval (const unsigned char *sigval, size_t sigvallen, int mdalgo, if (err) return err; - /* 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)) + if (eddsa_curve) + oid = eddsa_curve; + else { - case GCRY_MD_SHA1 | (GCRY_PK_RSA << 16): - 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); - case GCRY_MD_SHA256 | (GCRY_PK_RSA << 16): - oid = "1.2.840.113549.1.1.11"; /* sha256WithRSAEncryption */ - break; + 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_SHA384 | (GCRY_PK_RSA << 16): - oid = "1.2.840.113549.1.1.12"; /* sha384WithRSAEncryption */ - break; + case GCRY_MD_SHA256 | (GCRY_PK_RSA << 16): + oid = "1.2.840.113549.1.1.11"; /* sha256WithRSAEncryption */ + break; - case GCRY_MD_SHA512 | (GCRY_PK_RSA << 16): - oid = "1.2.840.113549.1.1.13"; /* sha512WithRSAEncryption */ - break; + case GCRY_MD_SHA384 | (GCRY_PK_RSA << 16): + oid = "1.2.840.113549.1.1.12"; /* sha384WithRSAEncryption */ + break; - case GCRY_MD_SHA224 | (GCRY_PK_ECC << 16): - oid = "1.2.840.10045.4.3.1"; /* ecdsa-with-sha224 */ - break; + case GCRY_MD_SHA512 | (GCRY_PK_RSA << 16): + oid = "1.2.840.113549.1.1.13"; /* sha512WithRSAEncryption */ + break; - case GCRY_MD_SHA256 | (GCRY_PK_ECC << 16): - oid = "1.2.840.10045.4.3.2"; /* ecdsa-with-sha256 */ - break; + case GCRY_MD_SHA224 | (GCRY_PK_ECC << 16): + oid = "1.2.840.10045.4.3.1"; /* ecdsa-with-sha224 */ + break; - case GCRY_MD_SHA384 | (GCRY_PK_ECC << 16): - oid = "1.2.840.10045.4.3.3"; /* ecdsa-with-sha384 */ - break; + case GCRY_MD_SHA256 | (GCRY_PK_ECC << 16): + oid = "1.2.840.10045.4.3.2"; /* ecdsa-with-sha256 */ + break; - case GCRY_MD_SHA512 | (GCRY_PK_ECC << 16): - oid = "1.2.840.10045.4.3.4"; /* ecdsa-with-sha512 */ - 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 | (GCRY_PK_EDDSA << 16): - oid = "1.3.101.112"; /* ed25519 */ - 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); + case GCRY_MD_SHA512 | (GCRY_PK_EDDSA << 16): + oid = "1.3.101.112"; /* ed25519 */ + break; + + default: + return gpg_error (GPG_ERR_DIGEST_ALGO); + } } if (is_pubkey)