diff --git a/agent/pksign.c b/agent/pksign.c index a2d5362be..0640b04ef 100644 --- a/agent/pksign.c +++ b/agent/pksign.c @@ -1,605 +1,610 @@ /* pksign.c - public key signing (well, actually using a secret key) * Copyright (C) 2001-2004, 2010 Free Software Foundation, Inc. * Copyright (C) 2001-2004, 2010, 2013 Werner Koch * * This file is part of GnuPG. * * GnuPG is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * GnuPG is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . */ #include #include #include #include #include #include #include #include "agent.h" #include "../common/i18n.h" static int do_encode_md (const byte * md, size_t mdlen, int algo, gcry_sexp_t * r_hash, int raw_value) { gcry_sexp_t hash; int rc; if (!raw_value) { const char *s; char tmp[16+1]; int i; s = gcry_md_algo_name (algo); if (!s || strlen (s) >= 16) { hash = NULL; rc = gpg_error (GPG_ERR_DIGEST_ALGO); } else { for (i=0; s[i]; i++) tmp[i] = ascii_tolower (s[i]); tmp[i] = '\0'; rc = gcry_sexp_build (&hash, NULL, "(data (flags pkcs1) (hash %s %b))", tmp, (int)mdlen, md); } } else { rc = gcry_sexp_build (&hash, NULL, "(data (flags raw) (value %b))", (int)mdlen, md); } *r_hash = hash; return rc; } /* Return the number of bits of the Q parameter from the DSA key KEY. */ static unsigned int get_dsa_qbits (gcry_sexp_t key) { gcry_sexp_t l1, l2; gcry_mpi_t q; unsigned int nbits; l1 = gcry_sexp_find_token (key, "private-key", 0); if (!l1) l1 = gcry_sexp_find_token (key, "protected-private-key", 0); if (!l1) l1 = gcry_sexp_find_token (key, "shadowed-private-key", 0); if (!l1) l1 = gcry_sexp_find_token (key, "public-key", 0); if (!l1) return 0; /* Does not contain a key object. */ l2 = gcry_sexp_cadr (l1); gcry_sexp_release (l1); l1 = gcry_sexp_find_token (l2, "q", 1); gcry_sexp_release (l2); if (!l1) return 0; /* Invalid object. */ q = gcry_sexp_nth_mpi (l1, 1, GCRYMPI_FMT_USG); gcry_sexp_release (l1); if (!q) return 0; /* Missing value. */ nbits = gcry_mpi_get_nbits (q); gcry_mpi_release (q); return nbits; } /* Return an appropriate hash algorithm to be used with RFC-6979 for a message digest of length MDLEN. Although a fallback of SHA-256 is used the current implementation in Libgcrypt will reject a hash algorithm which does not match the length of the message. */ static const char * rfc6979_hash_algo_string (size_t mdlen) { switch (mdlen) { case 20: return "sha1"; case 28: return "sha224"; case 32: return "sha256"; case 48: return "sha384"; case 64: return "sha512"; default: return "sha256"; } } /* Encode a message digest for use with the EdDSA algorithm (i.e. curve Ed25519). */ 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; 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; - err = gcry_sexp_build (&hash, NULL, - "(data(flags eddsa)(hash-algo sha512)(value %b))", - (int)mdlen, md); + err = gcry_sexp_build (&hash, NULL, fmt, (int)mdlen, md); if (!err) *r_hash = hash; return err; } /* Encode a message digest for use with an DSA algorithm. */ static gpg_error_t do_encode_dsa (const byte *md, size_t mdlen, int pkalgo, gcry_sexp_t pkey, gcry_sexp_t *r_hash) { gpg_error_t err; gcry_sexp_t hash; unsigned int qbits; *r_hash = NULL; if (pkalgo == GCRY_PK_ECC) qbits = gcry_pk_get_nbits (pkey); else if (pkalgo == GCRY_PK_DSA) qbits = get_dsa_qbits (pkey); else return gpg_error (GPG_ERR_WRONG_PUBKEY_ALGO); if (pkalgo == GCRY_PK_DSA && (qbits%8)) { /* FIXME: We check the QBITS but print a message about the hash length. */ log_error (_("DSA requires the hash length to be a" " multiple of 8 bits\n")); return gpg_error (GPG_ERR_INV_LENGTH); } /* Don't allow any Q smaller than 160 bits. We don't want someone to issue signatures from a key with a 16-bit Q or something like that, which would look correct but allow trivial forgeries. Yes, I know this rules out using MD5 with DSA. ;) */ if (qbits < 160) { log_error (_("%s key uses an unsafe (%u bit) hash\n"), gcry_pk_algo_name (pkalgo), qbits); return gpg_error (GPG_ERR_INV_LENGTH); } /* ECDSA 521 is special has it is larger than the largest hash we have (SHA-512). Thus we change the size for further processing to 512. */ if (pkalgo == GCRY_PK_ECC && qbits > 512) qbits = 512; /* Check if we're too short. Too long is safe as we'll automatically left-truncate. */ if (mdlen < qbits/8) { log_error (_("a %zu bit hash is not valid for a %u bit %s key\n"), mdlen*8, gcry_pk_get_nbits (pkey), gcry_pk_algo_name (pkalgo)); return gpg_error (GPG_ERR_INV_LENGTH); } /* Truncate. */ if (mdlen > qbits/8) mdlen = qbits/8; /* Create the S-expression. */ err = gcry_sexp_build (&hash, NULL, "(data (flags rfc6979) (hash %s %b))", rfc6979_hash_algo_string (mdlen), (int)mdlen, md); if (!err) *r_hash = hash; return err; } /* Special version of do_encode_md to take care of pkcs#1 padding. For TLS-MD5SHA1 we need to do the padding ourself as Libgrypt does not know about this special scheme. Fixme: We should have a pkcs1-only-padding flag for Libgcrypt. */ static int do_encode_raw_pkcs1 (const byte *md, size_t mdlen, unsigned int nbits, gcry_sexp_t *r_hash) { int rc; gcry_sexp_t hash; unsigned char *frame; size_t i, n, nframe; nframe = (nbits+7) / 8; if ( !mdlen || mdlen + 8 + 4 > nframe ) { /* Can't encode this hash into a frame of size NFRAME. */ return gpg_error (GPG_ERR_TOO_SHORT); } frame = xtrymalloc (nframe); if (!frame) return gpg_error_from_syserror (); /* Assemble the pkcs#1 block type 1. */ n = 0; frame[n++] = 0; frame[n++] = 1; /* Block type. */ i = nframe - mdlen - 3 ; log_assert (i >= 8); /* At least 8 bytes of padding. */ memset (frame+n, 0xff, i ); n += i; frame[n++] = 0; memcpy (frame+n, md, mdlen ); n += mdlen; log_assert (n == nframe); /* Create the S-expression. */ rc = gcry_sexp_build (&hash, NULL, "(data (flags raw) (value %b))", (int)nframe, frame); xfree (frame); *r_hash = hash; return rc; } /* SIGN whatever information we have accumulated in CTRL and return * the signature S-expression. LOOKUP is an optional function to * provide a way for lower layers to ask for the caching TTL. If a * CACHE_NONCE is given that cache item is first tried to get a * passphrase. If OVERRIDEDATA is not NULL, OVERRIDEDATALEN bytes * from this buffer are used instead of the data in CTRL. The * override feature is required to allow the use of Ed25519 with ssh * because Ed25519 does the hashing itself. */ gpg_error_t agent_pksign_do (ctrl_t ctrl, const char *cache_nonce, const char *desc_text, gcry_sexp_t *signature_sexp, cache_mode_t cache_mode, lookup_ttl_t lookup_ttl, const void *overridedata, size_t overridedatalen) { gpg_error_t err = 0; gcry_sexp_t s_skey = NULL; gcry_sexp_t s_sig = NULL; gcry_sexp_t s_hash = NULL; gcry_sexp_t s_pkey = NULL; unsigned char *shadow_info = NULL; int no_shadow_info = 0; const unsigned char *data; int datalen; int check_signature = 0; int algo; if (overridedata) { data = overridedata; datalen = overridedatalen; } else if (ctrl->digest.data) { data = ctrl->digest.data; datalen = ctrl->digest.valuelen; } else { data = ctrl->digest.value; datalen = ctrl->digest.valuelen; } if (!ctrl->have_keygrip) return gpg_error (GPG_ERR_NO_SECKEY); err = agent_key_from_file (ctrl, cache_nonce, desc_text, ctrl->keygrip, &shadow_info, cache_mode, lookup_ttl, &s_skey, NULL); if (gpg_err_code (err) == GPG_ERR_NO_SECKEY) no_shadow_info = 1; else if (err) { log_error ("failed to read the secret key\n"); goto leave; } algo = get_pk_algo_from_key (s_skey); if (shadow_info || no_shadow_info) { /* Divert operation to the smartcard. With NO_SHADOW_INFO set * we don't have the keystub but we want to see whether the key * is on the active card. */ size_t len; unsigned char *buf = NULL; if (no_shadow_info) { /* Try to get the public key from the card or fail with the * original NO_SECKEY error. We also write a stub file (we * are here only because no stub exists). */ char *serialno; unsigned char *pkbuf = NULL; size_t pkbuflen; char hexgrip[2*KEYGRIP_LEN+1]; char *keyref; if (agent_card_serialno (ctrl, &serialno, NULL)) { /* No card available or error reading the card. */ err = gpg_error (GPG_ERR_NO_SECKEY); goto leave; } bin2hex (ctrl->keygrip, KEYGRIP_LEN, hexgrip); if (agent_card_readkey (ctrl, hexgrip, &pkbuf, &keyref)) { /* No such key on the card. */ xfree (serialno); err = gpg_error (GPG_ERR_NO_SECKEY); goto leave; } pkbuflen = gcry_sexp_canon_len (pkbuf, 0, NULL, NULL); err = gcry_sexp_sscan (&s_pkey, NULL, (char*)pkbuf, pkbuflen); if (err) { xfree (serialno); xfree (pkbuf); xfree (keyref); log_error ("%s: corrupted key returned by scdaemon\n", __func__); goto leave; } if (keyref) agent_write_shadow_key (ctrl->keygrip, serialno, keyref, pkbuf, 0); xfree (serialno); xfree (pkbuf); xfree (keyref); } else { /* Get the public key from the stub file. */ err = agent_public_key_from_file (ctrl, ctrl->keygrip, &s_pkey); if (err) { log_error ("failed to read the public key\n"); goto leave; } } { char *desc2 = NULL; if (desc_text) agent_modify_description (desc_text, NULL, s_pkey, &desc2); err = divert_pksign (ctrl, desc2? desc2 : desc_text, ctrl->keygrip, data, datalen, ctrl->digest.algo, shadow_info, &buf, &len); xfree (desc2); } if (err) { log_error ("smartcard signing failed: %s\n", gpg_strerror (err)); goto leave; } if (algo == GCRY_PK_RSA) { unsigned char *p = buf; check_signature = 1; /* * Smartcard returns fixed-size data, which is good for * PKCS1. If variable-size unsigned MPI is needed, remove * zeros. */ if (ctrl->digest.algo == MD_USER_TLS_MD5SHA1 || ctrl->digest.raw_value) { int i; for (i = 0; i < len - 1; i++) if (p[i]) break; p += i; len -= i; } err = gcry_sexp_build (&s_sig, NULL, "(sig-val(rsa(s%b)))", (int)len, p); } else if (algo == GCRY_PK_EDDSA) { err = gcry_sexp_build (&s_sig, NULL, "(sig-val(eddsa(r%b)(s%b)))", (int)len/2, buf, (int)len/2, buf + len/2); } else if (algo == GCRY_PK_ECC) { unsigned char *r_buf, *s_buf; int r_buflen, s_buflen; int i; r_buflen = s_buflen = len/2; /* * Smartcard returns fixed-size data. For ECDSA signature, * variable-size unsigned MPI is assumed, thus, remove * zeros. */ r_buf = buf; for (i = 0; i < r_buflen - 1; i++) if (r_buf[i]) break; r_buf += i; r_buflen -= i; s_buf = buf + len/2; for (i = 0; i < s_buflen - 1; i++) if (s_buf[i]) break; s_buf += i; s_buflen -= i; err = gcry_sexp_build (&s_sig, NULL, "(sig-val(ecdsa(r%b)(s%b)))", r_buflen, r_buf, s_buflen, s_buf); } else err = gpg_error (GPG_ERR_NOT_IMPLEMENTED); xfree (buf); if (err) { log_error ("failed to convert sigbuf returned by divert_pksign " "into S-Exp: %s", gpg_strerror (err)); goto leave; } } else { /* No smartcard, but a private key (in S_SKEY). */ /* Put the hash into a sexp */ 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); else if (ctrl->digest.algo == MD_USER_TLS_MD5SHA1) err = do_encode_raw_pkcs1 (data, datalen, gcry_pk_get_nbits (s_skey), &s_hash); else if (algo == GCRY_PK_DSA || algo == GCRY_PK_ECC) err = do_encode_dsa (data, datalen, algo, s_skey, &s_hash); else err = do_encode_md (data, datalen, ctrl->digest.algo, &s_hash, ctrl->digest.raw_value); if (err) goto leave; if (algo == GCRY_PK_RSA && GCRYPT_VERSION_NUMBER < 0x010700) { /* It's RSA and Libgcrypt < 1.7 */ check_signature = 1; } if (DBG_CRYPTO) { gcry_log_debugsxp ("skey", s_skey); gcry_log_debugsxp ("hash", s_hash); } /* sign */ err = gcry_pk_sign (&s_sig, s_hash, s_skey); if (err) { log_error ("signing failed: %s\n", gpg_strerror (err)); goto leave; } if (DBG_CRYPTO) gcry_log_debugsxp ("rslt", s_sig); } /* Check that the signature verification worked and nothing is * fooling us e.g. by a bug in the signature create code or by * deliberately introduced faults. Because Libgcrypt 1.7 does this * for RSA internally there is no need to do it here again. We do * this always for card based RSA keys, though. */ if (check_signature) { gcry_sexp_t sexp_key = s_pkey? s_pkey: s_skey; if (s_hash == NULL) { if (ctrl->digest.algo == MD_USER_TLS_MD5SHA1) err = do_encode_raw_pkcs1 (data, datalen, gcry_pk_get_nbits (sexp_key), &s_hash); else err = do_encode_md (data, datalen, ctrl->digest.algo, &s_hash, ctrl->digest.raw_value); } if (!err) err = gcry_pk_verify (s_sig, s_hash, sexp_key); if (err) { log_error (_("checking created signature failed: %s\n"), gpg_strerror (err)); gcry_sexp_release (s_sig); s_sig = NULL; } } leave: *signature_sexp = s_sig; gcry_sexp_release (s_pkey); gcry_sexp_release (s_skey); gcry_sexp_release (s_hash); xfree (shadow_info); return err; } /* SIGN whatever information we have accumulated in CTRL and write it * back to OUTFP. If a CACHE_NONCE is given that cache item is first * tried to get a passphrase. */ gpg_error_t agent_pksign (ctrl_t ctrl, const char *cache_nonce, const char *desc_text, membuf_t *outbuf, cache_mode_t cache_mode) { gpg_error_t err; gcry_sexp_t s_sig = NULL; char *buf = NULL; size_t len = 0; err = agent_pksign_do (ctrl, cache_nonce, desc_text, &s_sig, cache_mode, NULL, NULL, 0); if (err) goto leave; len = gcry_sexp_sprint (s_sig, GCRYSEXP_FMT_CANON, NULL, 0); log_assert (len); buf = xtrymalloc (len); if (!buf) { err = gpg_error_from_syserror (); goto leave; } len = gcry_sexp_sprint (s_sig, GCRYSEXP_FMT_CANON, buf, len); log_assert (len); put_membuf (outbuf, buf, len); leave: gcry_sexp_release (s_sig); xfree (buf); return err; } diff --git a/agent/sexp-secret.c b/agent/sexp-secret.c index d67836769..b539659e2 100644 --- a/agent/sexp-secret.c +++ b/agent/sexp-secret.c @@ -1,141 +1,142 @@ /* sexp-secret.c - SEXP handling of the secret key * Copyright (C) 2020 g10 Code GmbH. * * This file is part of GnuPG. * * GnuPG is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * GnuPG is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . */ #include #include "agent.h" #include "../common/sexp-parse.h" /* * When it's for ECC, fixup private key part in the cannonical SEXP * representation in BUF. If not ECC, do nothing. */ gpg_error_t fixup_when_ecc_private_key (unsigned char *buf, size_t *buflen_p) { const unsigned char *s; char curve_name[256]; size_t n; size_t buflen = *buflen_p; s = buf; if (*s != '(') return gpg_error (GPG_ERR_INV_SEXP); s++; n = snext (&s); if (!n) return gpg_error (GPG_ERR_INV_SEXP); if (smatch (&s, n, "shadowed-private-key")) return 0; /* Nothing to do. */ if (!smatch (&s, n, "private-key")) return gpg_error (GPG_ERR_UNKNOWN_SEXP); if (*s != '(') return gpg_error (GPG_ERR_UNKNOWN_SEXP); s++; n = snext (&s); if (!smatch (&s, n, "ecc")) return 0; /* It's ECC */ while (*s == '(') { s++; n = snext (&s); if (!n) return gpg_error (GPG_ERR_INV_SEXP); if (n == 5 && !memcmp (s, "curve", 5)) { s += n; n = snext (&s); if (!n || n >= sizeof curve_name) return gpg_error (GPG_ERR_INV_SEXP); memcpy (curve_name, s, n); curve_name[n] = 0; s += n; } else if (n == 1 && *s == 'd') { unsigned char *s0; size_t n0; s += n; s0 = (unsigned char *)s; n = snext (&s); n0 = s - s0; if (!n) return gpg_error (GPG_ERR_INV_SEXP); else if (!*s /* Leading 0x00 added at the front for classic curve */ && strcmp (curve_name, "Ed25519") + && strcmp (curve_name, "Ed448") && strcmp (curve_name, "X448")) { size_t numsize; n--; buflen--; numsize = snprintf (s0, s-s0+1, "%u:", (unsigned int)n); memmove (s0+numsize, s+1, buflen - (s - buf)); memset (s0+numsize+buflen - (s - buf), 0, (n0 - numsize) + 1); buflen -= (n0 - numsize); s = s0+numsize+n; *buflen_p = buflen; } else s += n; } else { s += n; n = snext (&s); if (!n) return gpg_error (GPG_ERR_INV_SEXP); s += n; } if ( *s != ')' ) return gpg_error (GPG_ERR_INV_SEXP); s++; } if (*s != ')') return gpg_error (GPG_ERR_INV_SEXP); s++; return 0; } /* * Scan BUF to get SEXP, put into RESULT. Error offset will be in the * pointer at R_ERROFF. For ECC, the private part 'd' will be fixed * up; That part may have 0x00 prefix of signed MPI encoding, which is * incompatible to opaque MPI handling. */ gpg_error_t sexp_sscan_private_key (gcry_sexp_t *result, size_t *r_erroff, unsigned char *buf) { gpg_error_t err; size_t buflen, buflen0; buflen = buflen0 = gcry_sexp_canon_len (buf, 0, NULL, NULL); err = fixup_when_ecc_private_key (buf, &buflen); if (!err) err = gcry_sexp_sscan (result, r_erroff, (char*)buf, buflen0); wipememory (buf, buflen0); return err; } diff --git a/common/openpgp-oid.c b/common/openpgp-oid.c index 605caa679..4e53a74fd 100644 --- a/common/openpgp-oid.c +++ b/common/openpgp-oid.c @@ -1,680 +1,681 @@ /* openpgp-oids.c - OID helper for OpenPGP * Copyright (C) 2011 Free Software Foundation, Inc. * Copyright (C) 2013 Werner Koch * * This file is part of GnuPG. * * This file is free software; you can redistribute it and/or modify * it under the terms of either * * - the GNU Lesser General Public License as published by the Free * Software Foundation; either version 3 of the License, or (at * your option) any later version. * * or * * - the GNU General Public License as published by the Free * Software Foundation; either version 2 of the License, or (at * your option) any later version. * * or both in parallel, as here. * * This file is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . */ #include #include #include #include #include #include "util.h" #include "openpgpdefs.h" /* A table with all our supported OpenPGP curves. */ static struct { const char *name; /* Standard name. */ const char *oidstr; /* IETF formatted OID. */ unsigned int nbits; /* Nominal bit length of the curve. */ const char *alias; /* NULL or alternative name of the curve. */ int pubkey_algo; /* Required OpenPGP algo or 0 for ECDSA/ECDH. */ } oidtable[] = { { "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 }, { "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-384", "1.3.132.0.34", 384, "nistp384" }, { "NIST P-521", "1.3.132.0.35", 521, "nistp521" }, { "brainpoolP256r1", "1.3.36.3.3.2.8.1.1.7", 256 }, { "brainpoolP384r1", "1.3.36.3.3.2.8.1.1.11", 384 }, { "brainpoolP512r1", "1.3.36.3.3.2.8.1.1.13", 512 }, { "secp256k1", "1.3.132.0.10", 256 }, { NULL, NULL, 0} }; /* The OID for Curve Ed25519 in OpenPGP format. */ static const char oid_ed25519[] = { 0x09, 0x2b, 0x06, 0x01, 0x04, 0x01, 0xda, 0x47, 0x0f, 0x01 }; /* The OID for Curve25519 in OpenPGP format. */ static const char oid_cv25519[] = { 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x97, 0x55, 0x01, 0x05, 0x01 }; /* The OID for X448 in OpenPGP format. */ /* * Here, we have a little semantic discrepancy. X448 is the name of * the ECDH computation and the OID is assigned to the algorithm in * RFC 8410. Note that this OID is not the one which is assigned to * the curve itself (originally in 8410). Nevertheless, we use "X448" * for the curve in libgcrypt. */ static const char oid_cv448[] = { 0x03, 0x2b, 0x65, 0x6f }; /* A table to store keyalgo strings like "rsa2048 or "ed25519" so that * we do not need to allocate them. This is currently a simple array * but may eventually be changed to a fast data structure. Noet that * unknown algorithms are stored with (NBITS,CURVE) set to (0,NULL). */ struct keyalgo_string_s { enum gcry_pk_algos algo; /* Mandatory. */ unsigned int nbits; /* Size for classical algos. */ char *curve; /* Curvename (OID) or NULL. */ char *name; /* Allocated name. */ }; static struct keyalgo_string_s *keyalgo_strings; /* The table. */ static size_t keyalgo_strings_size; /* Allocated size. */ static size_t keyalgo_strings_used; /* Used size. */ /* Helper for openpgp_oid_from_str. */ static size_t make_flagged_int (unsigned long value, char *buf, size_t buflen) { int more = 0; int shift; /* fixme: figure out the number of bits in an ulong and start with that value as shift (after making it a multiple of 7) a more straigtforward implementation is to do it in reverse order using a temporary buffer - saves a lot of compares */ for (more=0, shift=28; shift > 0; shift -= 7) { if (more || value >= (1<> shift); value -= (value >> shift) << shift; more = 1; } } buf[buflen++] = value; return buflen; } /* Convert the OID given in dotted decimal form in STRING to an DER * encoding and store it as an opaque value at R_MPI. The format of * the DER encoded is not a regular ASN.1 object but the modified * format as used by OpenPGP for the ECC curve description. On error * the function returns and error code an NULL is stored at R_BUG. * Note that scanning STRING stops at the first white space * character. */ gpg_error_t openpgp_oid_from_str (const char *string, gcry_mpi_t *r_mpi) { unsigned char *buf; size_t buflen; unsigned long val1, val; const char *endp; int arcno; *r_mpi = NULL; if (!string || !*string) return gpg_error (GPG_ERR_INV_VALUE); /* We can safely assume that the encoded OID is shorter than the string. */ buf = xtrymalloc (1 + strlen (string) + 2); if (!buf) return gpg_error_from_syserror (); /* Save the first byte for the length. */ buflen = 1; val1 = 0; /* Avoid compiler warning. */ arcno = 0; do { arcno++; val = strtoul (string, (char**)&endp, 10); if (!digitp (string) || !(*endp == '.' || !*endp)) { xfree (buf); return gpg_error (GPG_ERR_INV_OID_STRING); } if (*endp == '.') string = endp+1; if (arcno == 1) { if (val > 2) break; /* Not allowed, error caught below. */ val1 = val; } else if (arcno == 2) { /* Need to combine the first two arcs in one octet. */ if (val1 < 2) { if (val > 39) { xfree (buf); return gpg_error (GPG_ERR_INV_OID_STRING); } buf[buflen++] = val1*40 + val; } else { val += 80; buflen = make_flagged_int (val, buf, buflen); } } else { buflen = make_flagged_int (val, buf, buflen); } } while (*endp == '.'); if (arcno == 1 || buflen < 2 || buflen > 254 ) { /* It is not possible to encode only the first arc. */ xfree (buf); return gpg_error (GPG_ERR_INV_OID_STRING); } *buf = buflen - 1; *r_mpi = gcry_mpi_set_opaque (NULL, buf, buflen * 8); if (!*r_mpi) { xfree (buf); return gpg_error_from_syserror (); } return 0; } /* Return a malloced string representation of the OID in the buffer * (BUF,LEN). In case of an error NULL is returned and ERRNO is set. * As per OpenPGP spec the first byte of the buffer is the length of * the rest; the function performs a consistency check. */ char * openpgp_oidbuf_to_str (const unsigned char *buf, size_t len) { char *string, *p; int n = 0; unsigned long val, valmask; valmask = (unsigned long)0xfe << (8 * (sizeof (valmask) - 1)); /* The first bytes gives the length; check consistency. */ if (!len || buf[0] != len -1) { gpg_err_set_errno (EINVAL); return NULL; } /* Skip length byte. */ len--; buf++; /* To calculate the length of the string we can safely assume an upper limit of 3 decimal characters per byte. Two extra bytes account for the special first octet */ string = p = xtrymalloc (len*(1+3)+2+1); if (!string) return NULL; if (!len) { *p = 0; return string; } if (buf[0] < 40) p += sprintf (p, "0.%d", buf[n]); else if (buf[0] < 80) p += sprintf (p, "1.%d", buf[n]-40); else { val = buf[n] & 0x7f; while ( (buf[n]&0x80) && ++n < len ) { if ( (val & valmask) ) goto badoid; /* Overflow. */ val <<= 7; val |= buf[n] & 0x7f; } if (val < 80) goto badoid; val -= 80; sprintf (p, "2.%lu", val); p += strlen (p); } for (n++; n < len; n++) { val = buf[n] & 0x7f; while ( (buf[n]&0x80) && ++n < len ) { if ( (val & valmask) ) goto badoid; /* Overflow. */ val <<= 7; val |= buf[n] & 0x7f; } sprintf (p, ".%lu", val); p += strlen (p); } *p = 0; return string; badoid: /* Return a special OID (gnu.gnupg.badoid) to indicate the error case. The OID is broken and thus we return one which can't do any harm. Formally this does not need to be a bad OID but an OID with an arc that can't be represented in a 32 bit word is more than likely corrupt. */ xfree (string); return xtrystrdup ("1.3.6.1.4.1.11591.2.12242973"); } /* Return a malloced string representation of the OID in the opaque * MPI A. In case of an error NULL is returned and ERRNO is set. */ char * openpgp_oid_to_str (gcry_mpi_t a) { const unsigned char *buf; unsigned int lengthi; if (!a || !gcry_mpi_get_flag (a, GCRYMPI_FLAG_OPAQUE) || !(buf = gcry_mpi_get_opaque (a, &lengthi))) { gpg_err_set_errno (EINVAL); return NULL; } return openpgp_oidbuf_to_str (buf, (lengthi+7)/8); } /* Return true if (BUF,LEN) represents the OID for Ed25519. */ int openpgp_oidbuf_is_ed25519 (const void *buf, size_t len) { return (buf && len == DIM (oid_ed25519) && !memcmp (buf, oid_ed25519, DIM (oid_ed25519))); } /* Return true if A represents the OID for Ed25519. */ int openpgp_oid_is_ed25519 (gcry_mpi_t a) { const unsigned char *buf; unsigned int nbits; if (!a || !gcry_mpi_get_flag (a, GCRYMPI_FLAG_OPAQUE)) return 0; buf = gcry_mpi_get_opaque (a, &nbits); return openpgp_oidbuf_is_ed25519 (buf, (nbits+7)/8); } /* Return true if (BUF,LEN) represents the OID for Curve25519. */ int openpgp_oidbuf_is_cv25519 (const void *buf, size_t len) { return (buf && len == DIM (oid_cv25519) && !memcmp (buf, oid_cv25519, DIM (oid_cv25519))); } /* Return true if (BUF,LEN) represents the OID for X448. */ static int openpgp_oidbuf_is_cv448 (const void *buf, size_t len) { return (buf && len == DIM (oid_cv448) && !memcmp (buf, oid_cv448, DIM (oid_cv448))); } /* Return true if the MPI A represents the OID for Curve25519. */ int openpgp_oid_is_cv25519 (gcry_mpi_t a) { const unsigned char *buf; unsigned int nbits; if (!a || !gcry_mpi_get_flag (a, GCRYMPI_FLAG_OPAQUE)) return 0; buf = gcry_mpi_get_opaque (a, &nbits); return openpgp_oidbuf_is_cv25519 (buf, (nbits+7)/8); } /* Return true if the MPI A represents the OID for X448. */ int openpgp_oid_is_cv448 (gcry_mpi_t a) { const unsigned char *buf; unsigned int nbits; if (!a || !gcry_mpi_get_flag (a, GCRYMPI_FLAG_OPAQUE)) return 0; buf = gcry_mpi_get_opaque (a, &nbits); return openpgp_oidbuf_is_cv448 (buf, (nbits+7)/8); } /* Map the Libgcrypt ECC curve NAME to an OID. If R_NBITS is not NULL store the bit size of the curve there. Returns NULL for unknown curve names. If R_ALGO is not NULL and a specific ECC algorithm is required for this curve its OpenPGP algorithm number is stored there; otherwise 0 is stored which indicates that ECDSA or ECDH can be used. */ const char * openpgp_curve_to_oid (const char *name, unsigned int *r_nbits, int *r_algo) { int i; unsigned int nbits = 0; const char *oidstr = NULL; int algo = 0; if (name) { for (i=0; oidtable[i].name; i++) if (!strcmp (oidtable[i].name, name) || (oidtable[i].alias && !strcmp (oidtable[i].alias, name))) { oidstr = oidtable[i].oidstr; nbits = oidtable[i].nbits; algo = oidtable[i].pubkey_algo; break; } if (!oidtable[i].name) { /* If not found assume the input is already an OID and check whether we support it. */ for (i=0; oidtable[i].name; i++) if (!strcmp (name, oidtable[i].oidstr)) { oidstr = oidtable[i].oidstr; nbits = oidtable[i].nbits; algo = oidtable[i].pubkey_algo; break; } } } if (r_nbits) *r_nbits = nbits; if (r_algo) *r_algo = algo; return oidstr; } /* Map an OpenPGP OID to the Libgcrypt curve name. Returns NULL for * unknown curve names. Unless CANON is set we prefer an alias name * here which is more suitable for printing. */ const char * openpgp_oid_to_curve (const char *oidstr, int canon) { int i; if (!oidstr) return NULL; for (i=0; oidtable[i].name; i++) if (!strcmp (oidtable[i].oidstr, oidstr)) return !canon && oidtable[i].alias? oidtable[i].alias : oidtable[i].name; return NULL; } /* Map an OpenPGP OID, name or alias to the Libgcrypt curve name. * Returns NULL for unknown curve names. Unless CANON is set we * prefer an alias name here which is more suitable for printing. */ const char * openpgp_oid_or_name_to_curve (const char *oidname, int canon) { int i; if (!oidname) return NULL; for (i=0; oidtable[i].name; i++) if (!strcmp (oidtable[i].oidstr, oidname) || !strcmp (oidtable[i].name, oidname) || (oidtable[i].alias &&!strcmp (oidtable[i].alias, oidname))) return !canon && oidtable[i].alias? oidtable[i].alias : oidtable[i].name; return NULL; } /* Return true if the curve with NAME is supported. */ static int curve_supported_p (const char *name) { int result = 0; gcry_sexp_t keyparms; if (!gcry_sexp_build (&keyparms, NULL, "(public-key(ecc(curve %s)))", name)) { result = !!gcry_pk_get_curve (keyparms, 0, NULL); gcry_sexp_release (keyparms); } return result; } /* Enumerate available and supported OpenPGP curves. The caller needs to set the integer variable at ITERP to zero and keep on calling this function until NULL is returned. */ const char * openpgp_enum_curves (int *iterp) { int idx = *iterp; while (idx >= 0 && idx < DIM (oidtable) && oidtable[idx].name) { if (curve_supported_p (oidtable[idx].name)) { *iterp = idx + 1; return oidtable[idx].alias? oidtable[idx].alias : oidtable[idx].name; } idx++; } *iterp = idx; return NULL; } /* Return the Libgcrypt name for the gpg curve NAME if supported. If * R_ALGO is not NULL the required OpenPGP public key algo or 0 is * stored at that address. If R_NBITS is not NULL the nominal bitsize * of the curves is stored there. NULL is returned if the curve is * not supported. */ const char * openpgp_is_curve_supported (const char *name, int *r_algo, unsigned int *r_nbits) { int idx; if (r_algo) *r_algo = 0; if (r_nbits) *r_nbits = 0; for (idx = 0; idx < DIM (oidtable) && oidtable[idx].name; idx++) { if ((!strcmp (name, oidtable[idx].name) || (oidtable[idx].alias && !strcmp (name, (oidtable[idx].alias)))) && curve_supported_p (oidtable[idx].name)) { if (r_algo) *r_algo = oidtable[idx].pubkey_algo; if (r_nbits) *r_nbits = oidtable[idx].nbits; return oidtable[idx].name; } } return NULL; } /* Map a Gcrypt public key algorithm number to the used by OpenPGP. * Returns 0 for unknown gcry algorithm. */ pubkey_algo_t map_gcry_pk_to_openpgp (enum gcry_pk_algos algo) { switch (algo) { case GCRY_PK_EDDSA: return PUBKEY_ALGO_EDDSA; case GCRY_PK_ECDSA: return PUBKEY_ALGO_ECDSA; case GCRY_PK_ECDH: return PUBKEY_ALGO_ECDH; default: return algo < 110 ? (pubkey_algo_t)algo : 0; } } /* Map an OpenPGP public key algorithm number to the one used by * Libgcrypt. Returns 0 for unknown gcry algorithm. */ enum gcry_pk_algos map_openpgp_pk_to_gcry (pubkey_algo_t algo) { switch (algo) { case PUBKEY_ALGO_EDDSA: return GCRY_PK_EDDSA; case PUBKEY_ALGO_ECDSA: return GCRY_PK_ECDSA; case PUBKEY_ALGO_ECDH: return GCRY_PK_ECDH; default: return algo < 110 ? algo : 0; } } /* Return a string describing the public key algorithm and the * keysize. For elliptic curves the function prints the name of the * curve because the keysize is a property of the curve. ALGO is the * Gcrypt algorithm number, CURVE is either NULL or gives the OID of * the curve, NBITS is either 0 or the size for algorithms like RSA. * The returned string is taken from permanent table. Examples * for the output are: * * "rsa3072" - RSA with 3072 bit * "elg1024" - Elgamal with 1024 bit * "ed25519" - ECC using the curve Ed25519. * "E_1.2.3.4" - ECC using the unsupported curve with OID "1.2.3.4". * "E_1.3.6.1.4.1.11591.2.12242973" - ECC with a bogus OID. * "unknown_N" - Unknown OpenPGP algorithm N. * If N is > 110 this is a gcrypt algo. */ const char * get_keyalgo_string (enum gcry_pk_algos algo, unsigned int nbits, const char *curve) { const char *prefix; int i; char *name, *curvebuf; switch (algo) { case GCRY_PK_RSA: prefix = "rsa"; break; case GCRY_PK_ELG: prefix = "elg"; break; case GCRY_PK_DSA: prefix = "dsa"; break; case GCRY_PK_ECC: case GCRY_PK_ECDH: case GCRY_PK_ECDSA: case GCRY_PK_EDDSA: prefix = ""; break; default: prefix = NULL; break; } if (prefix && *prefix && nbits) { for (i=0; i < keyalgo_strings_used; i++) { if (keyalgo_strings[i].algo == algo && keyalgo_strings[i].nbits && keyalgo_strings[i].nbits == nbits) return keyalgo_strings[i].name; } /* Not yet in the table - add it. */ name = xasprintf ("%s%u", prefix, nbits); nbits = nbits? nbits : 1; /* No nbits - oops - use 1 instead. */ curvebuf = NULL; } else if (prefix && !*prefix) { const char *curvename; for (i=0; i < keyalgo_strings_used; i++) { if (keyalgo_strings[i].algo == algo && keyalgo_strings[i].curve && !strcmp (keyalgo_strings[i].curve, curve)) return keyalgo_strings[i].name; } /* Not yet in the table - add it. */ curvename = openpgp_oid_or_name_to_curve (curve, 0); if (curvename) name = xasprintf ("%s", curvename); else if (curve) name = xasprintf ("E_%s", curve); else name = xasprintf ("E_error"); nbits = 0; curvebuf = xstrdup (curve); } else { for (i=0; i < keyalgo_strings_used; i++) { if (keyalgo_strings[i].algo == algo && !keyalgo_strings[i].nbits && !keyalgo_strings[i].curve) return keyalgo_strings[i].name; } /* Not yet in the table - add it. */ name = xasprintf ("unknown_%u", (unsigned int)algo); nbits = 0; curvebuf = NULL; } /* Store a new entry. This is a loop because of a possible nPth * thread switch during xrealloc. */ while (keyalgo_strings_used >= keyalgo_strings_size) { keyalgo_strings_size += 10; if (keyalgo_strings_size > 1024*1024) log_fatal ("%s: table getting too large - possible DoS\n", __func__); keyalgo_strings = xrealloc (keyalgo_strings, (keyalgo_strings_size * sizeof *keyalgo_strings)); } keyalgo_strings[keyalgo_strings_used].algo = algo; keyalgo_strings[keyalgo_strings_used].nbits = nbits; keyalgo_strings[keyalgo_strings_used].curve = curvebuf; keyalgo_strings[keyalgo_strings_used].name = name; keyalgo_strings_used++; return name; /* Note that this is in the table. */ } diff --git a/common/sexputil.c b/common/sexputil.c index b007b71f6..981a06664 100644 --- a/common/sexputil.c +++ b/common/sexputil.c @@ -1,804 +1,811 @@ /* sexputil.c - Utility functions for S-expressions. * Copyright (C) 2005, 2007, 2009 Free Software Foundation, Inc. * Copyright (C) 2013 Werner Koch * * This file is part of GnuPG. * * This file is free software; you can redistribute it and/or modify * it under the terms of either * * - the GNU Lesser General Public License as published by the Free * Software Foundation; either version 3 of the License, or (at * your option) any later version. * * or * * - the GNU General Public License as published by the Free * Software Foundation; either version 2 of the License, or (at * your option) any later version. * * or both in parallel, as here. * * This file is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . */ /* This file implements a few utility functions useful when working with canonical encrypted S-expressions (i.e. not the S-exprssion objects from libgcrypt). */ #include #include #include #include #include #include #ifdef HAVE_LOCALE_H #include #endif #include "util.h" #include "tlv.h" #include "sexp-parse.h" #include "openpgpdefs.h" /* for pubkey_algo_t */ /* Return a malloced string with the S-expression CANON in advanced format. Returns NULL on error. */ static char * sexp_to_string (gcry_sexp_t sexp) { size_t n; char *result; if (!sexp) return NULL; n = gcry_sexp_sprint (sexp, GCRYSEXP_FMT_ADVANCED, NULL, 0); if (!n) return NULL; result = xtrymalloc (n); if (!result) return NULL; n = gcry_sexp_sprint (sexp, GCRYSEXP_FMT_ADVANCED, result, n); if (!n) BUG (); return result; } /* Return a malloced string with the S-expression CANON in advanced format. Returns NULL on error. */ char * canon_sexp_to_string (const unsigned char *canon, size_t canonlen) { size_t n; gcry_sexp_t sexp; char *result; n = gcry_sexp_canon_len (canon, canonlen, NULL, NULL); if (!n) return NULL; if (gcry_sexp_sscan (&sexp, NULL, canon, n)) return NULL; result = sexp_to_string (sexp); gcry_sexp_release (sexp); return result; } /* Print the canonical encoded S-expression in SEXP in advanced format. SEXPLEN may be passed as 0 is SEXP is known to be valid. With TEXT of NULL print just the raw S-expression, with TEXT just an empty string, print a trailing linefeed, otherwise print an entire debug line. */ void log_printcanon (const char *text, const unsigned char *sexp, size_t sexplen) { if (text && *text) log_debug ("%s ", text); if (sexp) { char *buf = canon_sexp_to_string (sexp, sexplen); log_printf ("%s", buf? buf : "[invalid S-expression]"); xfree (buf); } if (text) log_printf ("\n"); } /* Print the gcrypt S-expression SEXP in advanced format. With TEXT of NULL print just the raw S-expression, with TEXT just an empty string, print a trailing linefeed, otherwise print an entire debug line. */ void log_printsexp (const char *text, gcry_sexp_t sexp) { if (text && *text) log_debug ("%s ", text); if (sexp) { char *buf = sexp_to_string (sexp); log_printf ("%s", buf? buf : "[invalid S-expression]"); xfree (buf); } if (text) log_printf ("\n"); } /* Helper function to create a canonical encoded S-expression from a Libgcrypt S-expression object. The function returns 0 on success and the malloced canonical S-expression is stored at R_BUFFER and the allocated length at R_BUFLEN. On error an error code is returned and (NULL, 0) stored at R_BUFFER and R_BUFLEN. If the allocated buffer length is not required, NULL by be used for R_BUFLEN. */ gpg_error_t make_canon_sexp (gcry_sexp_t sexp, unsigned char **r_buffer, size_t *r_buflen) { size_t len; unsigned char *buf; *r_buffer = NULL; if (r_buflen) *r_buflen = 0;; len = gcry_sexp_sprint (sexp, GCRYSEXP_FMT_CANON, NULL, 0); if (!len) return gpg_error (GPG_ERR_BUG); buf = xtrymalloc (len); if (!buf) return gpg_error_from_syserror (); len = gcry_sexp_sprint (sexp, GCRYSEXP_FMT_CANON, buf, len); if (!len) return gpg_error (GPG_ERR_BUG); *r_buffer = buf; if (r_buflen) *r_buflen = len; return 0; } /* Same as make_canon_sexp but pad the buffer to multiple of 64 bits. If SECURE is set, secure memory will be allocated. */ gpg_error_t make_canon_sexp_pad (gcry_sexp_t sexp, int secure, unsigned char **r_buffer, size_t *r_buflen) { size_t len; unsigned char *buf; *r_buffer = NULL; if (r_buflen) *r_buflen = 0;; len = gcry_sexp_sprint (sexp, GCRYSEXP_FMT_CANON, NULL, 0); if (!len) return gpg_error (GPG_ERR_BUG); len += (8 - len % 8) % 8; buf = secure? xtrycalloc_secure (1, len) : xtrycalloc (1, len); if (!buf) return gpg_error_from_syserror (); if (!gcry_sexp_sprint (sexp, GCRYSEXP_FMT_CANON, buf, len)) return gpg_error (GPG_ERR_BUG); *r_buffer = buf; if (r_buflen) *r_buflen = len; return 0; } /* Return the so called "keygrip" which is the SHA-1 hash of the public key parameters expressed in a way dependend on the algorithm. KEY is expected to be an canonical encoded S-expression with a public or private key. KEYLEN is the length of that buffer. GRIP must be at least 20 bytes long. On success 0 is returned, on error an error code. */ gpg_error_t keygrip_from_canon_sexp (const unsigned char *key, size_t keylen, unsigned char *grip) { gpg_error_t err; gcry_sexp_t sexp; if (!grip) return gpg_error (GPG_ERR_INV_VALUE); err = gcry_sexp_sscan (&sexp, NULL, (const char *)key, keylen); if (err) return err; if (!gcry_pk_get_keygrip (sexp, grip)) err = gpg_error (GPG_ERR_INTERNAL); gcry_sexp_release (sexp); return err; } /* Compare two simple S-expressions like "(3:foo)". Returns 0 if they are identical or !0 if they are not. Note that this function can't be used for sorting. */ int cmp_simple_canon_sexp (const unsigned char *a_orig, const unsigned char *b_orig) { const char *a = (const char *)a_orig; const char *b = (const char *)b_orig; unsigned long n1, n2; char *endp; if (!a && !b) return 0; /* Both are NULL, they are identical. */ if (!a || !b) return 1; /* One is NULL, they are not identical. */ if (*a != '(' || *b != '(') log_bug ("invalid S-exp in cmp_simple_canon_sexp\n"); a++; n1 = strtoul (a, &endp, 10); a = endp; b++; n2 = strtoul (b, &endp, 10); b = endp; if (*a != ':' || *b != ':' ) log_bug ("invalid S-exp in cmp_simple_canon_sexp\n"); if (n1 != n2) return 1; /* Not the same. */ for (a++, b++; n1; n1--, a++, b++) if (*a != *b) return 1; /* Not the same. */ return 0; } /* Create a simple S-expression from the hex string at LINE. Returns a newly allocated buffer with that canonical encoded S-expression or NULL in case of an error. On return the number of characters scanned in LINE will be stored at NSCANNED. This functions stops converting at the first character not representing a hexdigit. Odd numbers of hex digits are allowed; a leading zero is then assumed. If no characters have been found, NULL is returned.*/ unsigned char * make_simple_sexp_from_hexstr (const char *line, size_t *nscanned) { size_t n, len; const char *s; unsigned char *buf; unsigned char *p; char numbuf[50], *numbufp; size_t numbuflen; for (n=0, s=line; hexdigitp (s); s++, n++) ; if (nscanned) *nscanned = n; if (!n) return NULL; len = ((n+1) & ~0x01)/2; numbufp = smklen (numbuf, sizeof numbuf, len, &numbuflen); buf = xtrymalloc (1 + numbuflen + len + 1 + 1); if (!buf) return NULL; buf[0] = '('; p = (unsigned char *)stpcpy ((char *)buf+1, numbufp); s = line; if ((n&1)) { *p++ = xtoi_1 (s); s++; n--; } for (; n > 1; n -=2, s += 2) *p++ = xtoi_2 (s); *p++ = ')'; *p = 0; /* (Not really needed.) */ return buf; } /* Return the hash algorithm from a KSBA sig-val. SIGVAL is a canonical encoded S-expression. Return 0 if the hash algorithm is not encoded in SIG-VAL or it is not supported by libgcrypt. */ int hash_algo_from_sigval (const unsigned char *sigval) { const unsigned char *s = sigval; size_t n; int depth; char buffer[50]; if (!s || *s != '(') return 0; /* Invalid S-expression. */ s++; n = snext (&s); if (!n) return 0; /* Invalid S-expression. */ if (!smatch (&s, n, "sig-val")) return 0; /* Not a sig-val. */ if (*s != '(') return 0; /* Invalid S-expression. */ s++; /* Skip over the algo+parameter list. */ depth = 1; if (sskip (&s, &depth) || depth) return 0; /* Invalid S-expression. */ if (*s != '(') return 0; /* No further list. */ /* Check whether this is (hash ALGO). */ s++; n = snext (&s); if (!n) return 0; /* Invalid S-expression. */ if (!smatch (&s, n, "hash")) return 0; /* Not a "hash" keyword. */ n = snext (&s); if (!n || n+1 >= sizeof (buffer)) return 0; /* Algorithm string is missing or too long. */ memcpy (buffer, s, n); buffer[n] = 0; return gcry_md_map_name (buffer); } /* Create a public key S-expression for an RSA public key from the modulus M with length MLEN and the public exponent E with length ELEN. Returns a newly allocated buffer of NULL in case of a memory allocation problem. If R_LEN is not NULL, the length of the canonical S-expression is stored there. */ unsigned char * make_canon_sexp_from_rsa_pk (const void *m_arg, size_t mlen, const void *e_arg, size_t elen, size_t *r_len) { const unsigned char *m = m_arg; const unsigned char *e = e_arg; int m_extra = 0; int e_extra = 0; char mlen_str[35]; char elen_str[35]; unsigned char *keybuf, *p; const char part1[] = "(10:public-key(3:rsa(1:n"; const char part2[] = ")(1:e"; const char part3[] = ")))"; /* Remove leading zeroes. */ for (; mlen && !*m; mlen--, m++) ; for (; elen && !*e; elen--, e++) ; /* Insert a leading zero if the number would be zero or interpreted as negative. */ if (!mlen || (m[0] & 0x80)) m_extra = 1; if (!elen || (e[0] & 0x80)) e_extra = 1; /* Build the S-expression. */ snprintf (mlen_str, sizeof mlen_str, "%u:", (unsigned int)mlen+m_extra); snprintf (elen_str, sizeof elen_str, "%u:", (unsigned int)elen+e_extra); keybuf = xtrymalloc (strlen (part1) + strlen (mlen_str) + mlen + m_extra + strlen (part2) + strlen (elen_str) + elen + e_extra + strlen (part3) + 1); if (!keybuf) return NULL; p = stpcpy (keybuf, part1); p = stpcpy (p, mlen_str); if (m_extra) *p++ = 0; memcpy (p, m, mlen); p += mlen; p = stpcpy (p, part2); p = stpcpy (p, elen_str); if (e_extra) *p++ = 0; memcpy (p, e, elen); p += elen; p = stpcpy (p, part3); if (r_len) *r_len = p - keybuf; return keybuf; } /* Return the parameters of a public RSA key expressed as an canonical encoded S-expression. */ gpg_error_t get_rsa_pk_from_canon_sexp (const unsigned char *keydata, size_t keydatalen, unsigned char const **r_n, size_t *r_nlen, unsigned char const **r_e, size_t *r_elen) { gpg_error_t err; const unsigned char *buf, *tok; size_t buflen, toklen; int depth, last_depth1, last_depth2; const unsigned char *rsa_n = NULL; const unsigned char *rsa_e = NULL; size_t rsa_n_len, rsa_e_len; *r_n = NULL; *r_nlen = 0; *r_e = NULL; *r_elen = 0; buf = keydata; buflen = keydatalen; depth = 0; if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen))) return err; if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen))) return err; if (!tok || toklen != 10 || memcmp ("public-key", tok, toklen)) return gpg_error (GPG_ERR_BAD_PUBKEY); if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen))) return err; if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen))) return err; if (!tok || toklen != 3 || memcmp ("rsa", tok, toklen)) return gpg_error (GPG_ERR_WRONG_PUBKEY_ALGO); last_depth1 = depth; while (!(err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)) && depth && depth >= last_depth1) { if (tok) return gpg_error (GPG_ERR_UNKNOWN_SEXP); if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen))) return err; if (tok && toklen == 1) { const unsigned char **mpi; size_t *mpi_len; switch (*tok) { case 'n': mpi = &rsa_n; mpi_len = &rsa_n_len; break; case 'e': mpi = &rsa_e; mpi_len = &rsa_e_len; break; default: mpi = NULL; mpi_len = NULL; break; } if (mpi && *mpi) return gpg_error (GPG_ERR_DUP_VALUE); if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen))) return err; if (tok && mpi) { /* Strip off leading zero bytes and save. */ for (;toklen && !*tok; toklen--, tok++) ; *mpi = tok; *mpi_len = toklen; } } /* Skip to the end of the list. */ last_depth2 = depth; while (!(err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)) && depth && depth >= last_depth2) ; if (err) return err; } if (err) return err; if (!rsa_n || !rsa_n_len || !rsa_e || !rsa_e_len) return gpg_error (GPG_ERR_BAD_PUBKEY); *r_n = rsa_n; *r_nlen = rsa_n_len; *r_e = rsa_e; *r_elen = rsa_e_len; return 0; } /* Return the public key parameter Q of a public RSA or ECC key * expressed as an canonical encoded S-expression. */ gpg_error_t get_ecc_q_from_canon_sexp (const unsigned char *keydata, size_t keydatalen, unsigned char const **r_q, size_t *r_qlen) { gpg_error_t err; const unsigned char *buf, *tok; size_t buflen, toklen; int depth, last_depth1, last_depth2; const unsigned char *ecc_q = NULL; size_t ecc_q_len; *r_q = NULL; *r_qlen = 0; buf = keydata; buflen = keydatalen; depth = 0; if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen))) return err; if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen))) return err; if (!tok || toklen != 10 || memcmp ("public-key", tok, toklen)) return gpg_error (GPG_ERR_BAD_PUBKEY); if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen))) return err; if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen))) return err; if (tok && toklen == 3 && !memcmp ("ecc", tok, toklen)) ; else if (tok && toklen == 5 && (!memcmp ("ecdsa", tok, toklen) || !memcmp ("eddsa", tok, toklen))) ; else return gpg_error (GPG_ERR_WRONG_PUBKEY_ALGO); last_depth1 = depth; while (!(err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)) && depth && depth >= last_depth1) { if (tok) return gpg_error (GPG_ERR_UNKNOWN_SEXP); if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen))) return err; if (tok && toklen == 1) { const unsigned char **mpi; size_t *mpi_len; switch (*tok) { case 'q': mpi = &ecc_q; mpi_len = &ecc_q_len; break; default: mpi = NULL; mpi_len = NULL; break; } if (mpi && *mpi) return gpg_error (GPG_ERR_DUP_VALUE); if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen))) return err; if (tok && mpi) { *mpi = tok; *mpi_len = toklen; } } /* Skip to the end of the list. */ last_depth2 = depth; while (!(err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)) && depth && depth >= last_depth2) ; if (err) return err; } if (err) return err; if (!ecc_q || !ecc_q_len) return gpg_error (GPG_ERR_BAD_PUBKEY); *r_q = ecc_q; *r_qlen = ecc_q_len; return 0; } /* Return the algo of a public KEY of SEXP. */ int get_pk_algo_from_key (gcry_sexp_t key) { gcry_sexp_t list; const char *s; size_t n; char algoname[6]; int algo = 0; list = gcry_sexp_nth (key, 1); if (!list) goto out; s = gcry_sexp_nth_data (list, 0, &n); if (!s) goto out; if (n >= sizeof (algoname)) goto out; memcpy (algoname, s, n); algoname[n] = 0; algo = gcry_pk_map_name (algoname); if (algo == GCRY_PK_ECC) { - gcry_sexp_t l1 = gcry_sexp_find_token (list, "flags", 0); + gcry_sexp_t l1; int i; + l1 = gcry_sexp_find_token (list, "flags", 0); for (i = l1 ? gcry_sexp_length (l1)-1 : 0; i > 0; i--) { s = gcry_sexp_nth_data (l1, i, &n); if (!s) continue; /* Not a data element. */ if (n == 5 && !memcmp (s, "eddsa", 5)) { algo = GCRY_PK_EDDSA; break; } } 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: gcry_sexp_release (list); return algo; } /* This is a variant of get_pk_algo_from_key but takes an canonical * encoded S-expression as input. Returns a GCRYPT public key * identiier or 0 on error. */ int get_pk_algo_from_canon_sexp (const unsigned char *keydata, size_t keydatalen) { gcry_sexp_t sexp; int algo; if (gcry_sexp_sscan (&sexp, NULL, keydata, keydatalen)) return 0; algo = get_pk_algo_from_key (sexp); gcry_sexp_release (sexp); return algo; } /* Given the public key S_PKEY, return a new buffer with a descriptive * string for its algorithm. This function may return NULL on memory * error. If R_ALGOID is not NULL the gcrypt algo id is stored there. */ char * pubkey_algo_string (gcry_sexp_t s_pkey, enum gcry_pk_algos *r_algoid) { const char *prefix; gcry_sexp_t l1; char *algoname; int algo; char *result; if (r_algoid) *r_algoid = 0; l1 = gcry_sexp_find_token (s_pkey, "public-key", 0); if (!l1) return xtrystrdup ("E_no_key"); { gcry_sexp_t l_tmp = gcry_sexp_cadr (l1); gcry_sexp_release (l1); l1 = l_tmp; } algoname = gcry_sexp_nth_string (l1, 0); gcry_sexp_release (l1); if (!algoname) return xtrystrdup ("E_no_algo"); algo = gcry_pk_map_name (algoname); switch (algo) { case GCRY_PK_RSA: prefix = "rsa"; break; case GCRY_PK_ELG: prefix = "elg"; break; case GCRY_PK_DSA: prefix = "dsa"; break; case GCRY_PK_ECC: prefix = ""; break; default: prefix = NULL; break; } if (prefix && *prefix) result = xtryasprintf ("%s%u", prefix, gcry_pk_get_nbits (s_pkey)); else if (prefix) { const char *curve = gcry_pk_get_curve (s_pkey, 0, NULL); const char *name = openpgp_oid_to_curve (openpgp_curve_to_oid (curve, NULL, NULL), 0); if (name) result = xtrystrdup (name); else if (curve) result = xtryasprintf ("X_%s", curve); else result = xtrystrdup ("E_unknown"); } else result = xtryasprintf ("X_algo_%d", algo); if (r_algoid) *r_algoid = algo; xfree (algoname); return result; } /* Map a pubkey algo id from gcrypt to a string. This is the same as * gcry_pk_algo_name but makes sure that the ECC algo identifiers are * not all mapped to "ECC". */ const char * pubkey_algo_to_string (int algo) { if (algo == GCRY_PK_ECDSA) return "ECDSA"; else if (algo == GCRY_PK_ECDH) return "ECDH"; else if (algo == GCRY_PK_EDDSA) return "EdDSA"; else return gcry_pk_algo_name (algo); } /* Map a hash algo id from gcrypt to a string. This is the same as * gcry_md_algo_name but the returned string is lower case, as * expected by libksba and it avoids some overhead. */ const char * hash_algo_to_string (int algo) { static const struct { const char *name; int algo; } hashnames[] = { { "sha256", GCRY_MD_SHA256 }, { "sha512", GCRY_MD_SHA512 }, { "sha1", GCRY_MD_SHA1 }, { "sha384", GCRY_MD_SHA384 }, { "sha224", GCRY_MD_SHA224 }, { "sha3-224", GCRY_MD_SHA3_224 }, { "sha3-256", GCRY_MD_SHA3_256 }, { "sha3-384", GCRY_MD_SHA3_384 }, { "sha3-512", GCRY_MD_SHA3_512 }, { "ripemd160", GCRY_MD_RMD160 }, { "rmd160", GCRY_MD_RMD160 }, { "md2", GCRY_MD_MD2 }, { "md4", GCRY_MD_MD4 }, { "tiger", GCRY_MD_TIGER }, { "haval", GCRY_MD_HAVAL }, #if GCRYPT_VERSION_NUMBER >= 0x010900 { "sm3", GCRY_MD_SM3 }, #endif { "md5", GCRY_MD_MD5 } }; int i; for (i=0; i < DIM (hashnames); i++) if (algo == hashnames[i].algo) return hashnames[i].name; return "?"; } /* Map cipher modes to a string. */ const char * cipher_mode_to_string (int mode) { switch (mode) { case GCRY_CIPHER_MODE_CFB: return "CFB"; case GCRY_CIPHER_MODE_CBC: return "CBC"; case GCRY_CIPHER_MODE_GCM: return "GCM"; case GCRY_CIPHER_MODE_OCB: return "OCB"; case 14: return "EAX"; /* Only in gcrypt 1.9 */ default: return "[?]"; } } diff --git a/g10/export.c b/g10/export.c index d06896026..909b98701 100644 --- a/g10/export.c +++ b/g10/export.c @@ -1,2495 +1,2497 @@ /* export.c - Export keys in the OpenPGP defined format. * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, * 2005, 2010 Free Software Foundation, Inc. * Copyright (C) 1998-2016 Werner Koch * * This file is part of GnuPG. * * GnuPG is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * GnuPG is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . */ #include #include #include #include #include #include "gpg.h" #include "options.h" #include "packet.h" #include "../common/status.h" #include "keydb.h" #include "../common/util.h" #include "main.h" #include "../common/i18n.h" #include "../common/membuf.h" #include "../common/host2net.h" #include "../common/zb32.h" #include "../common/recsel.h" #include "../common/mbox-util.h" #include "../common/init.h" #include "trustdb.h" #include "call-agent.h" #include "key-clean.h" #include "pkglue.h" /* An object to keep track of subkeys. */ struct subkey_list_s { struct subkey_list_s *next; u32 kid[2]; }; typedef struct subkey_list_s *subkey_list_t; /* An object to track statistics for export operations. */ struct export_stats_s { ulong count; /* Number of processed keys. */ ulong secret_count; /* Number of secret keys seen. */ ulong exported; /* Number of actual exported keys. */ }; /* A global variable to store the selector created from * --export-filter keep-uid=EXPR. * --export-filter drop-subkey=EXPR. * * FIXME: We should put this into the CTRL object but that requires a * lot more changes right now. */ static recsel_expr_t export_keep_uid; static recsel_expr_t export_drop_subkey; /* An object used for a linked list to implement the * push_export_filter/pop_export_filters functions. */ struct export_filter_attic_s { struct export_filter_attic_s *next; recsel_expr_t export_keep_uid; recsel_expr_t export_drop_subkey; }; static struct export_filter_attic_s *export_filter_attic; /* Local prototypes. */ static int do_export (ctrl_t ctrl, strlist_t users, int secret, unsigned int options, export_stats_t stats); static int do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret, kbnode_t *keyblock_out, unsigned int options, export_stats_t stats, int *any); static gpg_error_t print_pka_or_dane_records /**/ (iobuf_t out, kbnode_t keyblock, PKT_public_key *pk, const void *data, size_t datalen, int print_pka, int print_dane); static void cleanup_export_globals (void) { recsel_release (export_keep_uid); export_keep_uid = NULL; recsel_release (export_drop_subkey); export_drop_subkey = NULL; } /* Option parser for export options. See parse_options for details. */ int parse_export_options(char *str,unsigned int *options,int noisy) { struct parse_options export_opts[]= { {"export-local-sigs",EXPORT_LOCAL_SIGS,NULL, N_("export signatures that are marked as local-only")}, {"export-attributes",EXPORT_ATTRIBUTES,NULL, N_("export attribute user IDs (generally photo IDs)")}, {"export-sensitive-revkeys",EXPORT_SENSITIVE_REVKEYS,NULL, N_("export revocation keys marked as \"sensitive\"")}, {"export-clean",EXPORT_CLEAN,NULL, N_("remove unusable parts from key during export")}, {"export-minimal",EXPORT_MINIMAL|EXPORT_CLEAN,NULL, N_("remove as much as possible from key during export")}, {"export-drop-uids", EXPORT_DROP_UIDS, NULL, N_("Do not export user id or attribute packets")}, {"export-pka", EXPORT_PKA_FORMAT, NULL, NULL }, {"export-dane", EXPORT_DANE_FORMAT, NULL, NULL }, {"backup", EXPORT_BACKUP, NULL, N_("use the GnuPG key backup format")}, {"export-backup", EXPORT_BACKUP, NULL, NULL }, /* Aliases for backward compatibility */ {"include-local-sigs",EXPORT_LOCAL_SIGS,NULL,NULL}, {"include-attributes",EXPORT_ATTRIBUTES,NULL,NULL}, {"include-sensitive-revkeys",EXPORT_SENSITIVE_REVKEYS,NULL,NULL}, /* dummy */ {"export-unusable-sigs",0,NULL,NULL}, {"export-clean-sigs",0,NULL,NULL}, {"export-clean-uids",0,NULL,NULL}, {NULL,0,NULL,NULL} /* add tags for include revoked and disabled? */ }; int rc; rc = parse_options (str, options, export_opts, noisy); if (!rc) return 0; /* Alter other options we want or don't want for restore. */ if ((*options & EXPORT_BACKUP)) { *options |= (EXPORT_LOCAL_SIGS | EXPORT_ATTRIBUTES | EXPORT_SENSITIVE_REVKEYS); *options &= ~(EXPORT_CLEAN | EXPORT_MINIMAL | EXPORT_PKA_FORMAT | EXPORT_DANE_FORMAT); } /* Dropping uids also means to drop attributes. */ if ((*options & EXPORT_DROP_UIDS)) *options &= ~(EXPORT_ATTRIBUTES); return rc; } /* Parse and set an export filter from string. STRING has the format * "NAME=EXPR" with NAME being the name of the filter. Spaces before * and after NAME are not allowed. If this function is called several * times all expressions for the same NAME are concatenated. * Supported filter names are: * * - keep-uid :: If the expression evaluates to true for a certain * user ID packet, that packet and all it dependencies * will be exported. The expression may use these * variables: * * - uid :: The entire user ID. * - mbox :: The mail box part of the user ID. * - primary :: Evaluate to true for the primary user ID. * * - drop-subkey :: If the expression evaluates to true for a subkey * packet that subkey and all it dependencies will be * remove from the keyblock. The expression may use these * variables: * * - secret :: 1 for a secret subkey, else 0. * - key_algo :: Public key algorithm id */ gpg_error_t parse_and_set_export_filter (const char *string) { gpg_error_t err; /* Auto register the cleanup function. */ register_mem_cleanup_func (cleanup_export_globals); if (!strncmp (string, "keep-uid=", 9)) err = recsel_parse_expr (&export_keep_uid, string+9); else if (!strncmp (string, "drop-subkey=", 12)) err = recsel_parse_expr (&export_drop_subkey, string+12); else err = gpg_error (GPG_ERR_INV_NAME); return err; } /* Push the current export filters onto a stack so that new export * filters can be defined which will be active until the next * pop_export_filters or another push_export_filters. */ void push_export_filters (void) { struct export_filter_attic_s *item; item = xcalloc (1, sizeof *item); item->export_keep_uid = export_keep_uid; export_keep_uid = NULL; item->export_drop_subkey = export_drop_subkey; export_drop_subkey = NULL; item->next = export_filter_attic; export_filter_attic = item; } /* Revert the last push_export_filters. */ void pop_export_filters (void) { struct export_filter_attic_s *item; item = export_filter_attic; if (!item) BUG (); /* No corresponding push. */ export_filter_attic = item->next; cleanup_export_globals (); export_keep_uid = item->export_keep_uid; export_drop_subkey = item->export_drop_subkey; } /* Create a new export stats object initialized to zero. On error returns NULL and sets ERRNO. */ export_stats_t export_new_stats (void) { export_stats_t stats; return xtrycalloc (1, sizeof *stats); } /* Release an export stats object. */ void export_release_stats (export_stats_t stats) { xfree (stats); } /* Print export statistics using the status interface. */ void export_print_stats (export_stats_t stats) { if (!stats) return; if (is_status_enabled ()) { char buf[15*20]; snprintf (buf, sizeof buf, "%lu %lu %lu", stats->count, stats->secret_count, stats->exported ); write_status_text (STATUS_EXPORT_RES, buf); } } /* * Export public keys (to stdout or to --output FILE). * * Depending on opt.armor the output is armored. OPTIONS are defined * in main.h. If USERS is NULL, all keys will be exported. STATS is * either an export stats object for update or NULL. * * This function is the core of "gpg --export". */ int export_pubkeys (ctrl_t ctrl, strlist_t users, unsigned int options, export_stats_t stats) { return do_export (ctrl, users, 0, options, stats); } /* * Export secret keys (to stdout or to --output FILE). * * Depending on opt.armor the output is armored. OPTIONS are defined * in main.h. If USERS is NULL, all secret keys will be exported. * STATS is either an export stats object for update or NULL. * * This function is the core of "gpg --export-secret-keys". */ int export_seckeys (ctrl_t ctrl, strlist_t users, unsigned int options, export_stats_t stats) { return do_export (ctrl, users, 1, options, stats); } /* * Export secret sub keys (to stdout or to --output FILE). * * This is the same as export_seckeys but replaces the primary key by * a stub key. Depending on opt.armor the output is armored. OPTIONS * are defined in main.h. If USERS is NULL, all secret subkeys will * be exported. STATS is either an export stats object for update or * NULL. * * This function is the core of "gpg --export-secret-subkeys". */ int export_secsubkeys (ctrl_t ctrl, strlist_t users, unsigned int options, export_stats_t stats) { return do_export (ctrl, users, 2, options, stats); } /* * Export a single key into a memory buffer. STATS is either an * export stats object for update or NULL. If PREFIX is not NULL * PREFIXLEN bytes from PREFIX are prepended to the R_DATA. */ gpg_error_t export_pubkey_buffer (ctrl_t ctrl, const char *keyspec, unsigned int options, const void *prefix, size_t prefixlen, export_stats_t stats, kbnode_t *r_keyblock, void **r_data, size_t *r_datalen) { gpg_error_t err; iobuf_t iobuf; int any; strlist_t helplist; *r_keyblock = NULL; *r_data = NULL; *r_datalen = 0; helplist = NULL; if (!add_to_strlist_try (&helplist, keyspec)) return gpg_error_from_syserror (); iobuf = iobuf_temp (); if (prefix && prefixlen) iobuf_write (iobuf, prefix, prefixlen); err = do_export_stream (ctrl, iobuf, helplist, 0, r_keyblock, options, stats, &any); if (!err && !any) err = gpg_error (GPG_ERR_NOT_FOUND); if (!err) { const void *src; size_t datalen; iobuf_flush_temp (iobuf); src = iobuf_get_temp_buffer (iobuf); datalen = iobuf_get_temp_length (iobuf); if (!datalen) err = gpg_error (GPG_ERR_NO_PUBKEY); else if (!(*r_data = xtrymalloc (datalen))) err = gpg_error_from_syserror (); else { memcpy (*r_data, src, datalen); *r_datalen = datalen; } } iobuf_close (iobuf); free_strlist (helplist); if (err && *r_keyblock) { release_kbnode (*r_keyblock); *r_keyblock = NULL; } return err; } /* Export the keys identified by the list of strings in USERS. If Secret is false public keys will be exported. With secret true secret keys will be exported; in this case 1 means the entire secret keyblock and 2 only the subkeys. OPTIONS are the export options to apply. */ static int do_export (ctrl_t ctrl, strlist_t users, int secret, unsigned int options, export_stats_t stats) { IOBUF out = NULL; int any, rc; armor_filter_context_t *afx = NULL; compress_filter_context_t zfx; memset( &zfx, 0, sizeof zfx); rc = open_outfile (-1, NULL, 0, !!secret, &out ); if (rc) return rc; if ( opt.armor && !(options & (EXPORT_PKA_FORMAT|EXPORT_DANE_FORMAT)) ) { afx = new_armor_context (); afx->what = secret? 5 : 1; push_armor_filter (afx, out); } rc = do_export_stream (ctrl, out, users, secret, NULL, options, stats, &any); if ( rc || !any ) iobuf_cancel (out); else iobuf_close (out); release_armor_context (afx); return rc; } /* Release an entire subkey list. */ static void release_subkey_list (subkey_list_t list) { while (list) { subkey_list_t tmp = list->next;; xfree (list); list = tmp; } } /* Returns true if NODE is a subkey and contained in LIST. */ static int subkey_in_list_p (subkey_list_t list, KBNODE node) { if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY || node->pkt->pkttype == PKT_SECRET_SUBKEY ) { u32 kid[2]; keyid_from_pk (node->pkt->pkt.public_key, kid); for (; list; list = list->next) if (list->kid[0] == kid[0] && list->kid[1] == kid[1]) return 1; } return 0; } /* Allocate a new subkey list item from NODE. */ static subkey_list_t new_subkey_list_item (KBNODE node) { subkey_list_t list = xcalloc (1, sizeof *list); if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY || node->pkt->pkttype == PKT_SECRET_SUBKEY) keyid_from_pk (node->pkt->pkt.public_key, list->kid); return list; } /* Helper function to check whether the subkey at NODE actually matches the description at DESC. The function returns true if the key under question has been specified by an exact specification (keyID or fingerprint) and does match the one at NODE. It is assumed that the packet at NODE is either a public or secret subkey. */ int exact_subkey_match_p (KEYDB_SEARCH_DESC *desc, kbnode_t node) { u32 kid[2]; byte fpr[MAX_FINGERPRINT_LEN]; size_t fprlen; int result = 0; switch(desc->mode) { case KEYDB_SEARCH_MODE_SHORT_KID: case KEYDB_SEARCH_MODE_LONG_KID: keyid_from_pk (node->pkt->pkt.public_key, kid); break; case KEYDB_SEARCH_MODE_FPR: fingerprint_from_pk (node->pkt->pkt.public_key, fpr, &fprlen); break; default: break; } switch(desc->mode) { case KEYDB_SEARCH_MODE_SHORT_KID: if (desc->u.kid[1] == kid[1]) result = 1; break; case KEYDB_SEARCH_MODE_LONG_KID: if (desc->u.kid[0] == kid[0] && desc->u.kid[1] == kid[1]) result = 1; break; case KEYDB_SEARCH_MODE_FPR: if (fprlen == desc->fprlen && !memcmp (desc->u.fpr, fpr, desc->fprlen)) result = 1; break; default: break; } return result; } /* Return an error if the key represented by the S-expression S_KEY * and the OpenPGP key represented by PK do not use the same curve. */ static gpg_error_t match_curve_skey_pk (gcry_sexp_t s_key, PKT_public_key *pk) { gcry_sexp_t curve = NULL; gcry_sexp_t flags = NULL; char *curve_str = NULL; char *flag; const char *oidstr = NULL; gcry_mpi_t curve_as_mpi = NULL; gpg_error_t err; int is_eddsa = 0; int idx = 0; if (!(pk->pubkey_algo==PUBKEY_ALGO_ECDH || pk->pubkey_algo==PUBKEY_ALGO_ECDSA || pk->pubkey_algo==PUBKEY_ALGO_EDDSA)) return gpg_error (GPG_ERR_PUBKEY_ALGO); curve = gcry_sexp_find_token (s_key, "curve", 0); if (!curve) { log_error ("no reported curve\n"); return gpg_error (GPG_ERR_UNKNOWN_CURVE); } curve_str = gcry_sexp_nth_string (curve, 1); gcry_sexp_release (curve); curve = NULL; if (!curve_str) { log_error ("no curve name\n"); return gpg_error (GPG_ERR_UNKNOWN_CURVE); } + if (!strcmp (curve_str, "Ed448")) + is_eddsa = 1; oidstr = openpgp_curve_to_oid (curve_str, NULL, NULL); if (!oidstr) { log_error ("no OID known for curve '%s'\n", curve_str); xfree (curve_str); return gpg_error (GPG_ERR_UNKNOWN_CURVE); } xfree (curve_str); err = openpgp_oid_from_str (oidstr, &curve_as_mpi); if (err) return err; if (gcry_mpi_cmp (pk->pkey[0], curve_as_mpi)) { log_error ("curves do not match\n"); gcry_mpi_release (curve_as_mpi); return gpg_error (GPG_ERR_INV_CURVE); } gcry_mpi_release (curve_as_mpi); flags = gcry_sexp_find_token (s_key, "flags", 0); if (flags) { for (idx = 1; idx < gcry_sexp_length (flags); idx++) { flag = gcry_sexp_nth_string (flags, idx); if (flag && (strcmp ("eddsa", flag) == 0)) is_eddsa = 1; gcry_free (flag); } } if (is_eddsa != (pk->pubkey_algo == PUBKEY_ALGO_EDDSA)) { log_error ("disagreement about EdDSA\n"); err = gpg_error (GPG_ERR_INV_CURVE); } return err; } /* Return a canonicalized public key algorithms. This is used to compare different flavors of algorithms (e.g. ELG and ELG_E are considered the same). */ static enum gcry_pk_algos canon_pk_algo (enum gcry_pk_algos algo) { switch (algo) { case GCRY_PK_RSA: case GCRY_PK_RSA_E: case GCRY_PK_RSA_S: return GCRY_PK_RSA; case GCRY_PK_ELG: case GCRY_PK_ELG_E: return GCRY_PK_ELG; case GCRY_PK_ECC: case GCRY_PK_ECDSA: case GCRY_PK_ECDH: return GCRY_PK_ECC; default: return algo; } } /* Take a cleartext dump of a secret key in PK and change the * parameter array in PK to include the secret parameters. */ static gpg_error_t cleartext_secret_key_to_openpgp (gcry_sexp_t s_key, PKT_public_key *pk) { gpg_error_t err; gcry_sexp_t top_list; gcry_sexp_t key = NULL; char *key_type = NULL; enum gcry_pk_algos pk_algo; struct seckey_info *ski; int idx, sec_start; gcry_mpi_t pub_params[10] = { NULL }; /* we look for a private-key, then the first element in it tells us the type */ top_list = gcry_sexp_find_token (s_key, "private-key", 0); if (!top_list) goto bad_seckey; /* ignore all S-expression after the first sublist -- we assume that they are comments or otherwise irrelevant to OpenPGP */ if (gcry_sexp_length(top_list) < 2) goto bad_seckey; key = gcry_sexp_nth (top_list, 1); if (!key) goto bad_seckey; key_type = gcry_sexp_nth_string(key, 0); pk_algo = gcry_pk_map_name (key_type); log_assert (!pk->seckey_info); pk->seckey_info = ski = xtrycalloc (1, sizeof *ski); if (!ski) { err = gpg_error_from_syserror (); goto leave; } switch (canon_pk_algo (pk_algo)) { case GCRY_PK_RSA: if (!is_RSA (pk->pubkey_algo)) goto bad_pubkey_algo; err = gcry_sexp_extract_param (key, NULL, "ne", &pub_params[0], &pub_params[1], NULL); for (idx=0; idx < 2 && !err; idx++) if (gcry_mpi_cmp(pk->pkey[idx], pub_params[idx])) err = gpg_error (GPG_ERR_BAD_PUBKEY); if (!err) { for (idx = 2; idx < 6 && !err; idx++) { gcry_mpi_release (pk->pkey[idx]); pk->pkey[idx] = NULL; } err = gcry_sexp_extract_param (key, NULL, "dpqu", &pk->pkey[2], &pk->pkey[3], &pk->pkey[4], &pk->pkey[5], NULL); } if (!err) { for (idx = 2; idx < 6; idx++) ski->csum += checksum_mpi (pk->pkey[idx]); } break; case GCRY_PK_DSA: if (!is_DSA (pk->pubkey_algo)) goto bad_pubkey_algo; err = gcry_sexp_extract_param (key, NULL, "pqgy", &pub_params[0], &pub_params[1], &pub_params[2], &pub_params[3], NULL); for (idx=0; idx < 4 && !err; idx++) if (gcry_mpi_cmp(pk->pkey[idx], pub_params[idx])) err = gpg_error (GPG_ERR_BAD_PUBKEY); if (!err) { gcry_mpi_release (pk->pkey[4]); pk->pkey[4] = NULL; err = gcry_sexp_extract_param (key, NULL, "x", &pk->pkey[4], NULL); } if (!err) ski->csum += checksum_mpi (pk->pkey[4]); break; case GCRY_PK_ELG: if (!is_ELGAMAL (pk->pubkey_algo)) goto bad_pubkey_algo; err = gcry_sexp_extract_param (key, NULL, "pgy", &pub_params[0], &pub_params[1], &pub_params[2], NULL); for (idx=0; idx < 3 && !err; idx++) if (gcry_mpi_cmp(pk->pkey[idx], pub_params[idx])) err = gpg_error (GPG_ERR_BAD_PUBKEY); if (!err) { gcry_mpi_release (pk->pkey[3]); pk->pkey[3] = NULL; err = gcry_sexp_extract_param (key, NULL, "x", &pk->pkey[3], NULL); } if (!err) ski->csum += checksum_mpi (pk->pkey[3]); break; case GCRY_PK_ECC: err = match_curve_skey_pk (key, pk); if (err) goto leave; else err = sexp_extract_param_sos (key, "q", &pub_params[0]); if (!err && (gcry_mpi_cmp(pk->pkey[1], pub_params[0]))) err = gpg_error (GPG_ERR_BAD_PUBKEY); sec_start = 2; if (pk->pubkey_algo == PUBKEY_ALGO_ECDH) sec_start += 1; if (!err) { gcry_mpi_release (pk->pkey[sec_start]); pk->pkey[sec_start] = NULL; err = sexp_extract_param_sos (key, "d", &pk->pkey[sec_start]); } if (!err) ski->csum += checksum_mpi (pk->pkey[sec_start]); break; default: pk->seckey_info = NULL; xfree (ski); err = gpg_error (GPG_ERR_NOT_IMPLEMENTED); break; } leave: gcry_sexp_release (top_list); gcry_sexp_release (key); gcry_free (key_type); for (idx=0; idx < DIM(pub_params); idx++) gcry_mpi_release (pub_params[idx]); return err; bad_pubkey_algo: err = gpg_error (GPG_ERR_PUBKEY_ALGO); goto leave; bad_seckey: err = gpg_error (GPG_ERR_BAD_SECKEY); goto leave; } /* Use the key transfer format given in S_PGP to create the secinfo structure in PK and change the parameter array in PK to include the secret parameters. */ static gpg_error_t transfer_format_to_openpgp (gcry_sexp_t s_pgp, PKT_public_key *pk) { gpg_error_t err; gcry_sexp_t top_list; gcry_sexp_t list = NULL; char *curve = NULL; const char *value; size_t valuelen; char *string; int idx; int is_v4, is_protected; enum gcry_pk_algos pk_algo; int protect_algo = 0; char iv[16]; int ivlen = 0; int s2k_mode = 0; int s2k_algo = 0; byte s2k_salt[8]; u32 s2k_count = 0; int is_ecdh = 0; size_t npkey, nskey; gcry_mpi_t skey[10]; /* We support up to 9 parameters. */ int skeyidx = 0; struct seckey_info *ski; /* gcry_log_debugsxp ("transferkey", s_pgp); */ top_list = gcry_sexp_find_token (s_pgp, "openpgp-private-key", 0); if (!top_list) goto bad_seckey; list = gcry_sexp_find_token (top_list, "version", 0); if (!list) goto bad_seckey; value = gcry_sexp_nth_data (list, 1, &valuelen); if (!value || valuelen != 1 || !(value[0] == '3' || value[0] == '4')) goto bad_seckey; is_v4 = (value[0] == '4'); gcry_sexp_release (list); list = gcry_sexp_find_token (top_list, "protection", 0); if (!list) goto bad_seckey; value = gcry_sexp_nth_data (list, 1, &valuelen); if (!value) goto bad_seckey; if (valuelen == 4 && !memcmp (value, "sha1", 4)) is_protected = 2; else if (valuelen == 3 && !memcmp (value, "sum", 3)) is_protected = 1; else if (valuelen == 4 && !memcmp (value, "none", 4)) is_protected = 0; else goto bad_seckey; if (is_protected) { string = gcry_sexp_nth_string (list, 2); if (!string) goto bad_seckey; protect_algo = gcry_cipher_map_name (string); xfree (string); value = gcry_sexp_nth_data (list, 3, &valuelen); if (!value || !valuelen || valuelen > sizeof iv) goto bad_seckey; memcpy (iv, value, valuelen); ivlen = valuelen; string = gcry_sexp_nth_string (list, 4); if (!string) goto bad_seckey; s2k_mode = strtol (string, NULL, 10); xfree (string); string = gcry_sexp_nth_string (list, 5); if (!string) goto bad_seckey; s2k_algo = gcry_md_map_name (string); xfree (string); value = gcry_sexp_nth_data (list, 6, &valuelen); if (!value || !valuelen || valuelen > sizeof s2k_salt) goto bad_seckey; memcpy (s2k_salt, value, valuelen); string = gcry_sexp_nth_string (list, 7); if (!string) goto bad_seckey; s2k_count = strtoul (string, NULL, 10); xfree (string); } /* Parse the gcrypt PK algo and check that it is okay. */ gcry_sexp_release (list); list = gcry_sexp_find_token (top_list, "algo", 0); if (!list) goto bad_seckey; string = gcry_sexp_nth_string (list, 1); if (!string) goto bad_seckey; pk_algo = gcry_pk_map_name (string); xfree (string); string = NULL; if (gcry_pk_algo_info (pk_algo, GCRYCTL_GET_ALGO_NPKEY, NULL, &npkey) || gcry_pk_algo_info (pk_algo, GCRYCTL_GET_ALGO_NSKEY, NULL, &nskey) || !npkey || npkey >= nskey) goto bad_seckey; /* Check that the pubkey algo matches the one from the public key. */ switch (canon_pk_algo (pk_algo)) { case GCRY_PK_RSA: if (!is_RSA (pk->pubkey_algo)) pk_algo = 0; /* Does not match. */ break; case GCRY_PK_DSA: if (!is_DSA (pk->pubkey_algo)) pk_algo = 0; /* Does not match. */ break; case GCRY_PK_ELG: if (!is_ELGAMAL (pk->pubkey_algo)) pk_algo = 0; /* Does not match. */ break; case GCRY_PK_ECC: if (pk->pubkey_algo == PUBKEY_ALGO_ECDSA) ; else if (pk->pubkey_algo == PUBKEY_ALGO_ECDH) is_ecdh = 1; else if (pk->pubkey_algo == PUBKEY_ALGO_EDDSA) ; else pk_algo = 0; /* Does not match. */ /* For ECC we do not have the domain parameters thus fix our info. */ npkey = 1; nskey = 2; break; default: pk_algo = 0; /* Oops. */ break; } if (!pk_algo) { err = gpg_error (GPG_ERR_PUBKEY_ALGO); goto leave; } /* This check has to go after the ecc adjustments. */ if (nskey > PUBKEY_MAX_NSKEY) goto bad_seckey; /* Parse the key parameters. */ gcry_sexp_release (list); list = gcry_sexp_find_token (top_list, "skey", 0); if (!list) goto bad_seckey; for (idx=0;;) { int is_enc; value = gcry_sexp_nth_data (list, ++idx, &valuelen); if (!value && skeyidx >= npkey) break; /* Ready. */ /* Check for too many parameters. Note that depending on the protection mode and version number we may see less than NSKEY (but at least NPKEY+1) parameters. */ if (idx >= 2*nskey) goto bad_seckey; if (skeyidx >= DIM (skey)-1) goto bad_seckey; if (!value || valuelen != 1 || !(value[0] == '_' || value[0] == 'e')) goto bad_seckey; is_enc = (value[0] == 'e'); value = gcry_sexp_nth_data (list, ++idx, &valuelen); if (!value || !valuelen) goto bad_seckey; if (is_enc || pk->pubkey_algo == PUBKEY_ALGO_ECDSA || pk->pubkey_algo == PUBKEY_ALGO_EDDSA || pk->pubkey_algo == PUBKEY_ALGO_ECDH) { skey[skeyidx] = gcry_mpi_set_opaque_copy (NULL, value, valuelen*8); if (!skey[skeyidx]) goto outofmem; if (is_enc) gcry_mpi_set_flag (skey[skeyidx], GCRYMPI_FLAG_USER1); } else { if (gcry_mpi_scan (skey + skeyidx, GCRYMPI_FMT_STD, value, valuelen, NULL)) goto bad_seckey; } skeyidx++; } skey[skeyidx++] = NULL; gcry_sexp_release (list); list = NULL; /* We have no need for the CSUM value thus we don't parse it. */ /* list = gcry_sexp_find_token (top_list, "csum", 0); */ /* if (list) */ /* { */ /* string = gcry_sexp_nth_string (list, 1); */ /* if (!string) */ /* goto bad_seckey; */ /* desired_csum = strtoul (string, NULL, 10); */ /* xfree (string); */ /* } */ /* else */ /* desired_csum = 0; */ /* gcry_sexp_release (list); list = NULL; */ /* Get the curve name if any, */ list = gcry_sexp_find_token (top_list, "curve", 0); if (list) { curve = gcry_sexp_nth_string (list, 1); gcry_sexp_release (list); list = NULL; } gcry_sexp_release (top_list); top_list = NULL; /* log_debug ("XXX is_v4=%d\n", is_v4); */ /* log_debug ("XXX pubkey_algo=%d\n", pubkey_algo); */ /* log_debug ("XXX is_protected=%d\n", is_protected); */ /* log_debug ("XXX protect_algo=%d\n", protect_algo); */ /* log_printhex ("XXX iv", iv, ivlen); */ /* log_debug ("XXX ivlen=%d\n", ivlen); */ /* log_debug ("XXX s2k_mode=%d\n", s2k_mode); */ /* log_debug ("XXX s2k_algo=%d\n", s2k_algo); */ /* log_printhex ("XXX s2k_salt", s2k_salt, sizeof s2k_salt); */ /* log_debug ("XXX s2k_count=%lu\n", (unsigned long)s2k_count); */ /* for (idx=0; skey[idx]; idx++) */ /* { */ /* int is_enc = gcry_mpi_get_flag (skey[idx], GCRYMPI_FLAG_OPAQUE); */ /* log_info ("XXX skey[%d]%s:", idx, is_enc? " (enc)":""); */ /* if (is_enc) */ /* { */ /* void *p; */ /* unsigned int nbits; */ /* p = gcry_mpi_get_opaque (skey[idx], &nbits); */ /* log_printhex (NULL, p, (nbits+7)/8); */ /* } */ /* else */ /* gcry_mpi_dump (skey[idx]); */ /* log_printf ("\n"); */ /* } */ if (!is_v4 || is_protected != 2 ) { /* We only support the v4 format and a SHA-1 checksum. */ err = gpg_error (GPG_ERR_NOT_IMPLEMENTED); goto leave; } /* We need to change the received parameters for ECC algorithms. The transfer format has the curve name and the parameters separate. We put them all into the SKEY array. */ if (canon_pk_algo (pk_algo) == GCRY_PK_ECC) { const char *oidstr; /* Assert that all required parameters are available. We also check that the array does not contain more parameters than needed (this was used by some beta versions of 2.1. */ if (!curve || !skey[0] || !skey[1] || skey[2]) { err = gpg_error (GPG_ERR_INTERNAL); goto leave; } oidstr = openpgp_curve_to_oid (curve, NULL, NULL); if (!oidstr) { log_error ("no OID known for curve '%s'\n", curve); err = gpg_error (GPG_ERR_UNKNOWN_CURVE); goto leave; } /* Put the curve's OID into the MPI array. This requires that we shift Q and D. For ECDH also insert the KDF parms. */ if (is_ecdh) { skey[4] = NULL; skey[3] = skey[1]; skey[2] = gcry_mpi_copy (pk->pkey[2]); } else { skey[3] = NULL; skey[2] = skey[1]; } skey[1] = skey[0]; skey[0] = NULL; err = openpgp_oid_from_str (oidstr, skey + 0); if (err) goto leave; /* Fixup the NPKEY and NSKEY to match OpenPGP reality. */ npkey = 2 + is_ecdh; nskey = 3 + is_ecdh; /* for (idx=0; skey[idx]; idx++) */ /* { */ /* log_info ("YYY skey[%d]:", idx); */ /* if (gcry_mpi_get_flag (skey[idx], GCRYMPI_FLAG_OPAQUE)) */ /* { */ /* void *p; */ /* unsigned int nbits; */ /* p = gcry_mpi_get_opaque (skey[idx], &nbits); */ /* log_printhex (NULL, p, (nbits+7)/8); */ /* } */ /* else */ /* gcry_mpi_dump (skey[idx]); */ /* log_printf ("\n"); */ /* } */ } /* Do some sanity checks. */ if (s2k_count > 255) { /* We expect an already encoded S2K count. */ err = gpg_error (GPG_ERR_INV_DATA); goto leave; } err = openpgp_cipher_test_algo (protect_algo); if (err) goto leave; err = openpgp_md_test_algo (s2k_algo); if (err) goto leave; /* Check that the public key parameters match. Note that since Libgcrypt 1.5 gcry_mpi_cmp handles opaque MPI correctly. */ for (idx=0; idx < npkey; idx++) if (gcry_mpi_cmp (pk->pkey[idx], skey[idx])) { err = gpg_error (GPG_ERR_BAD_PUBKEY); goto leave; } /* Check that the first secret key parameter in SKEY is encrypted and that there are no more secret key parameters. The latter is guaranteed by the v4 packet format. */ if (!gcry_mpi_get_flag (skey[npkey], GCRYMPI_FLAG_USER1)) goto bad_seckey; if (npkey+1 < DIM (skey) && skey[npkey+1]) goto bad_seckey; /* Check that the secret key parameters in PK are all set to NULL. */ for (idx=npkey; idx < nskey; idx++) if (pk->pkey[idx]) goto bad_seckey; /* Now build the protection info. */ pk->seckey_info = ski = xtrycalloc (1, sizeof *ski); if (!ski) { err = gpg_error_from_syserror (); goto leave; } ski->is_protected = 1; ski->sha1chk = 1; ski->algo = protect_algo; ski->s2k.mode = s2k_mode; ski->s2k.hash_algo = s2k_algo; log_assert (sizeof ski->s2k.salt == sizeof s2k_salt); memcpy (ski->s2k.salt, s2k_salt, sizeof s2k_salt); ski->s2k.count = s2k_count; log_assert (ivlen <= sizeof ski->iv); memcpy (ski->iv, iv, ivlen); ski->ivlen = ivlen; /* Store the protected secret key parameter. */ pk->pkey[npkey] = skey[npkey]; skey[npkey] = NULL; /* That's it. */ leave: gcry_free (curve); gcry_sexp_release (list); gcry_sexp_release (top_list); for (idx=0; idx < skeyidx; idx++) gcry_mpi_release (skey[idx]); return err; bad_seckey: err = gpg_error (GPG_ERR_BAD_SECKEY); goto leave; outofmem: err = gpg_error (GPG_ERR_ENOMEM); goto leave; } /* Print an "EXPORTED" status line. PK is the primary public key. */ static void print_status_exported (PKT_public_key *pk) { char *hexfpr; if (!is_status_enabled ()) return; hexfpr = hexfingerprint (pk, NULL, 0); write_status_text (STATUS_EXPORTED, hexfpr? hexfpr : "[?]"); xfree (hexfpr); } /* * Receive a secret key from agent specified by HEXGRIP. * * Since the key data from the agent is encrypted, decrypt it using * CIPHERHD context. Then, parse the decrypted key data into transfer * format, and put secret parameters into PK. * * If CLEARTEXT is 0, store the secret key material * passphrase-protected. Otherwise, store secret key material in the * clear. * * CACHE_NONCE_ADDR is used to share nonce for multiple key retrievals. */ gpg_error_t receive_seckey_from_agent (ctrl_t ctrl, gcry_cipher_hd_t cipherhd, int cleartext, char **cache_nonce_addr, const char *hexgrip, PKT_public_key *pk) { gpg_error_t err = 0; unsigned char *wrappedkey = NULL; size_t wrappedkeylen; unsigned char *key = NULL; size_t keylen, realkeylen; gcry_sexp_t s_skey; char *prompt; if (opt.verbose) log_info ("key %s: asking agent for the secret parts\n", hexgrip); prompt = gpg_format_keydesc (ctrl, pk, FORMAT_KEYDESC_EXPORT,1); err = agent_export_key (ctrl, hexgrip, prompt, !cleartext, cache_nonce_addr, &wrappedkey, &wrappedkeylen, pk->keyid, pk->main_keyid, pk->pubkey_algo); xfree (prompt); if (err) goto unwraperror; if (wrappedkeylen < 24) { err = gpg_error (GPG_ERR_INV_LENGTH); goto unwraperror; } keylen = wrappedkeylen - 8; key = xtrymalloc_secure (keylen); if (!key) { err = gpg_error_from_syserror (); goto unwraperror; } err = gcry_cipher_decrypt (cipherhd, key, keylen, wrappedkey, wrappedkeylen); if (err) goto unwraperror; realkeylen = gcry_sexp_canon_len (key, keylen, NULL, &err); if (!realkeylen) goto unwraperror; /* Invalid csexp. */ err = gcry_sexp_sscan (&s_skey, NULL, key, realkeylen); if (!err) { if (cleartext) err = cleartext_secret_key_to_openpgp (s_skey, pk); else err = transfer_format_to_openpgp (s_skey, pk); gcry_sexp_release (s_skey); } unwraperror: xfree (key); xfree (wrappedkey); if (err) { log_error ("key %s: error receiving key from agent:" " %s%s\n", hexgrip, gpg_strerror (err), gpg_err_code (err) == GPG_ERR_FULLY_CANCELED? "":_(" - skipped")); } return err; } /* Write KEYBLOCK either to stdout or to the file set with the * --output option. This is a simplified version of do_export_stream * which supports only a few export options. */ gpg_error_t write_keyblock_to_output (kbnode_t keyblock, int with_armor, unsigned int options) { gpg_error_t err; const char *fname; iobuf_t out; kbnode_t node; armor_filter_context_t *afx = NULL; iobuf_t out_help = NULL; PKT_public_key *pk = NULL; fname = opt.outfile? opt.outfile : "-"; if (is_secured_filename (fname) ) return gpg_error (GPG_ERR_EPERM); out = iobuf_create (fname, 0); if (!out) { err = gpg_error_from_syserror (); log_error(_("can't create '%s': %s\n"), fname, gpg_strerror (err)); return err; } if (opt.verbose) log_info (_("writing to '%s'\n"), iobuf_get_fname_nonnull (out)); if ((options & (EXPORT_PKA_FORMAT|EXPORT_DANE_FORMAT))) { with_armor = 0; out_help = iobuf_temp (); } if (with_armor) { afx = new_armor_context (); afx->what = 1; push_armor_filter (afx, out); } for (node = keyblock; node; node = node->next) { if (is_deleted_kbnode (node)) continue; if (node->pkt->pkttype == PKT_RING_TRUST) continue; /* Skip - they should not be here anyway. */ if (!pk && (node->pkt->pkttype == PKT_PUBLIC_KEY || node->pkt->pkttype == PKT_SECRET_KEY)) pk = node->pkt->pkt.public_key; if ((options & EXPORT_BACKUP)) err = build_packet_and_meta (out_help? out_help : out, node->pkt); else err = build_packet (out_help? out_help : out, node->pkt); if (err) { log_error ("build_packet(%d) failed: %s\n", node->pkt->pkttype, gpg_strerror (err) ); goto leave; } } err = 0; if (out_help && pk) { const void *data; size_t datalen; iobuf_flush_temp (out_help); data = iobuf_get_temp_buffer (out_help); datalen = iobuf_get_temp_length (out_help); err = print_pka_or_dane_records (out, keyblock, pk, data, datalen, (options & EXPORT_PKA_FORMAT), (options & EXPORT_DANE_FORMAT)); } leave: if (err) iobuf_cancel (out); else iobuf_close (out); iobuf_cancel (out_help); release_armor_context (afx); return err; } /* * Apply the keep-uid filter to the keyblock. The deleted nodes are * marked and thus the caller should call commit_kbnode afterwards. * KEYBLOCK must not have any blocks marked as deleted. */ static void apply_keep_uid_filter (ctrl_t ctrl, kbnode_t keyblock, recsel_expr_t selector) { kbnode_t node; struct impex_filter_parm_s parm; parm.ctrl = ctrl; for (node = keyblock->next; node; node = node->next ) { if (node->pkt->pkttype == PKT_USER_ID) { parm.node = node; if (!recsel_select (selector, impex_filter_getval, &parm)) { /* log_debug ("keep-uid: deleting '%s'\n", */ /* node->pkt->pkt.user_id->name); */ /* The UID packet and all following packets up to the * next UID or a subkey. */ delete_kbnode (node); for (; node->next && node->next->pkt->pkttype != PKT_USER_ID && node->next->pkt->pkttype != PKT_PUBLIC_SUBKEY && node->next->pkt->pkttype != PKT_SECRET_SUBKEY ; node = node->next) delete_kbnode (node->next); } /* else */ /* log_debug ("keep-uid: keeping '%s'\n", */ /* node->pkt->pkt.user_id->name); */ } } } /* * Apply the drop-subkey filter to the keyblock. The deleted nodes are * marked and thus the caller should call commit_kbnode afterwards. * KEYBLOCK must not have any blocks marked as deleted. */ static void apply_drop_subkey_filter (ctrl_t ctrl, kbnode_t keyblock, recsel_expr_t selector) { kbnode_t node; struct impex_filter_parm_s parm; parm.ctrl = ctrl; for (node = keyblock->next; node; node = node->next ) { if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY || node->pkt->pkttype == PKT_SECRET_SUBKEY) { parm.node = node; if (recsel_select (selector, impex_filter_getval, &parm)) { /*log_debug ("drop-subkey: deleting a key\n");*/ /* The subkey packet and all following packets up to the * next subkey. */ delete_kbnode (node); for (; node->next && node->next->pkt->pkttype != PKT_PUBLIC_SUBKEY && node->next->pkt->pkttype != PKT_SECRET_SUBKEY ; node = node->next) delete_kbnode (node->next); } } } } /* Print DANE or PKA records for all user IDs in KEYBLOCK to OUT. The * data for the record is taken from (DATA,DATELEN). PK is the public * key packet with the primary key. */ static gpg_error_t print_pka_or_dane_records (iobuf_t out, kbnode_t keyblock, PKT_public_key *pk, const void *data, size_t datalen, int print_pka, int print_dane) { gpg_error_t err = 0; kbnode_t kbctx, node; PKT_user_id *uid; char *mbox = NULL; char hashbuf[32]; char *hash = NULL; char *domain; const char *s; unsigned int len; estream_t fp = NULL; char *hexdata = NULL; char *hexfpr; hexfpr = hexfingerprint (pk, NULL, 0); if (!hexfpr) { err = gpg_error_from_syserror (); goto leave; } hexdata = bin2hex (data, datalen, NULL); if (!hexdata) { err = gpg_error_from_syserror (); goto leave; } ascii_strlwr (hexdata); fp = es_fopenmem (0, "rw,samethread"); if (!fp) { err = gpg_error_from_syserror (); goto leave; } for (kbctx = NULL; (node = walk_kbnode (keyblock, &kbctx, 0));) { if (node->pkt->pkttype != PKT_USER_ID) continue; uid = node->pkt->pkt.user_id; if (uid->flags.expired || uid->flags.revoked) continue; xfree (mbox); mbox = mailbox_from_userid (uid->name, 0); if (!mbox) continue; domain = strchr (mbox, '@'); *domain++ = 0; if (print_pka) { es_fprintf (fp, "$ORIGIN _pka.%s.\n; %s\n; ", domain, hexfpr); print_utf8_buffer (fp, uid->name, uid->len); es_putc ('\n', fp); gcry_md_hash_buffer (GCRY_MD_SHA1, hashbuf, mbox, strlen (mbox)); xfree (hash); hash = zb32_encode (hashbuf, 8*20); if (!hash) { err = gpg_error_from_syserror (); goto leave; } len = strlen (hexfpr)/2; es_fprintf (fp, "%s TYPE37 \\# %u 0006 0000 00 %02X %s\n\n", hash, 6 + len, len, hexfpr); } if (print_dane && hexdata) { es_fprintf (fp, "$ORIGIN _openpgpkey.%s.\n; %s\n; ", domain, hexfpr); print_utf8_buffer (fp, uid->name, uid->len); es_putc ('\n', fp); gcry_md_hash_buffer (GCRY_MD_SHA256, hashbuf, mbox, strlen (mbox)); xfree (hash); hash = bin2hex (hashbuf, 28, NULL); if (!hash) { err = gpg_error_from_syserror (); goto leave; } ascii_strlwr (hash); len = strlen (hexdata)/2; es_fprintf (fp, "%s TYPE61 \\# %u (\n", hash, len); for (s = hexdata; ;) { es_fprintf (fp, "\t%.64s\n", s); if (strlen (s) < 64) break; s += 64; } es_fputs ("\t)\n\n", fp); } } /* Make sure it is a string and write it. */ es_fputc (0, fp); { void *vp; if (es_fclose_snatch (fp, &vp, NULL)) { err = gpg_error_from_syserror (); goto leave; } fp = NULL; iobuf_writestr (out, vp); es_free (vp); } err = 0; leave: xfree (hash); xfree (mbox); es_fclose (fp); xfree (hexdata); xfree (hexfpr); return err; } /* Helper for do_export_stream which writes one keyblock to OUT. */ static gpg_error_t do_export_one_keyblock (ctrl_t ctrl, kbnode_t keyblock, u32 *keyid, iobuf_t out, int secret, unsigned int options, export_stats_t stats, int *any, KEYDB_SEARCH_DESC *desc, size_t ndesc, size_t descindex, gcry_cipher_hd_t cipherhd) { gpg_error_t err = gpg_error (GPG_ERR_NOT_FOUND); char *cache_nonce = NULL; subkey_list_t subkey_list = NULL; /* Track already processed subkeys. */ int skip_until_subkey = 0; int cleartext = 0; char *hexgrip = NULL; char *serialno = NULL; PKT_public_key *pk; u32 subkidbuf[2], *subkid; kbnode_t kbctx, node; /* NB: walk_kbnode skips packets marked as deleted. */ for (kbctx=NULL; (node = walk_kbnode (keyblock, &kbctx, 0)); ) { if (skip_until_subkey) { if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY) skip_until_subkey = 0; else continue; } /* We used to use comment packets, but not any longer. In * case we still have comments on a key, strip them here * before we call build_packet(). */ if (node->pkt->pkttype == PKT_COMMENT) continue; /* Skip ring trust packets - they should not be here anyway. */ if (node->pkt->pkttype == PKT_RING_TRUST) continue; /* If exact is set, then we only export what was requested * (plus the primary key, if the user didn't specifically * request it). */ if (desc[descindex].exact && node->pkt->pkttype == PKT_PUBLIC_SUBKEY) { if (!exact_subkey_match_p (desc+descindex, node)) { /* Before skipping this subkey, check whether any * other description wants an exact match on a * subkey and include that subkey into the output * too. Need to add this subkey to a list so that * it won't get processed a second time. * * So the first step here is to check that list and * skip in any case if the key is in that list. * * We need this whole mess because the import * function of GnuPG < 2.1 is not able to merge * secret keys and thus it is useless to output them * as two separate keys and have import merge them. */ if (subkey_in_list_p (subkey_list, node)) skip_until_subkey = 1; /* Already processed this one. */ else { size_t j; for (j=0; j < ndesc; j++) if (j != descindex && desc[j].exact && exact_subkey_match_p (desc+j, node)) break; if (!(j < ndesc)) skip_until_subkey = 1; /* No other one matching. */ } } if (skip_until_subkey) continue; /* Mark this one as processed. */ { subkey_list_t tmp = new_subkey_list_item (node); tmp->next = subkey_list; subkey_list = tmp; } } if (node->pkt->pkttype == PKT_SIGNATURE) { /* Do not export packets which are marked as not * exportable. */ if (!(options & EXPORT_LOCAL_SIGS) && !node->pkt->pkt.signature->flags.exportable) continue; /* not exportable */ /* Do not export packets with a "sensitive" revocation key * unless the user wants us to. Note that we do export * these when issuing the actual revocation (see revoke.c). */ if (!(options & EXPORT_SENSITIVE_REVKEYS) && node->pkt->pkt.signature->revkey) { int i; for (i = 0; i < node->pkt->pkt.signature->numrevkeys; i++) if ((node->pkt->pkt.signature->revkey[i].class & 0x40)) break; if (i < node->pkt->pkt.signature->numrevkeys) continue; } } /* Don't export user ids (and attributes)? This is not RFC-4880 * compliant but we allow it anyway. */ if ((options & EXPORT_DROP_UIDS) && node->pkt->pkttype == PKT_USER_ID) { /* Skip until we get to something that is not a user id (or * attrib) or a signature on it. */ while (kbctx->next && kbctx->next->pkt->pkttype == PKT_SIGNATURE) kbctx = kbctx->next; continue; } /* Don't export attribs? */ if (!(options & EXPORT_ATTRIBUTES) && node->pkt->pkttype == PKT_USER_ID && node->pkt->pkt.user_id->attrib_data) { /* Skip until we get to something that is not an attrib or a * signature on an attrib. */ while (kbctx->next && kbctx->next->pkt->pkttype == PKT_SIGNATURE) kbctx = kbctx->next; continue; } if (secret && (node->pkt->pkttype == PKT_PUBLIC_KEY || node->pkt->pkttype == PKT_PUBLIC_SUBKEY)) { pk = node->pkt->pkt.public_key; if (node->pkt->pkttype == PKT_PUBLIC_KEY) subkid = NULL; else { keyid_from_pk (pk, subkidbuf); subkid = subkidbuf; } if (pk->seckey_info) { log_error ("key %s: oops: seckey_info already set" " - skipped\n", keystr_with_sub (keyid, subkid)); skip_until_subkey = 1; continue; } xfree (hexgrip); err = hexkeygrip_from_pk (pk, &hexgrip); if (err) { log_error ("key %s: error computing keygrip: %s" " - skipped\n", keystr_with_sub (keyid, subkid), gpg_strerror (err)); skip_until_subkey = 1; err = 0; continue; } xfree (serialno); serialno = NULL; if (secret == 2 && node->pkt->pkttype == PKT_PUBLIC_KEY) { /* We are asked not to export the secret parts of the * primary key. Make up an error code to create the * stub. */ err = GPG_ERR_NOT_FOUND; } else err = agent_get_keyinfo (ctrl, hexgrip, &serialno, &cleartext); if ((!err && serialno) && secret == 2 && node->pkt->pkttype == PKT_PUBLIC_KEY) { /* It does not make sense to export a key with its * primary key on card using a non-key stub. Thus we * skip those keys when used with --export-secret-subkeys. */ log_info (_("key %s: key material on-card - skipped\n"), keystr_with_sub (keyid, subkid)); skip_until_subkey = 1; } else if (gpg_err_code (err) == GPG_ERR_NOT_FOUND || (!err && serialno)) { /* Create a key stub. */ struct seckey_info *ski; const char *s; pk->seckey_info = ski = xtrycalloc (1, sizeof *ski); if (!ski) { err = gpg_error_from_syserror (); goto leave; } ski->is_protected = 1; if (err) ski->s2k.mode = 1001; /* GNU dummy (no secret key). */ else { ski->s2k.mode = 1002; /* GNU-divert-to-card. */ for (s=serialno; sizeof (ski->ivlen) && *s && s[1]; ski->ivlen++, s += 2) ski->iv[ski->ivlen] = xtoi_2 (s); } if ((options & EXPORT_BACKUP)) err = build_packet_and_meta (out, node->pkt); else err = build_packet (out, node->pkt); if (!err && node->pkt->pkttype == PKT_PUBLIC_KEY) { stats->exported++; print_status_exported (node->pkt->pkt.public_key); } } else if (!err) { err = receive_seckey_from_agent (ctrl, cipherhd, cleartext, &cache_nonce, hexgrip, pk); if (err) { if (gpg_err_code (err) == GPG_ERR_FULLY_CANCELED) goto leave; skip_until_subkey = 1; err = 0; } else { if ((options & EXPORT_BACKUP)) err = build_packet_and_meta (out, node->pkt); else err = build_packet (out, node->pkt); if (node->pkt->pkttype == PKT_PUBLIC_KEY) { stats->exported++; print_status_exported (node->pkt->pkt.public_key); } } } else { log_error ("key %s: error getting keyinfo from agent: %s" " - skipped\n", keystr_with_sub (keyid, subkid), gpg_strerror (err)); skip_until_subkey = 1; err = 0; } xfree (pk->seckey_info); pk->seckey_info = NULL; { int i; for (i = pubkey_get_npkey (pk->pubkey_algo); i < pubkey_get_nskey (pk->pubkey_algo); i++) { gcry_mpi_release (pk->pkey[i]); pk->pkey[i] = NULL; } } } else /* Not secret or common packets. */ { if ((options & EXPORT_BACKUP)) err = build_packet_and_meta (out, node->pkt); else err = build_packet (out, node->pkt); if (!err && node->pkt->pkttype == PKT_PUBLIC_KEY) { stats->exported++; print_status_exported (node->pkt->pkt.public_key); } } if (err) { log_error ("build_packet(%d) failed: %s\n", node->pkt->pkttype, gpg_strerror (err)); goto leave; } if (!skip_until_subkey) *any = 1; } leave: release_subkey_list (subkey_list); xfree (serialno); xfree (hexgrip); xfree (cache_nonce); return err; } /* Export the keys identified by the list of strings in USERS to the stream OUT. If SECRET is false public keys will be exported. With secret true secret keys will be exported; in this case 1 means the entire secret keyblock and 2 only the subkeys. OPTIONS are the export options to apply. If KEYBLOCK_OUT is not NULL, AND the exit code is zero, a pointer to the first keyblock found and exported will be stored at this address; no other keyblocks are exported in this case. The caller must free the returned keyblock. If any key has been exported true is stored at ANY. */ static int do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret, kbnode_t *keyblock_out, unsigned int options, export_stats_t stats, int *any) { gpg_error_t err = 0; PACKET pkt; kbnode_t keyblock = NULL; kbnode_t node; size_t ndesc, descindex; KEYDB_SEARCH_DESC *desc = NULL; KEYDB_HANDLE kdbhd; strlist_t sl; gcry_cipher_hd_t cipherhd = NULL; struct export_stats_s dummystats; iobuf_t out_help = NULL; if (!stats) stats = &dummystats; *any = 0; init_packet (&pkt); kdbhd = keydb_new (ctrl); if (!kdbhd) return gpg_error_from_syserror (); /* For the PKA and DANE format open a helper iobuf and for DANE * enforce some options. */ if ((options & (EXPORT_PKA_FORMAT | EXPORT_DANE_FORMAT))) { out_help = iobuf_temp (); if ((options & EXPORT_DANE_FORMAT)) options |= EXPORT_MINIMAL | EXPORT_CLEAN; } if (!users) { ndesc = 1; desc = xcalloc (ndesc, sizeof *desc); desc[0].mode = KEYDB_SEARCH_MODE_FIRST; } else { for (ndesc=0, sl=users; sl; sl = sl->next, ndesc++) ; desc = xmalloc ( ndesc * sizeof *desc); for (ndesc=0, sl=users; sl; sl = sl->next) { if (!(err=classify_user_id (sl->d, desc+ndesc, 1))) ndesc++; else log_error (_("key \"%s\" not found: %s\n"), sl->d, gpg_strerror (err)); } keydb_disable_caching (kdbhd); /* We are looping the search. */ /* It would be nice to see which of the given users did actually match one in the keyring. To implement this we need to have a found flag for each entry in desc. To set this flag we must check all those entries after a match to mark all matched one - currently we stop at the first match. To do this we need an extra flag to enable this feature. */ } #ifdef ENABLE_SELINUX_HACKS if (secret) { log_error (_("exporting secret keys not allowed\n")); err = gpg_error (GPG_ERR_NOT_SUPPORTED); goto leave; } #endif /* For secret key export we need to setup a decryption context. */ if (secret) { void *kek = NULL; size_t keklen; err = agent_keywrap_key (ctrl, 1, &kek, &keklen); if (err) { log_error ("error getting the KEK: %s\n", gpg_strerror (err)); goto leave; } /* Prepare a cipher context. */ err = gcry_cipher_open (&cipherhd, GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_AESWRAP, 0); if (!err) err = gcry_cipher_setkey (cipherhd, kek, keklen); if (err) { log_error ("error setting up an encryption context: %s\n", gpg_strerror (err)); goto leave; } xfree (kek); kek = NULL; } for (;;) { u32 keyid[2]; PKT_public_key *pk; err = keydb_search (kdbhd, desc, ndesc, &descindex); if (!users) desc[0].mode = KEYDB_SEARCH_MODE_NEXT; if (err) break; /* Read the keyblock. */ release_kbnode (keyblock); keyblock = NULL; err = keydb_get_keyblock (kdbhd, &keyblock); if (err) { log_error (_("error reading keyblock: %s\n"), gpg_strerror (err)); goto leave; } node = find_kbnode (keyblock, PKT_PUBLIC_KEY); if (!node) { log_error ("public key packet not found in keyblock - skipped\n"); continue; } stats->count++; setup_main_keyids (keyblock); /* gpg_format_keydesc needs it. */ pk = node->pkt->pkt.public_key; keyid_from_pk (pk, keyid); /* If a secret key export is required we need to check whether we have a secret key at all and if so create the seckey_info structure. */ if (secret) { if (agent_probe_any_secret_key (ctrl, keyblock)) continue; /* No secret key (neither primary nor subkey). */ /* No v3 keys with GNU mode 1001. */ if (secret == 2 && pk->version == 3) { log_info (_("key %s: PGP 2.x style key - skipped\n"), keystr (keyid)); continue; } /* The agent does not yet allow export of v3 packets. It is actually questionable whether we should allow them at all. */ if (pk->version == 3) { log_info ("key %s: PGP 2.x style key (v3) export " "not yet supported - skipped\n", keystr (keyid)); continue; } stats->secret_count++; } /* Always do the cleaning on the public key part if requested. * A designated revocation is never stripped, even with * export-minimal set. */ if ((options & EXPORT_CLEAN)) { merge_keys_and_selfsig (ctrl, keyblock); clean_all_uids (ctrl, keyblock, opt.verbose, (options&EXPORT_MINIMAL), NULL, NULL); clean_all_subkeys (ctrl, keyblock, opt.verbose, (options&EXPORT_MINIMAL)? KEY_CLEAN_ALL /**/ : KEY_CLEAN_AUTHENCR, NULL, NULL); commit_kbnode (&keyblock); } if (export_keep_uid) { commit_kbnode (&keyblock); apply_keep_uid_filter (ctrl, keyblock, export_keep_uid); commit_kbnode (&keyblock); } if (export_drop_subkey) { commit_kbnode (&keyblock); apply_drop_subkey_filter (ctrl, keyblock, export_drop_subkey); commit_kbnode (&keyblock); } /* And write it. */ err = do_export_one_keyblock (ctrl, keyblock, keyid, out_help? out_help : out, secret, options, stats, any, desc, ndesc, descindex, cipherhd); if (err) break; if (keyblock_out) { *keyblock_out = keyblock; break; } if (out_help) { /* We want to write PKA or DANE records. OUT_HELP has the * keyblock and we print a record for each uid to OUT. */ const void *data; size_t datalen; iobuf_flush_temp (out_help); data = iobuf_get_temp_buffer (out_help); datalen = iobuf_get_temp_length (out_help); err = print_pka_or_dane_records (out, keyblock, pk, data, datalen, (options & EXPORT_PKA_FORMAT), (options & EXPORT_DANE_FORMAT)); if (err) goto leave; iobuf_close (out_help); out_help = iobuf_temp (); } } if (gpg_err_code (err) == GPG_ERR_NOT_FOUND) err = 0; leave: iobuf_cancel (out_help); gcry_cipher_close (cipherhd); xfree(desc); keydb_release (kdbhd); if (err || !keyblock_out) release_kbnode( keyblock ); if( !*any ) log_info(_("WARNING: nothing exported\n")); return err; } static gpg_error_t key_to_sshblob (membuf_t *mb, const char *identifier, ...) { va_list arg_ptr; gpg_error_t err = 0; unsigned char nbuf[4]; unsigned char *buf; size_t buflen; gcry_mpi_t a; ulongtobuf (nbuf, (ulong)strlen (identifier)); put_membuf (mb, nbuf, 4); put_membuf_str (mb, identifier); if (!strncmp (identifier, "ecdsa-sha2-", 11)) { ulongtobuf (nbuf, (ulong)strlen (identifier+11)); put_membuf (mb, nbuf, 4); put_membuf_str (mb, identifier+11); } va_start (arg_ptr, identifier); while ((a = va_arg (arg_ptr, gcry_mpi_t))) { err = gcry_mpi_aprint (GCRYMPI_FMT_SSH, &buf, &buflen, a); if (err) break; if (!strcmp (identifier, "ssh-ed25519") && buflen > 5 && buf[4] == 0x40) { /* We need to strip our 0x40 prefix. */ put_membuf (mb, "\x00\x00\x00\x20", 4); put_membuf (mb, buf+5, buflen-5); } else put_membuf (mb, buf, buflen); gcry_free (buf); } va_end (arg_ptr); return err; } static gpg_error_t export_one_ssh_key (estream_t fp, PKT_public_key *pk) { gpg_error_t err; const char *identifier = NULL; membuf_t mb; struct b64state b64_state; void *blob; size_t bloblen; init_membuf (&mb, 4096); switch (pk->pubkey_algo) { case PUBKEY_ALGO_DSA: identifier = "ssh-dss"; err = key_to_sshblob (&mb, identifier, pk->pkey[0], pk->pkey[1], pk->pkey[2], pk->pkey[3], NULL); break; case PUBKEY_ALGO_RSA: case PUBKEY_ALGO_RSA_S: identifier = "ssh-rsa"; err = key_to_sshblob (&mb, identifier, pk->pkey[1], pk->pkey[0], NULL); break; case PUBKEY_ALGO_ECDSA: { char *curveoid; const char *curve; curveoid = openpgp_oid_to_str (pk->pkey[0]); if (!curveoid) err = gpg_error_from_syserror (); else if (!(curve = openpgp_oid_to_curve (curveoid, 0))) err = gpg_error (GPG_ERR_UNKNOWN_CURVE); else { if (!strcmp (curve, "nistp256")) identifier = "ecdsa-sha2-nistp256"; else if (!strcmp (curve, "nistp384")) identifier = "ecdsa-sha2-nistp384"; else if (!strcmp (curve, "nistp521")) identifier = "ecdsa-sha2-nistp521"; if (!identifier) err = gpg_error (GPG_ERR_UNKNOWN_CURVE); else err = key_to_sshblob (&mb, identifier, pk->pkey[1], NULL); } xfree (curveoid); } break; case PUBKEY_ALGO_EDDSA: if (!openpgp_oid_is_ed25519 (pk->pkey[0])) err = gpg_error (GPG_ERR_UNKNOWN_CURVE); else { identifier = "ssh-ed25519"; err = key_to_sshblob (&mb, identifier, pk->pkey[1], NULL); } break; case PUBKEY_ALGO_ELGAMAL_E: case PUBKEY_ALGO_ELGAMAL: err = gpg_error (GPG_ERR_UNUSABLE_PUBKEY); break; default: err = GPG_ERR_PUBKEY_ALGO; break; } if (err) goto leave; err = b64enc_start_es (&b64_state, fp, ""); if (err) goto leave; blob = get_membuf (&mb, &bloblen); if (blob) { es_fprintf (fp, "%s ", identifier); err = b64enc_write (&b64_state, blob, bloblen); es_fprintf (fp, " openpgp:0x%08lX\n", (ulong)keyid_from_pk (pk, NULL)); xfree (blob); } b64enc_finish (&b64_state); leave: xfree (get_membuf (&mb, NULL)); return err; } /* Export the key identified by USERID in the SSH public key format. The function exports the latest subkey with Authentication capability unless the '!' suffix is used to export a specific key. */ gpg_error_t export_ssh_key (ctrl_t ctrl, const char *userid) { gpg_error_t err; kbnode_t keyblock = NULL; KEYDB_SEARCH_DESC desc; u32 latest_date; u32 curtime = make_timestamp (); kbnode_t latest_key, node; PKT_public_key *pk; estream_t fp = NULL; const char *fname = "-"; /* We need to know whether the key has been specified using the exact syntax ('!' suffix). Thus we need to run a classify_user_id on our own. */ err = classify_user_id (userid, &desc, 1); /* Get the public key. */ if (!err) { getkey_ctx_t getkeyctx; err = get_pubkey_byname (ctrl, GET_PUBKEY_NO_AKL, &getkeyctx, NULL, userid, &keyblock, NULL, 0 /* Only usable keys or given exact. */); if (!err) { err = getkey_next (ctrl, getkeyctx, NULL, NULL); if (!err) err = gpg_error (GPG_ERR_AMBIGUOUS_NAME); else if (gpg_err_code (err) == GPG_ERR_NO_PUBKEY) err = 0; } getkey_end (ctrl, getkeyctx); } if (err) { log_error (_("key \"%s\" not found: %s\n"), userid, gpg_strerror (err)); return err; } /* The finish_lookup code in getkey.c does not handle auth keys, thus we have to duplicate the code here to find the latest subkey. However, if the key has been found using an exact match ('!' notation) we use that key without any further checks and even allow the use of the primary key. */ latest_date = 0; latest_key = NULL; for (node = keyblock; node; node = node->next) { if ((node->pkt->pkttype == PKT_PUBLIC_SUBKEY || node->pkt->pkttype == PKT_PUBLIC_KEY) && node->pkt->pkt.public_key->flags.exact) { latest_key = node; break; } } if (!latest_key) { for (node = keyblock; node; node = node->next) { if (node->pkt->pkttype != PKT_PUBLIC_SUBKEY) continue; pk = node->pkt->pkt.public_key; if (DBG_LOOKUP) log_debug ("\tchecking subkey %08lX\n", (ulong) keyid_from_pk (pk, NULL)); if (!(pk->pubkey_usage & PUBKEY_USAGE_AUTH)) { if (DBG_LOOKUP) log_debug ("\tsubkey not usable for authentication\n"); continue; } if (!pk->flags.valid) { if (DBG_LOOKUP) log_debug ("\tsubkey not valid\n"); continue; } if (pk->flags.revoked) { if (DBG_LOOKUP) log_debug ("\tsubkey has been revoked\n"); continue; } if (pk->has_expired) { if (DBG_LOOKUP) log_debug ("\tsubkey has expired\n"); continue; } if (pk->timestamp > curtime && !opt.ignore_valid_from) { if (DBG_LOOKUP) log_debug ("\tsubkey not yet valid\n"); continue; } if (DBG_LOOKUP) log_debug ("\tsubkey might be fine\n"); /* In case a key has a timestamp of 0 set, we make sure that it is used. A better change would be to compare ">=" but that might also change the selected keys and is as such a more intrusive change. */ if (pk->timestamp > latest_date || (!pk->timestamp && !latest_date)) { latest_date = pk->timestamp; latest_key = node; } } /* If no subkey was suitable check the primary key. */ if (!latest_key && (node = keyblock) && node->pkt->pkttype == PKT_PUBLIC_KEY) { pk = node->pkt->pkt.public_key; if (DBG_LOOKUP) log_debug ("\tchecking primary key %08lX\n", (ulong) keyid_from_pk (pk, NULL)); if (!(pk->pubkey_usage & PUBKEY_USAGE_AUTH)) { if (DBG_LOOKUP) log_debug ("\tprimary key not usable for authentication\n"); } else if (!pk->flags.valid) { if (DBG_LOOKUP) log_debug ("\tprimary key not valid\n"); } else if (pk->flags.revoked) { if (DBG_LOOKUP) log_debug ("\tprimary key has been revoked\n"); } else if (pk->has_expired) { if (DBG_LOOKUP) log_debug ("\tprimary key has expired\n"); } else if (pk->timestamp > curtime && !opt.ignore_valid_from) { if (DBG_LOOKUP) log_debug ("\tprimary key not yet valid\n"); } else { if (DBG_LOOKUP) log_debug ("\tprimary key is fine\n"); latest_date = pk->timestamp; latest_key = node; } } } if (!latest_key) { err = gpg_error (GPG_ERR_UNUSABLE_PUBKEY); log_error (_("key \"%s\" not found: %s\n"), userid, gpg_strerror (err)); goto leave; } pk = latest_key->pkt->pkt.public_key; if (DBG_LOOKUP) log_debug ("\tusing key %08lX\n", (ulong) keyid_from_pk (pk, NULL)); if (opt.outfile && *opt.outfile && strcmp (opt.outfile, "-")) fp = es_fopen ((fname = opt.outfile), "w"); else fp = es_stdout; if (!fp) { err = gpg_error_from_syserror (); log_error (_("error creating '%s': %s\n"), fname, gpg_strerror (err)); goto leave; } err = export_one_ssh_key (fp, pk); if (err) goto leave; if (es_ferror (fp)) err = gpg_error_from_syserror (); else { if (es_fclose (fp)) err = gpg_error_from_syserror (); fp = NULL; } if (err) log_error (_("error writing '%s': %s\n"), fname, gpg_strerror (err)); leave: es_fclose (fp); release_kbnode (keyblock); return err; } diff --git a/g10/keygen.c b/g10/keygen.c index 590536726..d87b8480a 100644 --- a/g10/keygen.c +++ b/g10/keygen.c @@ -1,6140 +1,6154 @@ /* keygen.c - Generate a key pair * Copyright (C) 1998-2007, 2009-2011 Free Software Foundation, Inc. * Copyright (C) 2014, 2015, 2016, 2017, 2018 Werner Koch * Copyright (C) 2020 g10 Code GmbH * * This file is part of GnuPG. * * GnuPG is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * GnuPG is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . */ #include #include #include #include #include #include #include #include #include #include "gpg.h" #include "../common/util.h" #include "main.h" #include "packet.h" #include "../common/ttyio.h" #include "options.h" #include "keydb.h" #include "trustdb.h" #include "../common/status.h" #include "../common/i18n.h" #include "keyserver-internal.h" #include "call-agent.h" #include "pkglue.h" #include "../common/shareddefs.h" #include "../common/host2net.h" #include "../common/mbox-util.h" /* The default algorithms. If you change them, you should ensure the value is inside the bounds enforced by ask_keysize and gen_xxx. See also get_keysize_range which encodes the allowed ranges. */ #define DEFAULT_STD_KEY_PARAM "rsa3072/cert,sign+rsa3072/encr" #define FUTURE_STD_KEY_PARAM "ed25519/cert,sign+cv25519/encr" /* When generating keys using the streamlined key generation dialog, use this as a default expiration interval. */ const char *default_expiration_interval = "2y"; /* Flag bits used during key generation. */ #define KEYGEN_FLAG_NO_PROTECTION 1 #define KEYGEN_FLAG_TRANSIENT_KEY 2 #define KEYGEN_FLAG_CREATE_V5_KEY 4 /* Maximum number of supported algorithm preferences. */ #define MAX_PREFS 30 enum para_name { pKEYTYPE, pKEYLENGTH, pKEYCURVE, pKEYUSAGE, pSUBKEYTYPE, pSUBKEYLENGTH, pSUBKEYCURVE, pSUBKEYUSAGE, pAUTHKEYTYPE, pNAMEREAL, pNAMEEMAIL, pNAMECOMMENT, pPREFERENCES, pREVOKER, pUSERID, pCREATIONDATE, pKEYCREATIONDATE, /* Same in seconds since epoch. */ pEXPIREDATE, pKEYEXPIRE, /* in n seconds */ pSUBKEYCREATIONDATE, pSUBKEYEXPIRE, /* in n seconds */ pAUTHKEYCREATIONDATE, /* Not yet used. */ pPASSPHRASE, pSERIALNO, pCARDBACKUPKEY, pHANDLE, pKEYSERVER, pKEYGRIP, pSUBKEYGRIP, pVERSION, /* Desired version of the key packet. */ pSUBVERSION, /* Ditto for the subpacket. */ pCARDKEY /* The keygrips have been taken from active card (bool). */ }; struct para_data_s { struct para_data_s *next; int lnr; enum para_name key; union { u32 expire; u32 creation; int abool; unsigned int usage; struct revocation_key revkey; char value[1]; } u; }; struct output_control_s { int lnr; int dryrun; unsigned int keygen_flags; int use_files; struct { char *fname; char *newfname; IOBUF stream; armor_filter_context_t *afx; } pub; }; struct opaque_data_usage_and_pk { unsigned int usage; PKT_public_key *pk; }; /* FIXME: These globals vars are ugly. And using MAX_PREFS even for * aeads is useless, given that we don't expects more than a very few * algorithms. */ static int prefs_initialized = 0; static byte sym_prefs[MAX_PREFS]; static int nsym_prefs; static byte hash_prefs[MAX_PREFS]; static int nhash_prefs; static byte zip_prefs[MAX_PREFS]; static int nzip_prefs; static byte aead_prefs[MAX_PREFS]; static int naead_prefs; static int mdc_available; static int ks_modify; static int aead_available; static gpg_error_t parse_algo_usage_expire (ctrl_t ctrl, int for_subkey, const char *algostr, const char *usagestr, const char *expirestr, int *r_algo, unsigned int *r_usage, u32 *r_expire, unsigned int *r_nbits, const char **r_curve, int *r_version, char **r_keygrip, u32 *r_keytime); static void do_generate_keypair (ctrl_t ctrl, struct para_data_s *para, struct output_control_s *outctrl, int card ); static int write_keyblock (iobuf_t out, kbnode_t node); static gpg_error_t gen_card_key (int keyno, int algo, int is_primary, kbnode_t pub_root, u32 *timestamp, u32 expireval, int keygen_flags); static unsigned int get_keysize_range (int algo, unsigned int *min, unsigned int *max); /* Return the algo string for a default new key. */ const char * get_default_pubkey_algo (void) { if (opt.def_new_key_algo) { if (*opt.def_new_key_algo && !strchr (opt.def_new_key_algo, ':')) return opt.def_new_key_algo; /* To avoid checking that option every time we delay that until * here. The only thing we really need to make sure is that * there is no colon in the string so that the --gpgconf-list * command won't mess up its output. */ log_info (_("invalid value for option '%s'\n"), "--default-new-key-algo"); } return DEFAULT_STD_KEY_PARAM; } static void print_status_key_created (int letter, PKT_public_key *pk, const char *handle) { byte array[MAX_FINGERPRINT_LEN], *s; char *buf, *p; size_t i, n; if (!handle) handle = ""; buf = xmalloc (MAX_FINGERPRINT_LEN*2+31 + strlen (handle) + 1); p = buf; if (letter || pk) { *p++ = letter; if (pk) { *p++ = ' '; fingerprint_from_pk (pk, array, &n); s = array; /* Fixme: Use bin2hex */ for (i=0; i < n ; i++, s++, p += 2) snprintf (p, 3, "%02X", *s); } } if (*handle) { *p++ = ' '; for (i=0; handle[i] && i < 100; i++) *p++ = isspace ((unsigned int)handle[i])? '_':handle[i]; } *p = 0; write_status_text ((letter || pk)?STATUS_KEY_CREATED:STATUS_KEY_NOT_CREATED, buf); xfree (buf); } static void print_status_key_not_created (const char *handle) { print_status_key_created (0, NULL, handle); } static gpg_error_t write_uid (kbnode_t root, const char *s) { PACKET *pkt = xmalloc_clear (sizeof *pkt); size_t n = strlen (s); if (n > MAX_UID_PACKET_LENGTH - 10) return gpg_error (GPG_ERR_INV_USER_ID); pkt->pkttype = PKT_USER_ID; pkt->pkt.user_id = xmalloc_clear (sizeof *pkt->pkt.user_id + n); pkt->pkt.user_id->len = n; pkt->pkt.user_id->ref = 1; strcpy (pkt->pkt.user_id->name, s); add_kbnode (root, new_kbnode (pkt)); return 0; } static void do_add_key_flags (PKT_signature *sig, unsigned int use) { byte buf[1]; buf[0] = 0; /* The spec says that all primary keys MUST be able to certify. */ if(sig->sig_class!=0x18) buf[0] |= 0x01; if (use & PUBKEY_USAGE_SIG) buf[0] |= 0x02; if (use & PUBKEY_USAGE_ENC) buf[0] |= 0x04 | 0x08; if (use & PUBKEY_USAGE_AUTH) buf[0] |= 0x20; build_sig_subpkt (sig, SIGSUBPKT_KEY_FLAGS, buf, 1); } int keygen_add_key_expire (PKT_signature *sig, void *opaque) { PKT_public_key *pk = opaque; byte buf[8]; u32 u; if (pk->expiredate) { if (pk->expiredate > pk->timestamp) u = pk->expiredate - pk->timestamp; else u = 1; buf[0] = (u >> 24) & 0xff; buf[1] = (u >> 16) & 0xff; buf[2] = (u >> 8) & 0xff; buf[3] = u & 0xff; build_sig_subpkt (sig, SIGSUBPKT_KEY_EXPIRE, buf, 4); } else { /* Make sure we don't leave a key expiration subpacket lying around */ delete_sig_subpkt (sig->hashed, SIGSUBPKT_KEY_EXPIRE); } return 0; } /* Add the key usage (i.e. key flags) in SIG from the public keys * pubkey_usage field. OPAQUE has the public key. */ int keygen_add_key_flags (PKT_signature *sig, void *opaque) { PKT_public_key *pk = opaque; do_add_key_flags (sig, pk->pubkey_usage); return 0; } static int keygen_add_key_flags_and_expire (PKT_signature *sig, void *opaque) { struct opaque_data_usage_and_pk *oduap = opaque; do_add_key_flags (sig, oduap->usage); return keygen_add_key_expire (sig, oduap->pk); } static int set_one_pref (int val, int type, const char *item, byte *buf, int *nbuf) { int i; for (i=0; i < *nbuf; i++ ) if (buf[i] == val) { log_info (_("preference '%s' duplicated\n"), item); return -1; } if (*nbuf >= MAX_PREFS) { if(type==1) log_info(_("too many cipher preferences\n")); else if(type==2) log_info(_("too many digest preferences\n")); else if(type==3) log_info(_("too many compression preferences\n")); else if(type==4) log_info(_("too many AEAD preferences\n")); else BUG(); return -1; } buf[(*nbuf)++] = val; return 0; } /* * Parse the supplied string and use it to set the standard * preferences. The string may be in a form like the one printed by * "pref" (something like: "S10 S3 H3 H2 Z2 Z1") or the actual * cipher/hash/compress names. Use NULL to set the default * preferences. Returns: 0 = okay */ int keygen_set_std_prefs (const char *string,int personal) { byte sym[MAX_PREFS], hash[MAX_PREFS], zip[MAX_PREFS], aead[MAX_PREFS]; int nsym=0, nhash=0, nzip=0, naead=0, val, rc=0; int mdc=1, modify=0; /* mdc defaults on, modify defaults off. */ char dummy_string[25*4+1]; /* Enough for 25 items. */ if (!string || !ascii_strcasecmp (string, "default")) { if (opt.def_preference_list) string=opt.def_preference_list; else { int any_compress = 0; dummy_string[0]='\0'; /* The rationale why we use the order AES256,192,128 is for compatibility reasons with PGP. If gpg would define AES128 first, we would get the somewhat confusing situation: gpg -r pgpkey -r gpgkey ---gives--> AES256 gpg -r gpgkey -r pgpkey ---gives--> AES Note that by using --personal-cipher-preferences it is possible to prefer AES128. */ /* Make sure we do not add more than 15 items here, as we could overflow the size of dummy_string. We currently have at most 12. */ if ( !openpgp_cipher_test_algo (CIPHER_ALGO_AES256) ) strcat(dummy_string,"S9 "); if ( !openpgp_cipher_test_algo (CIPHER_ALGO_AES192) ) strcat(dummy_string,"S8 "); if ( !openpgp_cipher_test_algo (CIPHER_ALGO_AES) ) strcat(dummy_string,"S7 "); strcat(dummy_string,"S2 "); /* 3DES */ if (opt.flags.rfc4880bis && !openpgp_aead_test_algo (AEAD_ALGO_OCB)) strcat(dummy_string,"A2 "); if (opt.flags.rfc4880bis && !openpgp_aead_test_algo (AEAD_ALGO_EAX)) strcat(dummy_string,"A1 "); if (personal) { /* The default internal hash algo order is: * SHA-256, SHA-384, SHA-512, SHA-224, SHA-1. */ if (!openpgp_md_test_algo (DIGEST_ALGO_SHA256)) strcat (dummy_string, "H8 "); if (!openpgp_md_test_algo (DIGEST_ALGO_SHA384)) strcat (dummy_string, "H9 "); if (!openpgp_md_test_algo (DIGEST_ALGO_SHA512)) strcat (dummy_string, "H10 "); } else { /* The default advertised hash algo order is: * SHA-512, SHA-384, SHA-256, SHA-224, SHA-1. */ if (!openpgp_md_test_algo (DIGEST_ALGO_SHA512)) strcat (dummy_string, "H10 "); if (!openpgp_md_test_algo (DIGEST_ALGO_SHA384)) strcat (dummy_string, "H9 "); if (!openpgp_md_test_algo (DIGEST_ALGO_SHA256)) strcat (dummy_string, "H8 "); } if (!openpgp_md_test_algo (DIGEST_ALGO_SHA224)) strcat (dummy_string, "H11 "); strcat (dummy_string, "H2 "); /* SHA-1 */ if(!check_compress_algo(COMPRESS_ALGO_ZLIB)) { strcat(dummy_string,"Z2 "); any_compress = 1; } if(!check_compress_algo(COMPRESS_ALGO_BZIP2)) { strcat(dummy_string,"Z3 "); any_compress = 1; } if(!check_compress_algo(COMPRESS_ALGO_ZIP)) { strcat(dummy_string,"Z1 "); any_compress = 1; } /* In case we have no compress algo at all, declare that we prefer no compression. */ if (!any_compress) strcat(dummy_string,"Z0 "); /* Remove the trailing space. */ if (*dummy_string && dummy_string[strlen (dummy_string)-1] == ' ') dummy_string[strlen (dummy_string)-1] = 0; string=dummy_string; } } else if (!ascii_strcasecmp (string, "none")) string = ""; if(strlen(string)) { char *prefstringbuf; char *tok, *prefstring; /* We need a writable string. */ prefstring = prefstringbuf = xstrdup (string); while((tok=strsep(&prefstring," ,"))) { if((val=string_to_cipher_algo (tok))) { if(set_one_pref(val,1,tok,sym,&nsym)) rc=-1; } else if((val=string_to_digest_algo (tok))) { if(set_one_pref(val,2,tok,hash,&nhash)) rc=-1; } else if((val=string_to_compress_algo(tok))>-1) { if(set_one_pref(val,3,tok,zip,&nzip)) rc=-1; } else if ((val=string_to_aead_algo (tok))) { if (set_one_pref (val, 4, tok, aead, &naead)) rc = -1; } else if (ascii_strcasecmp(tok,"mdc")==0) mdc=1; else if (ascii_strcasecmp(tok,"no-mdc")==0) mdc=0; else if (ascii_strcasecmp(tok,"ks-modify")==0) modify=1; else if (ascii_strcasecmp(tok,"no-ks-modify")==0) modify=0; else { log_info (_("invalid item '%s' in preference string\n"),tok); rc=-1; } } xfree (prefstringbuf); } if(!rc) { if(personal) { if(personal==PREFTYPE_SYM) { xfree(opt.personal_cipher_prefs); if(nsym==0) opt.personal_cipher_prefs=NULL; else { int i; opt.personal_cipher_prefs= xmalloc(sizeof(prefitem_t *)*(nsym+1)); for (i=0; iref=1; uid->prefs = xmalloc ((sizeof(prefitem_t *)* (nsym_prefs+naead_prefs+nhash_prefs+nzip_prefs+1))); for(i=0;iprefs[j].type=PREFTYPE_SYM; uid->prefs[j].value=sym_prefs[i]; } for (i=0; i < naead_prefs; i++, j++) { uid->prefs[j].type = PREFTYPE_AEAD; uid->prefs[j].value = aead_prefs[i]; } for(i=0;iprefs[j].type=PREFTYPE_HASH; uid->prefs[j].value=hash_prefs[i]; } for(i=0;iprefs[j].type=PREFTYPE_ZIP; uid->prefs[j].value=zip_prefs[i]; } uid->prefs[j].type=PREFTYPE_NONE; uid->prefs[j].value=0; uid->flags.mdc = mdc_available; uid->flags.aead = aead_available; uid->flags.ks_modify = ks_modify; return uid; } static void add_feature_mdc (PKT_signature *sig,int enabled) { const byte *s; size_t n; int i; char *buf; s = parse_sig_subpkt (sig, 1, SIGSUBPKT_FEATURES, &n ); /* Already set or cleared */ if (s && n && ((enabled && (s[0] & 0x01)) || (!enabled && !(s[0] & 0x01)))) return; if (!s || !n) { /* create a new one */ n = 1; buf = xmalloc_clear (n); } else { buf = xmalloc (n); memcpy (buf, s, n); } if(enabled) buf[0] |= 0x01; /* MDC feature */ else buf[0] &= ~0x01; /* Are there any bits set? */ for(i=0;ihashed, SIGSUBPKT_FEATURES); else build_sig_subpkt (sig, SIGSUBPKT_FEATURES, buf, n); xfree (buf); } static void add_feature_aead (PKT_signature *sig, int enabled) { const byte *s; size_t n; int i; char *buf; s = parse_sig_subpkt (sig, 1, SIGSUBPKT_FEATURES, &n ); if (s && n && ((enabled && (s[0] & 0x02)) || (!enabled && !(s[0] & 0x02)))) return; /* Already set or cleared */ if (!s || !n) { /* Create a new one */ n = 1; buf = xmalloc_clear (n); } else { buf = xmalloc (n); memcpy (buf, s, n); } if (enabled) buf[0] |= 0x02; /* AEAD supported */ else buf[0] &= ~0x02; /* Are there any bits set? */ for (i=0; i < n; i++) if (buf[i]) break; if (i == n) delete_sig_subpkt (sig->hashed, SIGSUBPKT_FEATURES); else build_sig_subpkt (sig, SIGSUBPKT_FEATURES, buf, n); xfree (buf); } static void add_feature_v5 (PKT_signature *sig, int enabled) { const byte *s; size_t n; int i; char *buf; s = parse_sig_subpkt (sig, 1, SIGSUBPKT_FEATURES, &n ); if (s && n && ((enabled && (s[0] & 0x04)) || (!enabled && !(s[0] & 0x04)))) return; /* Already set or cleared */ if (!s || !n) { /* Create a new one */ n = 1; buf = xmalloc_clear (n); } else { buf = xmalloc (n); memcpy (buf, s, n); } if (enabled) buf[0] |= 0x04; /* v5 key supported */ else buf[0] &= ~0x04; /* Are there any bits set? */ for (i=0; i < n; i++) if (buf[i]) break; if (i == n) delete_sig_subpkt (sig->hashed, SIGSUBPKT_FEATURES); else build_sig_subpkt (sig, SIGSUBPKT_FEATURES, buf, n); xfree (buf); } static void add_keyserver_modify (PKT_signature *sig,int enabled) { const byte *s; size_t n; int i; char *buf; /* The keyserver modify flag is a negative flag (i.e. no-modify) */ enabled=!enabled; s = parse_sig_subpkt (sig, 1, SIGSUBPKT_KS_FLAGS, &n ); /* Already set or cleared */ if (s && n && ((enabled && (s[0] & 0x80)) || (!enabled && !(s[0] & 0x80)))) return; if (!s || !n) { /* create a new one */ n = 1; buf = xmalloc_clear (n); } else { buf = xmalloc (n); memcpy (buf, s, n); } if(enabled) buf[0] |= 0x80; /* no-modify flag */ else buf[0] &= ~0x80; /* Are there any bits set? */ for(i=0;ihashed, SIGSUBPKT_KS_FLAGS); else build_sig_subpkt (sig, SIGSUBPKT_KS_FLAGS, buf, n); xfree (buf); } int keygen_upd_std_prefs (PKT_signature *sig, void *opaque) { (void)opaque; if (!prefs_initialized) keygen_set_std_prefs (NULL, 0); if (nsym_prefs) build_sig_subpkt (sig, SIGSUBPKT_PREF_SYM, sym_prefs, nsym_prefs); else { delete_sig_subpkt (sig->hashed, SIGSUBPKT_PREF_SYM); delete_sig_subpkt (sig->unhashed, SIGSUBPKT_PREF_SYM); } if (naead_prefs) build_sig_subpkt (sig, SIGSUBPKT_PREF_AEAD, aead_prefs, naead_prefs); else { delete_sig_subpkt (sig->hashed, SIGSUBPKT_PREF_AEAD); delete_sig_subpkt (sig->unhashed, SIGSUBPKT_PREF_AEAD); } if (nhash_prefs) build_sig_subpkt (sig, SIGSUBPKT_PREF_HASH, hash_prefs, nhash_prefs); else { delete_sig_subpkt (sig->hashed, SIGSUBPKT_PREF_HASH); delete_sig_subpkt (sig->unhashed, SIGSUBPKT_PREF_HASH); } if (nzip_prefs) build_sig_subpkt (sig, SIGSUBPKT_PREF_COMPR, zip_prefs, nzip_prefs); else { delete_sig_subpkt (sig->hashed, SIGSUBPKT_PREF_COMPR); delete_sig_subpkt (sig->unhashed, SIGSUBPKT_PREF_COMPR); } /* Make sure that the MDC feature flag is set if needed. */ add_feature_mdc (sig,mdc_available); add_feature_aead (sig, aead_available); add_feature_v5 (sig, opt.flags.rfc4880bis); add_keyserver_modify (sig,ks_modify); keygen_add_keyserver_url(sig,NULL); return 0; } /**************** * Add preference to the self signature packet. * This is only called for packets with version > 3. */ int keygen_add_std_prefs (PKT_signature *sig, void *opaque) { PKT_public_key *pk = opaque; do_add_key_flags (sig, pk->pubkey_usage); keygen_add_key_expire (sig, opaque ); keygen_upd_std_prefs (sig, opaque); keygen_add_keyserver_url (sig,NULL); return 0; } int keygen_add_keyserver_url(PKT_signature *sig, void *opaque) { const char *url=opaque; if(!url) url=opt.def_keyserver_url; if(url) build_sig_subpkt(sig,SIGSUBPKT_PREF_KS,url,strlen(url)); else delete_sig_subpkt (sig->hashed,SIGSUBPKT_PREF_KS); return 0; } int keygen_add_notations(PKT_signature *sig,void *opaque) { struct notation *notation; /* We always start clean */ delete_sig_subpkt(sig->hashed,SIGSUBPKT_NOTATION); delete_sig_subpkt(sig->unhashed,SIGSUBPKT_NOTATION); sig->flags.notation=0; for(notation=opaque;notation;notation=notation->next) if(!notation->flags.ignore) { unsigned char *buf; unsigned int n1,n2; n1=strlen(notation->name); if(notation->altvalue) n2=strlen(notation->altvalue); else if(notation->bdat) n2=notation->blen; else n2=strlen(notation->value); buf = xmalloc( 8 + n1 + n2 ); /* human readable or not */ buf[0] = notation->bdat?0:0x80; buf[1] = buf[2] = buf[3] = 0; buf[4] = n1 >> 8; buf[5] = n1; buf[6] = n2 >> 8; buf[7] = n2; memcpy(buf+8, notation->name, n1 ); if(notation->altvalue) memcpy(buf+8+n1, notation->altvalue, n2 ); else if(notation->bdat) memcpy(buf+8+n1, notation->bdat, n2 ); else memcpy(buf+8+n1, notation->value, n2 ); build_sig_subpkt( sig, SIGSUBPKT_NOTATION | (notation->flags.critical?SIGSUBPKT_FLAG_CRITICAL:0), buf, 8+n1+n2 ); xfree(buf); } return 0; } int keygen_add_revkey (PKT_signature *sig, void *opaque) { struct revocation_key *revkey = opaque; byte buf[2+MAX_FINGERPRINT_LEN]; log_assert (revkey->fprlen <= MAX_FINGERPRINT_LEN); buf[0] = revkey->class; buf[1] = revkey->algid; memcpy (buf + 2, revkey->fpr, revkey->fprlen); memset (buf + 2 + revkey->fprlen, 0, sizeof (revkey->fpr) - revkey->fprlen); build_sig_subpkt (sig, SIGSUBPKT_REV_KEY, buf, 2+revkey->fprlen); /* All sigs with revocation keys set are nonrevocable. */ sig->flags.revocable = 0; buf[0] = 0; build_sig_subpkt (sig, SIGSUBPKT_REVOCABLE, buf, 1); parse_revkeys (sig); return 0; } /* Create a back-signature. If TIMESTAMP is not NULL, use it for the signature creation time. */ gpg_error_t make_backsig (ctrl_t ctrl, PKT_signature *sig, PKT_public_key *pk, PKT_public_key *sub_pk, PKT_public_key *sub_psk, u32 timestamp, const char *cache_nonce) { gpg_error_t err; PKT_signature *backsig; cache_public_key (sub_pk); err = make_keysig_packet (ctrl, &backsig, pk, NULL, sub_pk, sub_psk, 0x19, timestamp, 0, NULL, NULL, cache_nonce); if (err) log_error ("make_keysig_packet failed for backsig: %s\n", gpg_strerror (err)); else { /* Get it into a binary packed form. */ IOBUF backsig_out = iobuf_temp(); PACKET backsig_pkt; init_packet (&backsig_pkt); backsig_pkt.pkttype = PKT_SIGNATURE; backsig_pkt.pkt.signature = backsig; err = build_packet (backsig_out, &backsig_pkt); free_packet (&backsig_pkt, NULL); if (err) log_error ("build_packet failed for backsig: %s\n", gpg_strerror (err)); else { size_t pktlen = 0; byte *buf = iobuf_get_temp_buffer (backsig_out); /* Remove the packet header. */ if(buf[0]&0x40) { if (buf[1] < 192) { pktlen = buf[1]; buf += 2; } else if(buf[1] < 224) { pktlen = (buf[1]-192)*256; pktlen += buf[2]+192; buf += 3; } else if (buf[1] == 255) { pktlen = buf32_to_size_t (buf+2); buf += 6; } else BUG (); } else { int mark = 1; switch (buf[0]&3) { case 3: BUG (); break; case 2: pktlen = (size_t)buf[mark++] << 24; pktlen |= buf[mark++] << 16; /* fall through */ case 1: pktlen |= buf[mark++] << 8; /* fall through */ case 0: pktlen |= buf[mark++]; } buf += mark; } /* Now make the binary blob into a subpacket. */ build_sig_subpkt (sig, SIGSUBPKT_SIGNATURE, buf, pktlen); iobuf_close (backsig_out); } } return err; } /* Write a direct key signature to the first key in ROOT using the key PSK. REVKEY is describes the direct key signature and TIMESTAMP is the timestamp to set on the signature. */ static gpg_error_t write_direct_sig (ctrl_t ctrl, kbnode_t root, PKT_public_key *psk, struct revocation_key *revkey, u32 timestamp, const char *cache_nonce) { gpg_error_t err; PACKET *pkt; PKT_signature *sig; KBNODE node; PKT_public_key *pk; if (opt.verbose) log_info (_("writing direct signature\n")); /* Get the pk packet from the pub_tree. */ node = find_kbnode (root, PKT_PUBLIC_KEY); if (!node) BUG (); pk = node->pkt->pkt.public_key; /* We have to cache the key, so that the verification of the signature creation is able to retrieve the public key. */ cache_public_key (pk); /* Make the signature. */ err = make_keysig_packet (ctrl, &sig, pk, NULL,NULL, psk, 0x1F, timestamp, 0, keygen_add_revkey, revkey, cache_nonce); if (err) { log_error ("make_keysig_packet failed: %s\n", gpg_strerror (err) ); return err; } pkt = xmalloc_clear (sizeof *pkt); pkt->pkttype = PKT_SIGNATURE; pkt->pkt.signature = sig; add_kbnode (root, new_kbnode (pkt)); return err; } /* Write a self-signature to the first user id in ROOT using the key PSK. USE and TIMESTAMP give the extra data we need for the signature. */ static gpg_error_t write_selfsigs (ctrl_t ctrl, kbnode_t root, PKT_public_key *psk, unsigned int use, u32 timestamp, const char *cache_nonce) { gpg_error_t err; PACKET *pkt; PKT_signature *sig; PKT_user_id *uid; KBNODE node; PKT_public_key *pk; if (opt.verbose) log_info (_("writing self signature\n")); /* Get the uid packet from the list. */ node = find_kbnode (root, PKT_USER_ID); if (!node) BUG(); /* No user id packet in tree. */ uid = node->pkt->pkt.user_id; /* Get the pk packet from the pub_tree. */ node = find_kbnode (root, PKT_PUBLIC_KEY); if (!node) BUG(); pk = node->pkt->pkt.public_key; /* The usage has not yet been set - do it now. */ pk->pubkey_usage = use; /* We have to cache the key, so that the verification of the signature creation is able to retrieve the public key. */ cache_public_key (pk); /* Make the signature. */ err = make_keysig_packet (ctrl, &sig, pk, uid, NULL, psk, 0x13, timestamp, 0, keygen_add_std_prefs, pk, cache_nonce); if (err) { log_error ("make_keysig_packet failed: %s\n", gpg_strerror (err)); return err; } pkt = xmalloc_clear (sizeof *pkt); pkt->pkttype = PKT_SIGNATURE; pkt->pkt.signature = sig; add_kbnode (root, new_kbnode (pkt)); return err; } /* Write the key binding signature. If TIMESTAMP is not NULL use the signature creation time. PRI_PSK is the key use for signing. SUB_PSK is a key used to create a back-signature; that one is only used if USE has the PUBKEY_USAGE_SIG capability. */ static int write_keybinding (ctrl_t ctrl, kbnode_t root, PKT_public_key *pri_psk, PKT_public_key *sub_psk, unsigned int use, u32 timestamp, const char *cache_nonce) { gpg_error_t err; PACKET *pkt; PKT_signature *sig; KBNODE node; PKT_public_key *pri_pk, *sub_pk; struct opaque_data_usage_and_pk oduap; if (opt.verbose) log_info(_("writing key binding signature\n")); /* Get the primary pk packet from the tree. */ node = find_kbnode (root, PKT_PUBLIC_KEY); if (!node) BUG(); pri_pk = node->pkt->pkt.public_key; /* We have to cache the key, so that the verification of the * signature creation is able to retrieve the public key. */ cache_public_key (pri_pk); /* Find the last subkey. */ sub_pk = NULL; for (node = root; node; node = node->next ) { if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY) sub_pk = node->pkt->pkt.public_key; } if (!sub_pk) BUG(); /* Make the signature. */ oduap.usage = use; oduap.pk = sub_pk; err = make_keysig_packet (ctrl, &sig, pri_pk, NULL, sub_pk, pri_psk, 0x18, timestamp, 0, keygen_add_key_flags_and_expire, &oduap, cache_nonce); if (err) { log_error ("make_keysig_packeto failed: %s\n", gpg_strerror (err)); return err; } /* Make a backsig. */ if (use & PUBKEY_USAGE_SIG) { err = make_backsig (ctrl, sig, pri_pk, sub_pk, sub_psk, timestamp, cache_nonce); if (err) return err; } pkt = xmalloc_clear ( sizeof *pkt ); pkt->pkttype = PKT_SIGNATURE; pkt->pkt.signature = sig; add_kbnode (root, new_kbnode (pkt) ); return err; } static gpg_error_t ecckey_from_sexp (gcry_mpi_t *array, gcry_sexp_t sexp, int algo) { gpg_error_t err; gcry_sexp_t list, l2; char *curve = NULL; int i; const char *oidstr; unsigned int nbits; array[0] = NULL; array[1] = NULL; array[2] = NULL; list = gcry_sexp_find_token (sexp, "public-key", 0); if (!list) return gpg_error (GPG_ERR_INV_OBJ); l2 = gcry_sexp_cadr (list); gcry_sexp_release (list); list = l2; if (!list) return gpg_error (GPG_ERR_NO_OBJ); l2 = gcry_sexp_find_token (list, "curve", 0); if (!l2) { err = gpg_error (GPG_ERR_NO_OBJ); goto leave; } curve = gcry_sexp_nth_string (l2, 1); if (!curve) { err = gpg_error (GPG_ERR_NO_OBJ); goto leave; } gcry_sexp_release (l2); oidstr = openpgp_curve_to_oid (curve, &nbits, NULL); if (!oidstr) { /* That can't happen because we used one of the curves gpg_curve_to_oid knows about. */ err = gpg_error (GPG_ERR_INV_OBJ); goto leave; } err = openpgp_oid_from_str (oidstr, &array[0]); if (err) goto leave; err = sexp_extract_param_sos (list, "q", &array[1]); if (err) goto leave; gcry_sexp_release (list); if (algo == PUBKEY_ALGO_ECDH) { array[2] = pk_ecdh_default_params (nbits); if (!array[2]) { err = gpg_error_from_syserror (); goto leave; } } leave: xfree (curve); if (err) { for (i=0; i < 3; i++) { gcry_mpi_release (array[i]); array[i] = NULL; } } return err; } /* Extract key parameters from SEXP and store them in ARRAY. ELEMS is a string where each character denotes a parameter name. TOPNAME is the name of the top element above the elements. */ static int key_from_sexp (gcry_mpi_t *array, gcry_sexp_t sexp, const char *topname, const char *elems) { gcry_sexp_t list, l2; const char *s; int i, idx; int rc = 0; list = gcry_sexp_find_token (sexp, topname, 0); if (!list) return gpg_error (GPG_ERR_INV_OBJ); l2 = gcry_sexp_cadr (list); gcry_sexp_release (list); list = l2; if (!list) return gpg_error (GPG_ERR_NO_OBJ); for (idx=0,s=elems; *s; s++, idx++) { l2 = gcry_sexp_find_token (list, s, 1); if (!l2) { rc = gpg_error (GPG_ERR_NO_OBJ); /* required parameter not found */ goto leave; } array[idx] = gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG); gcry_sexp_release (l2); if (!array[idx]) { rc = gpg_error (GPG_ERR_INV_OBJ); /* required parameter invalid */ goto leave; } } gcry_sexp_release (list); leave: if (rc) { for (i=0; itimestamp = timestamp; pk->version = (keygen_flags & KEYGEN_FLAG_CREATE_V5_KEY)? 5 : 4; if (expireval) pk->expiredate = pk->timestamp + expireval; pk->pubkey_algo = algo; if (algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_EDDSA || algo == PUBKEY_ALGO_ECDH ) err = ecckey_from_sexp (pk->pkey, s_key, algo); else err = key_from_sexp (pk->pkey, s_key, "public-key", algoelem); if (err) { log_error ("key_from_sexp failed: %s\n", gpg_strerror (err) ); gcry_sexp_release (s_key); free_public_key (pk); return err; } gcry_sexp_release (s_key); pkt = xtrycalloc (1, sizeof *pkt); if (!pkt) { err = gpg_error_from_syserror (); free_public_key (pk); return err; } pkt->pkttype = is_subkey ? PKT_PUBLIC_SUBKEY : PKT_PUBLIC_KEY; pkt->pkt.public_key = pk; add_kbnode (pub_root, new_kbnode (pkt)); return 0; } /* Common code for the key generation function gen_xxx. */ static int common_gen (const char *keyparms, int algo, const char *algoelem, kbnode_t pub_root, u32 timestamp, u32 expireval, int is_subkey, int keygen_flags, const char *passphrase, char **cache_nonce_addr, char **passwd_nonce_addr) { int err; PACKET *pkt; PKT_public_key *pk; gcry_sexp_t s_key; err = agent_genkey (NULL, cache_nonce_addr, passwd_nonce_addr, keyparms, !!(keygen_flags & KEYGEN_FLAG_NO_PROTECTION), passphrase, &s_key); if (err) { log_error ("agent_genkey failed: %s\n", gpg_strerror (err) ); return err; } pk = xtrycalloc (1, sizeof *pk); if (!pk) { err = gpg_error_from_syserror (); gcry_sexp_release (s_key); return err; } pk->timestamp = timestamp; pk->version = (keygen_flags & KEYGEN_FLAG_CREATE_V5_KEY)? 5 : 4; if (expireval) pk->expiredate = pk->timestamp + expireval; pk->pubkey_algo = algo; if (algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_EDDSA || algo == PUBKEY_ALGO_ECDH ) err = ecckey_from_sexp (pk->pkey, s_key, algo); else err = key_from_sexp (pk->pkey, s_key, "public-key", algoelem); if (err) { log_error ("key_from_sexp failed: %s\n", gpg_strerror (err) ); gcry_sexp_release (s_key); free_public_key (pk); return err; } gcry_sexp_release (s_key); pkt = xtrycalloc (1, sizeof *pkt); if (!pkt) { err = gpg_error_from_syserror (); free_public_key (pk); return err; } pkt->pkttype = is_subkey ? PKT_PUBLIC_SUBKEY : PKT_PUBLIC_KEY; pkt->pkt.public_key = pk; add_kbnode (pub_root, new_kbnode (pkt)); return 0; } /* * Generate an Elgamal key. */ static int gen_elg (int algo, unsigned int nbits, KBNODE pub_root, u32 timestamp, u32 expireval, int is_subkey, int keygen_flags, const char *passphrase, char **cache_nonce_addr, char **passwd_nonce_addr) { int err; char *keyparms; char nbitsstr[35]; log_assert (is_ELGAMAL (algo)); if (nbits < 1024) { nbits = 2048; log_info (_("keysize invalid; using %u bits\n"), nbits ); } else if (nbits > 4096) { nbits = 4096; log_info (_("keysize invalid; using %u bits\n"), nbits ); } if ((nbits % 32)) { nbits = ((nbits + 31) / 32) * 32; log_info (_("keysize rounded up to %u bits\n"), nbits ); } /* Note that we use transient-key only if no-protection has also been enabled. */ snprintf (nbitsstr, sizeof nbitsstr, "%u", nbits); keyparms = xtryasprintf ("(genkey(%s(nbits %zu:%s)%s))", algo == GCRY_PK_ELG_E ? "openpgp-elg" : algo == GCRY_PK_ELG ? "elg" : "x-oops" , strlen (nbitsstr), nbitsstr, ((keygen_flags & KEYGEN_FLAG_TRANSIENT_KEY) && (keygen_flags & KEYGEN_FLAG_NO_PROTECTION))? "(transient-key)" : "" ); if (!keyparms) err = gpg_error_from_syserror (); else { err = common_gen (keyparms, algo, "pgy", pub_root, timestamp, expireval, is_subkey, keygen_flags, passphrase, cache_nonce_addr, passwd_nonce_addr); xfree (keyparms); } return err; } /* * Generate an DSA key */ static gpg_error_t gen_dsa (unsigned int nbits, KBNODE pub_root, u32 timestamp, u32 expireval, int is_subkey, int keygen_flags, const char *passphrase, char **cache_nonce_addr, char **passwd_nonce_addr) { int err; unsigned int qbits; char *keyparms; char nbitsstr[35]; char qbitsstr[35]; if (nbits < 768) { nbits = 2048; log_info(_("keysize invalid; using %u bits\n"), nbits ); } else if ( nbits > 3072 ) { nbits = 3072; log_info(_("keysize invalid; using %u bits\n"), nbits ); } if( (nbits % 64) ) { nbits = ((nbits + 63) / 64) * 64; log_info(_("keysize rounded up to %u bits\n"), nbits ); } /* To comply with FIPS rules we round up to the next value unless in expert mode. */ if (!opt.expert && nbits > 1024 && (nbits % 1024)) { nbits = ((nbits + 1023) / 1024) * 1024; log_info(_("keysize rounded up to %u bits\n"), nbits ); } /* Figure out a q size based on the key size. FIPS 180-3 says: L = 1024, N = 160 L = 2048, N = 224 L = 2048, N = 256 L = 3072, N = 256 2048/256 is an odd pair since there is also a 2048/224 and 3072/256. Matching sizes is not a very exact science. We'll do 256 qbits for nbits over 2047, 224 for nbits over 1024 but less than 2048, and 160 for 1024 (DSA1). */ if (nbits > 2047) qbits = 256; else if ( nbits > 1024) qbits = 224; else qbits = 160; if (qbits != 160 ) log_info (_("WARNING: some OpenPGP programs can't" " handle a DSA key with this digest size\n")); snprintf (nbitsstr, sizeof nbitsstr, "%u", nbits); snprintf (qbitsstr, sizeof qbitsstr, "%u", qbits); keyparms = xtryasprintf ("(genkey(dsa(nbits %zu:%s)(qbits %zu:%s)%s))", strlen (nbitsstr), nbitsstr, strlen (qbitsstr), qbitsstr, ((keygen_flags & KEYGEN_FLAG_TRANSIENT_KEY) && (keygen_flags & KEYGEN_FLAG_NO_PROTECTION))? "(transient-key)" : "" ); if (!keyparms) err = gpg_error_from_syserror (); else { err = common_gen (keyparms, PUBKEY_ALGO_DSA, "pqgy", pub_root, timestamp, expireval, is_subkey, keygen_flags, passphrase, cache_nonce_addr, passwd_nonce_addr); xfree (keyparms); } return err; } /* * Generate an ECC key */ static gpg_error_t gen_ecc (int algo, const char *curve, kbnode_t pub_root, u32 timestamp, u32 expireval, int is_subkey, int keygen_flags, const char *passphrase, char **cache_nonce_addr, char **passwd_nonce_addr) { gpg_error_t err; char *keyparms; log_assert (algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_EDDSA || algo == PUBKEY_ALGO_ECDH); if (!curve || !*curve) return gpg_error (GPG_ERR_UNKNOWN_CURVE); /* Map the displayed short forms of some curves to their canonical * names. */ if (!ascii_strcasecmp (curve, "cv25519")) curve = "Curve25519"; else if (!ascii_strcasecmp (curve, "ed25519")) curve = "Ed25519"; else if (!ascii_strcasecmp (curve, "cv448")) curve = "X448"; + else if (!ascii_strcasecmp (curve, "ed448")) + curve = "Ed448"; /* Note that we use the "comp" flag with EdDSA to request the use of a 0x40 compression prefix octet. */ - if (algo == PUBKEY_ALGO_EDDSA) + if (algo == PUBKEY_ALGO_EDDSA && !strcmp (curve, "Ed25519")) keyparms = xtryasprintf ("(genkey(ecc(curve %zu:%s)(flags eddsa comp%s)))", strlen (curve), curve, (((keygen_flags & KEYGEN_FLAG_TRANSIENT_KEY) && (keygen_flags & KEYGEN_FLAG_NO_PROTECTION))? " 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")) keyparms = xtryasprintf ("(genkey(ecc(curve %zu:%s)(flags djb-tweak 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, "X448")) 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 keyparms = xtryasprintf ("(genkey(ecc(curve %zu:%s)(flags nocomp%s)))", strlen (curve), curve, (((keygen_flags & KEYGEN_FLAG_TRANSIENT_KEY) && (keygen_flags & KEYGEN_FLAG_NO_PROTECTION))? " transient-key" : "")); if (!keyparms) err = gpg_error_from_syserror (); else { err = common_gen (keyparms, algo, "", pub_root, timestamp, expireval, is_subkey, keygen_flags, passphrase, cache_nonce_addr, passwd_nonce_addr); xfree (keyparms); } return err; } /* * Generate an RSA key. */ static int gen_rsa (int algo, unsigned int nbits, KBNODE pub_root, u32 timestamp, u32 expireval, int is_subkey, int keygen_flags, const char *passphrase, char **cache_nonce_addr, char **passwd_nonce_addr) { int err; char *keyparms; char nbitsstr[35]; const unsigned maxsize = (opt.flags.large_rsa ? 8192 : 4096); log_assert (is_RSA(algo)); if (!nbits) nbits = get_keysize_range (algo, NULL, NULL); if (nbits < 1024) { nbits = 3072; log_info (_("keysize invalid; using %u bits\n"), nbits ); } else if (nbits > maxsize) { nbits = maxsize; log_info (_("keysize invalid; using %u bits\n"), nbits ); } if ((nbits % 32)) { nbits = ((nbits + 31) / 32) * 32; log_info (_("keysize rounded up to %u bits\n"), nbits ); } snprintf (nbitsstr, sizeof nbitsstr, "%u", nbits); keyparms = xtryasprintf ("(genkey(rsa(nbits %zu:%s)%s))", strlen (nbitsstr), nbitsstr, ((keygen_flags & KEYGEN_FLAG_TRANSIENT_KEY) && (keygen_flags & KEYGEN_FLAG_NO_PROTECTION))? "(transient-key)" : "" ); if (!keyparms) err = gpg_error_from_syserror (); else { err = common_gen (keyparms, algo, "ne", pub_root, timestamp, expireval, is_subkey, keygen_flags, passphrase, cache_nonce_addr, passwd_nonce_addr); xfree (keyparms); } return err; } /**************** * check valid days: * return 0 on error or the multiplier */ static int check_valid_days( const char *s ) { if( !digitp(s) ) return 0; for( s++; *s; s++) if( !digitp(s) ) break; if( !*s ) return 1; if( s[1] ) return 0; /* e.g. "2323wc" */ if( *s == 'd' || *s == 'D' ) return 1; if( *s == 'w' || *s == 'W' ) return 7; if( *s == 'm' || *s == 'M' ) return 30; if( *s == 'y' || *s == 'Y' ) return 365; return 0; } static void print_key_flags(int flags) { if(flags&PUBKEY_USAGE_SIG) tty_printf("%s ",_("Sign")); if(flags&PUBKEY_USAGE_CERT) tty_printf("%s ",_("Certify")); if(flags&PUBKEY_USAGE_ENC) tty_printf("%s ",_("Encrypt")); if(flags&PUBKEY_USAGE_AUTH) tty_printf("%s ",_("Authenticate")); } /* Ask for the key flags and return them. CURRENT gives the current * usage which should normally be given as 0. MASK gives the allowed * flags. */ unsigned int ask_key_flags_with_mask (int algo, int subkey, unsigned int current, unsigned int mask) { /* TRANSLATORS: Please use only plain ASCII characters for the * translation. If this is not possible use single digits. The * string needs to 8 bytes long. Here is a description of the * functions: * * s = Toggle signing capability * e = Toggle encryption capability * a = Toggle authentication capability * q = Finish */ const char *togglers = _("SsEeAaQq"); char *answer = NULL; const char *s; unsigned int possible; if ( strlen(togglers) != 8 ) { tty_printf ("NOTE: Bad translation at %s:%d. " "Please report.\n", __FILE__, __LINE__); togglers = "11223300"; } /* Mask the possible usage flags. This is for example used for a * card based key. For ECDH we need to allows additional usages if * they are provided. */ possible = (openpgp_pk_algo_usage (algo) & mask); if (algo == PUBKEY_ALGO_ECDH) possible |= (current & (PUBKEY_USAGE_ENC |PUBKEY_USAGE_CERT |PUBKEY_USAGE_SIG |PUBKEY_USAGE_AUTH)); /* However, only primary keys may certify. */ if (subkey) possible &= ~PUBKEY_USAGE_CERT; /* Preload the current set with the possible set, without * authentication if CURRENT is 0. If CURRENT is non-zero we mask * with all possible usages. */ if (current) current &= possible; else current = (possible&~PUBKEY_USAGE_AUTH); for (;;) { tty_printf("\n"); tty_printf(_("Possible actions for this %s key: "), (algo == PUBKEY_ALGO_ECDH || algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_EDDSA) ? "ECC" : openpgp_pk_algo_name (algo)); print_key_flags(possible); tty_printf("\n"); tty_printf(_("Current allowed actions: ")); print_key_flags(current); tty_printf("\n\n"); if(possible&PUBKEY_USAGE_SIG) tty_printf(_(" (%c) Toggle the sign capability\n"), togglers[0]); if(possible&PUBKEY_USAGE_ENC) tty_printf(_(" (%c) Toggle the encrypt capability\n"), togglers[2]); if(possible&PUBKEY_USAGE_AUTH) tty_printf(_(" (%c) Toggle the authenticate capability\n"), togglers[4]); tty_printf(_(" (%c) Finished\n"),togglers[6]); tty_printf("\n"); xfree(answer); answer = cpr_get("keygen.flags",_("Your selection? ")); cpr_kill_prompt(); if (*answer == '=') { /* Hack to allow direct entry of the capabilities. */ current = 0; for (s=answer+1; *s; s++) { if ((*s == 's' || *s == 'S') && (possible&PUBKEY_USAGE_SIG)) current |= PUBKEY_USAGE_SIG; else if ((*s == 'e' || *s == 'E') && (possible&PUBKEY_USAGE_ENC)) current |= PUBKEY_USAGE_ENC; else if ((*s == 'a' || *s == 'A') && (possible&PUBKEY_USAGE_AUTH)) current |= PUBKEY_USAGE_AUTH; else if (!subkey && *s == 'c') { /* Accept 'c' for the primary key because USAGE_CERT will be set anyway. This is for folks who want to experiment with a cert-only primary key. */ current |= PUBKEY_USAGE_CERT; } } break; } else if (strlen(answer)>1) tty_printf(_("Invalid selection.\n")); else if(*answer=='\0' || *answer==togglers[6] || *answer==togglers[7]) break; else if((*answer==togglers[0] || *answer==togglers[1]) && possible&PUBKEY_USAGE_SIG) { if(current&PUBKEY_USAGE_SIG) current&=~PUBKEY_USAGE_SIG; else current|=PUBKEY_USAGE_SIG; } else if((*answer==togglers[2] || *answer==togglers[3]) && possible&PUBKEY_USAGE_ENC) { if(current&PUBKEY_USAGE_ENC) current&=~PUBKEY_USAGE_ENC; else current|=PUBKEY_USAGE_ENC; } else if((*answer==togglers[4] || *answer==togglers[5]) && possible&PUBKEY_USAGE_AUTH) { if(current&PUBKEY_USAGE_AUTH) current&=~PUBKEY_USAGE_AUTH; else current|=PUBKEY_USAGE_AUTH; } else tty_printf(_("Invalid selection.\n")); } xfree(answer); return current; } unsigned int ask_key_flags (int algo, int subkey, unsigned int current) { return ask_key_flags_with_mask (algo, subkey, current, ~0); } /* Check whether we have a key for the key with HEXGRIP. Returns 0 if there is no such key or the OpenPGP algo number for the key. */ static int check_keygrip (ctrl_t ctrl, const char *hexgrip) { gpg_error_t err; unsigned char *public; size_t publiclen; int algo; if (hexgrip[0] == '&') hexgrip++; err = agent_readkey (ctrl, 0, hexgrip, &public); if (err) return 0; publiclen = gcry_sexp_canon_len (public, 0, NULL, NULL); algo = get_pk_algo_from_canon_sexp (public, publiclen); xfree (public); return map_gcry_pk_to_openpgp (algo); } /* Ask for an algorithm. The function returns the algorithm id to * create. If ADDMODE is false the function won't show an option to * create the primary and subkey combined and won't set R_USAGE * either. If a combined algorithm has been selected, the subkey * algorithm is stored at R_SUBKEY_ALGO. If R_KEYGRIP is given, the * user has the choice to enter the keygrip of an existing key. That * keygrip is then stored at this address. The caller needs to free * it. If R_CARDKEY is not NULL and the keygrip has been taken from * an active card, true is stored there; if R_KEYTIME is not NULL the * creation time of that key is then stored there. */ static int ask_algo (ctrl_t ctrl, int addmode, int *r_subkey_algo, unsigned int *r_usage, char **r_keygrip, int *r_cardkey, u32 *r_keytime) { gpg_error_t err; char *keygrip = NULL; u32 keytime = 0; char *answer = NULL; int cardkey = 0; int algo; int dummy_algo; if (!r_subkey_algo) r_subkey_algo = &dummy_algo; tty_printf (_("Please select what kind of key you want:\n")); #if GPG_USE_RSA if (!addmode) tty_printf (_(" (%d) RSA and RSA (default)\n"), 1 ); #endif if (!addmode && opt.compliance != CO_DE_VS) tty_printf (_(" (%d) DSA and Elgamal\n"), 2 ); if (opt.compliance != CO_DE_VS) tty_printf (_(" (%d) DSA (sign only)\n"), 3 ); #if GPG_USE_RSA tty_printf (_(" (%d) RSA (sign only)\n"), 4 ); #endif if (addmode) { if (opt.compliance != CO_DE_VS) tty_printf (_(" (%d) Elgamal (encrypt only)\n"), 5 ); #if GPG_USE_RSA tty_printf (_(" (%d) RSA (encrypt only)\n"), 6 ); #endif } if (opt.expert) { if (opt.compliance != CO_DE_VS) tty_printf (_(" (%d) DSA (set your own capabilities)\n"), 7 ); #if GPG_USE_RSA tty_printf (_(" (%d) RSA (set your own capabilities)\n"), 8 ); #endif } #if GPG_USE_ECDSA || GPG_USE_ECDH || GPG_USE_EDDSA if (opt.expert && !addmode) tty_printf (_(" (%d) ECC and ECC\n"), 9 ); if (opt.expert) tty_printf (_(" (%d) ECC (sign only)\n"), 10 ); if (opt.expert) tty_printf (_(" (%d) ECC (set your own capabilities)\n"), 11 ); if (opt.expert && addmode) tty_printf (_(" (%d) ECC (encrypt only)\n"), 12 ); #endif if (opt.expert && r_keygrip) tty_printf (_(" (%d) Existing key\n"), 13 ); if (r_keygrip) tty_printf (_(" (%d) Existing key from card\n"), 14 ); for (;;) { *r_usage = 0; *r_subkey_algo = 0; xfree (answer); answer = cpr_get ("keygen.algo", _("Your selection? ")); cpr_kill_prompt (); algo = *answer? atoi (answer) : 1; if (opt.compliance == CO_DE_VS && (algo == 2 || algo == 3 || algo == 5 || algo == 7)) { tty_printf (_("Invalid selection.\n")); } else if ((algo == 1 || !strcmp (answer, "rsa+rsa")) && !addmode) { algo = PUBKEY_ALGO_RSA; *r_subkey_algo = PUBKEY_ALGO_RSA; break; } else if ((algo == 2 || !strcmp (answer, "dsa+elg")) && !addmode) { algo = PUBKEY_ALGO_DSA; *r_subkey_algo = PUBKEY_ALGO_ELGAMAL_E; break; } else if (algo == 3 || !strcmp (answer, "dsa")) { algo = PUBKEY_ALGO_DSA; *r_usage = PUBKEY_USAGE_SIG; break; } else if (algo == 4 || !strcmp (answer, "rsa/s")) { algo = PUBKEY_ALGO_RSA; *r_usage = PUBKEY_USAGE_SIG; break; } else if ((algo == 5 || !strcmp (answer, "elg")) && addmode) { algo = PUBKEY_ALGO_ELGAMAL_E; *r_usage = PUBKEY_USAGE_ENC; break; } else if ((algo == 6 || !strcmp (answer, "rsa/e")) && addmode) { algo = PUBKEY_ALGO_RSA; *r_usage = PUBKEY_USAGE_ENC; break; } else if ((algo == 7 || !strcmp (answer, "dsa/*")) && opt.expert) { algo = PUBKEY_ALGO_DSA; *r_usage = ask_key_flags (algo, addmode, 0); break; } else if ((algo == 8 || !strcmp (answer, "rsa/*")) && opt.expert) { algo = PUBKEY_ALGO_RSA; *r_usage = ask_key_flags (algo, addmode, 0); break; } else if ((algo == 9 || !strcmp (answer, "ecc+ecc")) && opt.expert && !addmode) { algo = PUBKEY_ALGO_ECDSA; *r_subkey_algo = PUBKEY_ALGO_ECDH; break; } else if ((algo == 10 || !strcmp (answer, "ecc/s")) && opt.expert) { algo = PUBKEY_ALGO_ECDSA; *r_usage = PUBKEY_USAGE_SIG; break; } else if ((algo == 11 || !strcmp (answer, "ecc/*")) && opt.expert) { algo = PUBKEY_ALGO_ECDSA; *r_usage = ask_key_flags (algo, addmode, 0); break; } else if ((algo == 12 || !strcmp (answer, "ecc/e")) && opt.expert && addmode) { algo = PUBKEY_ALGO_ECDH; *r_usage = PUBKEY_USAGE_ENC; break; } else if ((algo == 13 || !strcmp (answer, "keygrip")) && opt.expert && r_keygrip) { for (;;) { xfree (answer); answer = tty_get (_("Enter the keygrip: ")); tty_kill_prompt (); trim_spaces (answer); if (!*answer) { xfree (answer); answer = NULL; continue; } if (strlen (answer) != 40 && !(answer[0] == '&' && strlen (answer+1) == 40)) tty_printf (_("Not a valid keygrip (expecting 40 hex digits)\n")); else if (!(algo = check_keygrip (ctrl, answer)) ) tty_printf (_("No key with this keygrip\n")); else break; /* Okay. */ } xfree (keygrip); keygrip = answer; answer = NULL; *r_usage = ask_key_flags (algo, addmode, 0); break; } else if ((algo == 14 || !strcmp (answer, "cardkey")) && r_keygrip) { char *serialno; keypair_info_t keypairlist, kpi; int count, selection; err = agent_scd_serialno (&serialno, NULL); if (err) { tty_printf (_("error reading the card: %s\n"), gpg_strerror (err)); goto ask_again; } tty_printf (_("Serial number of the card: %s\n"), serialno); xfree (serialno); err = agent_scd_keypairinfo (ctrl, NULL, &keypairlist); if (err) { tty_printf (_("error reading the card: %s\n"), gpg_strerror (err)); goto ask_again; } do { char *authkeyref, *encrkeyref, *signkeyref; agent_scd_getattr_one ("$AUTHKEYID", &authkeyref); agent_scd_getattr_one ("$ENCRKEYID", &encrkeyref); agent_scd_getattr_one ("$SIGNKEYID", &signkeyref); tty_printf (_("Available keys:\n")); for (count=1, kpi=keypairlist; kpi; kpi = kpi->next, count++) { gcry_sexp_t s_pkey; char *algostr = NULL; enum gcry_pk_algos algoid = 0; const char *keyref = kpi->idstr; int any = 0; if (keyref && !agent_scd_readkey (ctrl, keyref, &s_pkey, NULL)) { algostr = pubkey_algo_string (s_pkey, &algoid); gcry_sexp_release (s_pkey); } /* We need to tweak the algo in case GCRY_PK_ECC is * returned because pubkey_algo_string is not aware * of the OpenPGP algo mapping. We need to * distinguish between ECDH and ECDSA but we can do * that only if we got usage flags. * Note: Keep this in sync with parse_key_parameter_part. */ if (algoid == GCRY_PK_ECC && algostr) { if (!strcmp (algostr, "ed25519")) kpi->algo = PUBKEY_ALGO_EDDSA; + else if (!strcmp (algostr, "ed448")) + kpi->algo = PUBKEY_ALGO_EDDSA; else if (!strcmp (algostr, "cv25519")) kpi->algo = PUBKEY_ALGO_ECDH; else if (!strcmp (algostr, "cv448")) kpi->algo = PUBKEY_ALGO_ECDH; else if ((kpi->usage & GCRY_PK_USAGE_ENCR)) kpi->algo = PUBKEY_ALGO_ECDH; else kpi->algo = PUBKEY_ALGO_ECDSA; } else kpi->algo = map_gcry_pk_to_openpgp (algoid); tty_printf (" (%d) %s %s %s", count, kpi->keygrip, keyref, algostr); if ((kpi->usage & GCRY_PK_USAGE_CERT)) { tty_printf ("%scert", any?",":" ("); any = 1; } if ((kpi->usage & GCRY_PK_USAGE_SIGN)) { tty_printf ("%ssign%s", any?",":" (", (signkeyref && keyref && !strcmp (signkeyref, keyref))? "*":""); any = 1; } if ((kpi->usage & GCRY_PK_USAGE_AUTH)) { tty_printf ("%sauth%s", any?",":" (", (authkeyref && keyref && !strcmp (authkeyref, keyref))? "*":""); any = 1; } if ((kpi->usage & GCRY_PK_USAGE_ENCR)) { tty_printf ("%sencr%s", any?",":" (", (encrkeyref && keyref && !strcmp (encrkeyref, keyref))? "*":""); any = 1; } tty_printf ("%s\n", any?")":""); xfree (algostr); } xfree (answer); answer = cpr_get ("keygen.cardkey", _("Your selection? ")); cpr_kill_prompt (); trim_spaces (answer); selection = atoi (answer); xfree (authkeyref); xfree (encrkeyref); xfree (signkeyref); } while (!(selection > 0 && selection < count)); for (count=1,kpi=keypairlist; kpi; kpi = kpi->next, count++) if (count == selection) break; if (!kpi) { /* Just in case COUNT is zero (no keys). */ free_keypair_info (keypairlist); goto ask_again; } xfree (keygrip); keygrip = xstrdup (kpi->keygrip); cardkey = 1; algo = kpi->algo; keytime = kpi->keytime; /* In expert mode allow to change the usage flags. */ if (opt.expert) *r_usage = ask_key_flags_with_mask (algo, addmode, kpi->usage, kpi->usage); else { *r_usage = kpi->usage; if (addmode) *r_usage &= ~GCRY_PK_USAGE_CERT; } free_keypair_info (keypairlist); break; } else tty_printf (_("Invalid selection.\n")); ask_again: ; } xfree(answer); if (r_keygrip) *r_keygrip = keygrip; if (r_cardkey) *r_cardkey = cardkey; if (r_keytime) *r_keytime = keytime; return algo; } static unsigned int get_keysize_range (int algo, unsigned int *min, unsigned int *max) { unsigned int def; unsigned int dummy1, dummy2; if (!min) min = &dummy1; if (!max) max = &dummy2; switch(algo) { case PUBKEY_ALGO_DSA: *min = opt.expert? 768 : 1024; *max=3072; def=2048; break; case PUBKEY_ALGO_ECDSA: case PUBKEY_ALGO_ECDH: *min=256; *max=521; def=256; break; case PUBKEY_ALGO_EDDSA: *min=255; *max=441; def=255; break; default: *min = opt.compliance == CO_DE_VS ? 2048: 1024; *max = 4096; def = 3072; break; } return def; } /* Return a fixed up keysize depending on ALGO. */ static unsigned int fixup_keysize (unsigned int nbits, int algo, int silent) { if (algo == PUBKEY_ALGO_DSA && (nbits % 64)) { nbits = ((nbits + 63) / 64) * 64; if (!silent) tty_printf (_("rounded up to %u bits\n"), nbits); } else if (algo == PUBKEY_ALGO_EDDSA) { if (nbits != 255 && nbits != 441) { if (nbits < 256) nbits = 255; else nbits = 441; if (!silent) tty_printf (_("rounded to %u bits\n"), nbits); } } else if (algo == PUBKEY_ALGO_ECDH || algo == PUBKEY_ALGO_ECDSA) { if (nbits != 256 && nbits != 384 && nbits != 521) { if (nbits < 256) nbits = 256; else if (nbits < 384) nbits = 384; else nbits = 521; if (!silent) tty_printf (_("rounded to %u bits\n"), nbits); } } else if ((nbits % 32)) { nbits = ((nbits + 31) / 32) * 32; if (!silent) tty_printf (_("rounded up to %u bits\n"), nbits ); } return nbits; } /* Ask for the key size. ALGO is the algorithm. If PRIMARY_KEYSIZE is not 0, the function asks for the size of the encryption subkey. */ static unsigned ask_keysize (int algo, unsigned int primary_keysize) { unsigned int nbits; unsigned int min, def, max; int for_subkey = !!primary_keysize; int autocomp = 0; def = get_keysize_range (algo, &min, &max); if (primary_keysize && !opt.expert) { /* Deduce the subkey size from the primary key size. */ if (algo == PUBKEY_ALGO_DSA && primary_keysize > 3072) nbits = 3072; /* For performance reasons we don't support more than 3072 bit DSA. However we won't see this case anyway because DSA can't be used as an encryption subkey ;-). */ else nbits = primary_keysize; autocomp = 1; goto leave; } tty_printf(_("%s keys may be between %u and %u bits long.\n"), openpgp_pk_algo_name (algo), min, max); for (;;) { char *prompt, *answer; if (for_subkey) prompt = xasprintf (_("What keysize do you want " "for the subkey? (%u) "), def); else prompt = xasprintf (_("What keysize do you want? (%u) "), def); answer = cpr_get ("keygen.size", prompt); cpr_kill_prompt (); nbits = *answer? atoi (answer): def; xfree(prompt); xfree(answer); if(nbitsmax) tty_printf(_("%s keysizes must be in the range %u-%u\n"), openpgp_pk_algo_name (algo), min, max); else break; } tty_printf (_("Requested keysize is %u bits\n"), nbits); leave: nbits = fixup_keysize (nbits, algo, autocomp); return nbits; } /* Ask for the curve. ALGO is the selected algorithm which this function may adjust. Returns a const string of the name of the curve. */ const char * ask_curve (int *algo, int *subkey_algo, const char *current) { /* NB: We always use a complete algo list so that we have stable numbers in the menu regardless on how Gpg was configured. */ struct { const char *name; const char* eddsa_curve; /* Corresponding EdDSA curve. */ const char *pretty_name; unsigned int supported : 1; /* Supported by gpg. */ unsigned int de_vs : 1; /* Allowed in CO_DE_VS. */ unsigned int expert_only : 1; /* Only with --expert */ unsigned int available : 1; /* Available in Libycrypt (runtime checked) */ } curves[] = { #if GPG_USE_ECDSA || GPG_USE_ECDH # define MY_USE_ECDSADH 1 #else # define MY_USE_ECDSADH 0 #endif { "Curve25519", "Ed25519", "Curve 25519", !!GPG_USE_EDDSA, 0, 0, 0 }, { "Curve448", "Ed448", "Curve 448", 0/*reserved*/ , 0, 1, 0 }, { "NIST P-256", NULL, NULL, MY_USE_ECDSADH, 0, 1, 0 }, { "NIST P-384", NULL, NULL, MY_USE_ECDSADH, 0, 0, 0 }, { "NIST P-521", NULL, NULL, MY_USE_ECDSADH, 0, 1, 0 }, { "brainpoolP256r1", NULL, "Brainpool P-256", MY_USE_ECDSADH, 1, 1, 0 }, { "brainpoolP384r1", NULL, "Brainpool P-384", MY_USE_ECDSADH, 1, 1, 0 }, { "brainpoolP512r1", NULL, "Brainpool P-512", MY_USE_ECDSADH, 1, 1, 0 }, { "secp256k1", NULL, NULL, MY_USE_ECDSADH, 0, 1, 0 }, }; #undef MY_USE_ECDSADH int idx; char *answer; const char *result = NULL; gcry_sexp_t keyparms; tty_printf (_("Please select which elliptic curve you want:\n")); keyparms = NULL; for (idx=0; idx < DIM(curves); idx++) { int rc; curves[idx].available = 0; if (!curves[idx].supported) continue; if (opt.compliance==CO_DE_VS) { if (!curves[idx].de_vs) continue; /* Not allowed. */ } else if (!opt.expert && curves[idx].expert_only) continue; /* We need to switch from the ECDH name of the curve to the EDDSA name of the curve if we want a signing key. */ gcry_sexp_release (keyparms); rc = gcry_sexp_build (&keyparms, NULL, "(public-key(ecc(curve %s)))", curves[idx].eddsa_curve? curves[idx].eddsa_curve /**/ : curves[idx].name); if (rc) continue; if (!gcry_pk_get_curve (keyparms, 0, NULL)) continue; if (subkey_algo && curves[idx].eddsa_curve) { /* Both Curve 25519 (or 448) keys are to be created. Check that Libgcrypt also supports the real Curve25519 (or 448). */ gcry_sexp_release (keyparms); rc = gcry_sexp_build (&keyparms, NULL, "(public-key(ecc(curve %s)))", curves[idx].name); if (rc) continue; if (!gcry_pk_get_curve (keyparms, 0, NULL)) continue; } curves[idx].available = 1; tty_printf (" (%d) %s\n", idx + 1, curves[idx].pretty_name? curves[idx].pretty_name:curves[idx].name); } gcry_sexp_release (keyparms); for (;;) { answer = cpr_get ("keygen.curve", _("Your selection? ")); cpr_kill_prompt (); idx = *answer? atoi (answer) : 1; if (!*answer && current) { xfree(answer); return NULL; } else if (*answer && !idx) { /* See whether the user entered the name of the curve. */ for (idx=0; idx < DIM(curves); idx++) { if (!opt.expert && curves[idx].expert_only) continue; if (!stricmp (curves[idx].name, answer) || (curves[idx].pretty_name && !stricmp (curves[idx].pretty_name, answer))) break; } if (idx == DIM(curves)) idx = -1; } else idx--; xfree(answer); answer = NULL; if (idx < 0 || idx >= DIM (curves) || !curves[idx].available) tty_printf (_("Invalid selection.\n")); else { /* If the user selected a signing algorithm and Curve25519 we need to set the algo to EdDSA and update the curve name. If switching away from EdDSA, we need to set the algo back to ECDSA. */ if (*algo == PUBKEY_ALGO_ECDSA || *algo == PUBKEY_ALGO_EDDSA) { if (curves[idx].eddsa_curve) { if (subkey_algo && *subkey_algo == PUBKEY_ALGO_ECDSA) *subkey_algo = PUBKEY_ALGO_EDDSA; *algo = PUBKEY_ALGO_EDDSA; result = curves[idx].eddsa_curve; } else { if (subkey_algo && *subkey_algo == PUBKEY_ALGO_EDDSA) *subkey_algo = PUBKEY_ALGO_ECDSA; *algo = PUBKEY_ALGO_ECDSA; result = curves[idx].name; } } else result = curves[idx].name; break; } } if (!result) result = curves[0].name; return result; } /**************** * Parse an expire string and return its value in seconds. * Returns (u32)-1 on error. * This isn't perfect since scan_isodatestr returns unix time, and * OpenPGP actually allows a 32-bit time *plus* a 32-bit offset. * Because of this, we only permit setting expirations up to 2106, but * OpenPGP could theoretically allow up to 2242. I think we'll all * just cope for the next few years until we get a 64-bit time_t or * similar. */ u32 parse_expire_string( const char *string ) { int mult; u32 seconds; u32 abs_date = 0; u32 curtime = make_timestamp (); time_t tt; if (!string || !*string || !strcmp (string, "none") || !strcmp (string, "never") || !strcmp (string, "-")) seconds = 0; else if (!strncmp (string, "seconds=", 8)) seconds = atoi (string+8); else if ((abs_date = scan_isodatestr(string)) && (abs_date+86400/2) > curtime) seconds = (abs_date+86400/2) - curtime; else if ((tt = isotime2epoch (string)) != (time_t)(-1)) seconds = (u32)tt - curtime; else if ((mult = check_valid_days (string))) seconds = atoi (string) * 86400L * mult; else seconds = (u32)(-1); return seconds; } /* Parse a Creation-Date string which is either "1986-04-26" or "19860426T042640". Returns 0 on error. */ static u32 parse_creation_string (const char *string) { u32 seconds; if (!*string) seconds = 0; else if ( !strncmp (string, "seconds=", 8) ) seconds = atoi (string+8); else if ( !(seconds = scan_isodatestr (string))) { time_t tmp = isotime2epoch (string); seconds = (tmp == (time_t)(-1))? 0 : tmp; } return seconds; } /* object == 0 for a key, and 1 for a sig */ u32 ask_expire_interval(int object,const char *def_expire) { u32 interval; char *answer; switch(object) { case 0: if(def_expire) BUG(); tty_printf(_("Please specify how long the key should be valid.\n" " 0 = key does not expire\n" " = key expires in n days\n" " w = key expires in n weeks\n" " m = key expires in n months\n" " y = key expires in n years\n")); break; case 1: if(!def_expire) BUG(); tty_printf(_("Please specify how long the signature should be valid.\n" " 0 = signature does not expire\n" " = signature expires in n days\n" " w = signature expires in n weeks\n" " m = signature expires in n months\n" " y = signature expires in n years\n")); break; default: BUG(); } /* Note: The elgamal subkey for DSA has no expiration date because * it must be signed with the DSA key and this one has the expiration * date */ answer = NULL; for(;;) { u32 curtime; xfree(answer); if(object==0) answer = cpr_get("keygen.valid",_("Key is valid for? (0) ")); else { char *prompt; prompt = xasprintf (_("Signature is valid for? (%s) "), def_expire); answer = cpr_get("siggen.valid",prompt); xfree(prompt); if(*answer=='\0') answer=xstrdup(def_expire); } cpr_kill_prompt(); trim_spaces(answer); curtime = make_timestamp (); interval = parse_expire_string( answer ); if( interval == (u32)-1 ) { tty_printf(_("invalid value\n")); continue; } if( !interval ) { tty_printf((object==0) ? _("Key does not expire at all\n") : _("Signature does not expire at all\n")); } else { tty_printf(object==0 ? _("Key expires at %s\n") : _("Signature expires at %s\n"), asctimestamp((ulong)(curtime + interval) ) ); #if SIZEOF_TIME_T <= 4 && !defined (HAVE_UNSIGNED_TIME_T) if ( (time_t)((ulong)(curtime+interval)) < 0 ) tty_printf (_("Your system can't display dates beyond 2038.\n" "However, it will be correctly handled up to" " 2106.\n")); else #endif /*SIZEOF_TIME_T*/ if ( (time_t)((unsigned long)(curtime+interval)) < curtime ) { tty_printf (_("invalid value\n")); continue; } } if( cpr_enabled() || cpr_get_answer_is_yes("keygen.valid.okay", _("Is this correct? (y/N) ")) ) break; } xfree(answer); return interval; } u32 ask_expiredate() { u32 x = ask_expire_interval(0,NULL); return x? make_timestamp() + x : 0; } static PKT_user_id * uid_from_string (const char *string) { size_t n; PKT_user_id *uid; n = strlen (string); uid = xmalloc_clear (sizeof *uid + n); uid->len = n; strcpy (uid->name, string); uid->ref = 1; return uid; } /* Return true if the user id UID already exists in the keyblock. */ static int uid_already_in_keyblock (kbnode_t keyblock, const char *uid) { PKT_user_id *uidpkt = uid_from_string (uid); kbnode_t node; int result = 0; for (node=keyblock; node && !result; node=node->next) if (!is_deleted_kbnode (node) && node->pkt->pkttype == PKT_USER_ID && !cmp_user_ids (uidpkt, node->pkt->pkt.user_id)) result = 1; free_user_id (uidpkt); return result; } /* Ask for a user ID. With a MODE of 1 an extra help prompt is printed for use during a new key creation. If KEYBLOCK is not NULL the function prevents the creation of an already existing user ID. IF FULL is not set some prompts are not shown. */ static char * ask_user_id (int mode, int full, KBNODE keyblock) { char *answer; char *aname, *acomment, *amail, *uid; if ( !mode ) { /* TRANSLATORS: This is the new string telling the user what gpg is now going to do (i.e. ask for the parts of the user ID). Note that if you do not translate this string, a different string will be used, which might still have a correct translation. */ const char *s1 = N_("\n" "GnuPG needs to construct a user ID to identify your key.\n" "\n"); const char *s2 = _(s1); if (!strcmp (s1, s2)) { /* There is no translation for the string thus we to use the old info text. gettext has no way to tell whether a translation is actually available, thus we need to to compare again. */ /* TRANSLATORS: This string is in general not anymore used but you should keep your existing translation. In case the new string is not translated this old string will be used. */ const char *s3 = N_("\n" "You need a user ID to identify your key; " "the software constructs the user ID\n" "from the Real Name, Comment and Email Address in this form:\n" " \"Heinrich Heine (Der Dichter) \"\n\n"); const char *s4 = _(s3); if (strcmp (s3, s4)) s2 = s3; /* A translation exists - use it. */ } tty_printf ("%s", s2) ; } uid = aname = acomment = amail = NULL; for(;;) { char *p; int fail=0; if( !aname ) { for(;;) { xfree(aname); aname = cpr_get("keygen.name",_("Real name: ")); trim_spaces(aname); cpr_kill_prompt(); if( opt.allow_freeform_uid ) break; if( strpbrk( aname, "<>" ) ) { tty_printf(_("Invalid character in name\n")); tty_printf(_("The characters '%s' and '%s' may not " "appear in name\n"), "<", ">"); } else if( digitp(aname) ) tty_printf(_("Name may not start with a digit\n")); else if (*aname && strlen (aname) < 5) { tty_printf(_("Name must be at least 5 characters long\n")); /* However, we allow an empty name. */ } else break; } } if( !amail ) { for(;;) { xfree(amail); amail = cpr_get("keygen.email",_("Email address: ")); trim_spaces(amail); cpr_kill_prompt(); if( !*amail || opt.allow_freeform_uid ) break; /* no email address is okay */ else if ( !is_valid_mailbox (amail) ) tty_printf(_("Not a valid email address\n")); else break; } } if (!acomment) { if (full) { for(;;) { xfree(acomment); acomment = cpr_get("keygen.comment",_("Comment: ")); trim_spaces(acomment); cpr_kill_prompt(); if( !*acomment ) break; /* no comment is okay */ else if( strpbrk( acomment, "()" ) ) tty_printf(_("Invalid character in comment\n")); else break; } } else { xfree (acomment); acomment = xstrdup (""); } } xfree(uid); uid = p = xmalloc(strlen(aname)+strlen(amail)+strlen(acomment)+12+10); if (!*aname && *amail && !*acomment && !random_is_faked ()) { /* Empty name and comment but with mail address. Use simplified form with only the non-angle-bracketed mail address. */ p = stpcpy (p, amail); } else { p = stpcpy (p, aname ); if (*acomment) p = stpcpy(stpcpy(stpcpy(p," ("), acomment),")"); if (*amail) p = stpcpy(stpcpy(stpcpy(p," <"), amail),">"); } /* Append a warning if the RNG is switched into fake mode. */ if ( random_is_faked () ) strcpy(p, " (insecure!)" ); /* print a note in case that UTF8 mapping has to be done */ for(p=uid; *p; p++ ) { if( *p & 0x80 ) { tty_printf(_("You are using the '%s' character set.\n"), get_native_charset() ); break; } } tty_printf(_("You selected this USER-ID:\n \"%s\"\n\n"), uid); if( !*amail && !opt.allow_freeform_uid && (strchr( aname, '@' ) || strchr( acomment, '@'))) { fail = 1; tty_printf(_("Please don't put the email address " "into the real name or the comment\n") ); } if (!fail && keyblock) { if (uid_already_in_keyblock (keyblock, uid)) { tty_printf (_("Such a user ID already exists on this key!\n")); fail = 1; } } for(;;) { /* TRANSLATORS: These are the allowed answers in lower and uppercase. Below you will find the matching string which should be translated accordingly and the letter changed to match the one in the answer string. n = Change name c = Change comment e = Change email o = Okay (ready, continue) q = Quit */ const char *ansstr = _("NnCcEeOoQq"); if( strlen(ansstr) != 10 ) BUG(); if( cpr_enabled() ) { answer = xstrdup (ansstr + (fail?8:6)); answer[1] = 0; } else if (full) { answer = cpr_get("keygen.userid.cmd", fail? _("Change (N)ame, (C)omment, (E)mail or (Q)uit? ") : _("Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? ")); cpr_kill_prompt(); } else { answer = cpr_get("keygen.userid.cmd", fail? _("Change (N)ame, (E)mail, or (Q)uit? ") : _("Change (N)ame, (E)mail, or (O)kay/(Q)uit? ")); cpr_kill_prompt(); } if( strlen(answer) > 1 ) ; else if( *answer == ansstr[0] || *answer == ansstr[1] ) { xfree(aname); aname = NULL; break; } else if( *answer == ansstr[2] || *answer == ansstr[3] ) { xfree(acomment); acomment = NULL; break; } else if( *answer == ansstr[4] || *answer == ansstr[5] ) { xfree(amail); amail = NULL; break; } else if( *answer == ansstr[6] || *answer == ansstr[7] ) { if( fail ) { tty_printf(_("Please correct the error first\n")); } else { xfree(aname); aname = NULL; xfree(acomment); acomment = NULL; xfree(amail); amail = NULL; break; } } else if( *answer == ansstr[8] || *answer == ansstr[9] ) { xfree(aname); aname = NULL; xfree(acomment); acomment = NULL; xfree(amail); amail = NULL; xfree(uid); uid = NULL; break; } xfree(answer); } xfree(answer); if (!amail && !acomment) break; xfree(uid); uid = NULL; } if( uid ) { char *p = native_to_utf8( uid ); xfree( uid ); uid = p; } return uid; } /* Basic key generation. Here we divert to the actual generation routines based on the requested algorithm. */ static int do_create (int algo, unsigned int nbits, const char *curve, kbnode_t pub_root, u32 timestamp, u32 expiredate, int is_subkey, int keygen_flags, const char *passphrase, char **cache_nonce_addr, char **passwd_nonce_addr) { gpg_error_t err; /* Fixme: The entropy collecting message should be moved to a libgcrypt progress handler. */ if (!opt.batch) tty_printf (_( "We need to generate a lot of random bytes. It is a good idea to perform\n" "some other action (type on the keyboard, move the mouse, utilize the\n" "disks) during the prime generation; this gives the random number\n" "generator a better chance to gain enough entropy.\n") ); if (algo == PUBKEY_ALGO_ELGAMAL_E) err = gen_elg (algo, nbits, pub_root, timestamp, expiredate, is_subkey, keygen_flags, passphrase, cache_nonce_addr, passwd_nonce_addr); else if (algo == PUBKEY_ALGO_DSA) err = gen_dsa (nbits, pub_root, timestamp, expiredate, is_subkey, keygen_flags, passphrase, cache_nonce_addr, passwd_nonce_addr); else if (algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_EDDSA || algo == PUBKEY_ALGO_ECDH) err = gen_ecc (algo, curve, pub_root, timestamp, expiredate, is_subkey, keygen_flags, passphrase, cache_nonce_addr, passwd_nonce_addr); else if (algo == PUBKEY_ALGO_RSA) err = gen_rsa (algo, nbits, pub_root, timestamp, expiredate, is_subkey, keygen_flags, passphrase, cache_nonce_addr, passwd_nonce_addr); else BUG(); return err; } /* Generate a new user id packet or return NULL if canceled. If KEYBLOCK is not NULL the function prevents the creation of an already existing user ID. If UIDSTR is not NULL the user is not asked but UIDSTR is used to create the user id packet; if the user id already exists NULL is returned. UIDSTR is expected to be utf-8 encoded and should have already been checked for a valid length etc. */ PKT_user_id * generate_user_id (KBNODE keyblock, const char *uidstr) { PKT_user_id *uid; char *p; if (uidstr) { if (uid_already_in_keyblock (keyblock, uidstr)) return NULL; /* Already exists. */ uid = uid_from_string (uidstr); } else { p = ask_user_id (1, 1, keyblock); if (!p) return NULL; /* Canceled. */ uid = uid_from_string (p); xfree (p); } return uid; } /* Helper for parse_key_parameter_part_parameter_string for one part of the * specification string; i.e. ALGO/FLAGS. If STRING is NULL or empty * success is returned. On error an error code is returned. Note * that STRING may be modified by this function. NULL may be passed * for any parameter. FOR_SUBKEY shall be true if this is used as a * subkey. If CLEAR_CERT is set a default CERT usage will be cleared; * this is useful if for example the default algorithm is used for a * subkey. If R_KEYVERSION is not NULL it will receive the version of * the key; this is currently 4 but can be changed with the flag "v5" * to create a v5 key. If R_KEYTIME is not NULL and the key has been * taken from active OpenPGP card, its creation time is stored * there. */ static gpg_error_t parse_key_parameter_part (ctrl_t ctrl, char *string, int for_subkey, int clear_cert, int *r_algo, unsigned int *r_size, unsigned int *r_keyuse, char const **r_curve, int *r_keyversion, char **r_keygrip, u32 *r_keytime) { gpg_error_t err; char *flags; int algo; char *endp; const char *curve = NULL; int ecdh_or_ecdsa = 0; unsigned int size; int keyuse; int keyversion = 4; int i; const char *s; int from_card = 0; char *keygrip = NULL; u32 keytime = 0; if (!string || !*string) return 0; /* Success. */ flags = strchr (string, '/'); if (flags) *flags++ = 0; algo = 0; if (!ascii_strcasecmp (string, "card")) from_card = 1; else if (strlen (string) >= 3 && (digitp (string+3) || !string[3])) { if (!ascii_memcasecmp (string, "rsa", 3)) algo = PUBKEY_ALGO_RSA; else if (!ascii_memcasecmp (string, "dsa", 3)) algo = PUBKEY_ALGO_DSA; else if (!ascii_memcasecmp (string, "elg", 3)) algo = PUBKEY_ALGO_ELGAMAL_E; } if (from_card) ; /* We need the flags before we can figure out the key to use. */ else if (algo) { if (!string[3]) size = get_keysize_range (algo, NULL, NULL); else { size = strtoul (string+3, &endp, 10); if (size < 512 || size > 16384 || *endp) return gpg_error (GPG_ERR_INV_VALUE); } } else if ((curve = openpgp_is_curve_supported (string, &algo, &size))) { if (!algo) { algo = PUBKEY_ALGO_ECDH; /* Default ECC algorithm. */ ecdh_or_ecdsa = 1; /* We may need to switch the algo. */ } } else return gpg_error (GPG_ERR_UNKNOWN_CURVE); /* Parse the flags. */ keyuse = 0; if (flags) { char **tokens = NULL; tokens = strtokenize (flags, ","); if (!tokens) return gpg_error_from_syserror (); for (i=0; (s = tokens[i]); i++) { if (!*s) ; else if (!ascii_strcasecmp (s, "sign")) keyuse |= PUBKEY_USAGE_SIG; else if (!ascii_strcasecmp (s, "encrypt") || !ascii_strcasecmp (s, "encr")) keyuse |= PUBKEY_USAGE_ENC; else if (!ascii_strcasecmp (s, "auth")) keyuse |= PUBKEY_USAGE_AUTH; else if (!ascii_strcasecmp (s, "cert")) keyuse |= PUBKEY_USAGE_CERT; else if (!ascii_strcasecmp (s, "ecdsa") && !from_card) { if (algo == PUBKEY_ALGO_ECDH || algo == PUBKEY_ALGO_ECDSA) algo = PUBKEY_ALGO_ECDSA; else { xfree (tokens); return gpg_error (GPG_ERR_INV_FLAG); } ecdh_or_ecdsa = 0; } else if (!ascii_strcasecmp (s, "ecdh") && !from_card) { if (algo == PUBKEY_ALGO_ECDH || algo == PUBKEY_ALGO_ECDSA) algo = PUBKEY_ALGO_ECDH; else { xfree (tokens); return gpg_error (GPG_ERR_INV_FLAG); } ecdh_or_ecdsa = 0; } else if (!ascii_strcasecmp (s, "eddsa") && !from_card) { /* Not required but we allow it for consistency. */ if (algo == PUBKEY_ALGO_EDDSA) ; else { xfree (tokens); return gpg_error (GPG_ERR_INV_FLAG); } } else if (!ascii_strcasecmp (s, "v5")) { if (opt.flags.rfc4880bis) keyversion = 5; } else if (!ascii_strcasecmp (s, "v4")) keyversion = 4; else { xfree (tokens); return gpg_error (GPG_ERR_UNKNOWN_FLAG); } } xfree (tokens); } /* If not yet decided switch between ecdh and ecdsa unless we want * to read the algo from the current card. */ if (from_card) { keypair_info_t keypairlist, kpi; char *reqkeyref; if (!keyuse) keyuse = (for_subkey? PUBKEY_USAGE_ENC /* */ : (PUBKEY_USAGE_CERT|PUBKEY_USAGE_SIG)); /* Access the card to make sure we have one and to show the S/N. */ { char *serialno; err = agent_scd_serialno (&serialno, NULL); if (err) { log_error (_("error reading the card: %s\n"), gpg_strerror (err)); return err; } if (!opt.quiet) log_info (_("Serial number of the card: %s\n"), serialno); xfree (serialno); } err = agent_scd_keypairinfo (ctrl, NULL, &keypairlist); if (err) { log_error (_("error reading the card: %s\n"), gpg_strerror (err)); return err; } agent_scd_getattr_one ((keyuse & (PUBKEY_USAGE_SIG|PUBKEY_USAGE_CERT)) ? "$SIGNKEYID":"$ENCRKEYID", &reqkeyref); algo = 0; /* Should already be the case. */ for (kpi=keypairlist; kpi && !algo; kpi = kpi->next) { gcry_sexp_t s_pkey; char *algostr = NULL; enum gcry_pk_algos algoid = 0; const char *keyref = kpi->idstr; if (!reqkeyref) continue; /* Card does not provide the info (skip all). */ if (!keyref) continue; /* Ooops. */ if (strcmp (reqkeyref, keyref)) continue; /* This is not the requested keyref. */ if ((keyuse & (PUBKEY_USAGE_SIG|PUBKEY_USAGE_CERT)) && (kpi->usage & (GCRY_PK_USAGE_SIGN|GCRY_PK_USAGE_CERT))) ; /* Okay */ else if ((keyuse & PUBKEY_USAGE_ENC) && (kpi->usage & GCRY_PK_USAGE_ENCR)) ; /* Okay */ else continue; /* Not usable for us. */ if (agent_scd_readkey (ctrl, keyref, &s_pkey, NULL)) continue; /* Could not read the key. */ algostr = pubkey_algo_string (s_pkey, &algoid); gcry_sexp_release (s_pkey); /* Map to OpenPGP algo number. * We need to tweak the algo in case GCRY_PK_ECC is * returned because pubkey_algo_string is not aware * of the OpenPGP algo mapping. We need to * distinguish between ECDH and ECDSA but we can do * that only if we got usage flags. * Note: Keep this in sync with ask_algo. */ if (algoid == GCRY_PK_ECC && algostr) { if (!strcmp (algostr, "ed25519")) algo = PUBKEY_ALGO_EDDSA; + else if (!strcmp (algostr, "ed448")) + kpi->algo = PUBKEY_ALGO_EDDSA; else if (!strcmp (algostr, "cv25519")) algo = PUBKEY_ALGO_ECDH; else if (!strcmp (algostr, "cv448")) algo = PUBKEY_ALGO_ECDH; else if ((kpi->usage & GCRY_PK_USAGE_ENCR)) algo = PUBKEY_ALGO_ECDH; else algo = PUBKEY_ALGO_ECDSA; } else algo = map_gcry_pk_to_openpgp (algoid); xfree (algostr); xfree (keygrip); keygrip = xtrystrdup (kpi->keygrip); if (!keygrip) { err = gpg_error_from_syserror (); xfree (reqkeyref); free_keypair_info (keypairlist); return err; } keytime = kpi->keytime; } xfree (reqkeyref); free_keypair_info (keypairlist); if (!algo || !keygrip) { err = gpg_error (GPG_ERR_PUBKEY_ALGO); log_error ("no usable key on the card: %s\n", gpg_strerror (err)); xfree (keygrip); return err; } } else if (ecdh_or_ecdsa && keyuse) algo = (keyuse & PUBKEY_USAGE_ENC)? PUBKEY_ALGO_ECDH : PUBKEY_ALGO_ECDSA; else if (ecdh_or_ecdsa) algo = for_subkey? PUBKEY_ALGO_ECDH : PUBKEY_ALGO_ECDSA; /* Set or fix key usage. */ if (!keyuse) { if (algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_EDDSA || algo == PUBKEY_ALGO_DSA) keyuse = PUBKEY_USAGE_SIG; else if (algo == PUBKEY_ALGO_RSA) keyuse = for_subkey? PUBKEY_USAGE_ENC : PUBKEY_USAGE_SIG; else keyuse = PUBKEY_USAGE_ENC; } else if (algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_EDDSA || algo == PUBKEY_ALGO_DSA) { keyuse &= ~PUBKEY_USAGE_ENC; /* Forbid encryption. */ } else if (algo == PUBKEY_ALGO_ECDH || algo == PUBKEY_ALGO_ELGAMAL_E) { keyuse = PUBKEY_USAGE_ENC; /* Allow only encryption. */ } /* Make sure a primary key can certify. */ if (!for_subkey) keyuse |= PUBKEY_USAGE_CERT; /* But if requested remove th cert usage. */ if (clear_cert) keyuse &= ~PUBKEY_USAGE_CERT; /* Check that usage is actually possible. */ if (/**/((keyuse & (PUBKEY_USAGE_SIG|PUBKEY_USAGE_AUTH|PUBKEY_USAGE_CERT)) && !pubkey_get_nsig (algo)) || ((keyuse & PUBKEY_USAGE_ENC) && !pubkey_get_nenc (algo)) || (for_subkey && (keyuse & PUBKEY_USAGE_CERT))) { xfree (keygrip); return gpg_error (GPG_ERR_WRONG_KEY_USAGE); } /* Return values. */ if (r_algo) *r_algo = algo; if (r_size) { unsigned int min, def, max; /* Make sure the keysize is in the allowed range. */ def = get_keysize_range (algo, &min, &max); if (!size) size = def; else if (size < min) size = min; else if (size > max) size = max; *r_size = fixup_keysize (size, algo, 1); } if (r_keyuse) *r_keyuse = keyuse; if (r_curve) *r_curve = curve; if (r_keyversion) *r_keyversion = keyversion; if (r_keygrip) *r_keygrip = keygrip; else xfree (keygrip); if (r_keytime) *r_keytime = keytime; return 0; } /* Parse and return the standard key generation parameter. * The string is expected to be in this format: * * ALGO[/FLAGS][+SUBALGO[/FLAGS]] * * Here ALGO is a string in the same format as printed by the * keylisting. For example: * * rsa3072 := RSA with 3072 bit. * dsa2048 := DSA with 2048 bit. * elg2048 := Elgamal with 2048 bit. * ed25519 := EDDSA using curve Ed25519. + * ed448 := EDDSA using curve Ed448. * cv25519 := ECDH using curve Curve25519. * cv448 := ECDH using curve X448. * nistp256:= ECDSA or ECDH using curve NIST P-256 * * All strings with an unknown prefix are considered an elliptic * curve. Curves which have no implicit algorithm require that FLAGS * is given to select whether ECDSA or ECDH is used; this can either * be done using an algorithm keyword or usage keywords. * * FLAGS is a comma delimited string of keywords: * * cert := Allow usage Certify * sign := Allow usage Sign * encr := Allow usage Encrypt * auth := Allow usage Authentication * encrypt := Alias for "encr" * ecdsa := Use algorithm ECDSA. * eddsa := Use algorithm EdDSA. * ecdh := Use algorithm ECDH. * v5 := Create version 5 key (requires option --rfc4880bis) * * There are several defaults and fallbacks depending on the * algorithm. PART can be used to select which part of STRING is * used: * -1 := Both parts * 0 := Only the part of the primary key * 1 := If there is one part parse that one, if there are * two parts parse the part which best matches the * SUGGESTED_USE or in case that can't be evaluated the second part. * Always return using the args for the primary key (R_ALGO,....). * */ gpg_error_t parse_key_parameter_string (ctrl_t ctrl, const char *string, int part, unsigned int suggested_use, int *r_algo, unsigned int *r_size, unsigned int *r_keyuse, char const **r_curve, int *r_version, char **r_keygrip, u32 *r_keytime, int *r_subalgo, unsigned int *r_subsize, unsigned int *r_subkeyuse, char const **r_subcurve, int *r_subversion, char **r_subkeygrip, u32 *r_subkeytime) { gpg_error_t err = 0; char *primary, *secondary; if (r_algo) *r_algo = 0; if (r_size) *r_size = 0; if (r_keyuse) *r_keyuse = 0; if (r_curve) *r_curve = NULL; if (r_version) *r_version = 4; if (r_keygrip) *r_keygrip = NULL; if (r_keytime) *r_keytime = 0; if (r_subalgo) *r_subalgo = 0; if (r_subsize) *r_subsize = 0; if (r_subkeyuse) *r_subkeyuse = 0; if (r_subcurve) *r_subcurve = NULL; if (r_subversion) *r_subversion = 4; if (r_subkeygrip) *r_subkeygrip = NULL; if (r_subkeytime) *r_subkeytime = 0; if (!string || !*string || !ascii_strcasecmp (string, "default") || !strcmp (string, "-")) string = get_default_pubkey_algo (); else if (!ascii_strcasecmp (string, "future-default") || !ascii_strcasecmp (string, "futuredefault")) string = FUTURE_STD_KEY_PARAM; else if (!ascii_strcasecmp (string, "card")) string = "card/cert,sign+card/encr"; primary = xstrdup (string); secondary = strchr (primary, '+'); if (secondary) *secondary++ = 0; if (part == -1 || part == 0) { err = parse_key_parameter_part (ctrl, primary, 0, 0, r_algo, r_size, r_keyuse, r_curve, r_version, r_keygrip, r_keytime); if (!err && part == -1) err = parse_key_parameter_part (ctrl, secondary, 1, 0, r_subalgo, r_subsize, r_subkeyuse, r_subcurve, r_subversion, r_subkeygrip, r_subkeytime); } else if (part == 1) { /* If we have SECONDARY, use that part. If there is only one * part consider this to be the subkey algo. In case a * SUGGESTED_USE has been given and the usage of the secondary * part does not match SUGGESTED_USE try again using the primary * part. Note that when falling back to the primary key we need * to force clearing the cert usage. */ if (secondary) { err = parse_key_parameter_part (ctrl, secondary, 1, 0, r_algo, r_size, r_keyuse, r_curve, r_version, r_keygrip, r_keytime); if (!err && suggested_use && r_keyuse && !(suggested_use & *r_keyuse)) err = parse_key_parameter_part (ctrl, primary, 1, 1 /*(clear cert)*/, r_algo, r_size, r_keyuse, r_curve, r_version, r_keygrip, r_keytime); } else err = parse_key_parameter_part (ctrl, primary, 1, 0, r_algo, r_size, r_keyuse, r_curve, r_version, r_keygrip, r_keytime); } xfree (primary); return err; } /* Append R to the linked list PARA. */ static void append_to_parameter (struct para_data_s *para, struct para_data_s *r) { log_assert (para); while (para->next) para = para->next; para->next = r; } /* Release the parameter list R. */ static void release_parameter_list (struct para_data_s *r) { struct para_data_s *r2; for (; r ; r = r2) { r2 = r->next; if (r->key == pPASSPHRASE && *r->u.value) wipememory (r->u.value, strlen (r->u.value)); xfree (r); } } static struct para_data_s * get_parameter( struct para_data_s *para, enum para_name key ) { struct para_data_s *r; for( r = para; r && r->key != key; r = r->next ) ; return r; } static const char * get_parameter_value( struct para_data_s *para, enum para_name key ) { struct para_data_s *r = get_parameter( para, key ); return (r && *r->u.value)? r->u.value : NULL; } /* This is similar to get_parameter_value but also returns the empty string. This is required so that quick_generate_keypair can use an empty Passphrase to specify no-protection. */ static const char * get_parameter_passphrase (struct para_data_s *para) { struct para_data_s *r = get_parameter (para, pPASSPHRASE); return r ? r->u.value : NULL; } static int get_parameter_algo (ctrl_t ctrl, struct para_data_s *para, enum para_name key, int *r_default) { int i; struct para_data_s *r = get_parameter( para, key ); if (r_default) *r_default = 0; if (!r) return -1; /* Note that we need to handle the ECC algorithms specified as strings directly because Libgcrypt folds them all to ECC. */ if (!ascii_strcasecmp (r->u.value, "default")) { /* Note: If you change this default algo, remember to change it * also in gpg.c:gpgconf_list. */ /* FIXME: We only allow the algo here and have a separate thing * for the curve etc. That is a ugly but demanded for backward * compatibility with the batch key generation. It would be * better to make full use of parse_key_parameter_string. */ parse_key_parameter_string (ctrl, NULL, 0, 0, &i, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); if (r_default) *r_default = 1; } else if (digitp (r->u.value)) i = atoi( r->u.value ); else if (!strcmp (r->u.value, "ELG-E") || !strcmp (r->u.value, "ELG")) i = PUBKEY_ALGO_ELGAMAL_E; else if (!ascii_strcasecmp (r->u.value, "EdDSA")) i = PUBKEY_ALGO_EDDSA; else if (!ascii_strcasecmp (r->u.value, "ECDSA")) i = PUBKEY_ALGO_ECDSA; else if (!ascii_strcasecmp (r->u.value, "ECDH")) i = PUBKEY_ALGO_ECDH; else i = map_gcry_pk_to_openpgp (gcry_pk_map_name (r->u.value)); if (i == PUBKEY_ALGO_RSA_E || i == PUBKEY_ALGO_RSA_S) i = 0; /* we don't want to allow generation of these algorithms */ return i; } /* Parse a usage string. The usage keywords "auth", "sign", "encr" * may be delimited by space, tab, or comma. On error -1 is returned * instead of the usage flags. */ static int parse_usagestr (const char *usagestr) { gpg_error_t err; char **tokens = NULL; const char *s; int i; unsigned int use = 0; tokens = strtokenize (usagestr, " \t,"); if (!tokens) { err = gpg_error_from_syserror (); log_error ("strtokenize failed: %s\n", gpg_strerror (err)); return -1; } for (i=0; (s = tokens[i]); i++) { if (!*s) ; else if (!ascii_strcasecmp (s, "sign")) use |= PUBKEY_USAGE_SIG; else if (!ascii_strcasecmp (s, "encrypt") || !ascii_strcasecmp (s, "encr")) use |= PUBKEY_USAGE_ENC; else if (!ascii_strcasecmp (s, "auth")) use |= PUBKEY_USAGE_AUTH; else if (!ascii_strcasecmp (s, "cert")) use |= PUBKEY_USAGE_CERT; else { xfree (tokens); return -1; /* error */ } } xfree (tokens); return use; } /* * Parse the usage parameter and set the keyflags. Returns -1 on * error, 0 for no usage given or 1 for usage available. */ static int parse_parameter_usage (const char *fname, struct para_data_s *para, enum para_name key) { struct para_data_s *r = get_parameter( para, key ); int i; if (!r) return 0; /* none (this is an optional parameter)*/ i = parse_usagestr (r->u.value); if (i == -1) { log_error ("%s:%d: invalid usage list\n", fname, r->lnr ); return -1; /* error */ } r->u.usage = i; return 1; } static int parse_revocation_key (const char *fname, struct para_data_s *para, enum para_name key) { struct para_data_s *r = get_parameter( para, key ); struct revocation_key revkey; char *pn; int i; if( !r ) return 0; /* none (this is an optional parameter) */ pn = r->u.value; revkey.class=0x80; revkey.algid=atoi(pn); if(!revkey.algid) goto fail; /* Skip to the fpr */ while(*pn && *pn!=':') pn++; if(*pn!=':') goto fail; pn++; for(i=0;iu.revkey,&revkey,sizeof(struct revocation_key)); return 0; fail: log_error("%s:%d: invalid revocation key\n", fname, r->lnr ); return -1; /* error */ } static u32 get_parameter_u32( struct para_data_s *para, enum para_name key ) { struct para_data_s *r = get_parameter( para, key ); if( !r ) return 0; if (r->key == pKEYCREATIONDATE || r->key == pSUBKEYCREATIONDATE || r->key == pAUTHKEYCREATIONDATE) return r->u.creation; if( r->key == pKEYEXPIRE || r->key == pSUBKEYEXPIRE ) return r->u.expire; if( r->key == pKEYUSAGE || r->key == pSUBKEYUSAGE ) return r->u.usage; return (unsigned int)strtoul( r->u.value, NULL, 10 ); } static unsigned int get_parameter_uint( struct para_data_s *para, enum para_name key ) { return get_parameter_u32( para, key ); } static struct revocation_key * get_parameter_revkey( struct para_data_s *para, enum para_name key ) { struct para_data_s *r = get_parameter( para, key ); return r? &r->u.revkey : NULL; } static int get_parameter_bool (struct para_data_s *para, enum para_name key) { struct para_data_s *r = get_parameter (para, key); return (r && r->u.abool); } static int proc_parameter_file (ctrl_t ctrl, struct para_data_s *para, const char *fname, struct output_control_s *outctrl, int card ) { struct para_data_s *r; const char *s1, *s2, *s3; size_t n; char *p; int is_default = 0; int have_user_id = 0; int err, algo; /* Check that we have all required parameters. */ r = get_parameter( para, pKEYTYPE ); if(r) { algo = get_parameter_algo (ctrl, para, pKEYTYPE, &is_default); if (openpgp_pk_test_algo2 (algo, PUBKEY_USAGE_SIG)) { log_error ("%s:%d: invalid algorithm\n", fname, r->lnr ); return -1; } } else { log_error ("%s: no Key-Type specified\n",fname); return -1; } err = parse_parameter_usage (fname, para, pKEYUSAGE); if (!err) { /* Default to algo capabilities if key-usage is not provided and no default algorithm has been requested. */ r = xmalloc_clear(sizeof(*r)); r->key = pKEYUSAGE; r->u.usage = (is_default ? (PUBKEY_USAGE_CERT | PUBKEY_USAGE_SIG) : openpgp_pk_algo_usage(algo)); append_to_parameter (para, r); } else if (err == -1) return -1; else { r = get_parameter (para, pKEYUSAGE); if (r && (r->u.usage & ~openpgp_pk_algo_usage (algo))) { log_error ("%s:%d: specified Key-Usage not allowed for algo %d\n", fname, r->lnr, algo); return -1; } } is_default = 0; r = get_parameter( para, pSUBKEYTYPE ); if(r) { algo = get_parameter_algo (ctrl, para, pSUBKEYTYPE, &is_default); if (openpgp_pk_test_algo (algo)) { log_error ("%s:%d: invalid algorithm\n", fname, r->lnr ); return -1; } err = parse_parameter_usage (fname, para, pSUBKEYUSAGE); if (!err) { /* Default to algo capabilities if subkey-usage is not provided */ r = xmalloc_clear (sizeof(*r)); r->key = pSUBKEYUSAGE; r->u.usage = (is_default ? PUBKEY_USAGE_ENC : openpgp_pk_algo_usage (algo)); append_to_parameter (para, r); } else if (err == -1) return -1; else { r = get_parameter (para, pSUBKEYUSAGE); if (r && (r->u.usage & ~openpgp_pk_algo_usage (algo))) { log_error ("%s:%d: specified Subkey-Usage not allowed" " for algo %d\n", fname, r->lnr, algo); return -1; } } } if( get_parameter_value( para, pUSERID ) ) have_user_id=1; else { /* create the formatted user ID */ s1 = get_parameter_value( para, pNAMEREAL ); s2 = get_parameter_value( para, pNAMECOMMENT ); s3 = get_parameter_value( para, pNAMEEMAIL ); if( s1 || s2 || s3 ) { n = (s1?strlen(s1):0) + (s2?strlen(s2):0) + (s3?strlen(s3):0); r = xmalloc_clear( sizeof *r + n + 20 ); r->key = pUSERID; p = r->u.value; if( s1 ) p = stpcpy(p, s1 ); if( s2 ) p = stpcpy(stpcpy(stpcpy(p," ("), s2 ),")"); if( s3 ) { /* If we have only the email part, do not add the space * and the angle brackets. */ if (*r->u.value) p = stpcpy(stpcpy(stpcpy(p," <"), s3 ),">"); else p = stpcpy (p, s3); } append_to_parameter (para, r); have_user_id=1; } } if(!have_user_id) { log_error("%s: no User-ID specified\n",fname); return -1; } /* Set preferences, if any. */ keygen_set_std_prefs(get_parameter_value( para, pPREFERENCES ), 0); /* Set keyserver, if any. */ s1=get_parameter_value( para, pKEYSERVER ); if(s1) { struct keyserver_spec *spec; spec = parse_keyserver_uri (s1, 1); if(spec) { free_keyserver_spec(spec); opt.def_keyserver_url=s1; } else { r = get_parameter (para, pKEYSERVER); log_error("%s:%d: invalid keyserver url\n", fname, r->lnr ); return -1; } } /* Set revoker, if any. */ if (parse_revocation_key (fname, para, pREVOKER)) return -1; /* Make KEYCREATIONDATE from Creation-Date. We ignore this if the * key has been taken from a card and a keycreationtime has already * been set. This is so that we don't generate a key with a * fingerprint different from the one stored on the OpenPGP card. */ r = get_parameter (para, pCREATIONDATE); if (r && *r->u.value && !(get_parameter_bool (para, pCARDKEY) && get_parameter_u32 (para, pKEYCREATIONDATE))) { u32 seconds; seconds = parse_creation_string (r->u.value); if (!seconds) { log_error ("%s:%d: invalid creation date\n", fname, r->lnr ); return -1; } r->u.creation = seconds; r->key = pKEYCREATIONDATE; /* Change that entry. */ } /* Make KEYEXPIRE from Expire-Date. */ r = get_parameter( para, pEXPIREDATE ); if( r && *r->u.value ) { u32 seconds; seconds = parse_expire_string( r->u.value ); if( seconds == (u32)-1 ) { log_error("%s:%d: invalid expire date\n", fname, r->lnr ); return -1; } r->u.expire = seconds; r->key = pKEYEXPIRE; /* change hat entry */ /* also set it for the subkey */ r = xmalloc_clear( sizeof *r + 20 ); r->key = pSUBKEYEXPIRE; r->u.expire = seconds; append_to_parameter (para, r); } do_generate_keypair (ctrl, para, outctrl, card ); return 0; } /**************** * Kludge to allow non interactive key generation controlled * by a parameter file. * Note, that string parameters are expected to be in UTF-8 */ static void read_parameter_file (ctrl_t ctrl, const char *fname ) { static struct { const char *name; enum para_name key; } keywords[] = { { "Key-Type", pKEYTYPE}, { "Key-Length", pKEYLENGTH }, { "Key-Curve", pKEYCURVE }, { "Key-Usage", pKEYUSAGE }, { "Subkey-Type", pSUBKEYTYPE }, { "Subkey-Length", pSUBKEYLENGTH }, { "Subkey-Curve", pSUBKEYCURVE }, { "Subkey-Usage", pSUBKEYUSAGE }, { "Name-Real", pNAMEREAL }, { "Name-Email", pNAMEEMAIL }, { "Name-Comment", pNAMECOMMENT }, { "Expire-Date", pEXPIREDATE }, { "Creation-Date", pCREATIONDATE }, { "Passphrase", pPASSPHRASE }, { "Preferences", pPREFERENCES }, { "Revoker", pREVOKER }, { "Handle", pHANDLE }, { "Keyserver", pKEYSERVER }, { "Keygrip", pKEYGRIP }, { "Key-Grip", pKEYGRIP }, { "Subkey-grip", pSUBKEYGRIP }, { "Key-Version", pVERSION }, { "Subkey-Version", pSUBVERSION }, { NULL, 0 } }; IOBUF fp; byte *line; unsigned int maxlen, nline; char *p; int lnr; const char *err = NULL; struct para_data_s *para, *r; int i; struct output_control_s outctrl; memset( &outctrl, 0, sizeof( outctrl ) ); outctrl.pub.afx = new_armor_context (); if( !fname || !*fname) fname = "-"; fp = iobuf_open (fname); if (fp && is_secured_file (iobuf_get_fd (fp))) { iobuf_close (fp); fp = NULL; gpg_err_set_errno (EPERM); } if (!fp) { log_error (_("can't open '%s': %s\n"), fname, strerror(errno) ); return; } iobuf_ioctl (fp, IOBUF_IOCTL_NO_CACHE, 1, NULL); lnr = 0; err = NULL; para = NULL; maxlen = 1024; line = NULL; while ( iobuf_read_line (fp, &line, &nline, &maxlen) ) { char *keyword, *value; lnr++; if( !maxlen ) { err = "line too long"; break; } for( p = line; isspace(*(byte*)p); p++ ) ; if( !*p || *p == '#' ) continue; keyword = p; if( *keyword == '%' ) { for( ; !isspace(*(byte*)p); p++ ) ; if( *p ) *p++ = 0; for( ; isspace(*(byte*)p); p++ ) ; value = p; trim_trailing_ws( value, strlen(value) ); if( !ascii_strcasecmp( keyword, "%echo" ) ) log_info("%s\n", value ); else if( !ascii_strcasecmp( keyword, "%dry-run" ) ) outctrl.dryrun = 1; else if( !ascii_strcasecmp( keyword, "%ask-passphrase" ) ) ; /* Dummy for backward compatibility. */ else if( !ascii_strcasecmp( keyword, "%no-ask-passphrase" ) ) ; /* Dummy for backward compatibility. */ else if( !ascii_strcasecmp( keyword, "%no-protection" ) ) outctrl.keygen_flags |= KEYGEN_FLAG_NO_PROTECTION; else if( !ascii_strcasecmp( keyword, "%transient-key" ) ) outctrl.keygen_flags |= KEYGEN_FLAG_TRANSIENT_KEY; else if( !ascii_strcasecmp( keyword, "%commit" ) ) { outctrl.lnr = lnr; if (proc_parameter_file (ctrl, para, fname, &outctrl, 0 )) print_status_key_not_created (get_parameter_value (para, pHANDLE)); release_parameter_list( para ); para = NULL; } else if( !ascii_strcasecmp( keyword, "%pubring" ) ) { if( outctrl.pub.fname && !strcmp( outctrl.pub.fname, value ) ) ; /* still the same file - ignore it */ else { xfree( outctrl.pub.newfname ); outctrl.pub.newfname = xstrdup( value ); outctrl.use_files = 1; } } else if( !ascii_strcasecmp( keyword, "%secring" ) ) { /* Ignore this command. */ } else log_info("skipping control '%s' (%s)\n", keyword, value ); continue; } if( !(p = strchr( p, ':' )) || p == keyword ) { err = "missing colon"; break; } if( *p ) *p++ = 0; for( ; isspace(*(byte*)p); p++ ) ; if( !*p ) { err = "missing argument"; break; } value = p; trim_trailing_ws( value, strlen(value) ); for(i=0; keywords[i].name; i++ ) { if( !ascii_strcasecmp( keywords[i].name, keyword ) ) break; } if( !keywords[i].name ) { err = "unknown keyword"; break; } if( keywords[i].key != pKEYTYPE && !para ) { err = "parameter block does not start with \"Key-Type\""; break; } if( keywords[i].key == pKEYTYPE && para ) { outctrl.lnr = lnr; if (proc_parameter_file (ctrl, para, fname, &outctrl, 0 )) print_status_key_not_created (get_parameter_value (para, pHANDLE)); release_parameter_list( para ); para = NULL; } else { for( r = para; r; r = r->next ) { if( r->key == keywords[i].key ) break; } if( r ) { err = "duplicate keyword"; break; } } if (!opt.flags.rfc4880bis && (keywords[i].key == pVERSION || keywords[i].key == pSUBVERSION)) ; /* Ignore version unless --rfc4880bis is active. */ else { r = xmalloc_clear( sizeof *r + strlen( value ) ); r->lnr = lnr; r->key = keywords[i].key; strcpy( r->u.value, value ); r->next = para; para = r; } } if( err ) log_error("%s:%d: %s\n", fname, lnr, err ); else if( iobuf_error (fp) ) { log_error("%s:%d: read error\n", fname, lnr); } else if( para ) { outctrl.lnr = lnr; if (proc_parameter_file (ctrl, para, fname, &outctrl, 0 )) print_status_key_not_created (get_parameter_value (para, pHANDLE)); } if( outctrl.use_files ) { /* close open streams */ iobuf_close( outctrl.pub.stream ); /* Must invalidate that ugly cache to actually close it. */ if (outctrl.pub.fname) iobuf_ioctl (NULL, IOBUF_IOCTL_INVALIDATE_CACHE, 0, (char*)outctrl.pub.fname); xfree( outctrl.pub.fname ); xfree( outctrl.pub.newfname ); } xfree (line); release_parameter_list( para ); iobuf_close (fp); release_armor_context (outctrl.pub.afx); } /* Helper for quick_generate_keypair. */ static struct para_data_s * quickgen_set_para (struct para_data_s *para, int for_subkey, int algo, int nbits, const char *curve, unsigned int use, int version, const char *keygrip, u32 keytime) { struct para_data_s *r; r = xmalloc_clear (sizeof *r + 30); r->key = for_subkey? pSUBKEYUSAGE : pKEYUSAGE; if (use) snprintf (r->u.value, 30, "%s%s%s%s", (use & PUBKEY_USAGE_ENC)? "encr " : "", (use & PUBKEY_USAGE_SIG)? "sign " : "", (use & PUBKEY_USAGE_AUTH)? "auth " : "", (use & PUBKEY_USAGE_CERT)? "cert " : ""); else strcpy (r->u.value, for_subkey ? "encr" : "sign"); r->next = para; para = r; r = xmalloc_clear (sizeof *r + 20); r->key = for_subkey? pSUBKEYTYPE : pKEYTYPE; snprintf (r->u.value, 20, "%d", algo); r->next = para; para = r; if (keygrip) { r = xmalloc_clear (sizeof *r + strlen (keygrip)); r->key = for_subkey? pSUBKEYGRIP : pKEYGRIP; strcpy (r->u.value, keygrip); r->next = para; para = r; } else if (curve) { r = xmalloc_clear (sizeof *r + strlen (curve)); r->key = for_subkey? pSUBKEYCURVE : pKEYCURVE; strcpy (r->u.value, curve); r->next = para; para = r; } else { r = xmalloc_clear (sizeof *r + 20); r->key = for_subkey? pSUBKEYLENGTH : pKEYLENGTH; sprintf (r->u.value, "%u", nbits); r->next = para; para = r; } if (opt.flags.rfc4880bis) { r = xmalloc_clear (sizeof *r + 20); r->key = for_subkey? pSUBVERSION : pVERSION; snprintf (r->u.value, 20, "%d", version); r->next = para; para = r; } if (keytime) { r = xmalloc_clear (sizeof *r); r->key = for_subkey? pSUBKEYCREATIONDATE : pKEYCREATIONDATE; r->u.creation = keytime; r->next = para; para = r; } return para; } /* * Unattended generation of a standard key. */ void quick_generate_keypair (ctrl_t ctrl, const char *uid, const char *algostr, const char *usagestr, const char *expirestr) { gpg_error_t err; struct para_data_s *para = NULL; struct para_data_s *r; struct output_control_s outctrl; int use_tty; u32 keytime = 0; memset (&outctrl, 0, sizeof outctrl); use_tty = (!opt.batch && !opt.answer_yes && !*algostr && !*usagestr && !*expirestr && !cpr_enabled () && gnupg_isatty (fileno (stdin)) && gnupg_isatty (fileno (stdout)) && gnupg_isatty (fileno (stderr))); r = xmalloc_clear (sizeof *r + strlen (uid)); r->key = pUSERID; strcpy (r->u.value, uid); r->next = para; para = r; uid = trim_spaces (r->u.value); if (!*uid || (!opt.allow_freeform_uid && !is_valid_user_id (uid))) { log_error (_("Key generation failed: %s\n"), gpg_strerror (GPG_ERR_INV_USER_ID)); goto leave; } /* If gpg is directly used on the console ask whether a key with the given user id shall really be created. */ if (use_tty) { tty_printf (_("About to create a key for:\n \"%s\"\n\n"), uid); if (!cpr_get_answer_is_yes_def ("quick_keygen.okay", _("Continue? (Y/n) "), 1)) goto leave; } /* Check whether such a user ID already exists. */ { KEYDB_HANDLE kdbhd; KEYDB_SEARCH_DESC desc; memset (&desc, 0, sizeof desc); desc.mode = KEYDB_SEARCH_MODE_EXACT; desc.u.name = uid; kdbhd = keydb_new (ctrl); if (!kdbhd) goto leave; err = keydb_search (kdbhd, &desc, 1, NULL); keydb_release (kdbhd); if (gpg_err_code (err) != GPG_ERR_NOT_FOUND) { log_info (_("A key for \"%s\" already exists\n"), uid); if (opt.answer_yes) ; else if (!use_tty || !cpr_get_answer_is_yes_def ("quick_keygen.force", _("Create anyway? (y/N) "), 0)) { write_status_error ("genkey", gpg_error (304)); log_inc_errorcount (); /* we used log_info */ goto leave; } log_info (_("creating anyway\n")); } } if (!*expirestr || strcmp (expirestr, "-") == 0) expirestr = default_expiration_interval; if ((!*algostr || !ascii_strcasecmp (algostr, "default") || !ascii_strcasecmp (algostr, "future-default") || !ascii_strcasecmp (algostr, "futuredefault") || !ascii_strcasecmp (algostr, "card")) && (!*usagestr || !ascii_strcasecmp (usagestr, "default") || !strcmp (usagestr, "-"))) { /* Use default key parameters. */ int algo, subalgo, version, subversion; unsigned int size, subsize; unsigned int keyuse, subkeyuse; const char *curve, *subcurve; char *keygrip, *subkeygrip; u32 subkeytime; err = parse_key_parameter_string (ctrl, algostr, -1, 0, &algo, &size, &keyuse, &curve, &version, &keygrip, &keytime, &subalgo, &subsize, &subkeyuse, &subcurve, &subversion, &subkeygrip, &subkeytime); if (err) { log_error (_("Key generation failed: %s\n"), gpg_strerror (err)); goto leave; } para = quickgen_set_para (para, 0, algo, size, curve, keyuse, version, keygrip, keytime); if (subalgo) para = quickgen_set_para (para, 1, subalgo, subsize, subcurve, subkeyuse, subversion, subkeygrip, subkeytime); if (*expirestr) { u32 expire; expire = parse_expire_string (expirestr); if (expire == (u32)-1 ) { err = gpg_error (GPG_ERR_INV_VALUE); log_error (_("Key generation failed: %s\n"), gpg_strerror (err)); goto leave; } r = xmalloc_clear (sizeof *r + 20); r->key = pKEYEXPIRE; r->u.expire = expire; r->next = para; para = r; } xfree (keygrip); xfree (subkeygrip); } else { /* Extended unattended mode. Creates only the primary key. */ int algo, version; unsigned int use; u32 expire; unsigned int nbits; const char *curve; char *keygrip; err = parse_algo_usage_expire (ctrl, 0, algostr, usagestr, expirestr, &algo, &use, &expire, &nbits, &curve, &version, &keygrip, &keytime); if (err) { log_error (_("Key generation failed: %s\n"), gpg_strerror (err) ); goto leave; } para = quickgen_set_para (para, 0, algo, nbits, curve, use, version, keygrip, keytime); r = xmalloc_clear (sizeof *r + 20); r->key = pKEYEXPIRE; r->u.expire = expire; r->next = para; para = r; xfree (keygrip); } /* If the pinentry loopback mode is not and we have a static passphrase (i.e. set with --passphrase{,-fd,-file} while in batch mode), we use that passphrase for the new key. */ if (opt.pinentry_mode != PINENTRY_MODE_LOOPBACK && have_static_passphrase ()) { const char *s = get_static_passphrase (); r = xmalloc_clear (sizeof *r + strlen (s)); r->key = pPASSPHRASE; strcpy (r->u.value, s); r->next = para; para = r; } /* If KEYTIME is set we know that the key has been taken from the * card. Store that flag in the parameters. */ if (keytime) { r = xmalloc_clear (sizeof *r); r->key = pCARDKEY; r->u.abool = 1; r->next = para; para = r; } proc_parameter_file (ctrl, para, "[internal]", &outctrl, 0); leave: release_parameter_list (para); } /* * Generate a keypair (fname is only used in batch mode) If * CARD_SERIALNO is not NULL the function will create the keys on an * OpenPGP Card. If CARD_BACKUP_KEY has been set and CARD_SERIALNO is * NOT NULL, the encryption key for the card is generated on the host, * imported to the card and a backup file created by gpg-agent. If * FULL is not set only the basic prompts are used (except for batch * mode). */ void generate_keypair (ctrl_t ctrl, int full, const char *fname, const char *card_serialno, int card_backup_key) { gpg_error_t err; unsigned int nbits; char *uid = NULL; int algo; unsigned int use; int both = 0; u32 expire; struct para_data_s *para = NULL; struct para_data_s *r; struct output_control_s outctrl; #ifndef ENABLE_CARD_SUPPORT (void)card_backup_key; #endif memset( &outctrl, 0, sizeof( outctrl ) ); if (opt.batch && card_serialno) { /* We don't yet support unattended key generation with a card * serial number. */ log_error (_("can't do this in batch mode\n")); print_further_info ("key generation with card serial number"); return; } if (opt.batch) { read_parameter_file (ctrl, fname); return; } if (card_serialno) { #ifdef ENABLE_CARD_SUPPORT struct agent_card_info_s info; memset (&info, 0, sizeof (info)); err = agent_scd_getattr ("KEY-ATTR", &info); if (err) { log_error (_("error getting current key info: %s\n"), gpg_strerror (err)); return; } r = xcalloc (1, sizeof *r + strlen (card_serialno) ); r->key = pSERIALNO; strcpy( r->u.value, card_serialno); r->next = para; para = r; r = xcalloc (1, sizeof *r + 20 ); r->key = pKEYTYPE; sprintf( r->u.value, "%d", info.key_attr[0].algo ); r->next = para; para = r; r = xcalloc (1, sizeof *r + 20 ); r->key = pKEYUSAGE; strcpy (r->u.value, "sign"); r->next = para; para = r; r = xcalloc (1, sizeof *r + 20 ); r->key = pSUBKEYTYPE; sprintf( r->u.value, "%d", info.key_attr[1].algo ); r->next = para; para = r; r = xcalloc (1, sizeof *r + 20 ); r->key = pSUBKEYUSAGE; strcpy (r->u.value, "encrypt"); r->next = para; para = r; if (info.key_attr[1].algo == PUBKEY_ALGO_RSA) { r = xcalloc (1, sizeof *r + 20 ); r->key = pSUBKEYLENGTH; sprintf( r->u.value, "%u", info.key_attr[1].nbits); r->next = para; para = r; } else if (info.key_attr[1].algo == PUBKEY_ALGO_ECDSA || info.key_attr[1].algo == PUBKEY_ALGO_EDDSA || info.key_attr[1].algo == PUBKEY_ALGO_ECDH) { r = xcalloc (1, sizeof *r + strlen (info.key_attr[1].curve)); r->key = pSUBKEYCURVE; strcpy (r->u.value, info.key_attr[1].curve); r->next = para; para = r; } r = xcalloc (1, sizeof *r + 20 ); r->key = pAUTHKEYTYPE; sprintf( r->u.value, "%d", info.key_attr[2].algo ); r->next = para; para = r; if (card_backup_key) { r = xcalloc (1, sizeof *r + 1); r->key = pCARDBACKUPKEY; strcpy (r->u.value, "1"); r->next = para; para = r; } #endif /*ENABLE_CARD_SUPPORT*/ } else if (full) /* Full featured key generation. */ { int subkey_algo; char *key_from_hexgrip = NULL; int cardkey; u32 keytime; algo = ask_algo (ctrl, 0, &subkey_algo, &use, &key_from_hexgrip, &cardkey, &keytime); if (key_from_hexgrip) { r = xmalloc_clear( sizeof *r + 20 ); r->key = pKEYTYPE; sprintf( r->u.value, "%d", algo); r->next = para; para = r; if (use) { r = xmalloc_clear( sizeof *r + 25 ); r->key = pKEYUSAGE; sprintf( r->u.value, "%s%s%s", (use & PUBKEY_USAGE_SIG)? "sign ":"", (use & PUBKEY_USAGE_ENC)? "encrypt ":"", (use & PUBKEY_USAGE_AUTH)? "auth":"" ); r->next = para; para = r; } r = xmalloc_clear( sizeof *r + 40 ); r->key = pKEYGRIP; strcpy (r->u.value, key_from_hexgrip); r->next = para; para = r; r = xmalloc_clear (sizeof *r); r->key = pCARDKEY; r->u.abool = cardkey; r->next = para; para = r; if (cardkey) { r = xmalloc_clear (sizeof *r); r->key = pKEYCREATIONDATE; r->u.creation = keytime; r->next = para; para = r; } xfree (key_from_hexgrip); } else { const char *curve = NULL; if (subkey_algo) { /* Create primary and subkey at once. */ both = 1; if (algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_EDDSA || algo == PUBKEY_ALGO_ECDH) { curve = ask_curve (&algo, &subkey_algo, NULL); r = xmalloc_clear( sizeof *r + 20 ); r->key = pKEYTYPE; sprintf( r->u.value, "%d", algo); r->next = para; para = r; nbits = 0; r = xmalloc_clear (sizeof *r + strlen (curve)); r->key = pKEYCURVE; strcpy (r->u.value, curve); r->next = para; para = r; } else { r = xmalloc_clear( sizeof *r + 20 ); r->key = pKEYTYPE; sprintf( r->u.value, "%d", algo); r->next = para; para = r; nbits = ask_keysize (algo, 0); r = xmalloc_clear( sizeof *r + 20 ); r->key = pKEYLENGTH; sprintf( r->u.value, "%u", nbits); r->next = para; para = r; } r = xmalloc_clear( sizeof *r + 20 ); r->key = pKEYUSAGE; strcpy( r->u.value, "sign" ); r->next = para; para = r; r = xmalloc_clear( sizeof *r + 20 ); r->key = pSUBKEYTYPE; sprintf( r->u.value, "%d", subkey_algo); r->next = para; para = r; r = xmalloc_clear( sizeof *r + 20 ); r->key = pSUBKEYUSAGE; strcpy( r->u.value, "encrypt" ); r->next = para; para = r; if (algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_EDDSA || algo == PUBKEY_ALGO_ECDH) { if (algo == PUBKEY_ALGO_EDDSA && subkey_algo == PUBKEY_ALGO_ECDH) { /* Need to switch to a different curve for the encryption key. */ curve = "Curve25519"; } r = xmalloc_clear (sizeof *r + strlen (curve)); r->key = pSUBKEYCURVE; strcpy (r->u.value, curve); r->next = para; para = r; } } else /* Create only a single key. */ { /* For ECC we need to ask for the curve before storing the algo because ask_curve may change the algo. */ if (algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_EDDSA || algo == PUBKEY_ALGO_ECDH) { curve = ask_curve (&algo, NULL, NULL); r = xmalloc_clear (sizeof *r + strlen (curve)); r->key = pKEYCURVE; strcpy (r->u.value, curve); r->next = para; para = r; } r = xmalloc_clear( sizeof *r + 20 ); r->key = pKEYTYPE; sprintf( r->u.value, "%d", algo ); r->next = para; para = r; if (use) { r = xmalloc_clear( sizeof *r + 25 ); r->key = pKEYUSAGE; sprintf( r->u.value, "%s%s%s", (use & PUBKEY_USAGE_SIG)? "sign ":"", (use & PUBKEY_USAGE_ENC)? "encrypt ":"", (use & PUBKEY_USAGE_AUTH)? "auth":"" ); r->next = para; para = r; } nbits = 0; } if (algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_EDDSA || algo == PUBKEY_ALGO_ECDH) { /* The curve has already been set. */ } else { nbits = ask_keysize (both? subkey_algo : algo, nbits); r = xmalloc_clear( sizeof *r + 20 ); r->key = both? pSUBKEYLENGTH : pKEYLENGTH; sprintf( r->u.value, "%u", nbits); r->next = para; para = r; } } } else /* Default key generation. */ { int subalgo, version, subversion; unsigned int size, subsize; unsigned int keyuse, subkeyuse; const char *curve, *subcurve; char *keygrip, *subkeygrip; u32 keytime, subkeytime; tty_printf ( _("Note: Use \"%s %s\"" " for a full featured key generation dialog.\n"), #if USE_GPG2_HACK GPG_NAME "2" #else GPG_NAME #endif , "--full-generate-key" ); err = parse_key_parameter_string (ctrl, NULL, -1, 0, &algo, &size, &keyuse, &curve, &version, &keygrip, &keytime, &subalgo, &subsize, &subkeyuse, &subcurve, &subversion, &subkeygrip, &subkeytime); if (err) { log_error (_("Key generation failed: %s\n"), gpg_strerror (err)); return; } para = quickgen_set_para (para, 0, algo, size, curve, keyuse, version, keygrip, keytime); if (subalgo) para = quickgen_set_para (para, 1, subalgo, subsize, subcurve, subkeyuse, subversion, subkeygrip, subkeytime); xfree (keygrip); xfree (subkeygrip); } expire = full? ask_expire_interval (0, NULL) : parse_expire_string (default_expiration_interval); r = xcalloc (1, sizeof *r + 20); r->key = pKEYEXPIRE; r->u.expire = expire; r->next = para; para = r; r = xcalloc (1, sizeof *r + 20); r->key = pSUBKEYEXPIRE; r->u.expire = expire; r->next = para; para = r; uid = ask_user_id (0, full, NULL); if (!uid) { log_error(_("Key generation canceled.\n")); release_parameter_list( para ); return; } r = xcalloc (1, sizeof *r + strlen (uid)); r->key = pUSERID; strcpy (r->u.value, uid); r->next = para; para = r; proc_parameter_file (ctrl, para, "[internal]", &outctrl, !!card_serialno); release_parameter_list (para); } /* Create and delete a dummy packet to start off a list of kbnodes. */ static void start_tree(KBNODE *tree) { PACKET *pkt; pkt=xmalloc_clear(sizeof(*pkt)); pkt->pkttype=PKT_NONE; *tree=new_kbnode(pkt); delete_kbnode(*tree); } /* Write the *protected* secret key to the file. */ static gpg_error_t card_write_key_to_backup_file (PKT_public_key *sk, const char *backup_dir) { gpg_error_t err = 0; int rc; char keyid_buffer[2 * 8 + 1]; char name_buffer[50]; char *fname; IOBUF fp; mode_t oldmask; PACKET *pkt = NULL; format_keyid (pk_keyid (sk), KF_LONG, keyid_buffer, sizeof (keyid_buffer)); snprintf (name_buffer, sizeof name_buffer, "sk_%s.gpg", keyid_buffer); fname = make_filename (backup_dir, name_buffer, NULL); /* Note that the umask call is not anymore needed because iobuf_create now takes care of it. However, it does not harm and thus we keep it. */ oldmask = umask (077); if (is_secured_filename (fname)) { fp = NULL; gpg_err_set_errno (EPERM); } else fp = iobuf_create (fname, 1); umask (oldmask); if (!fp) { err = gpg_error_from_syserror (); log_error (_("can't create backup file '%s': %s\n"), fname, strerror (errno) ); goto leave; } pkt = xcalloc (1, sizeof *pkt); pkt->pkttype = PKT_SECRET_KEY; pkt->pkt.secret_key = sk; rc = build_packet (fp, pkt); if (rc) { log_error ("build packet failed: %s\n", gpg_strerror (rc)); iobuf_cancel (fp); } else { char *fprbuf; iobuf_close (fp); iobuf_ioctl (NULL, IOBUF_IOCTL_INVALIDATE_CACHE, 0, (char*)fname); log_info (_("Note: backup of card key saved to '%s'\n"), fname); fprbuf = hexfingerprint (sk, NULL, 0); if (!fprbuf) { err = gpg_error_from_syserror (); goto leave; } write_status_text_and_buffer (STATUS_BACKUP_KEY_CREATED, fprbuf, fname, strlen (fname), 0); xfree (fprbuf); } leave: xfree (pkt); xfree (fname); return err; } /* Store key to card and make a backup file in OpenPGP format. */ static gpg_error_t card_store_key_with_backup (ctrl_t ctrl, PKT_public_key *sub_psk, const char *backup_dir) { PKT_public_key *sk; gnupg_isotime_t timestamp; gpg_error_t err; char *hexgrip; int rc; struct agent_card_info_s info; gcry_cipher_hd_t cipherhd = NULL; char *cache_nonce = NULL; void *kek = NULL; size_t keklen; sk = copy_public_key (NULL, sub_psk); if (!sk) return gpg_error_from_syserror (); epoch2isotime (timestamp, (time_t)sk->timestamp); err = hexkeygrip_from_pk (sk, &hexgrip); if (err) return err; memset(&info, 0, sizeof (info)); rc = agent_scd_getattr ("SERIALNO", &info); if (rc) return (gpg_error_t)rc; rc = agent_keytocard (hexgrip, 2, 1, info.serialno, timestamp); xfree (info.serialno); if (rc) { err = (gpg_error_t)rc; goto leave; } err = agent_keywrap_key (ctrl, 1, &kek, &keklen); if (err) { log_error ("error getting the KEK: %s\n", gpg_strerror (err)); goto leave; } err = gcry_cipher_open (&cipherhd, GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_AESWRAP, 0); if (!err) err = gcry_cipher_setkey (cipherhd, kek, keklen); if (err) { log_error ("error setting up an encryption context: %s\n", gpg_strerror (err)); goto leave; } err = receive_seckey_from_agent (ctrl, cipherhd, 0, &cache_nonce, hexgrip, sk); if (err) { log_error ("error getting secret key from agent: %s\n", gpg_strerror (err)); goto leave; } err = card_write_key_to_backup_file (sk, backup_dir); if (err) log_error ("writing card key to backup file: %s\n", gpg_strerror (err)); else /* Remove secret key data in agent side. */ agent_scd_learn (NULL, 1); leave: xfree (cache_nonce); gcry_cipher_close (cipherhd); xfree (kek); xfree (hexgrip); free_public_key (sk); return err; } static void do_generate_keypair (ctrl_t ctrl, struct para_data_s *para, struct output_control_s *outctrl, int card) { gpg_error_t err; KBNODE pub_root = NULL; const char *s; PKT_public_key *pri_psk = NULL; PKT_public_key *sub_psk = NULL; struct revocation_key *revkey; int did_sub = 0; u32 keytimestamp, subkeytimestamp, authkeytimestamp, signtimestamp; char *cache_nonce = NULL; int algo; u32 expire; const char *key_from_hexgrip = NULL; int cardkey; unsigned int keygen_flags; if (outctrl->dryrun) { log_info("dry-run mode - key generation skipped\n"); return; } if ( outctrl->use_files ) { if ( outctrl->pub.newfname ) { iobuf_close(outctrl->pub.stream); outctrl->pub.stream = NULL; if (outctrl->pub.fname) iobuf_ioctl (NULL, IOBUF_IOCTL_INVALIDATE_CACHE, 0, (char*)outctrl->pub.fname); xfree( outctrl->pub.fname ); outctrl->pub.fname = outctrl->pub.newfname; outctrl->pub.newfname = NULL; if (is_secured_filename (outctrl->pub.fname) ) { outctrl->pub.stream = NULL; gpg_err_set_errno (EPERM); } else outctrl->pub.stream = iobuf_create (outctrl->pub.fname, 0); if (!outctrl->pub.stream) { log_error(_("can't create '%s': %s\n"), outctrl->pub.newfname, strerror(errno) ); return; } if (opt.armor) { outctrl->pub.afx->what = 1; push_armor_filter (outctrl->pub.afx, outctrl->pub.stream); } } log_assert( outctrl->pub.stream ); if (opt.verbose) log_info (_("writing public key to '%s'\n"), outctrl->pub.fname ); } /* We create the packets as a tree of kbnodes. Because the structure we create is known in advance we simply generate a linked list. The first packet is a dummy packet which we flag as deleted. The very first packet must always be a KEY packet. */ start_tree (&pub_root); cardkey = get_parameter_bool (para, pCARDKEY); /* In the case that the keys are created from the card we need to * take the timestamps from the card. Only in this case a * pSUBKEYCREATIONDATE or pAUTHKEYCREATIONDATE might be defined and * then we need to use that so that the fingerprint of the subkey * also matches the pre-computed and stored one on the card. In * this case we also use the current time to create the * self-signatures. */ keytimestamp = get_parameter_u32 (para, pKEYCREATIONDATE); if (!keytimestamp) keytimestamp = make_timestamp (); subkeytimestamp = cardkey? get_parameter_u32 (para, pSUBKEYCREATIONDATE) : 0; if (!subkeytimestamp) subkeytimestamp = keytimestamp; authkeytimestamp = cardkey? get_parameter_u32 (para, pAUTHKEYCREATIONDATE): 0; if (!authkeytimestamp) authkeytimestamp = keytimestamp; signtimestamp = cardkey? make_timestamp () : keytimestamp; /* log_debug ("XXX: cardkey ..: %d\n", cardkey); */ /* log_debug ("XXX: keytime ..: %s\n", isotimestamp (keytimestamp)); */ /* log_debug ("XXX: subkeytime: %s\n", isotimestamp (subkeytimestamp)); */ /* log_debug ("XXX: authkeytim: %s\n", isotimestamp (authkeytimestamp)); */ /* log_debug ("XXX: signtime .: %s\n", isotimestamp (signtimestamp)); */ /* Fixme: Check that this comment is still valid: Note that, depending on the backend (i.e. the used scdaemon version), the card key generation may update TIMESTAMP for each key. Thus we need to pass TIMESTAMP to all signing function to make sure that the binding signature is done using the timestamp of the corresponding (sub)key and not that of the primary key. An alternative implementation could tell the signing function the node of the subkey but that is more work than just to pass the current timestamp. */ algo = get_parameter_algo (ctrl, para, pKEYTYPE, NULL ); expire = get_parameter_u32( para, pKEYEXPIRE ); key_from_hexgrip = get_parameter_value (para, pKEYGRIP); if (cardkey && !key_from_hexgrip) BUG (); keygen_flags = outctrl->keygen_flags; if (get_parameter_uint (para, pVERSION) == 5) keygen_flags |= KEYGEN_FLAG_CREATE_V5_KEY; if (key_from_hexgrip) err = do_create_from_keygrip (ctrl, algo, key_from_hexgrip, cardkey, pub_root, keytimestamp, expire, 0, keygen_flags); else if (!card) err = do_create (algo, get_parameter_uint( para, pKEYLENGTH ), get_parameter_value (para, pKEYCURVE), pub_root, keytimestamp, expire, 0, keygen_flags, get_parameter_passphrase (para), &cache_nonce, NULL); else err = gen_card_key (1, algo, 1, pub_root, &keytimestamp, expire, keygen_flags); /* Get the pointer to the generated public key packet. */ if (!err) { pri_psk = pub_root->next->pkt->pkt.public_key; log_assert (pri_psk); /* Make sure a few fields are correctly set up before going further. */ pri_psk->flags.primary = 1; keyid_from_pk (pri_psk, NULL); /* We don't use pk_keyid to get keyid, because it also asserts that main_keyid is set! */ keyid_copy (pri_psk->main_keyid, pri_psk->keyid); } if (!err && (revkey = get_parameter_revkey (para, pREVOKER))) err = write_direct_sig (ctrl, pub_root, pri_psk, revkey, signtimestamp, cache_nonce); if (!err && (s = get_parameter_value (para, pUSERID))) { err = write_uid (pub_root, s ); if (!err) err = write_selfsigs (ctrl, pub_root, pri_psk, get_parameter_uint (para, pKEYUSAGE), signtimestamp, cache_nonce); } /* Write the auth key to the card before the encryption key. This is a partial workaround for a PGP bug (as of this writing, all versions including 8.1), that causes it to try and encrypt to the most recent subkey regardless of whether that subkey is actually an encryption type. In this case, the auth key is an RSA key so it succeeds. */ if (!err && card && get_parameter (para, pAUTHKEYTYPE)) { err = gen_card_key (3, get_parameter_algo (ctrl, para, pAUTHKEYTYPE, NULL ), 0, pub_root, &authkeytimestamp, expire, keygen_flags); if (!err) err = write_keybinding (ctrl, pub_root, pri_psk, NULL, PUBKEY_USAGE_AUTH, signtimestamp, cache_nonce); } if (!err && get_parameter (para, pSUBKEYTYPE)) { int subkey_algo = get_parameter_algo (ctrl, para, pSUBKEYTYPE, NULL); s = NULL; key_from_hexgrip = get_parameter_value (para, pSUBKEYGRIP); keygen_flags = outctrl->keygen_flags; if (get_parameter_uint (para, pSUBVERSION) == 5) keygen_flags |= KEYGEN_FLAG_CREATE_V5_KEY; if (key_from_hexgrip) err = do_create_from_keygrip (ctrl, subkey_algo, key_from_hexgrip, cardkey, pub_root, subkeytimestamp, get_parameter_u32 (para, pSUBKEYEXPIRE), 1, keygen_flags); else if (!card || (s = get_parameter_value (para, pCARDBACKUPKEY))) { err = do_create (subkey_algo, get_parameter_uint (para, pSUBKEYLENGTH), get_parameter_value (para, pSUBKEYCURVE), pub_root, subkeytimestamp, get_parameter_u32 (para, pSUBKEYEXPIRE), 1, s? KEYGEN_FLAG_NO_PROTECTION : keygen_flags, get_parameter_passphrase (para), &cache_nonce, NULL); /* Get the pointer to the generated public subkey packet. */ if (!err) { kbnode_t node; for (node = pub_root; node; node = node->next) if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY) sub_psk = node->pkt->pkt.public_key; log_assert (sub_psk); if (s) err = card_store_key_with_backup (ctrl, sub_psk, gnupg_homedir ()); } } else { err = gen_card_key (2, subkey_algo, 0, pub_root, &subkeytimestamp, expire, keygen_flags); } if (!err) err = write_keybinding (ctrl, pub_root, pri_psk, sub_psk, get_parameter_uint (para, pSUBKEYUSAGE), signtimestamp, cache_nonce); did_sub = 1; } if (!err && outctrl->use_files) /* Direct write to specified files. */ { err = write_keyblock (outctrl->pub.stream, pub_root); if (err) log_error ("can't write public key: %s\n", gpg_strerror (err)); } else if (!err) /* Write to the standard keyrings. */ { KEYDB_HANDLE pub_hd; pub_hd = keydb_new (ctrl); if (!pub_hd) err = gpg_error_from_syserror (); else { err = keydb_locate_writable (pub_hd); if (err) log_error (_("no writable public keyring found: %s\n"), gpg_strerror (err)); } if (!err && opt.verbose) { log_info (_("writing public key to '%s'\n"), keydb_get_resource_name (pub_hd)); } if (!err) { err = keydb_insert_keyblock (pub_hd, pub_root); if (err) log_error (_("error writing public keyring '%s': %s\n"), keydb_get_resource_name (pub_hd), gpg_strerror (err)); } keydb_release (pub_hd); if (!err) { int no_enc_rsa; PKT_public_key *pk; no_enc_rsa = ((get_parameter_algo (ctrl, para, pKEYTYPE, NULL) == PUBKEY_ALGO_RSA) && get_parameter_uint (para, pKEYUSAGE) && !((get_parameter_uint (para, pKEYUSAGE) & PUBKEY_USAGE_ENC)) ); pk = find_kbnode (pub_root, PKT_PUBLIC_KEY)->pkt->pkt.public_key; keyid_from_pk (pk, pk->main_keyid); register_trusted_keyid (pk->main_keyid); update_ownertrust (ctrl, pk, ((get_ownertrust (ctrl, pk) & ~TRUST_MASK) | TRUST_ULTIMATE )); gen_standard_revoke (ctrl, pk, cache_nonce); /* Get rid of the first empty packet. */ commit_kbnode (&pub_root); if (!opt.batch) { tty_printf (_("public and secret key created and signed.\n") ); tty_printf ("\n"); merge_keys_and_selfsig (ctrl, pub_root); list_keyblock_direct (ctrl, pub_root, 0, 1, opt.fingerprint || opt.with_fingerprint, 1); } if (!opt.batch && (get_parameter_algo (ctrl, para, pKEYTYPE, NULL) == PUBKEY_ALGO_DSA || no_enc_rsa ) && !get_parameter (para, pSUBKEYTYPE) ) { tty_printf(_("Note that this key cannot be used for " "encryption. You may want to use\n" "the command \"--edit-key\" to generate a " "subkey for this purpose.\n") ); } } } if (err) { if (opt.batch) log_error ("key generation failed: %s\n", gpg_strerror (err) ); else tty_printf (_("Key generation failed: %s\n"), gpg_strerror (err) ); write_status_error (card? "card_key_generate":"key_generate", err); print_status_key_not_created ( get_parameter_value (para, pHANDLE) ); } else { PKT_public_key *pk = find_kbnode (pub_root, PKT_PUBLIC_KEY)->pkt->pkt.public_key; print_status_key_created (did_sub? 'B':'P', pk, get_parameter_value (para, pHANDLE)); } release_kbnode (pub_root); xfree (cache_nonce); } static gpg_error_t parse_algo_usage_expire (ctrl_t ctrl, int for_subkey, const char *algostr, const char *usagestr, const char *expirestr, int *r_algo, unsigned int *r_usage, u32 *r_expire, unsigned int *r_nbits, const char **r_curve, int *r_version, char **r_keygrip, u32 *r_keytime) { gpg_error_t err; int algo; unsigned int use, nbits; u32 expire; int wantuse; int version = 4; const char *curve = NULL; *r_curve = NULL; if (r_keygrip) *r_keygrip = NULL; if (r_keytime) *r_keytime = 0; nbits = 0; /* Parse the algo string. */ if (algostr && *algostr == '&' && strlen (algostr) == 41) { /* Take algo from existing key. */ algo = check_keygrip (ctrl, algostr+1); /* FIXME: We need the curve name as well. */ return gpg_error (GPG_ERR_NOT_IMPLEMENTED); } err = parse_key_parameter_string (ctrl, algostr, for_subkey? 1 : 0, usagestr? parse_usagestr (usagestr):0, &algo, &nbits, &use, &curve, &version, r_keygrip, r_keytime, NULL, NULL, NULL, NULL, NULL, NULL, NULL); if (err) { if (r_keygrip) { xfree (*r_keygrip); *r_keygrip = NULL; } return err; } /* Parse the usage string. */ if (!usagestr || !*usagestr || !ascii_strcasecmp (usagestr, "default") || !strcmp (usagestr, "-")) ; /* Keep usage from parse_key_parameter_string. */ else if ((wantuse = parse_usagestr (usagestr)) != -1) use = wantuse; else { if (r_keygrip) { xfree (*r_keygrip); *r_keygrip = NULL; } return gpg_error (GPG_ERR_INV_VALUE); } /* Make sure a primary key has the CERT usage. */ if (!for_subkey) use |= PUBKEY_USAGE_CERT; /* Check that usage is possible. NB: We have the same check in * parse_key_parameter_string but need it here again in case the * separate usage value has been given. */ if (/**/((use & (PUBKEY_USAGE_SIG|PUBKEY_USAGE_AUTH|PUBKEY_USAGE_CERT)) && !pubkey_get_nsig (algo)) || ((use & PUBKEY_USAGE_ENC) && !pubkey_get_nenc (algo)) || (for_subkey && (use & PUBKEY_USAGE_CERT))) { if (r_keygrip) { xfree (*r_keygrip); *r_keygrip = NULL; } return gpg_error (GPG_ERR_WRONG_KEY_USAGE); } /* Parse the expire string. */ expire = parse_expire_string (expirestr); if (expire == (u32)-1 ) { if (r_keygrip) { xfree (*r_keygrip); *r_keygrip = NULL; } return gpg_error (GPG_ERR_INV_VALUE); } if (curve) *r_curve = curve; *r_algo = algo; *r_usage = use; *r_expire = expire; *r_nbits = nbits; *r_version = version; return 0; } /* Add a new subkey to an existing key. Returns 0 if a new key has been generated and put into the keyblocks. If any of ALGOSTR, USAGESTR, or EXPIRESTR is NULL interactive mode is used. */ gpg_error_t generate_subkeypair (ctrl_t ctrl, kbnode_t keyblock, const char *algostr, const char *usagestr, const char *expirestr) { gpg_error_t err = 0; int interactive; kbnode_t node; PKT_public_key *pri_psk = NULL; PKT_public_key *sub_psk = NULL; int algo; unsigned int use; u32 expire; unsigned int nbits = 0; const char *curve = NULL; u32 cur_time; char *key_from_hexgrip = NULL; u32 keytime = 0; int cardkey = 0; char *hexgrip = NULL; char *serialno = NULL; char *cache_nonce = NULL; char *passwd_nonce = NULL; int keygen_flags = 0; interactive = (!algostr || !usagestr || !expirestr); /* Break out the primary key. */ node = find_kbnode (keyblock, PKT_PUBLIC_KEY); if (!node) { log_error ("Oops; primary key missing in keyblock!\n"); err = gpg_error (GPG_ERR_BUG); goto leave; } pri_psk = node->pkt->pkt.public_key; cur_time = make_timestamp (); if (pri_psk->timestamp > cur_time) { ulong d = pri_psk->timestamp - cur_time; log_info ( d==1 ? _("key has been created %lu second " "in future (time warp or clock problem)\n") : _("key has been created %lu seconds " "in future (time warp or clock problem)\n"), d ); if (!opt.ignore_time_conflict) { err = gpg_error (GPG_ERR_TIME_CONFLICT); goto leave; } } if (pri_psk->version < 4) { log_info (_("Note: creating subkeys for v3 keys " "is not OpenPGP compliant\n")); err = gpg_error (GPG_ERR_CONFLICT); goto leave; } err = hexkeygrip_from_pk (pri_psk, &hexgrip); if (err) goto leave; if (agent_get_keyinfo (NULL, hexgrip, &serialno, NULL)) { if (interactive) tty_printf (_("Secret parts of primary key are not available.\n")); else log_info ( _("Secret parts of primary key are not available.\n")); err = gpg_error (GPG_ERR_NO_SECKEY); goto leave; } if (serialno) { if (interactive) tty_printf (_("Secret parts of primary key are stored on-card.\n")); else log_info ( _("Secret parts of primary key are stored on-card.\n")); } if (interactive) { algo = ask_algo (ctrl, 1, NULL, &use, &key_from_hexgrip, &cardkey, &keytime); log_assert (algo); if (key_from_hexgrip) nbits = 0; else if (algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_EDDSA || algo == PUBKEY_ALGO_ECDH) curve = ask_curve (&algo, NULL, NULL); else nbits = ask_keysize (algo, 0); expire = ask_expire_interval (0, NULL); if (!cpr_enabled() && !cpr_get_answer_is_yes("keygen.sub.okay", _("Really create? (y/N) "))) { err = gpg_error (GPG_ERR_CANCELED); goto leave; } } else /* Unattended mode. */ { int version; err = parse_algo_usage_expire (ctrl, 1, algostr, usagestr, expirestr, &algo, &use, &expire, &nbits, &curve, &version, &key_from_hexgrip, &keytime); if (err) goto leave; if (version == 5) keygen_flags |= KEYGEN_FLAG_CREATE_V5_KEY; } /* Verify the passphrase now so that we get a cache item for the * primary key passphrase. The agent also returns a passphrase * nonce, which we can use to set the passphrase for the subkey to * that of the primary key. */ { char *desc = gpg_format_keydesc (ctrl, pri_psk, FORMAT_KEYDESC_NORMAL, 1); err = agent_passwd (ctrl, hexgrip, desc, 1 /*=verify*/, &cache_nonce, &passwd_nonce); xfree (desc); if (gpg_err_code (err) == GPG_ERR_NOT_IMPLEMENTED && gpg_err_source (err) == GPG_ERR_SOURCE_GPGAGENT) err = 0; /* Very likely that the key is on a card. */ if (err) goto leave; } /* Start creation. */ if (key_from_hexgrip) { err = do_create_from_keygrip (ctrl, algo, key_from_hexgrip, cardkey, keyblock, keytime? keytime : cur_time, expire, 1, keygen_flags); } else { const char *passwd; /* If the pinentry loopback mode is not and we have a static passphrase (i.e. set with --passphrase{,-fd,-file} while in batch mode), we use that passphrase for the new subkey. */ if (opt.pinentry_mode != PINENTRY_MODE_LOOPBACK && have_static_passphrase ()) passwd = get_static_passphrase (); else passwd = NULL; err = do_create (algo, nbits, curve, keyblock, cur_time, expire, 1, keygen_flags, passwd, &cache_nonce, &passwd_nonce); } if (err) goto leave; /* Get the pointer to the generated public subkey packet. */ for (node = keyblock; node; node = node->next) if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY) sub_psk = node->pkt->pkt.public_key; /* Write the binding signature. */ err = write_keybinding (ctrl, keyblock, pri_psk, sub_psk, use, cur_time, cache_nonce); if (err) goto leave; print_status_key_created ('S', sub_psk, NULL); leave: xfree (key_from_hexgrip); xfree (hexgrip); xfree (serialno); xfree (cache_nonce); xfree (passwd_nonce); if (err) log_error (_("Key generation failed: %s\n"), gpg_strerror (err) ); return err; } #ifdef ENABLE_CARD_SUPPORT /* Generate a subkey on a card. */ gpg_error_t generate_card_subkeypair (ctrl_t ctrl, kbnode_t pub_keyblock, int keyno, const char *serialno) { gpg_error_t err = 0; kbnode_t node; PKT_public_key *pri_pk = NULL; unsigned int use; u32 expire; u32 cur_time; struct para_data_s *para = NULL; PKT_public_key *sub_pk = NULL; int algo; struct agent_card_info_s info; int keygen_flags = 0; /* FIXME!!! */ log_assert (keyno >= 1 && keyno <= 3); memset (&info, 0, sizeof (info)); err = agent_scd_getattr ("KEY-ATTR", &info); if (err) { log_error (_("error getting current key info: %s\n"), gpg_strerror (err)); return err; } algo = info.key_attr[keyno-1].algo; para = xtrycalloc (1, sizeof *para + strlen (serialno) ); if (!para) { err = gpg_error_from_syserror (); goto leave; } para->key = pSERIALNO; strcpy (para->u.value, serialno); /* Break out the primary secret key */ node = find_kbnode (pub_keyblock, PKT_PUBLIC_KEY); if (!node) { log_error ("Oops; public key lost!\n"); err = gpg_error (GPG_ERR_INTERNAL); goto leave; } pri_pk = node->pkt->pkt.public_key; cur_time = make_timestamp(); if (pri_pk->timestamp > cur_time) { ulong d = pri_pk->timestamp - cur_time; log_info (d==1 ? _("key has been created %lu second " "in future (time warp or clock problem)\n") : _("key has been created %lu seconds " "in future (time warp or clock problem)\n"), d ); if (!opt.ignore_time_conflict) { err = gpg_error (GPG_ERR_TIME_CONFLICT); goto leave; } } if (pri_pk->version < 4) { log_info (_("Note: creating subkeys for v3 keys " "is not OpenPGP compliant\n")); err = gpg_error (GPG_ERR_NOT_SUPPORTED); goto leave; } expire = ask_expire_interval (0, NULL); if (keyno == 1) use = PUBKEY_USAGE_SIG; else if (keyno == 2) use = PUBKEY_USAGE_ENC; else use = PUBKEY_USAGE_AUTH; if (!cpr_enabled() && !cpr_get_answer_is_yes("keygen.cardsub.okay", _("Really create? (y/N) "))) { err = gpg_error (GPG_ERR_CANCELED); goto leave; } /* Note, that depending on the backend, the card key generation may update CUR_TIME. */ err = gen_card_key (keyno, algo, 0, pub_keyblock, &cur_time, expire, keygen_flags); /* Get the pointer to the generated public subkey packet. */ if (!err) { for (node = pub_keyblock; node; node = node->next) if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY) sub_pk = node->pkt->pkt.public_key; log_assert (sub_pk); err = write_keybinding (ctrl, pub_keyblock, pri_pk, sub_pk, use, cur_time, NULL); } leave: if (err) log_error (_("Key generation failed: %s\n"), gpg_strerror (err) ); else print_status_key_created ('S', sub_pk, NULL); release_parameter_list (para); return err; } #endif /* !ENABLE_CARD_SUPPORT */ /* * Write a keyblock to an output stream */ static int write_keyblock( IOBUF out, KBNODE node ) { for( ; node ; node = node->next ) { if(!is_deleted_kbnode(node)) { int rc = build_packet( out, node->pkt ); if( rc ) { log_error("build_packet(%d) failed: %s\n", node->pkt->pkttype, gpg_strerror (rc) ); return rc; } } } return 0; } /* Note that timestamp is an in/out arg. * FIXME: Does not yet support v5 keys. */ static gpg_error_t gen_card_key (int keyno, int algo, int is_primary, kbnode_t pub_root, u32 *timestamp, u32 expireval, int keygen_flags) { #ifdef ENABLE_CARD_SUPPORT gpg_error_t err; PACKET *pkt; PKT_public_key *pk; char keyid[10]; unsigned char *public; gcry_sexp_t s_key; snprintf (keyid, DIM(keyid), "OPENPGP.%d", keyno); pk = xtrycalloc (1, sizeof *pk ); if (!pk) return gpg_error_from_syserror (); pkt = xtrycalloc (1, sizeof *pkt); if (!pkt) { xfree (pk); return gpg_error_from_syserror (); } /* Note: SCD knows the serialnumber, thus there is no point in passing it. */ err = agent_scd_genkey (keyno, 1, timestamp); /* The code below is not used because we force creation of * the a card key (3rd arg). * if (gpg_err_code (rc) == GPG_ERR_EEXIST) * { * tty_printf ("\n"); * log_error ("WARNING: key does already exists!\n"); * tty_printf ("\n"); * if ( cpr_get_answer_is_yes( "keygen.card.replace_key", * _("Replace existing key? "))) * rc = agent_scd_genkey (keyno, 1, timestamp); * } */ if (err) { log_error ("key generation failed: %s\n", gpg_strerror (err)); xfree (pkt); xfree (pk); return err; } /* Send the READKEY command so that the agent creates a shadow key for card key. We need to do that now so that we are able to create the self-signatures. */ err = agent_readkey (NULL, 1, keyid, &public); if (err) return err; err = gcry_sexp_sscan (&s_key, NULL, public, gcry_sexp_canon_len (public, 0, NULL, NULL)); xfree (public); if (err) return err; if (algo == PUBKEY_ALGO_RSA) err = key_from_sexp (pk->pkey, s_key, "public-key", "ne"); else if (algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_EDDSA || algo == PUBKEY_ALGO_ECDH ) err = ecckey_from_sexp (pk->pkey, s_key, algo); else err = gpg_error (GPG_ERR_PUBKEY_ALGO); gcry_sexp_release (s_key); if (err) { log_error ("key_from_sexp failed: %s\n", gpg_strerror (err) ); free_public_key (pk); return err; } pk->timestamp = *timestamp; pk->version = (keygen_flags & KEYGEN_FLAG_CREATE_V5_KEY)? 5 : 4; if (expireval) pk->expiredate = pk->timestamp + expireval; pk->pubkey_algo = algo; pkt->pkttype = is_primary ? PKT_PUBLIC_KEY : PKT_PUBLIC_SUBKEY; pkt->pkt.public_key = pk; add_kbnode (pub_root, new_kbnode (pkt)); return 0; #else (void)keyno; (void)is_primary; (void)pub_root; (void)timestamp; (void)expireval; return gpg_error (GPG_ERR_NOT_SUPPORTED); #endif /*!ENABLE_CARD_SUPPORT*/ } diff --git a/g10/pkglue.c b/g10/pkglue.c index eda13009b..cd6e90838 100644 --- a/g10/pkglue.c +++ b/g10/pkglue.c @@ -1,525 +1,541 @@ /* pkglue.c - public key operations glue code * Copyright (C) 2000, 2003, 2010 Free Software Foundation, Inc. * Copyright (C) 2014 Werner Koch * * This file is part of GnuPG. * * GnuPG is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * GnuPG is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . */ #include #include #include #include #include #include "gpg.h" #include "../common/util.h" #include "pkglue.h" #include "main.h" #include "options.h" /* FIXME: Better change the function name because mpi_ is used by gcrypt macros. */ gcry_mpi_t get_mpi_from_sexp (gcry_sexp_t sexp, const char *item, int mpifmt) { gcry_sexp_t list; gcry_mpi_t data; list = gcry_sexp_find_token (sexp, item, 0); log_assert (list); data = gcry_sexp_nth_mpi (list, 1, mpifmt); log_assert (data); gcry_sexp_release (list); return data; } /* Extract SOS representation from SEXP for PARAM, return the result in R_SOS. */ gpg_error_t sexp_extract_param_sos (gcry_sexp_t sexp, const char *param, gcry_mpi_t *r_sos) { gpg_error_t err; gcry_sexp_t l2 = gcry_sexp_find_token (sexp, param, 0); *r_sos = NULL; if (!l2) err = gpg_error (GPG_ERR_NO_OBJ); else { size_t buflen; void *p0 = gcry_sexp_nth_buffer (l2, 1, &buflen); if (!p0) err = gpg_error_from_syserror (); else { gcry_mpi_t sos; unsigned int nbits = buflen*8; unsigned char *p = p0; if (nbits >= 8 && !(*p & 0x80)) if (--nbits >= 7 && !(*p & 0x40)) if (--nbits >= 6 && !(*p & 0x20)) if (--nbits >= 5 && !(*p & 0x10)) if (--nbits >= 4 && !(*p & 0x08)) if (--nbits >= 3 && !(*p & 0x04)) if (--nbits >= 2 && !(*p & 0x02)) if (--nbits >= 1 && !(*p & 0x01)) --nbits; sos = gcry_mpi_set_opaque (NULL, p0, nbits); if (sos) { gcry_mpi_set_flag (sos, GCRYMPI_FLAG_USER2); *r_sos = sos; err = 0; } else err = gpg_error_from_syserror (); } gcry_sexp_release (l2); } return err; } static byte * get_data_from_sexp (gcry_sexp_t sexp, const char *item, size_t *r_size) { gcry_sexp_t list; size_t valuelen; const char *value; byte *v; if (DBG_CRYPTO) log_printsexp ("get_data_from_sexp:", sexp); list = gcry_sexp_find_token (sexp, item, 0); log_assert (list); value = gcry_sexp_nth_data (list, 1, &valuelen); log_assert (value); v = xtrymalloc (valuelen); memcpy (v, value, valuelen); gcry_sexp_release (list); *r_size = valuelen; return v; } /**************** * Emulate our old PK interface here - sometime in the future we might * change the internal design to directly fit to libgcrypt. */ int pk_verify (pubkey_algo_t pkalgo, gcry_mpi_t hash, gcry_mpi_t *data, gcry_mpi_t *pkey) { gcry_sexp_t s_sig, s_hash, s_pkey; int rc; - unsigned int neededfixedlen = 0; /* Make a sexp from pkey. */ if (pkalgo == PUBKEY_ALGO_DSA) { rc = gcry_sexp_build (&s_pkey, NULL, "(public-key(dsa(p%m)(q%m)(g%m)(y%m)))", pkey[0], pkey[1], pkey[2], pkey[3]); } else if (pkalgo == PUBKEY_ALGO_ELGAMAL_E || pkalgo == PUBKEY_ALGO_ELGAMAL) { rc = gcry_sexp_build (&s_pkey, NULL, "(public-key(elg(p%m)(g%m)(y%m)))", pkey[0], pkey[1], pkey[2]); } else if (pkalgo == PUBKEY_ALGO_RSA || pkalgo == PUBKEY_ALGO_RSA_S) { rc = gcry_sexp_build (&s_pkey, NULL, "(public-key(rsa(n%m)(e%m)))", pkey[0], pkey[1]); } else if (pkalgo == PUBKEY_ALGO_ECDSA) { char *curve = openpgp_oid_to_str (pkey[0]); if (!curve) rc = gpg_error_from_syserror (); else { rc = gcry_sexp_build (&s_pkey, NULL, "(public-key(ecdsa(curve %s)(q%m)))", curve, pkey[1]); xfree (curve); } } else if (pkalgo == PUBKEY_ALGO_EDDSA) { char *curve = openpgp_oid_to_str (pkey[0]); if (!curve) rc = gpg_error_from_syserror (); else { - rc = gcry_sexp_build (&s_pkey, NULL, - "(public-key(ecc(curve %s)" - "(flags eddsa)(q%m)))", - curve, pkey[1]); + const char *fmt; + + if (openpgp_oid_is_ed25519 (pkey[0])) + 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); } - - if (openpgp_oid_is_ed25519 (pkey[0])) - neededfixedlen = 256 / 8; } else return GPG_ERR_PUBKEY_ALGO; if (rc) BUG (); /* gcry_sexp_build should never fail. */ /* Put hash into a S-Exp s_hash. */ if (pkalgo == PUBKEY_ALGO_EDDSA) { - if (gcry_sexp_build (&s_hash, NULL, - "(data(flags eddsa)(hash-algo sha512)(value %m))", - hash)) + const char *fmt; + + 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. */ } else { if (gcry_sexp_build (&s_hash, NULL, "%m", hash)) BUG (); /* gcry_sexp_build should never fail. */ } /* Put data into a S-Exp s_sig. */ s_sig = NULL; if (pkalgo == PUBKEY_ALGO_DSA) { if (!data[0] || !data[1]) rc = gpg_error (GPG_ERR_BAD_MPI); else rc = gcry_sexp_build (&s_sig, NULL, "(sig-val(dsa(r%m)(s%m)))", data[0], data[1]); } else if (pkalgo == PUBKEY_ALGO_ECDSA) { if (!data[0] || !data[1]) rc = gpg_error (GPG_ERR_BAD_MPI); else rc = gcry_sexp_build (&s_sig, NULL, "(sig-val(ecdsa(r%m)(s%m)))", data[0], data[1]); } else if (pkalgo == PUBKEY_ALGO_EDDSA) { gcry_mpi_t r = data[0]; gcry_mpi_t s = data[1]; - size_t rlen, slen, n; /* (bytes) */ - char buf[64]; - unsigned int nbits; - - log_assert (neededfixedlen <= sizeof buf); - 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 + if (openpgp_oid_is_ed25519 (pkey[0])) { - /* We need to fixup the length in case of leading zeroes. - * OpenPGP does not allow leading zeroes and the parser for - * the signature packet has no information on the use curve, - * 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; - * 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 - && !gcry_mpi_get_flag (r, GCRYMPI_FLAG_OPAQUE) - && !(rc=gcry_mpi_print (GCRYMPI_FMT_USG, buf, sizeof buf, &n, r))) - { - log_assert (n < neededfixedlen); - memmove (buf + (neededfixedlen - n), buf, n); - memset (buf, 0, neededfixedlen - n); - r = gcry_mpi_set_opaque_copy (NULL, buf, neededfixedlen * 8); - } - else if (rlen < neededfixedlen - && gcry_mpi_get_flag (r, GCRYMPI_FLAG_OPAQUE)) - { - const unsigned char *p; + size_t rlen, slen, n; /* (bytes) */ + char buf[64]; + unsigned int nbits; + unsigned int neededfixedlen = 256 / 8; - p = gcry_mpi_get_opaque (r, &nbits); - n = (nbits+7)/8; - memcpy (buf + (neededfixedlen - n), p, n); - memset (buf, 0, neededfixedlen - n); - 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; + log_assert (neededfixedlen <= sizeof buf); - 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 (!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. + * OpenPGP does not allow leading zeroes and the parser for + * the signature packet has no information on the use curve, + * 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; + * 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 + && !gcry_mpi_get_flag (r, GCRYMPI_FLAG_OPAQUE) + && !(rc=gcry_mpi_print (GCRYMPI_FMT_USG, buf, sizeof buf, &n, r))) + { + log_assert (n < neededfixedlen); + memmove (buf + (neededfixedlen - n), buf, n); + memset (buf, 0, neededfixedlen - n); + r = gcry_mpi_set_opaque_copy (NULL, buf, neededfixedlen * 8); + } + else if (rlen < neededfixedlen + && gcry_mpi_get_flag (r, GCRYMPI_FLAG_OPAQUE)) + { + const unsigned char *p; + + p = gcry_mpi_get_opaque (r, &nbits); + n = (nbits+7)/8; + memcpy (buf + (neededfixedlen - n), p, n); + memset (buf, 0, neededfixedlen - n); + 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); + } } + } + else + rc = 0; - if (!rc) - rc = gcry_sexp_build (&s_sig, NULL, - "(sig-val(eddsa(r%M)(s%M)))", r, s); + 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); - } + 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) { if (!data[0] || !data[1]) rc = gpg_error (GPG_ERR_BAD_MPI); else rc = gcry_sexp_build (&s_sig, NULL, "(sig-val(elg(r%m)(s%m)))", data[0], data[1]); } else if (pkalgo == PUBKEY_ALGO_RSA || pkalgo == PUBKEY_ALGO_RSA_S) { if (!data[0]) rc = gpg_error (GPG_ERR_BAD_MPI); else rc = gcry_sexp_build (&s_sig, NULL, "(sig-val(rsa(s%m)))", data[0]); } else BUG (); if (!rc) rc = gcry_pk_verify (s_sig, s_hash, s_pkey); gcry_sexp_release (s_sig); gcry_sexp_release (s_hash); gcry_sexp_release (s_pkey); return rc; } /**************** * Emulate our old PK interface here - sometime in the future we might * change the internal design to directly fit to libgcrypt. * PK is only required to compute the fingerprint for ECDH. */ int pk_encrypt (pubkey_algo_t algo, gcry_mpi_t *resarr, gcry_mpi_t data, PKT_public_key *pk, gcry_mpi_t *pkey) { gcry_sexp_t s_ciph = NULL; gcry_sexp_t s_data = NULL; gcry_sexp_t s_pkey = NULL; int rc; /* Make a sexp from pkey. */ if (algo == PUBKEY_ALGO_ELGAMAL || algo == PUBKEY_ALGO_ELGAMAL_E) { rc = gcry_sexp_build (&s_pkey, NULL, "(public-key(elg(p%m)(g%m)(y%m)))", pkey[0], pkey[1], pkey[2]); /* Put DATA into a simplified S-expression. */ if (!rc) rc = gcry_sexp_build (&s_data, NULL, "%m", data); } else if (algo == PUBKEY_ALGO_RSA || algo == PUBKEY_ALGO_RSA_E) { rc = gcry_sexp_build (&s_pkey, NULL, "(public-key(rsa(n%m)(e%m)))", pkey[0], pkey[1]); /* Put DATA into a simplified S-expression. */ if (!rc) rc = gcry_sexp_build (&s_data, NULL, "%m", data); } else if (algo == PUBKEY_ALGO_ECDH) { gcry_mpi_t k; rc = pk_ecdh_generate_ephemeral_key (pkey, &k); if (!rc) { char *curve; curve = openpgp_oid_to_str (pkey[0]); if (!curve) rc = gpg_error_from_syserror (); else { int with_djb_tweak_flag = openpgp_oid_is_cv25519 (pkey[0]); /* Now use the ephemeral secret to compute the shared point. */ rc = gcry_sexp_build (&s_pkey, NULL, with_djb_tweak_flag ? "(public-key(ecdh(curve%s)(flags djb-tweak)(q%m)))" : "(public-key(ecdh(curve%s)(q%m)))", curve, pkey[1]); xfree (curve); /* Put K into a simplified S-expression. */ if (!rc) rc = gcry_sexp_build (&s_data, NULL, "%m", k); } gcry_mpi_release (k); } } else rc = gpg_error (GPG_ERR_PUBKEY_ALGO); /* Pass it to libgcrypt. */ if (!rc) rc = gcry_pk_encrypt (&s_ciph, s_data, s_pkey); gcry_sexp_release (s_data); gcry_sexp_release (s_pkey); if (rc) ; else if (algo == PUBKEY_ALGO_ECDH) { gcry_mpi_t public, result; byte fp[MAX_FINGERPRINT_LEN]; size_t fpn; byte *shared; size_t nshared; /* Get the shared point and the ephemeral public key. */ shared = get_data_from_sexp (s_ciph, "s", &nshared); rc = sexp_extract_param_sos (s_ciph, "e", &public); gcry_sexp_release (s_ciph); s_ciph = NULL; if (DBG_CRYPTO) { log_debug ("ECDH ephemeral key:"); gcry_mpi_dump (public); log_printf ("\n"); } result = NULL; fingerprint_from_pk (pk, fp, &fpn); if (fpn != 20) rc = gpg_error (GPG_ERR_INV_LENGTH); if (!rc) { unsigned int nbits; byte *p = gcry_mpi_get_opaque (data, &nbits); rc = pk_ecdh_encrypt_with_shared_point (shared, nshared, fp, p, (nbits+7)/8, pkey, &result); } xfree (shared); if (!rc) { resarr[0] = public; resarr[1] = result; } else { gcry_mpi_release (public); gcry_mpi_release (result); } } else /* Elgamal or RSA case. */ { /* Fixme: Add better error handling or make gnupg use S-expressions directly. */ resarr[0] = get_mpi_from_sexp (s_ciph, "a", GCRYMPI_FMT_USG); if (!is_RSA (algo)) resarr[1] = get_mpi_from_sexp (s_ciph, "b", GCRYMPI_FMT_USG); } gcry_sexp_release (s_ciph); return rc; } /* Check whether SKEY is a suitable secret key. */ int pk_check_secret_key (pubkey_algo_t pkalgo, gcry_mpi_t *skey) { gcry_sexp_t s_skey; int rc; if (pkalgo == PUBKEY_ALGO_DSA) { rc = gcry_sexp_build (&s_skey, NULL, "(private-key(dsa(p%m)(q%m)(g%m)(y%m)(x%m)))", skey[0], skey[1], skey[2], skey[3], skey[4]); } else if (pkalgo == PUBKEY_ALGO_ELGAMAL || pkalgo == PUBKEY_ALGO_ELGAMAL_E) { rc = gcry_sexp_build (&s_skey, NULL, "(private-key(elg(p%m)(g%m)(y%m)(x%m)))", skey[0], skey[1], skey[2], skey[3]); } else if (is_RSA (pkalgo)) { rc = gcry_sexp_build (&s_skey, NULL, "(private-key(rsa(n%m)(e%m)(d%m)(p%m)(q%m)(u%m)))", skey[0], skey[1], skey[2], skey[3], skey[4], skey[5]); } else if (pkalgo == PUBKEY_ALGO_ECDSA || pkalgo == PUBKEY_ALGO_ECDH) { char *curve = openpgp_oid_to_str (skey[0]); if (!curve) rc = gpg_error_from_syserror (); else { rc = gcry_sexp_build (&s_skey, NULL, "(private-key(ecc(curve%s)(q%m)(d%m)))", curve, skey[1], skey[2]); xfree (curve); } } else if (pkalgo == PUBKEY_ALGO_EDDSA) { char *curve = openpgp_oid_to_str (skey[0]); if (!curve) rc = gpg_error_from_syserror (); else { - rc = gcry_sexp_build (&s_skey, NULL, - "(private-key(ecc(curve %s)" - "(flags eddsa)(q%m)(d%m)))", - curve, skey[1], skey[2]); + const char *fmt; + + if (openpgp_oid_is_ed25519 (skey[0])) + 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); } } else return GPG_ERR_PUBKEY_ALGO; if (!rc) { rc = gcry_pk_testkey (s_skey); gcry_sexp_release (s_skey); } return rc; } diff --git a/g10/sign.c b/g10/sign.c index 8f72d8102..d6c938acc 100644 --- a/g10/sign.c +++ b/g10/sign.c @@ -1,1934 +1,1937 @@ /* sign.c - sign data * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, * 2007, 2010, 2012 Free Software Foundation, Inc. * * This file is part of GnuPG. * * GnuPG is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * GnuPG is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . */ #include #include #include #include #include #include "gpg.h" #include "options.h" #include "packet.h" #include "../common/status.h" #include "../common/iobuf.h" #include "keydb.h" #include "../common/util.h" #include "main.h" #include "filter.h" #include "../common/ttyio.h" #include "trustdb.h" #include "../common/status.h" #include "../common/i18n.h" #include "pkglue.h" #include "../common/sysutils.h" #include "call-agent.h" #include "../common/mbox-util.h" #include "../common/compliance.h" #ifdef HAVE_DOSISH_SYSTEM #define LF "\r\n" #else #define LF "\n" #endif /* Bitflags to convey hints on what kind of signayire is created. */ #define SIGNHINT_KEYSIG 1 #define SIGNHINT_SELFSIG 2 /* Hack */ static int recipient_digest_algo; /* A type for the extra data we hash into v5 signature packets. */ struct pt_extra_hash_data_s { unsigned char mode; u32 timestamp; unsigned char namelen; char name[1]; }; typedef struct pt_extra_hash_data_s *pt_extra_hash_data_t; /* * Create notations and other stuff. It is assumed that the strings in * STRLIST are already checked to contain only printable data and have * a valid NAME=VALUE format. */ static void mk_notation_policy_etc (ctrl_t ctrl, PKT_signature *sig, PKT_public_key *pk, PKT_public_key *pksk) { const char *string; char *p = NULL; strlist_t pu = NULL; struct notation *nd = NULL; struct expando_args args; log_assert (sig->version >= 4); memset (&args, 0, sizeof(args)); args.pk = pk; args.pksk = pksk; /* Notation data. */ if (IS_ATTST_SIGS(sig)) ; else if (IS_SIG(sig) && opt.sig_notations) nd = opt.sig_notations; else if (IS_CERT(sig) && opt.cert_notations) nd = opt.cert_notations; if (nd) { struct notation *item; for (item = nd; item; item = item->next) { item->altvalue = pct_expando (ctrl, item->value,&args); if (!item->altvalue) log_error (_("WARNING: unable to %%-expand notation " "(too large). Using unexpanded.\n")); } keygen_add_notations (sig, nd); for (item = nd; item; item = item->next) { xfree (item->altvalue); item->altvalue = NULL; } } /* Set policy URL. */ if (IS_ATTST_SIGS(sig)) ; else if (IS_SIG(sig) && opt.sig_policy_url) pu = opt.sig_policy_url; else if (IS_CERT(sig) && opt.cert_policy_url) pu = opt.cert_policy_url; for (; pu; pu = pu->next) { string = pu->d; p = pct_expando (ctrl, string, &args); if (!p) { log_error(_("WARNING: unable to %%-expand policy URL " "(too large). Using unexpanded.\n")); p = xstrdup(string); } build_sig_subpkt (sig, (SIGSUBPKT_POLICY | ((pu->flags & 1)?SIGSUBPKT_FLAG_CRITICAL:0)), p, strlen (p)); xfree (p); } /* Preferred keyserver URL. */ if (IS_SIG(sig) && opt.sig_keyserver_url) pu = opt.sig_keyserver_url; for (; pu; pu = pu->next) { string = pu->d; p = pct_expando (ctrl, string, &args); if (!p) { log_error (_("WARNING: unable to %%-expand preferred keyserver URL" " (too large). Using unexpanded.\n")); p = xstrdup (string); } build_sig_subpkt (sig, (SIGSUBPKT_PREF_KS | ((pu->flags & 1)?SIGSUBPKT_FLAG_CRITICAL:0)), p, strlen (p)); xfree (p); } /* Set signer's user id. */ if (IS_SIG (sig) && !opt.flags.disable_signer_uid) { char *mbox; /* For now we use the uid which was used to locate the key. */ if (pksk->user_id && (mbox = mailbox_from_userid (pksk->user_id->name, 0))) { if (DBG_LOOKUP) log_debug ("setting Signer's UID to '%s'\n", mbox); build_sig_subpkt (sig, SIGSUBPKT_SIGNERS_UID, mbox, strlen (mbox)); xfree (mbox); } else if (opt.sender_list) { /* If a list of --sender was given we scan that list and use * the first one matching a user id of the current key. */ /* FIXME: We need to get the list of user ids for the PKSK * packet. That requires either a function to look it up * again or we need to extend the key packet struct to link * to the primary key which in turn could link to the user * ids. Too much of a change right now. Let's take just * one from the supplied list and hope that the caller * passed a matching one. */ build_sig_subpkt (sig, SIGSUBPKT_SIGNERS_UID, opt.sender_list->d, strlen (opt.sender_list->d)); } } } /* * Put the Key Block subpacket into SIG for key PKSK. Returns an * error code on failure. */ static gpg_error_t mk_sig_subpkt_key_block (ctrl_t ctrl, PKT_signature *sig, PKT_public_key *pksk) { gpg_error_t err; char *mbox; char *filterexp = NULL; int save_opt_armor = opt.armor; int save_opt_verbose = opt.verbose; char hexfpr[2*MAX_FINGERPRINT_LEN + 1]; void *data = NULL; size_t datalen; kbnode_t keyblock = NULL; push_export_filters (); opt.armor = 0; hexfingerprint (pksk, hexfpr, sizeof hexfpr); /* Get the user id so that we know which one to insert into the * key. */ if (pksk->user_id && (mbox = mailbox_from_userid (pksk->user_id->name, 0))) { if (DBG_LOOKUP) log_debug ("including key with UID '%s' (specified)\n", mbox); filterexp = xasprintf ("keep-uid= -- mbox = %s", mbox); xfree (mbox); } else if (opt.sender_list) { /* If --sender was given we use the first one from that list. */ if (DBG_LOOKUP) log_debug ("including key with UID '%s' (--sender)\n", opt.sender_list->d); filterexp = xasprintf ("keep-uid= -- mbox = %s", opt.sender_list->d); } else /* Use the primary user id. */ { if (DBG_LOOKUP) log_debug ("including key with primary UID\n"); filterexp = xstrdup ("keep-uid= primary -t"); } if (DBG_LOOKUP) log_debug ("export filter expression: %s\n", filterexp); err = parse_and_set_export_filter (filterexp); if (err) goto leave; xfree (filterexp); filterexp = xasprintf ("drop-subkey= fpr <> %s && usage !~ e", hexfpr); if (DBG_LOOKUP) log_debug ("export filter expression: %s\n", filterexp); err = parse_and_set_export_filter (filterexp); if (err) goto leave; opt.verbose = 0; err = export_pubkey_buffer (ctrl, hexfpr, EXPORT_MINIMAL|EXPORT_CLEAN, "", 1, /* Prefix with the reserved byte. */ NULL, &keyblock, &data, &datalen); opt.verbose = save_opt_verbose; if (err) { log_error ("failed to get to be included key: %s\n", gpg_strerror (err)); goto leave; } build_sig_subpkt (sig, SIGSUBPKT_KEY_BLOCK, data, datalen); leave: xfree (data); release_kbnode (keyblock); xfree (filterexp); opt.armor = save_opt_armor; pop_export_filters (); return err; } /* * Helper to hash a user ID packet. */ static void hash_uid (gcry_md_hd_t md, int sigversion, const PKT_user_id *uid) { byte buf[5]; (void)sigversion; if (uid->attrib_data) { buf[0] = 0xd1; /* Indicates an attribute packet. */ buf[1] = uid->attrib_len >> 24; /* Always use 4 length bytes. */ buf[2] = uid->attrib_len >> 16; buf[3] = uid->attrib_len >> 8; buf[4] = uid->attrib_len; } else { buf[0] = 0xb4; /* Indicates a userid packet. */ buf[1] = uid->len >> 24; /* Always use 4 length bytes. */ buf[2] = uid->len >> 16; buf[3] = uid->len >> 8; buf[4] = uid->len; } gcry_md_write( md, buf, 5 ); if (uid->attrib_data) gcry_md_write (md, uid->attrib_data, uid->attrib_len ); else gcry_md_write (md, uid->name, uid->len ); } /* * Helper to hash some parts from the signature. EXTRAHASH gives the * extra data to be hashed into v5 signatures; it may by NULL for * detached signatures. */ static void hash_sigversion_to_magic (gcry_md_hd_t md, const PKT_signature *sig, pt_extra_hash_data_t extrahash) { byte buf[10]; int i; size_t n; gcry_md_putc (md, sig->version); gcry_md_putc (md, sig->sig_class); gcry_md_putc (md, sig->pubkey_algo); gcry_md_putc (md, sig->digest_algo); if (sig->hashed) { n = sig->hashed->len; gcry_md_putc (md, (n >> 8) ); gcry_md_putc (md, n ); gcry_md_write (md, sig->hashed->data, n ); n += 6; } else { gcry_md_putc (md, 0); /* Always hash the length of the subpacket. */ gcry_md_putc (md, 0); n = 6; } /* Hash data from the literal data packet. */ if (sig->version >= 5 && (sig->sig_class == 0x00 || sig->sig_class == 0x01)) { /* - One octet content format * - File name (one octet length followed by the name) * - Four octet timestamp */ if (extrahash) { buf[0] = extrahash->mode; buf[1] = extrahash->namelen; gcry_md_write (md, buf, 2); if (extrahash->namelen) gcry_md_write (md, extrahash->name, extrahash->namelen); buf[0] = extrahash->timestamp >> 24; buf[1] = extrahash->timestamp >> 16; buf[2] = extrahash->timestamp >> 8; buf[3] = extrahash->timestamp; gcry_md_write (md, buf, 4); } else /* Detached signatures */ { memset (buf, 0, 6); gcry_md_write (md, buf, 6); } } /* Add some magic aka known as postscript. The idea was to make it * impossible to make up a document with a v3 signature and then * turn this into a v4 signature for another document. The last * hashed 5 bytes of a v4 signature should never look like a the * last 5 bytes of a v3 signature. The length can be used to parse * from the end. */ i = 0; buf[i++] = sig->version; /* Hash convention version. */ buf[i++] = 0xff; /* Not any sig type value. */ if (sig->version >= 5) { /* Note: We don't hashed any data larger than 2^32 and thus we * can always use 0 here. See also note below. */ buf[i++] = 0; buf[i++] = 0; buf[i++] = 0; buf[i++] = 0; } buf[i++] = n >> 24; /* (n is only 16 bit, so this is always 0) */ buf[i++] = n >> 16; buf[i++] = n >> 8; buf[i++] = n; gcry_md_write (md, buf, i); } /* Perform the sign operation. If CACHE_NONCE is given the agent is * advised to use that cached passphrase for the key. SIGNHINTS has * hints so that we can do some additional checks. */ static int do_sign (ctrl_t ctrl, PKT_public_key *pksk, PKT_signature *sig, gcry_md_hd_t md, int mdalgo, const char *cache_nonce, unsigned int signhints) { gpg_error_t err; byte *dp; char *hexgrip; if (pksk->timestamp > sig->timestamp ) { ulong d = pksk->timestamp - sig->timestamp; log_info (ngettext("key %s was created %lu second" " in the future (time warp or clock problem)\n", "key %s was created %lu seconds" " in the future (time warp or clock problem)\n", d), keystr_from_pk (pksk), d); if (!opt.ignore_time_conflict) return gpg_error (GPG_ERR_TIME_CONFLICT); } print_pubkey_algo_note (pksk->pubkey_algo); if (!mdalgo) mdalgo = gcry_md_get_algo (md); if ((signhints & SIGNHINT_KEYSIG) && !(signhints & SIGNHINT_SELFSIG) && mdalgo == GCRY_MD_SHA1 && !opt.flags.allow_weak_key_signatures) { /* We do not allow the creation of third-party key signatures * using SHA-1 because we also reject them when verifying. Note * that this will render dsa1024 keys unsuitable for such * keysigs and in turn the WoT. */ print_sha1_keysig_rejected_note (); err = gpg_error (GPG_ERR_DIGEST_ALGO); goto leave; } /* Check compliance. */ if (! gnupg_digest_is_allowed (opt.compliance, 1, mdalgo)) { log_error (_("digest algorithm '%s' may not be used in %s mode\n"), gcry_md_algo_name (mdalgo), gnupg_compliance_option_string (opt.compliance)); err = gpg_error (GPG_ERR_DIGEST_ALGO); goto leave; } if (! gnupg_pk_is_allowed (opt.compliance, PK_USE_SIGNING, pksk->pubkey_algo, pksk->pkey, nbits_from_pk (pksk), NULL)) { log_error (_("key %s may not be used for signing in %s mode\n"), keystr_from_pk (pksk), gnupg_compliance_option_string (opt.compliance)); err = gpg_error (GPG_ERR_PUBKEY_ALGO); goto leave; } if (!gnupg_rng_is_compliant (opt.compliance)) { err = gpg_error (GPG_ERR_FORBIDDEN); log_error (_("%s is not compliant with %s mode\n"), "RNG", gnupg_compliance_option_string (opt.compliance)); write_status_error ("random-compliance", err); goto leave; } print_digest_algo_note (mdalgo); dp = gcry_md_read (md, mdalgo); sig->digest_algo = mdalgo; sig->digest_start[0] = dp[0]; sig->digest_start[1] = dp[1]; mpi_release (sig->data[0]); sig->data[0] = NULL; mpi_release (sig->data[1]); sig->data[1] = NULL; err = hexkeygrip_from_pk (pksk, &hexgrip); if (!err) { char *desc; gcry_sexp_t s_sigval; desc = gpg_format_keydesc (ctrl, pksk, FORMAT_KEYDESC_NORMAL, 1); err = agent_pksign (NULL/*ctrl*/, cache_nonce, hexgrip, desc, pksk->keyid, pksk->main_keyid, pksk->pubkey_algo, dp, gcry_md_get_algo_dlen (mdalgo), mdalgo, &s_sigval); xfree (desc); if (err) ; else if (pksk->pubkey_algo == GCRY_PK_RSA || pksk->pubkey_algo == GCRY_PK_RSA_S) sig->data[0] = get_mpi_from_sexp (s_sigval, "s", GCRYMPI_FMT_USG); else if (pksk->pubkey_algo == PUBKEY_ALGO_ECDSA || pksk->pubkey_algo == PUBKEY_ALGO_EDDSA) { err = sexp_extract_param_sos (s_sigval, "r", &sig->data[0]); if (!err) err = sexp_extract_param_sos (s_sigval, "s", &sig->data[1]); } else { sig->data[0] = get_mpi_from_sexp (s_sigval, "r", GCRYMPI_FMT_USG); sig->data[1] = get_mpi_from_sexp (s_sigval, "s", GCRYMPI_FMT_USG); } gcry_sexp_release (s_sigval); } xfree (hexgrip); leave: if (err) log_error (_("signing failed: %s\n"), gpg_strerror (err)); else { if (opt.verbose) { char *ustr = get_user_id_string_native (ctrl, sig->keyid); log_info (_("%s/%s signature from: \"%s\"\n"), openpgp_pk_algo_name (pksk->pubkey_algo), openpgp_md_algo_name (sig->digest_algo), ustr); xfree (ustr); } } return err; } static int complete_sig (ctrl_t ctrl, PKT_signature *sig, PKT_public_key *pksk, gcry_md_hd_t md, const char *cache_nonce, unsigned int signhints) { int rc; /* if (!(rc = check_secret_key (pksk, 0))) */ rc = do_sign (ctrl, pksk, sig, md, 0, cache_nonce, signhints); return rc; } /* Return true if the key seems to be on a version 1 OpenPGP card. This works by asking the agent and may fail if the card has not yet been used with the agent. */ static int openpgp_card_v1_p (PKT_public_key *pk) { gpg_error_t err; int result; /* Shortcut if we are not using RSA: The v1 cards only support RSA thus there is no point in looking any further. */ if (!is_RSA (pk->pubkey_algo)) return 0; if (!pk->flags.serialno_valid) { char *hexgrip; err = hexkeygrip_from_pk (pk, &hexgrip); if (err) { log_error ("error computing a keygrip: %s\n", gpg_strerror (err)); return 0; /* Ooops. */ } xfree (pk->serialno); agent_get_keyinfo (NULL, hexgrip, &pk->serialno, NULL); xfree (hexgrip); pk->flags.serialno_valid = 1; } if (!pk->serialno) result = 0; /* Error from a past agent_get_keyinfo or no card. */ else { /* The version number of the card is included in the serialno. */ result = !strncmp (pk->serialno, "D2760001240101", 14); } return result; } static int match_dsa_hash (unsigned int qbytes) { if (qbytes <= 20) return DIGEST_ALGO_SHA1; if (qbytes <= 28) return DIGEST_ALGO_SHA224; if (qbytes <= 32) return DIGEST_ALGO_SHA256; if (qbytes <= 48) return DIGEST_ALGO_SHA384; if (qbytes <= 66 ) /* 66 corresponds to 521 (64 to 512) */ return DIGEST_ALGO_SHA512; return DEFAULT_DIGEST_ALGO; /* DEFAULT_DIGEST_ALGO will certainly fail, but it's the best wrong answer we have if a digest larger than 512 bits is requested. */ } /* First try --digest-algo. If that isn't set, see if the recipient has a preferred algorithm (which is also filtered through --personal-digest-prefs). If we're making a signature without a particular recipient (i.e. signing, rather than signing+encrypting) then take the first algorithm in --personal-digest-prefs that is usable for the pubkey algorithm. If --personal-digest-prefs isn't 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 ECDSA. However, we use SHA256 as the default algorithm. Possible improvement: Use the highest-ranked usable algorithm from the signing key prefs either before or after using the personal list? */ static int hash_for (PKT_public_key *pk) { if (opt.def_digest_algo) { return opt.def_digest_algo; } else if (recipient_digest_algo) { return recipient_digest_algo; } - else if (pk->pubkey_algo == PUBKEY_ALGO_EDDSA - && openpgp_oid_is_ed25519 (pk->pkey[0])) + else if (pk->pubkey_algo == PUBKEY_ALGO_EDDSA) { if (opt.personal_digest_prefs) return opt.personal_digest_prefs[0].value; 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 || pk->pubkey_algo == PUBKEY_ALGO_ECDSA) { unsigned int qbytes = gcry_mpi_get_nbits (pk->pkey[1]); if (pk->pubkey_algo == PUBKEY_ALGO_ECDSA) qbytes = ecdsa_qbits_from_Q (qbytes); qbytes = qbytes/8; /* It's a DSA key, so find a hash that is the same size as q or larger. If q is 160, assume it is an old DSA key and use a 160-bit hash unless --enable-dsa2 is set, in which case act like a new DSA key that just happens to have a 160-bit q (i.e. allow truncation). If q is not 160, by definition it must be a new DSA key. */ if (opt.personal_digest_prefs) { prefitem_t *prefs; if (qbytes != 20 || opt.flags.dsa2) { for (prefs=opt.personal_digest_prefs; prefs->type; prefs++) if (gcry_md_get_algo_dlen (prefs->value) >= qbytes) return prefs->value; } else { for (prefs=opt.personal_digest_prefs; prefs->type; prefs++) if (gcry_md_get_algo_dlen (prefs->value) == qbytes) return prefs->value; } } return match_dsa_hash(qbytes); } else if (openpgp_card_v1_p (pk)) { /* The sk lives on a smartcard, and old smartcards only handle SHA-1 and RIPEMD/160. Newer smartcards (v2.0) don't have this restriction anymore. Fortunately the serial number encodes the version of the card and thus we know that this key is on a v1 card. */ if(opt.personal_digest_prefs) { prefitem_t *prefs; for (prefs=opt.personal_digest_prefs;prefs->type;prefs++) if (prefs->value==DIGEST_ALGO_SHA1 || prefs->value==DIGEST_ALGO_RMD160) return prefs->value; } return DIGEST_ALGO_SHA1; } else if (opt.personal_digest_prefs) { /* It's not DSA, so we can use whatever the first hash algorithm is in the pref list */ return opt.personal_digest_prefs[0].value; } else return DEFAULT_DIGEST_ALGO; } static void print_status_sig_created (PKT_public_key *pk, PKT_signature *sig, int what) { byte array[MAX_FINGERPRINT_LEN]; char buf[100+MAX_FINGERPRINT_LEN*2]; size_t n; snprintf (buf, sizeof buf - 2*MAX_FINGERPRINT_LEN, "%c %d %d %02x %lu ", what, sig->pubkey_algo, sig->digest_algo, sig->sig_class, (ulong)sig->timestamp ); fingerprint_from_pk (pk, array, &n); bin2hex (array, n, buf + strlen (buf)); write_status_text( STATUS_SIG_CREATED, buf ); } /* * Loop over the secret certificates in SK_LIST and build the one pass * signature packets. OpenPGP says that the data should be bracket by * the onepass-sig and signature-packet; so we build these onepass * packet here in reverse order. */ static int write_onepass_sig_packets (SK_LIST sk_list, IOBUF out, int sigclass ) { int skcount; SK_LIST sk_rover; for (skcount=0, sk_rover=sk_list; sk_rover; sk_rover = sk_rover->next) skcount++; for (; skcount; skcount--) { PKT_public_key *pk; PKT_onepass_sig *ops; PACKET pkt; int i, rc; for (i=0, sk_rover = sk_list; sk_rover; sk_rover = sk_rover->next) if (++i == skcount) break; pk = sk_rover->pk; ops = xmalloc_clear (sizeof *ops); ops->sig_class = sigclass; ops->digest_algo = hash_for (pk); ops->pubkey_algo = pk->pubkey_algo; keyid_from_pk (pk, ops->keyid); ops->last = (skcount == 1); init_packet (&pkt); pkt.pkttype = PKT_ONEPASS_SIG; pkt.pkt.onepass_sig = ops; rc = build_packet (out, &pkt); free_packet (&pkt, NULL); if (rc) { log_error ("build onepass_sig packet failed: %s\n", gpg_strerror (rc)); return rc; } } return 0; } /* * Helper to write the plaintext (literal data) packet. At * R_EXTRAHASH a malloced object with the with the extra data hashed * into v5 signatures is stored. */ static int write_plaintext_packet (iobuf_t out, iobuf_t inp, const char *fname, int ptmode, pt_extra_hash_data_t *r_extrahash) { PKT_plaintext *pt = NULL; u32 filesize; int rc = 0; if (!opt.no_literal) pt = setup_plaintext_name (fname, inp); /* Try to calculate the length of the data. */ if ( !iobuf_is_pipe_filename (fname) && *fname) { off_t tmpsize; int overflow; if (!(tmpsize = iobuf_get_filelength (inp, &overflow)) && !overflow && opt.verbose) log_info (_("WARNING: '%s' is an empty file\n"), fname); /* We can't encode the length of very large files because * OpenPGP uses only 32 bit for file sizes. So if the size of a * file is larger than 2^32 minus some bytes for packet headers, * we switch to partial length encoding. */ if (tmpsize < (IOBUF_FILELENGTH_LIMIT - 65536)) filesize = tmpsize; else filesize = 0; /* Because the text_filter modifies the length of the * data, it is not possible to know the used length * without a double read of the file - to avoid that * we simple use partial length packets. */ if (ptmode == 't' || ptmode == 'u' || ptmode == 'm') filesize = 0; } else filesize = opt.set_filesize? opt.set_filesize : 0; /* stdin */ if (!opt.no_literal) { PACKET pkt; /* Note that PT has been initialized above in no_literal mode. */ pt->timestamp = make_timestamp (); pt->mode = ptmode; pt->len = filesize; pt->new_ctb = !pt->len; pt->buf = inp; init_packet (&pkt); pkt.pkttype = PKT_PLAINTEXT; pkt.pkt.plaintext = pt; /*cfx.datalen = filesize? calc_packet_length( &pkt ) : 0;*/ if ((rc = build_packet (out, &pkt))) log_error ("build_packet(PLAINTEXT) failed: %s\n", gpg_strerror (rc) ); *r_extrahash = xtrymalloc (sizeof **r_extrahash + pt->namelen); if (!*r_extrahash) rc = gpg_error_from_syserror (); else { (*r_extrahash)->mode = pt->mode; (*r_extrahash)->timestamp = pt->timestamp; (*r_extrahash)->namelen = pt->namelen; /* Note that the last byte of NAME won't be initialized * because we don't need it. */ memcpy ((*r_extrahash)->name, pt->name, pt->namelen); } pt->buf = NULL; free_packet (&pkt, NULL); } else { byte copy_buffer[4096]; int bytes_copied; *r_extrahash = xtrymalloc (sizeof **r_extrahash); if (!*r_extrahash) { rc = gpg_error_from_syserror (); goto leave; } /* FIXME: We need to parse INP to get the to be hashed data from * it. */ (*r_extrahash)->mode = 0; (*r_extrahash)->timestamp = 0; (*r_extrahash)->namelen = 0; while ((bytes_copied = iobuf_read (inp, copy_buffer, 4096)) != -1) if ((rc = iobuf_write (out, copy_buffer, bytes_copied))) { log_error ("copying input to output failed: %s\n", gpg_strerror (rc)); break; } wipememory (copy_buffer, 4096); /* burn buffer */ } leave: return rc; } /* * Write the signatures from the SK_LIST to OUT. HASH must be a * non-finalized hash which will not be changes here. EXTRAHASH is * either NULL or the extra data tro be hashed into v5 signatures. */ static int write_signature_packets (ctrl_t ctrl, SK_LIST sk_list, IOBUF out, gcry_md_hd_t hash, pt_extra_hash_data_t extrahash, int sigclass, u32 timestamp, u32 duration, int status_letter, const char *cache_nonce) { SK_LIST sk_rover; /* Loop over the certificates with secret keys. */ for (sk_rover = sk_list; sk_rover; sk_rover = sk_rover->next) { PKT_public_key *pk; PKT_signature *sig; gcry_md_hd_t md; gpg_error_t err; pk = sk_rover->pk; /* Build the signature packet. */ sig = xtrycalloc (1, sizeof *sig); if (!sig) return gpg_error_from_syserror (); if (pk->version >= 5) sig->version = 5; /* Required for v5 keys. */ else sig->version = 4; /* Required. */ keyid_from_pk (pk, sig->keyid); sig->digest_algo = hash_for (pk); sig->pubkey_algo = pk->pubkey_algo; if (timestamp) sig->timestamp = timestamp; else sig->timestamp = make_timestamp(); if (duration) sig->expiredate = sig->timestamp + duration; sig->sig_class = sigclass; if (gcry_md_copy (&md, hash)) BUG (); build_sig_subpkt_from_sig (sig, pk); mk_notation_policy_etc (ctrl, sig, NULL, pk); if (opt.flags.include_key_block && IS_SIG (sig)) err = mk_sig_subpkt_key_block (ctrl, sig, pk); else err = 0; hash_sigversion_to_magic (md, sig, extrahash); gcry_md_final (md); if (!err) err = do_sign (ctrl, pk, sig, md, hash_for (pk), cache_nonce, 0); gcry_md_close (md); if (!err) { /* Write the packet. */ PACKET pkt; init_packet (&pkt); pkt.pkttype = PKT_SIGNATURE; pkt.pkt.signature = sig; err = build_packet (out, &pkt); if (!err && is_status_enabled()) print_status_sig_created (pk, sig, status_letter); free_packet (&pkt, NULL); if (err) log_error ("build signature packet failed: %s\n", gpg_strerror (err)); } else free_seckey_enc (sig); if (err) return err; } return 0; } /* * Sign the files whose names are in FILENAME. * If DETACHED has the value true, * make a detached signature. If FILENAMES->d is NULL read from stdin * and ignore the detached mode. Sign the file with all secret keys * which can be taken from LOCUSR, if this is NULL, use the default one * If ENCRYPTFLAG is true, use REMUSER (or ask if it is NULL) to encrypt the * signed data for these users. * If OUTFILE is not NULL; this file is used for output and the function * does not ask for overwrite permission; output is then always * uncompressed, non-armored and in binary mode. */ int sign_file (ctrl_t ctrl, strlist_t filenames, int detached, strlist_t locusr, int encryptflag, strlist_t remusr, const char *outfile ) { const char *fname; armor_filter_context_t *afx; compress_filter_context_t zfx; md_filter_context_t mfx; text_filter_context_t tfx; progress_filter_context_t *pfx; encrypt_filter_context_t efx; iobuf_t inp = NULL; iobuf_t out = NULL; PACKET pkt; int rc = 0; PK_LIST pk_list = NULL; SK_LIST sk_list = NULL; SK_LIST sk_rover = NULL; int multifile = 0; u32 duration=0; pt_extra_hash_data_t extrahash = NULL; pfx = new_progress_context (); afx = new_armor_context (); memset (&zfx, 0, sizeof zfx); memset (&mfx, 0, sizeof mfx); memset (&efx, 0, sizeof efx); efx.ctrl = ctrl; init_packet (&pkt); if (filenames) { fname = filenames->d; multifile = !!filenames->next; } else fname = NULL; if (fname && filenames->next && (!detached || encryptflag)) log_bug ("multiple files can only be detached signed"); if (encryptflag == 2 && (rc = setup_symkey (&efx.symkey_s2k, &efx.symkey_dek))) goto leave; if (opt.ask_sig_expire && !opt.batch) duration = ask_expire_interval(1,opt.def_sig_expire); else duration = parse_expire_string(opt.def_sig_expire); /* Note: In the old non-agent version the following call used to * unprotect the secret key. This is now done on demand by the agent. */ if ((rc = build_sk_list (ctrl, locusr, &sk_list, PUBKEY_USAGE_SIG ))) goto leave; if (encryptflag && (rc = build_pk_list (ctrl, remusr, &pk_list))) goto leave; /* Prepare iobufs. */ if (multifile) /* have list of filenames */ inp = NULL; /* we do it later */ else { inp = iobuf_open(fname); if (inp && is_secured_file (iobuf_get_fd (inp))) { iobuf_close (inp); inp = NULL; gpg_err_set_errno (EPERM); } if (!inp) { rc = gpg_error_from_syserror (); log_error (_("can't open '%s': %s\n"), fname? fname: "[stdin]", strerror (errno)); goto leave; } handle_progress (pfx, inp, fname); } if (outfile) { if (is_secured_filename (outfile)) { out = NULL; gpg_err_set_errno (EPERM); } else out = iobuf_create (outfile, 0); if (!out) { rc = gpg_error_from_syserror (); log_error (_("can't create '%s': %s\n"), outfile, gpg_strerror (rc)); goto leave; } else if (opt.verbose) log_info (_("writing to '%s'\n"), outfile); } else if ((rc = open_outfile (-1, fname, opt.armor? 1 : detached? 2 : 0, 0, &out))) { goto leave; } /* Prepare to calculate the MD over the input. */ if (opt.textmode && !outfile && !multifile) { memset (&tfx, 0, sizeof tfx); iobuf_push_filter (inp, text_filter, &tfx); } if (gcry_md_open (&mfx.md, 0, 0)) BUG (); if (DBG_HASHING) gcry_md_debug (mfx.md, "sign"); /* If we're encrypting and signing, it is reasonable to pick the * hash algorithm to use out of the recipient key prefs. This is * best effort only, as in a DSA2 and smartcard world there are * cases where we cannot please everyone with a single hash (DSA2 * wants >160 and smartcards want =160). In the future this could * be more complex with different hashes for each sk, but the * current design requires a single hash for all SKs. */ if (pk_list) { if (opt.def_digest_algo) { if (!opt.expert && select_algo_from_prefs (pk_list,PREFTYPE_HASH, opt.def_digest_algo, NULL) != opt.def_digest_algo) { log_info (_("WARNING: forcing digest algorithm %s (%d)" " violates recipient preferences\n"), gcry_md_algo_name (opt.def_digest_algo), opt.def_digest_algo); } } else { int algo; int smartcard=0; union pref_hint hint; hint.digest_length = 0; /* Of course, if the recipient asks for something * unreasonable (like the wrong hash for a DSA key) then * don't do it. Check all sk's - if any are DSA or live * on a smartcard, then the hash has restrictions and we * may not be able to give the recipient what they want. * For DSA, pass a hint for the largest q we have. Note * that this means that a q>160 key will override a q=160 * key and force the use of truncation for the q=160 key. * The alternative would be to ignore the recipient prefs * completely and get a different hash for each DSA key in * hash_for(). The override behavior here is more or less * reasonable as it is under the control of the user which * keys they sign with for a given message and the fact * that the message with multiple signatures won't be * usable on an implementation that doesn't understand * DSA2 anyway. */ for (sk_rover = sk_list; sk_rover; sk_rover = sk_rover->next ) { if (sk_rover->pk->pubkey_algo == PUBKEY_ALGO_DSA || sk_rover->pk->pubkey_algo == PUBKEY_ALGO_ECDSA) { int temp_hashlen = gcry_mpi_get_nbits (sk_rover->pk->pkey[1]); if (sk_rover->pk->pubkey_algo == PUBKEY_ALGO_ECDSA) temp_hashlen = ecdsa_qbits_from_Q (temp_hashlen); temp_hashlen = (temp_hashlen+7)/8; /* Pick a hash that is large enough for our largest Q */ if (hint.digest_length < temp_hashlen) hint.digest_length = temp_hashlen; } /* FIXME: need to check gpg-agent for this. */ /* else if (sk_rover->pk->is_protected */ /* && sk_rover->pk->protect.s2k.mode == 1002) */ /* smartcard = 1; */ } /* Current smartcards only do 160-bit hashes. If we have * to have a >160-bit hash, then we can't use the * recipient prefs as we'd need both =160 and >160 at the * same time and recipient prefs currently require a * single hash for all signatures. All this may well have * to change as the cards add algorithms. */ if ((!smartcard || (smartcard && hint.digest_length==20)) && ((algo = select_algo_from_prefs (pk_list, PREFTYPE_HASH, -1, &hint)) > 0)) { recipient_digest_algo = algo; } } } for (sk_rover = sk_list; sk_rover; sk_rover = sk_rover->next) gcry_md_enable (mfx.md, hash_for (sk_rover->pk)); if (!multifile) iobuf_push_filter (inp, md_filter, &mfx); if (detached && !encryptflag) afx->what = 2; if (opt.armor && !outfile) push_armor_filter (afx, out); if (encryptflag) { efx.pk_list = pk_list; /* fixme: set efx.cfx.datalen if known */ iobuf_push_filter (out, encrypt_filter, &efx); } if (opt.compress_algo && !outfile && !detached) { int compr_algo = opt.compress_algo; /* If not forced by user */ if (compr_algo==-1) { /* If we're not encrypting, then select_algo_from_prefs * will fail and we'll end up with the default. If we are * encrypting, select_algo_from_prefs cannot fail since * there is an assumed preference for uncompressed data. * Still, if it did fail, we'll also end up with the * default. */ if ((compr_algo = select_algo_from_prefs (pk_list, PREFTYPE_ZIP, -1, NULL)) == -1) { compr_algo = default_compress_algo(); } } else if (!opt.expert && pk_list && select_algo_from_prefs (pk_list, PREFTYPE_ZIP, compr_algo, NULL) != compr_algo) { log_info (_("WARNING: forcing compression algorithm %s (%d)" " violates recipient preferences\n"), compress_algo_to_string (compr_algo), compr_algo); } /* Algo 0 means no compression. */ if (compr_algo) push_compress_filter (out, &zfx, compr_algo); } /* Write the one-pass signature packets if needed */ if (!detached) { rc = write_onepass_sig_packets (sk_list, out, opt.textmode && !outfile ? 0x01:0x00); if (rc) goto leave; } write_status_begin_signing (mfx.md); /* Setup the inner packet. */ if (detached) { if (multifile) { strlist_t sl; if (opt.verbose) log_info (_("signing:") ); /* Must walk reverse trough this list. */ for (sl = strlist_last(filenames); sl; sl = strlist_prev( filenames, sl)) { inp = iobuf_open (sl->d); if (inp && is_secured_file (iobuf_get_fd (inp))) { iobuf_close (inp); inp = NULL; gpg_err_set_errno (EPERM); } if (!inp) { rc = gpg_error_from_syserror (); log_error (_("can't open '%s': %s\n"), sl->d, gpg_strerror (rc)); goto leave; } handle_progress (pfx, inp, sl->d); if (opt.verbose) log_printf (" '%s'", sl->d ); if (opt.textmode) { memset (&tfx, 0, sizeof tfx); iobuf_push_filter (inp, text_filter, &tfx); } iobuf_push_filter (inp, md_filter, &mfx); while (iobuf_get (inp) != -1) ; iobuf_close (inp); inp = NULL; } if (opt.verbose) log_printf ("\n"); } else { /* Read, so that the filter can calculate the digest. */ while (iobuf_get(inp) != -1) ; } } else { rc = write_plaintext_packet (out, inp, fname, (opt.textmode && !outfile) ? (opt.mimemode? 'm' : 't') : 'b', &extrahash); } /* Catch errors from above. */ if (rc) goto leave; /* Write the signatures. */ rc = write_signature_packets (ctrl, sk_list, out, mfx.md, extrahash, opt.textmode && !outfile? 0x01 : 0x00, 0, duration, detached ? 'D':'S', NULL); if (rc) goto leave; leave: if (rc) iobuf_cancel (out); else { iobuf_close (out); if (encryptflag) write_status (STATUS_END_ENCRYPTION); } iobuf_close (inp); gcry_md_close (mfx.md); release_sk_list (sk_list); release_pk_list (pk_list); recipient_digest_algo = 0; release_progress_context (pfx); release_armor_context (afx); xfree (extrahash); return rc; } /* * Make a clear signature. Note that opt.armor is not needed. */ int clearsign_file (ctrl_t ctrl, const char *fname, strlist_t locusr, const char *outfile) { armor_filter_context_t *afx; progress_filter_context_t *pfx; gcry_md_hd_t textmd = NULL; iobuf_t inp = NULL; iobuf_t out = NULL; PACKET pkt; int rc = 0; SK_LIST sk_list = NULL; SK_LIST sk_rover = NULL; u32 duration = 0; pfx = new_progress_context (); afx = new_armor_context (); init_packet( &pkt ); if (opt.ask_sig_expire && !opt.batch) duration = ask_expire_interval (1, opt.def_sig_expire); else duration = parse_expire_string (opt.def_sig_expire); /* Note: In the old non-agent version the following call used to * unprotect the secret key. This is now done on demand by the agent. */ if ((rc=build_sk_list (ctrl, locusr, &sk_list, PUBKEY_USAGE_SIG))) goto leave; /* Prepare iobufs. */ inp = iobuf_open (fname); if (inp && is_secured_file (iobuf_get_fd (inp))) { iobuf_close (inp); inp = NULL; gpg_err_set_errno (EPERM); } if (!inp) { rc = gpg_error_from_syserror (); log_error (_("can't open '%s': %s\n"), fname? fname: "[stdin]", gpg_strerror (rc)); goto leave; } handle_progress (pfx, inp, fname); if (outfile) { if (is_secured_filename (outfile)) { outfile = NULL; gpg_err_set_errno (EPERM); } else out = iobuf_create (outfile, 0); if (!out) { rc = gpg_error_from_syserror (); log_error (_("can't create '%s': %s\n"), outfile, gpg_strerror (rc)); goto leave; } else if (opt.verbose) log_info (_("writing to '%s'\n"), outfile); } else if ((rc = open_outfile (-1, fname, 1, 0, &out))) { goto leave; } iobuf_writestr (out, "-----BEGIN PGP SIGNED MESSAGE-----" LF); { const char *s; int any = 0; byte hashs_seen[256]; memset (hashs_seen, 0, sizeof hashs_seen); iobuf_writestr (out, "Hash: " ); for (sk_rover = sk_list; sk_rover; sk_rover = sk_rover->next) { int i = hash_for (sk_rover->pk); if (!hashs_seen[ i & 0xff ]) { s = gcry_md_algo_name (i); if (s) { hashs_seen[ i & 0xff ] = 1; if (any) iobuf_put (out, ','); iobuf_writestr (out, s); any = 1; } } } log_assert (any); iobuf_writestr (out, LF); } if (opt.not_dash_escaped) iobuf_writestr (out, "NotDashEscaped: You need "GPG_NAME " to verify this message" LF); iobuf_writestr (out, LF ); if (gcry_md_open (&textmd, 0, 0)) BUG (); for (sk_rover = sk_list; sk_rover; sk_rover = sk_rover->next) gcry_md_enable (textmd, hash_for(sk_rover->pk)); if (DBG_HASHING) gcry_md_debug (textmd, "clearsign"); copy_clearsig_text (out, inp, textmd, !opt.not_dash_escaped, opt.escape_from); /* fixme: check for read errors */ /* Now write the armor. */ afx->what = 2; push_armor_filter (afx, out); /* Write the signatures. */ rc = write_signature_packets (ctrl, sk_list, out, textmd, NULL, 0x01, 0, duration, 'C', NULL); if (rc) goto leave; leave: if (rc) iobuf_cancel (out); else iobuf_close (out); iobuf_close (inp); gcry_md_close (textmd); release_sk_list (sk_list); release_progress_context (pfx); release_armor_context (afx); return rc; } /* * Sign and conventionally encrypt the given file. * FIXME: Far too much code is duplicated - revamp the whole file. */ int sign_symencrypt_file (ctrl_t ctrl, const char *fname, strlist_t locusr) { armor_filter_context_t *afx; progress_filter_context_t *pfx; compress_filter_context_t zfx; md_filter_context_t mfx; text_filter_context_t tfx; cipher_filter_context_t cfx; iobuf_t inp = NULL; iobuf_t out = NULL; PACKET pkt; STRING2KEY *s2k = NULL; int rc = 0; SK_LIST sk_list = NULL; SK_LIST sk_rover = NULL; int algo; u32 duration = 0; int canceled; pt_extra_hash_data_t extrahash = NULL; pfx = new_progress_context (); afx = new_armor_context (); memset (&zfx, 0, sizeof zfx); memset (&mfx, 0, sizeof mfx); memset (&tfx, 0, sizeof tfx); memset (&cfx, 0, sizeof cfx); init_packet (&pkt); if (opt.ask_sig_expire && !opt.batch) duration = ask_expire_interval (1, opt.def_sig_expire); else duration = parse_expire_string (opt.def_sig_expire); /* Note: In the old non-agent version the following call used to * unprotect the secret key. This is now done on demand by the agent. */ rc = build_sk_list (ctrl, locusr, &sk_list, PUBKEY_USAGE_SIG); if (rc) goto leave; /* Prepare iobufs. */ inp = iobuf_open (fname); if (inp && is_secured_file (iobuf_get_fd (inp))) { iobuf_close (inp); inp = NULL; gpg_err_set_errno (EPERM); } if (!inp) { rc = gpg_error_from_syserror (); log_error (_("can't open '%s': %s\n"), fname? fname: "[stdin]", gpg_strerror (rc)); goto leave; } handle_progress (pfx, inp, fname); /* Prepare key. */ s2k = xmalloc_clear (sizeof *s2k); s2k->mode = opt.s2k_mode; s2k->hash_algo = S2K_DIGEST_ALGO; algo = default_cipher_algo (); cfx.dek = passphrase_to_dek (algo, s2k, 1, 1, NULL, &canceled); if (!cfx.dek || !cfx.dek->keylen) { rc = gpg_error (canceled?GPG_ERR_CANCELED:GPG_ERR_BAD_PASSPHRASE); log_error (_("error creating passphrase: %s\n"), gpg_strerror (rc)); goto leave; } cfx.dek->use_aead = use_aead (NULL, cfx.dek->algo); if (!cfx.dek->use_aead) cfx.dek->use_mdc = !!use_mdc (NULL, cfx.dek->algo); if (!opt.quiet || !opt.batch) log_info (_("%s.%s encryption will be used\n"), openpgp_cipher_algo_name (algo), cfx.dek->use_aead? openpgp_aead_algo_name (cfx.dek->use_aead) /**/ : "CFB"); /* Now create the outfile. */ rc = open_outfile (-1, fname, opt.armor? 1:0, 0, &out); if (rc) goto leave; /* Prepare to calculate the MD over the input. */ if (opt.textmode) iobuf_push_filter (inp, text_filter, &tfx); if (gcry_md_open (&mfx.md, 0, 0)) BUG (); if (DBG_HASHING) gcry_md_debug (mfx.md, "symc-sign"); for (sk_rover = sk_list; sk_rover; sk_rover = sk_rover->next) gcry_md_enable (mfx.md, hash_for (sk_rover->pk)); iobuf_push_filter (inp, md_filter, &mfx); /* Push armor output filter */ if (opt.armor) push_armor_filter (afx, out); /* Write the symmetric key packet */ /* (current filters: armor)*/ { PKT_symkey_enc *enc = xmalloc_clear( sizeof *enc ); enc->version = 4; enc->cipher_algo = cfx.dek->algo; enc->s2k = *s2k; pkt.pkttype = PKT_SYMKEY_ENC; pkt.pkt.symkey_enc = enc; if ((rc = build_packet (out, &pkt))) log_error ("build symkey packet failed: %s\n", gpg_strerror (rc)); xfree (enc); } /* Push the encryption filter */ iobuf_push_filter (out, cfx.dek->use_aead? cipher_filter_aead /**/ : cipher_filter_cfb, &cfx); /* Push the compress filter */ if (default_compress_algo()) { if (cfx.dek && (cfx.dek->use_mdc || cfx.dek->use_aead)) zfx.new_ctb = 1; push_compress_filter (out, &zfx,default_compress_algo() ); } /* Write the one-pass signature packets */ /* (current filters: zip - encrypt - armor) */ rc = write_onepass_sig_packets (sk_list, out, opt.textmode? 0x01:0x00); if (rc) goto leave; write_status_begin_signing (mfx.md); /* Pipe data through all filters; i.e. write the signed stuff. */ /* (current filters: zip - encrypt - armor) */ rc = write_plaintext_packet (out, inp, fname, opt.textmode ? (opt.mimemode?'m':'t'):'b', &extrahash); if (rc) goto leave; /* Write the signatures. */ /* (current filters: zip - encrypt - armor) */ rc = write_signature_packets (ctrl, sk_list, out, mfx.md, extrahash, opt.textmode? 0x01 : 0x00, 0, duration, 'S', NULL); if (rc) goto leave; leave: if (rc) iobuf_cancel (out); else { iobuf_close (out); write_status (STATUS_END_ENCRYPTION); } iobuf_close (inp); release_sk_list (sk_list); gcry_md_close (mfx.md); xfree (cfx.dek); xfree (s2k); release_progress_context (pfx); release_armor_context (afx); xfree (extrahash); return rc; } /* * Create a v4 signature in *RET_SIG. * * PK is the primary key to sign (required for all sigs) * UID is the user id to sign (required for 0x10..0x13, 0x30) * SUBPK is subkey to sign (required for 0x18, 0x19, 0x28) * * PKSK is the signing key * * SIGCLASS is the type of signature to create. * * DIGEST_ALGO is the digest algorithm. If it is 0 the function * selects an appropriate one. * * TIMESTAMP is the timestamp to use for the signature. 0 means "now" * * DURATION is the amount of time (in seconds) until the signature * expires. * * This function creates the following subpackets: issuer, created, * and expire (if duration is not 0). Additional subpackets can be * added using MKSUBPKT, which is called after these subpackets are * added and before the signature is generated. OPAQUE is passed to * MKSUBPKT. */ int make_keysig_packet (ctrl_t ctrl, PKT_signature **ret_sig, PKT_public_key *pk, PKT_user_id *uid, PKT_public_key *subpk, PKT_public_key *pksk, int sigclass, u32 timestamp, u32 duration, int (*mksubpkt)(PKT_signature *, void *), void *opaque, const char *cache_nonce) { PKT_signature *sig; int rc = 0; int sigversion; int digest_algo; gcry_md_hd_t md; u32 pk_keyid[2], pksk_keyid[2]; unsigned int signhints; log_assert ((sigclass >= 0x10 && sigclass <= 0x13) || sigclass == 0x1F || sigclass == 0x20 || sigclass == 0x18 || sigclass == 0x19 || sigclass == 0x30 || sigclass == 0x28 ); if (pksk->version >= 5) sigversion = 5; else sigversion = 4; /* Select the digest algo to use. */ if (opt.cert_digest_algo) /* Forceful override by the user. */ digest_algo = opt.cert_digest_algo; else if (pksk->pubkey_algo == PUBKEY_ALGO_DSA) /* Meet DSA requirements. */ digest_algo = match_dsa_hash (gcry_mpi_get_nbits (pksk->pkey[1])/8); - else if (pksk->pubkey_algo == PUBKEY_ALGO_ECDSA /* Meet ECDSA requirements. */ - || pksk->pubkey_algo == PUBKEY_ALGO_EDDSA) + else if (pksk->pubkey_algo == PUBKEY_ALGO_ECDSA) /* Meet ECDSA requirements. */ + 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])) - digest_algo = DIGEST_ALGO_SHA256; + if (gcry_mpi_get_nbits (pksk->pkey[1]) > 256) + digest_algo = DIGEST_ALGO_SHA512; else - digest_algo = match_dsa_hash - (ecdsa_qbits_from_Q (gcry_mpi_get_nbits (pksk->pkey[1]))/8); + digest_algo = DIGEST_ALGO_SHA256; } else /* Use the default. */ digest_algo = DEFAULT_DIGEST_ALGO; signhints = SIGNHINT_KEYSIG; keyid_from_pk (pk, pk_keyid); keyid_from_pk (pksk, pksk_keyid); if (pk_keyid[0] == pksk_keyid[0] && pk_keyid[1] == pksk_keyid[1]) signhints |= SIGNHINT_SELFSIG; if (gcry_md_open (&md, digest_algo, 0)) BUG (); /* Hash the public key certificate. */ hash_public_key (md, pk); if (sigclass == 0x18 || sigclass == 0x19 || sigclass == 0x28) { /* Hash the subkey binding/backsig/revocation. */ hash_public_key (md, subpk); } else if (sigclass != 0x1F && sigclass != 0x20) { /* Hash the user id. */ hash_uid (md, sigversion, uid); } /* Make the signature packet. */ sig = xmalloc_clear (sizeof *sig); sig->version = sigversion; sig->flags.exportable = 1; sig->flags.revocable = 1; keyid_from_pk (pksk, sig->keyid); sig->pubkey_algo = pksk->pubkey_algo; sig->digest_algo = digest_algo; sig->timestamp = timestamp? timestamp : make_timestamp (); if (duration) sig->expiredate = sig->timestamp + duration; sig->sig_class = sigclass; build_sig_subpkt_from_sig (sig, pksk); mk_notation_policy_etc (ctrl, sig, pk, pksk); /* Crucial that the call to mksubpkt comes LAST before the calls * to finalize the sig as that makes it possible for the mksubpkt * function to get a reliable pointer to the subpacket area. */ if (mksubpkt) rc = (*mksubpkt)(sig, opaque); if (!rc) { hash_sigversion_to_magic (md, sig, NULL); gcry_md_final (md); rc = complete_sig (ctrl, sig, pksk, md, cache_nonce, signhints); } gcry_md_close (md); if (rc) free_seckey_enc (sig); else *ret_sig = sig; return rc; } /* * Create a new signature packet based on an existing one. * Only user ID signatures are supported for now. * PK is the public key to work on. * PKSK is the key used to make the signature. * * TODO: Merge this with make_keysig_packet. */ gpg_error_t update_keysig_packet (ctrl_t ctrl, PKT_signature **ret_sig, PKT_signature *orig_sig, PKT_public_key *pk, PKT_user_id *uid, PKT_public_key *subpk, PKT_public_key *pksk, int (*mksubpkt)(PKT_signature *, void *), void *opaque) { PKT_signature *sig; gpg_error_t rc = 0; int digest_algo; gcry_md_hd_t md; u32 pk_keyid[2], pksk_keyid[2]; unsigned int signhints = 0; if ((!orig_sig || !pk || !pksk) || (orig_sig->sig_class >= 0x10 && orig_sig->sig_class <= 0x13 && !uid) || (orig_sig->sig_class == 0x18 && !subpk)) return GPG_ERR_GENERAL; /* Either use the override digest algo or in the normal case the * original digest algorithm. However, iff the original digest * algorithms is SHA-1 and we are in gnupg or de-vs compliance mode * we switch to SHA-256 (done by the macro). */ if (opt.cert_digest_algo) digest_algo = opt.cert_digest_algo; else if (pksk->pubkey_algo == PUBKEY_ALGO_DSA || pksk->pubkey_algo == PUBKEY_ALGO_ECDSA || pksk->pubkey_algo == PUBKEY_ALGO_EDDSA) digest_algo = orig_sig->digest_algo; else if (orig_sig->digest_algo == DIGEST_ALGO_SHA1 || orig_sig->digest_algo == DIGEST_ALGO_RMD160) digest_algo = DEFAULT_DIGEST_ALGO; else digest_algo = orig_sig->digest_algo; signhints = SIGNHINT_KEYSIG; keyid_from_pk (pk, pk_keyid); keyid_from_pk (pksk, pksk_keyid); if (pk_keyid[0] == pksk_keyid[0] && pk_keyid[1] == pksk_keyid[1]) signhints |= SIGNHINT_SELFSIG; if (gcry_md_open (&md, digest_algo, 0)) BUG (); /* Hash the public key certificate and the user id. */ hash_public_key (md, pk); if (orig_sig->sig_class == 0x18) hash_public_key (md, subpk); else hash_uid (md, orig_sig->version, uid); /* Create a new signature packet. */ sig = copy_signature (NULL, orig_sig); sig->digest_algo = digest_algo; /* We need to create a new timestamp so that new sig expiration * calculations are done correctly... */ sig->timestamp = make_timestamp(); /* ... but we won't make a timestamp earlier than the existing * one. */ { int tmout = 0; while (sig->timestamp <= orig_sig->timestamp) { if (++tmout > 5 && !opt.ignore_time_conflict) { rc = gpg_error (GPG_ERR_TIME_CONFLICT); goto leave; } gnupg_sleep (1); sig->timestamp = make_timestamp(); } } /* Note that already expired sigs will remain expired (with a * duration of 1) since build-packet.c:build_sig_subpkt_from_sig * detects this case. */ /* Put the updated timestamp into the sig. Note that this will * automagically lower any sig expiration dates to correctly * correspond to the differences in the timestamps (i.e. the * duration will shrink). */ build_sig_subpkt_from_sig (sig, pksk); if (mksubpkt) rc = (*mksubpkt)(sig, opaque); if (!rc) { hash_sigversion_to_magic (md, sig, NULL); gcry_md_final (md); rc = complete_sig (ctrl, sig, pksk, md, NULL, signhints); } leave: gcry_md_close (md); if (rc) free_seckey_enc (sig); else *ret_sig = sig; return rc; }