gpg,agent: Support Ed448 signing.

* agent/pksign.c (do_encode_eddsa): First argument is NBITs,
so that it can support Ed448, as well as Ed25519.
(agent_pksign_do): Follow the change.
* agent/sexp-secret.c (fixup_when_ecc_private_key): No fix-up needed
for Ed448, it's only for classic curves.
* common/openpgp-oid.c (oidtable): Add Ed448.
* common/sexputil.c (get_pk_algo_from_key): Ed448 is only for EdDSA.
* g10/export.c (match_curve_skey_pk): Ed448 is for EdDSA.
* g10/keygen.c (gen_ecc): Support Ed448 with the name of "ed448".
(ask_algo, parse_key_parameter_part): Handle "ed448".
* g10/pkglue.c (pk_verify): Support Ed448.
(pk_check_secret_key): Support Ed448.
* g10/sign.c (hash_for): Defaults to SHA512 for Ed448.
(make_keysig_packet): Likewise.

Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
This commit is contained in:
NIIBE Yutaka 2020-06-24 10:05:03 +09:00
parent c94eea15d6
commit a763bb2580
8 changed files with 147 additions and 98 deletions

View File

@ -129,15 +129,20 @@ rfc6979_hash_algo_string (size_t mdlen)
/* Encode a message digest for use with the EdDSA algorithm /* Encode a message digest for use with the EdDSA algorithm
(i.e. curve Ed25519). */ (i.e. curve Ed25519). */
static gpg_error_t static gpg_error_t
do_encode_eddsa (const byte *md, size_t mdlen, gcry_sexp_t *r_hash) do_encode_eddsa (size_t nbits, const byte *md, size_t mdlen,
gcry_sexp_t *r_hash)
{ {
gpg_error_t err; gpg_error_t err;
gcry_sexp_t hash; gcry_sexp_t hash;
const char *fmt;
if (nbits == 448)
fmt = "(data(value %b))";
else
fmt = "(data(flags eddsa)(hash-algo sha512)(value %b))";
*r_hash = NULL; *r_hash = NULL;
err = gcry_sexp_build (&hash, NULL, err = gcry_sexp_build (&hash, NULL, fmt, (int)mdlen, md);
"(data(flags eddsa)(hash-algo sha512)(value %b))",
(int)mdlen, md);
if (!err) if (!err)
*r_hash = hash; *r_hash = hash;
return err; return err;
@ -482,7 +487,7 @@ agent_pksign_do (ctrl_t ctrl, const char *cache_nonce,
/* Put the hash into a sexp */ /* Put the hash into a sexp */
if (algo == GCRY_PK_EDDSA) if (algo == GCRY_PK_EDDSA)
err = do_encode_eddsa (data, datalen, err = do_encode_eddsa (gcry_pk_get_nbits (s_skey), data, datalen,
&s_hash); &s_hash);
else if (ctrl->digest.algo == MD_USER_TLS_MD5SHA1) else if (ctrl->digest.algo == MD_USER_TLS_MD5SHA1)
err = do_encode_raw_pkcs1 (data, datalen, err = do_encode_raw_pkcs1 (data, datalen,

View File

@ -83,6 +83,7 @@ fixup_when_ecc_private_key (unsigned char *buf, size_t *buflen_p)
return gpg_error (GPG_ERR_INV_SEXP); return gpg_error (GPG_ERR_INV_SEXP);
else if (!*s /* Leading 0x00 added at the front for classic curve */ else if (!*s /* Leading 0x00 added at the front for classic curve */
&& strcmp (curve_name, "Ed25519") && strcmp (curve_name, "Ed25519")
&& strcmp (curve_name, "Ed448")
&& strcmp (curve_name, "X448")) && strcmp (curve_name, "X448"))
{ {
size_t numsize; size_t numsize;

View File

@ -49,6 +49,7 @@ static struct {
{ "Curve25519", "1.3.6.1.4.1.3029.1.5.1", 255, "cv25519", PUBKEY_ALGO_ECDH }, { "Curve25519", "1.3.6.1.4.1.3029.1.5.1", 255, "cv25519", PUBKEY_ALGO_ECDH },
{ "Ed25519", "1.3.6.1.4.1.11591.15.1", 255, "ed25519", PUBKEY_ALGO_EDDSA }, { "Ed25519", "1.3.6.1.4.1.11591.15.1", 255, "ed25519", PUBKEY_ALGO_EDDSA },
{ "X448", "1.3.101.111", 448, "cv448", PUBKEY_ALGO_ECDH }, { "X448", "1.3.101.111", 448, "cv448", PUBKEY_ALGO_ECDH },
{ "Ed448", "1.3.101.113", 448, "ed448", PUBKEY_ALGO_EDDSA },
{ "NIST P-256", "1.2.840.10045.3.1.7", 256, "nistp256" }, { "NIST P-256", "1.2.840.10045.3.1.7", 256, "nistp256" },
{ "NIST P-384", "1.3.132.0.34", 384, "nistp384" }, { "NIST P-384", "1.3.132.0.34", 384, "nistp384" },

View File

@ -624,9 +624,10 @@ get_pk_algo_from_key (gcry_sexp_t key)
algo = gcry_pk_map_name (algoname); algo = gcry_pk_map_name (algoname);
if (algo == GCRY_PK_ECC) if (algo == GCRY_PK_ECC)
{ {
gcry_sexp_t l1 = gcry_sexp_find_token (list, "flags", 0); gcry_sexp_t l1;
int i; int i;
l1 = gcry_sexp_find_token (list, "flags", 0);
for (i = l1 ? gcry_sexp_length (l1)-1 : 0; i > 0; i--) for (i = l1 ? gcry_sexp_length (l1)-1 : 0; i > 0; i--)
{ {
s = gcry_sexp_nth_data (l1, i, &n); s = gcry_sexp_nth_data (l1, i, &n);
@ -640,6 +641,12 @@ get_pk_algo_from_key (gcry_sexp_t key)
} }
} }
gcry_sexp_release (l1); gcry_sexp_release (l1);
l1 = gcry_sexp_find_token (list, "curve", 0);
s = gcry_sexp_nth_data (l1, 1, &n);
if (n == 5 && !memcmp (s, "Ed448", 5))
algo = GCRY_PK_EDDSA;
gcry_sexp_release (l1);
} }
out: out:

View File

@ -568,6 +568,8 @@ match_curve_skey_pk (gcry_sexp_t s_key, PKT_public_key *pk)
log_error ("no curve name\n"); log_error ("no curve name\n");
return gpg_error (GPG_ERR_UNKNOWN_CURVE); return gpg_error (GPG_ERR_UNKNOWN_CURVE);
} }
if (!strcmp (curve_str, "Ed448"))
is_eddsa = 1;
oidstr = openpgp_curve_to_oid (curve_str, NULL, NULL); oidstr = openpgp_curve_to_oid (curve_str, NULL, NULL);
if (!oidstr) if (!oidstr)
{ {

View File

@ -1750,16 +1750,25 @@ gen_ecc (int algo, const char *curve, kbnode_t pub_root,
curve = "Ed25519"; curve = "Ed25519";
else if (!ascii_strcasecmp (curve, "cv448")) else if (!ascii_strcasecmp (curve, "cv448"))
curve = "X448"; curve = "X448";
else if (!ascii_strcasecmp (curve, "ed448"))
curve = "Ed448";
/* Note that we use the "comp" flag with EdDSA to request the use of /* Note that we use the "comp" flag with EdDSA to request the use of
a 0x40 compression prefix octet. */ a 0x40 compression prefix octet. */
if (algo == PUBKEY_ALGO_EDDSA) if (algo == PUBKEY_ALGO_EDDSA && !strcmp (curve, "Ed25519"))
keyparms = xtryasprintf keyparms = xtryasprintf
("(genkey(ecc(curve %zu:%s)(flags eddsa comp%s)))", ("(genkey(ecc(curve %zu:%s)(flags eddsa comp%s)))",
strlen (curve), curve, strlen (curve), curve,
(((keygen_flags & KEYGEN_FLAG_TRANSIENT_KEY) (((keygen_flags & KEYGEN_FLAG_TRANSIENT_KEY)
&& (keygen_flags & KEYGEN_FLAG_NO_PROTECTION))? && (keygen_flags & KEYGEN_FLAG_NO_PROTECTION))?
" transient-key" : "")); " transient-key" : ""));
else if (algo == PUBKEY_ALGO_EDDSA && !strcmp (curve, "Ed448"))
keyparms = xtryasprintf
("(genkey(ecc(curve %zu:%s)(flags comp%s)))",
strlen (curve), curve,
(((keygen_flags & KEYGEN_FLAG_TRANSIENT_KEY)
&& (keygen_flags & KEYGEN_FLAG_NO_PROTECTION))?
" transient-key" : ""));
else if (algo == PUBKEY_ALGO_ECDH && !strcmp (curve, "Curve25519")) else if (algo == PUBKEY_ALGO_ECDH && !strcmp (curve, "Curve25519"))
keyparms = xtryasprintf keyparms = xtryasprintf
("(genkey(ecc(curve %zu:%s)(flags djb-tweak comp%s)))", ("(genkey(ecc(curve %zu:%s)(flags djb-tweak comp%s)))",
@ -2326,6 +2335,8 @@ ask_algo (ctrl_t ctrl, int addmode, int *r_subkey_algo, unsigned int *r_usage,
{ {
if (!strcmp (algostr, "ed25519")) if (!strcmp (algostr, "ed25519"))
kpi->algo = PUBKEY_ALGO_EDDSA; kpi->algo = PUBKEY_ALGO_EDDSA;
else if (!strcmp (algostr, "ed448"))
kpi->algo = PUBKEY_ALGO_EDDSA;
else if (!strcmp (algostr, "cv25519")) else if (!strcmp (algostr, "cv25519"))
kpi->algo = PUBKEY_ALGO_ECDH; kpi->algo = PUBKEY_ALGO_ECDH;
else if (!strcmp (algostr, "cv448")) else if (!strcmp (algostr, "cv448"))
@ -3481,6 +3492,8 @@ parse_key_parameter_part (ctrl_t ctrl,
{ {
if (!strcmp (algostr, "ed25519")) if (!strcmp (algostr, "ed25519"))
algo = PUBKEY_ALGO_EDDSA; algo = PUBKEY_ALGO_EDDSA;
else if (!strcmp (algostr, "ed448"))
kpi->algo = PUBKEY_ALGO_EDDSA;
else if (!strcmp (algostr, "cv25519")) else if (!strcmp (algostr, "cv25519"))
algo = PUBKEY_ALGO_ECDH; algo = PUBKEY_ALGO_ECDH;
else if (!strcmp (algostr, "cv448")) else if (!strcmp (algostr, "cv448"))
@ -3611,6 +3624,7 @@ parse_key_parameter_part (ctrl_t ctrl,
* dsa2048 := DSA with 2048 bit. * dsa2048 := DSA with 2048 bit.
* elg2048 := Elgamal with 2048 bit. * elg2048 := Elgamal with 2048 bit.
* ed25519 := EDDSA using curve Ed25519. * ed25519 := EDDSA using curve Ed25519.
* ed448 := EDDSA using curve Ed448.
* cv25519 := ECDH using curve Curve25519. * cv25519 := ECDH using curve Curve25519.
* cv448 := ECDH using curve X448. * cv448 := ECDH using curve X448.
* nistp256:= ECDSA or ECDH using curve NIST P-256 * nistp256:= ECDSA or ECDH using curve NIST P-256

View File

@ -131,7 +131,6 @@ pk_verify (pubkey_algo_t pkalgo, gcry_mpi_t hash,
{ {
gcry_sexp_t s_sig, s_hash, s_pkey; gcry_sexp_t s_sig, s_hash, s_pkey;
int rc; int rc;
unsigned int neededfixedlen = 0;
/* Make a sexp from pkey. */ /* Make a sexp from pkey. */
if (pkalgo == PUBKEY_ALGO_DSA) if (pkalgo == PUBKEY_ALGO_DSA)
@ -171,15 +170,16 @@ pk_verify (pubkey_algo_t pkalgo, gcry_mpi_t hash,
rc = gpg_error_from_syserror (); rc = gpg_error_from_syserror ();
else else
{ {
rc = gcry_sexp_build (&s_pkey, NULL, const char *fmt;
"(public-key(ecc(curve %s)"
"(flags eddsa)(q%m)))", if (openpgp_oid_is_ed25519 (pkey[0]))
curve, pkey[1]); fmt = "(public-key(ecc(curve %s)(flags eddsa)(q%m)))";
else
fmt = "(public-key(ecc(curve %s)(q%m)))";
rc = gcry_sexp_build (&s_pkey, NULL, fmt, curve, pkey[1]);
xfree (curve); xfree (curve);
} }
if (openpgp_oid_is_ed25519 (pkey[0]))
neededfixedlen = 256 / 8;
} }
else else
return GPG_ERR_PUBKEY_ALGO; return GPG_ERR_PUBKEY_ALGO;
@ -190,9 +190,14 @@ pk_verify (pubkey_algo_t pkalgo, gcry_mpi_t hash,
/* Put hash into a S-Exp s_hash. */ /* Put hash into a S-Exp s_hash. */
if (pkalgo == PUBKEY_ALGO_EDDSA) if (pkalgo == PUBKEY_ALGO_EDDSA)
{ {
if (gcry_sexp_build (&s_hash, NULL, const char *fmt;
"(data(flags eddsa)(hash-algo sha512)(value %m))",
hash)) if (openpgp_oid_is_ed25519 (pkey[0]))
fmt = "(data(flags eddsa)(hash-algo sha512)(value %m))";
else
fmt = "(data(value %m))";
if (gcry_sexp_build (&s_hash, NULL, fmt, hash))
BUG (); /* gcry_sexp_build should never fail. */ BUG (); /* gcry_sexp_build should never fail. */
} }
else else
@ -223,80 +228,87 @@ pk_verify (pubkey_algo_t pkalgo, gcry_mpi_t hash,
{ {
gcry_mpi_t r = data[0]; gcry_mpi_t r = data[0];
gcry_mpi_t s = data[1]; gcry_mpi_t s = data[1];
size_t rlen, slen, n; /* (bytes) */
char buf[64];
unsigned int nbits;
log_assert (neededfixedlen <= sizeof buf); if (openpgp_oid_is_ed25519 (pkey[0]))
if (!r || !s)
rc = gpg_error (GPG_ERR_BAD_MPI);
else if ((rlen = (gcry_mpi_get_nbits (r)+7)/8) > neededfixedlen || !rlen)
rc = gpg_error (GPG_ERR_BAD_MPI);
else if ((slen = (gcry_mpi_get_nbits (s)+7)/8) > neededfixedlen || !slen)
rc = gpg_error (GPG_ERR_BAD_MPI);
else
{ {
/* We need to fixup the length in case of leading zeroes. size_t rlen, slen, n; /* (bytes) */
* OpenPGP does not allow leading zeroes and the parser for char buf[64];
* the signature packet has no information on the use curve, unsigned int nbits;
* thus we need to do it here. We won't do it for opaque unsigned int neededfixedlen = 256 / 8;
* MPIs under the assumption that they are known to be fine;
* we won't see them here anyway but the check is anyway
* required. Fixme: A nifty feature for gcry_sexp_build
* would be a format to left pad the value (e.g. "%*M"). */
rc = 0;
if (rlen < neededfixedlen log_assert (neededfixedlen <= sizeof buf);
&& !gcry_mpi_get_flag (r, GCRYMPI_FLAG_OPAQUE)
&& !(rc=gcry_mpi_print (GCRYMPI_FMT_USG, buf, sizeof buf, &n, r))) if (!r || !s)
rc = gpg_error (GPG_ERR_BAD_MPI);
else if ((rlen = (gcry_mpi_get_nbits (r)+7)/8) > neededfixedlen || !rlen)
rc = gpg_error (GPG_ERR_BAD_MPI);
else if ((slen = (gcry_mpi_get_nbits (s)+7)/8) > neededfixedlen || !slen)
rc = gpg_error (GPG_ERR_BAD_MPI);
else
{ {
log_assert (n < neededfixedlen); /* We need to fixup the length in case of leading zeroes.
memmove (buf + (neededfixedlen - n), buf, n); * OpenPGP does not allow leading zeroes and the parser for
memset (buf, 0, neededfixedlen - n); * the signature packet has no information on the use curve,
r = gcry_mpi_set_opaque_copy (NULL, buf, neededfixedlen * 8); * thus we need to do it here. We won't do it for opaque
} * MPIs under the assumption that they are known to be fine;
else if (rlen < neededfixedlen * we won't see them here anyway but the check is anyway
&& gcry_mpi_get_flag (r, GCRYMPI_FLAG_OPAQUE)) * required. Fixme: A nifty feature for gcry_sexp_build
{ * would be a format to left pad the value (e.g. "%*M"). */
const unsigned char *p; rc = 0;
p = gcry_mpi_get_opaque (r, &nbits); if (rlen < neededfixedlen
n = (nbits+7)/8; && !gcry_mpi_get_flag (r, GCRYMPI_FLAG_OPAQUE)
memcpy (buf + (neededfixedlen - n), p, n); && !(rc=gcry_mpi_print (GCRYMPI_FMT_USG, buf, sizeof buf, &n, r)))
memset (buf, 0, neededfixedlen - n); {
gcry_mpi_set_opaque_copy (r, buf, neededfixedlen * 8); log_assert (n < neededfixedlen);
} memmove (buf + (neededfixedlen - n), buf, n);
if (slen < neededfixedlen memset (buf, 0, neededfixedlen - n);
&& !gcry_mpi_get_flag (s, GCRYMPI_FLAG_OPAQUE) r = gcry_mpi_set_opaque_copy (NULL, buf, neededfixedlen * 8);
&& !(rc=gcry_mpi_print (GCRYMPI_FMT_USG, buf, sizeof buf, &n, s))) }
{ else if (rlen < neededfixedlen
log_assert (n < neededfixedlen); && gcry_mpi_get_flag (r, GCRYMPI_FLAG_OPAQUE))
memmove (buf + (neededfixedlen - n), buf, n); {
memset (buf, 0, neededfixedlen - n); const unsigned char *p;
s = gcry_mpi_set_opaque_copy (NULL, buf, neededfixedlen * 8);
}
else if (slen < neededfixedlen
&& gcry_mpi_get_flag (s, GCRYMPI_FLAG_OPAQUE))
{
const unsigned char *p;
p = gcry_mpi_get_opaque (s, &nbits); p = gcry_mpi_get_opaque (r, &nbits);
n = (nbits+7)/8; n = (nbits+7)/8;
memcpy (buf + (neededfixedlen - n), p, n); memcpy (buf + (neededfixedlen - n), p, n);
memset (buf, 0, neededfixedlen - n); memset (buf, 0, neededfixedlen - n);
gcry_mpi_set_opaque_copy (s, buf, neededfixedlen * 8); gcry_mpi_set_opaque_copy (r, buf, neededfixedlen * 8);
}
if (slen < neededfixedlen
&& !gcry_mpi_get_flag (s, GCRYMPI_FLAG_OPAQUE)
&& !(rc=gcry_mpi_print (GCRYMPI_FMT_USG, buf, sizeof buf, &n, s)))
{
log_assert (n < neededfixedlen);
memmove (buf + (neededfixedlen - n), buf, n);
memset (buf, 0, neededfixedlen - n);
s = gcry_mpi_set_opaque_copy (NULL, buf, neededfixedlen * 8);
}
else if (slen < neededfixedlen
&& gcry_mpi_get_flag (s, GCRYMPI_FLAG_OPAQUE))
{
const unsigned char *p;
p = gcry_mpi_get_opaque (s, &nbits);
n = (nbits+7)/8;
memcpy (buf + (neededfixedlen - n), p, n);
memset (buf, 0, neededfixedlen - n);
gcry_mpi_set_opaque_copy (s, buf, neededfixedlen * 8);
}
} }
if (!rc)
rc = gcry_sexp_build (&s_sig, NULL,
"(sig-val(eddsa(r%M)(s%M)))", r, s);
if (r != data[0])
gcry_mpi_release (r);
if (s != data[1])
gcry_mpi_release (s);
} }
else
rc = 0;
if (!rc)
rc = gcry_sexp_build (&s_sig, NULL,
"(sig-val(eddsa(r%M)(s%M)))", r, s);
if (r != data[0])
gcry_mpi_release (r);
if (s != data[1])
gcry_mpi_release (s);
} }
else if (pkalgo == PUBKEY_ALGO_ELGAMAL || pkalgo == PUBKEY_ALGO_ELGAMAL_E) else if (pkalgo == PUBKEY_ALGO_ELGAMAL || pkalgo == PUBKEY_ALGO_ELGAMAL_E)
{ {
@ -506,10 +518,14 @@ pk_check_secret_key (pubkey_algo_t pkalgo, gcry_mpi_t *skey)
rc = gpg_error_from_syserror (); rc = gpg_error_from_syserror ();
else else
{ {
rc = gcry_sexp_build (&s_skey, NULL, const char *fmt;
"(private-key(ecc(curve %s)"
"(flags eddsa)(q%m)(d%m)))", if (openpgp_oid_is_ed25519 (skey[0]))
curve, skey[1], skey[2]); fmt = "(private-key(ecc(curve %s)(flags eddsa)(q%m)(d%m)))";
else
fmt = "(private-key(ecc(curve %s)(q%m)(d%m)))";
rc = gcry_sexp_build (&s_skey, NULL, fmt, curve, skey[1], skey[2]);
xfree (curve); xfree (curve);
} }
} }

View File

@ -630,7 +630,7 @@ match_dsa_hash (unsigned int qbytes)
usable for the pubkey algorithm. If --personal-digest-prefs isn't usable for the pubkey algorithm. If --personal-digest-prefs isn't
set, then take the OpenPGP default (i.e. SHA-1). set, then take the OpenPGP default (i.e. SHA-1).
Note that Ed25519+EdDSA takes an input of arbitrary length and thus Note that EdDSA takes an input of arbitrary length and thus
we don't enforce any particular algorithm like we do for standard we don't enforce any particular algorithm like we do for standard
ECDSA. However, we use SHA256 as the default algorithm. ECDSA. However, we use SHA256 as the default algorithm.
@ -649,13 +649,15 @@ hash_for (PKT_public_key *pk)
{ {
return recipient_digest_algo; return recipient_digest_algo;
} }
else if (pk->pubkey_algo == PUBKEY_ALGO_EDDSA else if (pk->pubkey_algo == PUBKEY_ALGO_EDDSA)
&& openpgp_oid_is_ed25519 (pk->pkey[0]))
{ {
if (opt.personal_digest_prefs) if (opt.personal_digest_prefs)
return opt.personal_digest_prefs[0].value; return opt.personal_digest_prefs[0].value;
else else
return DIGEST_ALGO_SHA256; if (gcry_mpi_get_nbits (pk->pkey[1]) > 256)
return DIGEST_ALGO_SHA512;
else
return DIGEST_ALGO_SHA256;
} }
else if (pk->pubkey_algo == PUBKEY_ALGO_DSA else if (pk->pubkey_algo == PUBKEY_ALGO_DSA
|| pk->pubkey_algo == PUBKEY_ALGO_ECDSA) || pk->pubkey_algo == PUBKEY_ALGO_ECDSA)
@ -1742,14 +1744,15 @@ make_keysig_packet (ctrl_t ctrl,
digest_algo = opt.cert_digest_algo; digest_algo = opt.cert_digest_algo;
else if (pksk->pubkey_algo == PUBKEY_ALGO_DSA) /* Meet DSA requirements. */ else if (pksk->pubkey_algo == PUBKEY_ALGO_DSA) /* Meet DSA requirements. */
digest_algo = match_dsa_hash (gcry_mpi_get_nbits (pksk->pkey[1])/8); digest_algo = match_dsa_hash (gcry_mpi_get_nbits (pksk->pkey[1])/8);
else if (pksk->pubkey_algo == PUBKEY_ALGO_ECDSA /* Meet ECDSA requirements. */ else if (pksk->pubkey_algo == PUBKEY_ALGO_ECDSA) /* Meet ECDSA requirements. */
|| pksk->pubkey_algo == PUBKEY_ALGO_EDDSA) digest_algo = match_dsa_hash
(ecdsa_qbits_from_Q (gcry_mpi_get_nbits (pksk->pkey[1]))/8);
else if (pksk->pubkey_algo == PUBKEY_ALGO_EDDSA)
{ {
if (openpgp_oid_is_ed25519 (pksk->pkey[0])) if (gcry_mpi_get_nbits (pksk->pkey[1]) > 256)
digest_algo = DIGEST_ALGO_SHA256; digest_algo = DIGEST_ALGO_SHA512;
else else
digest_algo = match_dsa_hash digest_algo = DIGEST_ALGO_SHA256;
(ecdsa_qbits_from_Q (gcry_mpi_get_nbits (pksk->pkey[1]))/8);
} }
else /* Use the default. */ else /* Use the default. */
digest_algo = DEFAULT_DIGEST_ALGO; digest_algo = DEFAULT_DIGEST_ALGO;