diff --git a/agent/pksign.c b/agent/pksign.c index b2ee28f22..4d0a240e9 100644 --- a/agent/pksign.c +++ b/agent/pksign.c @@ -1,502 +1,499 @@ /* pksign.c - public key signing (well, actually using a secret key) * Copyright (C) 2001, 2002, 2003, 2004, 2010 Free Software Foundation, Inc. * Copyright (C) 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 #include #include "agent.h" #include "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) { for (i=0; i < strlen (s); i++) tmp[i] = tolower (s[i]); tmp[i] = '\0'; } rc = gcry_sexp_build (&hash, NULL, "(data (flags pkcs1) (hash %s %b))", tmp, (int)mdlen, md); } else { gcry_mpi_t mpi; rc = gcry_mpi_scan (&mpi, GCRYMPI_FMT_USG, md, mdlen, NULL); if (! rc) { rc = gcry_sexp_build (&hash, NULL, "(data (flags raw) (value %m))", mpi); gcry_mpi_release (mpi); } } *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) { gpg_error_t err; gcry_sexp_t hash; *r_hash = NULL; err = gcry_sexp_build (&hash, NULL, "(data(flags eddsa)(hash-algo sha512)(value %b))", (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 dsaalgo, gcry_sexp_t pkey, +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; - int pkalgo; *r_hash = NULL; - pkalgo = map_pk_openpgp_to_gcry (dsaalgo); - if (pkalgo == GCRY_PK_ECDSA) 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); } /* Check if we're too short. Too long is safe as we'll * automatically left-truncate. * * This check would require the use of SHA512 with ECDSA 512. I * think this is overkill to fail in this case. Therefore, relax * the check, but only for ECDSA keys. We may need to adjust it * later for general case. (Note that the check is really a bug for * ECDSA 521 as the only hash that matches it is SHA 512, but 512 < * 521 ). */ if (mdlen < ((pkalgo==GCRY_PK_ECDSA && qbits > 521) ? 512 : 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)); /* FIXME: we need to check the requirements for ECDSA. */ if (mdlen < 20 || pkalgo == GCRY_PK_DSA) 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 ; 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; 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. */ int 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) { gcry_sexp_t s_skey = NULL, s_sig = NULL; unsigned char *shadow_info = NULL; unsigned int rc = 0; /* FIXME: gpg-error? */ if (! ctrl->have_keygrip) return gpg_error (GPG_ERR_NO_SECKEY); rc = agent_key_from_file (ctrl, cache_nonce, desc_text, ctrl->keygrip, &shadow_info, cache_mode, lookup_ttl, &s_skey, NULL); if (rc) { log_error ("failed to read the secret key\n"); goto leave; } if (!s_skey) { /* Divert operation to the smartcard */ gcry_sexp_t s_pkey, l; const char *name; size_t len; unsigned char *buf = NULL; int is_RSA = 0; int is_ECDSA = 0; /* Check keytype by public key */ rc = agent_public_key_from_file (ctrl, ctrl->keygrip, &s_pkey); if (rc) { log_error ("failed to read the public key\n"); goto leave; } l = gcry_sexp_cadr (s_pkey); name = gcry_sexp_nth_data (l, 0, &len); if (len == 3 && !memcmp (name, "rsa", 3)) is_RSA = 1; else if (len == 5 && !memcmp (name, "ecdsa", 5)) is_ECDSA = 1; gcry_sexp_release (l); gcry_sexp_release (s_pkey); rc = divert_pksign (ctrl, ctrl->digest.value, ctrl->digest.valuelen, ctrl->digest.algo, shadow_info, &buf, &len); if (rc) { log_error ("smartcard signing failed: %s\n", gpg_strerror (rc)); goto leave; } if (is_RSA) { if (*buf & 0x80) { len++; buf = xtryrealloc (buf, len); if (!buf) goto leave; memmove (buf + 1, buf, len - 1); *buf = 0; } rc = gcry_sexp_build (&s_sig, NULL, "(sig-val(rsa(s%b)))", len, buf); } else if (is_ECDSA) { unsigned char *r_buf_allocated = NULL; unsigned char *s_buf_allocated = NULL; unsigned char *r_buf, *s_buf; int r_buflen, s_buflen; r_buflen = s_buflen = len/2; if (*buf & 0x80) { r_buflen++; r_buf_allocated = xtrymalloc (r_buflen); if (!r_buf_allocated) goto leave; r_buf = r_buf_allocated; memcpy (r_buf + 1, buf, len/2); *r_buf = 0; } else r_buf = buf; if (*(buf + len/2) & 0x80) { s_buflen++; s_buf_allocated = xtrymalloc (s_buflen); if (!s_buf_allocated) { xfree (r_buf_allocated); goto leave; } s_buf = s_buf_allocated; memcpy (s_buf + 1, buf + len/2, len/2); *s_buf = 0; } else s_buf = buf + len/2; rc = gcry_sexp_build (&s_sig, NULL, "(sig-val(ecdsa(r%b)(s%b)))", r_buflen, r_buf, s_buflen, s_buf); xfree (r_buf_allocated); xfree (s_buf_allocated); } else rc = gpg_error (GPG_ERR_NOT_IMPLEMENTED); xfree (buf); if (rc) { log_error ("failed to convert sigbuf returned by divert_pksign " "into S-Exp: %s", gpg_strerror (rc)); goto leave; } } else { /* No smartcard, but a private key */ gcry_sexp_t s_hash = NULL; int dsaalgo; /* Put the hash into a sexp */ if (agent_is_eddsa_key (s_skey)) rc = do_encode_eddsa (ctrl->digest.value, ctrl->digest.valuelen, &s_hash); else if (ctrl->digest.algo == MD_USER_TLS_MD5SHA1) rc = do_encode_raw_pkcs1 (ctrl->digest.value, ctrl->digest.valuelen, gcry_pk_get_nbits (s_skey), &s_hash); else if ( (dsaalgo = agent_is_dsa_key (s_skey)) ) rc = do_encode_dsa (ctrl->digest.value, ctrl->digest.valuelen, dsaalgo, s_skey, &s_hash); else rc = do_encode_md (ctrl->digest.value, ctrl->digest.valuelen, ctrl->digest.algo, &s_hash, ctrl->digest.raw_value); if (rc) goto leave; if (DBG_CRYPTO) { gcry_log_debugsxp ("skey", s_skey); gcry_log_debugsxp ("hash", s_hash); } /* sign */ rc = gcry_pk_sign (&s_sig, s_hash, s_skey); gcry_sexp_release (s_hash); if (rc) { log_error ("signing failed: %s\n", gpg_strerror (rc)); goto leave; } if (DBG_CRYPTO) gcry_log_debugsxp ("rslt", s_sig); } leave: *signature_sexp = s_sig; gcry_sexp_release (s_skey); xfree (shadow_info); return rc; } /* 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. */ int agent_pksign (ctrl_t ctrl, const char *cache_nonce, const char *desc_text, membuf_t *outbuf, cache_mode_t cache_mode) { gcry_sexp_t s_sig = NULL; char *buf = NULL; size_t len = 0; int rc = 0; rc = agent_pksign_do (ctrl, cache_nonce, desc_text, &s_sig, cache_mode, NULL); if (rc) goto leave; len = gcry_sexp_sprint (s_sig, GCRYSEXP_FMT_CANON, NULL, 0); assert (len); buf = xmalloc (len); len = gcry_sexp_sprint (s_sig, GCRYSEXP_FMT_CANON, buf, len); assert (len); put_membuf (outbuf, buf, len); leave: gcry_sexp_release (s_sig); xfree (buf); return rc; } diff --git a/common/sexputil.c b/common/sexputil.c index e18756a89..f15b94c66 100644 --- a/common/sexputil.c +++ b/common/sexputil.c @@ -1,555 +1,558 @@ /* 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-expresions (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" /* 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 gcryp S-expression in 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 depended 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 fucntions 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 neaded.) */ 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 futher 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 const part1[] = "(10:public-key(3:rsa(1:n"; const char const part2[] = ")(1:e"; const char const 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 algo of a public RSA expressed as an canonical encoded - S-expression. On error the algo is set to 0. */ + S-expression. The return value is a statically allocated + string. On error that string is set to NULL. */ gpg_error_t get_pk_algo_from_canon_sexp (const unsigned char *keydata, size_t keydatalen, - int *r_algo) + const char **r_algo) { gpg_error_t err; const unsigned char *buf, *tok; size_t buflen, toklen; int depth; - *r_algo = 0; + *r_algo = NULL; 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) return gpg_error (GPG_ERR_BAD_PUBKEY); if (toklen == 3 && !memcmp ("rsa", tok, toklen)) - *r_algo = GCRY_PK_RSA; + *r_algo = "rsa"; else if (toklen == 3 && !memcmp ("dsa", tok, toklen)) - *r_algo = GCRY_PK_DSA; + *r_algo = "dsa"; else if (toklen == 3 && !memcmp ("elg", tok, toklen)) - *r_algo = GCRY_PK_ELG; + *r_algo = "elg"; else if (toklen == 5 && !memcmp ("ecdsa", tok, toklen)) - *r_algo = GCRY_PK_ECDSA; + *r_algo = "ecdsa"; + else if (toklen == 5 && !memcmp ("eddsa", tok, toklen)) + *r_algo = "eddsa"; else - return gpg_error (GPG_ERR_PUBKEY_ALGO); + return gpg_error (GPG_ERR_PUBKEY_ALGO); return 0; } diff --git a/common/util.h b/common/util.h index f93888837..c4acb0bd3 100644 --- a/common/util.h +++ b/common/util.h @@ -1,348 +1,348 @@ /* util.h - Utility functions for GnuPG * Copyright (C) 2001, 2002, 2003, 2004, 2009 Free Software Foundation, Inc. * * This file is part of JNLIB, which is a subsystem of GnuPG. * * JNLIB 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. * * JNLIB 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 copies of the GNU General Public License * and the GNU Lesser General Public License along with this program; * if not, see . */ #ifndef GNUPG_COMMON_UTIL_H #define GNUPG_COMMON_UTIL_H #include /* We need this for the memory function protos. */ #include /* We need errno. */ #include /* We need gpg_error_t. */ /* Hash function used with libksba. */ #define HASH_FNC ((void (*)(void *, const void*,size_t))gcry_md_write) /* Estream replaces most uses of stdio. */ #include "../common/estream.h" #include "../common/estream-printf.h" /* Get all the stuff from jnlib. */ #include "../common/logging.h" #include "../common/argparse.h" #include "../common/stringhelp.h" #include "../common/mischelp.h" #include "../common/strlist.h" #include "../common/dotlock.h" #include "../common/utf8conv.h" #include "../common/dynload.h" #include "gettime.h" /* Redefine asprintf by our estream version which uses our own memory allocator.. */ #define asprintf estream_asprintf #define vasprintf estream_vasprintf /* Due to a bug in mingw32's snprintf related to the 'l' modifier and for increased portability we use our snprintf on all systems. */ #undef snprintf #define snprintf estream_snprintf /* GCC attributes. */ #if __GNUC__ >= 4 # define GNUPG_GCC_A_SENTINEL(a) __attribute__ ((sentinel(a))) #else # define GNUPG_GCC_A_SENTINEL(a) #endif /* We need this type even if we are not using libreadline and or we did not include libreadline in the current file. */ #ifndef GNUPG_LIBREADLINE_H_INCLUDED typedef char **rl_completion_func_t (const char *, int, int); #endif /*!GNUPG_LIBREADLINE_H_INCLUDED*/ /* Handy malloc macros - please use only them. */ #define xtrymalloc(a) gcry_malloc ((a)) #define xtrymalloc_secure(a) gcry_malloc_secure ((a)) #define xtrycalloc(a,b) gcry_calloc ((a),(b)) #define xtrycalloc_secure(a,b) gcry_calloc_secure ((a),(b)) #define xtryrealloc(a,b) gcry_realloc ((a),(b)) #define xtrystrdup(a) gcry_strdup ((a)) #define xfree(a) gcry_free ((a)) #define xfree_fnc gcry_free #define xmalloc(a) gcry_xmalloc ((a)) #define xmalloc_secure(a) gcry_xmalloc_secure ((a)) #define xcalloc(a,b) gcry_xcalloc ((a),(b)) #define xcalloc_secure(a,b) gcry_xcalloc_secure ((a),(b)) #define xrealloc(a,b) gcry_xrealloc ((a),(b)) #define xstrdup(a) gcry_xstrdup ((a)) /* For compatibility with gpg 1.4 we also define these: */ #define xmalloc_clear(a) gcry_xcalloc (1, (a)) #define xmalloc_secure_clear(a) gcry_xcalloc_secure (1, (a)) /* The default error source of the application. This is different from GPG_ERR_SOURCE_DEFAULT in that it does not depend on the source file and thus is usable in code shared by applications. Defined by init.c. */ extern gpg_err_source_t default_errsource; /* Convenience function to return a gpg-error code for memory allocation failures. This function makes sure that an error will be returned even if accidently ERRNO is not set. */ static inline gpg_error_t out_of_core (void) { return gpg_error_from_syserror (); } /*-- signal.c --*/ void gnupg_init_signals (int mode, void (*fast_cleanup)(void)); void gnupg_block_all_signals (void); void gnupg_unblock_all_signals (void); /*-- yesno.c --*/ int answer_is_yes (const char *s); int answer_is_yes_no_default (const char *s, int def_answer); int answer_is_yes_no_quit (const char *s); int answer_is_okay_cancel (const char *s, int def_answer); /*-- xreadline.c --*/ ssize_t read_line (FILE *fp, char **addr_of_buffer, size_t *length_of_buffer, size_t *max_length); /*-- b64enc.c and b64dec.c --*/ struct b64state { unsigned int flags; int idx; int quad_count; FILE *fp; estream_t stream; char *title; unsigned char radbuf[4]; u32 crc; int stop_seen:1; int invalid_encoding:1; gpg_error_t lasterr; }; gpg_error_t b64enc_start (struct b64state *state, FILE *fp, const char *title); gpg_error_t b64enc_start_es (struct b64state *state, estream_t fp, const char *title); gpg_error_t b64enc_write (struct b64state *state, const void *buffer, size_t nbytes); gpg_error_t b64enc_finish (struct b64state *state); gpg_error_t b64dec_start (struct b64state *state, const char *title); gpg_error_t b64dec_proc (struct b64state *state, void *buffer, size_t length, size_t *r_nbytes); gpg_error_t b64dec_finish (struct b64state *state); /*-- sexputil.c */ char *canon_sexp_to_string (const unsigned char *canon, size_t canonlen); void log_printcanon (const char *text, const unsigned char *sexp, size_t sexplen); void log_printsexp (const char *text, gcry_sexp_t sexp); gpg_error_t make_canon_sexp (gcry_sexp_t sexp, unsigned char **r_buffer, size_t *r_buflen); gpg_error_t make_canon_sexp_pad (gcry_sexp_t sexp, int secure, unsigned char **r_buffer, size_t *r_buflen); gpg_error_t keygrip_from_canon_sexp (const unsigned char *key, size_t keylen, unsigned char *grip); int cmp_simple_canon_sexp (const unsigned char *a, const unsigned char *b); unsigned char *make_simple_sexp_from_hexstr (const char *line, size_t *nscanned); int hash_algo_from_sigval (const unsigned char *sigval); unsigned char *make_canon_sexp_from_rsa_pk (const void *m, size_t mlen, const void *e, size_t elen, size_t *r_len); 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 get_pk_algo_from_canon_sexp (const unsigned char *keydata, size_t keydatalen, - int *r_algo); + const char **r_algo); /*-- convert.c --*/ int hex2bin (const char *string, void *buffer, size_t length); int hexcolon2bin (const char *string, void *buffer, size_t length); char *bin2hex (const void *buffer, size_t length, char *stringbuf); char *bin2hexcolon (const void *buffer, size_t length, char *stringbuf); const char *hex2str (const char *hexstring, char *buffer, size_t bufsize, size_t *buflen); char *hex2str_alloc (const char *hexstring, size_t *r_count); /*-- percent.c --*/ char *percent_plus_escape (const char *string); char *percent_plus_unescape (const char *string, int nulrepl); char *percent_unescape (const char *string, int nulrepl); size_t percent_plus_unescape_inplace (char *string, int nulrepl); size_t percent_unescape_inplace (char *string, int nulrepl); /*-- openpgp-oid.c --*/ gpg_error_t openpgp_oid_from_str (const char *string, gcry_mpi_t *r_mpi); char *openpgp_oid_to_str (gcry_mpi_t a); int openpgp_oid_is_ed25519 (gcry_mpi_t a); const char *openpgp_curve_to_oid (const char *name, unsigned int *r_nbits); const char *openpgp_oid_to_curve (const char *oid); /*-- homedir.c --*/ const char *standard_homedir (void); const char *default_homedir (void); const char *gnupg_sysconfdir (void); const char *gnupg_bindir (void); const char *gnupg_libexecdir (void); const char *gnupg_libdir (void); const char *gnupg_datadir (void); const char *gnupg_localedir (void); const char *gnupg_cachedir (void); const char *dirmngr_socket_name (void); /* All module names. We also include gpg and gpgsm for the sake for gpgconf. */ #define GNUPG_MODULE_NAME_AGENT 1 #define GNUPG_MODULE_NAME_PINENTRY 2 #define GNUPG_MODULE_NAME_SCDAEMON 3 #define GNUPG_MODULE_NAME_DIRMNGR 4 #define GNUPG_MODULE_NAME_PROTECT_TOOL 5 #define GNUPG_MODULE_NAME_CHECK_PATTERN 6 #define GNUPG_MODULE_NAME_GPGSM 7 #define GNUPG_MODULE_NAME_GPG 8 #define GNUPG_MODULE_NAME_CONNECT_AGENT 9 #define GNUPG_MODULE_NAME_GPGCONF 10 #define GNUPG_MODULE_NAME_DIRMNGR_LDAP 11 const char *gnupg_module_name (int which); /*-- gpgrlhelp.c --*/ void gnupg_rl_initialize (void); /*-- helpfile.c --*/ char *gnupg_get_help_string (const char *key, int only_current_locale); /*-- localename.c --*/ const char *gnupg_messages_locale_name (void); /*-- miscellaneous.c --*/ /* This function is called at startup to tell libgcrypt to use our own logging subsystem. */ void setup_libgcrypt_logging (void); /* Same as estream_asprintf but die on memory failure. */ char *xasprintf (const char *fmt, ...) JNLIB_GCC_A_PRINTF(1,2); /* This is now an alias to estream_asprintf. */ char *xtryasprintf (const char *fmt, ...) JNLIB_GCC_A_PRINTF(1,2); /* Replacement for gcry_cipher_algo_name. */ const char *gnupg_cipher_algo_name (int algo); const char *print_fname_stdout (const char *s); const char *print_fname_stdin (const char *s); void print_utf8_buffer2 (estream_t fp, const void *p, size_t n, int delim); void print_utf8_buffer (estream_t fp, const void *p, size_t n); void print_hexstring (FILE *fp, const void *buffer, size_t length, int reserved); char *make_printable_string (const void *p, size_t n, int delim); int is_file_compressed (const char *s, int *ret_rc); int match_multistr (const char *multistr,const char *match); int gnupg_compare_version (const char *a, const char *b); /*-- Simple replacement functions. */ /* We use the gnupg_ttyname macro to be safe not to run into conflicts which an extisting but broken ttyname. */ #if !defined(HAVE_TTYNAME) || defined(HAVE_BROKEN_TTYNAME) # define gnupg_ttyname(n) _gnupg_ttyname ((n)) /* Systems without ttyname (W32) will merely return NULL. */ static inline char * _gnupg_ttyname (int fd) { (void)fd; return NULL; } #else /*HAVE_TTYNAME*/ # define gnupg_ttyname(n) ttyname ((n)) #endif /*HAVE_TTYNAME */ #ifdef HAVE_W32CE_SYSTEM #define getpid() GetCurrentProcessId () char *_gnupg_getenv (const char *name); /* See sysutils.c */ #define getenv(a) _gnupg_getenv ((a)) char *_gnupg_setenv (const char *name); /* See sysutils.c */ #define setenv(a,b,c) _gnupg_setenv ((a),(b),(c)) int _gnupg_isatty (int fd); #define gnupg_isatty(a) _gnupg_isatty ((a)) #else #define gnupg_isatty(a) isatty ((a)) #endif /*-- Macros to replace ctype ones to avoid locale problems. --*/ #define spacep(p) (*(p) == ' ' || *(p) == '\t') #define digitp(p) (*(p) >= '0' && *(p) <= '9') #define hexdigitp(a) (digitp (a) \ || (*(a) >= 'A' && *(a) <= 'F') \ || (*(a) >= 'a' && *(a) <= 'f')) /* Note this isn't identical to a C locale isspace() without \f and \v, but works for the purposes used here. */ #define ascii_isspace(a) ((a)==' ' || (a)=='\n' || (a)=='\r' || (a)=='\t') /* The atoi macros assume that the buffer has only valid digits. */ #define atoi_1(p) (*(p) - '0' ) #define atoi_2(p) ((atoi_1(p) * 10) + atoi_1((p)+1)) #define atoi_4(p) ((atoi_2(p) * 100) + atoi_2((p)+2)) #define xtoi_1(p) (*(p) <= '9'? (*(p)- '0'): \ *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10)) #define xtoi_2(p) ((xtoi_1(p) * 16) + xtoi_1((p)+1)) #define xtoi_4(p) ((xtoi_2(p) * 256) + xtoi_2((p)+2)) /*-- Forward declaration of the commonly used server control structure. */ /* (We need it here as it is used by some callback prototypes.) */ struct server_control_s; typedef struct server_control_s *ctrl_t; #endif /*GNUPG_COMMON_UTIL_H*/ diff --git a/g10/build-packet.c b/g10/build-packet.c index f31ca888f..7464979cf 100644 --- a/g10/build-packet.c +++ b/g10/build-packet.c @@ -1,1381 +1,1382 @@ /* build-packet.c - assemble packets and write them * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, * 2006, 2010, 2011 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 #include "gpg.h" #include "util.h" #include "packet.h" #include "status.h" #include "iobuf.h" #include "i18n.h" #include "options.h" static int do_user_id( IOBUF out, int ctb, PKT_user_id *uid ); static int do_key (iobuf_t out, int ctb, PKT_public_key *pk); static int do_symkey_enc( IOBUF out, int ctb, PKT_symkey_enc *enc ); static int do_pubkey_enc( IOBUF out, int ctb, PKT_pubkey_enc *enc ); static u32 calc_plaintext( PKT_plaintext *pt ); static int do_plaintext( IOBUF out, int ctb, PKT_plaintext *pt ); static int do_encrypted( IOBUF out, int ctb, PKT_encrypted *ed ); static int do_encrypted_mdc( IOBUF out, int ctb, PKT_encrypted *ed ); static int do_compressed( IOBUF out, int ctb, PKT_compressed *cd ); static int do_signature( IOBUF out, int ctb, PKT_signature *sig ); static int do_onepass_sig( IOBUF out, int ctb, PKT_onepass_sig *ops ); static int calc_header_length( u32 len, int new_ctb ); static int write_16(IOBUF inp, u16 a); static int write_32(IOBUF inp, u32 a); static int write_header( IOBUF out, int ctb, u32 len ); static int write_sign_packet_header( IOBUF out, int ctb, u32 len ); static int write_header2( IOBUF out, int ctb, u32 len, int hdrlen ); static int write_new_header( IOBUF out, int ctb, u32 len, int hdrlen ); static int write_version( IOBUF out, int ctb ); /**************** * Build a packet and write it to INP * Returns: 0 := okay * >0 := error * Note: Caller must free the packet */ int build_packet( IOBUF out, PACKET *pkt ) { int new_ctb=0, rc=0, ctb; int pkttype; if( DBG_PACKET ) log_debug("build_packet() type=%d\n", pkt->pkttype ); assert( pkt->pkt.generic ); switch ((pkttype = pkt->pkttype)) { case PKT_PUBLIC_KEY: if (pkt->pkt.public_key->seckey_info) pkttype = PKT_SECRET_KEY; break; case PKT_PUBLIC_SUBKEY: if (pkt->pkt.public_key->seckey_info) pkttype = PKT_SECRET_SUBKEY; break; case PKT_PLAINTEXT: new_ctb = pkt->pkt.plaintext->new_ctb; break; case PKT_ENCRYPTED: case PKT_ENCRYPTED_MDC: new_ctb = pkt->pkt.encrypted->new_ctb; break; case PKT_COMPRESSED:new_ctb = pkt->pkt.compressed->new_ctb; break; case PKT_USER_ID: if( pkt->pkt.user_id->attrib_data ) pkttype = PKT_ATTRIBUTE; break; default: break; } if( new_ctb || pkttype > 15 ) /* new format */ ctb = 0xc0 | (pkttype & 0x3f); else ctb = 0x80 | ((pkttype & 15)<<2); switch( pkttype ) { case PKT_ATTRIBUTE: case PKT_USER_ID: rc = do_user_id( out, ctb, pkt->pkt.user_id ); break; case PKT_OLD_COMMENT: case PKT_COMMENT: /* Ignore these. Theoretically, this will never be called as we have no way to output comment packets any longer, but just in case there is some code path that would end up outputting a comment that was written before comments were dropped (in the public key?) this is a no-op. */ break; case PKT_PUBLIC_SUBKEY: case PKT_PUBLIC_KEY: case PKT_SECRET_SUBKEY: case PKT_SECRET_KEY: rc = do_key (out, ctb, pkt->pkt.public_key); break; case PKT_SYMKEY_ENC: rc = do_symkey_enc( out, ctb, pkt->pkt.symkey_enc ); break; case PKT_PUBKEY_ENC: rc = do_pubkey_enc( out, ctb, pkt->pkt.pubkey_enc ); break; case PKT_PLAINTEXT: rc = do_plaintext( out, ctb, pkt->pkt.plaintext ); break; case PKT_ENCRYPTED: rc = do_encrypted( out, ctb, pkt->pkt.encrypted ); break; case PKT_ENCRYPTED_MDC: rc = do_encrypted_mdc( out, ctb, pkt->pkt.encrypted ); break; case PKT_COMPRESSED: rc = do_compressed( out, ctb, pkt->pkt.compressed ); break; case PKT_SIGNATURE: rc = do_signature( out, ctb, pkt->pkt.signature ); break; case PKT_ONEPASS_SIG: rc = do_onepass_sig( out, ctb, pkt->pkt.onepass_sig ); break; case PKT_RING_TRUST: break; /* ignore it (keyring.c does write it directly)*/ case PKT_MDC: /* we write it directly, so we should never see it here. */ default: log_bug("invalid packet type in build_packet()\n"); break; } return rc; } /* * Write the mpi A to OUT. */ gpg_error_t gpg_mpi_write (iobuf_t out, gcry_mpi_t a) { int rc; if (gcry_mpi_get_flag (a, GCRYMPI_FLAG_OPAQUE)) { unsigned int nbits; const void *p; unsigned int lenhdr[2]; p = gcry_mpi_get_opaque (a, &nbits); lenhdr[0] = nbits >> 8; lenhdr[1] = nbits; rc = iobuf_write (out, lenhdr, 2); if (!rc) rc = iobuf_write (out, p, (nbits+7)/8); } else { char buffer[(MAX_EXTERN_MPI_BITS+7)/8+2]; /* 2 is for the mpi length. */ size_t nbytes; nbytes = DIM(buffer); rc = gcry_mpi_print (GCRYMPI_FMT_PGP, buffer, nbytes, &nbytes, a ); if( !rc ) rc = iobuf_write( out, buffer, nbytes ); else if (gpg_err_code(rc) == GPG_ERR_TOO_SHORT ) { log_info ("mpi too large (%u bits)\n", gcry_mpi_get_nbits (a)); /* The buffer was too small. We better tell the user about the MPI. */ rc = gpg_error (GPG_ERR_TOO_LARGE); } } return rc; } /* * Write an opaque MPI to the output stream without length info. */ gpg_error_t gpg_mpi_write_nohdr (iobuf_t out, gcry_mpi_t a) { int rc; if (gcry_mpi_get_flag (a, GCRYMPI_FLAG_OPAQUE)) { unsigned int nbits; const void *p; p = gcry_mpi_get_opaque (a, &nbits); rc = iobuf_write (out, p, (nbits+7)/8); } else rc = gpg_error (GPG_ERR_BAD_MPI); return rc; } /* Calculate the length of a packet described by PKT. */ u32 calc_packet_length( PACKET *pkt ) { u32 n=0; int new_ctb = 0; assert( pkt->pkt.generic ); switch( pkt->pkttype ) { case PKT_PLAINTEXT: n = calc_plaintext( pkt->pkt.plaintext ); new_ctb = pkt->pkt.plaintext->new_ctb; break; case PKT_ATTRIBUTE: case PKT_USER_ID: case PKT_COMMENT: case PKT_PUBLIC_KEY: case PKT_SECRET_KEY: case PKT_SYMKEY_ENC: case PKT_PUBKEY_ENC: case PKT_ENCRYPTED: case PKT_SIGNATURE: case PKT_ONEPASS_SIG: case PKT_RING_TRUST: case PKT_COMPRESSED: default: log_bug("invalid packet type in calc_packet_length()"); break; } n += calc_header_length(n, new_ctb); return n; } static gpg_error_t write_fake_data (IOBUF out, gcry_mpi_t a) { unsigned int n; void *p; if (!a) return 0; p = gcry_mpi_get_opaque ( a, &n); return iobuf_write (out, p, (n+7)/8 ); } static int do_user_id( IOBUF out, int ctb, PKT_user_id *uid ) { int rc; if (uid->attrib_data) { write_header(out, ctb, uid->attrib_len); rc = iobuf_write( out, uid->attrib_data, uid->attrib_len ); } else { write_header2( out, ctb, uid->len, 2 ); rc = iobuf_write( out, uid->name, uid->len ); } return rc; } static int do_key (iobuf_t out, int ctb, PKT_public_key *pk) { gpg_error_t err = 0; int i, nskey, npkey; iobuf_t a = iobuf_temp(); /* Build in a self-enlarging buffer. */ /* Write the version number - if none is specified, use 3 */ if ( !pk->version ) iobuf_put ( a, 3 ); else iobuf_put ( a, pk->version ); write_32 (a, pk->timestamp ); /* v3 needs the expiration time. */ if ( pk->version < 4 ) { u16 ndays; if ( pk->expiredate ) ndays = (u16)((pk->expiredate - pk->timestamp) / 86400L); else ndays = 0; write_16(a, ndays); } iobuf_put (a, pk->pubkey_algo ); /* Get number of secret and public parameters. They are held in one array first the public ones, then the secret ones. */ nskey = pubkey_get_nskey (pk->pubkey_algo); npkey = pubkey_get_npkey (pk->pubkey_algo); /* If we don't have any public parameters - which is the case if we don't know the algorithm used - the parameters are stored as one blob in a faked (opaque) MPI. */ if (!npkey) { write_fake_data (a, pk->pkey[0]); goto leave; } assert (npkey < nskey); for (i=0; i < npkey; i++ ) { - if ((pk->pubkey_algo == PUBKEY_ALGO_ECDSA && (i == 0)) - || ((pk->pubkey_algo == PUBKEY_ALGO_ECDH) && (i == 0 || i == 2))) + if ( (pk->pubkey_algo == PUBKEY_ALGO_ECDSA && (i == 0)) + || (pk->pubkey_algo == PUBKEY_ALGO_EDDSA && (i == 0)) + || (pk->pubkey_algo == PUBKEY_ALGO_ECDH && (i == 0 || i == 2))) err = gpg_mpi_write_nohdr (a, pk->pkey[i]); else err = gpg_mpi_write (a, pk->pkey[i]); if (err) goto leave; } if (pk->seckey_info) { /* This is a secret key packet. */ struct seckey_info *ski = pk->seckey_info; /* Build the header for protected (encrypted) secret parameters. */ if (ski->is_protected) { if ( is_RSA (pk->pubkey_algo) && pk->version < 4 && !ski->s2k.mode ) { /* The simple rfc1991 (v3) way. */ iobuf_put (a, ski->algo ); iobuf_write (a, ski->iv, ski->ivlen); } else { /* OpenPGP protection according to rfc2440. */ iobuf_put (a, ski->sha1chk? 0xfe : 0xff); iobuf_put (a, ski->algo); if (ski->s2k.mode >= 1000) { /* These modes are not possible in OpenPGP, we use them to implement our extensions, 101 can be viewed as a private/experimental extension (this is not specified in rfc2440 but the same scheme is used for all other algorithm identifiers). */ iobuf_put (a, 101); iobuf_put (a, ski->s2k.hash_algo); iobuf_write (a, "GNU", 3 ); iobuf_put (a, ski->s2k.mode - 1000); } else { iobuf_put (a, ski->s2k.mode); iobuf_put (a, ski->s2k.hash_algo); } if (ski->s2k.mode == 1 || ski->s2k.mode == 3) iobuf_write (a, ski->s2k.salt, 8); if (ski->s2k.mode == 3) iobuf_put (a, ski->s2k.count); /* For our special modes 1001, 1002 we do not need an IV. */ if (ski->s2k.mode != 1001 && ski->s2k.mode != 1002) iobuf_write (a, ski->iv, ski->ivlen); } } else /* Not protected. */ iobuf_put (a, 0 ); if (ski->s2k.mode == 1001) ; /* GnuPG extension - don't write a secret key at all. */ else if (ski->s2k.mode == 1002) { /* GnuPG extension - divert to OpenPGP smartcard. */ /* Length of the serial number or 0 for no serial number. */ iobuf_put (a, ski->ivlen ); /* The serial number gets stored in the IV field. */ iobuf_write (a, ski->iv, ski->ivlen); } else if (ski->is_protected && pk->version >= 4) { /* The secret key is protected - write it out as it is. */ byte *p; unsigned int ndatabits; assert (gcry_mpi_get_flag (pk->pkey[npkey], GCRYMPI_FLAG_OPAQUE)); p = gcry_mpi_get_opaque (pk->pkey[npkey], &ndatabits); iobuf_write (a, p, (ndatabits+7)/8 ); } else if (ski->is_protected) { /* The secret key is protected the old v4 way. */ for ( ; i < nskey; i++ ) { byte *p; unsigned int ndatabits; assert (gcry_mpi_get_flag (pk->pkey[i], GCRYMPI_FLAG_OPAQUE)); p = gcry_mpi_get_opaque (pk->pkey[i], &ndatabits); iobuf_write (a, p, (ndatabits+7)/8); } write_16 (a, ski->csum ); } else { /* Non-protected key. */ for ( ; i < nskey; i++ ) if ( (err = gpg_mpi_write (a, pk->pkey[i]))) goto leave; write_16 (a, ski->csum ); } } leave: if (!err) { /* Build the header of the packet - which we must do after writing all the other stuff, so that we know the length of the packet */ write_header2 (out, ctb, iobuf_get_temp_length(a), pk->hdrbytes); /* And finally write it out to the real stream. */ err = iobuf_write_temp (out, a); } iobuf_close (a); /* Close the temporary buffer */ return err; } static int do_symkey_enc( IOBUF out, int ctb, PKT_symkey_enc *enc ) { int rc = 0; IOBUF a = iobuf_temp(); assert( enc->version == 4 ); switch( enc->s2k.mode ) { case 0: case 1: case 3: break; default: log_bug("do_symkey_enc: s2k=%d\n", enc->s2k.mode ); } iobuf_put( a, enc->version ); iobuf_put( a, enc->cipher_algo ); iobuf_put( a, enc->s2k.mode ); iobuf_put( a, enc->s2k.hash_algo ); if( enc->s2k.mode == 1 || enc->s2k.mode == 3 ) { iobuf_write(a, enc->s2k.salt, 8 ); if( enc->s2k.mode == 3 ) iobuf_put(a, enc->s2k.count); } if( enc->seskeylen ) iobuf_write(a, enc->seskey, enc->seskeylen ); write_header(out, ctb, iobuf_get_temp_length(a) ); rc = iobuf_write_temp( out, a ); iobuf_close(a); return rc; } static int do_pubkey_enc( IOBUF out, int ctb, PKT_pubkey_enc *enc ) { int rc = 0; int n, i; IOBUF a = iobuf_temp(); write_version( a, ctb ); if ( enc->throw_keyid ) { write_32(a, 0 ); /* Don't tell Eve who can decrypt the message. */ write_32(a, 0 ); } else { write_32(a, enc->keyid[0] ); write_32(a, enc->keyid[1] ); } iobuf_put(a,enc->pubkey_algo ); n = pubkey_get_nenc( enc->pubkey_algo ); if ( !n ) write_fake_data( a, enc->data[0] ); for (i=0; i < n && !rc ; i++ ) { if (enc->pubkey_algo == PUBKEY_ALGO_ECDH && i == 1) rc = gpg_mpi_write_nohdr (a, enc->data[i]); else rc = gpg_mpi_write (a, enc->data[i]); } if (!rc) { write_header (out, ctb, iobuf_get_temp_length(a) ); rc = iobuf_write_temp (out, a); } iobuf_close(a); return rc; } static u32 calc_plaintext( PKT_plaintext *pt ) { /* Truncate namelen to the maximum 255 characters. Note this means that a function that calls build_packet with an illegal literal packet will get it back legalized. */ if(pt->namelen>255) pt->namelen=255; return pt->len? (1 + 1 + pt->namelen + 4 + pt->len) : 0; } static int do_plaintext( IOBUF out, int ctb, PKT_plaintext *pt ) { int i, rc = 0; u32 n; byte buf[1000]; /* this buffer has the plaintext! */ int nbytes; write_header(out, ctb, calc_plaintext( pt ) ); iobuf_put(out, pt->mode ); iobuf_put(out, pt->namelen ); for(i=0; i < pt->namelen; i++ ) iobuf_put(out, pt->name[i] ); rc = write_32(out, pt->timestamp ); if (rc) return rc; n = 0; while( (nbytes=iobuf_read(pt->buf, buf, 1000)) != -1 ) { rc = iobuf_write (out, buf, nbytes); if (rc) break; n += nbytes; } wipememory(buf,1000); /* burn the buffer */ if( (ctb&0x40) && !pt->len ) iobuf_set_partial_block_mode(out, 0 ); /* turn off partial */ if( pt->len && n != pt->len ) log_error("do_plaintext(): wrote %lu bytes but expected %lu bytes\n", (ulong)n, (ulong)pt->len ); return rc; } static int do_encrypted( IOBUF out, int ctb, PKT_encrypted *ed ) { int rc = 0; u32 n; n = ed->len ? (ed->len + ed->extralen) : 0; write_header(out, ctb, n ); /* This is all. The caller has to write the real data */ return rc; } static int do_encrypted_mdc( IOBUF out, int ctb, PKT_encrypted *ed ) { int rc = 0; u32 n; assert( ed->mdc_method ); /* Take version number and the following MDC packet in account. */ n = ed->len ? (ed->len + ed->extralen + 1 + 22) : 0; write_header(out, ctb, n ); iobuf_put(out, 1 ); /* version */ /* This is all. The caller has to write the real data */ return rc; } static int do_compressed( IOBUF out, int ctb, PKT_compressed *cd ) { int rc = 0; /* We must use the old convention and don't use blockmode for the sake of PGP 2 compatibility. However if the new_ctb flag was set, CTB is already formatted as new style and write_header2 does create a partial length encoding using new the new style. */ write_header2(out, ctb, 0, 0); iobuf_put(out, cd->algorithm ); /* This is all. The caller has to write the real data */ return rc; } /**************** * Delete all subpackets of type REQTYPE and return a bool whether a packet * was deleted. */ int delete_sig_subpkt (subpktarea_t *area, sigsubpkttype_t reqtype ) { int buflen; sigsubpkttype_t type; byte *buffer, *bufstart; size_t n; size_t unused = 0; int okay = 0; if( !area ) return 0; buflen = area->len; buffer = area->data; for(;;) { if( !buflen ) { okay = 1; break; } bufstart = buffer; n = *buffer++; buflen--; if( n == 255 ) { if( buflen < 4 ) break; n = (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3]; buffer += 4; buflen -= 4; } else if( n >= 192 ) { if( buflen < 2 ) break; n = (( n - 192 ) << 8) + *buffer + 192; buffer++; buflen--; } if( buflen < n ) break; type = *buffer & 0x7f; if( type == reqtype ) { buffer++; buflen--; n--; if( n > buflen ) break; buffer += n; /* point to next subpkt */ buflen -= n; memmove (bufstart, buffer, buflen); /* shift */ unused += buffer - bufstart; buffer = bufstart; } else { buffer += n; buflen -=n; } } if (!okay) log_error ("delete_subpkt: buffer shorter than subpacket\n"); assert (unused <= area->len); area->len -= unused; return !!unused; } /**************** * Create or update a signature subpacket for SIG of TYPE. This * functions knows where to put the data (hashed or unhashed). The * function may move data from the unhashed part to the hashed one. * Note: All pointers into sig->[un]hashed (e.g. returned by * parse_sig_subpkt) are not valid after a call to this function. The * data to put into the subpaket should be in a buffer with a length * of buflen. */ void build_sig_subpkt (PKT_signature *sig, sigsubpkttype_t type, const byte *buffer, size_t buflen ) { byte *p; int critical, hashed; subpktarea_t *oldarea, *newarea; size_t nlen, n, n0; critical = (type & SIGSUBPKT_FLAG_CRITICAL); type &= ~SIGSUBPKT_FLAG_CRITICAL; /* Sanity check buffer sizes */ if(parse_one_sig_subpkt(buffer,buflen,type)<0) BUG(); switch(type) { case SIGSUBPKT_NOTATION: case SIGSUBPKT_POLICY: case SIGSUBPKT_REV_KEY: case SIGSUBPKT_SIGNATURE: /* we do allow multiple subpackets */ break; default: /* we don't allow multiple subpackets */ delete_sig_subpkt(sig->hashed,type); delete_sig_subpkt(sig->unhashed,type); break; } /* Any special magic that needs to be done for this type so the packet doesn't need to be reparsed? */ switch(type) { case SIGSUBPKT_NOTATION: sig->flags.notation=1; break; case SIGSUBPKT_POLICY: sig->flags.policy_url=1; break; case SIGSUBPKT_PREF_KS: sig->flags.pref_ks=1; break; case SIGSUBPKT_EXPORTABLE: if(buffer[0]) sig->flags.exportable=1; else sig->flags.exportable=0; break; case SIGSUBPKT_REVOCABLE: if(buffer[0]) sig->flags.revocable=1; else sig->flags.revocable=0; break; case SIGSUBPKT_TRUST: sig->trust_depth=buffer[0]; sig->trust_value=buffer[1]; break; case SIGSUBPKT_REGEXP: sig->trust_regexp=buffer; break; /* This should never happen since we don't currently allow creating such a subpacket, but just in case... */ case SIGSUBPKT_SIG_EXPIRE: if(buffer_to_u32(buffer)+sig->timestamp<=make_timestamp()) sig->flags.expired=1; else sig->flags.expired=0; break; default: break; } if( (buflen+1) >= 8384 ) nlen = 5; /* write 5 byte length header */ else if( (buflen+1) >= 192 ) nlen = 2; /* write 2 byte length header */ else nlen = 1; /* just a 1 byte length header */ switch( type ) { /* The issuer being unhashed is a historical oddity. It should work equally as well hashed. Of course, if even an unhashed issuer is tampered with, it makes it awfully hard to verify the sig... */ case SIGSUBPKT_ISSUER: case SIGSUBPKT_SIGNATURE: hashed = 0; break; default: hashed = 1; break; } if( critical ) type |= SIGSUBPKT_FLAG_CRITICAL; oldarea = hashed? sig->hashed : sig->unhashed; /* Calculate new size of the area and allocate */ n0 = oldarea? oldarea->len : 0; n = n0 + nlen + 1 + buflen; /* length, type, buffer */ if (oldarea && n <= oldarea->size) { /* fits into the unused space */ newarea = oldarea; /*log_debug ("updating area for type %d\n", type );*/ } else if (oldarea) { newarea = xrealloc (oldarea, sizeof (*newarea) + n - 1); newarea->size = n; /*log_debug ("reallocating area for type %d\n", type );*/ } else { newarea = xmalloc (sizeof (*newarea) + n - 1); newarea->size = n; /*log_debug ("allocating area for type %d\n", type );*/ } newarea->len = n; p = newarea->data + n0; if (nlen == 5) { *p++ = 255; *p++ = (buflen+1) >> 24; *p++ = (buflen+1) >> 16; *p++ = (buflen+1) >> 8; *p++ = (buflen+1); *p++ = type; memcpy (p, buffer, buflen); } else if (nlen == 2) { *p++ = (buflen+1-192) / 256 + 192; *p++ = (buflen+1-192) % 256; *p++ = type; memcpy (p, buffer, buflen); } else { *p++ = buflen+1; *p++ = type; memcpy (p, buffer, buflen); } if (hashed) sig->hashed = newarea; else sig->unhashed = newarea; } /**************** * Put all the required stuff from SIG into subpackets of sig. * Hmmm, should we delete those subpackets which are in a wrong area? */ void build_sig_subpkt_from_sig( PKT_signature *sig ) { u32 u; byte buf[8]; u = sig->keyid[0]; buf[0] = (u >> 24) & 0xff; buf[1] = (u >> 16) & 0xff; buf[2] = (u >> 8) & 0xff; buf[3] = u & 0xff; u = sig->keyid[1]; buf[4] = (u >> 24) & 0xff; buf[5] = (u >> 16) & 0xff; buf[6] = (u >> 8) & 0xff; buf[7] = u & 0xff; build_sig_subpkt( sig, SIGSUBPKT_ISSUER, buf, 8 ); u = sig->timestamp; buf[0] = (u >> 24) & 0xff; buf[1] = (u >> 16) & 0xff; buf[2] = (u >> 8) & 0xff; buf[3] = u & 0xff; build_sig_subpkt( sig, SIGSUBPKT_SIG_CREATED, buf, 4 ); if(sig->expiredate) { if(sig->expiredate>sig->timestamp) u=sig->expiredate-sig->timestamp; else u=1; /* A 1-second expiration time is the shortest one OpenPGP has */ buf[0] = (u >> 24) & 0xff; buf[1] = (u >> 16) & 0xff; buf[2] = (u >> 8) & 0xff; buf[3] = u & 0xff; /* Mark this CRITICAL, so if any implementation doesn't understand sigs that can expire, it'll just disregard this sig altogether. */ build_sig_subpkt( sig, SIGSUBPKT_SIG_EXPIRE | SIGSUBPKT_FLAG_CRITICAL, buf, 4 ); } } void build_attribute_subpkt(PKT_user_id *uid,byte type, const void *buf,u32 buflen, const void *header,u32 headerlen) { byte *attrib; int idx; if(1+headerlen+buflen>8383) idx=5; else if(1+headerlen+buflen>191) idx=2; else idx=1; /* realloc uid->attrib_data to the right size */ uid->attrib_data=xrealloc(uid->attrib_data, uid->attrib_len+idx+1+headerlen+buflen); attrib=&uid->attrib_data[uid->attrib_len]; if(idx==5) { attrib[0]=255; attrib[1]=(1+headerlen+buflen) >> 24; attrib[2]=(1+headerlen+buflen) >> 16; attrib[3]=(1+headerlen+buflen) >> 8; attrib[4]=1+headerlen+buflen; } else if(idx==2) { attrib[0]=(1+headerlen+buflen-192) / 256 + 192; attrib[1]=(1+headerlen+buflen-192) % 256; } else attrib[0]=1+headerlen+buflen; /* Good luck finding a JPEG this small! */ attrib[idx++]=type; /* Tack on our data at the end */ if(headerlen>0) memcpy(&attrib[idx],header,headerlen); memcpy(&attrib[idx+headerlen],buf,buflen); uid->attrib_len+=idx+headerlen+buflen; } struct notation * string_to_notation(const char *string,int is_utf8) { const char *s; int saw_at=0; struct notation *notation; notation=xmalloc_clear(sizeof(*notation)); if(*string=='-') { notation->flags.ignore=1; string++; } if(*string=='!') { notation->flags.critical=1; string++; } /* If and when the IETF assigns some official name tags, we'll have to add them here. */ for( s=string ; *s != '='; s++ ) { if( *s=='@') saw_at++; /* -notationname is legal without an = sign */ if(!*s && notation->flags.ignore) break; if( !*s || !isascii (*s) || (!isgraph(*s) && !isspace(*s)) ) { log_error(_("a notation name must have only printable characters" " or spaces, and end with an '='\n") ); goto fail; } } notation->name=xmalloc((s-string)+1); strncpy(notation->name,string,s-string); notation->name[s-string]='\0'; if(!saw_at && !opt.expert) { log_error(_("a user notation name must contain the '@' character\n")); goto fail; } if (saw_at > 1) { log_error(_("a notation name must not contain more than" " one '@' character\n")); goto fail; } if(*s) { const char *i=s+1; int highbit=0; /* we only support printable text - therefore we enforce the use of only printable characters (an empty value is valid) */ for(s++; *s ; s++ ) { if ( !isascii (*s) ) highbit=1; else if (iscntrl(*s)) { log_error(_("a notation value must not use any" " control characters\n")); goto fail; } } if(!highbit || is_utf8) notation->value=xstrdup(i); else notation->value=native_to_utf8(i); } return notation; fail: free_notation(notation); return NULL; } struct notation * sig_to_notation(PKT_signature *sig) { const byte *p; size_t len; int seq=0,crit; struct notation *list=NULL; while((p=enum_sig_subpkt(sig->hashed,SIGSUBPKT_NOTATION,&len,&seq,&crit))) { int n1,n2; struct notation *n=NULL; if(len<8) { log_info(_("WARNING: invalid notation data found\n")); continue; } n1=(p[4]<<8)|p[5]; n2=(p[6]<<8)|p[7]; if(8+n1+n2!=len) { log_info(_("WARNING: invalid notation data found\n")); continue; } n=xmalloc_clear(sizeof(*n)); n->name=xmalloc(n1+1); memcpy(n->name,&p[8],n1); n->name[n1]='\0'; if(p[0]&0x80) { n->value=xmalloc(n2+1); memcpy(n->value,&p[8+n1],n2); n->value[n2]='\0'; } else { n->bdat=xmalloc(n2); n->blen=n2; memcpy(n->bdat,&p[8+n1],n2); n->value=xmalloc(2+strlen(_("not human readable"))+2+1); strcpy(n->value,"[ "); strcat(n->value,_("not human readable")); strcat(n->value," ]"); } n->flags.critical=crit; n->next=list; list=n; } return list; } void free_notation(struct notation *notation) { while(notation) { struct notation *n=notation; xfree(n->name); xfree(n->value); xfree(n->altvalue); xfree(n->bdat); notation=n->next; xfree(n); } } static int do_signature( IOBUF out, int ctb, PKT_signature *sig ) { int rc = 0; int n, i; IOBUF a = iobuf_temp(); if ( !sig->version ) iobuf_put( a, 3 ); else iobuf_put( a, sig->version ); if ( sig->version < 4 ) iobuf_put (a, 5 ); /* Constant */ iobuf_put (a, sig->sig_class ); if ( sig->version < 4 ) { write_32(a, sig->timestamp ); write_32(a, sig->keyid[0] ); write_32(a, sig->keyid[1] ); } iobuf_put(a, sig->pubkey_algo ); iobuf_put(a, sig->digest_algo ); if ( sig->version >= 4 ) { size_t nn; /* Timestamp and keyid must have been packed into the subpackets prior to the call of this function, because these subpackets are hashed. */ nn = sig->hashed? sig->hashed->len : 0; write_16(a, nn); if (nn) iobuf_write( a, sig->hashed->data, nn ); nn = sig->unhashed? sig->unhashed->len : 0; write_16(a, nn); if (nn) iobuf_write( a, sig->unhashed->data, nn ); } iobuf_put(a, sig->digest_start[0] ); iobuf_put(a, sig->digest_start[1] ); n = pubkey_get_nsig( sig->pubkey_algo ); if ( !n ) write_fake_data( a, sig->data[0] ); for (i=0; i < n && !rc ; i++ ) rc = gpg_mpi_write (a, sig->data[i] ); if (!rc) { if ( is_RSA(sig->pubkey_algo) && sig->version < 4 ) write_sign_packet_header(out, ctb, iobuf_get_temp_length(a) ); else write_header(out, ctb, iobuf_get_temp_length(a) ); rc = iobuf_write_temp( out, a ); } iobuf_close(a); return rc; } static int do_onepass_sig( IOBUF out, int ctb, PKT_onepass_sig *ops ) { int rc = 0; IOBUF a = iobuf_temp(); write_version( a, ctb ); iobuf_put(a, ops->sig_class ); iobuf_put(a, ops->digest_algo ); iobuf_put(a, ops->pubkey_algo ); write_32(a, ops->keyid[0] ); write_32(a, ops->keyid[1] ); iobuf_put(a, ops->last ); write_header(out, ctb, iobuf_get_temp_length(a) ); rc = iobuf_write_temp( out, a ); iobuf_close(a); return rc; } static int write_16(IOBUF out, u16 a) { iobuf_put(out, a>>8); if( iobuf_put(out,a) ) return -1; return 0; } static int write_32(IOBUF out, u32 a) { iobuf_put(out, a>> 24); iobuf_put(out, a>> 16); iobuf_put(out, a>> 8); return iobuf_put(out, a); } /**************** * calculate the length of a header */ static int calc_header_length( u32 len, int new_ctb ) { if( !len ) return 1; /* only the ctb */ if( new_ctb ) { if( len < 192 ) return 2; if( len < 8384 ) return 3; else return 6; } if( len < 256 ) return 2; if( len < 65536 ) return 3; return 5; } /**************** * Write the CTB and the packet length */ static int write_header( IOBUF out, int ctb, u32 len ) { return write_header2( out, ctb, len, 0 ); } static int write_sign_packet_header (IOBUF out, int ctb, u32 len) { (void)ctb; /* Work around a bug in the pgp read function for signature packets, which are not correctly coded and silently assume at some point 2 byte length headers.*/ iobuf_put (out, 0x89 ); iobuf_put (out, len >> 8 ); return iobuf_put (out, len) == -1 ? -1:0; } /**************** * If HDRLEN is > 0, try to build a header of this length. We need * this so that we can hash packets without reading them again. If * len is 0, write a partial or indeterminate length header, unless * hdrlen is specified in which case write an actual zero length * (using the specified hdrlen). */ static int write_header2( IOBUF out, int ctb, u32 len, int hdrlen ) { if( ctb & 0x40 ) return write_new_header( out, ctb, len, hdrlen ); if( hdrlen ) { if( hdrlen == 2 && len < 256 ) ; else if( hdrlen == 3 && len < 65536 ) ctb |= 1; else ctb |= 2; } else { if( !len ) ctb |= 3; else if( len < 256 ) ; else if( len < 65536 ) ctb |= 1; else ctb |= 2; } if( iobuf_put(out, ctb ) ) return -1; if( len || hdrlen ) { if( ctb & 2 ) { if(iobuf_put(out, len >> 24 )) return -1; if(iobuf_put(out, len >> 16 )) return -1; } if( ctb & 3 ) if(iobuf_put(out, len >> 8 )) return -1; if( iobuf_put(out, len ) ) return -1; } return 0; } static int write_new_header( IOBUF out, int ctb, u32 len, int hdrlen ) { if( hdrlen ) log_bug("can't cope with hdrlen yet\n"); if( iobuf_put(out, ctb ) ) return -1; if( !len ) { iobuf_set_partial_block_mode(out, 512 ); } else { if( len < 192 ) { if( iobuf_put(out, len ) ) return -1; } else if( len < 8384 ) { len -= 192; if( iobuf_put( out, (len / 256) + 192) ) return -1; if( iobuf_put( out, (len % 256) ) ) return -1; } else { if( iobuf_put( out, 0xff ) ) return -1; if( iobuf_put( out, (len >> 24)&0xff ) ) return -1; if( iobuf_put( out, (len >> 16)&0xff ) ) return -1; if( iobuf_put( out, (len >> 8)&0xff ) ) return -1; if( iobuf_put( out, len & 0xff ) ) return -1; } } return 0; } static int write_version (IOBUF out, int ctb) { (void)ctb; if (iobuf_put (out, 3)) return -1; return 0; } diff --git a/g10/export.c b/g10/export.c index 01bdd5e82..a7d1cf873 100644 --- a/g10/export.c +++ b/g10/export.c @@ -1,1337 +1,1339 @@ /* export.c - Export keys in the OpenPGP defined format. * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, * 2005, 2010 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 #include "gpg.h" #include "options.h" #include "packet.h" #include "status.h" #include "keydb.h" #include "util.h" #include "main.h" #include "i18n.h" #include "trustdb.h" #include "call-agent.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; static int do_export (ctrl_t ctrl, strlist_t users, int secret, unsigned int options ); static int do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret, kbnode_t *keyblock_out, unsigned int options, int *any); static int build_sexp (iobuf_t out, PACKET *pkt, int *indent); 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-sexp-format",EXPORT_SEXP_FORMAT, NULL, N_("export keys in an S-expression based format")}, /* 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? */ }; return parse_options(str,options,export_opts,noisy); } /**************** * Export the public keys (to standard out or --output). * Depending on opt.armor the output is armored. * options are defined in main.h. * If USERS is NULL, the complete ring will be exported. */ int export_pubkeys (ctrl_t ctrl, strlist_t users, unsigned int options ) { return do_export (ctrl, users, 0, options ); } /**************** * Export to an already opened stream; return -1 if no keys have * been exported */ int export_pubkeys_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, kbnode_t *keyblock_out, unsigned int options ) { int any, rc; rc = do_export_stream (ctrl, out, users, 0, keyblock_out, options, &any); if (!rc && !any) rc = -1; return rc; } /* * Export a single key into a memory buffer. */ gpg_error_t export_pubkey_buffer (ctrl_t ctrl, const char *keyspec, unsigned int options, 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 (); err = do_export_stream (ctrl, iobuf, helplist, 0, r_keyblock, options, &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; } int export_seckeys (ctrl_t ctrl, strlist_t users ) { /* Use only relevant options for the secret key. */ unsigned int options = (opt.export_options & EXPORT_SEXP_FORMAT); return do_export (ctrl, users, 1, options); } int export_secsubkeys (ctrl_t ctrl, strlist_t users ) { /* Use only relevant options for the secret key. */ unsigned int options = (opt.export_options & EXPORT_SEXP_FORMAT); return do_export (ctrl, users, 2, options); } /* 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 ) { 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 (GNUPG_INVALID_FD, NULL, 0, &out ); if (rc) return rc; if (!(options & EXPORT_SEXP_FORMAT)) { if ( opt.armor ) { afx = new_armor_context (); afx->what = secret? 5 : 1; push_armor_filter (afx, out); } if ( opt.compress_keys ) push_compress_filter (out,&zfx,default_compress_algo()); } rc = do_export_stream (ctrl, out, users, secret, NULL, options, &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. */ static int exact_subkey_match_p (KEYDB_SEARCH_DESC *desc, KBNODE 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_FPR16: case KEYDB_SEARCH_MODE_FPR20: 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_FPR16: if (!memcmp (desc->u.fpr, fpr, 16)) result = 1; break; case KEYDB_SEARCH_MODE_FPR20: case KEYDB_SEARCH_MODE_FPR: if (!memcmp (desc->u.fpr, fpr, 20)) result = 1; break; default: break; } return result; } /* Return a canonicalized public key algoithms. This is used to compare different flavors of algorithms (e.g. ELG and ELG_E are considered the same). */ static int canon_pubkey_algo (int 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; default: return algo; } } /* 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; const char *value; size_t valuelen; char *string; int idx; int is_v4, is_protected; int pubkey_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; size_t npkey, nskey; gcry_mpi_t skey[10]; /* We support up to 9 parameters. */ int skeyidx = 0; struct seckey_info *ski; 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); } 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; pubkey_algo = gcry_pk_map_name (string); xfree (string); if (gcry_pk_algo_info (pubkey_algo, GCRYCTL_GET_ALGO_NPKEY, NULL, &npkey) || gcry_pk_algo_info (pubkey_algo, GCRYCTL_GET_ALGO_NSKEY, NULL, &nskey) || !npkey || npkey >= nskey || nskey > PUBKEY_MAX_NSKEY) goto bad_seckey; pubkey_algo = map_pk_gcry_to_openpgp (pubkey_algo); 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) { void *p = xtrymalloc (valuelen); if (!p) goto outofmem; memcpy (p, value, valuelen); skey[skeyidx] = gcry_mpi_set_opaque (NULL, p, valuelen*8); if (!skey[skeyidx]) goto outofmem; } 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 valuel 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; */ 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 all parameters but OpenPGP defines that only the OID of the curve is to be used. */ - if (pubkey_algo == PUBKEY_ALGO_ECDSA || pubkey_algo == PUBKEY_ALGO_ECDH) + if (pubkey_algo == PUBKEY_ALGO_ECDSA + || pubkey_algo == PUBKEY_ALGO_EDDSA + || pubkey_algo == PUBKEY_ALGO_ECDH) { gcry_sexp_t s_pubkey; const char *curvename, *curveoidstr; gcry_mpi_t mpi; /* We build an S-expression with the public key parameters and ask Libgcrypt to return the matching curve name. */ if (npkey != 6 || !skey[0] || !skey[1] || !skey[2] || !skey[3] || !skey[4] || !skey[5] || !skey[6] || skey[7]) { err = gpg_error (GPG_ERR_INTERNAL); goto leave; } err = gcry_sexp_build (&s_pubkey, NULL, "(public-key(ecc(p%m)(a%m)(b%m)(g%m)(n%m)))", skey[0], skey[1], skey[2], skey[3], skey[4]); if (err) goto leave; curvename = gcry_pk_get_curve (s_pubkey, 0, NULL); gcry_sexp_release (s_pubkey); curveoidstr = openpgp_curve_to_oid (curvename, NULL); if (!curveoidstr) { log_error ("no OID known for curve '%s'\n", curvename); err = gpg_error (GPG_ERR_UNKNOWN_NAME); goto leave; } err = openpgp_oid_from_str (curveoidstr, &mpi); if (err) goto leave; /* Now replace the curve parameters by the OID and shift the rest of the parameters. */ gcry_mpi_release (skey[0]); skey[0] = mpi; for (idx=1; idx <= 4; idx++) gcry_mpi_release (skey[idx]); skey[1] = skey[5]; skey[2] = skey[6]; for (idx=3; idx <= 6; idx++) skey[idx] = NULL; /* Fixup the NPKEY and NSKEY to match OpenPGP reality. */ npkey = 2; nskey = 3; /* 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; } if (canon_pubkey_algo (pubkey_algo) != canon_pubkey_algo (pk->pubkey_algo)) { err = gpg_error (GPG_ERR_PUBKEY_ALGO); 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_OPAQUE)) 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; assert (sizeof ski->s2k.salt == sizeof s2k_salt); memcpy (ski->s2k.salt, s2k_salt, sizeof s2k_salt); ski->s2k.count = s2k_count; 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_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; } /* 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 it 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, int *any) { gpg_error_t err = 0; PACKET pkt; KBNODE keyblock = NULL; KBNODE kbctx, node; size_t ndesc, descindex; KEYDB_SEARCH_DESC *desc = NULL; subkey_list_t subkey_list = NULL; /* Track already processed subkeys. */ KEYDB_HANDLE kdbhd; strlist_t sl; int indent = 0; gcry_cipher_hd_t cipherhd = NULL; *any = 0; init_packet (&pkt); kdbhd = keydb_new (); 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)); } /* 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; } while (!(err = keydb_search (kdbhd, desc, ndesc, &descindex))) { int skip_until_subkey = 0; u32 keyid[2]; PKT_public_key *pk; if (!users) desc[0].mode = KEYDB_SEARCH_MODE_NEXT; /* 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; } 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 to export 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; } } /* Always do the cleaning on the public key part if requested. Note that we don't yet set this option if we are exporting secret keys. Note that both export-clean and export-minimal only apply to UID sigs (0x10, 0x11, 0x12, and 0x13). A designated revocation is never stripped, even with export-minimal set. */ if ((options & EXPORT_CLEAN)) clean_key (keyblock, opt.verbose, (options&EXPORT_MINIMAL), NULL, NULL); /* And write it. */ 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; /* Make sure that ring_trust packets never get exported. */ 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;ipkt->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 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)) { u32 subkidbuf[2], *subkid; char *hexgrip, *serialno; 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; } 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; } 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; serialno = NULL; } else err = agent_get_keyinfo (ctrl, hexgrip, &serialno); 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 (); xfree (hexgrip); 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_SEXP_FORMAT)) err = build_sexp (out, node->pkt, &indent); else err = build_packet (out, node->pkt); } else if (!err) { /* FIXME: Move this spaghetti code into a separate function. */ unsigned char *wrappedkey = NULL; size_t wrappedkeylen; unsigned char *key = NULL; size_t keylen, realkeylen; gcry_sexp_t s_skey; if (opt.verbose) log_info ("key %s: asking agent for the secret parts\n", keystr_with_sub (keyid, subkid)); err = agent_export_key (ctrl, hexgrip, "Key foo", NULL, &wrappedkey, &wrappedkeylen); 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); xfree (key); key = NULL; if (err) goto unwraperror; err = transfer_format_to_openpgp (s_skey, pk); gcry_sexp_release (s_skey); if (err) goto unwraperror; if ((options&EXPORT_SEXP_FORMAT)) err = build_sexp (out, node->pkt, &indent); else err = build_packet (out, node->pkt); goto unwraperror_leave; unwraperror: xfree (wrappedkey); xfree (key); if (err) { log_error ("key %s: error receiving key from agent:" " %s%s\n", keystr_with_sub (keyid, subkid), gpg_strerror (err), gpg_err_code (err) == GPG_ERR_FULLY_CANCELED? "":_(" - skipped")); if (gpg_err_code (err) == GPG_ERR_FULLY_CANCELED) goto leave; skip_until_subkey = 1; err = 0; } unwraperror_leave: ; } 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; xfree (hexgrip); } else { if ((options&EXPORT_SEXP_FORMAT)) err = build_sexp (out, node->pkt, &indent); else err = build_packet (out, node->pkt); } if (err) { log_error ("build_packet(%d) failed: %s\n", node->pkt->pkttype, gpg_strerror (err)); goto leave; } if (!skip_until_subkey) *any = 1; } if ((options&EXPORT_SEXP_FORMAT) && indent) { for (; indent; indent--) iobuf_put (out, ')'); iobuf_put (out, '\n'); } if (keyblock_out) { *keyblock_out = keyblock; break; } } if ((options&EXPORT_SEXP_FORMAT) && indent) { for (; indent; indent--) iobuf_put (out, ')'); iobuf_put (out, '\n'); } if (gpg_err_code (err) == GPG_ERR_NOT_FOUND) err = 0; leave: gcry_cipher_close (cipherhd); release_subkey_list (subkey_list); xfree(desc); keydb_release (kdbhd); if (err || !keyblock_out) release_kbnode( keyblock ); if( !*any ) log_info(_("WARNING: nothing exported\n")); return err; } /* static int */ /* write_sexp_line (iobuf_t out, int *indent, const char *text) */ /* { */ /* int i; */ /* for (i=0; i < *indent; i++) */ /* iobuf_put (out, ' '); */ /* iobuf_writestr (out, text); */ /* return 0; */ /* } */ /* static int */ /* write_sexp_keyparm (iobuf_t out, int *indent, const char *name, gcry_mpi_t a) */ /* { */ /* int rc; */ /* unsigned char *buffer; */ /* write_sexp_line (out, indent, "("); */ /* iobuf_writestr (out, name); */ /* iobuf_writestr (out, " #"); */ /* rc = gcry_mpi_aprint (GCRYMPI_FMT_HEX, &buffer, NULL, a); */ /* assert (!rc); */ /* iobuf_writestr (out, buffer); */ /* iobuf_writestr (out, "#)"); */ /* gcry_free (buffer); */ /* return 0; */ /* } */ static int build_sexp_seckey (iobuf_t out, PACKET *pkt, int *indent) { (void)out; (void)pkt; (void)indent; /* FIXME: Not yet implemented. */ return gpg_error (GPG_ERR_NOT_IMPLEMENTED); /* PKT_secret_key *sk = pkt->pkt.secret_key; */ /* char tmpbuf[100]; */ /* if (pkt->pkttype == PKT_SECRET_KEY) */ /* { */ /* iobuf_writestr (out, "(openpgp-key\n"); */ /* (*indent)++; */ /* } */ /* else */ /* { */ /* iobuf_writestr (out, " (subkey\n"); */ /* (*indent)++; */ /* } */ /* (*indent)++; */ /* write_sexp_line (out, indent, "(private-key\n"); */ /* (*indent)++; */ /* if (is_RSA (sk->pubkey_algo) && !sk->is_protected) */ /* { */ /* write_sexp_line (out, indent, "(rsa\n"); */ /* (*indent)++; */ /* write_sexp_keyparm (out, indent, "n", sk->skey[0]); iobuf_put (out,'\n'); */ /* write_sexp_keyparm (out, indent, "e", sk->skey[1]); iobuf_put (out,'\n'); */ /* write_sexp_keyparm (out, indent, "d", sk->skey[2]); iobuf_put (out,'\n'); */ /* write_sexp_keyparm (out, indent, "p", sk->skey[3]); iobuf_put (out,'\n'); */ /* write_sexp_keyparm (out, indent, "q", sk->skey[4]); iobuf_put (out,'\n'); */ /* write_sexp_keyparm (out, indent, "u", sk->skey[5]); */ /* iobuf_put (out,')'); iobuf_put (out,'\n'); */ /* (*indent)--; */ /* } */ /* else if (sk->pubkey_algo == PUBKEY_ALGO_DSA && !sk->is_protected) */ /* { */ /* write_sexp_line (out, indent, "(dsa\n"); */ /* (*indent)++; */ /* write_sexp_keyparm (out, indent, "p", sk->skey[0]); iobuf_put (out,'\n'); */ /* write_sexp_keyparm (out, indent, "q", sk->skey[1]); iobuf_put (out,'\n'); */ /* write_sexp_keyparm (out, indent, "g", sk->skey[2]); iobuf_put (out,'\n'); */ /* write_sexp_keyparm (out, indent, "y", sk->skey[3]); iobuf_put (out,'\n'); */ /* write_sexp_keyparm (out, indent, "x", sk->skey[4]); */ /* iobuf_put (out,')'); iobuf_put (out,'\n'); */ /* (*indent)--; */ /* } */ /* else if (sk->pubkey_algo == PUBKEY_ALGO_ECDSA && !sk->is_protected) */ /* { */ /* write_sexp_line (out, indent, "(ecdsa\n"); */ /* (*indent)++; */ /* write_sexp_keyparm (out, indent, "c", sk->skey[0]); iobuf_put (out,'\n'); */ /* write_sexp_keyparm (out, indent, "q", sk->skey[6]); iobuf_put (out,'\n'); */ /* write_sexp_keyparm (out, indent, "d", sk->skey[7]); */ /* iobuf_put (out,')'); iobuf_put (out,'\n'); */ /* (*indent)--; */ /* } */ /* else if (is_ELGAMAL (sk->pubkey_algo) && !sk->is_protected) */ /* { */ /* write_sexp_line (out, indent, "(elg\n"); */ /* (*indent)++; */ /* write_sexp_keyparm (out, indent, "p", sk->skey[0]); iobuf_put (out,'\n'); */ /* write_sexp_keyparm (out, indent, "g", sk->skey[2]); iobuf_put (out,'\n'); */ /* write_sexp_keyparm (out, indent, "y", sk->skey[3]); iobuf_put (out,'\n'); */ /* write_sexp_keyparm (out, indent, "x", sk->skey[4]); */ /* iobuf_put (out,')'); iobuf_put (out,'\n'); */ /* (*indent)--; */ /* } */ /* write_sexp_line (out, indent, "(attrib\n"); (*indent)++; */ /* sprintf (tmpbuf, "(created \"%lu\"", (unsigned long)sk->timestamp); */ /* write_sexp_line (out, indent, tmpbuf); */ /* iobuf_put (out,')'); (*indent)--; /\* close created *\/ */ /* iobuf_put (out,')'); (*indent)--; /\* close attrib *\/ */ /* iobuf_put (out,')'); (*indent)--; /\* close private-key *\/ */ /* if (pkt->pkttype != PKT_SECRET_KEY) */ /* iobuf_put (out,')'), (*indent)--; /\* close subkey *\/ */ /* iobuf_put (out,'\n'); */ /* return 0; */ } /* For some packet types we write them in a S-expression format. This is still EXPERIMENTAL and subject to change. */ static int build_sexp (iobuf_t out, PACKET *pkt, int *indent) { int rc; switch (pkt->pkttype) { case PKT_SECRET_KEY: case PKT_SECRET_SUBKEY: rc = build_sexp_seckey (out, pkt, indent); break; default: rc = 0; break; } return rc; } diff --git a/g10/getkey.c b/g10/getkey.c index 4453a92d5..9cad71b37 100644 --- a/g10/getkey.c +++ b/g10/getkey.c @@ -1,3072 +1,3073 @@ /* getkey.c - Get a key from the database * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, * 2007, 2008, 2010 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 #include "gpg.h" #include "util.h" #include "packet.h" #include "iobuf.h" #include "keydb.h" #include "options.h" #include "main.h" #include "trustdb.h" #include "i18n.h" #include "keyserver-internal.h" #include "call-agent.h" #define MAX_PK_CACHE_ENTRIES PK_UID_CACHE_SIZE #define MAX_UID_CACHE_ENTRIES PK_UID_CACHE_SIZE #if MAX_PK_CACHE_ENTRIES < 2 #error We need the cache for key creation #endif struct getkey_ctx_s { int exact; int want_secret; /* The caller requested only secret keys. */ KBNODE keyblock; KBPOS kbpos; KBNODE found_key; /* Pointer into some keyblock. */ strlist_t extra_list; /* Will be freed when releasing the context. */ int last_rc; int req_usage; int req_algo; KEYDB_HANDLE kr_handle; int not_allocated; int nitems; KEYDB_SEARCH_DESC items[1]; }; #if 0 static struct { int any; int okay_count; int nokey_count; int error_count; } lkup_stats[21]; #endif typedef struct keyid_list { struct keyid_list *next; u32 keyid[2]; } *keyid_list_t; #if MAX_PK_CACHE_ENTRIES typedef struct pk_cache_entry { struct pk_cache_entry *next; u32 keyid[2]; PKT_public_key *pk; } *pk_cache_entry_t; static pk_cache_entry_t pk_cache; static int pk_cache_entries; /* Number of entries in pk cache. */ static int pk_cache_disabled; #endif #if MAX_UID_CACHE_ENTRIES < 5 #error we really need the userid cache #endif typedef struct user_id_db { struct user_id_db *next; keyid_list_t keyids; int len; char name[1]; } *user_id_db_t; static user_id_db_t user_id_db; static int uid_cache_entries; /* Number of entries in uid cache. */ static void merge_selfsigs (kbnode_t keyblock); static int lookup (getkey_ctx_t ctx, kbnode_t *ret_keyblock, int want_secret); #if 0 static void print_stats () { int i; for (i = 0; i < DIM (lkup_stats); i++) { if (lkup_stats[i].any) fprintf (stderr, "lookup stats: mode=%-2d ok=%-6d nokey=%-6d err=%-6d\n", i, lkup_stats[i].okay_count, lkup_stats[i].nokey_count, lkup_stats[i].error_count); } } #endif void cache_public_key (PKT_public_key * pk) { #if MAX_PK_CACHE_ENTRIES pk_cache_entry_t ce, ce2; u32 keyid[2]; if (pk_cache_disabled) return; if (pk->flags.dont_cache) return; if (is_ELGAMAL (pk->pubkey_algo) || pk->pubkey_algo == PUBKEY_ALGO_DSA || pk->pubkey_algo == PUBKEY_ALGO_ECDSA + || pk->pubkey_algo == PUBKEY_ALGO_EDDSA || pk->pubkey_algo == PUBKEY_ALGO_ECDH || is_RSA (pk->pubkey_algo)) { keyid_from_pk (pk, keyid); } else return; /* Don't know how to get the keyid. */ for (ce = pk_cache; ce; ce = ce->next) if (ce->keyid[0] == keyid[0] && ce->keyid[1] == keyid[1]) { if (DBG_CACHE) log_debug ("cache_public_key: already in cache\n"); return; } if (pk_cache_entries >= MAX_PK_CACHE_ENTRIES) { int n; /* Remove the last 50% of the entries. */ for (ce = pk_cache, n = 0; ce && n < pk_cache_entries/2; n++) ce = ce->next; if (ce != pk_cache && ce->next) { ce2 = ce->next; ce->next = NULL; ce = ce2; for (; ce; ce = ce2) { ce2 = ce->next; free_public_key (ce->pk); xfree (ce); pk_cache_entries--; } } assert (pk_cache_entries < MAX_PK_CACHE_ENTRIES); } pk_cache_entries++; ce = xmalloc (sizeof *ce); ce->next = pk_cache; pk_cache = ce; ce->pk = copy_public_key (NULL, pk); ce->keyid[0] = keyid[0]; ce->keyid[1] = keyid[1]; #endif } /* Return a const utf-8 string with the text "[User ID not found]". This function is required so that we don't need to switch gettext's encoding temporary. */ static const char * user_id_not_found_utf8 (void) { static char *text; if (!text) text = native_to_utf8 (_("[User ID not found]")); return text; } /* Return the user ID from the given keyblock. * We use the primary uid flag which has been set by the merge_selfsigs * function. The returned value is only valid as long as then given * keyblock is not changed. */ static const char * get_primary_uid (KBNODE keyblock, size_t * uidlen) { KBNODE k; const char *s; for (k = keyblock; k; k = k->next) { if (k->pkt->pkttype == PKT_USER_ID && !k->pkt->pkt.user_id->attrib_data && k->pkt->pkt.user_id->is_primary) { *uidlen = k->pkt->pkt.user_id->len; return k->pkt->pkt.user_id->name; } } s = user_id_not_found_utf8 (); *uidlen = strlen (s); return s; } static void release_keyid_list (keyid_list_t k) { while (k) { keyid_list_t k2 = k->next; xfree (k); k = k2; } } /**************** * Store the association of keyid and userid * Feed only public keys to this function. */ static void cache_user_id (KBNODE keyblock) { user_id_db_t r; const char *uid; size_t uidlen; keyid_list_t keyids = NULL; KBNODE k; for (k = keyblock; k; k = k->next) { if (k->pkt->pkttype == PKT_PUBLIC_KEY || k->pkt->pkttype == PKT_PUBLIC_SUBKEY) { keyid_list_t a = xmalloc_clear (sizeof *a); /* Hmmm: For a long list of keyids it might be an advantage * to append the keys. */ keyid_from_pk (k->pkt->pkt.public_key, a->keyid); /* First check for duplicates. */ for (r = user_id_db; r; r = r->next) { keyid_list_t b = r->keyids; for (b = r->keyids; b; b = b->next) { if (b->keyid[0] == a->keyid[0] && b->keyid[1] == a->keyid[1]) { if (DBG_CACHE) log_debug ("cache_user_id: already in cache\n"); release_keyid_list (keyids); xfree (a); return; } } } /* Now put it into the cache. */ a->next = keyids; keyids = a; } } if (!keyids) BUG (); /* No key no fun. */ uid = get_primary_uid (keyblock, &uidlen); if (uid_cache_entries >= MAX_UID_CACHE_ENTRIES) { /* fixme: use another algorithm to free some cache slots */ r = user_id_db; user_id_db = r->next; release_keyid_list (r->keyids); xfree (r); uid_cache_entries--; } r = xmalloc (sizeof *r + uidlen - 1); r->keyids = keyids; r->len = uidlen; memcpy (r->name, uid, r->len); r->next = user_id_db; user_id_db = r; uid_cache_entries++; } void getkey_disable_caches () { #if MAX_PK_CACHE_ENTRIES { pk_cache_entry_t ce, ce2; for (ce = pk_cache; ce; ce = ce2) { ce2 = ce->next; free_public_key (ce->pk); xfree (ce); } pk_cache_disabled = 1; pk_cache_entries = 0; pk_cache = NULL; } #endif /* fixme: disable user id cache ? */ } static void pk_from_block (GETKEY_CTX ctx, PKT_public_key * pk, KBNODE keyblock) { KBNODE a = ctx->found_key ? ctx->found_key : keyblock; assert (a->pkt->pkttype == PKT_PUBLIC_KEY || a->pkt->pkttype == PKT_PUBLIC_SUBKEY); copy_public_key (pk, a->pkt->pkt.public_key); } /* Get a public key and store it into the allocated pk can be called * with PK set to NULL to just read it into some internal * structures. */ int get_pubkey (PKT_public_key * pk, u32 * keyid) { int internal = 0; int rc = 0; #if MAX_PK_CACHE_ENTRIES if (pk) { /* Try to get it from the cache. We don't do this when pk is NULL as it does not guarantee that the user IDs are cached. */ pk_cache_entry_t ce; for (ce = pk_cache; ce; ce = ce->next) { if (ce->keyid[0] == keyid[0] && ce->keyid[1] == keyid[1]) { copy_public_key (pk, ce->pk); return 0; } } } #endif /* More init stuff. */ if (!pk) { pk = xmalloc_clear (sizeof *pk); internal++; } /* Do a lookup. */ { struct getkey_ctx_s ctx; KBNODE kb = NULL; memset (&ctx, 0, sizeof ctx); ctx.exact = 1; /* Use the key ID exactly as given. */ ctx.not_allocated = 1; ctx.kr_handle = keydb_new (); ctx.nitems = 1; ctx.items[0].mode = KEYDB_SEARCH_MODE_LONG_KID; ctx.items[0].u.kid[0] = keyid[0]; ctx.items[0].u.kid[1] = keyid[1]; ctx.req_algo = pk->req_algo; ctx.req_usage = pk->req_usage; rc = lookup (&ctx, &kb, 0); if (!rc) { pk_from_block (&ctx, pk, kb); } get_pubkey_end (&ctx); release_kbnode (kb); } if (!rc) goto leave; rc = G10ERR_NO_PUBKEY; leave: if (!rc) cache_public_key (pk); if (internal) free_public_key (pk); return rc; } /* Get a public key and store it into the allocated pk. This function differs from get_pubkey() in that it does not do a check of the key to avoid recursion. It should be used only in very certain cases. It will only retrieve primary keys. */ int get_pubkey_fast (PKT_public_key * pk, u32 * keyid) { int rc = 0; KEYDB_HANDLE hd; KBNODE keyblock; u32 pkid[2]; assert (pk); #if MAX_PK_CACHE_ENTRIES { /* Try to get it from the cache */ pk_cache_entry_t ce; for (ce = pk_cache; ce; ce = ce->next) { if (ce->keyid[0] == keyid[0] && ce->keyid[1] == keyid[1]) { if (pk) copy_public_key (pk, ce->pk); return 0; } } } #endif hd = keydb_new (); rc = keydb_search_kid (hd, keyid); if (gpg_err_code (rc) == GPG_ERR_NOT_FOUND) { keydb_release (hd); return G10ERR_NO_PUBKEY; } rc = keydb_get_keyblock (hd, &keyblock); keydb_release (hd); if (rc) { log_error ("keydb_get_keyblock failed: %s\n", g10_errstr (rc)); return G10ERR_NO_PUBKEY; } assert (keyblock && keyblock->pkt && (keyblock->pkt->pkttype == PKT_PUBLIC_KEY || keyblock->pkt->pkttype == PKT_PUBLIC_SUBKEY)); keyid_from_pk (keyblock->pkt->pkt.public_key, pkid); if (keyid[0] == pkid[0] && keyid[1] == pkid[1]) copy_public_key (pk, keyblock->pkt->pkt.public_key); else rc = G10ERR_NO_PUBKEY; release_kbnode (keyblock); /* Not caching key here since it won't have all of the fields properly set. */ return rc; } KBNODE get_pubkeyblock (u32 * keyid) { struct getkey_ctx_s ctx; int rc = 0; KBNODE keyblock = NULL; memset (&ctx, 0, sizeof ctx); /* No need to set exact here because we want the entire block. */ ctx.not_allocated = 1; ctx.kr_handle = keydb_new (); ctx.nitems = 1; ctx.items[0].mode = KEYDB_SEARCH_MODE_LONG_KID; ctx.items[0].u.kid[0] = keyid[0]; ctx.items[0].u.kid[1] = keyid[1]; rc = lookup (&ctx, &keyblock, 0); get_pubkey_end (&ctx); return rc ? NULL : keyblock; } /* * Get a public key and store it into PK. This functions check that a * corresponding secret key is available. With no secret key it does * not succeeed. */ gpg_error_t get_seckey (PKT_public_key *pk, u32 *keyid) { gpg_error_t err; struct getkey_ctx_s ctx; kbnode_t keyblock = NULL; memset (&ctx, 0, sizeof ctx); ctx.exact = 1; /* Use the key ID exactly as given. */ ctx.not_allocated = 1; ctx.kr_handle = keydb_new (); ctx.nitems = 1; ctx.items[0].mode = KEYDB_SEARCH_MODE_LONG_KID; ctx.items[0].u.kid[0] = keyid[0]; ctx.items[0].u.kid[1] = keyid[1]; ctx.req_algo = pk->req_algo; ctx.req_usage = pk->req_usage; err = lookup (&ctx, &keyblock, 1); if (!err) { pk_from_block (&ctx, pk, keyblock); } get_pubkey_end (&ctx); release_kbnode (keyblock); if (!err) err = agent_probe_secret_key (/*ctrl*/NULL, pk); return err; } static int skip_unusable (void *dummy, u32 * keyid, PKT_user_id * uid) { int unusable = 0; KBNODE keyblock; (void) dummy; keyblock = get_pubkeyblock (keyid); if (!keyblock) { log_error ("error checking usability status of %s\n", keystr (keyid)); goto leave; } /* Is the user ID in question revoked/expired? */ if (uid) { KBNODE node; for (node = keyblock; node; node = node->next) { if (node->pkt->pkttype == PKT_USER_ID) { if (cmp_user_ids (uid, node->pkt->pkt.user_id) == 0 && (node->pkt->pkt.user_id->is_revoked || node->pkt->pkt.user_id->is_expired)) { unusable = 1; break; } } } } if (!unusable) unusable = pk_is_disabled (keyblock->pkt->pkt.public_key); leave: release_kbnode (keyblock); return unusable; } /* Try to get the pubkey by the userid. This function looks for the * first pubkey certificate which has the given name in a user_id. If * PK has the pubkey algo set, the function will only return a pubkey * with that algo. If NAMELIST is NULL, the first key is returned. * The caller should provide storage for the PK or pass NULL if it is * not needed. If RET_KB is not NULL the function stores the entire * keyblock at that address. */ static int key_byname (GETKEY_CTX *retctx, strlist_t namelist, PKT_public_key *pk, int want_secret, int include_unusable, KBNODE * ret_kb, KEYDB_HANDLE * ret_kdbhd) { int rc = 0; int n; strlist_t r; GETKEY_CTX ctx; KBNODE help_kb = NULL; if (retctx) { /* Reset the returned context in case of error. */ assert (!ret_kdbhd); /* Not allowed because the handle is stored in the context. */ *retctx = NULL; } if (ret_kdbhd) *ret_kdbhd = NULL; if (!namelist) { ctx = xmalloc_clear (sizeof *ctx); ctx->nitems = 1; ctx->items[0].mode = KEYDB_SEARCH_MODE_FIRST; if (!include_unusable) ctx->items[0].skipfnc = skip_unusable; } else { /* Build the search context. */ for (n = 0, r = namelist; r; r = r->next) n++; ctx = xmalloc_clear (sizeof *ctx + (n - 1) * sizeof ctx->items); ctx->nitems = n; for (n = 0, r = namelist; r; r = r->next, n++) { gpg_error_t err; err = classify_user_id (r->d, &ctx->items[n], 1); if (ctx->items[n].exact) ctx->exact = 1; if (err) { xfree (ctx); return gpg_err_code (err); /* FIXME: remove gpg_err_code. */ } if (!include_unusable && ctx->items[n].mode != KEYDB_SEARCH_MODE_SHORT_KID && ctx->items[n].mode != KEYDB_SEARCH_MODE_LONG_KID && ctx->items[n].mode != KEYDB_SEARCH_MODE_FPR16 && ctx->items[n].mode != KEYDB_SEARCH_MODE_FPR20 && ctx->items[n].mode != KEYDB_SEARCH_MODE_FPR) ctx->items[n].skipfnc = skip_unusable; } } ctx->want_secret = want_secret; ctx->kr_handle = keydb_new (); if (!ret_kb) ret_kb = &help_kb; if (pk) { ctx->req_algo = pk->req_algo; ctx->req_usage = pk->req_usage; } rc = lookup (ctx, ret_kb, want_secret); if (!rc && pk) { pk_from_block (ctx, pk, *ret_kb); } release_kbnode (help_kb); if (retctx) /* Caller wants the context. */ *retctx = ctx; else { if (ret_kdbhd) { *ret_kdbhd = ctx->kr_handle; ctx->kr_handle = NULL; } get_pubkey_end (ctx); } return rc; } /* Find a public key from NAME and return the keyblock or the key. If ret_kdb is not NULL, the KEYDB handle used to locate this keyblock is returned and the caller is responsible for closing it. If a key was not found (or if local search has been disabled) and NAME is a valid RFC822 mailbox and --auto-key-locate has been enabled, we try to import the key via the online mechanisms defined by --auto-key-locate. */ int get_pubkey_byname (ctrl_t ctrl, GETKEY_CTX * retctx, PKT_public_key * pk, const char *name, KBNODE * ret_keyblock, KEYDB_HANDLE * ret_kdbhd, int include_unusable, int no_akl) { int rc; strlist_t namelist = NULL; struct akl *akl; int is_mbox; int nodefault = 0; int anylocalfirst = 0; if (retctx) *retctx = NULL; is_mbox = is_valid_mailbox (name); /* Check whether we the default local search has been disabled. This is the case if either the "nodefault" or the "local" keyword are in the list of auto key locate mechanisms. ANYLOCALFIRST is set if the search order has the local method before any other or if "local" is used first by default. This makes sure that if a RETCTX is used it gets only set if a local search has precedence over the other search methods and only then a followup call to get_pubkey_next shall succeed. */ if (!no_akl) { for (akl = opt.auto_key_locate; akl; akl = akl->next) if (akl->type == AKL_NODEFAULT || akl->type == AKL_LOCAL) { nodefault = 1; break; } for (akl = opt.auto_key_locate; akl; akl = akl->next) if (akl->type != AKL_NODEFAULT) { if (akl->type == AKL_LOCAL) anylocalfirst = 1; break; } } if (!nodefault) anylocalfirst = 1; if (nodefault && is_mbox) { /* Nodefault but a mailbox - let the AKL locate the key. */ rc = G10ERR_NO_PUBKEY; } else { add_to_strlist (&namelist, name); rc = key_byname (retctx, namelist, pk, 0, include_unusable, ret_keyblock, ret_kdbhd); } /* If the requested name resembles a valid mailbox and automatic retrieval has been enabled, we try to import the key. */ if (gpg_err_code (rc) == G10ERR_NO_PUBKEY && !no_akl && is_mbox) { for (akl = opt.auto_key_locate; akl; akl = akl->next) { unsigned char *fpr = NULL; size_t fpr_len; int did_key_byname = 0; int no_fingerprint = 0; const char *mechanism = "?"; switch (akl->type) { case AKL_NODEFAULT: /* This is a dummy mechanism. */ mechanism = "None"; rc = G10ERR_NO_PUBKEY; break; case AKL_LOCAL: mechanism = "Local"; did_key_byname = 1; if (retctx) { get_pubkey_end (*retctx); *retctx = NULL; } add_to_strlist (&namelist, name); rc = key_byname (anylocalfirst ? retctx : NULL, namelist, pk, 0, include_unusable, ret_keyblock, ret_kdbhd); break; case AKL_CERT: mechanism = "DNS CERT"; glo_ctrl.in_auto_key_retrieve++; rc = keyserver_import_cert (ctrl, name, &fpr, &fpr_len); glo_ctrl.in_auto_key_retrieve--; break; case AKL_PKA: mechanism = "PKA"; glo_ctrl.in_auto_key_retrieve++; rc = keyserver_import_pka (ctrl, name, &fpr, &fpr_len); glo_ctrl.in_auto_key_retrieve--; break; case AKL_LDAP: mechanism = "LDAP"; glo_ctrl.in_auto_key_retrieve++; rc = keyserver_import_ldap (ctrl, name, &fpr, &fpr_len); glo_ctrl.in_auto_key_retrieve--; break; case AKL_KEYSERVER: /* Strictly speaking, we don't need to only use a valid mailbox for the getname search, but it helps cut down on the problem of searching for something like "john" and getting a whole lot of keys back. */ if (opt.keyserver) { mechanism = opt.keyserver->uri; glo_ctrl.in_auto_key_retrieve++; rc = keyserver_import_name (ctrl, name, &fpr, &fpr_len, opt.keyserver); glo_ctrl.in_auto_key_retrieve--; } else { mechanism = "Unconfigured keyserver"; rc = G10ERR_NO_PUBKEY; } break; case AKL_SPEC: { struct keyserver_spec *keyserver; mechanism = akl->spec->uri; keyserver = keyserver_match (akl->spec); glo_ctrl.in_auto_key_retrieve++; rc = keyserver_import_name (ctrl, name, &fpr, &fpr_len, keyserver); glo_ctrl.in_auto_key_retrieve--; } break; } /* Use the fingerprint of the key that we actually fetched. This helps prevent problems where the key that we fetched doesn't have the same name that we used to fetch it. In the case of CERT and PKA, this is an actual security requirement as the URL might point to a key put in by an attacker. By forcing the use of the fingerprint, we won't use the attacker's key here. */ if (!rc && fpr) { char fpr_string[MAX_FINGERPRINT_LEN * 2 + 1]; assert (fpr_len <= MAX_FINGERPRINT_LEN); free_strlist (namelist); namelist = NULL; bin2hex (fpr, fpr_len, fpr_string); if (opt.verbose) log_info ("auto-key-locate found fingerprint %s\n", fpr_string); add_to_strlist (&namelist, fpr_string); } else if (!rc && !fpr && !did_key_byname) { no_fingerprint = 1; rc = G10ERR_NO_PUBKEY; } xfree (fpr); fpr = NULL; if (!rc && !did_key_byname) { if (retctx) { get_pubkey_end (*retctx); *retctx = NULL; } rc = key_byname (anylocalfirst ? retctx : NULL, namelist, pk, 0, include_unusable, ret_keyblock, ret_kdbhd); } if (!rc) { /* Key found. */ log_info (_("automatically retrieved '%s' via %s\n"), name, mechanism); break; } if (rc != G10ERR_NO_PUBKEY || opt.verbose || no_fingerprint) log_info (_("error retrieving '%s' via %s: %s\n"), name, mechanism, no_fingerprint ? _("No fingerprint") : g10_errstr (rc)); } } if (rc && retctx) { get_pubkey_end (*retctx); *retctx = NULL; } if (retctx && *retctx) { assert (!(*retctx)->extra_list); (*retctx)->extra_list = namelist; } else free_strlist (namelist); return rc; } int get_pubkey_bynames (GETKEY_CTX * retctx, PKT_public_key * pk, strlist_t names, KBNODE * ret_keyblock) { return key_byname (retctx, names, pk, 0, 1, ret_keyblock, NULL); } int get_pubkey_next (GETKEY_CTX ctx, PKT_public_key * pk, KBNODE * ret_keyblock) { int rc; rc = lookup (ctx, ret_keyblock, 0); if (!rc && pk && ret_keyblock) pk_from_block (ctx, pk, *ret_keyblock); return rc; } void get_pubkey_end (GETKEY_CTX ctx) { if (ctx) { memset (&ctx->kbpos, 0, sizeof ctx->kbpos); keydb_release (ctx->kr_handle); free_strlist (ctx->extra_list); if (!ctx->not_allocated) xfree (ctx); } } /* Search for a key with the given fingerprint. * FIXME: * We should replace this with the _byname function. This can be done * by creating a userID conforming to the unified fingerprint style. */ int get_pubkey_byfprint (PKT_public_key * pk, const byte * fprint, size_t fprint_len) { int rc; if (fprint_len == 20 || fprint_len == 16) { struct getkey_ctx_s ctx; KBNODE kb = NULL; memset (&ctx, 0, sizeof ctx); ctx.exact = 1; ctx.not_allocated = 1; ctx.kr_handle = keydb_new (); ctx.nitems = 1; ctx.items[0].mode = fprint_len == 16 ? KEYDB_SEARCH_MODE_FPR16 : KEYDB_SEARCH_MODE_FPR20; memcpy (ctx.items[0].u.fpr, fprint, fprint_len); rc = lookup (&ctx, &kb, 0); if (!rc && pk) pk_from_block (&ctx, pk, kb); release_kbnode (kb); get_pubkey_end (&ctx); } else rc = G10ERR_GENERAL; /* Oops */ return rc; } /* Get a public key and store it into the allocated pk. This function differs from get_pubkey_byfprint() in that it does not do a check of the key to avoid recursion. It should be used only in very certain cases. PK may be NULL to check just for the existance of the key. */ int get_pubkey_byfprint_fast (PKT_public_key * pk, const byte * fprint, size_t fprint_len) { int rc = 0; KEYDB_HANDLE hd; KBNODE keyblock; byte fprbuf[MAX_FINGERPRINT_LEN]; int i; for (i = 0; i < MAX_FINGERPRINT_LEN && i < fprint_len; i++) fprbuf[i] = fprint[i]; while (i < MAX_FINGERPRINT_LEN) fprbuf[i++] = 0; hd = keydb_new (); rc = keydb_search_fpr (hd, fprbuf); if (gpg_err_code (rc) == GPG_ERR_NOT_FOUND) { keydb_release (hd); return G10ERR_NO_PUBKEY; } rc = keydb_get_keyblock (hd, &keyblock); keydb_release (hd); if (rc) { log_error ("keydb_get_keyblock failed: %s\n", g10_errstr (rc)); return G10ERR_NO_PUBKEY; } assert (keyblock->pkt->pkttype == PKT_PUBLIC_KEY || keyblock->pkt->pkttype == PKT_PUBLIC_SUBKEY); if (pk) copy_public_key (pk, keyblock->pkt->pkt.public_key); release_kbnode (keyblock); /* Not caching key here since it won't have all of the fields properly set. */ return 0; } /* Search for a key with the given fingerprint and return the * complete keyblock which may have more than only this key. */ int get_keyblock_byfprint (KBNODE * ret_keyblock, const byte * fprint, size_t fprint_len) { int rc; if (fprint_len == 20 || fprint_len == 16) { struct getkey_ctx_s ctx; memset (&ctx, 0, sizeof ctx); ctx.not_allocated = 1; ctx.kr_handle = keydb_new (); ctx.nitems = 1; ctx.items[0].mode = (fprint_len == 16 ? KEYDB_SEARCH_MODE_FPR16 : KEYDB_SEARCH_MODE_FPR20); memcpy (ctx.items[0].u.fpr, fprint, fprint_len); rc = lookup (&ctx, ret_keyblock, 0); get_pubkey_end (&ctx); } else rc = G10ERR_GENERAL; /* Oops */ return rc; } /* Get a secret key by NAME and store it into PK. If NAME is NULL use * the default key. This functions checks that a corresponding secret * key is available. With no secret key it does not succeeed. */ gpg_error_t get_seckey_byname (PKT_public_key *pk, const char *name) { gpg_error_t err; strlist_t namelist = NULL; int include_unusable = 1; /* If we have no name, try to use the default secret key. If we have no default, we'll use the first usable one. */ if (!name && opt.def_secret_key && *opt.def_secret_key) add_to_strlist (&namelist, opt.def_secret_key); else if (name) add_to_strlist (&namelist, name); else include_unusable = 0; err = key_byname (NULL, namelist, pk, 1, include_unusable, NULL, NULL); free_strlist (namelist); return err; } /* Search for a key with the given fingerprint. * FIXME: * We should replace this with the _byname function. This can be done * by creating a userID conforming to the unified fingerprint style. */ gpg_error_t get_seckey_byfprint (PKT_public_key *pk, const byte * fprint, size_t fprint_len) { gpg_error_t err; if (fprint_len == 20 || fprint_len == 16) { struct getkey_ctx_s ctx; kbnode_t kb = NULL; memset (&ctx, 0, sizeof ctx); ctx.exact = 1; ctx.not_allocated = 1; ctx.kr_handle = keydb_new (); ctx.nitems = 1; ctx.items[0].mode = fprint_len == 16 ? KEYDB_SEARCH_MODE_FPR16 : KEYDB_SEARCH_MODE_FPR20; memcpy (ctx.items[0].u.fpr, fprint, fprint_len); err = lookup (&ctx, &kb, 1); if (!err && pk) pk_from_block (&ctx, pk, kb); release_kbnode (kb); get_pubkey_end (&ctx); } else err = gpg_error (GPG_ERR_BUG); return err; } /* Search for a secret key with the given fingerprint and return the complete keyblock which may have more than only this key. Return an error if no corresponding secret key is available. */ gpg_error_t get_seckeyblock_byfprint (kbnode_t *ret_keyblock, const byte *fprint, size_t fprint_len) { gpg_error_t err; struct getkey_ctx_s ctx; if (fprint_len != 20 && fprint_len == 16) return gpg_error (GPG_ERR_BUG); memset (&ctx, 0, sizeof ctx); ctx.not_allocated = 1; ctx.kr_handle = keydb_new (); ctx.nitems = 1; ctx.items[0].mode = (fprint_len == 16 ? KEYDB_SEARCH_MODE_FPR16 : KEYDB_SEARCH_MODE_FPR20); memcpy (ctx.items[0].u.fpr, fprint, fprint_len); err = lookup (&ctx, ret_keyblock, 1); get_pubkey_end (&ctx); return err; } /* The new function to return a key. FIXME: Document it. */ gpg_error_t getkey_bynames (getkey_ctx_t *retctx, PKT_public_key *pk, strlist_t names, int want_secret, kbnode_t *ret_keyblock) { return key_byname (retctx, names, pk, want_secret, 1, ret_keyblock, NULL); } /* Get a key by name and store it into PK if that is not NULL. If * RETCTX is not NULL return the search context which needs to be * released by the caller using getkey_end. If NAME is NULL use the * default key (see below). On success and if RET_KEYBLOCK is not * NULL the found keyblock is stored at this address. WANT_SECRET * passed as true requires that a secret key is available for the * selected key. * * If WANT_SECRET is true and NAME is NULL and a default key has been * defined that defined key is used. In all other cases the first * available key is used. * * FIXME: Explain what is up with unusable keys. * * FIXME: We also have the get_pubkey_byname function which has a * different semantic. Should be merged with this one. */ gpg_error_t getkey_byname (getkey_ctx_t *retctx, PKT_public_key *pk, const char *name, int want_secret, kbnode_t *ret_keyblock) { gpg_error_t err; strlist_t namelist = NULL; int with_unusable = 1; if (want_secret && !name && opt.def_secret_key && *opt.def_secret_key) add_to_strlist (&namelist, opt.def_secret_key); else if (name) add_to_strlist (&namelist, name); else with_unusable = 0; err = key_byname (retctx, namelist, pk, want_secret, with_unusable, ret_keyblock, NULL); /* FIXME: Check that we really return GPG_ERR_NO_SECKEY if WANT_SECRET has been used. */ free_strlist (namelist); return err; } /* The new function to return the next key. */ gpg_error_t getkey_next (getkey_ctx_t ctx, PKT_public_key *pk, kbnode_t *ret_keyblock) { int rc; /* Fixme: Make sure this is proper gpg_error */ rc = lookup (ctx, ret_keyblock, ctx->want_secret); if (!rc && pk && ret_keyblock) pk_from_block (ctx, pk, *ret_keyblock); return rc; } /* The new function to finish a key listing. */ void getkey_end (getkey_ctx_t ctx) { get_pubkey_end (ctx); } /************************************************ ************* Merging stuff ******************** ************************************************/ /* Merge all self-signatures with the keys. */ void merge_keys_and_selfsig (KBNODE keyblock) { if (!keyblock) ; else if (keyblock->pkt->pkttype == PKT_PUBLIC_KEY) merge_selfsigs (keyblock); else log_debug ("FIXME: merging secret key blocks is not anymore available\n"); } static int parse_key_usage (PKT_signature * sig) { int key_usage = 0; const byte *p; size_t n; byte flags; p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_KEY_FLAGS, &n); if (p && n) { /* First octet of the keyflags. */ flags = *p; if (flags & 1) { key_usage |= PUBKEY_USAGE_CERT; flags &= ~1; } if (flags & 2) { key_usage |= PUBKEY_USAGE_SIG; flags &= ~2; } /* We do not distinguish between encrypting communications and encrypting storage. */ if (flags & (0x04 | 0x08)) { key_usage |= PUBKEY_USAGE_ENC; flags &= ~(0x04 | 0x08); } if (flags & 0x20) { key_usage |= PUBKEY_USAGE_AUTH; flags &= ~0x20; } if (flags) key_usage |= PUBKEY_USAGE_UNKNOWN; if (!key_usage) key_usage |= PUBKEY_USAGE_NONE; } else if (p) /* Key flags of length zero. */ key_usage |= PUBKEY_USAGE_NONE; /* We set PUBKEY_USAGE_UNKNOWN to indicate that this key has a capability that we do not handle. This serves to distinguish between a zero key usage which we handle as the default capabilities for that algorithm, and a usage that we do not handle. Likewise we use PUBKEY_USAGE_NONE to indicate that key_flags have been given but they do not specify any usage. */ return key_usage; } /* Apply information from SIGNODE (which is the valid self-signature * associated with that UID) to the UIDNODE: * - wether the UID has been revoked * - assumed creation date of the UID * - temporary store the keyflags here * - temporary store the key expiration time here * - mark whether the primary user ID flag hat been set. * - store the preferences */ static void fixup_uidnode (KBNODE uidnode, KBNODE signode, u32 keycreated) { PKT_user_id *uid = uidnode->pkt->pkt.user_id; PKT_signature *sig = signode->pkt->pkt.signature; const byte *p, *sym, *hash, *zip; size_t n, nsym, nhash, nzip; sig->flags.chosen_selfsig = 1;/* We chose this one. */ uid->created = 0; /* Not created == invalid. */ if (IS_UID_REV (sig)) { uid->is_revoked = 1; return; /* Has been revoked. */ } else uid->is_revoked = 0; uid->expiredate = sig->expiredate; if (sig->flags.expired) { uid->is_expired = 1; return; /* Has expired. */ } else uid->is_expired = 0; uid->created = sig->timestamp; /* This one is okay. */ uid->selfsigversion = sig->version; /* If we got this far, it's not expired :) */ uid->is_expired = 0; /* Store the key flags in the helper variable for later processing. */ uid->help_key_usage = parse_key_usage (sig); /* Ditto for the key expiration. */ p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_KEY_EXPIRE, NULL); if (p && buffer_to_u32 (p)) uid->help_key_expire = keycreated + buffer_to_u32 (p); else uid->help_key_expire = 0; /* Set the primary user ID flag - we will later wipe out some * of them to only have one in our keyblock. */ uid->is_primary = 0; p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_PRIMARY_UID, NULL); if (p && *p) uid->is_primary = 2; /* We could also query this from the unhashed area if it is not in * the hased area and then later try to decide which is the better * there should be no security problem with this. * For now we only look at the hashed one. */ /* Now build the preferences list. These must come from the hashed section so nobody can modify the ciphers a key is willing to accept. */ p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_PREF_SYM, &n); sym = p; nsym = p ? n : 0; p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_PREF_HASH, &n); hash = p; nhash = p ? n : 0; p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_PREF_COMPR, &n); zip = p; nzip = p ? n : 0; if (uid->prefs) xfree (uid->prefs); n = nsym + nhash + nzip; if (!n) uid->prefs = NULL; else { uid->prefs = xmalloc (sizeof (*uid->prefs) * (n + 1)); n = 0; for (; nsym; nsym--, n++) { uid->prefs[n].type = PREFTYPE_SYM; uid->prefs[n].value = *sym++; } for (; nhash; nhash--, n++) { uid->prefs[n].type = PREFTYPE_HASH; uid->prefs[n].value = *hash++; } for (; nzip; nzip--, n++) { uid->prefs[n].type = PREFTYPE_ZIP; uid->prefs[n].value = *zip++; } uid->prefs[n].type = PREFTYPE_NONE; /* End of list marker */ uid->prefs[n].value = 0; } /* See whether we have the MDC feature. */ uid->flags.mdc = 0; p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_FEATURES, &n); if (p && n && (p[0] & 0x01)) uid->flags.mdc = 1; /* And the keyserver modify flag. */ uid->flags.ks_modify = 1; p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_KS_FLAGS, &n); if (p && n && (p[0] & 0x80)) uid->flags.ks_modify = 0; } static void sig_to_revoke_info (PKT_signature * sig, struct revoke_info *rinfo) { rinfo->date = sig->timestamp; rinfo->algo = sig->pubkey_algo; rinfo->keyid[0] = sig->keyid[0]; rinfo->keyid[1] = sig->keyid[1]; } /* Note that R_REVOKED may be set to 0, 1 or 2. */ static void merge_selfsigs_main (KBNODE keyblock, int *r_revoked, struct revoke_info *rinfo) { PKT_public_key *pk = NULL; KBNODE k; u32 kid[2]; u32 sigdate, uiddate, uiddate2; KBNODE signode, uidnode, uidnode2; u32 curtime = make_timestamp (); unsigned int key_usage = 0; u32 keytimestamp = 0; u32 key_expire = 0; int key_expire_seen = 0; byte sigversion = 0; *r_revoked = 0; memset (rinfo, 0, sizeof (*rinfo)); if (keyblock->pkt->pkttype != PKT_PUBLIC_KEY) BUG (); pk = keyblock->pkt->pkt.public_key; keytimestamp = pk->timestamp; keyid_from_pk (pk, kid); pk->main_keyid[0] = kid[0]; pk->main_keyid[1] = kid[1]; if (pk->version < 4) { /* Before v4 the key packet itself contains the expiration date * and there was no way to change it, so we start with the one * from the key packet. */ key_expire = pk->max_expiredate; key_expire_seen = 1; } /* First pass: Find the latest direct key self-signature. We assume * that the newest one overrides all others. */ /* In case this key was already merged. */ xfree (pk->revkey); pk->revkey = NULL; pk->numrevkeys = 0; signode = NULL; sigdate = 0; /* Helper variable to find the latest signature. */ for (k = keyblock; k && k->pkt->pkttype != PKT_USER_ID; k = k->next) { if (k->pkt->pkttype == PKT_SIGNATURE) { PKT_signature *sig = k->pkt->pkt.signature; if (sig->keyid[0] == kid[0] && sig->keyid[1] == kid[1]) { if (check_key_signature (keyblock, k, NULL)) ; /* Signature did not verify. */ else if (IS_KEY_REV (sig)) { /* Key has been revoked - there is no way to * override such a revocation, so we theoretically * can stop now. We should not cope with expiration * times for revocations here because we have to * assume that an attacker can generate all kinds of * signatures. However due to the fact that the key * has been revoked it does not harm either and by * continuing we gather some more info on that * key. */ *r_revoked = 1; sig_to_revoke_info (sig, rinfo); } else if (IS_KEY_SIG (sig)) { /* Add any revocation keys onto the pk. This is particularly interesting since we normally only get data from the most recent 1F signature, but you need multiple 1F sigs to properly handle revocation keys (PGP does it this way, and a revocation key could be sensitive and hence in a different signature). */ if (sig->revkey) { int i; pk->revkey = xrealloc (pk->revkey, sizeof (struct revocation_key) * (pk->numrevkeys + sig->numrevkeys)); for (i = 0; i < sig->numrevkeys; i++) memcpy (&pk->revkey[pk->numrevkeys++], sig->revkey[i], sizeof (struct revocation_key)); } if (sig->timestamp >= sigdate) { if (sig->flags.expired) ; /* Signature has expired - ignore it. */ else { sigdate = sig->timestamp; signode = k; if (sig->version > sigversion) sigversion = sig->version; } } } } } } /* Remove dupes from the revocation keys. */ if (pk->revkey) { int i, j, x, changed = 0; for (i = 0; i < pk->numrevkeys; i++) { for (j = i + 1; j < pk->numrevkeys; j++) { if (memcmp (&pk->revkey[i], &pk->revkey[j], sizeof (struct revocation_key)) == 0) { /* remove j */ for (x = j; x < pk->numrevkeys - 1; x++) pk->revkey[x] = pk->revkey[x + 1]; pk->numrevkeys--; j--; changed = 1; } } } if (changed) pk->revkey = xrealloc (pk->revkey, pk->numrevkeys * sizeof (struct revocation_key)); } if (signode) { /* Some information from a direct key signature take precedence * over the same information given in UID sigs. */ PKT_signature *sig = signode->pkt->pkt.signature; const byte *p; key_usage = parse_key_usage (sig); p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_KEY_EXPIRE, NULL); if (p && buffer_to_u32 (p)) { key_expire = keytimestamp + buffer_to_u32 (p); key_expire_seen = 1; } /* Mark that key as valid: One direct key signature should * render a key as valid. */ pk->flags.valid = 1; } /* Pass 1.5: Look for key revocation signatures that were not made by the key (i.e. did a revocation key issue a revocation for us?). Only bother to do this if there is a revocation key in the first place and we're not revoked already. */ if (!*r_revoked && pk->revkey) for (k = keyblock; k && k->pkt->pkttype != PKT_USER_ID; k = k->next) { if (k->pkt->pkttype == PKT_SIGNATURE) { PKT_signature *sig = k->pkt->pkt.signature; if (IS_KEY_REV (sig) && (sig->keyid[0] != kid[0] || sig->keyid[1] != kid[1])) { int rc = check_revocation_keys (pk, sig); if (rc == 0) { *r_revoked = 2; sig_to_revoke_info (sig, rinfo); /* Don't continue checking since we can't be any more revoked than this. */ break; } else if (rc == G10ERR_NO_PUBKEY) pk->flags.maybe_revoked = 1; /* A failure here means the sig did not verify, was not issued by a revocation key, or a revocation key loop was broken. If a revocation key isn't findable, however, the key might be revoked and we don't know it. */ /* TODO: In the future handle subkey and cert revocations? PGP doesn't, but it's in 2440. */ } } } /* Second pass: Look at the self-signature of all user IDs. */ signode = uidnode = NULL; sigdate = 0; /* Helper variable to find the latest signature in one UID. */ for (k = keyblock; k && k->pkt->pkttype != PKT_PUBLIC_SUBKEY; k = k->next) { if (k->pkt->pkttype == PKT_USER_ID) { if (uidnode && signode) { fixup_uidnode (uidnode, signode, keytimestamp); pk->flags.valid = 1; } uidnode = k; signode = NULL; sigdate = 0; } else if (k->pkt->pkttype == PKT_SIGNATURE && uidnode) { PKT_signature *sig = k->pkt->pkt.signature; if (sig->keyid[0] == kid[0] && sig->keyid[1] == kid[1]) { if (check_key_signature (keyblock, k, NULL)) ; /* signature did not verify */ else if ((IS_UID_SIG (sig) || IS_UID_REV (sig)) && sig->timestamp >= sigdate) { /* Note: we allow to invalidate cert revocations * by a newer signature. An attacker can't use this * because a key should be revoced with a key revocation. * The reason why we have to allow for that is that at * one time an email address may become invalid but later * the same email address may become valid again (hired, * fired, hired again). */ sigdate = sig->timestamp; signode = k; signode->pkt->pkt.signature->flags.chosen_selfsig = 0; if (sig->version > sigversion) sigversion = sig->version; } } } } if (uidnode && signode) { fixup_uidnode (uidnode, signode, keytimestamp); pk->flags.valid = 1; } /* If the key isn't valid yet, and we have --allow-non-selfsigned-uid set, then force it valid. */ if (!pk->flags.valid && opt.allow_non_selfsigned_uid) { if (opt.verbose) log_info (_("Invalid key %s made valid by" " --allow-non-selfsigned-uid\n"), keystr_from_pk (pk)); pk->flags.valid = 1; } /* The key STILL isn't valid, so try and find an ultimately trusted signature. */ if (!pk->flags.valid) { uidnode = NULL; for (k = keyblock; k && k->pkt->pkttype != PKT_PUBLIC_SUBKEY; k = k->next) { if (k->pkt->pkttype == PKT_USER_ID) uidnode = k; else if (k->pkt->pkttype == PKT_SIGNATURE && uidnode) { PKT_signature *sig = k->pkt->pkt.signature; if (sig->keyid[0] != kid[0] || sig->keyid[1] != kid[1]) { PKT_public_key *ultimate_pk; ultimate_pk = xmalloc_clear (sizeof (*ultimate_pk)); /* We don't want to use the full get_pubkey to avoid infinite recursion in certain cases. There is no reason to check that an ultimately trusted key is still valid - if it has been revoked or the user should also renmove the ultimate trust flag. */ if (get_pubkey_fast (ultimate_pk, sig->keyid) == 0 && check_key_signature2 (keyblock, k, ultimate_pk, NULL, NULL, NULL, NULL) == 0 && get_ownertrust (ultimate_pk) == TRUST_ULTIMATE) { free_public_key (ultimate_pk); pk->flags.valid = 1; break; } free_public_key (ultimate_pk); } } } } /* Record the highest selfsig version so we know if this is a v3 key through and through, or a v3 key with a v4 selfsig somewhere. This is useful in a few places to know if the key must be treated as PGP2-style or OpenPGP-style. Note that a selfsig revocation with a higher version number will also raise this value. This is okay since such a revocation must be issued by the user (i.e. it cannot be issued by someone else to modify the key behavior.) */ pk->selfsigversion = sigversion; /* Now that we had a look at all user IDs we can now get some information * from those user IDs. */ if (!key_usage) { /* Find the latest user ID with key flags set. */ uiddate = 0; /* Helper to find the latest user ID. */ for (k = keyblock; k && k->pkt->pkttype != PKT_PUBLIC_SUBKEY; k = k->next) { if (k->pkt->pkttype == PKT_USER_ID) { PKT_user_id *uid = k->pkt->pkt.user_id; if (uid->help_key_usage && uid->created > uiddate) { key_usage = uid->help_key_usage; uiddate = uid->created; } } } } if (!key_usage) { /* No key flags at all: get it from the algo. */ key_usage = openpgp_pk_algo_usage (pk->pubkey_algo); } else { /* Check that the usage matches the usage as given by the algo. */ int x = openpgp_pk_algo_usage (pk->pubkey_algo); if (x) /* Mask it down to the actual allowed usage. */ key_usage &= x; } /* Whatever happens, it's a primary key, so it can certify. */ pk->pubkey_usage = key_usage | PUBKEY_USAGE_CERT; if (!key_expire_seen) { /* Find the latest valid user ID with a key expiration set * Note, that this may be a different one from the above because * some user IDs may have no expiration date set. */ uiddate = 0; for (k = keyblock; k && k->pkt->pkttype != PKT_PUBLIC_SUBKEY; k = k->next) { if (k->pkt->pkttype == PKT_USER_ID) { PKT_user_id *uid = k->pkt->pkt.user_id; if (uid->help_key_expire && uid->created > uiddate) { key_expire = uid->help_key_expire; uiddate = uid->created; } } } } /* Currently only v3 keys have a maximum expiration date, but I'll bet v5 keys get this feature again. */ if (key_expire == 0 || (pk->max_expiredate && key_expire > pk->max_expiredate)) key_expire = pk->max_expiredate; pk->has_expired = key_expire >= curtime ? 0 : key_expire; pk->expiredate = key_expire; /* Fixme: we should see how to get rid of the expiretime fields but * this needs changes at other places too. */ /* And now find the real primary user ID and delete all others. */ uiddate = uiddate2 = 0; uidnode = uidnode2 = NULL; for (k = keyblock; k && k->pkt->pkttype != PKT_PUBLIC_SUBKEY; k = k->next) { if (k->pkt->pkttype == PKT_USER_ID && !k->pkt->pkt.user_id->attrib_data) { PKT_user_id *uid = k->pkt->pkt.user_id; if (uid->is_primary) { if (uid->created > uiddate) { uiddate = uid->created; uidnode = k; } else if (uid->created == uiddate && uidnode) { /* The dates are equal, so we need to do a different (and arbitrary) comparison. This should rarely, if ever, happen. It's good to try and guarantee that two different GnuPG users with two different keyrings at least pick the same primary. */ if (cmp_user_ids (uid, uidnode->pkt->pkt.user_id) > 0) uidnode = k; } } else { if (uid->created > uiddate2) { uiddate2 = uid->created; uidnode2 = k; } else if (uid->created == uiddate2 && uidnode2) { if (cmp_user_ids (uid, uidnode2->pkt->pkt.user_id) > 0) uidnode2 = k; } } } } if (uidnode) { for (k = keyblock; k && k->pkt->pkttype != PKT_PUBLIC_SUBKEY; k = k->next) { if (k->pkt->pkttype == PKT_USER_ID && !k->pkt->pkt.user_id->attrib_data) { PKT_user_id *uid = k->pkt->pkt.user_id; if (k != uidnode) uid->is_primary = 0; } } } else if (uidnode2) { /* None is flagged primary - use the latest user ID we have, and disambiguate with the arbitrary packet comparison. */ uidnode2->pkt->pkt.user_id->is_primary = 1; } else { /* None of our uids were self-signed, so pick the one that sorts first to be the primary. This is the best we can do here since there are no self sigs to date the uids. */ uidnode = NULL; for (k = keyblock; k && k->pkt->pkttype != PKT_PUBLIC_SUBKEY; k = k->next) { if (k->pkt->pkttype == PKT_USER_ID && !k->pkt->pkt.user_id->attrib_data) { if (!uidnode) { uidnode = k; uidnode->pkt->pkt.user_id->is_primary = 1; continue; } else { if (cmp_user_ids (k->pkt->pkt.user_id, uidnode->pkt->pkt.user_id) > 0) { uidnode->pkt->pkt.user_id->is_primary = 0; uidnode = k; uidnode->pkt->pkt.user_id->is_primary = 1; } else k->pkt->pkt.user_id->is_primary = 0; /* just to be safe */ } } } } } /* Convert a buffer to a signature. Useful for 0x19 embedded sigs. Caller must free the signature when they are done. */ static PKT_signature * buf_to_sig (const byte * buf, size_t len) { PKT_signature *sig = xmalloc_clear (sizeof (PKT_signature)); IOBUF iobuf = iobuf_temp_with_content (buf, len); int save_mode = set_packet_list_mode (0); if (parse_signature (iobuf, PKT_SIGNATURE, len, sig) != 0) { xfree (sig); sig = NULL; } set_packet_list_mode (save_mode); iobuf_close (iobuf); return sig; } static void merge_selfsigs_subkey (KBNODE keyblock, KBNODE subnode) { PKT_public_key *mainpk = NULL, *subpk = NULL; PKT_signature *sig; KBNODE k; u32 mainkid[2]; u32 sigdate = 0; KBNODE signode; u32 curtime = make_timestamp (); unsigned int key_usage = 0; u32 keytimestamp = 0; u32 key_expire = 0; const byte *p; if (subnode->pkt->pkttype != PKT_PUBLIC_SUBKEY) BUG (); mainpk = keyblock->pkt->pkt.public_key; if (mainpk->version < 4) return;/* (actually this should never happen) */ keyid_from_pk (mainpk, mainkid); subpk = subnode->pkt->pkt.public_key; keytimestamp = subpk->timestamp; subpk->flags.valid = 0; subpk->main_keyid[0] = mainpk->main_keyid[0]; subpk->main_keyid[1] = mainpk->main_keyid[1]; /* Find the latest key binding self-signature. */ signode = NULL; sigdate = 0; /* Helper to find the latest signature. */ for (k = subnode->next; k && k->pkt->pkttype != PKT_PUBLIC_SUBKEY; k = k->next) { if (k->pkt->pkttype == PKT_SIGNATURE) { sig = k->pkt->pkt.signature; if (sig->keyid[0] == mainkid[0] && sig->keyid[1] == mainkid[1]) { if (check_key_signature (keyblock, k, NULL)) ; /* Signature did not verify. */ else if (IS_SUBKEY_REV (sig)) { /* Note that this means that the date on a revocation sig does not matter - even if the binding sig is dated after the revocation sig, the subkey is still marked as revoked. This seems ok, as it is just as easy to make new subkeys rather than re-sign old ones as the problem is in the distribution. Plus, PGP (7) does this the same way. */ subpk->flags.revoked = 1; sig_to_revoke_info (sig, &subpk->revoked); /* Although we could stop now, we continue to * figure out other information like the old expiration * time. */ } else if (IS_SUBKEY_SIG (sig) && sig->timestamp >= sigdate) { if (sig->flags.expired) ; /* Signature has expired - ignore it. */ else { sigdate = sig->timestamp; signode = k; signode->pkt->pkt.signature->flags.chosen_selfsig = 0; } } } } } /* No valid key binding. */ if (!signode) return; sig = signode->pkt->pkt.signature; sig->flags.chosen_selfsig = 1; /* So we know which selfsig we chose later. */ key_usage = parse_key_usage (sig); if (!key_usage) { /* No key flags at all: get it from the algo. */ key_usage = openpgp_pk_algo_usage (subpk->pubkey_algo); } else { /* Check that the usage matches the usage as given by the algo. */ int x = openpgp_pk_algo_usage (subpk->pubkey_algo); if (x) /* Mask it down to the actual allowed usage. */ key_usage &= x; } subpk->pubkey_usage = key_usage; p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_KEY_EXPIRE, NULL); if (p && buffer_to_u32 (p)) key_expire = keytimestamp + buffer_to_u32 (p); else key_expire = 0; subpk->has_expired = key_expire >= curtime ? 0 : key_expire; subpk->expiredate = key_expire; /* Algo doesn't exist. */ if (openpgp_pk_test_algo (subpk->pubkey_algo)) return; subpk->flags.valid = 1; /* Find the most recent 0x19 embedded signature on our self-sig. */ if (!subpk->flags.backsig) { int seq = 0; size_t n; PKT_signature *backsig = NULL; sigdate = 0; /* We do this while() since there may be other embedded signatures in the future. We only want 0x19 here. */ while ((p = enum_sig_subpkt (sig->hashed, SIGSUBPKT_SIGNATURE, &n, &seq, NULL))) if (n > 3 && ((p[0] == 3 && p[2] == 0x19) || (p[0] == 4 && p[1] == 0x19))) { PKT_signature *tempsig = buf_to_sig (p, n); if (tempsig) { if (tempsig->timestamp > sigdate) { if (backsig) free_seckey_enc (backsig); backsig = tempsig; sigdate = backsig->timestamp; } else free_seckey_enc (tempsig); } } seq = 0; /* It is safe to have this in the unhashed area since the 0x19 is located on the selfsig for convenience, not security. */ while ((p = enum_sig_subpkt (sig->unhashed, SIGSUBPKT_SIGNATURE, &n, &seq, NULL))) if (n > 3 && ((p[0] == 3 && p[2] == 0x19) || (p[0] == 4 && p[1] == 0x19))) { PKT_signature *tempsig = buf_to_sig (p, n); if (tempsig) { if (tempsig->timestamp > sigdate) { if (backsig) free_seckey_enc (backsig); backsig = tempsig; sigdate = backsig->timestamp; } else free_seckey_enc (tempsig); } } if (backsig) { /* At ths point, backsig contains the most recent 0x19 sig. Let's see if it is good. */ /* 2==valid, 1==invalid, 0==didn't check */ if (check_backsig (mainpk, subpk, backsig) == 0) subpk->flags.backsig = 2; else subpk->flags.backsig = 1; free_seckey_enc (backsig); } } } /* * Merge information from the self-signatures with the key, so that * we can later use them more easy. * The function works by first applying the self signatures to the * primary key and the to each subkey. * Here are the rules we use to decide which inormation from which * self-signature is used: * We check all self signatures or validity and ignore all invalid signatures. * All signatures are then ordered by their creation date .... * For the primary key: * FIXME the docs */ static void merge_selfsigs (KBNODE keyblock) { KBNODE k; int revoked; struct revoke_info rinfo; PKT_public_key *main_pk; prefitem_t *prefs; unsigned int mdc_feature; if (keyblock->pkt->pkttype != PKT_PUBLIC_KEY) { if (keyblock->pkt->pkttype == PKT_SECRET_KEY) { log_error ("expected public key but found secret key " "- must stop\n"); /* We better exit here because a public key is expected at other places too. FIXME: Figure this out earlier and don't get to here at all */ g10_exit (1); } BUG (); } merge_selfsigs_main (keyblock, &revoked, &rinfo); /* Now merge in the data from each of the subkeys. */ for (k = keyblock; k; k = k->next) { if (k->pkt->pkttype == PKT_PUBLIC_SUBKEY) { merge_selfsigs_subkey (keyblock, k); } } main_pk = keyblock->pkt->pkt.public_key; if (revoked || main_pk->has_expired || !main_pk->flags.valid) { /* If the primary key is revoked, expired, or invalid we * better set the appropriate flags on that key and all * subkeys. */ for (k = keyblock; k; k = k->next) { if (k->pkt->pkttype == PKT_PUBLIC_KEY || k->pkt->pkttype == PKT_PUBLIC_SUBKEY) { PKT_public_key *pk = k->pkt->pkt.public_key; if (!main_pk->flags.valid) pk->flags.valid = 0; if (revoked && !pk->flags.revoked) { pk->flags.revoked = revoked; memcpy (&pk->revoked, &rinfo, sizeof (rinfo)); } if (main_pk->has_expired) pk->has_expired = main_pk->has_expired; } } return; } /* Set the preference list of all keys to those of the primary real * user ID. Note: we use these preferences when we don't know by * which user ID the key has been selected. * fixme: we should keep atoms of commonly used preferences or * use reference counting to optimize the preference lists storage. * FIXME: it might be better to use the intersection of * all preferences. * Do a similar thing for the MDC feature flag. */ prefs = NULL; mdc_feature = 0; for (k = keyblock; k && k->pkt->pkttype != PKT_PUBLIC_SUBKEY; k = k->next) { if (k->pkt->pkttype == PKT_USER_ID && !k->pkt->pkt.user_id->attrib_data && k->pkt->pkt.user_id->is_primary) { prefs = k->pkt->pkt.user_id->prefs; mdc_feature = k->pkt->pkt.user_id->flags.mdc; break; } } for (k = keyblock; k; k = k->next) { if (k->pkt->pkttype == PKT_PUBLIC_KEY || k->pkt->pkttype == PKT_PUBLIC_SUBKEY) { PKT_public_key *pk = k->pkt->pkt.public_key; if (pk->prefs) xfree (pk->prefs); pk->prefs = copy_prefs (prefs); pk->flags.mdc = mdc_feature; } } } /* See whether the key fits our requirements and in case we do not * request the primary key, select a suitable subkey. * * Returns: True when a suitable key has been found. * * We have to distinguish four cases: FIXME! * 1. No usage and no primary key requested * Examples for this case are that we have a keyID to be used * for decrytion or verification. * 2. No usage but primary key requested * This is the case for all functions which work on an * entire keyblock, e.g. for editing or listing * 3. Usage and primary key requested * FXME * 4. Usage but no primary key requested * FIXME * FIXME: Tell what is going to happen here and something about the rationale * Note: We don't use this function if no specific usage is requested; * This way the getkey functions can be used for plain key listings. * * CTX ist the keyblock we are investigating, if FOUNDK is not NULL this * is the key we actually found by looking at the keyid or a fingerprint and * may either point to the primary or one of the subkeys. */ static int finish_lookup (GETKEY_CTX ctx) { KBNODE keyblock = ctx->keyblock; KBNODE k; KBNODE foundk = NULL; PKT_user_id *foundu = NULL; #define USAGE_MASK (PUBKEY_USAGE_SIG|PUBKEY_USAGE_ENC|PUBKEY_USAGE_CERT) unsigned int req_usage = (ctx->req_usage & USAGE_MASK); /* Request the primary if we're certifying another key, and also if signing data while --pgp6 or --pgp7 is on since pgp 6 and 7 do not understand signatures made by a signing subkey. PGP 8 does. */ int req_prim = (ctx->req_usage & PUBKEY_USAGE_CERT) || ((PGP6 || PGP7) && (ctx->req_usage & PUBKEY_USAGE_SIG)); u32 latest_date; KBNODE latest_key; u32 curtime = make_timestamp (); assert (keyblock->pkt->pkttype == PKT_PUBLIC_KEY); ctx->found_key = NULL; if (ctx->exact) { for (k = keyblock; k; k = k->next) { if ((k->flag & 1)) { assert (k->pkt->pkttype == PKT_PUBLIC_KEY || k->pkt->pkttype == PKT_PUBLIC_SUBKEY); foundk = k; break; } } } for (k = keyblock; k; k = k->next) { if ((k->flag & 2)) { assert (k->pkt->pkttype == PKT_USER_ID); foundu = k->pkt->pkt.user_id; break; } } if (DBG_CACHE) log_debug ("finish_lookup: checking key %08lX (%s)(req_usage=%x)\n", (ulong) keyid_from_pk (keyblock->pkt->pkt.public_key, NULL), foundk ? "one" : "all", req_usage); if (!req_usage) { latest_key = foundk ? foundk : keyblock; goto found; } latest_date = 0; latest_key = NULL; /* Do not look at subkeys if a certification key is requested. */ if ((!foundk || foundk->pkt->pkttype == PKT_PUBLIC_SUBKEY) && !req_prim) { KBNODE nextk; /* Either start a loop or check just this one subkey. */ for (k = foundk ? foundk : keyblock; k; k = nextk) { PKT_public_key *pk; nextk = k->next; if (k->pkt->pkttype != PKT_PUBLIC_SUBKEY) continue; if (foundk) nextk = NULL; /* what a hack */ pk = k->pkt->pkt.public_key; if (DBG_CACHE) log_debug ("\tchecking subkey %08lX\n", (ulong) keyid_from_pk (pk, NULL)); if (!pk->flags.valid) { if (DBG_CACHE) log_debug ("\tsubkey not valid\n"); continue; } if (pk->flags.revoked) { if (DBG_CACHE) log_debug ("\tsubkey has been revoked\n"); continue; } if (pk->has_expired) { if (DBG_CACHE) log_debug ("\tsubkey has expired\n"); continue; } if (pk->timestamp > curtime && !opt.ignore_valid_from) { if (DBG_CACHE) log_debug ("\tsubkey not yet valid\n"); continue; } if (!((pk->pubkey_usage & USAGE_MASK) & req_usage)) { if (DBG_CACHE) log_debug ("\tusage does not match: want=%x have=%x\n", req_usage, pk->pubkey_usage); continue; } if (DBG_CACHE) 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 = k; } } } /* Okay now try the primary key unless we want an exact * key ID match on a subkey */ if ((!latest_key && !(ctx->exact && foundk != keyblock)) || req_prim) { PKT_public_key *pk; if (DBG_CACHE && !foundk && !req_prim) log_debug ("\tno suitable subkeys found - trying primary\n"); pk = keyblock->pkt->pkt.public_key; if (!pk->flags.valid) { if (DBG_CACHE) log_debug ("\tprimary key not valid\n"); } else if (pk->flags.revoked) { if (DBG_CACHE) log_debug ("\tprimary key has been revoked\n"); } else if (pk->has_expired) { if (DBG_CACHE) log_debug ("\tprimary key has expired\n"); } else if (!((pk->pubkey_usage & USAGE_MASK) & req_usage)) { if (DBG_CACHE) log_debug ("\tprimary key usage does not match: " "want=%x have=%x\n", req_usage, pk->pubkey_usage); } else /* Okay. */ { if (DBG_CACHE) log_debug ("\tprimary key may be used\n"); latest_key = keyblock; latest_date = pk->timestamp; } } if (!latest_key) { if (DBG_CACHE) log_debug ("\tno suitable key found - giving up\n"); return 0; /* Not found. */ } found: if (DBG_CACHE) log_debug ("\tusing key %08lX\n", (ulong) keyid_from_pk (latest_key->pkt->pkt.public_key, NULL)); if (latest_key) { PKT_public_key *pk = latest_key->pkt->pkt.public_key; if (pk->user_id) free_user_id (pk->user_id); pk->user_id = scopy_user_id (foundu); } ctx->found_key = latest_key; if (latest_key != keyblock && opt.verbose) { char *tempkeystr = xstrdup (keystr_from_pk (latest_key->pkt->pkt.public_key)); log_info (_("using subkey %s instead of primary key %s\n"), tempkeystr, keystr_from_pk (keyblock->pkt->pkt.public_key)); xfree (tempkeystr); } cache_user_id (keyblock); return 1; /* Found. */ } /* The main function to lookup a key. On success the found keyblock is stored at RET_KEYBLOCK and also in CTX. If WANT_SECRET is true a corresponding secret key is required. */ static int lookup (getkey_ctx_t ctx, kbnode_t *ret_keyblock, int want_secret) { int rc; int no_suitable_key = 0; rc = 0; while (!(rc = keydb_search (ctx->kr_handle, ctx->items, ctx->nitems, NULL))) { /* If we are searching for the first key we have to make sure that the next iteration does not do an implicit reset. This can be triggered by an empty key ring. */ if (ctx->nitems && ctx->items->mode == KEYDB_SEARCH_MODE_FIRST) ctx->items->mode = KEYDB_SEARCH_MODE_NEXT; rc = keydb_get_keyblock (ctx->kr_handle, &ctx->keyblock); if (rc) { log_error ("keydb_get_keyblock failed: %s\n", g10_errstr (rc)); rc = 0; goto skip; } if (want_secret && agent_probe_any_secret_key (NULL, ctx->keyblock)) goto skip; /* No secret key available. */ /* Warning: node flag bits 0 and 1 should be preserved by * merge_selfsigs. For secret keys, premerge did tranfer the * keys to the keyblock. */ merge_selfsigs (ctx->keyblock); if (finish_lookup (ctx)) { no_suitable_key = 0; goto found; } else no_suitable_key = 1; skip: /* Release resources and continue search. */ release_kbnode (ctx->keyblock); ctx->keyblock = NULL; } found: if (rc && gpg_err_code (rc) != GPG_ERR_NOT_FOUND) log_error ("keydb_search failed: %s\n", g10_errstr (rc)); if (!rc) { *ret_keyblock = ctx->keyblock; /* Return the keyblock. */ ctx->keyblock = NULL; } else if (gpg_err_code (rc) == GPG_ERR_NOT_FOUND && no_suitable_key) rc = want_secret? G10ERR_UNU_SECKEY : G10ERR_UNU_PUBKEY; else if (gpg_err_code (rc) == GPG_ERR_NOT_FOUND) rc = want_secret? G10ERR_NO_SECKEY : G10ERR_NO_PUBKEY; release_kbnode (ctx->keyblock); ctx->keyblock = NULL; ctx->last_rc = rc; return rc; } /* * Enumerate certain secret keys. Caller must use these procedure: * 1) create a void pointer and initialize it to NULL * 2) pass this void pointer by reference to this function * and provide space for the secret key (pass a buffer for sk) * 3) call this function as long as it does not return an error. * The error code GPG_ERR_EOF indicates the end of the listing. * 4) Always call this function a last time with SK set to NULL, * so that can free it's context. */ gpg_error_t enum_secret_keys (void **context, PKT_public_key *sk) { gpg_error_t err = 0; const char *name; struct { int eof; int state; strlist_t sl; kbnode_t keyblock; kbnode_t node; } *c = *context; if (!c) { /* Make a new context. */ c = xtrycalloc (1, sizeof *c); if (!c) return gpg_error_from_syserror (); *context = c; } if (!sk) { /* Free the context. */ release_kbnode (c->keyblock); xfree (c); *context = NULL; return 0; } if (c->eof) return gpg_error (GPG_ERR_EOF); for (;;) { /* Loop until we have a keyblock. */ while (!c->keyblock) { /* Loop over the list of secret keys. */ do { name = NULL; switch (c->state) { case 0: /* First try to use the --default-key. */ if (opt.def_secret_key && *opt.def_secret_key) name = opt.def_secret_key; c->state = 1; break; case 1: /* Init list of keys to try. */ c->sl = opt.secret_keys_to_try; c->state++; break; case 2: /* Get next item from list. */ if (c->sl) { name = c->sl->d; c->sl = c->sl->next; } else c->state++; break; default: /* No more names to check - stop. */ c->eof = 1; return gpg_error (GPG_ERR_EOF); } } while (!name || !*name); err = getkey_byname (NULL, NULL, name, 1, &c->keyblock); if (err) { /* getkey_byname might return a keyblock even in the error case - I have not checked. Thus better release it. */ release_kbnode (c->keyblock); c->keyblock = NULL; } else c->node = c->keyblock; } /* Get the next key from the current keyblock. */ for (; c->node; c->node = c->node->next) { if (c->node->pkt->pkttype == PKT_PUBLIC_KEY || c->node->pkt->pkttype == PKT_PUBLIC_SUBKEY) { copy_public_key (sk, c->node->pkt->pkt.public_key); c->node = c->node->next; return 0; /* Found. */ } } /* Dispose the keyblock and continue. */ release_kbnode (c->keyblock); c->keyblock = NULL; } } /********************************************* *********** User ID printing helpers ******* *********************************************/ /* Return a string with a printable representation of the user_id. * this string must be freed by xfree. */ char * get_user_id_string (u32 * keyid) { user_id_db_t r; char *p; int pass = 0; /* Try it two times; second pass reads from key resources. */ do { for (r = user_id_db; r; r = r->next) { keyid_list_t a; for (a = r->keyids; a; a = a->next) { if (a->keyid[0] == keyid[0] && a->keyid[1] == keyid[1]) { p = xmalloc (keystrlen () + 1 + r->len + 1); sprintf (p, "%s %.*s", keystr (keyid), r->len, r->name); return p; } } } } while (++pass < 2 && !get_pubkey (NULL, keyid)); p = xmalloc (keystrlen () + 5); sprintf (p, "%s [?]", keystr (keyid)); return p; } char * get_user_id_string_native (u32 * keyid) { char *p = get_user_id_string (keyid); char *p2 = utf8_to_native (p, strlen (p), 0); xfree (p); return p2; } char * get_long_user_id_string (u32 * keyid) { user_id_db_t r; char *p; int pass = 0; /* Try it two times; second pass reads from key resources. */ do { for (r = user_id_db; r; r = r->next) { keyid_list_t a; for (a = r->keyids; a; a = a->next) { if (a->keyid[0] == keyid[0] && a->keyid[1] == keyid[1]) { p = xmalloc (r->len + 20); sprintf (p, "%08lX%08lX %.*s", (ulong) keyid[0], (ulong) keyid[1], r->len, r->name); return p; } } } } while (++pass < 2 && !get_pubkey (NULL, keyid)); p = xmalloc (25); sprintf (p, "%08lX%08lX [?]", (ulong) keyid[0], (ulong) keyid[1]); return p; } char * get_user_id (u32 * keyid, size_t * rn) { user_id_db_t r; char *p; int pass = 0; /* Try it two times; second pass reads from key resources. */ do { for (r = user_id_db; r; r = r->next) { keyid_list_t a; for (a = r->keyids; a; a = a->next) { if (a->keyid[0] == keyid[0] && a->keyid[1] == keyid[1]) { p = xmalloc (r->len); memcpy (p, r->name, r->len); *rn = r->len; return p; } } } } while (++pass < 2 && !get_pubkey (NULL, keyid)); p = xstrdup (user_id_not_found_utf8 ()); *rn = strlen (p); return p; } char * get_user_id_native (u32 * keyid) { size_t rn; char *p = get_user_id (keyid, &rn); char *p2 = utf8_to_native (p, rn, 0); xfree (p); return p2; } KEYDB_HANDLE get_ctx_handle (GETKEY_CTX ctx) { return ctx->kr_handle; } static void free_akl (struct akl *akl) { if (akl->spec) free_keyserver_spec (akl->spec); xfree (akl); } void release_akl (void) { while (opt.auto_key_locate) { struct akl *akl2 = opt.auto_key_locate; opt.auto_key_locate = opt.auto_key_locate->next; free_akl (akl2); } } /* Returns false on error. */ int parse_auto_key_locate (char *options) { char *tok; while ((tok = optsep (&options))) { struct akl *akl, *check, *last = NULL; int dupe = 0; if (tok[0] == '\0') continue; akl = xmalloc_clear (sizeof (*akl)); if (ascii_strcasecmp (tok, "nodefault") == 0) akl->type = AKL_NODEFAULT; else if (ascii_strcasecmp (tok, "local") == 0) akl->type = AKL_LOCAL; else if (ascii_strcasecmp (tok, "ldap") == 0) akl->type = AKL_LDAP; else if (ascii_strcasecmp (tok, "keyserver") == 0) akl->type = AKL_KEYSERVER; #ifdef USE_DNS_CERT else if (ascii_strcasecmp (tok, "cert") == 0) akl->type = AKL_CERT; #endif #ifdef USE_DNS_PKA else if (ascii_strcasecmp (tok, "pka") == 0) akl->type = AKL_PKA; #endif else if ((akl->spec = parse_keyserver_uri (tok, 1, NULL, 0))) akl->type = AKL_SPEC; else { free_akl (akl); return 0; } /* We must maintain the order the user gave us */ for (check = opt.auto_key_locate; check; last = check, check = check->next) { /* Check for duplicates */ if (check->type == akl->type && (akl->type != AKL_SPEC || (akl->type == AKL_SPEC && strcmp (check->spec->uri, akl->spec->uri) == 0))) { dupe = 1; free_akl (akl); break; } } if (!dupe) { if (last) last->next = akl; else opt.auto_key_locate = akl; } } return 1; } /* Return true if a secret key or secret subkey is available for one of the public keys in KEYBLOCK. */ int have_any_secret_key (ctrl_t ctrl, kbnode_t keyblock) { kbnode_t node; for (node = keyblock; node; node = node->next) if ((node->pkt->pkttype == PKT_PUBLIC_KEY || node->pkt->pkttype == PKT_PUBLIC_SUBKEY) && !agent_probe_secret_key (ctrl, node->pkt->pkt.public_key)) return 1; return 0; } /* Return true if a secret key is available for the public key with * the given KEYID. This is just a fast check and does not tell us * whether the secret key is valid. It merely tells os whether there * is some secret key. */ int have_secret_key_with_kid (u32 *keyid) { gpg_error_t err; KEYDB_HANDLE kdbhd; KEYDB_SEARCH_DESC desc; kbnode_t keyblock; kbnode_t node; int result = 0; kdbhd = keydb_new (); memset (&desc, 0, sizeof desc); desc.mode = KEYDB_SEARCH_MODE_LONG_KID; desc.u.kid[0] = keyid[0]; desc.u.kid[1] = keyid[1]; while (!result && !(err = keydb_search (kdbhd, &desc, 1, NULL))) { desc.mode = KEYDB_SEARCH_MODE_NEXT; err = keydb_get_keyblock (kdbhd, &keyblock); if (err) { log_error (_("error reading keyblock: %s\n"), g10_errstr (err)); break; } for (node = keyblock; node; node = node->next) { /* Bit 0 of the flags is set if the search found the key using that key or subkey. */ if ((node->flag & 1)) { assert (node->pkt->pkttype == PKT_PUBLIC_KEY || node->pkt->pkttype == PKT_PUBLIC_SUBKEY); if (!agent_probe_secret_key (NULL, node->pkt->pkt.public_key)) { result = 1; break; } } } release_kbnode (keyblock); } keydb_release (kdbhd); return result; } #if 0 /* * Merge the secret keys from secblock into the pubblock thereby * replacing the public (sub)keys with their secret counterparts Hmmm: * It might be better to get away from the concept of entire secret * keys at all and have a way to store just the real secret parts * from the key. * * FIXME: this is not anymore needed but we keep it as example code for the * new code we need to write for the import/export feature. */ static void merge_public_with_secret (KBNODE pubblock, KBNODE secblock) { KBNODE pub; assert (pubblock->pkt->pkttype == PKT_PUBLIC_KEY); assert (secblock->pkt->pkttype == PKT_SECRET_KEY); for (pub = pubblock; pub; pub = pub->next) { if (pub->pkt->pkttype == PKT_PUBLIC_KEY) { PKT_public_key *pk = pub->pkt->pkt.public_key; PKT_secret_key *sk = secblock->pkt->pkt.secret_key; assert (pub == pubblock); /* Only in the first node. */ /* There is nothing to compare in this case, so just replace * some information. */ copy_public_parts_to_secret_key (pk, sk); free_public_key (pk); pub->pkt->pkttype = PKT_SECRET_KEY; pub->pkt->pkt.secret_key = copy_secret_key (NULL, sk); } else if (pub->pkt->pkttype == PKT_PUBLIC_SUBKEY) { KBNODE sec; PKT_public_key *pk = pub->pkt->pkt.public_key; /* This is more complicated: It may happen that the sequence * of the subkeys dosn't match, so we have to find the * appropriate secret key. */ for (sec = secblock->next; sec; sec = sec->next) { if (sec->pkt->pkttype == PKT_SECRET_SUBKEY) { PKT_secret_key *sk = sec->pkt->pkt.secret_key; if (!cmp_public_secret_key (pk, sk)) { copy_public_parts_to_secret_key (pk, sk); free_public_key (pk); pub->pkt->pkttype = PKT_SECRET_SUBKEY; pub->pkt->pkt.secret_key = copy_secret_key (NULL, sk); break; } } } if (!sec) BUG (); /* Already checked in premerge. */ } } } /* This function checks that for every public subkey a corresponding * secret subkey is available and deletes the public subkey otherwise. * We need this function because we can't delete it later when we * actually merge the secret parts into the pubring. * The function also plays some games with the node flags. * * FIXME: this is not anymore needed but we keep it as example code for the * new code we need to write for the import/export feature. */ static void premerge_public_with_secret (KBNODE pubblock, KBNODE secblock) { KBNODE last, pub; assert (pubblock->pkt->pkttype == PKT_PUBLIC_KEY); assert (secblock->pkt->pkttype == PKT_SECRET_KEY); for (pub = pubblock, last = NULL; pub; last = pub, pub = pub->next) { pub->flag &= ~3; /* Reset bits 0 and 1. */ if (pub->pkt->pkttype == PKT_PUBLIC_SUBKEY) { KBNODE sec; PKT_public_key *pk = pub->pkt->pkt.public_key; for (sec = secblock->next; sec; sec = sec->next) { if (sec->pkt->pkttype == PKT_SECRET_SUBKEY) { PKT_secret_key *sk = sec->pkt->pkt.secret_key; if (!cmp_public_secret_key (pk, sk)) { if (sk->protect.s2k.mode == 1001) { /* The secret parts are not available so we can't use that key for signing etc. Fix the pubkey usage */ pk->pubkey_usage &= ~(PUBKEY_USAGE_SIG | PUBKEY_USAGE_AUTH); } /* Transfer flag bits 0 and 1 to the pubblock. */ pub->flag |= (sec->flag & 3); break; } } } if (!sec) { KBNODE next, ll; if (opt.verbose) log_info (_("no secret subkey" " for public subkey %s - ignoring\n"), keystr_from_pk (pk)); /* We have to remove the subkey in this case. */ assert (last); /* Find the next subkey. */ for (next = pub->next, ll = pub; next && next->pkt->pkttype != PKT_PUBLIC_SUBKEY; ll = next, next = next->next) ; /* Make new link. */ last->next = next; /* Release this public subkey with all sigs. */ ll->next = NULL; release_kbnode (pub); /* Let the loop continue. */ pub = last; } } } /* We need to copy the found bits (0 and 1) from the secret key to the public key. This has already been done for the subkeys but got lost on the primary key - fix it here. */ pubblock->flag |= (secblock->flag & 3); } #endif /*0*/ diff --git a/g10/import.c b/g10/import.c index 3846c213f..7ba7303b7 100644 --- a/g10/import.c +++ b/g10/import.c @@ -1,2682 +1,2683 @@ /* import.c - import a key into our key storage. * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, * 2007, 2010, 2011 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 #include "gpg.h" #include "options.h" #include "packet.h" #include "status.h" #include "keydb.h" #include "util.h" #include "trustdb.h" #include "main.h" #include "i18n.h" #include "ttyio.h" #include "status.h" #include "keyserver-internal.h" #include "call-agent.h" #include "../common/membuf.h" struct stats_s { ulong count; ulong no_user_id; ulong imported; ulong imported_rsa; ulong n_uids; ulong n_sigs; ulong n_subk; ulong unchanged; ulong n_revoc; ulong secret_read; ulong secret_imported; ulong secret_dups; ulong skipped_new_keys; ulong not_imported; ulong n_sigs_cleaned; ulong n_uids_cleaned; }; static int import (ctrl_t ctrl, IOBUF inp, const char* fname, struct stats_s *stats, unsigned char **fpr, size_t *fpr_len, unsigned int options); static int read_block( IOBUF a, PACKET **pending_pkt, KBNODE *ret_root ); static void revocation_present (ctrl_t ctrl, kbnode_t keyblock); static int import_one (ctrl_t ctrl, const char *fname, KBNODE keyblock,struct stats_s *stats, unsigned char **fpr,size_t *fpr_len, unsigned int options,int from_sk); static int import_secret_one (ctrl_t ctrl, const char *fname, KBNODE keyblock, struct stats_s *stats, unsigned int options); static int import_revoke_cert( const char *fname, KBNODE node, struct stats_s *stats); static int chk_self_sigs( const char *fname, KBNODE keyblock, PKT_public_key *pk, u32 *keyid, int *non_self ); static int delete_inv_parts( const char *fname, KBNODE keyblock, u32 *keyid, unsigned int options ); static int merge_blocks( const char *fname, KBNODE keyblock_orig, KBNODE keyblock, u32 *keyid, int *n_uids, int *n_sigs, int *n_subk ); static int append_uid( KBNODE keyblock, KBNODE node, int *n_sigs, const char *fname, u32 *keyid ); static int append_key( KBNODE keyblock, KBNODE node, int *n_sigs, const char *fname, u32 *keyid ); static int merge_sigs( KBNODE dst, KBNODE src, int *n_sigs, const char *fname, u32 *keyid ); static int merge_keysigs( KBNODE dst, KBNODE src, int *n_sigs, const char *fname, u32 *keyid ); int parse_import_options(char *str,unsigned int *options,int noisy) { struct parse_options import_opts[]= { {"import-local-sigs",IMPORT_LOCAL_SIGS,NULL, N_("import signatures that are marked as local-only")}, {"repair-pks-subkey-bug",IMPORT_REPAIR_PKS_SUBKEY_BUG,NULL, N_("repair damage from the pks keyserver during import")}, {"fast-import",IMPORT_FAST,NULL, N_("do not update the trustdb after import")}, {"merge-only",IMPORT_MERGE_ONLY,NULL, N_("only accept updates to existing keys")}, {"import-clean",IMPORT_CLEAN,NULL, N_("remove unusable parts from key after import")}, {"import-minimal",IMPORT_MINIMAL|IMPORT_CLEAN,NULL, N_("remove as much as possible from key after import")}, /* Aliases for backward compatibility */ {"allow-local-sigs",IMPORT_LOCAL_SIGS,NULL,NULL}, {"repair-hkp-subkey-bug",IMPORT_REPAIR_PKS_SUBKEY_BUG,NULL,NULL}, /* dummy */ {"import-unusable-sigs",0,NULL,NULL}, {"import-clean-sigs",0,NULL,NULL}, {"import-clean-uids",0,NULL,NULL}, {"convert-sk-to-pk",0, NULL,NULL}, /* Not anymore needed due to the new design. */ {NULL,0,NULL,NULL} }; return parse_options(str,options,import_opts,noisy); } void * import_new_stats_handle (void) { return xmalloc_clear ( sizeof (struct stats_s) ); } void import_release_stats_handle (void *p) { xfree (p); } /**************** * Import the public keys from the given filename. Input may be armored. * This function rejects all keys which are not validly self signed on at * least one userid. Only user ids which are self signed will be imported. * Other signatures are not checked. * * Actually this function does a merge. It works like this: * * - get the keyblock * - check self-signatures and remove all userids and their signatures * without/invalid self-signatures. * - reject the keyblock, if we have no valid userid. * - See whether we have this key already in one of our pubrings. * If not, simply add it to the default keyring. * - Compare the key and the self-signatures of the new and the one in * our keyring. If they are different something weird is going on; * ask what to do. * - See whether we have only non-self-signature on one user id; if not * ask the user what to do. * - compare the signatures: If we already have this signature, check * that they compare okay; if not, issue a warning and ask the user. * (consider looking at the timestamp and use the newest?) * - Simply add the signature. Can't verify here because we may not have * the signature's public key yet; verification is done when putting it * into the trustdb, which is done automagically as soon as this pubkey * is used. * - Proceed with next signature. * * Key revocation certificates have special handling. * */ static int import_keys_internal (ctrl_t ctrl, iobuf_t inp, char **fnames, int nnames, void *stats_handle, unsigned char **fpr, size_t *fpr_len, unsigned int options ) { int i, rc = 0; struct stats_s *stats = stats_handle; if (!stats) stats = import_new_stats_handle (); if (inp) { rc = import (ctrl, inp, "[stream]", stats, fpr, fpr_len, options); } else { if( !fnames && !nnames ) nnames = 1; /* Ohh what a ugly hack to jump into the loop */ for(i=0; i < nnames; i++ ) { const char *fname = fnames? fnames[i] : NULL; IOBUF inp2 = iobuf_open(fname); if( !fname ) fname = "[stdin]"; if (inp2 && is_secured_file (iobuf_get_fd (inp2))) { iobuf_close (inp2); inp2 = NULL; gpg_err_set_errno (EPERM); } if( !inp2 ) log_error(_("can't open '%s': %s\n"), fname, strerror(errno) ); else { rc = import (ctrl, inp2, fname, stats, fpr, fpr_len, options); iobuf_close(inp2); /* Must invalidate that ugly cache to actually close it. */ iobuf_ioctl (NULL, IOBUF_IOCTL_INVALIDATE_CACHE, 0, (char*)fname); if( rc ) log_error("import from '%s' failed: %s\n", fname, g10_errstr(rc) ); } if( !fname ) break; } } if (!stats_handle) { import_print_stats (stats); import_release_stats_handle (stats); } /* If no fast import and the trustdb is dirty (i.e. we added a key or userID that had something other than a selfsig, a signature that was other than a selfsig, or any revocation), then update/check the trustdb if the user specified by setting interactive or by not setting no-auto-check-trustdb */ if(!(options&IMPORT_FAST)) trustdb_check_or_update(); return rc; } void import_keys (ctrl_t ctrl, char **fnames, int nnames, void *stats_handle, unsigned int options ) { import_keys_internal (ctrl, NULL, fnames, nnames, stats_handle, NULL, NULL, options); } int import_keys_stream (ctrl_t ctrl, IOBUF inp, void *stats_handle, unsigned char **fpr, size_t *fpr_len,unsigned int options) { return import_keys_internal (ctrl, inp, NULL, 0, stats_handle, fpr, fpr_len, options); } /* Variant of import_keys_stream reading from an estream_t. */ int import_keys_es_stream (ctrl_t ctrl, estream_t fp, void *stats_handle, unsigned char **fpr, size_t *fpr_len, unsigned int options) { int rc; iobuf_t inp; inp = iobuf_esopen (fp, "r", 1); if (!inp) { rc = gpg_error_from_syserror (); log_error ("iobuf_esopen failed: %s\n", gpg_strerror (rc)); return rc; } rc = import_keys_internal (ctrl, inp, NULL, 0, stats_handle, fpr, fpr_len, options); iobuf_close (inp); return rc; } static int import (ctrl_t ctrl, IOBUF inp, const char* fname,struct stats_s *stats, unsigned char **fpr,size_t *fpr_len,unsigned int options ) { PACKET *pending_pkt = NULL; KBNODE keyblock = NULL; /* Need to initialize because gcc can't grasp the return semantics of read_block. */ int rc = 0; getkey_disable_caches(); if( !opt.no_armor ) { /* armored reading is not disabled */ armor_filter_context_t *afx; afx = new_armor_context (); afx->only_keyblocks = 1; push_armor_filter (afx, inp); release_armor_context (afx); } while( !(rc = read_block( inp, &pending_pkt, &keyblock) )) { if( keyblock->pkt->pkttype == PKT_PUBLIC_KEY ) rc = import_one (ctrl, fname, keyblock, stats, fpr, fpr_len, options, 0); else if( keyblock->pkt->pkttype == PKT_SECRET_KEY ) rc = import_secret_one (ctrl, fname, keyblock, stats, options); else if( keyblock->pkt->pkttype == PKT_SIGNATURE && keyblock->pkt->pkt.signature->sig_class == 0x20 ) rc = import_revoke_cert( fname, keyblock, stats ); else { log_info( _("skipping block of type %d\n"), keyblock->pkt->pkttype ); } release_kbnode(keyblock); /* fixme: we should increment the not imported counter but this does only make sense if we keep on going despite of errors. */ if( rc ) break; if( !(++stats->count % 100) && !opt.quiet ) log_info(_("%lu keys processed so far\n"), stats->count ); } if( rc == -1 ) rc = 0; else if( rc && rc != G10ERR_INV_KEYRING ) log_error( _("error reading '%s': %s\n"), fname, g10_errstr(rc)); return rc; } void import_print_stats (void *hd) { struct stats_s *stats = hd; if( !opt.quiet ) { log_info(_("Total number processed: %lu\n"), stats->count ); if( stats->skipped_new_keys ) log_info(_(" skipped new keys: %lu\n"), stats->skipped_new_keys ); if( stats->no_user_id ) log_info(_(" w/o user IDs: %lu\n"), stats->no_user_id ); if( stats->imported || stats->imported_rsa ) { log_info(_(" imported: %lu"), stats->imported ); if (stats->imported_rsa) log_printf (" (RSA: %lu)", stats->imported_rsa ); log_printf ("\n"); } if( stats->unchanged ) log_info(_(" unchanged: %lu\n"), stats->unchanged ); if( stats->n_uids ) log_info(_(" new user IDs: %lu\n"), stats->n_uids ); if( stats->n_subk ) log_info(_(" new subkeys: %lu\n"), stats->n_subk ); if( stats->n_sigs ) log_info(_(" new signatures: %lu\n"), stats->n_sigs ); if( stats->n_revoc ) log_info(_(" new key revocations: %lu\n"), stats->n_revoc ); if( stats->secret_read ) log_info(_(" secret keys read: %lu\n"), stats->secret_read ); if( stats->secret_imported ) log_info(_(" secret keys imported: %lu\n"), stats->secret_imported ); if( stats->secret_dups ) log_info(_(" secret keys unchanged: %lu\n"), stats->secret_dups ); if( stats->not_imported ) log_info(_(" not imported: %lu\n"), stats->not_imported ); if( stats->n_sigs_cleaned) log_info(_(" signatures cleaned: %lu\n"),stats->n_sigs_cleaned); if( stats->n_uids_cleaned) log_info(_(" user IDs cleaned: %lu\n"),stats->n_uids_cleaned); } if( is_status_enabled() ) { char buf[14*20]; sprintf(buf, "%lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu", stats->count, stats->no_user_id, stats->imported, stats->imported_rsa, stats->unchanged, stats->n_uids, stats->n_subk, stats->n_sigs, stats->n_revoc, stats->secret_read, stats->secret_imported, stats->secret_dups, stats->skipped_new_keys, stats->not_imported ); write_status_text( STATUS_IMPORT_RES, buf ); } } /* Return true if PKTTYPE is valid in a keyblock. */ static int valid_keyblock_packet (int pkttype) { switch (pkttype) { case PKT_PUBLIC_KEY: case PKT_PUBLIC_SUBKEY: case PKT_SECRET_KEY: case PKT_SECRET_SUBKEY: case PKT_SIGNATURE: case PKT_USER_ID: case PKT_ATTRIBUTE: case PKT_RING_TRUST: return 1; default: return 0; } } /**************** * Read the next keyblock from stream A. * PENDING_PKT should be initialzed to NULL * and not chnaged form the caller. * Return: 0 = okay, -1 no more blocks or another errorcode. */ static int read_block( IOBUF a, PACKET **pending_pkt, KBNODE *ret_root ) { int rc; PACKET *pkt; KBNODE root = NULL; int in_cert; if( *pending_pkt ) { root = new_kbnode( *pending_pkt ); *pending_pkt = NULL; in_cert = 1; } else in_cert = 0; pkt = xmalloc( sizeof *pkt ); init_packet(pkt); while( (rc=parse_packet(a, pkt)) != -1 ) { if( rc ) { /* ignore errors */ if( rc != G10ERR_UNKNOWN_PACKET ) { log_error("read_block: read error: %s\n", g10_errstr(rc) ); rc = G10ERR_INV_KEYRING; goto ready; } free_packet( pkt ); init_packet(pkt); continue; } if( !root && pkt->pkttype == PKT_SIGNATURE && pkt->pkt.signature->sig_class == 0x20 ) { /* this is a revocation certificate which is handled * in a special way */ root = new_kbnode( pkt ); pkt = NULL; goto ready; } /* make a linked list of all packets */ switch( pkt->pkttype ) { case PKT_COMPRESSED: if(check_compress_algo(pkt->pkt.compressed->algorithm)) { rc = G10ERR_COMPR_ALGO; goto ready; } else { compress_filter_context_t *cfx = xmalloc_clear( sizeof *cfx ); pkt->pkt.compressed->buf = NULL; push_compress_filter2(a,cfx,pkt->pkt.compressed->algorithm,1); } free_packet( pkt ); init_packet(pkt); break; case PKT_RING_TRUST: /* skip those packets */ free_packet( pkt ); init_packet(pkt); break; case PKT_PUBLIC_KEY: case PKT_SECRET_KEY: if( in_cert ) { /* store this packet */ *pending_pkt = pkt; pkt = NULL; goto ready; } in_cert = 1; default: if (in_cert && valid_keyblock_packet (pkt->pkttype)) { if( !root ) root = new_kbnode( pkt ); else add_kbnode( root, new_kbnode( pkt ) ); pkt = xmalloc( sizeof *pkt ); } init_packet(pkt); break; } } ready: if( rc == -1 && root ) rc = 0; if( rc ) release_kbnode( root ); else *ret_root = root; free_packet( pkt ); xfree( pkt ); return rc; } /* Walk through the subkeys on a pk to find if we have the PKS disease: multiple subkeys with their binding sigs stripped, and the sig for the first subkey placed after the last subkey. That is, instead of "pk uid sig sub1 bind1 sub2 bind2 sub3 bind3" we have "pk uid sig sub1 sub2 sub3 bind1". We can't do anything about sub2 and sub3, as they are already lost, but we can try and rescue sub1 by reordering the keyblock so that it reads "pk uid sig sub1 bind1 sub2 sub3". Returns TRUE if the keyblock was modified. */ static int fix_pks_corruption(KBNODE keyblock) { int changed=0,keycount=0; KBNODE node,last=NULL,sknode=NULL; /* First determine if we have the problem at all. Look for 2 or more subkeys in a row, followed by a single binding sig. */ for(node=keyblock;node;last=node,node=node->next) { if(node->pkt->pkttype==PKT_PUBLIC_SUBKEY) { keycount++; if(!sknode) sknode=node; } else if(node->pkt->pkttype==PKT_SIGNATURE && node->pkt->pkt.signature->sig_class==0x18 && keycount>=2 && node->next==NULL) { /* We might have the problem, as this key has two subkeys in a row without any intervening packets. */ /* Sanity check */ if(last==NULL) break; /* Temporarily attach node to sknode. */ node->next=sknode->next; sknode->next=node; last->next=NULL; /* Note we aren't checking whether this binding sig is a selfsig. This is not necessary here as the subkey and binding sig will be rejected later if that is the case. */ if(check_key_signature(keyblock,node,NULL)) { /* Not a match, so undo the changes. */ sknode->next=node->next; last->next=node; node->next=NULL; break; } else { sknode->flag |= 1; /* Mark it good so we don't need to check it again */ changed=1; break; } } else keycount=0; } return changed; } /* Versions of GnuPG before 1.4.11 and 2.0.16 allowed to import bogus direct key signatures. A side effect of this was that a later import of the same good direct key signatures was not possible because the cmp_signature check in merge_blocks considered them equal. Although direct key signatures are now checked during import, there might still be bogus signatures sitting in a keyring. We need to detect and delete them before doing a merge. This function returns the number of removed sigs. */ static int fix_bad_direct_key_sigs (kbnode_t keyblock, u32 *keyid) { gpg_error_t err; kbnode_t node; int count = 0; for (node = keyblock->next; node; node=node->next) { if (node->pkt->pkttype == PKT_USER_ID) break; if (node->pkt->pkttype == PKT_SIGNATURE && IS_KEY_SIG (node->pkt->pkt.signature)) { err = check_key_signature (keyblock, node, NULL); if (err && gpg_err_code (err) != GPG_ERR_PUBKEY_ALGO ) { /* If we don't know the error, we can't decide; this is not a problem because cmp_signature can't compare the signature either. */ log_info ("key %s: invalid direct key signature removed\n", keystr (keyid)); delete_kbnode (node); count++; } } } return count; } static void print_import_ok (PKT_public_key *pk, unsigned int reason) { byte array[MAX_FINGERPRINT_LEN], *s; char buf[MAX_FINGERPRINT_LEN*2+30], *p; size_t i, n; snprintf (buf, sizeof buf, "%u ", reason); p = buf + strlen (buf); fingerprint_from_pk (pk, array, &n); s = array; for (i=0; i < n ; i++, s++, p += 2) sprintf (p, "%02X", *s); write_status_text (STATUS_IMPORT_OK, buf); } static void print_import_check (PKT_public_key * pk, PKT_user_id * id) { char * buf; byte fpr[24]; u32 keyid[2]; size_t i, pos = 0, n; buf = xmalloc (17+41+id->len+32); keyid_from_pk (pk, keyid); sprintf (buf, "%08X%08X ", keyid[0], keyid[1]); pos = 17; fingerprint_from_pk (pk, fpr, &n); for (i = 0; i < n; i++, pos += 2) sprintf (buf+pos, "%02X", fpr[i]); strcat (buf, " "); pos += 1; strcat (buf, id->name); write_status_text (STATUS_IMPORT_CHECK, buf); xfree (buf); } static void check_prefs_warning(PKT_public_key *pk) { log_info(_("WARNING: key %s contains preferences for unavailable\n" "algorithms on these user IDs:\n"), keystr_from_pk(pk)); } static void check_prefs (ctrl_t ctrl, kbnode_t keyblock) { kbnode_t node; PKT_public_key *pk; int problem=0; merge_keys_and_selfsig(keyblock); pk=keyblock->pkt->pkt.public_key; for(node=keyblock;node;node=node->next) { if(node->pkt->pkttype==PKT_USER_ID && node->pkt->pkt.user_id->created && node->pkt->pkt.user_id->prefs) { PKT_user_id *uid=node->pkt->pkt.user_id; prefitem_t *prefs=uid->prefs; char *user=utf8_to_native(uid->name,strlen(uid->name),0); for(;prefs->type;prefs++) { char num[10]; /* prefs->value is a byte, so we're over safe here */ sprintf(num,"%u",prefs->value); if(prefs->type==PREFTYPE_SYM) { if (openpgp_cipher_test_algo (prefs->value)) { const char *algo = (openpgp_cipher_test_algo (prefs->value) ? num : openpgp_cipher_algo_name (prefs->value)); if(!problem) check_prefs_warning(pk); log_info(_(" \"%s\": preference for cipher" " algorithm %s\n"), user, algo); problem=1; } } else if(prefs->type==PREFTYPE_HASH) { if(openpgp_md_test_algo(prefs->value)) { const char *algo = (gcry_md_test_algo (prefs->value) ? num : gcry_md_algo_name (prefs->value)); if(!problem) check_prefs_warning(pk); log_info(_(" \"%s\": preference for digest" " algorithm %s\n"), user, algo); problem=1; } } else if(prefs->type==PREFTYPE_ZIP) { if(check_compress_algo (prefs->value)) { const char *algo=compress_algo_to_string(prefs->value); if(!problem) check_prefs_warning(pk); log_info(_(" \"%s\": preference for compression" " algorithm %s\n"),user,algo?algo:num); problem=1; } } } xfree(user); } } if(problem) { log_info(_("it is strongly suggested that you update" " your preferences and\n")); log_info(_("re-distribute this key to avoid potential algorithm" " mismatch problems\n")); if(!opt.batch) { strlist_t sl=NULL,locusr=NULL; size_t fprlen=0; byte fpr[MAX_FINGERPRINT_LEN],*p; char username[(MAX_FINGERPRINT_LEN*2)+1]; unsigned int i; p=fingerprint_from_pk(pk,fpr,&fprlen); for(i=0;ipkt->pkt.public_key; keyid_from_pk( pk, keyid ); uidnode = find_next_kbnode( keyblock, PKT_USER_ID ); if( opt.verbose && !opt.interactive ) { log_info( "pub %4u%c/%s %s ", nbits_from_pk( pk ), pubkey_letter( pk->pubkey_algo ), keystr_from_pk(pk), datestr_from_pk(pk) ); if (uidnode) print_utf8_buffer (log_get_stream (), uidnode->pkt->pkt.user_id->name, uidnode->pkt->pkt.user_id->len ); log_printf ("\n"); } if( !uidnode ) { log_error( _("key %s: no user ID\n"), keystr_from_pk(pk)); return 0; } if (opt.interactive) { if(is_status_enabled()) print_import_check (pk, uidnode->pkt->pkt.user_id); merge_keys_and_selfsig (keyblock); tty_printf ("\n"); show_basic_key_info (keyblock); tty_printf ("\n"); if (!cpr_get_answer_is_yes ("import.okay", "Do you want to import this key? (y/N) ")) return 0; } collapse_uids(&keyblock); /* Clean the key that we're about to import, to cut down on things that we have to clean later. This has no practical impact on the end result, but does result in less logging which might confuse the user. */ if(options&IMPORT_CLEAN) clean_key(keyblock,opt.verbose,options&IMPORT_MINIMAL,NULL,NULL); clear_kbnode_flags( keyblock ); if((options&IMPORT_REPAIR_PKS_SUBKEY_BUG) && fix_pks_corruption(keyblock) && opt.verbose) log_info(_("key %s: PKS subkey corruption repaired\n"), keystr_from_pk(pk)); rc = chk_self_sigs( fname, keyblock , pk, keyid, &non_self ); if( rc ) return rc== -1? 0:rc; /* If we allow such a thing, mark unsigned uids as valid */ if( opt.allow_non_selfsigned_uid ) for( node=keyblock; node; node = node->next ) if( node->pkt->pkttype == PKT_USER_ID && !(node->flag & 1) ) { char *user=utf8_to_native(node->pkt->pkt.user_id->name, node->pkt->pkt.user_id->len,0); node->flag |= 1; log_info( _("key %s: accepted non self-signed user ID \"%s\"\n"), keystr_from_pk(pk),user); xfree(user); } if( !delete_inv_parts( fname, keyblock, keyid, options ) ) { log_error( _("key %s: no valid user IDs\n"), keystr_from_pk(pk)); if( !opt.quiet ) log_info(_("this may be caused by a missing self-signature\n")); stats->no_user_id++; return 0; } /* do we have this key already in one of our pubrings ? */ pk_orig = xmalloc_clear( sizeof *pk_orig ); rc = get_pubkey_fast ( pk_orig, keyid ); if( rc && rc != G10ERR_NO_PUBKEY && rc != G10ERR_UNU_PUBKEY ) { log_error( _("key %s: public key not found: %s\n"), keystr(keyid), g10_errstr(rc)); } else if ( rc && (opt.import_options&IMPORT_MERGE_ONLY) ) { if( opt.verbose ) log_info( _("key %s: new key - skipped\n"), keystr(keyid)); rc = 0; stats->skipped_new_keys++; } else if( rc ) { /* insert this key */ KEYDB_HANDLE hd = keydb_new (); rc = keydb_locate_writable (hd, NULL); if (rc) { log_error (_("no writable keyring found: %s\n"), g10_errstr (rc)); keydb_release (hd); return G10ERR_GENERAL; } if( opt.verbose > 1 ) log_info (_("writing to '%s'\n"), keydb_get_resource_name (hd) ); rc = keydb_insert_keyblock (hd, keyblock ); if (rc) log_error (_("error writing keyring '%s': %s\n"), keydb_get_resource_name (hd), g10_errstr(rc)); else { /* This should not be possible since we delete the ownertrust when a key is deleted, but it can happen if the keyring and trustdb are out of sync. It can also be made to happen with the trusted-key command. */ clear_ownertrusts (pk); if(non_self) revalidation_mark (); } keydb_release (hd); /* we are ready */ if( !opt.quiet ) { char *p=get_user_id_native (keyid); log_info( _("key %s: public key \"%s\" imported\n"), keystr(keyid),p); xfree(p); } if( is_status_enabled() ) { char *us = get_long_user_id_string( keyid ); write_status_text( STATUS_IMPORTED, us ); xfree(us); print_import_ok (pk, 1); } stats->imported++; if( is_RSA( pk->pubkey_algo ) ) stats->imported_rsa++; new_key = 1; } else { /* merge */ KEYDB_HANDLE hd; int n_uids, n_sigs, n_subk, n_sigs_cleaned, n_uids_cleaned; /* Compare the original against the new key; just to be sure nothing * weird is going on */ if( cmp_public_keys( pk_orig, pk ) ) { log_error( _("key %s: doesn't match our copy\n"),keystr(keyid)); goto leave; } /* now read the original keyblock */ hd = keydb_new (); { byte afp[MAX_FINGERPRINT_LEN]; size_t an; fingerprint_from_pk (pk_orig, afp, &an); while (an < MAX_FINGERPRINT_LEN) afp[an++] = 0; rc = keydb_search_fpr (hd, afp); } if( rc ) { log_error (_("key %s: can't locate original keyblock: %s\n"), keystr(keyid), g10_errstr(rc)); keydb_release (hd); goto leave; } rc = keydb_get_keyblock (hd, &keyblock_orig ); if (rc) { log_error (_("key %s: can't read original keyblock: %s\n"), keystr(keyid), g10_errstr(rc)); keydb_release (hd); goto leave; } /* Make sure the original direct key sigs are all sane. */ n_sigs_cleaned = fix_bad_direct_key_sigs (keyblock_orig, keyid); if (n_sigs_cleaned) commit_kbnode (&keyblock_orig); /* and try to merge the block */ clear_kbnode_flags( keyblock_orig ); clear_kbnode_flags( keyblock ); n_uids = n_sigs = n_subk = n_uids_cleaned = 0; rc = merge_blocks( fname, keyblock_orig, keyblock, keyid, &n_uids, &n_sigs, &n_subk ); if( rc ) { keydb_release (hd); goto leave; } if(options&IMPORT_CLEAN) clean_key(keyblock_orig,opt.verbose,options&IMPORT_MINIMAL, &n_uids_cleaned,&n_sigs_cleaned); if( n_uids || n_sigs || n_subk || n_sigs_cleaned || n_uids_cleaned) { mod_key = 1; /* keyblock_orig has been updated; write */ rc = keydb_update_keyblock (hd, keyblock_orig); if (rc) log_error (_("error writing keyring '%s': %s\n"), keydb_get_resource_name (hd), g10_errstr(rc) ); else if(non_self) revalidation_mark (); /* we are ready */ if( !opt.quiet ) { char *p=get_user_id_native(keyid); if( n_uids == 1 ) log_info( _("key %s: \"%s\" 1 new user ID\n"), keystr(keyid),p); else if( n_uids ) log_info( _("key %s: \"%s\" %d new user IDs\n"), keystr(keyid),p,n_uids); if( n_sigs == 1 ) log_info( _("key %s: \"%s\" 1 new signature\n"), keystr(keyid), p); else if( n_sigs ) log_info( _("key %s: \"%s\" %d new signatures\n"), keystr(keyid), p, n_sigs ); if( n_subk == 1 ) log_info( _("key %s: \"%s\" 1 new subkey\n"), keystr(keyid), p); else if( n_subk ) log_info( _("key %s: \"%s\" %d new subkeys\n"), keystr(keyid), p, n_subk ); if(n_sigs_cleaned==1) log_info(_("key %s: \"%s\" %d signature cleaned\n"), keystr(keyid),p,n_sigs_cleaned); else if(n_sigs_cleaned) log_info(_("key %s: \"%s\" %d signatures cleaned\n"), keystr(keyid),p,n_sigs_cleaned); if(n_uids_cleaned==1) log_info(_("key %s: \"%s\" %d user ID cleaned\n"), keystr(keyid),p,n_uids_cleaned); else if(n_uids_cleaned) log_info(_("key %s: \"%s\" %d user IDs cleaned\n"), keystr(keyid),p,n_uids_cleaned); xfree(p); } stats->n_uids +=n_uids; stats->n_sigs +=n_sigs; stats->n_subk +=n_subk; stats->n_sigs_cleaned +=n_sigs_cleaned; stats->n_uids_cleaned +=n_uids_cleaned; if (is_status_enabled ()) print_import_ok (pk, ((n_uids?2:0)|(n_sigs?4:0)|(n_subk?8:0))); } else { same_key = 1; if (is_status_enabled ()) print_import_ok (pk, 0); if( !opt.quiet ) { char *p=get_user_id_native(keyid); log_info( _("key %s: \"%s\" not changed\n"),keystr(keyid),p); xfree(p); } stats->unchanged++; } keydb_release (hd); hd = NULL; } leave: if (mod_key || new_key || same_key) { /* A little explanation for this: we fill in the fingerprint when importing keys as it can be useful to know the fingerprint in certain keyserver-related cases (a keyserver asked for a particular name, but the key doesn't have that name). However, in cases where we're importing more than one key at a time, we cannot know which key to fingerprint. In these cases, rather than guessing, we do not fingerprinting at all, and we must hope the user ID on the keys are useful. Note that we need to do this for new keys, merged keys and even for unchanged keys. This is required because for example the --auto-key-locate feature may import an already imported key and needs to know the fingerprint of the key in all cases. */ if (fpr) { xfree (*fpr); /* Note that we need to compare against 0 here because COUNT gets only incremented after returning form this function. */ if (stats->count == 0) *fpr = fingerprint_from_pk (pk, NULL, fpr_len); else *fpr = NULL; } } /* Now that the key is definitely incorporated into the keydb, we need to check if a designated revocation is present or if the prefs are not rational so we can warn the user. */ if (mod_key) { revocation_present (ctrl, keyblock_orig); if (!from_sk && have_secret_key_with_kid (keyid)) check_prefs (ctrl, keyblock_orig); } else if (new_key) { revocation_present (ctrl, keyblock); if (!from_sk && have_secret_key_with_kid (keyid)) check_prefs (ctrl, keyblock); } release_kbnode( keyblock_orig ); free_public_key( pk_orig ); return rc; } /* Extract one MPI value from the S-expression PKEY which is expected to hold a "public-key". Returns NULL on error. */ static gcry_mpi_t one_mpi_from_pkey (gcry_sexp_t pkey, const char *name, size_t namelen) { gcry_sexp_t list, l2; gcry_mpi_t a; list = gcry_sexp_find_token (pkey, "public-key", 0); if (!list) return NULL; l2 = gcry_sexp_cadr (list); gcry_sexp_release (list); list = l2; if (!list) return NULL; l2 = gcry_sexp_find_token (list, name, namelen); if (!l2) { gcry_sexp_release (list); return NULL; } a = gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG); gcry_sexp_release (l2); gcry_sexp_release (list); return a; } /* Transfer all the secret keys in SEC_KEYBLOCK to the gpg-agent. The function prints diagnostics and returns an error code. */ static gpg_error_t transfer_secret_keys (ctrl_t ctrl, struct stats_s *stats, kbnode_t sec_keyblock) { gpg_error_t err = 0; void *kek = NULL; size_t keklen; kbnode_t ctx = NULL; kbnode_t node; PKT_public_key *main_pk, *pk; struct seckey_info *ski; int nskey; membuf_t mbuf; int i, j; unsigned int n; void *format_args_buf_ptr[PUBKEY_MAX_NSKEY]; int format_args_buf_int[PUBKEY_MAX_NSKEY]; void *format_args[2*PUBKEY_MAX_NSKEY]; gcry_sexp_t skey, prot, tmpsexp; unsigned char *transferkey = NULL; size_t transferkeylen; gcry_cipher_hd_t cipherhd = NULL; unsigned char *wrappedkey = NULL; size_t wrappedkeylen; char *cache_nonce = NULL; gcry_mpi_t ecc_params[5] = {NULL, NULL, NULL, NULL, NULL}; /* Get the current KEK. */ err = agent_keywrap_key (ctrl, 0, &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) goto leave; xfree (kek); kek = NULL; main_pk = NULL; while ((node = walk_kbnode (sec_keyblock, &ctx, 0))) { if (node->pkt->pkttype != PKT_SECRET_KEY && node->pkt->pkttype != PKT_SECRET_SUBKEY) continue; pk = node->pkt->pkt.public_key; if (!main_pk) main_pk = pk; /* Make sure the keyids are available. */ keyid_from_pk (pk, NULL); if (node->pkt->pkttype == PKT_SECRET_KEY) { pk->main_keyid[0] = pk->keyid[0]; pk->main_keyid[1] = pk->keyid[1]; } else { pk->main_keyid[0] = main_pk->keyid[0]; pk->main_keyid[1] = main_pk->keyid[1]; } ski = pk->seckey_info; if (!ski) BUG (); stats->count++; stats->secret_read++; /* We ignore stub keys. The way we handle them in other parts of the code is by asking the agent whether any secret key is available for a given keyblock and then concluding that we have a secret key; all secret (sub)keys of the keyblock the agent does not know of are then stub keys. This works also for card stub keys. The learn command or the card-status command may be used to check with the agent whether a card has been inserted and a stub key is in turn generated by the agent. */ if (ski->s2k.mode == 1001 || ski->s2k.mode == 1002) continue; /* Convert our internal secret key object into an S-expression. */ nskey = pubkey_get_nskey (pk->pubkey_algo); if (!nskey || nskey > PUBKEY_MAX_NSKEY) { err = gpg_error (GPG_ERR_BAD_SECKEY); log_error ("internal error: %s\n", gpg_strerror (err)); goto leave; } init_membuf (&mbuf, 50); put_membuf_str (&mbuf, "(skey"); if (pk->pubkey_algo == PUBKEY_ALGO_ECDSA + || pk->pubkey_algo == PUBKEY_ALGO_EDDSA || pk->pubkey_algo == PUBKEY_ALGO_ECDH) { /* We need special treatment for ECC algorithms. OpenPGP stores only the curve name but the agent expects a full key. This is so that we can keep all curve name validation code out of gpg-agent. */ #if PUBKEY_MAX_NSKEY < 7 #error PUBKEY_MAX_NSKEY too low for ECC #endif char *curve = openpgp_oid_to_str (pk->pkey[0]); if (!curve) err = gpg_error_from_syserror (); else { - gcry_sexp_t cparam = gcry_pk_get_param (GCRY_PK_ECDSA, curve); + gcry_sexp_t cparam = gcry_pk_get_param (GCRY_PK_ECC, curve); xfree (curve); if (!cparam) err = gpg_error (GPG_ERR_UNKNOWN_CURVE); else { const char *s; /* Append the curve parameters P, A, B, G and N. */ for (i=j=0; !err && *(s = "pabgn"+i); i++) { ecc_params[i] = one_mpi_from_pkey (cparam, s, 1); if (!ecc_params[i]) err = gpg_error (GPG_ERR_INV_CURVE); else { put_membuf_str (&mbuf, " _ %m"); format_args[j++] = ecc_params+i; } } gcry_sexp_release (cparam); if (!err) { /* Append the public key element Q. */ put_membuf_str (&mbuf, " _ %m"); format_args[j++] = pk->pkey + 1; /* Append the secret key element D. Note that for ECDH we need to skip PKEY[2] because this holds the KEK which is not needed. */ i = pk->pubkey_algo == PUBKEY_ALGO_ECDH? 3 : 2; if (gcry_mpi_get_flag (pk->pkey[i], GCRYMPI_FLAG_OPAQUE)) { put_membuf_str (&mbuf, " e %b"); format_args_buf_ptr[i] = gcry_mpi_get_opaque (pk->pkey[i],&n); format_args_buf_int[i] = (n+7)/8; format_args[j++] = format_args_buf_int + i; format_args[j++] = format_args_buf_ptr + i; } else { put_membuf_str (&mbuf, " _ %m"); format_args[j++] = pk->pkey + i; } } } } } else { /* Standard case for the old (non-ECC) algorithms. */ for (i=j=0; i < nskey; i++) { if (!pk->pkey[i]) ; /* Protected keys only have NPKEY+1 elements. */ else if (gcry_mpi_get_flag (pk->pkey[i], GCRYMPI_FLAG_OPAQUE)) { put_membuf_str (&mbuf, " e %b"); format_args_buf_ptr[i] = gcry_mpi_get_opaque (pk->pkey[i],&n); format_args_buf_int[i] = (n+7)/8; format_args[j++] = format_args_buf_int + i; format_args[j++] = format_args_buf_ptr + i; } else { put_membuf_str (&mbuf, " _ %m"); format_args[j++] = pk->pkey + i; } } } put_membuf_str (&mbuf, ")\n"); put_membuf (&mbuf, "", 1); if (err) xfree (get_membuf (&mbuf, NULL)); else { char *format = get_membuf (&mbuf, NULL); if (!format) err = gpg_error_from_syserror (); else err = gcry_sexp_build_array (&skey, NULL, format, format_args); xfree (format); } if (err) { log_error ("error building skey array: %s\n", gpg_strerror (err)); goto leave; } if (ski->is_protected) { char countbuf[35]; /* Note that the IVLEN may be zero if we are working on a dummy key. We can't express that in an S-expression and thus we send dummy data for the IV. */ snprintf (countbuf, sizeof countbuf, "%lu", (unsigned long)ski->s2k.count); err = gcry_sexp_build (&prot, NULL, " (protection %s %s %b %d %s %b %s)\n", ski->sha1chk? "sha1":"sum", openpgp_cipher_algo_name (ski->algo), ski->ivlen? (int)ski->ivlen:1, ski->ivlen? ski->iv: (const unsigned char*)"X", ski->s2k.mode, openpgp_md_algo_name (ski->s2k.hash_algo), (int)sizeof (ski->s2k.salt), ski->s2k.salt, countbuf); } else err = gcry_sexp_build (&prot, NULL, " (protection none)\n"); tmpsexp = NULL; xfree (transferkey); transferkey = NULL; if (!err) err = gcry_sexp_build (&tmpsexp, NULL, "(openpgp-private-key\n" " (version %d)\n" " (algo %s)\n" " %S\n" " (csum %d)\n" " %S)\n", pk->version, openpgp_pk_algo_name (pk->pubkey_algo), skey, (int)(unsigned long)ski->csum, prot); gcry_sexp_release (skey); gcry_sexp_release (prot); if (!err) err = make_canon_sexp_pad (tmpsexp, 1, &transferkey, &transferkeylen); gcry_sexp_release (tmpsexp); if (err) { log_error ("error building transfer key: %s\n", gpg_strerror (err)); goto leave; } /* Wrap the key. */ wrappedkeylen = transferkeylen + 8; xfree (wrappedkey); wrappedkey = xtrymalloc (wrappedkeylen); if (!wrappedkey) err = gpg_error_from_syserror (); else err = gcry_cipher_encrypt (cipherhd, wrappedkey, wrappedkeylen, transferkey, transferkeylen); if (err) goto leave; xfree (transferkey); transferkey = NULL; /* Send the wrapped key to the agent. */ { char *desc = gpg_format_keydesc (pk, 1, 1); err = agent_import_key (ctrl, desc, &cache_nonce, wrappedkey, wrappedkeylen, opt.batch); xfree (desc); } if (!err) { if (opt.verbose) log_info (_("key %s: secret key imported\n"), keystr_from_pk_with_sub (main_pk, pk)); stats->secret_imported++; } else if ( gpg_err_code (err) == GPG_ERR_EEXIST ) { if (opt.verbose) log_info (_("key %s: secret key already exists\n"), keystr_from_pk_with_sub (main_pk, pk)); err = 0; stats->secret_dups++; } else { log_error (_("key %s: error sending to agent: %s\n"), keystr_from_pk_with_sub (main_pk, pk), gpg_strerror (err)); if (gpg_err_code (err) == GPG_ERR_CANCELED || gpg_err_code (err) == GPG_ERR_FULLY_CANCELED) break; /* Don't try the other subkeys. */ } } leave: for (i=0; i < DIM (ecc_params); i++) gcry_mpi_release (ecc_params[i]); xfree (cache_nonce); xfree (wrappedkey); xfree (transferkey); gcry_cipher_close (cipherhd); xfree (kek); return err; } /* Walk a secret keyblock and produce a public keyblock out of it. Returns a new node or NULL on error. */ static kbnode_t sec_to_pub_keyblock (kbnode_t sec_keyblock) { kbnode_t pub_keyblock = NULL; kbnode_t ctx = NULL; kbnode_t secnode, pubnode; while ((secnode = walk_kbnode (sec_keyblock, &ctx, 0))) { if (secnode->pkt->pkttype == PKT_SECRET_KEY || secnode->pkt->pkttype == PKT_SECRET_SUBKEY) { /* Make a public key. */ PACKET *pkt; PKT_public_key *pk; pkt = xtrycalloc (1, sizeof *pkt); pk = pkt? copy_public_key (NULL, secnode->pkt->pkt.public_key): NULL; if (!pk) { xfree (pkt); release_kbnode (pub_keyblock); return NULL; } if (secnode->pkt->pkttype == PKT_SECRET_KEY) pkt->pkttype = PKT_PUBLIC_KEY; else pkt->pkttype = PKT_PUBLIC_SUBKEY; pkt->pkt.public_key = pk; pubnode = new_kbnode (pkt); } else { pubnode = clone_kbnode (secnode); } if (!pub_keyblock) pub_keyblock = pubnode; else add_kbnode (pub_keyblock, pubnode); } return pub_keyblock; } /**************** * Ditto for secret keys. Handling is simpler than for public keys. * We allow secret key importing only when allow is true, this is so * that a secret key can not be imported accidently and thereby tampering * with the trust calculation. */ static int import_secret_one (ctrl_t ctrl, const char *fname, KBNODE keyblock, struct stats_s *stats, unsigned int options) { PKT_public_key *pk; struct seckey_info *ski; KBNODE node, uidnode; u32 keyid[2]; int rc = 0; int nr_prev; kbnode_t pub_keyblock; /* Get the key and print some info about it */ node = find_kbnode (keyblock, PKT_SECRET_KEY); if (!node) BUG (); pk = node->pkt->pkt.public_key; keyid_from_pk (pk, keyid); uidnode = find_next_kbnode (keyblock, PKT_USER_ID); if (opt.verbose) { log_info ("sec %4u%c/%s %s ", nbits_from_pk (pk), pubkey_letter (pk->pubkey_algo), keystr_from_pk (pk), datestr_from_pk (pk)); if (uidnode) print_utf8_buffer (log_get_stream (), uidnode->pkt->pkt.user_id->name, uidnode->pkt->pkt.user_id->len); log_printf ("\n"); } stats->secret_read++; if (!uidnode) { log_error( _("key %s: no user ID\n"), keystr_from_pk (pk)); return 0; } ski = pk->seckey_info; if (!ski) { /* Actually an internal error. */ log_error ("key %s: secret key info missing\n", keystr_from_pk (pk)); return 0; } /* A quick check to not import keys with an invalid protection cipher algorithm (only checks the primary key, though). */ if (ski->algo > 110) { log_error (_("key %s: secret key with invalid cipher %d" " - skipped\n"), keystr_from_pk (pk), ski->algo); return 0; } #ifdef ENABLE_SELINUX_HACKS if (1) { /* We don't allow to import secret keys because that may be used to put a secret key into the keyring and the user might later be tricked into signing stuff with that key. */ log_error (_("importing secret keys not allowed\n")); return 0; } #endif clear_kbnode_flags (keyblock); nr_prev = stats->skipped_new_keys; /* Make a public key out of the key. */ pub_keyblock = sec_to_pub_keyblock (keyblock); if (!pub_keyblock) log_error ("key %s: failed to create public key from secret key\n", keystr_from_pk (pk)); else { /* Note that this outputs an IMPORT_OK status message for the public key block, and below we will output another one for the secret keys. FIXME? */ import_one (ctrl, fname, pub_keyblock, stats, NULL, NULL, options, 1); /* Fixme: We should check for an invalid keyblock and cancel the secret key import in this case. */ release_kbnode (pub_keyblock); /* At least we cancel the secret key import when the public key import was skipped due to MERGE_ONLY option and a new key. */ if (stats->skipped_new_keys <= nr_prev) { /* Read the keyblock again to get the effects of a merge. */ /* Fixme: we should do this based on the fingerprint or even better let import_one return the merged keyblock. */ node = get_pubkeyblock (keyid); if (!node) log_error ("key %s: failed to re-lookup public key\n", keystr_from_pk (pk)); else { nr_prev = stats->secret_imported; if (!transfer_secret_keys (ctrl, stats, keyblock)) { int status = 16; if (!opt.quiet) log_info (_("key %s: secret key imported\n"), keystr_from_pk (pk)); if (stats->secret_imported > nr_prev) status |= 1; if (is_status_enabled ()) print_import_ok (pk, status); check_prefs (ctrl, node); } release_kbnode (node); } } } return rc; } /**************** * Import a revocation certificate; this is a single signature packet. */ static int import_revoke_cert( const char *fname, KBNODE node, struct stats_s *stats ) { PKT_public_key *pk=NULL; KBNODE onode, keyblock = NULL; KEYDB_HANDLE hd = NULL; u32 keyid[2]; int rc = 0; (void)fname; assert( !node->next ); assert( node->pkt->pkttype == PKT_SIGNATURE ); assert( node->pkt->pkt.signature->sig_class == 0x20 ); keyid[0] = node->pkt->pkt.signature->keyid[0]; keyid[1] = node->pkt->pkt.signature->keyid[1]; pk = xmalloc_clear( sizeof *pk ); rc = get_pubkey( pk, keyid ); if( rc == G10ERR_NO_PUBKEY ) { log_error(_("key %s: no public key -" " can't apply revocation certificate\n"), keystr(keyid)); rc = 0; goto leave; } else if( rc ) { log_error(_("key %s: public key not found: %s\n"), keystr(keyid), g10_errstr(rc)); goto leave; } /* read the original keyblock */ hd = keydb_new (); { byte afp[MAX_FINGERPRINT_LEN]; size_t an; fingerprint_from_pk (pk, afp, &an); while (an < MAX_FINGERPRINT_LEN) afp[an++] = 0; rc = keydb_search_fpr (hd, afp); } if (rc) { log_error (_("key %s: can't locate original keyblock: %s\n"), keystr(keyid), g10_errstr(rc)); goto leave; } rc = keydb_get_keyblock (hd, &keyblock ); if (rc) { log_error (_("key %s: can't read original keyblock: %s\n"), keystr(keyid), g10_errstr(rc)); goto leave; } /* it is okay, that node is not in keyblock because * check_key_signature works fine for sig_class 0x20 in this * special case. */ rc = check_key_signature( keyblock, node, NULL); if( rc ) { log_error( _("key %s: invalid revocation certificate" ": %s - rejected\n"), keystr(keyid), g10_errstr(rc)); goto leave; } /* check whether we already have this */ for(onode=keyblock->next; onode; onode=onode->next ) { if( onode->pkt->pkttype == PKT_USER_ID ) break; else if( onode->pkt->pkttype == PKT_SIGNATURE && !cmp_signatures(node->pkt->pkt.signature, onode->pkt->pkt.signature)) { rc = 0; goto leave; /* yes, we already know about it */ } } /* insert it */ insert_kbnode( keyblock, clone_kbnode(node), 0 ); /* and write the keyblock back */ rc = keydb_update_keyblock (hd, keyblock ); if (rc) log_error (_("error writing keyring '%s': %s\n"), keydb_get_resource_name (hd), g10_errstr(rc) ); keydb_release (hd); hd = NULL; /* we are ready */ if( !opt.quiet ) { char *p=get_user_id_native (keyid); log_info( _("key %s: \"%s\" revocation certificate imported\n"), keystr(keyid),p); xfree(p); } stats->n_revoc++; /* If the key we just revoked was ultimately trusted, remove its ultimate trust. This doesn't stop the user from putting the ultimate trust back, but is a reasonable solution for now. */ if(get_ownertrust(pk)==TRUST_ULTIMATE) clear_ownertrusts(pk); revalidation_mark (); leave: keydb_release (hd); release_kbnode( keyblock ); free_public_key( pk ); return rc; } /* * Loop over the keyblock and check all self signatures. * Mark all user-ids with a self-signature by setting flag bit 0. * Mark all user-ids with an invalid self-signature by setting bit 1. * This works also for subkeys, here the subkey is marked. Invalid or * extra subkey sigs (binding or revocation) are marked for deletion. * non_self is set to true if there are any sigs other than self-sigs * in this keyblock. */ static int chk_self_sigs (const char *fname, kbnode_t keyblock, PKT_public_key *pk, u32 *keyid, int *non_self ) { kbnode_t n, knode = NULL; PKT_signature *sig; int rc; u32 bsdate=0, rsdate=0; kbnode_t bsnode = NULL, rsnode = NULL; (void)fname; (void)pk; for (n=keyblock; (n = find_next_kbnode (n, 0)); ) { if (n->pkt->pkttype == PKT_PUBLIC_SUBKEY) { knode = n; bsdate = 0; rsdate = 0; bsnode = NULL; rsnode = NULL; continue; } if ( n->pkt->pkttype != PKT_SIGNATURE ) continue; sig = n->pkt->pkt.signature; if ( keyid[0] != sig->keyid[0] || keyid[1] != sig->keyid[1] ) { *non_self = 1; continue; } /* This just caches the sigs for later use. That way we import a fully-cached key which speeds things up. */ if (!opt.no_sig_cache) check_key_signature (keyblock, n, NULL); if ( IS_UID_SIG(sig) || IS_UID_REV(sig) ) { KBNODE unode = find_prev_kbnode( keyblock, n, PKT_USER_ID ); if ( !unode ) { log_error( _("key %s: no user ID for signature\n"), keystr(keyid)); return -1; /* The complete keyblock is invalid. */ } /* If it hasn't been marked valid yet, keep trying. */ if (!(unode->flag&1)) { rc = check_key_signature (keyblock, n, NULL); if ( rc ) { if ( opt.verbose ) { char *p = utf8_to_native (unode->pkt->pkt.user_id->name, strlen (unode->pkt->pkt.user_id->name),0); log_info (gpg_err_code(rc) == G10ERR_PUBKEY_ALGO ? _("key %s: unsupported public key " "algorithm on user ID \"%s\"\n"): _("key %s: invalid self-signature " "on user ID \"%s\"\n"), keystr (keyid),p); xfree (p); } } else unode->flag |= 1; /* Mark that signature checked. */ } } else if (IS_KEY_SIG (sig)) { rc = check_key_signature (keyblock, n, NULL); if ( rc ) { if (opt.verbose) log_info (gpg_err_code (rc) == G10ERR_PUBKEY_ALGO ? _("key %s: unsupported public key algorithm\n"): _("key %s: invalid direct key signature\n"), keystr (keyid)); n->flag |= 4; } } else if ( IS_SUBKEY_SIG (sig) ) { /* Note that this works based solely on the timestamps like the rest of gpg. If the standard gets revocation targets, this may need to be revised. */ if ( !knode ) { if (opt.verbose) log_info (_("key %s: no subkey for key binding\n"), keystr (keyid)); n->flag |= 4; /* delete this */ } else { rc = check_key_signature (keyblock, n, NULL); if ( rc ) { if (opt.verbose) log_info (gpg_err_code (rc) == G10ERR_PUBKEY_ALGO ? _("key %s: unsupported public key" " algorithm\n"): _("key %s: invalid subkey binding\n"), keystr (keyid)); n->flag |= 4; } else { /* It's valid, so is it newer? */ if (sig->timestamp >= bsdate) { knode->flag |= 1; /* The subkey is valid. */ if (bsnode) { /* Delete the last binding sig since this one is newer */ bsnode->flag |= 4; if (opt.verbose) log_info (_("key %s: removed multiple subkey" " binding\n"),keystr(keyid)); } bsnode = n; bsdate = sig->timestamp; } else n->flag |= 4; /* older */ } } } else if ( IS_SUBKEY_REV (sig) ) { /* We don't actually mark the subkey as revoked right now, so just check that the revocation sig is the most recent valid one. Note that we don't care if the binding sig is newer than the revocation sig. See the comment in getkey.c:merge_selfsigs_subkey for more. */ if ( !knode ) { if (opt.verbose) log_info (_("key %s: no subkey for key revocation\n"), keystr(keyid)); n->flag |= 4; /* delete this */ } else { rc = check_key_signature (keyblock, n, NULL); if ( rc ) { if(opt.verbose) log_info (gpg_err_code (rc) == G10ERR_PUBKEY_ALGO ? _("key %s: unsupported public" " key algorithm\n"): _("key %s: invalid subkey revocation\n"), keystr(keyid)); n->flag |= 4; } else { /* It's valid, so is it newer? */ if (sig->timestamp >= rsdate) { if (rsnode) { /* Delete the last revocation sig since this one is newer. */ rsnode->flag |= 4; if (opt.verbose) log_info (_("key %s: removed multiple subkey" " revocation\n"),keystr(keyid)); } rsnode = n; rsdate = sig->timestamp; } else n->flag |= 4; /* older */ } } } } return 0; } /**************** * delete all parts which are invalid and those signatures whose * public key algorithm is not available in this implemenation; * but consider RSA as valid, because parse/build_packets knows * about it. * returns: true if at least one valid user-id is left over. */ static int delete_inv_parts( const char *fname, KBNODE keyblock, u32 *keyid, unsigned int options) { KBNODE node; int nvalid=0, uid_seen=0, subkey_seen=0; (void)fname; for(node=keyblock->next; node; node = node->next ) { if( node->pkt->pkttype == PKT_USER_ID ) { uid_seen = 1; if( (node->flag & 2) || !(node->flag & 1) ) { if( opt.verbose ) { char *p=utf8_to_native(node->pkt->pkt.user_id->name, node->pkt->pkt.user_id->len,0); log_info( _("key %s: skipped user ID \"%s\"\n"), keystr(keyid),p); xfree(p); } delete_kbnode( node ); /* the user-id */ /* and all following packets up to the next user-id */ while( node->next && node->next->pkt->pkttype != PKT_USER_ID && node->next->pkt->pkttype != PKT_PUBLIC_SUBKEY && node->next->pkt->pkttype != PKT_SECRET_SUBKEY ){ delete_kbnode( node->next ); node = node->next; } } else nvalid++; } else if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY || node->pkt->pkttype == PKT_SECRET_SUBKEY ) { if( (node->flag & 2) || !(node->flag & 1) ) { if( opt.verbose ) log_info( _("key %s: skipped subkey\n"),keystr(keyid)); delete_kbnode( node ); /* the subkey */ /* and all following signature packets */ while( node->next && node->next->pkt->pkttype == PKT_SIGNATURE ) { delete_kbnode( node->next ); node = node->next; } } else subkey_seen = 1; } else if (node->pkt->pkttype == PKT_SIGNATURE && openpgp_pk_test_algo (node->pkt->pkt.signature->pubkey_algo) && node->pkt->pkt.signature->pubkey_algo != PUBKEY_ALGO_RSA ) delete_kbnode( node ); /* build_packet() can't handle this */ else if( node->pkt->pkttype == PKT_SIGNATURE && !node->pkt->pkt.signature->flags.exportable && !(options&IMPORT_LOCAL_SIGS) && !have_secret_key_with_kid (node->pkt->pkt.signature->keyid)) { /* here we violate the rfc a bit by still allowing * to import non-exportable signature when we have the * the secret key used to create this signature - it * seems that this makes sense */ if(opt.verbose) log_info( _("key %s: non exportable signature" " (class 0x%02X) - skipped\n"), keystr(keyid), node->pkt->pkt.signature->sig_class ); delete_kbnode( node ); } else if( node->pkt->pkttype == PKT_SIGNATURE && node->pkt->pkt.signature->sig_class == 0x20 ) { if( uid_seen ) { if(opt.verbose) log_info( _("key %s: revocation certificate" " at wrong place - skipped\n"),keystr(keyid)); delete_kbnode( node ); } else { /* If the revocation cert is from a different key than the one we're working on don't check it - it's probably from a revocation key and won't be verifiable with this key anyway. */ if(node->pkt->pkt.signature->keyid[0]==keyid[0] && node->pkt->pkt.signature->keyid[1]==keyid[1]) { int rc = check_key_signature( keyblock, node, NULL); if( rc ) { if(opt.verbose) log_info( _("key %s: invalid revocation" " certificate: %s - skipped\n"), keystr(keyid), g10_errstr(rc)); delete_kbnode( node ); } } } } else if( node->pkt->pkttype == PKT_SIGNATURE && (node->pkt->pkt.signature->sig_class == 0x18 || node->pkt->pkt.signature->sig_class == 0x28) && !subkey_seen ) { if(opt.verbose) log_info( _("key %s: subkey signature" " in wrong place - skipped\n"), keystr(keyid)); delete_kbnode( node ); } else if( node->pkt->pkttype == PKT_SIGNATURE && !IS_CERT(node->pkt->pkt.signature)) { if(opt.verbose) log_info(_("key %s: unexpected signature class (0x%02X) -" " skipped\n"),keystr(keyid), node->pkt->pkt.signature->sig_class); delete_kbnode(node); } else if( (node->flag & 4) ) /* marked for deletion */ delete_kbnode( node ); } /* note: because keyblock is the public key, it is never marked * for deletion and so keyblock cannot change */ commit_kbnode( &keyblock ); return nvalid; } /**************** * It may happen that the imported keyblock has duplicated user IDs. * We check this here and collapse those user IDs together with their * sigs into one. * Returns: True if the keyblock has changed. */ int collapse_uids( KBNODE *keyblock ) { KBNODE uid1; int any=0; for(uid1=*keyblock;uid1;uid1=uid1->next) { KBNODE uid2; if(is_deleted_kbnode(uid1)) continue; if(uid1->pkt->pkttype!=PKT_USER_ID) continue; for(uid2=uid1->next;uid2;uid2=uid2->next) { if(is_deleted_kbnode(uid2)) continue; if(uid2->pkt->pkttype!=PKT_USER_ID) continue; if(cmp_user_ids(uid1->pkt->pkt.user_id, uid2->pkt->pkt.user_id)==0) { /* We have a duplicated uid */ KBNODE sig1,last; any=1; /* Now take uid2's signatures, and attach them to uid1 */ for(last=uid2;last->next;last=last->next) { if(is_deleted_kbnode(last)) continue; if(last->next->pkt->pkttype==PKT_USER_ID || last->next->pkt->pkttype==PKT_PUBLIC_SUBKEY || last->next->pkt->pkttype==PKT_SECRET_SUBKEY) break; } /* Snip out uid2 */ (find_prev_kbnode(*keyblock,uid2,0))->next=last->next; /* Now put uid2 in place as part of uid1 */ last->next=uid1->next; uid1->next=uid2; delete_kbnode(uid2); /* Now dedupe uid1 */ for(sig1=uid1->next;sig1;sig1=sig1->next) { KBNODE sig2; if(is_deleted_kbnode(sig1)) continue; if(sig1->pkt->pkttype==PKT_USER_ID || sig1->pkt->pkttype==PKT_PUBLIC_SUBKEY || sig1->pkt->pkttype==PKT_SECRET_SUBKEY) break; if(sig1->pkt->pkttype!=PKT_SIGNATURE) continue; for(sig2=sig1->next,last=sig1;sig2;last=sig2,sig2=sig2->next) { if(is_deleted_kbnode(sig2)) continue; if(sig2->pkt->pkttype==PKT_USER_ID || sig2->pkt->pkttype==PKT_PUBLIC_SUBKEY || sig2->pkt->pkttype==PKT_SECRET_SUBKEY) break; if(sig2->pkt->pkttype!=PKT_SIGNATURE) continue; if(cmp_signatures(sig1->pkt->pkt.signature, sig2->pkt->pkt.signature)==0) { /* We have a match, so delete the second signature */ delete_kbnode(sig2); sig2=last; } } } } } } commit_kbnode(keyblock); if(any && !opt.quiet) { const char *key="???"; if ((uid1 = find_kbnode (*keyblock, PKT_PUBLIC_KEY)) ) key = keystr_from_pk (uid1->pkt->pkt.public_key); else if ((uid1 = find_kbnode( *keyblock, PKT_SECRET_KEY)) ) key = keystr_from_pk (uid1->pkt->pkt.public_key); log_info (_("key %s: duplicated user ID detected - merged\n"), key); } return any; } /* Check for a 0x20 revocation from a revocation key that is not present. This may be called without the benefit of merge_xxxx so you can't rely on pk->revkey and friends. */ static void revocation_present (ctrl_t ctrl, kbnode_t keyblock) { kbnode_t onode, inode; PKT_public_key *pk = keyblock->pkt->pkt.public_key; for(onode=keyblock->next;onode;onode=onode->next) { /* If we reach user IDs, we're done. */ if(onode->pkt->pkttype==PKT_USER_ID) break; if(onode->pkt->pkttype==PKT_SIGNATURE && onode->pkt->pkt.signature->sig_class==0x1F && onode->pkt->pkt.signature->revkey) { int idx; PKT_signature *sig=onode->pkt->pkt.signature; for(idx=0;idxnumrevkeys;idx++) { u32 keyid[2]; keyid_from_fingerprint(sig->revkey[idx]->fpr, MAX_FINGERPRINT_LEN,keyid); for(inode=keyblock->next;inode;inode=inode->next) { /* If we reach user IDs, we're done. */ if(inode->pkt->pkttype==PKT_USER_ID) break; if(inode->pkt->pkttype==PKT_SIGNATURE && inode->pkt->pkt.signature->sig_class==0x20 && inode->pkt->pkt.signature->keyid[0]==keyid[0] && inode->pkt->pkt.signature->keyid[1]==keyid[1]) { /* Okay, we have a revocation key, and a revocation issued by it. Do we have the key itself? */ int rc; rc=get_pubkey_byfprint_fast (NULL,sig->revkey[idx]->fpr, MAX_FINGERPRINT_LEN); if(rc==G10ERR_NO_PUBKEY || rc==G10ERR_UNU_PUBKEY) { char *tempkeystr=xstrdup(keystr_from_pk(pk)); /* No, so try and get it */ if(opt.keyserver && (opt.keyserver_options.options & KEYSERVER_AUTO_KEY_RETRIEVE)) { log_info(_("WARNING: key %s may be revoked:" " fetching revocation key %s\n"), tempkeystr,keystr(keyid)); keyserver_import_fprint (ctrl, sig->revkey[idx]->fpr, MAX_FINGERPRINT_LEN, opt.keyserver); /* Do we have it now? */ rc=get_pubkey_byfprint_fast (NULL, sig->revkey[idx]->fpr, MAX_FINGERPRINT_LEN); } if(rc==G10ERR_NO_PUBKEY || rc==G10ERR_UNU_PUBKEY) log_info(_("WARNING: key %s may be revoked:" " revocation key %s not present.\n"), tempkeystr,keystr(keyid)); xfree(tempkeystr); } } } } } } } /**************** * compare and merge the blocks * * o compare the signatures: If we already have this signature, check * that they compare okay; if not, issue a warning and ask the user. * o Simply add the signature. Can't verify here because we may not have * the signature's public key yet; verification is done when putting it * into the trustdb, which is done automagically as soon as this pubkey * is used. * Note: We indicate newly inserted packets with flag bit 0 */ static int merge_blocks( const char *fname, KBNODE keyblock_orig, KBNODE keyblock, u32 *keyid, int *n_uids, int *n_sigs, int *n_subk ) { KBNODE onode, node; int rc, found; /* 1st: handle revocation certificates */ for(node=keyblock->next; node; node=node->next ) { if( node->pkt->pkttype == PKT_USER_ID ) break; else if( node->pkt->pkttype == PKT_SIGNATURE && node->pkt->pkt.signature->sig_class == 0x20 ) { /* check whether we already have this */ found = 0; for(onode=keyblock_orig->next; onode; onode=onode->next ) { if( onode->pkt->pkttype == PKT_USER_ID ) break; else if( onode->pkt->pkttype == PKT_SIGNATURE && onode->pkt->pkt.signature->sig_class == 0x20 && !cmp_signatures(onode->pkt->pkt.signature, node->pkt->pkt.signature)) { found = 1; break; } } if( !found ) { KBNODE n2 = clone_kbnode(node); insert_kbnode( keyblock_orig, n2, 0 ); n2->flag |= 1; ++*n_sigs; if(!opt.quiet) { char *p=get_user_id_native (keyid); log_info(_("key %s: \"%s\" revocation" " certificate added\n"), keystr(keyid),p); xfree(p); } } } } /* 2nd: merge in any direct key (0x1F) sigs */ for(node=keyblock->next; node; node=node->next ) { if( node->pkt->pkttype == PKT_USER_ID ) break; else if( node->pkt->pkttype == PKT_SIGNATURE && node->pkt->pkt.signature->sig_class == 0x1F ) { /* check whether we already have this */ found = 0; for(onode=keyblock_orig->next; onode; onode=onode->next ) { if( onode->pkt->pkttype == PKT_USER_ID ) break; else if( onode->pkt->pkttype == PKT_SIGNATURE && onode->pkt->pkt.signature->sig_class == 0x1F && !cmp_signatures(onode->pkt->pkt.signature, node->pkt->pkt.signature)) { found = 1; break; } } if( !found ) { KBNODE n2 = clone_kbnode(node); insert_kbnode( keyblock_orig, n2, 0 ); n2->flag |= 1; ++*n_sigs; if(!opt.quiet) log_info( _("key %s: direct key signature added\n"), keystr(keyid)); } } } /* 3rd: try to merge new certificates in */ for(onode=keyblock_orig->next; onode; onode=onode->next ) { if( !(onode->flag & 1) && onode->pkt->pkttype == PKT_USER_ID) { /* find the user id in the imported keyblock */ for(node=keyblock->next; node; node=node->next ) if( node->pkt->pkttype == PKT_USER_ID && !cmp_user_ids( onode->pkt->pkt.user_id, node->pkt->pkt.user_id ) ) break; if( node ) { /* found: merge */ rc = merge_sigs( onode, node, n_sigs, fname, keyid ); if( rc ) return rc; } } } /* 4th: add new user-ids */ for(node=keyblock->next; node; node=node->next ) { if( node->pkt->pkttype == PKT_USER_ID) { /* do we have this in the original keyblock */ for(onode=keyblock_orig->next; onode; onode=onode->next ) if( onode->pkt->pkttype == PKT_USER_ID && !cmp_user_ids( onode->pkt->pkt.user_id, node->pkt->pkt.user_id ) ) break; if( !onode ) { /* this is a new user id: append */ rc = append_uid( keyblock_orig, node, n_sigs, fname, keyid); if( rc ) return rc; ++*n_uids; } } } /* 5th: add new subkeys */ for(node=keyblock->next; node; node=node->next ) { onode = NULL; if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY ) { /* do we have this in the original keyblock? */ for(onode=keyblock_orig->next; onode; onode=onode->next ) if( onode->pkt->pkttype == PKT_PUBLIC_SUBKEY && !cmp_public_keys( onode->pkt->pkt.public_key, node->pkt->pkt.public_key ) ) break; if( !onode ) { /* this is a new subkey: append */ rc = append_key( keyblock_orig, node, n_sigs, fname, keyid); if( rc ) return rc; ++*n_subk; } } else if( node->pkt->pkttype == PKT_SECRET_SUBKEY ) { /* do we have this in the original keyblock? */ for(onode=keyblock_orig->next; onode; onode=onode->next ) if( onode->pkt->pkttype == PKT_SECRET_SUBKEY && !cmp_public_keys (onode->pkt->pkt.public_key, node->pkt->pkt.public_key) ) break; if( !onode ) { /* this is a new subkey: append */ rc = append_key( keyblock_orig, node, n_sigs, fname, keyid); if( rc ) return rc; ++*n_subk; } } } /* 6th: merge subkey certificates */ for(onode=keyblock_orig->next; onode; onode=onode->next ) { if( !(onode->flag & 1) && ( onode->pkt->pkttype == PKT_PUBLIC_SUBKEY || onode->pkt->pkttype == PKT_SECRET_SUBKEY) ) { /* find the subkey in the imported keyblock */ for(node=keyblock->next; node; node=node->next ) { if ((node->pkt->pkttype == PKT_PUBLIC_SUBKEY || node->pkt->pkttype == PKT_SECRET_SUBKEY) && !cmp_public_keys( onode->pkt->pkt.public_key, node->pkt->pkt.public_key ) ) break; } if( node ) { /* found: merge */ rc = merge_keysigs( onode, node, n_sigs, fname, keyid ); if( rc ) return rc; } } } return 0; } /**************** * append the userid starting with NODE and all signatures to KEYBLOCK. */ static int append_uid (KBNODE keyblock, KBNODE node, int *n_sigs, const char *fname, u32 *keyid ) { KBNODE n, n_where=NULL; (void)fname; (void)keyid; assert(node->pkt->pkttype == PKT_USER_ID ); /* find the position */ for( n = keyblock; n; n_where = n, n = n->next ) { if( n->pkt->pkttype == PKT_PUBLIC_SUBKEY || n->pkt->pkttype == PKT_SECRET_SUBKEY ) break; } if( !n ) n_where = NULL; /* and append/insert */ while( node ) { /* we add a clone to the original keyblock, because this * one is released first */ n = clone_kbnode(node); if( n_where ) { insert_kbnode( n_where, n, 0 ); n_where = n; } else add_kbnode( keyblock, n ); n->flag |= 1; node->flag |= 1; if( n->pkt->pkttype == PKT_SIGNATURE ) ++*n_sigs; node = node->next; if( node && node->pkt->pkttype != PKT_SIGNATURE ) break; } return 0; } /**************** * Merge the sigs from SRC onto DST. SRC and DST are both a PKT_USER_ID. * (how should we handle comment packets here?) */ static int merge_sigs( KBNODE dst, KBNODE src, int *n_sigs, const char *fname, u32 *keyid ) { KBNODE n, n2; int found=0; (void)fname; (void)keyid; assert(dst->pkt->pkttype == PKT_USER_ID ); assert(src->pkt->pkttype == PKT_USER_ID ); for(n=src->next; n && n->pkt->pkttype != PKT_USER_ID; n = n->next ) { if( n->pkt->pkttype != PKT_SIGNATURE ) continue; if( n->pkt->pkt.signature->sig_class == 0x18 || n->pkt->pkt.signature->sig_class == 0x28 ) continue; /* skip signatures which are only valid on subkeys */ found = 0; for(n2=dst->next; n2 && n2->pkt->pkttype != PKT_USER_ID; n2 = n2->next) if(!cmp_signatures(n->pkt->pkt.signature,n2->pkt->pkt.signature)) { found++; break; } if( !found ) { /* This signature is new or newer, append N to DST. * We add a clone to the original keyblock, because this * one is released first */ n2 = clone_kbnode(n); insert_kbnode( dst, n2, PKT_SIGNATURE ); n2->flag |= 1; n->flag |= 1; ++*n_sigs; } } return 0; } /**************** * Merge the sigs from SRC onto DST. SRC and DST are both a PKT_xxx_SUBKEY. */ static int merge_keysigs (KBNODE dst, KBNODE src, int *n_sigs, const char *fname, u32 *keyid) { KBNODE n, n2; int found=0; (void)fname; (void)keyid; assert( dst->pkt->pkttype == PKT_PUBLIC_SUBKEY || dst->pkt->pkttype == PKT_SECRET_SUBKEY ); for(n=src->next; n ; n = n->next ) { if( n->pkt->pkttype == PKT_PUBLIC_SUBKEY || n->pkt->pkttype == PKT_PUBLIC_KEY ) break; if( n->pkt->pkttype != PKT_SIGNATURE ) continue; found = 0; for(n2=dst->next; n2; n2 = n2->next){ if( n2->pkt->pkttype == PKT_PUBLIC_SUBKEY || n2->pkt->pkttype == PKT_PUBLIC_KEY ) break; if( n2->pkt->pkttype == PKT_SIGNATURE && n->pkt->pkt.signature->keyid[0] == n2->pkt->pkt.signature->keyid[0] && n->pkt->pkt.signature->keyid[1] == n2->pkt->pkt.signature->keyid[1] && n->pkt->pkt.signature->timestamp <= n2->pkt->pkt.signature->timestamp && n->pkt->pkt.signature->sig_class == n2->pkt->pkt.signature->sig_class ) { found++; break; } } if( !found ) { /* This signature is new or newer, append N to DST. * We add a clone to the original keyblock, because this * one is released first */ n2 = clone_kbnode(n); insert_kbnode( dst, n2, PKT_SIGNATURE ); n2->flag |= 1; n->flag |= 1; ++*n_sigs; } } return 0; } /* * Append the subkey starting with NODE and all signatures to KEYBLOCK. * Mark all new and copied packets by setting flag bit 0. */ static int append_key (KBNODE keyblock, KBNODE node, int *n_sigs, const char *fname, u32 *keyid) { KBNODE n; (void)fname; (void)keyid; assert( node->pkt->pkttype == PKT_PUBLIC_SUBKEY || node->pkt->pkttype == PKT_SECRET_SUBKEY ); while( node ) { /* we add a clone to the original keyblock, because this * one is released first */ n = clone_kbnode(node); add_kbnode( keyblock, n ); n->flag |= 1; node->flag |= 1; if( n->pkt->pkttype == PKT_SIGNATURE ) ++*n_sigs; node = node->next; if( node && node->pkt->pkttype != PKT_SIGNATURE ) break; } return 0; } diff --git a/g10/keygen.c b/g10/keygen.c index bbd02c517..50919fdaf 100644 --- a/g10/keygen.c +++ b/g10/keygen.c @@ -1,4455 +1,4497 @@ /* keygen.c - generate a key pair * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 * 2007, 2009, 2010, 2011 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 #include #include #include #include #include "gpg.h" #include "util.h" #include "main.h" #include "packet.h" #include "ttyio.h" #include "options.h" #include "keydb.h" #include "trustdb.h" #include "status.h" #include "i18n.h" #include "keyserver-internal.h" #include "call-agent.h" #include "pkglue.h" /* The default algorithms. If you change them remember to change them also in gpg.c:gpgconf_list. You should also check that the value is inside the bounds enforced by ask_keysize and gen_xxx. */ #define DEFAULT_STD_ALGO GCRY_PK_RSA #define DEFAULT_STD_KEYSIZE 2048 /* Flag bits used during key generation. */ #define KEYGEN_FLAG_NO_PROTECTION 1 #define KEYGEN_FLAG_TRANSIENT_KEY 2 /* 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 */ pSUBKEYEXPIRE, /* in n seconds */ pPASSPHRASE, pPASSPHRASE_DEK, pPASSPHRASE_S2K, pSERIALNO, pCARDBACKUPKEY, pHANDLE, pKEYSERVER }; struct para_data_s { struct para_data_s *next; int lnr; enum para_name key; union { DEK *dek; STRING2KEY *s2k; u32 expire; u32 creation; unsigned int usage; struct revocation_key revkey; char value[1]; } u; }; struct output_control_s { int lnr; int dryrun; int ask_passphrase; 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; }; 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 int mdc_available,ks_modify; static void do_generate_keypair( 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 algo, int keyno, int is_primary, kbnode_t pub_root, u32 *timestamp, u32 expireval); static int gen_card_key_with_backup (int algo, int keyno, int is_primary, kbnode_t pub_root, u32 timestamp, u32 expireval, struct para_data_s *para); 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; *p++ = ' '; fingerprint_from_pk (pk, array, &n); s = array; for (i=0; i < n ; i++, s++, p += 2) sprintf (p, "%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 void write_uid( KBNODE root, const char *s ) { PACKET *pkt = xmalloc_clear(sizeof *pkt ); size_t n = strlen(s); pkt->pkttype = PKT_USER_ID; pkt->pkt.user_id = xmalloc_clear( sizeof *pkt->pkt.user_id + n - 1 ); 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 ) ); } 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; } 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 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]; int nsym=0, nhash=0, nzip=0, val, rc=0; int mdc=1, modify=0; /* mdc defaults on, modify defaults off. */ char dummy_string[20*4+1]; /* Enough for 20 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 "); if ( !openpgp_cipher_test_algo (CIPHER_ALGO_CAST5) ) strcat(dummy_string,"S3 "); strcat(dummy_string,"S2 "); /* 3DES */ /* If we have it, IDEA goes *after* 3DES so it won't be used unless we're encrypting along with a V3 key. Ideally, we would only put the S1 preference in if the key was RSA and <=2048 bits, as that is what won't break PGP2, but that is difficult with the current code, and not really worth checking as a non-RSA <=2048 bit key wouldn't be usable by PGP2 anyway. -dms */ if (PGP2 && !openpgp_cipher_test_algo (CIPHER_ALGO_IDEA) ) strcat(dummy_string,"S1 "); /* The default hash algo order is: SHA-256, SHA-1, SHA-384, SHA-512, SHA-224. Ordering SHA-1 before SHA-384 might be viewed as a bit strange; it is done because we expect that soon enough SHA-3 will be available and at that point there should be no more need for SHA-384 etc. Anyway this order is just a default and can easily be changed by a config option. */ if (!openpgp_md_test_algo (DIGEST_ALGO_SHA256)) strcat (dummy_string, "H8 "); strcat (dummy_string, "H2 "); /* SHA-1 */ if (!openpgp_md_test_algo (DIGEST_ALGO_SHA384)) strcat (dummy_string, "H9 "); if (!openpgp_md_test_algo (DIGEST_ALGO_SHA512)) strcat (dummy_string, "H10 "); if (!openpgp_md_test_algo (DIGEST_ALGO_SHA224)) strcat (dummy_string, "H11 "); 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 compresssion. */ 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 *tok,*prefstring; prefstring=xstrdup(string); /* need a writable 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 (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(prefstring); } 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+nhash_prefs+nzip_prefs+1))); for(i=0;iprefs[j].type=PREFTYPE_SYM; uid->prefs[j].value=sym_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.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->hashed, 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_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->hashed, 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 (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_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]; buf[0] = revkey->class; buf[1] = revkey->algid; memcpy (&buf[2], revkey->fpr, MAX_FINGERPRINT_LEN); build_sig_subpkt (sig, SIGSUBPKT_REV_KEY, buf, 2+MAX_FINGERPRINT_LEN); /* 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 (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 (&backsig, pk, NULL, sub_pk, sub_psk, 0x19, 0, 0, timestamp, 0, NULL, NULL, cache_nonce); if (err) log_error ("make_keysig_packet failed for backsig: %s\n", g10_errstr(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); if (err) log_error ("build_packet failed for backsig: %s\n", g10_errstr(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 = buf[2] << 24; pktlen |= buf[3] << 16; pktlen |= buf[4] << 8; pktlen |= buf[5]; buf += 6; } else BUG (); } else { int mark = 1; switch (buf[0]&3) { case 3: BUG (); break; case 2: pktlen = buf[mark++] << 24; pktlen |= buf[mark++] << 16; case 1: pktlen |= buf[mark++] << 8; 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 (KBNODE 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 (&sig, pk, NULL,NULL, psk, 0x1F, 0, 0, timestamp, 0, keygen_add_revkey, revkey, cache_nonce); if (err) { log_error ("make_keysig_packet failed: %s\n", g10_errstr (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 (KBNODE 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 (&sig, pk, uid, NULL, psk, 0x13, 0, 0, timestamp, 0, keygen_add_std_prefs, pk, cache_nonce); if (err) { log_error ("make_keysig_packet failed: %s\n", g10_errstr (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 (KBNODE 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 (&sig, pri_pk, NULL, sub_pk, pri_psk, 0x18, 0, 0, timestamp, 0, keygen_add_key_flags_and_expire, &oduap, cache_nonce); if (err) { log_error ("make_keysig_packet failed: %s\n", g10_errstr (err)); return err; } /* Make a backsig. */ if (use & PUBKEY_USAGE_SIG) { err = make_backsig (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; 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); 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; l2 = gcry_sexp_find_token (list, "q", 0); if (!l2) { err = gpg_error (GPG_ERR_NO_OBJ); goto leave; } array[1] = gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG); gcry_sexp_release (l2); if (!array[1]) { err = gpg_error (GPG_ERR_INV_OBJ); 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: 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 = 4; if (expireval) pk->expiredate = pk->timestamp + expireval; pk->pubkey_algo = algo; - if (algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_ECDH) + 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 fucntion 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, char **cache_nonce_addr) { int err; PACKET *pkt; PKT_public_key *pk; gcry_sexp_t s_key; err = agent_genkey (NULL, cache_nonce_addr, keyparms, !!(keygen_flags & KEYGEN_FLAG_NO_PROTECTION), &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 = 4; if (expireval) pk->expiredate = pk->timestamp + expireval; pk->pubkey_algo = algo; - if (algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_ECDH) + 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, char **cache_nonce_addr) { int err; char *keyparms; char nbitsstr[35]; assert (is_ELGAMAL (algo)); if (nbits < 512) { nbits = 2048; 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, cache_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, char **cache_nonce_addr) { int err; unsigned int qbits; char *keyparms; char nbitsstr[35]; char qbitsstr[35]; if ( nbits < 512) { 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, cache_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, char **cache_nonce_addr) { gpg_error_t err; char *keyparms; - assert (algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_ECDH); + assert (algo == PUBKEY_ALGO_ECDSA + || algo == PUBKEY_ALGO_EDDSA + || algo == PUBKEY_ALGO_ECDH); if (!curve || !*curve) return gpg_error (GPG_ERR_UNKNOWN_CURVE); keyparms = xtryasprintf ("(genkey(ecc(curve %zu:%s)(flags nocomp%s%s)))", strlen (curve), curve, (((keygen_flags & KEYGEN_FLAG_TRANSIENT_KEY) && (keygen_flags & KEYGEN_FLAG_NO_PROTECTION))? " transient-key" : ""), (!strcmp (curve, "Ed25519")? " eddsa":"")); if (!keyparms) err = gpg_error_from_syserror (); else { err = common_gen (keyparms, algo, "", pub_root, timestamp, expireval, is_subkey, keygen_flags, cache_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, char **cache_nonce_addr) { int err; char *keyparms; char nbitsstr[35]; assert (is_RSA(algo)); if (!nbits) nbits = DEFAULT_STD_KEYSIZE; if (nbits < 1024) { nbits = 2048; 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, cache_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")); } /* Returns the key flags */ static unsigned int ask_key_flags(int algo,int subkey) { /* 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; unsigned int current=0; unsigned int possible=openpgp_pk_algo_usage(algo); if ( strlen(togglers) != 8 ) { tty_printf ("NOTE: Bad translation at %s:%d. " "Please report.\n", __FILE__, __LINE__); togglers = "11223300"; } /* Only primary keys may certify. */ if(subkey) possible&=~PUBKEY_USAGE_CERT; /* Preload the current set with the possible set, minus authentication, since nobody really uses auth yet. */ current=possible&~PUBKEY_USAGE_AUTH; for(;;) { tty_printf("\n"); tty_printf(_("Possible actions for a %s key: "), 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(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; } /* 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; + const char *algostr; if (hexgrip[0] == '&') hexgrip++; err = agent_readkey (ctrl, 0, hexgrip, &public); if (err) return 0; publiclen = gcry_sexp_canon_len (public, 0, NULL, NULL); - get_pk_algo_from_canon_sexp (public, publiclen, &algo); + get_pk_algo_from_canon_sexp (public, publiclen, &algostr); xfree (public); - switch (algo) - { - case GCRY_PK_RSA: return PUBKEY_ALGO_RSA; - case GCRY_PK_DSA: return PUBKEY_ALGO_DSA; - case GCRY_PK_ELG_E: return PUBKEY_ALGO_ELGAMAL_E; - case GCRY_PK_ECDH: return PUBKEY_ALGO_ECDH; - case GCRY_PK_ECDSA: return PUBKEY_ALGO_ECDSA; - default: return 0; - } + /* FIXME: Mapping of ECC algorithms is probably not correct. */ + if (!algostr) + return 0; + else if (!strcmp (algostr, "rsa")) + return PUBKEY_ALGO_RSA; + else if (!strcmp (algostr, "dsa")) + return PUBKEY_ALGO_DSA; + else if (!strcmp (algostr, "elg")) + return PUBKEY_ALGO_ELGAMAL_E; + else if (!strcmp (algostr, "ecc")) + return PUBKEY_ALGO_ECDH; + else if (!strcmp (algostr, "ecdsa")) + return PUBKEY_ALGO_ECDSA; + else if (!strcmp (algostr, "eddsa")) + return PUBKEY_ALGO_EDDSA; + else + return 0; } /* 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. */ static int ask_algo (ctrl_t ctrl, int addmode, int *r_subkey_algo, unsigned int *r_usage, char **r_keygrip) { char *keygrip = NULL; char *answer; 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 (!addmode) tty_printf (_(" (%d) RSA and RSA (default)\n"), 1 ); if (!addmode) tty_printf (_(" (%d) DSA and Elgamal\n"), 2 ); tty_printf (_(" (%d) DSA (sign only)\n"), 3 ); tty_printf (_(" (%d) RSA (sign only)\n"), 4 ); if (addmode) { tty_printf (_(" (%d) Elgamal (encrypt only)\n"), 5 ); tty_printf (_(" (%d) RSA (encrypt only)\n"), 6 ); } if (opt.expert) { tty_printf (_(" (%d) DSA (set your own capabilities)\n"), 7 ); tty_printf (_(" (%d) RSA (set your own capabilities)\n"), 8 ); } if (opt.expert && !addmode) - tty_printf (_(" (%d) ECDSA and ECDH\n"), 9 ); + tty_printf (_(" (%d) ECC\n"), 9 ); if (opt.expert) - tty_printf (_(" (%d) ECDSA (sign only)\n"), 10 ); + tty_printf (_(" (%d) ECC (sign only)\n"), 10 ); if (opt.expert) - tty_printf (_(" (%d) ECDSA (set your own capabilities)\n"), 11 ); + tty_printf (_(" (%d) ECC (set your own capabilities)\n"), 11 ); if (opt.expert && addmode) - tty_printf (_(" (%d) ECDH (encrypt only)\n"), 12 ); + tty_printf (_(" (%d) ECC (encrypt only)\n"), 12 ); if (opt.expert && r_keygrip) tty_printf (_(" (%d) Existing key\n"), 13 ); for (;;) { *r_usage = 0; *r_subkey_algo = 0; answer = cpr_get ("keygen.algo", _("Your selection? ")); cpr_kill_prompt (); algo = *answer? atoi (answer) : 1; xfree(answer); answer = NULL; if (algo == 1 && !addmode) { algo = PUBKEY_ALGO_RSA; *r_subkey_algo = PUBKEY_ALGO_RSA; break; } else if (algo == 2 && !addmode) { algo = PUBKEY_ALGO_DSA; *r_subkey_algo = PUBKEY_ALGO_ELGAMAL_E; break; } else if (algo == 3) { algo = PUBKEY_ALGO_DSA; *r_usage = PUBKEY_USAGE_SIG; break; } else if (algo == 4) { algo = PUBKEY_ALGO_RSA; *r_usage = PUBKEY_USAGE_SIG; break; } else if (algo == 5 && addmode) { algo = PUBKEY_ALGO_ELGAMAL_E; *r_usage = PUBKEY_USAGE_ENC; break; } else if (algo == 6 && addmode) { algo = PUBKEY_ALGO_RSA; *r_usage = PUBKEY_USAGE_ENC; break; } else if (algo == 7 && opt.expert) { algo = PUBKEY_ALGO_DSA; *r_usage = ask_key_flags (algo, addmode); break; } else if (algo == 8 && opt.expert) { algo = PUBKEY_ALGO_RSA; *r_usage = ask_key_flags (algo, addmode); break; } else if (algo == 9 && opt.expert && !addmode) { algo = PUBKEY_ALGO_ECDSA; *r_subkey_algo = PUBKEY_ALGO_ECDH; break; } else if (algo == 10 && opt.expert) { algo = PUBKEY_ALGO_ECDSA; *r_usage = PUBKEY_USAGE_SIG; break; } else if (algo == 11 && opt.expert) { algo = PUBKEY_ALGO_ECDSA; *r_usage = ask_key_flags (algo, addmode); break; } else if (algo == 12 && opt.expert && addmode) { algo = PUBKEY_ALGO_ECDH; *r_usage = PUBKEY_USAGE_ENC; break; } else if (algo == 13 && 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); break; } else tty_printf (_("Invalid selection.\n")); } if (r_keygrip) *r_keygrip = keygrip; return algo; } /* 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, min, def = DEFAULT_STD_KEYSIZE, max=4096; int for_subkey = !!primary_keysize; int autocomp = 0; if(opt.expert) min=512; else min=1024; 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; } switch(algo) { case PUBKEY_ALGO_DSA: def=2048; max=3072; break; case PUBKEY_ALGO_ECDSA: case PUBKEY_ALGO_ECDH: min=256; def=256; max=521; break; + case PUBKEY_ALGO_EDDSA: + min=255; + def=255; + max=441; + break; + case PUBKEY_ALGO_RSA: min=1024; break; } 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: if (algo == PUBKEY_ALGO_DSA && (nbits % 64)) { nbits = ((nbits + 63) / 64) * 64; if (!autocomp) 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 (!autocomp) + 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 (!autocomp) tty_printf (_("rounded to %u bits\n"), nbits); } } else if ((nbits % 32)) { nbits = ((nbits + 31) / 32) * 32; if (!autocomp) 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 char * ask_curve (void) { struct { const char *name; int available; int expert_only; const char *pretty_name; } curves[] = { { "Ed25519", 0, 0, "Curve 25519" }, { "NIST P-256", 0, 1, }, { "NIST P-384", 0, 0, }, { "NIST P-521", 0, 1, }, { "brainpoolP256r1", 0, 1, "Brainpool P-256" }, { "brainpoolP384r1", 0, 1, "Brainpool P-384" }, { "brainpoolP512r1", 0, 1, "Brainpool P-512" }, { "secp256k1", 0, 1 }, }; int idx; char *answer; 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 (!opt.expert && curves[idx].expert_only) continue; 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 && !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 { result = xstrdup (curves[idx].name); break; } } if (!result) result = xstrdup (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) 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; } /* Parsean 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=make_timestamp(); xfree(answer); if(object==0) answer = cpr_get("keygen.valid",_("Key is valid for? (0) ")); else { char *prompt; #define PROMPTSTRING _("Signature is valid for? (%s) ") /* This will actually end up larger than necessary because of the 2 bytes for '%s' */ prompt=xmalloc(strlen(PROMPTSTRING)+strlen(def_expire)+1); sprintf(prompt,PROMPTSTRING,def_expire); #undef PROMPTSTRING answer = cpr_get("siggen.valid",prompt); xfree(prompt); if(*answer=='\0') answer=xstrdup(def_expire); } cpr_kill_prompt(); trim_spaces(answer); 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; } /* 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. */ static char * ask_user_id (int mode, 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 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")); else if( digitp(aname) ) tty_printf(_("Name may not start with a digit\n")); else if( strlen(aname) < 5 ) tty_printf(_("Name must be at least 5 characters long\n")); 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 ) { 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; } } xfree(uid); uid = p = xmalloc(strlen(aname)+strlen(amail)+strlen(acomment)+12+10); 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) { PKT_user_id *uidpkt = uid_from_string (uid); KBNODE node; for (node=keyblock; node && !fail; node=node->next) if (!is_deleted_kbnode (node) && node->pkt->pkttype == PKT_USER_ID && !cmp_user_ids (uidpkt, node->pkt->pkt.user_id)) fail = 1; if (fail) tty_printf (_("Such a user ID already exists on this key!\n")); free_user_id (uidpkt); } 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 { 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(); } 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 && !amail ) break; xfree(uid); uid = NULL; } if( uid ) { char *p = native_to_utf8( uid ); xfree( uid ); uid = p; } return uid; } /* MODE 0 - standard 1 - Ask for passphrase of the card backup key. */ static DEK * do_ask_passphrase (STRING2KEY **ret_s2k, int mode, int *r_canceled) { DEK *dek = NULL; STRING2KEY *s2k; const char *errtext = NULL; const char *custdesc = NULL; tty_printf(_("You need a Passphrase to protect your secret key.\n\n") ); if (mode == 1) custdesc = _("Please enter a passphrase to protect the off-card " "backup of the new encryption key."); s2k = xmalloc_secure( sizeof *s2k ); for(;;) { s2k->mode = opt.s2k_mode; s2k->hash_algo = S2K_DIGEST_ALGO; dek = passphrase_to_dek_ext (NULL, 0, opt.s2k_cipher_algo, s2k, 2, errtext, custdesc, NULL, r_canceled); if (!dek && *r_canceled) { xfree(dek); dek = NULL; xfree(s2k); s2k = NULL; break; } else if( !dek ) { errtext = N_("passphrase not correctly repeated; try again"); tty_printf(_("%s.\n"), _(errtext)); } else if( !dek->keylen ) { xfree(dek); dek = NULL; xfree(s2k); s2k = NULL; tty_printf(_( "You don't want a passphrase - this is probably a *bad* idea!\n" "I will do it anyway. You can change your passphrase at any time,\n" "using this program with the option \"--edit-key\".\n\n")); break; } else break; /* okay */ } *ret_s2k = s2k; return dek; } /* 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 pub_root, u32 timestamp, u32 expiredate, int is_subkey, int keygen_flags, char **cache_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, cache_nonce_addr); else if (algo == PUBKEY_ALGO_DSA) err = gen_dsa (nbits, pub_root, timestamp, expiredate, is_subkey, keygen_flags, cache_nonce_addr); - else if (algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_ECDH) + 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, cache_nonce_addr); else if (algo == PUBKEY_ALGO_RSA) err = gen_rsa (algo, nbits, pub_root, timestamp, expiredate, is_subkey, keygen_flags, cache_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. */ PKT_user_id * generate_user_id (KBNODE keyblock) { char *p; p = ask_user_id (1, keyblock); if (!p) return NULL; /* Canceled. */ return uid_from_string (p); } /* Append R to the linked list PARA. */ static void append_to_parameter (struct para_data_s *para, struct para_data_s *r) { 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_DEK) xfree (r->u.dek); else if (r->key == pPASSPHRASE_S2K ) xfree (r->u.s2k); 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; } static int get_parameter_algo( 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; if (!ascii_strcasecmp (r->u.value, "default")) { /* Note: If you change this default algo, remember to change it also in gpg.c:gpgconf_list. */ i = DEFAULT_STD_ALGO; 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 = GCRY_PK_ELG_E; else i = map_pk_gcry_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 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 ); char *p, *pn; unsigned int use; if( !r ) return 0; /* none (this is an optional parameter)*/ use = 0; pn = r->u.value; while ( (p = strsep (&pn, " \t,")) ) { if ( !*p) ; else if ( !ascii_strcasecmp (p, "sign") ) use |= PUBKEY_USAGE_SIG; else if ( !ascii_strcasecmp (p, "encrypt") ) use |= PUBKEY_USAGE_ENC; else if ( !ascii_strcasecmp (p, "auth") ) use |= PUBKEY_USAGE_AUTH; else { log_error("%s:%d: invalid usage list\n", fname, r->lnr ); return -1; /* error */ } } r->u.usage = use; 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 ) 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 proc_parameter_file( 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 (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 (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 ) p = stpcpy(stpcpy(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,NULL,0); if(spec) { free_keyserver_spec(spec); opt.def_keyserver_url=s1; } else { 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 DEK and S2K from the Passphrase. */ if (outctrl->ask_passphrase) { /* %ask-passphrase is active - ignore pPASSPRASE and ask. This feature is required so that GUIs are able to do a key creation but have gpg-agent ask for the passphrase. */ int canceled = 0; STRING2KEY *s2k; DEK *dek; dek = do_ask_passphrase (&s2k, 0, &canceled); if (dek) { r = xmalloc_clear( sizeof *r ); r->key = pPASSPHRASE_DEK; r->u.dek = dek; append_to_parameter (para, r); r = xmalloc_clear( sizeof *r ); r->key = pPASSPHRASE_S2K; r->u.s2k = s2k; append_to_parameter (para, r); } if (canceled) { log_error ("%s:%d: key generation canceled\n", fname, r->lnr ); return -1; } } else { r = get_parameter( para, pPASSPHRASE ); if ( r && *r->u.value ) { /* We have a plain text passphrase - create a DEK from it. * It is a little bit ridiculous to keep it in secure memory * but because we do this always, why not here. */ STRING2KEY *s2k; DEK *dek; s2k = xmalloc ( sizeof *s2k ); s2k->mode = opt.s2k_mode; s2k->hash_algo = S2K_DIGEST_ALGO; set_next_passphrase ( r->u.value ); dek = passphrase_to_dek (NULL, 0, opt.s2k_cipher_algo, s2k, 2, NULL, NULL); if (!dek) { log_error ("%s:%d: error post processing the passphrase\n", fname, r->lnr ); xfree (s2k); return -1; } set_next_passphrase (NULL); memset (r->u.value, 0, strlen(r->u.value)); r = xmalloc_clear (sizeof *r); r->key = pPASSPHRASE_S2K; r->u.s2k = s2k; append_to_parameter (para, r); r = xmalloc_clear (sizeof *r); r->key = pPASSPHRASE_DEK; r->u.dek = dek; append_to_parameter (para, r); } } /* Make KEYCREATIONDATE from Creation-Date. */ r = get_parameter (para, pCREATIONDATE); if (r && *r->u.value) { 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( 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( 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 }, { 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" ) ) outctrl.ask_passphrase = 1; else if( !ascii_strcasecmp( keyword, "%no-ask-passphrase" ) ) outctrl.ask_passphrase = 0; 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( 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( 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; } } 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( 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 ); } release_parameter_list( para ); iobuf_close (fp); release_armor_context (outctrl.pub.afx); } /* * 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. */ void generate_keypair (ctrl_t ctrl, const char *fname, const char *card_serialno, int card_backup_key) { 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; memset( &outctrl, 0, sizeof( outctrl ) ); if (opt.batch && card_serialno) { /* We don't yet support unattended key generation. */ log_error (_("can't do this in batch mode\n")); return; } if (opt.batch) { read_parameter_file( fname ); return; } if (card_serialno) { #ifdef ENABLE_CARD_SUPPORT r = xcalloc (1, sizeof *r + strlen (card_serialno) ); r->key = pSERIALNO; strcpy( r->u.value, card_serialno); r->next = para; para = r; algo = PUBKEY_ALGO_RSA; r = xcalloc (1, sizeof *r + 20 ); r->key = pKEYTYPE; sprintf( r->u.value, "%d", 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", 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; r = xcalloc (1, sizeof *r + 20 ); r->key = pAUTHKEYTYPE; sprintf( r->u.value, "%d", 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 { int subkey_algo; char *curve = NULL; /* Fixme: To support creating a primary key by keygrip we better also define the keyword for the parameter file. Note that the subkey case will never be asserted if a keygrip has been given. */ algo = ask_algo (ctrl, 0, &subkey_algo, &use, NULL); if (subkey_algo) { /* Create primary and subkey at once. */ both = 1; r = xmalloc_clear( sizeof *r + 20 ); r->key = pKEYTYPE; sprintf( r->u.value, "%d", algo ); r->next = para; para = r; - if (algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_ECDH) + if (algo == PUBKEY_ALGO_ECDSA + || algo == PUBKEY_ALGO_EDDSA + || algo == PUBKEY_ALGO_ECDH) { curve = ask_curve (); + nbits = 0; r = xmalloc_clear (sizeof *r + strlen (curve)); r->key = pKEYCURVE; strcpy (r->u.value, curve); r->next = para; para = r; } else { 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; } else { 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_ECDH) + if (algo == PUBKEY_ALGO_ECDSA + || algo == PUBKEY_ALGO_EDDSA + || algo == PUBKEY_ALGO_ECDH) { if (!both) curve = ask_curve (); r = xmalloc_clear (sizeof *r + strlen (curve)); r->key = both? pSUBKEYCURVE : pKEYCURVE; strcpy (r->u.value, curve); r->next = para; para = r; } 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; } xfree (curve); } expire = ask_expire_interval(0,NULL); r = xmalloc_clear( sizeof *r + 20 ); r->key = pKEYEXPIRE; r->u.expire = expire; r->next = para; para = r; r = xmalloc_clear( sizeof *r + 20 ); r->key = pSUBKEYEXPIRE; r->u.expire = expire; r->next = para; para = r; uid = ask_user_id (0, NULL); if( !uid ) { log_error(_("Key generation canceled.\n")); release_parameter_list( para ); return; } r = xmalloc_clear( sizeof *r + strlen(uid) ); r->key = pUSERID; strcpy( r->u.value, uid ); r->next = para; para = r; proc_parameter_file( para, "[internal]", &outctrl, !!card_serialno); release_parameter_list( para ); } #if 0 /* not required */ /* Generate a raw key and return it as a secret key packet. The function will ask for the passphrase and return a protected as well as an unprotected copy of a new secret key packet. 0 is returned on success and the caller must then free the returned values. */ static int generate_raw_key (int algo, unsigned int nbits, u32 created_at, PKT_secret_key **r_sk_unprotected, PKT_secret_key **r_sk_protected) { int rc; DEK *dek = NULL; STRING2KEY *s2k = NULL; PKT_secret_key *sk = NULL; int i; size_t nskey, npkey; gcry_sexp_t s_parms, s_key; int canceled; npkey = pubkey_get_npkey (algo); nskey = pubkey_get_nskey (algo); assert (nskey <= PUBKEY_MAX_NSKEY && npkey < nskey); if (nbits < 512) { nbits = 512; 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 ); } dek = do_ask_passphrase (&s2k, 1, &canceled); if (canceled) { rc = gpg_error (GPG_ERR_CANCELED); goto leave; } sk = xmalloc_clear (sizeof *sk); sk->timestamp = created_at; sk->version = 4; sk->pubkey_algo = algo; if ( !is_RSA (algo) ) { log_error ("only RSA is supported for offline generated keys\n"); rc = gpg_error (GPG_ERR_NOT_IMPLEMENTED); goto leave; } rc = gcry_sexp_build (&s_parms, NULL, "(genkey(rsa(nbits %d)))", (int)nbits); if (rc) log_bug ("gcry_sexp_build failed: %s\n", gpg_strerror (rc)); rc = gcry_pk_genkey (&s_key, s_parms); gcry_sexp_release (s_parms); if (rc) { log_error ("gcry_pk_genkey failed: %s\n", gpg_strerror (rc) ); goto leave; } rc = key_from_sexp (sk->skey, s_key, "private-key", "nedpqu"); gcry_sexp_release (s_key); if (rc) { log_error ("key_from_sexp failed: %s\n", gpg_strerror (rc) ); goto leave; } for (i=npkey; i < nskey; i++) sk->csum += checksum_mpi (sk->skey[i]); if (r_sk_unprotected) *r_sk_unprotected = copy_secret_key (NULL, sk); rc = genhelp_protect (dek, s2k, sk); if (rc) goto leave; if (r_sk_protected) { *r_sk_protected = sk; sk = NULL; } leave: if (sk) free_secret_key (sk); xfree (dek); xfree (s2k); return rc; } #endif /* ENABLE_CARD_SUPPORT */ /* 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); } static void do_generate_keypair (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 timestamp; char *cache_nonce = NULL; 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 ); 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); } } 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); timestamp = get_parameter_u32 (para, pKEYCREATIONDATE); if (!timestamp) timestamp = make_timestamp (); /* 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. */ if (!card) err = do_create (get_parameter_algo( para, pKEYTYPE, NULL ), get_parameter_uint( para, pKEYLENGTH ), get_parameter_value (para, pKEYCURVE), pub_root, timestamp, get_parameter_u32( para, pKEYEXPIRE ), 0, outctrl->keygen_flags, &cache_nonce); else err = gen_card_key (PUBKEY_ALGO_RSA, 1, 1, pub_root, ×tamp, get_parameter_u32 (para, pKEYEXPIRE)); /* Get the pointer to the generated public key packet. */ if (!err) { pri_psk = pub_root->next->pkt->pkt.public_key; assert (pri_psk); } if (!err && (revkey = get_parameter_revkey (para, pREVOKER))) err = write_direct_sig (pub_root, pri_psk, revkey, timestamp, cache_nonce); if (!err && (s = get_parameter_value (para, pUSERID))) { write_uid (pub_root, s ); err = write_selfsigs (pub_root, pri_psk, get_parameter_uint (para, pKEYUSAGE), timestamp, 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 (PUBKEY_ALGO_RSA, 3, 0, pub_root, ×tamp, get_parameter_u32 (para, pKEYEXPIRE)); if (!err) err = write_keybinding (pub_root, pri_psk, NULL, PUBKEY_USAGE_AUTH, timestamp, cache_nonce); } if (!err && get_parameter (para, pSUBKEYTYPE)) { sub_psk = NULL; if (!card) { err = do_create (get_parameter_algo (para, pSUBKEYTYPE, NULL), get_parameter_uint (para, pSUBKEYLENGTH), get_parameter_value (para, pSUBKEYCURVE), pub_root, timestamp, get_parameter_u32 (para, pSUBKEYEXPIRE), 1, outctrl->keygen_flags, &cache_nonce); /* 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; assert (sub_psk); } } else { if ((s = get_parameter_value (para, pCARDBACKUPKEY))) { /* A backup of the encryption key has been requested. Generate the key in software and import it then to the card. Write a backup file. */ err = gen_card_key_with_backup (PUBKEY_ALGO_RSA, 2, 0, pub_root, timestamp, get_parameter_u32 (para, pKEYEXPIRE), para); } else { err = gen_card_key (PUBKEY_ALGO_RSA, 2, 0, pub_root, ×tamp, get_parameter_u32 (para, pKEYEXPIRE)); } } if (!err) err = write_keybinding (pub_root, pri_psk, sub_psk, get_parameter_uint (para, pSUBKEYUSAGE), timestamp, 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", g10_errstr (err)); } else if (!err) /* Write to the standard keyrings. */ { KEYDB_HANDLE pub_hd = keydb_new (); err = keydb_locate_writable (pub_hd, NULL); if (err) log_error (_("no writable public keyring found: %s\n"), g10_errstr (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), g10_errstr(err)); } keydb_release (pub_hd); if (!err) { int no_enc_rsa; PKT_public_key *pk; no_enc_rsa = ((get_parameter_algo (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 (pk, ((get_ownertrust (pk) & ~TRUST_MASK) | TRUST_ULTIMATE )); if (!opt.batch) { tty_printf (_("public and secret key created and signed.\n") ); tty_printf ("\n"); list_keyblock (pub_root, 0, 1, NULL); } if (!opt.batch && (get_parameter_algo (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", g10_errstr(err) ); else tty_printf (_("Key generation failed: %s\n"), g10_errstr(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); } /* Add a new subkey to an existing key. Returns 0 if a new key has been generated and put into the keyblocks. */ gpg_error_t generate_subkeypair (ctrl_t ctrl, kbnode_t keyblock) { gpg_error_t err = 0; 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; char *curve = NULL; u32 cur_time; char *hexgrip = NULL; char *serialno = NULL; /* 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)) { tty_printf (_("Secret parts of primary key are not available.\n")); goto leave; } if (serialno) tty_printf (_("Secret parts of primary key are stored on-card.\n")); xfree (hexgrip); hexgrip = NULL; algo = ask_algo (ctrl, 1, NULL, &use, &hexgrip); assert (algo); if (hexgrip) nbits = 0; - else if (algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_ECDH) + else if (algo == PUBKEY_ALGO_ECDSA + || algo == PUBKEY_ALGO_EDDSA + || algo == PUBKEY_ALGO_ECDH) curve = ask_curve (); 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; } if (hexgrip) err = do_create_from_keygrip (ctrl, algo, hexgrip, keyblock, cur_time, expire, 1); else err = do_create (algo, nbits, curve, keyblock, cur_time, expire, 1, 0, NULL); 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 (keyblock, pri_psk, sub_psk, use, cur_time, NULL); if (err) goto leave; write_status_text (STATUS_KEY_CREATED, "S"); leave: xfree (curve); xfree (hexgrip); xfree (serialno); if (err) log_error (_("Key generation failed: %s\n"), g10_errstr (err) ); return err; } #ifdef ENABLE_CARD_SUPPORT /* Generate a subkey on a card. */ gpg_error_t generate_card_subkeypair (kbnode_t pub_keyblock, int keyno, const char *serialno) { gpg_error_t err = 0; kbnode_t node; PKT_public_key *pri_pk = NULL; int algo; unsigned int use; u32 expire; u32 cur_time; struct para_data_s *para = NULL; assert (keyno >= 1 && keyno <= 3); 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; publkic 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; } algo = PUBKEY_ALGO_RSA; 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 (algo, keyno, 0, pub_keyblock, &cur_time, expire); /* Get the pointer to the generated public subkey packet. */ if (!err) { PKT_public_key *sub_pk = NULL; for (node = pub_keyblock; node; node = node->next) if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY) sub_pk = node->pkt->pkt.public_key; assert (sub_pk); err = write_keybinding (pub_keyblock, pri_pk, sub_pk, use, cur_time, NULL); } leave: if (err) log_error (_("Key generation failed: %s\n"), g10_errstr(err) ); else write_status_text (STATUS_KEY_CREATED, "S"); 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, g10_errstr(rc) ); return rc; } } } return 0; } /* Note that timestamp is an in/out arg. */ static gpg_error_t gen_card_key (int algo, int keyno, int is_primary, kbnode_t pub_root, u32 *timestamp, u32 expireval) { #ifdef ENABLE_CARD_SUPPORT gpg_error_t err; struct agent_card_genkey_s info; PACKET *pkt; PKT_public_key *pk; if (algo != PUBKEY_ALGO_RSA) return gpg_error (GPG_ERR_PUBKEY_ALGO); 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 (&info, keyno, 1, NULL, *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 (&info, keyno, 1); * } */ if (!err && (!info.n || !info.e)) { log_error ("communication error with SCD\n"); gcry_mpi_release (info.n); gcry_mpi_release (info.e); err = gpg_error (GPG_ERR_GENERAL); } if (err) { log_error ("key generation failed: %s\n", gpg_strerror (err)); xfree (pkt); xfree (pk); return err; } if (*timestamp != info.created_at) log_info ("NOTE: the key does not use the suggested creation date\n"); *timestamp = info.created_at; pk->timestamp = info.created_at; pk->version = 4; if (expireval) pk->expiredate = pk->timestamp + expireval; pk->pubkey_algo = algo; pk->pkey[0] = info.n; pk->pkey[1] = info.e; 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 return gpg_error (GPG_ERR_NOT_SUPPORTED); #endif /*!ENABLE_CARD_SUPPORT*/ } static int gen_card_key_with_backup (int algo, int keyno, int is_primary, KBNODE pub_root, u32 timestamp, u32 expireval, struct para_data_s *para) { #if 0 /* FIXME: Move this to gpg-agent. */ int rc; const char *s; PACKET *pkt; PKT_secret_key *sk, *sk_unprotected = NULL, *sk_protected = NULL; PKT_public_key *pk; size_t n; int i; unsigned int nbits; /* Get the size of the key directly from the card. */ { struct agent_card_info_s info; memset (&info, 0, sizeof info); if (!agent_scd_getattr ("KEY-ATTR", &info) && info.key_attr[1].algo) nbits = info.key_attr[1].nbits; else nbits = 1024; /* All pre-v2.0 cards. */ agent_release_card_info (&info); } /* Create a key of this size in memory. */ rc = generate_raw_key (algo, nbits, timestamp, &sk_unprotected, &sk_protected); if (rc) return rc; /* Store the key to the card. */ rc = save_unprotected_key_to_card (sk_unprotected, keyno); if (rc) { log_error (_("storing key onto card failed: %s\n"), g10_errstr (rc)); free_secret_key (sk_unprotected); free_secret_key (sk_protected); write_status_errcode ("save_key_to_card", rc); return rc; } /* Get rid of the secret key parameters and store the serial numer. */ sk = sk_unprotected; n = pubkey_get_nskey (sk->pubkey_algo); for (i=pubkey_get_npkey (sk->pubkey_algo); i < n; i++) { gcry_mpi_release (sk->skey[i]); sk->skey[i] = NULL; } i = pubkey_get_npkey (sk->pubkey_algo); sk->skey[i] = gcry_mpi_set_opaque (NULL, xstrdup ("dummydata"), 10*8); sk->is_protected = 1; sk->protect.s2k.mode = 1002; s = get_parameter_value (para, pSERIALNO); assert (s); for (sk->protect.ivlen=0; sk->protect.ivlen < 16 && *s && s[1]; sk->protect.ivlen++, s += 2) sk->protect.iv[sk->protect.ivlen] = xtoi_2 (s); /* Now write the *protected* secret key to the file. */ { char name_buffer[50]; char *fname; IOBUF fp; mode_t oldmask; keyid_from_sk (sk, NULL); snprintf (name_buffer, sizeof name_buffer, "sk_%08lX%08lX.gpg", (ulong)sk->keyid[0], (ulong)sk->keyid[1]); fname = make_filename (backup_dir, name_buffer, NULL); oldmask = umask (077); if (is_secured_filename (fname)) { fp = NULL; gpg_err_set_errno (EPERM); } else fp = iobuf_create (fname); umask (oldmask); if (!fp) { rc = gpg_error_from_syserror (); log_error (_("can't create backup file '%s': %s\n"), fname, strerror(errno) ); xfree (fname); free_secret_key (sk_unprotected); free_secret_key (sk_protected); return rc; } pkt = xcalloc (1, sizeof *pkt); pkt->pkttype = PKT_SECRET_KEY; pkt->pkt.secret_key = sk_protected; sk_protected = NULL; rc = build_packet (fp, pkt); if (rc) { log_error("build packet failed: %s\n", g10_errstr(rc) ); iobuf_cancel (fp); } else { unsigned char array[MAX_FINGERPRINT_LEN]; char *fprbuf, *p; 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); fingerprint_from_sk (sk, array, &n); p = fprbuf = xmalloc (MAX_FINGERPRINT_LEN*2 + 1 + 1); for (i=0; i < n ; i++, p += 2) sprintf (p, "%02X", array[i]); *p++ = ' '; *p = 0; write_status_text_and_buffer (STATUS_BACKUP_KEY_CREATED, fprbuf, fname, strlen (fname), 0); xfree (fprbuf); } free_packet (pkt); xfree (pkt); xfree (fname); if (rc) { free_secret_key (sk_unprotected); return rc; } } /* Create the public key from the secret key. */ pk = xcalloc (1, sizeof *pk ); pk->timestamp = sk->timestamp; pk->version = sk->version; if (expireval) pk->expiredate = sk->expiredate = sk->timestamp + expireval; pk->pubkey_algo = sk->pubkey_algo; n = pubkey_get_npkey (sk->pubkey_algo); for (i=0; i < n; i++) pk->pkey[i] = mpi_copy (sk->skey[i]); /* Build packets and add them to the node lists. */ pkt = xcalloc (1,sizeof *pkt); pkt->pkttype = is_primary ? PKT_PUBLIC_KEY : PKT_PUBLIC_SUBKEY; pkt->pkt.public_key = pk; add_kbnode(pub_root, new_kbnode( pkt )); pkt = xcalloc (1,sizeof *pkt); pkt->pkttype = is_primary ? PKT_SECRET_KEY : PKT_SECRET_SUBKEY; pkt->pkt.secret_key = sk; add_kbnode(sec_root, new_kbnode( pkt )); return 0; #else return gpg_error (GPG_ERR_NOT_SUPPORTED); #endif /*!ENABLE_CARD_SUPPORT*/ } #if 0 int save_unprotected_key_to_card (PKT_public_key *sk, int keyno) { int rc; unsigned char *rsa_n = NULL; unsigned char *rsa_e = NULL; unsigned char *rsa_p = NULL; unsigned char *rsa_q = NULL; size_t rsa_n_len, rsa_e_len, rsa_p_len, rsa_q_len; unsigned char *sexp = NULL; unsigned char *p; char numbuf[55], numbuf2[50]; assert (is_RSA (sk->pubkey_algo)); assert (!sk->is_protected); /* Copy the parameters into straight buffers. */ gcry_mpi_aprint (GCRYMPI_FMT_USG, &rsa_n, &rsa_n_len, sk->skey[0]); gcry_mpi_aprint (GCRYMPI_FMT_USG, &rsa_e, &rsa_e_len, sk->skey[1]); gcry_mpi_aprint (GCRYMPI_FMT_USG, &rsa_p, &rsa_p_len, sk->skey[3]); gcry_mpi_aprint (GCRYMPI_FMT_USG, &rsa_q, &rsa_q_len, sk->skey[4]); if (!rsa_n || !rsa_e || !rsa_p || !rsa_q) { rc = G10ERR_INV_ARG; goto leave; } /* Put the key into an S-expression. */ sexp = p = xmalloc_secure (30 + rsa_n_len + rsa_e_len + rsa_p_len + rsa_q_len + 4*sizeof (numbuf) + 25 + sizeof(numbuf) + 20); p = stpcpy (p,"(11:private-key(3:rsa(1:n"); sprintf (numbuf, "%u:", (unsigned int)rsa_n_len); p = stpcpy (p, numbuf); memcpy (p, rsa_n, rsa_n_len); p += rsa_n_len; sprintf (numbuf, ")(1:e%u:", (unsigned int)rsa_e_len); p = stpcpy (p, numbuf); memcpy (p, rsa_e, rsa_e_len); p += rsa_e_len; sprintf (numbuf, ")(1:p%u:", (unsigned int)rsa_p_len); p = stpcpy (p, numbuf); memcpy (p, rsa_p, rsa_p_len); p += rsa_p_len; sprintf (numbuf, ")(1:q%u:", (unsigned int)rsa_q_len); p = stpcpy (p, numbuf); memcpy (p, rsa_q, rsa_q_len); p += rsa_q_len; p = stpcpy (p,"))(10:created-at"); sprintf (numbuf2, "%lu", (unsigned long)sk->timestamp); sprintf (numbuf, "%lu:", (unsigned long)strlen (numbuf2)); p = stpcpy (stpcpy (stpcpy (p, numbuf), numbuf2), "))"); /* Fixme: Unfortunately we don't have the serialnumber available - thus we can't pass it down to the agent. */ rc = agent_scd_writekey (keyno, NULL, sexp, p - sexp); leave: xfree (sexp); xfree (rsa_n); xfree (rsa_e); xfree (rsa_p); xfree (rsa_q); return rc; } #endif /*ENABLE_CARD_SUPPORT*/ diff --git a/g10/keyid.c b/g10/keyid.c index d08cceeb2..5fa44ef9c 100644 --- a/g10/keyid.c +++ b/g10/keyid.c @@ -1,799 +1,801 @@ /* keyid.c - key ID and fingerprint handling * Copyright (C) 1998, 1999, 2000, 2001, 2003, * 2004, 2006, 2010 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 #include #include "gpg.h" #include "util.h" #include "main.h" #include "packet.h" #include "options.h" #include "keydb.h" #include "i18n.h" #include "rmd160.h" #define KEYID_STR_SIZE 19 #ifdef HAVE_UNSIGNED_TIME_T # define IS_INVALID_TIME_T(a) ((a) == (time_t)(-1)) #else /* Error or 32 bit time_t and value after 2038-01-19. */ # define IS_INVALID_TIME_T(a) ((a) < 0) #endif /* Return a letter describing the public key algorithms. */ int pubkey_letter( int algo ) { switch (algo) { case PUBKEY_ALGO_RSA: return 'R' ; case PUBKEY_ALGO_RSA_E: return 'r' ; case PUBKEY_ALGO_RSA_S: return 's' ; case PUBKEY_ALGO_ELGAMAL_E: return 'g' ; case PUBKEY_ALGO_ELGAMAL: return 'G' ; case PUBKEY_ALGO_DSA: return 'D' ; + case PUBKEY_ALGO_EDDSA: return 'E' ; /* ECC EdDSA (sign only) */ case PUBKEY_ALGO_ECDSA: return 'E' ; /* ECC DSA (sign only) */ case PUBKEY_ALGO_ECDH: return 'e' ; /* ECC DH (encrypt only) */ default: return '?'; } } /* Hash a public key. This function is useful for v4 fingerprints and for v3 or v4 key signing. */ void hash_public_key (gcry_md_hd_t md, PKT_public_key *pk) { unsigned int n = 6; unsigned int nn[PUBKEY_MAX_NPKEY]; byte *pp[PUBKEY_MAX_NPKEY]; int i; unsigned int nbits; size_t nbytes; int npkey = pubkey_get_npkey (pk->pubkey_algo); /* Two extra bytes for the expiration date in v3 */ if(pk->version<4) n+=2; /* FIXME: We can avoid the extra malloc by calling only the first mpi_print here which computes the required length and calling the real mpi_print only at the end. The speed advantage would only be for ECC (opaque MPIs) or if we could implement an mpi_print variant with a callback handler to do the hashing. */ if (npkey==0 && pk->pkey[0] && gcry_mpi_get_flag (pk->pkey[0], GCRYMPI_FLAG_OPAQUE)) { pp[0] = gcry_mpi_get_opaque (pk->pkey[0], &nbits); nn[0] = (nbits+7)/8; n+=nn[0]; } else { for (i=0; i < npkey; i++ ) { if (gcry_mpi_get_flag (pk->pkey[i], GCRYMPI_FLAG_OPAQUE)) { const void *p; p = gcry_mpi_get_opaque (pk->pkey[i], &nbits); pp[i] = xmalloc ((nbits+7)/8); memcpy (pp[i], p, (nbits+7)/8); nn[i] = (nbits+7)/8; n += nn[i]; } else { if (gcry_mpi_print (GCRYMPI_FMT_PGP, NULL, 0, &nbytes, pk->pkey[i])) BUG (); pp[i] = xmalloc (nbytes); if (gcry_mpi_print (GCRYMPI_FMT_PGP, pp[i], nbytes, &nbytes, pk->pkey[i])) BUG (); nn[i] = nbytes; n += nn[i]; } } } gcry_md_putc ( md, 0x99 ); /* ctb */ /* What does it mean if n is greater than than 0xFFFF ? */ gcry_md_putc ( md, n >> 8 ); /* 2 byte length header */ gcry_md_putc ( md, n ); gcry_md_putc ( md, pk->version ); gcry_md_putc ( md, pk->timestamp >> 24 ); gcry_md_putc ( md, pk->timestamp >> 16 ); gcry_md_putc ( md, pk->timestamp >> 8 ); gcry_md_putc ( md, pk->timestamp ); if(pk->version<4) { u16 days=0; if(pk->expiredate) days=(u16)((pk->expiredate - pk->timestamp) / 86400L); gcry_md_putc ( md, days >> 8 ); gcry_md_putc ( md, days ); } gcry_md_putc ( md, pk->pubkey_algo ); if(npkey==0 && pk->pkey[0] && gcry_mpi_get_flag (pk->pkey[0], GCRYMPI_FLAG_OPAQUE)) { gcry_md_write (md, pp[0], nn[0]); } else for(i=0; i < npkey; i++ ) { gcry_md_write ( md, pp[i], nn[i] ); xfree(pp[i]); } } static gcry_md_hd_t do_fingerprint_md( PKT_public_key *pk ) { gcry_md_hd_t md; if (gcry_md_open (&md, DIGEST_ALGO_SHA1, 0)) BUG (); hash_public_key(md,pk); gcry_md_final( md ); return md; } /* fixme: Check whether we can replace this function or if not describe why we need it. */ u32 v3_keyid (gcry_mpi_t a, u32 *ki) { byte *buffer, *p; size_t nbytes; if (gcry_mpi_print (GCRYMPI_FMT_USG, NULL, 0, &nbytes, a )) BUG (); /* fixme: allocate it on the stack */ buffer = xmalloc (nbytes); if (gcry_mpi_print( GCRYMPI_FMT_USG, buffer, nbytes, NULL, a )) BUG (); if (nbytes < 8) /* oops */ ki[0] = ki[1] = 0; else { p = buffer + nbytes - 8; ki[0] = (p[0] << 24) | (p[1] <<16) | (p[2] << 8) | p[3]; p += 4; ki[1] = (p[0] << 24) | (p[1] <<16) | (p[2] << 8) | p[3]; } xfree (buffer); return ki[1]; } size_t keystrlen(void) { switch(opt.keyid_format) { case KF_SHORT: return 8; case KF_LONG: return 16; case KF_0xSHORT: return 10; case KF_0xLONG: return 18; default: BUG(); } } const char * keystr (u32 *keyid) { static char keyid_str[KEYID_STR_SIZE]; switch (opt.keyid_format) { case KF_SHORT: snprintf (keyid_str, sizeof keyid_str, "%08lX", (ulong)keyid[1]); break; case KF_LONG: if (keyid[0]) snprintf (keyid_str, sizeof keyid_str, "%08lX%08lX", (ulong)keyid[0], (ulong)keyid[1]); else snprintf (keyid_str, sizeof keyid_str, "%08lX", (ulong)keyid[1]); break; case KF_0xSHORT: snprintf (keyid_str, sizeof keyid_str, "0x%08lX", (ulong)keyid[1]); break; case KF_0xLONG: if(keyid[0]) snprintf (keyid_str, sizeof keyid_str, "0x%08lX%08lX", (ulong)keyid[0],(ulong)keyid[1]); else snprintf (keyid_str, sizeof keyid_str, "0x%08lX", (ulong)keyid[1]); break; default: BUG(); } return keyid_str; } const char * keystr_with_sub (u32 *main_kid, u32 *sub_kid) { static char buffer[KEYID_STR_SIZE+1+KEYID_STR_SIZE]; char *p; mem2str (buffer, keystr (main_kid), KEYID_STR_SIZE); if (sub_kid) { p = buffer + strlen (buffer); *p++ = '/'; mem2str (p, keystr (sub_kid), KEYID_STR_SIZE); } return buffer; } const char * keystr_from_pk(PKT_public_key *pk) { keyid_from_pk(pk,NULL); return keystr(pk->keyid); } const char * keystr_from_pk_with_sub (PKT_public_key *main_pk, PKT_public_key *sub_pk) { keyid_from_pk (main_pk, NULL); if (sub_pk) keyid_from_pk (sub_pk, NULL); return keystr_with_sub (main_pk->keyid, sub_pk? sub_pk->keyid:NULL); } const char * keystr_from_desc(KEYDB_SEARCH_DESC *desc) { switch(desc->mode) { case KEYDB_SEARCH_MODE_LONG_KID: case KEYDB_SEARCH_MODE_SHORT_KID: return keystr(desc->u.kid); case KEYDB_SEARCH_MODE_FPR20: { u32 keyid[2]; keyid[0] = ((unsigned char)desc->u.fpr[12] << 24 | (unsigned char)desc->u.fpr[13] << 16 | (unsigned char)desc->u.fpr[14] << 8 | (unsigned char)desc->u.fpr[15]); keyid[1] = ((unsigned char)desc->u.fpr[16] << 24 | (unsigned char)desc->u.fpr[17] << 16 | (unsigned char)desc->u.fpr[18] << 8 | (unsigned char)desc->u.fpr[19]); return keystr(keyid); } case KEYDB_SEARCH_MODE_FPR16: return "?v3 fpr?"; default: BUG(); } } /* * Get the keyid from the public key and put it into keyid * if this is not NULL. Return the 32 low bits of the keyid. */ u32 keyid_from_pk (PKT_public_key *pk, u32 *keyid) { u32 lowbits; u32 dummy_keyid[2]; if (!keyid) keyid = dummy_keyid; if( pk->keyid[0] || pk->keyid[1] ) { keyid[0] = pk->keyid[0]; keyid[1] = pk->keyid[1]; lowbits = keyid[1]; } else if( pk->version < 4 ) { if( is_RSA(pk->pubkey_algo) ) { lowbits = (pubkey_get_npkey (pk->pubkey_algo) ? v3_keyid ( pk->pkey[0], keyid ) : 0); /* From n. */ pk->keyid[0] = keyid[0]; pk->keyid[1] = keyid[1]; } else pk->keyid[0]=pk->keyid[1]=keyid[0]=keyid[1]=lowbits=0xFFFFFFFF; } else { const byte *dp; gcry_md_hd_t md; md = do_fingerprint_md(pk); if(md) { dp = gcry_md_read ( md, 0 ); keyid[0] = dp[12] << 24 | dp[13] << 16 | dp[14] << 8 | dp[15] ; keyid[1] = dp[16] << 24 | dp[17] << 16 | dp[18] << 8 | dp[19] ; lowbits = keyid[1]; gcry_md_close (md); pk->keyid[0] = keyid[0]; pk->keyid[1] = keyid[1]; } else pk->keyid[0]=pk->keyid[1]=keyid[0]=keyid[1]=lowbits=0xFFFFFFFF; } return lowbits; } /* * Get the keyid from the fingerprint. This function is simple for most * keys, but has to do a keylookup for old stayle keys. */ u32 keyid_from_fingerprint( const byte *fprint, size_t fprint_len, u32 *keyid ) { u32 dummy_keyid[2]; if( !keyid ) keyid = dummy_keyid; if (fprint_len != 20) { /* This is special as we have to lookup the key first. */ PKT_public_key pk; int rc; memset (&pk, 0, sizeof pk); rc = get_pubkey_byfprint (&pk, fprint, fprint_len); if( rc ) { log_error("Oops: keyid_from_fingerprint: no pubkey\n"); keyid[0] = 0; keyid[1] = 0; } else keyid_from_pk (&pk, keyid); } else { const byte *dp = fprint; keyid[0] = dp[12] << 24 | dp[13] << 16 | dp[14] << 8 | dp[15] ; keyid[1] = dp[16] << 24 | dp[17] << 16 | dp[18] << 8 | dp[19] ; } return keyid[1]; } u32 keyid_from_sig (PKT_signature *sig, u32 *keyid) { if( keyid ) { keyid[0] = sig->keyid[0]; keyid[1] = sig->keyid[1]; } return sig->keyid[1]; } byte * namehash_from_uid (PKT_user_id *uid) { if (!uid->namehash) { uid->namehash = xmalloc (20); if (uid->attrib_data) rmd160_hash_buffer (uid->namehash, uid->attrib_data, uid->attrib_len); else rmd160_hash_buffer (uid->namehash, uid->name, uid->len); } return uid->namehash; } /* * Return the number of bits used in PK. */ unsigned int nbits_from_pk (PKT_public_key *pk) { return pubkey_nbits (pk->pubkey_algo, pk->pkey); } static const char * mk_datestr (char *buffer, time_t atime) { struct tm *tp; if (IS_INVALID_TIME_T (atime)) strcpy (buffer, "????" "-??" "-??"); /* Mark this as invalid. */ else { tp = gmtime (&atime); sprintf (buffer,"%04d-%02d-%02d", 1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday ); } return buffer; } /* * return a string with the creation date of the pk * Note: this is alloced in a static buffer. * Format is: yyyy-mm-dd */ const char * datestr_from_pk (PKT_public_key *pk) { static char buffer[11+5]; time_t atime = pk->timestamp; return mk_datestr (buffer, atime); } const char * datestr_from_sig (PKT_signature *sig ) { static char buffer[11+5]; time_t atime = sig->timestamp; return mk_datestr (buffer, atime); } const char * expirestr_from_pk (PKT_public_key *pk) { static char buffer[11+5]; time_t atime; if (!pk->expiredate) return _("never "); atime = pk->expiredate; return mk_datestr (buffer, atime); } const char * expirestr_from_sig (PKT_signature *sig) { static char buffer[11+5]; time_t atime; if (!sig->expiredate) return _("never "); atime=sig->expiredate; return mk_datestr (buffer, atime); } const char * revokestr_from_pk( PKT_public_key *pk ) { static char buffer[11+5]; time_t atime; if(!pk->revoked.date) return _("never "); atime=pk->revoked.date; return mk_datestr (buffer, atime); } const char * usagestr_from_pk( PKT_public_key *pk ) { static char buffer[10]; int i = 0; unsigned int use = pk->pubkey_usage; if ( use & PUBKEY_USAGE_SIG ) buffer[i++] = 'S'; if ( use & PUBKEY_USAGE_CERT ) buffer[i++] = 'C'; if ( use & PUBKEY_USAGE_ENC ) buffer[i++] = 'E'; if ( (use & PUBKEY_USAGE_AUTH) ) buffer[i++] = 'A'; while (i < 4) buffer[i++] = ' '; buffer[i] = 0; return buffer; } const char * colon_strtime (u32 t) { static char buf[20]; if (!t) return ""; snprintf (buf, sizeof buf, "%lu", (ulong)t); return buf; } const char * colon_datestr_from_pk (PKT_public_key *pk) { static char buf[20]; snprintf (buf, sizeof buf, "%lu", (ulong)pk->timestamp); return buf; } const char * colon_datestr_from_sig (PKT_signature *sig) { static char buf[20]; snprintf (buf, sizeof buf, "%lu", (ulong)sig->timestamp); return buf; } const char * colon_expirestr_from_sig (PKT_signature *sig) { static char buf[20]; if (!sig->expiredate) return ""; snprintf (buf, sizeof buf,"%lu", (ulong)sig->expiredate); return buf; } /* * Return a byte array with the fingerprint for the given PK/SK * The length of the array is returned in ret_len. Caller must free * the array or provide an array of length MAX_FINGERPRINT_LEN. */ byte * fingerprint_from_pk (PKT_public_key *pk, byte *array, size_t *ret_len) { byte *buf; const byte *dp; size_t len, nbytes; int i; if ( pk->version < 4 ) { if ( is_RSA(pk->pubkey_algo) ) { /* RSA in version 3 packets is special. */ gcry_md_hd_t md; if (gcry_md_open (&md, DIGEST_ALGO_MD5, 0)) BUG (); if ( pubkey_get_npkey (pk->pubkey_algo) > 1 ) { for (i=0; i < 2; i++) { if (gcry_mpi_print (GCRYMPI_FMT_USG, NULL, 0, &nbytes, pk->pkey[i])) BUG (); /* fixme: Better allocate BUF on the stack */ buf = xmalloc (nbytes); if (gcry_mpi_print (GCRYMPI_FMT_USG, buf, nbytes, NULL, pk->pkey[i])) BUG (); gcry_md_write (md, buf, nbytes); xfree (buf); } } gcry_md_final (md); if (!array) array = xmalloc (16); len = 16; memcpy (array, gcry_md_read (md, DIGEST_ALGO_MD5), 16); gcry_md_close(md); } else { if (!array) array = xmalloc(16); len = 16; memset (array,0,16); } } else { gcry_md_hd_t md; md = do_fingerprint_md(pk); dp = gcry_md_read( md, 0 ); len = gcry_md_get_algo_dlen (gcry_md_get_algo (md)); assert( len <= MAX_FINGERPRINT_LEN ); if (!array) array = xmalloc ( len ); memcpy (array, dp, len ); pk->keyid[0] = dp[12] << 24 | dp[13] << 16 | dp[14] << 8 | dp[15] ; pk->keyid[1] = dp[16] << 24 | dp[17] << 16 | dp[18] << 8 | dp[19] ; gcry_md_close( md); } *ret_len = len; return array; } /* Return the so called KEYGRIP which is the SHA-1 hash of the public key parameters expressed as an canoncial encoded S-Exp. ARRAY must be 20 bytes long. Returns 0 on sucess or an error code. */ gpg_error_t keygrip_from_pk (PKT_public_key *pk, unsigned char *array) { gpg_error_t err; gcry_sexp_t s_pkey; if (DBG_PACKET) log_debug ("get_keygrip for public key\n"); switch (pk->pubkey_algo) { case GCRY_PK_DSA: err = gcry_sexp_build (&s_pkey, NULL, "(public-key(dsa(p%m)(q%m)(g%m)(y%m)))", pk->pkey[0], pk->pkey[1], pk->pkey[2], pk->pkey[3]); break; case GCRY_PK_ELG: case GCRY_PK_ELG_E: err = gcry_sexp_build (&s_pkey, NULL, "(public-key(elg(p%m)(g%m)(y%m)))", pk->pkey[0], pk->pkey[1], pk->pkey[2]); break; case GCRY_PK_RSA: case GCRY_PK_RSA_S: case GCRY_PK_RSA_E: err = gcry_sexp_build (&s_pkey, NULL, "(public-key(rsa(n%m)(e%m)))", pk->pkey[0], pk->pkey[1]); break; + case PUBKEY_ALGO_EDDSA: case PUBKEY_ALGO_ECDSA: case PUBKEY_ALGO_ECDH: { char *curve = openpgp_oid_to_str (pk->pkey[0]); if (!curve) err = gpg_error_from_syserror (); else { err = gcry_sexp_build (&s_pkey, NULL, "(public-key(ecc(curve%s)(q%m)))", curve, pk->pkey[1]); xfree (curve); } } break; default: err = gpg_error (GPG_ERR_PUBKEY_ALGO); break; } if (err) return err; if (!gcry_pk_get_keygrip (s_pkey, array)) { log_error ("error computing keygrip\n"); err = gpg_error (GPG_ERR_GENERAL); } else { if (DBG_PACKET) log_printhex ("keygrip=", array, 20); /* FIXME: Save the keygrip in PK. */ } gcry_sexp_release (s_pkey); return 0; } /* Store an allocated buffer with the keygrip of PK encoded as a hexstring at r_GRIP. Returns 0 on success. */ gpg_error_t hexkeygrip_from_pk (PKT_public_key *pk, char **r_grip) { gpg_error_t err; unsigned char grip[20]; *r_grip = NULL; err = keygrip_from_pk (pk, grip); if (!err) { char * buf = xtrymalloc (20*2+1); if (!buf) err = gpg_error_from_syserror (); else { bin2hex (grip, 20, buf); *r_grip = buf; } } return err; } diff --git a/g10/keylist.c b/g10/keylist.c index 356fac320..9a96c872e 100644 --- a/g10/keylist.c +++ b/g10/keylist.c @@ -1,1690 +1,1694 @@ /* keylist.c - Print information about OpenPGP keys * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, * 2008, 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 #ifdef HAVE_DOSISH_SYSTEM #include /* for setmode() */ #endif #include "gpg.h" #include "options.h" #include "packet.h" #include "status.h" #include "keydb.h" #include "photoid.h" #include "util.h" #include "ttyio.h" #include "trustdb.h" #include "main.h" #include "i18n.h" #include "status.h" #include "call-agent.h" static void list_all (int); static void list_one (strlist_t names, int secret); static void locate_one (ctrl_t ctrl, strlist_t names); static void print_card_serialno (const char *serialno); struct sig_stats { int inv_sigs; int no_key; int oth_err; }; /* The stream used to write attribute packets to. */ static estream_t attrib_fp; /* List the keys. If list is NULL, all available keys are listed. With LOCATE_MODE set the locate algorithm is used to find a key. */ void public_key_list (ctrl_t ctrl, strlist_t list, int locate_mode) { if (opt.with_colons) { byte trust_model, marginals, completes, cert_depth, min_cert_level; ulong created, nextcheck; read_trust_options (&trust_model, &created, &nextcheck, &marginals, &completes, &cert_depth, &min_cert_level); es_fprintf (es_stdout, "tru:"); if (nextcheck && nextcheck <= make_timestamp ()) es_fprintf (es_stdout, "o"); if (trust_model != opt.trust_model) es_fprintf (es_stdout, "t"); if (opt.trust_model == TM_PGP || opt.trust_model == TM_CLASSIC) { if (marginals != opt.marginals_needed) es_fprintf (es_stdout, "m"); if (completes != opt.completes_needed) es_fprintf (es_stdout, "c"); if (cert_depth != opt.max_cert_depth) es_fprintf (es_stdout, "d"); if (min_cert_level != opt.min_cert_level) es_fprintf (es_stdout, "l"); } es_fprintf (es_stdout, ":%d:%lu:%lu", trust_model, created, nextcheck); /* Only show marginals, completes, and cert_depth in the classic or PGP trust models since they are not meaningful otherwise. */ if (trust_model == TM_PGP || trust_model == TM_CLASSIC) es_fprintf (es_stdout, ":%d:%d:%d", marginals, completes, cert_depth); es_fprintf (es_stdout, "\n"); } /* We need to do the stale check right here because it might need to update the keyring while we already have the keyring open. This is very bad for W32 because of a sharing violation. For real OSes it might lead to false results if we are later listing a keyring which is associated with the inode of a deleted file. */ check_trustdb_stale (); if (locate_mode) locate_one (ctrl, list); else if (!list) list_all (0); else list_one (list, 0); } void secret_key_list (ctrl_t ctrl, strlist_t list) { (void)ctrl; check_trustdb_stale (); if (!list) list_all (1); else /* List by user id */ list_one (list, 1); } void print_seckey_info (PKT_public_key *pk) { u32 keyid[2]; char *p; keyid_from_pk (pk, keyid); p = get_user_id_native (keyid); tty_printf ("\nsec %4u%c/%s %s %s\n", nbits_from_pk (pk), pubkey_letter (pk->pubkey_algo), keystr (keyid), datestr_from_pk (pk), p); xfree (p); } /* Print information about the public key. With FP passed as NULL, the tty output interface is used, otherwise output is directted to the given stream. */ void print_pubkey_info (estream_t fp, PKT_public_key * pk) { u32 keyid[2]; char *p; keyid_from_pk (pk, keyid); /* If the pk was chosen by a particular user ID, that is the one to print. */ if (pk->user_id) p = utf8_to_native (pk->user_id->name, pk->user_id->len, 0); else p = get_user_id_native (keyid); if (fp) tty_printf ("\n"); tty_fprintf (fp, "pub %4u%c/%s %s %s\n", nbits_from_pk (pk), pubkey_letter (pk->pubkey_algo), keystr (keyid), datestr_from_pk (pk), p); xfree (p); } /* Print basic information of a secret key including the card serial number information. */ #ifdef ENABLE_CARD_SUPPORT void print_card_key_info (estream_t fp, kbnode_t keyblock) { kbnode_t node; char *hexgrip; char *serialno; int s2k_char; for (node = keyblock; node; node = node->next) { if (node->pkt->pkttype == PKT_PUBLIC_KEY || node->pkt->pkttype == PKT_PUBLIC_SUBKEY) { int rc; PKT_public_key *pk = node->pkt->pkt.public_key; serialno = NULL; rc = hexkeygrip_from_pk (pk, &hexgrip); if (rc) { log_error ("error computing a keygrip: %s\n", gpg_strerror (rc)); s2k_char = '?'; } else if (!agent_get_keyinfo (NULL, hexgrip, &serialno)) s2k_char = serialno? '>':' '; else s2k_char = '#'; /* Key not found. */ tty_fprintf (fp, "%s%c %4u%c/%s ", node->pkt->pkttype == PKT_PUBLIC_KEY ? "sec" : "ssb", s2k_char, nbits_from_pk (pk), pubkey_letter (pk->pubkey_algo), keystr_from_pk (pk)); tty_fprintf (fp, _("created: %s"), datestr_from_pk (pk)); tty_fprintf (fp, " "); tty_fprintf (fp, _("expires: %s"), expirestr_from_pk (pk)); if (serialno) { tty_fprintf (fp, "\n "); tty_fprintf (fp, _("card-no: ")); if (strlen (serialno) == 32 && !strncmp (serialno, "D27600012401", 12)) { /* This is an OpenPGP card. Print the relevant part. */ /* Example: D2760001240101010001000003470000 */ /* xxxxyyyyyyyy */ tty_fprintf (fp, "%.*s %.*s", 4, serialno+16, 8, serialno+20); } else tty_fprintf (fp, "%s", serialno); } tty_fprintf (fp, "\n"); xfree (hexgrip); xfree (serialno); } } } #endif /*ENABLE_CARD_SUPPORT*/ /* Flags = 0x01 hashed 0x02 critical. */ static void status_one_subpacket (sigsubpkttype_t type, size_t len, int flags, const byte * buf) { char status[40]; /* Don't print these. */ if (len > 256) return; snprintf (status, sizeof status, "%d %u %u ", type, flags, (unsigned int) len); write_status_text_and_buffer (STATUS_SIG_SUBPACKET, status, buf, len, 0); } /* Print a policy URL. Allowed values for MODE are: * 0 - print to stdout. * 1 - use log_info and emit status messages. * 2 - emit only status messages. */ void show_policy_url (PKT_signature * sig, int indent, int mode) { const byte *p; size_t len; int seq = 0, crit; estream_t fp = mode ? log_get_stream () : es_stdout; while ((p = enum_sig_subpkt (sig->hashed, SIGSUBPKT_POLICY, &len, &seq, &crit))) { if (mode != 2) { int i; const char *str; for (i = 0; i < indent; i++) es_putc (' ', fp); if (crit) str = _("Critical signature policy: "); else str = _("Signature policy: "); if (mode) log_info ("%s", str); else es_fprintf (fp, "%s", str); print_utf8_buffer (fp, p, len); es_fprintf (fp, "\n"); } if (mode) write_status_buffer (STATUS_POLICY_URL, p, len, 0); } } /* mode=0 for stdout. mode=1 for log_info + status messages mode=2 for status messages only */ /* TODO: use this */ void show_keyserver_url (PKT_signature * sig, int indent, int mode) { const byte *p; size_t len; int seq = 0, crit; estream_t fp = mode ? log_get_stream () : es_stdout; while ((p = enum_sig_subpkt (sig->hashed, SIGSUBPKT_PREF_KS, &len, &seq, &crit))) { if (mode != 2) { int i; const char *str; for (i = 0; i < indent; i++) es_putc (' ', es_stdout); if (crit) str = _("Critical preferred keyserver: "); else str = _("Preferred keyserver: "); if (mode) log_info ("%s", str); else es_fprintf (es_stdout, "%s", str); print_utf8_buffer (fp, p, len); es_fprintf (fp, "\n"); } if (mode) status_one_subpacket (SIGSUBPKT_PREF_KS, len, (crit ? 0x02 : 0) | 0x01, p); } } /* mode=0 for stdout. mode=1 for log_info + status messages mode=2 for status messages only Defined bits in WHICH: 1 == standard notations 2 == user notations */ void show_notation (PKT_signature * sig, int indent, int mode, int which) { estream_t fp = mode ? log_get_stream () : es_stdout; struct notation *nd, *notations; if (which == 0) which = 3; notations = sig_to_notation (sig); /* There may be multiple notations in the same sig. */ for (nd = notations; nd; nd = nd->next) { if (mode != 2) { int has_at = !!strchr (nd->name, '@'); if ((which & 1 && !has_at) || (which & 2 && has_at)) { int i; const char *str; for (i = 0; i < indent; i++) es_putc (' ', es_stdout); if (nd->flags.critical) str = _("Critical signature notation: "); else str = _("Signature notation: "); if (mode) log_info ("%s", str); else es_fprintf (es_stdout, "%s", str); /* This is all UTF8 */ print_utf8_buffer (fp, nd->name, strlen (nd->name)); es_fprintf (fp, "="); print_utf8_buffer (fp, nd->value, strlen (nd->value)); es_fprintf (fp, "\n"); } } if (mode) { write_status_buffer (STATUS_NOTATION_NAME, nd->name, strlen (nd->name), 0); write_status_buffer (STATUS_NOTATION_DATA, nd->value, strlen (nd->value), 50); } } free_notation (notations); } static void print_signature_stats (struct sig_stats *s) { if (s->inv_sigs == 1) tty_printf (_("1 bad signature\n")); else if (s->inv_sigs) tty_printf (_("%d bad signatures\n"), s->inv_sigs); if (s->no_key == 1) tty_printf (_("1 signature not checked due to a missing key\n")); else if (s->no_key) tty_printf (_("%d signatures not checked due to missing keys\n"), s->no_key); if (s->oth_err == 1) tty_printf (_("1 signature not checked due to an error\n")); else if (s->oth_err) tty_printf (_("%d signatures not checked due to errors\n"), s->oth_err); } static void list_all (int secret) { KEYDB_HANDLE hd; KBNODE keyblock = NULL; int rc = 0; const char *lastresname, *resname; struct sig_stats stats; memset (&stats, 0, sizeof (stats)); hd = keydb_new (); if (!hd) rc = gpg_error (GPG_ERR_GENERAL); else rc = keydb_search_first (hd); if (rc) { if (gpg_err_code (rc) != GPG_ERR_NOT_FOUND) log_error ("keydb_search_first failed: %s\n", g10_errstr (rc)); goto leave; } lastresname = NULL; do { rc = keydb_get_keyblock (hd, &keyblock); if (rc) { log_error ("keydb_get_keyblock failed: %s\n", g10_errstr (rc)); goto leave; } if (secret && agent_probe_any_secret_key (NULL, keyblock)) ; /* Secret key listing requested but this isn't one. */ else { if (!opt.with_colons) { resname = keydb_get_resource_name (hd); if (lastresname != resname) { int i; es_fprintf (es_stdout, "%s\n", resname); for (i = strlen (resname); i; i--) es_putc ('-', es_stdout); es_putc ('\n', es_stdout); lastresname = resname; } } merge_keys_and_selfsig (keyblock); list_keyblock (keyblock, secret, opt.fingerprint, opt.check_sigs ? &stats : NULL); } release_kbnode (keyblock); keyblock = NULL; } while (!(rc = keydb_search_next (hd))); if (rc && gpg_err_code (rc) != GPG_ERR_NOT_FOUND) log_error ("keydb_search_next failed: %s\n", g10_errstr (rc)); if (opt.check_sigs && !opt.with_colons) print_signature_stats (&stats); leave: release_kbnode (keyblock); keydb_release (hd); } static void list_one (strlist_t names, int secret) { int rc = 0; KBNODE keyblock = NULL; GETKEY_CTX ctx; const char *resname; const char *keyring_str = _("Keyring"); int i; struct sig_stats stats; memset (&stats, 0, sizeof (stats)); /* fixme: using the bynames function has the disadvantage that we * don't know wether one of the names given was not found. OTOH, * this function has the advantage to list the names in the * sequence as defined by the keyDB and does not duplicate * outputs. A solution could be do test whether all given have * been listed (this needs a way to use the keyDB search * functions) or to have the search function return indicators for * found names. Yet another way is to use the keydb search * facilities directly. */ rc = getkey_bynames (&ctx, NULL, names, secret, &keyblock); if (rc) { log_error ("error reading key: %s\n", g10_errstr (rc)); get_pubkey_end (ctx); return; } do { if ((opt.list_options & LIST_SHOW_KEYRING) && !opt.with_colons) { resname = keydb_get_resource_name (get_ctx_handle (ctx)); es_fprintf (es_stdout, "%s: %s\n", keyring_str, resname); for (i = strlen (resname) + strlen (keyring_str) + 2; i; i--) es_putc ('-', es_stdout); es_putc ('\n', es_stdout); } list_keyblock (keyblock, secret, opt.fingerprint, (!secret && opt.check_sigs)? &stats : NULL); release_kbnode (keyblock); } while (!getkey_next (ctx, NULL, &keyblock)); getkey_end (ctx); if (opt.check_sigs && !opt.with_colons) print_signature_stats (&stats); } static void locate_one (ctrl_t ctrl, strlist_t names) { int rc = 0; strlist_t sl; GETKEY_CTX ctx = NULL; KBNODE keyblock = NULL; struct sig_stats stats; memset (&stats, 0, sizeof (stats)); for (sl = names; sl; sl = sl->next) { rc = get_pubkey_byname (ctrl, &ctx, NULL, sl->d, &keyblock, NULL, 1, 0); if (rc) { if (gpg_err_code (rc) != GPG_ERR_NO_PUBKEY) log_error ("error reading key: %s\n", g10_errstr (rc)); } else { do { list_keyblock (keyblock, 0, opt.fingerprint, opt.check_sigs ? &stats : NULL); release_kbnode (keyblock); } while (ctx && !get_pubkey_next (ctx, NULL, &keyblock)); get_pubkey_end (ctx); ctx = NULL; } } if (opt.check_sigs && !opt.with_colons) print_signature_stats (&stats); } static void print_key_data (PKT_public_key * pk) { int n = pk ? pubkey_get_npkey (pk->pubkey_algo) : 0; int i; for (i = 0; i < n; i++) { es_fprintf (es_stdout, "pkd:%d:%u:", i, mpi_get_nbits (pk->pkey[i])); mpi_print (es_stdout, pk->pkey[i], 1); es_putc (':', es_stdout); es_putc ('\n', es_stdout); } } static void print_capabilities (PKT_public_key *pk, KBNODE keyblock) { unsigned int use = pk->pubkey_usage; int c_printed = 0; if (use & PUBKEY_USAGE_ENC) es_putc ('e', es_stdout); if (use & PUBKEY_USAGE_SIG) { es_putc ('s', es_stdout); if (pk->flags.primary) { es_putc ('c', es_stdout); /* The PUBKEY_USAGE_CERT flag was introduced later and we used to always print 'c' for a primary key. To avoid any regression here we better track whether we printed 'c' already. */ c_printed = 1; } } if ((use & PUBKEY_USAGE_CERT) && !c_printed) es_putc ('c', es_stdout); if ((use & PUBKEY_USAGE_AUTH)) es_putc ('a', es_stdout); if ((use & PUBKEY_USAGE_UNKNOWN)) es_putc ('?', es_stdout); if (keyblock) { /* Figure out the usable capabilities. */ KBNODE k; int enc = 0, sign = 0, cert = 0, auth = 0, disabled = 0; for (k = keyblock; k; k = k->next) { if (k->pkt->pkttype == PKT_PUBLIC_KEY || k->pkt->pkttype == PKT_PUBLIC_SUBKEY) { pk = k->pkt->pkt.public_key; if (pk->flags.primary) disabled = pk_is_disabled (pk); if (pk->flags.valid && !pk->flags.revoked && !pk->has_expired) { if (pk->pubkey_usage & PUBKEY_USAGE_ENC) enc = 1; if (pk->pubkey_usage & PUBKEY_USAGE_SIG) { sign = 1; if (pk->flags.primary) cert = 1; } if (pk->pubkey_usage & PUBKEY_USAGE_CERT) cert = 1; if ((pk->pubkey_usage & PUBKEY_USAGE_AUTH)) auth = 1; } } } if (enc) es_putc ('E', es_stdout); if (sign) es_putc ('S', es_stdout); if (cert) es_putc ('C', es_stdout); if (auth) es_putc ('A', es_stdout); if (disabled) es_putc ('D', es_stdout); } es_putc (':', es_stdout); } /* FLAGS: 0x01 hashed 0x02 critical */ static void print_one_subpacket (sigsubpkttype_t type, size_t len, int flags, const byte * buf) { size_t i; es_fprintf (es_stdout, "spk:%d:%u:%u:", type, flags, (unsigned int) len); for (i = 0; i < len; i++) { /* printable ascii other than : and % */ if (buf[i] >= 32 && buf[i] <= 126 && buf[i] != ':' && buf[i] != '%') es_fprintf (es_stdout, "%c", buf[i]); else es_fprintf (es_stdout, "%%%02X", buf[i]); } es_fprintf (es_stdout, "\n"); } void print_subpackets_colon (PKT_signature * sig) { byte *i; assert (opt.show_subpackets); for (i = opt.show_subpackets; *i; i++) { const byte *p; size_t len; int seq, crit; seq = 0; while ((p = enum_sig_subpkt (sig->hashed, *i, &len, &seq, &crit))) print_one_subpacket (*i, len, 0x01 | (crit ? 0x02 : 0), p); seq = 0; while ((p = enum_sig_subpkt (sig->unhashed, *i, &len, &seq, &crit))) print_one_subpacket (*i, len, 0x00 | (crit ? 0x02 : 0), p); } } void dump_attribs (const PKT_user_id *uid, PKT_public_key *pk) { int i; if (!attrib_fp) return; for (i = 0; i < uid->numattribs; i++) { if (is_status_enabled ()) { byte array[MAX_FINGERPRINT_LEN], *p; char buf[(MAX_FINGERPRINT_LEN * 2) + 90]; size_t j, n; if (!pk) BUG (); fingerprint_from_pk (pk, array, &n); p = array; for (j = 0; j < n; j++, p++) sprintf (buf + 2 * j, "%02X", *p); sprintf (buf + strlen (buf), " %lu %u %u %u %lu %lu %u", (ulong) uid->attribs[i].len, uid->attribs[i].type, i + 1, uid->numattribs, (ulong) uid->created, (ulong) uid->expiredate, ((uid->is_primary ? 0x01 : 0) | (uid-> is_revoked ? 0x02 : 0) | (uid->is_expired ? 0x04 : 0))); write_status_text (STATUS_ATTRIBUTE, buf); } es_fwrite (uid->attribs[i].data, uid->attribs[i].len, 1, attrib_fp); es_fflush (attrib_fp); } } static void list_keyblock_print (KBNODE keyblock, int secret, int fpr, void *opaque) { int rc; KBNODE kbctx; KBNODE node; PKT_public_key *pk; struct sig_stats *stats = opaque; int skip_sigs = 0; int s2k_char; char *hexgrip = NULL; char *serialno = NULL; /* Get the keyid from the keyblock. */ node = find_kbnode (keyblock, PKT_PUBLIC_KEY); if (!node) { log_error ("Oops; key lost!\n"); dump_kbnode (keyblock); return; } pk = node->pkt->pkt.public_key; if (secret || opt.with_keygrip) { rc = hexkeygrip_from_pk (pk, &hexgrip); if (rc) log_error ("error computing a keygrip: %s\n", gpg_strerror (rc)); } if (secret) { if (!agent_get_keyinfo (NULL, hexgrip, &serialno)) s2k_char = serialno? '>':' '; else s2k_char = '#'; /* Key not found. */ } else s2k_char = ' '; check_trustdb_stale (); es_fprintf (es_stdout, "%s%c %4u%c/%s %s", secret? "sec":"pub", s2k_char, nbits_from_pk (pk), pubkey_letter (pk->pubkey_algo), keystr_from_pk (pk), datestr_from_pk (pk)); if (pk->pubkey_algo == PUBKEY_ALGO_ECDSA + || pk->pubkey_algo == PUBKEY_ALGO_EDDSA || pk->pubkey_algo == PUBKEY_ALGO_ECDH) { char *curve = openpgp_oid_to_str (pk->pkey[0]); const char *name = openpgp_oid_to_curve (curve); if (!*name || *name == '?') name = curve; es_fprintf (es_stdout, " %s", name); xfree (curve); } if (pk->flags.revoked) { es_fprintf (es_stdout, " ["); es_fprintf (es_stdout, _("revoked: %s"), revokestr_from_pk (pk)); es_fprintf (es_stdout, "]"); } else if (pk->has_expired) { es_fprintf (es_stdout, " ["); es_fprintf (es_stdout, _("expired: %s"), expirestr_from_pk (pk)); es_fprintf (es_stdout, "]"); } else if (pk->expiredate) { es_fprintf (es_stdout, " ["); es_fprintf (es_stdout, _("expires: %s"), expirestr_from_pk (pk)); es_fprintf (es_stdout, "]"); } #if 0 /* I need to think about this some more. It's easy enough to include, but it looks sort of confusing in the listing... */ if (opt.list_options & LIST_SHOW_VALIDITY) { int validity = get_validity (pk, NULL); es_fprintf (es_stdout, " [%s]", trust_value_to_string (validity)); } #endif es_fprintf (es_stdout, "\n"); if (fpr) print_fingerprint (pk, 0); if (opt.with_keygrip && hexgrip) es_fprintf (es_stdout, " Keygrip = %s\n", hexgrip); if (serialno) print_card_serialno (serialno); if (opt.with_key_data) print_key_data (pk); for (kbctx = NULL; (node = walk_kbnode (keyblock, &kbctx, 0));) { if (node->pkt->pkttype == PKT_USER_ID && !opt.fast_list_mode) { PKT_user_id *uid = node->pkt->pkt.user_id; if (pk && (uid->is_expired || uid->is_revoked) && !(opt.list_options & LIST_SHOW_UNUSABLE_UIDS)) { skip_sigs = 1; continue; } else skip_sigs = 0; if (attrib_fp && uid->attrib_data != NULL) dump_attribs (uid, pk); if ((uid->is_revoked || uid->is_expired) || ((opt.list_options & LIST_SHOW_UID_VALIDITY) && pk)) { const char *validity; int indent; validity = uid_trust_string_fixed (pk, uid); indent = (keystrlen () + 9) - atoi (uid_trust_string_fixed (NULL, NULL)); if (indent < 0 || indent > 40) indent = 0; es_fprintf (es_stdout, "uid%*s%s ", indent, "", validity); } else es_fprintf (es_stdout, "uid%*s", (int) keystrlen () + 10, ""); print_utf8_buffer (es_stdout, uid->name, uid->len); es_putc ('\n', es_stdout); if ((opt.list_options & LIST_SHOW_PHOTOS) && uid->attribs != NULL) show_photos (uid->attribs, uid->numattribs, pk, uid); } else if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY) { PKT_public_key *pk2 = node->pkt->pkt.public_key; if ((pk2->flags.revoked || pk2->has_expired) && !(opt.list_options & LIST_SHOW_UNUSABLE_SUBKEYS)) { skip_sigs = 1; continue; } else skip_sigs = 0; xfree (serialno); serialno = NULL; xfree (hexgrip); hexgrip = NULL; if (secret || opt.with_keygrip) { rc = hexkeygrip_from_pk (pk2, &hexgrip); if (rc) log_error ("error computing a keygrip: %s\n", gpg_strerror (rc)); } if (secret) { if (!agent_get_keyinfo (NULL, hexgrip, &serialno)) s2k_char = serialno? '>':' '; else s2k_char = '#'; /* Key not found. */ } else s2k_char = ' '; es_fprintf (es_stdout, "%s%c %4u%c/%s %s", secret? "ssb":"sub", s2k_char, nbits_from_pk (pk2), pubkey_letter (pk2->pubkey_algo), keystr_from_pk (pk2), datestr_from_pk (pk2)); if (pk2->pubkey_algo == PUBKEY_ALGO_ECDSA + || pk2->pubkey_algo == PUBKEY_ALGO_EDDSA || pk2->pubkey_algo == PUBKEY_ALGO_ECDH) { char *curve = openpgp_oid_to_str (pk2->pkey[0]); const char *name = openpgp_oid_to_curve (curve); if (!*name || *name == '?') name = curve; es_fprintf (es_stdout, " %s", name); xfree (curve); } if (pk2->flags.revoked) { es_fprintf (es_stdout, " ["); es_fprintf (es_stdout, _("revoked: %s"), revokestr_from_pk (pk2)); es_fprintf (es_stdout, "]"); } else if (pk2->has_expired) { es_fprintf (es_stdout, " ["); es_fprintf (es_stdout, _("expired: %s"), expirestr_from_pk (pk2)); es_fprintf (es_stdout, "]"); } else if (pk2->expiredate) { es_fprintf (es_stdout, " ["); es_fprintf (es_stdout, _("expires: %s"), expirestr_from_pk (pk2)); es_fprintf (es_stdout, "]"); } es_putc ('\n', es_stdout); if (fpr > 1) { print_fingerprint (pk2, 0); if (serialno) print_card_serialno (serialno); } if (opt.with_keygrip && hexgrip) es_fprintf (es_stdout, " Keygrip = %s\n", hexgrip); if (opt.with_key_data) print_key_data (pk2); } else if (opt.list_sigs && node->pkt->pkttype == PKT_SIGNATURE && !skip_sigs) { PKT_signature *sig = node->pkt->pkt.signature; int sigrc; char *sigstr; if (stats) { rc = check_key_signature (keyblock, node, NULL); switch (gpg_err_code (rc)) { case 0: sigrc = '!'; break; case GPG_ERR_BAD_SIGNATURE: stats->inv_sigs++; sigrc = '-'; break; case GPG_ERR_NO_PUBKEY: case GPG_ERR_UNUSABLE_PUBKEY: stats->no_key++; continue; default: stats->oth_err++; sigrc = '%'; break; } /* TODO: Make sure a cached sig record here still has the pk that issued it. See also keyedit.c:print_and_check_one_sig */ } else { rc = 0; sigrc = ' '; } if (sig->sig_class == 0x20 || sig->sig_class == 0x28 || sig->sig_class == 0x30) sigstr = "rev"; else if ((sig->sig_class & ~3) == 0x10) sigstr = "sig"; else if (sig->sig_class == 0x18) sigstr = "sig"; else if (sig->sig_class == 0x1F) sigstr = "sig"; else { es_fprintf (es_stdout, "sig " "[unexpected signature class 0x%02x]\n", sig->sig_class); continue; } es_fputs (sigstr, es_stdout); es_fprintf (es_stdout, "%c%c %c%c%c%c%c%c %s %s", sigrc, (sig->sig_class - 0x10 > 0 && sig->sig_class - 0x10 < 4) ? '0' + sig->sig_class - 0x10 : ' ', sig->flags.exportable ? ' ' : 'L', sig->flags.revocable ? ' ' : 'R', sig->flags.policy_url ? 'P' : ' ', sig->flags.notation ? 'N' : ' ', sig->flags.expired ? 'X' : ' ', (sig->trust_depth > 9) ? 'T' : (sig->trust_depth > 0) ? '0' + sig->trust_depth : ' ', keystr (sig->keyid), datestr_from_sig (sig)); if (opt.list_options & LIST_SHOW_SIG_EXPIRE) es_fprintf (es_stdout, " %s", expirestr_from_sig (sig)); es_fprintf (es_stdout, " "); if (sigrc == '%') es_fprintf (es_stdout, "[%s] ", g10_errstr (rc)); else if (sigrc == '?') ; else if (!opt.fast_list_mode) { size_t n; char *p = get_user_id (sig->keyid, &n); print_utf8_buffer (es_stdout, p, n); xfree (p); } es_putc ('\n', es_stdout); if (sig->flags.policy_url && (opt.list_options & LIST_SHOW_POLICY_URLS)) show_policy_url (sig, 3, 0); if (sig->flags.notation && (opt.list_options & LIST_SHOW_NOTATIONS)) show_notation (sig, 3, 0, ((opt. list_options & LIST_SHOW_STD_NOTATIONS) ? 1 : 0) + ((opt. list_options & LIST_SHOW_USER_NOTATIONS) ? 2 : 0)); if (sig->flags.pref_ks && (opt.list_options & LIST_SHOW_KEYSERVER_URLS)) show_keyserver_url (sig, 3, 0); /* fixme: check or list other sigs here */ } } es_putc ('\n', es_stdout); xfree (serialno); xfree (hexgrip); } void print_revokers (PKT_public_key * pk) { /* print the revoker record */ if (!pk->revkey && pk->numrevkeys) BUG (); else { int i, j; for (i = 0; i < pk->numrevkeys; i++) { byte *p; es_fprintf (es_stdout, "rvk:::%d::::::", pk->revkey[i].algid); p = pk->revkey[i].fpr; for (j = 0; j < 20; j++, p++) es_fprintf (es_stdout, "%02X", *p); es_fprintf (es_stdout, ":%02x%s:\n", pk->revkey[i].class, (pk->revkey[i].class & 0x40) ? "s" : ""); } } } static void list_keyblock_colon (KBNODE keyblock, int secret, int fpr) { int rc; KBNODE kbctx; KBNODE node; PKT_public_key *pk; u32 keyid[2]; int trustletter = 0; int ulti_hack = 0; int i; char *p; char *hexgrip = NULL; char *serialno = NULL; int stubkey; /* Get the keyid from the keyblock. */ node = find_kbnode (keyblock, PKT_PUBLIC_KEY); if (!node) { log_error ("Oops; key lost!\n"); dump_kbnode (keyblock); return; } pk = node->pkt->pkt.public_key; if (secret || opt.with_keygrip || opt.with_key_data) { rc = hexkeygrip_from_pk (pk, &hexgrip); if (rc) log_error ("error computing a keygrip: %s\n", gpg_strerror (rc)); } stubkey = 0; if (secret && agent_get_keyinfo (NULL, hexgrip, &serialno)) stubkey = 1; /* Key not found. */ keyid_from_pk (pk, keyid); es_fputs (secret? "sec:":"pub:", es_stdout); if (!pk->flags.valid) es_putc ('i', es_stdout); else if (pk->flags.revoked) es_putc ('r', es_stdout); else if (pk->has_expired) es_putc ('e', es_stdout); else if (opt.fast_list_mode || opt.no_expensive_trust_checks) ; else { trustletter = get_validity_info (pk, NULL); if (trustletter == 'u') ulti_hack = 1; es_putc (trustletter, es_stdout); } es_fprintf (es_stdout, ":%u:%d:%08lX%08lX:%s:%s::", nbits_from_pk (pk), pk->pubkey_algo, (ulong) keyid[0], (ulong) keyid[1], colon_datestr_from_pk (pk), colon_strtime (pk->expiredate)); if (!opt.fast_list_mode && !opt.no_expensive_trust_checks) es_putc (get_ownertrust_info (pk), es_stdout); es_putc (':', es_stdout); es_putc (':', es_stdout); es_putc (':', es_stdout); print_capabilities (pk, keyblock); es_putc (':', es_stdout); /* End of field 13. */ es_putc (':', es_stdout); /* End of field 14. */ if (secret) { if (stubkey) es_putc ('#', es_stdout); else if (serialno) es_fputs (serialno, es_stdout); } es_putc (':', es_stdout); /* End of field 15. */ es_putc (':', es_stdout); /* End of field 16. */ if (pk->pubkey_algo == PUBKEY_ALGO_ECDSA + || pk->pubkey_algo == PUBKEY_ALGO_EDDSA || pk->pubkey_algo == PUBKEY_ALGO_ECDH) { char *curve = openpgp_oid_to_str (pk->pkey[0]); const char *name = openpgp_oid_to_curve (curve); if (!*name || *name == '?') name = curve; es_fputs (name, es_stdout); xfree (curve); } es_putc (':', es_stdout); /* End of field 17. */ es_putc ('\n', es_stdout); print_revokers (pk); if (fpr) print_fingerprint (pk, 0); if (opt.with_key_data || opt.with_keygrip) { if (hexgrip) es_fprintf (es_stdout, "grp:::::::::%s:\n", hexgrip); if (opt.with_key_data) print_key_data (pk); } for (kbctx = NULL; (node = walk_kbnode (keyblock, &kbctx, 0));) { if (node->pkt->pkttype == PKT_USER_ID && !opt.fast_list_mode) { char *str; PKT_user_id *uid = node->pkt->pkt.user_id; if (attrib_fp && node->pkt->pkt.user_id->attrib_data != NULL) dump_attribs (node->pkt->pkt.user_id, pk); /* * Fixme: We need a valid flag here too */ str = uid->attrib_data ? "uat" : "uid"; if (uid->is_revoked) es_fprintf (es_stdout, "%s:r::::", str); else if (uid->is_expired) es_fprintf (es_stdout, "%s:e::::", str); else if (opt.no_expensive_trust_checks) es_fprintf (es_stdout, "%s:::::", str); else { int uid_validity; if (pk && !ulti_hack) uid_validity = get_validity_info (pk, uid); else uid_validity = 'u'; es_fprintf (es_stdout, "%s:%c::::", str, uid_validity); } es_fprintf (es_stdout, "%s:", colon_strtime (uid->created)); es_fprintf (es_stdout, "%s:", colon_strtime (uid->expiredate)); namehash_from_uid (uid); for (i = 0; i < 20; i++) es_fprintf (es_stdout, "%02X", uid->namehash[i]); es_fprintf (es_stdout, "::"); if (uid->attrib_data) es_fprintf (es_stdout, "%u %lu", uid->numattribs, uid->attrib_len); else es_write_sanitized (es_stdout, uid->name, uid->len, ":", NULL); es_putc (':', es_stdout); es_putc ('\n', es_stdout); } else if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY) { u32 keyid2[2]; PKT_public_key *pk2; pk2 = node->pkt->pkt.public_key; xfree (hexgrip); hexgrip = NULL; xfree (serialno); serialno = NULL; if (secret || opt.with_keygrip || opt.with_key_data) { rc = hexkeygrip_from_pk (pk2, &hexgrip); if (rc) log_error ("error computing a keygrip: %s\n", gpg_strerror (rc)); } stubkey = 0; if (secret && agent_get_keyinfo (NULL, hexgrip, &serialno)) stubkey = 1; /* Key not found. */ keyid_from_pk (pk2, keyid2); es_fputs (secret? "ssb:":"sub:", es_stdout); if (!pk2->flags.valid) es_putc ('i', es_stdout); else if (pk2->flags.revoked) es_putc ('r', es_stdout); else if (pk2->has_expired) es_putc ('e', es_stdout); else if (opt.fast_list_mode || opt.no_expensive_trust_checks) ; else { /* TRUSTLETTER should always be defined here. */ if (trustletter) es_fprintf (es_stdout, "%c", trustletter); } es_fprintf (es_stdout, ":%u:%d:%08lX%08lX:%s:%s:::::", nbits_from_pk (pk2), pk2->pubkey_algo, (ulong) keyid2[0], (ulong) keyid2[1], colon_datestr_from_pk (pk2), colon_strtime (pk2->expiredate) /* fixme: add LID and ownertrust here */ ); print_capabilities (pk2, NULL); es_putc (':', es_stdout); /* End of field 13. */ es_putc (':', es_stdout); /* End of field 14. */ if (secret) { if (stubkey) es_putc ('#', es_stdout); else if (serialno) es_fputs (serialno, es_stdout); } es_putc (':', es_stdout); /* End of field 15. */ es_putc (':', es_stdout); /* End of field 16. */ if (pk->pubkey_algo == PUBKEY_ALGO_ECDSA + || pk->pubkey_algo == PUBKEY_ALGO_EDDSA || pk->pubkey_algo == PUBKEY_ALGO_ECDH) { char *curve = openpgp_oid_to_str (pk->pkey[0]); const char *name = openpgp_oid_to_curve (curve); if (!*name || *name == '?') name = curve; es_fputs (name, es_stdout); xfree (curve); } es_putc (':', es_stdout); /* End of field 17. */ es_putc ('\n', es_stdout); if (fpr > 1) print_fingerprint (pk2, 0); if (opt.with_key_data || opt.with_keygrip) { if (hexgrip) es_fprintf (es_stdout, "grp:::::::::%s:\n", hexgrip); if (opt.with_key_data) print_key_data (pk2); } } else if (opt.list_sigs && node->pkt->pkttype == PKT_SIGNATURE) { PKT_signature *sig = node->pkt->pkt.signature; int sigrc, fprokay = 0; char *sigstr; size_t fplen; byte fparray[MAX_FINGERPRINT_LEN]; if (sig->sig_class == 0x20 || sig->sig_class == 0x28 || sig->sig_class == 0x30) sigstr = "rev"; else if ((sig->sig_class & ~3) == 0x10) sigstr = "sig"; else if (sig->sig_class == 0x18) sigstr = "sig"; else if (sig->sig_class == 0x1F) sigstr = "sig"; else { es_fprintf (es_stdout, "sig::::::::::%02x%c:\n", sig->sig_class, sig->flags.exportable ? 'x' : 'l'); continue; } if (opt.check_sigs) { PKT_public_key *signer_pk = NULL; fflush (stdout); if (opt.no_sig_cache) signer_pk = xmalloc_clear (sizeof (PKT_public_key)); rc = check_key_signature2 (keyblock, node, NULL, signer_pk, NULL, NULL, NULL); switch (gpg_err_code (rc)) { case 0: sigrc = '!'; break; case GPG_ERR_BAD_SIGNATURE: sigrc = '-'; break; case GPG_ERR_NO_PUBKEY: case GPG_ERR_UNUSABLE_PUBKEY: sigrc = '?'; break; default: sigrc = '%'; break; } if (opt.no_sig_cache) { if (!rc) { fingerprint_from_pk (signer_pk, fparray, &fplen); fprokay = 1; } free_public_key (signer_pk); } } else { rc = 0; sigrc = ' '; } es_fputs (sigstr, es_stdout); es_putc (':', es_stdout); if (sigrc != ' ') es_putc (sigrc, es_stdout); es_fprintf (es_stdout, "::%d:%08lX%08lX:%s:%s:", sig->pubkey_algo, (ulong) sig->keyid[0], (ulong) sig->keyid[1], colon_datestr_from_sig (sig), colon_expirestr_from_sig (sig)); if (sig->trust_depth || sig->trust_value) es_fprintf (es_stdout, "%d %d", sig->trust_depth, sig->trust_value); es_fprintf (es_stdout, ":"); if (sig->trust_regexp) es_write_sanitized (es_stdout, sig->trust_regexp, strlen (sig->trust_regexp), ":", NULL); es_fprintf (es_stdout, ":"); if (sigrc == '%') es_fprintf (es_stdout, "[%s] ", g10_errstr (rc)); else if (sigrc == '?') ; else if (!opt.fast_list_mode) { size_t n; p = get_user_id (sig->keyid, &n); es_write_sanitized (es_stdout, p, n, ":", NULL); xfree (p); } es_fprintf (es_stdout, ":%02x%c::", sig->sig_class, sig->flags.exportable ? 'x' : 'l'); if (opt.no_sig_cache && opt.check_sigs && fprokay) { for (i = 0; i < fplen; i++) es_fprintf (es_stdout, "%02X", fparray[i]); } es_fprintf (es_stdout, ":::%d:\n", sig->digest_algo); if (opt.show_subpackets) print_subpackets_colon (sig); /* fixme: check or list other sigs here */ } } xfree (hexgrip); xfree (serialno); } /* * Reorder the keyblock so that the primary user ID (and not attribute * packet) comes first. Fixme: Replace this by a generic sort * function. */ static void do_reorder_keyblock (KBNODE keyblock, int attr) { KBNODE primary = NULL, primary0 = NULL, primary2 = NULL; KBNODE last, node; for (node = keyblock; node; primary0 = node, node = node->next) { if (node->pkt->pkttype == PKT_USER_ID && ((attr && node->pkt->pkt.user_id->attrib_data) || (!attr && !node->pkt->pkt.user_id->attrib_data)) && node->pkt->pkt.user_id->is_primary) { primary = primary2 = node; for (node = node->next; node; primary2 = node, node = node->next) { if (node->pkt->pkttype == PKT_USER_ID || node->pkt->pkttype == PKT_PUBLIC_SUBKEY || node->pkt->pkttype == PKT_SECRET_SUBKEY) { break; } } break; } } if (!primary) return; /* No primary key flag found (should not happen). */ for (last = NULL, node = keyblock; node; last = node, node = node->next) { if (node->pkt->pkttype == PKT_USER_ID) break; } assert (node); assert (last); /* The user ID is never the first packet. */ assert (primary0); /* Ditto (this is the node before primary). */ if (node == primary) return; /* Already the first one. */ last->next = primary; primary0->next = primary2->next; primary2->next = node; } void reorder_keyblock (KBNODE keyblock) { do_reorder_keyblock (keyblock, 1); do_reorder_keyblock (keyblock, 0); } void list_keyblock (KBNODE keyblock, int secret, int fpr, void *opaque) { reorder_keyblock (keyblock); if (opt.with_colons) list_keyblock_colon (keyblock, secret, fpr); else list_keyblock_print (keyblock, secret, fpr, opaque); } /* * Function to print the finperprint. * mode 0: as used in key listings, opt.with_colons is honored * 1: print using log_info () * 2: direct use of tty * 3: direct use of tty but only primary key. * * Modes 1 and 2 will try and print both subkey and primary key * fingerprints. A MODE with bit 7 set is used internally. */ void print_fingerprint (PKT_public_key *pk, int mode) { byte array[MAX_FINGERPRINT_LEN], *p; size_t i, n; estream_t fp; const char *text; int primary = 0; if (pk->main_keyid[0] == pk->keyid[0] && pk->main_keyid[1] == pk->keyid[1]) primary = 1; /* Just to be safe */ if ((mode & 0x80) && !primary) { log_error ("primary key is not really primary!\n"); return; } mode &= ~0x80; if (!primary && (mode == 1 || mode == 2)) { PKT_public_key *primary_pk = xmalloc_clear (sizeof (*primary_pk)); get_pubkey (primary_pk, pk->main_keyid); print_fingerprint (primary_pk, mode | 0x80); free_public_key (primary_pk); } if (mode == 1) { fp = log_get_stream (); if (primary) text = _("Primary key fingerprint:"); else text = _(" Subkey fingerprint:"); } else if (mode == 2) { fp = NULL; /* Use tty. */ if (primary) /* TRANSLATORS: this should fit into 24 bytes to that the * fingerprint data is properly aligned with the user ID */ text = _(" Primary key fingerprint:"); else text = _(" Subkey fingerprint:"); } else if (mode == 3) { fp = NULL; /* Use tty. */ text = _(" Key fingerprint ="); } else { fp = es_stdout; text = _(" Key fingerprint ="); } fingerprint_from_pk (pk, array, &n); p = array; if (opt.with_colons && !mode) { es_fprintf (fp, "fpr:::::::::"); for (i = 0; i < n; i++, p++) es_fprintf (fp, "%02X", *p); es_putc (':', fp); } else { tty_fprintf (fp, "%s", text); if (n == 20) { for (i = 0; i < n; i++, i++, p += 2) tty_fprintf (fp, "%s %02X%02X", i==10? " ":"", *p, p[1]); } else { for (i = 0; i < n; i++, p++) tty_fprintf (fp, "%s %02X", (i && !(i % 8))? " ":"", *p); } } tty_fprintf (fp, "\n"); } /* Print the serial number of an OpenPGP card if available. */ static void print_card_serialno (const char *serialno) { if (!serialno) return; if (opt.with_colons) return; /* Handled elsewhere. */ es_fputs (_(" Card serial no. ="), es_stdout); es_putc (' ', es_stdout); if (strlen (serialno) == 32 && !strncmp (serialno, "D27600012401", 12)) { /* This is an OpenPGP card. Print the relevant part. */ /* Example: D2760001240101010001000003470000 */ /* xxxxyyyyyyyy */ es_fprintf (es_stdout, "%.*s %.*s", 4, serialno+16, 8, serialno+20); } else es_fputs (serialno, es_stdout); es_putc ('\n', es_stdout); } void set_attrib_fd (int fd) { static int last_fd = -1; if (fd != -1 && last_fd == fd) return; /* Fixme: Do we need to check for the log stream here? */ if (attrib_fp && attrib_fp != log_get_stream ()) es_fclose (attrib_fp); attrib_fp = NULL; if (fd == -1) return; #ifdef HAVE_DOSISH_SYSTEM setmode (fd, O_BINARY); #endif if (fd == 1) attrib_fp = es_stdout; else if (fd == 2) attrib_fp = es_stderr; else attrib_fp = es_fdopen (fd, "wb"); if (!attrib_fp) { log_fatal ("can't open fd %d for attribute output: %s\n", fd, strerror (errno)); } last_fd = fd; } diff --git a/g10/keyserver.c b/g10/keyserver.c index 0ec616bc0..0f60f7d37 100644 --- a/g10/keyserver.c +++ b/g10/keyserver.c @@ -1,1899 +1,1899 @@ /* keyserver.c - generic keyserver code * Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, * 2009, 2011, 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 #include #include "gpg.h" #include "iobuf.h" #include "filter.h" #include "keydb.h" #include "status.h" #include "exec.h" #include "main.h" #include "i18n.h" #include "ttyio.h" #include "options.h" #include "packet.h" #include "trustdb.h" #include "keyserver-internal.h" #include "util.h" #include "dns-cert.h" #include "pka.h" #ifdef USE_DNS_SRV #include "srv.h" #endif #include "membuf.h" #include "call-dirmngr.h" #ifdef HAVE_W32_SYSTEM /* It seems Vista doesn't grok X_OK and so fails access() tests. Previous versions interpreted X_OK as F_OK anyway, so we'll just use F_OK directly. */ #undef X_OK #define X_OK F_OK #endif /* HAVE_W32_SYSTEM */ struct keyrec { KEYDB_SEARCH_DESC desc; u32 createtime,expiretime; int size,flags; byte type; IOBUF uidbuf; unsigned int lines; }; /* Parameters for the search line handler. */ struct search_line_handler_parm_s { ctrl_t ctrl; /* The session control structure. */ char *searchstr_disp; /* Native encoded search string or NULL. */ KEYDB_SEARCH_DESC *desc; /* Array with search descriptions. */ int count; /* Number of keys we are currently prepared to handle. This is the size of the DESC array. If it is too small, it will grow safely. */ int validcount; /* Enable the "Key x-y of z" messages. */ int nkeys; /* Number of processed records. */ int any_lines; /* At least one line has been processed. */ unsigned int numlines; /* Counter for displayed lines. */ int eof_seen; /* EOF encountered. */ int not_found; /* Set if no keys have been found. */ }; enum ks_action {KS_UNKNOWN=0,KS_GET,KS_GETNAME,KS_SEND,KS_SEARCH}; static struct parse_options keyserver_opts[]= { /* some of these options are not real - just for the help message */ {"max-cert-size",0,NULL,NULL}, {"include-revoked",0,NULL,N_("include revoked keys in search results")}, {"include-subkeys",0,NULL,N_("include subkeys when searching by key ID")}, {"use-temp-files",0,NULL, N_("use temporary files to pass data to keyserver helpers")}, {"keep-temp-files",KEYSERVER_KEEP_TEMP_FILES,NULL, N_("do not delete temporary files after using them")}, {"refresh-add-fake-v3-keyids",KEYSERVER_ADD_FAKE_V3,NULL, NULL}, {"auto-key-retrieve",KEYSERVER_AUTO_KEY_RETRIEVE,NULL, N_("automatically retrieve keys when verifying signatures")}, {"honor-keyserver-url",KEYSERVER_HONOR_KEYSERVER_URL,NULL, N_("honor the preferred keyserver URL set on the key")}, {"honor-pka-record",KEYSERVER_HONOR_PKA_RECORD,NULL, N_("honor the PKA record set on a key when retrieving keys")}, {NULL,0,NULL,NULL} }; static gpg_error_t keyserver_get (ctrl_t ctrl, KEYDB_SEARCH_DESC *desc, int ndesc, struct keyserver_spec *keyserver); static gpg_error_t keyserver_put (ctrl_t ctrl, strlist_t keyspecs, struct keyserver_spec *keyserver); /* Reasonable guess. The commonly used test key simon.josefsson.org is larger than 32k, thus we need at least this value. */ #define DEFAULT_MAX_CERT_SIZE 65536 static size_t max_cert_size=DEFAULT_MAX_CERT_SIZE; static void add_canonical_option(char *option,strlist_t *list) { char *arg=argsplit(option); if(arg) { char *joined; joined=xmalloc(strlen(option)+1+strlen(arg)+1); /* Make a canonical name=value form with no spaces */ strcpy(joined,option); strcat(joined,"="); strcat(joined,arg); append_to_strlist(list,joined); xfree(joined); } else append_to_strlist(list,option); } int parse_keyserver_options(char *options) { int ret=1; char *tok; char *max_cert=NULL; keyserver_opts[0].value=&max_cert; while((tok=optsep(&options))) { if(tok[0]=='\0') continue; /* For backwards compatibility. 1.2.x used honor-http-proxy and there are a good number of documents published that recommend it. */ if(ascii_strcasecmp(tok,"honor-http-proxy")==0) tok="http-proxy"; else if(ascii_strcasecmp(tok,"no-honor-http-proxy")==0) tok="no-http-proxy"; /* We accept quite a few possible options here - some options to handle specially, the keyserver_options list, and import and export options that pertain to keyserver operations. Note that you must use strncasecmp here as there might be an =argument attached which will foil the use of strcasecmp. */ #ifdef EXEC_TEMPFILE_ONLY if(ascii_strncasecmp(tok,"use-temp-files",14)==0 || ascii_strncasecmp(tok,"no-use-temp-files",17)==0) log_info(_("WARNING: keyserver option '%s' is not used" " on this platform\n"),tok); #else if(ascii_strncasecmp(tok,"use-temp-files",14)==0) opt.keyserver_options.options|=KEYSERVER_USE_TEMP_FILES; else if(ascii_strncasecmp(tok,"no-use-temp-files",17)==0) opt.keyserver_options.options&=~KEYSERVER_USE_TEMP_FILES; #endif else if(!parse_options(tok,&opt.keyserver_options.options, keyserver_opts,0) && !parse_import_options(tok, &opt.keyserver_options.import_options,0) && !parse_export_options(tok, &opt.keyserver_options.export_options,0)) { /* All of the standard options have failed, so the option is destined for a keyserver plugin. */ add_canonical_option(tok,&opt.keyserver_options.other); } } if(max_cert) { max_cert_size=strtoul(max_cert,(char **)NULL,10); if(max_cert_size==0) max_cert_size=DEFAULT_MAX_CERT_SIZE; } return ret; } void free_keyserver_spec(struct keyserver_spec *keyserver) { xfree(keyserver->uri); xfree(keyserver->scheme); xfree(keyserver->auth); xfree(keyserver->host); xfree(keyserver->port); xfree(keyserver->path); xfree(keyserver->opaque); free_strlist(keyserver->options); xfree(keyserver); } /* Return 0 for match */ static int cmp_keyserver_spec(struct keyserver_spec *one,struct keyserver_spec *two) { if(ascii_strcasecmp(one->scheme,two->scheme)==0) { if(one->host && two->host && ascii_strcasecmp(one->host,two->host)==0) { if((one->port && two->port && ascii_strcasecmp(one->port,two->port)==0) || (!one->port && !two->port)) return 0; } else if(one->opaque && two->opaque && ascii_strcasecmp(one->opaque,two->opaque)==0) return 0; } return 1; } /* Try and match one of our keyservers. If we can, return that. If we can't, return our input. */ struct keyserver_spec * keyserver_match(struct keyserver_spec *spec) { struct keyserver_spec *ks; for(ks=opt.keyserver;ks;ks=ks->next) if(cmp_keyserver_spec(spec,ks)==0) return ks; return spec; } /* TODO: once we cut over to an all-curl world, we don't need this parser any longer so it can be removed, or at least moved to keyserver/ksutil.c for limited use in gpgkeys_ldap or the like. */ keyserver_spec_t parse_keyserver_uri (const char *string,int require_scheme, const char *configname,unsigned int configlineno) { int assume_hkp=0; struct keyserver_spec *keyserver; const char *idx; int count; char *uri,*options; assert(string!=NULL); keyserver=xmalloc_clear(sizeof(struct keyserver_spec)); uri=xstrdup(string); options=strchr(uri,' '); if(options) { char *tok; *options='\0'; options++; while((tok=optsep(&options))) add_canonical_option(tok,&keyserver->options); } /* Get the scheme */ for(idx=uri,count=0;*idx && *idx!=':';idx++) { count++; /* Do we see the start of an RFC-2732 ipv6 address here? If so, there clearly isn't a scheme so get out early. */ if(*idx=='[') { /* Was the '[' the first thing in the string? If not, we have a mangled scheme with a [ in it so fail. */ if(count==1) break; else goto fail; } } if(count==0) goto fail; if(*idx=='\0' || *idx=='[') { if(require_scheme) return NULL; /* Assume HKP if there is no scheme */ assume_hkp=1; keyserver->scheme=xstrdup("hkp"); keyserver->uri=xmalloc(strlen(keyserver->scheme)+3+strlen(uri)+1); strcpy(keyserver->uri,keyserver->scheme); strcat(keyserver->uri,"://"); strcat(keyserver->uri,uri); } else { int i; keyserver->uri=xstrdup(uri); keyserver->scheme=xmalloc(count+1); /* Force to lowercase */ for(i=0;ischeme[i]=ascii_tolower(uri[i]); keyserver->scheme[i]='\0'; /* Skip past the scheme and colon */ uri+=count+1; } if(ascii_strcasecmp(keyserver->scheme,"x-broken-hkp")==0) { deprecated_warning(configname,configlineno,"x-broken-hkp", "--keyserver-options ","broken-http-proxy"); xfree(keyserver->scheme); keyserver->scheme=xstrdup("hkp"); append_to_strlist(&opt.keyserver_options.other,"broken-http-proxy"); } else if(ascii_strcasecmp(keyserver->scheme,"x-hkp")==0) { /* Canonicalize this to "hkp" so it works with both the internal and external keyserver interface. */ xfree(keyserver->scheme); keyserver->scheme=xstrdup("hkp"); } if (uri[0]=='/' && uri[1]=='/' && uri[2] == '/') { /* Three slashes means network path with a default host name. This is a hack because it does not crok all possible combiantions. We should better repalce all code bythe parser from http.c. */ keyserver->path = xstrdup (uri+2); } else if(assume_hkp || (uri[0]=='/' && uri[1]=='/')) { /* Two slashes means network path. */ /* Skip over the "//", if any */ if(!assume_hkp) uri+=2; /* Do we have userinfo auth data present? */ for(idx=uri,count=0;*idx && *idx!='@' && *idx!='/';idx++) count++; /* We found a @ before the slash, so that means everything before the @ is auth data. */ if(*idx=='@') { if(count==0) goto fail; keyserver->auth=xmalloc(count+1); strncpy(keyserver->auth,uri,count); keyserver->auth[count]='\0'; uri+=count+1; } /* Is it an RFC-2732 ipv6 [literal address] ? */ if(*uri=='[') { for(idx=uri+1,count=1;*idx && ((isascii (*idx) && isxdigit(*idx)) || *idx==':' || *idx=='.');idx++) count++; /* Is the ipv6 literal address terminated? */ if(*idx==']') count++; else goto fail; } else for(idx=uri,count=0;*idx && *idx!=':' && *idx!='/';idx++) count++; if(count==0) goto fail; keyserver->host=xmalloc(count+1); strncpy(keyserver->host,uri,count); keyserver->host[count]='\0'; /* Skip past the host */ uri+=count; if(*uri==':') { /* It would seem to be reasonable to limit the range of the ports to values between 1-65535, but RFC 1738 and 1808 imply there is no limit. Of course, the real world has limits. */ for(idx=uri+1,count=0;*idx && *idx!='/';idx++) { count++; /* Ports are digits only */ if(!digitp(idx)) goto fail; } keyserver->port=xmalloc(count+1); strncpy(keyserver->port,uri+1,count); keyserver->port[count]='\0'; /* Skip past the colon and port number */ uri+=1+count; } /* Everything else is the path */ if(*uri) keyserver->path=xstrdup(uri); else keyserver->path=xstrdup("/"); if(keyserver->path[1]) keyserver->flags.direct_uri=1; } else if(uri[0]!='/') { /* No slash means opaque. Just record the opaque blob and get out. */ keyserver->opaque=xstrdup(uri); } else { /* One slash means absolute path. We don't need to support that yet. */ goto fail; } return keyserver; fail: free_keyserver_spec(keyserver); return NULL; } struct keyserver_spec * parse_preferred_keyserver(PKT_signature *sig) { struct keyserver_spec *spec=NULL; const byte *p; size_t plen; p=parse_sig_subpkt(sig->hashed,SIGSUBPKT_PREF_KS,&plen); if(p && plen) { byte *dupe=xmalloc(plen+1); memcpy(dupe,p,plen); dupe[plen]='\0'; spec=parse_keyserver_uri(dupe,1,NULL,0); xfree(dupe); } return spec; } static void print_keyrec(int number,struct keyrec *keyrec) { int i; iobuf_writebyte(keyrec->uidbuf,0); iobuf_flush_temp(keyrec->uidbuf); es_printf ("(%d)\t%s ", number, iobuf_get_temp_buffer (keyrec->uidbuf)); if (keyrec->size>0) es_printf ("%d bit ", keyrec->size); if(keyrec->type) { const char *str; - str = gcry_pk_algo_name (map_pk_openpgp_to_gcry (keyrec->type)); + str = openpgp_pk_algo_name (keyrec->type); if (str && strcmp (str, "?")) es_printf ("%s ",str); else es_printf ("unknown "); } switch(keyrec->desc.mode) { /* If the keyserver helper gave us a short keyid, we have no choice but to use it. Do check --keyid-format to add a 0x if needed. */ case KEYDB_SEARCH_MODE_SHORT_KID: es_printf ("key %s%08lX", (opt.keyid_format==KF_0xSHORT || opt.keyid_format==KF_0xLONG)?"0x":"", (ulong)keyrec->desc.u.kid[1]); break; /* However, if it gave us a long keyid, we can honor --keyid-format via keystr(). */ case KEYDB_SEARCH_MODE_LONG_KID: es_printf ("key %s",keystr(keyrec->desc.u.kid)); break; /* If it gave us a PGP 2.x fingerprint, not much we can do beyond displaying it. */ case KEYDB_SEARCH_MODE_FPR16: es_printf ("key "); for(i=0;i<16;i++) es_printf ("%02X",keyrec->desc.u.fpr[i]); break; /* If we get a modern fingerprint, we have the most flexibility. */ case KEYDB_SEARCH_MODE_FPR20: { u32 kid[2]; keyid_from_fingerprint(keyrec->desc.u.fpr,20,kid); es_printf("key %s",keystr(kid)); } break; default: BUG(); break; } if(keyrec->createtime>0) { es_printf (", "); es_printf (_("created: %s"), strtimestamp(keyrec->createtime)); } if(keyrec->expiretime>0) { es_printf (", "); es_printf (_("expires: %s"), strtimestamp(keyrec->expiretime)); } if (keyrec->flags&1) es_printf (" (%s)", _("revoked")); if(keyrec->flags&2) es_printf (" (%s)", _("disabled")); if(keyrec->flags&4) es_printf (" (%s)", _("expired")); es_printf ("\n"); } /* Returns a keyrec (which must be freed) once a key is complete, and NULL otherwise. Call with a NULL keystring once key parsing is complete to return any unfinished keys. */ static struct keyrec * parse_keyrec(char *keystring) { /* FIXME: Remove the static and put the data into the parms we use for the caller anyway. */ static struct keyrec *work=NULL; struct keyrec *ret=NULL; char *record; int i; if(keystring==NULL) { if(work==NULL) return NULL; else if(work->desc.mode==KEYDB_SEARCH_MODE_NONE) { xfree(work); return NULL; } else { ret=work; work=NULL; return ret; } } if(work==NULL) { work=xmalloc_clear(sizeof(struct keyrec)); work->uidbuf=iobuf_temp(); } trim_trailing_ws (keystring, strlen (keystring)); if((record=strsep(&keystring,":"))==NULL) return ret; if(ascii_strcasecmp("pub",record)==0) { char *tok; gpg_error_t err; if(work->desc.mode) { ret=work; work=xmalloc_clear(sizeof(struct keyrec)); work->uidbuf=iobuf_temp(); } if((tok=strsep(&keystring,":"))==NULL) return ret; err = classify_user_id (tok, &work->desc, 1); if (err || (work->desc.mode != KEYDB_SEARCH_MODE_SHORT_KID && work->desc.mode != KEYDB_SEARCH_MODE_LONG_KID && work->desc.mode != KEYDB_SEARCH_MODE_FPR16 && work->desc.mode != KEYDB_SEARCH_MODE_FPR20)) { work->desc.mode=KEYDB_SEARCH_MODE_NONE; return ret; } /* Note all items after this are optional. This allows us to have a pub line as simple as pub:keyid and nothing else. */ work->lines++; if((tok=strsep(&keystring,":"))==NULL) return ret; work->type=atoi(tok); if((tok=strsep(&keystring,":"))==NULL) return ret; work->size=atoi(tok); if((tok=strsep(&keystring,":"))==NULL) return ret; if(atoi(tok)<=0) work->createtime=0; else work->createtime=atoi(tok); if((tok=strsep(&keystring,":"))==NULL) return ret; if(atoi(tok)<=0) work->expiretime=0; else { work->expiretime=atoi(tok); /* Force the 'e' flag on if this key is expired. */ if(work->expiretime<=make_timestamp()) work->flags|=4; } if((tok=strsep(&keystring,":"))==NULL) return ret; while(*tok) switch(*tok++) { case 'r': case 'R': work->flags|=1; break; case 'd': case 'D': work->flags|=2; break; case 'e': case 'E': work->flags|=4; break; } } else if(ascii_strcasecmp("uid",record)==0 && work->desc.mode) { char *userid,*tok,*decoded; if((tok=strsep(&keystring,":"))==NULL) return ret; if(strlen(tok)==0) return ret; userid=tok; /* By definition, de-%-encoding is always smaller than the original string so we can decode in place. */ i=0; while(*tok) if(tok[0]=='%' && tok[1] && tok[2]) { int c; userid[i] = (c=hextobyte(&tok[1])) == -1 ? '?' : c; i++; tok+=3; } else userid[i++]=*tok++; /* We don't care about the other info provided in the uid: line since no keyserver supports marking userids with timestamps or revoked/expired/disabled yet. */ /* No need to check for control characters, as utf8_to_native does this for us. */ decoded=utf8_to_native(userid,i,0); if(strlen(decoded)>opt.screen_columns-10) decoded[opt.screen_columns-10]='\0'; iobuf_writestr(work->uidbuf,decoded); xfree(decoded); iobuf_writestr(work->uidbuf,"\n\t"); work->lines++; } /* Ignore any records other than "pri" and "uid" for easy future growth. */ return ret; } /* Show a prompt and allow the user to select keys for retrieval. */ static gpg_error_t show_prompt (ctrl_t ctrl, KEYDB_SEARCH_DESC *desc, int numdesc, int count, const char *search) { gpg_error_t err; char *answer = NULL; es_fflush (es_stdout); if (count && opt.command_fd == -1) { static int from = 1; tty_printf ("Keys %d-%d of %d for \"%s\". ", from, numdesc, count, search); from = numdesc + 1; } again: err = 0; xfree (answer); answer = cpr_get_no_help ("keysearch.prompt", _("Enter number(s), N)ext, or Q)uit > ")); /* control-d */ if (answer[0]=='\x04') { tty_printf ("Q\n"); answer[0] = 'q'; } if (answer[0]=='q' || answer[0]=='Q') err = gpg_error (GPG_ERR_CANCELED); else if (atoi (answer) >= 1 && atoi (answer) <= numdesc) { char *split = answer; char *num; int numarray[50]; int numidx = 0; int idx; while ((num = strsep (&split, " ,"))) if (atoi (num) >= 1 && atoi (num) <= numdesc) { if (numidx >= DIM (numarray)) { tty_printf ("Too many keys selected\n"); goto again; } numarray[numidx++] = atoi (num); } if (!numidx) goto again; { KEYDB_SEARCH_DESC *selarray; selarray = xtrymalloc (numidx * sizeof *selarray); if (!selarray) { err = gpg_error_from_syserror (); goto leave; } for (idx = 0; idx < numidx; idx++) selarray[idx] = desc[numarray[idx]-1]; err = keyserver_get (ctrl, selarray, numidx, NULL); xfree (selarray); } } leave: xfree (answer); return err; } /* This is a callback used by call-dirmngr.c to process the result of KS_SEARCH command. LINE is the actual data line received with all escaping removed and guaranteed to be exactly one line with stripped LF; an EOF is indicated by LINE passed as NULL. LINE may be modified after return. */ static gpg_error_t search_line_handler (void *opaque, char *line) { struct search_line_handler_parm_s *parm = opaque; gpg_error_t err = 0; struct keyrec *keyrec; if (parm->eof_seen && line) { log_debug ("ooops: unexpected data after EOF\n"); line = NULL; } /* Print the received line. */ if (opt.with_colons && line) { log_debug ("%s\n",line); } /* Look for an info: line. The only current info: values defined are the version and key count. */ if (line && !parm->any_lines && !ascii_strncasecmp ("info:", line, 5)) { char *str = line + 5; char *tok; if ((tok = strsep (&str, ":"))) { int version; if (sscanf (tok, "%d", &version) !=1 ) version = 1; if (version !=1 ) { log_error (_("invalid keyserver protocol " "(us %d!=handler %d)\n"), 1, version); return gpg_error (GPG_ERR_UNSUPPORTED_PROTOCOL); } } if ((tok = strsep (&str, ":")) && sscanf (tok, "%d", &parm->count) == 1) { if (!parm->count) parm->not_found = 1;/* Server indicated that no items follow. */ else if (parm->count < 0) parm->count = 10; /* Bad value - assume something reasonable. */ else parm->validcount = 1; /* COUNT seems to be okay. */ } parm->any_lines = 1; return 0; /* Line processing finished. */ } again: if (line) keyrec = parse_keyrec (line); else { /* Received EOF - flush data */ parm->eof_seen = 1; keyrec = parse_keyrec (NULL); if (!keyrec) { if (!parm->nkeys) parm->not_found = 1; /* No keys at all. */ else { if (parm->nkeys != parm->count) parm->validcount = 0; if (!(opt.with_colons && opt.batch)) { err = show_prompt (parm->ctrl, parm->desc, parm->nkeys, parm->validcount? parm->count : 0, parm->searchstr_disp); return err; } } } } /* Save the key in the key array. */ if (keyrec) { /* Allocate or enlarge the key array if needed. */ if (!parm->desc) { if (parm->count < 1) { parm->count = 10; parm->validcount = 0; } parm->desc = xtrymalloc (parm->count * sizeof *parm->desc); if (!parm->desc) { err = gpg_error_from_syserror (); iobuf_close (keyrec->uidbuf); xfree (keyrec); return err; } } else if (parm->nkeys == parm->count) { /* Keyserver sent more keys than claimed in the info: line. */ KEYDB_SEARCH_DESC *tmp; int newcount = parm->count + 10; tmp = xtryrealloc (parm->desc, newcount * sizeof *parm->desc); if (!tmp) { err = gpg_error_from_syserror (); iobuf_close (keyrec->uidbuf); xfree (keyrec); return err; } parm->count = newcount; parm->desc = tmp; parm->validcount = 0; } parm->desc[parm->nkeys] = keyrec->desc; if (!opt.with_colons) { /* SCREEN_LINES - 1 for the prompt. */ if (parm->numlines + keyrec->lines > opt.screen_lines - 1) { err = show_prompt (parm->ctrl, parm->desc, parm->nkeys, parm->validcount ? parm->count:0, parm->searchstr_disp); if (err) return err; parm->numlines = 0; } print_keyrec (parm->nkeys+1, keyrec); } parm->numlines += keyrec->lines; iobuf_close (keyrec->uidbuf); xfree (keyrec); parm->any_lines = 1; parm->nkeys++; /* If we are here due to a flush after the EOF, run again for the last prompt. Fixme: Make this code better readable. */ if (parm->eof_seen) goto again; } return 0; } int keyserver_export (ctrl_t ctrl, strlist_t users) { gpg_error_t err; strlist_t sl=NULL; KEYDB_SEARCH_DESC desc; int rc=0; /* Weed out descriptors that we don't support sending */ for(;users;users=users->next) { err = classify_user_id (users->d, &desc, 1); if (err || (desc.mode != KEYDB_SEARCH_MODE_SHORT_KID && desc.mode != KEYDB_SEARCH_MODE_LONG_KID && desc.mode != KEYDB_SEARCH_MODE_FPR16 && desc.mode != KEYDB_SEARCH_MODE_FPR20)) { log_error(_("\"%s\" not a key ID: skipping\n"),users->d); continue; } else append_to_strlist(&sl,users->d); } if(sl) { rc = keyserver_put (ctrl, sl, opt.keyserver); free_strlist(sl); } return rc; } int keyserver_import (ctrl_t ctrl, strlist_t users) { gpg_error_t err; KEYDB_SEARCH_DESC *desc; int num=100,count=0; int rc=0; /* Build a list of key ids */ desc=xmalloc(sizeof(KEYDB_SEARCH_DESC)*num); for(;users;users=users->next) { err = classify_user_id (users->d, &desc[count], 1); if (err || (desc[count].mode != KEYDB_SEARCH_MODE_SHORT_KID && desc[count].mode != KEYDB_SEARCH_MODE_LONG_KID && desc[count].mode != KEYDB_SEARCH_MODE_FPR16 && desc[count].mode != KEYDB_SEARCH_MODE_FPR20)) { log_error (_("\"%s\" not a key ID: skipping\n"), users->d); continue; } count++; if(count==num) { num+=100; desc=xrealloc(desc,sizeof(KEYDB_SEARCH_DESC)*num); } } if(count>0) rc=keyserver_get (ctrl, desc, count, NULL); xfree(desc); return rc; } int keyserver_import_fprint (ctrl_t ctrl, const byte *fprint,size_t fprint_len, struct keyserver_spec *keyserver) { KEYDB_SEARCH_DESC desc; memset(&desc,0,sizeof(desc)); if(fprint_len==16) desc.mode=KEYDB_SEARCH_MODE_FPR16; else if(fprint_len==20) desc.mode=KEYDB_SEARCH_MODE_FPR20; else return -1; memcpy(desc.u.fpr,fprint,fprint_len); /* TODO: Warn here if the fingerprint we got doesn't match the one we asked for? */ return keyserver_get (ctrl, &desc, 1, keyserver); } int keyserver_import_keyid (ctrl_t ctrl, u32 *keyid,struct keyserver_spec *keyserver) { KEYDB_SEARCH_DESC desc; memset(&desc,0,sizeof(desc)); desc.mode=KEYDB_SEARCH_MODE_LONG_KID; desc.u.kid[0]=keyid[0]; desc.u.kid[1]=keyid[1]; return keyserver_get (ctrl, &desc,1, keyserver); } /* code mostly stolen from do_export_stream */ static int keyidlist(strlist_t users,KEYDB_SEARCH_DESC **klist,int *count,int fakev3) { int rc=0,ndesc,num=100; KBNODE keyblock=NULL,node; KEYDB_HANDLE kdbhd; KEYDB_SEARCH_DESC *desc; strlist_t sl; *count=0; *klist=xmalloc(sizeof(KEYDB_SEARCH_DESC)*num); kdbhd=keydb_new (); if(!users) { ndesc = 1; desc = xmalloc_clear ( 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) { gpg_error_t err; 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)); } } while (!(rc = keydb_search (kdbhd, desc, ndesc, NULL))) { if (!users) desc[0].mode = KEYDB_SEARCH_MODE_NEXT; /* read the keyblock */ rc = keydb_get_keyblock (kdbhd, &keyblock ); if( rc ) { log_error (_("error reading keyblock: %s\n"), g10_errstr(rc) ); goto leave; } if((node=find_kbnode(keyblock,PKT_PUBLIC_KEY))) { /* This is to work around a bug in some keyservers (pksd and OKS) that calculate v4 RSA keyids as if they were v3 RSA. The answer is to refresh both the correct v4 keyid (e.g. 99242560) and the fake v3 keyid (e.g. 68FDDBC7). This only happens for key refresh using the HKP scheme and if the refresh-add-fake-v3-keyids keyserver option is set. */ if(fakev3 && is_RSA(node->pkt->pkt.public_key->pubkey_algo) && node->pkt->pkt.public_key->version>=4) { (*klist)[*count].mode=KEYDB_SEARCH_MODE_LONG_KID; v3_keyid (node->pkt->pkt.public_key->pkey[0], (*klist)[*count].u.kid); (*count)++; if(*count==num) { num+=100; *klist=xrealloc(*klist,sizeof(KEYDB_SEARCH_DESC)*num); } } /* v4 keys get full fingerprints. v3 keys get long keyids. This is because it's easy to calculate any sort of keyid from a v4 fingerprint, but not a v3 fingerprint. */ if(node->pkt->pkt.public_key->version<4) { (*klist)[*count].mode=KEYDB_SEARCH_MODE_LONG_KID; keyid_from_pk(node->pkt->pkt.public_key, (*klist)[*count].u.kid); } else { size_t dummy; (*klist)[*count].mode=KEYDB_SEARCH_MODE_FPR20; fingerprint_from_pk(node->pkt->pkt.public_key, (*klist)[*count].u.fpr,&dummy); } /* This is a little hackish, using the skipfncvalue as a void* pointer to the keyserver spec, but we don't need the skipfnc here, and it saves having an additional field for this (which would be wasted space most of the time). */ (*klist)[*count].skipfncvalue=NULL; /* Are we honoring preferred keyservers? */ if(opt.keyserver_options.options&KEYSERVER_HONOR_KEYSERVER_URL) { PKT_user_id *uid=NULL; PKT_signature *sig=NULL; merge_keys_and_selfsig(keyblock); for(node=node->next;node;node=node->next) { if(node->pkt->pkttype==PKT_USER_ID && node->pkt->pkt.user_id->is_primary) uid=node->pkt->pkt.user_id; else if(node->pkt->pkttype==PKT_SIGNATURE && node->pkt->pkt.signature-> flags.chosen_selfsig && uid) { sig=node->pkt->pkt.signature; break; } } /* Try and parse the keyserver URL. If it doesn't work, then we end up writing NULL which indicates we are the same as any other key. */ if(sig) (*klist)[*count].skipfncvalue=parse_preferred_keyserver(sig); } (*count)++; if(*count==num) { num+=100; *klist=xrealloc(*klist,sizeof(KEYDB_SEARCH_DESC)*num); } } } if (gpg_err_code (rc) == GPG_ERR_NOT_FOUND) rc = 0; leave: if(rc) xfree(*klist); xfree(desc); keydb_release(kdbhd); release_kbnode(keyblock); return rc; } /* Note this is different than the original HKP refresh. It allows usernames to refresh only part of the keyring. */ int keyserver_refresh (ctrl_t ctrl, strlist_t users) { int rc,count,numdesc,fakev3=0; KEYDB_SEARCH_DESC *desc; unsigned int options=opt.keyserver_options.import_options; /* We switch merge-only on during a refresh, as 'refresh' should never import new keys, even if their keyids match. */ opt.keyserver_options.import_options|=IMPORT_MERGE_ONLY; /* Similarly, we switch on fast-import, since refresh may make multiple import sets (due to preferred keyserver URLs). We don't want each set to rebuild the trustdb. Instead we do it once at the end here. */ opt.keyserver_options.import_options|=IMPORT_FAST; /* If refresh_add_fake_v3_keyids is on and it's a HKP or MAILTO scheme, then enable fake v3 keyid generation. */ if((opt.keyserver_options.options&KEYSERVER_ADD_FAKE_V3) && opt.keyserver && (ascii_strcasecmp(opt.keyserver->scheme,"hkp")==0 || ascii_strcasecmp(opt.keyserver->scheme,"mailto")==0)) fakev3=1; rc=keyidlist(users,&desc,&numdesc,fakev3); if(rc) return rc; count=numdesc; if(count>0) { int i; /* Try to handle preferred keyserver keys first */ for(i=0;iuri,g10_errstr(rc)); else { /* We got it, so mark it as NONE so we don't try and get it again from the regular keyserver. */ desc[i].mode=KEYDB_SEARCH_MODE_NONE; count--; } free_keyserver_spec(keyserver); } } } if(count>0) { if(opt.keyserver) { if(count==1) log_info(_("refreshing 1 key from %s\n"),opt.keyserver->uri); else log_info(_("refreshing %d keys from %s\n"), count,opt.keyserver->uri); } rc=keyserver_get (ctrl, desc, numdesc, NULL); } xfree(desc); opt.keyserver_options.import_options=options; /* If the original options didn't have fast import, and the trustdb is dirty, rebuild. */ if(!(opt.keyserver_options.import_options&IMPORT_FAST)) trustdb_check_or_update(); return rc; } /* Search for keys on the keyservers. The patterns are given in the string list TOKENS. */ gpg_error_t keyserver_search (ctrl_t ctrl, strlist_t tokens) { gpg_error_t err; char *searchstr; struct search_line_handler_parm_s parm; memset (&parm, 0, sizeof parm); if (!tokens) return 0; /* Return success if no patterns are given. */ if (!opt.keyserver) { log_error (_("no keyserver known (use option --keyserver)\n")); return gpg_error (GPG_ERR_NO_KEYSERVER); } /* Write global options */ /* for(temp=opt.keyserver_options.other;temp;temp=temp->next) */ /* fprintf(spawn->tochild,"OPTION %s\n",temp->d); */ /* Write per-keyserver options */ /* for(temp=keyserver->options;temp;temp=temp->next) */ /* fprintf(spawn->tochild,"OPTION %s\n",temp->d); */ { membuf_t mb; strlist_t item; init_membuf (&mb, 1024); for (item = tokens; item; item = item->next) { if (item != tokens) put_membuf (&mb, " ", 1); put_membuf_str (&mb, item->d); } put_membuf (&mb, "", 1); /* Append Nul. */ searchstr = get_membuf (&mb, NULL); if (!searchstr) { err = gpg_error_from_syserror (); goto leave; } } /* FIXME: Enable the next line */ /* log_info (_("searching for \"%s\" from %s\n"), searchstr, keyserver->uri); */ parm.ctrl = ctrl; if (searchstr) parm.searchstr_disp = utf8_to_native (searchstr, strlen (searchstr), 0); err = gpg_dirmngr_ks_search (ctrl, searchstr, search_line_handler, &parm); if (parm.not_found) { if (parm.searchstr_disp) log_info (_("key \"%s\" not found on keyserver\n"), parm.searchstr_disp); else log_info (_("key not found on keyserver\n")); } if (gpg_err_code (err) == GPG_ERR_NO_KEYSERVER) log_error (_("no keyserver known (use option --keyserver)\n")); else if (err) log_error ("error searching keyserver: %s\n", gpg_strerror (err)); /* switch(ret) */ /* { */ /* case KEYSERVER_SCHEME_NOT_FOUND: */ /* log_error(_("no handler for keyserver scheme '%s'\n"), */ /* opt.keyserver->scheme); */ /* break; */ /* case KEYSERVER_NOT_SUPPORTED: */ /* log_error(_("action '%s' not supported with keyserver " */ /* "scheme '%s'\n"), "search", opt.keyserver->scheme); */ /* break; */ /* case KEYSERVER_TIMEOUT: */ /* log_error(_("keyserver timed out\n")); */ /* break; */ /* case KEYSERVER_INTERNAL_ERROR: */ /* default: */ /* log_error(_("keyserver internal error\n")); */ /* break; */ /* } */ /* return gpg_error (GPG_ERR_KEYSERVER); */ leave: xfree (parm.desc); xfree (parm.searchstr_disp); xfree(searchstr); return err; } /* Called using: import_name: rc = keyserver_work (ctrl, KS_GETNAME, list, NULL, 0, fpr, fpr_len, keyserver); import_ldap: rc = keyserver_work (ctrl, KS_GETNAME, list, NULL, 0, fpr, fpr_len, keyserver); */ static gpg_error_t keyserver_get (ctrl_t ctrl, KEYDB_SEARCH_DESC *desc, int ndesc, struct keyserver_spec *keyserver) { gpg_error_t err = 0; char **pattern; int idx, npat; estream_t datastream; /* Create an array filled with a search pattern for each key. The array is delimited by a NULL entry. */ pattern = xtrycalloc (ndesc+1, sizeof *pattern); if (!pattern) return gpg_error_from_syserror (); for (npat=idx=0; idx < ndesc; idx++) { int quiet = 0; if (desc[idx].mode == KEYDB_SEARCH_MODE_FPR20 || desc[idx].mode == KEYDB_SEARCH_MODE_FPR16) { pattern[npat] = xtrymalloc (2+2*20+1); if (!pattern[npat]) err = gpg_error_from_syserror (); else { strcpy (pattern[npat], "0x"); bin2hex (desc[idx].u.fpr, desc[idx].mode == KEYDB_SEARCH_MODE_FPR20? 20 : 16, pattern[npat]+2); npat++; } } else if(desc[idx].mode == KEYDB_SEARCH_MODE_LONG_KID) { pattern[npat] = xtryasprintf ("0x%08lX%08lX", (ulong)desc[idx].u.kid[0], (ulong)desc[idx].u.kid[1]); if (!pattern[npat]) err = gpg_error_from_syserror (); else npat++; } else if(desc[idx].mode == KEYDB_SEARCH_MODE_SHORT_KID) { pattern[npat] = xtryasprintf ("0x%08lX", (ulong)desc[idx].u.kid[1]); if (!pattern[npat]) err = gpg_error_from_syserror (); else npat++; } else if(desc[idx].mode == KEYDB_SEARCH_MODE_EXACT) { /* FIXME: We don't need this. It is used as a dummy by keyserver_fetch which passes an entire URL. Better use a separate function here. */ pattern[npat] = xtrystrdup ("0x0000000000000000"); if (!pattern[npat]) err = gpg_error_from_syserror (); else { npat++; quiet = 1; } } else if (desc[idx].mode == KEYDB_SEARCH_MODE_NONE) continue; else BUG(); if (err) { for (idx=0; idx < npat; idx++) xfree (pattern[idx]); xfree (pattern); return err; } if (!quiet && keyserver) { if (keyserver->host) log_info (_("requesting key %s from %s server %s\n"), keystr_from_desc (&desc[idx]), keyserver->scheme, keyserver->host); else log_info (_("requesting key %s from %s\n"), keystr_from_desc (&desc[idx]), keyserver->uri); } } err = gpg_dirmngr_ks_get (ctrl, pattern, &datastream); for (idx=0; idx < npat; idx++) xfree (pattern[idx]); xfree (pattern); if (!err) { void *stats_handle; stats_handle = import_new_stats_handle(); /* FIXME: Check whether this comment should be moved to dirmngr. Slurp up all the key data. In the future, it might be nice to look for KEY foo OUTOFBAND and FAILED indicators. It's harmless to ignore them, but ignoring them does make gpg complain about "no valid OpenPGP data found". One way to do this could be to continue parsing this line-by-line and make a temp iobuf for each key. */ import_keys_es_stream (ctrl, datastream, stats_handle, NULL, NULL, opt.keyserver_options.import_options); import_print_stats (stats_handle); import_release_stats_handle (stats_handle); } es_fclose (datastream); return err; } /* Send all keys specified by KEYSPECS to the KEYSERVERS. */ static gpg_error_t keyserver_put (ctrl_t ctrl, strlist_t keyspecs, struct keyserver_spec *keyserver) { gpg_error_t err; strlist_t kspec; if (!keyspecs) return 0; /* Return success if the list is empty. */ if (!opt.keyserver) { log_error (_("no keyserver known (use option --keyserver)\n")); return gpg_error (GPG_ERR_NO_KEYSERVER); } for (kspec = keyspecs; kspec; kspec = kspec->next) { void *data; size_t datalen; kbnode_t keyblock; err = export_pubkey_buffer (ctrl, kspec->d, opt.keyserver_options.export_options, &keyblock, &data, &datalen); if (err) log_error (_("skipped \"%s\": %s\n"), kspec->d, gpg_strerror (err)); else { if (keyserver->host) log_info (_("sending key %s to %s server %s\n"), keystr (keyblock->pkt->pkt.public_key->keyid), keyserver->scheme, keyserver->host); else log_info (_("sending key %s to %s\n"), keystr (keyblock->pkt->pkt.public_key->keyid), keyserver->uri); err = gpg_dirmngr_ks_put (ctrl, data, datalen, keyblock); release_kbnode (keyblock); xfree (data); if (err) log_error (_("keyserver send failed: %s\n"), gpg_strerror (err)); } } return err; } int keyserver_fetch (ctrl_t ctrl, strlist_t urilist) { gpg_error_t err; strlist_t sl; estream_t datastream; unsigned int options = opt.keyserver_options.import_options; /* Switch on fast-import, since fetch can handle more than one import and we don't want each set to rebuild the trustdb. Instead we do it once at the end. */ opt.keyserver_options.import_options |= IMPORT_FAST; for (sl=urilist; sl; sl=sl->next) { if (!opt.quiet) log_info (_("requesting key from '%s'\n"), sl->d); err = gpg_dirmngr_ks_fetch (ctrl, sl->d, &datastream); if (!err) { void *stats_handle; stats_handle = import_new_stats_handle(); import_keys_es_stream (ctrl, datastream, stats_handle, NULL, NULL, opt.keyserver_options.import_options); import_print_stats (stats_handle); import_release_stats_handle (stats_handle); } else log_info (_("WARNING: unable to fetch URI %s: %s\n"), sl->d, gpg_strerror (err)); es_fclose (datastream); } opt.keyserver_options.import_options = options; /* If the original options didn't have fast import, and the trustdb is dirty, rebuild. */ if (!(opt.keyserver_options.import_options&IMPORT_FAST)) trustdb_check_or_update (); return 0; } /* Import key in a CERT or pointed to by a CERT */ int keyserver_import_cert (ctrl_t ctrl, const char *name,unsigned char **fpr,size_t *fpr_len) { gpg_error_t err; char *domain,*look,*url; estream_t key; look=xstrdup(name); domain=strrchr(look,'@'); if(domain) *domain='.'; err = get_dns_cert (look, &key, fpr, fpr_len, &url); if (err) ; else if (key) { int armor_status=opt.no_armor; /* CERTs are always in binary format */ opt.no_armor=1; err = import_keys_es_stream (ctrl, key, NULL, fpr, fpr_len, opt.keyserver_options.import_options); opt.no_armor=armor_status; es_fclose (key); key = NULL; } else if (*fpr) { /* We only consider the IPGP type if a fingerprint was provided. This lets us select the right key regardless of what a URL points to, or get the key from a keyserver. */ if(url) { struct keyserver_spec *spec; spec=parse_keyserver_uri(url,1,NULL,0); if(spec) { err = keyserver_import_fprint (ctrl, *fpr,*fpr_len,spec); free_keyserver_spec(spec); } } else if(opt.keyserver) { /* If only a fingerprint is provided, try and fetch it from our --keyserver */ err = keyserver_import_fprint (ctrl, *fpr,*fpr_len,opt.keyserver); } else log_info(_("no keyserver known (use option --keyserver)\n")); /* Give a better string here? "CERT fingerprint for \"%s\" found, but no keyserver" " known (use option --keyserver)\n" ? */ } xfree(url); xfree(look); return err; } /* Import key pointed to by a PKA record. Return the requested fingerprint in fpr. */ int keyserver_import_pka (ctrl_t ctrl, const char *name,unsigned char **fpr,size_t *fpr_len) { char *uri; int rc = G10ERR_NO_PUBKEY; *fpr = xmalloc (20); *fpr_len = 20; uri = get_pka_info (name, *fpr); if (uri && *uri) { /* An URI is available. Lookup the key. */ struct keyserver_spec *spec; spec = parse_keyserver_uri (uri, 1, NULL, 0); if (spec) { rc = keyserver_import_fprint (ctrl, *fpr, 20, spec); free_keyserver_spec (spec); } xfree (uri); } if (rc) { xfree(*fpr); *fpr = NULL; } return rc; } /* Import all keys that match name */ int keyserver_import_name (ctrl_t ctrl, const char *name, unsigned char **fpr, size_t *fpr_len, struct keyserver_spec *keyserver) { strlist_t list=NULL; int rc; append_to_strlist(&list,name); rc = gpg_error (GPG_ERR_NOT_IMPLEMENTED); /* FIXME */ /* keyserver_work (ctrl, KS_GETNAME, list, NULL, */ /* 0, fpr, fpr_len, keyserver); */ free_strlist(list); return rc; } /* Import a key by name using LDAP */ int keyserver_import_ldap (ctrl_t ctrl, const char *name,unsigned char **fpr,size_t *fpr_len) { char *domain; struct keyserver_spec *keyserver; strlist_t list=NULL; int rc,hostlen=1; #ifdef USE_DNS_SRV struct srventry *srvlist=NULL; int srvcount,i; char srvname[MAXDNAME]; #endif /* Parse out the domain */ domain=strrchr(name,'@'); if(!domain) return G10ERR_GENERAL; domain++; keyserver=xmalloc_clear(sizeof(struct keyserver_spec)); keyserver->scheme=xstrdup("ldap"); keyserver->host=xmalloc(1); keyserver->host[0]='\0'; #ifdef USE_DNS_SRV snprintf(srvname,MAXDNAME,"_pgpkey-ldap._tcp.%s",domain); srvcount=getsrv(srvname,&srvlist); for(i=0;ihost=xrealloc(keyserver->host,hostlen); strcat(keyserver->host,srvlist[i].target); if(srvlist[i].port!=389) { char port[7]; hostlen+=6; /* a colon, plus 5 digits (unsigned 16-bit value) */ keyserver->host=xrealloc(keyserver->host,hostlen); snprintf(port,7,":%u",srvlist[i].port); strcat(keyserver->host,port); } strcat(keyserver->host," "); } free(srvlist); #endif /* If all else fails, do the PGP Universal trick of ldap://keys.(domain) */ hostlen+=5+strlen(domain); keyserver->host=xrealloc(keyserver->host,hostlen); strcat(keyserver->host,"keys."); strcat(keyserver->host,domain); append_to_strlist(&list,name); rc = gpg_error (GPG_ERR_NOT_IMPLEMENTED); /*FIXME*/ /* keyserver_work (ctrl, KS_GETNAME, list, NULL, */ /* 0, fpr, fpr_len, keyserver); */ free_strlist(list); free_keyserver_spec(keyserver); return rc; } diff --git a/g10/main.h b/g10/main.h index 4d3ab1b32..26283a783 100644 --- a/g10/main.h +++ b/g10/main.h @@ -1,375 +1,374 @@ /* main.h * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, * 2008, 2009, 2010 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 . */ #ifndef G10_MAIN_H #define G10_MAIN_H #include "types.h" #include "iobuf.h" #include "keydb.h" #include "util.h" /* It could be argued that the default cipher should be 3DES rather than CAST5, and the default compression should be 0 (i.e. uncompressed) rather than 1 (zip). However, the real world issues of speed and size come into play here. */ #define DEFAULT_CIPHER_ALGO CIPHER_ALGO_CAST5 #define DEFAULT_DIGEST_ALGO DIGEST_ALGO_SHA1 #define DEFAULT_S2K_DIGEST_ALGO DIGEST_ALGO_SHA1 #ifdef HAVE_ZIP # define DEFAULT_COMPRESS_ALGO COMPRESS_ALGO_ZIP #else # define DEFAULT_COMPRESS_ALGO COMPRESS_ALGO_NONE #endif #define S2K_DIGEST_ALGO (opt.s2k_digest_algo?opt.s2k_digest_algo:DEFAULT_S2K_DIGEST_ALGO) /* Various data objects. */ typedef struct { int header_okay; PK_LIST pk_list; DEK *symkey_dek; STRING2KEY *symkey_s2k; cipher_filter_context_t cfx; } encrypt_filter_context_t; struct groupitem { char *name; strlist_t values; struct groupitem *next; }; /*-- gpg.c --*/ extern int g10_errors_seen; #if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 5 ) void g10_exit(int rc) __attribute__ ((noreturn)); #else void g10_exit(int rc); #endif void print_pubkey_algo_note( int algo ); void print_cipher_algo_note( int algo ); void print_digest_algo_note( int algo ); /*-- armor.c --*/ char *make_radix64_string( const byte *data, size_t len ); /*-- misc.c --*/ void trap_unaligned(void); int disable_core_dumps(void); void register_secured_file (const char *fname); void unregister_secured_file (const char *fname); int is_secured_file (int fd); int is_secured_filename (const char *fname); u16 checksum_u16( unsigned n ); u16 checksum( byte *p, unsigned n ); u16 checksum_mpi( gcry_mpi_t a ); u32 buffer_to_u32( const byte *buffer ); const byte *get_session_marker( size_t *rlen ); int map_cipher_openpgp_to_gcry (int algo); #define openpgp_cipher_open(_a,_b,_c,_d) \ gcry_cipher_open((_a),map_cipher_openpgp_to_gcry((_b)),(_c),(_d)) #define openpgp_cipher_get_algo_keylen(_a) \ gcry_cipher_get_algo_keylen(map_cipher_openpgp_to_gcry((_a))) #define openpgp_cipher_get_algo_blklen(_a) \ gcry_cipher_get_algo_blklen(map_cipher_openpgp_to_gcry((_a))) int openpgp_cipher_blocklen (int algo); int openpgp_cipher_test_algo( int algo ); const char *openpgp_cipher_algo_name (int algo); -int map_pk_openpgp_to_gcry (int algo); int map_pk_gcry_to_openpgp (enum gcry_pk_algos algo); -int openpgp_pk_test_algo( int algo ); -int openpgp_pk_test_algo2 ( int algo, unsigned int use ); +int openpgp_pk_test_algo (pubkey_algo_t algo); +int openpgp_pk_test_algo2 (pubkey_algo_t algo, unsigned int use); int openpgp_pk_algo_usage ( int algo ); int openpgp_md_test_algo( int algo ); -const char *openpgp_pk_algo_name (int algo); +const char *openpgp_pk_algo_name (pubkey_algo_t algo); const char *openpgp_md_algo_name (int algo); struct expando_args { PKT_public_key *pk; PKT_public_key *pksk; byte imagetype; int validity_info; const char *validity_string; }; char *pct_expando(const char *string,struct expando_args *args); void deprecated_warning(const char *configname,unsigned int configlineno, const char *option,const char *repl1,const char *repl2); void deprecated_command (const char *name); void obsolete_option (const char *configname, unsigned int configlineno, const char *name); int string_to_cipher_algo (const char *string); int string_to_digest_algo (const char *string); const char *compress_algo_to_string(int algo); int string_to_compress_algo(const char *string); int check_compress_algo(int algo); int default_cipher_algo(void); int default_compress_algo(void); const char *compliance_option_string(void); void compliance_failure(void); struct parse_options { char *name; unsigned int bit; char **value; char *help; }; char *optsep(char **stringp); char *argsplit(char *string); int parse_options(char *str,unsigned int *options, struct parse_options *opts,int noisy); int has_invalid_email_chars (const char *s); int is_valid_mailbox (const char *name); const char *get_libexecdir (void); int path_access(const char *file,int mode); -int pubkey_get_npkey( int algo ); -int pubkey_get_nskey( int algo ); -int pubkey_get_nsig( int algo ); -int pubkey_get_nenc( int algo ); +int pubkey_get_npkey (pubkey_algo_t algo); +int pubkey_get_nskey (pubkey_algo_t algo); +int pubkey_get_nsig (pubkey_algo_t algo); +int pubkey_get_nenc (pubkey_algo_t algo); /* Temporary helpers. */ unsigned int pubkey_nbits( int algo, gcry_mpi_t *pkey ); int mpi_print (estream_t stream, gcry_mpi_t a, int mode); unsigned int ecdsa_qbits_from_Q (unsigned int qbits); /*-- status.c --*/ void set_status_fd ( int fd ); int is_status_enabled ( void ); void write_status ( int no ); void write_status_error (const char *where, gpg_error_t err); void write_status_errcode (const char *where, int errcode); void write_status_text ( int no, const char *text ); void write_status_strings (int no, const char *text, ...) GNUPG_GCC_A_SENTINEL(0); void write_status_buffer ( int no, const char *buffer, size_t len, int wrap ); void write_status_text_and_buffer ( int no, const char *text, const char *buffer, size_t len, int wrap ); void write_status_begin_signing (gcry_md_hd_t md); int cpr_enabled(void); char *cpr_get( const char *keyword, const char *prompt ); char *cpr_get_no_help( const char *keyword, const char *prompt ); char *cpr_get_utf8( const char *keyword, const char *prompt ); char *cpr_get_hidden( const char *keyword, const char *prompt ); void cpr_kill_prompt(void); int cpr_get_answer_is_yes( const char *keyword, const char *prompt ); int cpr_get_answer_yes_no_quit( const char *keyword, const char *prompt ); int cpr_get_answer_okay_cancel (const char *keyword, const char *prompt, int def_answer); /*-- helptext.c --*/ void display_online_help( const char *keyword ); /*-- encode.c --*/ int setup_symkey (STRING2KEY **symkey_s2k,DEK **symkey_dek); int encrypt_symmetric (const char *filename ); int encrypt_store (const char *filename ); int encrypt_crypt (ctrl_t ctrl, int filefd, const char *filename, strlist_t remusr, int use_symkey, pk_list_t provided_keys, int outputfd); void encrypt_crypt_files (ctrl_t ctrl, int nfiles, char **files, strlist_t remusr); int encrypt_filter (void *opaque, int control, iobuf_t a, byte *buf, size_t *ret_len); /*-- sign.c --*/ int complete_sig (PKT_signature *sig, PKT_public_key *pksk, gcry_md_hd_t md, const char *cache_nonce); int sign_file (ctrl_t ctrl, strlist_t filenames, int detached, strlist_t locusr, int do_encrypt, strlist_t remusr, const char *outfile ); int clearsign_file( const char *fname, strlist_t locusr, const char *outfile ); int sign_symencrypt_file (const char *fname, strlist_t locusr); /*-- sig-check.c --*/ int check_revocation_keys (PKT_public_key *pk, PKT_signature *sig); int check_backsig(PKT_public_key *main_pk,PKT_public_key *sub_pk, PKT_signature *backsig); int check_key_signature( KBNODE root, KBNODE node, int *is_selfsig ); int check_key_signature2( KBNODE root, KBNODE node, PKT_public_key *check_pk, PKT_public_key *ret_pk, int *is_selfsig, u32 *r_expiredate, int *r_expired ); /*-- delkey.c --*/ int delete_keys( strlist_t names, int secret, int allow_both ); /*-- keyedit.c --*/ void keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr, strlist_t commands, int quiet, int seckey_check ); void keyedit_passwd (ctrl_t ctrl, const char *username); void show_basic_key_info (KBNODE keyblock); /*-- keygen.c --*/ u32 parse_expire_string(const char *string); u32 ask_expire_interval(int object,const char *def_expire); u32 ask_expiredate(void); void generate_keypair (ctrl_t ctrl, const char *fname, const char *card_serialno, int card_backup_key); int keygen_set_std_prefs (const char *string,int personal); PKT_user_id *keygen_get_std_prefs (void); int keygen_add_key_expire( PKT_signature *sig, void *opaque ); int keygen_add_std_prefs( PKT_signature *sig, void *opaque ); int keygen_upd_std_prefs( PKT_signature *sig, void *opaque ); int keygen_add_keyserver_url(PKT_signature *sig, void *opaque); int keygen_add_notations(PKT_signature *sig,void *opaque); int keygen_add_revkey(PKT_signature *sig, void *opaque); gpg_error_t make_backsig (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 generate_subkeypair (ctrl_t ctrl, kbnode_t pub_keyblock); #ifdef ENABLE_CARD_SUPPORT gpg_error_t generate_card_subkeypair (kbnode_t pub_keyblock, int keyno, const char *serialno); int save_unprotected_key_to_card (PKT_public_key *sk, int keyno); #endif /*-- openfile.c --*/ int overwrite_filep( const char *fname ); char *make_outfile_name( const char *iname ); char *ask_outfile_name( const char *name, size_t namelen ); int open_outfile (int inp_fd, const char *iname, int mode, iobuf_t *a); iobuf_t open_sigfile( const char *iname, progress_filter_context_t *pfx ); void try_make_homedir( const char *fname ); /*-- seskey.c --*/ void make_session_key( DEK *dek ); gcry_mpi_t encode_session_key( int openpgp_pk_algo, DEK *dek, unsigned nbits ); gcry_mpi_t encode_md_value (PKT_public_key *pk, gcry_md_hd_t md, int hash_algo ); /*-- import.c --*/ int parse_import_options(char *str,unsigned int *options,int noisy); void import_keys (ctrl_t ctrl, char **fnames, int nnames, void *stats_hd, unsigned int options); int import_keys_stream (ctrl_t ctrl, iobuf_t inp, void *stats_hd, unsigned char **fpr, size_t *fpr_len, unsigned int options); int import_keys_es_stream (ctrl_t ctrl, estream_t fp, void *stats_handle, unsigned char **fpr, size_t *fpr_len, unsigned int options); void *import_new_stats_handle (void); void import_release_stats_handle (void *p); void import_print_stats (void *hd); int collapse_uids( KBNODE *keyblock ); /*-- export.c --*/ int parse_export_options(char *str,unsigned int *options,int noisy); int export_pubkeys (ctrl_t ctrl, strlist_t users, unsigned int options ); int export_pubkeys_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, kbnode_t *keyblock_out, unsigned int options ); gpg_error_t export_pubkey_buffer (ctrl_t ctrl, const char *keyspec, unsigned int options, kbnode_t *r_keyblock, void **r_data, size_t *r_datalen); int export_seckeys (ctrl_t ctrl, strlist_t users); int export_secsubkeys (ctrl_t ctrl, strlist_t users); /*-- dearmor.c --*/ int dearmor_file( const char *fname ); int enarmor_file( const char *fname ); /*-- revoke.c --*/ struct revocation_reason_info; int gen_revoke( const char *uname ); int gen_desig_revoke( const char *uname, strlist_t locusr); int revocation_reason_build_cb( PKT_signature *sig, void *opaque ); struct revocation_reason_info * ask_revocation_reason( int key_rev, int cert_rev, int hint ); void release_revocation_reason_info( struct revocation_reason_info *reason ); /*-- keylist.c --*/ void public_key_list (ctrl_t ctrl, strlist_t list, int locate_mode ); void secret_key_list (ctrl_t ctrl, strlist_t list ); void print_subpackets_colon(PKT_signature *sig); void reorder_keyblock (KBNODE keyblock); void list_keyblock( KBNODE keyblock, int secret, int fpr, void *opaque ); void print_fingerprint (PKT_public_key *pk, int mode); void print_revokers(PKT_public_key *pk); void show_policy_url(PKT_signature *sig,int indent,int mode); void show_keyserver_url(PKT_signature *sig,int indent,int mode); void show_notation(PKT_signature *sig,int indent,int mode,int which); void dump_attribs (const PKT_user_id *uid, PKT_public_key *pk); void set_attrib_fd(int fd); void print_seckey_info (PKT_public_key *pk); void print_pubkey_info (estream_t fp, PKT_public_key *pk); void print_card_key_info (estream_t fp, KBNODE keyblock); /*-- verify.c --*/ void print_file_status( int status, const char *name, int what ); int verify_signatures (ctrl_t ctrl, int nfiles, char **files ); int verify_files (ctrl_t ctrl, int nfiles, char **files ); int gpg_verify (ctrl_t ctrl, int sig_fd, int data_fd, estream_t out_fp); /*-- decrypt.c --*/ int decrypt_message (ctrl_t ctrl, const char *filename ); gpg_error_t decrypt_message_fd (ctrl_t ctrl, int input_fd, int output_fd); void decrypt_messages (ctrl_t ctrl, int nfiles, char *files[]); /*-- plaintext.c --*/ int hash_datafiles( gcry_md_hd_t md, gcry_md_hd_t md2, strlist_t files, const char *sigfilename, int textmode ); int hash_datafile_by_fd ( gcry_md_hd_t md, gcry_md_hd_t md2, int data_fd, int textmode ); PKT_plaintext *setup_plaintext_name(const char *filename,IOBUF iobuf); /*-- signal.c --*/ void init_signals(void); void block_all_signals(void); void unblock_all_signals(void); /*-- server.c --*/ int gpg_server (ctrl_t); gpg_error_t gpg_proxy_pinentry_notify (ctrl_t ctrl, const unsigned char *line); #ifdef ENABLE_CARD_SUPPORT /*-- card-util.c --*/ void change_pin (int no, int allow_admin); void card_status (estream_t fp, char *serialno, size_t serialnobuflen); void card_edit (ctrl_t ctrl, strlist_t commands); gpg_error_t card_generate_subkey (KBNODE pub_keyblock); int card_store_subkey (KBNODE node, int use); #endif #define S2K_DECODE_COUNT(_val) ((16ul + ((_val) & 15)) << (((_val) >> 4) + 6)) #endif /*G10_MAIN_H*/ diff --git a/g10/mainproc.c b/g10/mainproc.c index d8606cdf5..5f8d1197b 100644 --- a/g10/mainproc.c +++ b/g10/mainproc.c @@ -1,2243 +1,2244 @@ /* mainproc.c - handle packets * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, * 2008, 2009 Free Software Foundation, Inc. * Copyright (C) 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 "gpg.h" #include "util.h" #include "packet.h" #include "iobuf.h" #include "options.h" #include "keydb.h" #include "filter.h" #include "main.h" #include "status.h" #include "i18n.h" #include "trustdb.h" #include "keyserver-internal.h" #include "photoid.h" #include "pka.h" /* Put an upper limit on nested packets. The 32 is an arbitrary value, a much lower should actually be sufficient. */ #define MAX_NESTING_DEPTH 32 struct kidlist_item { struct kidlist_item *next; u32 kid[2]; int pubkey_algo; int reason; }; /**************** * Structure to hold the context */ typedef struct mainproc_context *CTX; struct mainproc_context { ctrl_t ctrl; struct mainproc_context *anchor; /* May be useful in the future. */ PKT_public_key *last_pubkey; PKT_user_id *last_user_id; md_filter_context_t mfx; int sigs_only; /* Process only signatures and reject all other stuff. */ int encrypt_only; /* Process only encryption messages. */ /* Name of the file with the complete signature or the file with the detached signature. This is currently only used to deduce the file name of the data file if that has not been given. */ const char *sigfilename; /* A structure to describe the signed data in case of a detached signature. */ struct { /* A file descriptor of the the signed data. Only used if not -1. */ int data_fd; /* A list of filenames with the data files or NULL. This is only used if DATA_FD is -1. */ strlist_t data_names; /* Flag to indicated that either one of the next previous fields is used. This is only needed for better readability. */ int used; } signed_data; DEK *dek; int last_was_session_key; KBNODE list; /* The current list of packets. */ IOBUF iobuf; /* Used to get the filename etc. */ int trustletter; /* Temporary usage in list_node. */ ulong symkeys; struct kidlist_item *pkenc_list; /* List of encryption packets. */ struct { unsigned int sig_seen:1; /* Set to true if a signature packet has been seen. */ unsigned int data:1; /* Any data packet seen */ unsigned int uncompress_failed:1; } any; }; static int do_proc_packets( CTX c, IOBUF a ); static void list_node( CTX c, KBNODE node ); static void proc_tree( CTX c, KBNODE node ); static int literals_seen; void reset_literals_seen(void) { literals_seen=0; } static void release_list( CTX c ) { if( !c->list ) return; proc_tree(c, c->list ); release_kbnode( c->list ); while( c->pkenc_list ) { struct kidlist_item *tmp = c->pkenc_list->next; xfree( c->pkenc_list ); c->pkenc_list = tmp; } c->pkenc_list = NULL; c->list = NULL; c->any.data = 0; c->any.uncompress_failed = 0; c->last_was_session_key = 0; xfree(c->dek); c->dek = NULL; } static int add_onepass_sig( CTX c, PACKET *pkt ) { KBNODE node; if ( c->list ) /* add another packet */ add_kbnode( c->list, new_kbnode( pkt )); else /* insert the first one */ c->list = node = new_kbnode( pkt ); return 1; } static int add_gpg_control( CTX c, PACKET *pkt ) { if ( pkt->pkt.gpg_control->control == CTRLPKT_CLEARSIGN_START ) { /* New clear text signature. * Process the last one and reset everything */ release_list(c); } if( c->list ) /* add another packet */ add_kbnode( c->list, new_kbnode( pkt )); else /* insert the first one */ c->list = new_kbnode( pkt ); return 1; } static int add_user_id( CTX c, PACKET *pkt ) { if( !c->list ) { log_error("orphaned user ID\n" ); return 0; } add_kbnode( c->list, new_kbnode( pkt ) ); return 1; } static int add_subkey( CTX c, PACKET *pkt ) { if( !c->list ) { log_error("subkey w/o mainkey\n" ); return 0; } add_kbnode( c->list, new_kbnode( pkt ) ); return 1; } static int add_ring_trust( CTX c, PACKET *pkt ) { if( !c->list ) { log_error("ring trust w/o key\n" ); return 0; } add_kbnode( c->list, new_kbnode( pkt ) ); return 1; } static int add_signature( CTX c, PACKET *pkt ) { KBNODE node; c->any.sig_seen = 1; if( pkt->pkttype == PKT_SIGNATURE && !c->list ) { /* This is the first signature for the following datafile. * GPG does not write such packets; instead it always uses * onepass-sig packets. The drawback of PGP's method * of prepending the signature to the data is * that it is not possible to make a signature from data read * from stdin. (GPG is able to read PGP stuff anyway.) */ node = new_kbnode( pkt ); c->list = node; return 1; } else if( !c->list ) return 0; /* oops (invalid packet sequence)*/ else if( !c->list->pkt ) BUG(); /* so nicht */ /* add a new signature node id at the end */ node = new_kbnode( pkt ); add_kbnode( c->list, node ); return 1; } static int symkey_decrypt_seskey( DEK *dek, byte *seskey, size_t slen ) { gcry_cipher_hd_t hd; if(slen < 17 || slen > 33) { log_error ( _("weird size for an encrypted session key (%d)\n"), (int)slen); return G10ERR_BAD_KEY; } if (openpgp_cipher_open (&hd, dek->algo, GCRY_CIPHER_MODE_CFB, 1)) BUG (); if (gcry_cipher_setkey ( hd, dek->key, dek->keylen )) BUG (); gcry_cipher_setiv ( hd, NULL, 0 ); gcry_cipher_decrypt ( hd, seskey, slen, NULL, 0 ); gcry_cipher_close ( hd ); /* Now we replace the dek components with the real session key to decrypt the contents of the sequencing packet. */ dek->keylen=slen-1; dek->algo=seskey[0]; if(dek->keylen > DIM(dek->key)) BUG (); memcpy(dek->key, seskey + 1, dek->keylen); /*log_hexdump( "thekey", dek->key, dek->keylen );*/ return 0; } static void proc_symkey_enc( CTX c, PACKET *pkt ) { PKT_symkey_enc *enc; enc = pkt->pkt.symkey_enc; if (!enc) log_error ("invalid symkey encrypted packet\n"); else if(!c->dek) { int algo = enc->cipher_algo; const char *s = openpgp_cipher_algo_name (algo); if (!openpgp_cipher_test_algo (algo)) { if(!opt.quiet) { if(enc->seskeylen) log_info(_("%s encrypted session key\n"), s ); else log_info(_("%s encrypted data\n"), s ); } } else log_error(_("encrypted with unknown algorithm %d\n"), algo ); if(openpgp_md_test_algo (enc->s2k.hash_algo)) { log_error(_("passphrase generated with unknown digest" " algorithm %d\n"),enc->s2k.hash_algo); s=NULL; } c->last_was_session_key = 2; if(!s || opt.list_only) goto leave; if(opt.override_session_key) { c->dek = xmalloc_clear( sizeof *c->dek ); if(get_override_session_key(c->dek, opt.override_session_key)) { xfree(c->dek); c->dek = NULL; } } else { c->dek = passphrase_to_dek (NULL, 0, algo, &enc->s2k, 3, NULL, NULL); if(c->dek) { c->dek->symmetric=1; /* FIXME: This doesn't work perfectly if a symmetric key comes before a public key in the message - if the user doesn't know the passphrase, then there is a chance that the "decrypted" algorithm will happen to be a valid one, which will make the returned dek appear valid, so we won't try any public keys that come later. */ if(enc->seskeylen) { if(symkey_decrypt_seskey(c->dek, enc->seskey, enc->seskeylen)) { xfree(c->dek); c->dek=NULL; } } else c->dek->algo_info_printed = 1; } } } leave: c->symkeys++; free_packet(pkt); } static void proc_pubkey_enc( CTX c, PACKET *pkt ) { PKT_pubkey_enc *enc; int result = 0; /* check whether the secret key is available and store in this case */ c->last_was_session_key = 1; enc = pkt->pkt.pubkey_enc; /*printf("enc: encrypted by a pubkey with keyid %08lX\n", enc->keyid[1] );*/ /* Hmmm: why do I have this algo check here - anyway there is * function to check it. */ if( opt.verbose ) log_info(_("public key is %s\n"), keystr(enc->keyid) ); if( is_status_enabled() ) { char buf[50]; /* FIXME: For ECC support we need to map the OpenPGP algo number to the Libgcrypt definef one. This is due a chicken-egg problem: We need to have code in libgcrypt for a new algorithm so to implement a proposed new algorithm before the IANA will finally assign an OpenPGP indentifier. */ snprintf (buf, sizeof buf, "%08lX%08lX %d 0", (ulong)enc->keyid[0], (ulong)enc->keyid[1], enc->pubkey_algo ); write_status_text( STATUS_ENC_TO, buf ); } if( !opt.list_only && opt.override_session_key ) { /* It does not make much sense to store the session key in * secure memory because it has already been passed on the * command line and the GCHQ knows about it. */ c->dek = xmalloc_clear( sizeof *c->dek ); result = get_override_session_key ( c->dek, opt.override_session_key ); if ( result ) { xfree(c->dek); c->dek = NULL; } } else if( is_ELGAMAL(enc->pubkey_algo) || enc->pubkey_algo == PUBKEY_ALGO_DSA || enc->pubkey_algo == PUBKEY_ALGO_ECDSA + || enc->pubkey_algo == PUBKEY_ALGO_EDDSA || enc->pubkey_algo == PUBKEY_ALGO_ECDH || is_RSA(enc->pubkey_algo) || enc->pubkey_algo == PUBKEY_ALGO_ELGAMAL) { /* Note that we also allow type 20 Elgamal keys for decryption. There are still a couple of those keys in active use as a subkey. */ /* FIXME: Store this all in a list and process it later so that we can prioritize what key to use. This gives a better user experience if wildcard keyids are used. */ if ( !c->dek && ((!enc->keyid[0] && !enc->keyid[1]) || opt.try_all_secrets || have_secret_key_with_kid (enc->keyid)) ) { if( opt.list_only ) result = -1; else { c->dek = xmalloc_secure_clear( sizeof *c->dek ); if( (result = get_session_key( enc, c->dek )) ) { /* error: delete the DEK */ xfree(c->dek); c->dek = NULL; } } } else result = G10ERR_NO_SECKEY; } else result = G10ERR_PUBKEY_ALGO; if( result == -1 ) ; else { /* store it for later display */ struct kidlist_item *x = xmalloc( sizeof *x ); x->kid[0] = enc->keyid[0]; x->kid[1] = enc->keyid[1]; x->pubkey_algo = enc->pubkey_algo; x->reason = result; x->next = c->pkenc_list; c->pkenc_list = x; if( !result && opt.verbose > 1 ) log_info( _("public key encrypted data: good DEK\n") ); } free_packet(pkt); } /**************** * Print the list of public key encrypted packets which we could * not decrypt. */ static void print_pkenc_list( struct kidlist_item *list, int failed ) { for( ; list; list = list->next ) { PKT_public_key *pk; const char *algstr; if ( failed && !list->reason ) continue; if ( !failed && list->reason ) continue; algstr = openpgp_pk_algo_name ( list->pubkey_algo ); pk = xmalloc_clear( sizeof *pk ); if( !algstr ) algstr = "[?]"; pk->pubkey_algo = list->pubkey_algo; if( !get_pubkey( pk, list->kid ) ) { char *p; log_info( _("encrypted with %u-bit %s key, ID %s, created %s\n"), nbits_from_pk( pk ), algstr, keystr_from_pk(pk), strtimestamp(pk->timestamp) ); p=get_user_id_native(list->kid); log_printf (_(" \"%s\"\n"),p); xfree(p); } else log_info(_("encrypted with %s key, ID %s\n"), algstr,keystr(list->kid)); free_public_key( pk ); if( list->reason == G10ERR_NO_SECKEY ) { if( is_status_enabled() ) { char buf[20]; snprintf (buf, sizeof buf, "%08lX%08lX", (ulong)list->kid[0], (ulong)list->kid[1]); write_status_text( STATUS_NO_SECKEY, buf ); } } else if (list->reason) { log_info(_("public key decryption failed: %s\n"), g10_errstr(list->reason)); write_status_error ("pkdecrypt_failed", list->reason); } } } static void proc_encrypted( CTX c, PACKET *pkt ) { int result = 0; if (!opt.quiet) { if(c->symkeys>1) log_info(_("encrypted with %lu passphrases\n"),c->symkeys); else if(c->symkeys==1) log_info(_("encrypted with 1 passphrase\n")); print_pkenc_list ( c->pkenc_list, 1 ); print_pkenc_list ( c->pkenc_list, 0 ); } /* FIXME: Figure out the session key by looking at all pkenc packets. */ write_status( STATUS_BEGIN_DECRYPTION ); /*log_debug("dat: %sencrypted data\n", c->dek?"":"conventional ");*/ if( opt.list_only ) result = -1; else if( !c->dek && !c->last_was_session_key ) { int algo; STRING2KEY s2kbuf, *s2k = NULL; if(opt.override_session_key) { c->dek = xmalloc_clear( sizeof *c->dek ); result=get_override_session_key(c->dek, opt.override_session_key); if(result) { xfree(c->dek); c->dek = NULL; } } else { /* Assume this is old style conventional encrypted data. */ algo = opt.def_cipher_algo; if ( algo ) log_info (_("assuming %s encrypted data\n"), openpgp_cipher_algo_name (algo)); else if ( openpgp_cipher_test_algo (CIPHER_ALGO_IDEA) ) { algo = opt.def_cipher_algo; if (!algo) algo = opt.s2k_cipher_algo; log_info (_("IDEA cipher unavailable, " "optimistically attempting to use %s instead\n"), openpgp_cipher_algo_name (algo)); } else { algo = CIPHER_ALGO_IDEA; if (!opt.s2k_digest_algo) { /* If no digest is given we assume MD5 */ s2kbuf.mode = 0; s2kbuf.hash_algo = DIGEST_ALGO_MD5; s2k = &s2kbuf; } log_info (_("assuming %s encrypted data\n"), "IDEA"); } c->dek = passphrase_to_dek ( NULL, 0, algo, s2k, 3, NULL, NULL ); if (c->dek) c->dek->algo_info_printed = 1; } } else if( !c->dek ) result = G10ERR_NO_SECKEY; if (!result) result = decrypt_data (c->ctrl, c, pkt->pkt.encrypted, c->dek ); if( result == -1 ) ; else if( !result || (gpg_err_code (result) == GPG_ERR_BAD_SIGNATURE && opt.ignore_mdc_error)) { write_status( STATUS_DECRYPTION_OKAY ); if( opt.verbose > 1 ) log_info(_("decryption okay\n")); if( pkt->pkt.encrypted->mdc_method && !result ) write_status( STATUS_GOODMDC ); else if(!opt.no_mdc_warn) log_info (_("WARNING: message was not integrity protected\n")); } else if( result == G10ERR_BAD_SIGN ) { glo_ctrl.lasterr = result; log_error(_("WARNING: encrypted message has been manipulated!\n")); write_status( STATUS_BADMDC ); write_status( STATUS_DECRYPTION_FAILED ); } else { if (gpg_err_code (result) == GPG_ERR_BAD_KEY && *c->dek->s2k_cacheid != '\0') { log_debug(_("cleared passphrase cached with ID: %s\n"), c->dek->s2k_cacheid); passphrase_clear_cache (NULL, c->dek->s2k_cacheid, 0); } glo_ctrl.lasterr = result; write_status( STATUS_DECRYPTION_FAILED ); log_error(_("decryption failed: %s\n"), g10_errstr(result)); /* Hmmm: does this work when we have encrypted using multiple * ways to specify the session key (symmmetric and PK)*/ } xfree(c->dek); c->dek = NULL; free_packet(pkt); c->last_was_session_key = 0; write_status( STATUS_END_DECRYPTION ); } static void proc_plaintext( CTX c, PACKET *pkt ) { PKT_plaintext *pt = pkt->pkt.plaintext; int any, clearsig, only_md5, rc; KBNODE n; literals_seen++; if( pt->namelen == 8 && !memcmp( pt->name, "_CONSOLE", 8 ) ) log_info(_("NOTE: sender requested \"for-your-eyes-only\"\n")); else if( opt.verbose ) log_info(_("original file name='%.*s'\n"), pt->namelen, pt->name); free_md_filter_context( &c->mfx ); if (gcry_md_open (&c->mfx.md, 0, 0)) BUG (); /* fixme: we may need to push the textfilter if we have sigclass 1 * and no armoring - Not yet tested * Hmmm, why don't we need it at all if we have sigclass 1 * Should we assume that plaintext in mode 't' has always sigclass 1?? * See: Russ Allbery's mail 1999-02-09 */ any = clearsig = only_md5 = 0; for(n=c->list; n; n = n->next ) { if( n->pkt->pkttype == PKT_ONEPASS_SIG ) { /* For the onepass signature case */ if( n->pkt->pkt.onepass_sig->digest_algo ) { gcry_md_enable (c->mfx.md, n->pkt->pkt.onepass_sig->digest_algo); if( !any && n->pkt->pkt.onepass_sig->digest_algo == DIGEST_ALGO_MD5 ) only_md5 = 1; else only_md5 = 0; any = 1; } if( n->pkt->pkt.onepass_sig->sig_class != 0x01 ) only_md5 = 0; } else if( n->pkt->pkttype == PKT_GPG_CONTROL && n->pkt->pkt.gpg_control->control == CTRLPKT_CLEARSIGN_START ) { /* For the clearsigned message case */ size_t datalen = n->pkt->pkt.gpg_control->datalen; const byte *data = n->pkt->pkt.gpg_control->data; /* check that we have at least the sigclass and one hash */ if ( datalen < 2 ) log_fatal("invalid control packet CTRLPKT_CLEARSIGN_START\n"); /* Note that we don't set the clearsig flag for not-dash-escaped * documents */ clearsig = (*data == 0x01); for( data++, datalen--; datalen; datalen--, data++ ) gcry_md_enable (c->mfx.md, *data); any = 1; break; /* Stop here as one-pass signature packets are not expected. */ } else if(n->pkt->pkttype==PKT_SIGNATURE) { /* For the SIG+LITERAL case that PGP used to use. */ gcry_md_enable ( c->mfx.md, n->pkt->pkt.signature->digest_algo ); any=1; } } if( !any && !opt.skip_verify ) { /* This is for the old GPG LITERAL+SIG case. It's not legal according to 2440, so hopefully it won't come up that often. There is no good way to specify what algorithms to use in that case, so these three are the historical answer. */ gcry_md_enable( c->mfx.md, DIGEST_ALGO_RMD160 ); gcry_md_enable( c->mfx.md, DIGEST_ALGO_SHA1 ); gcry_md_enable( c->mfx.md, DIGEST_ALGO_MD5 ); } if( opt.pgp2_workarounds && only_md5 && !opt.skip_verify ) { /* This is a kludge to work around a bug in pgp2. It does only * catch those mails which are armored. To catch the non-armored * pgp mails we could see whether there is the signature packet * in front of the plaintext. If someone needs this, send me a patch. */ if ( gcry_md_open (&c->mfx.md2, DIGEST_ALGO_MD5, 0) ) BUG (); } if ( DBG_HASHING ) { gcry_md_debug ( c->mfx.md, "verify" ); if ( c->mfx.md2 ) gcry_md_debug ( c->mfx.md2, "verify2" ); } rc=0; if (literals_seen>1) { log_info (_("WARNING: multiple plaintexts seen\n")); if (!opt.flags.allow_multiple_messages) { write_status_text (STATUS_ERROR, "proc_pkt.plaintext 89_BAD_DATA"); log_inc_errorcount (); rc = gpg_error (GPG_ERR_UNEXPECTED); } } if(!rc) { rc = handle_plaintext( pt, &c->mfx, c->sigs_only, clearsig ); if ( gpg_err_code (rc) == GPG_ERR_EACCES && !c->sigs_only ) { /* Can't write output but we hash it anyway to check the signature. */ rc = handle_plaintext( pt, &c->mfx, 1, clearsig ); } } if( rc ) log_error( "handle plaintext failed: %s\n", g10_errstr(rc)); free_packet(pkt); c->last_was_session_key = 0; /* We add a marker control packet instead of the plaintext packet. * This is so that we can later detect invalid packet sequences. */ n = new_kbnode (create_gpg_control (CTRLPKT_PLAINTEXT_MARK, NULL, 0)); if (c->list) add_kbnode (c->list, n); else c->list = n; } static int proc_compressed_cb( IOBUF a, void *info ) { if ( ((CTX)info)->signed_data.used && ((CTX)info)->signed_data.data_fd != -1) return proc_signature_packets_by_fd (((CTX)info)->ctrl, info, a, ((CTX)info)->signed_data.data_fd); else return proc_signature_packets (((CTX)info)->ctrl, info, a, ((CTX)info)->signed_data.data_names, ((CTX)info)->sigfilename ); } static int proc_encrypt_cb (IOBUF a, void *info ) { CTX c = info; return proc_encryption_packets (c->ctrl, info, a ); } static int proc_compressed( CTX c, PACKET *pkt ) { PKT_compressed *zd = pkt->pkt.compressed; int rc; /*printf("zip: compressed data packet\n");*/ if (c->sigs_only) rc = handle_compressed (c->ctrl, c, zd, proc_compressed_cb, c); else if( c->encrypt_only ) rc = handle_compressed (c->ctrl, c, zd, proc_encrypt_cb, c); else rc = handle_compressed (c->ctrl, c, zd, NULL, NULL); if (gpg_err_code (rc) == GPG_ERR_BAD_DATA) { if (!c->any.uncompress_failed) { CTX cc; for (cc=c; cc; cc = cc->anchor) cc->any.uncompress_failed = 1; log_error ("uncompressing failed: %s\n", gpg_strerror (rc)); } } else if (rc) log_error ("uncompressing failed: %s\n", gpg_strerror (rc)); free_packet(pkt); c->last_was_session_key = 0; return rc; } /**************** * check the signature * Returns: 0 = valid signature or an error code */ static int do_check_sig( CTX c, KBNODE node, int *is_selfsig, int *is_expkey, int *is_revkey ) { PKT_signature *sig; gcry_md_hd_t md = NULL, md2 = NULL; int algo, rc; assert( node->pkt->pkttype == PKT_SIGNATURE ); if( is_selfsig ) *is_selfsig = 0; sig = node->pkt->pkt.signature; algo = sig->digest_algo; rc = openpgp_md_test_algo(algo); if (rc) return rc; if( sig->sig_class == 0x00 ) { if( c->mfx.md ) { if (gcry_md_copy (&md, c->mfx.md )) BUG (); } else /* detached signature */ { /* signature_check() will enable the md*/ if (gcry_md_open (&md, 0, 0 )) BUG (); } } else if( sig->sig_class == 0x01 ) { /* how do we know that we have to hash the (already hashed) text * in canonical mode ??? (calculating both modes???) */ if( c->mfx.md ) { if (gcry_md_copy (&md, c->mfx.md )) BUG (); if( c->mfx.md2 && gcry_md_copy (&md2, c->mfx.md2 )) BUG (); } else { /* detached signature */ log_debug("Do we really need this here?"); /* signature_check() will enable the md*/ if (gcry_md_open (&md, 0, 0 )) BUG (); if (gcry_md_open (&md2, 0, 0 )) BUG (); } } else if( (sig->sig_class&~3) == 0x10 || sig->sig_class == 0x18 || sig->sig_class == 0x1f || sig->sig_class == 0x20 || sig->sig_class == 0x28 || sig->sig_class == 0x30 ) { if( c->list->pkt->pkttype == PKT_PUBLIC_KEY || c->list->pkt->pkttype == PKT_PUBLIC_SUBKEY ) { return check_key_signature( c->list, node, is_selfsig ); } else if( sig->sig_class == 0x20 ) { log_error (_("standalone revocation - " "use \"gpg --import\" to apply\n")); return G10ERR_NOT_PROCESSED; } else { log_error("invalid root packet for sigclass %02x\n", sig->sig_class); return G10ERR_SIG_CLASS; } } else return G10ERR_SIG_CLASS; rc = signature_check2( sig, md, NULL, is_expkey, is_revkey, NULL ); if( gpg_err_code (rc) == GPG_ERR_BAD_SIGNATURE && md2 ) rc = signature_check2( sig, md2, NULL, is_expkey, is_revkey, NULL ); gcry_md_close(md); gcry_md_close(md2); return rc; } static void print_userid( PACKET *pkt ) { if( !pkt ) BUG(); if( pkt->pkttype != PKT_USER_ID ) { printf("ERROR: unexpected packet type %d", pkt->pkttype ); return; } if( opt.with_colons ) { if(pkt->pkt.user_id->attrib_data) printf("%u %lu", pkt->pkt.user_id->numattribs, pkt->pkt.user_id->attrib_len); else es_write_sanitized (es_stdout, pkt->pkt.user_id->name, pkt->pkt.user_id->len, ":", NULL); } else print_utf8_buffer (es_stdout, pkt->pkt.user_id->name, pkt->pkt.user_id->len ); } /**************** * List the certificate in a user friendly way */ static void list_node( CTX c, KBNODE node ) { int any=0; int mainkey; if( !node ) ; else if( (mainkey = (node->pkt->pkttype == PKT_PUBLIC_KEY) ) || node->pkt->pkttype == PKT_PUBLIC_SUBKEY ) { PKT_public_key *pk = node->pkt->pkt.public_key; if( opt.with_colons ) { u32 keyid[2]; keyid_from_pk( pk, keyid ); if( mainkey ) c->trustletter = opt.fast_list_mode? 0 : get_validity_info( pk, NULL ); printf("%s:", mainkey? "pub":"sub" ); if( c->trustletter ) putchar( c->trustletter ); printf(":%u:%d:%08lX%08lX:%s:%s::", nbits_from_pk( pk ), pk->pubkey_algo, (ulong)keyid[0],(ulong)keyid[1], colon_datestr_from_pk( pk ), colon_strtime (pk->expiredate) ); if( mainkey && !opt.fast_list_mode ) putchar( get_ownertrust_info (pk) ); putchar(':'); if( node->next && node->next->pkt->pkttype == PKT_RING_TRUST) { putchar('\n'); any=1; if( opt.fingerprint ) print_fingerprint (pk, 0); printf("rtv:1:%u:\n", node->next->pkt->pkt.ring_trust->trustval ); } } else printf("%s %4u%c/%s %s%s", mainkey? "pub":"sub", nbits_from_pk( pk ), pubkey_letter( pk->pubkey_algo ), keystr_from_pk( pk ), datestr_from_pk( pk ), mainkey?" ":""); if( mainkey ) { /* and now list all userids with their signatures */ for( node = node->next; node; node = node->next ) { if( node->pkt->pkttype == PKT_SIGNATURE ) { if( !any ) { if( node->pkt->pkt.signature->sig_class == 0x20 ) puts("[revoked]"); else putchar('\n'); any = 1; } list_node(c, node ); } else if( node->pkt->pkttype == PKT_USER_ID ) { if( any ) { if( opt.with_colons ) printf("%s:::::::::", node->pkt->pkt.user_id->attrib_data?"uat":"uid"); else printf( "uid%*s", 28, "" ); } print_userid( node->pkt ); if( opt.with_colons ) putchar(':'); putchar('\n'); if( opt.fingerprint && !any ) print_fingerprint ( pk, 0 ); if( opt.with_colons && node->next && node->next->pkt->pkttype == PKT_RING_TRUST ) { printf("rtv:2:%u:\n", node->next->pkt->pkt.ring_trust? node->next->pkt->pkt.ring_trust->trustval : 0); } any=1; } else if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY ) { if( !any ) { putchar('\n'); any = 1; } list_node(c, node ); } } } else { /* of subkey */ if( pk->flags.revoked ) { printf(" ["); printf(_("revoked: %s"),revokestr_from_pk(pk)); printf("]"); } else if( pk->expiredate ) { printf(" ["); printf(_("expires: %s"),expirestr_from_pk(pk)); printf("]"); } } if( !any ) putchar('\n'); if( !mainkey && opt.fingerprint > 1 ) print_fingerprint( pk, 0 ); } else if( (mainkey = (node->pkt->pkttype == PKT_SECRET_KEY) ) || node->pkt->pkttype == PKT_SECRET_SUBKEY ) { log_debug ("FIXME: No way to print secret key packets here\n"); /* fixme: We may use a fucntion to trun a secret key packet into a public key one and use that here. */ /* PKT_secret_key *sk = node->pkt->pkt.secret_key; */ /* if( opt.with_colons ) */ /* { */ /* u32 keyid[2]; */ /* keyid_from_sk( sk, keyid ); */ /* printf("%s::%u:%d:%08lX%08lX:%s:%s:::", */ /* mainkey? "sec":"ssb", */ /* nbits_from_sk( sk ), */ /* sk->pubkey_algo, */ /* (ulong)keyid[0],(ulong)keyid[1], */ /* colon_datestr_from_sk( sk ), */ /* colon_strtime (sk->expiredate) */ /* /\* fixme: add LID *\/ ); */ /* } */ /* else */ /* printf("%s %4u%c/%s %s ", mainkey? "sec":"ssb", */ /* nbits_from_sk( sk ), pubkey_letter( sk->pubkey_algo ), */ /* keystr_from_sk( sk ), datestr_from_sk( sk )); */ /* if( mainkey ) { */ /* /\* and now list all userids with their signatures *\/ */ /* for( node = node->next; node; node = node->next ) { */ /* if( node->pkt->pkttype == PKT_SIGNATURE ) { */ /* if( !any ) { */ /* if( node->pkt->pkt.signature->sig_class == 0x20 ) */ /* puts("[revoked]"); */ /* else */ /* putchar('\n'); */ /* any = 1; */ /* } */ /* list_node(c, node ); */ /* } */ /* else if( node->pkt->pkttype == PKT_USER_ID ) { */ /* if( any ) { */ /* if( opt.with_colons ) */ /* printf("%s:::::::::", */ /* node->pkt->pkt.user_id->attrib_data?"uat":"uid"); */ /* else */ /* printf( "uid%*s", 28, "" ); */ /* } */ /* print_userid( node->pkt ); */ /* if( opt.with_colons ) */ /* putchar(':'); */ /* putchar('\n'); */ /* if( opt.fingerprint && !any ) */ /* print_fingerprint( NULL, sk, 0 ); */ /* any=1; */ /* } */ /* else if( node->pkt->pkttype == PKT_SECRET_SUBKEY ) { */ /* if( !any ) { */ /* putchar('\n'); */ /* any = 1; */ /* } */ /* list_node(c, node ); */ /* } */ /* } */ /* } */ /* if( !any ) */ /* putchar('\n'); */ /* if( !mainkey && opt.fingerprint > 1 ) */ /* print_fingerprint( NULL, sk, 0 ); */ } else if( node->pkt->pkttype == PKT_SIGNATURE ) { PKT_signature *sig = node->pkt->pkt.signature; int is_selfsig = 0; int rc2=0; size_t n; char *p; int sigrc = ' '; if( !opt.verbose ) return; if( sig->sig_class == 0x20 || sig->sig_class == 0x30 ) fputs("rev", stdout); else fputs("sig", stdout); if( opt.check_sigs ) { fflush(stdout); rc2=do_check_sig( c, node, &is_selfsig, NULL, NULL ); switch (gpg_err_code (rc2)) { case 0: sigrc = '!'; break; case GPG_ERR_BAD_SIGNATURE: sigrc = '-'; break; case GPG_ERR_NO_PUBKEY: case GPG_ERR_UNUSABLE_PUBKEY: sigrc = '?'; break; default: sigrc = '%'; break; } } else { /* check whether this is a self signature */ u32 keyid[2]; if( c->list->pkt->pkttype == PKT_PUBLIC_KEY || c->list->pkt->pkttype == PKT_SECRET_KEY ) { keyid_from_pk (c->list->pkt->pkt.public_key, keyid); if( keyid[0] == sig->keyid[0] && keyid[1] == sig->keyid[1] ) is_selfsig = 1; } } if( opt.with_colons ) { putchar(':'); if( sigrc != ' ' ) putchar(sigrc); printf("::%d:%08lX%08lX:%s:%s:", sig->pubkey_algo, (ulong)sig->keyid[0], (ulong)sig->keyid[1], colon_datestr_from_sig(sig), colon_expirestr_from_sig(sig)); if(sig->trust_depth || sig->trust_value) printf("%d %d",sig->trust_depth,sig->trust_value); printf(":"); if(sig->trust_regexp) es_write_sanitized (es_stdout,sig->trust_regexp, strlen(sig->trust_regexp), ":", NULL); printf(":"); } else printf("%c %s %s ", sigrc, keystr(sig->keyid), datestr_from_sig(sig)); if( sigrc == '%' ) printf("[%s] ", g10_errstr(rc2) ); else if( sigrc == '?' ) ; else if( is_selfsig ) { if( opt.with_colons ) putchar(':'); fputs( sig->sig_class == 0x18? "[keybind]":"[selfsig]", stdout); if( opt.with_colons ) putchar(':'); } else if( !opt.fast_list_mode ) { p = get_user_id( sig->keyid, &n ); es_write_sanitized (es_stdout, p, n, opt.with_colons?":":NULL, NULL ); xfree(p); } if( opt.with_colons ) printf(":%02x%c:", sig->sig_class, sig->flags.exportable?'x':'l'); putchar('\n'); } else log_error("invalid node with packet of type %d\n", node->pkt->pkttype); } int proc_packets (ctrl_t ctrl, void *anchor, IOBUF a ) { int rc; CTX c = xmalloc_clear( sizeof *c ); c->ctrl = ctrl; c->anchor = anchor; rc = do_proc_packets( c, a ); xfree( c ); return rc; } int proc_signature_packets (ctrl_t ctrl, void *anchor, IOBUF a, strlist_t signedfiles, const char *sigfilename ) { CTX c = xmalloc_clear( sizeof *c ); int rc; c->ctrl = ctrl; c->anchor = anchor; c->sigs_only = 1; c->signed_data.data_fd = -1; c->signed_data.data_names = signedfiles; c->signed_data.used = !!signedfiles; c->sigfilename = sigfilename; rc = do_proc_packets( c, a ); /* If we have not encountered any signature we print an error messages, send a NODATA status back and return an error code. Using log_error is required because verify_files does not check error codes for each file but we want to terminate the process with an error. */ if (!rc && !c->any.sig_seen) { write_status_text (STATUS_NODATA, "4"); log_error (_("no signature found\n")); rc = G10ERR_NO_DATA; } /* Propagate the signature seen flag upward. Do this only on success so that we won't issue the nodata status several times. */ if (!rc && c->anchor && c->any.sig_seen) c->anchor->any.sig_seen = 1; xfree( c ); return rc; } int proc_signature_packets_by_fd (ctrl_t ctrl, void *anchor, IOBUF a, int signed_data_fd ) { int rc; CTX c; c = xtrycalloc (1, sizeof *c); if (!c) return gpg_error_from_syserror (); c->ctrl = ctrl; c->anchor = anchor; c->sigs_only = 1; c->signed_data.data_fd = signed_data_fd; c->signed_data.data_names = NULL; c->signed_data.used = (signed_data_fd != -1); rc = do_proc_packets ( c, a ); /* If we have not encountered any signature we print an error messages, send a NODATA status back and return an error code. Using log_error is required because verify_files does not check error codes for each file but we want to terminate the process with an error. */ if (!rc && !c->any.sig_seen) { write_status_text (STATUS_NODATA, "4"); log_error (_("no signature found\n")); rc = gpg_error (GPG_ERR_NO_DATA); } /* Propagate the signature seen flag upward. Do this only on success so that we won't issue the nodata status several times. */ if (!rc && c->anchor && c->any.sig_seen) c->anchor->any.sig_seen = 1; xfree ( c ); return rc; } int proc_encryption_packets (ctrl_t ctrl, void *anchor, IOBUF a ) { CTX c = xmalloc_clear( sizeof *c ); int rc; c->ctrl = ctrl; c->anchor = anchor; c->encrypt_only = 1; rc = do_proc_packets( c, a ); xfree( c ); return rc; } static int check_nesting (CTX c) { int level; for (level=0; c; c = c->anchor) level++; if (level > MAX_NESTING_DEPTH) { log_error ("input data with too deeply nested packets\n"); write_status_text (STATUS_UNEXPECTED, "1"); return GPG_ERR_BAD_DATA; } return 0; } static int do_proc_packets( CTX c, IOBUF a ) { PACKET *pkt; int rc = 0; int any_data = 0; int newpkt; rc = check_nesting (c); if (rc) return rc; pkt = xmalloc( sizeof *pkt ); c->iobuf = a; init_packet(pkt); while( (rc=parse_packet(a, pkt)) != -1 ) { any_data = 1; if( rc ) { free_packet(pkt); /* stop processing when an invalid packet has been encountered * but don't do so when we are doing a --list-packets. */ if (gpg_err_code (rc) == GPG_ERR_INV_PACKET && opt.list_packets != 2 ) break; continue; } newpkt = -1; if( opt.list_packets ) { switch( pkt->pkttype ) { case PKT_PUBKEY_ENC: proc_pubkey_enc( c, pkt ); break; case PKT_SYMKEY_ENC: proc_symkey_enc( c, pkt ); break; case PKT_ENCRYPTED: case PKT_ENCRYPTED_MDC: proc_encrypted( c, pkt ); break; case PKT_COMPRESSED: rc = proc_compressed( c, pkt ); break; default: newpkt = 0; break; } } else if( c->sigs_only ) { switch( pkt->pkttype ) { case PKT_PUBLIC_KEY: case PKT_SECRET_KEY: case PKT_USER_ID: case PKT_SYMKEY_ENC: case PKT_PUBKEY_ENC: case PKT_ENCRYPTED: case PKT_ENCRYPTED_MDC: write_status_text( STATUS_UNEXPECTED, "0" ); rc = G10ERR_UNEXPECTED; goto leave; case PKT_SIGNATURE: newpkt = add_signature( c, pkt ); break; case PKT_PLAINTEXT: proc_plaintext( c, pkt ); break; case PKT_COMPRESSED: rc = proc_compressed( c, pkt ); break; case PKT_ONEPASS_SIG: newpkt = add_onepass_sig( c, pkt ); break; case PKT_GPG_CONTROL: newpkt = add_gpg_control(c, pkt); break; default: newpkt = 0; break; } } else if( c->encrypt_only ) { switch( pkt->pkttype ) { case PKT_PUBLIC_KEY: case PKT_SECRET_KEY: case PKT_USER_ID: write_status_text( STATUS_UNEXPECTED, "0" ); rc = G10ERR_UNEXPECTED; goto leave; case PKT_SIGNATURE: newpkt = add_signature( c, pkt ); break; case PKT_SYMKEY_ENC: proc_symkey_enc( c, pkt ); break; case PKT_PUBKEY_ENC: proc_pubkey_enc( c, pkt ); break; case PKT_ENCRYPTED: case PKT_ENCRYPTED_MDC: proc_encrypted( c, pkt ); break; case PKT_PLAINTEXT: proc_plaintext( c, pkt ); break; case PKT_COMPRESSED: rc = proc_compressed( c, pkt ); break; case PKT_ONEPASS_SIG: newpkt = add_onepass_sig( c, pkt ); break; case PKT_GPG_CONTROL: newpkt = add_gpg_control(c, pkt); break; default: newpkt = 0; break; } } else { switch( pkt->pkttype ) { case PKT_PUBLIC_KEY: case PKT_SECRET_KEY: release_list( c ); c->list = new_kbnode( pkt ); newpkt = 1; break; case PKT_PUBLIC_SUBKEY: case PKT_SECRET_SUBKEY: newpkt = add_subkey( c, pkt ); break; case PKT_USER_ID: newpkt = add_user_id( c, pkt ); break; case PKT_SIGNATURE: newpkt = add_signature( c, pkt ); break; case PKT_PUBKEY_ENC: proc_pubkey_enc( c, pkt ); break; case PKT_SYMKEY_ENC: proc_symkey_enc( c, pkt ); break; case PKT_ENCRYPTED: case PKT_ENCRYPTED_MDC: proc_encrypted( c, pkt ); break; case PKT_PLAINTEXT: proc_plaintext( c, pkt ); break; case PKT_COMPRESSED: rc = proc_compressed( c, pkt ); break; case PKT_ONEPASS_SIG: newpkt = add_onepass_sig( c, pkt ); break; case PKT_GPG_CONTROL: newpkt = add_gpg_control(c, pkt); break; case PKT_RING_TRUST: newpkt = add_ring_trust( c, pkt ); break; default: newpkt = 0; break; } } if (rc) goto leave; /* This is a very ugly construct and frankly, I don't remember why * I used it. Adding the MDC check here is a hack. * The right solution is to initiate another context for encrypted * packet and not to reuse the current one ... It works right * when there is a compression packet inbetween which adds just * an extra layer. * Hmmm: Rewrite this whole module here?? */ if( pkt->pkttype != PKT_SIGNATURE && pkt->pkttype != PKT_MDC ) c->any.data = (pkt->pkttype == PKT_PLAINTEXT); if( newpkt == -1 ) ; else if( newpkt ) { pkt = xmalloc( sizeof *pkt ); init_packet(pkt); } else free_packet(pkt); } if( rc == G10ERR_INVALID_PACKET ) write_status_text( STATUS_NODATA, "3" ); if( any_data ) rc = 0; else if( rc == -1 ) write_status_text( STATUS_NODATA, "2" ); leave: release_list( c ); xfree(c->dek); free_packet( pkt ); xfree( pkt ); free_md_filter_context( &c->mfx ); return rc; } /* Helper for pka_uri_from_sig to parse the to-be-verified address out of the notation data. */ static pka_info_t * get_pka_address (PKT_signature *sig) { pka_info_t *pka = NULL; struct notation *nd,*notation; notation=sig_to_notation(sig); for(nd=notation;nd;nd=nd->next) { if(strcmp(nd->name,"pka-address@gnupg.org")!=0) continue; /* Not the notation we want. */ /* For now we only use the first valid PKA notation. In future we might want to keep additional PKA notations in a linked list. */ if (is_valid_mailbox (nd->value)) { pka = xmalloc (sizeof *pka + strlen(nd->value)); pka->valid = 0; pka->checked = 0; pka->uri = NULL; strcpy (pka->email, nd->value); break; } } free_notation(notation); return pka; } /* Return the URI from a DNS PKA record. If this record has already be retrieved for the signature we merely return it; if not we go out and try to get that DNS record. */ static const char * pka_uri_from_sig (PKT_signature *sig) { if (!sig->flags.pka_tried) { assert (!sig->pka_info); sig->flags.pka_tried = 1; sig->pka_info = get_pka_address (sig); if (sig->pka_info) { char *uri; uri = get_pka_info (sig->pka_info->email, sig->pka_info->fpr); if (uri) { sig->pka_info->valid = 1; if (!*uri) xfree (uri); else sig->pka_info->uri = uri; } } } return sig->pka_info? sig->pka_info->uri : NULL; } static int check_sig_and_print( CTX c, KBNODE node ) { PKT_signature *sig = node->pkt->pkt.signature; const char *astr; int rc, is_expkey=0, is_revkey=0; if (opt.skip_verify) { log_info(_("signature verification suppressed\n")); return 0; } /* Check that the message composition is valid. Per RFC-2440bis (-15) allowed: S{1,n} -- detached signature. S{1,n} P -- old style PGP2 signature O{1,n} P S{1,n} -- standard OpenPGP signature. C P S{1,n} -- cleartext signature. O = One-Pass Signature packet. S = Signature packet. P = OpenPGP Message packet (Encrypted | Compressed | Literal) (Note that the current rfc2440bis draft also allows for a signed message but that does not work as it introduces ambiguities.) We keep track of these packages using the marker packet CTRLPKT_PLAINTEXT_MARK. C = Marker packet for cleartext signatures. We reject all other messages. Actually we are calling this too often, i.e. for verification of each message but better have some duplicate work than to silently introduce a bug here. */ { KBNODE n; int n_onepass, n_sig; /* log_debug ("checking signature packet composition\n"); */ /* dump_kbnode (c->list); */ n = c->list; assert (n); if ( n->pkt->pkttype == PKT_SIGNATURE ) { /* This is either "S{1,n}" case (detached signature) or "S{1,n} P" (old style PGP2 signature). */ for (n = n->next; n; n = n->next) if (n->pkt->pkttype != PKT_SIGNATURE) break; if (!n) ; /* Okay, this is a detached signature. */ else if (n->pkt->pkttype == PKT_GPG_CONTROL && (n->pkt->pkt.gpg_control->control == CTRLPKT_PLAINTEXT_MARK) ) { if (n->next) goto ambiguous; /* We only allow one P packet. */ } else goto ambiguous; } else if (n->pkt->pkttype == PKT_ONEPASS_SIG) { /* This is the "O{1,n} P S{1,n}" case (standard signature). */ for (n_onepass=1, n = n->next; n && n->pkt->pkttype == PKT_ONEPASS_SIG; n = n->next) n_onepass++; if (!n || !(n->pkt->pkttype == PKT_GPG_CONTROL && (n->pkt->pkt.gpg_control->control == CTRLPKT_PLAINTEXT_MARK))) goto ambiguous; for (n_sig=0, n = n->next; n && n->pkt->pkttype == PKT_SIGNATURE; n = n->next) n_sig++; if (!n_sig) goto ambiguous; /* If we wanted to disallow multiple sig verification, we'd do something like this: if (n && !opt.allow_multisig_verification) goto ambiguous; However, now that we have --allow-multiple-messages, this can stay allowable as we can't get here unless multiple messages (i.e. multiple literals) are allowed. */ if (n_onepass != n_sig) { log_info ("number of one-pass packets does not match " "number of signature packets\n"); goto ambiguous; } } else if (n->pkt->pkttype == PKT_GPG_CONTROL && n->pkt->pkt.gpg_control->control == CTRLPKT_CLEARSIGN_START ) { /* This is the "C P S{1,n}" case (clear text signature). */ n = n->next; if (!n || !(n->pkt->pkttype == PKT_GPG_CONTROL && (n->pkt->pkt.gpg_control->control == CTRLPKT_PLAINTEXT_MARK))) goto ambiguous; for (n_sig=0, n = n->next; n && n->pkt->pkttype == PKT_SIGNATURE; n = n->next) n_sig++; if (n || !n_sig) goto ambiguous; } else { ambiguous: log_error(_("can't handle this ambiguous signature data\n")); return 0; } } /* (Indendation below not yet changed to GNU style.) */ astr = openpgp_pk_algo_name ( sig->pubkey_algo ); if(keystrlen()>8) { log_info(_("Signature made %s\n"),asctimestamp(sig->timestamp)); log_info(_(" using %s key %s\n"), astr? astr: "?",keystr(sig->keyid)); } else log_info(_("Signature made %s using %s key ID %s\n"), asctimestamp(sig->timestamp), astr? astr: "?", keystr(sig->keyid)); rc = do_check_sig(c, node, NULL, &is_expkey, &is_revkey ); /* If the key isn't found, check for a preferred keyserver */ if(rc==G10ERR_NO_PUBKEY && sig->flags.pref_ks) { const byte *p; int seq=0; size_t n; while((p=enum_sig_subpkt(sig->hashed,SIGSUBPKT_PREF_KS,&n,&seq,NULL))) { /* According to my favorite copy editor, in English grammar, you say "at" if the key is located on a web page, but "from" if it is located on a keyserver. I'm not going to even try to make two strings here :) */ log_info(_("Key available at: ") ); print_utf8_buffer (log_get_stream(), p, n); log_printf ("\n"); if(opt.keyserver_options.options&KEYSERVER_AUTO_KEY_RETRIEVE && opt.keyserver_options.options&KEYSERVER_HONOR_KEYSERVER_URL) { struct keyserver_spec *spec; spec=parse_preferred_keyserver(sig); if(spec) { int res; glo_ctrl.in_auto_key_retrieve++; res = keyserver_import_keyid (c->ctrl, sig->keyid,spec); glo_ctrl.in_auto_key_retrieve--; if(!res) rc=do_check_sig(c, node, NULL, &is_expkey, &is_revkey ); free_keyserver_spec(spec); if(!rc) break; } } } } /* If the preferred keyserver thing above didn't work, our second try is to use the URI from a DNS PKA record. */ if ( rc == G10ERR_NO_PUBKEY && opt.keyserver_options.options&KEYSERVER_AUTO_KEY_RETRIEVE && opt.keyserver_options.options&KEYSERVER_HONOR_PKA_RECORD) { const char *uri = pka_uri_from_sig (sig); if (uri) { /* FIXME: We might want to locate the key using the fingerprint instead of the keyid. */ int res; struct keyserver_spec *spec; spec = parse_keyserver_uri (uri, 1, NULL, 0); if (spec) { glo_ctrl.in_auto_key_retrieve++; res = keyserver_import_keyid (c->ctrl, sig->keyid, spec); glo_ctrl.in_auto_key_retrieve--; free_keyserver_spec (spec); if (!res) rc = do_check_sig(c, node, NULL, &is_expkey, &is_revkey ); } } } /* If the preferred keyserver thing above didn't work and we got no information from the DNS PKA, this is a third try. */ if( rc == G10ERR_NO_PUBKEY && opt.keyserver && opt.keyserver_options.options&KEYSERVER_AUTO_KEY_RETRIEVE) { int res; glo_ctrl.in_auto_key_retrieve++; res=keyserver_import_keyid (c->ctrl, sig->keyid, opt.keyserver ); glo_ctrl.in_auto_key_retrieve--; if(!res) rc = do_check_sig(c, node, NULL, &is_expkey, &is_revkey ); } if( !rc || gpg_err_code (rc) == GPG_ERR_BAD_SIGNATURE ) { KBNODE un, keyblock; int count=0, statno; char keyid_str[50]; PKT_public_key *pk=NULL; if(rc) statno=STATUS_BADSIG; else if(sig->flags.expired) statno=STATUS_EXPSIG; else if(is_expkey) statno=STATUS_EXPKEYSIG; else if(is_revkey) statno=STATUS_REVKEYSIG; else statno=STATUS_GOODSIG; keyblock = get_pubkeyblock( sig->keyid ); sprintf (keyid_str, "%08lX%08lX [uncertain] ", (ulong)sig->keyid[0], (ulong)sig->keyid[1]); /* find and print the primary user ID */ for( un=keyblock; un; un = un->next ) { char *p; int valid; if(un->pkt->pkttype==PKT_PUBLIC_KEY) { pk=un->pkt->pkt.public_key; continue; } if( un->pkt->pkttype != PKT_USER_ID ) continue; if ( !un->pkt->pkt.user_id->created ) continue; if ( un->pkt->pkt.user_id->is_revoked ) continue; if ( un->pkt->pkt.user_id->is_expired ) continue; if ( !un->pkt->pkt.user_id->is_primary ) continue; /* We want the textual primary user ID here */ if ( un->pkt->pkt.user_id->attrib_data ) continue; assert(pk); /* Get it before we print anything to avoid interrupting the output with the "please do a --check-trustdb" line. */ valid=get_validity(pk,un->pkt->pkt.user_id); keyid_str[17] = 0; /* cut off the "[uncertain]" part */ write_status_text_and_buffer (statno, keyid_str, un->pkt->pkt.user_id->name, un->pkt->pkt.user_id->len, -1 ); p=utf8_to_native(un->pkt->pkt.user_id->name, un->pkt->pkt.user_id->len,0); if(rc) log_info(_("BAD signature from \"%s\""),p); else if(sig->flags.expired) log_info(_("Expired signature from \"%s\""),p); else log_info(_("Good signature from \"%s\""),p); xfree(p); if(opt.verify_options&VERIFY_SHOW_UID_VALIDITY) log_printf (" [%s]\n",trust_value_to_string(valid)); else log_printf ("\n"); count++; } if( !count ) { /* just in case that we have no valid textual userid */ char *p; /* Try for an invalid textual userid */ for( un=keyblock; un; un = un->next ) { if( un->pkt->pkttype == PKT_USER_ID && !un->pkt->pkt.user_id->attrib_data ) break; } /* Try for any userid at all */ if(!un) { for( un=keyblock; un; un = un->next ) { if( un->pkt->pkttype == PKT_USER_ID ) break; } } if (opt.trust_model==TM_ALWAYS || !un) keyid_str[17] = 0; /* cut off the "[uncertain]" part */ write_status_text_and_buffer (statno, keyid_str, un? un->pkt->pkt.user_id->name:"[?]", un? un->pkt->pkt.user_id->len:3, -1 ); if(un) p=utf8_to_native(un->pkt->pkt.user_id->name, un->pkt->pkt.user_id->len,0); else p=xstrdup("[?]"); if(rc) log_info(_("BAD signature from \"%s\""),p); else if(sig->flags.expired) log_info(_("Expired signature from \"%s\""),p); else log_info(_("Good signature from \"%s\""),p); if (opt.trust_model!=TM_ALWAYS && un) log_printf (" %s",_("[uncertain]") ); log_printf ("\n"); } /* If we have a good signature and already printed * the primary user ID, print all the other user IDs */ if ( count && !rc && !(opt.verify_options&VERIFY_SHOW_PRIMARY_UID_ONLY)) { char *p; for( un=keyblock; un; un = un->next ) { if( un->pkt->pkttype != PKT_USER_ID ) continue; if((un->pkt->pkt.user_id->is_revoked || un->pkt->pkt.user_id->is_expired) && !(opt.verify_options&VERIFY_SHOW_UNUSABLE_UIDS)) continue; /* Only skip textual primaries */ if ( un->pkt->pkt.user_id->is_primary && !un->pkt->pkt.user_id->attrib_data ) continue; if(un->pkt->pkt.user_id->attrib_data) { dump_attribs (un->pkt->pkt.user_id, pk); if(opt.verify_options&VERIFY_SHOW_PHOTOS) show_photos(un->pkt->pkt.user_id->attribs, un->pkt->pkt.user_id->numattribs, pk ,un->pkt->pkt.user_id); } p=utf8_to_native(un->pkt->pkt.user_id->name, un->pkt->pkt.user_id->len,0); log_info(_(" aka \"%s\""),p); xfree(p); if(opt.verify_options&VERIFY_SHOW_UID_VALIDITY) { const char *valid; if(un->pkt->pkt.user_id->is_revoked) valid=_("revoked"); else if(un->pkt->pkt.user_id->is_expired) valid=_("expired"); else valid=trust_value_to_string(get_validity(pk, un->pkt-> pkt.user_id)); log_printf (" [%s]\n",valid); } else log_printf ("\n"); } } release_kbnode( keyblock ); if( !rc ) { if(opt.verify_options&VERIFY_SHOW_POLICY_URLS) show_policy_url(sig,0,1); else show_policy_url(sig,0,2); if(opt.verify_options&VERIFY_SHOW_KEYSERVER_URLS) show_keyserver_url(sig,0,1); else show_keyserver_url(sig,0,2); if(opt.verify_options&VERIFY_SHOW_NOTATIONS) show_notation(sig,0,1, ((opt.verify_options&VERIFY_SHOW_STD_NOTATIONS)?1:0)+ ((opt.verify_options&VERIFY_SHOW_USER_NOTATIONS)?2:0)); else show_notation(sig,0,2,0); } if( !rc && is_status_enabled() ) { /* print a status response with the fingerprint */ PKT_public_key *vpk = xmalloc_clear( sizeof *vpk ); if( !get_pubkey( vpk, sig->keyid ) ) { byte array[MAX_FINGERPRINT_LEN], *p; char buf[MAX_FINGERPRINT_LEN*4+90], *bufp; size_t i, n; bufp = buf; fingerprint_from_pk( vpk, array, &n ); p = array; for(i=0; i < n ; i++, p++, bufp += 2) sprintf(bufp, "%02X", *p ); /* TODO: Replace the reserved '0' in the field below with bits for status flags (policy url, notation, etc.). Remember to make the buffer larger to match! */ sprintf(bufp, " %s %lu %lu %d 0 %d %d %02X ", strtimestamp( sig->timestamp ), (ulong)sig->timestamp,(ulong)sig->expiredate, sig->version,sig->pubkey_algo,sig->digest_algo, sig->sig_class); bufp = bufp + strlen (bufp); if (!vpk->flags.primary) { u32 akid[2]; akid[0] = vpk->main_keyid[0]; akid[1] = vpk->main_keyid[1]; free_public_key (vpk); vpk = xmalloc_clear( sizeof *vpk ); if (get_pubkey (vpk, akid)) { /* impossible error, we simply return a zeroed out fpr */ n = MAX_FINGERPRINT_LEN < 20? MAX_FINGERPRINT_LEN : 20; memset (array, 0, n); } else fingerprint_from_pk( vpk, array, &n ); } p = array; for(i=0; i < n ; i++, p++, bufp += 2) sprintf(bufp, "%02X", *p ); write_status_text( STATUS_VALIDSIG, buf ); } free_public_key( vpk ); } if (!rc) { if(opt.verify_options&VERIFY_PKA_LOOKUPS) pka_uri_from_sig (sig); /* Make sure PKA info is available. */ rc = check_signatures_trust( sig ); } if(sig->flags.expired) { log_info(_("Signature expired %s\n"), asctimestamp(sig->expiredate)); rc=G10ERR_GENERAL; /* need a better error here? */ } else if(sig->expiredate) log_info(_("Signature expires %s\n"),asctimestamp(sig->expiredate)); if(opt.verbose) log_info(_("%s signature, digest algorithm %s\n"), sig->sig_class==0x00?_("binary"): sig->sig_class==0x01?_("textmode"):_("unknown"), gcry_md_algo_name (sig->digest_algo)); if( rc ) g10_errors_seen = 1; if( opt.batch && rc ) g10_exit(1); } else { char buf[50]; sprintf(buf, "%08lX%08lX %d %d %02x %lu %d", (ulong)sig->keyid[0], (ulong)sig->keyid[1], sig->pubkey_algo, sig->digest_algo, sig->sig_class, (ulong)sig->timestamp, rc ); write_status_text( STATUS_ERRSIG, buf ); if( rc == G10ERR_NO_PUBKEY ) { buf[16] = 0; write_status_text( STATUS_NO_PUBKEY, buf ); } if( rc != G10ERR_NOT_PROCESSED ) log_error(_("Can't check signature: %s\n"), g10_errstr(rc) ); } return rc; } /**************** * Process the tree which starts at node */ static void proc_tree( CTX c, KBNODE node ) { KBNODE n1; int rc; if( opt.list_packets || opt.list_only ) return; /* we must skip our special plaintext marker packets here becuase they may be the root packet. These packets are only used in addionla checks and skipping them here doesn't matter */ while ( node && node->pkt->pkttype == PKT_GPG_CONTROL && node->pkt->pkt.gpg_control->control == CTRLPKT_PLAINTEXT_MARK ) { node = node->next; } if (!node) return; c->trustletter = ' '; if( node->pkt->pkttype == PKT_PUBLIC_KEY || node->pkt->pkttype == PKT_PUBLIC_SUBKEY ) { merge_keys_and_selfsig( node ); list_node( c, node ); } else if( node->pkt->pkttype == PKT_SECRET_KEY ) { merge_keys_and_selfsig( node ); list_node( c, node ); } else if( node->pkt->pkttype == PKT_ONEPASS_SIG ) { /* check all signatures */ if( !c->any.data ) { int use_textmode = 0; free_md_filter_context( &c->mfx ); /* prepare to create all requested message digests */ if (gcry_md_open (&c->mfx.md, 0, 0)) BUG (); /* fixme: why looking for the signature packet and not the one-pass packet? */ for ( n1 = node; (n1 = find_next_kbnode(n1, PKT_SIGNATURE )); ) { gcry_md_enable (c->mfx.md, n1->pkt->pkt.signature->digest_algo); } if (n1 && n1->pkt->pkt.onepass_sig->sig_class == 0x01) use_textmode = 1; /* Ask for file and hash it. */ if( c->sigs_only ) { if (c->signed_data.used && c->signed_data.data_fd != -1) rc = hash_datafile_by_fd (c->mfx.md, NULL, c->signed_data.data_fd, use_textmode); else rc = hash_datafiles (c->mfx.md, NULL, c->signed_data.data_names, c->sigfilename, use_textmode ); } else { rc = ask_for_detached_datafile (c->mfx.md, c->mfx.md2, iobuf_get_real_fname(c->iobuf), use_textmode ); } if( rc ) { log_error("can't hash datafile: %s\n", g10_errstr(rc)); return; } } else if ( c->signed_data.used ) { log_error (_("not a detached signature\n") ); return; } for( n1 = node; (n1 = find_next_kbnode(n1, PKT_SIGNATURE )); ) check_sig_and_print( c, n1 ); } else if( node->pkt->pkttype == PKT_GPG_CONTROL && node->pkt->pkt.gpg_control->control == CTRLPKT_CLEARSIGN_START ) { /* clear text signed message */ if( !c->any.data ) { log_error("cleartext signature without data\n" ); return; } else if ( c->signed_data.used ) { log_error (_("not a detached signature\n") ); return; } for( n1 = node; (n1 = find_next_kbnode(n1, PKT_SIGNATURE )); ) check_sig_and_print( c, n1 ); } else if( node->pkt->pkttype == PKT_SIGNATURE ) { PKT_signature *sig = node->pkt->pkt.signature; int multiple_ok=1; n1=find_next_kbnode(node, PKT_SIGNATURE); if(n1) { byte class=sig->sig_class; byte hash=sig->digest_algo; for(; n1; (n1 = find_next_kbnode(n1, PKT_SIGNATURE))) { /* We can't currently handle multiple signatures of different classes or digests (we'd pretty much have to run a different hash context for each), but if they are all the same, make an exception. */ if(n1->pkt->pkt.signature->sig_class!=class || n1->pkt->pkt.signature->digest_algo!=hash) { multiple_ok=0; log_info(_("WARNING: multiple signatures detected. " "Only the first will be checked.\n")); break; } } } if( sig->sig_class != 0x00 && sig->sig_class != 0x01 ) log_info(_("standalone signature of class 0x%02x\n"), sig->sig_class); else if( !c->any.data ) { /* detached signature */ free_md_filter_context( &c->mfx ); if (gcry_md_open (&c->mfx.md, sig->digest_algo, 0)) BUG (); if( !opt.pgp2_workarounds ) ; else if( sig->digest_algo == DIGEST_ALGO_MD5 && is_RSA( sig->pubkey_algo ) ) { /* enable a workaround for a pgp2 bug */ if (gcry_md_open (&c->mfx.md2, DIGEST_ALGO_MD5, 0)) BUG (); } else if( sig->digest_algo == DIGEST_ALGO_SHA1 && sig->pubkey_algo == PUBKEY_ALGO_DSA && sig->sig_class == 0x01 ) { /* enable the workaround also for pgp5 when the detached * signature has been created in textmode */ if (gcry_md_open (&c->mfx.md2, sig->digest_algo, 0 )) BUG (); } #if 0 /* workaround disabled */ /* Here we have another hack to work around a pgp 2 bug * It works by not using the textmode for detached signatures; * this will let the first signature check (on md) fail * but the second one (on md2) which adds an extra CR should * then produce the "correct" hash. This is very, very ugly * hack but it may help in some cases (and break others) */ /* c->mfx.md2? 0 :(sig->sig_class == 0x01) */ #endif if ( DBG_HASHING ) { gcry_md_debug( c->mfx.md, "verify" ); if ( c->mfx.md2 ) gcry_md_debug( c->mfx.md2, "verify2" ); } if( c->sigs_only ) { if (c->signed_data.used && c->signed_data.data_fd != -1) rc = hash_datafile_by_fd (c->mfx.md, c->mfx.md2, c->signed_data.data_fd, (sig->sig_class == 0x01)); else rc = hash_datafiles (c->mfx.md, c->mfx.md2, c->signed_data.data_names, c->sigfilename, (sig->sig_class == 0x01)); } else { rc = ask_for_detached_datafile( c->mfx.md, c->mfx.md2, iobuf_get_real_fname(c->iobuf), (sig->sig_class == 0x01) ); } if( rc ) { log_error("can't hash datafile: %s\n", g10_errstr(rc)); return; } } else if ( c->signed_data.used ) { log_error (_("not a detached signature\n") ); return; } else if (!opt.quiet) log_info(_("old style (PGP 2.x) signature\n")); if(multiple_ok) for( n1 = node; n1; (n1 = find_next_kbnode(n1, PKT_SIGNATURE )) ) check_sig_and_print( c, n1 ); else check_sig_and_print( c, node ); } else { dump_kbnode (c->list); log_error(_("invalid root packet detected in proc_tree()\n")); dump_kbnode (node); } } diff --git a/g10/misc.c b/g10/misc.c index 9f6ff1e6b..1ac5430a2 100644 --- a/g10/misc.c +++ b/g10/misc.c @@ -1,1541 +1,1537 @@ /* misc.c - miscellaneous functions * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, * 2008, 2009, 2010 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 #if defined(__linux__) && defined(__alpha__) && __GLIBC__ < 2 #include #include #endif #ifdef HAVE_SETRLIMIT #include #include #include #endif #ifdef ENABLE_SELINUX_HACKS #include #endif #ifdef HAVE_W32_SYSTEM #include #include #include #include #ifndef CSIDL_APPDATA #define CSIDL_APPDATA 0x001a #endif #ifndef CSIDL_LOCAL_APPDATA #define CSIDL_LOCAL_APPDATA 0x001c #endif #ifndef CSIDL_FLAG_CREATE #define CSIDL_FLAG_CREATE 0x8000 #endif #endif /*HAVE_W32_SYSTEM*/ #include "gpg.h" #ifdef HAVE_W32_SYSTEM # include "status.h" #endif /*HAVE_W32_SYSTEM*/ #include "util.h" #include "main.h" #include "photoid.h" #include "options.h" #include "call-agent.h" #include "i18n.h" #include static int string_count_chr (const char *string, int c) { int count; for (count=0; *string; string++ ) if ( *string == c ) count++; return count; } #ifdef ENABLE_SELINUX_HACKS /* A object and a global variable to keep track of files marked as secured. */ struct secured_file_item { struct secured_file_item *next; ino_t ino; dev_t dev; }; static struct secured_file_item *secured_files; #endif /*ENABLE_SELINUX_HACKS*/ /* For the sake of SELinux we want to restrict access through gpg to certain files we keep under our own control. This function registers such a file and is_secured_file may then be used to check whether a file has ben registered as secured. */ void register_secured_file (const char *fname) { #ifdef ENABLE_SELINUX_HACKS struct stat buf; struct secured_file_item *sf; /* Note that we stop immediatley if something goes wrong here. */ if (stat (fname, &buf)) log_fatal (_("fstat of '%s' failed in %s: %s\n"), fname, "register_secured_file", strerror (errno)); /* log_debug ("registering '%s' i=%lu.%lu\n", fname, */ /* (unsigned long)buf.st_dev, (unsigned long)buf.st_ino); */ for (sf=secured_files; sf; sf = sf->next) { if (sf->ino == buf.st_ino && sf->dev == buf.st_dev) return; /* Already registered. */ } sf = xmalloc (sizeof *sf); sf->ino = buf.st_ino; sf->dev = buf.st_dev; sf->next = secured_files; secured_files = sf; #else /*!ENABLE_SELINUX_HACKS*/ (void)fname; #endif /*!ENABLE_SELINUX_HACKS*/ } /* Remove a file registered as secure. */ void unregister_secured_file (const char *fname) { #ifdef ENABLE_SELINUX_HACKS struct stat buf; struct secured_file_item *sf, *sfprev; if (stat (fname, &buf)) { log_error (_("fstat of '%s' failed in %s: %s\n"), fname, "unregister_secured_file", strerror (errno)); return; } /* log_debug ("unregistering '%s' i=%lu.%lu\n", fname, */ /* (unsigned long)buf.st_dev, (unsigned long)buf.st_ino); */ for (sfprev=NULL,sf=secured_files; sf; sfprev=sf, sf = sf->next) { if (sf->ino == buf.st_ino && sf->dev == buf.st_dev) { if (sfprev) sfprev->next = sf->next; else secured_files = sf->next; xfree (sf); return; } } #else /*!ENABLE_SELINUX_HACKS*/ (void)fname; #endif /*!ENABLE_SELINUX_HACKS*/ } /* Return true if FD is corresponds to a secured file. Using -1 for FS is allowed and will return false. */ int is_secured_file (int fd) { #ifdef ENABLE_SELINUX_HACKS struct stat buf; struct secured_file_item *sf; if (fd == -1) return 0; /* No file descriptor so it can't be secured either. */ /* Note that we print out a error here and claim that a file is secure if something went wrong. */ if (fstat (fd, &buf)) { log_error (_("fstat(%d) failed in %s: %s\n"), fd, "is_secured_file", strerror (errno)); return 1; } /* log_debug ("is_secured_file (%d) i=%lu.%lu\n", fd, */ /* (unsigned long)buf.st_dev, (unsigned long)buf.st_ino); */ for (sf=secured_files; sf; sf = sf->next) { if (sf->ino == buf.st_ino && sf->dev == buf.st_dev) return 1; /* Yes. */ } #else /*!ENABLE_SELINUX_HACKS*/ (void)fd; #endif /*!ENABLE_SELINUX_HACKS*/ return 0; /* No. */ } /* Return true if FNAME is corresponds to a secured file. Using NULL, "" or "-" for FS is allowed and will return false. This function is used before creating a file, thus it won't fail if the file does not exist. */ int is_secured_filename (const char *fname) { #ifdef ENABLE_SELINUX_HACKS struct stat buf; struct secured_file_item *sf; if (iobuf_is_pipe_filename (fname) || !*fname) return 0; /* Note that we print out a error here and claim that a file is secure if something went wrong. */ if (stat (fname, &buf)) { if (errno == ENOENT || errno == EPERM || errno == EACCES) return 0; log_error (_("fstat of '%s' failed in %s: %s\n"), fname, "is_secured_filename", strerror (errno)); return 1; } /* log_debug ("is_secured_filename (%s) i=%lu.%lu\n", fname, */ /* (unsigned long)buf.st_dev, (unsigned long)buf.st_ino); */ for (sf=secured_files; sf; sf = sf->next) { if (sf->ino == buf.st_ino && sf->dev == buf.st_dev) return 1; /* Yes. */ } #else /*!ENABLE_SELINUX_HACKS*/ (void)fname; #endif /*!ENABLE_SELINUX_HACKS*/ return 0; /* No. */ } u16 checksum_u16( unsigned n ) { u16 a; a = (n >> 8) & 0xff; a += n & 0xff; return a; } u16 checksum( byte *p, unsigned n ) { u16 a; for(a=0; n; n-- ) a += *p++; return a; } u16 checksum_mpi (gcry_mpi_t a) { u16 csum; byte *buffer; size_t nbytes; if ( gcry_mpi_print (GCRYMPI_FMT_PGP, NULL, 0, &nbytes, a) ) BUG (); /* Fixme: For numbers not in secure memory we should use a stack * based buffer and only allocate a larger one if mpi_print returns * an error. */ buffer = (gcry_is_secure(a)? gcry_xmalloc_secure (nbytes) : gcry_xmalloc (nbytes)); if ( gcry_mpi_print (GCRYMPI_FMT_PGP, buffer, nbytes, NULL, a) ) BUG (); csum = checksum (buffer, nbytes); xfree (buffer); return csum; } u32 buffer_to_u32( const byte *buffer ) { unsigned long a; a = *buffer << 24; a |= buffer[1] << 16; a |= buffer[2] << 8; a |= buffer[3]; return a; } void print_pubkey_algo_note( int algo ) { if(algo >= 100 && algo <= 110) { static int warn=0; if(!warn) { warn=1; log_info (_("WARNING: using experimental public key algorithm %s\n"), openpgp_cipher_algo_name (algo)); } } else if (algo == 20) { log_info (_("WARNING: Elgamal sign+encrypt keys are deprecated\n")); } } void print_cipher_algo_note( int algo ) { if(algo >= 100 && algo <= 110) { static int warn=0; if(!warn) { warn=1; log_info (_("WARNING: using experimental cipher algorithm %s\n"), openpgp_cipher_algo_name (algo)); } } } void print_digest_algo_note( int algo ) { if(algo >= 100 && algo <= 110) { static int warn=0; if(!warn) { warn=1; log_info (_("WARNING: using experimental digest algorithm %s\n"), gcry_md_algo_name (algo)); } } else if(algo==DIGEST_ALGO_MD5) log_info (_("WARNING: digest algorithm %s is deprecated\n"), gcry_md_algo_name (algo)); } /* Map OpenPGP algo numbers to those used by Libgcrypt. We need to do this for algorithms we implemented in Libgcrypt after they become part of OpenPGP. */ int map_cipher_openpgp_to_gcry (int algo) { switch (algo) { case CIPHER_ALGO_CAMELLIA128: return 310; case CIPHER_ALGO_CAMELLIA192: return 311; case CIPHER_ALGO_CAMELLIA256: return 312; default: return algo; } } /* The inverse fucntion of above. */ static int map_cipher_gcry_to_openpgp (int algo) { switch (algo) { case 310: return CIPHER_ALGO_CAMELLIA128; case 311: return CIPHER_ALGO_CAMELLIA192; case 312: return CIPHER_ALGO_CAMELLIA256; default: return algo; } } -/* Map OpenPGP public key algorithm numbers to those used by - Libgcrypt. */ -int -map_pk_openpgp_to_gcry (int algo) -{ - switch (algo) - { - case PUBKEY_ALGO_ECDSA: return GCRY_PK_ECDSA; - case PUBKEY_ALGO_ECDH: return GCRY_PK_ECDH; - default: return algo; - } -} - -/* Map Gcrypt public key algorithm numbers to those used by - OpenPGP. */ +/* Map Gcrypt public key algorithm numbers to those used by OpenPGP. + FIXME: This mapping is used at only two places - we should get rid + of it. */ int map_pk_gcry_to_openpgp (enum gcry_pk_algos algo) { switch (algo) { case GCRY_PK_ECDSA: return PUBKEY_ALGO_ECDSA; case GCRY_PK_ECDH: return PUBKEY_ALGO_ECDH; default: return algo < 110 ? algo : 0; } } /* Return the block length of an OpenPGP cipher algorithm. */ int openpgp_cipher_blocklen (int algo) { /* We use the numbers from OpenPGP to be sure that we get the right block length. This is so that the packet parsing code works even for unknown algorithms (for which we assume 8 due to tradition). NOTE: If you change the the returned blocklen above 16, check the callers because they may use a fixed size buffer of that size. */ switch (algo) { case 7: case 8: case 9: /* AES */ case 10: /* Twofish */ case 11: case 12: case 13: /* Camellia */ return 16; default: return 8; } } /**************** * Wrapper around the libgcrypt function with additonal checks on * the OpenPGP contraints for the algo ID. */ int openpgp_cipher_test_algo( int algo ) { /* (5 and 6 are marked reserved by rfc4880.) */ if ( algo < 0 || algo > 110 || algo == 5 || algo == 6 ) return gpg_error (GPG_ERR_CIPHER_ALGO); return gcry_cipher_test_algo (map_cipher_openpgp_to_gcry (algo)); } /* Map the OpenPGP cipher algorithm whose ID is contained in ALGORITHM to a string representation of the algorithm name. For unknown algorithm IDs this function returns "?". */ const char * openpgp_cipher_algo_name (int algo) { return gnupg_cipher_algo_name (map_cipher_openpgp_to_gcry (algo)); } + +/* Return 0 if ALGO is a supported OpenPGP public key algorithm. */ int -openpgp_pk_test_algo( int algo ) +openpgp_pk_test_algo (pubkey_algo_t algo) { - /* Dont't allow type 20 keys unless in rfc2440 mode. */ - if (!RFC2440 && algo == 20) - return gpg_error (GPG_ERR_PUBKEY_ALGO); - - if (algo == GCRY_PK_ELG_E) - algo = GCRY_PK_ELG; - - if (algo < 0 || algo > 110) - return gpg_error (GPG_ERR_PUBKEY_ALGO); - - return gcry_pk_test_algo (map_pk_openpgp_to_gcry (algo)); + return openpgp_pk_test_algo2 (algo, 0); } + +/* Return 0 if ALGO is a supported OpenPGP public key algorithm and + allows the usage USE. */ int -openpgp_pk_test_algo2( int algo, unsigned int use ) +openpgp_pk_test_algo2 (pubkey_algo_t algo, unsigned int use) { + enum gcry_pk_algos ga = 0; size_t use_buf = use; - /* Dont't allow type 20 keys unless in rfc2440 mode. */ - if (!RFC2440 && algo == 20) - return gpg_error (GPG_ERR_PUBKEY_ALGO); - - if (algo == GCRY_PK_ELG_E) - algo = GCRY_PK_ELG; - - if (algo < 0 || algo > 110) + switch (algo) + { + case PUBKEY_ALGO_RSA: ga = GCRY_PK_RSA; break; + case PUBKEY_ALGO_RSA_E: ga = GCRY_PK_RSA_E; break; + case PUBKEY_ALGO_RSA_S: ga = GCRY_PK_RSA_S; break; + case PUBKEY_ALGO_ELGAMAL_E: ga = GCRY_PK_ELG; break; + case PUBKEY_ALGO_DSA: ga = GCRY_PK_DSA; break; + + case PUBKEY_ALGO_ECDH: + case PUBKEY_ALGO_ECDSA: + case PUBKEY_ALGO_EDDSA: ga = GCRY_PK_ECC; break; + + case PUBKEY_ALGO_ELGAMAL: + /* Dont't allow type 20 keys unless in rfc2440 mode. */ + if (RFC2440) + ga = GCRY_PK_ELG; + break; + } + if (!ga) return gpg_error (GPG_ERR_PUBKEY_ALGO); - return gcry_pk_algo_info (map_pk_openpgp_to_gcry (algo), - GCRYCTL_TEST_ALGO, NULL, &use_buf); + /* No check whether Libgcrypt has support for the algorithm. */ + return gcry_pk_algo_info (ga, GCRYCTL_TEST_ALGO, NULL, &use_buf); } + int openpgp_pk_algo_usage ( int algo ) { int use = 0; /* They are hardwired in gpg 1.0. */ switch ( algo ) { case PUBKEY_ALGO_RSA: use = (PUBKEY_USAGE_CERT | PUBKEY_USAGE_SIG | PUBKEY_USAGE_ENC | PUBKEY_USAGE_AUTH); break; case PUBKEY_ALGO_RSA_E: case PUBKEY_ALGO_ECDH: use = PUBKEY_USAGE_ENC; break; case PUBKEY_ALGO_RSA_S: use = PUBKEY_USAGE_CERT | PUBKEY_USAGE_SIG; break; case PUBKEY_ALGO_ELGAMAL: if (RFC2440) use = PUBKEY_USAGE_ENC; break; case PUBKEY_ALGO_ELGAMAL_E: use = PUBKEY_USAGE_ENC; break; case PUBKEY_ALGO_DSA: use = PUBKEY_USAGE_CERT | PUBKEY_USAGE_SIG | PUBKEY_USAGE_AUTH; break; case PUBKEY_ALGO_ECDSA: + case PUBKEY_ALGO_EDDSA: use = PUBKEY_USAGE_CERT | PUBKEY_USAGE_SIG | PUBKEY_USAGE_AUTH; default: break; } return use; } /* Map the OpenPGP pubkey algorithm whose ID is contained in ALGO to a string representation of the algorithm name. For unknown algorithm IDs this function returns "?". */ const char * -openpgp_pk_algo_name (int algo) +openpgp_pk_algo_name (pubkey_algo_t algo) { - return gcry_pk_algo_name (map_pk_openpgp_to_gcry (algo)); + switch (algo) + { + case PUBKEY_ALGO_RSA: + case PUBKEY_ALGO_RSA_E: + case PUBKEY_ALGO_RSA_S: return "RSA"; + case PUBKEY_ALGO_ELGAMAL: + case PUBKEY_ALGO_ELGAMAL_E: return "ELG"; + case PUBKEY_ALGO_DSA: return "DSA"; + case PUBKEY_ALGO_ECDH: + case PUBKEY_ALGO_ECDSA: + case PUBKEY_ALGO_EDDSA: return "ECC"; + } + return "?"; } int openpgp_md_test_algo( int algo ) { /* Note: If the list of actual supported OpenPGP algorithms changes, make sure that our hard coded values at print_status_begin_signing() gets updated. */ /* 4, 5, 6, 7 are defined by rfc2440 but will be removed from the next revision of the standard. */ if (algo < 0 || algo > 110 || (algo >= 4 && algo <= 7)) return gpg_error (GPG_ERR_DIGEST_ALGO); return gcry_md_test_algo (algo); } /* Map the OpenPGP digest algorithm whose ID is contained in ALGO to a string representation of the algorithm name. For unknown algorithm IDs this function returns "?". */ const char * openpgp_md_algo_name (int algo) { if (algo < 0 || algo > 110) return "?"; return gcry_md_algo_name (algo); } static unsigned long get_signature_count (PKT_public_key *pk) { #ifdef ENABLE_CARD_SUPPORT struct agent_card_info_s info; (void)pk; if (!agent_scd_getattr ("SIG-COUNTER",&info)) return info.sig_counter; else return 0; #else (void)pk; return 0; #endif } /* Expand %-strings. Returns a string which must be xfreed. Returns NULL if the string cannot be expanded (too large). */ char * pct_expando(const char *string,struct expando_args *args) { const char *ch=string; int idx=0,maxlen=0,done=0; u32 pk_keyid[2]={0,0},sk_keyid[2]={0,0}; char *ret=NULL; if(args->pk) keyid_from_pk(args->pk,pk_keyid); if(args->pksk) keyid_from_pk (args->pksk, sk_keyid); /* This is used so that %k works in photoid command strings in --list-secret-keys (which of course has a sk, but no pk). */ if(!args->pk && args->pksk) keyid_from_pk (args->pksk, pk_keyid); while(*ch!='\0') { if(!done) { /* 8192 is way bigger than we'll need here */ if(maxlen>=8192) goto fail; maxlen+=1024; ret=xrealloc(ret,maxlen); } done=0; if(*ch=='%') { switch(*(ch+1)) { case 's': /* short key id */ if(idx+8pksk)); idx+=strlen(&ret[idx]); done=1; } break; case 'p': /* primary pk fingerprint of a sk */ case 'f': /* pk fingerprint */ case 'g': /* sk fingerprint */ { byte array[MAX_FINGERPRINT_LEN]; size_t len; int i; if((*(ch+1))=='p' && args->pksk) { if(args->pksk->flags.primary) fingerprint_from_pk (args->pksk, array, &len); else if (args->pksk->main_keyid[0] || args->pksk->main_keyid[1]) { /* FIXME: Document teh code and check whether it is still needed. */ PKT_public_key *pk= xmalloc_clear(sizeof(PKT_public_key)); if (!get_pubkey_fast (pk,args->pksk->main_keyid)) fingerprint_from_pk (pk, array, &len); else memset (array, 0, (len=MAX_FINGERPRINT_LEN)); free_public_key (pk); } else memset(array,0,(len=MAX_FINGERPRINT_LEN)); } else if((*(ch+1))=='f' && args->pk) fingerprint_from_pk (args->pk, array, &len); else if((*(ch+1))=='g' && args->pksk) fingerprint_from_pk (args->pksk, array, &len); else memset(array,0,(len=MAX_FINGERPRINT_LEN)); if(idx+(len*2)validity_info && idx+1validity_info; ret[idx]='\0'; done=1; } break; /* The text string types */ case 't': case 'T': case 'V': { const char *str=NULL; switch(*(ch+1)) { case 't': /* e.g. "jpg" */ str=image_type_to_string(args->imagetype,0); break; case 'T': /* e.g. "image/jpeg" */ str=image_type_to_string(args->imagetype,2); break; case 'V': /* e.g. "full", "expired", etc. */ str=args->validity_string; break; } if(str && idx+strlen(str)='A' && file[0]<='Z') || (file[0]>='a' && file[0]<='z')) && file[1]==':') #else || file[0]=='/' #endif ) return access(file,mode); else { /* At least as large as, but most often larger than we need. */ char *buffer=xmalloc(strlen(envpath)+1+strlen(file)+1); char *split,*item,*path=xstrdup(envpath); split=path; while((item=strsep(&split,PATHSEP_S))) { strcpy(buffer,item); strcat(buffer,"/"); strcat(buffer,file); ret=access(buffer,mode); if(ret==0) break; } xfree(path); xfree(buffer); } return ret; } /* Return the number of public key parameters as used by OpenPGP. */ int -pubkey_get_npkey (int algo) +pubkey_get_npkey (pubkey_algo_t algo) { - size_t n; - - /* ECC is special. */ - if (algo == PUBKEY_ALGO_ECDSA) - return 2; - else if (algo == PUBKEY_ALGO_ECDH) - return 3; - - /* All other algorithms match those of Libgcrypt. */ - if (algo == GCRY_PK_ELG_E) - algo = GCRY_PK_ELG; - else if (is_RSA (algo)) - algo = GCRY_PK_RSA; - - if (gcry_pk_algo_info (algo, GCRYCTL_GET_ALGO_NPKEY, NULL, &n)) - n = 0; - return n; + switch (algo) + { + case PUBKEY_ALGO_RSA: + case PUBKEY_ALGO_RSA_E: + case PUBKEY_ALGO_RSA_S: return 2; + case PUBKEY_ALGO_ELGAMAL_E: return 3; + case PUBKEY_ALGO_DSA: return 4; + case PUBKEY_ALGO_ECDH: return 3; + case PUBKEY_ALGO_ECDSA: return 2; + case PUBKEY_ALGO_ELGAMAL: return 3; + case PUBKEY_ALGO_EDDSA: return 2; + } + return 0; } /* Return the number of secret key parameters as used by OpenPGP. */ int -pubkey_get_nskey (int algo) +pubkey_get_nskey (pubkey_algo_t algo) { - size_t n; - - /* ECC is special. */ - if (algo == PUBKEY_ALGO_ECDSA) - return 3; - else if (algo == PUBKEY_ALGO_ECDH) - return 4; - - /* All other algorithms match those of Libgcrypt. */ - if (algo == GCRY_PK_ELG_E) - algo = GCRY_PK_ELG; - else if (is_RSA (algo)) - algo = GCRY_PK_RSA; - - if (gcry_pk_algo_info( algo, GCRYCTL_GET_ALGO_NSKEY, NULL, &n )) - n = 0; - return n; + switch (algo) + { + case PUBKEY_ALGO_RSA: + case PUBKEY_ALGO_RSA_E: + case PUBKEY_ALGO_RSA_S: return 6; + case PUBKEY_ALGO_ELGAMAL_E: return 4; + case PUBKEY_ALGO_DSA: return 5; + case PUBKEY_ALGO_ECDH: return 4; + case PUBKEY_ALGO_ECDSA: return 3; + case PUBKEY_ALGO_ELGAMAL: return 4; + case PUBKEY_ALGO_EDDSA: return 3; + } + return 0; } /* Temporary helper. */ int -pubkey_get_nsig (int algo) +pubkey_get_nsig (pubkey_algo_t algo) { - size_t n; - - /* ECC is special. */ - if (algo == PUBKEY_ALGO_ECDSA) - return 2; - else if (algo == PUBKEY_ALGO_ECDH) - return 0; - - if (algo == GCRY_PK_ELG_E) - algo = GCRY_PK_ELG; - else if (is_RSA (algo)) - algo = GCRY_PK_RSA; - - if (gcry_pk_algo_info( algo, GCRYCTL_GET_ALGO_NSIGN, NULL, &n)) - n = 0; - return n; + switch (algo) + { + case PUBKEY_ALGO_RSA: + case PUBKEY_ALGO_RSA_E: + case PUBKEY_ALGO_RSA_S: return 1; + case PUBKEY_ALGO_ELGAMAL_E: return 0; + case PUBKEY_ALGO_DSA: return 2; + case PUBKEY_ALGO_ECDH: return 0; + case PUBKEY_ALGO_ECDSA: return 2; + case PUBKEY_ALGO_ELGAMAL: return 2; + case PUBKEY_ALGO_EDDSA: return 2; + } + return 0; } /* Temporary helper. */ int -pubkey_get_nenc (int algo) +pubkey_get_nenc (pubkey_algo_t algo) { - size_t n; - - /* ECC is special. */ - if (algo == PUBKEY_ALGO_ECDSA) - return 0; - else if (algo == PUBKEY_ALGO_ECDH) - return 2; - - if (algo == GCRY_PK_ELG_E) - algo = GCRY_PK_ELG; - else if (is_RSA (algo)) - algo = GCRY_PK_RSA; - - if (gcry_pk_algo_info( algo, GCRYCTL_GET_ALGO_NENCR, NULL, &n )) - n = 0; - return n; + switch (algo) + { + case PUBKEY_ALGO_RSA: + case PUBKEY_ALGO_RSA_E: + case PUBKEY_ALGO_RSA_S: return 1; + case PUBKEY_ALGO_ELGAMAL_E: return 2; + case PUBKEY_ALGO_DSA: return 0; + case PUBKEY_ALGO_ECDH: return 2; + case PUBKEY_ALGO_ECDSA: return 0; + case PUBKEY_ALGO_ELGAMAL: return 2; + case PUBKEY_ALGO_EDDSA: return 0; + } + return 0; } /* Temporary helper. */ unsigned int pubkey_nbits( int algo, gcry_mpi_t *key ) { int rc, nbits; gcry_sexp_t sexp; if( algo == PUBKEY_ALGO_DSA ) { rc = gcry_sexp_build ( &sexp, NULL, "(public-key(dsa(p%m)(q%m)(g%m)(y%m)))", key[0], key[1], key[2], key[3] ); } else if( algo == PUBKEY_ALGO_ELGAMAL || algo == PUBKEY_ALGO_ELGAMAL_E ) { rc = gcry_sexp_build ( &sexp, NULL, "(public-key(elg(p%m)(g%m)(y%m)))", key[0], key[1], key[2] ); } else if( is_RSA (algo) ) { rc = gcry_sexp_build ( &sexp, NULL, "(public-key(rsa(n%m)(e%m)))", key[0], key[1] ); } - else if( algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_ECDH ) { + else if (algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_ECDH + || algo == PUBKEY_ALGO_EDDSA) { char *curve = openpgp_oid_to_str (key[0]); if (!curve) rc = gpg_error_from_syserror (); else { rc = gcry_sexp_build (&sexp, NULL, "(public-key(ecc(curve%s)(q%m)))", curve, key[1]); xfree (curve); } } else return 0; if ( rc ) BUG (); nbits = gcry_pk_get_nbits( sexp ); gcry_sexp_release( sexp ); return nbits; } int mpi_print (estream_t fp, gcry_mpi_t a, int mode) { int n=0; if (!a) return es_fprintf (fp, "[MPI_NULL]"); if (!mode) { unsigned int n1; n1 = gcry_mpi_get_nbits(a); n += es_fprintf (fp, "[%u bits]", n1); } else if (gcry_mpi_get_flag (a, GCRYMPI_FLAG_OPAQUE)) { unsigned int nbits; unsigned char *p = gcry_mpi_get_opaque (a, &nbits); if (!p) n += es_fprintf (fp, "[invalid opaque value]"); else { nbits = (nbits + 7)/8; for (; nbits; nbits--, p++) n += es_fprintf (fp, "%02X", *p); } } else { unsigned char *buffer; if (gcry_mpi_aprint (GCRYMPI_FMT_HEX, &buffer, NULL, a)) BUG (); es_fputs (buffer, fp); n += strlen (buffer); gcry_free (buffer); } return n; } /* pkey[1] or skey[1] is Q for ECDSA, which is an uncompressed point, i.e. 04 */ unsigned int ecdsa_qbits_from_Q (unsigned int qbits) { if ((qbits%8) > 3) { log_error (_("ECDSA public key is expected to be in SEC encoding " "multiple of 8 bits\n")); return 0; } qbits -= qbits%8; qbits /= 2; return qbits; } diff --git a/g10/parse-packet.c b/g10/parse-packet.c index 32fbbd60d..f70878846 100644 --- a/g10/parse-packet.c +++ b/g10/parse-packet.c @@ -1,2845 +1,2848 @@ /* parse-packet.c - read packets * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, * 2007, 2009, 2010 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 "util.h" #include "packet.h" #include "iobuf.h" #include "filter.h" #include "photoid.h" #include "options.h" #include "main.h" #include "i18n.h" static int mpi_print_mode; static int list_mode; static estream_t listfp; static int parse (IOBUF inp, PACKET * pkt, int onlykeypkts, off_t * retpos, int *skip, IOBUF out, int do_skip #ifdef DEBUG_PARSE_PACKET , const char *dbg_w, const char *dbg_f, int dbg_l #endif ); static int copy_packet (IOBUF inp, IOBUF out, int pkttype, unsigned long pktlen, int partial); static void skip_packet (IOBUF inp, int pkttype, unsigned long pktlen, int partial); static void *read_rest (IOBUF inp, size_t pktlen); static int parse_marker (IOBUF inp, int pkttype, unsigned long pktlen); static int parse_symkeyenc (IOBUF inp, int pkttype, unsigned long pktlen, PACKET * packet); static int parse_pubkeyenc (IOBUF inp, int pkttype, unsigned long pktlen, PACKET * packet); static int parse_onepass_sig (IOBUF inp, int pkttype, unsigned long pktlen, PKT_onepass_sig * ops); static int parse_key (IOBUF inp, int pkttype, unsigned long pktlen, byte * hdr, int hdrlen, PACKET * packet); static int parse_user_id (IOBUF inp, int pkttype, unsigned long pktlen, PACKET * packet); static int parse_attribute (IOBUF inp, int pkttype, unsigned long pktlen, PACKET * packet); static int parse_comment (IOBUF inp, int pkttype, unsigned long pktlen, PACKET * packet); static void parse_trust (IOBUF inp, int pkttype, unsigned long pktlen, PACKET * packet); static int parse_plaintext (IOBUF inp, int pkttype, unsigned long pktlen, PACKET * packet, int new_ctb, int partial); static int parse_compressed (IOBUF inp, int pkttype, unsigned long pktlen, PACKET * packet, int new_ctb); static int parse_encrypted (IOBUF inp, int pkttype, unsigned long pktlen, PACKET * packet, int new_ctb, int partial); static int parse_mdc (IOBUF inp, int pkttype, unsigned long pktlen, PACKET * packet, int new_ctb); static int parse_gpg_control (IOBUF inp, int pkttype, unsigned long pktlen, PACKET * packet, int partial); static unsigned short read_16 (IOBUF inp) { unsigned short a; a = iobuf_get_noeof (inp) << 8; a |= iobuf_get_noeof (inp); return a; } static unsigned long read_32 (IOBUF inp) { unsigned long a; a = iobuf_get_noeof (inp) << 24; a |= iobuf_get_noeof (inp) << 16; a |= iobuf_get_noeof (inp) << 8; a |= iobuf_get_noeof (inp); return a; } /* Read an external representation of an mpi and return the MPI. The * external format is a 16 bit unsigned value stored in network byte * order, giving the number of bits for the following integer. The * integer is stored with MSB first (left padded with zeroes to align * on a byte boundary). */ static gcry_mpi_t mpi_read (iobuf_t inp, unsigned int *ret_nread, int secure) { /*FIXME: Needs to be synced with gnupg14/mpi/mpicoder.c */ int c, c1, c2, i; unsigned int nbits, nbytes; size_t nread = 0; gcry_mpi_t a = NULL; byte *buf = NULL; byte *p; if ((c = c1 = iobuf_get (inp)) == -1) goto leave; nbits = c << 8; if ((c = c2 = iobuf_get (inp)) == -1) goto leave; nbits |= c; if (nbits > MAX_EXTERN_MPI_BITS) { log_error ("mpi too large (%u bits)\n", nbits); goto leave; } nread = 2; nbytes = (nbits + 7) / 8; buf = secure ? gcry_xmalloc_secure (nbytes + 2) : gcry_xmalloc (nbytes + 2); p = buf; p[0] = c1; p[1] = c2; for (i = 0; i < nbytes; i++) { p[i + 2] = iobuf_get (inp) & 0xff; nread++; } if (gcry_mpi_scan (&a, GCRYMPI_FMT_PGP, buf, nread, &nread)) a = NULL; leave: gcry_free (buf); if (nread > *ret_nread) log_bug ("mpi larger than packet (%zu/%u)", nread, *ret_nread); else *ret_nread = nread; return a; } int set_packet_list_mode (int mode) { int old = list_mode; list_mode = mode; /* FIXME(gcrypt) mpi_print_mode = DBG_MPI; */ /* We use stdout print only if invoked by the --list-packets command but switch to stderr in all other cases. This breaks the previous behaviour but that seems to be more of a bug than intentional. I don't believe that any application makes use of this long standing annoying way of printing to stdout except when doing a --list-packets. If this assumption fails, it will be easy to add an option for the listing stream. Note that we initialize it only once; mainly because some code may switch the option value later back to 1 and we want to have all output to the same stream. Using stderr is not actually very clean because it bypasses the logging code but it is a special thing anyway. I am not sure whether using log_stream() would be better. Perhaps we should enable the list mdoe only with a special option. */ if (!listfp) listfp = opt.list_packets == 2 ? es_stdout : es_stderr; return old; } static void unknown_pubkey_warning (int algo) { static byte unknown_pubkey_algos[256]; algo &= 0xff; if (!unknown_pubkey_algos[algo]) { if (opt.verbose) log_info (_("can't handle public key algorithm %d\n"), algo); unknown_pubkey_algos[algo] = 1; } } /* Parse a packet and return it in packet structure. * Returns: 0 := valid packet in pkt * -1 := no more packets * >0 := error * Note: The function may return an error and a partly valid packet; * caller must free this packet. */ #ifdef DEBUG_PARSE_PACKET int dbg_parse_packet (IOBUF inp, PACKET *pkt, const char *dbg_f, int dbg_l) { int skip, rc; do { rc = parse (inp, pkt, 0, NULL, &skip, NULL, 0, "parse", dbg_f, dbg_l); } while (skip); return rc; } #else /*!DEBUG_PARSE_PACKET*/ int parse_packet (IOBUF inp, PACKET * pkt) { int skip, rc; do { rc = parse (inp, pkt, 0, NULL, &skip, NULL, 0); } while (skip); return rc; } #endif /*!DEBUG_PARSE_PACKET*/ /* * Like parse packet, but only return secret or public (sub)key * packets. */ #ifdef DEBUG_PARSE_PACKET int dbg_search_packet (IOBUF inp, PACKET * pkt, off_t * retpos, int with_uid, const char *dbg_f, int dbg_l) { int skip, rc; do { rc = parse (inp, pkt, with_uid ? 2 : 1, retpos, &skip, NULL, 0, "search", dbg_f, dbg_l); } while (skip); return rc; } #else /*!DEBUG_PARSE_PACKET*/ int search_packet (IOBUF inp, PACKET * pkt, off_t * retpos, int with_uid) { int skip, rc; do { rc = parse (inp, pkt, with_uid ? 2 : 1, retpos, &skip, NULL, 0); } while (skip); return rc; } #endif /*!DEBUG_PARSE_PACKET*/ /* * Copy all packets from INP to OUT, thereby removing unused spaces. */ #ifdef DEBUG_PARSE_PACKET int dbg_copy_all_packets (IOBUF inp, IOBUF out, const char *dbg_f, int dbg_l) { PACKET pkt; int skip, rc = 0; do { init_packet (&pkt); } while (! (rc = parse (inp, &pkt, 0, NULL, &skip, out, 0, "copy", dbg_f, dbg_l))); return rc; } #else /*!DEBUG_PARSE_PACKET*/ int copy_all_packets (IOBUF inp, IOBUF out) { PACKET pkt; int skip, rc = 0; do { init_packet (&pkt); } while (!(rc = parse (inp, &pkt, 0, NULL, &skip, out, 0))); return rc; } #endif /*!DEBUG_PARSE_PACKET*/ /* * Copy some packets from INP to OUT, thereby removing unused spaces. * Stop at offset STOPoff (i.e. don't copy packets at this or later * offsets) */ #ifdef DEBUG_PARSE_PACKET int dbg_copy_some_packets (IOBUF inp, IOBUF out, off_t stopoff, const char *dbg_f, int dbg_l) { PACKET pkt; int skip, rc = 0; do { if (iobuf_tell (inp) >= stopoff) return 0; init_packet (&pkt); } while (!(rc = parse (inp, &pkt, 0, NULL, &skip, out, 0, "some", dbg_f, dbg_l))); return rc; } #else /*!DEBUG_PARSE_PACKET*/ int copy_some_packets (IOBUF inp, IOBUF out, off_t stopoff) { PACKET pkt; int skip, rc = 0; do { if (iobuf_tell (inp) >= stopoff) return 0; init_packet (&pkt); } while (!(rc = parse (inp, &pkt, 0, NULL, &skip, out, 0))); return rc; } #endif /*!DEBUG_PARSE_PACKET*/ /* * Skip over N packets */ #ifdef DEBUG_PARSE_PACKET int dbg_skip_some_packets (IOBUF inp, unsigned n, const char *dbg_f, int dbg_l) { int skip, rc = 0; PACKET pkt; for (; n && !rc; n--) { init_packet (&pkt); rc = parse (inp, &pkt, 0, NULL, &skip, NULL, 1, "skip", dbg_f, dbg_l); } return rc; } #else /*!DEBUG_PARSE_PACKET*/ int skip_some_packets (IOBUF inp, unsigned n) { int skip, rc = 0; PACKET pkt; for (; n && !rc; n--) { init_packet (&pkt); rc = parse (inp, &pkt, 0, NULL, &skip, NULL, 1); } return rc; } #endif /*!DEBUG_PARSE_PACKET*/ /* * Parse packet. Stores 1 at SKIP 1 if the packet should be skipped; * this is the case if either ONLYKEYPKTS is set and the parsed packet * isn't a key packet or the packet-type is 0, indicating deleted * stuff. If OUT is not NULL, a special copymode is used. */ static int parse (IOBUF inp, PACKET * pkt, int onlykeypkts, off_t * retpos, int *skip, IOBUF out, int do_skip #ifdef DEBUG_PARSE_PACKET , const char *dbg_w, const char *dbg_f, int dbg_l #endif ) { int rc = 0, c, ctb, pkttype, lenbytes; unsigned long pktlen; byte hdr[8]; int hdrlen; int new_ctb = 0, partial = 0; int with_uid = (onlykeypkts == 2); *skip = 0; assert (!pkt->pkt.generic); if (retpos) *retpos = iobuf_tell (inp); if ((ctb = iobuf_get (inp)) == -1) { rc = -1; goto leave; } hdrlen = 0; hdr[hdrlen++] = ctb; if (!(ctb & 0x80)) { log_error ("%s: invalid packet (ctb=%02x)\n", iobuf_where (inp), ctb); rc = gpg_error (GPG_ERR_INV_PACKET); goto leave; } pktlen = 0; new_ctb = !!(ctb & 0x40); if (new_ctb) { pkttype = ctb & 0x3f; if ((c = iobuf_get (inp)) == -1) { log_error ("%s: 1st length byte missing\n", iobuf_where (inp)); rc = gpg_error (GPG_ERR_INV_PACKET); goto leave; } hdr[hdrlen++] = c; if (c < 192) pktlen = c; else if (c < 224) { pktlen = (c - 192) * 256; if ((c = iobuf_get (inp)) == -1) { log_error ("%s: 2nd length byte missing\n", iobuf_where (inp)); rc = gpg_error (GPG_ERR_INV_PACKET); goto leave; } hdr[hdrlen++] = c; pktlen += c + 192; } else if (c == 255) { pktlen = (hdr[hdrlen++] = iobuf_get_noeof (inp)) << 24; pktlen |= (hdr[hdrlen++] = iobuf_get_noeof (inp)) << 16; pktlen |= (hdr[hdrlen++] = iobuf_get_noeof (inp)) << 8; if ((c = iobuf_get (inp)) == -1) { log_error ("%s: 4 byte length invalid\n", iobuf_where (inp)); rc = gpg_error (GPG_ERR_INV_PACKET); goto leave; } pktlen |= (hdr[hdrlen++] = c); } else /* Partial body length. */ { switch (pkttype) { case PKT_PLAINTEXT: case PKT_ENCRYPTED: case PKT_ENCRYPTED_MDC: case PKT_COMPRESSED: iobuf_set_partial_block_mode (inp, c & 0xff); pktlen = 0; /* To indicate partial length. */ partial = 1; break; default: log_error ("%s: partial length for invalid" " packet type %d\n", iobuf_where (inp), pkttype); rc = gpg_error (GPG_ERR_INV_PACKET); goto leave; } } } else { pkttype = (ctb >> 2) & 0xf; lenbytes = ((ctb & 3) == 3) ? 0 : (1 << (ctb & 3)); if (!lenbytes) { pktlen = 0; /* Don't know the value. */ /* This isn't really partial, but we can treat it the same in a "read until the end" sort of way. */ partial = 1; if (pkttype != PKT_ENCRYPTED && pkttype != PKT_PLAINTEXT && pkttype != PKT_COMPRESSED) { log_error ("%s: indeterminate length for invalid" " packet type %d\n", iobuf_where (inp), pkttype); rc = gpg_error (GPG_ERR_INV_PACKET); goto leave; } } else { for (; lenbytes; lenbytes--) { pktlen <<= 8; pktlen |= hdr[hdrlen++] = iobuf_get_noeof (inp); } } } if (pktlen == (unsigned long) (-1)) { /* With some probability this is caused by a problem in the * the uncompressing layer - in some error cases it just loops * and spits out 0xff bytes. */ log_error ("%s: garbled packet detected\n", iobuf_where (inp)); g10_exit (2); } if (out && pkttype) { rc = iobuf_write (out, hdr, hdrlen); if (!rc) rc = copy_packet (inp, out, pkttype, pktlen, partial); goto leave; } if (with_uid && pkttype == PKT_USER_ID) ; else if (do_skip || !pkttype || (onlykeypkts && pkttype != PKT_PUBLIC_SUBKEY && pkttype != PKT_PUBLIC_KEY && pkttype != PKT_SECRET_SUBKEY && pkttype != PKT_SECRET_KEY)) { iobuf_skip_rest (inp, pktlen, partial); *skip = 1; rc = 0; goto leave; } if (DBG_PACKET) { #ifdef DEBUG_PARSE_PACKET log_debug ("parse_packet(iob=%d): type=%d length=%lu%s (%s.%s.%d)\n", iobuf_id (inp), pkttype, pktlen, new_ctb ? " (new_ctb)" : "", dbg_w, dbg_f, dbg_l); #else log_debug ("parse_packet(iob=%d): type=%d length=%lu%s\n", iobuf_id (inp), pkttype, pktlen, new_ctb ? " (new_ctb)" : ""); #endif } pkt->pkttype = pkttype; rc = G10ERR_UNKNOWN_PACKET; /* default error */ switch (pkttype) { case PKT_PUBLIC_KEY: case PKT_PUBLIC_SUBKEY: case PKT_SECRET_KEY: case PKT_SECRET_SUBKEY: pkt->pkt.public_key = xmalloc_clear (sizeof *pkt->pkt.public_key); rc = parse_key (inp, pkttype, pktlen, hdr, hdrlen, pkt); break; case PKT_SYMKEY_ENC: rc = parse_symkeyenc (inp, pkttype, pktlen, pkt); break; case PKT_PUBKEY_ENC: rc = parse_pubkeyenc (inp, pkttype, pktlen, pkt); break; case PKT_SIGNATURE: pkt->pkt.signature = xmalloc_clear (sizeof *pkt->pkt.signature); rc = parse_signature (inp, pkttype, pktlen, pkt->pkt.signature); break; case PKT_ONEPASS_SIG: pkt->pkt.onepass_sig = xmalloc_clear (sizeof *pkt->pkt.onepass_sig); rc = parse_onepass_sig (inp, pkttype, pktlen, pkt->pkt.onepass_sig); break; case PKT_USER_ID: rc = parse_user_id (inp, pkttype, pktlen, pkt); break; case PKT_ATTRIBUTE: pkt->pkttype = pkttype = PKT_USER_ID; /* we store it in the userID */ rc = parse_attribute (inp, pkttype, pktlen, pkt); break; case PKT_OLD_COMMENT: case PKT_COMMENT: rc = parse_comment (inp, pkttype, pktlen, pkt); break; case PKT_RING_TRUST: parse_trust (inp, pkttype, pktlen, pkt); rc = 0; break; case PKT_PLAINTEXT: rc = parse_plaintext (inp, pkttype, pktlen, pkt, new_ctb, partial); break; case PKT_COMPRESSED: rc = parse_compressed (inp, pkttype, pktlen, pkt, new_ctb); break; case PKT_ENCRYPTED: case PKT_ENCRYPTED_MDC: rc = parse_encrypted (inp, pkttype, pktlen, pkt, new_ctb, partial); break; case PKT_MDC: rc = parse_mdc (inp, pkttype, pktlen, pkt, new_ctb); break; case PKT_GPG_CONTROL: rc = parse_gpg_control (inp, pkttype, pktlen, pkt, partial); break; case PKT_MARKER: rc = parse_marker (inp, pkttype, pktlen); break; default: skip_packet (inp, pkttype, pktlen, partial); break; } leave: /* FIXME: Do we leak in case of an error? */ if (!rc && iobuf_error (inp)) rc = G10ERR_INV_KEYRING; return rc; } static void dump_hex_line (int c, int *i) { if (*i && !(*i % 8)) { if (*i && !(*i % 24)) es_fprintf (listfp, "\n%4d:", *i); else es_putc (' ', listfp); } if (c == -1) es_fprintf (listfp, " EOF"); else es_fprintf (listfp, " %02x", c); ++*i; } static int copy_packet (IOBUF inp, IOBUF out, int pkttype, unsigned long pktlen, int partial) { int rc; int n; char buf[100]; if (partial) { while ((n = iobuf_read (inp, buf, 100)) != -1) if ((rc = iobuf_write (out, buf, n))) return rc; /* write error */ } else if (!pktlen && pkttype == PKT_COMPRESSED) { log_debug ("copy_packet: compressed!\n"); /* compressed packet, copy till EOF */ while ((n = iobuf_read (inp, buf, 100)) != -1) if ((rc = iobuf_write (out, buf, n))) return rc; /* write error */ } else { for (; pktlen; pktlen -= n) { n = pktlen > 100 ? 100 : pktlen; n = iobuf_read (inp, buf, n); if (n == -1) return gpg_error (GPG_ERR_EOF); if ((rc = iobuf_write (out, buf, n))) return rc; /* write error */ } } return 0; } static void skip_packet (IOBUF inp, int pkttype, unsigned long pktlen, int partial) { if (list_mode) { es_fprintf (listfp, ":unknown packet: type %2d, length %lu\n", pkttype, pktlen); if (pkttype) { int c, i = 0; es_fputs ("dump:", listfp); if (partial) { while ((c = iobuf_get (inp)) != -1) dump_hex_line (c, &i); } else { for (; pktlen; pktlen--) { dump_hex_line ((c = iobuf_get (inp)), &i); if (c == -1) break; } } es_putc ('\n', listfp); return; } } iobuf_skip_rest (inp, pktlen, partial); } /* Read PKTLEN bytes form INP and return them in a newly allocated buffer. In case of an error NULL is returned and a error messages printed. */ static void * read_rest (IOBUF inp, size_t pktlen) { int c; byte *buf, *p; buf = xtrymalloc (pktlen); if (!buf) { gpg_error_t err = gpg_error_from_syserror (); log_error ("error reading rest of packet: %s\n", gpg_strerror (err)); return NULL; } for (p = buf; pktlen; pktlen--) { c = iobuf_get (inp); if (c == -1) { log_error ("premature eof while reading rest of packet\n"); xfree (buf); return NULL; } *p++ = c; } return buf; } /* Read a special size+body from INP. On success store an opaque MPI with it at R_DATA. On error return an error code and store NULL at R_DATA. Even in the error case store the number of read bytes at R_NREAD. The caller shall pass the remaining size of the packet in PKTLEN. */ static gpg_error_t read_size_body (iobuf_t inp, int pktlen, size_t *r_nread, gcry_mpi_t *r_data) { char buffer[256]; char *tmpbuf; int i, c, nbytes; *r_nread = 0; *r_data = NULL; if (!pktlen) return gpg_error (GPG_ERR_INV_PACKET); c = iobuf_readbyte (inp); if (c < 0) return gpg_error (GPG_ERR_INV_PACKET); pktlen--; ++*r_nread; nbytes = c; if (nbytes < 2 || nbytes > 254) return gpg_error (GPG_ERR_INV_PACKET); if (nbytes > pktlen) return gpg_error (GPG_ERR_INV_PACKET); buffer[0] = nbytes; for (i = 0; i < nbytes; i++) { c = iobuf_get (inp); if (c < 0) return gpg_error (GPG_ERR_INV_PACKET); ++*r_nread; buffer[1+i] = c; } tmpbuf = xtrymalloc (1 + nbytes); if (!tmpbuf) return gpg_error_from_syserror (); memcpy (tmpbuf, buffer, 1 + nbytes); *r_data = gcry_mpi_set_opaque (NULL, tmpbuf, 8 * (1 + nbytes)); if (!*r_data) { xfree (tmpbuf); return gpg_error_from_syserror (); } return 0; } /* Parse a marker packet. */ static int parse_marker (IOBUF inp, int pkttype, unsigned long pktlen) { (void) pkttype; if (pktlen != 3) goto fail; if (iobuf_get (inp) != 'P') { pktlen--; goto fail; } if (iobuf_get (inp) != 'G') { pktlen--; goto fail; } if (iobuf_get (inp) != 'P') { pktlen--; goto fail; } if (list_mode) es_fputs (":marker packet: PGP\n", listfp); return 0; fail: log_error ("invalid marker packet\n"); iobuf_skip_rest (inp, pktlen, 0); return G10ERR_INVALID_PACKET; } static int parse_symkeyenc (IOBUF inp, int pkttype, unsigned long pktlen, PACKET * packet) { PKT_symkey_enc *k; int rc = 0; int i, version, s2kmode, cipher_algo, hash_algo, seskeylen, minlen; if (pktlen < 4) { log_error ("packet(%d) too short\n", pkttype); rc = gpg_error (GPG_ERR_INV_PACKET); goto leave; } version = iobuf_get_noeof (inp); pktlen--; if (version != 4) { log_error ("packet(%d) with unknown version %d\n", pkttype, version); rc = gpg_error (GPG_ERR_INV_PACKET); goto leave; } if (pktlen > 200) { /* (we encode the seskeylen in a byte) */ log_error ("packet(%d) too large\n", pkttype); rc = gpg_error (GPG_ERR_INV_PACKET); goto leave; } cipher_algo = iobuf_get_noeof (inp); pktlen--; s2kmode = iobuf_get_noeof (inp); pktlen--; hash_algo = iobuf_get_noeof (inp); pktlen--; switch (s2kmode) { case 0: /* Simple S2K. */ minlen = 0; break; case 1: /* Salted S2K. */ minlen = 8; break; case 3: /* Iterated+salted S2K. */ minlen = 9; break; default: log_error ("unknown S2K mode %d\n", s2kmode); goto leave; } if (minlen > pktlen) { log_error ("packet with S2K %d too short\n", s2kmode); rc = gpg_error (GPG_ERR_INV_PACKET); goto leave; } seskeylen = pktlen - minlen; k = packet->pkt.symkey_enc = xmalloc_clear (sizeof *packet->pkt.symkey_enc + seskeylen - 1); k->version = version; k->cipher_algo = cipher_algo; k->s2k.mode = s2kmode; k->s2k.hash_algo = hash_algo; if (s2kmode == 1 || s2kmode == 3) { for (i = 0; i < 8 && pktlen; i++, pktlen--) k->s2k.salt[i] = iobuf_get_noeof (inp); } if (s2kmode == 3) { k->s2k.count = iobuf_get (inp); pktlen--; } k->seskeylen = seskeylen; if (k->seskeylen) { for (i = 0; i < seskeylen && pktlen; i++, pktlen--) k->seskey[i] = iobuf_get_noeof (inp); /* What we're watching out for here is a session key decryptor with no salt. The RFC says that using salt for this is a MUST. */ if (s2kmode != 1 && s2kmode != 3) log_info (_("WARNING: potentially insecure symmetrically" " encrypted session key\n")); } assert (!pktlen); if (list_mode) { es_fprintf (listfp, ":symkey enc packet: version %d, cipher %d, s2k %d, hash %d", version, cipher_algo, s2kmode, hash_algo); if (seskeylen) es_fprintf (listfp, ", seskey %d bits", (seskeylen - 1) * 8); es_fprintf (listfp, "\n"); if (s2kmode == 1 || s2kmode == 3) { es_fprintf (listfp, "\tsalt "); es_write_hexstring (listfp, k->s2k.salt, 8, 0, NULL); if (s2kmode == 3) es_fprintf (listfp, ", count %lu (%lu)", S2K_DECODE_COUNT ((ulong) k->s2k.count), (ulong) k->s2k.count); es_fprintf (listfp, "\n"); } } leave: iobuf_skip_rest (inp, pktlen, 0); return rc; } static int parse_pubkeyenc (IOBUF inp, int pkttype, unsigned long pktlen, PACKET * packet) { int rc = 0; int i, ndata; PKT_pubkey_enc *k; k = packet->pkt.pubkey_enc = xmalloc_clear (sizeof *packet->pkt.pubkey_enc); if (pktlen < 12) { log_error ("packet(%d) too short\n", pkttype); rc = gpg_error (GPG_ERR_INV_PACKET); goto leave; } k->version = iobuf_get_noeof (inp); pktlen--; if (k->version != 2 && k->version != 3) { log_error ("packet(%d) with unknown version %d\n", pkttype, k->version); rc = gpg_error (GPG_ERR_INV_PACKET); goto leave; } k->keyid[0] = read_32 (inp); pktlen -= 4; k->keyid[1] = read_32 (inp); pktlen -= 4; k->pubkey_algo = iobuf_get_noeof (inp); pktlen--; k->throw_keyid = 0; /* Only used as flag for build_packet. */ if (list_mode) es_fprintf (listfp, ":pubkey enc packet: version %d, algo %d, keyid %08lX%08lX\n", k->version, k->pubkey_algo, (ulong) k->keyid[0], (ulong) k->keyid[1]); ndata = pubkey_get_nenc (k->pubkey_algo); if (!ndata) { if (list_mode) es_fprintf (listfp, "\tunsupported algorithm %d\n", k->pubkey_algo); unknown_pubkey_warning (k->pubkey_algo); k->data[0] = NULL; /* No need to store the encrypted data. */ } else { for (i = 0; i < ndata; i++) { if (k->pubkey_algo == PUBKEY_ALGO_ECDH && i == 1) { size_t n; rc = read_size_body (inp, pktlen, &n, k->data+i); pktlen -= n; } else { int n = pktlen; k->data[i] = mpi_read (inp, &n, 0); pktlen -= n; if (!k->data[i]) rc = gpg_error (GPG_ERR_INV_PACKET); } if (rc) goto leave; if (list_mode) { es_fprintf (listfp, "\tdata: "); mpi_print (listfp, k->data[i], mpi_print_mode); es_putc ('\n', listfp); } } } leave: iobuf_skip_rest (inp, pktlen, 0); return rc; } static void dump_sig_subpkt (int hashed, int type, int critical, const byte * buffer, size_t buflen, size_t length) { const char *p = NULL; int i; /* The CERT has warning out with explains how to use GNUPG to detect * the ARRs - we print our old message here when it is a faked ARR * and add an additional notice. */ if (type == SIGSUBPKT_ARR && !hashed) { es_fprintf (listfp, "\tsubpkt %d len %u (additional recipient request)\n" "WARNING: PGP versions > 5.0 and < 6.5.8 will automagically " "encrypt to this key and thereby reveal the plaintext to " "the owner of this ARR key. Detailed info follows:\n", type, (unsigned) length); } buffer++; length--; es_fprintf (listfp, "\t%s%ssubpkt %d len %u (", /*) */ critical ? "critical " : "", hashed ? "hashed " : "", type, (unsigned) length); if (length > buflen) { es_fprintf (listfp, "too short: buffer is only %u)\n", (unsigned) buflen); return; } switch (type) { case SIGSUBPKT_SIG_CREATED: if (length >= 4) es_fprintf (listfp, "sig created %s", strtimestamp (buffer_to_u32 (buffer))); break; case SIGSUBPKT_SIG_EXPIRE: if (length >= 4) { if (buffer_to_u32 (buffer)) es_fprintf (listfp, "sig expires after %s", strtimevalue (buffer_to_u32 (buffer))); else es_fprintf (listfp, "sig does not expire"); } break; case SIGSUBPKT_EXPORTABLE: if (length) es_fprintf (listfp, "%sexportable", *buffer ? "" : "not "); break; case SIGSUBPKT_TRUST: if (length != 2) p = "[invalid trust subpacket]"; else es_fprintf (listfp, "trust signature of depth %d, value %d", buffer[0], buffer[1]); break; case SIGSUBPKT_REGEXP: if (!length) p = "[invalid regexp subpacket]"; else es_fprintf (listfp, "regular expression: \"%s\"", buffer); break; case SIGSUBPKT_REVOCABLE: if (length) es_fprintf (listfp, "%srevocable", *buffer ? "" : "not "); break; case SIGSUBPKT_KEY_EXPIRE: if (length >= 4) { if (buffer_to_u32 (buffer)) es_fprintf (listfp, "key expires after %s", strtimevalue (buffer_to_u32 (buffer))); else es_fprintf (listfp, "key does not expire"); } break; case SIGSUBPKT_PREF_SYM: es_fputs ("pref-sym-algos:", listfp); for (i = 0; i < length; i++) es_fprintf (listfp, " %d", buffer[i]); break; case SIGSUBPKT_REV_KEY: es_fputs ("revocation key: ", listfp); if (length < 22) p = "[too short]"; else { es_fprintf (listfp, "c=%02x a=%d f=", buffer[0], buffer[1]); for (i = 2; i < length; i++) es_fprintf (listfp, "%02X", buffer[i]); } break; case SIGSUBPKT_ISSUER: if (length >= 8) es_fprintf (listfp, "issuer key ID %08lX%08lX", (ulong) buffer_to_u32 (buffer), (ulong) buffer_to_u32 (buffer + 4)); break; case SIGSUBPKT_NOTATION: { es_fputs ("notation: ", listfp); if (length < 8) p = "[too short]"; else { const byte *s = buffer; size_t n1, n2; n1 = (s[4] << 8) | s[5]; n2 = (s[6] << 8) | s[7]; s += 8; if (8 + n1 + n2 != length) p = "[error]"; else { es_write_sanitized (listfp, s, n1, ")", NULL); es_putc ('=', listfp); if (*buffer & 0x80) es_write_sanitized (listfp, s + n1, n2, ")", NULL); else p = "[not human readable]"; } } } break; case SIGSUBPKT_PREF_HASH: es_fputs ("pref-hash-algos:", listfp); for (i = 0; i < length; i++) es_fprintf (listfp, " %d", buffer[i]); break; case SIGSUBPKT_PREF_COMPR: es_fputs ("pref-zip-algos:", listfp); for (i = 0; i < length; i++) es_fprintf (listfp, " %d", buffer[i]); break; case SIGSUBPKT_KS_FLAGS: es_fputs ("key server preferences:", listfp); for (i = 0; i < length; i++) es_fprintf (listfp, " %02X", buffer[i]); break; case SIGSUBPKT_PREF_KS: es_fputs ("preferred key server: ", listfp); es_write_sanitized (listfp, buffer, length, ")", NULL); break; case SIGSUBPKT_PRIMARY_UID: p = "primary user ID"; break; case SIGSUBPKT_POLICY: es_fputs ("policy: ", listfp); es_write_sanitized (listfp, buffer, length, ")", NULL); break; case SIGSUBPKT_KEY_FLAGS: es_fputs ("key flags:", listfp); for (i = 0; i < length; i++) es_fprintf (listfp, " %02X", buffer[i]); break; case SIGSUBPKT_SIGNERS_UID: p = "signer's user ID"; break; case SIGSUBPKT_REVOC_REASON: if (length) { es_fprintf (listfp, "revocation reason 0x%02x (", *buffer); es_write_sanitized (listfp, buffer + 1, length - 1, ")", NULL); p = ")"; } break; case SIGSUBPKT_ARR: es_fputs ("Big Brother's key (ignored): ", listfp); if (length < 22) p = "[too short]"; else { es_fprintf (listfp, "c=%02x a=%d f=", buffer[0], buffer[1]); if (length > 2) es_write_hexstring (listfp, buffer+2, length-2, 0, NULL); } break; case SIGSUBPKT_FEATURES: es_fputs ("features:", listfp); for (i = 0; i < length; i++) es_fprintf (listfp, " %02x", buffer[i]); break; case SIGSUBPKT_SIGNATURE: es_fputs ("signature: ", listfp); if (length < 17) p = "[too short]"; else es_fprintf (listfp, "v%d, class 0x%02X, algo %d, digest algo %d", buffer[0], buffer[0] == 3 ? buffer[2] : buffer[1], buffer[0] == 3 ? buffer[15] : buffer[2], buffer[0] == 3 ? buffer[16] : buffer[3]); break; default: if (type >= 100 && type <= 110) p = "experimental / private subpacket"; else p = "?"; break; } es_fprintf (listfp, "%s)\n", p ? p : ""); } /* * Returns: >= 0 use this offset into buffer * -1 explicitly reject returning this type * -2 subpacket too short */ int parse_one_sig_subpkt (const byte * buffer, size_t n, int type) { switch (type) { case SIGSUBPKT_REV_KEY: if (n < 22) break; return 0; case SIGSUBPKT_SIG_CREATED: case SIGSUBPKT_SIG_EXPIRE: case SIGSUBPKT_KEY_EXPIRE: if (n < 4) break; return 0; case SIGSUBPKT_KEY_FLAGS: case SIGSUBPKT_KS_FLAGS: case SIGSUBPKT_PREF_SYM: case SIGSUBPKT_PREF_HASH: case SIGSUBPKT_PREF_COMPR: case SIGSUBPKT_POLICY: case SIGSUBPKT_PREF_KS: case SIGSUBPKT_FEATURES: case SIGSUBPKT_REGEXP: return 0; case SIGSUBPKT_SIGNATURE: case SIGSUBPKT_EXPORTABLE: case SIGSUBPKT_REVOCABLE: case SIGSUBPKT_REVOC_REASON: if (!n) break; return 0; case SIGSUBPKT_ISSUER: /* issuer key ID */ if (n < 8) break; return 0; case SIGSUBPKT_NOTATION: /* minimum length needed, and the subpacket must be well-formed where the name length and value length all fit inside the packet. */ if (n < 8 || 8 + ((buffer[4] << 8) | buffer[5]) + ((buffer[6] << 8) | buffer[7]) != n) break; return 0; case SIGSUBPKT_PRIMARY_UID: if (n != 1) break; return 0; case SIGSUBPKT_TRUST: if (n != 2) break; return 0; default: return 0; } return -2; } /* Return true if we understand the critical notation. */ static int can_handle_critical_notation (const byte * name, size_t len) { if (len == 32 && memcmp (name, "preferred-email-encoding@pgp.com", 32) == 0) return 1; if (len == 21 && memcmp (name, "pka-address@gnupg.org", 21) == 0) return 1; return 0; } static int can_handle_critical (const byte * buffer, size_t n, int type) { switch (type) { case SIGSUBPKT_NOTATION: if (n >= 8) return can_handle_critical_notation (buffer + 8, (buffer[4] << 8) | buffer[5]); else return 0; case SIGSUBPKT_SIGNATURE: case SIGSUBPKT_SIG_CREATED: case SIGSUBPKT_SIG_EXPIRE: case SIGSUBPKT_KEY_EXPIRE: case SIGSUBPKT_EXPORTABLE: case SIGSUBPKT_REVOCABLE: case SIGSUBPKT_REV_KEY: case SIGSUBPKT_ISSUER: /* issuer key ID */ case SIGSUBPKT_PREF_SYM: case SIGSUBPKT_PREF_HASH: case SIGSUBPKT_PREF_COMPR: case SIGSUBPKT_KEY_FLAGS: case SIGSUBPKT_PRIMARY_UID: case SIGSUBPKT_FEATURES: case SIGSUBPKT_TRUST: case SIGSUBPKT_REGEXP: /* Is it enough to show the policy or keyserver? */ case SIGSUBPKT_POLICY: case SIGSUBPKT_PREF_KS: return 1; default: return 0; } } const byte * enum_sig_subpkt (const subpktarea_t * pktbuf, sigsubpkttype_t reqtype, size_t * ret_n, int *start, int *critical) { const byte *buffer; int buflen; int type; int critical_dummy; int offset; size_t n; int seq = 0; int reqseq = start ? *start : 0; if (!critical) critical = &critical_dummy; if (!pktbuf || reqseq == -1) { /* return some value different from NULL to indicate that * there is no critical bit we do not understand. The caller * will never use the value. Yes I know, it is an ugly hack */ return reqtype == SIGSUBPKT_TEST_CRITICAL ? (const byte *) &pktbuf : NULL; } buffer = pktbuf->data; buflen = pktbuf->len; while (buflen) { n = *buffer++; buflen--; if (n == 255) /* 4 byte length header. */ { if (buflen < 4) goto too_short; n = (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3]; buffer += 4; buflen -= 4; } else if (n >= 192) /* 4 byte special encoded length header. */ { if (buflen < 2) goto too_short; n = ((n - 192) << 8) + *buffer + 192; buffer++; buflen--; } if (buflen < n) goto too_short; type = *buffer; if (type & 0x80) { type &= 0x7f; *critical = 1; } else *critical = 0; if (!(++seq > reqseq)) ; else if (reqtype == SIGSUBPKT_TEST_CRITICAL) { if (*critical) { if (n - 1 > buflen + 1) goto too_short; if (!can_handle_critical (buffer + 1, n - 1, type)) { if (opt.verbose) log_info (_("subpacket of type %d has " "critical bit set\n"), type); if (start) *start = seq; return NULL; /* This is an error. */ } } } else if (reqtype < 0) /* List packets. */ dump_sig_subpkt (reqtype == SIGSUBPKT_LIST_HASHED, type, *critical, buffer, buflen, n); else if (type == reqtype) /* Found. */ { buffer++; n--; if (n > buflen) goto too_short; if (ret_n) *ret_n = n; offset = parse_one_sig_subpkt (buffer, n, type); switch (offset) { case -2: log_error ("subpacket of type %d too short\n", type); return NULL; case -1: return NULL; default: break; } if (start) *start = seq; return buffer + offset; } buffer += n; buflen -= n; } if (reqtype == SIGSUBPKT_TEST_CRITICAL) return buffer; /* Used as True to indicate that there is no. */ /* Critical bit we don't understand. */ if (start) *start = -1; return NULL; /* End of packets; not found. */ too_short: if (opt.verbose) log_info ("buffer shorter than subpacket\n"); if (start) *start = -1; return NULL; } const byte * parse_sig_subpkt (const subpktarea_t * buffer, sigsubpkttype_t reqtype, size_t * ret_n) { return enum_sig_subpkt (buffer, reqtype, ret_n, NULL, NULL); } const byte * parse_sig_subpkt2 (PKT_signature * sig, sigsubpkttype_t reqtype, size_t * ret_n) { const byte *p; p = parse_sig_subpkt (sig->hashed, reqtype, ret_n); if (!p) p = parse_sig_subpkt (sig->unhashed, reqtype, ret_n); return p; } /* Find all revocation keys. Look in hashed area only. */ void parse_revkeys (PKT_signature * sig) { struct revocation_key *revkey; int seq = 0; size_t len; if (sig->sig_class != 0x1F) return; while ((revkey = (struct revocation_key *) enum_sig_subpkt (sig->hashed, SIGSUBPKT_REV_KEY, &len, &seq, NULL))) { if (len == sizeof (struct revocation_key) && (revkey->class & 0x80)) /* 0x80 bit must be set. */ { sig->revkey = xrealloc (sig->revkey, sizeof (struct revocation_key *) * (sig->numrevkeys + 1)); sig->revkey[sig->numrevkeys] = revkey; sig->numrevkeys++; } } } int parse_signature (IOBUF inp, int pkttype, unsigned long pktlen, PKT_signature * sig) { int md5_len = 0; unsigned n; int is_v4 = 0; int rc = 0; int i, ndata; if (pktlen < 16) { log_error ("packet(%d) too short\n", pkttype); goto leave; } sig->version = iobuf_get_noeof (inp); pktlen--; if (sig->version == 4) is_v4 = 1; else if (sig->version != 2 && sig->version != 3) { log_error ("packet(%d) with unknown version %d\n", pkttype, sig->version); rc = gpg_error (GPG_ERR_INV_PACKET); goto leave; } if (!is_v4) { md5_len = iobuf_get_noeof (inp); pktlen--; } sig->sig_class = iobuf_get_noeof (inp); pktlen--; if (!is_v4) { sig->timestamp = read_32 (inp); pktlen -= 4; sig->keyid[0] = read_32 (inp); pktlen -= 4; sig->keyid[1] = read_32 (inp); pktlen -= 4; } sig->pubkey_algo = iobuf_get_noeof (inp); pktlen--; sig->digest_algo = iobuf_get_noeof (inp); pktlen--; sig->flags.exportable = 1; sig->flags.revocable = 1; if (is_v4) /* Read subpackets. */ { n = read_16 (inp); pktlen -= 2; /* Length of hashed data. */ if (n > 10000) { log_error ("signature packet: hashed data too long\n"); rc = G10ERR_INVALID_PACKET; goto leave; } if (n) { sig->hashed = xmalloc (sizeof (*sig->hashed) + n - 1); sig->hashed->size = n; sig->hashed->len = n; if (iobuf_read (inp, sig->hashed->data, n) != n) { log_error ("premature eof while reading " "hashed signature data\n"); rc = -1; goto leave; } pktlen -= n; } n = read_16 (inp); pktlen -= 2; /* Length of unhashed data. */ if (n > 10000) { log_error ("signature packet: unhashed data too long\n"); rc = G10ERR_INVALID_PACKET; goto leave; } if (n) { sig->unhashed = xmalloc (sizeof (*sig->unhashed) + n - 1); sig->unhashed->size = n; sig->unhashed->len = n; if (iobuf_read (inp, sig->unhashed->data, n) != n) { log_error ("premature eof while reading " "unhashed signature data\n"); rc = -1; goto leave; } pktlen -= n; } } if (pktlen < 5) /* Sanity check. */ { log_error ("packet(%d) too short\n", pkttype); rc = G10ERR_INVALID_PACKET; goto leave; } sig->digest_start[0] = iobuf_get_noeof (inp); pktlen--; sig->digest_start[1] = iobuf_get_noeof (inp); pktlen--; if (is_v4 && sig->pubkey_algo) /* Extract required information. */ { const byte *p; size_t len; /* Set sig->flags.unknown_critical if there is a critical bit * set for packets which we do not understand. */ if (!parse_sig_subpkt (sig->hashed, SIGSUBPKT_TEST_CRITICAL, NULL) || !parse_sig_subpkt (sig->unhashed, SIGSUBPKT_TEST_CRITICAL, NULL)) sig->flags.unknown_critical = 1; p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_SIG_CREATED, NULL); if (p) sig->timestamp = buffer_to_u32 (p); else if (!(sig->pubkey_algo >= 100 && sig->pubkey_algo <= 110) && opt.verbose) log_info ("signature packet without timestamp\n"); p = parse_sig_subpkt2 (sig, SIGSUBPKT_ISSUER, NULL); if (p) { sig->keyid[0] = buffer_to_u32 (p); sig->keyid[1] = buffer_to_u32 (p + 4); } else if (!(sig->pubkey_algo >= 100 && sig->pubkey_algo <= 110) && opt.verbose) log_info ("signature packet without keyid\n"); p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_SIG_EXPIRE, NULL); if (p && buffer_to_u32 (p)) sig->expiredate = sig->timestamp + buffer_to_u32 (p); if (sig->expiredate && sig->expiredate <= make_timestamp ()) sig->flags.expired = 1; p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_POLICY, NULL); if (p) sig->flags.policy_url = 1; p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_PREF_KS, NULL); if (p) sig->flags.pref_ks = 1; p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_NOTATION, NULL); if (p) sig->flags.notation = 1; p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_REVOCABLE, NULL); if (p && *p == 0) sig->flags.revocable = 0; p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_TRUST, &len); if (p && len == 2) { sig->trust_depth = p[0]; sig->trust_value = p[1]; /* Only look for a regexp if there is also a trust subpacket. */ sig->trust_regexp = parse_sig_subpkt (sig->hashed, SIGSUBPKT_REGEXP, &len); /* If the regular expression is of 0 length, there is no regular expression. */ if (len == 0) sig->trust_regexp = NULL; } /* We accept the exportable subpacket from either the hashed or unhashed areas as older versions of gpg put it in the unhashed area. In theory, anyway, we should never see this packet off of a local keyring. */ p = parse_sig_subpkt2 (sig, SIGSUBPKT_EXPORTABLE, NULL); if (p && *p == 0) sig->flags.exportable = 0; /* Find all revocation keys. */ if (sig->sig_class == 0x1F) parse_revkeys (sig); } if (list_mode) { es_fprintf (listfp, ":signature packet: algo %d, keyid %08lX%08lX\n" "\tversion %d, created %lu, md5len %d, sigclass 0x%02x\n" "\tdigest algo %d, begin of digest %02x %02x\n", sig->pubkey_algo, (ulong) sig->keyid[0], (ulong) sig->keyid[1], sig->version, (ulong) sig->timestamp, md5_len, sig->sig_class, sig->digest_algo, sig->digest_start[0], sig->digest_start[1]); if (is_v4) { parse_sig_subpkt (sig->hashed, SIGSUBPKT_LIST_HASHED, NULL); parse_sig_subpkt (sig->unhashed, SIGSUBPKT_LIST_UNHASHED, NULL); } } ndata = pubkey_get_nsig (sig->pubkey_algo); if (!ndata) { if (list_mode) es_fprintf (listfp, "\tunknown algorithm %d\n", sig->pubkey_algo); unknown_pubkey_warning (sig->pubkey_algo); /* We store the plain material in data[0], so that we are able * to write it back with build_packet(). */ if (pktlen > (5 * MAX_EXTERN_MPI_BITS / 8)) { /* We include a limit to avoid too trivial DoS attacks by having gpg allocate too much memory. */ log_error ("signature packet: too much data\n"); rc = G10ERR_INVALID_PACKET; } else { sig->data[0] = gcry_mpi_set_opaque (NULL, read_rest (inp, pktlen), pktlen * 8); pktlen = 0; } } else { for (i = 0; i < ndata; i++) { n = pktlen; sig->data[i] = mpi_read (inp, &n, 0); pktlen -= n; if (list_mode) { es_fprintf (listfp, "\tdata: "); mpi_print (listfp, sig->data[i], mpi_print_mode); es_putc ('\n', listfp); } if (!sig->data[i]) rc = G10ERR_INVALID_PACKET; } } leave: iobuf_skip_rest (inp, pktlen, 0); return rc; } static int parse_onepass_sig (IOBUF inp, int pkttype, unsigned long pktlen, PKT_onepass_sig * ops) { int version; int rc = 0; if (pktlen < 13) { log_error ("packet(%d) too short\n", pkttype); rc = gpg_error (GPG_ERR_INV_PACKET); goto leave; } version = iobuf_get_noeof (inp); pktlen--; if (version != 3) { log_error ("onepass_sig with unknown version %d\n", version); rc = gpg_error (GPG_ERR_INV_PACKET); goto leave; } ops->sig_class = iobuf_get_noeof (inp); pktlen--; ops->digest_algo = iobuf_get_noeof (inp); pktlen--; ops->pubkey_algo = iobuf_get_noeof (inp); pktlen--; ops->keyid[0] = read_32 (inp); pktlen -= 4; ops->keyid[1] = read_32 (inp); pktlen -= 4; ops->last = iobuf_get_noeof (inp); pktlen--; if (list_mode) es_fprintf (listfp, ":onepass_sig packet: keyid %08lX%08lX\n" "\tversion %d, sigclass 0x%02x, digest %d, pubkey %d, " "last=%d\n", (ulong) ops->keyid[0], (ulong) ops->keyid[1], version, ops->sig_class, ops->digest_algo, ops->pubkey_algo, ops->last); leave: iobuf_skip_rest (inp, pktlen, 0); return rc; } static gcry_mpi_t read_protected_v3_mpi (IOBUF inp, unsigned long *length) { int c; unsigned int nbits, nbytes; unsigned char *buf, *p; gcry_mpi_t val; if (*length < 2) { log_error ("mpi too small\n"); return NULL; } if ((c = iobuf_get (inp)) == -1) return NULL; --*length; nbits = c << 8; if ((c = iobuf_get (inp)) == -1) return NULL; --*length; nbits |= c; if (nbits > 16384) { log_error ("mpi too large (%u bits)\n", nbits); return NULL; } nbytes = (nbits + 7) / 8; buf = p = xmalloc (2 + nbytes); *p++ = nbits >> 8; *p++ = nbits; for (; nbytes && *length; nbytes--, --*length) *p++ = iobuf_get (inp); if (nbytes) { log_error ("packet shorter than mpi\n"); xfree (buf); return NULL; } /* Convert buffer into an opaque MPI. */ val = gcry_mpi_set_opaque (NULL, buf, (p - buf) * 8); return val; } static int parse_key (IOBUF inp, int pkttype, unsigned long pktlen, byte * hdr, int hdrlen, PACKET * pkt) { gpg_error_t err = 0; int i, version, algorithm; unsigned long timestamp, expiredate, max_expiredate; int npkey, nskey; int is_v4 = 0; int rc = 0; u32 keyid[2]; PKT_public_key *pk; (void) hdr; pk = pkt->pkt.public_key; /* PK has been cleared. */ version = iobuf_get_noeof (inp); pktlen--; if (pkttype == PKT_PUBLIC_SUBKEY && version == '#') { /* Early versions of G10 used the old PGP comments packets; * luckily all those comments are started by a hash. */ if (list_mode) { es_fprintf (listfp, ":rfc1991 comment packet: \""); for (; pktlen; pktlen--) { int c; c = iobuf_get_noeof (inp); if (c >= ' ' && c <= 'z') es_putc (c, listfp); else es_fprintf (listfp, "\\x%02x", c); } es_fprintf (listfp, "\"\n"); } iobuf_skip_rest (inp, pktlen, 0); return 0; } else if (version == 4) is_v4 = 1; else if (version != 2 && version != 3) { log_error ("packet(%d) with unknown version %d\n", pkttype, version); err = gpg_error (GPG_ERR_INV_PACKET); goto leave; } if (pktlen < 11) { log_error ("packet(%d) too short\n", pkttype); err = gpg_error (GPG_ERR_INV_PACKET); goto leave; } timestamp = read_32 (inp); pktlen -= 4; if (is_v4) { expiredate = 0; /* have to get it from the selfsignature */ max_expiredate = 0; } else { unsigned short ndays; ndays = read_16 (inp); pktlen -= 2; if (ndays) expiredate = timestamp + ndays * 86400L; else expiredate = 0; max_expiredate = expiredate; } algorithm = iobuf_get_noeof (inp); pktlen--; if (list_mode) es_fprintf (listfp, ":%s key packet:\n" "\tversion %d, algo %d, created %lu, expires %lu\n", pkttype == PKT_PUBLIC_KEY ? "public" : pkttype == PKT_SECRET_KEY ? "secret" : pkttype == PKT_PUBLIC_SUBKEY ? "public sub" : pkttype == PKT_SECRET_SUBKEY ? "secret sub" : "??", version, algorithm, timestamp, expiredate); pk->timestamp = timestamp; pk->expiredate = expiredate; pk->max_expiredate = max_expiredate; pk->hdrbytes = hdrlen; pk->version = version; pk->flags.primary = (pkttype == PKT_PUBLIC_KEY || pkttype == PKT_SECRET_KEY); pk->pubkey_algo = algorithm; nskey = pubkey_get_nskey (algorithm); npkey = pubkey_get_npkey (algorithm); if (!npkey) { if (list_mode) es_fprintf (listfp, "\tunknown algorithm %d\n", algorithm); unknown_pubkey_warning (algorithm); } if (!npkey) { /* Unknown algorithm - put data into an opaque MPI. */ pk->pkey[0] = gcry_mpi_set_opaque (NULL, read_rest (inp, pktlen), pktlen * 8); pktlen = 0; goto leave; } else { for (i = 0; i < npkey; i++) { - if ((algorithm == PUBKEY_ALGO_ECDSA && (i == 0)) - || ((algorithm == PUBKEY_ALGO_ECDH) && (i == 0 || i == 2))) + if ( (algorithm == PUBKEY_ALGO_ECDSA && (i == 0)) + || (algorithm == PUBKEY_ALGO_EDDSA && (i == 0)) + || (algorithm == PUBKEY_ALGO_ECDH && (i == 0 || i == 2))) { + /* Read the OID (i==1) or the KDF params (i==2). */ size_t n; err = read_size_body (inp, pktlen, &n, pk->pkey+i); pktlen -= n; } else { unsigned int n = pktlen; pk->pkey[i] = mpi_read (inp, &n, 0); pktlen -= n; if (!pk->pkey[i]) err = gpg_error (GPG_ERR_INV_PACKET); } if (err) goto leave; if (list_mode) { es_fprintf (listfp, "\tpkey[%d]: ", i); mpi_print (listfp, pk->pkey[i], mpi_print_mode); if ((algorithm == PUBKEY_ALGO_ECDSA + || algorithm == PUBKEY_ALGO_EDDSA || algorithm == PUBKEY_ALGO_ECDH) && i==0) { char *curve = openpgp_oid_to_str (pk->pkey[0]); es_fprintf (listfp, " %s (%s)", openpgp_oid_to_curve (curve), curve); xfree (curve); } es_putc ('\n', listfp); } } } if (list_mode) keyid_from_pk (pk, keyid); if (pkttype == PKT_SECRET_KEY || pkttype == PKT_SECRET_SUBKEY) { struct seckey_info *ski; byte temp[16]; size_t snlen = 0; pk->seckey_info = ski = xtrycalloc (1, sizeof *ski); if (!pk->seckey_info) { err = gpg_error_from_syserror (); goto leave; } ski->algo = iobuf_get_noeof (inp); pktlen--; if (ski->algo) { ski->is_protected = 1; ski->s2k.count = 0; if (ski->algo == 254 || ski->algo == 255) { if (pktlen < 3) { err = gpg_error (GPG_ERR_INV_PACKET); goto leave; } ski->sha1chk = (ski->algo == 254); ski->algo = iobuf_get_noeof (inp); pktlen--; /* Note that a ski->algo > 110 is illegal, but I'm not erroring on it here as otherwise there would be no way to delete such a key. */ ski->s2k.mode = iobuf_get_noeof (inp); pktlen--; ski->s2k.hash_algo = iobuf_get_noeof (inp); pktlen--; /* Check for the special GNU extension. */ if (is_v4 && ski->s2k.mode == 101) { for (i = 0; i < 4 && pktlen; i++, pktlen--) temp[i] = iobuf_get_noeof (inp); if (i < 4 || memcmp (temp, "GNU", 3)) { if (list_mode) es_fprintf (listfp, "\tunknown S2K %d\n", ski->s2k.mode); err = gpg_error (GPG_ERR_INV_PACKET); goto leave; } /* Here we know that it is a GNU extension. What * follows is the GNU protection mode: All values * have special meanings and they are mapped to MODE * with a base of 1000. */ ski->s2k.mode = 1000 + temp[3]; } /* Read the salt. */ switch (ski->s2k.mode) { case 1: case 3: for (i = 0; i < 8 && pktlen; i++, pktlen--) temp[i] = iobuf_get_noeof (inp); memcpy (ski->s2k.salt, temp, 8); break; } /* Check the mode. */ switch (ski->s2k.mode) { case 0: if (list_mode) es_fprintf (listfp, "\tsimple S2K"); break; case 1: if (list_mode) es_fprintf (listfp, "\tsalted S2K"); break; case 3: if (list_mode) es_fprintf (listfp, "\titer+salt S2K"); break; case 1001: if (list_mode) es_fprintf (listfp, "\tgnu-dummy S2K"); break; case 1002: if (list_mode) es_fprintf (listfp, "\tgnu-divert-to-card S2K"); break; default: if (list_mode) es_fprintf (listfp, "\tunknown %sS2K %d\n", ski->s2k.mode < 1000 ? "" : "GNU ", ski->s2k.mode); err = gpg_error (GPG_ERR_INV_PACKET); goto leave; } /* Print some info. */ if (list_mode) { es_fprintf (listfp, ", algo: %d,%s hash: %d", ski->algo, ski->sha1chk ? " SHA1 protection," : " simple checksum,", ski->s2k.hash_algo); if (ski->s2k.mode == 1 || ski->s2k.mode == 3) { es_fprintf (listfp, ", salt: "); es_write_hexstring (listfp, ski->s2k.salt, 8, 0, NULL); } es_putc ('\n', listfp); } /* Read remaining protection parameters. */ if (ski->s2k.mode == 3) { if (pktlen < 1) { err = gpg_error (GPG_ERR_INV_PACKET); goto leave; } ski->s2k.count = iobuf_get (inp); pktlen--; if (list_mode) es_fprintf (listfp, "\tprotect count: %lu (%lu)\n", (ulong)S2K_DECODE_COUNT ((ulong)ski->s2k.count), (ulong) ski->s2k.count); } else if (ski->s2k.mode == 1002) { /* Read the serial number. */ if (pktlen < 1) { err = gpg_error (GPG_ERR_INV_PACKET); goto leave; } snlen = iobuf_get (inp); pktlen--; if (pktlen < snlen || snlen == (size_t)(-1)) { err = gpg_error (GPG_ERR_INV_PACKET); goto leave; } } } else /* Old version; no S2K, so we set mode to 0, hash MD5. */ { /* Note that a ski->algo > 110 is illegal, but I'm not erroring on it here as otherwise there would be no way to delete such a key. */ ski->s2k.mode = 0; ski->s2k.hash_algo = DIGEST_ALGO_MD5; if (list_mode) es_fprintf (listfp, "\tprotect algo: %d (hash algo: %d)\n", ski->algo, ski->s2k.hash_algo); } /* It is really ugly that we don't know the size * of the IV here in cases we are not aware of the algorithm. * so a * ski->ivlen = cipher_get_blocksize (ski->algo); * won't work. The only solution I see is to hardwire it. * NOTE: if you change the ivlen above 16, don't forget to * enlarge temp. */ ski->ivlen = openpgp_cipher_blocklen (ski->algo); assert (ski->ivlen <= sizeof (temp)); if (ski->s2k.mode == 1001) ski->ivlen = 0; else if (ski->s2k.mode == 1002) ski->ivlen = snlen < 16 ? snlen : 16; if (pktlen < ski->ivlen) { err = gpg_error (GPG_ERR_INV_PACKET); goto leave; } for (i = 0; i < ski->ivlen && pktlen; i++, pktlen--) temp[i] = iobuf_get_noeof (inp); if (list_mode) { es_fprintf (listfp, ski->s2k.mode == 1002 ? "\tserial-number: " : "\tprotect IV: "); for (i = 0; i < ski->ivlen; i++) es_fprintf (listfp, " %02x", temp[i]); es_putc ('\n', listfp); } memcpy (ski->iv, temp, ski->ivlen); } /* It does not make sense to read it into secure memory. * If the user is so careless, not to protect his secret key, * we can assume, that he operates an open system :=(. * So we put the key into secure memory when we unprotect it. */ if (ski->s2k.mode == 1001 || ski->s2k.mode == 1002) { /* Better set some dummy stuff here. */ pk->pkey[npkey] = gcry_mpi_set_opaque (NULL, xstrdup ("dummydata"), 10 * 8); pktlen = 0; } else if (is_v4 && ski->is_protected) { /* Ugly: The length is encrypted too, so we read all stuff * up to the end of the packet into the first SKEY * element. */ pk->pkey[npkey] = gcry_mpi_set_opaque (NULL, read_rest (inp, pktlen), pktlen * 8); pktlen = 0; if (list_mode) es_fprintf (listfp, "\tskey[%d]: [v4 protected]\n", npkey); } else { /* The v3 method: The mpi length is not encrypted. */ for (i = npkey; i < nskey; i++) { if (ski->is_protected) { pk->pkey[i] = read_protected_v3_mpi (inp, &pktlen); if (list_mode) es_fprintf (listfp, "\tskey[%d]: [v3 protected]\n", i); } else { unsigned int n = pktlen; pk->pkey[i] = mpi_read (inp, &n, 0); pktlen -= n; if (list_mode) { es_fprintf (listfp, "\tskey[%d]: ", i); mpi_print (listfp, pk->pkey[i], mpi_print_mode); es_putc ('\n', listfp); } } if (!pk->pkey[i]) err = gpg_error (GPG_ERR_INV_PACKET); } if (err) goto leave; ski->csum = read_16 (inp); pktlen -= 2; if (list_mode) es_fprintf (listfp, "\tchecksum: %04hx\n", ski->csum); } } if (list_mode) es_fprintf (listfp, "\tkeyid: %08lX%08lX\n", (ulong) keyid[0], (ulong) keyid[1]); leave: iobuf_skip_rest (inp, pktlen, 0); return rc; } /* Attribute subpackets have the same format as v4 signature subpackets. This is not part of OpenPGP, but is done in several versions of PGP nevertheless. */ int parse_attribute_subpkts (PKT_user_id * uid) { size_t n; int count = 0; struct user_attribute *attribs = NULL; const byte *buffer = uid->attrib_data; int buflen = uid->attrib_len; byte type; xfree (uid->attribs); while (buflen) { n = *buffer++; buflen--; if (n == 255) /* 4 byte length header. */ { if (buflen < 4) goto too_short; n = (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3]; buffer += 4; buflen -= 4; } else if (n >= 192) /* 2 byte special encoded length header. */ { if (buflen < 2) goto too_short; n = ((n - 192) << 8) + *buffer + 192; buffer++; buflen--; } if (buflen < n) goto too_short; attribs = xrealloc (attribs, (count + 1) * sizeof (struct user_attribute)); memset (&attribs[count], 0, sizeof (struct user_attribute)); type = *buffer; buffer++; buflen--; n--; attribs[count].type = type; attribs[count].data = buffer; attribs[count].len = n; buffer += n; buflen -= n; count++; } uid->attribs = attribs; uid->numattribs = count; return count; too_short: if (opt.verbose) log_info ("buffer shorter than attribute subpacket\n"); uid->attribs = attribs; uid->numattribs = count; return count; } static int parse_user_id (IOBUF inp, int pkttype, unsigned long pktlen, PACKET * packet) { byte *p; /* Cap the size of a user ID at 2k: a value absurdly large enough that there is no sane user ID string (which is printable text as of RFC2440bis) that won't fit in it, but yet small enough to avoid allocation problems. A large pktlen may not be allocatable, and a very large pktlen could actually cause our allocation to wrap around in xmalloc to a small number. */ if (pktlen > 2048) { log_error ("packet(%d) too large\n", pkttype); iobuf_skip_rest (inp, pktlen, 0); return G10ERR_INVALID_PACKET; } packet->pkt.user_id = xmalloc_clear (sizeof *packet->pkt.user_id + pktlen); packet->pkt.user_id->len = pktlen; packet->pkt.user_id->ref = 1; p = packet->pkt.user_id->name; for (; pktlen; pktlen--, p++) *p = iobuf_get_noeof (inp); *p = 0; if (list_mode) { int n = packet->pkt.user_id->len; es_fprintf (listfp, ":user ID packet: \""); /* fixme: Hey why don't we replace this with es_write_sanitized?? */ for (p = packet->pkt.user_id->name; n; p++, n--) { if (*p >= ' ' && *p <= 'z') es_putc (*p, listfp); else es_fprintf (listfp, "\\x%02x", *p); } es_fprintf (listfp, "\"\n"); } return 0; } void make_attribute_uidname (PKT_user_id * uid, size_t max_namelen) { assert (max_namelen > 70); if (uid->numattribs <= 0) sprintf (uid->name, "[bad attribute packet of size %lu]", uid->attrib_len); else if (uid->numattribs > 1) sprintf (uid->name, "[%d attributes of size %lu]", uid->numattribs, uid->attrib_len); else { /* Only one attribute, so list it as the "user id" */ if (uid->attribs->type == ATTRIB_IMAGE) { u32 len; byte type; if (parse_image_header (uid->attribs, &type, &len)) sprintf (uid->name, "[%.20s image of size %lu]", image_type_to_string (type, 1), (ulong) len); else sprintf (uid->name, "[invalid image]"); } else sprintf (uid->name, "[unknown attribute of size %lu]", (ulong) uid->attribs->len); } uid->len = strlen (uid->name); } static int parse_attribute (IOBUF inp, int pkttype, unsigned long pktlen, PACKET * packet) { byte *p; (void) pkttype; #define EXTRA_UID_NAME_SPACE 71 packet->pkt.user_id = xmalloc_clear (sizeof *packet->pkt.user_id + EXTRA_UID_NAME_SPACE); packet->pkt.user_id->ref = 1; packet->pkt.user_id->attrib_data = xmalloc (pktlen); packet->pkt.user_id->attrib_len = pktlen; p = packet->pkt.user_id->attrib_data; for (; pktlen; pktlen--, p++) *p = iobuf_get_noeof (inp); /* Now parse out the individual attribute subpackets. This is somewhat pointless since there is only one currently defined attribute type (jpeg), but it is correct by the spec. */ parse_attribute_subpkts (packet->pkt.user_id); make_attribute_uidname (packet->pkt.user_id, EXTRA_UID_NAME_SPACE); if (list_mode) { es_fprintf (listfp, ":attribute packet: %s\n", packet->pkt.user_id->name); } return 0; } static int parse_comment (IOBUF inp, int pkttype, unsigned long pktlen, PACKET * packet) { byte *p; /* Cap comment packet at a reasonable value to avoid an integer overflow in the malloc below. Comment packets are actually not anymore define my OpenPGP and we even stopped to use our private comment packet. */ if (pktlen > 65536) { log_error ("packet(%d) too large\n", pkttype); iobuf_skip_rest (inp, pktlen, 0); return G10ERR_INVALID_PACKET; } packet->pkt.comment = xmalloc (sizeof *packet->pkt.comment + pktlen - 1); packet->pkt.comment->len = pktlen; p = packet->pkt.comment->data; for (; pktlen; pktlen--, p++) *p = iobuf_get_noeof (inp); if (list_mode) { int n = packet->pkt.comment->len; es_fprintf (listfp, ":%scomment packet: \"", pkttype == PKT_OLD_COMMENT ? "OpenPGP draft " : ""); for (p = packet->pkt.comment->data; n; p++, n--) { if (*p >= ' ' && *p <= 'z') es_putc (*p, listfp); else es_fprintf (listfp, "\\x%02x", *p); } es_fprintf (listfp, "\"\n"); } return 0; } static void parse_trust (IOBUF inp, int pkttype, unsigned long pktlen, PACKET * pkt) { int c; (void) pkttype; if (pktlen) { c = iobuf_get_noeof (inp); pktlen--; pkt->pkt.ring_trust = xmalloc (sizeof *pkt->pkt.ring_trust); pkt->pkt.ring_trust->trustval = c; pkt->pkt.ring_trust->sigcache = 0; if (!c && pktlen == 1) { c = iobuf_get_noeof (inp); pktlen--; /* We require that bit 7 of the sigcache is 0 (easier eof handling). */ if (!(c & 0x80)) pkt->pkt.ring_trust->sigcache = c; } if (list_mode) es_fprintf (listfp, ":trust packet: flag=%02x sigcache=%02x\n", pkt->pkt.ring_trust->trustval, pkt->pkt.ring_trust->sigcache); } else { if (list_mode) es_fprintf (listfp, ":trust packet: empty\n"); } iobuf_skip_rest (inp, pktlen, 0); } static int parse_plaintext (IOBUF inp, int pkttype, unsigned long pktlen, PACKET * pkt, int new_ctb, int partial) { int rc = 0; int mode, namelen; PKT_plaintext *pt; byte *p; int c, i; if (!partial && pktlen < 6) { log_error ("packet(%d) too short (%lu)\n", pkttype, (ulong) pktlen); rc = gpg_error (GPG_ERR_INV_PACKET); goto leave; } mode = iobuf_get_noeof (inp); if (pktlen) pktlen--; namelen = iobuf_get_noeof (inp); if (pktlen) pktlen--; /* Note that namelen will never exceed 255 bytes. */ pt = pkt->pkt.plaintext = xmalloc (sizeof *pkt->pkt.plaintext + namelen - 1); pt->new_ctb = new_ctb; pt->mode = mode; pt->namelen = namelen; pt->is_partial = partial; if (pktlen) { for (i = 0; pktlen > 4 && i < namelen; pktlen--, i++) pt->name[i] = iobuf_get_noeof (inp); } else { for (i = 0; i < namelen; i++) if ((c = iobuf_get (inp)) == -1) break; else pt->name[i] = c; } pt->timestamp = read_32 (inp); if (pktlen) pktlen -= 4; pt->len = pktlen; pt->buf = inp; pktlen = 0; if (list_mode) { es_fprintf (listfp, ":literal data packet:\n" "\tmode %c (%X), created %lu, name=\"", mode >= ' ' && mode < 'z' ? mode : '?', mode, (ulong) pt->timestamp); for (p = pt->name, i = 0; i < namelen; p++, i++) { if (*p >= ' ' && *p <= 'z') es_putc (*p, listfp); else es_fprintf (listfp, "\\x%02x", *p); } es_fprintf (listfp, "\",\n\traw data: "); if (partial) es_fprintf (listfp, "unknown length\n"); else es_fprintf (listfp, "%lu bytes\n", (ulong) pt->len); } leave: return rc; } static int parse_compressed (IOBUF inp, int pkttype, unsigned long pktlen, PACKET * pkt, int new_ctb) { PKT_compressed *zd; /* PKTLEN is here 0, but data follows (this should be the last object in a file or the compress algorithm should know the length). */ (void) pkttype; (void) pktlen; zd = pkt->pkt.compressed = xmalloc (sizeof *pkt->pkt.compressed); zd->algorithm = iobuf_get_noeof (inp); zd->len = 0; /* not used */ zd->new_ctb = new_ctb; zd->buf = inp; if (list_mode) es_fprintf (listfp, ":compressed packet: algo=%d\n", zd->algorithm); return 0; } static int parse_encrypted (IOBUF inp, int pkttype, unsigned long pktlen, PACKET * pkt, int new_ctb, int partial) { int rc = 0; PKT_encrypted *ed; unsigned long orig_pktlen = pktlen; ed = pkt->pkt.encrypted = xmalloc (sizeof *pkt->pkt.encrypted); /* ed->len is set below. */ ed->extralen = 0; /* Unknown here; only used in build_packet. */ ed->buf = NULL; ed->new_ctb = new_ctb; ed->is_partial = partial; if (pkttype == PKT_ENCRYPTED_MDC) { /* Fixme: add some pktlen sanity checks. */ int version; version = iobuf_get_noeof (inp); if (orig_pktlen) pktlen--; if (version != 1) { log_error ("encrypted_mdc packet with unknown version %d\n", version); /*skip_rest(inp, pktlen); should we really do this? */ rc = gpg_error (GPG_ERR_INV_PACKET); goto leave; } ed->mdc_method = DIGEST_ALGO_SHA1; } else ed->mdc_method = 0; /* A basic sanity check. We need at least an 8 byte IV plus the 2 detection bytes. Note that we don't known the algorithm and thus we may only check against the minimum blocksize. */ if (orig_pktlen && pktlen < 10) { /* Actually this is blocksize+2. */ log_error ("packet(%d) too short\n", pkttype); rc = G10ERR_INVALID_PACKET; iobuf_skip_rest (inp, pktlen, partial); goto leave; } /* Store the remaining length of the encrypted data (i.e. without the MDC version number but with the IV etc.). This value is required during decryption. */ ed->len = pktlen; if (list_mode) { if (orig_pktlen) es_fprintf (listfp, ":encrypted data packet:\n\tlength: %lu\n", orig_pktlen); else es_fprintf (listfp, ":encrypted data packet:\n\tlength: unknown\n"); if (ed->mdc_method) es_fprintf (listfp, "\tmdc_method: %d\n", ed->mdc_method); } ed->buf = inp; leave: return rc; } /* Note, that this code is not anymore used in real life because the MDC checking is now done right after the decryption in decrypt_data. */ static int parse_mdc (IOBUF inp, int pkttype, unsigned long pktlen, PACKET * pkt, int new_ctb) { int rc = 0; PKT_mdc *mdc; byte *p; (void) pkttype; mdc = pkt->pkt.mdc = xmalloc (sizeof *pkt->pkt.mdc); if (list_mode) es_fprintf (listfp, ":mdc packet: length=%lu\n", pktlen); if (!new_ctb || pktlen != 20) { log_error ("mdc_packet with invalid encoding\n"); rc = gpg_error (GPG_ERR_INV_PACKET); goto leave; } p = mdc->hash; for (; pktlen; pktlen--, p++) *p = iobuf_get_noeof (inp); leave: return rc; } /* * This packet is internally generated by us (ibn armor.c) to transfer * some information to the lower layer. To make sure that this packet * is really a GPG faked one and not one comming from outside, we * first check that there is a unique tag in it. * * The format of such a control packet is: * n byte session marker * 1 byte control type CTRLPKT_xxxxx * m byte control data */ static int parse_gpg_control (IOBUF inp, int pkttype, unsigned long pktlen, PACKET * packet, int partial) { byte *p; const byte *sesmark; size_t sesmarklen; int i; (void) pkttype; if (list_mode) es_fprintf (listfp, ":packet 63: length %lu ", pktlen); sesmark = get_session_marker (&sesmarklen); if (pktlen < sesmarklen + 1) /* 1 is for the control bytes */ goto skipit; for (i = 0; i < sesmarklen; i++, pktlen--) { if (sesmark[i] != iobuf_get_noeof (inp)) goto skipit; } if (pktlen > 4096) goto skipit; /* Definitely too large. We skip it to avoid an overflow in the malloc. */ if (list_mode) puts ("- gpg control packet"); packet->pkt.gpg_control = xmalloc (sizeof *packet->pkt.gpg_control + pktlen - 1); packet->pkt.gpg_control->control = iobuf_get_noeof (inp); pktlen--; packet->pkt.gpg_control->datalen = pktlen; p = packet->pkt.gpg_control->data; for (; pktlen; pktlen--, p++) *p = iobuf_get_noeof (inp); return 0; skipit: if (list_mode) { int c; i = 0; es_fprintf (listfp, "- private (rest length %lu)\n", pktlen); if (partial) { while ((c = iobuf_get (inp)) != -1) dump_hex_line (c, &i); } else { for (; pktlen; pktlen--) { dump_hex_line ((c = iobuf_get (inp)), &i); if (c == -1) break; } } es_putc ('\n', listfp); } iobuf_skip_rest (inp, pktlen, 0); return gpg_error (GPG_ERR_INV_PACKET); } /* Create a GPG control packet to be used internally as a placeholder. */ PACKET * create_gpg_control (ctrlpkttype_t type, const byte * data, size_t datalen) { PACKET *packet; byte *p; packet = xmalloc (sizeof *packet); init_packet (packet); packet->pkttype = PKT_GPG_CONTROL; packet->pkt.gpg_control = xmalloc (sizeof *packet->pkt.gpg_control + datalen - 1); packet->pkt.gpg_control->control = type; packet->pkt.gpg_control->datalen = datalen; p = packet->pkt.gpg_control->data; for (; datalen; datalen--, p++) *p = *data++; return packet; } diff --git a/g10/pkglue.c b/g10/pkglue.c index 7e50a1c3d..67d2efd39 100644 --- a/g10/pkglue.c +++ b/g10/pkglue.c @@ -1,352 +1,364 @@ /* pkglue.c - public key operations glue code - * Copyright (C) 2000, 2003, 2010 Free Software Foundation, Inc. + * 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 #include "gpg.h" #include "util.h" #include "pkglue.h" #include "main.h" #include "options.h" /* FIXME: Better chnage the fucntion 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); assert (list); data = gcry_sexp_nth_mpi (list, 1, mpifmt); assert (data); gcry_sexp_release (list); return data; } /**************** * Emulate our old PK interface here - sometime in the future we might * change the internal design to directly fit to libgcrypt. */ int -pk_verify (int algo, gcry_mpi_t hash, gcry_mpi_t *data, gcry_mpi_t *pkey) +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; - const int pkalgo = map_pk_openpgp_to_gcry (algo); - int is_ed25519 = 0; /* Make a sexp from pkey. */ - if (pkalgo == GCRY_PK_DSA) + 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 == GCRY_PK_ELG || pkalgo == GCRY_PK_ELG_E) + 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 == GCRY_PK_RSA || pkalgo == GCRY_PK_RSA_S) + 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 == GCRY_PK_ECDSA) /* Same as GCRY_PK_ECDH */ + else if (pkalgo == PUBKEY_ALGO_ECDSA) { - is_ed25519 = openpgp_oid_is_ed25519 (pkey[0]); - if (is_ed25519) - rc = gcry_sexp_build (&s_pkey, NULL, - "(public-key(ecc(curve Ed25519)" - "(flags eddsa)(q%m)))", - pkey[1]); + 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 { - 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); - } + rc = gcry_sexp_build (&s_pkey, NULL, + "(public-key(ecc(curve %s)" + "(flags eddsa)(q%m)))", + curve, pkey[1]); + xfree (curve); } } else return GPG_ERR_PUBKEY_ALGO; if (rc) BUG (); /* gcry_sexp_build should never fail. */ /* Put hash into a S-Exp s_hash. */ - if (is_ed25519) + if (pkalgo == PUBKEY_ALGO_EDDSA) { if (gcry_sexp_build (&s_hash, NULL, "(data(flags eddsa)(hash-algo sha512)(value %m))", 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 == GCRY_PK_DSA) + 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 == GCRY_PK_ECDSA) + else if (pkalgo == PUBKEY_ALGO_ECDSA) { if (!data[0] || !data[1]) rc = gpg_error (GPG_ERR_BAD_MPI); - else if (is_ed25519) - rc = gcry_sexp_build (&s_sig, NULL, - "(sig-val(eddsa(r%M)(s%M)))", data[0], data[1]); else rc = gcry_sexp_build (&s_sig, NULL, "(sig-val(ecdsa(r%m)(s%m)))", data[0], data[1]); } - else if (pkalgo == GCRY_PK_ELG || pkalgo == GCRY_PK_ELG_E) + else if (pkalgo == PUBKEY_ALGO_EDDSA) + { + if (!data[0] || !data[1]) + rc = gpg_error (GPG_ERR_BAD_MPI); + else + rc = gcry_sexp_build (&s_sig, NULL, + "(sig-val(eddsa(r%M)(s%M)))", data[0], data[1]); + } + 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 == GCRY_PK_RSA || pkalgo == GCRY_PK_RSA_S) + 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 (int algo, gcry_mpi_t *resarr, gcry_mpi_t data, +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, s_data, s_pkey; int rc; /* Make a sexp from pkey. */ - if (algo == GCRY_PK_ELG || algo == GCRY_PK_ELG_E) + 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 || gcry_sexp_build (&s_data, NULL, "%m", data)) BUG (); } - else if (algo == GCRY_PK_RSA || algo == GCRY_PK_RSA_E) + 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 || gcry_sexp_build (&s_data, NULL, "%m", data)) BUG (); } else if (algo == PUBKEY_ALGO_ECDH) { gcry_mpi_t k; char *curve; rc = pk_ecdh_generate_ephemeral_key (pkey, &k); if (rc) return rc; curve = openpgp_oid_to_str (pkey[0]); if (!curve) rc = gpg_error_from_syserror (); else { /* Now use the ephemeral secret to compute the shared point. */ rc = gcry_sexp_build (&s_pkey, NULL, "(public-key(ecdh(curve%s)(q%m)))", curve, pkey[1]); xfree (curve); /* FIXME: Take care of RC. */ /* Put K into a simplified S-expression. */ if (rc || gcry_sexp_build (&s_data, NULL, "%m", k)) BUG (); } } else return gpg_error (GPG_ERR_PUBKEY_ALGO); /* Pass it to libgcrypt. */ rc = gcry_pk_encrypt (&s_ciph, s_data, s_pkey); gcry_sexp_release (s_data); gcry_sexp_release (s_pkey); if (rc) ; else if (algo == PUBKEY_ALGO_ECDH) { gcry_mpi_t shared, public, result; byte fp[MAX_FINGERPRINT_LEN]; size_t fpn; /* Get the shared point and the ephemeral public key. */ shared = get_mpi_from_sexp (s_ciph, "s", GCRYMPI_FMT_USG); public = get_mpi_from_sexp (s_ciph, "e", GCRYMPI_FMT_USG); gcry_sexp_release (s_ciph); s_ciph = NULL; if (DBG_CIPHER) { 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); else rc = pk_ecdh_encrypt_with_shared_point (1 /*=encrypton*/, shared, fp, data, pkey, &result); gcry_mpi_release (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 (algo != GCRY_PK_RSA && algo != GCRY_PK_RSA_E) + 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 (int algo, gcry_mpi_t *skey) +pk_check_secret_key (pubkey_algo_t pkalgo, gcry_mpi_t *skey) { gcry_sexp_t s_skey; int rc; - const int gcry_pkalgo = map_pk_openpgp_to_gcry( algo ); - if (gcry_pkalgo == GCRY_PK_DSA) + 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 (gcry_pkalgo == GCRY_PK_ELG || gcry_pkalgo == GCRY_PK_ELG_E) + 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 (gcry_pkalgo == GCRY_PK_RSA - || gcry_pkalgo == GCRY_PK_RSA_S || gcry_pkalgo == GCRY_PK_RSA_E) + 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 (gcry_pkalgo == GCRY_PK_ECDSA || gcry_pkalgo == GCRY_PK_ECDH) + else if (pkalgo == PUBKEY_ALGO_ECDSA || pkalgo == PUBKEY_ALGO_ECDH) { - if (openpgp_oid_is_ed25519 (skey[0])) + 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 Ed25519)" - "(flags eddsa)(q%m)(d%m)))", - skey[1], skey[2]); + "(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 { - 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(ecdsa(curve%s)(q%m)(d%m)))", - curve, skey[1], skey[2]); - xfree (curve); - } + rc = gcry_sexp_build (&s_skey, NULL, + "(private-key(ecc(curve %s)" + "(flags eddsa)(q%m)(d%m)))", + 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/pkglue.h b/g10/pkglue.h index 48bfbb5e0..ba1097c2e 100644 --- a/g10/pkglue.h +++ b/g10/pkglue.h @@ -1,50 +1,50 @@ /* pkglue.h - public key operations definitions * Copyright (C) 2003, 2010 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 . */ #ifndef GNUPG_G10_PKGLUE_H #define GNUPG_G10_PKGLUE_H #include "packet.h" /* For PKT_public_key. */ /*-- pkglue.c --*/ gcry_mpi_t get_mpi_from_sexp (gcry_sexp_t sexp, const char *item, int mpifmt); -int pk_verify (int algo, gcry_mpi_t hash, gcry_mpi_t *data, +int pk_verify (pubkey_algo_t algo, gcry_mpi_t hash, gcry_mpi_t *data, gcry_mpi_t *pkey); -int pk_encrypt (int algo, gcry_mpi_t *resarr, gcry_mpi_t data, +int pk_encrypt (pubkey_algo_t algo, gcry_mpi_t *resarr, gcry_mpi_t data, PKT_public_key *pk, gcry_mpi_t *pkey); -int pk_check_secret_key (int algo, gcry_mpi_t *skey); +int pk_check_secret_key (pubkey_algo_t algo, gcry_mpi_t *skey); /*-- ecdh.c --*/ gcry_mpi_t pk_ecdh_default_params (unsigned int qbits); gpg_error_t pk_ecdh_generate_ephemeral_key (gcry_mpi_t *pkey, gcry_mpi_t *r_k); gpg_error_t pk_ecdh_encrypt_with_shared_point /* */ (int is_encrypt, gcry_mpi_t shared_mpi, const byte pk_fp[MAX_FINGERPRINT_LEN], gcry_mpi_t data, gcry_mpi_t *pkey, gcry_mpi_t *out); int pk_ecdh_encrypt (gcry_mpi_t *resarr, const byte pk_fp[MAX_FINGERPRINT_LEN], gcry_mpi_t data, gcry_mpi_t * pkey); int pk_ecdh_decrypt (gcry_mpi_t *result, const byte sk_fp[MAX_FINGERPRINT_LEN], gcry_mpi_t data, gcry_mpi_t shared, gcry_mpi_t * skey); #endif /*GNUPG_G10_PKGLUE_H*/ diff --git a/g10/pubkey-enc.c b/g10/pubkey-enc.c index ab18ed716..042a25598 100644 --- a/g10/pubkey-enc.c +++ b/g10/pubkey-enc.c @@ -1,430 +1,431 @@ /* pubkey-enc.c - Process a public key encoded packet. * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2006, 2009, * 2010 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 "util.h" #include "packet.h" #include "keydb.h" #include "trustdb.h" #include "status.h" #include "options.h" #include "main.h" #include "i18n.h" #include "pkglue.h" #include "call-agent.h" static gpg_error_t get_it (PKT_pubkey_enc *k, DEK *dek, PKT_public_key *sk, u32 *keyid); /* Check that the given algo is mentioned in one of the valid user-ids. */ static int is_algo_in_prefs (kbnode_t keyblock, preftype_t type, int algo) { kbnode_t k; for (k = keyblock; k; k = k->next) { if (k->pkt->pkttype == PKT_USER_ID) { PKT_user_id *uid = k->pkt->pkt.user_id; prefitem_t *prefs = uid->prefs; if (uid->created && prefs && !uid->is_revoked && !uid->is_expired) { for (; prefs->type; prefs++) if (prefs->type == type && prefs->value == algo) return 1; } } } return 0; } /* * Get the session key from a pubkey enc packet and return it in DEK, * which should have been allocated in secure memory by the caller. */ gpg_error_t get_session_key (PKT_pubkey_enc * k, DEK * dek) { PKT_public_key *sk = NULL; int rc; if (DBG_CLOCK) log_clock ("get_session_key enter"); rc = openpgp_pk_test_algo2 (k->pubkey_algo, PUBKEY_USAGE_ENC); if (rc) goto leave; if ((k->keyid[0] || k->keyid[1]) && !opt.try_all_secrets) { sk = xmalloc_clear (sizeof *sk); sk->pubkey_algo = k->pubkey_algo; /* We want a pubkey with this algo. */ if (!(rc = get_seckey (sk, k->keyid))) rc = get_it (k, dek, sk, k->keyid); } else if (opt.skip_hidden_recipients) rc = gpg_error (GPG_ERR_NO_SECKEY); else /* Anonymous receiver: Try all available secret keys. */ { void *enum_context = NULL; u32 keyid[2]; for (;;) { free_public_key (sk); sk = xmalloc_clear (sizeof *sk); rc = enum_secret_keys (&enum_context, sk); if (rc) { rc = G10ERR_NO_SECKEY; break; } if (sk->pubkey_algo != k->pubkey_algo) continue; if (!(sk->pubkey_usage & PUBKEY_USAGE_ENC)) continue; keyid_from_pk (sk, keyid); if (!opt.quiet) log_info (_("anonymous recipient; trying secret key %s ...\n"), keystr (keyid)); rc = get_it (k, dek, sk, keyid); if (!rc) { if (!opt.quiet) log_info (_("okay, we are the anonymous recipient.\n")); break; } else if (gpg_err_code (rc) == GPG_ERR_FULLY_CANCELED) break; /* Don't try any more secret keys. */ } enum_secret_keys (&enum_context, NULL); /* free context */ } leave: free_public_key (sk); if (DBG_CLOCK) log_clock ("get_session_key leave"); return rc; } static gpg_error_t get_it (PKT_pubkey_enc *enc, DEK *dek, PKT_public_key *sk, u32 *keyid) { gpg_error_t err; byte *frame = NULL; unsigned int n; size_t nframe; u16 csum, csum2; int padding; gcry_sexp_t s_data; char *desc; char *keygrip; byte fp[MAX_FINGERPRINT_LEN]; size_t fpn; - const int pkalgo = map_pk_openpgp_to_gcry (sk->pubkey_algo); if (DBG_CLOCK) log_clock ("decryption start"); /* Get the keygrip. */ err = hexkeygrip_from_pk (sk, &keygrip); if (err) goto leave; /* Convert the data to an S-expression. */ - if (pkalgo == GCRY_PK_ELG || pkalgo == GCRY_PK_ELG_E) + if (sk->pubkey_algo == PUBKEY_ALGO_ELGAMAL + || sk->pubkey_algo == PUBKEY_ALGO_ELGAMAL_E) { if (!enc->data[0] || !enc->data[1]) err = gpg_error (GPG_ERR_BAD_MPI); else err = gcry_sexp_build (&s_data, NULL, "(enc-val(elg(a%m)(b%m)))", enc->data[0], enc->data[1]); } - else if (pkalgo == GCRY_PK_RSA || pkalgo == GCRY_PK_RSA_E) + else if (sk->pubkey_algo == PUBKEY_ALGO_RSA + || sk->pubkey_algo == PUBKEY_ALGO_RSA_E) { if (!enc->data[0]) err = gpg_error (GPG_ERR_BAD_MPI); else err = gcry_sexp_build (&s_data, NULL, "(enc-val(rsa(a%m)))", enc->data[0]); } - else if (pkalgo == GCRY_PK_ECDH) + else if (sk->pubkey_algo == PUBKEY_ALGO_ECDH) { if (!enc->data[0] || !enc->data[1]) err = gpg_error (GPG_ERR_BAD_MPI); else err = gcry_sexp_build (&s_data, NULL, "(enc-val(ecdh(s%m)(e%m)))", enc->data[0], enc->data[1]); } else err = gpg_error (GPG_ERR_BUG); if (err) goto leave; if (sk->pubkey_algo == PUBKEY_ALGO_ECDH) { fingerprint_from_pk (sk, fp, &fpn); assert (fpn == 20); } /* Decrypt. */ desc = gpg_format_keydesc (sk, 0, 1); err = agent_pkdecrypt (NULL, keygrip, desc, sk->keyid, sk->main_keyid, sk->pubkey_algo, s_data, &frame, &nframe, &padding); xfree (desc); gcry_sexp_release (s_data); if (err) goto leave; /* Now get the DEK (data encryption key) from the frame * * Old versions encode the DEK in in this format (msb is left): * * 0 1 DEK(16 bytes) CSUM(2 bytes) 0 RND(n bytes) 2 * * Later versions encode the DEK like this: * * 0 2 RND(n bytes) 0 A DEK(k bytes) CSUM(2 bytes) * * (mpi_get_buffer already removed the leading zero). * * RND are non-zero randow bytes. * A is the cipher algorithm * DEK is the encryption key (session key) with length k * CSUM */ if (DBG_CIPHER) log_printhex ("DEK frame:", frame, nframe); n = 0; if (sk->pubkey_algo == PUBKEY_ALGO_ECDH) { gcry_mpi_t shared_mpi; gcry_mpi_t decoded; /* At the beginning the frame are the bytes of shared point MPI. */ err = gcry_mpi_scan (&shared_mpi, GCRYMPI_FMT_USG, frame, nframe, NULL); if (err) { err = gpg_error (GPG_ERR_WRONG_SECKEY); goto leave; } err = pk_ecdh_decrypt (&decoded, fp, enc->data[1]/*encr data as an MPI*/, shared_mpi, sk->pkey); mpi_release (shared_mpi); if(err) goto leave; /* Reuse NFRAME, which size is sufficient to include the session key. */ err = gcry_mpi_print (GCRYMPI_FMT_USG, frame, nframe, &nframe, decoded); mpi_release (decoded); if (err) goto leave; /* Now the frame are the bytes decrypted but padded session key. */ /* Allow double padding for the benefit of DEK size concealment. Higher than this is wasteful. */ if (!nframe || frame[nframe-1] > 8*2 || nframe <= 8 || frame[nframe-1] > nframe) { err = gpg_error (GPG_ERR_WRONG_SECKEY); goto leave; } nframe -= frame[nframe-1]; /* Remove padding. */ assert (!n); /* (used just below) */ } else { if (padding) { if (n + 7 > nframe) { err = gpg_error (GPG_ERR_WRONG_SECKEY); goto leave; } if (frame[n] == 1 && frame[nframe - 1] == 2) { log_info (_("old encoding of the DEK is not supported\n")); err = gpg_error (GPG_ERR_CIPHER_ALGO); goto leave; } if (frame[n] != 2) /* Something went wrong. */ { err = gpg_error (GPG_ERR_WRONG_SECKEY); goto leave; } for (n++; n < nframe && frame[n]; n++) /* Skip the random bytes. */ ; n++; /* Skip the zero byte. */ } } if (n + 4 > nframe) { err = gpg_error (GPG_ERR_WRONG_SECKEY); goto leave; } dek->keylen = nframe - (n + 1) - 2; dek->algo = frame[n++]; err = openpgp_cipher_test_algo (dek->algo); if (err) { if (!opt.quiet && gpg_err_code (err) == GPG_ERR_CIPHER_ALGO) { log_info (_("cipher algorithm %d%s is unknown or disabled\n"), dek->algo, dek->algo == CIPHER_ALGO_IDEA ? " (IDEA)" : ""); } dek->algo = 0; goto leave; } if (dek->keylen != openpgp_cipher_get_algo_keylen (dek->algo)) { err = gpg_error (GPG_ERR_WRONG_SECKEY); goto leave; } /* Copy the key to DEK and compare the checksum. */ csum = frame[nframe - 2] << 8; csum |= frame[nframe - 1]; memcpy (dek->key, frame + n, dek->keylen); for (csum2 = 0, n = 0; n < dek->keylen; n++) csum2 += dek->key[n]; if (csum != csum2) { err = gpg_error (GPG_ERR_WRONG_SECKEY); goto leave; } if (DBG_CLOCK) log_clock ("decryption ready"); if (DBG_CIPHER) log_printhex ("DEK is:", dek->key, dek->keylen); /* Check that the algo is in the preferences and whether it has expired. */ { PKT_public_key *pk = NULL; KBNODE pkb = get_pubkeyblock (keyid); if (!pkb) { err = -1; log_error ("oops: public key not found for preference check\n"); } else if (pkb->pkt->pkt.public_key->selfsigversion > 3 && dek->algo != CIPHER_ALGO_3DES && !opt.quiet && !is_algo_in_prefs (pkb, PREFTYPE_SYM, dek->algo)) log_info (_("WARNING: cipher algorithm %s not found in recipient" " preferences\n"), openpgp_cipher_algo_name (dek->algo)); if (!err) { KBNODE k; for (k = pkb; k; k = k->next) { if (k->pkt->pkttype == PKT_PUBLIC_KEY || k->pkt->pkttype == PKT_PUBLIC_SUBKEY) { u32 aki[2]; keyid_from_pk (k->pkt->pkt.public_key, aki); if (aki[0] == keyid[0] && aki[1] == keyid[1]) { pk = k->pkt->pkt.public_key; break; } } } if (!pk) BUG (); if (pk->expiredate && pk->expiredate <= make_timestamp ()) { log_info (_("NOTE: secret key %s expired at %s\n"), keystr (keyid), asctimestamp (pk->expiredate)); } } if (pk && pk->flags.revoked) { log_info (_("NOTE: key has been revoked")); log_printf ("\n"); show_revocation_reason (pk, 1); } release_kbnode (pkb); err = 0; } leave: xfree (frame); xfree (keygrip); return err; } /* * Get the session key from the given string. * String is supposed to be formatted as this: * : */ gpg_error_t get_override_session_key (DEK *dek, const char *string) { const char *s; int i; if (!string) return G10ERR_BAD_KEY; dek->algo = atoi (string); if (dek->algo < 1) return G10ERR_BAD_KEY; if (!(s = strchr (string, ':'))) return G10ERR_BAD_KEY; s++; for (i = 0; i < DIM (dek->key) && *s; i++, s += 2) { int c = hextobyte (s); if (c == -1) return G10ERR_BAD_KEY; dek->key[i] = c; } if (*s) return G10ERR_BAD_KEY; dek->keylen = i; return 0; } diff --git a/g10/seskey.c b/g10/seskey.c index 7d0429278..410f0bfa6 100644 --- a/g10/seskey.c +++ b/g10/seskey.c @@ -1,351 +1,351 @@ /* seskey.c - make sesssion keys etc. * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, * 2006, 2009, 2010 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 "util.h" #include "options.h" #include "main.h" #include "i18n.h" /**************** * Make a session key and put it into DEK */ void make_session_key( DEK *dek ) { gcry_cipher_hd_t chd; int i, rc; dek->keylen = openpgp_cipher_get_algo_keylen (dek->algo); if (openpgp_cipher_open (&chd, dek->algo, GCRY_CIPHER_MODE_CFB, (GCRY_CIPHER_SECURE | (dek->algo >= 100 ? 0 : GCRY_CIPHER_ENABLE_SYNC))) ) BUG(); gcry_randomize (dek->key, dek->keylen, GCRY_STRONG_RANDOM ); for (i=0; i < 16; i++ ) { rc = gcry_cipher_setkey (chd, dek->key, dek->keylen); if (!rc) { gcry_cipher_close (chd); return; } if (gpg_err_code (rc) != GPG_ERR_WEAK_KEY) BUG(); log_info(_("weak key created - retrying\n") ); /* Renew the session key until we get a non-weak key. */ gcry_randomize (dek->key, dek->keylen, GCRY_STRONG_RANDOM); } log_fatal (_("cannot avoid weak key for symmetric cipher; " "tried %d times!\n"), i); } /**************** * Encode the session key. NBITS is the number of bits which should be used * for packing the session key. * returns: A mpi with the session key (caller must free) */ gcry_mpi_t encode_session_key (int openpgp_pk_algo, DEK *dek, unsigned int nbits) { size_t nframe = (nbits+7) / 8; byte *p; byte *frame; int i,n; u16 csum; gcry_mpi_t a; if (DBG_CIPHER) log_debug ("encode_session_key: encoding %d byte DEK", dek->keylen); csum = 0; for (p = dek->key, i=0; i < dek->keylen; i++) csum += *p++; /* Shortcut for ECDH. It's padding is minimal to simply make the output be a multiple of 8 bytes. */ if (openpgp_pk_algo == PUBKEY_ALGO_ECDH) { /* Pad to 8 byte granulatiry; the padding byte is the number of * padded bytes. * * A DEK(k bytes) CSUM(2 bytes) 0x 0x 0x 0x ... 0x * +---- x times ---+ */ nframe = (( 1 + dek->keylen + 2 /* The value so far is always odd. */ + 7 ) & (~7)); /* alg+key+csum fit and the size is congruent to 8. */ assert (!(nframe%8) && nframe > 1 + dek->keylen + 2 ); frame = xmalloc_secure (nframe); n = 0; frame[n++] = dek->algo; memcpy (frame+n, dek->key, dek->keylen); n += dek->keylen; frame[n++] = csum >> 8; frame[n++] = csum; i = nframe - n; /* Number of padded bytes. */ memset (frame+n, i, i); /* Use it as the value of each padded byte. */ assert (n+i == nframe); if (DBG_CIPHER) log_debug ("encode_session_key: " "[%d] %02x %02x %02x ... %02x %02x %02x\n", (int) nframe, frame[0], frame[1], frame[2], frame[nframe-3], frame[nframe-2], frame[nframe-1]); if (gcry_mpi_scan (&a, GCRYMPI_FMT_USG, frame, nframe, &nframe)) BUG(); xfree(frame); return a; } /* The current limitation is that we can only use a session key * whose length is a multiple of BITS_PER_MPI_LIMB * I think we can live with that. */ if (dek->keylen + 7 > nframe || !nframe) log_bug ("can't encode a %d bit key in a %d bits frame\n", dek->keylen*8, nbits ); /* We encode the session key in this way: * * 0 2 RND(n bytes) 0 A DEK(k bytes) CSUM(2 bytes) * * (But how can we store the leading 0 - the external representaion * of MPIs doesn't allow leading zeroes =:-) * * RND are non-zero random bytes. * A is the cipher algorithm * DEK is the encryption key (session key) length k depends on the * cipher algorithm (20 is used with blowfish160). * CSUM is the 16 bit checksum over the DEK */ frame = xmalloc_secure( nframe ); n = 0; frame[n++] = 0; frame[n++] = 2; i = nframe - 6 - dek->keylen; assert( i > 0 ); p = gcry_random_bytes_secure (i, GCRY_STRONG_RANDOM); /* Replace zero bytes by new values. */ for (;;) { int j, k; byte *pp; /* Count the zero bytes. */ for (j=k=0; j < i; j++ ) if (!p[j]) k++; if (!k) break; /* Okay: no zero bytes. */ k += k/128 + 3; /* Better get some more. */ pp = gcry_random_bytes_secure (k, GCRY_STRONG_RANDOM); for (j=0; j < i && k ;) { if (!p[j]) p[j] = pp[--k]; if (p[j]) j++; } xfree (pp); } memcpy (frame+n, p, i); xfree (p); n += i; frame[n++] = 0; frame[n++] = dek->algo; memcpy (frame+n, dek->key, dek->keylen ); n += dek->keylen; frame[n++] = csum >>8; frame[n++] = csum; assert (n == nframe); if (gcry_mpi_scan( &a, GCRYMPI_FMT_USG, frame, n, &nframe)) BUG(); xfree (frame); return a; } static gcry_mpi_t do_encode_md( gcry_md_hd_t md, int algo, size_t len, unsigned nbits, const byte *asn, size_t asnlen ) { size_t nframe = (nbits+7) / 8; byte *frame; int i,n; gcry_mpi_t a; if( len + asnlen + 4 > nframe ) log_bug ("can't encode a %d bit MD into a %d bits frame, algo=%d\n", (int)(len*8), (int)nbits, algo); /* We encode the MD in this way: * * 0 1 PAD(n bytes) 0 ASN(asnlen bytes) MD(len bytes) * * PAD consists of FF bytes. */ frame = gcry_md_is_secure (md)? xmalloc_secure (nframe) : xmalloc (nframe); n = 0; frame[n++] = 0; frame[n++] = 1; /* block type */ i = nframe - len - asnlen -3 ; assert( i > 1 ); memset( frame+n, 0xff, i ); n += i; frame[n++] = 0; memcpy( frame+n, asn, asnlen ); n += asnlen; memcpy( frame+n, gcry_md_read (md, algo), len ); n += len; assert( n == nframe ); if (gcry_mpi_scan( &a, GCRYMPI_FMT_USG, frame, n, &nframe )) BUG(); xfree(frame); /* Note that PGP before version 2.3 encoded the MD as: * * 0 1 MD(16 bytes) 0 PAD(n bytes) 1 * * The MD is always 16 bytes here because it's always MD5. We do * not support pre-v2.3 signatures, but I'm including this comment * so the information is easily found in the future. */ return a; } /**************** * Encode a message digest into an MPI. * If it's for a DSA signature, make sure that the hash is large * enough to fill up q. If the hash is too big, take the leftmost * bits. */ gcry_mpi_t encode_md_value (PKT_public_key *pk, gcry_md_hd_t md, int hash_algo) { gcry_mpi_t frame; - int pkalgo; size_t mdlen; assert (hash_algo); assert (pk); - pkalgo = map_pk_openpgp_to_gcry (pk->pubkey_algo); - - if (pkalgo == GCRY_PK_ECDSA && openpgp_oid_is_ed25519 (pk->pkey[0])) + if (pk->pubkey_algo == PUBKEY_ALGO_EDDSA) { + /* EdDSA signs data of arbitrary length. Thus no special + treatment is required. */ frame = gcry_mpi_set_opaque_copy (NULL, gcry_md_read (md, hash_algo), 8*gcry_md_get_algo_dlen (hash_algo)); } - else if (pkalgo == GCRY_PK_DSA || pkalgo == GCRY_PK_ECDSA) + else if (pk->pubkey_algo == PUBKEY_ALGO_DSA + || pk->pubkey_algo == PUBKEY_ALGO_ECDSA) { /* It's a DSA signature, so find out the size of q. */ size_t qbits = gcry_mpi_get_nbits (pk->pkey[1]); /* pkey[1] is Q for ECDSA, which is an uncompressed point, i.e. 04 */ - if (pkalgo == GCRY_PK_ECDSA) + if (pk->pubkey_algo == PUBKEY_ALGO_ECDSA) qbits = ecdsa_qbits_from_Q (qbits); /* Make sure it is a multiple of 8 bits. */ - if ((qbits%8)) { log_error(_("DSA requires the hash length to be a" " multiple of 8 bits\n")); return NULL; } /* Don't allow any q smaller than 160 bits. This might need a revisit as the DSA2 design firms up, but for now, 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 %s uses an unsafe (%zu bit) hash\n"), - gcry_pk_algo_name (pkalgo), keystr_from_pk (pk), qbits); + openpgp_pk_algo_name (pk->pubkey_algo), + keystr_from_pk (pk), qbits); return NULL; } /* ECDSA 521 is special has it is larger than the largest hash we have (SHA-512). Thus we chnage the size for further processing to 512. */ - if (pkalgo == GCRY_PK_ECDSA && qbits > 512) + if (pk->pubkey_algo == PUBKEY_ALGO_ECDSA && qbits > 512) qbits = 512; /* Check if we're too short. Too long is safe as we'll automatically left-truncate. */ mdlen = gcry_md_get_algo_dlen (hash_algo); if (mdlen < qbits/8) { log_error (_("%s key %s requires a %zu bit or larger hash " "(hash is %s)\n"), - gcry_pk_algo_name (pkalgo), - keystr_from_pk(pk), qbits, + openpgp_pk_algo_name (pk->pubkey_algo), + keystr_from_pk (pk), qbits, gcry_md_algo_name (hash_algo)); return NULL; } /* Note that we do the truncation by passing QBITS/8 as length to mpi_scan. */ if (gcry_mpi_scan (&frame, GCRYMPI_FMT_USG, gcry_md_read (md, hash_algo), qbits/8, NULL)) BUG(); } else { gpg_error_t rc; byte *asn; size_t asnlen; rc = gcry_md_algo_info (hash_algo, GCRYCTL_GET_ASNOID, NULL, &asnlen); if (rc) log_fatal ("can't get OID of digest algorithm %d: %s\n", hash_algo, gpg_strerror (rc)); asn = xtrymalloc (asnlen); if (!asn) return NULL; if ( gcry_md_algo_info (hash_algo, GCRYCTL_GET_ASNOID, asn, &asnlen) ) BUG(); frame = do_encode_md (md, hash_algo, gcry_md_get_algo_dlen (hash_algo), gcry_mpi_get_nbits (pk->pkey[0]), asn, asnlen); xfree (asn); } return frame; } diff --git a/g10/sign.c b/g10/sign.c index e4d329067..098655dce 100644 --- a/g10/sign.c +++ b/g10/sign.c @@ -1,1675 +1,1676 @@ /* 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 #include "gpg.h" #include "options.h" #include "packet.h" #include "status.h" #include "iobuf.h" #include "keydb.h" #include "util.h" #include "main.h" #include "filter.h" #include "ttyio.h" #include "trustdb.h" #include "status.h" #include "i18n.h" #include "pkglue.h" #include "sysutils.h" #include "call-agent.h" #ifdef HAVE_DOSISH_SYSTEM #define LF "\r\n" #else #define LF "\n" #endif static int recipient_digest_algo=0; /**************** * Create notations and other stuff. It is assumed that the stings in * STRLIST are already checked to contain only printable data and have * a valid NAME=VALUE format. */ static void mk_notation_policy_etc (PKT_signature *sig, PKT_public_key *pk, PKT_public_key *pksk) { const char *string; char *s=NULL; strlist_t pu=NULL; struct notation *nd=NULL; struct expando_args args; assert(sig->version>=4); memset(&args,0,sizeof(args)); args.pk=pk; args.pksk=pksk; /* notation data */ 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 *i; for(i=nd;i;i=i->next) { i->altvalue=pct_expando(i->value,&args); if(!i->altvalue) log_error(_("WARNING: unable to %%-expand notation " "(too large). Using unexpanded.\n")); } keygen_add_notations(sig,nd); for(i=nd;i;i=i->next) { xfree(i->altvalue); i->altvalue=NULL; } } /* set policy URL */ 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; s=pct_expando(string,&args); if(!s) { log_error(_("WARNING: unable to %%-expand policy URL " "(too large). Using unexpanded.\n")); s=xstrdup(string); } build_sig_subpkt(sig,SIGSUBPKT_POLICY| ((pu->flags & 1)?SIGSUBPKT_FLAG_CRITICAL:0), s,strlen(s)); xfree(s); } /* preferred keyserver URL */ if( IS_SIG(sig) && opt.sig_keyserver_url ) pu=opt.sig_keyserver_url; for(;pu;pu=pu->next) { string = pu->d; s=pct_expando(string,&args); if(!s) { log_error(_("WARNING: unable to %%-expand preferred keyserver URL" " (too large). Using unexpanded.\n")); s=xstrdup(string); } build_sig_subpkt(sig,SIGSUBPKT_PREF_KS| ((pu->flags & 1)?SIGSUBPKT_FLAG_CRITICAL:0), s,strlen(s)); xfree(s); } } /* * Helper to hash a user ID packet. */ static void hash_uid (gcry_md_hd_t md, int sigversion, const PKT_user_id *uid) { if ( sigversion >= 4 ) { byte buf[5]; 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 */ static void hash_sigversion_to_magic (gcry_md_hd_t md, const PKT_signature *sig) { if (sig->version >= 4) gcry_md_putc (md, sig->version); gcry_md_putc (md, sig->sig_class); if (sig->version < 4) { u32 a = sig->timestamp; gcry_md_putc (md, (a >> 24) & 0xff ); gcry_md_putc (md, (a >> 16) & 0xff ); gcry_md_putc (md, (a >> 8) & 0xff ); gcry_md_putc (md, a & 0xff ); } else { byte buf[6]; size_t n; 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; } /* add some magic */ buf[0] = sig->version; buf[1] = 0xff; buf[2] = n >> 24; /* hmmm, n is only 16 bit, so this is always 0 */ buf[3] = n >> 16; buf[4] = n >> 8; buf[5] = n; gcry_md_write (md, buf, 6); } } /* Perform the sign operation. If CACHE_NONCE is given the agent is advised to use that cached passphrase fro the key. */ static int do_sign (PKT_public_key *pksk, PKT_signature *sig, gcry_md_hd_t md, int mdalgo, const char *cache_nonce) { gpg_error_t err; gcry_mpi_t frame; byte *dp; char *hexgrip; if (pksk->timestamp > sig->timestamp ) { ulong d = pksk->timestamp - sig->timestamp; 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) return gpg_error (GPG_ERR_TIME_CONFLICT); } print_pubkey_algo_note (pksk->pubkey_algo); if (!mdalgo) mdalgo = gcry_md_get_algo (md); 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]; sig->data[0] = NULL; sig->data[1] = NULL; err = hexkeygrip_from_pk (pksk, &hexgrip); if (!err) { char *desc; gcry_sexp_t s_sigval; desc = gpg_format_keydesc (pksk, 0, 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 (openpgp_oid_is_ed25519 (pksk->pkey[0])) { sig->data[0] = get_mpi_from_sexp (s_sigval, "r", GCRYMPI_FMT_OPAQUE); sig->data[1] = get_mpi_from_sexp (s_sigval, "s", GCRYMPI_FMT_OPAQUE); } 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); /* 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. */ if (!err && !opt.no_sig_create_check) { PKT_public_key *pk = xmalloc_clear (sizeof *pk); if (get_pubkey (pk, sig->keyid )) err = gpg_error (GPG_ERR_NO_PUBKEY); else { frame = encode_md_value (pk, md, sig->digest_algo ); if (!frame) err = gpg_error (GPG_ERR_GENERAL); else err = pk_verify (pk->pubkey_algo, frame, sig->data, pk->pkey); gcry_mpi_release (frame); } if (err) log_error (_("checking created signature failed: %s\n"), g10_errstr (err)); free_public_key (pk); } if (err) log_error (_("signing failed: %s\n"), g10_errstr (err)); else { if (opt.verbose) { char *ustr = get_user_id_string_native (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; } int complete_sig (PKT_signature *sig, PKT_public_key *pksk, gcry_md_hd_t md, const char *cache_nonce) { int rc; /* if (!(rc = check_secret_key (pksk, 0))) */ rc = do_sign (pksk, sig, md, 0, cache_nonce); 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); 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 --preferred-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 --preferred-digest-prefs that is usable for the pubkey algorithm. If --preferred-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 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_ECDSA + else if (pk->pubkey_algo == PUBKEY_ALGO_EDDSA && openpgp_oid_is_ed25519 (pk->pkey[0])) { if (opt.personal_digest_prefs) return opt.personal_digest_prefs[0].value; 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 (PGP2 && pk->pubkey_algo == PUBKEY_ALGO_RSA && pk->version < 4 ) { /* Old-style PGP only understands MD5 */ return DIGEST_ALGO_MD5; } 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; } /* Return true iff all keys in SK_LIST are old style (v3 RSA). */ static int only_old_style (SK_LIST sk_list) { SK_LIST sk_rover = NULL; int old_style = 0; for (sk_rover = sk_list; sk_rover; sk_rover = sk_rover->next) { PKT_public_key *pk = sk_rover->pk; if (pk->pubkey_algo == PUBKEY_ALGO_RSA && pk->version < 4) old_style = 1; else return 0; } return old_style; } 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); if (rc) { log_error ("build onepass_sig packet failed: %s\n", g10_errstr(rc)); return rc; } } return 0; } /* * Helper to write the plaintext (literal data) packet */ static int write_plaintext_packet (IOBUF out, IOBUF inp, const char *fname, int ptmode) { 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' ) filesize = 0; } else filesize = opt.set_filesize? opt.set_filesize : 0; /* stdin */ if (!opt.no_literal) { PACKET pkt; pt->timestamp = make_timestamp (); pt->mode = ptmode; pt->len = filesize; pt->new_ctb = !pt->len && !RFC1991; 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", g10_errstr(rc) ); pt->buf = NULL; } else { byte copy_buffer[4096]; int bytes_copied; 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 */ } /* fixme: it seems that we never freed pt/pkt */ return rc; } /* * Write the signatures from the SK_LIST to OUT. HASH must be a non-finalized * hash which will not be changes here. */ static int write_signature_packets (SK_LIST sk_list, IOBUF out, gcry_md_hd_t hash, 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; int rc; pk = sk_rover->pk; /* Build the signature packet. */ sig = xmalloc_clear (sizeof *sig); if (opt.force_v3_sigs || RFC1991) sig->version = 3; else if (duration || opt.sig_policy_url || opt.sig_notations || opt.sig_keyserver_url) sig->version = 4; else sig->version = pk->version; 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 (); if (sig->version >= 4) { build_sig_subpkt_from_sig (sig); mk_notation_policy_etc (sig, pk, NULL); } hash_sigversion_to_magic (md, sig); gcry_md_final (md); rc = do_sign (pk, sig, md, hash_for (pk), cache_nonce); gcry_md_close (md); if (!rc) { /* Write the packet. */ PACKET pkt; init_packet (&pkt); pkt.pkttype = PKT_SIGNATURE; pkt.pkt.signature = sig; rc = build_packet (out, &pkt); if (!rc && is_status_enabled()) print_status_sig_created (pk, sig, status_letter); free_packet (&pkt); if (rc) log_error ("build signature packet failed: %s\n", gpg_strerror (rc)); } if (rc) return rc; } 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 inp = NULL, 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; pfx = new_progress_context (); afx = new_armor_context (); memset( &zfx, 0, sizeof zfx); memset( &mfx, 0, sizeof mfx); memset( &efx, 0, sizeof efx); 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.force_v3_sigs && !RFC1991) { 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 (locusr, &sk_list, PUBKEY_USAGE_SIG )) ) goto leave; if(PGP2 && !only_old_style(sk_list)) { log_info(_("you can only detach-sign with PGP 2.x style keys " "while in --pgp2 mode\n")); compliance_failure(); } if (encryptflag && (rc=build_pk_list (ctrl, remusr, &pk_list, PUBKEY_USAGE_ENC))) 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 ); if( !out ) { rc = gpg_error_from_syserror (); log_error(_("can't create '%s': %s\n"), outfile, strerror(errno) ); goto leave; } else if( opt.verbose ) log_info(_("writing to '%s'\n"), outfile ); } else if( (rc = open_outfile (GNUPG_INVALID_FD, fname, opt.armor? 1: detached? 2: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, 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 + || (sk_rover->pk->pubkey_algo == PUBKEY_ALGO_EDDSA && !openpgp_oid_is_ed25519 (sk_rover->pk->pkey[1]))) { int temp_hashlen = (gcry_mpi_get_nbits (sk_rover->pk->pkey[1])); - if (sk_rover->pk->pubkey_algo == PUBKEY_ALGO_ECDSA) + if (sk_rover->pk->pubkey_algo == PUBKEY_ALGO_EDDSA) 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_lengthpk->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)) if ( (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 && !RFC1991 ) 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 || opt.compress_sigs) ) { 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 && !RFC1991) { 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,strerror(errno)); goto leave; } handle_progress (pfx, inp, sl->d); if( opt.verbose ) fprintf(stderr, " '%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 ) putc( '\n', stderr ); } 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 ? 't':'b'); } /* catch errors from above */ if (rc) goto leave; /* write the signatures */ rc = write_signature_packets (sk_list, out, mfx.md, 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); return rc; } /**************** * make a clear signature. note that opt.armor is not needed */ int clearsign_file( 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 inp = NULL, out = NULL; PACKET pkt; int rc = 0; SK_LIST sk_list = NULL; SK_LIST sk_rover = NULL; int old_style = RFC1991; int only_md5 = 0; u32 duration=0; pfx = new_progress_context (); afx = new_armor_context (); init_packet( &pkt ); if(!opt.force_v3_sigs && !RFC1991) { 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( locusr, &sk_list, PUBKEY_USAGE_SIG )) ) goto leave; if( !old_style && !duration ) old_style = only_old_style( sk_list ); if(PGP2 && !only_old_style(sk_list)) { log_info(_("you can only clearsign with PGP 2.x style keys " "while in --pgp2 mode\n")); compliance_failure(); } /* 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]", strerror(errno) ); 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 ); if( !out ) { rc = gpg_error_from_syserror (); log_error(_("can't create '%s': %s\n"), outfile, strerror(errno) ); goto leave; } else if( opt.verbose ) log_info(_("writing to '%s'\n"), outfile ); } else if( (rc = open_outfile (GNUPG_INVALID_FD, fname, 1, &out )) ) goto leave; iobuf_writestr(out, "-----BEGIN PGP SIGNED MESSAGE-----" LF ); for (sk_rover = sk_list; sk_rover; sk_rover = sk_rover->next) { if (hash_for (sk_rover->pk) == DIGEST_ALGO_MD5) only_md5 = 1; else { only_md5 = 0; break; } } if( !(old_style && only_md5) ) { 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; } } } 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, (old_style && only_md5) ); /* fixme: check for read errors */ /* now write the armor */ afx->what = 2; push_armor_filter (afx, out); /* Write the signatures. */ rc = write_signature_packets (sk_list, out, textmd, 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 (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 inp = NULL, 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; 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.force_v3_sigs && !RFC1991) { 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 (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]", strerror(errno) ); goto leave; } handle_progress (pfx, inp, fname); /* prepare key */ s2k = xmalloc_clear( sizeof *s2k ); s2k->mode = RFC1991? 0:opt.s2k_mode; s2k->hash_algo = S2K_DIGEST_ALGO; algo = default_cipher_algo(); if (!opt.quiet || !opt.batch) log_info (_("%s encryption will be used\n"), openpgp_cipher_algo_name (algo) ); cfx.dek = passphrase_to_dek( NULL, 0, algo, s2k, 2, 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; } /* We have no way to tell if the recipient can handle messages with an MDC, so this defaults to no. Perhaps in a few years, this can be defaulted to yes. Note that like regular encrypting, --force-mdc overrides --disable-mdc. */ if(opt.force_mdc) cfx.dek->use_mdc=1; /* now create the outfile */ rc = open_outfile (GNUPG_INVALID_FD, fname, opt.armor? 1: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)*/ if (!RFC1991) { 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", g10_errstr(rc) ); xfree(enc); } /* Push the encryption filter */ iobuf_push_filter( out, cipher_filter, &cfx ); /* Push the compress filter */ if (default_compress_algo()) push_compress_filter(out,&zfx,default_compress_algo()); /* Write the one-pass signature packets */ /*(current filters: zip - encrypt - armor)*/ if (!RFC1991) { 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 ? 't':'b'); if (rc) goto leave; /* Write the signatures */ /*(current filters: zip - encrypt - armor)*/ rc = write_signature_packets (sk_list, out, mfx.md, 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); return rc; } /**************** * Create a signature packet for the given public key certificate and * the user id and return it in ret_sig. User signature class SIGCLASS * user-id is not used (and may be NULL if sigclass is 0x20) If * DIGEST_ALGO is 0 the function selects an appropriate one. * SIGVERSION gives the minimal required signature packet version; * this is needed so that special properties like local sign are not * applied (actually: dropped) when a v3 key is used. TIMESTAMP is * the timestamp to use for the signature. 0 means "now" */ int make_keysig_packet( PKT_signature **ret_sig, PKT_public_key *pk, PKT_user_id *uid, PKT_public_key *subpk, PKT_public_key *pksk, int sigclass, int digest_algo, int sigversion, u32 timestamp, u32 duration, int (*mksubpkt)(PKT_signature *, void *), void *opaque, const char *cache_nonce) { PKT_signature *sig; int rc=0; gcry_md_hd_t md; assert( (sigclass >= 0x10 && sigclass <= 0x13) || sigclass == 0x1F || sigclass == 0x20 || sigclass == 0x18 || sigclass == 0x19 || sigclass == 0x30 || sigclass == 0x28 ); if (opt.force_v4_certs) sigversion = 4; if (sigversion < pksk->version) sigversion = pksk->version; /* If you are making a signature on a v4 key using your v3 key, it doesn't make sense to generate a v3 sig. After all, no v3-only PGP implementation could understand the v4 key in the first place. Note that this implies that a signature on an attribute uid is usually going to be v4 as well, since they are not generally found on v3 keys. */ if (sigversion < pk->version) sigversion = pk->version; if( !digest_algo ) { /* Basically, this means use SHA1 always unless it's a v3 RSA key making a v3 cert (use MD5), or the user specified something (use whatever they said), or it's DSA (use the best match). They still can't pick an inappropriate hash for DSA or the signature will fail. Note that this still allows the caller of make_keysig_packet to override the user setting if it must. */ if(opt.cert_digest_algo) digest_algo=opt.cert_digest_algo; else if(pksk->pubkey_algo == PUBKEY_ALGO_RSA && pk->version<4 && sigversion<4) digest_algo = DIGEST_ALGO_MD5; else if(pksk->pubkey_algo == PUBKEY_ALGO_DSA) digest_algo = match_dsa_hash (gcry_mpi_get_nbits (pksk->pkey[1])/8); - else if(pksk->pubkey_algo == PUBKEY_ALGO_ECDSA ) + else if (pksk->pubkey_algo == PUBKEY_ALGO_ECDSA + || pksk->pubkey_algo == PUBKEY_ALGO_EDDSA) { if (openpgp_oid_is_ed25519 (pksk->pkey[0])) digest_algo = DIGEST_ALGO_SHA256; else digest_algo = match_dsa_hash (ecdsa_qbits_from_Q (gcry_mpi_get_nbits (pksk->pkey[1]))/8); } else digest_algo = DIGEST_ALGO_SHA1; } 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); } /* and 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; if(timestamp) sig->timestamp=timestamp; else sig->timestamp=make_timestamp(); if(duration) sig->expiredate=sig->timestamp+duration; sig->sig_class = sigclass; if( sig->version >= 4 ) { build_sig_subpkt_from_sig( sig ); mk_notation_policy_etc (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( sig->version >= 4 && mksubpkt ) rc = (*mksubpkt)( sig, opaque ); if( !rc ) { hash_sigversion_to_magic (md, sig); gcry_md_final (md); rc = complete_sig (sig, pksk, md, cache_nonce); } 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. */ int update_keysig_packet( 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; int rc = 0; int digest_algo; gcry_md_hd_t md; if ((!orig_sig || !pk || !pksk) || (orig_sig->sig_class >= 0x10 && orig_sig->sig_class <= 0x13 && !uid) || (orig_sig->sig_class == 0x18 && !subpk)) return G10ERR_GENERAL; if ( opt.cert_digest_algo ) digest_algo = opt.cert_digest_algo; else digest_algo = orig_sig->digest_algo; 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. */ while(sig->timestamp<=orig_sig->timestamp) { 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. */ if( sig->version >= 4 ) { /* 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 ); if (mksubpkt) rc = (*mksubpkt)(sig, opaque); } if (!rc) { hash_sigversion_to_magic (md, sig); gcry_md_final (md); rc = complete_sig (sig, pksk, md, NULL); } gcry_md_close (md); if( rc ) free_seckey_enc (sig); else *ret_sig = sig; return rc; } diff --git a/sm/certreqgen-ui.c b/sm/certreqgen-ui.c index 1035404cd..368dc5567 100644 --- a/sm/certreqgen-ui.c +++ b/sm/certreqgen-ui.c @@ -1,432 +1,436 @@ /* certreqgen-ui.c - Simple user interface for certreqgen.c * Copyright (C) 2007, 2010, 2011 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 #include #include #include "gpgsm.h" #include #include "i18n.h" #include "ttyio.h" #include "membuf.h" /* Prompt for lines and append them to MB. */ static void ask_mb_lines (membuf_t *mb, const char *prefix) { char *answer = NULL; do { xfree (answer); answer = tty_get ("> "); tty_kill_prompt (); trim_spaces (answer); if (*answer) { put_membuf_str (mb, prefix); put_membuf_str (mb, answer); put_membuf (mb, "\n", 1); } } while (*answer); xfree (answer); } /* Helper to store stuff in a membuf. */ void store_key_value_lf (membuf_t *mb, const char *key, const char *value) { put_membuf_str (mb, key); put_membuf_str (mb, value); put_membuf (mb, "\n", 1); } /* Helper tp store a membuf create by mb_ask_lines into MB. Returns -1 on error. */ int store_mb_lines (membuf_t *mb, membuf_t *lines) { char *p; if (get_membuf_len (lines)) { put_membuf (lines, "", 1); p = get_membuf (lines, NULL); if (!p) return -1; put_membuf_str (mb, p); xfree (p); } return 0; } /* Chech whether we have a key for the key with HEXGRIP. Returns NULL if not or a string describing the type of the key (RSA, ELG, DSA, etc..). */ static const char * check_keygrip (ctrl_t ctrl, const char *hexgrip) { gpg_error_t err; ksba_sexp_t public; size_t publiclen; - int algo; + const char *algostr; if (hexgrip[0] == '&') hexgrip++; err = gpgsm_agent_readkey (ctrl, 0, hexgrip, &public); if (err) return NULL; publiclen = gcry_sexp_canon_len (public, 0, NULL, NULL); - get_pk_algo_from_canon_sexp (public, publiclen, &algo); + get_pk_algo_from_canon_sexp (public, publiclen, &algostr); xfree (public); - switch (algo) - { - case GCRY_PK_RSA: return "RSA"; - case GCRY_PK_DSA: return "DSA"; - case GCRY_PK_ELG: return "ELG"; - case GCRY_PK_ECDSA: return "ECDSA"; - default: return NULL; - } + if (!algostr) + return NULL; + else if (!strcmp (algostr, "rsa")) + return "RSA"; + else if (!strcmp (algostr, "dsa")) + return "DSA"; + else if (!strcmp (algostr, "elg")) + return "ELG"; + else if (!strcmp (algostr, "ecdsa")) + return "ECDSA"; + else + return NULL; } /* This function is used to create a certificate request from the command line. In the past the similar gpgsm-gencert.sh script has been used for it; however that scripts requires a full Unix shell and thus is not suitable for the Windows port. So here is the re-implementation. */ void gpgsm_gencertreq_tty (ctrl_t ctrl, estream_t output_stream) { gpg_error_t err; char *answer; int selection; estream_t fp = NULL; int method; char *keytype_buffer = NULL; const char *keytype; char *keygrip = NULL; unsigned int nbits; int minbits = 1024; int maxbits = 4096; int defbits = 2048; const char *keyusage; char *subject_name; membuf_t mb_email, mb_dns, mb_uri, mb_result; char *result = NULL; int i; const char *s, *s2; int selfsigned; answer = NULL; init_membuf (&mb_email, 100); init_membuf (&mb_dns, 100); init_membuf (&mb_uri, 100); init_membuf (&mb_result, 512); again: /* Get the type of the key. */ tty_printf (_("Please select what kind of key you want:\n")); tty_printf (_(" (%d) RSA\n"), 1 ); tty_printf (_(" (%d) Existing key\n"), 2 ); tty_printf (_(" (%d) Existing key from card\n"), 3 ); do { xfree (answer); answer = tty_get (_("Your selection? ")); tty_kill_prompt (); selection = *answer? atoi (answer): 1; } while (!(selection >= 1 && selection <= 3)); method = selection; /* Get size of the key. */ if (method == 1) { keytype = "RSA"; for (;;) { xfree (answer); answer = tty_getf (_("What keysize do you want? (%u) "), defbits); tty_kill_prompt (); trim_spaces (answer); nbits = *answer? atoi (answer): defbits; if (nbits < minbits || nbits > maxbits) tty_printf(_("%s keysizes must be in the range %u-%u\n"), "RSA", minbits, maxbits); else break; /* Okay. */ } tty_printf (_("Requested keysize is %u bits\n"), nbits); /* We round it up so that it better matches the word size. */ if (( nbits % 64)) { nbits = ((nbits + 63) / 64) * 64; tty_printf (_("rounded up to %u bits\n"), nbits); } } else if (method == 2) { for (;;) { xfree (answer); answer = tty_get (_("Enter the keygrip: ")); tty_kill_prompt (); trim_spaces (answer); if (!*answer) goto again; else if (strlen (answer) != 40 && !(answer[0] == '&' && strlen (answer+1) == 40)) tty_printf (_("Not a valid keygrip (expecting 40 hex digits)\n")); else if (!(keytype = check_keygrip (ctrl, answer)) ) tty_printf (_("No key with this keygrip\n")); else break; /* Okay. */ } xfree (keygrip); keygrip = answer; answer = NULL; nbits = 1024; /* A dummy value is sufficient. */ } else /* method == 3 */ { char *serialno; strlist_t keypairlist, sl; int count; err = gpgsm_agent_scd_serialno (ctrl, &serialno); if (err) { tty_printf (_("error reading the card: %s\n"), gpg_strerror (err)); goto again; } tty_printf (_("Serial number of the card: %s\n"), serialno); xfree (serialno); err = gpgsm_agent_scd_keypairinfo (ctrl, &keypairlist); if (err) { tty_printf (_("error reading the card: %s\n"), gpg_strerror (err)); goto again; } do { tty_printf (_("Available keys:\n")); for (count=1,sl=keypairlist; sl; sl = sl->next, count++) tty_printf (" (%d) %s\n", count, sl->d); xfree (answer); answer = tty_get (_("Your selection? ")); tty_kill_prompt (); trim_spaces (answer); selection = atoi (answer); } while (!(selection > 0 && selection < count)); for (count=1,sl=keypairlist; sl; sl = sl->next, count++) if (count == selection) break; s = sl->d; while (*s && !spacep (s)) s++; while (spacep (s)) s++; xfree (keygrip); keygrip = NULL; xfree (keytype_buffer); keytype_buffer = xasprintf ("card:%s", s); free_strlist (keypairlist); keytype = keytype_buffer; nbits = 1024; /* A dummy value is sufficient. */ } /* Ask for the key usage. */ tty_printf (_("Possible actions for a %s key:\n"), "RSA"); tty_printf (_(" (%d) sign, encrypt\n"), 1 ); tty_printf (_(" (%d) sign\n"), 2 ); tty_printf (_(" (%d) encrypt\n"), 3 ); do { xfree (answer); answer = tty_get (_("Your selection? ")); tty_kill_prompt (); trim_spaces (answer); selection = *answer? atoi (answer): 1; switch (selection) { case 1: keyusage = "sign, encrypt"; break; case 2: keyusage = "sign"; break; case 3: keyusage = "encrypt"; break; default: keyusage = NULL; break; } } while (!keyusage); /* Get the subject name. */ do { size_t erroff, errlen; xfree (answer); answer = tty_get (_("Enter the X.509 subject name: ")); tty_kill_prompt (); trim_spaces (answer); if (!*answer) tty_printf (_("No subject name given\n")); else if ( (err = ksba_dn_teststr (answer, 0, &erroff, &errlen)) ) { if (gpg_err_code (err) == GPG_ERR_UNKNOWN_NAME) tty_printf (_("Invalid subject name label '%.*s'\n"), (int)errlen, answer+erroff); else { /* TRANSLATORS: The 22 in the second string is the length of the first string up to the "%s". Please adjust it do the length of your translation. The second string is merely passed to atoi so you can drop everything after the number. */ tty_printf (_("Invalid subject name '%s'\n"), answer); tty_printf ("%*s^\n", atoi (_("22 translator: see " "certreg-ui.c:gpgsm_gencertreq_tty")) + (int)erroff, ""); } *answer = 0; } } while (!*answer); subject_name = answer; answer = NULL; /* Get the email addresses. */ tty_printf (_("Enter email addresses")); tty_printf (_(" (end with an empty line):\n")); ask_mb_lines (&mb_email, "Name-Email: "); /* DNS names. */ tty_printf (_("Enter DNS names")); tty_printf (_(" (optional; end with an empty line):\n")); ask_mb_lines (&mb_dns, "Name-DNS: "); /* URIs. */ tty_printf (_("Enter URIs")); tty_printf (_(" (optional; end with an empty line):\n")); ask_mb_lines (&mb_uri, "Name-URI: "); /* Want a self-signed certificate? */ selfsigned = tty_get_answer_is_yes (_("Create self-signed certificate? (y/N) ")); /* Put it all together. */ store_key_value_lf (&mb_result, "Key-Type: ", keytype); { char numbuf[30]; snprintf (numbuf, sizeof numbuf, "%u", nbits); store_key_value_lf (&mb_result, "Key-Length: ", numbuf); } if (keygrip) store_key_value_lf (&mb_result, "Key-Grip: ", keygrip); store_key_value_lf (&mb_result, "Key-Usage: ", keyusage); if (selfsigned) store_key_value_lf (&mb_result, "Serial: ", "random"); store_key_value_lf (&mb_result, "Name-DN: ", subject_name); if (store_mb_lines (&mb_result, &mb_email)) goto mem_error; if (store_mb_lines (&mb_result, &mb_dns)) goto mem_error; if (store_mb_lines (&mb_result, &mb_uri)) goto mem_error; put_membuf (&mb_result, "", 1); result = get_membuf (&mb_result, NULL); if (!result) goto mem_error; tty_printf (_("These parameters are used:\n")); for (s=result; (s2 = strchr (s, '\n')); s = s2+1, i++) tty_printf (" %.*s\n", (int)(s2-s), s); tty_printf ("\n"); if (!tty_get_answer_is_yes ("Proceed with creation? (y/N) ")) goto leave; /* Now create a parameter file and generate the key. */ fp = es_fopenmem (0, "w+"); if (!fp) { log_error (_("error creating temporary file: %s\n"), strerror (errno)); goto leave; } es_fputs (result, fp); es_rewind (fp); if (selfsigned) tty_printf ("%s", _("Now creating self-signed certificate. ")); else tty_printf ("%s", _("Now creating certificate request. ")); tty_printf ("%s", _("This may take a while ...\n")); { int save_pem = ctrl->create_pem; ctrl->create_pem = 1; /* Force creation of PEM. */ err = gpgsm_genkey (ctrl, fp, output_stream); ctrl->create_pem = save_pem; } if (!err) { if (selfsigned) tty_printf (_("Ready.\n")); else tty_printf (_("Ready. You should now send this request to your CA.\n")); } goto leave; mem_error: log_error (_("resource problem: out of core\n")); leave: es_fclose (fp); xfree (answer); xfree (subject_name); xfree (keytype_buffer); xfree (keygrip); xfree (get_membuf (&mb_email, NULL)); xfree (get_membuf (&mb_dns, NULL)); xfree (get_membuf (&mb_uri, NULL)); xfree (get_membuf (&mb_result, NULL)); xfree (result); }