diff --git a/g10/build-packet.c b/g10/build-packet.c index fc64c9c9f..b4e03d007 100644 --- a/g10/build-packet.c +++ b/g10/build-packet.c @@ -1,1827 +1,1827 @@ /* 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 "gpg.h" #include "../common/util.h" #include "packet.h" #include "../common/status.h" #include "../common/iobuf.h" #include "../common/i18n.h" #include "options.h" #include "../common/host2net.h" static gpg_error_t do_ring_trust (iobuf_t out, PKT_ring_trust *rt); 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_encrypted_aead (iobuf_t 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 ); /* Returns 1 if CTB is a new format ctb and 0 if CTB is an old format ctb. */ static int ctb_new_format_p (int ctb) { /* Bit 7 must always be set. */ log_assert ((ctb & (1 << 7))); /* Bit 6 indicates whether the packet is a new format packet. */ return (ctb & (1 << 6)); } /* Extract the packet type from a CTB. */ static int ctb_pkttype (int ctb) { if (ctb_new_format_p (ctb)) /* Bits 0 through 5 are the packet type. */ return (ctb & ((1 << 6) - 1)); else /* Bits 2 through 5 are the packet type. */ return (ctb & ((1 << 6) - 1)) >> 2; } /* Build a packet and write it to the stream OUT. * Returns: 0 on success or on an error code. */ int build_packet (IOBUF out, PACKET *pkt) { int rc = 0; int new_ctb = 0; int ctb, pkttype; if (DBG_PACKET) log_debug ("build_packet() type=%d\n", pkt->pkttype); log_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: case PKT_ENCRYPTED_AEAD: 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_ENCRYPTED_AEAD: rc = do_encrypted_aead (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: /* Ignore it (only written by build_packet_and_meta) */ break; 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; } /* Build a packet and write it to the stream OUT. This variant also * writes the meta data using ring trust packets. Returns: 0 on * success or on error code. */ gpg_error_t build_packet_and_meta (iobuf_t out, PACKET *pkt) { gpg_error_t err; PKT_ring_trust rt = {0}; err = build_packet (out, pkt); if (err) ; else if (pkt->pkttype == PKT_SIGNATURE) { PKT_signature *sig = pkt->pkt.signature; rt.subtype = RING_TRUST_SIG; /* Note: trustval is not yet used. */ if (sig->flags.checked) { rt.sigcache = 1; if (sig->flags.valid) rt.sigcache |= 2; } err = do_ring_trust (out, &rt); } else if (pkt->pkttype == PKT_USER_ID || pkt->pkttype == PKT_ATTRIBUTE) { PKT_user_id *uid = pkt->pkt.user_id; rt.subtype = RING_TRUST_UID; rt.keyorg = uid->keyorg; rt.keyupdate = uid->keyupdate; rt.url = uid->updateurl; err = do_ring_trust (out, &rt); rt.url = NULL; } else if (pkt->pkttype == PKT_PUBLIC_KEY || pkt->pkttype == PKT_SECRET_KEY) { PKT_public_key *pk = pkt->pkt.public_key; rt.subtype = RING_TRUST_KEY; rt.keyorg = pk->keyorg; rt.keyupdate = pk->keyupdate; rt.url = pk->updateurl; err = do_ring_trust (out, &rt); rt.url = NULL; } return err; } /* * 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 unsigned char *p; unsigned char lenhdr[2]; /* gcry_log_debugmpi ("a", a); */ p = gcry_mpi_get_opaque (a, &nbits); if (p) { /* Strip leading zero bits. */ for (; nbits >= 8 && !*p; p++, nbits -= 8) ; if (nbits >= 8 && !(*p & 0x80)) if (--nbits >= 7 && !(*p & 0x40)) if (--nbits >= 6 && !(*p & 0x20)) if (--nbits >= 5 && !(*p & 0x10)) if (--nbits >= 4 && !(*p & 0x08)) if (--nbits >= 3 && !(*p & 0x04)) if (--nbits >= 2 && !(*p & 0x02)) if (--nbits >= 1 && !(*p & 0x01)) --nbits; } /* gcry_log_debug (" [%u bit]\n", nbits); */ /* gcry_log_debughex (" ", p, (nbits+7)/8); */ lenhdr[0] = nbits >> 8; lenhdr[1] = nbits; rc = iobuf_write (out, lenhdr, 2); if (!rc && p) 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 = p ? iobuf_write (out, p, (nbits+7)/8) : 0; } 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; log_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; if (!gcry_mpi_get_flag (a, GCRYMPI_FLAG_OPAQUE)) return 0; /* e.g. due to generating a key with wrong usage. */ p = gcry_mpi_get_opaque ( a, &n); if (!p) return 0; /* For example due to a read error in parse-packet.c:read_rest. */ return iobuf_write (out, p, (n+7)/8 ); } /* Write a ring trust meta packet. */ static gpg_error_t do_ring_trust (iobuf_t out, PKT_ring_trust *rt) { unsigned int namelen = 0; unsigned int pktlen = 6; if (rt->subtype == RING_TRUST_KEY || rt->subtype == RING_TRUST_UID) { if (rt->url) namelen = strlen (rt->url); pktlen += 1 + 4 + 1 + namelen; } write_header (out, (0x80 | ((PKT_RING_TRUST & 15)<<2)), pktlen); iobuf_put (out, rt->trustval); iobuf_put (out, rt->sigcache); iobuf_write (out, "gpg", 3); iobuf_put (out, rt->subtype); if (rt->subtype == RING_TRUST_KEY || rt->subtype == RING_TRUST_UID) { iobuf_put (out, rt->keyorg); write_32 (out, rt->keyupdate); iobuf_put (out, namelen); if (namelen) iobuf_write (out, rt->url, namelen); } return 0; } /* Serialize the user id (RFC 4880, Section 5.11) or the user * attribute UID (Section 5.12) and write it to OUT. * * CTB is the serialization's CTB. It specifies the header format and * the packet's type. The header length must not be set. */ static int do_user_id( IOBUF out, int ctb, PKT_user_id *uid ) { int rc; int hdrlen; log_assert (ctb_pkttype (ctb) == PKT_USER_ID || ctb_pkttype (ctb) == PKT_ATTRIBUTE); /* We need to take special care of a user ID with a length of 0: * Without forcing HDRLEN to 2 in this case an indeterminate length * packet would be written which is not allowed. Note that we are * always called with a CTB indicating an old packet header format, * so that forcing a 2 octet header works. */ if (uid->attrib_data) { hdrlen = uid->attrib_len? 0 : 2; write_header2 (out, ctb, uid->attrib_len, hdrlen); rc = iobuf_write( out, uid->attrib_data, uid->attrib_len ); } else { hdrlen = uid->len? 0 : 2; write_header2 (out, ctb, uid->len, hdrlen); rc = iobuf_write( out, uid->name, uid->len ); } return rc; } /* Serialize the key (RFC 4880, Section 5.5) described by PK and write * it to OUT. * * This function serializes both primary keys and subkeys with or * without a secret part. * * CTB is the serialization's CTB. It specifies the header format and * the packet's type. The header length must not be set. * * PK->VERSION specifies the serialization format. A value of 0 means * to use the default version. Currently, only version 4 packets are * supported. */ static int do_key (iobuf_t out, int ctb, PKT_public_key *pk) { gpg_error_t err = 0; /* The length of the body is stored in the packet's header, which occurs before the body. Unfortunately, we don't know the length of the packet's body until we've written all of the data! To work around this, we first write the data into this temporary buffer, then generate the header, and finally copy the contents of this buffer to OUT. */ iobuf_t a = iobuf_temp(); int i, nskey, npkey; log_assert (pk->version == 0 || pk->version == 4); log_assert (ctb_pkttype (ctb) == PKT_PUBLIC_KEY || ctb_pkttype (ctb) == PKT_PUBLIC_SUBKEY || ctb_pkttype (ctb) == PKT_SECRET_KEY || ctb_pkttype (ctb) == PKT_SECRET_SUBKEY); /* Write the version number - if none is specified, use 4 */ if ( !pk->version ) iobuf_put ( a, 4 ); else iobuf_put ( a, pk->version ); write_32 (a, pk->timestamp ); iobuf_put (a, pk->pubkey_algo ); /* Get number of secret and public parameters. They are held in one array: the public ones followed by 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 for example 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; } log_assert (npkey < nskey); for (i=0; i < npkey; i++ ) { 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) { /* 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) { /* The secret key is protected - write it out as it is. */ byte *p; unsigned int ndatabits; log_assert (gcry_mpi_get_flag (pk->pkey[npkey], GCRYMPI_FLAG_OPAQUE)); p = gcry_mpi_get_opaque (pk->pkey[npkey], &ndatabits); if (p) iobuf_write (a, p, (ndatabits+7)/8 ); } 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), 0); /* And finally write it out to the real stream. */ err = iobuf_write_temp (out, a); } iobuf_close (a); /* Close the temporary buffer */ return err; } /* Serialize the symmetric-key encrypted session key packet (RFC 4880, * 5.3) described by ENC and write it to OUT. * * CTB is the serialization's CTB. It specifies the header format and * the packet's type. The header length must not be set. */ static int do_symkey_enc( IOBUF out, int ctb, PKT_symkey_enc *enc ) { int rc = 0; IOBUF a = iobuf_temp(); log_assert (ctb_pkttype (ctb) == PKT_SYMKEY_ENC); + log_assert (enc->version == 4 || enc->version == 5); - /* The only acceptable version. */ - log_assert( enc->version == 4 ); - - /* RFC 4880, Section 3.7. */ switch (enc->s2k.mode) { case 0: /* Simple S2K. */ case 1: /* Salted S2K. */ case 3: /* Iterated and salted S2K. */ break; /* Reasonable values. */ 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); + iobuf_put (a, enc->version); + iobuf_put (a, enc->cipher_algo); + if (enc->version == 5) + iobuf_put (a, enc->aead_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 ); + 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 ); + write_header (out, ctb, iobuf_get_temp_length(a)); + rc = iobuf_write_temp (out, a); - iobuf_close(a); - return rc; + iobuf_close (a); + return rc; } /* Serialize the public-key encrypted session key packet (RFC 4880, 5.1) described by ENC and write it to OUT. CTB is the serialization's CTB. It specifies the header format and the packet's type. The header length must not be set. */ static int do_pubkey_enc( IOBUF out, int ctb, PKT_pubkey_enc *enc ) { int rc = 0; int n, i; IOBUF a = iobuf_temp(); log_assert (ctb_pkttype (ctb) == PKT_PUBKEY_ENC); iobuf_put (a, 3); /* Version. */ 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; } /* Calculate the length of the serialized plaintext packet PT (RFC 4480, Section 5.9). */ 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; } /* Serialize the plaintext packet (RFC 4880, 5.9) described by PT and write it to OUT. The body of the message is stored in PT->BUF. The amount of data to write is PT->LEN. (PT->BUF should be configured to return EOF after this much data has been read.) If PT->LEN is 0 and CTB indicates that this is a new format packet, then partial block mode is assumed to have been enabled on OUT. On success, partial block mode is disabled. If PT->BUF is NULL, the caller must write out the data. In this case, if PT->LEN was 0, then partial body length mode was enabled and the caller must disable it by calling iobuf_set_partial_body_length_mode (out, 0). */ static int do_plaintext( IOBUF out, int ctb, PKT_plaintext *pt ) { int rc = 0; size_t nbytes; log_assert (ctb_pkttype (ctb) == PKT_PLAINTEXT); write_header(out, ctb, calc_plaintext( pt ) ); log_assert (pt->mode == 'b' || pt->mode == 't' || pt->mode == 'u' || pt->mode == 'm' || pt->mode == 'l' || pt->mode == '1'); iobuf_put(out, pt->mode ); iobuf_put(out, pt->namelen ); iobuf_write (out, pt->name, pt->namelen); rc = write_32(out, pt->timestamp ); if (rc) return rc; if (pt->buf) { nbytes = iobuf_copy (out, pt->buf); if(ctb_new_format_p (ctb) && !pt->len) /* Turn off partial body length mode. */ iobuf_set_partial_body_length_mode (out, 0); if( pt->len && nbytes != pt->len ) log_error("do_plaintext(): wrote %lu bytes but expected %lu bytes\n", (ulong)nbytes, (ulong)pt->len ); } return rc; } /* Serialize the symmetrically encrypted data packet (RFC 4880, Section 5.7) described by ED and write it to OUT. Note: this only writes the packets header! The call must then follow up and write the initial random data and the body to OUT. (If you use the encryption iobuf filter (cipher_filter), then this is done automatically.) */ static int do_encrypted( IOBUF out, int ctb, PKT_encrypted *ed ) { int rc = 0; u32 n; log_assert (! ed->mdc_method); log_assert (ctb_pkttype (ctb) == PKT_ENCRYPTED); 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; } /* Serialize the symmetrically encrypted integrity protected data packet (RFC 4880, Section 5.13) described by ED and write it to OUT. Note: this only writes the packet's header! The caller must then follow up and write the initial random data, the body and the MDC packet to OUT. (If you use the encryption iobuf filter (cipher_filter), then this is done automatically.) */ static int do_encrypted_mdc( IOBUF out, int ctb, PKT_encrypted *ed ) { int rc = 0; u32 n; log_assert (ed->mdc_method); log_assert (ctb_pkttype (ctb) == PKT_ENCRYPTED_MDC); /* 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; } /* Serialize the symmetrically AEAD encrypted data packet * (rfc4880bis-03, Section 5.16) described by ED and write it to OUT. * * Note: this only writes only packet's header. The caller must then * follow up and write the actual encrypted data. This should be done * by pushing the the cipher_filter_aead. */ static int do_encrypted_aead (iobuf_t out, int ctb, PKT_encrypted *ed) { u32 n; log_assert (ctb_pkttype (ctb) == PKT_ENCRYPTED_AEAD); n = ed->len ? (ed->len + ed->extralen + 4) : 0; write_header (out, ctb, n ); iobuf_writebyte (out, 1); /* Version. */ iobuf_writebyte (out, ed->cipher_algo); iobuf_writebyte (out, ed->aead_algo); iobuf_writebyte (out, ed->chunkbyte); /* This is all. The caller has to write the encrypted data */ return 0; } /* Serialize the compressed packet (RFC 4880, Section 5.6) described by CD and write it to OUT. Note: this only writes the packet's header! The caller must then follow up and write the body to OUT. */ static int do_compressed( IOBUF out, int ctb, PKT_compressed *cd ) { int rc = 0; log_assert (ctb_pkttype (ctb) == PKT_COMPRESSED); /* 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 = buf32_to_size_t (buffer); 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"); log_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(buf32_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. * PKSK is the signing key. * Hmmm, should we delete those subpackets which are in a wrong area? */ void build_sig_subpkt_from_sig (PKT_signature *sig, PKT_public_key *pksk) { u32 u; byte buf[1+MAX_FINGERPRINT_LEN]; size_t fprlen; /* For v4 keys we need to write the ISSUER subpacket. We do not * want that for a future v5 format. */ if (pksk->version < 5) { 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); } /* Write the new ISSUER_FPR subpacket. */ fingerprint_from_pk (pksk, buf+1, &fprlen); if (fprlen == 20) { buf[0] = pksk->version; build_sig_subpkt (sig, SIGSUBPKT_ISSUER_FPR, buf, 21); } /* Write the timestamp. */ 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; } /* Returns a human-readable string corresponding to the notation. This ignores notation->value. The caller must free the result. */ static char * notation_value_to_human_readable_string (struct notation *notation) { if(notation->bdat) /* Binary data. */ { size_t len = notation->blen; int i; char preview[20]; for (i = 0; i < len && i < sizeof (preview) - 1; i ++) if (isprint (notation->bdat[i])) preview[i] = notation->bdat[i]; else preview[i] = '?'; preview[i] = 0; return xasprintf (_("[ not human readable (%zu bytes: %s%s) ]"), len, preview, i < len ? "..." : ""); } else /* The value is human-readable. */ return xstrdup (notation->value); } /* Turn the notation described by the string STRING into a notation. STRING has the form: - -name - Delete the notation. - name@domain.name=value - Normal notation - !name@domain.name=value - Notation with critical bit set. The caller must free the result using free_notation(). */ 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; } /* Like string_to_notation, but store opaque data rather than human readable data. */ struct notation * blob_to_notation(const char *name, const char *data, size_t len) { const char *s; int saw_at=0; struct notation *notation; notation=xmalloc_clear(sizeof(*notation)); if(*name=='-') { notation->flags.ignore=1; name++; } if(*name=='!') { notation->flags.critical=1; name++; } /* If and when the IETF assigns some official name tags, we'll have to add them here. */ for( s=name ; *s; s++ ) { if( *s=='@') saw_at++; /* -notationname is legal without an = sign */ if(!*s && notation->flags.ignore) break; if (*s == '=') { log_error(_("a notation name may not contain an '=' character\n")); goto fail; } if (!isascii (*s) || (!isgraph(*s) && !isspace(*s))) { log_error(_("a notation name must have only printable characters" " or spaces\n") ); goto fail; } } notation->name=xstrdup (name); 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; } notation->bdat = xmalloc (len); memcpy (notation->bdat, data, len); notation->blen = len; notation->value = notation_value_to_human_readable_string (notation); 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; int crit; notation_t list = NULL; /* See RFC 4880, 5.2.3.16 for the format of notation data. In short, a notation has: - 4 bytes of flags - 2 byte name length (n1) - 2 byte value length (n2) - n1 bytes of name data - n2 bytes of value data */ 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; } /* name length. */ n1=(p[4]<<8)|p[5]; /* value length. */ 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) /* The value is human-readable. */ { n->value=xmalloc(n2+1); memcpy(n->value,&p[8+n1],n2); n->value[n2]='\0'; n->flags.human = 1; } else /* Binary data. */ { n->bdat=xmalloc(n2); n->blen=n2; memcpy(n->bdat,&p[8+n1],n2); n->value = notation_value_to_human_readable_string (n); } n->flags.critical=crit; n->next=list; list=n; } return list; } /* Release the resources associated with the *list* of notations. To release a single notation, make sure that notation->next is NULL. */ 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); } } /* Serialize the signature packet (RFC 4880, Section 5.2) described by SIG and write it to OUT. */ static int do_signature( IOBUF out, int ctb, PKT_signature *sig ) { int rc = 0; int n, i; IOBUF a = iobuf_temp(); log_assert (ctb_pkttype (ctb) == PKT_SIGNATURE); if ( !sig->version || sig->version == 3) { iobuf_put( a, 3 ); /* Version 3 packets don't support subpackets. */ log_assert (! sig->hashed); log_assert (! sig->unhashed); } 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; } /* Serialize the one-pass signature packet (RFC 4880, Section 5.4) described by OPS and write it to OUT. */ static int do_onepass_sig( IOBUF out, int ctb, PKT_onepass_sig *ops ) { log_assert (ctb_pkttype (ctb) == PKT_ONEPASS_SIG); write_header(out, ctb, 4 + 8 + 1); iobuf_put (out, 3); /* Version. */ iobuf_put(out, ops->sig_class ); iobuf_put(out, ops->digest_algo ); iobuf_put(out, ops->pubkey_algo ); write_32(out, ops->keyid[0] ); write_32(out, ops->keyid[1] ); iobuf_put(out, ops->last ); return 0; } /* Write a 16-bit quantity to OUT in big endian order. */ static int write_16(IOBUF out, u16 a) { iobuf_put(out, a>>8); if( iobuf_put(out,a) ) return -1; return 0; } /* Write a 32-bit quantity to OUT in big endian order. */ 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. * * LEN is the length of the packet's body. NEW_CTB is whether we are * using a new or old format packet. * * This function does not handle indeterminate lengths or partial body * lengths. (If you pass LEN as 0, then this function assumes you * really mean an empty body.) */ static int calc_header_length( u32 len, int new_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; } /**************** * Write a packet header to OUT. * * CTB is the ctb. It determines whether a new or old format packet * header should be written. The length field is adjusted, but the * CTB is otherwise written out as is. * * LEN is the length of the packet's body. * * If HDRLEN is set, then we don't necessarily use the most efficient * encoding to store LEN, but the specified length. (If this is not * possible, this is a bug.) In this case, LEN=0 means a 0 length * packet. Note: setting HDRLEN is only supported for old format * packets! * * If HDRLEN is not set, then the shortest encoding is used. In this * case, LEN=0 means the body has an indeterminate length and a * partial body length header (if a new format packet) or an * indeterminate length header (if an old format packet) is written * out. Further, if using partial body lengths, this enables partial * body length mode on OUT. */ static int write_header2( IOBUF out, int ctb, u32 len, int hdrlen ) { if (ctb_new_format_p (ctb)) return write_new_header( out, ctb, len, hdrlen ); /* An old format packet. Refer to RFC 4880, Section 4.2.1 to understand how lengths are encoded in this case. */ /* The length encoding is stored in the two least significant bits. Make sure they are cleared. */ log_assert ((ctb & 3) == 0); log_assert (hdrlen == 0 || hdrlen == 2 || hdrlen == 3 || hdrlen == 5); if (hdrlen) /* Header length is given. */ { if( hdrlen == 2 && len < 256 ) /* 00 => 1 byte length. */ ; else if( hdrlen == 3 && len < 65536 ) /* 01 => 2 byte length. If len < 256, this is not the most compact encoding, but it is a correct encoding. */ ctb |= 1; else if (hdrlen == 5) /* 10 => 4 byte length. If len < 65536, this is not the most compact encoding, but it is a correct encoding. */ ctb |= 2; else log_bug ("Can't encode length=%d in a %d byte header!\n", len, hdrlen); } else { if( !len ) /* 11 => Indeterminate length. */ ctb |= 3; else if( len < 256 ) /* 00 => 1 byte length. */ ; else if( len < 65536 ) /* 01 => 2 byte length. */ ctb |= 1; else /* 10 => 4 byte length. */ 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; } /* Write a new format header to OUT. CTB is the ctb. LEN is the length of the packet's body. If LEN is 0, then enables partial body length mode (i.e., the body is of an indeterminant length) on OUT. Note: this function cannot be used to generate a header for a zero length packet. HDRLEN is the length of the packet's header. If HDRLEN is 0, the shortest encoding is chosen based on the length of the packet's body. Currently, values other than 0 are not supported. Returns 0 on success. */ 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_body_length_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; } diff --git a/g10/decrypt-data.c b/g10/decrypt-data.c index 7ed0bf006..46650f269 100644 --- a/g10/decrypt-data.c +++ b/g10/decrypt-data.c @@ -1,1025 +1,1027 @@ /* decrypt-data.c - Decrypt an encrypted data packet * Copyright (C) 1998-2001, 2005-2006, 2009 Free Software Foundation, Inc. * Copyright (C) 1998-2001, 2005-2006, 2009, 2018 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 "gpg.h" #include "../common/util.h" #include "packet.h" #include "options.h" #include "../common/i18n.h" #include "../common/status.h" #include "../common/compliance.h" static int aead_decode_filter (void *opaque, int control, iobuf_t a, byte *buf, size_t *ret_len); static int mdc_decode_filter ( void *opaque, int control, IOBUF a, byte *buf, size_t *ret_len); static int decode_filter ( void *opaque, int control, IOBUF a, byte *buf, size_t *ret_len); /* Our context object. */ struct decode_filter_context_s { /* Recounter (max value is 2). We need it becuase we do not know * whether the iobuf or the outer control code frees this object * first. */ int refcount; /* The cipher handle. */ gcry_cipher_hd_t cipher_hd; /* The hash handle for use in MDC mode. */ gcry_md_hd_t mdc_hash; /* The start IV for AEAD encryption. */ byte startiv[16]; /* The holdback buffer. For AEAD we need 32 bytes for MDC 22 bytes * are enough. The flag indicates whether the holdback buffer is * filled. */ char defer[32]; unsigned int defer_filled : 1; /* Working on a partial length packet. */ unsigned int partial : 1; /* EOF indicator with these true values: * 1 = normal EOF * 2 = premature EOF (tag incomplete) * 3 = premature EOF (general) */ unsigned int eof_seen : 2; /* The actually used cipher algo for AEAD. */ byte cipher_algo; /* The AEAD algo. */ byte aead_algo; /* The encoded chunk byte for AEAD. */ byte chunkbyte; /* The decoded CHUNKBYTE. */ uint64_t chunksize; /* The chunk index for AEAD. */ uint64_t chunkindex; /* The number of bytes in the current chunk. */ uint64_t chunklen; /* The total count of decrypted plaintext octets. */ uint64_t total; /* Remaining bytes in the packet according to the packet header. * Not used if PARTIAL is true. */ size_t length; }; typedef struct decode_filter_context_s *decode_filter_ctx_t; /* Helper to release the decode context. */ static void release_dfx_context (decode_filter_ctx_t dfx) { if (!dfx) return; log_assert (dfx->refcount); if ( !--dfx->refcount ) { gcry_cipher_close (dfx->cipher_hd); dfx->cipher_hd = NULL; gcry_md_close (dfx->mdc_hash); dfx->mdc_hash = NULL; xfree (dfx); } } /* Set the nonce for AEAD. This also reset the decryption machinery * so that the handle can be used for a new chunk. */ static gpg_error_t aead_set_nonce (decode_filter_ctx_t dfx) { unsigned char nonce[16]; int i; switch (dfx->aead_algo) { case AEAD_ALGO_OCB: memcpy (nonce, dfx->startiv, 15); i = 7; break; case AEAD_ALGO_EAX: memcpy (nonce, dfx->startiv, 16); i = 8; break; default: BUG (); } nonce[i++] ^= dfx->chunkindex >> 56; nonce[i++] ^= dfx->chunkindex >> 48; nonce[i++] ^= dfx->chunkindex >> 40; nonce[i++] ^= dfx->chunkindex >> 32; nonce[i++] ^= dfx->chunkindex >> 24; nonce[i++] ^= dfx->chunkindex >> 16; nonce[i++] ^= dfx->chunkindex >> 8; nonce[i++] ^= dfx->chunkindex; log_printhex (nonce, i, "nonce:"); return gcry_cipher_setiv (dfx->cipher_hd, nonce, i); } /* Set the additional data for the current chunk. If FINAL is set the * final AEAD chunk is processed. */ static gpg_error_t aead_set_ad (decode_filter_ctx_t dfx, int final) { unsigned char ad[21]; ad[0] = (0xc0 | PKT_ENCRYPTED_AEAD); ad[1] = 1; ad[2] = dfx->cipher_algo; ad[3] = dfx->aead_algo; ad[4] = dfx->chunkbyte; ad[5] = dfx->chunkindex >> 56; ad[6] = dfx->chunkindex >> 48; ad[7] = dfx->chunkindex >> 40; ad[8] = dfx->chunkindex >> 32; ad[9] = dfx->chunkindex >> 24; ad[10]= dfx->chunkindex >> 16; ad[11]= dfx->chunkindex >> 8; ad[12]= dfx->chunkindex; if (final) { ad[13] = dfx->total >> 56; ad[14] = dfx->total >> 48; ad[15] = dfx->total >> 40; ad[16] = dfx->total >> 32; ad[17] = dfx->total >> 24; ad[18] = dfx->total >> 16; ad[19] = dfx->total >> 8; ad[20] = dfx->total; } log_printhex (ad, final? 21 : 13, "authdata:"); return gcry_cipher_authenticate (dfx->cipher_hd, ad, final? 21 : 13); } /**************** * Decrypt the data, specified by ED with the key DEK. */ int decrypt_data (ctrl_t ctrl, void *procctx, PKT_encrypted *ed, DEK *dek) { decode_filter_ctx_t dfx; byte *p; int rc=0, c, i; byte temp[32]; unsigned int blocksize; unsigned int nprefix; dfx = xtrycalloc (1, sizeof *dfx); if (!dfx) return gpg_error_from_syserror (); dfx->refcount = 1; if ( opt.verbose && !dek->algo_info_printed ) { if (!openpgp_cipher_test_algo (dek->algo)) - log_info (_("%s encrypted data\n"), - openpgp_cipher_algo_name (dek->algo)); + log_info (_("%s.%s encrypted data\n"), + openpgp_cipher_algo_name (dek->algo), + ed->aead_algo? openpgp_aead_algo_name (ed->aead_algo) + /**/ : "CFB"); else log_info (_("encrypted with unknown algorithm %d\n"), dek->algo ); dek->algo_info_printed = 1; } /* Check compliance. */ if (! gnupg_cipher_is_allowed (opt.compliance, 0, dek->algo, GCRY_CIPHER_MODE_CFB)) { log_error (_("cipher algorithm '%s' may not be used in %s mode\n"), openpgp_cipher_algo_name (dek->algo), gnupg_compliance_option_string (opt.compliance)); rc = gpg_error (GPG_ERR_CIPHER_ALGO); goto leave; } write_status_printf (STATUS_DECRYPTION_INFO, "%d %d %d", ed->mdc_method, dek->algo, ed->aead_algo); if (opt.show_session_key) { char numbuf[30]; char *hexbuf; if (ed->aead_algo) snprintf (numbuf, sizeof numbuf, "%d.%u:", dek->algo, ed->aead_algo); else snprintf (numbuf, sizeof numbuf, "%d:", dek->algo); hexbuf = bin2hex (dek->key, dek->keylen, NULL); if (!hexbuf) { rc = gpg_error_from_syserror (); goto leave; } log_info ("session key: '%s%s'\n", numbuf, hexbuf); write_status_strings (STATUS_SESSION_KEY, numbuf, hexbuf, NULL); xfree (hexbuf); } rc = openpgp_cipher_test_algo (dek->algo); if (rc) goto leave; blocksize = openpgp_cipher_get_algo_blklen (dek->algo); if ( !blocksize || blocksize > 16 ) log_fatal ("unsupported blocksize %u\n", blocksize ); if (ed->aead_algo) { enum gcry_cipher_modes ciphermode; unsigned int startivlen; if (blocksize != 16) { rc = gpg_error (GPG_ERR_CIPHER_ALGO); goto leave; } rc = openpgp_aead_algo_info (ed->aead_algo, &ciphermode, &startivlen); if (rc) goto leave; log_assert (startivlen <= sizeof dfx->startiv); if (ed->chunkbyte > 56) { log_error ("invalid AEAD chunkbyte %u\n", ed->chunkbyte); rc = gpg_error (GPG_ERR_INV_PACKET); goto leave; } /* Read the Start-IV. */ if (ed->len) { for (i=0; i < startivlen && ed->len; i++, ed->len--) { if ((c=iobuf_get (ed->buf)) == -1) break; dfx->startiv[i] = c; } } else { for (i=0; i < startivlen; i++ ) if ( (c=iobuf_get (ed->buf)) == -1 ) break; else dfx->startiv[i] = c; } if (i != startivlen) { log_error ("Start-IV in AEAD packet too short (%d/%u)\n", i, startivlen); rc = gpg_error (GPG_ERR_TOO_SHORT); goto leave; } dfx->cipher_algo = ed->cipher_algo; dfx->aead_algo = ed->aead_algo; dfx->chunkbyte = ed->chunkbyte; dfx->chunksize = (uint64_t)1 << (dfx->chunkbyte + 6); if (dek->algo != dfx->cipher_algo) log_info ("Note: different cipher algorithms used (%s/%s)\n", openpgp_cipher_algo_name (dek->algo), openpgp_cipher_algo_name (dfx->cipher_algo)); rc = openpgp_cipher_open (&dfx->cipher_hd, dfx->cipher_algo, ciphermode, GCRY_CIPHER_SECURE); if (rc) goto leave; /* Should never happen. */ log_printhex (dek->key, dek->keylen, "thekey:"); rc = gcry_cipher_setkey (dfx->cipher_hd, dek->key, dek->keylen); if (gpg_err_code (rc) == GPG_ERR_WEAK_KEY) { log_info (_("WARNING: message was encrypted with" " a weak key in the symmetric cipher.\n")); rc = 0; } else if (rc) { log_error("key setup failed: %s\n", gpg_strerror (rc)); goto leave; } if (!ed->buf) { log_error(_("problem handling encrypted packet\n")); goto leave; } rc = aead_set_nonce (dfx); if (rc) goto leave; rc = aead_set_ad (dfx, 0); if (rc) goto leave; } else /* CFB encryption. */ { nprefix = blocksize; if ( ed->len && ed->len < (nprefix+2) ) { /* An invalid message. We can't check that during parsing because we may not know the used cipher then. */ rc = gpg_error (GPG_ERR_INV_PACKET); goto leave; } if ( ed->mdc_method ) { if (gcry_md_open (&dfx->mdc_hash, ed->mdc_method, 0 )) BUG (); if ( DBG_HASHING ) gcry_md_debug (dfx->mdc_hash, "checkmdc"); } rc = openpgp_cipher_open (&dfx->cipher_hd, dek->algo, GCRY_CIPHER_MODE_CFB, (GCRY_CIPHER_SECURE | ((ed->mdc_method || dek->algo >= 100)? 0 : GCRY_CIPHER_ENABLE_SYNC))); if (rc) { /* We should never get an error here cause we already checked * that the algorithm is available. */ BUG(); } /* log_hexdump( "thekey", dek->key, dek->keylen );*/ rc = gcry_cipher_setkey (dfx->cipher_hd, dek->key, dek->keylen); if ( gpg_err_code (rc) == GPG_ERR_WEAK_KEY ) { log_info(_("WARNING: message was encrypted with" " a weak key in the symmetric cipher.\n")); rc=0; } else if( rc ) { log_error("key setup failed: %s\n", gpg_strerror (rc) ); goto leave; } if (!ed->buf) { log_error(_("problem handling encrypted packet\n")); goto leave; } gcry_cipher_setiv (dfx->cipher_hd, NULL, 0); if ( ed->len ) { for (i=0; i < (nprefix+2) && ed->len; i++, ed->len-- ) { if ( (c=iobuf_get(ed->buf)) == -1 ) break; else temp[i] = c; } } else { for (i=0; i < (nprefix+2); i++ ) if ( (c=iobuf_get(ed->buf)) == -1 ) break; else temp[i] = c; } gcry_cipher_decrypt (dfx->cipher_hd, temp, nprefix+2, NULL, 0); gcry_cipher_sync (dfx->cipher_hd); p = temp; /* log_hexdump( "prefix", temp, nprefix+2 ); */ if (dek->symmetric && (p[nprefix-2] != p[nprefix] || p[nprefix-1] != p[nprefix+1]) ) { rc = gpg_error (GPG_ERR_BAD_KEY); goto leave; } if ( dfx->mdc_hash ) gcry_md_write (dfx->mdc_hash, temp, nprefix+2); } dfx->refcount++; dfx->partial = !!ed->is_partial; dfx->length = ed->len; if (ed->aead_algo) iobuf_push_filter ( ed->buf, aead_decode_filter, dfx ); else if (ed->mdc_method) iobuf_push_filter ( ed->buf, mdc_decode_filter, dfx ); else iobuf_push_filter ( ed->buf, decode_filter, dfx ); if (opt.unwrap_encryption) { char *filename = NULL; estream_t fp; rc = get_output_file ("", 0, ed->buf, &filename, &fp); if (! rc) { iobuf_t output = iobuf_esopen (fp, "w", 0); armor_filter_context_t *afx = NULL; if (opt.armor) { afx = new_armor_context (); push_armor_filter (afx, output); } iobuf_copy (output, ed->buf); if ((rc = iobuf_error (ed->buf))) log_error (_("error reading '%s': %s\n"), filename, gpg_strerror (rc)); else if ((rc = iobuf_error (output))) log_error (_("error writing '%s': %s\n"), filename, gpg_strerror (rc)); iobuf_close (output); if (afx) release_armor_context (afx); } xfree (filename); } else proc_packets (ctrl, procctx, ed->buf ); ed->buf = NULL; if (dfx->eof_seen > 1 ) rc = gpg_error (GPG_ERR_INV_PACKET); else if ( ed->mdc_method ) { /* We used to let parse-packet.c handle the MDC packet but this turned out to be a problem with compressed packets: With old style packets there is no length information available and the decompressor uses an implicit end. However we can't know this implicit end beforehand (:-) and thus may feed the decompressor with more bytes than actually needed. It would be possible to unread the extra bytes but due to our weird iobuf system any unread is non reliable due to filters already popped off. The easy and sane solution is to care about the MDC packet only here and never pass it to the packet parser. Fortunatley the OpenPGP spec requires a strict format for the MDC packet so that we know that 22 bytes are appended. */ int datalen = gcry_md_get_algo_dlen (ed->mdc_method); log_assert (dfx->cipher_hd); log_assert (dfx->mdc_hash); gcry_cipher_decrypt (dfx->cipher_hd, dfx->defer, 22, NULL, 0); gcry_md_write (dfx->mdc_hash, dfx->defer, 2); gcry_md_final (dfx->mdc_hash); if ( dfx->defer[0] != '\xd3' || dfx->defer[1] != '\x14' || datalen != 20 || memcmp (gcry_md_read (dfx->mdc_hash, 0), dfx->defer+2, datalen)) rc = gpg_error (GPG_ERR_BAD_SIGNATURE); /* log_printhex("MDC message:", dfx->defer, 22); */ /* log_printhex("MDC calc:", gcry_md_read (dfx->mdc_hash,0), datalen); */ } leave: release_dfx_context (dfx); return rc; } /* The core of the AEAD decryption. This is the underflow function of * the aead_decode_filter. */ static gpg_error_t aead_underflow (decode_filter_ctx_t dfx, iobuf_t a, byte *buf, size_t *ret_len) { const size_t size = *ret_len; /* The initial length of BUF. */ gpg_error_t err; size_t n; /* Finally the number of decrypted bytes in BUF. */ int c; log_assert (size > 64); /* Our code requires at least this size. */ /* Get at least 32 bytes and put it ahead in the buffer. */ if (dfx->partial) { for (n=32; n < 64; n++) { if ((c = iobuf_get (a)) == -1) break; buf[n] = c; } } else { for (n=32; n < 64 && dfx->length; n++, dfx->length--) { if ((c = iobuf_get (a)) == -1) break; /* Premature EOF. */ buf[n] = c; } } if (n == 64) { /* We got 32 bytes from A which are good for the last chunk's * auth tag and the final chunk's auth tag. On the first time * we don't have anything in the defer buffer and thus we move * those 32 bytes to the start of the buffer. All further calls * will copy the deferred 32 bytes to the start of the * buffer. */ if (!dfx->defer_filled) { memcpy (buf, buf+32, 32); n = 32; /* Continue at this position. */ } else { memcpy (buf, dfx->defer, 32); } /* Now fill up the provided buffer. */ if (dfx->partial) { for (; n < size; n++ ) { if ((c = iobuf_get (a)) == -1) { dfx->eof_seen = 1; /* Normal EOF. */ break; } buf[n] = c; } } else { for (; n < size && dfx->length; n++, dfx->length--) { c = iobuf_get (a); if (c == -1) { dfx->eof_seen = 3; /* Premature EOF. */ break; } buf[n] = c; } if (!dfx->length) dfx->eof_seen = 1; /* Normal EOF. */ } /* Move the trailing 32 bytes back to the defer buffer. We * got at least 64 bytes and thus a memmove is not needed. */ n -= 32; memcpy (dfx->defer, buf+n, 32); dfx->defer_filled = 1; } else if (!dfx->defer_filled) { /* EOF seen but empty defer buffer. This means that we did not * read enough for the two auth tags. */ n -= 32; memcpy (buf, buf+32, n ); dfx->eof_seen = 2; /* EOF with incomplete tag. */ } else { /* EOF seen (i.e. read less than 32 bytes). */ memcpy (buf, dfx->defer, 32); n -= 32; memcpy (dfx->defer, buf+n, 32); dfx->eof_seen = 1; /* Normal EOF. */ } log_debug ("decrypt: chunklen=%ju total=%ju size=%zu n=%zu%s\n", (uintmax_t)dfx->chunklen, (uintmax_t)dfx->total, size, n, dfx->eof_seen? " eof":""); /* Now decrypt the buffer. */ if (n && dfx->eof_seen > 1) { err = gpg_error (GPG_ERR_TRUNCATED); } else if (!n) { log_assert (dfx->eof_seen); err = gpg_error (GPG_ERR_EOF); } else { size_t off = 0; if (dfx->chunklen + n >= dfx->chunksize) { size_t n0 = dfx->chunksize - dfx->chunklen; log_debug ("chunksize will be reached: n0=%zu\n", n0); gcry_cipher_final (dfx->cipher_hd); err = gcry_cipher_decrypt (dfx->cipher_hd, buf, n0, NULL, 0); if (err) { log_debug ("gcry_cipher_decrypt failed (1): %s\n", gpg_strerror (err)); goto leave; } /*log_printhex (buf, n, "buf:");*/ dfx->chunklen += n0; dfx->total += n0; off = n0; n -= n0; log_debug ("bytes left: %zu off=%zu\n", n, off); log_assert (n >= 16); log_assert (dfx->defer_filled); log_printhex (buf+off, 16, "tag:"); err = gcry_cipher_checktag (dfx->cipher_hd, buf + off, 16); if (err) { log_debug ("gcry_cipher_checktag failed (1): %s\n", gpg_strerror (err)); /* Return Bad Signature like we do with MDC encryption. */ if (gpg_err_code (err) == GPG_ERR_CHECKSUM) err = gpg_error (GPG_ERR_BAD_SIGNATURE); goto leave; } /* Remove that tag from the output. */ memmove (buf + off, buf + off + 16, n - 16); n -= 16; /* Prepare a new chunk. */ dfx->chunklen = 0; dfx->chunkindex++; err = aead_set_nonce (dfx); if (err) goto leave; err = aead_set_ad (dfx, 0); if (err) goto leave; } if (dfx->eof_seen) { /* This is the last block of the last chunk. Its length may * not be a multiple of the block length. We expect that it * is followed by two authtags. The first being the one * from the current chunk and the second form the final * chunk encrypting the empty string. Note that for the * other blocks we assume a multiple of the block length * which is only true because the filter is called with * large 2^n sized buffers. There is no assert because * gcry_cipher_decrypt would detect such an error. */ gcry_cipher_final (dfx->cipher_hd); /*log_printhex (buf+off, n, "buf+off:");*/ } err = gcry_cipher_decrypt (dfx->cipher_hd, buf + off, n, NULL, 0); if (err) { log_debug ("gcry_cipher_decrypt failed (2): %s\n",gpg_strerror (err)); goto leave; } dfx->chunklen += n; dfx->total += n; if (dfx->eof_seen) { /* log_printhex (buf+off, n, "buf+off:"); */ log_debug ("eof seen: chunklen=%ju total=%ju off=%zu n=%zu\n", (uintmax_t)dfx->chunklen, (uintmax_t)dfx->total, off, n); log_assert (dfx->defer_filled); err = gcry_cipher_checktag (dfx->cipher_hd, dfx->defer, 16); if (err) { log_debug ("gcry_cipher_checktag failed (2): %s\n", gpg_strerror (err)); /* Return Bad Signature like we do with MDC encryption. */ if (gpg_err_code (err) == GPG_ERR_CHECKSUM) err = gpg_error (GPG_ERR_BAD_SIGNATURE); goto leave; } /* Check the final chunk. */ dfx->chunkindex++; err = aead_set_nonce (dfx); if (err) goto leave; err = aead_set_ad (dfx, 1); if (err) goto leave; gcry_cipher_final (dfx->cipher_hd); /* decrypt an empty string. */ err = gcry_cipher_decrypt (dfx->cipher_hd, buf, 0, NULL, 0); if (err) { log_debug ("gcry_cipher_decrypt failed (final): %s\n", gpg_strerror (err)); goto leave; } err = gcry_cipher_checktag (dfx->cipher_hd, dfx->defer+16, 16); if (err) { log_debug ("gcry_cipher_checktag failed (final): %s\n", gpg_strerror (err)); /* Return Bad Signature like we do with MDC encryption. */ if (gpg_err_code (err) == GPG_ERR_CHECKSUM) err = gpg_error (GPG_ERR_BAD_SIGNATURE); goto leave; } n += off; log_debug ("eof seen: returning %zu\n", n); /* log_printhex (buf, n, "buf:"); */ } else n += off; } leave: /* In case of a real error we better wipe out the buffer than to * keep partly encrypted data. */ if (err && gpg_err_code (err) != GPG_ERR_EOF) memset (buf, 0, size); *ret_len = n; return err; } /* The IOBUF filter used to decrypt AEAD encrypted data. */ static int aead_decode_filter (void *opaque, int control, IOBUF a, byte *buf, size_t *ret_len) { decode_filter_ctx_t dfx = opaque; int rc = 0; if ( control == IOBUFCTRL_UNDERFLOW && dfx->eof_seen ) { *ret_len = 0; rc = -1; } else if ( control == IOBUFCTRL_UNDERFLOW ) { log_assert (a); rc = aead_underflow (dfx, a, buf, ret_len); if (gpg_err_code (rc) == GPG_ERR_EOF) rc = -1; /* We need to use the old convention in the filter. */ } else if ( control == IOBUFCTRL_FREE ) { release_dfx_context (dfx); } else if ( control == IOBUFCTRL_DESC ) { mem2str (buf, "aead_decode_filter", *ret_len); } return rc; } static int mdc_decode_filter (void *opaque, int control, IOBUF a, byte *buf, size_t *ret_len) { decode_filter_ctx_t dfx = opaque; size_t n, size = *ret_len; int rc = 0; int c; /* Note: We need to distinguish between a partial and a fixed length packet. The first is the usual case as created by GPG. However for short messages the format degrades to a fixed length packet and other implementations might use fixed length as well. Only looking for the EOF on fixed data works only if the encrypted packet is not followed by other data. This used to be a long standing bug which was fixed on 2009-10-02. */ if ( control == IOBUFCTRL_UNDERFLOW && dfx->eof_seen ) { *ret_len = 0; rc = -1; } else if( control == IOBUFCTRL_UNDERFLOW ) { log_assert (a); log_assert (size > 44); /* Our code requires at least this size. */ /* Get at least 22 bytes and put it ahead in the buffer. */ if (dfx->partial) { for (n=22; n < 44; n++) { if ( (c = iobuf_get(a)) == -1 ) break; buf[n] = c; } } else { for (n=22; n < 44 && dfx->length; n++, dfx->length--) { c = iobuf_get (a); if (c == -1) break; /* Premature EOF. */ buf[n] = c; } } if (n == 44) { /* We have enough stuff - flush the deferred stuff. */ if ( !dfx->defer_filled ) /* First time. */ { memcpy (buf, buf+22, 22); n = 22; } else { memcpy (buf, dfx->defer, 22); } /* Fill up the buffer. */ if (dfx->partial) { for (; n < size; n++ ) { if ( (c = iobuf_get(a)) == -1 ) { dfx->eof_seen = 1; /* Normal EOF. */ break; } buf[n] = c; } } else { for (; n < size && dfx->length; n++, dfx->length--) { c = iobuf_get(a); if (c == -1) { dfx->eof_seen = 3; /* Premature EOF. */ break; } buf[n] = c; } if (!dfx->length) dfx->eof_seen = 1; /* Normal EOF. */ } /* Move the trailing 22 bytes back to the defer buffer. We have at least 44 bytes thus a memmove is not needed. */ n -= 22; memcpy (dfx->defer, buf+n, 22 ); dfx->defer_filled = 1; } else if ( !dfx->defer_filled ) /* EOF seen but empty defer buffer. */ { /* This is bad because it means an incomplete hash. */ n -= 22; memcpy (buf, buf+22, n ); dfx->eof_seen = 2; /* EOF with incomplete hash. */ } else /* EOF seen (i.e. read less than 22 bytes). */ { memcpy (buf, dfx->defer, 22 ); n -= 22; memcpy (dfx->defer, buf+n, 22 ); dfx->eof_seen = 1; /* Normal EOF. */ } if ( n ) { if ( dfx->cipher_hd ) gcry_cipher_decrypt (dfx->cipher_hd, buf, n, NULL, 0); if ( dfx->mdc_hash ) gcry_md_write (dfx->mdc_hash, buf, n); } else { log_assert ( dfx->eof_seen ); rc = -1; /* Return EOF. */ } *ret_len = n; } else if ( control == IOBUFCTRL_FREE ) { release_dfx_context (dfx); } else if ( control == IOBUFCTRL_DESC ) { mem2str (buf, "mdc_decode_filter", *ret_len); } return rc; } static int decode_filter( void *opaque, int control, IOBUF a, byte *buf, size_t *ret_len) { decode_filter_ctx_t fc = opaque; size_t size = *ret_len; size_t n; int c, rc = 0; if ( control == IOBUFCTRL_UNDERFLOW && fc->eof_seen ) { *ret_len = 0; rc = -1; } else if ( control == IOBUFCTRL_UNDERFLOW ) { log_assert (a); if (fc->partial) { for (n=0; n < size; n++ ) { c = iobuf_get(a); if (c == -1) { fc->eof_seen = 1; /* Normal EOF. */ break; } buf[n] = c; } } else { for (n=0; n < size && fc->length; n++, fc->length--) { c = iobuf_get(a); if (c == -1) { fc->eof_seen = 3; /* Premature EOF. */ break; } buf[n] = c; } if (!fc->length) fc->eof_seen = 1; /* Normal EOF. */ } if (n) { if (fc->cipher_hd) gcry_cipher_decrypt (fc->cipher_hd, buf, n, NULL, 0); } else { if (!fc->eof_seen) fc->eof_seen = 1; rc = -1; /* Return EOF. */ } *ret_len = n; } else if ( control == IOBUFCTRL_FREE ) { release_dfx_context (fc); } else if ( control == IOBUFCTRL_DESC ) { mem2str (buf, "decode_filter", *ret_len); } return rc; } diff --git a/g10/encrypt.c b/g10/encrypt.c index 4cc4b1a29..c6c9e3a03 100644 --- a/g10/encrypt.c +++ b/g10/encrypt.c @@ -1,1177 +1,1240 @@ /* encrypt.c - Main encryption driver * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, * 2006, 2009 Free Software Foundation, Inc. * Copyright (C) 2016 g10 Code GmbH * * This file is part of GnuPG. * * GnuPG is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * GnuPG is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . */ #include #include #include #include #include #include "gpg.h" #include "options.h" #include "packet.h" #include "../common/status.h" #include "../common/iobuf.h" #include "keydb.h" #include "../common/util.h" #include "main.h" #include "filter.h" #include "trustdb.h" #include "../common/i18n.h" #include "../common/status.h" #include "pkglue.h" #include "../common/compliance.h" static int encrypt_simple( const char *filename, int mode, int use_seskey ); static int write_pubkey_enc_from_list (ctrl_t ctrl, PK_LIST pk_list, DEK *dek, iobuf_t out); /**************** * Encrypt FILENAME with only the symmetric cipher. Take input from - * stdin if FILENAME is NULL. + * stdin if FILENAME is NULL. If --force-aead is used we use an SKESK. */ int encrypt_symmetric (const char *filename) { - return encrypt_simple( filename, 1, 0 ); + return encrypt_simple( filename, 1, opt.force_aead); } /**************** * Encrypt FILENAME as a literal data packet only. Take input from * stdin if FILENAME is NULL. */ int encrypt_store (const char *filename) { return encrypt_simple( filename, 0, 0 ); } /* Encrypt a session key using DEK and store a pointer to the result * at R_ENCKEY and its length at R_ENCKEYLEN. * - * R_SESKEY points to the unencrypted session key (.KEY, >KEYLEN) and + * R_SESKEY points to the unencrypted session key (.KEY, .KEYLEN) and * the algorithm that will be used to encrypt the contents of the * SKESK packet (.ALGO). If R_SESKEY points to NULL, then a random * session key that is appropriate for DEK->ALGO is generated and - * stored at R_SESKEY. + * stored at R_SESKEY. If AEAD_ALGO is not 0 the given AEAD algorithm + * is used for encryption. */ gpg_error_t -encrypt_seskey (DEK *dek, DEK **r_seskey, void **r_enckey, size_t *r_enckeylen) +encrypt_seskey (DEK *dek, aead_algo_t aead_algo, + DEK **r_seskey, void **r_enckey, size_t *r_enckeylen) { gpg_error_t err; gcry_cipher_hd_t hd = NULL; byte *buf = NULL; DEK *seskey; *r_enckey = NULL; *r_enckeylen = 0; if (*r_seskey) seskey = *r_seskey; else { seskey = xtrycalloc (1, sizeof(DEK)); if (!seskey) { err = gpg_error_from_syserror (); goto leave; } seskey->algo = dek->algo; make_session_key (seskey); /*log_hexdump( "thekey", c->key, c->keylen );*/ } - buf = xtrymalloc_secure (1 + seskey->keylen); - if (!buf) + + if (aead_algo) { - err = gpg_error_from_syserror (); - goto leave; - } + unsigned int noncelen; + enum gcry_cipher_modes ciphermode; + byte ad[4]; + + err = openpgp_aead_algo_info (aead_algo, &ciphermode, &noncelen); + if (err) + goto leave; + + /* Allocate space for the nonce, the key, and the authentication + * tag (16). */ + buf = xtrymalloc_secure (noncelen + seskey->keylen + 16); + if (!buf) + { + err = gpg_error_from_syserror (); + goto leave; + } - /* The encrypted session key is prefixed with a one-octet algorithm id. */ - buf[0] = seskey->algo; - memcpy (buf + 1, seskey->key, seskey->keylen); - - err = openpgp_cipher_open (&hd, dek->algo, GCRY_CIPHER_MODE_CFB, 1); - if (!err) - err = gcry_cipher_setkey (hd, dek->key, dek->keylen); - if (!err) - err = gcry_cipher_setiv (hd, NULL, 0); - if (!err) - err = gcry_cipher_encrypt (hd, buf, seskey->keylen + 1, NULL, 0); - if (err) - goto leave; + gcry_randomize (buf, noncelen, GCRY_STRONG_RANDOM); + + err = openpgp_cipher_open (&hd, dek->algo, + ciphermode, GCRY_CIPHER_SECURE); + if (!err) + err = gcry_cipher_setkey (hd, dek->key, dek->keylen); + if (!err) + err = gcry_cipher_setiv (hd, buf, noncelen); + if (err) + goto leave; + + ad[0] = (0xc0 | PKT_SYMKEY_ENC); + ad[1] = 5; + ad[2] = dek->algo; + ad[3] = aead_algo; + err = gcry_cipher_authenticate (hd, ad, 4); + if (err) + goto leave; + + memcpy (buf + noncelen, seskey->key, seskey->keylen); + gcry_cipher_final (hd); + err = gcry_cipher_encrypt (hd, buf + noncelen, seskey->keylen, NULL,0); + if (err) + goto leave; + err = gcry_cipher_gettag (hd, buf + noncelen + seskey->keylen, 16); + if (err) + goto leave; + *r_enckeylen = noncelen + seskey->keylen + 16; + *r_enckey = buf; + buf = NULL; + } + else + { + /* In the old version 4 SKESK the encrypted session key is + * prefixed with a one-octet algorithm id. */ + buf = xtrymalloc_secure (1 + seskey->keylen); + if (!buf) + { + err = gpg_error_from_syserror (); + goto leave; + } + buf[0] = seskey->algo; + memcpy (buf + 1, seskey->key, seskey->keylen); + + err = openpgp_cipher_open (&hd, dek->algo, GCRY_CIPHER_MODE_CFB, 1); + if (!err) + err = gcry_cipher_setkey (hd, dek->key, dek->keylen); + if (!err) + err = gcry_cipher_setiv (hd, NULL, 0); + if (!err) + err = gcry_cipher_encrypt (hd, buf, seskey->keylen + 1, NULL, 0); + if (err) + goto leave; + *r_enckeylen = seskey->keylen + 1; + *r_enckey = buf; + buf = NULL; + } - *r_enckey = buf; - buf = NULL; - *r_enckeylen = seskey->keylen + 1; /* Return the session key in case we allocated it. */ *r_seskey = seskey; seskey = NULL; leave: gcry_cipher_close (hd); if (seskey != *r_seskey) xfree (seskey); xfree (buf); return err; } /* Return the AEAD algo if we shall use AEAD mode. Returns 0 if AEAD * shall not be used. */ aead_algo_t use_aead (pk_list_t pk_list, int algo) { int can_use; if (!opt.flags.rfc4880bis) { if (opt.force_aead) log_info ("Warning: Option %s currently requires option '%s'\n", "--force-aead", "--rfc4880bis"); return 0; } can_use = openpgp_cipher_get_algo_blklen (algo) == 16; /* With --force-mdc we clearly do not want AEAD. */ if (opt.force_mdc) return 0; /* However with --force-aead we want AEAD. */ if (opt.force_aead) { if (!can_use) { log_info ("Warning: request to use AEAD ignored for cipher '%s'\n", openpgp_cipher_algo_name (algo)); return 0; } return default_aead_algo (); } /* AEAD does only work with 128 bit cipher blocklength. */ if (!can_use) return 0; /* If all keys support AEAD we can use it. */ return select_aead_from_pklist (pk_list); } /* We try very hard to use a MDC */ int use_mdc (pk_list_t pk_list,int algo) { /* RFC-2440 don't has MDC */ if (RFC2440) return 0; /* --force-mdc overrides --disable-mdc */ if(opt.force_mdc) return 1; if(opt.disable_mdc) return 0; /* Do the keys really support MDC? */ if(select_mdc_from_pklist(pk_list)) return 1; /* The keys don't support MDC, so now we do a bit of a hack - if any of the AESes or TWOFISH are in the prefs, we assume that the user can handle a MDC. This is valid for PGP 7, which can handle MDCs though it will not generate them. 2440bis allows this, by the way. */ if(select_algo_from_prefs(pk_list,PREFTYPE_SYM, CIPHER_ALGO_AES,NULL)==CIPHER_ALGO_AES) return 1; if(select_algo_from_prefs(pk_list,PREFTYPE_SYM, CIPHER_ALGO_AES192,NULL)==CIPHER_ALGO_AES192) return 1; if(select_algo_from_prefs(pk_list,PREFTYPE_SYM, CIPHER_ALGO_AES256,NULL)==CIPHER_ALGO_AES256) return 1; if(select_algo_from_prefs(pk_list,PREFTYPE_SYM, CIPHER_ALGO_TWOFISH,NULL)==CIPHER_ALGO_TWOFISH) return 1; /* Last try. Use MDC for the modern ciphers. */ if (openpgp_cipher_get_algo_blklen (algo) != 8) return 1; if (opt.verbose) warn_missing_mdc_from_pklist (pk_list); return 0; /* No MDC */ } /* We don't want to use use_seskey yet because older gnupg versions can't handle it, and there isn't really any point unless we're making a message that can be decrypted by a public key or passphrase. */ static int encrypt_simple (const char *filename, int mode, int use_seskey) { iobuf_t inp, out; PACKET pkt; PKT_plaintext *pt = NULL; STRING2KEY *s2k = NULL; void *enckey = NULL; size_t enckeylen = 0; int rc = 0; u32 filesize; cipher_filter_context_t cfx; armor_filter_context_t *afx = NULL; compress_filter_context_t zfx; text_filter_context_t tfx; progress_filter_context_t *pfx; int do_compress = !!default_compress_algo(); if (!gnupg_rng_is_compliant (opt.compliance)) { rc = gpg_error (GPG_ERR_FORBIDDEN); log_error (_("%s is not compliant with %s mode\n"), "RNG", gnupg_compliance_option_string (opt.compliance)); write_status_error ("random-compliance", rc); return rc; } pfx = new_progress_context (); memset( &cfx, 0, sizeof cfx); memset( &zfx, 0, sizeof zfx); memset( &tfx, 0, sizeof tfx); init_packet(&pkt); /* Prepare iobufs. */ inp = iobuf_open(filename); if (inp) iobuf_ioctl (inp, IOBUF_IOCTL_NO_CACHE, 1, NULL); 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"), filename? filename: "[stdin]", strerror(errno) ); release_progress_context (pfx); return rc; } handle_progress (pfx, inp, filename); if (opt.textmode) iobuf_push_filter( inp, text_filter, &tfx ); cfx.dek = NULL; if ( mode ) { int canceled; aead_algo_t aead_algo; s2k = xmalloc_clear( sizeof *s2k ); s2k->mode = opt.s2k_mode; s2k->hash_algo = S2K_DIGEST_ALGO; cfx.dek = passphrase_to_dek (default_cipher_algo (), s2k, 1, 0, NULL, &canceled); if ( !cfx.dek || !cfx.dek->keylen ) { rc = gpg_error (canceled? GPG_ERR_CANCELED:GPG_ERR_INV_PASSPHRASE); xfree (cfx.dek); xfree (s2k); iobuf_close (inp); log_error (_("error creating passphrase: %s\n"), gpg_strerror (rc)); release_progress_context (pfx); return rc; } if (use_seskey && s2k->mode != 1 && s2k->mode != 3) { use_seskey = 0; log_info (_("can't use a symmetric ESK packet " "due to the S2K mode\n")); } /* See whether we want to use AEAD. */ aead_algo = use_aead (NULL, cfx.dek->algo); if ( use_seskey ) { DEK *dek = NULL; - rc = encrypt_seskey (cfx.dek, &dek, &enckey, &enckeylen); + rc = encrypt_seskey (cfx.dek, aead_algo, &dek, &enckey, &enckeylen); if (rc) { xfree (cfx.dek); xfree (s2k); iobuf_close (inp); release_progress_context (pfx); return rc; } /* Replace key in DEK. */ xfree (cfx.dek); cfx.dek = dek; } - if (opt.verbose) - log_info(_("using cipher %s\n"), - openpgp_cipher_algo_name (cfx.dek->algo)); - if (aead_algo) cfx.dek->use_aead = aead_algo; else cfx.dek->use_mdc = !!use_mdc (NULL, cfx.dek->algo); + + if (opt.verbose) + log_info(_("using cipher %s.%s\n"), + openpgp_cipher_algo_name (cfx.dek->algo), + cfx.dek->use_aead? openpgp_aead_algo_name (cfx.dek->use_aead) + /**/ : "CFB"); } if (do_compress && cfx.dek && (cfx.dek->use_mdc || cfx.dek->use_aead) && is_file_compressed(filename, &rc)) { if (opt.verbose) log_info(_("'%s' already compressed\n"), filename); do_compress = 0; } if ( rc || (rc = open_outfile (-1, filename, opt.armor? 1:0, 0, &out ))) { iobuf_cancel (inp); xfree (cfx.dek); xfree (s2k); release_progress_context (pfx); return rc; } if ( opt.armor ) { afx = new_armor_context (); push_armor_filter (afx, out); } if ( s2k ) { /* Fixme: This is quite similar to write_symkey_enc. */ PKT_symkey_enc *enc = xmalloc_clear (sizeof *enc + enckeylen); - enc->version = 4; + enc->version = cfx.dek->use_aead ? 5 : 4; enc->cipher_algo = cfx.dek->algo; + enc->aead_algo = cfx.dek->use_aead; enc->s2k = *s2k; if (enckeylen) { enc->seskeylen = enckeylen; memcpy (enc->seskey, enckey, enckeylen); } pkt.pkttype = PKT_SYMKEY_ENC; pkt.pkt.symkey_enc = enc; if ((rc = build_packet( out, &pkt ))) log_error("build symkey packet failed: %s\n", gpg_strerror (rc) ); xfree (enc); xfree (enckey); enckey = NULL; } if (!opt.no_literal) pt = setup_plaintext_name (filename, inp); /* Note that PGP 5 has problems decrypting symmetrically encrypted data if the file length is in the inner packet. It works when only partial length headers are use. In the past, we always used partial body length here, but since PGP 2, PGP 6, and PGP 7 need the file length, and nobody should be using PGP 5 nowadays anyway, this is now set to the file length. Note also that this only applies to the RFC-1991 style symmetric messages, and not the RFC-2440 style. PGP 6 and 7 work with either partial length or fixed length with the new style messages. */ if ( !iobuf_is_pipe_filename (filename) && *filename && !opt.textmode ) { off_t tmpsize; int overflow; if ( !(tmpsize = iobuf_get_filelength(inp, &overflow)) && !overflow && opt.verbose) log_info(_("WARNING: '%s' is an empty file\n"), filename ); /* 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; } else filesize = opt.set_filesize ? opt.set_filesize : 0; /* stdin */ if (!opt.no_literal) { /* Note that PT has been initialized above in !no_literal mode. */ pt->timestamp = make_timestamp(); pt->mode = opt.mimemode? 'm' : opt.textmode? 't' : 'b'; pt->len = filesize; pt->new_ctb = !pt->len; pt->buf = inp; pkt.pkttype = PKT_PLAINTEXT; pkt.pkt.plaintext = pt; cfx.datalen = filesize && !do_compress ? calc_packet_length( &pkt ) : 0; } else { cfx.datalen = filesize && !do_compress ? filesize : 0; pkt.pkttype = 0; pkt.pkt.generic = NULL; } /* Register the cipher filter. */ if (mode) iobuf_push_filter (out, cfx.dek->use_aead? cipher_filter_aead /**/ : cipher_filter_cfb, &cfx ); /* Register the compress filter. */ if ( do_compress ) { if (cfx.dek && (cfx.dek->use_mdc || cfx.dek->use_aead)) zfx.new_ctb = 1; push_compress_filter (out, &zfx, default_compress_algo()); } /* Do the work. */ if (!opt.no_literal) { if ( (rc = build_packet( out, &pkt )) ) log_error("build_packet failed: %s\n", gpg_strerror (rc) ); } else { /* User requested not to create a literal packet, so we copy the plain data. */ 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 */ } /* Finish the stuff. */ iobuf_close (inp); if (rc) iobuf_cancel(out); else { iobuf_close (out); /* fixme: check returncode */ if (mode) write_status ( STATUS_END_ENCRYPTION ); } if (pt) pt->buf = NULL; free_packet (&pkt, NULL); xfree (enckey); xfree (cfx.dek); xfree (s2k); release_armor_context (afx); release_progress_context (pfx); return rc; } int setup_symkey (STRING2KEY **symkey_s2k,DEK **symkey_dek) { int canceled; *symkey_s2k=xmalloc_clear(sizeof(STRING2KEY)); (*symkey_s2k)->mode = opt.s2k_mode; (*symkey_s2k)->hash_algo = S2K_DIGEST_ALGO; *symkey_dek = passphrase_to_dek (opt.s2k_cipher_algo, *symkey_s2k, 1, 0, NULL, &canceled); if(!*symkey_dek || !(*symkey_dek)->keylen) { xfree(*symkey_dek); xfree(*symkey_s2k); return gpg_error (canceled?GPG_ERR_CANCELED:GPG_ERR_BAD_PASSPHRASE); } return 0; } static int -write_symkey_enc (STRING2KEY *symkey_s2k, DEK *symkey_dek, DEK *dek, - iobuf_t out) +write_symkey_enc (STRING2KEY *symkey_s2k, aead_algo_t aead_algo, + DEK *symkey_dek, DEK *dek, iobuf_t out) { int rc; void *enckey; size_t enckeylen; PKT_symkey_enc *enc; PACKET pkt; - rc = encrypt_seskey (symkey_dek, &dek, &enckey, &enckeylen); + rc = encrypt_seskey (symkey_dek, aead_algo, &dek, &enckey, &enckeylen); if (rc) return rc; enc = xtrycalloc (1, sizeof (PKT_symkey_enc) + enckeylen); if (!enc) { rc = gpg_error_from_syserror (); xfree (enckey); return rc; } - enc->version = 4; + enc->version = aead_algo? 5 : 4; enc->cipher_algo = opt.s2k_cipher_algo; + enc->aead_algo = aead_algo; enc->s2k = *symkey_s2k; enc->seskeylen = enckeylen; memcpy (enc->seskey, enckey, enckeylen); xfree (enckey); pkt.pkttype = PKT_SYMKEY_ENC; pkt.pkt.symkey_enc = enc; if ((rc=build_packet(out,&pkt))) log_error("build symkey_enc packet failed: %s\n",gpg_strerror (rc)); xfree (enc); return rc; } /* * Encrypt the file with the given userids (or ask if none is * supplied). Either FILENAME or FILEFD must be given, but not both. * The caller may provide a checked list of public keys in * PROVIDED_PKS; if not the function builds a list of keys on its own. * * Note that FILEFD is currently only used by cmd_encrypt in the * not yet finished server.c. */ int encrypt_crypt (ctrl_t ctrl, int filefd, const char *filename, strlist_t remusr, int use_symkey, pk_list_t provided_keys, int outputfd) { iobuf_t inp = NULL; iobuf_t out = NULL; PACKET pkt; PKT_plaintext *pt = NULL; DEK *symkey_dek = NULL; STRING2KEY *symkey_s2k = NULL; int rc = 0, rc2 = 0; u32 filesize; cipher_filter_context_t cfx; armor_filter_context_t *afx = NULL; compress_filter_context_t zfx; text_filter_context_t tfx; progress_filter_context_t *pfx; PK_LIST pk_list; int do_compress; int compliant; if (filefd != -1 && filename) return gpg_error (GPG_ERR_INV_ARG); /* Both given. */ do_compress = !!opt.compress_algo; pfx = new_progress_context (); memset( &cfx, 0, sizeof cfx); memset( &zfx, 0, sizeof zfx); memset( &tfx, 0, sizeof tfx); init_packet(&pkt); if (use_symkey && (rc=setup_symkey(&symkey_s2k,&symkey_dek))) { release_progress_context (pfx); return rc; } if (provided_keys) pk_list = provided_keys; else { if ((rc = build_pk_list (ctrl, remusr, &pk_list))) { release_progress_context (pfx); return rc; } } /* Prepare iobufs. */ #ifdef HAVE_W32_SYSTEM if (filefd == -1) inp = iobuf_open (filename); else { inp = NULL; gpg_err_set_errno (ENOSYS); } #else if (filefd == GNUPG_INVALID_FD) inp = iobuf_open (filename); else inp = iobuf_fdopen_nc (FD2INT(filefd), "rb"); #endif if (inp) iobuf_ioctl (inp, IOBUF_IOCTL_NO_CACHE, 1, NULL); if (inp && is_secured_file (iobuf_get_fd (inp))) { iobuf_close (inp); inp = NULL; gpg_err_set_errno (EPERM); } if (!inp) { char xname[64]; rc = gpg_error_from_syserror (); if (filefd != -1) snprintf (xname, sizeof xname, "[fd %d]", filefd); else if (!filename) strcpy (xname, "[stdin]"); else *xname = 0; log_error (_("can't open '%s': %s\n"), *xname? xname : filename, gpg_strerror (rc) ); goto leave; } if (opt.verbose) log_info (_("reading from '%s'\n"), iobuf_get_fname_nonnull (inp)); handle_progress (pfx, inp, filename); if (opt.textmode) iobuf_push_filter (inp, text_filter, &tfx); rc = open_outfile (outputfd, filename, opt.armor? 1:0, 0, &out); if (rc) goto leave; if (opt.armor) { afx = new_armor_context (); push_armor_filter (afx, out); } /* Create a session key. */ cfx.dek = xmalloc_secure_clear (sizeof *cfx.dek); if (!opt.def_cipher_algo) { /* Try to get it from the prefs. */ cfx.dek->algo = select_algo_from_prefs (pk_list, PREFTYPE_SYM, -1, NULL); /* The only way select_algo_from_prefs can fail here is when mixing v3 and v4 keys, as v4 keys have an implicit preference entry for 3DES, and the pk_list cannot be empty. In this case, use 3DES anyway as it's the safest choice - perhaps the v3 key is being used in an OpenPGP implementation and we know that the implementation behind any v4 key can handle 3DES. */ if (cfx.dek->algo == -1) { cfx.dek->algo = CIPHER_ALGO_3DES; } /* In case 3DES has been selected, print a warning if any key does not have a preference for AES. This should help to indentify why encrypting to several recipients falls back to 3DES. */ if (opt.verbose && cfx.dek->algo == CIPHER_ALGO_3DES) warn_missing_aes_from_pklist (pk_list); } else { if (!opt.expert && (select_algo_from_prefs (pk_list, PREFTYPE_SYM, opt.def_cipher_algo, NULL) != opt.def_cipher_algo)) { log_info(_("WARNING: forcing symmetric cipher %s (%d)" " violates recipient preferences\n"), openpgp_cipher_algo_name (opt.def_cipher_algo), opt.def_cipher_algo); } cfx.dek->algo = opt.def_cipher_algo; } /* Check compliance. */ if (! gnupg_cipher_is_allowed (opt.compliance, 1, cfx.dek->algo, GCRY_CIPHER_MODE_CFB)) { log_error (_("cipher algorithm '%s' may not be used in %s mode\n"), openpgp_cipher_algo_name (cfx.dek->algo), gnupg_compliance_option_string (opt.compliance)); rc = gpg_error (GPG_ERR_CIPHER_ALGO); goto leave; } if (!gnupg_rng_is_compliant (opt.compliance)) { rc = gpg_error (GPG_ERR_FORBIDDEN); log_error (_("%s is not compliant with %s mode\n"), "RNG", gnupg_compliance_option_string (opt.compliance)); write_status_error ("random-compliance", rc); goto leave; } compliant = gnupg_cipher_is_compliant (CO_DE_VS, cfx.dek->algo, GCRY_CIPHER_MODE_CFB); { pk_list_t pkr; for (pkr = pk_list; pkr; pkr = pkr->next) { PKT_public_key *pk = pkr->pk; unsigned int nbits = nbits_from_pk (pk); if (!gnupg_pk_is_compliant (opt.compliance, pk->pubkey_algo, pk->pkey, nbits, NULL)) log_info (_("WARNING: key %s is not suitable for encryption" " in %s mode\n"), keystr_from_pk (pk), gnupg_compliance_option_string (opt.compliance)); if (compliant && !gnupg_pk_is_compliant (CO_DE_VS, pk->pubkey_algo, pk->pkey, nbits, NULL)) compliant = 0; } } if (compliant) write_status_strings (STATUS_ENCRYPTION_COMPLIANCE_MODE, gnupg_status_compliance_flag (CO_DE_VS), NULL); cfx.dek->use_aead = use_aead (pk_list, cfx.dek->algo); if (!cfx.dek->use_aead) cfx.dek->use_mdc = !!use_mdc (pk_list, cfx.dek->algo); /* Only do the is-file-already-compressed check if we are using a * MDC or AEAD. This forces compressed files to be re-compressed if * we do not have a MDC to give some protection against chosen * ciphertext attacks. */ if (do_compress && (cfx.dek->use_mdc || cfx.dek->use_aead) && is_file_compressed (filename, &rc2)) { if (opt.verbose) log_info(_("'%s' already compressed\n"), filename); do_compress = 0; } if (rc2) { rc = rc2; goto leave; } make_session_key (cfx.dek); if (DBG_CRYPTO) log_printhex (cfx.dek->key, cfx.dek->keylen, "DEK is: "); rc = write_pubkey_enc_from_list (ctrl, pk_list, cfx.dek, out); if (rc) goto leave; /* We put the passphrase (if any) after any public keys as this - seems to be the most useful on the recipient side - there is no - point in prompting a user for a passphrase if they have the - secret key needed to decrypt. */ - if(use_symkey && (rc = write_symkey_enc(symkey_s2k,symkey_dek,cfx.dek,out))) + * seems to be the most useful on the recipient side - there is no + * point in prompting a user for a passphrase if they have the + * secret key needed to decrypt. */ + if (use_symkey && (rc = write_symkey_enc (symkey_s2k, cfx.dek->use_aead, + symkey_dek, cfx.dek, out))) goto leave; if (!opt.no_literal) pt = setup_plaintext_name (filename, inp); /* Get the size of the file if possible, i.e., if it is a real file. */ if (filename && *filename && !iobuf_is_pipe_filename (filename) && !opt.textmode ) { off_t tmpsize; int overflow; if ( !(tmpsize = iobuf_get_filelength(inp, &overflow)) && !overflow && opt.verbose) log_info(_("WARNING: '%s' is an empty file\n"), filename ); /* 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; } else filesize = opt.set_filesize ? opt.set_filesize : 0; /* stdin */ if (!opt.no_literal) { pt->timestamp = make_timestamp(); pt->mode = opt.mimemode? 'm' : opt.textmode ? 't' : 'b'; pt->len = filesize; pt->new_ctb = !pt->len; pt->buf = inp; pkt.pkttype = PKT_PLAINTEXT; pkt.pkt.plaintext = pt; cfx.datalen = filesize && !do_compress? calc_packet_length( &pkt ) : 0; } else cfx.datalen = filesize && !do_compress ? filesize : 0; /* Register the cipher filter. */ iobuf_push_filter (out, cfx.dek->use_aead? cipher_filter_aead /**/ : cipher_filter_cfb, &cfx); /* Register the compress filter. */ if (do_compress) { int compr_algo = opt.compress_algo; if (compr_algo == -1) { compr_algo = select_algo_from_prefs (pk_list, PREFTYPE_ZIP, -1, NULL); if (compr_algo == -1) compr_algo = DEFAULT_COMPRESS_ALGO; /* Theoretically impossible to get here since uncompressed is implicit. */ } else if (!opt.expert && 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) { if (cfx.dek && (cfx.dek->use_mdc || cfx.dek->use_aead)) zfx.new_ctb = 1; push_compress_filter (out,&zfx,compr_algo); } } /* Do the work. */ if (!opt.no_literal) { if ((rc = build_packet( out, &pkt ))) log_error ("build_packet failed: %s\n", gpg_strerror (rc)); } else { /* User requested not to create a literal packet, so we copy the plain data. */ byte copy_buffer[4096]; int bytes_copied; while ((bytes_copied = iobuf_read (inp, copy_buffer, 4096)) != -1) { rc = iobuf_write (out, copy_buffer, bytes_copied); if (rc) { log_error ("copying input to output failed: %s\n", gpg_strerror (rc)); break; } } wipememory (copy_buffer, 4096); /* Burn the buffer. */ } /* Finish the stuff. */ leave: iobuf_close (inp); if (rc) iobuf_cancel (out); else { iobuf_close (out); /* fixme: check returncode */ write_status (STATUS_END_ENCRYPTION); } if (pt) pt->buf = NULL; free_packet (&pkt, NULL); xfree (cfx.dek); xfree (symkey_dek); xfree (symkey_s2k); if (!provided_keys) release_pk_list (pk_list); release_armor_context (afx); release_progress_context (pfx); return rc; } /* * Filter to do a complete public key encryption. */ int encrypt_filter (void *opaque, int control, iobuf_t a, byte *buf, size_t *ret_len) { size_t size = *ret_len; encrypt_filter_context_t *efx = opaque; int rc = 0; if (control == IOBUFCTRL_UNDERFLOW) /* decrypt */ { BUG(); /* not used */ } else if ( control == IOBUFCTRL_FLUSH ) /* encrypt */ { if ( !efx->header_okay ) { efx->cfx.dek = xmalloc_secure_clear ( sizeof *efx->cfx.dek ); if ( !opt.def_cipher_algo ) { /* Try to get it from the prefs. */ efx->cfx.dek->algo = select_algo_from_prefs (efx->pk_list, PREFTYPE_SYM, -1, NULL); if (efx->cfx.dek->algo == -1 ) { /* Because 3DES is implicitly in the prefs, this can only happen if we do not have any public keys in the list. */ efx->cfx.dek->algo = DEFAULT_CIPHER_ALGO; } /* In case 3DES has been selected, print a warning if any key does not have a preference for AES. This should help to indentify why encrypting to several recipients falls back to 3DES. */ if (opt.verbose && efx->cfx.dek->algo == CIPHER_ALGO_3DES) warn_missing_aes_from_pklist (efx->pk_list); } else { if (!opt.expert && select_algo_from_prefs (efx->pk_list,PREFTYPE_SYM, opt.def_cipher_algo, NULL) != opt.def_cipher_algo) log_info(_("forcing symmetric cipher %s (%d) " "violates recipient preferences\n"), openpgp_cipher_algo_name (opt.def_cipher_algo), opt.def_cipher_algo); efx->cfx.dek->algo = opt.def_cipher_algo; } efx->cfx.dek->use_aead = use_aead (efx->pk_list, efx->cfx.dek->algo); if (!efx->cfx.dek->use_aead) efx->cfx.dek->use_mdc = !!use_mdc (efx->pk_list,efx->cfx.dek->algo); make_session_key ( efx->cfx.dek ); if (DBG_CRYPTO) log_printhex (efx->cfx.dek->key, efx->cfx.dek->keylen, "DEK is: "); rc = write_pubkey_enc_from_list (efx->ctrl, efx->pk_list, efx->cfx.dek, a); if (rc) return rc; if(efx->symkey_s2k && efx->symkey_dek) { - rc=write_symkey_enc(efx->symkey_s2k,efx->symkey_dek, - efx->cfx.dek,a); - if(rc) + rc = write_symkey_enc (efx->symkey_s2k, efx->cfx.dek->use_aead, + efx->symkey_dek, efx->cfx.dek, a); + if (rc) return rc; } iobuf_push_filter (a, efx->cfx.dek->use_aead? cipher_filter_aead /**/ : cipher_filter_cfb, &efx->cfx); efx->header_okay = 1; } rc = iobuf_write (a, buf, size); } else if (control == IOBUFCTRL_FREE) { xfree (efx->symkey_dek); xfree (efx->symkey_s2k); } else if ( control == IOBUFCTRL_DESC ) { mem2str (buf, "encrypt_filter", *ret_len); } return rc; } /* * Write a pubkey-enc packet for the public key PK to OUT. */ int write_pubkey_enc (ctrl_t ctrl, PKT_public_key *pk, int throw_keyid, DEK *dek, iobuf_t out) { PACKET pkt; PKT_pubkey_enc *enc; int rc; gcry_mpi_t frame; print_pubkey_algo_note ( pk->pubkey_algo ); enc = xmalloc_clear ( sizeof *enc ); enc->pubkey_algo = pk->pubkey_algo; keyid_from_pk( pk, enc->keyid ); enc->throw_keyid = throw_keyid; /* Okay, what's going on: We have the session key somewhere in * the structure DEK and want to encode this session key in an * integer value of n bits. pubkey_nbits gives us the number of * bits we have to use. We then encode the session key in some * way and we get it back in the big intger value FRAME. Then * we use FRAME, the public key PK->PKEY and the algorithm * number PK->PUBKEY_ALGO and pass it to pubkey_encrypt which * returns the encrypted value in the array ENC->DATA. This * array has a size which depends on the used algorithm (e.g. 2 * for Elgamal). We don't need frame anymore because we have * everything now in enc->data which is the passed to * build_packet(). */ frame = encode_session_key (pk->pubkey_algo, dek, pubkey_nbits (pk->pubkey_algo, pk->pkey)); rc = pk_encrypt (pk->pubkey_algo, enc->data, frame, pk, pk->pkey); gcry_mpi_release (frame); if (rc) log_error ("pubkey_encrypt failed: %s\n", gpg_strerror (rc) ); else { if ( opt.verbose ) { char *ustr = get_user_id_string_native (ctrl, enc->keyid); - log_info (_("%s/%s encrypted for: \"%s\"\n"), + log_info (_("%s/%s.%s encrypted for: \"%s\"\n"), openpgp_pk_algo_name (enc->pubkey_algo), openpgp_cipher_algo_name (dek->algo), + dek->use_aead? openpgp_aead_algo_name (dek->use_aead) + /**/ : "CFB", ustr ); xfree (ustr); } /* And write it. */ init_packet (&pkt); pkt.pkttype = PKT_PUBKEY_ENC; pkt.pkt.pubkey_enc = enc; rc = build_packet (out, &pkt); if (rc) log_error ("build_packet(pubkey_enc) failed: %s\n", gpg_strerror (rc)); } free_pubkey_enc(enc); return rc; } /* * Write pubkey-enc packets from the list of PKs to OUT. */ static int write_pubkey_enc_from_list (ctrl_t ctrl, PK_LIST pk_list, DEK *dek, iobuf_t out) { if (opt.throw_keyids && (PGP6 || PGP7 || PGP8)) { log_info(_("option '%s' may not be used in %s mode\n"), "--throw-keyids", gnupg_compliance_option_string (opt.compliance)); compliance_failure(); } for ( ; pk_list; pk_list = pk_list->next ) { PKT_public_key *pk = pk_list->pk; int throw_keyid = (opt.throw_keyids || (pk_list->flags&1)); int rc = write_pubkey_enc (ctrl, pk, throw_keyid, dek, out); if (rc) return rc; } return 0; } void encrypt_crypt_files (ctrl_t ctrl, int nfiles, char **files, strlist_t remusr) { int rc = 0; if (opt.outfile) { log_error(_("--output doesn't work for this command\n")); return; } if (!nfiles) { char line[2048]; unsigned int lno = 0; while ( fgets(line, DIM(line), stdin) ) { lno++; if (!*line || line[strlen(line)-1] != '\n') { log_error("input line %u too long or missing LF\n", lno); return; } line[strlen(line)-1] = '\0'; print_file_status(STATUS_FILE_START, line, 2); rc = encrypt_crypt (ctrl, -1, line, remusr, 0, NULL, -1); if (rc) log_error ("encryption of '%s' failed: %s\n", print_fname_stdin(line), gpg_strerror (rc) ); write_status( STATUS_FILE_DONE ); } } else { while (nfiles--) { print_file_status(STATUS_FILE_START, *files, 2); if ( (rc = encrypt_crypt (ctrl, -1, *files, remusr, 0, NULL, -1)) ) log_error("encryption of '%s' failed: %s\n", print_fname_stdin(*files), gpg_strerror (rc) ); write_status( STATUS_FILE_DONE ); files++; } } } diff --git a/g10/gpgcompose.c b/g10/gpgcompose.c index f22c7c202..094bc7614 100644 --- a/g10/gpgcompose.c +++ b/g10/gpgcompose.c @@ -1,3087 +1,3087 @@ /* gpgcompose.c - Maintainer tool to create OpenPGP messages by hand. * Copyright (C) 2016 g10 Code GmbH * * This file is part of GnuPG. * * GnuPG is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * GnuPG is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . */ #include #include #include "gpg.h" #include "packet.h" #include "keydb.h" #include "main.h" #include "options.h" static int do_debug; #define debug(fmt, ...) \ do { if (do_debug) log_debug (fmt, ##__VA_ARGS__); } while (0) /* --encryption, for instance, adds a filter in front of out. There is an operator (--encryption-pop) to end this. We use the following infrastructure to make it easy to pop the state. */ struct filter { void *func; void *context; int pkttype; int partial_block_mode; struct filter *next; }; /* Hack to ass CTRL to some functions. */ static ctrl_t global_ctrl; static struct filter *filters; static void filter_push (iobuf_t out, void *func, void *context, int type, int partial_block_mode) { gpg_error_t err; struct filter *f = xmalloc_clear (sizeof (*f)); f->next = filters; f->func = func; f->context = context; f->pkttype = type; f->partial_block_mode = partial_block_mode; filters = f; err = iobuf_push_filter (out, func, context); if (err) log_fatal ("Adding filter: %s\n", gpg_strerror (err)); } static void filter_pop (iobuf_t out, int expected_type) { gpg_error_t err; struct filter *f = filters; log_assert (f); if (f->pkttype != expected_type) log_fatal ("Attempted to pop a %s container, " "but current container is a %s container.\n", pkttype_str (f->pkttype), pkttype_str (expected_type)); if (f->pkttype == PKT_ENCRYPTED) { err = iobuf_pop_filter (out, f->func, f->context); if (err) log_fatal ("Popping encryption filter: %s\n", gpg_strerror (err)); } else log_fatal ("FILTERS appears to be corrupted.\n"); if (f->partial_block_mode) iobuf_set_partial_body_length_mode (out, 0); filters = f->next; xfree (f); } /* Return if CIPHER_ID is a valid cipher. */ static int valid_cipher (int cipher_id) { return (cipher_id == CIPHER_ALGO_IDEA || cipher_id == CIPHER_ALGO_3DES || cipher_id == CIPHER_ALGO_CAST5 || cipher_id == CIPHER_ALGO_BLOWFISH || cipher_id == CIPHER_ALGO_AES || cipher_id == CIPHER_ALGO_AES192 || cipher_id == CIPHER_ALGO_AES256 || cipher_id == CIPHER_ALGO_TWOFISH || cipher_id == CIPHER_ALGO_CAMELLIA128 || cipher_id == CIPHER_ALGO_CAMELLIA192 || cipher_id == CIPHER_ALGO_CAMELLIA256); } /* Parse a session key encoded as a string of the form x:HEXDIGITS where x is the algorithm id. (This is the format emitted by gpg --show-session-key.) */ struct session_key { int algo; int keylen; char *key; }; static struct session_key parse_session_key (const char *option, char *p, int require_algo) { char *tail; struct session_key sk; memset (&sk, 0, sizeof (sk)); /* Check for the optional "cipher-id:" at the start of the string. */ errno = 0; sk.algo = strtol (p, &tail, 10); if (! errno && tail && *tail == ':') { if (! valid_cipher (sk.algo)) log_info ("%s: %d is not a known cipher (but using anyways)\n", option, sk.algo); p = tail + 1; } else if (require_algo) log_fatal ("%s: Session key must have the form algo:HEXCHARACTERS.\n", option); else sk.algo = 0; /* Ignore a leading 0x. */ if (p[0] == '0' && p[1] == 'x') p += 2; if (strlen (p) % 2 != 0) log_fatal ("%s: session key must consist of an even number of hexadecimal characters.\n", option); sk.keylen = strlen (p) / 2; sk.key = xmalloc (sk.keylen); if (hex2bin (p, sk.key, sk.keylen) == -1) log_fatal ("%s: Session key must only contain hexadecimal characters\n", option); return sk; } /* A callback. OPTION_STR is the option that was matched. ARGC is the number of arguments following the option and ARGV are those arguments. (Thus, argv[0] is the first string following the option and argv[-1] is the option.) COOKIE is the opaque value passed to process_options. */ typedef int (*option_prcessor_t) (const char *option_str, int argc, char *argv[], void *cookie); struct option { /* The option that this matches. This must start with "--" or be the empty string. The empty string matches bare arguments. */ const char *option; /* The function to call to process this option. */ option_prcessor_t func; /* Documentation. */ const char *help; }; /* Merge two lists of options. Note: this makes a shallow copy! The caller must xfree() the result. */ static struct option * merge_options (struct option a[], struct option b[]) { int i, j; struct option *c; for (i = 0; a[i].option; i ++) ; for (j = 0; b[j].option; j ++) ; c = xmalloc ((i + j + 1) * sizeof (struct option)); memcpy (c, a, i * sizeof (struct option)); memcpy (&c[i], b, j * sizeof (struct option)); c[i + j].option = NULL; if (a[i].help && b[j].help) c[i + j].help = xasprintf ("%s\n\n%s", a[i].help, b[j].help); else if (a[i].help) c[i + j].help = a[i].help; else if (b[j].help) c[i + j].help = b[j].help; return c; } /* Returns whether ARG is an option. All options start with --. */ static int is_option (const char *arg) { return arg[0] == '-' && arg[1] == '-'; } /* OPTIONS is a NULL terminated array of struct option:s. Finds the entry that is the same as ARG. Returns -1 if no entry is found. The empty string option matches bare arguments. */ static int match_option (const struct option options[], const char *arg) { int i; int bare_arg = ! is_option (arg); for (i = 0; options[i].option; i ++) if ((! bare_arg && strcmp (options[i].option, arg) == 0) /* Non-options match the empty string. */ || (bare_arg && options[i].option[0] == '\0')) return i; return -1; } static void show_help (struct option options[]) { int i; int max_length = 0; int space; for (i = 0; options[i].option; i ++) { const char *option = options[i].option[0] ? options[i].option : "ARG"; int l = strlen (option); if (l > max_length) max_length = l; } space = 72 - (max_length + 2); if (space < 40) space = 40; for (i = 0; ; i ++) { const char *option = options[i].option; const char *help = options[i].help; int l; int j; char *tmp; char *formatted; char *p; char *newline; if (! option && ! help) break; if (option) { const char *o = option[0] ? option : "ARG"; l = strlen (o); fprintf (stdout, "%s", o); } if (! help) { fputc ('\n', stdout); continue; } if (option) for (j = l; j < max_length + 2; j ++) fputc (' ', stdout); #define BOLD_START "\033[1m" #define NORMAL_RESTORE "\033[0m" #define BOLD(x) BOLD_START x NORMAL_RESTORE if (! option || options[i].func) tmp = (char *) help; else tmp = xasprintf ("%s " BOLD("(Unimplemented.)"), help); if (! option) space = 72; formatted = format_text (tmp, space, space + 4); if (!formatted) abort (); if (tmp != help) xfree (tmp); if (! option) { printf ("\n%s\n", formatted); break; } for (p = formatted; p && *p; p = (*newline == '\0') ? newline : newline + 1) { newline = strchr (p, '\n'); if (! newline) newline = &p[strlen (p)]; l = (size_t) newline - (size_t) p; if (p != formatted) for (j = 0; j < max_length + 2; j ++) fputc (' ', stdout); fwrite (p, l, 1, stdout); fputc ('\n', stdout); } xfree (formatted); } } /* Return value is number of consumed argv elements. */ static int process_options (const char *parent_option, struct option break_options[], struct option local_options[], void *lcookie, struct option global_options[], void *gcookie, int argc, char *argv[]) { int i; for (i = 0; i < argc; i ++) { int j; struct option *option; void *cookie; int bare_arg; option_prcessor_t func; int consumed; if (break_options) { j = match_option (break_options, argv[i]); if (j != -1) /* Match. Break out. */ return i; } j = match_option (local_options, argv[i]); if (j == -1) { if (global_options) j = match_option (global_options, argv[i]); if (j == -1) { if (strcmp (argv[i], "--help") == 0) { if (! global_options) show_help (local_options); else { struct option *combined = merge_options (local_options, global_options); show_help (combined); xfree (combined); } g10_exit (0); } if (parent_option) log_fatal ("%s: Unknown option: %s\n", parent_option, argv[i]); else log_fatal ("Unknown option: %s\n", argv[i]); } option = &global_options[j]; cookie = gcookie; } else { option = &local_options[j]; cookie = lcookie; } bare_arg = strcmp (option->option, "") == 0; func = option->func; if (! func) { if (bare_arg) log_fatal ("Bare arguments unimplemented.\n"); else log_fatal ("Unimplemented option: %s\n", option->option); } consumed = func (bare_arg ? parent_option : argv[i], argc - i - !bare_arg, &argv[i + !bare_arg], cookie); i += consumed; if (bare_arg) i --; } return i; } /* The keys, subkeys, user ids and user attributes in the order that they were added. */ PACKET components[20]; /* The number of components. */ int ncomponents; static int add_component (int pkttype, void *component) { int i = ncomponents ++; log_assert (i < sizeof (components) / sizeof (components[0])); log_assert (pkttype == PKT_PUBLIC_KEY || pkttype == PKT_PUBLIC_SUBKEY || pkttype == PKT_SECRET_KEY || pkttype == PKT_SECRET_SUBKEY || pkttype == PKT_USER_ID || pkttype == PKT_ATTRIBUTE); components[i].pkttype = pkttype; components[i].pkt.generic = component; return i; } static void dump_component (PACKET *pkt) { struct kbnode_struct kbnode; if (! do_debug) return; memset (&kbnode, 0, sizeof (kbnode)); kbnode.pkt = pkt; dump_kbnode (&kbnode); } /* Returns the first primary key in COMPONENTS or NULL if there is none. */ static PKT_public_key * primary_key (void) { int i; for (i = 0; i < ncomponents; i ++) if (components[i].pkttype == PKT_PUBLIC_KEY) return components[i].pkt.public_key; return NULL; } /* The last session key (updated when adding a SK-ESK, PK-ESK or SED packet. */ static DEK session_key; static int user_id (const char *option, int argc, char *argv[], void *cookie); static int public_key (const char *option, int argc, char *argv[], void *cookie); static int sk_esk (const char *option, int argc, char *argv[], void *cookie); static int pk_esk (const char *option, int argc, char *argv[], void *cookie); static int encrypted (const char *option, int argc, char *argv[], void *cookie); static int encrypted_pop (const char *option, int argc, char *argv[], void *cookie); static int literal (const char *option, int argc, char *argv[], void *cookie); static int signature (const char *option, int argc, char *argv[], void *cookie); static int copy (const char *option, int argc, char *argv[], void *cookie); static struct option major_options[] = { { "--user-id", user_id, "Create a user id packet." }, { "--public-key", public_key, "Create a public key packet." }, { "--private-key", NULL, "Create a private key packet." }, { "--public-subkey", public_key, "Create a subkey packet." }, { "--private-subkey", NULL, "Create a private subkey packet." }, { "--sk-esk", sk_esk, "Create a symmetric-key encrypted session key packet." }, { "--pk-esk", pk_esk, "Create a public-key encrypted session key packet." }, { "--encrypted", encrypted, "Create a symmetrically encrypted data packet." }, { "--encrypted-mdc", encrypted, "Create a symmetrically encrypted and integrity protected data packet." }, { "--encrypted-pop", encrypted_pop, "Pop the most recent encryption container started by either" " --encrypted or --encrypted-mdc." }, { "--compressed", NULL, "Create a compressed data packet." }, { "--literal", literal, "Create a literal (plaintext) data packet." }, { "--signature", signature, "Create a signature packet." }, { "--onepass-sig", NULL, "Create a one-pass signature packet." }, { "--copy", copy, "Copy the specified file." }, { NULL, NULL, "To get more information about a given command, use:\n\n" " $ gpgcompose --command --help to list a command's options."}, }; static struct option global_options[] = { { NULL, NULL, NULL }, }; /* Make our lives easier and use a static limit for the user name. 10k is way more than enough anyways... */ const int user_id_max_len = 10 * 1024; static int user_id_name (const char *option, int argc, char *argv[], void *cookie) { PKT_user_id *uid = cookie; int l; if (argc == 0) log_fatal ("Usage: %s USER_ID\n", option); if (uid->len) log_fatal ("Attempt to set user id multiple times.\n"); l = strlen (argv[0]); if (l > user_id_max_len) log_fatal ("user id too long (max: %d)\n", user_id_max_len); memcpy (uid->name, argv[0], l); uid->name[l] = 0; uid->len = l; return 1; } static struct option user_id_options[] = { { "", user_id_name, "Set the user id. This is usually in the format " "\"Name (comment) \"" }, { NULL, NULL, "Example:\n\n" " $ gpgcompose --user-id \"USERID\" | " GPG_NAME " --list-packets" } }; static int user_id (const char *option, int argc, char *argv[], void *cookie) { iobuf_t out = cookie; gpg_error_t err; PKT_user_id *uid = xmalloc_clear (sizeof (*uid) + user_id_max_len); int c = add_component (PKT_USER_ID, uid); int processed; processed = process_options (option, major_options, user_id_options, uid, global_options, NULL, argc, argv); if (! uid->len) log_fatal ("%s: user id not given", option); err = build_packet (out, &components[c]); if (err) log_fatal ("Serializing user id packet: %s\n", gpg_strerror (err)); debug ("Wrote user id packet:\n"); dump_component (&components[c]); return processed; } static int pk_search_terms (const char *option, int argc, char *argv[], void *cookie) { gpg_error_t err; KEYDB_HANDLE hd; KEYDB_SEARCH_DESC desc; kbnode_t kb; PKT_public_key *pk = cookie; PKT_public_key *pk_ref; int i; if (argc == 0) log_fatal ("Usage: %s KEYID\n", option); if (pk->pubkey_algo) log_fatal ("%s: multiple keys provided\n", option); err = classify_user_id (argv[0], &desc, 0); if (err) log_fatal ("search terms '%s': %s\n", argv[0], gpg_strerror (err)); hd = keydb_new (); err = keydb_search (hd, &desc, 1, NULL); if (err) log_fatal ("looking up '%s': %s\n", argv[0], gpg_strerror (err)); err = keydb_get_keyblock (hd, &kb); if (err) log_fatal ("retrieving keyblock for '%s': %s\n", argv[0], gpg_strerror (err)); keydb_release (hd); pk_ref = kb->pkt->pkt.public_key; /* Copy the timestamp (if not already set), algo and public key parameters. */ if (! pk->timestamp) pk->timestamp = pk_ref->timestamp; pk->pubkey_algo = pk_ref->pubkey_algo; for (i = 0; i < pubkey_get_npkey (pk->pubkey_algo); i ++) pk->pkey[i] = gcry_mpi_copy (pk_ref->pkey[i]); release_kbnode (kb); return 1; } static int pk_timestamp (const char *option, int argc, char *argv[], void *cookie) { PKT_public_key *pk = cookie; char *tail = NULL; if (argc == 0) log_fatal ("Usage: %s TIMESTAMP\n", option); errno = 0; pk->timestamp = parse_timestamp (argv[0], &tail); if (errno || (tail && *tail)) log_fatal ("Invalid value passed to %s (%s)\n", option, argv[0]); return 1; } #define TIMESTAMP_HELP \ "Either as seconds since the epoch or as an ISO 8601 formatted " \ "string (yyyymmddThhmmss, where the T is a literal)." static struct option pk_options[] = { { "--timestamp", pk_timestamp, "The creation time. " TIMESTAMP_HELP }, { "", pk_search_terms, "The key to copy the creation time and public key parameters from." }, { NULL, NULL, "Example:\n\n" " $ gpgcompose --public-key $KEYID --user-id \"USERID\" \\\n" " | " GPG_NAME " --list-packets" } }; static int public_key (const char *option, int argc, char *argv[], void *cookie) { gpg_error_t err; iobuf_t out = cookie; PKT_public_key *pk; int c; int processed; int t = (strcmp (option, "--public-key") == 0 ? PKT_PUBLIC_KEY : PKT_PUBLIC_SUBKEY); (void) option; pk = xmalloc_clear (sizeof (*pk)); pk->version = 4; c = add_component (t, pk); processed = process_options (option, major_options, pk_options, pk, global_options, NULL, argc, argv); if (! pk->pubkey_algo) log_fatal ("%s: key to extract public key parameters from not given", option); /* Clear the keyid in case we updated one of the relevant fields after accessing it. */ pk->keyid[0] = pk->keyid[1] = 0; err = build_packet (out, &components[c]); if (err) log_fatal ("serializing %s packet: %s\n", t == PKT_PUBLIC_KEY ? "public key" : "subkey", gpg_strerror (err)); debug ("Wrote %s packet:\n", t == PKT_PUBLIC_KEY ? "public key" : "subkey"); dump_component (&components[c]); return processed; } struct signinfo { /* Key with which to sign. */ kbnode_t issuer_kb; PKT_public_key *issuer_pk; /* Overrides the issuer's key id. */ u32 issuer_keyid[2]; /* Sets the issuer's keyid to the primary key's key id. */ int issuer_keyid_self; /* Key to sign. */ PKT_public_key *pk; /* Subkey to sign. */ PKT_public_key *sk; /* User id to sign. */ PKT_user_id *uid; int class; int digest_algo; u32 timestamp; u32 key_expiration; byte *cipher_algorithms; int cipher_algorithms_len; byte *digest_algorithms; int digest_algorithms_len; byte *compress_algorithms; int compress_algorithms_len; u32 expiration; int exportable_set; int exportable; int revocable_set; int revocable; int trust_level_set; byte trust_args[2]; char *trust_scope; struct revocation_key *revocation_key; int nrevocation_keys; struct notation *notations; byte *key_server_preferences; int key_server_preferences_len; char *key_server; int primary_user_id_set; int primary_user_id; char *policy_uri; byte *key_flags; int key_flags_len; char *signers_user_id; byte reason_for_revocation_code; char *reason_for_revocation; byte *features; int features_len; /* Whether to corrupt the signature. */ int corrupt; }; static int sig_issuer (const char *option, int argc, char *argv[], void *cookie) { gpg_error_t err; KEYDB_HANDLE hd; KEYDB_SEARCH_DESC desc; struct signinfo *si = cookie; if (argc == 0) log_fatal ("Usage: %s KEYID\n", option); if (si->issuer_pk) log_fatal ("%s: multiple keys provided\n", option); err = classify_user_id (argv[0], &desc, 0); if (err) log_fatal ("search terms '%s': %s\n", argv[0], gpg_strerror (err)); hd = keydb_new (); err = keydb_search (hd, &desc, 1, NULL); if (err) log_fatal ("looking up '%s': %s\n", argv[0], gpg_strerror (err)); err = keydb_get_keyblock (hd, &si->issuer_kb); if (err) log_fatal ("retrieving keyblock for '%s': %s\n", argv[0], gpg_strerror (err)); keydb_release (hd); si->issuer_pk = si->issuer_kb->pkt->pkt.public_key; return 1; } static int sig_issuer_keyid (const char *option, int argc, char *argv[], void *cookie) { gpg_error_t err; KEYDB_SEARCH_DESC desc; struct signinfo *si = cookie; if (argc == 0) log_fatal ("Usage: %s KEYID|self\n", option); if (si->issuer_keyid[0] || si->issuer_keyid[1] || si->issuer_keyid_self) log_fatal ("%s given multiple times.\n", option); if (strcasecmp (argv[0], "self") == 0) { si->issuer_keyid_self = 1; return 1; } err = classify_user_id (argv[0], &desc, 0); if (err) log_fatal ("search terms '%s': %s\n", argv[0], gpg_strerror (err)); if (desc.mode != KEYDB_SEARCH_MODE_LONG_KID) log_fatal ("%s is not a valid long key id.\n", argv[0]); keyid_copy (si->issuer_keyid, desc.u.kid); return 1; } static int sig_pk (const char *option, int argc, char *argv[], void *cookie) { struct signinfo *si = cookie; int i; char *tail = NULL; if (argc == 0) log_fatal ("Usage: %s COMPONENT_INDEX\n", option); errno = 0; i = strtoul (argv[0], &tail, 10); if (errno || (tail && *tail)) log_fatal ("Invalid value passed to %s (%s)\n", option, argv[0]); if (i >= ncomponents) log_fatal ("%d: No such component (have %d components so far)\n", i, ncomponents); if (! (components[i].pkttype == PKT_PUBLIC_KEY || components[i].pkttype == PKT_PUBLIC_SUBKEY)) log_fatal ("Component %d is not a public key or a subkey.", i); if (strcmp (option, "--pk") == 0) { if (si->pk) log_fatal ("%s already given.\n", option); si->pk = components[i].pkt.public_key; } else if (strcmp (option, "--sk") == 0) { if (si->sk) log_fatal ("%s already given.\n", option); si->sk = components[i].pkt.public_key; } else log_fatal ("Cannot handle %s\n", option); return 1; } static int sig_user_id (const char *option, int argc, char *argv[], void *cookie) { struct signinfo *si = cookie; int i; char *tail = NULL; if (argc == 0) log_fatal ("Usage: %s COMPONENT_INDEX\n", option); if (si->uid) log_fatal ("%s already given.\n", option); errno = 0; i = strtoul (argv[0], &tail, 10); if (errno || (tail && *tail)) log_fatal ("Invalid value passed to %s (%s)\n", option, argv[0]); if (i >= ncomponents) log_fatal ("%d: No such component (have %d components so far)\n", i, ncomponents); if (! (components[i].pkttype != PKT_USER_ID || components[i].pkttype == PKT_ATTRIBUTE)) log_fatal ("Component %d is not a public key or a subkey.", i); si->uid = components[i].pkt.user_id; return 1; } static int sig_class (const char *option, int argc, char *argv[], void *cookie) { struct signinfo *si = cookie; int i; char *tail = NULL; if (argc == 0) log_fatal ("Usage: %s CLASS\n", option); errno = 0; i = strtoul (argv[0], &tail, 0); if (errno || (tail && *tail)) log_fatal ("Invalid value passed to %s (%s)\n", option, argv[0]); si->class = i; return 1; } static int sig_digest (const char *option, int argc, char *argv[], void *cookie) { struct signinfo *si = cookie; int i; char *tail = NULL; if (argc == 0) log_fatal ("Usage: %s DIGEST_ALGO\n", option); errno = 0; i = strtoul (argv[0], &tail, 10); if (errno || (tail && *tail)) log_fatal ("Invalid value passed to %s (%s)\n", option, argv[0]); si->digest_algo = i; return 1; } static int sig_timestamp (const char *option, int argc, char *argv[], void *cookie) { struct signinfo *si = cookie; char *tail = NULL; if (argc == 0) log_fatal ("Usage: %s TIMESTAMP\n", option); errno = 0; si->timestamp = parse_timestamp (argv[0], &tail); if (errno || (tail && *tail)) log_fatal ("Invalid value passed to %s (%s)\n", option, argv[0]); return 1; } static int sig_expiration (const char *option, int argc, char *argv[], void *cookie) { struct signinfo *si = cookie; int is_expiration = strcmp (option, "--expiration") == 0; u32 *i = is_expiration ? &si->expiration : &si->key_expiration; if (! is_expiration) log_assert (strcmp (option, "--key-expiration") == 0); if (argc == 0) log_fatal ("Usage: %s DURATION\n", option); *i = parse_expire_string (argv[0]); if (*i == (u32)-1) log_fatal ("Invalid value passed to %s (%s)\n", option, argv[0]); return 1; } static int sig_int_list (const char *option, int argc, char *argv[], void *cookie) { struct signinfo *si = cookie; int nvalues = 1; char *values = xmalloc (nvalues * sizeof (values[0])); char *tail = argv[0]; int i; byte **a; int *n; if (argc == 0) log_fatal ("Usage: %s VALUE[,VALUE...]\n", option); for (i = 0; tail && *tail; i ++) { int v; char *old_tail = tail; errno = 0; v = strtol (tail, &tail, 0); if (errno || old_tail == tail || (tail && !(*tail == ',' || *tail == 0))) log_fatal ("Invalid value passed to %s (%s). " "Expected a list of comma separated numbers\n", option, argv[0]); if (! (0 <= v && v <= 255)) log_fatal ("%s: %d is out of range (Expected: 0-255)\n", option, v); if (i == nvalues) { nvalues *= 2; values = xrealloc (values, nvalues * sizeof (values[0])); } values[i] = v; if (*tail == ',') tail ++; else log_assert (*tail == 0); } if (strcmp ("--cipher-algos", option) == 0) { a = &si->cipher_algorithms; n = &si->cipher_algorithms_len; } else if (strcmp ("--digest-algos", option) == 0) { a = &si->digest_algorithms; n = &si->digest_algorithms_len; } else if (strcmp ("--compress-algos", option) == 0) { a = &si->compress_algorithms; n = &si->compress_algorithms_len; } else log_fatal ("Cannot handle %s\n", option); if (*a) log_fatal ("Option %s given multiple times.\n", option); *a = values; *n = i; return 1; } static int sig_flag (const char *option, int argc, char *argv[], void *cookie) { struct signinfo *si = cookie; int range[2] = {0, 255}; char *tail; int v; if (strcmp (option, "--primary-user-id") == 0) range[1] = 1; if (argc <= 1) { if (range[0] == 0 && range[1] == 1) log_fatal ("Usage: %s 0|1\n", option); else log_fatal ("Usage: %s %d-%d\n", option, range[0], range[1]); } errno = 0; v = strtol (argv[0], &tail, 0); if (errno || (tail && *tail) || !(range[0] <= v && v <= range[1])) log_fatal ("Invalid value passed to %s (%s). Expected %d-%d\n", option, argv[0], range[0], range[1]); if (strcmp (option, "--exportable") == 0) { si->exportable_set = 1; si->exportable = v; } else if (strcmp (option, "--revocable") == 0) { si->revocable_set = 1; si->revocable = v; } else if (strcmp (option, "--primary-user-id") == 0) { si->primary_user_id_set = 1; si->primary_user_id = v; } else log_fatal ("Cannot handle %s\n", option); return 1; } static int sig_trust_level (const char *option, int argc, char *argv[], void *cookie) { struct signinfo *si = cookie; int i; char *tail; if (argc <= 1) log_fatal ("Usage: %s DEPTH TRUST_AMOUNT\n", option); for (i = 0; i < sizeof (si->trust_args) / sizeof (si->trust_args[0]); i ++) { int v; errno = 0; v = strtol (argv[i], &tail, 0); if (errno || (tail && *tail) || !(0 <= v && v <= 255)) log_fatal ("Invalid value passed to %s (%s). Expected 0-255\n", option, argv[i]); si->trust_args[i] = v; } si->trust_level_set = 1; return 2; } static int sig_string_arg (const char *option, int argc, char *argv[], void *cookie) { struct signinfo *si = cookie; char *p = argv[0]; char **s; if (argc == 0) log_fatal ("Usage: %s STRING\n", option); if (strcmp (option, "--trust-scope") == 0) s = &si->trust_scope; else if (strcmp (option, "--key-server") == 0) s = &si->key_server; else if (strcmp (option, "--signers-user-id") == 0) s = &si->signers_user_id; else if (strcmp (option, "--policy-uri") == 0) s = &si->policy_uri; else log_fatal ("Cannot handle %s\n", option); if (*s) log_fatal ("%s already given.\n", option); *s = xstrdup (p); return 1; } static int sig_revocation_key (const char *option, int argc, char *argv[], void *cookie) { gpg_error_t err; struct signinfo *si = cookie; int v; char *tail; PKT_public_key pk; struct revocation_key *revkey; if (argc < 2) log_fatal ("Usage: %s CLASS KEYID\n", option); memset (&pk, 0, sizeof (pk)); errno = 0; v = strtol (argv[0], &tail, 16); if (errno || (tail && *tail) || !(0 <= v && v <= 255)) log_fatal ("%s: Invalid class value (%s). Expected 0-255\n", option, argv[0]); pk.req_usage = PUBKEY_USAGE_SIG; err = get_pubkey_byname (NULL, NULL, &pk, argv[1], NULL, NULL, 1, 1); if (err) log_fatal ("looking up key %s: %s\n", argv[1], gpg_strerror (err)); si->nrevocation_keys ++; si->revocation_key = xrealloc (si->revocation_key, si->nrevocation_keys * sizeof (*si->revocation_key)); revkey = &si->revocation_key[si->nrevocation_keys - 1]; revkey->class = v; revkey->algid = pk.pubkey_algo; fingerprint_from_pk (&pk, revkey->fpr, NULL); release_public_key_parts (&pk); return 2; } static int sig_notation (const char *option, int argc, char *argv[], void *cookie) { struct signinfo *si = cookie; int is_blob = strcmp (option, "--notation") != 0; struct notation *notation; char *p = argv[0]; int p_free = 0; char *data; int data_size; int data_len; if (argc == 0) log_fatal ("Usage: %s [!<]name=value\n", option); if ((p[0] == '!' && p[1] == '<') || p[0] == '<') /* Read from a file. */ { char *filename = NULL; iobuf_t in; int prefix; if (p[0] == '<') p ++; else { /* Remove the '<', which string_to_notation does not understand, and preserve the '!'. */ p = xstrdup (&p[1]); p_free = 1; p[0] = '!'; } filename = strchr (p, '='); if (! filename) log_fatal ("No value specified. Usage: %s [!<]name=value\n", option); filename ++; prefix = (size_t) filename - (size_t) p; errno = 0; in = iobuf_open (filename); if (! in) log_fatal ("Opening '%s': %s\n", filename, errno ? strerror (errno): "unknown error"); /* A notation can be at most about a few dozen bytes short of 64k. Since this is relatively small, we just allocate that much instead of trying to dynamically size a buffer. */ data_size = 64 * 1024; data = xmalloc (data_size); log_assert (prefix <= data_size); memcpy (data, p, prefix); data_len = iobuf_read (in, &data[prefix], data_size - prefix - 1); if (data_len == -1) /* EOF => 0 bytes read. */ data_len = 0; if (data_len == data_size - prefix - 1) /* Technically, we should do another read and check for EOF, but what's one byte more or less? */ log_fatal ("Notation data doesn't fit in the packet.\n"); iobuf_close (in); /* NUL terminate it. */ data[prefix + data_len] = 0; if (p_free) xfree (p); p = data; p_free = 1; data = &p[prefix]; if (is_blob) p[prefix - 1] = 0; } else if (is_blob) { data = strchr (p, '='); if (! data) { data = p; data_len = 0; } else { p = xstrdup (p); p_free = 1; data = strchr (p, '='); log_assert (data); /* NUL terminate the name. */ *data = 0; data ++; data_len = strlen (data); } } if (is_blob) notation = blob_to_notation (p, data, data_len); else notation = string_to_notation (p, 1); if (! notation) log_fatal ("creating notation: an unknown error occurred.\n"); notation->next = si->notations; si->notations = notation; if (p_free) xfree (p); return 1; } static int sig_big_endian_arg (const char *option, int argc, char *argv[], void *cookie) { struct signinfo *si = cookie; char *p = argv[0]; int i; int l; char *bytes; if (argc == 0) log_fatal ("Usage: %s HEXDIGITS\n", option); /* Skip a leading "0x". */ if (p[0] == '0' && p[1] == 'x') p += 2; for (i = 0; i < strlen (p); i ++) if (!hexdigitp (&p[i])) log_fatal ("%s: argument ('%s') must consist of hex digits.\n", option, p); if (strlen (p) % 2 != 0) log_fatal ("%s: argument ('%s') must contain an even number of hex digits.\n", option, p); l = strlen (p) / 2; bytes = xmalloc (l); hex2bin (p, bytes, l); if (strcmp (option, "--key-server-preferences") == 0) { if (si->key_server_preferences) log_fatal ("%s given multiple times.\n", option); si->key_server_preferences = bytes; si->key_server_preferences_len = l; } else if (strcmp (option, "--key-flags") == 0) { if (si->key_flags) log_fatal ("%s given multiple times.\n", option); si->key_flags = bytes; si->key_flags_len = l; } else if (strcmp (option, "--features") == 0) { if (si->features) log_fatal ("%s given multiple times.\n", option); si->features = bytes; si->features_len = l; } else log_fatal ("Cannot handle %s\n", option); return 1; } static int sig_reason_for_revocation (const char *option, int argc, char *argv[], void *cookie) { struct signinfo *si = cookie; int v; char *tail; if (argc < 2) log_fatal ("Usage: %s REASON_CODE REASON_STRING\n", option); errno = 0; v = strtol (argv[0], &tail, 16); if (errno || (tail && *tail) || !(0 <= v && v <= 255)) log_fatal ("%s: Invalid reason code (%s). Expected 0-255\n", option, argv[0]); if (si->reason_for_revocation) log_fatal ("%s given multiple times.\n", option); si->reason_for_revocation_code = v; si->reason_for_revocation = xstrdup (argv[1]); return 2; } static int sig_corrupt (const char *option, int argc, char *argv[], void *cookie) { struct signinfo *si = cookie; (void) option; (void) argc; (void) argv; (void) cookie; si->corrupt = 1; return 0; } static struct option sig_options[] = { { "--issuer", sig_issuer, "The key to use to generate the signature."}, { "--issuer-keyid", sig_issuer_keyid, "Set the issuer's key id. This is useful for creating a " "self-signature. As a special case, the value \"self\" refers " "to the primary key's key id. " "(RFC 4880, Section 5.2.3.5)" }, { "--pk", sig_pk, "The primary keyas an index into the components (keys and uids) " "created so far where the first component has the index 0." }, { "--sk", sig_pk, "The subkey as an index into the components (keys and uids) created " "so far where the first component has the index 0. Only needed for " "0x18, 0x19, and 0x28 signatures." }, { "--user-id", sig_user_id, "The user id as an index into the components (keys and uids) created " "so far where the first component has the index 0. Only needed for " "0x10-0x13 and 0x30 signatures." }, { "--class", sig_class, "The signature's class. Valid values are " "0x10-0x13 (user id and primary-key certification), " "0x18 (subkey binding), " "0x19 (primary key binding), " "0x1f (direct primary key signature), " "0x20 (key revocation), " "0x28 (subkey revocation), and " "0x30 (certification revocation)." }, { "--digest", sig_digest, "The digest algorithm" }, { "--timestamp", sig_timestamp, "The signature's creation time. " TIMESTAMP_HELP " 0 means now. " "(RFC 4880, Section 5.2.3.4)" }, { "--key-expiration", sig_expiration, "The number of days until the associated key expires. To specify " "seconds, prefix the value with \"seconds=\". It is also possible " "to use 'y', 'm' and 'w' as simple multipliers. For instance, 2y " "means 2 years, etc. " "(RFC 4880, Section 5.2.3.6)" }, { "--cipher-algos", sig_int_list, "A comma separated list of the preferred cipher algorithms (identified by " "their number, see RFC 4880, Section 9). " "(RFC 4880, Section 5.2.3.7)" }, { "--digest-algos", sig_int_list, "A comma separated list of the preferred algorithms (identified by " "their number, see RFC 4880, Section 9). " "(RFC 4880, Section 5.2.3.8)" }, { "--compress-algos", sig_int_list, "A comma separated list of the preferred algorithms (identified by " "their number, see RFC 4880, Section 9)." "(RFC 4880, Section 5.2.3.9)" }, { "--expiration", sig_expiration, "The number of days until the signature expires. To specify seconds, " "prefix the value with \"seconds=\". It is also possible to use 'y', " "'m' and 'w' as simple multipliers. For instance, 2y means 2 years, " "etc. " "(RFC 4880, Section 5.2.3.10)" }, { "--exportable", sig_flag, "Mark this signature as exportable (1) or local (0). " "(RFC 4880, Section 5.2.3.11)" }, { "--revocable", sig_flag, "Mark this signature as revocable (1, revocations are ignored) " "or non-revocable (0). " "(RFC 4880, Section 5.2.3.12)" }, { "--trust-level", sig_trust_level, "Set the trust level. This takes two integer arguments (0-255): " "the trusted-introducer level and the degree of trust. " "(RFC 4880, Section 5.2.3.13.)" }, { "--trust-scope", sig_string_arg, "A regular expression that limits the scope of --trust-level. " "(RFC 4880, Section 5.2.3.14.)" }, { "--revocation-key", sig_revocation_key, "Specify a designated revoker. Takes two arguments: the class " "(normally 0x80 or 0xC0 (sensitive)) and the key id of the " "designatured revoker. May be given multiple times. " "(RFC 4880, Section 5.2.3.15)" }, { "--notation", sig_notation, "Add a human-readable notation of the form \"[!<]name=value\" where " "\"!\" means that the critical flag should be set and \"<\" means " "that VALUE is a file to read the data from. " "(RFC 4880, Section 5.2.3.16)" }, { "--notation-binary", sig_notation, "Add a binary notation of the form \"[!<]name=value\" where " "\"!\" means that the critical flag should be set and \"<\" means " "that VALUE is a file to read the data from. " "(RFC 4880, Section 5.2.3.16)" }, { "--key-server-preferences", sig_big_endian_arg, "Big-endian number encoding the keyserver preferences. " "(RFC 4880, Section 5.2.3.17)" }, { "--key-server", sig_string_arg, "The preferred keyserver. (RFC 4880, Section 5.2.3.18)" }, { "--primary-user-id", sig_flag, "Sets the primary user id flag. (RFC 4880, Section 5.2.3.19)" }, { "--policy-uri", sig_string_arg, "URI of a document that describes the issuer's signing policy. " "(RFC 4880, Section 5.2.3.20)" }, { "--key-flags", sig_big_endian_arg, "Big-endian number encoding the key flags. " "(RFC 4880, Section 5.2.3.21)" }, { "--signers-user-id", sig_string_arg, "The user id (as a string) responsible for the signing. " "(RFC 4880, Section 5.2.3.22)" }, { "--reason-for-revocation", sig_reason_for_revocation, "Takes two arguments: a reason for revocation code and a " "user-provided string. " "(RFC 4880, Section 5.2.3.23)" }, { "--features", sig_big_endian_arg, "Big-endian number encoding the feature flags. " "(RFC 4880, Section 5.2.3.24)" }, { "--signature-target", NULL, "Takes three arguments: the target signature's public key algorithm " " (as an integer), the hash algorithm (as an integer) and the hash " " (as a hexadecimal string). " "(RFC 4880, Section 5.2.3.25)" }, { "--embedded-signature", NULL, "An embedded signature. This must be immediately followed by a " "signature packet (created using --signature ...) or a filename " "containing the packet." "(RFC 4880, Section 5.2.3.26)" }, { "--hashed", NULL, "The following attributes will be placed in the hashed area of " "the signature. (This is the default and it reset at the end of" "each signature.)" }, { "--unhashed", NULL, "The following attributes will be placed in the unhashed area of " "the signature (and thus not integrity protected)." }, { "--corrupt", sig_corrupt, "Corrupt the signature." }, { NULL, NULL, "Example:\n\n" " $ gpgcompose --public-key $KEYID --user-id USERID \\\n" " --signature --class 0x10 --issuer $KEYID --issuer-keyid self \\\n" " | " GPG_NAME " --list-packets"} }; static int mksubpkt_callback (PKT_signature *sig, void *cookie) { struct signinfo *si = cookie; int i; if (si->key_expiration) { char buf[4]; buf[0] = (si->key_expiration >> 24) & 0xff; buf[1] = (si->key_expiration >> 16) & 0xff; buf[2] = (si->key_expiration >> 8) & 0xff; buf[3] = si->key_expiration & 0xff; build_sig_subpkt (sig, SIGSUBPKT_KEY_EXPIRE, buf, 4); } if (si->cipher_algorithms) build_sig_subpkt (sig, SIGSUBPKT_PREF_SYM, si->cipher_algorithms, si->cipher_algorithms_len); if (si->digest_algorithms) build_sig_subpkt (sig, SIGSUBPKT_PREF_HASH, si->digest_algorithms, si->digest_algorithms_len); if (si->compress_algorithms) build_sig_subpkt (sig, SIGSUBPKT_PREF_COMPR, si->compress_algorithms, si->compress_algorithms_len); if (si->exportable_set) { char buf = si->exportable; build_sig_subpkt (sig, SIGSUBPKT_EXPORTABLE, &buf, 1); } if (si->trust_level_set) build_sig_subpkt (sig, SIGSUBPKT_TRUST, si->trust_args, sizeof (si->trust_args)); if (si->trust_scope) build_sig_subpkt (sig, SIGSUBPKT_REGEXP, si->trust_scope, strlen (si->trust_scope)); for (i = 0; i < si->nrevocation_keys; i ++) { struct revocation_key *revkey = &si->revocation_key[i]; gpg_error_t err = keygen_add_revkey (sig, revkey); if (err) { u32 keyid[2]; keyid_from_fingerprint (global_ctrl, revkey->fpr, 20, keyid); log_fatal ("adding revocation key %s: %s\n", keystr (keyid), gpg_strerror (err)); } } /* keygen_add_revkey sets revocable=0 so be sure to do this after adding the rev keys. */ if (si->revocable_set) { char buf = si->revocable; build_sig_subpkt (sig, SIGSUBPKT_REVOCABLE, &buf, 1); } keygen_add_notations (sig, si->notations); if (si->key_server_preferences) build_sig_subpkt (sig, SIGSUBPKT_KS_FLAGS, si->key_server_preferences, si->key_server_preferences_len); if (si->key_server) build_sig_subpkt (sig, SIGSUBPKT_PREF_KS, si->key_server, strlen (si->key_server)); if (si->primary_user_id_set) { char buf = si->primary_user_id; build_sig_subpkt (sig, SIGSUBPKT_PRIMARY_UID, &buf, 1); } if (si->policy_uri) build_sig_subpkt (sig, SIGSUBPKT_POLICY, si->policy_uri, strlen (si->policy_uri)); if (si->key_flags) build_sig_subpkt (sig, SIGSUBPKT_KEY_FLAGS, si->key_flags, si->key_flags_len); if (si->signers_user_id) build_sig_subpkt (sig, SIGSUBPKT_SIGNERS_UID, si->signers_user_id, strlen (si->signers_user_id)); if (si->reason_for_revocation) { int len = 1 + strlen (si->reason_for_revocation); char *buf; buf = xmalloc (len); buf[0] = si->reason_for_revocation_code; memcpy (&buf[1], si->reason_for_revocation, len - 1); build_sig_subpkt (sig, SIGSUBPKT_REVOC_REASON, buf, len); xfree (buf); } if (si->features) build_sig_subpkt (sig, SIGSUBPKT_FEATURES, si->features, si->features_len); return 0; } static int signature (const char *option, int argc, char *argv[], void *cookie) { gpg_error_t err; iobuf_t out = cookie; struct signinfo si; int processed; PKT_public_key *pk; PKT_signature *sig; PACKET pkt; u32 keyid_orig[2], keyid[2]; (void) option; memset (&si, 0, sizeof (si)); memset (&pkt, 0, sizeof (pkt)); processed = process_options (option, major_options, sig_options, &si, global_options, NULL, argc, argv); if (ncomponents) { int pkttype = components[ncomponents - 1].pkttype; if (pkttype == PKT_PUBLIC_KEY) { if (! si.class) /* Direct key sig. */ si.class = 0x1F; } else if (pkttype == PKT_PUBLIC_SUBKEY) { if (! si.sk) si.sk = components[ncomponents - 1].pkt.public_key; if (! si.class) /* Subkey binding sig. */ si.class = 0x18; } else if (pkttype == PKT_USER_ID) { if (! si.uid) si.uid = components[ncomponents - 1].pkt.user_id; if (! si.class) /* Certification of a user id and public key packet. */ si.class = 0x10; } } pk = NULL; if (! si.pk || ! si.issuer_pk) /* No primary key specified. Default to the first one that we find. */ { int i; for (i = 0; i < ncomponents; i ++) if (components[i].pkttype == PKT_PUBLIC_KEY) { pk = components[i].pkt.public_key; break; } } if (! si.pk) { if (! pk) log_fatal ("%s: no primary key given and no primary key available", "--pk"); si.pk = pk; } if (! si.issuer_pk) { if (! pk) log_fatal ("%s: no issuer key given and no primary key available", "--issuer"); si.issuer_pk = pk; } if (si.class == 0x18 || si.class == 0x19 || si.class == 0x28) /* Requires the primary key and a subkey. */ { if (! si.sk) log_fatal ("sig class 0x%x requires a subkey (--sk)\n", si.class); } else if (si.class == 0x10 || si.class == 0x11 || si.class == 0x12 || si.class == 0x13 || si.class == 0x30) /* Requires the primary key and a user id. */ { if (! si.uid) log_fatal ("sig class 0x%x requires a uid (--uid)\n", si.class); } else if (si.class == 0x1F || si.class == 0x20) /* Just requires the primary key. */ ; else log_fatal ("Unsupported signature class: 0x%x\n", si.class); sig = xmalloc_clear (sizeof (*sig)); /* Save SI.ISSUER_PK->KEYID. */ keyid_copy (keyid_orig, pk_keyid (si.issuer_pk)); if (si.issuer_keyid[0] || si.issuer_keyid[1]) keyid_copy (si.issuer_pk->keyid, si.issuer_keyid); else if (si.issuer_keyid_self) { PKT_public_key *pripk = primary_key(); if (! pripk) log_fatal ("--issuer-keyid self given, but no primary key available.\n"); keyid_copy (si.issuer_pk->keyid, pk_keyid (pripk)); } /* Changing the issuer's key id is fragile. Check to make sure make_keysig_packet didn't recompute the keyid. */ keyid_copy (keyid, si.issuer_pk->keyid); err = make_keysig_packet (global_ctrl, &sig, si.pk, si.uid, si.sk, si.issuer_pk, si.class, si.digest_algo, si.timestamp, si.expiration, mksubpkt_callback, &si, NULL); log_assert (keyid_cmp (keyid, si.issuer_pk->keyid) == 0); if (err) log_fatal ("Generating signature: %s\n", gpg_strerror (err)); /* Restore SI.PK->KEYID. */ keyid_copy (si.issuer_pk->keyid, keyid_orig); if (si.corrupt) { /* Set the top 32-bits to 0xBAD0DEAD. */ int bits = gcry_mpi_get_nbits (sig->data[0]); gcry_mpi_t x = gcry_mpi_new (0); gcry_mpi_add_ui (x, x, 0xBAD0DEAD); gcry_mpi_lshift (x, x, bits > 32 ? bits - 32 : bits); gcry_mpi_clear_highbit (sig->data[0], bits > 32 ? bits - 32 : 0); gcry_mpi_add (sig->data[0], sig->data[0], x); gcry_mpi_release (x); } pkt.pkttype = PKT_SIGNATURE; pkt.pkt.signature = sig; err = build_packet (out, &pkt); if (err) log_fatal ("serializing public key packet: %s\n", gpg_strerror (err)); debug ("Wrote signature packet:\n"); dump_component (&pkt); xfree (sig); release_kbnode (si.issuer_kb); xfree (si.revocation_key); return processed; } struct sk_esk_info { /* The cipher used for encrypting the session key (when a session key is used). */ int cipher; /* The cipher used for encryping the SED packet. */ int sed_cipher; /* S2K related data. */ int hash; int mode; int mode_set; byte salt[8]; int salt_set; int iterations; /* If applying the S2K function to the passphrase is the session key or if it is the decryption key for the session key. */ int s2k_is_session_key; /* Generate a new, random session key. */ int new_session_key; /* The unencrypted session key. */ int session_key_len; char *session_key; char *password; }; static int sk_esk_cipher (const char *option, int argc, char *argv[], void *cookie) { struct sk_esk_info *si = cookie; char *usage = "integer|IDEA|3DES|CAST5|BLOWFISH|AES|AES192|AES256|CAMELLIA128|CAMELLIA192|CAMELLIA256"; int cipher; if (argc == 0) log_fatal ("Usage: %s %s\n", option, usage); if (strcasecmp (argv[0], "IDEA") == 0) cipher = CIPHER_ALGO_IDEA; else if (strcasecmp (argv[0], "3DES") == 0) cipher = CIPHER_ALGO_3DES; else if (strcasecmp (argv[0], "CAST5") == 0) cipher = CIPHER_ALGO_CAST5; else if (strcasecmp (argv[0], "BLOWFISH") == 0) cipher = CIPHER_ALGO_BLOWFISH; else if (strcasecmp (argv[0], "AES") == 0) cipher = CIPHER_ALGO_AES; else if (strcasecmp (argv[0], "AES192") == 0) cipher = CIPHER_ALGO_AES192; else if (strcasecmp (argv[0], "TWOFISH") == 0) cipher = CIPHER_ALGO_TWOFISH; else if (strcasecmp (argv[0], "CAMELLIA128") == 0) cipher = CIPHER_ALGO_CAMELLIA128; else if (strcasecmp (argv[0], "CAMELLIA192") == 0) cipher = CIPHER_ALGO_CAMELLIA192; else if (strcasecmp (argv[0], "CAMELLIA256") == 0) cipher = CIPHER_ALGO_CAMELLIA256; else { char *tail; int v; errno = 0; v = strtol (argv[0], &tail, 0); if (errno || (tail && *tail) || ! valid_cipher (v)) log_fatal ("Invalid or unsupported value. Usage: %s %s\n", option, usage); cipher = v; } if (strcmp (option, "--cipher") == 0) { if (si->cipher) log_fatal ("%s given multiple times.", option); si->cipher = cipher; } else if (strcmp (option, "--sed-cipher") == 0) { if (si->sed_cipher) log_fatal ("%s given multiple times.", option); si->sed_cipher = cipher; } return 1; } static int sk_esk_mode (const char *option, int argc, char *argv[], void *cookie) { struct sk_esk_info *si = cookie; char *usage = "integer|simple|salted|iterated"; if (argc == 0) log_fatal ("Usage: %s %s\n", option, usage); if (si->mode) log_fatal ("%s given multiple times.", option); if (strcasecmp (argv[0], "simple") == 0) si->mode = 0; else if (strcasecmp (argv[0], "salted") == 0) si->mode = 1; else if (strcasecmp (argv[0], "iterated") == 0) si->mode = 3; else { char *tail; int v; errno = 0; v = strtol (argv[0], &tail, 0); if (errno || (tail && *tail) || ! (v == 0 || v == 1 || v == 3)) log_fatal ("Invalid or unsupported value. Usage: %s %s\n", option, usage); si->mode = v; } si->mode_set = 1; return 1; } static int sk_esk_hash_algorithm (const char *option, int argc, char *argv[], void *cookie) { struct sk_esk_info *si = cookie; char *usage = "integer|MD5|SHA1|RMD160|SHA256|SHA384|SHA512|SHA224"; if (argc == 0) log_fatal ("Usage: %s %s\n", option, usage); if (si->hash) log_fatal ("%s given multiple times.", option); if (strcasecmp (argv[0], "MD5") == 0) si->hash = DIGEST_ALGO_MD5; else if (strcasecmp (argv[0], "SHA1") == 0) si->hash = DIGEST_ALGO_SHA1; else if (strcasecmp (argv[0], "RMD160") == 0) si->hash = DIGEST_ALGO_RMD160; else if (strcasecmp (argv[0], "SHA256") == 0) si->hash = DIGEST_ALGO_SHA256; else if (strcasecmp (argv[0], "SHA384") == 0) si->hash = DIGEST_ALGO_SHA384; else if (strcasecmp (argv[0], "SHA512") == 0) si->hash = DIGEST_ALGO_SHA512; else if (strcasecmp (argv[0], "SHA224") == 0) si->hash = DIGEST_ALGO_SHA224; else { char *tail; int v; errno = 0; v = strtol (argv[0], &tail, 0); if (errno || (tail && *tail) || ! (v == DIGEST_ALGO_MD5 || v == DIGEST_ALGO_SHA1 || v == DIGEST_ALGO_RMD160 || v == DIGEST_ALGO_SHA256 || v == DIGEST_ALGO_SHA384 || v == DIGEST_ALGO_SHA512 || v == DIGEST_ALGO_SHA224)) log_fatal ("Invalid or unsupported value. Usage: %s %s\n", option, usage); si->hash = v; } return 1; } static int sk_esk_salt (const char *option, int argc, char *argv[], void *cookie) { struct sk_esk_info *si = cookie; char *usage = "16-HEX-CHARACTERS"; char *p = argv[0]; if (argc == 0) log_fatal ("Usage: %s %s\n", option, usage); if (si->salt_set) log_fatal ("%s given multiple times.", option); if (p[0] == '0' && p[1] == 'x') p += 2; if (strlen (p) != 16) log_fatal ("%s: Salt must be exactly 16 hexadecimal characters (have: %zd)\n", option, strlen (p)); if (hex2bin (p, si->salt, sizeof (si->salt)) == -1) log_fatal ("%s: Salt must only contain hexadecimal characters\n", option); si->salt_set = 1; return 1; } static int sk_esk_iterations (const char *option, int argc, char *argv[], void *cookie) { struct sk_esk_info *si = cookie; char *usage = "ITERATION-COUNT"; char *tail; int v; if (argc == 0) log_fatal ("Usage: %s %s\n", option, usage); errno = 0; v = strtol (argv[0], &tail, 0); if (errno || (tail && *tail) || v < 0) log_fatal ("%s: Non-negative integer expected.\n", option); si->iterations = v; return 1; } static int sk_esk_session_key (const char *option, int argc, char *argv[], void *cookie) { struct sk_esk_info *si = cookie; char *usage = "HEX-CHARACTERS|auto|none"; char *p = argv[0]; struct session_key sk; if (argc == 0) log_fatal ("Usage: %s %s\n", option, usage); if (si->session_key || si->s2k_is_session_key || si->new_session_key) log_fatal ("%s given multiple times.", option); if (strcasecmp (p, "none") == 0) { si->s2k_is_session_key = 1; return 1; } if (strcasecmp (p, "new") == 0) { si->new_session_key = 1; return 1; } if (strcasecmp (p, "auto") == 0) return 1; sk = parse_session_key (option, p, 0); if (si->session_key) log_fatal ("%s given multiple times.", option); if (sk.algo) si->sed_cipher = sk.algo; si->session_key_len = sk.keylen; si->session_key = sk.key; return 1; } static int sk_esk_password (const char *option, int argc, char *argv[], void *cookie) { struct sk_esk_info *si = cookie; char *usage = "PASSWORD"; if (argc == 0) log_fatal ("Usage: --sk-esk %s\n", usage); if (si->password) log_fatal ("%s given multiple times.", option); si->password = xstrdup (argv[0]); return 1; } static struct option sk_esk_options[] = { { "--cipher", sk_esk_cipher, "The encryption algorithm for encrypting the session key. " "One of IDEA, 3DES, CAST5, BLOWFISH, AES (default), AES192, " "AES256, TWOFISH, CAMELLIA128, CAMELLIA192, or CAMELLIA256." }, { "--sed-cipher", sk_esk_cipher, "The encryption algorithm for encrypting the SED packet. " "One of IDEA, 3DES, CAST5, BLOWFISH, AES, AES192, " "AES256 (default), TWOFISH, CAMELLIA128, CAMELLIA192, or CAMELLIA256." }, { "--mode", sk_esk_mode, "The S2K mode. Either one of the strings \"simple\", \"salted\" " "or \"iterated\" or an integer." }, { "--hash", sk_esk_hash_algorithm, "The hash algorithm to used to derive the key. One of " "MD5, SHA1 (default), RMD160, SHA256, SHA384, SHA512, or SHA224." }, { "--salt", sk_esk_salt, "The S2K salt encoded as 16 hexadecimal characters. One needed " "if the S2K function is in salted or iterated mode." }, { "--iterations", sk_esk_iterations, "The iteration count. If not provided, a reasonable value is chosen. " "Note: due to the encoding scheme, not every value is valid. For " "convenience, the provided value will be rounded appropriately. " "Only needed if the S2K function is in iterated mode." }, { "--session-key", sk_esk_session_key, "The session key to be encrypted by the S2K function as a hexadecimal " "string. If this is \"new\", then a new session key is generated." "If this is \"auto\", then either the last session key is " "used, if the was none, one is generated. If this is \"none\", then " "the session key is the result of applying the S2K algorithms to the " "password. The session key may be prefaced with an integer and a colon " "to indicate the cipher to use for the SED packet (making --sed-cipher " "unnecessary and allowing the direct use of the result of " "\"" GPG_NAME " --show-session-key\")." }, { "", sk_esk_password, "The password." }, { NULL, NULL, "Example:\n\n" " $ gpgcompose --sk-esk foobar --encrypted \\\n" " --literal --value foo | " GPG_NAME " --list-packets" } }; static int sk_esk (const char *option, int argc, char *argv[], void *cookie) { iobuf_t out = cookie; gpg_error_t err; int processed; struct sk_esk_info si; DEK sesdek; DEK s2kdek; PKT_symkey_enc *ske; PACKET pkt; memset (&si, 0, sizeof (si)); processed = process_options (option, major_options, sk_esk_options, &si, global_options, NULL, argc, argv); if (! si.password) log_fatal ("%s: missing password. Usage: %s PASSWORD", option, option); /* Fill in defaults, if appropriate. */ if (! si.cipher) si.cipher = CIPHER_ALGO_AES; if (! si.sed_cipher) si.sed_cipher = CIPHER_ALGO_AES256; if (! si.hash) si.hash = DIGEST_ALGO_SHA1; if (! si.mode_set) /* Salted and iterated. */ si.mode = 3; if (si.mode != 0 && ! si.salt_set) /* Generate a salt. */ gcry_randomize (si.salt, 8, GCRY_STRONG_RANDOM); if (si.mode == 0) { if (si.iterations) log_info ("%s: --iterations provided, but not used for mode=0\n", option); si.iterations = 0; } else if (! si.iterations) si.iterations = 10000; memset (&sesdek, 0, sizeof (sesdek)); /* The session key is used to encrypt the SED packet. */ sesdek.algo = si.sed_cipher; if (si.session_key) /* Copy the unencrypted session key into SESDEK. */ { sesdek.keylen = openpgp_cipher_get_algo_keylen (sesdek.algo); if (sesdek.keylen != si.session_key_len) log_fatal ("%s: Cipher algorithm requires a %d byte session key, but provided session key is %d bytes.", option, sesdek.keylen, si.session_key_len); log_assert (sesdek.keylen <= sizeof (sesdek.key)); memcpy (sesdek.key, si.session_key, sesdek.keylen); } else if (! si.s2k_is_session_key || si.new_session_key) /* We need a session key, but one wasn't provided. Generate it. */ make_session_key (&sesdek); /* The encrypted session key needs 1 + SESDEK.KEYLEN bytes of space. */ ske = xmalloc_clear (sizeof (*ske) + sesdek.keylen); ske->version = 4; ske->cipher_algo = si.cipher; ske->s2k.mode = si.mode; ske->s2k.hash_algo = si.hash; log_assert (sizeof (si.salt) == sizeof (ske->s2k.salt)); memcpy (ske->s2k.salt, si.salt, sizeof (ske->s2k.salt)); if (! si.s2k_is_session_key) /* 0 means get the default. */ ske->s2k.count = encode_s2k_iterations (si.iterations); /* Derive the symmetric key that is either the session key or the key used to encrypt the session key. */ memset (&s2kdek, 0, sizeof (s2kdek)); s2kdek.algo = si.cipher; s2kdek.keylen = openpgp_cipher_get_algo_keylen (s2kdek.algo); err = gcry_kdf_derive (si.password, strlen (si.password), ske->s2k.mode == 3 ? GCRY_KDF_ITERSALTED_S2K : ske->s2k.mode == 1 ? GCRY_KDF_SALTED_S2K : GCRY_KDF_SIMPLE_S2K, ske->s2k.hash_algo, ske->s2k.salt, 8, S2K_DECODE_COUNT (ske->s2k.count), /* The size of the desired key and its buffer. */ s2kdek.keylen, s2kdek.key); if (err) log_fatal ("gcry_kdf_derive failed: %s", gpg_strerror (err)); if (si.s2k_is_session_key) { ske->seskeylen = 0; session_key = s2kdek; } else /* Encrypt the session key using the s2k specifier. */ { DEK *sesdekp = &sesdek; /* Now encrypt the session key (or rather, the algorithm used to encrypt the SKESK plus the session key) using ENCKEY. */ - err = encrypt_seskey (&s2kdek, &sesdekp, + err = encrypt_seskey (&s2kdek, 0, &sesdekp, (void**)&ske->seskey, (size_t *)&ske->seskeylen); if (err) log_fatal ("encrypt_seskey failed: %s\n", gpg_strerror (err)); /* Save the session key for later. */ session_key = sesdek; } pkt.pkttype = PKT_SYMKEY_ENC; pkt.pkt.symkey_enc = ske; err = build_packet (out, &pkt); if (err) log_fatal ("Serializing sym-key encrypted packet: %s\n", gpg_strerror (err)); debug ("Wrote sym-key encrypted packet:\n"); dump_component (&pkt); xfree (si.session_key); xfree (si.password); xfree (ske); return processed; } struct pk_esk_info { int session_key_set; int new_session_key; int sed_cipher; int session_key_len; char *session_key; int throw_keyid; char *keyid; }; static int pk_esk_session_key (const char *option, int argc, char *argv[], void *cookie) { struct pk_esk_info *pi = cookie; char *usage = "HEX-CHARACTERS|auto|none"; char *p = argv[0]; struct session_key sk; if (argc == 0) log_fatal ("Usage: %s %s\n", option, usage); if (pi->session_key_set) log_fatal ("%s given multiple times.", option); pi->session_key_set = 1; if (strcasecmp (p, "new") == 0) { pi->new_session_key = 1; return 1; } if (strcasecmp (p, "auto") == 0) return 1; sk = parse_session_key (option, p, 0); if (pi->session_key) log_fatal ("%s given multiple times.", option); if (sk.algo) pi->sed_cipher = sk.algo; pi->session_key_len = sk.keylen; pi->session_key = sk.key; return 1; } static int pk_esk_throw_keyid (const char *option, int argc, char *argv[], void *cookie) { struct pk_esk_info *pi = cookie; (void) option; (void) argc; (void) argv; pi->throw_keyid = 1; return 0; } static int pk_esk_keyid (const char *option, int argc, char *argv[], void *cookie) { struct pk_esk_info *pi = cookie; char *usage = "KEYID"; if (argc == 0) log_fatal ("Usage: %s %s\n", option, usage); if (pi->keyid) log_fatal ("Multiple key ids given, but only one is allowed."); pi->keyid = xstrdup (argv[0]); return 1; } static struct option pk_esk_options[] = { { "--session-key", pk_esk_session_key, "The session key to be encrypted by the S2K function as a hexadecimal " "string. If this is not given or is \"auto\", then the current " "session key is used. If there is no session key or this is \"new\", " "then a new session key is generated. The session key may be " "prefaced with an integer and a colon to indicate the cipher to use " "for the SED packet (making --sed-cipher unnecessary and allowing the " "direct use of the result of \"" GPG_NAME " --show-session-key\")." }, { "--throw-keyid", pk_esk_throw_keyid, "Throw the keyid." }, { "", pk_esk_keyid, "The key id." }, { NULL, NULL, "Example:\n\n" " $ gpgcompose --pk-esk $KEYID --encrypted --literal --value foo \\\n" " | " GPG_NAME " --list-packets"} }; static int pk_esk (const char *option, int argc, char *argv[], void *cookie) { iobuf_t out = cookie; gpg_error_t err; int processed; struct pk_esk_info pi; PKT_public_key pk; memset (&pi, 0, sizeof (pi)); processed = process_options (option, major_options, pk_esk_options, &pi, global_options, NULL, argc, argv); if (! pi.keyid) log_fatal ("%s: missing keyid. Usage: %s KEYID", option, option); memset (&pk, 0, sizeof (pk)); pk.req_usage = PUBKEY_USAGE_ENC; err = get_pubkey_byname (NULL, NULL, &pk, pi.keyid, NULL, NULL, 1, 1); if (err) log_fatal ("%s: looking up key %s: %s\n", option, pi.keyid, gpg_strerror (err)); if (pi.sed_cipher) /* Have a session key. */ { session_key.algo = pi.sed_cipher; session_key.keylen = pi.session_key_len; log_assert (session_key.keylen <= sizeof (session_key.key)); memcpy (session_key.key, pi.session_key, session_key.keylen); } if (pi.new_session_key || ! session_key.algo) { if (! pi.new_session_key) /* Default to AES256. */ session_key.algo = CIPHER_ALGO_AES256; make_session_key (&session_key); } err = write_pubkey_enc (global_ctrl, &pk, pi.throw_keyid, &session_key, out); if (err) log_fatal ("%s: writing pk_esk packet for %s: %s\n", option, pi.keyid, gpg_strerror (err)); debug ("Wrote pk_esk packet for %s\n", pi.keyid); xfree (pi.keyid); xfree (pi.session_key); return processed; } struct encinfo { int saw_session_key; }; static int encrypted_session_key (const char *option, int argc, char *argv[], void *cookie) { struct encinfo *ei = cookie; char *usage = "HEX-CHARACTERS|auto"; char *p = argv[0]; struct session_key sk; if (argc == 0) log_fatal ("Usage: %s %s\n", option, usage); if (ei->saw_session_key) log_fatal ("%s given multiple times.", option); ei->saw_session_key = 1; if (strcasecmp (p, "auto") == 0) return 1; sk = parse_session_key (option, p, 1); session_key.algo = sk.algo; log_assert (sk.keylen <= sizeof (session_key.key)); memcpy (session_key.key, sk.key, sk.keylen); xfree (sk.key); return 1; } static struct option encrypted_options[] = { { "--session-key", encrypted_session_key, "The session key to be encrypted by the S2K function as a hexadecimal " "string. If this is not given or is \"auto\", then the last session key " "is used. If there was none, then an error is raised. The session key " "must be prefaced with an integer and a colon to indicate the cipher " "to use (this is format used by \"" GPG_NAME " --show-session-key\")." }, { NULL, NULL, "After creating the packet, this command clears the current " "session key.\n\n" "Example: nested encryption packets:\n\n" " $ gpgcompose --sk-esk foo --encrypted-mdc \\\n" " --sk-esk bar --encrypted-mdc \\\n" " --literal --value 123 --encrypted-pop --encrypted-pop | " GPG_NAME" -d" } }; static int encrypted (const char *option, int argc, char *argv[], void *cookie) { iobuf_t out = cookie; int processed; struct encinfo ei; PKT_encrypted e; cipher_filter_context_t *cfx; memset (&ei, 0, sizeof (ei)); processed = process_options (option, major_options, encrypted_options, &ei, global_options, NULL, argc, argv); if (! session_key.algo) log_fatal ("%s: no session key configured\n" " (use e.g. --sk-esk PASSWORD or --pk-esk KEYID).\n", option); memset (&e, 0, sizeof (e)); /* We only need to set E->LEN, E->EXTRALEN (if E->LEN is not 0), and E->NEW_CTB. */ e.len = 0; e.new_ctb = 1; /* Register the cipher filter. */ cfx = xmalloc_clear (sizeof (*cfx)); /* Copy the session key. */ cfx->dek = xmalloc (sizeof (*cfx->dek)); *cfx->dek = session_key; if (do_debug) { char *buf; buf = xmalloc (2 * session_key.keylen + 1); debug ("session key: algo: %d; keylen: %d; key: %s\n", session_key.algo, session_key.keylen, bin2hex (session_key.key, session_key.keylen, buf)); xfree (buf); } if (strcmp (option, "--encrypted-mdc") == 0) cfx->dek->use_mdc = 1; else if (strcmp (option, "--encrypted") == 0) cfx->dek->use_mdc = 0; else log_fatal ("%s: option not handled by this function!\n", option); cfx->datalen = 0; filter_push (out, cipher_filter_cfb, cfx, PKT_ENCRYPTED, cfx->datalen == 0); debug ("Wrote encrypted packet:\n"); /* Clear the current session key. */ memset (&session_key, 0, sizeof (session_key)); return processed; } static struct option encrypted_pop_options[] = { { NULL, NULL, "Example:\n\n" " $ gpgcompose --sk-esk PASSWORD \\\n" " --encrypted-mdc \\\n" " --literal --value foo \\\n" " --encrypted-pop | " GPG_NAME " --list-packets" } }; static int encrypted_pop (const char *option, int argc, char *argv[], void *cookie) { iobuf_t out = cookie; int processed; processed = process_options (option, major_options, encrypted_pop_options, NULL, global_options, NULL, argc, argv); /* We only support a single option, --help, which causes the program * to exit. */ log_assert (processed == 0); filter_pop (out, PKT_ENCRYPTED); debug ("Popped encryption container.\n"); return processed; } struct data { int file; union { char *data; char *filename; }; struct data *next; }; /* This must be the first member of the struct to be able to use add_value! */ struct datahead { struct data *head; struct data **last_next; }; static int add_value (const char *option, int argc, char *argv[], void *cookie) { struct datahead *dh = cookie; struct data *d = xmalloc_clear (sizeof (struct data)); d->file = strcmp ("--file", option) == 0; if (! d->file) log_assert (strcmp ("--value", option) == 0); if (argc == 0) { if (d->file) log_fatal ("Usage: %s FILENAME\n", option); else log_fatal ("Usage: %s STRING\n", option); } if (! dh->last_next) /* First time through. Initialize DH->LAST_NEXT. */ { log_assert (! dh->head); dh->last_next = &dh->head; } if (d->file) d->filename = argv[0]; else d->data = argv[0]; /* Append it. */ *dh->last_next = d; dh->last_next = &d->next; return 1; } struct litinfo { /* This must be the first element for add_value to work! */ struct datahead data; int timestamp_set; u32 timestamp; char mode; int partial_body_length_encoding; char *name; }; static int literal_timestamp (const char *option, int argc, char *argv[], void *cookie) { struct litinfo *li = cookie; char *tail = NULL; if (argc == 0) log_fatal ("Usage: %s TIMESTAMP\n", option); errno = 0; li->timestamp = parse_timestamp (argv[0], &tail); if (errno || (tail && *tail)) log_fatal ("Invalid value passed to %s (%s)\n", option, argv[0]); li->timestamp_set = 1; return 1; } static int literal_mode (const char *option, int argc, char *argv[], void *cookie) { struct litinfo *li = cookie; if (argc == 0 || ! (strcmp (argv[0], "b") == 0 || strcmp (argv[0], "t") == 0 || strcmp (argv[0], "u") == 0)) log_fatal ("Usage: %s [btu]\n", option); li->mode = argv[0][0]; return 1; } static int literal_partial_body_length (const char *option, int argc, char *argv[], void *cookie) { struct litinfo *li = cookie; char *tail; int v; int range[2] = {0, 1}; if (argc <= 1) log_fatal ("Usage: %s [0|1]\n", option); errno = 0; v = strtol (argv[0], &tail, 0); if (errno || (tail && *tail) || !(range[0] <= v && v <= range[1])) log_fatal ("Invalid value passed to %s (%s). Expected %d-%d\n", option, argv[0], range[0], range[1]); li->partial_body_length_encoding = v; return 1; } static int literal_name (const char *option, int argc, char *argv[], void *cookie) { struct litinfo *li = cookie; if (argc <= 0) log_fatal ("Usage: %s NAME\n", option); if (strlen (argv[0]) > 255) log_fatal ("%s: name is too long (%zd > 255 characters).\n", option, strlen (argv[0])); li->name = argv[0]; return 1; } static struct option literal_options[] = { { "--value", add_value, "A string to store in the literal packet." }, { "--file", add_value, "A file to copy into the literal packet." }, { "--timestamp", literal_timestamp, "The literal packet's time stamp. This defaults to the current time." }, { "--mode", literal_mode, "The content's mode (normally 'b' (default), 't' or 'u')." }, { "--partial-body-length", literal_partial_body_length, "Force partial body length encoding." }, { "--name", literal_name, "The literal's name." }, { NULL, NULL, "Example:\n\n" " $ gpgcompose --literal --value foobar | " GPG_NAME " -d"} }; static int literal (const char *option, int argc, char *argv[], void *cookie) { iobuf_t out = cookie; gpg_error_t err; int processed; struct litinfo li; PKT_plaintext *pt; PACKET pkt; struct data *data; memset (&li, 0, sizeof (li)); processed = process_options (option, major_options, literal_options, &li, global_options, NULL, argc, argv); if (! li.data.head) log_fatal ("%s: no data provided (use --value or --file)", option); pt = xmalloc_clear (sizeof (*pt) + (li.name ? strlen (li.name) : 0)); pt->new_ctb = 1; if (li.timestamp_set) pt->timestamp = li.timestamp; else /* Default to the current time. */ pt->timestamp = make_timestamp (); pt->mode = li.mode; if (! pt->mode) /* Default to binary. */ pt->mode = 'b'; if (li.name) { strcpy (pt->name, li.name); pt->namelen = strlen (pt->name); } pkt.pkttype = PKT_PLAINTEXT; pkt.pkt.plaintext = pt; if (! li.partial_body_length_encoding) /* Compute the amount of data. */ { pt->len = 0; for (data = li.data.head; data; data = data->next) { if (data->file) { iobuf_t in; int overflow; off_t off; in = iobuf_open (data->filename); if (! in) /* An error opening the file. We do error handling below so just break here. */ { pt->len = 0; break; } off = iobuf_get_filelength (in, &overflow); iobuf_close (in); if (overflow || off == 0) /* Length is unknown or there was an error (unfortunately, iobuf_get_filelength doesn't distinguish between 0 length files and an error!). Fall back to partial body mode. */ { pt->len = 0; break; } pt->len += off; } else pt->len += strlen (data->data); } } err = build_packet (out, &pkt); if (err) log_fatal ("Serializing literal packet: %s\n", gpg_strerror (err)); /* Write out the data. */ for (data = li.data.head; data; data = data->next) { if (data->file) { iobuf_t in; errno = 0; in = iobuf_open (data->filename); if (! in) log_fatal ("Opening '%s': %s\n", data->filename, errno ? strerror (errno): "unknown error"); iobuf_copy (out, in); if (iobuf_error (in)) log_fatal ("Reading from %s: %s\n", data->filename, gpg_strerror (iobuf_error (in))); if (iobuf_error (out)) log_fatal ("Writing literal data from %s: %s\n", data->filename, gpg_strerror (iobuf_error (out))); iobuf_close (in); } else { err = iobuf_write (out, data->data, strlen (data->data)); if (err) log_fatal ("Writing literal data: %s\n", gpg_strerror (err)); } } if (! pt->len) { /* Disable partial body length mode. */ log_assert (pt->new_ctb == 1); iobuf_set_partial_body_length_mode (out, 0); } debug ("Wrote literal packet:\n"); dump_component (&pkt); while (li.data.head) { data = li.data.head->next; xfree (li.data.head); li.data.head = data; } xfree (pt); return processed; } static int copy_file (const char *option, int argc, char *argv[], void *cookie) { char **filep = cookie; if (argc == 0) log_fatal ("Usage: %s FILENAME\n", option); *filep = argv[0]; return 1; } static struct option copy_options[] = { { "", copy_file, "Copy the specified file to stdout." }, { NULL, NULL, "Example:\n\n" " $ gpgcompose --copy /etc/hostname\n\n" "This is particularly useful when combined with gpgsplit." } }; static int copy (const char *option, int argc, char *argv[], void *cookie) { iobuf_t out = cookie; char *file = NULL; iobuf_t in; int processed; processed = process_options (option, major_options, copy_options, &file, global_options, NULL, argc, argv); if (! file) log_fatal ("Usage: %s FILE\n", option); errno = 0; in = iobuf_open (file); if (! in) log_fatal ("Error opening %s: %s.\n", file, errno ? strerror (errno): "unknown error"); iobuf_copy (out, in); if (iobuf_error (out)) log_fatal ("Copying data to destination: %s\n", gpg_strerror (iobuf_error (out))); if (iobuf_error (in)) log_fatal ("Reading data from %s: %s\n", argv[0], gpg_strerror (iobuf_error (in))); iobuf_close (in); return processed; } int main (int argc, char *argv[]) { const char *filename = "-"; iobuf_t out; int preprocessed = 1; int processed; ctrl_t ctrl; opt.ignore_time_conflict = 1; /* Allow notations in the IETF space, for instance. */ opt.expert = 1; global_ctrl = ctrl = xcalloc (1, sizeof *ctrl); keydb_add_resource ("pubring" EXTSEP_S GPGEXT_GPG, KEYDB_RESOURCE_FLAG_DEFAULT); if (argc == 1) /* Nothing to do. */ return 0; if (strcmp (argv[1], "--output") == 0 || strcmp (argv[1], "-o") == 0) { filename = argv[2]; log_info ("Writing to %s\n", filename); preprocessed += 2; } out = iobuf_create (filename, 0); if (! out) log_fatal ("Failed to open stdout for writing\n"); processed = process_options (NULL, NULL, major_options, out, global_options, NULL, argc - preprocessed, &argv[preprocessed]); if (processed != argc - preprocessed) log_fatal ("Didn't process %d options.\n", argc - preprocessed - processed); iobuf_close (out); return 0; } /* Stubs duplicated from gpg.c. */ int g10_errors_seen = 0; /* Note: This function is used by signal handlers!. */ static void emergency_cleanup (void) { gcry_control (GCRYCTL_TERM_SECMEM ); } void g10_exit( int rc ) { gcry_control (GCRYCTL_UPDATE_RANDOM_SEED_FILE); emergency_cleanup (); rc = rc? rc : log_get_errorcount(0)? 2 : g10_errors_seen? 1 : 0; exit (rc); } void keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr, strlist_t commands, int quiet, int seckey_check) { (void) ctrl; (void) username; (void) locusr; (void) commands; (void) quiet; (void) seckey_check; } void show_basic_key_info (ctrl_t ctrl, KBNODE keyblock) { (void)ctrl; (void) keyblock; } int keyedit_print_one_sig (ctrl_t ctrl, estream_t fp, int rc, kbnode_t keyblock, kbnode_t node, int *inv_sigs, int *no_key, int *oth_err, int is_selfsig, int print_without_key, int extended) { (void) ctrl; (void) fp; (void) rc; (void) keyblock; (void) node; (void) inv_sigs; (void) no_key; (void) oth_err; (void) is_selfsig; (void) print_without_key; (void) extended; return 0; } diff --git a/g10/import.c b/g10/import.c index 71e39557c..ed679d5c0 100644 --- a/g10/import.c +++ b/g10/import.c @@ -1,3693 +1,3712 @@ /* import.c - import a key into our key storage. * Copyright (C) 1998-2007, 2010-2011 Free Software Foundation, Inc. * Copyright (C) 2014, 2016, 2017 Werner Koch * * This file is part of GnuPG. * * GnuPG is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * GnuPG is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . */ #include #include #include #include #include #include "gpg.h" #include "options.h" #include "packet.h" #include "../common/status.h" #include "keydb.h" #include "../common/util.h" #include "trustdb.h" #include "main.h" #include "../common/i18n.h" #include "../common/ttyio.h" #include "../common/recsel.h" #include "keyserver-internal.h" #include "call-agent.h" #include "../common/membuf.h" #include "../common/init.h" #include "../common/mbox-util.h" #include "key-check.h" struct import_stats_s { ulong count; ulong no_user_id; ulong imported; 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; ulong v3keys; /* Number of V3 keys seen. */ }; /* Node flag to indicate that a user ID or a subkey has a * valid self-signature. */ #define NODE_GOOD_SELFSIG 1 /* Node flag to indicate that a user ID or subkey has * an invalid self-signature. */ #define NODE_BAD_SELFSIG 2 /* Node flag to indicate that the node shall be deleted. */ #define NODE_DELETION_MARK 4 /* A node flag used to temporary mark a node. */ #define NODE_FLAG_A 8 /* An object and a global instance to store selectors created from * --import-filter keep-uid=EXPR. * --import-filter drop-sig=EXPR. * * FIXME: We should put this into the CTRL object but that requires a * lot more changes right now. For now we use save and restore * function to temporary change them. */ /* Definition of the import filters. */ struct import_filter_s { recsel_expr_t keep_uid; recsel_expr_t drop_sig; }; /* The current instance. */ struct import_filter_s import_filter; static int import (ctrl_t ctrl, IOBUF inp, const char* fname, struct import_stats_s *stats, unsigned char **fpr, size_t *fpr_len, unsigned int options, import_screener_t screener, void *screener_arg, int origin, const char *url); static int read_block (IOBUF a, int with_meta, PACKET **pending_pkt, kbnode_t *ret_root, int *r_v3keys); static void revocation_present (ctrl_t ctrl, kbnode_t keyblock); static gpg_error_t import_one (ctrl_t ctrl, kbnode_t keyblock, struct import_stats_s *stats, unsigned char **fpr, size_t *fpr_len, unsigned int options, int from_sk, int silent, import_screener_t screener, void *screener_arg, int origin, const char *url); static int import_secret_one (ctrl_t ctrl, kbnode_t keyblock, struct import_stats_s *stats, int batch, unsigned int options, int for_migration, import_screener_t screener, void *screener_arg); static int import_revoke_cert (ctrl_t ctrl, kbnode_t node, struct import_stats_s *stats); static int chk_self_sigs (ctrl_t ctrl, kbnode_t keyblock, u32 *keyid, int *non_self); static int delete_inv_parts (ctrl_t ctrl, kbnode_t keyblock, u32 *keyid, unsigned int options); static int any_uid_left (kbnode_t keyblock); static int merge_blocks (ctrl_t ctrl, unsigned int options, kbnode_t keyblock_orig, kbnode_t keyblock, u32 *keyid, u32 curtime, int origin, const char *url, int *n_uids, int *n_sigs, int *n_subk ); static gpg_error_t append_new_uid (unsigned int options, kbnode_t keyblock, kbnode_t node, u32 curtime, int origin, const char *url, int *n_sigs); static int append_key (kbnode_t keyblock, kbnode_t node, int *n_sigs); static int merge_sigs (kbnode_t dst, kbnode_t src, int *n_sigs); static int merge_keysigs (kbnode_t dst, kbnode_t src, int *n_sigs); static void release_import_filter (import_filter_t filt) { recsel_release (filt->keep_uid); filt->keep_uid = NULL; recsel_release (filt->drop_sig); filt->drop_sig = NULL; } static void cleanup_import_globals (void) { release_import_filter (&import_filter); } 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")}, {"keep-ownertrust", IMPORT_KEEP_OWNERTTRUST, NULL, N_("do not clear the ownertrust values during import")}, {"fast-import",IMPORT_FAST,NULL, N_("do not update the trustdb after import")}, {"import-show",IMPORT_SHOW,NULL, N_("show key during 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")}, {"import-export", IMPORT_EXPORT, NULL, N_("run import filters and export key immediately")}, {"restore", IMPORT_RESTORE, NULL, N_("assume the GnuPG key backup format")}, {"import-restore", IMPORT_RESTORE, NULL, NULL}, {"repair-keys", IMPORT_REPAIR_KEYS, NULL, N_("repair keys on import")}, /* No description to avoid string change: Fixme for 2.3 */ {"show-only", (IMPORT_SHOW | IMPORT_DRY_RUN), NULL, NULL}, /* 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} }; int rc; rc = parse_options (str, options, import_opts, noisy); if (rc && (*options & IMPORT_RESTORE)) { /* Alter other options we want or don't want for restore. */ *options |= (IMPORT_LOCAL_SIGS | IMPORT_KEEP_OWNERTTRUST); *options &= ~(IMPORT_MINIMAL | IMPORT_CLEAN | IMPORT_REPAIR_PKS_SUBKEY_BUG | IMPORT_MERGE_ONLY); } return rc; } /* Parse and set an import filter from string. STRING has the format * "NAME=EXPR" with NAME being the name of the filter. Spaces before * and after NAME are not allowed. If this function is all called * several times all expressions for the same NAME are concatenated. * Supported filter names are: * * - keep-uid :: If the expression evaluates to true for a certain * user ID packet, that packet and all it dependencies * will be imported. The expression may use these * variables: * * - uid :: The entire user ID. * - mbox :: The mail box part of the user ID. * - primary :: Evaluate to true for the primary user ID. */ gpg_error_t parse_and_set_import_filter (const char *string) { gpg_error_t err; /* Auto register the cleanup function. */ register_mem_cleanup_func (cleanup_import_globals); if (!strncmp (string, "keep-uid=", 9)) err = recsel_parse_expr (&import_filter.keep_uid, string+9); else if (!strncmp (string, "drop-sig=", 9)) err = recsel_parse_expr (&import_filter.drop_sig, string+9); else err = gpg_error (GPG_ERR_INV_NAME); return err; } /* Save the current import filters, return them, and clear the current * filters. Returns NULL on error and sets ERRNO. */ import_filter_t save_and_clear_import_filter (void) { import_filter_t filt; filt = xtrycalloc (1, sizeof *filt); if (!filt) return NULL; *filt = import_filter; memset (&import_filter, 0, sizeof import_filter); return filt; } /* Release the current import filters and restore them from NEWFILT. * Ownership of NEWFILT is moved to this function. */ void restore_import_filter (import_filter_t filt) { if (filt) { release_import_filter (&import_filter); import_filter = *filt; xfree (filt); } } import_stats_t import_new_stats_handle (void) { return xmalloc_clear ( sizeof (struct import_stats_s) ); } void import_release_stats_handle (import_stats_t p) { xfree (p); } /* Read a key from a file. Only the first key in the file is * considered and stored at R_KEYBLOCK. FNAME is the name of the * file. */ gpg_error_t read_key_from_file (ctrl_t ctrl, const char *fname, kbnode_t *r_keyblock) { gpg_error_t err; iobuf_t inp; PACKET *pending_pkt = NULL; kbnode_t keyblock = NULL; u32 keyid[2]; int v3keys; /* Dummy */ int non_self; /* Dummy */ (void)ctrl; *r_keyblock = NULL; inp = iobuf_open (fname); if (!inp) err = gpg_error_from_syserror (); else if (is_secured_file (iobuf_get_fd (inp))) { iobuf_close (inp); inp = NULL; err = gpg_error (GPG_ERR_EPERM); } else err = 0; if (err) { log_error (_("can't open '%s': %s\n"), iobuf_is_pipe_filename (fname)? "[stdin]": fname, gpg_strerror (err)); if (gpg_err_code (err) == GPG_ERR_ENOENT) err = gpg_error (GPG_ERR_NO_PUBKEY); goto leave; } /* Push the armor filter. */ { armor_filter_context_t *afx; afx = new_armor_context (); afx->only_keyblocks = 1; push_armor_filter (afx, inp); release_armor_context (afx); } /* Read the first non-v3 keyblock. */ while (!(err = read_block (inp, 0, &pending_pkt, &keyblock, &v3keys))) { if (keyblock->pkt->pkttype == PKT_PUBLIC_KEY) break; log_info (_("skipping block of type %d\n"), keyblock->pkt->pkttype); release_kbnode (keyblock); keyblock = NULL; } if (err) { if (gpg_err_code (err) != GPG_ERR_INV_KEYRING) log_error (_("error reading '%s': %s\n"), iobuf_is_pipe_filename (fname)? "[stdin]": fname, gpg_strerror (err)); goto leave; } keyid_from_pk (keyblock->pkt->pkt.public_key, keyid); if (!find_next_kbnode (keyblock, PKT_USER_ID)) { err = gpg_error (GPG_ERR_NO_USER_ID); goto leave; } collapse_uids (&keyblock); clear_kbnode_flags (keyblock); if (chk_self_sigs (ctrl, keyblock, keyid, &non_self)) { err = gpg_error (GPG_ERR_INV_KEYRING); goto leave; } if (!delete_inv_parts (ctrl, keyblock, keyid, 0) ) { err = gpg_error (GPG_ERR_NO_USER_ID); goto leave; } *r_keyblock = keyblock; keyblock = NULL; leave: if (inp) { iobuf_close (inp); /* Must invalidate that ugly cache to actually close the file. */ iobuf_ioctl (NULL, IOBUF_IOCTL_INVALIDATE_CACHE, 0, (char*)fname); } release_kbnode (keyblock); /* FIXME: Do we need to free PENDING_PKT ? */ return err; } /* * 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 gpg_error_t import_keys_internal (ctrl_t ctrl, iobuf_t inp, char **fnames, int nnames, import_stats_t stats_handle, unsigned char **fpr, size_t *fpr_len, unsigned int options, import_screener_t screener, void *screener_arg, int origin, const char *url) { int i; gpg_error_t err = 0; struct import_stats_s *stats = stats_handle; if (!stats) stats = import_new_stats_handle (); if (inp) { err = import (ctrl, inp, "[stream]", stats, fpr, fpr_len, options, screener, screener_arg, origin, url); } 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 { err = import (ctrl, inp2, fname, stats, fpr, fpr_len, options, screener, screener_arg, origin, url); iobuf_close (inp2); /* Must invalidate that ugly cache to actually close it. */ iobuf_ioctl (NULL, IOBUF_IOCTL_INVALIDATE_CACHE, 0, (char*)fname); if (err) log_error ("import from '%s' failed: %s\n", fname, gpg_strerror (err) ); } 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)) check_or_update_trustdb (ctrl); return err; } void import_keys (ctrl_t ctrl, char **fnames, int nnames, import_stats_t stats_handle, unsigned int options, int origin, const char *url) { import_keys_internal (ctrl, NULL, fnames, nnames, stats_handle, NULL, NULL, options, NULL, NULL, origin, url); } gpg_error_t import_keys_es_stream (ctrl_t ctrl, estream_t fp, import_stats_t stats_handle, unsigned char **fpr, size_t *fpr_len, unsigned int options, import_screener_t screener, void *screener_arg, int origin, const char *url) { gpg_error_t err; iobuf_t inp; inp = iobuf_esopen (fp, "rb", 1); if (!inp) { err = gpg_error_from_syserror (); log_error ("iobuf_esopen failed: %s\n", gpg_strerror (err)); return err; } err = import_keys_internal (ctrl, inp, NULL, 0, stats_handle, fpr, fpr_len, options, screener, screener_arg, origin, url); iobuf_close (inp); return err; } static int import (ctrl_t ctrl, IOBUF inp, const char* fname,struct import_stats_s *stats, unsigned char **fpr,size_t *fpr_len, unsigned int options, import_screener_t screener, void *screener_arg, int origin, const char *url) { PACKET *pending_pkt = NULL; kbnode_t keyblock = NULL; /* Need to initialize because gcc can't grasp the return semantics of read_block. */ int rc = 0; int v3keys; 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, !!(options & IMPORT_RESTORE), &pending_pkt, &keyblock, &v3keys))) { stats->v3keys += v3keys; if (keyblock->pkt->pkttype == PKT_PUBLIC_KEY) rc = import_one (ctrl, keyblock, stats, fpr, fpr_len, options, 0, 0, screener, screener_arg, origin, url); else if (keyblock->pkt->pkttype == PKT_SECRET_KEY) rc = import_secret_one (ctrl, keyblock, stats, opt.batch, options, 0, screener, screener_arg); else if (keyblock->pkt->pkttype == PKT_SIGNATURE && IS_KEY_REV (keyblock->pkt->pkt.signature) ) rc = import_revoke_cert (ctrl, 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. For now we do this only if the imported key is too large. */ if (gpg_err_code (rc) == GPG_ERR_TOO_LARGE && gpg_err_source (rc) == GPG_ERR_SOURCE_KEYBOX) { stats->not_imported++; } else if (rc) break; if (!(++stats->count % 100) && !opt.quiet) log_info (_("%lu keys processed so far\n"), stats->count ); } stats->v3keys += v3keys; if (rc == -1) rc = 0; else if (rc && gpg_err_code (rc) != GPG_ERR_INV_KEYRING) log_error (_("error reading '%s': %s\n"), fname, gpg_strerror (rc)); return rc; } /* Helper to migrate secring.gpg to GnuPG 2.1. */ gpg_error_t import_old_secring (ctrl_t ctrl, const char *fname) { gpg_error_t err; iobuf_t inp; PACKET *pending_pkt = NULL; kbnode_t keyblock = NULL; /* Need to initialize because gcc can't grasp the return semantics of read_block. */ struct import_stats_s *stats; int v3keys; 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) { err = gpg_error_from_syserror (); log_error (_("can't open '%s': %s\n"), fname, gpg_strerror (err)); return err; } getkey_disable_caches(); stats = import_new_stats_handle (); while (!(err = read_block (inp, 0, &pending_pkt, &keyblock, &v3keys))) { if (keyblock->pkt->pkttype == PKT_SECRET_KEY) err = import_secret_one (ctrl, keyblock, stats, 1, 0, 1, NULL, NULL); release_kbnode (keyblock); if (err) break; } import_release_stats_handle (stats); if (err == -1) err = 0; else if (err && gpg_err_code (err) != GPG_ERR_INV_KEYRING) log_error (_("error reading '%s': %s\n"), fname, gpg_strerror (err)); else if (err) log_error ("import from '%s' failed: %s\n", fname, gpg_strerror (err)); iobuf_close (inp); iobuf_ioctl (NULL, IOBUF_IOCTL_INVALIDATE_CACHE, 0, (char*)fname); return err; } void import_print_stats (import_stats_t stats) { if (!opt.quiet) { log_info(_("Total number processed: %lu\n"), stats->count + stats->v3keys); if (stats->v3keys) log_info(_(" skipped PGP-2 keys: %lu\n"), stats->v3keys); 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) { log_info(_(" imported: %lu"), stats->imported ); 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[15*20]; snprintf (buf, sizeof buf, "%lu %lu %lu 0 %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu", stats->count + stats->v3keys, stats->no_user_id, stats->imported, 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, stats->v3keys ); 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. * Meta data (ring trust packets) are only considered of WITH_META is set. * PENDING_PKT should be initialized to NULL and not changed by the caller. * Return: 0 = okay, -1 no more blocks or another errorcode. * The int at at R_V3KEY counts the number of unsupported v3 * keyblocks. */ static int read_block( IOBUF a, int with_meta, PACKET **pending_pkt, kbnode_t *ret_root, int *r_v3keys) { int rc; struct parse_packet_ctx_s parsectx; PACKET *pkt; kbnode_t root = NULL; int in_cert, in_v3key; *r_v3keys = 0; 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); init_parse_packet (&parsectx, a); if (!with_meta) parsectx.skip_meta = 1; in_v3key = 0; while ((rc=parse_packet (&parsectx, pkt)) != -1) { if (rc && (gpg_err_code (rc) == GPG_ERR_LEGACY_KEY && (pkt->pkttype == PKT_PUBLIC_KEY || pkt->pkttype == PKT_SECRET_KEY))) { in_v3key = 1; ++*r_v3keys; free_packet (pkt, &parsectx); init_packet (pkt); continue; } else if (rc ) /* (ignore errors) */ { if (gpg_err_code (rc) == GPG_ERR_UNKNOWN_PACKET) ; /* Do not show a diagnostic. */ else { log_error("read_block: read error: %s\n", gpg_strerror (rc) ); rc = GPG_ERR_INV_KEYRING; goto ready; } free_packet (pkt, &parsectx); init_packet(pkt); continue; } if (in_v3key && !(pkt->pkttype == PKT_PUBLIC_KEY || pkt->pkttype == PKT_SECRET_KEY)) { free_packet (pkt, &parsectx); init_packet(pkt); continue; } in_v3key = 0; if (!root && pkt->pkttype == PKT_SIGNATURE && IS_KEY_REV (pkt->pkt.signature) ) { /* 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 = GPG_ERR_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, &parsectx); init_packet(pkt); break; case PKT_RING_TRUST: /* Skip those packets unless we are in restore mode. */ if ((opt.import_options & IMPORT_RESTORE)) goto x_default; free_packet (pkt, &parsectx); 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; /* fall through */ default: x_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, &parsectx); deinit_parse_packet (&parsectx); 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 (ctrl_t ctrl, kbnode_t keyblock) { int changed = 0; int keycount = 0; kbnode_t node; kbnode_t last = NULL; kbnode_t 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 && IS_SUBKEY_SIG (node->pkt->pkt.signature) && keycount >= 2 && !node->next) { /* We might have the problem, as this key has two subkeys in a row without any intervening packets. */ /* Sanity check */ if (!last) 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 (ctrl, keyblock,node,NULL)) { /* Not a match, so undo the changes. */ sknode->next = node->next; last->next = node; node->next = NULL; break; } else { /* Mark it good so we don't need to check it again */ sknode->flag |= NODE_GOOD_SELFSIG; 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 (ctrl_t ctrl, 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 (ctrl, 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, n; size_t pos = 0; 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, " "); 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 (ctrl, 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_AEAD) + { + if (openpgp_aead_test_algo (prefs->value)) + { + /* FIXME: The test below is wrong. We should + * check if ...algo_name yields a "?" and + * only in that case use NUM. */ + const char *algo = + (openpgp_aead_test_algo (prefs->value) + ? num + : openpgp_aead_algo_name (prefs->value)); + if(!problem) + check_prefs_warning(pk); + log_info(_(" \"%s\": preference for AEAD" + " 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; strlist_t 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;ictrl; kbnode_t node = parm->node; static char numbuf[20]; const char *result; log_assert (ctrl && ctrl->magic == SERVER_CONTROL_MAGIC); if (node->pkt->pkttype == PKT_USER_ID || node->pkt->pkttype == PKT_ATTRIBUTE) { PKT_user_id *uid = node->pkt->pkt.user_id; if (!strcmp (propname, "uid")) result = uid->name; else if (!strcmp (propname, "mbox")) { if (!uid->mbox) { uid->mbox = mailbox_from_userid (uid->name); } result = uid->mbox; } else if (!strcmp (propname, "primary")) { result = uid->flags.primary? "1":"0"; } else if (!strcmp (propname, "expired")) { result = uid->flags.expired? "1":"0"; } else if (!strcmp (propname, "revoked")) { result = uid->flags.revoked? "1":"0"; } else result = NULL; } else if (node->pkt->pkttype == PKT_SIGNATURE) { PKT_signature *sig = node->pkt->pkt.signature; if (!strcmp (propname, "sig_created")) { snprintf (numbuf, sizeof numbuf, "%lu", (ulong)sig->timestamp); result = numbuf; } else if (!strcmp (propname, "sig_created_d")) { result = datestr_from_sig (sig); } else if (!strcmp (propname, "sig_algo")) { snprintf (numbuf, sizeof numbuf, "%d", sig->pubkey_algo); result = numbuf; } else if (!strcmp (propname, "sig_digest_algo")) { snprintf (numbuf, sizeof numbuf, "%d", sig->digest_algo); result = numbuf; } else if (!strcmp (propname, "expired")) { result = sig->flags.expired? "1":"0"; } else result = NULL; } else if (node->pkt->pkttype == PKT_PUBLIC_KEY || node->pkt->pkttype == PKT_SECRET_KEY || node->pkt->pkttype == PKT_PUBLIC_SUBKEY || node->pkt->pkttype == PKT_SECRET_SUBKEY) { PKT_public_key *pk = node->pkt->pkt.public_key; if (!strcmp (propname, "secret")) { result = (node->pkt->pkttype == PKT_SECRET_KEY || node->pkt->pkttype == PKT_SECRET_SUBKEY)? "1":"0"; } else if (!strcmp (propname, "key_algo")) { snprintf (numbuf, sizeof numbuf, "%d", pk->pubkey_algo); result = numbuf; } else if (!strcmp (propname, "key_created")) { snprintf (numbuf, sizeof numbuf, "%lu", (ulong)pk->timestamp); result = numbuf; } else if (!strcmp (propname, "key_created_d")) { result = datestr_from_pk (pk); } else if (!strcmp (propname, "expired")) { result = pk->has_expired? "1":"0"; } else if (!strcmp (propname, "revoked")) { result = pk->flags.revoked? "1":"0"; } else if (!strcmp (propname, "disabled")) { result = pk_is_disabled (pk)? "1":"0"; } else result = NULL; } else result = NULL; return result; } /* * Apply the keep-uid filter to the keyblock. The deleted nodes are * marked and thus the caller should call commit_kbnode afterwards. * KEYBLOCK must not have any blocks marked as deleted. */ static void apply_keep_uid_filter (ctrl_t ctrl, kbnode_t keyblock, recsel_expr_t selector) { kbnode_t node; struct impex_filter_parm_s parm; parm.ctrl = ctrl; for (node = keyblock->next; node; node = node->next ) { if (node->pkt->pkttype == PKT_USER_ID) { parm.node = node; if (!recsel_select (selector, impex_filter_getval, &parm)) { /* log_debug ("keep-uid: deleting '%s'\n", */ /* node->pkt->pkt.user_id->name); */ /* The UID packet and all following packets up to the * next UID or a subkey. */ delete_kbnode (node); for (; node->next && node->next->pkt->pkttype != PKT_USER_ID && node->next->pkt->pkttype != PKT_PUBLIC_SUBKEY && node->next->pkt->pkttype != PKT_SECRET_SUBKEY ; node = node->next) delete_kbnode (node->next); } /* else */ /* log_debug ("keep-uid: keeping '%s'\n", */ /* node->pkt->pkt.user_id->name); */ } } } /* * Apply the drop-sig filter to the keyblock. The deleted nodes are * marked and thus the caller should call commit_kbnode afterwards. * KEYBLOCK must not have any blocks marked as deleted. */ static void apply_drop_sig_filter (ctrl_t ctrl, kbnode_t keyblock, recsel_expr_t selector) { kbnode_t node; int active = 0; u32 main_keyid[2]; PKT_signature *sig; struct impex_filter_parm_s parm; parm.ctrl = ctrl; keyid_from_pk (keyblock->pkt->pkt.public_key, main_keyid); /* Loop over all signatures for user id and attribute packets which * are not self signatures. */ for (node = keyblock->next; node; node = node->next ) { if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY || node->pkt->pkttype == PKT_SECRET_SUBKEY) break; /* ready. */ if (node->pkt->pkttype == PKT_USER_ID || node->pkt->pkttype == PKT_ATTRIBUTE) active = 1; if (!active) continue; if (node->pkt->pkttype != PKT_SIGNATURE) continue; sig = node->pkt->pkt.signature; if (main_keyid[0] == sig->keyid[0] || main_keyid[1] == sig->keyid[1]) continue; /* Skip self-signatures. */ if (IS_UID_SIG(sig) || IS_UID_REV(sig)) { parm.node = node; if (recsel_select (selector, impex_filter_getval, &parm)) delete_kbnode (node); } } } /* Insert a key origin into a public key packet. */ static gpg_error_t insert_key_origin_pk (PKT_public_key *pk, u32 curtime, int origin, const char *url) { if (origin == KEYORG_WKD || origin == KEYORG_DANE) { /* For WKD and DANE we insert origin information also for the * key but we don't record the URL because we have have no use * for that: An update using a keyserver has higher precedence * and will thus update this origin info. For refresh using WKD * or DANE we need to go via the User ID anyway. Recall that we * are only inserting a new key. */ pk->keyorg = origin; pk->keyupdate = curtime; } else if (origin == KEYORG_KS && url) { /* If the key was retrieved from a keyserver using a fingerprint * request we add the meta information. Note that the use of a * fingerprint needs to be enforced by the caller of the import * function. This is commonly triggered by verifying a modern * signature which has an Issuer Fingerprint signature * subpacket. */ pk->keyorg = origin; pk->keyupdate = curtime; xfree (pk->updateurl); pk->updateurl = xtrystrdup (url); if (!pk->updateurl) return gpg_error_from_syserror (); } else if (origin == KEYORG_FILE) { pk->keyorg = origin; pk->keyupdate = curtime; } else if (origin == KEYORG_URL) { pk->keyorg = origin; pk->keyupdate = curtime; if (url) { xfree (pk->updateurl); pk->updateurl = xtrystrdup (url); if (!pk->updateurl) return gpg_error_from_syserror (); } } return 0; } /* Insert a key origin into a user id packet. */ static gpg_error_t insert_key_origin_uid (PKT_user_id *uid, u32 curtime, int origin, const char *url) { if (origin == KEYORG_WKD || origin == KEYORG_DANE) { /* We insert origin information on a UID only when we received * them via the Web Key Directory or a DANE record. The key we * receive here from the WKD has been filtered to contain only * the user ID as looked up in the WKD. For a DANE origin we * this should also be the case. Thus we will see here only one * user id. */ uid->keyorg = origin; uid->keyupdate = curtime; if (url) { xfree (uid->updateurl); uid->updateurl = xtrystrdup (url); if (!uid->updateurl) return gpg_error_from_syserror (); } } else if (origin == KEYORG_KS && url) { /* If the key was retrieved from a keyserver using a fingerprint * request we mark that also in the user ID. However we do not * store the keyserver URL in the UID. A later update (merge) * from a more trusted source will replace this info. */ uid->keyorg = origin; uid->keyupdate = curtime; } else if (origin == KEYORG_FILE) { uid->keyorg = origin; uid->keyupdate = curtime; } else if (origin == KEYORG_URL) { uid->keyorg = origin; uid->keyupdate = curtime; } return 0; } /* Apply meta data to KEYBLOCK. This sets the origin of the key to * ORIGIN and the updateurl to URL. Note that this function is only * used for a new key, that is not when we are merging keys. */ static gpg_error_t insert_key_origin (kbnode_t keyblock, int origin, const char *url) { gpg_error_t err; kbnode_t node; u32 curtime = make_timestamp (); for (node = keyblock; node; node = node->next) { if (is_deleted_kbnode (node)) ; else if (node->pkt->pkttype == PKT_PUBLIC_KEY) { err = insert_key_origin_pk (node->pkt->pkt.public_key, curtime, origin, url); if (err) return err; } else if (node->pkt->pkttype == PKT_USER_ID) { err = insert_key_origin_uid (node->pkt->pkt.user_id, curtime, origin, url); if (err) return err; } } return 0; } /* Update meta data on KEYBLOCK. This updates the key origin on the * public key according to ORIGIN and URL. The UIDs are already * updated when this function is called. */ static gpg_error_t update_key_origin (kbnode_t keyblock, u32 curtime, int origin, const char *url) { PKT_public_key *pk; log_assert (keyblock->pkt->pkttype == PKT_PUBLIC_KEY); pk = keyblock->pkt->pkt.public_key; if (pk->keyupdate > curtime) ; /* Don't do it for a time warp. */ else if (origin == KEYORG_WKD || origin == KEYORG_DANE) { /* We only update the origin info if they either have never been * set or are the origin was the same as the new one. If this * is WKD we also update the UID to show from which user id this * was updated. */ if (!pk->keyorg || pk->keyorg == KEYORG_WKD || pk->keyorg == KEYORG_DANE) { pk->keyorg = origin; pk->keyupdate = curtime; xfree (pk->updateurl); pk->updateurl = NULL; if (origin == KEYORG_WKD && url) { pk->updateurl = xtrystrdup (url); if (!pk->updateurl) return gpg_error_from_syserror (); } } } else if (origin == KEYORG_KS) { /* All updates from a keyserver are considered to have the * freshed key. Thus we always set the new key origin. */ pk->keyorg = origin; pk->keyupdate = curtime; xfree (pk->updateurl); pk->updateurl = NULL; if (url) { pk->updateurl = xtrystrdup (url); if (!pk->updateurl) return gpg_error_from_syserror (); } } else if (origin == KEYORG_FILE) { /* Updates from a file are considered to be fresh. */ pk->keyorg = origin; pk->keyupdate = curtime; xfree (pk->updateurl); pk->updateurl = NULL; } else if (origin == KEYORG_URL) { /* Updates from a URL are considered to be fresh. */ pk->keyorg = origin; pk->keyupdate = curtime; xfree (pk->updateurl); pk->updateurl = NULL; if (url) { pk->updateurl = xtrystrdup (url); if (!pk->updateurl) return gpg_error_from_syserror (); } } return 0; } /* * Try to import one keyblock. Return an error only in serious cases, * but never for an invalid keyblock. It uses log_error to increase * the internal errorcount, so that invalid input can be detected by * programs which called gpg. If SILENT is no messages are printed - * even most error messages are suppressed. ORIGIN is the origin of * the key (0 for unknown) and URL the corresponding URL. */ static gpg_error_t import_one (ctrl_t ctrl, kbnode_t keyblock, struct import_stats_s *stats, unsigned char **fpr, size_t *fpr_len, unsigned int options, int from_sk, int silent, import_screener_t screener, void *screener_arg, int origin, const char *url) { gpg_error_t err = 0; PKT_public_key *pk; kbnode_t node, uidnode; kbnode_t keyblock_orig = NULL; byte fpr2[MAX_FINGERPRINT_LEN]; size_t fpr2len; u32 keyid[2]; int new_key = 0; int mod_key = 0; int same_key = 0; int non_self = 0; size_t an; char pkstrbuf[PUBKEY_STRING_SIZE]; int merge_keys_done = 0; int any_filter = 0; KEYDB_HANDLE hd = NULL; /* Get the key and print some info about it. */ node = find_kbnode( keyblock, PKT_PUBLIC_KEY ); if (!node ) BUG(); pk = node->pkt->pkt.public_key; fingerprint_from_pk (pk, fpr2, &fpr2len); for (an = fpr2len; an < MAX_FINGERPRINT_LEN; an++) fpr2[an] = 0; keyid_from_pk( pk, keyid ); uidnode = find_next_kbnode( keyblock, PKT_USER_ID ); if (opt.verbose && !opt.interactive && !silent) { log_info( "pub %s/%s %s ", pubkey_string (pk, pkstrbuf, sizeof pkstrbuf), 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 ) { if (!silent) log_error( _("key %s: no user ID\n"), keystr_from_pk(pk)); return 0; } if (screener && screener (keyblock, screener_arg)) { log_error (_("key %s: %s\n"), keystr_from_pk (pk), _("rejected by import screener")); return 0; } if (opt.interactive && !silent) { if (is_status_enabled()) print_import_check (pk, uidnode->pkt->pkt.user_id); merge_keys_and_selfsig (ctrl, keyblock); tty_printf ("\n"); show_basic_key_info (ctrl, 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 (ctrl, keyblock, opt.verbose, (options&IMPORT_MINIMAL), NULL, NULL); clear_kbnode_flags( keyblock ); if ((options&IMPORT_REPAIR_PKS_SUBKEY_BUG) && fix_pks_corruption (ctrl, keyblock) && opt.verbose) log_info (_("key %s: PKS subkey corruption repaired\n"), keystr_from_pk(pk)); if ((options & IMPORT_REPAIR_KEYS)) key_check_all_keysigs (ctrl, 1, keyblock, 0, 0); if (chk_self_sigs (ctrl, keyblock, keyid, &non_self)) return 0; /* Invalid keyblock - error already printed. */ /* 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 & NODE_GOOD_SELFSIG) && !(node->flag & NODE_BAD_SELFSIG) ) { char *user=utf8_to_native(node->pkt->pkt.user_id->name, node->pkt->pkt.user_id->len,0); /* Fake a good signature status for the user id. */ node->flag |= NODE_GOOD_SELFSIG; log_info( _("key %s: accepted non self-signed user ID \"%s\"\n"), keystr_from_pk(pk),user); xfree(user); } } if (!delete_inv_parts (ctrl, keyblock, keyid, options ) ) { if (!silent) { 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; } /* Get rid of deleted nodes. */ commit_kbnode (&keyblock); /* Apply import filter. */ if (import_filter.keep_uid) { apply_keep_uid_filter (ctrl, keyblock, import_filter.keep_uid); commit_kbnode (&keyblock); any_filter = 1; } if (import_filter.drop_sig) { apply_drop_sig_filter (ctrl, keyblock, import_filter.drop_sig); commit_kbnode (&keyblock); any_filter = 1; } /* If we ran any filter we need to check that at least one user id * is left in the keyring. Note that we do not use log_error in * this case. */ if (any_filter && !any_uid_left (keyblock)) { if (!opt.quiet ) log_info ( _("key %s: no valid user IDs\n"), keystr_from_pk (pk)); stats->no_user_id++; return 0; } /* Show the key in the form it is merged or inserted. We skip this * if "import-export" is also active without --armor or the output * file has explicily been given. */ if ((options & IMPORT_SHOW) && !((options & IMPORT_EXPORT) && !opt.armor && !opt.outfile)) { merge_keys_and_selfsig (ctrl, keyblock); merge_keys_done = 1; /* Note that we do not want to show the validity because the key * has not yet imported. */ list_keyblock_direct (ctrl, keyblock, from_sk, 0, opt.fingerprint || opt.with_fingerprint, 1); es_fflush (es_stdout); } /* Write the keyblock to the output and do not actually import. */ if ((options & IMPORT_EXPORT)) { if (!merge_keys_done) { merge_keys_and_selfsig (ctrl, keyblock); merge_keys_done = 1; } err = write_keyblock_to_output (keyblock, opt.armor, opt.export_options); goto leave; } if (opt.dry_run || (options & IMPORT_DRY_RUN)) goto leave; /* Do we have this key already in one of our pubrings ? */ err = get_keyblock_byfprint_fast (&keyblock_orig, &hd, fpr2, fpr2len, 1/*locked*/); if ((err && gpg_err_code (err) != GPG_ERR_NO_PUBKEY && gpg_err_code (err) != GPG_ERR_UNUSABLE_PUBKEY) || !hd) { /* The !hd above is to catch a misbehaving function which * returns NO_PUBKEY for failing to allocate a handle. */ if (!silent) log_error (_("key %s: public key not found: %s\n"), keystr(keyid), gpg_strerror (err)); } else if (err && (opt.import_options&IMPORT_MERGE_ONLY) ) { if (opt.verbose && !silent ) log_info( _("key %s: new key - skipped\n"), keystr(keyid)); err = 0; stats->skipped_new_keys++; } else if (err) /* Insert this key. */ { /* Note: ERR can only be NO_PUBKEY or UNUSABLE_PUBKEY. */ int n_sigs_cleaned, n_uids_cleaned; err = keydb_locate_writable (hd); if (err) { log_error (_("no writable keyring found: %s\n"), gpg_strerror (err)); err = gpg_error (GPG_ERR_GENERAL); goto leave; } if (opt.verbose > 1 ) log_info (_("writing to '%s'\n"), keydb_get_resource_name (hd) ); if ((options & IMPORT_CLEAN)) clean_key (ctrl, keyblock, opt.verbose, (options&IMPORT_MINIMAL), &n_uids_cleaned,&n_sigs_cleaned); /* Unless we are in restore mode apply meta data to the * keyblock. Note that this will never change the first packet * and thus the address of KEYBLOCK won't change. */ if ( !(options & IMPORT_RESTORE) ) { err = insert_key_origin (keyblock, origin, url); if (err) { log_error ("insert_key_origin failed: %s\n", gpg_strerror (err)); err = gpg_error (GPG_ERR_GENERAL); goto leave; } } err = keydb_insert_keyblock (hd, keyblock ); if (err) log_error (_("error writing keyring '%s': %s\n"), keydb_get_resource_name (hd), gpg_strerror (err)); else if (!(opt.import_options & IMPORT_KEEP_OWNERTTRUST)) { /* 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 and by importing and locally exported key. */ clear_ownertrusts (ctrl, pk); if (non_self) revalidation_mark (ctrl); } /* Release the handle and thus unlock the keyring asap. */ keydb_release (hd); hd = NULL; /* We are ready. */ if (!opt.quiet && !silent) { char *p = get_user_id_byfpr_native (ctrl, fpr2); 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 (ctrl, keyid); write_status_text( STATUS_IMPORTED, us ); xfree(us); print_import_ok (pk, 1); } stats->imported++; new_key = 1; } else /* Key already exists - merge. */ { int n_uids, n_sigs, n_subk, n_sigs_cleaned, n_uids_cleaned; u32 curtime = make_timestamp (); /* Compare the original against the new key; just to be sure nothing * weird is going on */ if (cmp_public_keys (keyblock_orig->pkt->pkt.public_key, pk)) { if (!silent) log_error( _("key %s: doesn't match our copy\n"),keystr(keyid)); goto leave; } /* Make sure the original direct key sigs are all sane. */ n_sigs_cleaned = fix_bad_direct_key_sigs (ctrl, keyblock_orig, keyid); if (n_sigs_cleaned) commit_kbnode (&keyblock_orig); /* Try to merge KEYBLOCK into KEYBLOCK_ORIG. */ clear_kbnode_flags( keyblock_orig ); clear_kbnode_flags( keyblock ); n_uids = n_sigs = n_subk = n_uids_cleaned = 0; err = merge_blocks (ctrl, options, keyblock_orig, keyblock, keyid, curtime, origin, url, &n_uids, &n_sigs, &n_subk ); if (err) goto leave; if ((options & IMPORT_CLEAN)) clean_key (ctrl, 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) { /* Unless we are in restore mode apply meta data to the * keyblock. Note that this will never change the first packet * and thus the address of KEYBLOCK won't change. */ if ( !(options & IMPORT_RESTORE) ) { err = update_key_origin (keyblock_orig, curtime, origin, url); if (err) { log_error ("update_key_origin failed: %s\n", gpg_strerror (err)); goto leave; } } mod_key = 1; /* KEYBLOCK_ORIG has been updated; write */ err = keydb_update_keyblock (ctrl, hd, keyblock_orig); if (err) log_error (_("error writing keyring '%s': %s\n"), keydb_get_resource_name (hd), gpg_strerror (err)); else if (non_self) revalidation_mark (ctrl); /* Release the handle and thus unlock the keyring asap. */ keydb_release (hd); hd = NULL; /* We are ready. */ if (!opt.quiet && !silent) { char *p = get_user_id_byfpr_native (ctrl, fpr2); 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 () && !silent) print_import_ok (pk, ((n_uids?2:0)|(n_sigs?4:0)|(n_subk?8:0))); } else { /* Release the handle and thus unlock the keyring asap. */ keydb_release (hd); hd = NULL; /* Fixme: we do not track the time we last checked a key for * updates. To do this we would need to rewrite even the * keys which have no changes. */ same_key = 1; if (is_status_enabled ()) print_import_ok (pk, 0); if (!opt.quiet && !silent) { char *p = get_user_id_byfpr_native (ctrl, fpr2); log_info( _("key %s: \"%s\" not changed\n"),keystr(keyid),p); xfree(p); } stats->unchanged++; } } leave: keydb_release (hd); 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 from this function. */ if (!stats->count) *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 ); return err; } /* Transfer all the secret keys in SEC_KEYBLOCK to the gpg-agent. The function prints diagnostics and returns an error code. If BATCH is true the secret keys are stored by gpg-agent in the transfer format (i.e. no re-protection and aksing for passphrases). */ gpg_error_t transfer_secret_keys (ctrl_t ctrl, struct import_stats_s *stats, kbnode_t sec_keyblock, int batch, int force) { 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; void *format_args[2*PUBKEY_MAX_NSKEY]; gcry_sexp_t skey, prot, tmpsexp; gcry_sexp_t curve = NULL; unsigned char *transferkey = NULL; size_t transferkeylen; gcry_cipher_hd_t cipherhd = NULL; unsigned char *wrappedkey = NULL; size_t wrappedkeylen; char *cache_nonce = NULL; int stub_key_skipped = 0; /* 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 (); if (stats) { 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) { stub_key_skipped = 1; 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) { /* The ECC case. */ char *curvestr = openpgp_oid_to_str (pk->pkey[0]); if (!curvestr) err = gpg_error_from_syserror (); else { const char *curvename = openpgp_oid_to_curve (curvestr, 1); gcry_sexp_release (curve); err = gcry_sexp_build (&curve, NULL, "(curve %s)", curvename?curvename:curvestr); xfree (curvestr); if (!err) { j = 0; /* Append the public key element Q. */ put_membuf_str (&mbuf, " _ %m"); format_args[j++] = pk->pkey + 1; /* Append the secret key element D. For ECDH we skip PKEY[2] because this holds the KEK which is not needed by gpg-agent. */ i = pk->pubkey_algo == PUBKEY_ALGO_ECDH? 3 : 2; if (gcry_mpi_get_flag (pk->pkey[i], GCRYMPI_FLAG_USER1)) put_membuf_str (&mbuf, " e %m"); 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]) continue; /* Protected keys only have NPKEY+1 elements. */ if (gcry_mpi_get_flag (pk->pkey[i], GCRYMPI_FLAG_USER1)) put_membuf_str (&mbuf, " e %m"); else put_membuf_str (&mbuf, " _ %m"); format_args[j++] = pk->pkey + i; } } put_membuf_str (&mbuf, ")"); 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]; + /* FIXME: Support AEAD */ /* 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%S\n" " (csum %d)\n" " %S)\n", pk->version, openpgp_pk_algo_name (pk->pubkey_algo), curve, 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 (ctrl, pk, FORMAT_KEYDESC_IMPORT, 1); err = agent_import_key (ctrl, desc, &cache_nonce, wrappedkey, wrappedkeylen, batch, force, pk->keyid, pk->main_keyid, pk->pubkey_algo); xfree (desc); } if (!err) { if (opt.verbose) log_info (_("key %s: secret key imported\n"), keystr_from_pk_with_sub (main_pk, pk)); if (stats) 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; if (stats) 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. */ } } if (!err && stub_key_skipped) /* We need to notify user how to migrate stub keys. */ err = gpg_error (GPG_ERR_NOT_PROCESSED); leave: gcry_sexp_release (curve); 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 accidentally and thereby tampering * with the trust calculation. */ static int import_secret_one (ctrl_t ctrl, kbnode_t keyblock, struct import_stats_s *stats, int batch, unsigned int options, int for_migration, import_screener_t screener, void *screener_arg) { PKT_public_key *pk; struct seckey_info *ski; kbnode_t node, uidnode; u32 keyid[2]; int rc = 0; int nr_prev; kbnode_t pub_keyblock; char pkstrbuf[PUBKEY_STRING_SIZE]; /* 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 (screener && screener (keyblock, screener_arg)) { log_error (_("secret key %s: %s\n"), keystr_from_pk (pk), _("rejected by import screener")); return 0; } if (opt.verbose && !for_migration) { log_info ("sec %s/%s %s ", pubkey_string (pk, pkstrbuf, sizeof pkstrbuf), 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 ((options & IMPORT_NO_SECKEY)) { if (!for_migration) log_error (_("importing secret keys not allowed\n")); return 0; } if (!uidnode) { if (!for_migration) 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) { if (!for_migration) 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 importing 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, pub_keyblock, stats, NULL, NULL, options, 1, for_migration, screener, screener_arg, 0, NULL); /* 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 (!(opt.dry_run || (options & IMPORT_DRY_RUN)) && 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 (ctrl, keyid); if (!node) log_error ("key %s: failed to re-lookup public key\n", keystr_from_pk (pk)); else { gpg_error_t err; /* transfer_secret_keys collects subkey stats. */ struct import_stats_s subkey_stats = {0}; err = transfer_secret_keys (ctrl, &subkey_stats, keyblock, batch, 0); if (gpg_err_code (err) == GPG_ERR_NOT_PROCESSED) { /* TRANSLATORS: For smartcard, each private key on host has a reference (stub) to a smartcard and actual private key data is stored on the card. A single smartcard can have up to three private key data. Importing private key stub is always skipped in 2.1, and it returns GPG_ERR_NOT_PROCESSED. Instead, user should be suggested to run 'gpg --card-status', then, references to a card will be automatically created again. */ log_info (_("To migrate '%s', with each smartcard, " "run: %s\n"), "secring.gpg", "gpg --card-status"); err = 0; } if (!err) { int status = 16; if (!opt.quiet) log_info (_("key %s: secret key imported\n"), keystr_from_pk (pk)); if (subkey_stats.secret_imported) { status |= 1; stats->secret_imported += 1; } if (subkey_stats.secret_dups) stats->secret_dups += 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 (ctrl_t ctrl, kbnode_t node, struct import_stats_s *stats) { PKT_public_key *pk = NULL; kbnode_t onode; kbnode_t keyblock = NULL; KEYDB_HANDLE hd = NULL; u32 keyid[2]; int rc = 0; log_assert (!node->next ); log_assert (node->pkt->pkttype == PKT_SIGNATURE ); log_assert (IS_KEY_REV (node->pkt->pkt.signature)); keyid[0] = node->pkt->pkt.signature->keyid[0]; keyid[1] = node->pkt->pkt.signature->keyid[1]; pk = xmalloc_clear( sizeof *pk ); rc = get_pubkey (ctrl, pk, keyid ); if (gpg_err_code (rc) == GPG_ERR_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), gpg_strerror (rc)); goto leave; } /* Read the original keyblock. */ hd = keydb_new (); if (!hd) { rc = gpg_error_from_syserror (); goto leave; } { 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), gpg_strerror (rc)); goto leave; } rc = keydb_get_keyblock (hd, &keyblock ); if (rc) { log_error (_("key %s: can't read original keyblock: %s\n"), keystr(keyid), gpg_strerror (rc)); goto leave; } /* it is okay, that node is not in keyblock because * check_key_signature works fine for sig_class 0x20 (KEY_REV) in * this special case. */ rc = check_key_signature (ctrl, keyblock, node, NULL); if (rc ) { log_error( _("key %s: invalid revocation certificate" ": %s - rejected\n"), keystr(keyid), gpg_strerror (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 (ctrl, hd, keyblock ); if (rc) log_error (_("error writing keyring '%s': %s\n"), keydb_get_resource_name (hd), gpg_strerror (rc) ); keydb_release (hd); hd = NULL; /* we are ready */ if (!opt.quiet ) { char *p=get_user_id_native (ctrl, 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 (ctrl, pk) == TRUST_ULTIMATE) clear_ownertrusts (ctrl, pk); revalidation_mark (ctrl); leave: keydb_release (hd); release_kbnode( keyblock ); free_public_key( pk ); return rc; } /* Loop over the keyblock and check all self signatures. On return * the following bis in the node flags are set: * * - NODE_GOOD_SELFSIG :: User ID or subkey has a self-signature * - NODE_BAD_SELFSIG :: Used ID or subkey has an invalid self-signature * - NODE_DELETION_MARK :: This node shall be deleted * * NON_SELF is set to true if there are any sigs other than self-sigs * in this keyblock. * * Returns 0 on success or -1 (but not an error code) if the keyblock * is invalid. */ static int chk_self_sigs (ctrl_t ctrl, kbnode_t keyblock, 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; 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 (ctrl, keyblock, n, NULL); if ( IS_UID_SIG(sig) || IS_UID_REV(sig) ) { kbnode_t 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 & NODE_GOOD_SELFSIG)) { rc = check_key_signature (ctrl, 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) == GPG_ERR_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 |= NODE_GOOD_SELFSIG; } } else if (IS_KEY_SIG (sig)) { rc = check_key_signature (ctrl, keyblock, n, NULL); if ( rc ) { if (opt.verbose) log_info (gpg_err_code (rc) == GPG_ERR_PUBKEY_ALGO ? _("key %s: unsupported public key algorithm\n"): _("key %s: invalid direct key signature\n"), keystr (keyid)); n->flag |= NODE_DELETION_MARK; } } 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 |= NODE_DELETION_MARK; } else { rc = check_key_signature (ctrl, keyblock, n, NULL); if ( rc ) { if (opt.verbose) log_info (gpg_err_code (rc) == GPG_ERR_PUBKEY_ALGO ? _("key %s: unsupported public key" " algorithm\n"): _("key %s: invalid subkey binding\n"), keystr (keyid)); n->flag |= NODE_DELETION_MARK; } else { /* It's valid, so is it newer? */ if (sig->timestamp >= bsdate) { knode->flag |= NODE_GOOD_SELFSIG; /* Subkey is valid. */ if (bsnode) { /* Delete the last binding sig since this one is newer */ bsnode->flag |= NODE_DELETION_MARK; if (opt.verbose) log_info (_("key %s: removed multiple subkey" " binding\n"),keystr(keyid)); } bsnode = n; bsdate = sig->timestamp; } else n->flag |= NODE_DELETION_MARK; /* 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 |= NODE_DELETION_MARK; } else { rc = check_key_signature (ctrl, keyblock, n, NULL); if ( rc ) { if(opt.verbose) log_info (gpg_err_code (rc) == GPG_ERR_PUBKEY_ALGO ? _("key %s: unsupported public" " key algorithm\n"): _("key %s: invalid subkey revocation\n"), keystr(keyid)); n->flag |= NODE_DELETION_MARK; } 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 |= NODE_DELETION_MARK; if (opt.verbose) log_info (_("key %s: removed multiple subkey" " revocation\n"),keystr(keyid)); } rsnode = n; rsdate = sig->timestamp; } else n->flag |= NODE_DELETION_MARK; /* older */ } } } } return 0; } /* Delete all parts which are invalid and those signatures whose * public key algorithm is not available in this implementation; 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 (ctrl_t ctrl, kbnode_t keyblock, u32 *keyid, unsigned int options) { kbnode_t node; int nvalid=0, uid_seen=0, subkey_seen=0; for (node=keyblock->next; node; node = node->next ) { if (node->pkt->pkttype == PKT_USER_ID) { uid_seen = 1; if ((node->flag & NODE_BAD_SELFSIG) || !(node->flag & NODE_GOOD_SELFSIG)) { 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 & NODE_BAD_SELFSIG) || !(node->flag & NODE_GOOD_SELFSIG)) { 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 && IS_KEY_REV (node->pkt->pkt.signature)) { 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 (ctrl, keyblock, node, NULL); if (rc ) { if(opt.verbose) log_info( _("key %s: invalid revocation" " certificate: %s - skipped\n"), keystr(keyid), gpg_strerror (rc)); delete_kbnode( node ); } } } } else if (node->pkt->pkttype == PKT_SIGNATURE && (IS_SUBKEY_SIG (node->pkt->pkt.signature) || IS_SUBKEY_REV (node->pkt->pkt.signature)) && !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 & NODE_DELETION_MARK)) 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; } /* This function returns true if any UID is left in the keyring. */ static int any_uid_left (kbnode_t keyblock) { kbnode_t node; for (node=keyblock->next; node; node = node->next) if (node->pkt->pkttype == PKT_USER_ID) return 1; return 0; } /**************** * 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_t *keyblock ) { kbnode_t uid1; int any=0; for(uid1=*keyblock;uid1;uid1=uid1->next) { kbnode_t 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_t 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_t 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 && IS_KEY_SIG (onode->pkt->pkt.signature) && 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 (ctrl, 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 && IS_KEY_REV (inode->pkt->pkt.signature) && 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? */ gpg_error_t err; err = get_pubkey_byfprint_fast (NULL, sig->revkey[idx].fpr, MAX_FINGERPRINT_LEN); if (gpg_err_code (err) == GPG_ERR_NO_PUBKEY || gpg_err_code (err) == GPG_ERR_UNUSABLE_PUBKEY) { char *tempkeystr = xstrdup (keystr_from_pk (pk)); /* No, so try and get it */ if ((opt.keyserver_options.options & KEYSERVER_AUTO_KEY_RETRIEVE) && keyserver_any_configured (ctrl)) { 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, 0); /* Do we have it now? */ err = get_pubkey_byfprint_fast (NULL, sig->revkey[idx].fpr, MAX_FINGERPRINT_LEN); } if (gpg_err_code (err) == GPG_ERR_NO_PUBKEY || gpg_err_code (err) == GPG_ERR_UNUSABLE_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 NODE_FLAG_A. */ static int merge_blocks (ctrl_t ctrl, unsigned int options, kbnode_t keyblock_orig, kbnode_t keyblock, u32 *keyid, u32 curtime, int origin, const char *url, int *n_uids, int *n_sigs, int *n_subk ) { kbnode_t 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 && IS_KEY_REV (node->pkt->pkt.signature)) { /* 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 && IS_KEY_REV (onode->pkt->pkt.signature) && !cmp_signatures(onode->pkt->pkt.signature, node->pkt->pkt.signature)) { found = 1; break; } } if (!found) { kbnode_t n2 = clone_kbnode(node); insert_kbnode( keyblock_orig, n2, 0 ); n2->flag |= NODE_FLAG_A; ++*n_sigs; if(!opt.quiet) { char *p = get_user_id_native (ctrl, 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 && IS_KEY_SIG (node->pkt->pkt.signature)) { /* 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 && IS_KEY_SIG (onode->pkt->pkt.signature) && !cmp_signatures(onode->pkt->pkt.signature, node->pkt->pkt.signature)) { found = 1; break; } } if (!found ) { kbnode_t n2 = clone_kbnode(node); insert_kbnode( keyblock_orig, n2, 0 ); n2->flag |= NODE_FLAG_A; ++*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 & NODE_FLAG_A) && 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); 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_new_uid (options, keyblock_orig, node, curtime, origin, url, n_sigs); 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); 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); if (rc ) return rc; ++*n_subk; } } } /* 6th: merge subkey certificates */ for (onode=keyblock_orig->next; onode; onode=onode->next) { if (!(onode->flag & NODE_FLAG_A) && (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); if (rc ) return rc; } } } return 0; } /* Helper function for merge_blocks. * * Append the new userid starting with NODE and all signatures to * KEYBLOCK. ORIGIN and URL conveys the usual key origin info. The * integer at N_SIGS is updated with the number of new signatures. */ static gpg_error_t append_new_uid (unsigned int options, kbnode_t keyblock, kbnode_t node, u32 curtime, int origin, const char *url, int *n_sigs) { gpg_error_t err; kbnode_t n; kbnode_t n_where = NULL; log_assert (node->pkt->pkttype == PKT_USER_ID); /* Find the right position for the new user id and its signatures. */ 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->pkt->pkttype == PKT_USER_ID && !(options & IMPORT_RESTORE) ) { err = insert_key_origin_uid (n->pkt->pkt.user_id, curtime, origin, url); if (err) return err; } if (n_where) { insert_kbnode( n_where, n, 0 ); n_where = n; } else add_kbnode( keyblock, n ); n->flag |= NODE_FLAG_A; node->flag |= NODE_FLAG_A; if (n->pkt->pkttype == PKT_SIGNATURE ) ++*n_sigs; node = node->next; if (node && node->pkt->pkttype != PKT_SIGNATURE ) break; } return 0; } /* Helper function for merge_blocks * 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_t dst, kbnode_t src, int *n_sigs) { kbnode_t n, n2; int found = 0; log_assert (dst->pkt->pkttype == PKT_USER_ID); log_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 (IS_SUBKEY_SIG (n->pkt->pkt.signature) || IS_SUBKEY_REV (n->pkt->pkt.signature) ) 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 |= NODE_FLAG_A; n->flag |= NODE_FLAG_A; ++*n_sigs; } } return 0; } /* Helper function for merge_blocks * Merge the sigs from SRC onto DST. SRC and DST are both a PKT_xxx_SUBKEY. */ static int merge_keysigs (kbnode_t dst, kbnode_t src, int *n_sigs) { kbnode_t n, n2; int found = 0; log_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 |= NODE_FLAG_A; n->flag |= NODE_FLAG_A; ++*n_sigs; } } return 0; } /* Helper function for merge_blocks. * 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_t keyblock, kbnode_t node, int *n_sigs) { kbnode_t n; log_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 |= NODE_FLAG_A; node->flag |= NODE_FLAG_A; 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/keyedit.c b/g10/keyedit.c index 81344eb79..3ae96a3b2 100644 --- a/g10/keyedit.c +++ b/g10/keyedit.c @@ -1,6257 +1,6275 @@ /* keyedit.c - Edit properties of a key * Copyright (C) 1998-2010 Free Software Foundation, Inc. * Copyright (C) 1998-2017 Werner Koch * Copyright (C) 2015, 2016 g10 Code GmbH * * This file is part of GnuPG. * * GnuPG is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * GnuPG is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . */ #include #include #include #include #include #include #ifdef HAVE_LIBREADLINE # define GNUPG_LIBREADLINE_H_INCLUDED # include #endif #include "gpg.h" #include "options.h" #include "packet.h" #include "../common/status.h" #include "../common/iobuf.h" #include "keydb.h" #include "photoid.h" #include "../common/util.h" #include "main.h" #include "trustdb.h" #include "filter.h" #include "../common/ttyio.h" #include "../common/status.h" #include "../common/i18n.h" #include "keyserver-internal.h" #include "call-agent.h" #include "../common/host2net.h" #include "tofu.h" #include "key-check.h" #include "keyedit.h" static void show_prefs (PKT_user_id * uid, PKT_signature * selfsig, int verbose); static void show_names (ctrl_t ctrl, estream_t fp, kbnode_t keyblock, PKT_public_key * pk, unsigned int flag, int with_prefs); static void show_key_with_all_names (ctrl_t ctrl, estream_t fp, KBNODE keyblock, int only_marked, int with_revoker, int with_fpr, int with_subkeys, int with_prefs, int nowarn); static void show_key_and_fingerprint (ctrl_t ctrl, kbnode_t keyblock, int with_subkeys); static void show_key_and_grip (kbnode_t keyblock); static void subkey_expire_warning (kbnode_t keyblock); static int menu_adduid (ctrl_t ctrl, kbnode_t keyblock, int photo, const char *photo_name, const char *uidstr); static void menu_deluid (KBNODE pub_keyblock); static int menu_delsig (ctrl_t ctrl, kbnode_t pub_keyblock); static int menu_clean (ctrl_t ctrl, kbnode_t keyblock, int self_only); static void menu_delkey (KBNODE pub_keyblock); static int menu_addrevoker (ctrl_t ctrl, kbnode_t pub_keyblock, int sensitive); static gpg_error_t menu_expire (ctrl_t ctrl, kbnode_t pub_keyblock, int unattended, u32 newexpiration); static int menu_changeusage (ctrl_t ctrl, kbnode_t keyblock); static int menu_backsign (ctrl_t ctrl, kbnode_t pub_keyblock); static int menu_set_primary_uid (ctrl_t ctrl, kbnode_t pub_keyblock); static int menu_set_preferences (ctrl_t ctrl, kbnode_t pub_keyblock); static int menu_set_keyserver_url (ctrl_t ctrl, const char *url, kbnode_t pub_keyblock); static int menu_set_notation (ctrl_t ctrl, const char *string, kbnode_t pub_keyblock); static int menu_select_uid (KBNODE keyblock, int idx); static int menu_select_uid_namehash (KBNODE keyblock, const char *namehash); static int menu_select_key (KBNODE keyblock, int idx, char *p); static int count_uids (KBNODE keyblock); static int count_uids_with_flag (KBNODE keyblock, unsigned flag); static int count_keys_with_flag (KBNODE keyblock, unsigned flag); static int count_selected_uids (KBNODE keyblock); static int real_uids_left (KBNODE keyblock); static int count_selected_keys (KBNODE keyblock); static int menu_revsig (ctrl_t ctrl, kbnode_t keyblock); static int menu_revuid (ctrl_t ctrl, kbnode_t keyblock); static int core_revuid (ctrl_t ctrl, kbnode_t keyblock, KBNODE node, const struct revocation_reason_info *reason, int *modified); static int menu_revkey (ctrl_t ctrl, kbnode_t pub_keyblock); static int menu_revsubkey (ctrl_t ctrl, kbnode_t pub_keyblock); #ifndef NO_TRUST_MODELS static int enable_disable_key (ctrl_t ctrl, kbnode_t keyblock, int disable); #endif /*!NO_TRUST_MODELS*/ static void menu_showphoto (ctrl_t ctrl, kbnode_t keyblock); static int update_trust = 0; #define CONTROL_D ('D' - 'A' + 1) struct sign_attrib { int non_exportable, non_revocable; struct revocation_reason_info *reason; byte trust_depth, trust_value; char *trust_regexp; }; /* TODO: Fix duplicated code between here and the check-sigs/list-sigs code in keylist.c. */ static int print_and_check_one_sig_colon (ctrl_t ctrl, kbnode_t keyblock, kbnode_t node, int *inv_sigs, int *no_key, int *oth_err, int *is_selfsig, int print_without_key) { PKT_signature *sig = node->pkt->pkt.signature; int rc, sigrc; /* TODO: Make sure a cached sig record here still has the pk that issued it. See also keylist.c:list_keyblock_print */ rc = check_key_signature (ctrl, keyblock, node, is_selfsig); switch (gpg_err_code (rc)) { case 0: node->flag &= ~(NODFLG_BADSIG | NODFLG_NOKEY | NODFLG_SIGERR); sigrc = '!'; break; case GPG_ERR_BAD_SIGNATURE: node->flag = NODFLG_BADSIG; sigrc = '-'; if (inv_sigs) ++ * inv_sigs; break; case GPG_ERR_NO_PUBKEY: case GPG_ERR_UNUSABLE_PUBKEY: node->flag = NODFLG_NOKEY; sigrc = '?'; if (no_key) ++ * no_key; break; default: node->flag = NODFLG_SIGERR; sigrc = '%'; if (oth_err) ++ * oth_err; break; } if (sigrc != '?' || print_without_key) { es_printf ("sig:%c::%d:%08lX%08lX:%lu:%lu:", sigrc, sig->pubkey_algo, (ulong) sig->keyid[0], (ulong) sig->keyid[1], (ulong) sig->timestamp, (ulong) sig->expiredate); if (sig->trust_depth || sig->trust_value) es_printf ("%d %d", sig->trust_depth, sig->trust_value); es_printf (":"); if (sig->trust_regexp) es_write_sanitized (es_stdout, sig->trust_regexp, strlen (sig->trust_regexp), ":", NULL); es_printf ("::%02x%c\n", sig->sig_class, sig->flags.exportable ? 'x' : 'l'); if (opt.show_subpackets) print_subpackets_colon (sig); } return (sigrc == '!'); } /* * Print information about a signature (rc is its status), check it * and return true if the signature is okay. NODE must be a signature * packet. With EXTENDED set all possible signature list options will * always be printed. */ int keyedit_print_one_sig (ctrl_t ctrl, estream_t fp, int rc, kbnode_t keyblock, kbnode_t node, int *inv_sigs, int *no_key, int *oth_err, int is_selfsig, int print_without_key, int extended) { PKT_signature *sig = node->pkt->pkt.signature; int sigrc; int is_rev = sig->sig_class == 0x30; /* TODO: Make sure a cached sig record here still has the pk that issued it. See also keylist.c:list_keyblock_print */ switch (gpg_err_code (rc)) { case 0: node->flag &= ~(NODFLG_BADSIG | NODFLG_NOKEY | NODFLG_SIGERR); sigrc = '!'; break; case GPG_ERR_BAD_SIGNATURE: node->flag = NODFLG_BADSIG; sigrc = '-'; if (inv_sigs) ++ * inv_sigs; break; case GPG_ERR_NO_PUBKEY: case GPG_ERR_UNUSABLE_PUBKEY: node->flag = NODFLG_NOKEY; sigrc = '?'; if (no_key) ++ * no_key; break; default: node->flag = NODFLG_SIGERR; sigrc = '%'; if (oth_err) ++ * oth_err; break; } if (sigrc != '?' || print_without_key) { tty_fprintf (fp, "%s%c%c %c%c%c%c%c%c %s %s", is_rev ? "rev" : "sig", 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) || extended ) tty_fprintf (fp, " %s", expirestr_from_sig (sig)); tty_fprintf (fp, " "); if (sigrc == '%') tty_fprintf (fp, "[%s] ", gpg_strerror (rc)); else if (sigrc == '?') ; else if (is_selfsig) { tty_fprintf (fp, is_rev ? _("[revocation]") : _("[self-signature]")); if (extended && sig->flags.chosen_selfsig) tty_fprintf (fp, "*"); } else { size_t n; char *p = get_user_id (ctrl, sig->keyid, &n); tty_print_utf8_string2 (fp, p, n, opt.screen_columns - keystrlen () - 26 - ((opt. list_options & LIST_SHOW_SIG_EXPIRE) ? 11 : 0)); xfree (p); } if (fp == log_get_stream ()) log_printf ("\n"); else tty_fprintf (fp, "\n"); if (sig->flags.policy_url && ((opt.list_options & LIST_SHOW_POLICY_URLS) || extended)) show_policy_url (sig, 3, (!fp? -1 : fp == log_get_stream ()? 1 : 0)); if (sig->flags.notation && ((opt.list_options & LIST_SHOW_NOTATIONS) || extended)) show_notation (sig, 3, (!fp? -1 : fp == log_get_stream ()? 1 : 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) || extended)) show_keyserver_url (sig, 3, (!fp? -1 : fp == log_get_stream ()? 1 : 0)); if (extended) { PKT_public_key *pk = keyblock->pkt->pkt.public_key; const unsigned char *s; s = parse_sig_subpkt (sig->hashed, SIGSUBPKT_PRIMARY_UID, NULL); if (s && *s) tty_fprintf (fp, " [primary]\n"); s = parse_sig_subpkt (sig->hashed, SIGSUBPKT_KEY_EXPIRE, NULL); if (s && buf32_to_u32 (s)) tty_fprintf (fp, " [expires: %s]\n", isotimestamp (pk->timestamp + buf32_to_u32 (s))); } } return (sigrc == '!'); } static int print_and_check_one_sig (ctrl_t ctrl, kbnode_t keyblock, kbnode_t node, int *inv_sigs, int *no_key, int *oth_err, int *is_selfsig, int print_without_key, int extended) { int rc; rc = check_key_signature (ctrl, keyblock, node, is_selfsig); return keyedit_print_one_sig (ctrl, NULL, rc, keyblock, node, inv_sigs, no_key, oth_err, *is_selfsig, print_without_key, extended); } static int sign_mk_attrib (PKT_signature * sig, void *opaque) { struct sign_attrib *attrib = opaque; byte buf[8]; if (attrib->non_exportable) { buf[0] = 0; /* not exportable */ build_sig_subpkt (sig, SIGSUBPKT_EXPORTABLE, buf, 1); } if (attrib->non_revocable) { buf[0] = 0; /* not revocable */ build_sig_subpkt (sig, SIGSUBPKT_REVOCABLE, buf, 1); } if (attrib->reason) revocation_reason_build_cb (sig, attrib->reason); if (attrib->trust_depth) { /* Not critical. If someone doesn't understand trust sigs, this can still be a valid regular signature. */ buf[0] = attrib->trust_depth; buf[1] = attrib->trust_value; build_sig_subpkt (sig, SIGSUBPKT_TRUST, buf, 2); /* Critical. If someone doesn't understands regexps, this whole sig should be invalid. Note the +1 for the length - regexps are null terminated. */ if (attrib->trust_regexp) build_sig_subpkt (sig, SIGSUBPKT_FLAG_CRITICAL | SIGSUBPKT_REGEXP, attrib->trust_regexp, strlen (attrib->trust_regexp) + 1); } return 0; } static void trustsig_prompt (byte * trust_value, byte * trust_depth, char **regexp) { char *p; *trust_value = 0; *trust_depth = 0; *regexp = NULL; /* Same string as pkclist.c:do_edit_ownertrust */ tty_printf (_ ("Please decide how far you trust this user to correctly verify" " other users' keys\n(by looking at passports, checking" " fingerprints from different sources, etc.)\n")); tty_printf ("\n"); tty_printf (_(" %d = I trust marginally\n"), 1); tty_printf (_(" %d = I trust fully\n"), 2); tty_printf ("\n"); while (*trust_value == 0) { p = cpr_get ("trustsig_prompt.trust_value", _("Your selection? ")); trim_spaces (p); cpr_kill_prompt (); /* 60 and 120 are as per RFC2440 */ if (p[0] == '1' && !p[1]) *trust_value = 60; else if (p[0] == '2' && !p[1]) *trust_value = 120; xfree (p); } tty_printf ("\n"); tty_printf (_("Please enter the depth of this trust signature.\n" "A depth greater than 1 allows the key you are" " signing to make\n" "trust signatures on your behalf.\n")); tty_printf ("\n"); while (*trust_depth == 0) { p = cpr_get ("trustsig_prompt.trust_depth", _("Your selection? ")); trim_spaces (p); cpr_kill_prompt (); *trust_depth = atoi (p); xfree (p); } tty_printf ("\n"); tty_printf (_("Please enter a domain to restrict this signature, " "or enter for none.\n")); tty_printf ("\n"); p = cpr_get ("trustsig_prompt.trust_regexp", _("Your selection? ")); trim_spaces (p); cpr_kill_prompt (); if (strlen (p) > 0) { char *q = p; int regexplen = 100, ind; *regexp = xmalloc (regexplen); /* Now mangle the domain the user entered into a regexp. To do this, \-escape everything that isn't alphanumeric, and attach "<[^>]+[@.]" to the front, and ">$" to the end. */ strcpy (*regexp, "<[^>]+[@.]"); ind = strlen (*regexp); while (*q) { if (!((*q >= 'A' && *q <= 'Z') || (*q >= 'a' && *q <= 'z') || (*q >= '0' && *q <= '9'))) (*regexp)[ind++] = '\\'; (*regexp)[ind++] = *q; if ((regexplen - ind) < 3) { regexplen += 100; *regexp = xrealloc (*regexp, regexplen); } q++; } (*regexp)[ind] = '\0'; strcat (*regexp, ">$"); } xfree (p); tty_printf ("\n"); } /* * Loop over all LOCUSR and sign the uids after asking. If no * user id is marked, all user ids will be signed; if some user_ids * are marked only those will be signed. If QUICK is true the * function won't ask the user and use sensible defaults. */ static int sign_uids (ctrl_t ctrl, estream_t fp, kbnode_t keyblock, strlist_t locusr, int *ret_modified, int local, int nonrevocable, int trust, int interactive, int quick) { int rc = 0; SK_LIST sk_list = NULL; SK_LIST sk_rover = NULL; PKT_public_key *pk = NULL; KBNODE node, uidnode; PKT_public_key *primary_pk = NULL; int select_all = !count_selected_uids (keyblock) || interactive; /* Build a list of all signators. * * We use the CERT flag to request the primary which must always * be one which is capable of signing keys. I can't see a reason * why to sign keys using a subkey. Implementation of USAGE_CERT * is just a hack in getkey.c and does not mean that a subkey * marked as certification capable will be used. */ rc = build_sk_list (ctrl, locusr, &sk_list, PUBKEY_USAGE_CERT); if (rc) goto leave; /* Loop over all signators. */ for (sk_rover = sk_list; sk_rover; sk_rover = sk_rover->next) { u32 sk_keyid[2], pk_keyid[2]; char *p, *trust_regexp = NULL; int class = 0, selfsig = 0; u32 duration = 0, timestamp = 0; byte trust_depth = 0, trust_value = 0; pk = sk_rover->pk; keyid_from_pk (pk, sk_keyid); /* Set mark A for all selected user ids. */ for (node = keyblock; node; node = node->next) { if (select_all || (node->flag & NODFLG_SELUID)) node->flag |= NODFLG_MARK_A; else node->flag &= ~NODFLG_MARK_A; } /* Reset mark for uids which are already signed. */ uidnode = NULL; for (node = keyblock; node; node = node->next) { if (node->pkt->pkttype == PKT_PUBLIC_KEY) { primary_pk = node->pkt->pkt.public_key; keyid_from_pk (primary_pk, pk_keyid); /* Is this a self-sig? */ if (pk_keyid[0] == sk_keyid[0] && pk_keyid[1] == sk_keyid[1]) selfsig = 1; } else if (node->pkt->pkttype == PKT_USER_ID) { uidnode = (node->flag & NODFLG_MARK_A) ? node : NULL; if (uidnode) { int yesreally = 0; char *user; user = utf8_to_native (uidnode->pkt->pkt.user_id->name, uidnode->pkt->pkt.user_id->len, 0); if (opt.only_sign_text_ids && uidnode->pkt->pkt.user_id->attribs) { tty_fprintf (fp, _("Skipping user ID \"%s\"," " which is not a text ID.\n"), user); uidnode->flag &= ~NODFLG_MARK_A; uidnode = NULL; } else if (uidnode->pkt->pkt.user_id->flags.revoked) { tty_fprintf (fp, _("User ID \"%s\" is revoked."), user); if (selfsig) tty_fprintf (fp, "\n"); else if (opt.expert && !quick) { tty_fprintf (fp, "\n"); /* No, so remove the mark and continue */ if (!cpr_get_answer_is_yes ("sign_uid.revoke_okay", _("Are you sure you " "still want to sign " "it? (y/N) "))) { uidnode->flag &= ~NODFLG_MARK_A; uidnode = NULL; } else if (interactive) yesreally = 1; } else { uidnode->flag &= ~NODFLG_MARK_A; uidnode = NULL; tty_fprintf (fp, _(" Unable to sign.\n")); } } else if (uidnode->pkt->pkt.user_id->flags.expired) { tty_fprintf (fp, _("User ID \"%s\" is expired."), user); if (selfsig) tty_fprintf (fp, "\n"); else if (opt.expert && !quick) { tty_fprintf (fp, "\n"); /* No, so remove the mark and continue */ if (!cpr_get_answer_is_yes ("sign_uid.expire_okay", _("Are you sure you " "still want to sign " "it? (y/N) "))) { uidnode->flag &= ~NODFLG_MARK_A; uidnode = NULL; } else if (interactive) yesreally = 1; } else { uidnode->flag &= ~NODFLG_MARK_A; uidnode = NULL; tty_fprintf (fp, _(" Unable to sign.\n")); } } else if (!uidnode->pkt->pkt.user_id->created && !selfsig) { tty_fprintf (fp, _("User ID \"%s\" is not self-signed."), user); if (opt.expert && !quick) { tty_fprintf (fp, "\n"); /* No, so remove the mark and continue */ if (!cpr_get_answer_is_yes ("sign_uid.nosig_okay", _("Are you sure you " "still want to sign " "it? (y/N) "))) { uidnode->flag &= ~NODFLG_MARK_A; uidnode = NULL; } else if (interactive) yesreally = 1; } else { uidnode->flag &= ~NODFLG_MARK_A; uidnode = NULL; tty_fprintf (fp, _(" Unable to sign.\n")); } } if (uidnode && interactive && !yesreally && !quick) { tty_fprintf (fp, _("User ID \"%s\" is signable. "), user); if (!cpr_get_answer_is_yes ("sign_uid.sign_okay", _("Sign it? (y/N) "))) { uidnode->flag &= ~NODFLG_MARK_A; uidnode = NULL; } } xfree (user); } } else if (uidnode && node->pkt->pkttype == PKT_SIGNATURE && (node->pkt->pkt.signature->sig_class & ~3) == 0x10) { if (sk_keyid[0] == node->pkt->pkt.signature->keyid[0] && sk_keyid[1] == node->pkt->pkt.signature->keyid[1]) { char buf[50]; char *user; user = utf8_to_native (uidnode->pkt->pkt.user_id->name, uidnode->pkt->pkt.user_id->len, 0); /* It's a v3 self-sig. Make it into a v4 self-sig? */ if (node->pkt->pkt.signature->version < 4 && selfsig && !quick) { tty_fprintf (fp, _("The self-signature on \"%s\"\n" "is a PGP 2.x-style signature.\n"), user); /* Note that the regular PGP2 warning below still applies if there are no v4 sigs on this key at all. */ if (opt.expert) if (cpr_get_answer_is_yes ("sign_uid.v4_promote_okay", _("Do you want to promote " "it to an OpenPGP self-" "signature? (y/N) "))) { node->flag |= NODFLG_DELSIG; xfree (user); continue; } } /* Is the current signature expired? */ if (node->pkt->pkt.signature->flags.expired) { tty_fprintf (fp, _("Your current signature on \"%s\"\n" "has expired.\n"), user); if (quick || cpr_get_answer_is_yes ("sign_uid.replace_expired_okay", _("Do you want to issue a " "new signature to replace " "the expired one? (y/N) "))) { /* Mark these for later deletion. We don't want to delete them here, just in case the replacement signature doesn't happen for some reason. We only delete these after the replacement is already in place. */ node->flag |= NODFLG_DELSIG; xfree (user); continue; } } if (!node->pkt->pkt.signature->flags.exportable && !local) { /* It's a local sig, and we want to make a exportable sig. */ tty_fprintf (fp, _("Your current signature on \"%s\"\n" "is a local signature.\n"), user); if (quick || cpr_get_answer_is_yes ("sign_uid.local_promote_okay", _("Do you want to promote " "it to a full exportable " "signature? (y/N) "))) { /* Mark these for later deletion. We don't want to delete them here, just in case the replacement signature doesn't happen for some reason. We only delete these after the replacement is already in place. */ node->flag |= NODFLG_DELSIG; xfree (user); continue; } } /* Fixme: see whether there is a revocation in which * case we should allow signing it again. */ if (!node->pkt->pkt.signature->flags.exportable && local) tty_fprintf ( fp, _("\"%s\" was already locally signed by key %s\n"), user, keystr_from_pk (pk)); else tty_fprintf (fp, _("\"%s\" was already signed by key %s\n"), user, keystr_from_pk (pk)); if (opt.expert && !quick && cpr_get_answer_is_yes ("sign_uid.dupe_okay", _("Do you want to sign it " "again anyway? (y/N) "))) { /* Don't delete the old sig here since this is an --expert thing. */ xfree (user); continue; } snprintf (buf, sizeof buf, "%08lX%08lX", (ulong) pk->keyid[0], (ulong) pk->keyid[1]); write_status_text (STATUS_ALREADY_SIGNED, buf); uidnode->flag &= ~NODFLG_MARK_A; /* remove mark */ xfree (user); } } } /* Check whether any uids are left for signing. */ if (!count_uids_with_flag (keyblock, NODFLG_MARK_A)) { tty_fprintf (fp, _("Nothing to sign with key %s\n"), keystr_from_pk (pk)); continue; } /* Ask whether we really should sign these user id(s). */ tty_fprintf (fp, "\n"); show_key_with_all_names (ctrl, fp, keyblock, 1, 0, 1, 0, 0, 0); tty_fprintf (fp, "\n"); if (primary_pk->expiredate && !selfsig) { /* Static analyzer note: A claim that PRIMARY_PK might be NULL is not correct because it set from the public key packet which is always the first packet in a keyblock and parsed in the above loop over the keyblock. In case the keyblock has no packets at all and thus the loop was not entered the above count_uids_with_flag would have detected this case. */ u32 now = make_timestamp (); if (primary_pk->expiredate <= now) { tty_fprintf (fp, _("This key has expired!")); if (opt.expert && !quick) { tty_fprintf (fp, " "); if (!cpr_get_answer_is_yes ("sign_uid.expired_okay", _("Are you sure you still " "want to sign it? (y/N) "))) continue; } else { tty_fprintf (fp, _(" Unable to sign.\n")); continue; } } else { tty_fprintf (fp, _("This key is due to expire on %s.\n"), expirestr_from_pk (primary_pk)); if (opt.ask_cert_expire && !quick) { char *answer = cpr_get ("sign_uid.expire", _("Do you want your signature to " "expire at the same time? (Y/n) ")); if (answer_is_yes_no_default (answer, 1)) { /* This fixes the signature timestamp we're going to make as now. This is so the expiration date is exactly correct, and not a few seconds off (due to the time it takes to answer the questions, enter the passphrase, etc). */ timestamp = now; duration = primary_pk->expiredate - now; } cpr_kill_prompt (); xfree (answer); } } } /* Only ask for duration if we haven't already set it to match the expiration of the pk */ if (!duration && !selfsig) { if (opt.ask_cert_expire && !quick) duration = ask_expire_interval (1, opt.def_cert_expire); else duration = parse_expire_string (opt.def_cert_expire); } if (selfsig) ; else { if (opt.batch || !opt.ask_cert_level || quick) class = 0x10 + opt.def_cert_level; else { char *answer; tty_fprintf (fp, _("How carefully have you verified the key you are " "about to sign actually belongs\nto the person " "named above? If you don't know what to " "answer, enter \"0\".\n")); tty_fprintf (fp, "\n"); tty_fprintf (fp, _(" (0) I will not answer.%s\n"), opt.def_cert_level == 0 ? " (default)" : ""); tty_fprintf (fp, _(" (1) I have not checked at all.%s\n"), opt.def_cert_level == 1 ? " (default)" : ""); tty_fprintf (fp, _(" (2) I have done casual checking.%s\n"), opt.def_cert_level == 2 ? " (default)" : ""); tty_fprintf (fp, _(" (3) I have done very careful checking.%s\n"), opt.def_cert_level == 3 ? " (default)" : ""); tty_fprintf (fp, "\n"); while (class == 0) { answer = cpr_get ("sign_uid.class", _("Your selection? " "(enter '?' for more information): ")); if (answer[0] == '\0') class = 0x10 + opt.def_cert_level; /* Default */ else if (ascii_strcasecmp (answer, "0") == 0) class = 0x10; /* Generic */ else if (ascii_strcasecmp (answer, "1") == 0) class = 0x11; /* Persona */ else if (ascii_strcasecmp (answer, "2") == 0) class = 0x12; /* Casual */ else if (ascii_strcasecmp (answer, "3") == 0) class = 0x13; /* Positive */ else tty_fprintf (fp, _("Invalid selection.\n")); xfree (answer); } } if (trust && !quick) trustsig_prompt (&trust_value, &trust_depth, &trust_regexp); } if (!quick) { p = get_user_id_native (ctrl, sk_keyid); tty_fprintf (fp, _("Are you sure that you want to sign this key with your\n" "key \"%s\" (%s)\n"), p, keystr_from_pk (pk)); xfree (p); } if (selfsig) { tty_fprintf (fp, "\n"); tty_fprintf (fp, _("This will be a self-signature.\n")); if (local) { tty_fprintf (fp, "\n"); tty_fprintf (fp, _("WARNING: the signature will not be marked " "as non-exportable.\n")); } if (nonrevocable) { tty_fprintf (fp, "\n"); tty_fprintf (fp, _("WARNING: the signature will not be marked " "as non-revocable.\n")); } } else { if (local) { tty_fprintf (fp, "\n"); tty_fprintf (fp, _("The signature will be marked as non-exportable.\n")); } if (nonrevocable) { tty_fprintf (fp, "\n"); tty_fprintf (fp, _("The signature will be marked as non-revocable.\n")); } switch (class) { case 0x11: tty_fprintf (fp, "\n"); tty_fprintf (fp, _("I have not checked this key at all.\n")); break; case 0x12: tty_fprintf (fp, "\n"); tty_fprintf (fp, _("I have checked this key casually.\n")); break; case 0x13: tty_fprintf (fp, "\n"); tty_fprintf (fp, _("I have checked this key very carefully.\n")); break; } } tty_fprintf (fp, "\n"); if (opt.batch && opt.answer_yes) ; else if (quick) ; else if (!cpr_get_answer_is_yes ("sign_uid.okay", _("Really sign? (y/N) "))) continue; /* Now we can sign the user ids. */ reloop: /* (Must use this, because we are modifying the list.) */ primary_pk = NULL; for (node = keyblock; node; node = node->next) { if (node->pkt->pkttype == PKT_PUBLIC_KEY) primary_pk = node->pkt->pkt.public_key; else if (node->pkt->pkttype == PKT_USER_ID && (node->flag & NODFLG_MARK_A)) { PACKET *pkt; PKT_signature *sig; struct sign_attrib attrib; log_assert (primary_pk); memset (&attrib, 0, sizeof attrib); attrib.non_exportable = local; attrib.non_revocable = nonrevocable; attrib.trust_depth = trust_depth; attrib.trust_value = trust_value; attrib.trust_regexp = trust_regexp; node->flag &= ~NODFLG_MARK_A; /* We force creation of a v4 signature for local * signatures, otherwise we would not generate the * subpacket with v3 keys and the signature becomes * exportable. */ if (selfsig) rc = make_keysig_packet (ctrl, &sig, primary_pk, node->pkt->pkt.user_id, NULL, pk, 0x13, 0, 0, 0, keygen_add_std_prefs, primary_pk, NULL); else rc = make_keysig_packet (ctrl, &sig, primary_pk, node->pkt->pkt.user_id, NULL, pk, class, 0, timestamp, duration, sign_mk_attrib, &attrib, NULL); if (rc) { write_status_error ("keysig", rc); log_error (_("signing failed: %s\n"), gpg_strerror (rc)); goto leave; } *ret_modified = 1; /* We changed the keyblock. */ update_trust = 1; pkt = xmalloc_clear (sizeof *pkt); pkt->pkttype = PKT_SIGNATURE; pkt->pkt.signature = sig; insert_kbnode (node, new_kbnode (pkt), PKT_SIGNATURE); goto reloop; } } /* Delete any sigs that got promoted */ for (node = keyblock; node; node = node->next) if (node->flag & NODFLG_DELSIG) delete_kbnode (node); } /* End loop over signators. */ leave: release_sk_list (sk_list); return rc; } /* * Change the passphrase of the primary and all secondary keys. Note * that it is common to use only one passphrase for the primary and * all subkeys. However, this is now (since GnuPG 2.1) all up to the * gpg-agent. Returns 0 on success or an error code. */ static gpg_error_t change_passphrase (ctrl_t ctrl, kbnode_t keyblock) { gpg_error_t err; kbnode_t node; PKT_public_key *pk; int any; u32 keyid[2], subid[2]; char *hexgrip = NULL; char *cache_nonce = NULL; char *passwd_nonce = NULL; node = find_kbnode (keyblock, PKT_PUBLIC_KEY); if (!node) { log_error ("Oops; public key missing!\n"); err = gpg_error (GPG_ERR_INTERNAL); goto leave; } pk = node->pkt->pkt.public_key; keyid_from_pk (pk, keyid); /* Check whether it is likely that we will be able to change the passphrase for any subkey. */ for (any = 0, node = keyblock; node; node = node->next) { if (node->pkt->pkttype == PKT_PUBLIC_KEY || node->pkt->pkttype == PKT_PUBLIC_SUBKEY) { char *serialno; pk = node->pkt->pkt.public_key; keyid_from_pk (pk, subid); xfree (hexgrip); err = hexkeygrip_from_pk (pk, &hexgrip); if (err) goto leave; err = agent_get_keyinfo (ctrl, hexgrip, &serialno, NULL); if (!err && serialno) ; /* Key on card. */ else if (gpg_err_code (err) == GPG_ERR_NOT_FOUND) ; /* Maybe stub key. */ else if (!err) any = 1; /* Key is known. */ else log_error ("key %s: error getting keyinfo from agent: %s\n", keystr_with_sub (keyid, subid), gpg_strerror (err)); xfree (serialno); } } err = 0; if (!any) { tty_printf (_("Key has only stub or on-card key items - " "no passphrase to change.\n")); goto leave; } /* Change the passphrase for all keys. */ for (node = keyblock; node; node = node->next) { if (node->pkt->pkttype == PKT_PUBLIC_KEY || node->pkt->pkttype == PKT_PUBLIC_SUBKEY) { char *desc; pk = node->pkt->pkt.public_key; keyid_from_pk (pk, subid); xfree (hexgrip); err = hexkeygrip_from_pk (pk, &hexgrip); if (err) goto leave; desc = gpg_format_keydesc (ctrl, pk, FORMAT_KEYDESC_NORMAL, 1); err = agent_passwd (ctrl, hexgrip, desc, 0, &cache_nonce, &passwd_nonce); xfree (desc); if (err) log_log ((gpg_err_code (err) == GPG_ERR_CANCELED || gpg_err_code (err) == GPG_ERR_FULLY_CANCELED) ? GPGRT_LOGLVL_INFO : GPGRT_LOGLVL_ERROR, _("key %s: error changing passphrase: %s\n"), keystr_with_sub (keyid, subid), gpg_strerror (err)); if (gpg_err_code (err) == GPG_ERR_FULLY_CANCELED) break; } } leave: xfree (hexgrip); xfree (cache_nonce); xfree (passwd_nonce); return err; } /* Fix various problems in the keyblock. Returns true if the keyblock was changed. Note that a pointer to the keyblock must be given and the function may change it (i.e. replacing the first node). */ static int fix_keyblock (ctrl_t ctrl, kbnode_t *keyblockp) { int changed = 0; if (collapse_uids (keyblockp)) changed++; if (key_check_all_keysigs (ctrl, 1, *keyblockp, 0, 1)) changed++; reorder_keyblock (*keyblockp); /* If we modified the keyblock, make sure the flags are right. */ if (changed) merge_keys_and_selfsig (ctrl, *keyblockp); return changed; } static int parse_sign_type (const char *str, int *localsig, int *nonrevokesig, int *trustsig) { const char *p = str; while (*p) { if (ascii_strncasecmp (p, "l", 1) == 0) { *localsig = 1; p++; } else if (ascii_strncasecmp (p, "nr", 2) == 0) { *nonrevokesig = 1; p += 2; } else if (ascii_strncasecmp (p, "t", 1) == 0) { *trustsig = 1; p++; } else return 0; } return 1; } /* * Menu driven key editor. If seckey_check is true, then a secret key * that matches username will be looked for. If it is false, not all * commands will be available. * * Note: to keep track of certain selections we use node->mark MARKBIT_xxxx. */ /* Need an SK for this command */ #define KEYEDIT_NEED_SK 1 /* Need an SUB KEY for this command */ #define KEYEDIT_NEED_SUBSK 2 /* Match the tail of the string */ #define KEYEDIT_TAIL_MATCH 8 enum cmdids { cmdNONE = 0, cmdQUIT, cmdHELP, cmdFPR, cmdLIST, cmdSELUID, cmdCHECK, cmdSIGN, cmdREVSIG, cmdREVKEY, cmdREVUID, cmdDELSIG, cmdPRIMARY, cmdDEBUG, cmdSAVE, cmdADDUID, cmdADDPHOTO, cmdDELUID, cmdADDKEY, cmdDELKEY, cmdADDREVOKER, cmdTOGGLE, cmdSELKEY, cmdPASSWD, cmdTRUST, cmdPREF, cmdEXPIRE, cmdCHANGEUSAGE, cmdBACKSIGN, #ifndef NO_TRUST_MODELS cmdENABLEKEY, cmdDISABLEKEY, #endif /*!NO_TRUST_MODELS*/ cmdSHOWPREF, cmdSETPREF, cmdPREFKS, cmdNOTATION, cmdINVCMD, cmdSHOWPHOTO, cmdUPDTRUST, cmdCHKTRUST, cmdADDCARDKEY, cmdKEYTOCARD, cmdBKUPTOCARD, cmdCLEAN, cmdMINIMIZE, cmdGRIP, cmdNOP }; static struct { const char *name; enum cmdids id; int flags; const char *desc; } cmds[] = { { "quit", cmdQUIT, 0, N_("quit this menu")}, { "q", cmdQUIT, 0, NULL}, { "save", cmdSAVE, 0, N_("save and quit")}, { "help", cmdHELP, 0, N_("show this help")}, { "?", cmdHELP, 0, NULL}, { "fpr", cmdFPR, 0, N_("show key fingerprint")}, { "grip", cmdGRIP, 0, N_("show the keygrip")}, { "list", cmdLIST, 0, N_("list key and user IDs")}, { "l", cmdLIST, 0, NULL}, { "uid", cmdSELUID, 0, N_("select user ID N")}, { "key", cmdSELKEY, 0, N_("select subkey N")}, { "check", cmdCHECK, 0, N_("check signatures")}, { "c", cmdCHECK, 0, NULL}, { "change-usage", cmdCHANGEUSAGE, KEYEDIT_NEED_SK, NULL}, { "cross-certify", cmdBACKSIGN, KEYEDIT_NEED_SK, NULL}, { "backsign", cmdBACKSIGN, KEYEDIT_NEED_SK, NULL}, { "sign", cmdSIGN, KEYEDIT_TAIL_MATCH, N_("sign selected user IDs [* see below for related commands]")}, { "s", cmdSIGN, 0, NULL}, /* "lsign" and friends will never match since "sign" comes first and it is a tail match. They are just here so they show up in the help menu. */ { "lsign", cmdNOP, 0, N_("sign selected user IDs locally")}, { "tsign", cmdNOP, 0, N_("sign selected user IDs with a trust signature")}, { "nrsign", cmdNOP, 0, N_("sign selected user IDs with a non-revocable signature")}, { "debug", cmdDEBUG, 0, NULL}, { "adduid", cmdADDUID, KEYEDIT_NEED_SK, N_("add a user ID")}, { "addphoto", cmdADDPHOTO, KEYEDIT_NEED_SK, N_("add a photo ID")}, { "deluid", cmdDELUID, 0, N_("delete selected user IDs")}, /* delphoto is really deluid in disguise */ { "delphoto", cmdDELUID, 0, NULL}, { "addkey", cmdADDKEY, KEYEDIT_NEED_SK, N_("add a subkey")}, #ifdef ENABLE_CARD_SUPPORT { "addcardkey", cmdADDCARDKEY, KEYEDIT_NEED_SK, N_("add a key to a smartcard")}, { "keytocard", cmdKEYTOCARD, KEYEDIT_NEED_SK | KEYEDIT_NEED_SUBSK, N_("move a key to a smartcard")}, { "bkuptocard", cmdBKUPTOCARD, KEYEDIT_NEED_SK | KEYEDIT_NEED_SUBSK, N_("move a backup key to a smartcard")}, #endif /*ENABLE_CARD_SUPPORT */ { "delkey", cmdDELKEY, 0, N_("delete selected subkeys")}, { "addrevoker", cmdADDREVOKER, KEYEDIT_NEED_SK, N_("add a revocation key")}, { "delsig", cmdDELSIG, 0, N_("delete signatures from the selected user IDs")}, { "expire", cmdEXPIRE, KEYEDIT_NEED_SK | KEYEDIT_NEED_SUBSK, N_("change the expiration date for the key or selected subkeys")}, { "primary", cmdPRIMARY, KEYEDIT_NEED_SK, N_("flag the selected user ID as primary")}, { "toggle", cmdTOGGLE, KEYEDIT_NEED_SK, NULL}, /* Dummy command. */ { "t", cmdTOGGLE, KEYEDIT_NEED_SK, NULL}, { "pref", cmdPREF, 0, N_("list preferences (expert)")}, { "showpref", cmdSHOWPREF, 0, N_("list preferences (verbose)")}, { "setpref", cmdSETPREF, KEYEDIT_NEED_SK, N_("set preference list for the selected user IDs")}, { "updpref", cmdSETPREF, KEYEDIT_NEED_SK, NULL}, { "keyserver", cmdPREFKS, KEYEDIT_NEED_SK, N_("set the preferred keyserver URL for the selected user IDs")}, { "notation", cmdNOTATION, KEYEDIT_NEED_SK, N_("set a notation for the selected user IDs")}, { "passwd", cmdPASSWD, KEYEDIT_NEED_SK | KEYEDIT_NEED_SUBSK, N_("change the passphrase")}, { "password", cmdPASSWD, KEYEDIT_NEED_SK | KEYEDIT_NEED_SUBSK, NULL}, #ifndef NO_TRUST_MODELS { "trust", cmdTRUST, 0, N_("change the ownertrust")}, #endif /*!NO_TRUST_MODELS*/ { "revsig", cmdREVSIG, 0, N_("revoke signatures on the selected user IDs")}, { "revuid", cmdREVUID, KEYEDIT_NEED_SK, N_("revoke selected user IDs")}, { "revphoto", cmdREVUID, KEYEDIT_NEED_SK, NULL}, { "revkey", cmdREVKEY, KEYEDIT_NEED_SK, N_("revoke key or selected subkeys")}, #ifndef NO_TRUST_MODELS { "enable", cmdENABLEKEY, 0, N_("enable key")}, { "disable", cmdDISABLEKEY, 0, N_("disable key")}, #endif /*!NO_TRUST_MODELS*/ { "showphoto", cmdSHOWPHOTO, 0, N_("show selected photo IDs")}, { "clean", cmdCLEAN, 0, N_("compact unusable user IDs and remove unusable signatures from key")}, { "minimize", cmdMINIMIZE, 0, N_("compact unusable user IDs and remove all signatures from key")}, { NULL, cmdNONE, 0, NULL} }; #ifdef HAVE_LIBREADLINE /* These two functions are used by readline for command completion. */ static char * command_generator (const char *text, int state) { static int list_index, len; const char *name; /* If this is a new word to complete, initialize now. This includes saving the length of TEXT for efficiency, and initializing the index variable to 0. */ if (!state) { list_index = 0; len = strlen (text); } /* Return the next partial match */ while ((name = cmds[list_index].name)) { /* Only complete commands that have help text */ if (cmds[list_index++].desc && strncmp (name, text, len) == 0) return strdup (name); } return NULL; } static char ** keyedit_completion (const char *text, int start, int end) { /* If we are at the start of a line, we try and command-complete. If not, just do nothing for now. */ (void) end; if (start == 0) return rl_completion_matches (text, command_generator); rl_attempted_completion_over = 1; return NULL; } #endif /* HAVE_LIBREADLINE */ /* Main function of the menu driven key editor. */ void keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr, strlist_t commands, int quiet, int seckey_check) { enum cmdids cmd = 0; gpg_error_t err = 0; KBNODE keyblock = NULL; KEYDB_HANDLE kdbhd = NULL; int have_seckey = 0; int have_anyseckey = 0; char *answer = NULL; int redisplay = 1; int modified = 0; int sec_shadowing = 0; int run_subkey_warnings = 0; int have_commands = !!commands; if (opt.command_fd != -1) ; else if (opt.batch && !have_commands) { log_error (_("can't do this in batch mode\n")); goto leave; } #ifdef HAVE_W32_SYSTEM /* Due to Windows peculiarities we need to make sure that the trustdb stale check is done before we open another file (i.e. by searching for a key). In theory we could make sure that the files are closed after use but the open/close caches inhibits that and flushing the cache right before the stale check is not easy to implement. Thus we take the easy way out and run the stale check as early as possible. Note, that for non- W32 platforms it is run indirectly trough a call to get_validity (). */ check_trustdb_stale (ctrl); #endif /* Get the public key */ err = get_pubkey_byname (ctrl, NULL, NULL, username, &keyblock, &kdbhd, 1, 1); if (err) { log_error (_("key \"%s\" not found: %s\n"), username, gpg_strerror (err)); goto leave; } if (fix_keyblock (ctrl, &keyblock)) modified++; /* See whether we have a matching secret key. */ if (seckey_check) { have_anyseckey = !agent_probe_any_secret_key (ctrl, keyblock); if (have_anyseckey && !agent_probe_secret_key (ctrl, keyblock->pkt->pkt.public_key)) { /* The primary key is also available. */ have_seckey = 1; } if (have_seckey && !quiet) tty_printf (_("Secret key is available.\n")); else if (have_anyseckey && !quiet) tty_printf (_("Secret subkeys are available.\n")); } /* Main command loop. */ for (;;) { int i, arg_number, photo; const char *arg_string = ""; char *p; PKT_public_key *pk = keyblock->pkt->pkt.public_key; tty_printf ("\n"); if (redisplay && !quiet) { /* Show using flags: with_revoker, with_subkeys. */ show_key_with_all_names (ctrl, NULL, keyblock, 0, 1, 0, 1, 0, 0); tty_printf ("\n"); redisplay = 0; } if (run_subkey_warnings) { run_subkey_warnings = 0; if (!count_selected_keys (keyblock)) subkey_expire_warning (keyblock); } do { xfree (answer); if (have_commands) { if (commands) { answer = xstrdup (commands->d); commands = commands->next; } else if (opt.batch) { answer = xstrdup ("quit"); } else have_commands = 0; } if (!have_commands) { #ifdef HAVE_LIBREADLINE tty_enable_completion (keyedit_completion); #endif answer = cpr_get_no_help ("keyedit.prompt", GPG_NAME "> "); cpr_kill_prompt (); tty_disable_completion (); } trim_spaces (answer); } while (*answer == '#'); arg_number = 0; /* Here is the init which egcc complains about. */ photo = 0; /* Same here. */ if (!*answer) cmd = cmdLIST; else if (*answer == CONTROL_D) cmd = cmdQUIT; else if (digitp (answer)) { cmd = cmdSELUID; arg_number = atoi (answer); } else { if ((p = strchr (answer, ' '))) { *p++ = 0; trim_spaces (answer); trim_spaces (p); arg_number = atoi (p); arg_string = p; } for (i = 0; cmds[i].name; i++) { if (cmds[i].flags & KEYEDIT_TAIL_MATCH) { size_t l = strlen (cmds[i].name); size_t a = strlen (answer); if (a >= l) { if (!ascii_strcasecmp (&answer[a - l], cmds[i].name)) { answer[a - l] = '\0'; break; } } } else if (!ascii_strcasecmp (answer, cmds[i].name)) break; } if ((cmds[i].flags & (KEYEDIT_NEED_SK|KEYEDIT_NEED_SUBSK)) && !(((cmds[i].flags & KEYEDIT_NEED_SK) && have_seckey) || ((cmds[i].flags & KEYEDIT_NEED_SUBSK) && have_anyseckey))) { tty_printf (_("Need the secret key to do this.\n")); cmd = cmdNOP; } else cmd = cmds[i].id; } /* Dispatch the command. */ switch (cmd) { case cmdHELP: for (i = 0; cmds[i].name; i++) { if ((cmds[i].flags & (KEYEDIT_NEED_SK|KEYEDIT_NEED_SUBSK)) && !(((cmds[i].flags & KEYEDIT_NEED_SK) && have_seckey) ||((cmds[i].flags&KEYEDIT_NEED_SUBSK)&&have_anyseckey))) ; /* Skip those item if we do not have the secret key. */ else if (cmds[i].desc) tty_printf ("%-11s %s\n", cmds[i].name, _(cmds[i].desc)); } tty_printf ("\n"); tty_printf (_("* The 'sign' command may be prefixed with an 'l' for local " "signatures (lsign),\n" " a 't' for trust signatures (tsign), an 'nr' for " "non-revocable signatures\n" " (nrsign), or any combination thereof (ltsign, " "tnrsign, etc.).\n")); break; case cmdLIST: redisplay = 1; break; case cmdFPR: show_key_and_fingerprint (ctrl, keyblock, (*arg_string == '*' && (!arg_string[1] || spacep (arg_string + 1)))); break; case cmdGRIP: show_key_and_grip (keyblock); break; case cmdSELUID: if (strlen (arg_string) == NAMEHASH_LEN * 2) redisplay = menu_select_uid_namehash (keyblock, arg_string); else { if (*arg_string == '*' && (!arg_string[1] || spacep (arg_string + 1))) arg_number = -1; /* Select all. */ redisplay = menu_select_uid (keyblock, arg_number); } break; case cmdSELKEY: { if (*arg_string == '*' && (!arg_string[1] || spacep (arg_string + 1))) arg_number = -1; /* Select all. */ if (menu_select_key (keyblock, arg_number, p)) redisplay = 1; } break; case cmdCHECK: if (key_check_all_keysigs (ctrl, -1, keyblock, count_selected_uids (keyblock), !strcmp (arg_string, "selfsig"))) modified = 1; break; case cmdSIGN: { int localsig = 0, nonrevokesig = 0, trustsig = 0, interactive = 0; if (pk->flags.revoked) { tty_printf (_("Key is revoked.")); if (opt.expert) { tty_printf (" "); if (!cpr_get_answer_is_yes ("keyedit.sign_revoked.okay", _("Are you sure you still want to sign it? (y/N) "))) break; } else { tty_printf (_(" Unable to sign.\n")); break; } } if (count_uids (keyblock) > 1 && !count_selected_uids (keyblock)) { int result; if (opt.only_sign_text_ids) result = cpr_get_answer_is_yes ("keyedit.sign_all.okay", _("Really sign all user IDs? (y/N) ")); else result = cpr_get_answer_is_yes ("keyedit.sign_all.okay", _("Really sign all text user IDs? (y/N) ")); if (! result) { if (opt.interactive) interactive = 1; else { tty_printf (_("Hint: Select the user IDs to sign\n")); have_commands = 0; break; } } } /* What sort of signing are we doing? */ if (!parse_sign_type (answer, &localsig, &nonrevokesig, &trustsig)) { tty_printf (_("Unknown signature type '%s'\n"), answer); break; } sign_uids (ctrl, NULL, keyblock, locusr, &modified, localsig, nonrevokesig, trustsig, interactive, 0); } break; case cmdDEBUG: dump_kbnode (keyblock); break; case cmdTOGGLE: /* The toggle command is a leftover from old gpg versions where we worked with a secret and a public keyring. It is not necessary anymore but we keep this command for the sake of scripts using it. */ redisplay = 1; break; case cmdADDPHOTO: if (RFC2440) { tty_printf (_("This command is not allowed while in %s mode.\n"), gnupg_compliance_option_string (opt.compliance)); break; } photo = 1; /* fall through */ case cmdADDUID: if (menu_adduid (ctrl, keyblock, photo, arg_string, NULL)) { update_trust = 1; redisplay = 1; modified = 1; merge_keys_and_selfsig (ctrl, keyblock); } break; case cmdDELUID: { int n1; if (!(n1 = count_selected_uids (keyblock))) { tty_printf (_("You must select at least one user ID.\n")); if (!opt.expert) tty_printf (_("(Use the '%s' command.)\n"), "uid"); } else if (real_uids_left (keyblock) < 1) tty_printf (_("You can't delete the last user ID!\n")); else if (cpr_get_answer_is_yes ("keyedit.remove.uid.okay", n1 > 1 ? _("Really remove all selected user IDs? (y/N) ") : _("Really remove this user ID? (y/N) "))) { menu_deluid (keyblock); redisplay = 1; modified = 1; } } break; case cmdDELSIG: { int n1; if (!(n1 = count_selected_uids (keyblock))) { tty_printf (_("You must select at least one user ID.\n")); if (!opt.expert) tty_printf (_("(Use the '%s' command.)\n"), "uid"); } else if (menu_delsig (ctrl, keyblock)) { /* No redisplay here, because it may scroll away some * of the status output of this command. */ modified = 1; } } break; case cmdADDKEY: if (!generate_subkeypair (ctrl, keyblock, NULL, NULL, NULL)) { redisplay = 1; modified = 1; merge_keys_and_selfsig (ctrl, keyblock); } break; #ifdef ENABLE_CARD_SUPPORT case cmdADDCARDKEY: if (!card_generate_subkey (ctrl, keyblock)) { redisplay = 1; modified = 1; merge_keys_and_selfsig (ctrl, keyblock); } break; case cmdKEYTOCARD: { KBNODE node = NULL; switch (count_selected_keys (keyblock)) { case 0: if (cpr_get_answer_is_yes ("keyedit.keytocard.use_primary", /* TRANSLATORS: Please take care: This is about moving the key and not about removing it. */ _("Really move the primary key? (y/N) "))) node = keyblock; break; case 1: for (node = keyblock; node; node = node->next) { if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY && node->flag & NODFLG_SELKEY) break; } break; default: tty_printf (_("You must select exactly one key.\n")); break; } if (node) { PKT_public_key *xxpk = node->pkt->pkt.public_key; if (card_store_subkey (node, xxpk ? xxpk->pubkey_usage : 0)) { redisplay = 1; sec_shadowing = 1; } } } break; case cmdBKUPTOCARD: { /* Ask for a filename, check whether this is really a backup key as generated by the card generation, parse that key and store it on card. */ KBNODE node; char *fname; PACKET *pkt; IOBUF a; struct parse_packet_ctx_s parsectx; if (!*arg_string) { tty_printf (_("Command expects a filename argument\n")); break; } if (*arg_string == DIRSEP_C) fname = xstrdup (arg_string); else if (*arg_string == '~') fname = make_filename (arg_string, NULL); else fname = make_filename (gnupg_homedir (), arg_string, NULL); /* Open that file. */ a = iobuf_open (fname); if (a && is_secured_file (iobuf_get_fd (a))) { iobuf_close (a); a = NULL; gpg_err_set_errno (EPERM); } if (!a) { tty_printf (_("Can't open '%s': %s\n"), fname, strerror (errno)); xfree (fname); break; } /* Parse and check that file. */ pkt = xmalloc (sizeof *pkt); init_packet (pkt); init_parse_packet (&parsectx, a); err = parse_packet (&parsectx, pkt); deinit_parse_packet (&parsectx); iobuf_close (a); iobuf_ioctl (NULL, IOBUF_IOCTL_INVALIDATE_CACHE, 0, (char *) fname); if (!err && pkt->pkttype != PKT_SECRET_KEY && pkt->pkttype != PKT_SECRET_SUBKEY) err = GPG_ERR_NO_SECKEY; if (err) { tty_printf (_("Error reading backup key from '%s': %s\n"), fname, gpg_strerror (err)); xfree (fname); free_packet (pkt, NULL); xfree (pkt); break; } xfree (fname); node = new_kbnode (pkt); /* Transfer it to gpg-agent which handles secret keys. */ err = transfer_secret_keys (ctrl, NULL, node, 1, 1); /* Treat the pkt as a public key. */ pkt->pkttype = PKT_PUBLIC_KEY; /* Ask gpg-agent to store the secret key to card. */ if (card_store_subkey (node, 0)) { redisplay = 1; sec_shadowing = 1; } release_kbnode (node); } break; #endif /* ENABLE_CARD_SUPPORT */ case cmdDELKEY: { int n1; if (!(n1 = count_selected_keys (keyblock))) { tty_printf (_("You must select at least one key.\n")); if (!opt.expert) tty_printf (_("(Use the '%s' command.)\n"), "key"); } else if (!cpr_get_answer_is_yes ("keyedit.remove.subkey.okay", n1 > 1 ? _("Do you really want to delete the " "selected keys? (y/N) ") : _("Do you really want to delete this key? (y/N) "))) ; else { menu_delkey (keyblock); redisplay = 1; modified = 1; } } break; case cmdADDREVOKER: { int sensitive = 0; if (ascii_strcasecmp (arg_string, "sensitive") == 0) sensitive = 1; if (menu_addrevoker (ctrl, keyblock, sensitive)) { redisplay = 1; modified = 1; merge_keys_and_selfsig (ctrl, keyblock); } } break; case cmdREVUID: { int n1; if (!(n1 = count_selected_uids (keyblock))) { tty_printf (_("You must select at least one user ID.\n")); if (!opt.expert) tty_printf (_("(Use the '%s' command.)\n"), "uid"); } else if (cpr_get_answer_is_yes ("keyedit.revoke.uid.okay", n1 > 1 ? _("Really revoke all selected user IDs? (y/N) ") : _("Really revoke this user ID? (y/N) "))) { if (menu_revuid (ctrl, keyblock)) { modified = 1; redisplay = 1; } } } break; case cmdREVKEY: { int n1; if (!(n1 = count_selected_keys (keyblock))) { if (cpr_get_answer_is_yes ("keyedit.revoke.subkey.okay", _("Do you really want to revoke" " the entire key? (y/N) "))) { if (menu_revkey (ctrl, keyblock)) modified = 1; redisplay = 1; } } else if (cpr_get_answer_is_yes ("keyedit.revoke.subkey.okay", n1 > 1 ? _("Do you really want to revoke" " the selected subkeys? (y/N) ") : _("Do you really want to revoke" " this subkey? (y/N) "))) { if (menu_revsubkey (ctrl, keyblock)) modified = 1; redisplay = 1; } if (modified) merge_keys_and_selfsig (ctrl, keyblock); } break; case cmdEXPIRE: if (gpg_err_code (menu_expire (ctrl, keyblock, 0, 0)) == GPG_ERR_TRUE) { merge_keys_and_selfsig (ctrl, keyblock); run_subkey_warnings = 1; modified = 1; redisplay = 1; } break; case cmdCHANGEUSAGE: if (menu_changeusage (ctrl, keyblock)) { merge_keys_and_selfsig (ctrl, keyblock); modified = 1; redisplay = 1; } break; case cmdBACKSIGN: if (menu_backsign (ctrl, keyblock)) { modified = 1; redisplay = 1; } break; case cmdPRIMARY: if (menu_set_primary_uid (ctrl, keyblock)) { merge_keys_and_selfsig (ctrl, keyblock); modified = 1; redisplay = 1; } break; case cmdPASSWD: change_passphrase (ctrl, keyblock); break; #ifndef NO_TRUST_MODELS case cmdTRUST: if (opt.trust_model == TM_EXTERNAL) { tty_printf (_("Owner trust may not be set while " "using a user provided trust database\n")); break; } show_key_with_all_names (ctrl, NULL, keyblock, 0, 0, 0, 1, 0, 0); tty_printf ("\n"); if (edit_ownertrust (ctrl, find_kbnode (keyblock, PKT_PUBLIC_KEY)->pkt->pkt. public_key, 1)) { redisplay = 1; /* No real need to set update_trust here as edit_ownertrust() calls revalidation_mark() anyway. */ update_trust = 1; } break; #endif /*!NO_TRUST_MODELS*/ case cmdPREF: { int count = count_selected_uids (keyblock); log_assert (keyblock->pkt->pkttype == PKT_PUBLIC_KEY); show_names (ctrl, NULL, keyblock, keyblock->pkt->pkt.public_key, count ? NODFLG_SELUID : 0, 1); } break; case cmdSHOWPREF: { int count = count_selected_uids (keyblock); log_assert (keyblock->pkt->pkttype == PKT_PUBLIC_KEY); show_names (ctrl, NULL, keyblock, keyblock->pkt->pkt.public_key, count ? NODFLG_SELUID : 0, 2); } break; case cmdSETPREF: { PKT_user_id *tempuid; keygen_set_std_prefs (!*arg_string ? "default" : arg_string, 0); tempuid = keygen_get_std_prefs (); tty_printf (_("Set preference list to:\n")); show_prefs (tempuid, NULL, 1); free_user_id (tempuid); if (cpr_get_answer_is_yes ("keyedit.setpref.okay", count_selected_uids (keyblock) ? _("Really update the preferences" " for the selected user IDs? (y/N) ") : _("Really update the preferences? (y/N) "))) { if (menu_set_preferences (ctrl, keyblock)) { merge_keys_and_selfsig (ctrl, keyblock); modified = 1; redisplay = 1; } } } break; case cmdPREFKS: if (menu_set_keyserver_url (ctrl, *arg_string ? arg_string : NULL, keyblock)) { merge_keys_and_selfsig (ctrl, keyblock); modified = 1; redisplay = 1; } break; case cmdNOTATION: if (menu_set_notation (ctrl, *arg_string ? arg_string : NULL, keyblock)) { merge_keys_and_selfsig (ctrl, keyblock); modified = 1; redisplay = 1; } break; case cmdNOP: break; case cmdREVSIG: if (menu_revsig (ctrl, keyblock)) { redisplay = 1; modified = 1; } break; #ifndef NO_TRUST_MODELS case cmdENABLEKEY: case cmdDISABLEKEY: if (enable_disable_key (ctrl, keyblock, cmd == cmdDISABLEKEY)) { redisplay = 1; modified = 1; } break; #endif /*!NO_TRUST_MODELS*/ case cmdSHOWPHOTO: menu_showphoto (ctrl, keyblock); break; case cmdCLEAN: if (menu_clean (ctrl, keyblock, 0)) redisplay = modified = 1; break; case cmdMINIMIZE: if (menu_clean (ctrl, keyblock, 1)) redisplay = modified = 1; break; case cmdQUIT: if (have_commands) goto leave; if (!modified && !sec_shadowing) goto leave; if (!cpr_get_answer_is_yes ("keyedit.save.okay", _("Save changes? (y/N) "))) { if (cpr_enabled () || cpr_get_answer_is_yes ("keyedit.cancel.okay", _("Quit without saving? (y/N) "))) goto leave; break; } /* fall through */ case cmdSAVE: if (modified) { err = keydb_update_keyblock (ctrl, kdbhd, keyblock); if (err) { log_error (_("update failed: %s\n"), gpg_strerror (err)); break; } } if (sec_shadowing) { err = agent_scd_learn (NULL, 1); if (err) { log_error (_("update failed: %s\n"), gpg_strerror (err)); break; } } if (!modified && !sec_shadowing) tty_printf (_("Key not changed so no update needed.\n")); if (update_trust) { revalidation_mark (ctrl); update_trust = 0; } goto leave; case cmdINVCMD: default: tty_printf ("\n"); tty_printf (_("Invalid command (try \"help\")\n")); break; } } /* End of the main command loop. */ leave: release_kbnode (keyblock); keydb_release (kdbhd); xfree (answer); } /* Change the passphrase of the secret key identified by USERNAME. */ void keyedit_passwd (ctrl_t ctrl, const char *username) { gpg_error_t err; PKT_public_key *pk; kbnode_t keyblock = NULL; pk = xtrycalloc (1, sizeof *pk); if (!pk) { err = gpg_error_from_syserror (); goto leave; } err = getkey_byname (ctrl, NULL, pk, username, 1, &keyblock); if (err) goto leave; err = change_passphrase (ctrl, keyblock); leave: release_kbnode (keyblock); free_public_key (pk); if (err) { log_info ("error changing the passphrase for '%s': %s\n", username, gpg_strerror (err)); write_status_error ("keyedit.passwd", err); } else write_status_text (STATUS_SUCCESS, "keyedit.passwd"); } /* Helper for quick commands to find the keyblock for USERNAME. * Returns on success the key database handle at R_KDBHD and the * keyblock at R_KEYBLOCK. */ static gpg_error_t quick_find_keyblock (ctrl_t ctrl, const char *username, KEYDB_HANDLE *r_kdbhd, kbnode_t *r_keyblock) { gpg_error_t err; KEYDB_HANDLE kdbhd = NULL; kbnode_t keyblock = NULL; KEYDB_SEARCH_DESC desc; kbnode_t node; *r_kdbhd = NULL; *r_keyblock = NULL; /* Search the key; we don't want the whole getkey stuff here. */ kdbhd = keydb_new (); if (!kdbhd) { /* Note that keydb_new has already used log_error. */ err = gpg_error_from_syserror (); goto leave; } err = classify_user_id (username, &desc, 1); if (!err) err = keydb_search (kdbhd, &desc, 1, NULL); if (!err) { err = keydb_get_keyblock (kdbhd, &keyblock); if (err) { log_error (_("error reading keyblock: %s\n"), gpg_strerror (err)); goto leave; } /* Now with the keyblock retrieved, search again to detect an ambiguous specification. We need to save the found state so that we can do an update later. */ keydb_push_found_state (kdbhd); err = keydb_search (kdbhd, &desc, 1, NULL); if (!err) err = gpg_error (GPG_ERR_AMBIGUOUS_NAME); else if (gpg_err_code (err) == GPG_ERR_NOT_FOUND) err = 0; keydb_pop_found_state (kdbhd); if (!err) { /* We require the secret primary key to set the primary UID. */ node = find_kbnode (keyblock, PKT_PUBLIC_KEY); log_assert (node); err = agent_probe_secret_key (ctrl, node->pkt->pkt.public_key); } } else if (gpg_err_code (err) == GPG_ERR_NOT_FOUND) err = gpg_error (GPG_ERR_NO_PUBKEY); if (err) { log_error (_("key \"%s\" not found: %s\n"), username, gpg_strerror (err)); goto leave; } fix_keyblock (ctrl, &keyblock); merge_keys_and_selfsig (ctrl, keyblock); *r_keyblock = keyblock; keyblock = NULL; *r_kdbhd = kdbhd; kdbhd = NULL; leave: release_kbnode (keyblock); keydb_release (kdbhd); return err; } /* Unattended adding of a new keyid. USERNAME specifies the key. NEWUID is the new user id to add to the key. */ void keyedit_quick_adduid (ctrl_t ctrl, const char *username, const char *newuid) { gpg_error_t err; KEYDB_HANDLE kdbhd = NULL; kbnode_t keyblock = NULL; char *uidstring = NULL; uidstring = xstrdup (newuid); trim_spaces (uidstring); if (!*uidstring) { log_error ("%s\n", gpg_strerror (GPG_ERR_INV_USER_ID)); goto leave; } #ifdef HAVE_W32_SYSTEM /* See keyedit_menu for why we need this. */ check_trustdb_stale (ctrl); #endif /* Search the key; we don't want the whole getkey stuff here. */ err = quick_find_keyblock (ctrl, username, &kdbhd, &keyblock); if (err) goto leave; if (menu_adduid (ctrl, keyblock, 0, NULL, uidstring)) { err = keydb_update_keyblock (ctrl, kdbhd, keyblock); if (err) { log_error (_("update failed: %s\n"), gpg_strerror (err)); goto leave; } if (update_trust) revalidation_mark (ctrl); } leave: xfree (uidstring); release_kbnode (keyblock); keydb_release (kdbhd); } /* Unattended revocation of a keyid. USERNAME specifies the key. UIDTOREV is the user id revoke from the key. */ void keyedit_quick_revuid (ctrl_t ctrl, const char *username, const char *uidtorev) { gpg_error_t err; KEYDB_HANDLE kdbhd = NULL; kbnode_t keyblock = NULL; kbnode_t node; int modified = 0; size_t revlen; size_t valid_uids; #ifdef HAVE_W32_SYSTEM /* See keyedit_menu for why we need this. */ check_trustdb_stale (ctrl); #endif /* Search the key; we don't want the whole getkey stuff here. */ err = quick_find_keyblock (ctrl, username, &kdbhd, &keyblock); if (err) goto leave; /* Too make sure that we do not revoke the last valid UID, we first count how many valid UIDs there are. */ valid_uids = 0; for (node = keyblock; node; node = node->next) valid_uids += (node->pkt->pkttype == PKT_USER_ID && !node->pkt->pkt.user_id->flags.revoked && !node->pkt->pkt.user_id->flags.expired); /* Find the right UID. */ revlen = strlen (uidtorev); for (node = keyblock; node; node = node->next) { if (node->pkt->pkttype == PKT_USER_ID && revlen == node->pkt->pkt.user_id->len && !memcmp (node->pkt->pkt.user_id->name, uidtorev, revlen)) { struct revocation_reason_info *reason; /* Make sure that we do not revoke the last valid UID. */ if (valid_uids == 1 && ! node->pkt->pkt.user_id->flags.revoked && ! node->pkt->pkt.user_id->flags.expired) { log_error (_("cannot revoke the last valid user ID.\n")); err = gpg_error (GPG_ERR_INV_USER_ID); goto leave; } reason = get_default_uid_revocation_reason (); err = core_revuid (ctrl, keyblock, node, reason, &modified); release_revocation_reason_info (reason); if (err) goto leave; err = keydb_update_keyblock (ctrl, kdbhd, keyblock); if (err) { log_error (_("update failed: %s\n"), gpg_strerror (err)); goto leave; } revalidation_mark (ctrl); goto leave; } } err = gpg_error (GPG_ERR_NO_USER_ID); leave: if (err) { log_error (_("revoking the user ID failed: %s\n"), gpg_strerror (err)); write_status_error ("keyedit.revoke.uid", err); } release_kbnode (keyblock); keydb_release (kdbhd); } /* Unattended setting of the primary uid. USERNAME specifies the key. PRIMARYUID is the user id which shall be primary. */ void keyedit_quick_set_primary (ctrl_t ctrl, const char *username, const char *primaryuid) { gpg_error_t err; KEYDB_HANDLE kdbhd = NULL; kbnode_t keyblock = NULL; kbnode_t node; size_t primaryuidlen; int any; #ifdef HAVE_W32_SYSTEM /* See keyedit_menu for why we need this. */ check_trustdb_stale (ctrl); #endif err = quick_find_keyblock (ctrl, username, &kdbhd, &keyblock); if (err) goto leave; /* Find and mark the UID - we mark only the first valid one. */ primaryuidlen = strlen (primaryuid); any = 0; for (node = keyblock; node; node = node->next) { if (node->pkt->pkttype == PKT_USER_ID && !any && !node->pkt->pkt.user_id->flags.revoked && !node->pkt->pkt.user_id->flags.expired && primaryuidlen == node->pkt->pkt.user_id->len && !memcmp (node->pkt->pkt.user_id->name, primaryuid, primaryuidlen)) { node->flag |= NODFLG_SELUID; any = 1; } else node->flag &= ~NODFLG_SELUID; } if (!any) err = gpg_error (GPG_ERR_NO_USER_ID); else if (menu_set_primary_uid (ctrl, keyblock)) { merge_keys_and_selfsig (ctrl, keyblock); err = keydb_update_keyblock (ctrl, kdbhd, keyblock); if (err) { log_error (_("update failed: %s\n"), gpg_strerror (err)); goto leave; } revalidation_mark (ctrl); } else err = gpg_error (GPG_ERR_GENERAL); if (err) log_error (_("setting the primary user ID failed: %s\n"), gpg_strerror (err)); leave: release_kbnode (keyblock); keydb_release (kdbhd); } /* Find a keyblock by fingerprint because only this uniquely * identifies a key and may thus be used to select a key for * unattended subkey creation os key signing. */ static gpg_error_t find_by_primary_fpr (ctrl_t ctrl, const char *fpr, kbnode_t *r_keyblock, KEYDB_HANDLE *r_kdbhd) { gpg_error_t err; kbnode_t keyblock = NULL; KEYDB_HANDLE kdbhd = NULL; KEYDB_SEARCH_DESC desc; byte fprbin[MAX_FINGERPRINT_LEN]; size_t fprlen; *r_keyblock = NULL; *r_kdbhd = NULL; if (classify_user_id (fpr, &desc, 1) || !(desc.mode == KEYDB_SEARCH_MODE_FPR || desc.mode == KEYDB_SEARCH_MODE_FPR16 || desc.mode == KEYDB_SEARCH_MODE_FPR20)) { log_error (_("\"%s\" is not a fingerprint\n"), fpr); err = gpg_error (GPG_ERR_INV_NAME); goto leave; } err = get_pubkey_byname (ctrl, NULL, NULL, fpr, &keyblock, &kdbhd, 1, 1); if (err) { log_error (_("key \"%s\" not found: %s\n"), fpr, gpg_strerror (err)); goto leave; } /* Check that the primary fingerprint has been given. */ fingerprint_from_pk (keyblock->pkt->pkt.public_key, fprbin, &fprlen); if (fprlen == 16 && desc.mode == KEYDB_SEARCH_MODE_FPR16 && !memcmp (fprbin, desc.u.fpr, 16)) ; else if (fprlen == 16 && desc.mode == KEYDB_SEARCH_MODE_FPR && !memcmp (fprbin, desc.u.fpr, 16) && !desc.u.fpr[16] && !desc.u.fpr[17] && !desc.u.fpr[18] && !desc.u.fpr[19]) ; else if (fprlen == 20 && (desc.mode == KEYDB_SEARCH_MODE_FPR20 || desc.mode == KEYDB_SEARCH_MODE_FPR) && !memcmp (fprbin, desc.u.fpr, 20)) ; else { log_error (_("\"%s\" is not the primary fingerprint\n"), fpr); err = gpg_error (GPG_ERR_INV_NAME); goto leave; } *r_keyblock = keyblock; keyblock = NULL; *r_kdbhd = kdbhd; kdbhd = NULL; err = 0; leave: release_kbnode (keyblock); keydb_release (kdbhd); return err; } /* Unattended key signing function. If the key specifified by FPR is available and FPR is the primary fingerprint all user ids of the key are signed using the default signing key. If UIDS is an empty list all usable UIDs are signed, if it is not empty, only those user ids matching one of the entries of the list are signed. With LOCAL being true the signatures are marked as non-exportable. */ void keyedit_quick_sign (ctrl_t ctrl, const char *fpr, strlist_t uids, strlist_t locusr, int local) { gpg_error_t err; kbnode_t keyblock = NULL; KEYDB_HANDLE kdbhd = NULL; int modified = 0; PKT_public_key *pk; kbnode_t node; strlist_t sl; int any; #ifdef HAVE_W32_SYSTEM /* See keyedit_menu for why we need this. */ check_trustdb_stale (ctrl); #endif /* We require a fingerprint because only this uniquely identifies a key and may thus be used to select a key for unattended key signing. */ if (find_by_primary_fpr (ctrl, fpr, &keyblock, &kdbhd)) goto leave; if (fix_keyblock (ctrl, &keyblock)) modified++; /* Give some info in verbose. */ if (opt.verbose) { show_key_with_all_names (ctrl, es_stdout, keyblock, 0, 1/*with_revoker*/, 1/*with_fingerprint*/, 0, 0, 1); es_fflush (es_stdout); } pk = keyblock->pkt->pkt.public_key; if (pk->flags.revoked) { if (!opt.verbose) show_key_with_all_names (ctrl, es_stdout, keyblock, 0, 0, 0, 0, 0, 1); log_error ("%s%s", _("Key is revoked."), _(" Unable to sign.\n")); goto leave; } /* Set the flags according to the UIDS list. Fixme: We may want to use classify_user_id along with dedicated compare functions so that we match the same way as in the key lookup. */ any = 0; menu_select_uid (keyblock, 0); /* Better clear the flags first. */ for (sl=uids; sl; sl = sl->next) { const char *name = sl->d; int count = 0; sl->flags &= ~(1|2); /* Clear flags used for error reporting. */ for (node = keyblock; node; node = node->next) { if (node->pkt->pkttype == PKT_USER_ID) { PKT_user_id *uid = node->pkt->pkt.user_id; if (uid->attrib_data) ; else if (*name == '=' && strlen (name+1) == uid->len && !memcmp (uid->name, name + 1, uid->len)) { /* Exact match - we don't do a check for ambiguity * in this case. */ node->flag |= NODFLG_SELUID; if (any != -1) { sl->flags |= 1; /* Report as found. */ any = 1; } } else if (ascii_memistr (uid->name, uid->len, *name == '*'? name+1:name)) { node->flag |= NODFLG_SELUID; if (any != -1) { sl->flags |= 1; /* Report as found. */ any = 1; } count++; } } } if (count > 1) { any = -1; /* Force failure at end. */ sl->flags |= 2; /* Report as ambiguous. */ } } /* Check whether all given user ids were found. */ for (sl=uids; sl; sl = sl->next) if (!(sl->flags & 1)) any = -1; /* That user id was not found. */ /* Print an error if there was a problem with the user ids. */ if (uids && any < 1) { if (!opt.verbose) show_key_with_all_names (ctrl, es_stdout, keyblock, 0, 0, 0, 0, 0, 1); es_fflush (es_stdout); for (sl=uids; sl; sl = sl->next) { if ((sl->flags & 2)) log_info (_("Invalid user ID '%s': %s\n"), sl->d, gpg_strerror (GPG_ERR_AMBIGUOUS_NAME)); else if (!(sl->flags & 1)) log_info (_("Invalid user ID '%s': %s\n"), sl->d, gpg_strerror (GPG_ERR_NOT_FOUND)); } log_error ("%s %s", _("No matching user IDs."), _("Nothing to sign.\n")); goto leave; } /* Sign. */ sign_uids (ctrl, es_stdout, keyblock, locusr, &modified, local, 0, 0, 0, 1); es_fflush (es_stdout); if (modified) { err = keydb_update_keyblock (ctrl, kdbhd, keyblock); if (err) { log_error (_("update failed: %s\n"), gpg_strerror (err)); goto leave; } } else log_info (_("Key not changed so no update needed.\n")); if (update_trust) revalidation_mark (ctrl); leave: release_kbnode (keyblock); keydb_release (kdbhd); } /* Unattended subkey creation function. * */ void keyedit_quick_addkey (ctrl_t ctrl, const char *fpr, const char *algostr, const char *usagestr, const char *expirestr) { gpg_error_t err; kbnode_t keyblock; KEYDB_HANDLE kdbhd; int modified = 0; PKT_public_key *pk; #ifdef HAVE_W32_SYSTEM /* See keyedit_menu for why we need this. */ check_trustdb_stale (ctrl); #endif /* We require a fingerprint because only this uniquely identifies a * key and may thus be used to select a key for unattended subkey * creation. */ if (find_by_primary_fpr (ctrl, fpr, &keyblock, &kdbhd)) goto leave; if (fix_keyblock (ctrl, &keyblock)) modified++; pk = keyblock->pkt->pkt.public_key; if (pk->flags.revoked) { if (!opt.verbose) show_key_with_all_names (ctrl, es_stdout, keyblock, 0, 0, 0, 0, 0, 1); log_error ("%s%s", _("Key is revoked."), "\n"); goto leave; } /* Create the subkey. Note that the called function already prints * an error message. */ if (!generate_subkeypair (ctrl, keyblock, algostr, usagestr, expirestr)) modified = 1; es_fflush (es_stdout); /* Store. */ if (modified) { err = keydb_update_keyblock (ctrl, kdbhd, keyblock); if (err) { log_error (_("update failed: %s\n"), gpg_strerror (err)); goto leave; } } else log_info (_("Key not changed so no update needed.\n")); leave: release_kbnode (keyblock); keydb_release (kdbhd); } /* Unattended expiration setting function for the main key. If * SUBKEYFPRS is not NULL and SUBKEYSFPRS[0] is neither NULL, it is * expected to be an array of fingerprints for subkeys to change. It * may also be an array which just one item "*" to indicate that all * keys shall be set to that expiration date. */ void keyedit_quick_set_expire (ctrl_t ctrl, const char *fpr, const char *expirestr, char **subkeyfprs) { gpg_error_t err; kbnode_t keyblock, node; KEYDB_HANDLE kdbhd; int modified = 0; PKT_public_key *pk; u32 expire; int primary_only = 0; int idx; #ifdef HAVE_W32_SYSTEM /* See keyedit_menu for why we need this. */ check_trustdb_stale (ctrl); #endif /* We require a fingerprint because only this uniquely identifies a * key and may thus be used to select a key for unattended * expiration setting. */ err = find_by_primary_fpr (ctrl, fpr, &keyblock, &kdbhd); if (err) goto leave; if (fix_keyblock (ctrl, &keyblock)) modified++; pk = keyblock->pkt->pkt.public_key; if (pk->flags.revoked) { if (!opt.verbose) show_key_with_all_names (ctrl, es_stdout, keyblock, 0, 0, 0, 0, 0, 1); log_error ("%s%s", _("Key is revoked."), "\n"); err = gpg_error (GPG_ERR_CERT_REVOKED); goto leave; } expire = parse_expire_string (expirestr); if (expire == (u32)-1 ) { log_error (_("'%s' is not a valid expiration time\n"), expirestr); err = gpg_error (GPG_ERR_INV_VALUE); goto leave; } if (expire) expire += make_timestamp (); /* Check whether a subkey's expiration time shall be changed or the * expiration time of all keys. */ if (!subkeyfprs || !subkeyfprs[0]) primary_only = 1; else if ( !strcmp (subkeyfprs[0], "*") && !subkeyfprs[1]) { /* Change all subkeys keys which have not been revoked and are * not yet expired. */ merge_keys_and_selfsig (ctrl, keyblock); for (node = keyblock; node; node = node->next) { if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY && (pk = node->pkt->pkt.public_key) && !pk->flags.revoked && !pk->has_expired) node->flag |= NODFLG_SELKEY; } } else { /* Change specified subkeys. */ KEYDB_SEARCH_DESC desc; byte fprbin[MAX_FINGERPRINT_LEN]; size_t fprlen; err = 0; merge_keys_and_selfsig (ctrl, keyblock); for (idx=0; subkeyfprs[idx]; idx++) { int any = 0; /* Parse the fingerprint. */ if (classify_user_id (subkeyfprs[idx], &desc, 1) || !(desc.mode == KEYDB_SEARCH_MODE_FPR || desc.mode == KEYDB_SEARCH_MODE_FPR20)) { log_error (_("\"%s\" is not a proper fingerprint\n"), subkeyfprs[idx] ); if (!err) err = gpg_error (GPG_ERR_INV_NAME); continue; } /* Set the flag for the matching non revoked subkey. */ for (node = keyblock; node; node = node->next) { if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY && (pk = node->pkt->pkt.public_key) && !pk->flags.revoked ) { fingerprint_from_pk (pk, fprbin, &fprlen); if (fprlen == 20 && !memcmp (fprbin, desc.u.fpr, 20)) { node->flag |= NODFLG_SELKEY; any = 1; } } } if (!any) { log_error (_("subkey \"%s\" not found\n"), subkeyfprs[idx]); if (!err) err = gpg_error (GPG_ERR_NOT_FOUND); } } if (err) goto leave; } /* Set the new expiration date. */ err = menu_expire (ctrl, keyblock, primary_only? 1 : 2, expire); if (gpg_err_code (err) == GPG_ERR_TRUE) modified = 1; else if (err) goto leave; es_fflush (es_stdout); /* Store. */ if (modified) { err = keydb_update_keyblock (ctrl, kdbhd, keyblock); if (err) { log_error (_("update failed: %s\n"), gpg_strerror (err)); goto leave; } if (update_trust) revalidation_mark (ctrl); } else log_info (_("Key not changed so no update needed.\n")); leave: release_kbnode (keyblock); keydb_release (kdbhd); if (err) write_status_error ("set_expire", err); } static void tty_print_notations (int indent, PKT_signature * sig) { int first = 1; struct notation *notation, *nd; if (indent < 0) { first = 0; indent = -indent; } notation = sig_to_notation (sig); for (nd = notation; nd; nd = nd->next) { if (!first) tty_printf ("%*s", indent, ""); else first = 0; tty_print_utf8_string (nd->name, strlen (nd->name)); tty_printf ("="); tty_print_utf8_string (nd->value, strlen (nd->value)); tty_printf ("\n"); } free_notation (notation); } /* * Show preferences of a public keyblock. */ static void show_prefs (PKT_user_id * uid, PKT_signature * selfsig, int verbose) { const prefitem_t fake = { 0, 0 }; const prefitem_t *prefs; int i; if (!uid) return; if (uid->prefs) prefs = uid->prefs; else if (verbose) prefs = &fake; else return; if (verbose) { int any, des_seen = 0, sha1_seen = 0, uncomp_seen = 0; tty_printf (" "); tty_printf (_("Cipher: ")); for (i = any = 0; prefs[i].type; i++) { if (prefs[i].type == PREFTYPE_SYM) { if (any) tty_printf (", "); any = 1; /* We don't want to display strings for experimental algos */ if (!openpgp_cipher_test_algo (prefs[i].value) && prefs[i].value < 100) tty_printf ("%s", openpgp_cipher_algo_name (prefs[i].value)); else tty_printf ("[%d]", prefs[i].value); if (prefs[i].value == CIPHER_ALGO_3DES) des_seen = 1; } } if (!des_seen) { if (any) tty_printf (", "); tty_printf ("%s", openpgp_cipher_algo_name (CIPHER_ALGO_3DES)); } tty_printf ("\n "); + tty_printf (_("AEAD: ")); + for (i = any = 0; prefs[i].type; i++) + { + if (prefs[i].type == PREFTYPE_AEAD) + { + if (any) + tty_printf (", "); + any = 1; + /* We don't want to display strings for experimental algos */ + if (!openpgp_aead_test_algo (prefs[i].value) + && prefs[i].value < 100) + tty_printf ("%s", openpgp_aead_algo_name (prefs[i].value)); + else + tty_printf ("[%d]", prefs[i].value); + } + } + tty_printf ("\n "); tty_printf (_("Digest: ")); for (i = any = 0; prefs[i].type; i++) { if (prefs[i].type == PREFTYPE_HASH) { if (any) tty_printf (", "); any = 1; /* We don't want to display strings for experimental algos */ if (!gcry_md_test_algo (prefs[i].value) && prefs[i].value < 100) tty_printf ("%s", gcry_md_algo_name (prefs[i].value)); else tty_printf ("[%d]", prefs[i].value); if (prefs[i].value == DIGEST_ALGO_SHA1) sha1_seen = 1; } } if (!sha1_seen) { if (any) tty_printf (", "); tty_printf ("%s", gcry_md_algo_name (DIGEST_ALGO_SHA1)); } tty_printf ("\n "); tty_printf (_("Compression: ")); for (i = any = 0; prefs[i].type; i++) { if (prefs[i].type == PREFTYPE_ZIP) { const char *s = compress_algo_to_string (prefs[i].value); if (any) tty_printf (", "); any = 1; /* We don't want to display strings for experimental algos */ if (s && prefs[i].value < 100) tty_printf ("%s", s); else tty_printf ("[%d]", prefs[i].value); if (prefs[i].value == COMPRESS_ALGO_NONE) uncomp_seen = 1; } } if (!uncomp_seen) { if (any) tty_printf (", "); else { tty_printf ("%s", compress_algo_to_string (COMPRESS_ALGO_ZIP)); tty_printf (", "); } tty_printf ("%s", compress_algo_to_string (COMPRESS_ALGO_NONE)); } if (uid->flags.mdc || uid->flags.aead || !uid->flags.ks_modify) { tty_printf ("\n "); tty_printf (_("Features: ")); any = 0; if (uid->flags.mdc) { tty_printf ("MDC"); any = 1; } if (!uid->flags.aead) { if (any) tty_printf (", "); tty_printf ("AEAD"); } if (!uid->flags.ks_modify) { if (any) tty_printf (", "); tty_printf (_("Keyserver no-modify")); } } tty_printf ("\n"); if (selfsig) { const byte *pref_ks; size_t pref_ks_len; pref_ks = parse_sig_subpkt (selfsig->hashed, SIGSUBPKT_PREF_KS, &pref_ks_len); if (pref_ks && pref_ks_len) { tty_printf (" "); tty_printf (_("Preferred keyserver: ")); tty_print_utf8_string (pref_ks, pref_ks_len); tty_printf ("\n"); } if (selfsig->flags.notation) { tty_printf (" "); tty_printf (_("Notations: ")); tty_print_notations (5 + strlen (_("Notations: ")), selfsig); } } } else { tty_printf (" "); for (i = 0; prefs[i].type; i++) { tty_printf (" %c%d", prefs[i].type == PREFTYPE_SYM ? 'S' : + prefs[i].type == PREFTYPE_AEAD ? 'A' : prefs[i].type == PREFTYPE_HASH ? 'H' : prefs[i].type == PREFTYPE_ZIP ? 'Z' : '?', prefs[i].value); } if (uid->flags.mdc) tty_printf (" [mdc]"); if (uid->flags.aead) tty_printf (" [aead]"); if (!uid->flags.ks_modify) tty_printf (" [no-ks-modify]"); tty_printf ("\n"); } } /* This is the version of show_key_with_all_names used when opt.with_colons is used. It prints all available data in a easy to parse format and does not translate utf8 */ static void show_key_with_all_names_colon (ctrl_t ctrl, estream_t fp, kbnode_t keyblock) { KBNODE node; int i, j, ulti_hack = 0; byte pk_version = 0; PKT_public_key *primary = NULL; int have_seckey; if (!fp) fp = es_stdout; /* the keys */ for (node = keyblock; node; node = node->next) { if (node->pkt->pkttype == PKT_PUBLIC_KEY || (node->pkt->pkttype == PKT_PUBLIC_SUBKEY)) { PKT_public_key *pk = node->pkt->pkt.public_key; u32 keyid[2]; if (node->pkt->pkttype == PKT_PUBLIC_KEY) { pk_version = pk->version; primary = pk; } keyid_from_pk (pk, keyid); have_seckey = !agent_probe_secret_key (ctrl, pk); if (node->pkt->pkttype == PKT_PUBLIC_KEY) es_fputs (have_seckey? "sec:" : "pub:", fp); else es_fputs (have_seckey? "ssb:" : "sub:", fp); if (!pk->flags.valid) es_putc ('i', fp); else if (pk->flags.revoked) es_putc ('r', fp); else if (pk->has_expired) es_putc ('e', fp); else if (!(opt.fast_list_mode || opt.no_expensive_trust_checks)) { int trust = get_validity_info (ctrl, keyblock, pk, NULL); if (trust == 'u') ulti_hack = 1; es_putc (trust, fp); } es_fprintf (fp, ":%u:%d:%08lX%08lX:%lu:%lu::", nbits_from_pk (pk), pk->pubkey_algo, (ulong) keyid[0], (ulong) keyid[1], (ulong) pk->timestamp, (ulong) pk->expiredate); if (node->pkt->pkttype == PKT_PUBLIC_KEY && !(opt.fast_list_mode || opt.no_expensive_trust_checks)) es_putc (get_ownertrust_info (ctrl, pk, 0), fp); es_putc (':', fp); es_putc (':', fp); es_putc (':', fp); /* Print capabilities. */ if ((pk->pubkey_usage & PUBKEY_USAGE_ENC)) es_putc ('e', fp); if ((pk->pubkey_usage & PUBKEY_USAGE_SIG)) es_putc ('s', fp); if ((pk->pubkey_usage & PUBKEY_USAGE_CERT)) es_putc ('c', fp); if ((pk->pubkey_usage & PUBKEY_USAGE_AUTH)) es_putc ('a', fp); es_putc ('\n', fp); print_fingerprint (ctrl, fp, pk, 0); print_revokers (fp, pk); } } /* the user ids */ i = 0; for (node = keyblock; node; node = node->next) { if (node->pkt->pkttype == PKT_USER_ID) { PKT_user_id *uid = node->pkt->pkt.user_id; ++i; if (uid->attrib_data) es_fputs ("uat:", fp); else es_fputs ("uid:", fp); if (uid->flags.revoked) es_fputs ("r::::::::", fp); else if (uid->flags.expired) es_fputs ("e::::::::", fp); else if (opt.fast_list_mode || opt.no_expensive_trust_checks) es_fputs ("::::::::", fp); else { int uid_validity; if (primary && !ulti_hack) uid_validity = get_validity_info (ctrl, keyblock, primary, uid); else uid_validity = 'u'; es_fprintf (fp, "%c::::::::", uid_validity); } if (uid->attrib_data) es_fprintf (fp, "%u %lu", uid->numattribs, uid->attrib_len); else es_write_sanitized (fp, uid->name, uid->len, ":", NULL); es_putc (':', fp); /* signature class */ es_putc (':', fp); /* capabilities */ es_putc (':', fp); /* preferences */ if (pk_version > 3 || uid->selfsigversion > 3) { const prefitem_t *prefs = uid->prefs; for (j = 0; prefs && prefs[j].type; j++) { if (j) es_putc (' ', fp); es_fprintf (fp, "%c%d", prefs[j].type == PREFTYPE_SYM ? 'S' : prefs[j].type == PREFTYPE_HASH ? 'H' : prefs[j].type == PREFTYPE_ZIP ? 'Z' : '?', prefs[j].value); } if (uid->flags.mdc) es_fputs (",mdc", fp); if (uid->flags.aead) es_fputs (",aead", fp); if (!uid->flags.ks_modify) es_fputs (",no-ks-modify", fp); } es_putc (':', fp); /* flags */ es_fprintf (fp, "%d,", i); if (uid->flags.primary) es_putc ('p', fp); if (uid->flags.revoked) es_putc ('r', fp); if (uid->flags.expired) es_putc ('e', fp); if ((node->flag & NODFLG_SELUID)) es_putc ('s', fp); if ((node->flag & NODFLG_MARK_A)) es_putc ('m', fp); es_putc (':', fp); if (opt.trust_model == TM_TOFU || opt.trust_model == TM_TOFU_PGP) { #ifdef USE_TOFU enum tofu_policy policy; if (! tofu_get_policy (ctrl, primary, uid, &policy) && policy != TOFU_POLICY_NONE) es_fprintf (fp, "%s", tofu_policy_str (policy)); #endif /*USE_TOFU*/ } es_putc (':', fp); es_putc ('\n', fp); } } } static void show_names (ctrl_t ctrl, estream_t fp, kbnode_t keyblock, PKT_public_key * pk, unsigned int flag, int with_prefs) { KBNODE node; int i = 0; for (node = keyblock; node; node = node->next) { if (node->pkt->pkttype == PKT_USER_ID && !is_deleted_kbnode (node)) { PKT_user_id *uid = node->pkt->pkt.user_id; ++i; if (!flag || (flag && (node->flag & flag))) { if (!(flag & NODFLG_MARK_A) && pk) tty_fprintf (fp, "%s ", uid_trust_string_fixed (ctrl, pk, uid)); if (flag & NODFLG_MARK_A) tty_fprintf (fp, " "); else if (node->flag & NODFLG_SELUID) tty_fprintf (fp, "(%d)* ", i); else if (uid->flags.primary) tty_fprintf (fp, "(%d). ", i); else tty_fprintf (fp, "(%d) ", i); tty_print_utf8_string2 (fp, uid->name, uid->len, 0); tty_fprintf (fp, "\n"); if (with_prefs && pk) { if (pk->version > 3 || uid->selfsigversion > 3) { PKT_signature *selfsig = NULL; KBNODE signode; for (signode = node->next; signode && signode->pkt->pkttype == PKT_SIGNATURE; signode = signode->next) { if (signode->pkt->pkt.signature-> flags.chosen_selfsig) { selfsig = signode->pkt->pkt.signature; break; } } show_prefs (uid, selfsig, with_prefs == 2); } else tty_fprintf (fp, _("There are no preferences on a" " PGP 2.x-style user ID.\n")); } } } } } /* * Display the key a the user ids, if only_marked is true, do only so * for user ids with mark A flag set and do not display the index * number. If FP is not NULL print to the given stream and not to the * tty (ignored in with-colons mode). */ static void show_key_with_all_names (ctrl_t ctrl, estream_t fp, KBNODE keyblock, int only_marked, int with_revoker, int with_fpr, int with_subkeys, int with_prefs, int nowarn) { gpg_error_t err; kbnode_t node; int i; int do_warn = 0; int have_seckey = 0; char *serialno = NULL; PKT_public_key *primary = NULL; char pkstrbuf[PUBKEY_STRING_SIZE]; if (opt.with_colons) { show_key_with_all_names_colon (ctrl, fp, keyblock); return; } /* the keys */ for (node = keyblock; node; node = node->next) { if (node->pkt->pkttype == PKT_PUBLIC_KEY || (with_subkeys && node->pkt->pkttype == PKT_PUBLIC_SUBKEY && !is_deleted_kbnode (node))) { PKT_public_key *pk = node->pkt->pkt.public_key; const char *otrust = "err"; const char *trust = "err"; if (node->pkt->pkttype == PKT_PUBLIC_KEY) { /* do it here, so that debug messages don't clutter the * output */ static int did_warn = 0; trust = get_validity_string (ctrl, pk, NULL); otrust = get_ownertrust_string (ctrl, pk, 0); /* Show a warning once */ if (!did_warn && (get_validity (ctrl, keyblock, pk, NULL, NULL, 0) & TRUST_FLAG_PENDING_CHECK)) { did_warn = 1; do_warn = 1; } primary = pk; } if (pk->flags.revoked) { char *user = get_user_id_string_native (ctrl, pk->revoked.keyid); tty_fprintf (fp, _("The following key was revoked on" " %s by %s key %s\n"), revokestr_from_pk (pk), gcry_pk_algo_name (pk->revoked.algo), user); xfree (user); } if (with_revoker) { if (!pk->revkey && pk->numrevkeys) BUG (); else for (i = 0; i < pk->numrevkeys; i++) { u32 r_keyid[2]; char *user; const char *algo; algo = gcry_pk_algo_name (pk->revkey[i].algid); keyid_from_fingerprint (ctrl, pk->revkey[i].fpr, MAX_FINGERPRINT_LEN, r_keyid); user = get_user_id_string_native (ctrl, r_keyid); tty_fprintf (fp, _("This key may be revoked by %s key %s"), algo ? algo : "?", user); if (pk->revkey[i].class & 0x40) { tty_fprintf (fp, " "); tty_fprintf (fp, _("(sensitive)")); } tty_fprintf (fp, "\n"); xfree (user); } } keyid_from_pk (pk, NULL); xfree (serialno); serialno = NULL; { char *hexgrip; err = hexkeygrip_from_pk (pk, &hexgrip); if (err) { log_error ("error computing a keygrip: %s\n", gpg_strerror (err)); have_seckey = 0; } else have_seckey = !agent_get_keyinfo (ctrl, hexgrip, &serialno, NULL); xfree (hexgrip); } tty_fprintf (fp, "%s%c %s/%s", node->pkt->pkttype == PKT_PUBLIC_KEY && have_seckey? "sec" : node->pkt->pkttype == PKT_PUBLIC_KEY ? "pub" : have_seckey ? "ssb" : "sub", (node->flag & NODFLG_SELKEY) ? '*' : ' ', pubkey_string (pk, pkstrbuf, sizeof pkstrbuf), keystr (pk->keyid)); if (opt.legacy_list_mode) tty_fprintf (fp, " "); else tty_fprintf (fp, "\n "); tty_fprintf (fp, _("created: %s"), datestr_from_pk (pk)); tty_fprintf (fp, " "); if (pk->flags.revoked) tty_fprintf (fp, _("revoked: %s"), revokestr_from_pk (pk)); else if (pk->has_expired) tty_fprintf (fp, _("expired: %s"), expirestr_from_pk (pk)); else tty_fprintf (fp, _("expires: %s"), expirestr_from_pk (pk)); tty_fprintf (fp, " "); tty_fprintf (fp, _("usage: %s"), usagestr_from_pk (pk, 1)); tty_fprintf (fp, "\n"); if (serialno) { /* The agent told us that a secret key is available and that it has been stored on a card. */ tty_fprintf (fp, "%*s%s", opt.legacy_list_mode? 21:5, "", _("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\n", 4, serialno+16, 8, serialno+20); } else tty_fprintf (fp, "%s\n", serialno); } else if (pk->seckey_info && pk->seckey_info->is_protected && pk->seckey_info->s2k.mode == 1002) { /* FIXME: Check whether this code path is still used. */ tty_fprintf (fp, "%*s%s", opt.legacy_list_mode? 21:5, "", _("card-no: ")); if (pk->seckey_info->ivlen == 16 && !memcmp (pk->seckey_info->iv, "\xD2\x76\x00\x01\x24\x01", 6)) { /* This is an OpenPGP card. */ for (i = 8; i < 14; i++) { if (i == 10) tty_fprintf (fp, " "); tty_fprintf (fp, "%02X", pk->seckey_info->iv[i]); } } else { /* Unknown card: Print all. */ for (i = 0; i < pk->seckey_info->ivlen; i++) tty_fprintf (fp, "%02X", pk->seckey_info->iv[i]); } tty_fprintf (fp, "\n"); } if (node->pkt->pkttype == PKT_PUBLIC_KEY || node->pkt->pkttype == PKT_SECRET_KEY) { if (opt.trust_model != TM_ALWAYS) { tty_fprintf (fp, "%*s", opt.legacy_list_mode? ((int) keystrlen () + 13):5, ""); /* Ownertrust is only meaningful for the PGP or classic trust models, or PGP combined with TOFU */ if (opt.trust_model == TM_PGP || opt.trust_model == TM_CLASSIC || opt.trust_model == TM_TOFU_PGP) { int width = 14 - strlen (otrust); if (width <= 0) width = 1; tty_fprintf (fp, _("trust: %s"), otrust); tty_fprintf (fp, "%*s", width, ""); } tty_fprintf (fp, _("validity: %s"), trust); tty_fprintf (fp, "\n"); } if (node->pkt->pkttype == PKT_PUBLIC_KEY && (get_ownertrust (ctrl, pk) & TRUST_FLAG_DISABLED)) { tty_fprintf (fp, "*** "); tty_fprintf (fp, _("This key has been disabled")); tty_fprintf (fp, "\n"); } } if ((node->pkt->pkttype == PKT_PUBLIC_KEY || node->pkt->pkttype == PKT_SECRET_KEY) && with_fpr) { print_fingerprint (ctrl, fp, pk, 2); tty_fprintf (fp, "\n"); } } } show_names (ctrl, fp, keyblock, primary, only_marked ? NODFLG_MARK_A : 0, with_prefs); if (do_warn && !nowarn) tty_fprintf (fp, _("Please note that the shown key validity" " is not necessarily correct\n" "unless you restart the program.\n")); xfree (serialno); } /* Display basic key information. This function is suitable to show information on the key without any dependencies on the trustdb or any other internal GnuPG stuff. KEYBLOCK may either be a public or a secret key. This function may be called with KEYBLOCK containing secret keys and thus the printing of "pub" vs. "sec" does only depend on the packet type and not by checking with gpg-agent. */ void show_basic_key_info (ctrl_t ctrl, kbnode_t keyblock) { KBNODE node; int i; char pkstrbuf[PUBKEY_STRING_SIZE]; /* The primary key */ for (node = keyblock; node; node = node->next) { if (node->pkt->pkttype == PKT_PUBLIC_KEY || node->pkt->pkttype == PKT_SECRET_KEY) { PKT_public_key *pk = node->pkt->pkt.public_key; /* Note, we use the same format string as in other show functions to make the translation job easier. */ tty_printf ("%s %s/%s ", node->pkt->pkttype == PKT_PUBLIC_KEY ? "pub" : node->pkt->pkttype == PKT_PUBLIC_SUBKEY ? "sub" : node->pkt->pkttype == PKT_SECRET_KEY ? "sec" :"ssb", pubkey_string (pk, pkstrbuf, sizeof pkstrbuf), keystr_from_pk (pk)); tty_printf (_("created: %s"), datestr_from_pk (pk)); tty_printf (" "); tty_printf (_("expires: %s"), expirestr_from_pk (pk)); tty_printf ("\n"); print_fingerprint (ctrl, NULL, pk, 3); tty_printf ("\n"); } } /* The user IDs. */ for (i = 0, node = keyblock; node; node = node->next) { if (node->pkt->pkttype == PKT_USER_ID) { PKT_user_id *uid = node->pkt->pkt.user_id; ++i; tty_printf (" "); if (uid->flags.revoked) tty_printf ("[%s] ", _("revoked")); else if (uid->flags.expired) tty_printf ("[%s] ", _("expired")); tty_print_utf8_string (uid->name, uid->len); tty_printf ("\n"); } } } static void show_key_and_fingerprint (ctrl_t ctrl, kbnode_t keyblock, int with_subkeys) { kbnode_t node; PKT_public_key *pk = NULL; char pkstrbuf[PUBKEY_STRING_SIZE]; for (node = keyblock; node; node = node->next) { if (node->pkt->pkttype == PKT_PUBLIC_KEY) { pk = node->pkt->pkt.public_key; tty_printf ("pub %s/%s %s ", pubkey_string (pk, pkstrbuf, sizeof pkstrbuf), keystr_from_pk(pk), datestr_from_pk (pk)); } else if (node->pkt->pkttype == PKT_USER_ID) { PKT_user_id *uid = node->pkt->pkt.user_id; tty_print_utf8_string (uid->name, uid->len); break; } } tty_printf ("\n"); if (pk) print_fingerprint (ctrl, NULL, pk, 2); if (with_subkeys) { for (node = keyblock; node; node = node->next) { if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY) { pk = node->pkt->pkt.public_key; tty_printf ("sub %s/%s %s [%s]\n", pubkey_string (pk, pkstrbuf, sizeof pkstrbuf), keystr_from_pk(pk), datestr_from_pk (pk), usagestr_from_pk (pk, 0)); print_fingerprint (ctrl, NULL, pk, 4); } } } } /* Show a listing of the primary and its subkeys along with their keygrips. */ static void show_key_and_grip (kbnode_t keyblock) { kbnode_t node; PKT_public_key *pk = NULL; char pkstrbuf[PUBKEY_STRING_SIZE]; char *hexgrip; for (node = keyblock; node; node = node->next) { if (node->pkt->pkttype == PKT_PUBLIC_KEY || node->pkt->pkttype == PKT_PUBLIC_SUBKEY) { pk = node->pkt->pkt.public_key; tty_printf ("%s %s/%s %s [%s]\n", node->pkt->pkttype == PKT_PUBLIC_KEY? "pub":"sub", pubkey_string (pk, pkstrbuf, sizeof pkstrbuf), keystr_from_pk(pk), datestr_from_pk (pk), usagestr_from_pk (pk, 0)); if (!hexkeygrip_from_pk (pk, &hexgrip)) { tty_printf (" Keygrip: %s\n", hexgrip); xfree (hexgrip); } } } } /* Show a warning if no uids on the key have the primary uid flag set. */ static void no_primary_warning (KBNODE keyblock) { KBNODE node; int have_primary = 0, uid_count = 0; /* TODO: if we ever start behaving differently with a primary or non-primary attribute ID, we will need to check for attributes here as well. */ for (node = keyblock; node; node = node->next) { if (node->pkt->pkttype == PKT_USER_ID && node->pkt->pkt.user_id->attrib_data == NULL) { uid_count++; if (node->pkt->pkt.user_id->flags.primary == 2) { have_primary = 1; break; } } } if (uid_count > 1 && !have_primary) log_info (_ ("WARNING: no user ID has been marked as primary. This command" " may\n cause a different user ID to become" " the assumed primary.\n")); } /* Print a warning if the latest encryption subkey expires soon. This function is called after the expire data of the primary key has been changed. */ static void subkey_expire_warning (kbnode_t keyblock) { u32 curtime = make_timestamp (); kbnode_t node; PKT_public_key *pk; /* u32 mainexpire = 0; */ u32 subexpire = 0; u32 latest_date = 0; for (node = keyblock; node; node = node->next) { /* if (node->pkt->pkttype == PKT_PUBLIC_KEY) */ /* { */ /* pk = node->pkt->pkt.public_key; */ /* mainexpire = pk->expiredate; */ /* } */ if (node->pkt->pkttype != PKT_PUBLIC_SUBKEY) continue; pk = node->pkt->pkt.public_key; if (!pk->flags.valid) continue; if (pk->flags.revoked) continue; if (pk->timestamp > curtime) continue; /* Ignore future keys. */ if (!(pk->pubkey_usage & PUBKEY_USAGE_ENC)) continue; /* Not an encryption key. */ if (pk->timestamp > latest_date || (!pk->timestamp && !latest_date)) { latest_date = pk->timestamp; subexpire = pk->expiredate; } } if (!subexpire) return; /* No valid subkey with an expiration time. */ if (curtime + (10*86400) > subexpire) { log_info (_("WARNING: Your encryption subkey expires soon.\n")); log_info (_("You may want to change its expiration date too.\n")); } } /* * Ask for a new user id, add the self-signature, and update the * keyblock. If UIDSTRING is not NULL the user ID is generated * unattended using that string. UIDSTRING is expected to be utf-8 * encoded and white space trimmed. Returns true if there is a new * user id. */ static int menu_adduid (ctrl_t ctrl, kbnode_t pub_keyblock, int photo, const char *photo_name, const char *uidstring) { PKT_user_id *uid; PKT_public_key *pk = NULL; PKT_signature *sig = NULL; PACKET *pkt; KBNODE node; KBNODE pub_where = NULL; gpg_error_t err; if (photo && uidstring) return 0; /* Not allowed. */ for (node = pub_keyblock; node; pub_where = node, node = node->next) { if (node->pkt->pkttype == PKT_PUBLIC_KEY) pk = node->pkt->pkt.public_key; else if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY) break; } if (!node) /* No subkey. */ pub_where = NULL; log_assert (pk); if (photo) { int hasattrib = 0; for (node = pub_keyblock; node; node = node->next) if (node->pkt->pkttype == PKT_USER_ID && node->pkt->pkt.user_id->attrib_data != NULL) { hasattrib = 1; break; } /* It is legal but bad for compatibility to add a photo ID to a v3 key as it means that PGP2 will not be able to use that key anymore. Also, PGP may not expect a photo on a v3 key. Don't bother to ask this if the key already has a photo - any damage has already been done at that point. -dms */ if (pk->version == 3 && !hasattrib) { if (opt.expert) { tty_printf (_("WARNING: This is a PGP2-style key. " "Adding a photo ID may cause some versions\n" " of PGP to reject this key.\n")); if (!cpr_get_answer_is_yes ("keyedit.v3_photo.okay", _("Are you sure you still want " "to add it? (y/N) "))) return 0; } else { tty_printf (_("You may not add a photo ID to " "a PGP2-style key.\n")); return 0; } } uid = generate_photo_id (ctrl, pk, photo_name); } else uid = generate_user_id (pub_keyblock, uidstring); if (!uid) { if (uidstring) { write_status_error ("adduid", gpg_error (304)); log_error ("%s", _("Such a user ID already exists on this key!\n")); } return 0; } err = make_keysig_packet (ctrl, &sig, pk, uid, NULL, pk, 0x13, 0, 0, 0, keygen_add_std_prefs, pk, NULL); if (err) { write_status_error ("keysig", err); log_error ("signing failed: %s\n", gpg_strerror (err)); free_user_id (uid); return 0; } /* Insert/append to public keyblock */ pkt = xmalloc_clear (sizeof *pkt); pkt->pkttype = PKT_USER_ID; pkt->pkt.user_id = uid; node = new_kbnode (pkt); if (pub_where) insert_kbnode (pub_where, node, 0); else add_kbnode (pub_keyblock, node); pkt = xmalloc_clear (sizeof *pkt); pkt->pkttype = PKT_SIGNATURE; pkt->pkt.signature = sig; if (pub_where) insert_kbnode (node, new_kbnode (pkt), 0); else add_kbnode (pub_keyblock, new_kbnode (pkt)); return 1; } /* * Remove all selected userids from the keyring */ static void menu_deluid (KBNODE pub_keyblock) { KBNODE node; int selected = 0; for (node = pub_keyblock; node; node = node->next) { if (node->pkt->pkttype == PKT_USER_ID) { selected = node->flag & NODFLG_SELUID; if (selected) { /* Only cause a trust update if we delete a non-revoked user id */ if (!node->pkt->pkt.user_id->flags.revoked) update_trust = 1; delete_kbnode (node); } } else if (selected && node->pkt->pkttype == PKT_SIGNATURE) delete_kbnode (node); else if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY) selected = 0; } commit_kbnode (&pub_keyblock); } static int menu_delsig (ctrl_t ctrl, kbnode_t pub_keyblock) { KBNODE node; PKT_user_id *uid = NULL; int changed = 0; for (node = pub_keyblock; node; node = node->next) { if (node->pkt->pkttype == PKT_USER_ID) { uid = (node->flag & NODFLG_SELUID) ? node->pkt->pkt.user_id : NULL; } else if (uid && node->pkt->pkttype == PKT_SIGNATURE) { int okay, valid, selfsig, inv_sig, no_key, other_err; tty_printf ("uid "); tty_print_utf8_string (uid->name, uid->len); tty_printf ("\n"); okay = inv_sig = no_key = other_err = 0; if (opt.with_colons) valid = print_and_check_one_sig_colon (ctrl, pub_keyblock, node, &inv_sig, &no_key, &other_err, &selfsig, 1); else valid = print_and_check_one_sig (ctrl, pub_keyblock, node, &inv_sig, &no_key, &other_err, &selfsig, 1, 0); if (valid) { okay = cpr_get_answer_yes_no_quit ("keyedit.delsig.valid", _("Delete this good signature? (y/N/q)")); /* Only update trust if we delete a good signature. The other two cases do not affect trust. */ if (okay) update_trust = 1; } else if (inv_sig || other_err) okay = cpr_get_answer_yes_no_quit ("keyedit.delsig.invalid", _("Delete this invalid signature? (y/N/q)")); else if (no_key) okay = cpr_get_answer_yes_no_quit ("keyedit.delsig.unknown", _("Delete this unknown signature? (y/N/q)")); if (okay == -1) break; if (okay && selfsig && !cpr_get_answer_is_yes ("keyedit.delsig.selfsig", _("Really delete this self-signature? (y/N)"))) okay = 0; if (okay) { delete_kbnode (node); changed++; } } else if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY) uid = NULL; } if (changed) { commit_kbnode (&pub_keyblock); tty_printf (ngettext("Deleted %d signature.\n", "Deleted %d signatures.\n", changed), changed); } else tty_printf (_("Nothing deleted.\n")); return changed; } static int menu_clean (ctrl_t ctrl, kbnode_t keyblock, int self_only) { KBNODE uidnode; int modified = 0, select_all = !count_selected_uids (keyblock); for (uidnode = keyblock->next; uidnode && uidnode->pkt->pkttype != PKT_PUBLIC_SUBKEY; uidnode = uidnode->next) { if (uidnode->pkt->pkttype == PKT_USER_ID && (uidnode->flag & NODFLG_SELUID || select_all)) { int uids = 0, sigs = 0; char *user = utf8_to_native (uidnode->pkt->pkt.user_id->name, uidnode->pkt->pkt.user_id->len, 0); clean_one_uid (ctrl, keyblock, uidnode, opt.verbose, self_only, &uids, &sigs); if (uids) { const char *reason; if (uidnode->pkt->pkt.user_id->flags.revoked) reason = _("revoked"); else if (uidnode->pkt->pkt.user_id->flags.expired) reason = _("expired"); else reason = _("invalid"); tty_printf (_("User ID \"%s\" compacted: %s\n"), user, reason); modified = 1; } else if (sigs) { tty_printf (ngettext("User ID \"%s\": %d signature removed\n", "User ID \"%s\": %d signatures removed\n", sigs), user, sigs); modified = 1; } else { tty_printf (self_only == 1 ? _("User ID \"%s\": already minimized\n") : _("User ID \"%s\": already clean\n"), user); } xfree (user); } } return modified; } /* * Remove some of the secondary keys */ static void menu_delkey (KBNODE pub_keyblock) { KBNODE node; int selected = 0; for (node = pub_keyblock; node; node = node->next) { if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY) { selected = node->flag & NODFLG_SELKEY; if (selected) delete_kbnode (node); } else if (selected && node->pkt->pkttype == PKT_SIGNATURE) delete_kbnode (node); else selected = 0; } commit_kbnode (&pub_keyblock); /* No need to set update_trust here since signing keys are no longer used to certify other keys, so there is no change in trust when revoking/removing them. */ } /* * Ask for a new revoker, create the self-signature and put it into * the keyblock. Returns true if there is a new revoker. */ static int menu_addrevoker (ctrl_t ctrl, kbnode_t pub_keyblock, int sensitive) { PKT_public_key *pk = NULL; PKT_public_key *revoker_pk = NULL; PKT_signature *sig = NULL; PACKET *pkt; struct revocation_key revkey; size_t fprlen; int rc; log_assert (pub_keyblock->pkt->pkttype == PKT_PUBLIC_KEY); pk = pub_keyblock->pkt->pkt.public_key; if (pk->numrevkeys == 0 && pk->version == 3) { /* It is legal but bad for compatibility to add a revoker to a v3 key as it means that PGP2 will not be able to use that key anymore. Also, PGP may not expect a revoker on a v3 key. Don't bother to ask this if the key already has a revoker - any damage has already been done at that point. -dms */ if (opt.expert) { tty_printf (_("WARNING: This is a PGP 2.x-style key. " "Adding a designated revoker may cause\n" " some versions of PGP to reject this key.\n")); if (!cpr_get_answer_is_yes ("keyedit.v3_revoker.okay", _("Are you sure you still want " "to add it? (y/N) "))) return 0; } else { tty_printf (_("You may not add a designated revoker to " "a PGP 2.x-style key.\n")); return 0; } } for (;;) { char *answer; free_public_key (revoker_pk); revoker_pk = xmalloc_clear (sizeof (*revoker_pk)); tty_printf ("\n"); answer = cpr_get_utf8 ("keyedit.add_revoker", _("Enter the user ID of the designated revoker: ")); if (answer[0] == '\0' || answer[0] == CONTROL_D) { xfree (answer); goto fail; } /* Note that I'm requesting CERT here, which usually implies primary keys only, but some casual testing shows that PGP and GnuPG both can handle a designated revocation from a subkey. */ revoker_pk->req_usage = PUBKEY_USAGE_CERT; rc = get_pubkey_byname (ctrl, NULL, revoker_pk, answer, NULL, NULL, 1, 1); if (rc) { log_error (_("key \"%s\" not found: %s\n"), answer, gpg_strerror (rc)); xfree (answer); continue; } xfree (answer); fingerprint_from_pk (revoker_pk, revkey.fpr, &fprlen); if (fprlen != 20) { log_error (_("cannot appoint a PGP 2.x style key as a " "designated revoker\n")); continue; } revkey.class = 0x80; if (sensitive) revkey.class |= 0x40; revkey.algid = revoker_pk->pubkey_algo; if (cmp_public_keys (revoker_pk, pk) == 0) { /* This actually causes no harm (after all, a key that designates itself as a revoker is the same as a regular key), but it's easy enough to check. */ log_error (_("you cannot appoint a key as its own " "designated revoker\n")); continue; } keyid_from_pk (pk, NULL); /* Does this revkey already exist? */ if (!pk->revkey && pk->numrevkeys) BUG (); else { int i; for (i = 0; i < pk->numrevkeys; i++) { if (memcmp (&pk->revkey[i], &revkey, sizeof (struct revocation_key)) == 0) { char buf[50]; log_error (_("this key has already been designated " "as a revoker\n")); format_keyid (pk_keyid (pk), KF_LONG, buf, sizeof (buf)); write_status_text (STATUS_ALREADY_SIGNED, buf); break; } } if (i < pk->numrevkeys) continue; } print_pubkey_info (ctrl, NULL, revoker_pk); print_fingerprint (ctrl, NULL, revoker_pk, 2); tty_printf ("\n"); tty_printf (_("WARNING: appointing a key as a designated revoker " "cannot be undone!\n")); tty_printf ("\n"); if (!cpr_get_answer_is_yes ("keyedit.add_revoker.okay", _("Are you sure you want to appoint this " "key as a designated revoker? (y/N) "))) continue; free_public_key (revoker_pk); revoker_pk = NULL; break; } rc = make_keysig_packet (ctrl, &sig, pk, NULL, NULL, pk, 0x1F, 0, 0, 0, keygen_add_revkey, &revkey, NULL); if (rc) { write_status_error ("keysig", rc); log_error ("signing failed: %s\n", gpg_strerror (rc)); goto fail; } /* Insert into public keyblock. */ pkt = xmalloc_clear (sizeof *pkt); pkt->pkttype = PKT_SIGNATURE; pkt->pkt.signature = sig; insert_kbnode (pub_keyblock, new_kbnode (pkt), PKT_SIGNATURE); return 1; fail: if (sig) free_seckey_enc (sig); free_public_key (revoker_pk); return 0; } /* With FORCE_MAINKEY cleared this function handles the interactive * menu option "expire". With UNATTENDED set to 1 this function only * sets the expiration date of the primary key to NEWEXPIRATION and * avoid all interactivity; with a value of 2 only the flagged subkeys * are set to NEWEXPIRATION. Returns 0 if nothing was done, * GPG_ERR_TRUE if the key was modified, or any other error code. */ static gpg_error_t menu_expire (ctrl_t ctrl, kbnode_t pub_keyblock, int unattended, u32 newexpiration) { int signumber, rc; u32 expiredate; int only_mainkey; /* Set if only the mainkey is to be updated. */ PKT_public_key *main_pk, *sub_pk; PKT_user_id *uid; kbnode_t node; u32 keyid[2]; if (unattended) { only_mainkey = (unattended == 1); expiredate = newexpiration; } else { int n1; only_mainkey = 0; n1 = count_selected_keys (pub_keyblock); if (n1 > 1) { if (!cpr_get_answer_is_yes ("keyedit.expire_multiple_subkeys.okay", _("Are you sure you want to change the" " expiration time for multiple subkeys? (y/N) "))) return gpg_error (GPG_ERR_CANCELED);; } else if (n1) tty_printf (_("Changing expiration time for a subkey.\n")); else { tty_printf (_("Changing expiration time for the primary key.\n")); only_mainkey = 1; no_primary_warning (pub_keyblock); } expiredate = ask_expiredate (); } /* Now we can actually change the self-signature(s) */ main_pk = sub_pk = NULL; uid = NULL; signumber = 0; for (node = pub_keyblock; node; node = node->next) { if (node->pkt->pkttype == PKT_PUBLIC_KEY) { main_pk = node->pkt->pkt.public_key; keyid_from_pk (main_pk, keyid); main_pk->expiredate = expiredate; } else if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY) { if ((node->flag & NODFLG_SELKEY) && unattended != 1) { /* The flag is set and we do not want to set the * expiration date only for the main key. */ sub_pk = node->pkt->pkt.public_key; sub_pk->expiredate = expiredate; } else sub_pk = NULL; } else if (node->pkt->pkttype == PKT_USER_ID) uid = node->pkt->pkt.user_id; else if (main_pk && node->pkt->pkttype == PKT_SIGNATURE && (only_mainkey || sub_pk)) { PKT_signature *sig = node->pkt->pkt.signature; if (keyid[0] == sig->keyid[0] && keyid[1] == sig->keyid[1] && ((only_mainkey && uid && uid->created && (sig->sig_class & ~3) == 0x10) || (!only_mainkey && sig->sig_class == 0x18)) && sig->flags.chosen_selfsig) { /* This is a self-signature which is to be replaced. */ PKT_signature *newsig; PACKET *newpkt; signumber++; if ((only_mainkey && main_pk->version < 4) || (!only_mainkey && sub_pk->version < 4)) { log_info (_("You can't change the expiration date of a v3 key\n")); return gpg_error (GPG_ERR_LEGACY_KEY); } if (only_mainkey) rc = update_keysig_packet (ctrl, &newsig, sig, main_pk, uid, NULL, main_pk, keygen_add_key_expire, main_pk); else rc = update_keysig_packet (ctrl, &newsig, sig, main_pk, NULL, sub_pk, main_pk, keygen_add_key_expire, sub_pk); if (rc) { log_error ("make_keysig_packet failed: %s\n", gpg_strerror (rc)); if (gpg_err_code (rc) == GPG_ERR_TRUE) rc = GPG_ERR_GENERAL; return rc; } /* Replace the packet. */ newpkt = xmalloc_clear (sizeof *newpkt); newpkt->pkttype = PKT_SIGNATURE; newpkt->pkt.signature = newsig; free_packet (node->pkt, NULL); xfree (node->pkt); node->pkt = newpkt; sub_pk = NULL; } } } update_trust = 1; return gpg_error (GPG_ERR_TRUE); } /* Change the capability of a selected key. This command should only * be used to rectify badly created keys and as such is not suggested * for general use. */ static int menu_changeusage (ctrl_t ctrl, kbnode_t keyblock) { int n1, rc; int mainkey = 0; PKT_public_key *main_pk, *sub_pk; PKT_user_id *uid; kbnode_t node; u32 keyid[2]; n1 = count_selected_keys (keyblock); if (n1 > 1) { tty_printf (_("You must select exactly one key.\n")); return 0; } else if (n1) tty_printf ("Changing usage of a subkey.\n"); else { tty_printf ("Changing usage of the primary key.\n"); mainkey = 1; } /* Now we can actually change the self-signature(s) */ main_pk = sub_pk = NULL; uid = NULL; for (node = keyblock; node; node = node->next) { if (node->pkt->pkttype == PKT_PUBLIC_KEY) { main_pk = node->pkt->pkt.public_key; keyid_from_pk (main_pk, keyid); } else if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY) { if (node->flag & NODFLG_SELKEY) sub_pk = node->pkt->pkt.public_key; else sub_pk = NULL; } else if (node->pkt->pkttype == PKT_USER_ID) uid = node->pkt->pkt.user_id; else if (main_pk && node->pkt->pkttype == PKT_SIGNATURE && (mainkey || sub_pk)) { PKT_signature *sig = node->pkt->pkt.signature; if (keyid[0] == sig->keyid[0] && keyid[1] == sig->keyid[1] && ((mainkey && uid && uid->created && (sig->sig_class & ~3) == 0x10) || (!mainkey && sig->sig_class == 0x18)) && sig->flags.chosen_selfsig) { /* This is the self-signature which is to be replaced. */ PKT_signature *newsig; PACKET *newpkt; if ((mainkey && main_pk->version < 4) || (!mainkey && sub_pk->version < 4)) { log_info ("You can't change the capabilities of a v3 key\n"); return 0; } if (mainkey) main_pk->pubkey_usage = ask_key_flags (main_pk->pubkey_algo, 0, main_pk->pubkey_usage); else sub_pk->pubkey_usage = ask_key_flags (sub_pk->pubkey_algo, 1, sub_pk->pubkey_usage); if (mainkey) rc = update_keysig_packet (ctrl, &newsig, sig, main_pk, uid, NULL, main_pk, keygen_add_key_flags, main_pk); else rc = update_keysig_packet (ctrl, &newsig, sig, main_pk, NULL, sub_pk, main_pk, keygen_add_key_flags, sub_pk); if (rc) { log_error ("make_keysig_packet failed: %s\n", gpg_strerror (rc)); return 0; } /* Replace the packet. */ newpkt = xmalloc_clear (sizeof *newpkt); newpkt->pkttype = PKT_SIGNATURE; newpkt->pkt.signature = newsig; free_packet (node->pkt, NULL); xfree (node->pkt); node->pkt = newpkt; sub_pk = NULL; break; } } } return 1; } static int menu_backsign (ctrl_t ctrl, kbnode_t pub_keyblock) { int rc, modified = 0; PKT_public_key *main_pk; KBNODE node; u32 timestamp; log_assert (pub_keyblock->pkt->pkttype == PKT_PUBLIC_KEY); merge_keys_and_selfsig (ctrl, pub_keyblock); main_pk = pub_keyblock->pkt->pkt.public_key; keyid_from_pk (main_pk, NULL); /* We use the same timestamp for all backsigs so that we don't reveal information about the used machine. */ timestamp = make_timestamp (); for (node = pub_keyblock; node; node = node->next) { PKT_public_key *sub_pk = NULL; KBNODE node2, sig_pk = NULL /*,sig_sk = NULL*/; /* char *passphrase; */ /* Find a signing subkey with no backsig */ if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY) { if (node->pkt->pkt.public_key->pubkey_usage & PUBKEY_USAGE_SIG) { if (node->pkt->pkt.public_key->flags.backsig) tty_printf (_ ("signing subkey %s is already cross-certified\n"), keystr_from_pk (node->pkt->pkt.public_key)); else sub_pk = node->pkt->pkt.public_key; } else tty_printf (_("subkey %s does not sign and so does" " not need to be cross-certified\n"), keystr_from_pk (node->pkt->pkt.public_key)); } if (!sub_pk) continue; /* Find the selected selfsig on this subkey */ for (node2 = node->next; node2 && node2->pkt->pkttype == PKT_SIGNATURE; node2 = node2->next) if (node2->pkt->pkt.signature->version >= 4 && node2->pkt->pkt.signature->flags.chosen_selfsig) { sig_pk = node2; break; } if (!sig_pk) continue; /* Find the secret subkey that matches the public subkey */ log_debug ("FIXME: Check whether a secret subkey is available.\n"); /* if (!sub_sk) */ /* { */ /* tty_printf (_("no secret subkey for public subkey %s - ignoring\n"), */ /* keystr_from_pk (sub_pk)); */ /* continue; */ /* } */ /* Now we can get to work. */ rc = make_backsig (ctrl, sig_pk->pkt->pkt.signature, main_pk, sub_pk, sub_pk, timestamp, NULL); if (!rc) { PKT_signature *newsig; PACKET *newpkt; rc = update_keysig_packet (ctrl, &newsig, sig_pk->pkt->pkt.signature, main_pk, NULL, sub_pk, main_pk, NULL, NULL); if (!rc) { /* Put the new sig into place on the pubkey */ newpkt = xmalloc_clear (sizeof (*newpkt)); newpkt->pkttype = PKT_SIGNATURE; newpkt->pkt.signature = newsig; free_packet (sig_pk->pkt, NULL); xfree (sig_pk->pkt); sig_pk->pkt = newpkt; modified = 1; } else { log_error ("update_keysig_packet failed: %s\n", gpg_strerror (rc)); break; } } else { log_error ("make_backsig failed: %s\n", gpg_strerror (rc)); break; } } return modified; } static int change_primary_uid_cb (PKT_signature * sig, void *opaque) { byte buf[1]; /* first clear all primary uid flags so that we are sure none are * lingering around */ delete_sig_subpkt (sig->hashed, SIGSUBPKT_PRIMARY_UID); delete_sig_subpkt (sig->unhashed, SIGSUBPKT_PRIMARY_UID); /* if opaque is set,we want to set the primary id */ if (opaque) { buf[0] = 1; build_sig_subpkt (sig, SIGSUBPKT_PRIMARY_UID, buf, 1); } return 0; } /* * Set the primary uid flag for the selected UID. We will also reset * all other primary uid flags. For this to work we have to update * all the signature timestamps. If we would do this with the current * time, we lose quite a lot of information, so we use a kludge to * do this: Just increment the timestamp by one second which is * sufficient to updated a signature during import. */ static int menu_set_primary_uid (ctrl_t ctrl, kbnode_t pub_keyblock) { PKT_public_key *main_pk; PKT_user_id *uid; KBNODE node; u32 keyid[2]; int selected; int attribute = 0; int modified = 0; if (count_selected_uids (pub_keyblock) != 1) { tty_printf (_("Please select exactly one user ID.\n")); return 0; } main_pk = NULL; uid = NULL; selected = 0; /* Is our selected uid an attribute packet? */ for (node = pub_keyblock; node; node = node->next) if (node->pkt->pkttype == PKT_USER_ID && node->flag & NODFLG_SELUID) attribute = (node->pkt->pkt.user_id->attrib_data != NULL); for (node = pub_keyblock; node; node = node->next) { if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY) break; /* No more user ids expected - ready. */ if (node->pkt->pkttype == PKT_PUBLIC_KEY) { main_pk = node->pkt->pkt.public_key; keyid_from_pk (main_pk, keyid); } else if (node->pkt->pkttype == PKT_USER_ID) { uid = node->pkt->pkt.user_id; selected = node->flag & NODFLG_SELUID; } else if (main_pk && uid && node->pkt->pkttype == PKT_SIGNATURE) { PKT_signature *sig = node->pkt->pkt.signature; if (keyid[0] == sig->keyid[0] && keyid[1] == sig->keyid[1] && (uid && (sig->sig_class & ~3) == 0x10) && attribute == (uid->attrib_data != NULL) && sig->flags.chosen_selfsig) { if (sig->version < 4) { char *user = utf8_to_native (uid->name, strlen (uid->name), 0); log_info (_("skipping v3 self-signature on user ID \"%s\"\n"), user); xfree (user); } else { /* This is a selfsignature which is to be replaced. We can just ignore v3 signatures because they are not able to carry the primary ID flag. We also ignore self-sigs on user IDs that are not of the same type that we are making primary. That is, if we are making a user ID primary, we alter user IDs. If we are making an attribute packet primary, we alter attribute packets. */ /* FIXME: We must make sure that we only have one self-signature per user ID here (not counting revocations) */ PKT_signature *newsig; PACKET *newpkt; const byte *p; int action; /* See whether this signature has the primary UID flag. */ p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_PRIMARY_UID, NULL); if (!p) p = parse_sig_subpkt (sig->unhashed, SIGSUBPKT_PRIMARY_UID, NULL); if (p && *p) /* yes */ action = selected ? 0 : -1; else /* no */ action = selected ? 1 : 0; if (action) { int rc = update_keysig_packet (ctrl, &newsig, sig, main_pk, uid, NULL, main_pk, change_primary_uid_cb, action > 0 ? "x" : NULL); if (rc) { log_error ("update_keysig_packet failed: %s\n", gpg_strerror (rc)); return 0; } /* replace the packet */ newpkt = xmalloc_clear (sizeof *newpkt); newpkt->pkttype = PKT_SIGNATURE; newpkt->pkt.signature = newsig; free_packet (node->pkt, NULL); xfree (node->pkt); node->pkt = newpkt; modified = 1; } } } } } return modified; } /* * Set preferences to new values for the selected user IDs */ static int menu_set_preferences (ctrl_t ctrl, kbnode_t pub_keyblock) { PKT_public_key *main_pk; PKT_user_id *uid; KBNODE node; u32 keyid[2]; int selected, select_all; int modified = 0; no_primary_warning (pub_keyblock); select_all = !count_selected_uids (pub_keyblock); /* Now we can actually change the self signature(s) */ main_pk = NULL; uid = NULL; selected = 0; for (node = pub_keyblock; node; node = node->next) { if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY) break; /* No more user-ids expected - ready. */ if (node->pkt->pkttype == PKT_PUBLIC_KEY) { main_pk = node->pkt->pkt.public_key; keyid_from_pk (main_pk, keyid); } else if (node->pkt->pkttype == PKT_USER_ID) { uid = node->pkt->pkt.user_id; selected = select_all || (node->flag & NODFLG_SELUID); } else if (main_pk && uid && selected && node->pkt->pkttype == PKT_SIGNATURE) { PKT_signature *sig = node->pkt->pkt.signature; if (keyid[0] == sig->keyid[0] && keyid[1] == sig->keyid[1] && (uid && (sig->sig_class & ~3) == 0x10) && sig->flags.chosen_selfsig) { if (sig->version < 4) { char *user = utf8_to_native (uid->name, strlen (uid->name), 0); log_info (_("skipping v3 self-signature on user ID \"%s\"\n"), user); xfree (user); } else { /* This is a selfsignature which is to be replaced * We have to ignore v3 signatures because they are * not able to carry the preferences. */ PKT_signature *newsig; PACKET *newpkt; int rc; rc = update_keysig_packet (ctrl, &newsig, sig, main_pk, uid, NULL, main_pk, keygen_upd_std_prefs, NULL); if (rc) { log_error ("update_keysig_packet failed: %s\n", gpg_strerror (rc)); return 0; } /* replace the packet */ newpkt = xmalloc_clear (sizeof *newpkt); newpkt->pkttype = PKT_SIGNATURE; newpkt->pkt.signature = newsig; free_packet (node->pkt, NULL); xfree (node->pkt); node->pkt = newpkt; modified = 1; } } } } return modified; } static int menu_set_keyserver_url (ctrl_t ctrl, const char *url, kbnode_t pub_keyblock) { PKT_public_key *main_pk; PKT_user_id *uid; KBNODE node; u32 keyid[2]; int selected, select_all; int modified = 0; char *answer, *uri; no_primary_warning (pub_keyblock); if (url) answer = xstrdup (url); else { answer = cpr_get_utf8 ("keyedit.add_keyserver", _("Enter your preferred keyserver URL: ")); if (answer[0] == '\0' || answer[0] == CONTROL_D) { xfree (answer); return 0; } } if (ascii_strcasecmp (answer, "none") == 0) uri = NULL; else { struct keyserver_spec *keyserver = NULL; /* Sanity check the format */ keyserver = parse_keyserver_uri (answer, 1); xfree (answer); if (!keyserver) { log_info (_("could not parse keyserver URL\n")); return 0; } uri = xstrdup (keyserver->uri); free_keyserver_spec (keyserver); } select_all = !count_selected_uids (pub_keyblock); /* Now we can actually change the self signature(s) */ main_pk = NULL; uid = NULL; selected = 0; for (node = pub_keyblock; node; node = node->next) { if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY) break; /* ready */ if (node->pkt->pkttype == PKT_PUBLIC_KEY) { main_pk = node->pkt->pkt.public_key; keyid_from_pk (main_pk, keyid); } else if (node->pkt->pkttype == PKT_USER_ID) { uid = node->pkt->pkt.user_id; selected = select_all || (node->flag & NODFLG_SELUID); } else if (main_pk && uid && selected && node->pkt->pkttype == PKT_SIGNATURE) { PKT_signature *sig = node->pkt->pkt.signature; if (keyid[0] == sig->keyid[0] && keyid[1] == sig->keyid[1] && (uid && (sig->sig_class & ~3) == 0x10) && sig->flags.chosen_selfsig) { char *user = utf8_to_native (uid->name, strlen (uid->name), 0); if (sig->version < 4) log_info (_("skipping v3 self-signature on user ID \"%s\"\n"), user); else { /* This is a selfsignature which is to be replaced * We have to ignore v3 signatures because they are * not able to carry the subpacket. */ PKT_signature *newsig; PACKET *newpkt; int rc; const byte *p; size_t plen; p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_PREF_KS, &plen); if (p && plen) { tty_printf ("Current preferred keyserver for user" " ID \"%s\": ", user); tty_print_utf8_string (p, plen); tty_printf ("\n"); if (!cpr_get_answer_is_yes ("keyedit.confirm_keyserver", uri ? _("Are you sure you want to replace it? (y/N) ") : _("Are you sure you want to delete it? (y/N) "))) continue; } else if (uri == NULL) { /* There is no current keyserver URL, so there is no point in trying to un-set it. */ continue; } rc = update_keysig_packet (ctrl, &newsig, sig, main_pk, uid, NULL, main_pk, keygen_add_keyserver_url, uri); if (rc) { log_error ("update_keysig_packet failed: %s\n", gpg_strerror (rc)); xfree (uri); return 0; } /* replace the packet */ newpkt = xmalloc_clear (sizeof *newpkt); newpkt->pkttype = PKT_SIGNATURE; newpkt->pkt.signature = newsig; free_packet (node->pkt, NULL); xfree (node->pkt); node->pkt = newpkt; modified = 1; } xfree (user); } } } xfree (uri); return modified; } static int menu_set_notation (ctrl_t ctrl, const char *string, KBNODE pub_keyblock) { PKT_public_key *main_pk; PKT_user_id *uid; KBNODE node; u32 keyid[2]; int selected, select_all; int modified = 0; char *answer; struct notation *notation; no_primary_warning (pub_keyblock); if (string) answer = xstrdup (string); else { answer = cpr_get_utf8 ("keyedit.add_notation", _("Enter the notation: ")); if (answer[0] == '\0' || answer[0] == CONTROL_D) { xfree (answer); return 0; } } if (!ascii_strcasecmp (answer, "none") || !ascii_strcasecmp (answer, "-")) notation = NULL; /* Delete them all. */ else { notation = string_to_notation (answer, 0); if (!notation) { xfree (answer); return 0; } } xfree (answer); select_all = !count_selected_uids (pub_keyblock); /* Now we can actually change the self signature(s) */ main_pk = NULL; uid = NULL; selected = 0; for (node = pub_keyblock; node; node = node->next) { if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY) break; /* ready */ if (node->pkt->pkttype == PKT_PUBLIC_KEY) { main_pk = node->pkt->pkt.public_key; keyid_from_pk (main_pk, keyid); } else if (node->pkt->pkttype == PKT_USER_ID) { uid = node->pkt->pkt.user_id; selected = select_all || (node->flag & NODFLG_SELUID); } else if (main_pk && uid && selected && node->pkt->pkttype == PKT_SIGNATURE) { PKT_signature *sig = node->pkt->pkt.signature; if (keyid[0] == sig->keyid[0] && keyid[1] == sig->keyid[1] && (uid && (sig->sig_class & ~3) == 0x10) && sig->flags.chosen_selfsig) { char *user = utf8_to_native (uid->name, strlen (uid->name), 0); if (sig->version < 4) log_info (_("skipping v3 self-signature on user ID \"%s\"\n"), user); else { PKT_signature *newsig; PACKET *newpkt; int rc, skip = 0, addonly = 1; if (sig->flags.notation) { tty_printf ("Current notations for user ID \"%s\":\n", user); tty_print_notations (-9, sig); } else { tty_printf ("No notations on user ID \"%s\"\n", user); if (notation == NULL) { /* There are no current notations, so there is no point in trying to un-set them. */ continue; } } if (notation) { struct notation *n; int deleting = 0; notation->next = sig_to_notation (sig); for (n = notation->next; n; n = n->next) if (strcmp (n->name, notation->name) == 0) { if (notation->value) { if (strcmp (n->value, notation->value) == 0) { if (notation->flags.ignore) { /* Value match with a delete flag. */ n->flags.ignore = 1; deleting = 1; } else { /* Adding the same notation twice, so don't add it at all. */ skip = 1; tty_printf ("Skipping notation:" " %s=%s\n", notation->name, notation->value); break; } } } else { /* No value, so it means delete. */ n->flags.ignore = 1; deleting = 1; } if (n->flags.ignore) { tty_printf ("Removing notation: %s=%s\n", n->name, n->value); addonly = 0; } } if (!notation->flags.ignore && !skip) tty_printf ("Adding notation: %s=%s\n", notation->name, notation->value); /* We tried to delete, but had no matches. */ if (notation->flags.ignore && !deleting) continue; } else { tty_printf ("Removing all notations\n"); addonly = 0; } if (skip || (!addonly && !cpr_get_answer_is_yes ("keyedit.confirm_notation", _("Proceed? (y/N) ")))) continue; rc = update_keysig_packet (ctrl, &newsig, sig, main_pk, uid, NULL, main_pk, keygen_add_notations, notation); if (rc) { log_error ("update_keysig_packet failed: %s\n", gpg_strerror (rc)); free_notation (notation); xfree (user); return 0; } /* replace the packet */ newpkt = xmalloc_clear (sizeof *newpkt); newpkt->pkttype = PKT_SIGNATURE; newpkt->pkt.signature = newsig; free_packet (node->pkt, NULL); xfree (node->pkt); node->pkt = newpkt; modified = 1; if (notation) { /* Snip off the notation list from the sig */ free_notation (notation->next); notation->next = NULL; } xfree (user); } } } } free_notation (notation); return modified; } /* * Select one user id or remove all selection if IDX is 0 or select * all if IDX is -1. Returns: True if the selection changed. */ static int menu_select_uid (KBNODE keyblock, int idx) { KBNODE node; int i; if (idx == -1) /* Select all. */ { for (node = keyblock; node; node = node->next) if (node->pkt->pkttype == PKT_USER_ID) node->flag |= NODFLG_SELUID; return 1; } else if (idx) /* Toggle. */ { for (i = 0, node = keyblock; node; node = node->next) { if (node->pkt->pkttype == PKT_USER_ID) if (++i == idx) break; } if (!node) { tty_printf (_("No user ID with index %d\n"), idx); return 0; } for (i = 0, node = keyblock; node; node = node->next) { if (node->pkt->pkttype == PKT_USER_ID) { if (++i == idx) { if ((node->flag & NODFLG_SELUID)) node->flag &= ~NODFLG_SELUID; else node->flag |= NODFLG_SELUID; } } } } else /* Unselect all */ { for (node = keyblock; node; node = node->next) if (node->pkt->pkttype == PKT_USER_ID) node->flag &= ~NODFLG_SELUID; } return 1; } /* Search in the keyblock for a uid that matches namehash */ static int menu_select_uid_namehash (KBNODE keyblock, const char *namehash) { byte hash[NAMEHASH_LEN]; KBNODE node; int i; log_assert (strlen (namehash) == NAMEHASH_LEN * 2); for (i = 0; i < NAMEHASH_LEN; i++) hash[i] = hextobyte (&namehash[i * 2]); for (node = keyblock->next; node; node = node->next) { if (node->pkt->pkttype == PKT_USER_ID) { namehash_from_uid (node->pkt->pkt.user_id); if (memcmp (node->pkt->pkt.user_id->namehash, hash, NAMEHASH_LEN) == 0) { if (node->flag & NODFLG_SELUID) node->flag &= ~NODFLG_SELUID; else node->flag |= NODFLG_SELUID; break; } } } if (!node) { tty_printf (_("No user ID with hash %s\n"), namehash); return 0; } return 1; } /* * Select secondary keys * Returns: True if the selection changed. */ static int menu_select_key (KBNODE keyblock, int idx, char *p) { KBNODE node; int i, j; int is_hex_digits; is_hex_digits = p && strlen (p) >= 8; if (is_hex_digits) { /* Skip initial spaces. */ while (spacep (p)) p ++; /* If the id starts with 0x accept and ignore it. */ if (p[0] == '0' && p[1] == 'x') p += 2; for (i = 0, j = 0; p[i]; i ++) if (hexdigitp (&p[i])) { p[j] = toupper (p[i]); j ++; } else if (spacep (&p[i])) /* Skip spaces. */ { } else { is_hex_digits = 0; break; } if (is_hex_digits) /* In case we skipped some spaces, add a new NUL terminator. */ { p[j] = 0; /* If we skipped some spaces, make sure that we still have at least 8 characters. */ is_hex_digits = (/* Short keyid. */ strlen (p) == 8 /* Long keyid. */ || strlen (p) == 16 /* Fingerprints are (currently) 32 or 40 characters. */ || strlen (p) >= 32); } } if (is_hex_digits) { int found_one = 0; for (node = keyblock; node; node = node->next) if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY || node->pkt->pkttype == PKT_SECRET_SUBKEY) { int match = 0; if (strlen (p) == 8 || strlen (p) == 16) { u32 kid[2]; char kid_str[17]; keyid_from_pk (node->pkt->pkt.public_key, kid); format_keyid (kid, strlen (p) == 8 ? KF_SHORT : KF_LONG, kid_str, sizeof (kid_str)); if (strcmp (p, kid_str) == 0) match = 1; } else { char fp[2*MAX_FINGERPRINT_LEN + 1]; hexfingerprint (node->pkt->pkt.public_key, fp, sizeof (fp)); if (strcmp (fp, p) == 0) match = 1; } if (match) { if ((node->flag & NODFLG_SELKEY)) node->flag &= ~NODFLG_SELKEY; else node->flag |= NODFLG_SELKEY; found_one = 1; } } if (found_one) return 1; tty_printf (_("No subkey with key ID '%s'.\n"), p); return 0; } if (idx == -1) /* Select all. */ { for (node = keyblock; node; node = node->next) if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY || node->pkt->pkttype == PKT_SECRET_SUBKEY) node->flag |= NODFLG_SELKEY; } else if (idx) /* Toggle selection. */ { for (i = 0, node = keyblock; node; node = node->next) { if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY || node->pkt->pkttype == PKT_SECRET_SUBKEY) if (++i == idx) break; } if (!node) { tty_printf (_("No subkey with index %d\n"), idx); return 0; } for (i = 0, node = keyblock; node; node = node->next) { if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY || node->pkt->pkttype == PKT_SECRET_SUBKEY) if (++i == idx) { if ((node->flag & NODFLG_SELKEY)) node->flag &= ~NODFLG_SELKEY; else node->flag |= NODFLG_SELKEY; } } } else /* Unselect all. */ { for (node = keyblock; node; node = node->next) if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY || node->pkt->pkttype == PKT_SECRET_SUBKEY) node->flag &= ~NODFLG_SELKEY; } return 1; } static int count_uids_with_flag (KBNODE keyblock, unsigned flag) { KBNODE node; int i = 0; for (node = keyblock; node; node = node->next) if (node->pkt->pkttype == PKT_USER_ID && (node->flag & flag)) i++; return i; } static int count_keys_with_flag (KBNODE keyblock, unsigned flag) { KBNODE node; int i = 0; for (node = keyblock; node; node = node->next) if ((node->pkt->pkttype == PKT_PUBLIC_SUBKEY || node->pkt->pkttype == PKT_SECRET_SUBKEY) && (node->flag & flag)) i++; return i; } static int count_uids (KBNODE keyblock) { KBNODE node; int i = 0; for (node = keyblock; node; node = node->next) if (node->pkt->pkttype == PKT_USER_ID) i++; return i; } /* * Returns true if there is at least one selected user id */ static int count_selected_uids (KBNODE keyblock) { return count_uids_with_flag (keyblock, NODFLG_SELUID); } static int count_selected_keys (KBNODE keyblock) { return count_keys_with_flag (keyblock, NODFLG_SELKEY); } /* Returns how many real (i.e. not attribute) uids are unmarked. */ static int real_uids_left (KBNODE keyblock) { KBNODE node; int real = 0; for (node = keyblock; node; node = node->next) if (node->pkt->pkttype == PKT_USER_ID && !(node->flag & NODFLG_SELUID) && !node->pkt->pkt.user_id->attrib_data) real++; return real; } /* * Ask whether the signature should be revoked. If the user commits this, * flag bit MARK_A is set on the signature and the user ID. */ static void ask_revoke_sig (ctrl_t ctrl, kbnode_t keyblock, kbnode_t node) { int doit = 0; PKT_user_id *uid; PKT_signature *sig = node->pkt->pkt.signature; KBNODE unode = find_prev_kbnode (keyblock, node, PKT_USER_ID); if (!unode) { log_error ("Oops: no user ID for signature\n"); return; } uid = unode->pkt->pkt.user_id; if (opt.with_colons) { if (uid->attrib_data) printf ("uat:::::::::%u %lu", uid->numattribs, uid->attrib_len); else { es_printf ("uid:::::::::"); es_write_sanitized (es_stdout, uid->name, uid->len, ":", NULL); } es_printf ("\n"); print_and_check_one_sig_colon (ctrl, keyblock, node, NULL, NULL, NULL, NULL, 1); } else { char *p = utf8_to_native (unode->pkt->pkt.user_id->name, unode->pkt->pkt.user_id->len, 0); tty_printf (_("user ID: \"%s\"\n"), p); xfree (p); tty_printf (_("signed by your key %s on %s%s%s\n"), keystr (sig->keyid), datestr_from_sig (sig), sig->flags.exportable ? "" : _(" (non-exportable)"), ""); } if (sig->flags.expired) { tty_printf (_("This signature expired on %s.\n"), expirestr_from_sig (sig)); /* Use a different question so we can have different help text */ doit = cpr_get_answer_is_yes ("ask_revoke_sig.expired", _("Are you sure you still want to revoke it? (y/N) ")); } else doit = cpr_get_answer_is_yes ("ask_revoke_sig.one", _("Create a revocation certificate for this signature? (y/N) ")); if (doit) { node->flag |= NODFLG_MARK_A; unode->flag |= NODFLG_MARK_A; } } /* * Display all user ids of the current public key together with signatures * done by one of our keys. Then walk over all this sigs and ask the user * whether he wants to revoke this signature. * Return: True when the keyblock has changed. */ static int menu_revsig (ctrl_t ctrl, kbnode_t keyblock) { PKT_signature *sig; PKT_public_key *primary_pk; KBNODE node; int changed = 0; int rc, any, skip = 1, all = !count_selected_uids (keyblock); struct revocation_reason_info *reason = NULL; log_assert (keyblock->pkt->pkttype == PKT_PUBLIC_KEY); /* First check whether we have any signatures at all. */ any = 0; for (node = keyblock; node; node = node->next) { node->flag &= ~(NODFLG_SELSIG | NODFLG_MARK_A); if (node->pkt->pkttype == PKT_USER_ID) { if (node->flag & NODFLG_SELUID || all) skip = 0; else skip = 1; } else if (!skip && node->pkt->pkttype == PKT_SIGNATURE && ((sig = node->pkt->pkt.signature), have_secret_key_with_kid (sig->keyid))) { if ((sig->sig_class & ~3) == 0x10) { any = 1; break; } } } if (!any) { tty_printf (_("Not signed by you.\n")); return 0; } /* FIXME: detect duplicates here */ tty_printf (_("You have signed these user IDs on key %s:\n"), keystr_from_pk (keyblock->pkt->pkt.public_key)); for (node = keyblock; node; node = node->next) { node->flag &= ~(NODFLG_SELSIG | NODFLG_MARK_A); if (node->pkt->pkttype == PKT_USER_ID) { if (node->flag & NODFLG_SELUID || all) { PKT_user_id *uid = node->pkt->pkt.user_id; /* Hmmm: Should we show only UIDs with a signature? */ tty_printf (" "); tty_print_utf8_string (uid->name, uid->len); tty_printf ("\n"); skip = 0; } else skip = 1; } else if (!skip && node->pkt->pkttype == PKT_SIGNATURE && ((sig = node->pkt->pkt.signature), have_secret_key_with_kid (sig->keyid))) { if ((sig->sig_class & ~3) == 0x10) { tty_printf (" "); tty_printf (_("signed by your key %s on %s%s%s\n"), keystr (sig->keyid), datestr_from_sig (sig), sig->flags.exportable ? "" : _(" (non-exportable)"), sig->flags.revocable ? "" : _(" (non-revocable)")); if (sig->flags.revocable) node->flag |= NODFLG_SELSIG; } else if (sig->sig_class == 0x30) { tty_printf (" "); tty_printf (_("revoked by your key %s on %s\n"), keystr (sig->keyid), datestr_from_sig (sig)); } } } tty_printf ("\n"); /* ask */ for (node = keyblock; node; node = node->next) { if (!(node->flag & NODFLG_SELSIG)) continue; ask_revoke_sig (ctrl, keyblock, node); } /* present selected */ any = 0; for (node = keyblock; node; node = node->next) { if (!(node->flag & NODFLG_MARK_A)) continue; if (!any) { any = 1; tty_printf (_("You are about to revoke these signatures:\n")); } if (node->pkt->pkttype == PKT_USER_ID) { PKT_user_id *uid = node->pkt->pkt.user_id; tty_printf (" "); tty_print_utf8_string (uid->name, uid->len); tty_printf ("\n"); } else if (node->pkt->pkttype == PKT_SIGNATURE) { sig = node->pkt->pkt.signature; tty_printf (" "); tty_printf (_("signed by your key %s on %s%s%s\n"), keystr (sig->keyid), datestr_from_sig (sig), "", sig->flags.exportable ? "" : _(" (non-exportable)")); } } if (!any) return 0; /* none selected */ if (!cpr_get_answer_is_yes ("ask_revoke_sig.okay", _("Really create the revocation certificates? (y/N) "))) return 0; /* forget it */ reason = ask_revocation_reason (0, 1, 0); if (!reason) { /* user decided to cancel */ return 0; } /* now we can sign the user ids */ reloop: /* (must use this, because we are modifying the list) */ primary_pk = keyblock->pkt->pkt.public_key; for (node = keyblock; node; node = node->next) { KBNODE unode; PACKET *pkt; struct sign_attrib attrib; PKT_public_key *signerkey; if (!(node->flag & NODFLG_MARK_A) || node->pkt->pkttype != PKT_SIGNATURE) continue; unode = find_prev_kbnode (keyblock, node, PKT_USER_ID); log_assert (unode); /* we already checked this */ memset (&attrib, 0, sizeof attrib); attrib.reason = reason; attrib.non_exportable = !node->pkt->pkt.signature->flags.exportable; node->flag &= ~NODFLG_MARK_A; signerkey = xmalloc_secure_clear (sizeof *signerkey); if (get_seckey (ctrl, signerkey, node->pkt->pkt.signature->keyid)) { log_info (_("no secret key\n")); free_public_key (signerkey); continue; } rc = make_keysig_packet (ctrl, &sig, primary_pk, unode->pkt->pkt.user_id, NULL, signerkey, 0x30, 0, 0, 0, sign_mk_attrib, &attrib, NULL); free_public_key (signerkey); if (rc) { write_status_error ("keysig", rc); log_error (_("signing failed: %s\n"), gpg_strerror (rc)); release_revocation_reason_info (reason); return changed; } changed = 1; /* we changed the keyblock */ update_trust = 1; /* Are we revoking our own uid? */ if (primary_pk->keyid[0] == sig->keyid[0] && primary_pk->keyid[1] == sig->keyid[1]) unode->pkt->pkt.user_id->flags.revoked = 1; pkt = xmalloc_clear (sizeof *pkt); pkt->pkttype = PKT_SIGNATURE; pkt->pkt.signature = sig; insert_kbnode (unode, new_kbnode (pkt), 0); goto reloop; } release_revocation_reason_info (reason); return changed; } /* return 0 if revocation of NODE (which must be a User ID) was successful, non-zero if there was an error. *modified will be set to 1 if a change was made. */ static int core_revuid (ctrl_t ctrl, kbnode_t keyblock, KBNODE node, const struct revocation_reason_info *reason, int *modified) { PKT_public_key *pk = keyblock->pkt->pkt.public_key; gpg_error_t rc; if (node->pkt->pkttype != PKT_USER_ID) { rc = gpg_error (GPG_ERR_NO_USER_ID); write_status_error ("keysig", rc); log_error (_("tried to revoke a non-user ID: %s\n"), gpg_strerror (rc)); return 1; } else { PKT_user_id *uid = node->pkt->pkt.user_id; if (uid->flags.revoked) { char *user = utf8_to_native (uid->name, uid->len, 0); log_info (_("user ID \"%s\" is already revoked\n"), user); xfree (user); } else { PACKET *pkt; PKT_signature *sig; struct sign_attrib attrib; u32 timestamp = make_timestamp (); if (uid->created >= timestamp) { /* Okay, this is a problem. The user ID selfsig was created in the future, so we need to warn the user and set our revocation timestamp one second after that so everything comes out clean. */ log_info (_("WARNING: a user ID signature is dated %d" " seconds in the future\n"), uid->created - timestamp); timestamp = uid->created + 1; } memset (&attrib, 0, sizeof attrib); /* should not need to cast away const here; but revocation_reason_build_cb needs to take a non-const void* in order to meet the function signtuare for the mksubpkt argument to make_keysig_packet */ attrib.reason = (struct revocation_reason_info *)reason; rc = make_keysig_packet (ctrl, &sig, pk, uid, NULL, pk, 0x30, 0, timestamp, 0, sign_mk_attrib, &attrib, NULL); if (rc) { write_status_error ("keysig", rc); log_error (_("signing failed: %s\n"), gpg_strerror (rc)); return 1; } else { pkt = xmalloc_clear (sizeof *pkt); pkt->pkttype = PKT_SIGNATURE; pkt->pkt.signature = sig; insert_kbnode (node, new_kbnode (pkt), 0); #ifndef NO_TRUST_MODELS /* If the trustdb has an entry for this key+uid then the trustdb needs an update. */ if (!update_trust && ((get_validity (ctrl, keyblock, pk, uid, NULL, 0) & TRUST_MASK) >= TRUST_UNDEFINED)) update_trust = 1; #endif /*!NO_TRUST_MODELS*/ node->pkt->pkt.user_id->flags.revoked = 1; if (modified) *modified = 1; } } return 0; } } /* Revoke a user ID (i.e. revoke a user ID selfsig). Return true if keyblock changed. */ static int menu_revuid (ctrl_t ctrl, kbnode_t pub_keyblock) { PKT_public_key *pk = pub_keyblock->pkt->pkt.public_key; KBNODE node; int changed = 0; int rc; struct revocation_reason_info *reason = NULL; size_t valid_uids; /* Note that this is correct as per the RFCs, but nevertheless somewhat meaningless in the real world. 1991 did define the 0x30 sig class, but PGP 2.x did not actually implement it, so it would probably be safe to use v4 revocations everywhere. -ds */ for (node = pub_keyblock; node; node = node->next) if (pk->version > 3 || (node->pkt->pkttype == PKT_USER_ID && node->pkt->pkt.user_id->selfsigversion > 3)) { if ((reason = ask_revocation_reason (0, 1, 4))) break; else goto leave; } /* Too make sure that we do not revoke the last valid UID, we first count how many valid UIDs there are. */ valid_uids = 0; for (node = pub_keyblock; node; node = node->next) valid_uids += node->pkt->pkttype == PKT_USER_ID && ! node->pkt->pkt.user_id->flags.revoked && ! node->pkt->pkt.user_id->flags.expired; reloop: /* (better this way because we are modifying the keyring) */ for (node = pub_keyblock; node; node = node->next) if (node->pkt->pkttype == PKT_USER_ID && (node->flag & NODFLG_SELUID)) { int modified = 0; /* Make sure that we do not revoke the last valid UID. */ if (valid_uids == 1 && ! node->pkt->pkt.user_id->flags.revoked && ! node->pkt->pkt.user_id->flags.expired) { log_error (_("Cannot revoke the last valid user ID.\n")); goto leave; } rc = core_revuid (ctrl, pub_keyblock, node, reason, &modified); if (rc) goto leave; if (modified) { node->flag &= ~NODFLG_SELUID; changed = 1; goto reloop; } } if (changed) commit_kbnode (&pub_keyblock); leave: release_revocation_reason_info (reason); return changed; } /* * Revoke the whole key. */ static int menu_revkey (ctrl_t ctrl, kbnode_t pub_keyblock) { PKT_public_key *pk = pub_keyblock->pkt->pkt.public_key; int rc, changed = 0; struct revocation_reason_info *reason; PACKET *pkt; PKT_signature *sig; if (pk->flags.revoked) { tty_printf (_("Key %s is already revoked.\n"), keystr_from_pk (pk)); return 0; } reason = ask_revocation_reason (1, 0, 0); /* user decided to cancel */ if (!reason) return 0; rc = make_keysig_packet (ctrl, &sig, pk, NULL, NULL, pk, 0x20, 0, 0, 0, revocation_reason_build_cb, reason, NULL); if (rc) { write_status_error ("keysig", rc); log_error (_("signing failed: %s\n"), gpg_strerror (rc)); goto scram; } changed = 1; /* we changed the keyblock */ pkt = xmalloc_clear (sizeof *pkt); pkt->pkttype = PKT_SIGNATURE; pkt->pkt.signature = sig; insert_kbnode (pub_keyblock, new_kbnode (pkt), 0); commit_kbnode (&pub_keyblock); update_trust = 1; scram: release_revocation_reason_info (reason); return changed; } static int menu_revsubkey (ctrl_t ctrl, kbnode_t pub_keyblock) { PKT_public_key *mainpk; KBNODE node; int changed = 0; int rc; struct revocation_reason_info *reason = NULL; reason = ask_revocation_reason (1, 0, 0); if (!reason) return 0; /* User decided to cancel. */ reloop: /* (better this way because we are modifying the keyring) */ mainpk = pub_keyblock->pkt->pkt.public_key; for (node = pub_keyblock; node; node = node->next) { if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY && (node->flag & NODFLG_SELKEY)) { PACKET *pkt; PKT_signature *sig; PKT_public_key *subpk = node->pkt->pkt.public_key; struct sign_attrib attrib; if (subpk->flags.revoked) { tty_printf (_("Subkey %s is already revoked.\n"), keystr_from_pk (subpk)); continue; } memset (&attrib, 0, sizeof attrib); attrib.reason = reason; node->flag &= ~NODFLG_SELKEY; rc = make_keysig_packet (ctrl, &sig, mainpk, NULL, subpk, mainpk, 0x28, 0, 0, 0, sign_mk_attrib, &attrib, NULL); if (rc) { write_status_error ("keysig", rc); log_error (_("signing failed: %s\n"), gpg_strerror (rc)); release_revocation_reason_info (reason); return changed; } changed = 1; /* we changed the keyblock */ pkt = xmalloc_clear (sizeof *pkt); pkt->pkttype = PKT_SIGNATURE; pkt->pkt.signature = sig; insert_kbnode (node, new_kbnode (pkt), 0); goto reloop; } } commit_kbnode (&pub_keyblock); /* No need to set update_trust here since signing keys no longer are used to certify other keys, so there is no change in trust when revoking/removing them */ release_revocation_reason_info (reason); return changed; } /* Note that update_ownertrust is going to mark the trustdb dirty when enabling or disabling a key. This is arguably sub-optimal as disabled keys are still counted in the web of trust, but perhaps not worth adding extra complexity to change. -ds */ #ifndef NO_TRUST_MODELS static int enable_disable_key (ctrl_t ctrl, kbnode_t keyblock, int disable) { PKT_public_key *pk = find_kbnode (keyblock, PKT_PUBLIC_KEY)->pkt->pkt.public_key; unsigned int trust, newtrust; trust = newtrust = get_ownertrust (ctrl, pk); newtrust &= ~TRUST_FLAG_DISABLED; if (disable) newtrust |= TRUST_FLAG_DISABLED; if (trust == newtrust) return 0; /* already in that state */ update_ownertrust (ctrl, pk, newtrust); return 0; } #endif /*!NO_TRUST_MODELS*/ static void menu_showphoto (ctrl_t ctrl, kbnode_t keyblock) { KBNODE node; int select_all = !count_selected_uids (keyblock); int count = 0; PKT_public_key *pk = NULL; /* Look for the public key first. We have to be really, really, explicit as to which photo this is, and what key it is a UID on since people may want to sign it. */ for (node = keyblock; node; node = node->next) { if (node->pkt->pkttype == PKT_PUBLIC_KEY) pk = node->pkt->pkt.public_key; else if (node->pkt->pkttype == PKT_USER_ID) { PKT_user_id *uid = node->pkt->pkt.user_id; count++; if ((select_all || (node->flag & NODFLG_SELUID)) && uid->attribs != NULL) { int i; for (i = 0; i < uid->numattribs; i++) { byte type; u32 size; if (uid->attribs[i].type == ATTRIB_IMAGE && parse_image_header (&uid->attribs[i], &type, &size)) { tty_printf (_("Displaying %s photo ID of size %ld for " "key %s (uid %d)\n"), image_type_to_string (type, 1), (ulong) size, keystr_from_pk (pk), count); show_photos (ctrl, &uid->attribs[i], 1, pk, uid); } } } } } } diff --git a/g10/main.h b/g10/main.h index 96899acf5..a02c5740f 100644 --- a/g10/main.h +++ b/g10/main.h @@ -1,506 +1,506 @@ /* 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 "../common/types.h" #include "../common/iobuf.h" #include "keydb.h" #include "keyedit.h" #include "../common/util.h" /* It could be argued that the default cipher should be 3DES rather than AES128, 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. */ #if GPG_USE_AES256 # define DEFAULT_CIPHER_ALGO CIPHER_ALGO_AES256 #elif GPG_USE_AES128 # define DEFAULT_CIPHER_ALGO CIPHER_ALGO_AES #elif GPG_USE_CAST5 # define DEFAULT_CIPHER_ALGO CIPHER_ALGO_CAST5 #else # define DEFAULT_CIPHER_ALGO CIPHER_ALGO_3DES #endif #define DEFAULT_AEAD_ALGO AEAD_ALGO_EAX #define DEFAULT_DIGEST_ALGO ((GNUPG)? DIGEST_ALGO_SHA256: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 { ctrl_t ctrl; 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; }; struct weakhash { enum gcry_md_algos algo; int rejection_shown; struct weakhash *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 (pubkey_algo_t algo); void print_cipher_algo_note (cipher_algo_t algo); void print_digest_algo_note (digest_algo_t algo); void print_digest_rejected_note (enum gcry_md_algos algo); void print_reported_error (gpg_error_t err, gpg_err_code_t skip_if_ec); void print_further_info (const char *format, ...) GPGRT_ATTR_PRINTF(1,2); void additional_weak_digest (const char* digestname); /*-- armor.c --*/ char *make_radix64_string( const byte *data, size_t len ); /*-- misc.c --*/ void trap_unaligned(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 ); enum gcry_cipher_algos map_cipher_openpgp_to_gcry (cipher_algo_t 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 (cipher_algo_t algo); int openpgp_cipher_test_algo(cipher_algo_t algo); const char *openpgp_cipher_algo_name (cipher_algo_t algo); gpg_error_t openpgp_aead_test_algo (aead_algo_t algo); const char *openpgp_aead_algo_name (aead_algo_t algo); gpg_error_t openpgp_aead_algo_info (aead_algo_t algo, enum gcry_cipher_modes *r_mode, unsigned int *r_noncelen); pubkey_algo_t map_pk_gcry_to_openpgp (enum gcry_pk_algos algo); 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 ); const char *openpgp_pk_algo_name (pubkey_algo_t algo); enum gcry_md_algos map_md_openpgp_to_gcry (digest_algo_t algo); int openpgp_md_test_algo (digest_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; const byte *namehash; }; 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_scdaemon_option (const char *configname, unsigned int configlineno, const char *name); int string_to_cipher_algo (const char *string); aead_algo_t string_to_aead_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); aead_algo_t default_aead_algo(void); int default_compress_algo(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); const char *get_libexecdir (void); int path_access(const char *file,int mode); 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); /*-- cpr.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_failure (const char *where, gpg_error_t err); void write_status_text ( int no, const char *text ); void write_status_printf (int no, const char *format, ...) GPGRT_ATTR_PRINTF(2,3); void write_status_strings (int no, const char *text, ...) GPGRT_ATTR_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_def (const char *keyword, const char *prompt, int def_yes); 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); -gpg_error_t encrypt_seskey (DEK *dek, DEK **r_seskey, +gpg_error_t encrypt_seskey (DEK *dek, aead_algo_t aead_algo, DEK **r_seskey, void **r_enckey, size_t *r_enckeylen); aead_algo_t use_aead (pk_list_t pk_list, int algo); int use_mdc (pk_list_t pk_list,int algo); 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); int write_pubkey_enc (ctrl_t ctrl, PKT_public_key *pk, int throw_keyid, DEK *dek, iobuf_t out); /*-- sign.c --*/ 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 (ctrl_t ctrl, const char *fname, strlist_t locusr, const char *outfile); int sign_symencrypt_file (ctrl_t ctrl, const char *fname, strlist_t locusr); /*-- sig-check.c --*/ void sig_check_dump_stats (void); /* SIG is a revocation signature. Check if any of PK's designated revokers generated it. If so, return 0. Note: this function (correctly) doesn't care if the designated revoker is revoked. */ int check_revocation_keys (ctrl_t ctrl, PKT_public_key *pk, PKT_signature *sig); /* Check that the backsig BACKSIG from the subkey SUB_PK to its primary key MAIN_PK is valid. */ int check_backsig(PKT_public_key *main_pk,PKT_public_key *sub_pk, PKT_signature *backsig); /* Check that the signature SIG over a key (e.g., a key binding or a key revocation) is valid. (To check signatures over data, use check_signature.) */ int check_key_signature (ctrl_t ctrl, kbnode_t root, kbnode_t sig, int *is_selfsig ); /* Like check_key_signature, but with the ability to specify some additional parameters and get back additional information. See the documentation for the implementation for details. */ int check_key_signature2 (ctrl_t ctrl, kbnode_t root, kbnode_t node, PKT_public_key *check_pk, PKT_public_key *ret_pk, int *is_selfsig, u32 *r_expiredate, int *r_expired); /* Returns whether SIGNER generated the signature SIG over the packet PACKET, which is a key, subkey or uid, and comes from the key block KB. If SIGNER is NULL, it is looked up based on the information in SIG. If not NULL, sets *IS_SELFSIG to indicate whether the signature is a self-signature and *RET_PK to a copy of the signer's key. */ gpg_error_t check_signature_over_key_or_uid (ctrl_t ctrl, PKT_public_key *signer, PKT_signature *sig, KBNODE kb, PACKET *packet, int *is_selfsig, PKT_public_key *ret_pk); /*-- delkey.c --*/ gpg_error_t delete_keys (ctrl_t ctrl, strlist_t names, int secret, int allow_both); /*-- keygen.c --*/ const char *get_default_pubkey_algo (void); u32 parse_expire_string(const char *string); u32 ask_expire_interval(int object,const char *def_expire); u32 ask_expiredate(void); unsigned int ask_key_flags (int algo, int subkey, unsigned int current); void quick_generate_keypair (ctrl_t ctrl, const char *uid, const char *algostr, const char *usagestr, const char *expirestr); void generate_keypair (ctrl_t ctrl, int full, 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_key_flags (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 (ctrl_t ctrl, PKT_signature *sig, PKT_public_key *pk, PKT_public_key *sub_pk, PKT_public_key *sub_psk, u32 timestamp, const char *cache_nonce); gpg_error_t generate_subkeypair (ctrl_t ctrl, kbnode_t keyblock, const char *algostr, const char *usagestr, const char *expirestr); #ifdef ENABLE_CARD_SUPPORT gpg_error_t generate_card_subkeypair (ctrl_t ctrl, kbnode_t pub_keyblock, int keyno, const char *serialno); #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, int restrictedperm, iobuf_t *a); char *get_matching_datafile (const char *sigfilename); iobuf_t open_sigfile (const char *sigfilename, progress_filter_context_t *pfx); void try_make_homedir( const char *fname ); char *get_openpgp_revocdir (const char *home); /*-- 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 --*/ struct import_stats_s; typedef struct import_stats_s *import_stats_t; struct import_filter_s; typedef struct import_filter_s *import_filter_t; typedef gpg_error_t (*import_screener_t)(kbnode_t keyblock, void *arg); int parse_import_options(char *str,unsigned int *options,int noisy); gpg_error_t parse_and_set_import_filter (const char *string); import_filter_t save_and_clear_import_filter (void); void restore_import_filter (import_filter_t filt); gpg_error_t read_key_from_file (ctrl_t ctrl, const char *fname, kbnode_t *r_keyblock); void import_keys (ctrl_t ctrl, char **fnames, int nnames, import_stats_t stats_hd, unsigned int options, int origin, const char *url); gpg_error_t import_keys_es_stream (ctrl_t ctrl, estream_t fp, import_stats_t stats_handle, unsigned char **fpr, size_t *fpr_len, unsigned int options, import_screener_t screener, void *screener_arg, int origin, const char *url); gpg_error_t import_old_secring (ctrl_t ctrl, const char *fname); import_stats_t import_new_stats_handle (void); void import_release_stats_handle (import_stats_t hd); void import_print_stats (import_stats_t hd); /* Communication for impex_filter_getval */ struct impex_filter_parm_s { ctrl_t ctrl; kbnode_t node; }; const char *impex_filter_getval (void *cookie, const char *propname); gpg_error_t transfer_secret_keys (ctrl_t ctrl, struct import_stats_s *stats, kbnode_t sec_keyblock, int batch, int force); int collapse_uids( KBNODE *keyblock ); /*-- export.c --*/ struct export_stats_s; typedef struct export_stats_s *export_stats_t; export_stats_t export_new_stats (void); void export_release_stats (export_stats_t stats); void export_print_stats (export_stats_t stats); int parse_export_options(char *str,unsigned int *options,int noisy); gpg_error_t parse_and_set_export_filter (const char *string); int export_pubkeys (ctrl_t ctrl, strlist_t users, unsigned int options, export_stats_t stats); int export_seckeys (ctrl_t ctrl, strlist_t users, unsigned int options, export_stats_t stats); int export_secsubkeys (ctrl_t ctrl, strlist_t users, unsigned int options, export_stats_t stats); gpg_error_t export_pubkey_buffer (ctrl_t ctrl, const char *keyspec, unsigned int options, export_stats_t stats, kbnode_t *r_keyblock, void **r_data, size_t *r_datalen); gpg_error_t receive_seckey_from_agent (ctrl_t ctrl, gcry_cipher_hd_t cipherhd, int cleartext, char **cache_nonce_addr, const char *hexgrip, PKT_public_key *pk); gpg_error_t write_keyblock_to_output (kbnode_t keyblock, int with_armor, unsigned int options); gpg_error_t export_ssh_key (ctrl_t ctrl, const char *userid); /*-- dearmor.c --*/ int dearmor_file( const char *fname ); int enarmor_file( const char *fname ); /*-- revoke.c --*/ struct revocation_reason_info; int gen_standard_revoke (ctrl_t ctrl, PKT_public_key *psk, const char *cache_nonce); int gen_revoke (ctrl_t ctrl, const char *uname); int gen_desig_revoke (ctrl_t ctrl, 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 ); struct revocation_reason_info * get_default_uid_revocation_reason(void); 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_direct (ctrl_t ctrl, kbnode_t keyblock, int secret, int has_secret, int fpr, int no_validity); void print_fingerprint (ctrl_t ctrl, estream_t fp, PKT_public_key *pk, int mode); void print_revokers (estream_t fp, 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); char *format_seckey_info (ctrl_t ctrl, PKT_public_key *pk); void print_seckey_info (ctrl_t ctrl, PKT_public_key *pk); void print_pubkey_info (ctrl_t ctrl, estream_t fp, PKT_public_key *pk); void print_card_key_info (estream_t fp, KBNODE keyblock); void print_key_line (ctrl_t ctrl, estream_t fp, PKT_public_key *pk, int secret); /*-- 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); /*-- 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 (ctrl_t ctrl, estream_t fp, const char *serialno); void card_edit (ctrl_t ctrl, strlist_t commands); gpg_error_t card_generate_subkey (ctrl_t ctrl, kbnode_t pub_keyblock); int card_store_subkey (KBNODE node, int use); #endif #define S2K_DECODE_COUNT(_val) ((16ul + ((_val) & 15)) << (((_val) >> 4) + 6)) /*-- migrate.c --*/ void migrate_secring (ctrl_t ctrl); #endif /*G10_MAIN_H*/ diff --git a/g10/mainproc.c b/g10/mainproc.c index 92da98242..d1d44d774 100644 --- a/g10/mainproc.c +++ b/g10/mainproc.c @@ -1,2557 +1,2623 @@ /* mainproc.c - handle packets * Copyright (C) 1998-2009 Free Software Foundation, Inc. * Copyright (C) 2013-2014 Werner Koch * * This file is part of GnuPG. * * GnuPG is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * GnuPG is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . */ #include #include #include #include #include #include "gpg.h" #include "../common/util.h" #include "packet.h" #include "../common/iobuf.h" #include "options.h" #include "keydb.h" #include "filter.h" #include "main.h" #include "../common/status.h" #include "../common/i18n.h" #include "trustdb.h" #include "keyserver-internal.h" #include "photoid.h" #include "../common/mbox-util.h" #include "call-dirmngr.h" #include "../common/compliance.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 /* An object to build a list of keyid related info. */ struct kidlist_item { struct kidlist_item *next; u32 kid[2]; int pubkey_algo; int reason; }; /* * Object to hold the processing 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 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_t list; /* The current list of packets. */ iobuf_t iobuf; /* Used to get the filename etc. */ int trustletter; /* Temporary usage in list_node. */ ulong symkeys; /* Number of symmetrically encrypted session keys. */ 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; }; /*** Local prototypes. ***/ static int do_proc_packets (ctrl_t ctrl, CTX c, iobuf_t a); static void list_node (CTX c, kbnode_t node); static void proc_tree (CTX c, kbnode_t node); static int literals_seen; /*** Functions. ***/ void reset_literals_seen(void) { literals_seen = 0; } static void release_list( CTX c ) { 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_t 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_t 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 item at the end. */ node = new_kbnode (pkt); add_kbnode (c->list, node); return 1; } -static int +static gpg_error_t symkey_decrypt_seskey (DEK *dek, byte *seskey, size_t slen) { + gpg_error_t err; gcry_cipher_hd_t hd; + unsigned int noncelen, keylen; + enum gcry_cipher_modes ciphermode; + byte ad[4]; + + if (dek->use_aead) + { + err = openpgp_aead_algo_info (dek->use_aead, &ciphermode, &noncelen); + if (err) + return err; + } + else + { + ciphermode = GCRY_CIPHER_MODE_CFB; + noncelen = 0; + } - if(slen < 17 || slen > 33) + /* Check that the session key has a size of 16 to 32 bytes. */ + if ((dek->use_aead && (slen < (noncelen + 16 + 16) + || slen > (noncelen + 32 + 16))) + || (!dek->use_aead && (slen < 17 || slen > 33))) { log_error ( _("weird size for an encrypted session key (%d)\n"), (int)slen); - return GPG_ERR_BAD_KEY; + return gpg_error (GPG_ERR_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]; + err = openpgp_cipher_open (&hd, dek->algo, ciphermode, GCRY_CIPHER_SECURE); + if (!err) + err = gcry_cipher_setkey (hd, dek->key, dek->keylen); + if (!err) + err = gcry_cipher_setiv (hd, noncelen? seskey : NULL, noncelen); + if (err) + goto leave; - if(dek->keylen > DIM(dek->key)) - BUG (); - - memcpy(dek->key, seskey + 1, dek->keylen); + if (dek->use_aead) + { + byte ad[4]; + + ad[0] = (0xc0 | PKT_SYMKEY_ENC); + ad[1] = 5; + ad[2] = dek->algo; + ad[3] = dek->use_aead; + err = gcry_cipher_authenticate (hd, ad, 4); + if (err) + goto leave; + gcry_cipher_final (hd); + keylen = slen - noncelen - 16; + err = gcry_cipher_decrypt (hd, seskey+noncelen, keylen, NULL, 0); + if (err) + goto leave; + err = gcry_cipher_checktag (hd, seskey+noncelen+keylen, 16); + if (err) + goto leave; + /* Now we replace the dek components with the real session key to + * decrypt the contents of the sequencing packet. */ + if (keylen > DIM(dek->key)) + { + err = gpg_error (GPG_ERR_TOO_LARGE); + goto leave; + } + dek->keylen = keylen; + memcpy (dek->key, seskey + noncelen, dek->keylen); + } + else + { + gcry_cipher_decrypt (hd, seskey, slen, NULL, 0 ); + /* Now we replace the dek components with the real session key to + * decrypt the contents of the sequencing packet. */ + keylen = slen-1; + if (keylen > DIM(dek->key)) + { + err = gpg_error (GPG_ERR_TOO_LARGE); + goto leave; + } + dek->algo = seskey[0]; + dek->keylen = keylen; + memcpy (dek->key, seskey + 1, dek->keylen); + } /*log_hexdump( "thekey", dek->key, dek->keylen );*/ - return 0; + leave: + gcry_cipher_close (hd); + return err; } static void proc_symkey_enc (CTX c, PACKET *pkt) { + gpg_error_t err; 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); + const char *a = (enc->aead_algo ? openpgp_aead_algo_name (enc->aead_algo) + /**/ : "CFB"); if (!openpgp_cipher_test_algo (algo)) { if (!opt.quiet) { if (enc->seskeylen) - log_info (_("%s encrypted session key\n"), s ); + log_info (_("%s.%s encrypted session key\n"), s, a ); else - log_info (_("%s encrypted data\n"), s ); + log_info (_("%s.%s encrypted data\n"), s, a ); } } else - log_error (_("encrypted with unknown algorithm %d\n"), algo); + log_error (_("encrypted with unknown algorithm %d.%s\n"), algo, a); 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 (algo, &enc->s2k, 0, 0, NULL, NULL); if (c->dek) { c->dek->symmetric = 1; + c->dek->use_aead = enc->aead_algo; /* 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)) + err = symkey_decrypt_seskey (c->dek, + enc->seskey, enc->seskeylen); + if (err) { + log_info ("decryption of the symmetrically encrypted" + " session key failed: %s\n", + gpg_strerror (err)); + if (gpg_err_code (err) != GPG_ERR_BAD_KEY) + log_fatal ("process terminated to be bug compatible" + " with GnuPG <= 2.2\n"); xfree (c->dek); c->dek = NULL; } } else c->dek->algo_info_printed = 1; } } } leave: c->symkeys++; free_packet (pkt, NULL); } static void proc_pubkey_enc (ctrl_t ctrl, 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 defined 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 identifier. */ 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 (enc->pubkey_algo == PUBKEY_ALGO_ELGAMAL_E || enc->pubkey_algo == PUBKEY_ALGO_ECDH || enc->pubkey_algo == PUBKEY_ALGO_RSA || enc->pubkey_algo == PUBKEY_ALGO_RSA_E || 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 (ctrl, enc, c->dek))) { /* Error: Delete the DEK. */ xfree (c->dek); c->dek = NULL; } } } else result = GPG_ERR_NO_SECKEY; } else result = GPG_ERR_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, NULL); } /* * Print the list of public key encrypted packets which we could * not decrypt. */ static void print_pkenc_list (ctrl_t ctrl, 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 (ctrl, 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 (ctrl, 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 (gpg_err_code (list->reason) == GPG_ERR_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"), gpg_strerror (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->ctrl, c->pkenc_list, 1 ); print_pkenc_list (c->ctrl, 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; STRING2KEY *s2k = NULL; int canceled; 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 SHA-1. */ s2kbuf.mode = 0; s2kbuf.hash_algo = DIGEST_ALGO_SHA1; s2k = &s2kbuf; } log_info (_("assuming %s encrypted data\n"), "IDEA"); } c->dek = passphrase_to_dek (algo, s2k, 0, 0, NULL, &canceled); if (c->dek) c->dek->algo_info_printed = 1; else if (canceled) result = gpg_error (GPG_ERR_CANCELED); else result = gpg_error (GPG_ERR_INV_PASSPHRASE); } } else if (!c->dek) result = GPG_ERR_NO_SECKEY; /* Compute compliance with CO_DE_VS. */ if (!result && is_status_enabled () /* Symmetric encryption and asymmetric encryption voids compliance. */ && (c->symkeys != !!c->pkenc_list ) /* Overriding session key voids compliance. */ && !opt.override_session_key /* Check symmetric cipher. */ && gnupg_cipher_is_compliant (CO_DE_VS, c->dek->algo, GCRY_CIPHER_MODE_CFB)) { struct kidlist_item *i; int compliant = 1; PKT_public_key *pk = xmalloc (sizeof *pk); if ( !(c->pkenc_list || c->symkeys) ) log_debug ("%s: where else did the session key come from?\n", __func__); /* Now check that every key used to encrypt the session key is * compliant. */ for (i = c->pkenc_list; i && compliant; i = i->next) { memset (pk, 0, sizeof *pk); pk->pubkey_algo = i->pubkey_algo; if (get_pubkey (c->ctrl, pk, i->kid) != 0 || ! gnupg_pk_is_compliant (CO_DE_VS, pk->pubkey_algo, pk->pkey, nbits_from_pk (pk), NULL)) compliant = 0; release_public_key_parts (pk); } xfree (pk); if (compliant) write_status_strings (STATUS_DECRYPTION_COMPLIANCE_MODE, gnupg_status_compliance_flag (CO_DE_VS), NULL); } if (!result) result = decrypt_data (c->ctrl, c, pkt->pkt.encrypted, c->dek ); if (result == -1) ; else if (!result && !opt.ignore_mdc_error && !pkt->pkt.encrypted->mdc_method && !pkt->pkt.encrypted->aead_algo && openpgp_cipher_get_algo_blklen (c->dek->algo) != 8 && c->dek->algo != CIPHER_ALGO_TWOFISH) { /* The message has been decrypted but has no MDC despite that a modern cipher (blocklength != 64 bit, except for Twofish) is used and the option to ignore MDC errors is not used: To avoid attacks changing an MDC message to a non-MDC message, we fail here. */ log_error (_("WARNING: message was not integrity protected\n")); if (opt.verbose > 1) log_info ("decryption forced to fail\n"); write_status (STATUS_DECRYPTION_FAILED); } else if (!result || (gpg_err_code (result) == GPG_ERR_BAD_SIGNATURE && !pkt->pkt.encrypted->aead_algo && opt.ignore_mdc_error)) { /* All is fine or for an MDC message the MDC failed but the * --ignore-mdc-error option is active. For compatibility * reasons we issue GOODMDC also for AEAD messages. */ write_status (STATUS_DECRYPTION_OKAY); if (opt.verbose > 1) log_info(_("decryption okay\n")); if (pkt->pkt.encrypted->aead_algo) write_status (STATUS_GOODMDC); else 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 (gpg_err_code (result) == GPG_ERR_BAD_SIGNATURE || gpg_err_code (result) == GPG_ERR_TRUNCATED) { 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 || gpg_err_code (result) == GPG_ERR_CIPHER_ALGO) && *c->dek->s2k_cacheid != '\0') { if (opt.debug) log_debug ("cleared passphrase cached with ID: %s\n", c->dek->s2k_cacheid); passphrase_clear_cache (c->dek->s2k_cacheid); } glo_ctrl.lasterr = result; write_status (STATUS_DECRYPTION_FAILED); log_error (_("decryption failed: %s\n"), gpg_strerror (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, NULL); 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, rc; kbnode_t 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 = 0; for (n=c->list; n; n = n->next ) { if (n->pkt->pkttype == PKT_ONEPASS_SIG) { /* 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); any = 1; } } else if (n->pkt->pkttype == PKT_GPG_CONTROL && n->pkt->pkt.gpg_control->control == CTRLPKT_CLEARSIGN_START) { /* 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) { /* 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 there are the historical answer. */ gcry_md_enable (c->mfx.md, DIGEST_ALGO_RMD160); gcry_md_enable (c->mfx.md, DIGEST_ALGO_SHA1); } 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) { /* It we are in --verify mode, we do not want to output the * signed text. However, if --output is also used we do what * has been requested and write out the signed data. */ rc = handle_plaintext (pt, &c->mfx, (opt.outfp || opt.outfile)? 0 : 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", gpg_strerror (rc)); free_packet (pkt, NULL); 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_t 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_t 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, NULL); c->last_was_session_key = 0; return rc; } /* * Check the signature. If R_PK is not NULL a copy of the public key * used to verify the signature will be stored there, or NULL if not * found. Returns: 0 = valid signature or an error code */ static int do_check_sig (CTX c, kbnode_t node, int *is_selfsig, int *is_expkey, int *is_revkey, PKT_public_key **r_pk) { PKT_signature *sig; gcry_md_hd_t md = NULL; gcry_md_hd_t md2 = NULL; gcry_md_hd_t md_good = NULL; int algo, rc; if (r_pk) *r_pk = NULL; log_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 */ { /* check_signature() 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?"); /* check_signature() 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->ctrl, c->list, node, is_selfsig); } else if (sig->sig_class == 0x20) { log_error (_("standalone revocation - " "use \"gpg --import\" to apply\n")); return GPG_ERR_NOT_PROCESSED; } else { log_error ("invalid root packet for sigclass %02x\n", sig->sig_class); return GPG_ERR_SIG_CLASS; } } else return GPG_ERR_SIG_CLASS; /* We only get here if we are checking the signature of a binary (0x00) or text document (0x01). */ rc = check_signature2 (c->ctrl, sig, md, NULL, is_expkey, is_revkey, r_pk); if (! rc) md_good = md; else if (gpg_err_code (rc) == GPG_ERR_BAD_SIGNATURE && md2) { PKT_public_key *pk2; rc = check_signature2 (c->ctrl, sig, md2, NULL, is_expkey, is_revkey, r_pk? &pk2 : NULL); if (!rc) { md_good = md2; if (r_pk) { free_public_key (*r_pk); *r_pk = pk2; } } } if (md_good) { unsigned char *buffer = gcry_md_read (md_good, sig->digest_algo); sig->digest_len = gcry_md_get_algo_dlen (map_md_openpgp_to_gcry (algo)); memcpy (sig->digest, buffer, sig->digest_len); } 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) { es_printf ("ERROR: unexpected packet type %d", pkt->pkttype ); return; } if (opt.with_colons) { if (pkt->pkt.user_id->attrib_data) es_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 keyblock in a user friendly way */ static void list_node (CTX c, kbnode_t node) { if (!node) ; else if (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 (pk->flags.primary) c->trustletter = (opt.fast_list_mode ? 0 : get_validity_info (c->ctrl, node->pkt->pkttype == PKT_PUBLIC_KEY ? node : NULL, pk, NULL)); es_printf ("%s:", pk->flags.primary? "pub":"sub" ); if (c->trustletter) es_putc (c->trustletter, es_stdout); es_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 (pk->flags.primary && !opt.fast_list_mode) es_putc (get_ownertrust_info (c->ctrl, pk, 1), es_stdout); es_putc (':', es_stdout); es_putc ('\n', es_stdout); } else { print_key_line (c->ctrl, es_stdout, pk, 0); } if (opt.keyid_format == KF_NONE && !opt.with_colons) ; /* Already printed. */ else if ((pk->flags.primary && opt.fingerprint) || opt.fingerprint > 1) print_fingerprint (c->ctrl, NULL, pk, 0); if (pk->flags.primary) { int kl = opt.keyid_format == KF_NONE? 0 : keystrlen (); /* Now list all userids with their signatures. */ for (node = node->next; node; node = node->next) { if (node->pkt->pkttype == PKT_SIGNATURE) { list_node (c, node ); } else if (node->pkt->pkttype == PKT_USER_ID) { if (opt.with_colons) es_printf ("%s:::::::::", node->pkt->pkt.user_id->attrib_data?"uat":"uid"); else es_printf ("uid%*s", kl + (opt.legacy_list_mode? 9:11), "" ); print_userid (node->pkt); if (opt.with_colons) es_putc (':', es_stdout); es_putc ('\n', es_stdout); } else if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY) { list_node(c, node ); } } } } else if (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 function to turn a secret key packet into a public key one and use that here. */ } 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) es_fputs ("rev", es_stdout); else es_fputs ("sig", es_stdout); if (opt.check_sigs) { fflush (stdout); rc2 = do_check_sig (c, node, &is_selfsig, NULL, 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) { es_putc (':', es_stdout); if (sigrc != ' ') es_putc (sigrc, es_stdout); es_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) es_printf ("%d %d",sig->trust_depth,sig->trust_value); es_putc (':', es_stdout); if (sig->trust_regexp) es_write_sanitized (es_stdout, sig->trust_regexp, strlen (sig->trust_regexp), ":", NULL); es_putc (':', es_stdout); } else es_printf ("%c %s %s ", sigrc, keystr (sig->keyid), datestr_from_sig(sig)); if (sigrc == '%') es_printf ("[%s] ", gpg_strerror (rc2) ); else if (sigrc == '?') ; else if (is_selfsig) { if (opt.with_colons) es_putc (':', es_stdout); es_fputs (sig->sig_class == 0x18? "[keybind]":"[selfsig]", es_stdout); if (opt.with_colons) es_putc (':', es_stdout); } else if (!opt.fast_list_mode) { p = get_user_id (c->ctrl, sig->keyid, &n); es_write_sanitized (es_stdout, p, n, opt.with_colons?":":NULL, NULL ); xfree (p); } if (opt.with_colons) es_printf (":%02x%c:", sig->sig_class, sig->flags.exportable?'x':'l'); es_putc ('\n', es_stdout); } else log_error ("invalid node with packet of type %d\n", node->pkt->pkttype); } int proc_packets (ctrl_t ctrl, void *anchor, iobuf_t a ) { int rc; CTX c = xmalloc_clear (sizeof *c); c->ctrl = ctrl; c->anchor = anchor; rc = do_proc_packets (ctrl, c, a); xfree (c); return rc; } int proc_signature_packets (ctrl_t ctrl, void *anchor, iobuf_t 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 (ctrl, 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_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_signature_packets_by_fd (ctrl_t ctrl, void *anchor, iobuf_t 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 (ctrl, 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_t a ) { CTX c = xmalloc_clear (sizeof *c); int rc; c->ctrl = ctrl; c->anchor = anchor; c->encrypt_only = 1; rc = do_proc_packets (ctrl, 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 (ctrl_t ctrl, CTX c, iobuf_t a) { PACKET *pkt; struct parse_packet_ctx_s parsectx; 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); init_parse_packet (&parsectx, a); while ((rc=parse_packet (&parsectx, pkt)) != -1) { any_data = 1; if (rc) { free_packet (pkt, &parsectx); /* 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 == 0) break; continue; } newpkt = -1; if (opt.list_packets) { switch (pkt->pkttype) { case PKT_PUBKEY_ENC: proc_pubkey_enc (ctrl, c, pkt); break; case PKT_SYMKEY_ENC: proc_symkey_enc (c, pkt); break; case PKT_ENCRYPTED: case PKT_ENCRYPTED_MDC: case PKT_ENCRYPTED_AEAD: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: case PKT_ENCRYPTED_AEAD: write_status_text( STATUS_UNEXPECTED, "0" ); rc = GPG_ERR_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 = GPG_ERR_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 (ctrl, c, pkt); break; case PKT_ENCRYPTED: case PKT_ENCRYPTED_MDC: case PKT_ENCRYPTED_AEAD: 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 (ctrl, c, pkt); break; case PKT_SYMKEY_ENC: proc_symkey_enc (c, pkt); break; case PKT_ENCRYPTED: case PKT_ENCRYPTED_MDC: case PKT_ENCRYPTED_AEAD: 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 between 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, &parsectx); } if (rc == GPG_ERR_INV_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, &parsectx); deinit_parse_packet (&parsectx); 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 (CTX c, PKT_signature *sig) { if (!sig->flags.pka_tried) { log_assert (!sig->pka_info); sig->flags.pka_tried = 1; sig->pka_info = get_pka_address (sig); if (sig->pka_info) { char *url; unsigned char *fpr; size_t fprlen; if (!gpg_dirmngr_get_pka (c->ctrl, sig->pka_info->email, &fpr, &fprlen, &url)) { if (fpr && fprlen == sizeof sig->pka_info->fpr) { memcpy (sig->pka_info->fpr, fpr, fprlen); if (url) { sig->pka_info->valid = 1; if (!*url) xfree (url); else sig->pka_info->uri = url; url = NULL; } } xfree (fpr); xfree (url); } } } return sig->pka_info? sig->pka_info->uri : NULL; } /* Return true if the AKL has the WKD method specified. */ static int akl_has_wkd_method (void) { struct akl *akl; for (akl = opt.auto_key_locate; akl; akl = akl->next) if (akl->type == AKL_WKD) return 1; return 0; } /* Return the ISSUER fingerprint string in human readbale format if * available. Caller must release the string. */ static char * issuer_fpr_string (PKT_signature *sig) { const byte *p; size_t n; p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_ISSUER_FPR, &n); if (p && n == 21 && p[0] == 4) return bin2hex (p+1, n-1, NULL); return NULL; } static void print_good_bad_signature (int statno, const char *keyid_str, kbnode_t un, PKT_signature *sig, int rc) { char *p; 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); xfree (p); } static int check_sig_and_print (CTX c, kbnode_t node) { PKT_signature *sig = node->pkt->pkt.signature; const char *astr; int rc; int is_expkey = 0; int is_revkey = 0; char *issuer_fpr; PKT_public_key *pk = NULL; /* The public key for the signature or NULL. */ int tried_ks_by_fpr; 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_t n; int n_onepass, n_sig; /* log_debug ("checking signature packet composition\n"); */ /* dump_kbnode (c->list); */ n = c->list; log_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; } } if (sig->signers_uid) write_status_buffer (STATUS_NEWSIG, sig->signers_uid, strlen (sig->signers_uid), 0); else write_status_text (STATUS_NEWSIG, NULL); astr = openpgp_pk_algo_name ( sig->pubkey_algo ); if ((issuer_fpr = issuer_fpr_string (sig))) { log_info (_("Signature made %s\n"), asctimestamp(sig->timestamp)); log_info (_(" using %s key %s\n"), astr? astr: "?", issuer_fpr); xfree (issuer_fpr); } else if (!keystrlen () || keystrlen () > 8) { log_info (_("Signature made %s\n"), asctimestamp(sig->timestamp)); log_info (_(" using %s key %s\n"), astr? astr: "?", keystr(sig->keyid)); } else /* Legacy format. */ log_info (_("Signature made %s using %s key ID %s\n"), asctimestamp(sig->timestamp), astr? astr: "?", keystr(sig->keyid)); /* In verbose mode print the signers UID. */ if (sig->signers_uid) log_info (_(" issuer \"%s\"\n"), sig->signers_uid); rc = do_check_sig (c, node, NULL, &is_expkey, &is_revkey, &pk); /* If the key isn't found, check for a preferred keyserver. */ if (gpg_err_code (rc) == GPG_ERR_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; free_public_key (pk); pk = NULL; glo_ctrl.in_auto_key_retrieve++; res = keyserver_import_keyid (c->ctrl, sig->keyid,spec, 1); glo_ctrl.in_auto_key_retrieve--; if (!res) rc = do_check_sig (c, node, NULL, &is_expkey, &is_revkey, &pk); free_keyserver_spec (spec); if (!rc) break; } } } } /* If the avove methods didn't work, our next try is to use the URI * from a DNS PKA record. */ if (gpg_err_code (rc) == GPG_ERR_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 (c, 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); if (spec) { free_public_key (pk); pk = NULL; glo_ctrl.in_auto_key_retrieve++; res = keyserver_import_keyid (c->ctrl, sig->keyid, spec, 1); glo_ctrl.in_auto_key_retrieve--; free_keyserver_spec (spec); if (!res) rc = do_check_sig (c, node, NULL, &is_expkey, &is_revkey, &pk); } } } /* If the above methods didn't work, our next try is to locate * the key via its fingerprint from a keyserver. This requires * that the signers fingerprint is encoded in the signature. We * favor this over the WKD method (to be tried next), because an * arbitrary keyserver is less subject to web bug like monitoring. */ tried_ks_by_fpr = 0; if (gpg_err_code (rc) == GPG_ERR_NO_PUBKEY && (opt.keyserver_options.options&KEYSERVER_AUTO_KEY_RETRIEVE) && keyserver_any_configured (c->ctrl)) { int res; const byte *p; size_t n; p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_ISSUER_FPR, &n); if (p && n == 21 && p[0] == 4) { /* v4 packet with a SHA-1 fingerprint. */ free_public_key (pk); pk = NULL; glo_ctrl.in_auto_key_retrieve++; res = keyserver_import_fprint (c->ctrl, p+1, n-1, opt.keyserver, 1); tried_ks_by_fpr = 1; glo_ctrl.in_auto_key_retrieve--; if (!res) rc = do_check_sig (c, node, NULL, &is_expkey, &is_revkey, &pk); } } /* If the above methods didn't work, our next try is to retrieve the * key from the WKD. */ if (gpg_err_code (rc) == GPG_ERR_NO_PUBKEY && (opt.keyserver_options.options & KEYSERVER_AUTO_KEY_RETRIEVE) && !opt.flags.disable_signer_uid && akl_has_wkd_method () && sig->signers_uid) { int res; free_public_key (pk); pk = NULL; glo_ctrl.in_auto_key_retrieve++; res = keyserver_import_wkd (c->ctrl, sig->signers_uid, 1, NULL, NULL); glo_ctrl.in_auto_key_retrieve--; /* Fixme: If the fingerprint is embedded in the signature, * compare it to the fingerprint of the returned key. */ if (!res) rc = do_check_sig (c, node, NULL, &is_expkey, &is_revkey, &pk); } /* If the above methods did't work, our next try is to use a * keyserver. */ if (gpg_err_code (rc) == GPG_ERR_NO_PUBKEY && (opt.keyserver_options.options&KEYSERVER_AUTO_KEY_RETRIEVE) && !tried_ks_by_fpr && keyserver_any_configured (c->ctrl)) { int res; free_public_key (pk); pk = NULL; glo_ctrl.in_auto_key_retrieve++; res = keyserver_import_keyid (c->ctrl, sig->keyid, opt.keyserver, 1); glo_ctrl.in_auto_key_retrieve--; if (!res) rc = do_check_sig (c, node, NULL, &is_expkey, &is_revkey, &pk); } if (!rc || gpg_err_code (rc) == GPG_ERR_BAD_SIGNATURE) { kbnode_t un, keyblock; int count = 0; int statno; char keyid_str[50]; PKT_public_key *mainpk = 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; /* FIXME: We should have the public key in PK and thus the * keyblock has already been fetched. Thus we could use the * fingerprint or PK itself to lookup the entire keyblock. That * would best be done with a cache. */ keyblock = get_pubkeyblock (c->ctrl, sig->keyid); snprintf (keyid_str, sizeof keyid_str, "%08lX%08lX [uncertain] ", (ulong)sig->keyid[0], (ulong)sig->keyid[1]); /* Find and print the primary user ID along with the "Good|Expired|Bad signature" line. */ for (un=keyblock; un; un = un->next) { int valid; if (un->pkt->pkttype==PKT_PUBLIC_KEY) { mainpk = 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->flags.revoked) continue; if (un->pkt->pkt.user_id->flags.expired) continue; if (!un->pkt->pkt.user_id->flags.primary) continue; /* We want the textual primary user ID here */ if (un->pkt->pkt.user_id->attrib_data) continue; log_assert (mainpk); /* Since this is just informational, don't actually ask the user to update any trust information. (Note: we register the signature later.) Because print_good_bad_signature does not print a LF we need to compute the validity before calling that function. */ if ((opt.verify_options & VERIFY_SHOW_UID_VALIDITY)) valid = get_validity (c->ctrl, keyblock, mainpk, un->pkt->pkt.user_id, NULL, 0); else valid = 0; /* Not used. */ keyid_str[17] = 0; /* cut off the "[uncertain]" part */ print_good_bad_signature (statno, keyid_str, un, sig, rc); if ((opt.verify_options & VERIFY_SHOW_UID_VALIDITY)) log_printf (" [%s]\n",trust_value_to_string(valid)); else log_printf ("\n"); count++; } log_assert (mainpk); /* In case we did not found a valid textual userid above we print the first user id packet or a "[?]" instead along with the "Good|Expired|Bad signature" line. */ if (!count) { /* 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 */ print_good_bad_signature (statno, keyid_str, un, sig, rc); 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->flags.revoked || un->pkt->pkt.user_id->flags.expired) && !(opt.verify_options & VERIFY_SHOW_UNUSABLE_UIDS)) continue; /* Skip textual primary user ids which we printed above. */ if (un->pkt->pkt.user_id->flags.primary && !un->pkt->pkt.user_id->attrib_data ) continue; /* If this user id has attribute data, print that. */ if (un->pkt->pkt.user_id->attrib_data) { dump_attribs (un->pkt->pkt.user_id, mainpk); if (opt.verify_options&VERIFY_SHOW_PHOTOS) show_photos (c->ctrl, un->pkt->pkt.user_id->attribs, un->pkt->pkt.user_id->numattribs, mainpk ,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->flags.revoked) valid = _("revoked"); else if (un->pkt->pkt.user_id->flags.expired) valid = _("expired"); else /* Since this is just informational, don't actually ask the user to update any trust information. */ valid = (trust_value_to_string (get_validity (c->ctrl, keyblock, mainpk, un->pkt->pkt.user_id, NULL, 0))); log_printf (" [%s]\n",valid); } else log_printf ("\n"); } } /* For good signatures print notation data. */ 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); } /* For good signatures print the VALIDSIG status line. */ if (!rc && is_status_enabled () && pk) { char pkhex[MAX_FINGERPRINT_LEN*2+1]; char mainpkhex[MAX_FINGERPRINT_LEN*2+1]; hexfingerprint (pk, pkhex, sizeof pkhex); hexfingerprint (mainpk, mainpkhex, sizeof mainpkhex); /* TODO: Replace the reserved '0' in the field below with bits for status flags (policy url, notation, etc.). */ write_status_printf (STATUS_VALIDSIG, "%s %s %lu %lu %d 0 %d %d %02X %s", pkhex, strtimestamp (sig->timestamp), (ulong)sig->timestamp, (ulong)sig->expiredate, sig->version, sig->pubkey_algo, sig->digest_algo, sig->sig_class, mainpkhex); } /* Print compliance warning for Good signatures. */ if (!rc && pk && !opt.quiet && !gnupg_pk_is_compliant (opt.compliance, pk->pubkey_algo, pk->pkey, nbits_from_pk (pk), NULL)) { log_info (_("WARNING: This key is not suitable for signing" " in %s mode\n"), gnupg_compliance_option_string (opt.compliance)); } /* For good signatures compute and print the trust information. Note that in the Tofu trust model this may ask the user on how to resolve a conflict. */ if (!rc) { if ((opt.verify_options & VERIFY_PKA_LOOKUPS)) pka_uri_from_sig (c, sig); /* Make sure PKA info is available. */ rc = check_signatures_trust (c->ctrl, sig); } /* Print extra information about the signature. */ if (sig->flags.expired) { log_info (_("Signature expired %s\n"), asctimestamp(sig->expiredate)); rc = GPG_ERR_GENERAL; /* Need a better error here? */ } else if (sig->expiredate) log_info (_("Signature expires %s\n"), asctimestamp(sig->expiredate)); if (opt.verbose) { char pkstrbuf[PUBKEY_STRING_SIZE]; if (pk) pubkey_string (pk, pkstrbuf, sizeof pkstrbuf); else *pkstrbuf = 0; log_info (_("%s signature, digest algorithm %s%s%s\n"), sig->sig_class==0x00?_("binary"): sig->sig_class==0x01?_("textmode"):_("unknown"), gcry_md_algo_name (sig->digest_algo), *pkstrbuf?_(", key algorithm "):"", pkstrbuf); } /* Print final warnings. */ if (!rc && !c->signed_data.used) { /* Signature is basically good but we test whether the deprecated command gpg --verify FILE.sig was used instead of gpg --verify FILE.sig FILE to verify a detached signature. If we figure out that a data file with a matching name exists, we print a warning. The problem is that the first form would also verify a standard signature. This behavior could be used to create a made up .sig file for a tarball by creating a standard signature from a valid detached signature packet (for example from a signed git tag). Then replace the sig file on the FTP server along with a changed tarball. Using the first form the verify command would correctly verify the signature but don't even consider the tarball. */ kbnode_t n; char *dfile; dfile = get_matching_datafile (c->sigfilename); if (dfile) { for (n = c->list; n; n = n->next) if (n->pkt->pkttype != PKT_SIGNATURE) break; if (n) { /* Not only signature packets in the tree thus this is not a detached signature. */ log_info (_("WARNING: not a detached signature; " "file '%s' was NOT verified!\n"), dfile); } xfree (dfile); } } /* Compute compliance with CO_DE_VS. */ if (pk && is_status_enabled () && gnupg_pk_is_compliant (CO_DE_VS, pk->pubkey_algo, pk->pkey, nbits_from_pk (pk), NULL) && gnupg_digest_is_compliant (CO_DE_VS, sig->digest_algo)) write_status_strings (STATUS_VERIFICATION_COMPLIANCE_MODE, gnupg_status_compliance_flag (CO_DE_VS), NULL); free_public_key (pk); pk = NULL; release_kbnode( keyblock ); if (rc) g10_errors_seen = 1; if (opt.batch && rc) g10_exit (1); } else { char buf[50]; snprintf (buf, sizeof 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, gpg_err_code (rc)); write_status_text (STATUS_ERRSIG, buf); if (gpg_err_code (rc) == GPG_ERR_NO_PUBKEY) { buf[16] = 0; write_status_text (STATUS_NO_PUBKEY, buf); } if (gpg_err_code (rc) != GPG_ERR_NOT_PROCESSED) log_error (_("Can't check signature: %s\n"), gpg_strerror (rc)); } return rc; } /* * Process the tree which starts at node */ static void proc_tree (CTX c, kbnode_t node) { kbnode_t n1; int rc; if (opt.list_packets || opt.list_only) return; /* We must skip our special plaintext marker packets here because they may be the root packet. These packets are only used in additional 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 (c->ctrl, node); list_node (c, node); } else if (node->pkt->pkttype == PKT_SECRET_KEY) { merge_keys_and_selfsig (c->ctrl, 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. */ rc = gcry_md_open (&c->mfx.md, 0, 0); if (rc) goto hash_err; /* 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); } hash_err: if (rc) { log_error ("can't hash datafile: %s\n", gpg_strerror (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 (we'd pretty much have to run a * different hash context for each), but if they are all * the same and it is detached signature, we make an * exception. Note that the old code also disallowed * multiple signatures if the digest algorithms are * different. We softened this restriction only for * detached signatures, to be on the safe side. */ if (n1->pkt->pkt.signature->sig_class != class || (c->any.data && 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); rc = gcry_md_open (&c->mfx.md, sig->digest_algo, 0); if (rc) goto detached_hash_err; if (multiple_ok) { /* If we have and want to handle multiple signatures we * need to enable all hash algorithms for the context. */ for (n1 = node; (n1 = find_next_kbnode (n1, PKT_SIGNATURE)); ) if (!openpgp_md_test_algo (n1->pkt->pkt.signature->digest_algo)) gcry_md_enable (c->mfx.md, map_md_openpgp_to_gcry (n1->pkt->pkt.signature->digest_algo)); } if (RFC2440 || RFC4880) ; /* Strict RFC mode. */ else if (sig->digest_algo == DIGEST_ALGO_SHA1 && sig->pubkey_algo == PUBKEY_ALGO_DSA && sig->sig_class == 0x01) { /* Enable a workaround for a pgp5 bug when the detached * signature has been created in textmode. Note that we * do not implement this for multiple signatures with * different hash algorithms. */ rc = gcry_md_open (&c->mfx.md2, sig->digest_algo, 0); if (rc) goto detached_hash_err; } /* Here we used to have another hack to work around a pgp * 2 bug: It worked by not using the textmode for detached * signatures; this would let the first signature check * (on md) fail but the second one (on md2), which adds an * extra CR would then have produced the "correct" hash. * This is very, very ugly hack but it may haved help in * some cases (and break others). * c->mfx.md2? 0 :(sig->sig_class == 0x01) */ 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)); } detached_hash_err: if (rc) { log_error ("can't hash datafile: %s\n", gpg_strerror (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/packet.h b/g10/packet.h index 4d155746e..4f4569f66 100644 --- a/g10/packet.h +++ b/g10/packet.h @@ -1,925 +1,928 @@ /* packet.h - OpenPGP packet definitions * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, * 2007 Free Software Foundation, Inc. * Copyright (C) 2015 g10 Code GmbH * * This file is part of GnuPG. * * GnuPG is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * GnuPG is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . */ #ifndef G10_PACKET_H #define G10_PACKET_H #include "../common/types.h" #include "../common/iobuf.h" #include "../common/strlist.h" #include "dek.h" #include "filter.h" #include "../common/openpgpdefs.h" #include "../common/userids.h" #include "../common/util.h" #define DEBUG_PARSE_PACKET 1 /* Constants to allocate static MPI arrays. */ #define PUBKEY_MAX_NPKEY 5 #define PUBKEY_MAX_NSKEY 7 #define PUBKEY_MAX_NSIG 2 #define PUBKEY_MAX_NENC 2 /* Usage flags */ #define PUBKEY_USAGE_SIG GCRY_PK_USAGE_SIGN /* Good for signatures. */ #define PUBKEY_USAGE_ENC GCRY_PK_USAGE_ENCR /* Good for encryption. */ #define PUBKEY_USAGE_CERT GCRY_PK_USAGE_CERT /* Also good to certify keys.*/ #define PUBKEY_USAGE_AUTH GCRY_PK_USAGE_AUTH /* Good for authentication. */ #define PUBKEY_USAGE_UNKNOWN GCRY_PK_USAGE_UNKN /* Unknown usage flag. */ #define PUBKEY_USAGE_NONE 256 /* No usage given. */ #if (GCRY_PK_USAGE_SIGN | GCRY_PK_USAGE_ENCR | GCRY_PK_USAGE_CERT \ | GCRY_PK_USAGE_AUTH | GCRY_PK_USAGE_UNKN) >= 256 # error Please choose another value for PUBKEY_USAGE_NONE #endif /* Helper macros. */ #define is_RSA(a) ((a)==PUBKEY_ALGO_RSA || (a)==PUBKEY_ALGO_RSA_E \ || (a)==PUBKEY_ALGO_RSA_S ) #define is_ELGAMAL(a) ((a)==PUBKEY_ALGO_ELGAMAL_E) #define is_DSA(a) ((a)==PUBKEY_ALGO_DSA) /* A pointer to the packet object. */ typedef struct packet_struct PACKET; /* PKT_GPG_CONTROL types */ typedef enum { CTRLPKT_CLEARSIGN_START = 1, CTRLPKT_PIPEMODE = 2, CTRLPKT_PLAINTEXT_MARK =3 } ctrlpkttype_t; typedef enum { PREFTYPE_NONE = 0, PREFTYPE_SYM = 1, PREFTYPE_HASH = 2, PREFTYPE_ZIP = 3, PREFTYPE_AEAD = 4 } preftype_t; typedef struct { byte type; byte value; } prefitem_t; /* A string-to-key specifier as defined in RFC 4880, Section 3.7. */ typedef struct { int mode; /* Must be an integer due to the GNU modes 1001 et al. */ byte hash_algo; byte salt[8]; /* The *coded* (i.e., the serialized version) iteration count. */ u32 count; } STRING2KEY; /* A symmetric-key encrypted session key packet as defined in RFC 4880, Section 5.3. All fields are serialized. */ typedef struct { - /* RFC 4880: this must be 4. */ + /* We support version 4 (rfc4880) and 5 (rfc4880bis). */ byte version; - /* The cipher algorithm used to encrypt the session key. (This may - be different from the algorithm that is used to encrypt the SED - packet.) */ + /* The cipher algorithm used to encrypt the session key. Note that + * this may be different from the algorithm that is used to encrypt + * bulk data. */ byte cipher_algo; + /* The AEAD algorithm or 0 for CFB encryption. */ + byte aead_algo; /* The string-to-key specifier. */ STRING2KEY s2k; /* The length of SESKEY in bytes or 0 if this packet does not encrypt a session key. (In the latter case, the results of the S2K function on the password is the session key. See RFC 4880, Section 5.3.) */ byte seskeylen; - /* The session key as encrypted by the S2K specifier. */ + /* The session key as encrypted by the S2K specifier. For AEAD this + * includes the nonce and the authentication tag. */ byte seskey[1]; } PKT_symkey_enc; /* A public-key encrypted session key packet as defined in RFC 4880, Section 5.1. All fields are serialized. */ typedef struct { /* The 64-bit keyid. */ u32 keyid[2]; /* The packet's version. Currently, only version 3 is defined. */ byte version; /* The algorithm used for the public key encryption scheme. */ byte pubkey_algo; /* Whether to hide the key id. This value is not directly serialized. */ byte throw_keyid; /* The session key. */ gcry_mpi_t data[PUBKEY_MAX_NENC]; } PKT_pubkey_enc; /* A one-pass signature packet as defined in RFC 4880, Section 5.4. All fields are serialized. */ typedef struct { u32 keyid[2]; /* The 64-bit keyid */ /* The signature's classification (RFC 4880, Section 5.2.1). */ byte sig_class; byte digest_algo; /* algorithm used for digest */ byte pubkey_algo; /* algorithm used for public key scheme */ /* A message can be signed by multiple keys. In this case, there are n one-pass signature packets before the message to sign and n signatures packets after the message. It is conceivable that someone wants to not only sign the message, but all of the signatures. Now we need to distinguish between signing the message and signing the message plus the surrounding signatures. This is the point of this flag. If set, it means: I sign all of the data starting at the next packet. */ byte last; } PKT_onepass_sig; /* A v4 OpenPGP signature has a hashed and unhashed area containing co-called signature subpackets (RFC 4880, Section 5.2.3). These areas are described by this data structure. Use enum_sig_subpkt to parse this area. */ typedef struct { size_t size; /* allocated */ size_t len; /* used (serialized) */ byte data[1]; /* the serialized subpackes (serialized) */ } subpktarea_t; /* The in-memory representation of a designated revoker signature subpacket (RFC 4880, Section 5.2.3.15). */ struct revocation_key { /* A bit field. 0x80 must be set. 0x40 means this information is sensitive (and should not be uploaded to a keyserver by default). */ byte class; /* The public-key algorithm ID. */ byte algid; /* The fingerprint of the authorized key. */ byte fpr[MAX_FINGERPRINT_LEN]; }; /* Object to keep information about a PKA DNS record. */ typedef struct { int valid; /* An actual PKA record exists for EMAIL. */ int checked; /* Set to true if the FPR has been checked against the actual key. */ char *uri; /* Malloced string with the URI. NULL if the URI is not available.*/ unsigned char fpr[20]; /* The fingerprint as stored in the PKA RR. */ char email[1];/* The email address from the notation data. */ } pka_info_t; /* A signature packet (RFC 4880, Section 5.2). Only a subset of these fields are directly serialized (these are marked as such); the rest are read from the subpackets, which are not synthesized when serializing this data structure (i.e., when using build_packet()). Instead, the subpackets must be created by hand. */ typedef struct { struct { unsigned checked:1; /* Signature has been checked. */ unsigned valid:1; /* Signature is good (if checked is set). */ unsigned chosen_selfsig:1; /* A selfsig that is the chosen one. */ unsigned unknown_critical:1; unsigned exportable:1; unsigned revocable:1; unsigned policy_url:1; /* At least one policy URL is present */ unsigned notation:1; /* At least one notation is present */ unsigned pref_ks:1; /* At least one preferred keyserver is present */ unsigned expired:1; unsigned pka_tried:1; /* Set if we tried to retrieve the PKA record. */ } flags; /* The key that allegedly generated this signature. (Directly serialized in v3 sigs; for v4 sigs, this must be explicitly added as an issuer subpacket (5.2.3.5.) */ u32 keyid[2]; /* When the signature was made (seconds since the Epoch). (Directly serialized in v3 sigs; for v4 sigs, this must be explicitly added as a signature creation time subpacket (5.2.3.4).) */ u32 timestamp; u32 expiredate; /* Expires at this date or 0 if not at all. */ /* The serialization format used / to use. If 0, then defaults to version 3. (Serialized.) */ byte version; /* The signature type. (See RFC 4880, Section 5.2.1.) */ byte sig_class; /* Algorithm used for public key scheme (e.g., PUBKEY_ALGO_RSA). (Serialized.) */ byte pubkey_algo; /* Algorithm used for digest (e.g., DIGEST_ALGO_SHA1). (Serialized.) */ byte digest_algo; byte trust_depth; byte trust_value; const byte *trust_regexp; struct revocation_key *revkey; int numrevkeys; pka_info_t *pka_info; /* Malloced PKA data or NULL if not available. See also flags.pka_tried. */ char *signers_uid; /* Malloced value of the SIGNERS_UID * subpacket or NULL. This string has * already been sanitized. */ subpktarea_t *hashed; /* All subpackets with hashed data (v4 only). */ subpktarea_t *unhashed; /* Ditto for unhashed data. */ /* First 2 bytes of the digest. (Serialized. Note: this is not automatically filled in when serializing a signature!) */ byte digest_start[2]; /* The signature. (Serialized.) */ gcry_mpi_t data[PUBKEY_MAX_NSIG]; /* The message digest and its length (in bytes). Note the maximum digest length is 512 bits (64 bytes). If DIGEST_LEN is 0, then the digest's value has not been saved here. */ byte digest[512 / 8]; int digest_len; } PKT_signature; #define ATTRIB_IMAGE 1 /* This is the cooked form of attributes. */ struct user_attribute { byte type; const byte *data; u32 len; }; /* A user id (RFC 4880, Section 5.11) or a user attribute packet (RFC 4880, Section 5.12). Only a subset of these fields are directly serialized (these are marked as such); the rest are read from the self-signatures in merge_keys_and_selfsig()). */ typedef struct { int ref; /* reference counter */ /* The length of NAME. */ int len; struct user_attribute *attribs; int numattribs; /* If this is not NULL, the packet is a user attribute rather than a user id (See RFC 4880 5.12). (Serialized.) */ byte *attrib_data; /* The length of ATTRIB_DATA. */ unsigned long attrib_len; byte *namehash; int help_key_usage; u32 help_key_expire; int help_full_count; int help_marginal_count; u32 expiredate; /* expires at this date or 0 if not at all */ prefitem_t *prefs; /* list of preferences (may be NULL)*/ u32 created; /* according to the self-signature */ u32 keyupdate; /* From the ring trust packet. */ char *updateurl; /* NULL or the URL of the last update origin. */ byte keyorg; /* From the ring trust packet. */ byte selfsigversion; struct { unsigned int mdc:1; unsigned int aead:1; unsigned int ks_modify:1; unsigned int compacted:1; unsigned int primary:2; /* 2 if set via the primary flag, 1 if calculated */ unsigned int revoked:1; unsigned int expired:1; } flags; char *mbox; /* NULL or the result of mailbox_from_userid. */ /* The text contained in the user id packet, which is normally the * name and email address of the key holder (See RFC 4880 5.11). * (Serialized.). For convenience an extra Nul is always appended. */ char name[1]; } PKT_user_id; struct revoke_info { /* revoked at this date */ u32 date; /* the keyid of the revoking key (selfsig or designated revoker) */ u32 keyid[2]; /* the algo of the revoking key */ byte algo; }; /* Information pertaining to secret keys. */ struct seckey_info { int is_protected:1; /* The secret info is protected and must */ /* be decrypted before use, the protected */ /* MPIs are simply (void*) pointers to memory */ /* and should never be passed to a mpi_xxx() */ int sha1chk:1; /* SHA1 is used instead of a 16 bit checksum */ u16 csum; /* Checksum for old protection modes. */ byte algo; /* Cipher used to protect the secret information. */ STRING2KEY s2k; /* S2K parameter. */ byte ivlen; /* Used length of the IV. */ byte iv[16]; /* Initialization vector for CFB mode. */ }; /**************** * The in-memory representation of a public key (RFC 4880, Section * 5.5). Note: this structure contains significantly more information * than is contained in an OpenPGP public key packet. This * information is derived from the self-signed signatures (by * merge_keys_and_selfsig()) and is ignored when serializing the * packet. The fields that are actually written out when serializing * this packet are marked as accordingly. * * We assume that secret keys have the same number of parameters as * the public key and that the public parameters are the first items * in the PKEY array. Thus NPKEY is always less than NSKEY and it is * possible to compare the secret and public keys by comparing the * first NPKEY elements of the PKEY array. Note that since GnuPG 2.1 * we don't use secret keys anymore directly because they are managed * by gpg-agent. However for parsing OpenPGP key files we need a way * to temporary store those secret keys. We do this by putting them * into the public key structure and extending the PKEY field to NSKEY * elements; the extra secret key information are stored in the * SECKEY_INFO field. */ typedef struct { /* When the key was created. (Serialized.) */ u32 timestamp; u32 expiredate; /* expires at this date or 0 if not at all */ u32 max_expiredate; /* must not expire past this date */ struct revoke_info revoked; /* An OpenPGP packet consists of a header and a body. This is the size of the header. If this is 0, an appropriate size is automatically chosen based on the size of the body. (Serialized.) */ byte hdrbytes; /* The serialization format. If 0, the default version (4) is used when serializing. (Serialized.) */ byte version; byte selfsigversion; /* highest version of all of the self-sigs */ /* The public key algorithm. (Serialized.) */ byte pubkey_algo; byte pubkey_usage; /* for now only used to pass it to getkey() */ byte req_usage; /* hack to pass a request to getkey() */ u32 has_expired; /* set to the expiration date if expired */ /* keyid of the primary key. Never access this value directly. Instead, use pk_main_keyid(). */ u32 main_keyid[2]; /* keyid of this key. Never access this value directly! Instead, use pk_keyid(). */ u32 keyid[2]; prefitem_t *prefs; /* list of preferences (may be NULL) */ struct { unsigned int mdc:1; /* MDC feature set. */ unsigned int aead:1; /* AEAD feature set. */ unsigned int disabled_valid:1;/* The next flag is valid. */ unsigned int disabled:1; /* The key has been disabled. */ unsigned int primary:1; /* This is a primary key. */ unsigned int revoked:2; /* Key has been revoked. 1 = revoked by the owner 2 = revoked by designated revoker. */ unsigned int maybe_revoked:1; /* A designated revocation is present, but without the key to check it. */ unsigned int valid:1; /* Key (especially subkey) is valid. */ unsigned int dont_cache:1; /* Do not cache this key. */ unsigned int backsig:2; /* 0=none, 1=bad, 2=good. */ unsigned int serialno_valid:1;/* SERIALNO below is valid. */ unsigned int exact:1; /* Found via exact (!) search. */ } flags; PKT_user_id *user_id; /* If != NULL: found by that uid. */ struct revocation_key *revkey; int numrevkeys; u32 trust_timestamp; byte trust_depth; byte trust_value; byte keyorg; /* From the ring trust packet. */ u32 keyupdate; /* From the ring trust packet. */ char *updateurl; /* NULL or the URL of the last update origin. */ const byte *trust_regexp; char *serialno; /* Malloced hex string or NULL if it is likely not on a card. See also flags.serialno_valid. */ /* If not NULL this malloced structure describes a secret key. (Serialized.) */ struct seckey_info *seckey_info; /* The public key. Contains pubkey_get_npkey (pubkey_algo) + pubkey_get_nskey (pubkey_algo) MPIs. (If pubkey_get_npkey returns 0, then the algorithm is not understood and the PKEY contains a single opaque MPI.) (Serialized.) */ gcry_mpi_t pkey[PUBKEY_MAX_NSKEY]; /* Right, NSKEY elements. */ } PKT_public_key; /* Evaluates as true if the pk is disabled, and false if it isn't. If there is no disable value cached, fill one in. */ #define pk_is_disabled(a) \ (((a)->flags.disabled_valid)? \ ((a)->flags.disabled):(cache_disabled_value(ctrl,(a)))) typedef struct { int len; /* length of data */ char data[1]; } PKT_comment; /* A compression packet (RFC 4880, Section 5.6). */ typedef struct { /* Not used. */ u32 len; /* Whether the serialized version of the packet used / should use the new format. */ byte new_ctb; /* The compression algorithm. */ byte algorithm; /* An iobuf holding the data to be decompressed. (This is not used for compression!) */ iobuf_t buf; } PKT_compressed; /* A symmetrically encrypted data packet (RFC 4880, Section 5.7) or a symmetrically encrypted integrity protected data packet (Section 5.13) */ typedef struct { /* Remaining length of encrypted data. */ u32 len; /* When encrypting in CFB mode, the first block size bytes of data * are random data and the following 2 bytes are copies of the last * two bytes of the random data (RFC 4880, Section 5.7). This * provides a simple check that the key is correct. EXTRALEN is the * size of this extra data or, in AEAD mode, the length of the * headers and the tags. This is used by build_packet when writing * out the packet's header. */ int extralen; /* Whether the serialized version of the packet used / should use the new format. */ byte new_ctb; /* Whether the packet has an indeterminate length (old format) or was encoded using partial body length headers (new format). Note: this is ignored when encrypting. */ byte is_partial; /* If 0, MDC is disabled. Otherwise, the MDC method that was used (only DIGEST_ALGO_SHA1 has ever been defined). */ byte mdc_method; /* If 0, AEAD is not used. Otherwise, the used AEAD algorithm. * MDC_METHOD (above) shall be zero if AEAD is used. */ byte aead_algo; /* The cipher algo for/from the AEAD packet. 0 for other encryption * packets. */ byte cipher_algo; /* The chunk byte from the AEAD packet. */ byte chunkbyte; /* An iobuf holding the data to be decrypted. (This is not used for encryption!) */ iobuf_t buf; } PKT_encrypted; typedef struct { byte hash[20]; } PKT_mdc; /* Subtypes for the ring trust packet. */ #define RING_TRUST_SIG 0 /* The classical signature cache. */ #define RING_TRUST_KEY 1 /* A KEYORG on a primary key. */ #define RING_TRUST_UID 2 /* A KEYORG on a user id. */ /* The local only ring trust packet which OpenPGP declares as * implementation defined. GnuPG uses this to cache signature * verification status and since 2.1.18 also to convey information * about the origin of a key. Note that this packet is not part * struct packet_struct because we use it only local in the packet * parser and builder. */ typedef struct { unsigned int trustval; unsigned int sigcache; unsigned char subtype; /* The subtype of this ring trust packet. */ unsigned char keyorg; /* The origin of the key (KEYORG_*). */ u32 keyupdate; /* The wall time the key was last updated. */ char *url; /* NULL or the URL of the source. */ } PKT_ring_trust; /* A plaintext packet (see RFC 4880, 5.9). */ typedef struct { /* The length of data in BUF or 0 if unknown. */ u32 len; /* A buffer containing the data stored in the packet's body. */ iobuf_t buf; byte new_ctb; byte is_partial; /* partial length encoded */ /* The data's formatting. This is either 'b', 't', 'u', 'l' or '1' (however, the last two are deprecated). */ int mode; u32 timestamp; /* The name of the file. This can be at most 255 characters long, since namelen is just a byte in the serialized format. */ int namelen; char name[1]; } PKT_plaintext; typedef struct { int control; size_t datalen; char data[1]; } PKT_gpg_control; /* combine all packets into a union */ struct packet_struct { pkttype_t pkttype; union { void *generic; PKT_symkey_enc *symkey_enc; /* PKT_SYMKEY_ENC */ PKT_pubkey_enc *pubkey_enc; /* PKT_PUBKEY_ENC */ PKT_onepass_sig *onepass_sig; /* PKT_ONEPASS_SIG */ PKT_signature *signature; /* PKT_SIGNATURE */ PKT_public_key *public_key; /* PKT_PUBLIC_[SUB]KEY */ PKT_public_key *secret_key; /* PKT_SECRET_[SUB]KEY */ PKT_comment *comment; /* PKT_COMMENT */ PKT_user_id *user_id; /* PKT_USER_ID */ PKT_compressed *compressed; /* PKT_COMPRESSED */ PKT_encrypted *encrypted; /* PKT_ENCRYPTED[_MDC] */ PKT_mdc *mdc; /* PKT_MDC */ PKT_plaintext *plaintext; /* PKT_PLAINTEXT */ PKT_gpg_control *gpg_control; /* PKT_GPG_CONTROL */ } pkt; }; #define init_packet(a) do { (a)->pkttype = 0; \ (a)->pkt.generic = NULL; \ } while(0) /* A notation. See RFC 4880, Section 5.2.3.16. */ struct notation { /* The notation's name. */ char *name; /* If the notation is human readable, then the value is stored here as a NUL-terminated string. If it is not human readable a human readable approximation of the binary value _may_ be stored here. */ char *value; /* Sometimes we want to %-expand the value. In these cases, we save that transformed value here. */ char *altvalue; /* If the notation is not human readable, then the value is stored here. */ unsigned char *bdat; /* The amount of data stored in BDAT. Note: if this is 0 and BDAT is NULL, this does not necessarily mean that the value is human readable. It could be that we have a 0-length value. To determine whether the notation is human readable, always check if VALUE is not NULL. This works, because if a human-readable value has a length of 0, we will still allocate space for the NUL byte. */ size_t blen; struct { /* The notation is critical. */ unsigned int critical:1; /* The notation is human readable. */ unsigned int human:1; /* The notation should be deleted. */ unsigned int ignore:1; } flags; /* A field to facilitate creating a list of notations. */ struct notation *next; }; typedef struct notation *notation_t; /*-- mainproc.c --*/ void reset_literals_seen(void); int proc_packets (ctrl_t ctrl, void *ctx, iobuf_t a ); int proc_signature_packets (ctrl_t ctrl, void *ctx, iobuf_t a, strlist_t signedfiles, const char *sigfile ); int proc_signature_packets_by_fd (ctrl_t ctrl, void *anchor, IOBUF a, int signed_data_fd ); int proc_encryption_packets (ctrl_t ctrl, void *ctx, iobuf_t a); int list_packets( iobuf_t a ); /*-- parse-packet.c --*/ /* Sets the packet list mode to MODE (i.e., whether we are dumping a packet or not). Returns the current mode. This allows for temporarily suspending dumping by doing the following: int saved_mode = set_packet_list_mode (0); ... set_packet_list_mode (saved_mode); */ int set_packet_list_mode( int mode ); /* A context used with parse_packet. */ struct parse_packet_ctx_s { iobuf_t inp; /* The input stream with the packets. */ struct packet_struct last_pkt; /* The last parsed packet. */ int free_last_pkt; /* Indicates that LAST_PKT must be freed. */ int skip_meta; /* Skip ring trust packets. */ unsigned int n_parsed_packets; /* Number of parsed packets. */ }; typedef struct parse_packet_ctx_s *parse_packet_ctx_t; #define init_parse_packet(a,i) do { \ (a)->inp = (i); \ (a)->last_pkt.pkttype = 0; \ (a)->last_pkt.pkt.generic= NULL;\ (a)->free_last_pkt = 0; \ (a)->skip_meta = 0; \ (a)->n_parsed_packets = 0; \ } while (0) #define deinit_parse_packet(a) do { \ if ((a)->free_last_pkt) \ free_packet (NULL, (a)); \ } while (0) #if DEBUG_PARSE_PACKET /* There are debug functions and should not be used directly. */ int dbg_search_packet (parse_packet_ctx_t ctx, PACKET *pkt, off_t *retpos, int with_uid, const char* file, int lineno ); int dbg_parse_packet (parse_packet_ctx_t ctx, PACKET *ret_pkt, const char *file, int lineno); int dbg_copy_all_packets( iobuf_t inp, iobuf_t out, const char* file, int lineno ); int dbg_copy_some_packets( iobuf_t inp, iobuf_t out, off_t stopoff, const char* file, int lineno ); int dbg_skip_some_packets( iobuf_t inp, unsigned n, const char* file, int lineno ); #define search_packet( a,b,c,d ) \ dbg_search_packet( (a), (b), (c), (d), __FILE__, __LINE__ ) #define parse_packet( a, b ) \ dbg_parse_packet( (a), (b), __FILE__, __LINE__ ) #define copy_all_packets( a,b ) \ dbg_copy_all_packets((a),(b), __FILE__, __LINE__ ) #define copy_some_packets( a,b,c ) \ dbg_copy_some_packets((a),(b),(c), __FILE__, __LINE__ ) #define skip_some_packets( a,b ) \ dbg_skip_some_packets((a),(b), __FILE__, __LINE__ ) #else /* Return the next valid OpenPGP packet in *PKT. (This function will * skip any packets whose type is 0.) CTX must have been setup prior to * calling this function. * * Returns 0 on success, -1 if EOF is reached, and an error code * otherwise. In the case of an error, the packet in *PKT may be * partially constructed. As such, even if there is an error, it is * necessary to free *PKT to avoid a resource leak. To detect what * has been allocated, clear *PKT before calling this function. */ int parse_packet (parse_packet_ctx_t ctx, PACKET *pkt); /* Return the first OpenPGP packet in *PKT that contains a key (either * a public subkey, a public key, a secret subkey or a secret key) or, * if WITH_UID is set, a user id. * * Saves the position in the pipeline of the start of the returned * packet (according to iobuf_tell) in RETPOS, if it is not NULL. * * The return semantics are the same as parse_packet. */ int search_packet (parse_packet_ctx_t ctx, PACKET *pkt, off_t *retpos, int with_uid); /* Copy all packets (except invalid packets, i.e., those with a type * of 0) from INP to OUT until either an error occurs or EOF is * reached. * * Returns -1 when end of file is reached or an error code, if an * error occurred. (Note: this function never returns 0, because it * effectively keeps going until it gets an EOF.) */ int copy_all_packets (iobuf_t inp, iobuf_t out ); /* Like copy_all_packets, but stops at the first packet that starts at * or after STOPOFF (as indicated by iobuf_tell). * * Example: if STOPOFF is 100, the first packet in INP goes from * 0 to 110 and the next packet starts at offset 111, then the packet * starting at offset 0 will be completely processed (even though it * extends beyond STOPOFF) and the packet starting at offset 111 will * not be processed at all. */ int copy_some_packets (iobuf_t inp, iobuf_t out, off_t stopoff); /* Skips the next N packets from INP. * * If parsing a packet returns an error code, then the function stops * immediately and returns the error code. Note: in the case of an * error, this function does not indicate how many packets were * successfully processed. */ int skip_some_packets (iobuf_t inp, unsigned int n); #endif /* Parse a signature packet and store it in *SIG. The signature packet is read from INP. The OpenPGP header (the tag and the packet's length) have already been read; the next byte read from INP should be the first byte of the packet's contents. The packet's type (as extract from the tag) must be passed as PKTTYPE and the packet's length must be passed as PKTLEN. This is used as the upper bound on the amount of data read from INP. If the packet is shorter than PKTLEN, the data at the end will be silently skipped. If an error occurs, an error code will be returned. -1 means the EOF was encountered. 0 means parsing was successful. */ int parse_signature( iobuf_t inp, int pkttype, unsigned long pktlen, PKT_signature *sig ); /* Given a subpacket area (typically either PKT_signature.hashed or PKT_signature.unhashed), either: - test whether there are any subpackets with the critical bit set that we don't understand, - list the subpackets, or, - find a subpacket with a specific type. REQTYPE indicates the type of operation. If REQTYPE is SIGSUBPKT_TEST_CRITICAL, then this function checks whether there are any subpackets that have the critical bit and which GnuPG cannot handle. If GnuPG understands all subpackets whose critical bit is set, then this function returns simply returns SUBPKTS. If there is a subpacket whose critical bit is set and which GnuPG does not understand, then this function returns NULL and, if START is not NULL, sets *START to the 1-based index of the subpacket that violates the constraint. If REQTYPE is SIGSUBPKT_LIST_HASHED or SIGSUBPKT_LIST_UNHASHED, the packets are dumped. Note: if REQTYPE is SIGSUBPKT_LIST_HASHED, this function does not check whether the hash is correct; this is merely an indication of the section that the subpackets came from. If REQTYPE is anything else, then this function interprets the values as a subpacket type and looks for the first subpacket with that type. If such a packet is found, *CRITICAL (if not NULL) is set if the critical bit was set, *RET_N is set to the offset of the subpacket's content within the SUBPKTS buffer, *START is set to the 1-based index of the subpacket within the buffer, and returns &SUBPKTS[*RET_N]. *START is the number of initial subpackets to not consider. Thus, if *START is 2, then the first 2 subpackets are ignored. */ const byte *enum_sig_subpkt ( const subpktarea_t *subpkts, sigsubpkttype_t reqtype, size_t *ret_n, int *start, int *critical ); /* Shorthand for: enum_sig_subpkt (buffer, reqtype, ret_n, NULL, NULL); */ const byte *parse_sig_subpkt ( const subpktarea_t *buffer, sigsubpkttype_t reqtype, size_t *ret_n ); /* This calls parse_sig_subpkt first on the hashed signature area in SIG and then, if that returns NULL, calls parse_sig_subpkt on the unhashed subpacket area in SIG. */ const byte *parse_sig_subpkt2 ( PKT_signature *sig, sigsubpkttype_t reqtype); /* Returns whether the N byte large buffer BUFFER is sufficient to hold a subpacket of type TYPE. Note: the buffer refers to the contents of the subpacket (not the header) and it must already be initialized: for some subpackets, it checks some internal constraints. Returns 0 if the size is acceptable. Returns -2 if the buffer is definitely too short. To check for an error, check whether the return value is less than 0. */ int parse_one_sig_subpkt( const byte *buffer, size_t n, int type ); /* Looks for revocation key subpackets (see RFC 4880 5.2.3.15) in the hashed area of the signature packet. Any that are found are added to SIG->REVKEY and SIG->NUMREVKEYS is updated appropriately. */ void parse_revkeys(PKT_signature *sig); /* Extract the attributes from the buffer at UID->ATTRIB_DATA and update UID->ATTRIBS and UID->NUMATTRIBS accordingly. */ int parse_attribute_subpkts(PKT_user_id *uid); /* Set the UID->NAME field according to the attributes. MAX_NAMELEN must be at least 71. */ void make_attribute_uidname(PKT_user_id *uid, size_t max_namelen); /* Allocate and initialize a new GPG control packet. DATA is the data to save in the packet. */ PACKET *create_gpg_control ( ctrlpkttype_t type, const byte *data, size_t datalen ); /*-- build-packet.c --*/ int build_packet (iobuf_t out, PACKET *pkt); gpg_error_t build_packet_and_meta (iobuf_t out, PACKET *pkt); gpg_error_t gpg_mpi_write (iobuf_t out, gcry_mpi_t a); gpg_error_t gpg_mpi_write_nohdr (iobuf_t out, gcry_mpi_t a); u32 calc_packet_length( PACKET *pkt ); void build_sig_subpkt( PKT_signature *sig, sigsubpkttype_t type, const byte *buffer, size_t buflen ); void build_sig_subpkt_from_sig (PKT_signature *sig, PKT_public_key *pksk); int delete_sig_subpkt(subpktarea_t *buffer, sigsubpkttype_t type ); void build_attribute_subpkt(PKT_user_id *uid,byte type, const void *buf,u32 buflen, const void *header,u32 headerlen); struct notation *string_to_notation(const char *string,int is_utf8); struct notation *blob_to_notation(const char *name, const char *data, size_t len); struct notation *sig_to_notation(PKT_signature *sig); void free_notation(struct notation *notation); /*-- free-packet.c --*/ void free_symkey_enc( PKT_symkey_enc *enc ); void free_pubkey_enc( PKT_pubkey_enc *enc ); void free_seckey_enc( PKT_signature *enc ); void release_public_key_parts( PKT_public_key *pk ); void free_public_key( PKT_public_key *key ); void free_attributes(PKT_user_id *uid); void free_user_id( PKT_user_id *uid ); void free_comment( PKT_comment *rem ); void free_packet (PACKET *pkt, parse_packet_ctx_t parsectx); prefitem_t *copy_prefs (const prefitem_t *prefs); PKT_public_key *copy_public_key( PKT_public_key *d, PKT_public_key *s ); PKT_signature *copy_signature( PKT_signature *d, PKT_signature *s ); PKT_user_id *scopy_user_id (PKT_user_id *sd ); int cmp_public_keys( PKT_public_key *a, PKT_public_key *b ); int cmp_signatures( PKT_signature *a, PKT_signature *b ); int cmp_user_ids( PKT_user_id *a, PKT_user_id *b ); /*-- sig-check.c --*/ /* Check a signature. This is shorthand for check_signature2 with the unnamed arguments passed as NULL. */ int check_signature (ctrl_t ctrl, PKT_signature *sig, gcry_md_hd_t digest); /* Check a signature. Looks up the public key from the key db. (If * R_PK is not NULL, it is stored at RET_PK.) DIGEST contains a * valid hash context that already includes the signed data. This * function adds the relevant meta-data to the hash before finalizing * it and verifying the signature. */ gpg_error_t check_signature2 (ctrl_t ctrl, PKT_signature *sig, gcry_md_hd_t digest, u32 *r_expiredate, int *r_expired, int *r_revoked, PKT_public_key **r_pk); /*-- pubkey-enc.c --*/ gpg_error_t get_session_key (ctrl_t ctrl, PKT_pubkey_enc *k, DEK *dek); gpg_error_t get_override_session_key (DEK *dek, const char *string); /*-- compress.c --*/ int handle_compressed (ctrl_t ctrl, void *ctx, PKT_compressed *cd, int (*callback)(iobuf_t, void *), void *passthru ); /*-- encr-data.c --*/ int decrypt_data (ctrl_t ctrl, void *ctx, PKT_encrypted *ed, DEK *dek ); /*-- plaintext.c --*/ gpg_error_t get_output_file (const byte *embedded_name, int embedded_namelen, iobuf_t data, char **fnamep, estream_t *fpp); int handle_plaintext( PKT_plaintext *pt, md_filter_context_t *mfx, int nooutput, int clearsig ); int ask_for_detached_datafile( gcry_md_hd_t md, gcry_md_hd_t md2, const char *inname, int textmode ); /*-- sign.c --*/ int make_keysig_packet (ctrl_t ctrl, PKT_signature **ret_sig, PKT_public_key *pk, PKT_user_id *uid, PKT_public_key *subpk, PKT_public_key *pksk, int sigclass, int digest_algo, u32 timestamp, u32 duration, int (*mksubpkt)(PKT_signature *, void *), void *opaque, const char *cache_nonce); gpg_error_t update_keysig_packet (ctrl_t ctrl, PKT_signature **ret_sig, PKT_signature *orig_sig, PKT_public_key *pk, PKT_user_id *uid, PKT_public_key *subpk, PKT_public_key *pksk, int (*mksubpkt)(PKT_signature *, void *), void *opaque ); /*-- keygen.c --*/ PKT_user_id *generate_user_id (kbnode_t keyblock, const char *uidstr); #endif /*G10_PACKET_H*/ diff --git a/g10/parse-packet.c b/g10/parse-packet.c index de51770af..5c6d364ee 100644 --- a/g10/parse-packet.c +++ b/g10/parse-packet.c @@ -1,3444 +1,3466 @@ /* parse-packet.c - read packets * Copyright (C) 1998-2007, 2009-2010 Free Software Foundation, Inc. * Copyright (C) 2014, 2018 Werner Koch * Copyright (C) 2015 g10 Code GmbH * * This file is part of GnuPG. * * GnuPG is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * GnuPG is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * SPDX-License-Identifier: GPL-3.0+ */ #include #include #include #include #include "gpg.h" #include "../common/util.h" #include "packet.h" #include "../common/iobuf.h" #include "filter.h" #include "photoid.h" #include "options.h" #include "main.h" #include "../common/i18n.h" #include "../common/host2net.h" /* Maximum length of packets to avoid excessive memory allocation. */ #define MAX_KEY_PACKET_LENGTH (256 * 1024) #define MAX_UID_PACKET_LENGTH ( 2 * 1024) #define MAX_COMMENT_PACKET_LENGTH ( 64 * 1024) #define MAX_ATTR_PACKET_LENGTH ( 16 * 1024*1024) static int mpi_print_mode; static int list_mode; static estream_t listfp; static int parse (parse_packet_ctx_t ctx, PACKET *pkt, int onlykeypkts, off_t * retpos, int *skip, IOBUF out, int do_skip #if 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 gpg_error_t parse_ring_trust (parse_packet_ctx_t ctx, unsigned long pktlen); 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 gpg_error_t parse_encrypted_aead (IOBUF inp, int pkttype, unsigned long pktlen, PACKET *packet, 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); /* Read a 16-bit value in MSB order (big endian) from an iobuf. */ static unsigned short read_16 (IOBUF inp) { unsigned short a; a = (unsigned short)iobuf_get_noeof (inp) << 8; a |= iobuf_get_noeof (inp); return a; } /* Read a 32-bit value in MSB order (big endian) from an iobuf. */ static unsigned long read_32 (IOBUF inp) { unsigned long a; a = (unsigned long)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 MSB first and is left padded with zero bits to align on a byte boundary. The caller must set *RET_NREAD to the maximum number of bytes to read from the pipeline INP. This function sets *RET_NREAD to be the number of bytes actually read from the pipeline. If SECURE is true, the integer is stored in secure memory (allocated using gcry_xmalloc_secure). */ static gcry_mpi_t mpi_read (iobuf_t inp, unsigned int *ret_nread, int secure) { int c, c1, c2, i; unsigned int nmax = *ret_nread; unsigned int nbits, nbytes; size_t nread = 0; gcry_mpi_t a = NULL; byte *buf = NULL; byte *p; if (!nmax) goto overflow; if ((c = c1 = iobuf_get (inp)) == -1) goto leave; if (++nread == nmax) goto overflow; nbits = c << 8; if ((c = c2 = iobuf_get (inp)) == -1) goto leave; ++nread; nbits |= c; if (nbits > MAX_EXTERN_MPI_BITS) { log_error ("mpi too large (%u bits)\n", nbits); goto leave; } 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++) { if (nread == nmax) goto overflow; c = iobuf_get (inp); if (c == -1) goto leave; p[i + 2] = c; nread ++; } if (gcry_mpi_scan (&a, GCRYMPI_FMT_PGP, buf, nread, &nread)) a = NULL; *ret_nread = nread; gcry_free(buf); return a; overflow: log_error ("mpi larger than indicated length (%u bits)\n", 8*nmax); leave: *ret_nread = nread; gcry_free(buf); return a; } int set_packet_list_mode (int mode) { int old = list_mode; list_mode = mode; /* We use stdout 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 there is code which switches opt.list_mode back to 1 and we want to have all output to the same stream. The MPI_PRINT_MODE will be enabled if the corresponding debug flag is set or if we are in --list-packets and --verbose is given. 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 mode only with a special option. */ if (!listfp) { if (opt.list_packets) { listfp = es_stdout; if (opt.verbose) mpi_print_mode = 1; } else listfp = es_stderr; if (DBG_MPI) mpi_print_mode = 1; } return old; } /* If OPT.VERBOSE is set, print a warning that the algorithm ALGO is not suitable for signing and encryption. */ static void unknown_pubkey_warning (int algo) { static byte unknown_pubkey_algos[256]; /* First check whether the algorithm is usable but not suitable for encryption/signing. */ if (pubkey_get_npkey (algo)) { if (opt.verbose) { if (!pubkey_get_nsig (algo)) log_info ("public key algorithm %s not suitable for %s\n", openpgp_pk_algo_name (algo), "signing"); if (!pubkey_get_nenc (algo)) log_info ("public key algorithm %s not suitable for %s\n", openpgp_pk_algo_name (algo), "encryption"); } } else { 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; } } } #if DEBUG_PARSE_PACKET int dbg_parse_packet (parse_packet_ctx_t ctx, PACKET *pkt, const char *dbg_f, int dbg_l) { int skip, rc; do { rc = parse (ctx, pkt, 0, NULL, &skip, NULL, 0, "parse", dbg_f, dbg_l); } while (skip && ! rc); return rc; } #else /*!DEBUG_PARSE_PACKET*/ int parse_packet (parse_packet_ctx_t ctx, PACKET *pkt) { int skip, rc; do { rc = parse (ctx, pkt, 0, NULL, &skip, NULL, 0); } while (skip && ! rc); return rc; } #endif /*!DEBUG_PARSE_PACKET*/ /* * Like parse packet, but only return secret or public (sub)key * packets. */ #if DEBUG_PARSE_PACKET int dbg_search_packet (parse_packet_ctx_t ctx, PACKET *pkt, off_t * retpos, int with_uid, const char *dbg_f, int dbg_l) { int skip, rc; do { rc = parse (ctx, pkt, with_uid ? 2 : 1, retpos, &skip, NULL, 0, "search", dbg_f, dbg_l); } while (skip && ! rc); return rc; } #else /*!DEBUG_PARSE_PACKET*/ int search_packet (parse_packet_ctx_t ctx, PACKET *pkt, off_t * retpos, int with_uid) { int skip, rc; do { rc = parse (ctx, pkt, with_uid ? 2 : 1, retpos, &skip, NULL, 0); } while (skip && ! rc); return rc; } #endif /*!DEBUG_PARSE_PACKET*/ /* * Copy all packets from INP to OUT, thereby removing unused spaces. */ #if DEBUG_PARSE_PACKET int dbg_copy_all_packets (iobuf_t inp, iobuf_t out, const char *dbg_f, int dbg_l) { PACKET pkt; struct parse_packet_ctx_s parsectx; int skip, rc = 0; if (! out) log_bug ("copy_all_packets: OUT may not be NULL.\n"); init_parse_packet (&parsectx, inp); do { init_packet (&pkt); } while (! (rc = parse (&parsectx, &pkt, 0, NULL, &skip, out, 0, "copy", dbg_f, dbg_l))); deinit_parse_packet (&parsectx); return rc; } #else /*!DEBUG_PARSE_PACKET*/ int copy_all_packets (iobuf_t inp, iobuf_t out) { PACKET pkt; struct parse_packet_ctx_s parsectx; int skip, rc = 0; if (! out) log_bug ("copy_all_packets: OUT may not be NULL.\n"); init_parse_packet (&parsectx, inp); do { init_packet (&pkt); } while (!(rc = parse (&parsectx, &pkt, 0, NULL, &skip, out, 0))); deinit_parse_packet (&parsectx); 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) */ #if DEBUG_PARSE_PACKET int dbg_copy_some_packets (iobuf_t inp, iobuf_t out, off_t stopoff, const char *dbg_f, int dbg_l) { int rc = 0; PACKET pkt; int skip; struct parse_packet_ctx_s parsectx; init_parse_packet (&parsectx, inp); do { if (iobuf_tell (inp) >= stopoff) { deinit_parse_packet (&parsectx); return 0; } init_packet (&pkt); } while (!(rc = parse (&parsectx, &pkt, 0, NULL, &skip, out, 0, "some", dbg_f, dbg_l))); deinit_parse_packet (&parsectx); return rc; } #else /*!DEBUG_PARSE_PACKET*/ int copy_some_packets (iobuf_t inp, iobuf_t out, off_t stopoff) { int rc = 0; PACKET pkt; struct parse_packet_ctx_s parsectx; int skip; init_parse_packet (&parsectx, inp); do { if (iobuf_tell (inp) >= stopoff) { deinit_parse_packet (&parsectx); return 0; } init_packet (&pkt); } while (!(rc = parse (&parsectx, &pkt, 0, NULL, &skip, out, 0))); deinit_parse_packet (&parsectx); return rc; } #endif /*!DEBUG_PARSE_PACKET*/ /* * Skip over N packets */ #if DEBUG_PARSE_PACKET int dbg_skip_some_packets (iobuf_t inp, unsigned n, const char *dbg_f, int dbg_l) { int rc = 0; int skip; PACKET pkt; struct parse_packet_ctx_s parsectx; init_parse_packet (&parsectx, inp); for (; n && !rc; n--) { init_packet (&pkt); rc = parse (&parsectx, &pkt, 0, NULL, &skip, NULL, 1, "skip", dbg_f, dbg_l); } deinit_parse_packet (&parsectx); return rc; } #else /*!DEBUG_PARSE_PACKET*/ int skip_some_packets (iobuf_t inp, unsigned int n) { int rc = 0; int skip; PACKET pkt; struct parse_packet_ctx_s parsectx; init_parse_packet (&parsectx, inp); for (; n && !rc; n--) { init_packet (&pkt); rc = parse (&parsectx, &pkt, 0, NULL, &skip, NULL, 1); } deinit_parse_packet (&parsectx); return rc; } #endif /*!DEBUG_PARSE_PACKET*/ /* Parse a packet and save it in *PKT. If OUT is not NULL and the packet is valid (its type is not 0), then the header, the initial length field and the packet's contents are written to OUT. In this case, the packet is not saved in *PKT. ONLYKEYPKTS is a simple packet filter. If ONLYKEYPKTS is set to 1, then only public subkey packets, public key packets, private subkey packets and private key packets are parsed. The rest are skipped (i.e., the header and the contents are read from the pipeline and discarded). If ONLYKEYPKTS is set to 2, then in addition to the above 4 types of packets, user id packets are also accepted. DO_SKIP is a more coarse grained filter. Unless ONLYKEYPKTS is set to 2 and the packet is a user id packet, all packets are skipped. Finally, if a packet is invalid (it's type is 0), it is skipped. If a packet is skipped and SKIP is not NULL, then *SKIP is set to 1. Note: ONLYKEYPKTS and DO_SKIP are only respected if OUT is NULL, i.e., the packets are not simply being copied. If RETPOS is not NULL, then the position of CTX->INP (as returned by iobuf_tell) is saved there before any data is read from CTX->INP. */ static int parse (parse_packet_ctx_t ctx, PACKET *pkt, int onlykeypkts, off_t * retpos, int *skip, IOBUF out, int do_skip #if DEBUG_PARSE_PACKET , const char *dbg_w, const char *dbg_f, int dbg_l #endif ) { int rc = 0; iobuf_t inp; int c, ctb, pkttype, lenbytes; unsigned long pktlen; byte hdr[8]; int hdrlen; int new_ctb = 0, partial = 0; int with_uid = (onlykeypkts == 2); off_t pos; *skip = 0; inp = ctx->inp; again: log_assert (!pkt->pkt.generic); if (retpos || list_mode) { pos = iobuf_tell (inp); if (retpos) *retpos = pos; } else pos = 0; /* (silence compiler warning) */ /* The first byte of a packet is the so-called tag. The highest bit must be set. */ 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; } /* Immediately following the header is the length. There are two formats: the old format and the new format. If bit 6 (where the least significant bit is bit 0) is set in the tag, then we are dealing with a new format packet. Otherwise, it is an old format packet. */ pktlen = 0; new_ctb = !!(ctb & 0x40); if (new_ctb) { /* Get the packet's type. This is encoded in the 6 least significant bits of the tag. */ pkttype = ctb & 0x3f; /* Extract the packet's length. New format packets have 4 ways to encode the packet length. The value of the first byte determines the encoding and partially determines the length. See section 4.2.2 of RFC 4880 for details. */ 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) { int i; char value[4]; for (i = 0; i < 4; i ++) { 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; } value[i] = hdr[hdrlen++] = c; } pktlen = buf32_to_ulong (value); } else /* Partial body length. */ { switch (pkttype) { case PKT_PLAINTEXT: case PKT_ENCRYPTED: case PKT_ENCRYPTED_MDC: case PKT_ENCRYPTED_AEAD: case PKT_COMPRESSED: iobuf_set_partial_body_length_mode (inp, c & 0xff); pktlen = 0; /* To indicate partial length. */ partial = 1; break; default: log_error ("%s: partial length invalid for" " packet type %d\n", iobuf_where (inp), pkttype); rc = gpg_error (GPG_ERR_INV_PACKET); goto leave; } } } else /* This is an old format packet. */ { /* Extract the packet's type. This is encoded in bits 2-5. */ pkttype = (ctb >> 2) & 0xf; /* The type of length encoding is encoded in bits 0-1 of the tag. */ 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; c = iobuf_get (inp); if (c == -1) { log_error ("%s: length invalid\n", iobuf_where (inp)); rc = gpg_error (GPG_ERR_INV_PACKET); goto leave; } pktlen |= hdr[hdrlen++] = c; } } } /* Sometimes the decompressing layer enters an error state in which it simply outputs 0xff for every byte read. If we have a stream of 0xff bytes, then it will be detected as a new format packet with type 63 and a 4-byte encoded length that is 4G-1. Since packets with type 63 are private and we use them as a control packet, which won't be 4 GB, we reject such packets as invalid. */ if (pkttype == 63 && pktlen == 0xFFFFFFFF) { /* 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) { /* This type of copying won't work if the packet uses a partial body length. (In other words, this only works if HDR is actually the length.) Currently, no callers require this functionality so we just log this as an error. */ if (partial) { log_error ("parse: Can't copy partial packet. Aborting.\n"); rc = gpg_error (GPG_ERR_INV_PACKET); goto leave; } 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) /* If ONLYKEYPKTS is set to 2, then we never skip user id packets, even if DO_SKIP is set. */ ; else if (do_skip /* type==0 is not allowed. This is an invalid packet. */ || !pkttype /* When ONLYKEYPKTS is set, we don't skip keys. */ || (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) { #if 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 } if (list_mode) es_fprintf (listfp, "# off=%lu ctb=%02x tag=%d hlen=%d plen=%lu%s%s\n", (unsigned long)pos, ctb, pkttype, hdrlen, pktlen, partial? (new_ctb ? " partial" : " indeterminate") :"", new_ctb? " new-ctb":""); /* Count it. */ ctx->n_parsed_packets++; pkt->pkttype = pkttype; rc = GPG_ERR_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: { rc = parse_ring_trust (ctx, pktlen); if (!rc) goto again; /* Directly read the next packet. */ } 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_ENCRYPTED_AEAD: rc = parse_encrypted_aead (inp, pkttype, pktlen, pkt, partial); 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: /* Unknown packet. Skip it. */ skip_packet (inp, pkttype, pktlen, partial); break; } /* Store a shallow copy of certain packets in the context. */ free_packet (NULL, ctx); if (!rc && (pkttype == PKT_PUBLIC_KEY || pkttype == PKT_SECRET_KEY || pkttype == PKT_USER_ID || pkttype == PKT_ATTRIBUTE || pkttype == PKT_SIGNATURE)) { ctx->last_pkt = *pkt; } leave: /* FIXME: We leak in case of an error (see the xmalloc's above). */ if (!rc && iobuf_error (inp)) rc = GPG_ERR_INV_KEYRING; /* FIXME: We use only the error code for now to avoid problems with callers which have not been checked to always use gpg_err_code() when comparing error codes. */ return rc == -1? -1 : gpg_err_code (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; } /* Copy the contents of a packet from the pipeline IN to the pipeline OUT. The header and length have already been read from INP and the decoded values are given as PKGTYPE and PKTLEN. If the packet is a partial body length packet (RFC 4880, Section 4.2.2.4), then iobuf_set_partial_block_modeiobuf_set_partial_block_mode should already have been called on INP and PARTIAL should be set. If PARTIAL is set or PKTLEN is 0 and PKTTYPE is PKT_COMPRESSED, copy until the first EOF is encountered on INP. Returns 0 on success and an error code if an error occurs. */ 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, sizeof (buf))) != -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, sizeof (buf))) != -1) if ((rc = iobuf_write (out, buf, n))) return rc; /* write error */ } else { for (; pktlen; pktlen -= n) { n = pktlen > sizeof (buf) ? sizeof (buf) : 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; } /* Skip an unknown packet. PKTTYPE is the packet's type, PKTLEN is the length of the packet's content and PARTIAL is whether partial body length encoding in used (in this case PKTLEN is ignored). */ 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 (including reading fewer than PKTLEN bytes from INP before EOF is returned), NULL is returned and an error message is logged. */ 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"); if (list_mode) es_fputs (":marker packet: [invalid]\n", listfp); iobuf_skip_rest (inp, pktlen, 0); return GPG_ERR_INV_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; + int i, version, s2kmode, cipher_algo, aead_algo, hash_algo, seskeylen, minlen; if (pktlen < 4) { log_error ("packet(%d) too short\n", pkttype); if (list_mode) es_fprintf (listfp, ":symkey enc packet: [too short]\n"); rc = gpg_error (GPG_ERR_INV_PACKET); goto leave; } version = iobuf_get_noeof (inp); pktlen--; - if (version != 4) + if (version == 4) + ; + else if (version == 5) + ; + else { log_error ("packet(%d) with unknown version %d\n", pkttype, version); if (list_mode) es_fprintf (listfp, ":symkey enc packet: [unknown version]\n"); 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); if (list_mode) es_fprintf (listfp, ":symkey enc packet: [too large]\n"); rc = gpg_error (GPG_ERR_INV_PACKET); goto leave; } cipher_algo = iobuf_get_noeof (inp); pktlen--; + if (version == 5) + { + aead_algo = iobuf_get_noeof (inp); + pktlen--; + } + else + aead_algo = 0; 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); if (list_mode) es_fprintf (listfp, ":symkey enc packet: [unknown S2K mode]\n"); goto leave; } if (minlen > pktlen) { log_error ("packet with S2K %d too short\n", s2kmode); if (list_mode) es_fprintf (listfp, ":symkey enc packet: [too short]\n"); 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->aead_algo = aead_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")); } log_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); + ":symkey enc packet: version %d, cipher %d, aead %d," + " s2k %d, hash %d", + version, cipher_algo, aead_algo, s2kmode, hash_algo); if (seskeylen) - es_fprintf (listfp, ", seskey %d bits", (seskeylen - 1) * 8); + { + /* To compute the size of the session key we need to know + * the size of the AEAD nonce which we may not know. Thus + * we show only the seize of the entire encrypted session + * key. */ + if (aead_algo) + es_fprintf (listfp, ", encrypted seskey %d bytes", seskeylen); + else + 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); if (list_mode) es_fputs (":pubkey enc packet: [too short]\n", listfp); 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); if (list_mode) es_fputs (":pubkey enc packet: [unknown version]\n", listfp); 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; } /* Dump a subpacket to LISTFP. BUFFER contains the subpacket in question and points to the type field in the subpacket header (not the start of the header). TYPE is the subpacket's type with the critical bit cleared. CRITICAL is the value of the CRITICAL bit. BUFLEN is the length of the buffer and LENGTH is the length of the subpacket according to the subpacket's header. */ 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 (buf32_to_u32 (buffer))); break; case SIGSUBPKT_SIG_EXPIRE: if (length >= 4) { if (buf32_to_u32 (buffer)) es_fprintf (listfp, "sig expires after %s", strtimevalue (buf32_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: \""); es_write_sanitized (listfp, buffer, length, "\"", NULL); p = "\""; } break; case SIGSUBPKT_REVOCABLE: if (length) es_fprintf (listfp, "%srevocable", *buffer ? "" : "not "); break; case SIGSUBPKT_KEY_EXPIRE: if (length >= 4) { if (buf32_to_u32 (buffer)) es_fprintf (listfp, "key expires after %s", strtimevalue (buf32_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_PREF_AEAD: es_fputs ("pref-aead-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) buf32_to_u32 (buffer), (ulong) buf32_to_u32 (buffer + 4)); break; case SIGSUBPKT_ISSUER_FPR: if (length >= 21) { char *tmp; es_fprintf (listfp, "issuer fpr v%d ", buffer[0]); tmp = bin2hex (buffer+1, length-1, NULL); if (tmp) { es_fputs (tmp, listfp); xfree (tmp); } } 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 ("keyserver preferences:", listfp); for (i = 0; i < length; i++) es_fprintf (listfp, " %02X", buffer[i]); break; case SIGSUBPKT_PREF_KS: es_fputs ("preferred keyserver: ", 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_AEAD: 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_ISSUER_FPR: /* issuer key ID */ if (n < 21) 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) { size_t notation_len = ((buffer[4] << 8) | buffer[5]); if (n - 8 >= notation_len) return can_handle_critical_notation (buffer + 8, notation_len); } 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_ISSUER_FPR: /* issuer fingerprint */ case SIGSUBPKT_PREF_SYM: case SIGSUBPKT_PREF_AEAD: 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: case SIGSUBPKT_REVOC_REASON: /* At least we know about it. */ 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) { static char dummy[] = "x"; /* Return a value different from NULL to indicate that * there is no critical bit we do not understand. */ return reqtype == SIGSUBPKT_TEST_CRITICAL ? dummy : 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 = buf32_to_size_t (buffer); 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) /* Returning NULL means we found a subpacket with the critical bit set that we don't grok. We've iterated over all the subpackets and haven't found such a packet so we need to return a non-NULL value. */ return buffer; /* 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) { const byte *p; p = parse_sig_subpkt (sig->hashed, reqtype, NULL); if (!p) p = parse_sig_subpkt (sig->unhashed, reqtype, NULL); return p; } /* Find all revocation keys. Look in hashed area only. */ void parse_revkeys (PKT_signature * sig) { const byte *revkey; int seq = 0; size_t len; if (sig->sig_class != 0x1F) return; while ((revkey = enum_sig_subpkt (sig->hashed, SIGSUBPKT_REV_KEY, &len, &seq, NULL))) { if (/* The only valid length is 22 bytes. See RFC 4880 5.2.3.15. */ len == 22 /* 0x80 bit must be set on the class. */ && (revkey[0] & 0x80)) { sig->revkey = xrealloc (sig->revkey, sizeof (struct revocation_key) * (sig->numrevkeys + 1)); /* Copy the individual fields. */ sig->revkey[sig->numrevkeys].class = revkey[0]; sig->revkey[sig->numrevkeys].algid = revkey[1]; memcpy (sig->revkey[sig->numrevkeys].fpr, &revkey[2], 20); 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); if (list_mode) es_fputs (":signature packet: [too short]\n", listfp); 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); if (list_mode) es_fputs (":signature packet: [unknown version]\n", listfp); rc = gpg_error (GPG_ERR_INV_PACKET); goto leave; } if (!is_v4) { if (pktlen == 0) goto underflow; md5_len = iobuf_get_noeof (inp); pktlen--; } if (pktlen == 0) goto underflow; sig->sig_class = iobuf_get_noeof (inp); pktlen--; if (!is_v4) { if (pktlen < 12) goto underflow; sig->timestamp = read_32 (inp); pktlen -= 4; sig->keyid[0] = read_32 (inp); pktlen -= 4; sig->keyid[1] = read_32 (inp); pktlen -= 4; } if (pktlen < 2) goto underflow; 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. */ { if (pktlen < 2) goto underflow; n = read_16 (inp); pktlen -= 2; /* Length of hashed data. */ if (pktlen < n) goto underflow; if (n > 10000) { log_error ("signature packet: hashed data too long\n"); if (list_mode) es_fputs (":signature packet: [hashed data too long]\n", listfp); rc = GPG_ERR_INV_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"); if (list_mode) es_fputs (":signature packet: [premature eof]\n", listfp); rc = -1; goto leave; } pktlen -= n; } if (pktlen < 2) goto underflow; n = read_16 (inp); pktlen -= 2; /* Length of unhashed data. */ if (pktlen < n) goto underflow; if (n > 10000) { log_error ("signature packet: unhashed data too long\n"); if (list_mode) es_fputs (":signature packet: [unhashed data too long]\n", listfp); rc = GPG_ERR_INV_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"); if (list_mode) es_fputs (":signature packet: [premature eof]\n", listfp); rc = -1; goto leave; } pktlen -= n; } } if (pktlen < 2) goto underflow; 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 = buf32_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); if (p) { sig->keyid[0] = buf32_to_u32 (p); sig->keyid[1] = buf32_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 && buf32_to_u32 (p)) sig->expiredate = sig->timestamp + buf32_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_SIGNERS_UID, &len); if (p && len) { sig->signers_uid = try_make_printable_string (p, len, 0); if (!sig->signers_uid) { rc = gpg_error_from_syserror (); goto leave; } } 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); 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 = GPG_ERR_INV_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 = GPG_ERR_INV_PACKET; } } leave: iobuf_skip_rest (inp, pktlen, 0); return rc; underflow: log_error ("packet(%d) too short\n", pkttype); if (list_mode) es_fputs (":signature packet: [too short]\n", listfp); iobuf_skip_rest (inp, pktlen, 0); return GPG_ERR_INV_PACKET; } 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); if (list_mode) es_fputs (":onepass_sig packet: [too short]\n", listfp); 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); if (list_mode) es_fputs (":onepass_sig packet: [unknown version]\n", listfp); 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 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; 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 (inp); if (c == -1) break; /* Ooops: shorter than indicated. */ 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) { /* The only supported version. Use an older gpg version (i.e. gpg 1.4) to parse v3 packets. */ } else if (version == 2 || version == 3) { if (opt.verbose > 1) log_info ("packet(%d) with obsolete version %d\n", pkttype, version); if (list_mode) es_fprintf (listfp, ":key packet: [obsolete version %d]\n", version); pk->version = version; err = gpg_error (GPG_ERR_LEGACY_KEY); goto leave; } else { log_error ("packet(%d) with unknown version %d\n", pkttype, version); if (list_mode) es_fputs (":key packet: [unknown version]\n", listfp); err = gpg_error (GPG_ERR_INV_PACKET); goto leave; } if (pktlen < 11) { log_error ("packet(%d) too short\n", pkttype); if (list_mode) es_fputs (":key packet: [too short]\n", listfp); err = gpg_error (GPG_ERR_INV_PACKET); goto leave; } else if (pktlen > MAX_KEY_PACKET_LENGTH) { log_error ("packet(%d) too large\n", pkttype); if (list_mode) es_fputs (":key packet: [too larget]\n", listfp); err = gpg_error (GPG_ERR_INV_PACKET); goto leave; } timestamp = read_32 (inp); pktlen -= 4; expiredate = 0; /* have to get it from the selfsignature */ max_expiredate = 0; 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_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]); const char *name = openpgp_oid_to_curve (curve, 0); es_fprintf (listfp, " %s (%s)", name?name:"", 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; if (pktlen < 1) { err = gpg_error (GPG_ERR_INV_PACKET); goto leave; } 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 (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); if (i < 8) { err = gpg_error (GPG_ERR_INV_PACKET); goto leave; } 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); log_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; 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 (ski->is_protected) { if (pktlen < 2) /* At least two bytes for the length. */ { err = gpg_error (GPG_ERR_INV_PACKET); goto leave; } /* 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); /* Mark that MPI as protected - we need this information for importing a key. The OPAQUE flag can't be used because we also store public EdDSA values in opaque MPIs. */ if (pk->pkey[npkey]) gcry_mpi_set_flag (pk->pkey[npkey], GCRYMPI_FLAG_USER1); pktlen = 0; if (list_mode) es_fprintf (listfp, "\tskey[%d]: [v4 protected]\n", npkey); } else { /* Not encrypted. */ for (i = npkey; i < nskey; i++) { unsigned int n; if (pktlen < 2) /* At least two bytes for the length. */ { err = gpg_error (GPG_ERR_INV_PACKET); goto leave; } 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; if (pktlen < 2) { err = gpg_error (GPG_ERR_INV_PACKET); goto leave; } ski->csum = read_16 (inp); pktlen -= 2; if (list_mode) es_fprintf (listfp, "\tchecksum: %04hx\n", ski->csum); } } /* Note that KEYID below has been initialized above in list_mode. */ if (list_mode) es_fprintf (listfp, "\tkeyid: %08lX%08lX\n", (ulong) keyid[0], (ulong) keyid[1]); leave: iobuf_skip_rest (inp, pktlen, 0); return err; } /* 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 = buf32_to_size_t (buffer); 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; if (!n) { /* Too short to encode the subpacket type. */ if (opt.verbose) log_info ("attribute subpacket too short\n"); break; } 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 > MAX_UID_PACKET_LENGTH) { log_error ("packet(%d) too large\n", pkttype); if (list_mode) es_fprintf (listfp, ":user ID packet: [too large]\n"); iobuf_skip_rest (inp, pktlen, 0); return GPG_ERR_INV_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) { log_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; /* We better cap the size of an attribute packet to make DoS not too easy. 16MB should be more then enough for one attribute packet (ie. a photo). */ if (pktlen > MAX_ATTR_PACKET_LENGTH) { log_error ("packet(%d) too large\n", pkttype); if (list_mode) es_fprintf (listfp, ":attribute packet: [too large]\n"); iobuf_skip_rest (inp, pktlen, 0); return GPG_ERR_INV_PACKET; } #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? pktlen:1); 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 > MAX_COMMENT_PACKET_LENGTH) { log_error ("packet(%d) too large\n", pkttype); if (list_mode) es_fprintf (listfp, ":%scomment packet: [too large]\n", pkttype == PKT_OLD_COMMENT ? "OpenPGP draft " : ""); iobuf_skip_rest (inp, pktlen, 0); return GPG_ERR_INV_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; } /* Parse a ring trust packet RFC4880 (5.10). * * This parser is special in that the packet is not stored as a packet * but its content is merged into the previous packet. */ static gpg_error_t parse_ring_trust (parse_packet_ctx_t ctx, unsigned long pktlen) { gpg_error_t err; iobuf_t inp = ctx->inp; PKT_ring_trust rt = {0}; int c; int not_gpg = 0; if (!pktlen) { if (list_mode) es_fprintf (listfp, ":trust packet: empty\n"); err = 0; goto leave; } c = iobuf_get_noeof (inp); pktlen--; rt.trustval = c; if (pktlen) { if (!c) { c = iobuf_get_noeof (inp); /* We require that bit 7 of the sigcache is 0 (easier * eof handling). */ if (!(c & 0x80)) rt.sigcache = c; } else iobuf_get_noeof (inp); /* Dummy read. */ pktlen--; } /* Next is the optional subtype. */ if (pktlen > 3) { char tmp[4]; tmp[0] = iobuf_get_noeof (inp); tmp[1] = iobuf_get_noeof (inp); tmp[2] = iobuf_get_noeof (inp); tmp[3] = iobuf_get_noeof (inp); pktlen -= 4; if (!memcmp (tmp, "gpg", 3)) rt.subtype = tmp[3]; else not_gpg = 1; } /* If it is a key or uid subtype read the remaining data. */ if ((rt.subtype == RING_TRUST_KEY || rt.subtype == RING_TRUST_UID) && pktlen >= 6 ) { int i; unsigned int namelen; rt.keyorg = iobuf_get_noeof (inp); pktlen--; rt.keyupdate = read_32 (inp); pktlen -= 4; namelen = iobuf_get_noeof (inp); pktlen--; if (namelen && pktlen) { rt.url = xtrymalloc (namelen + 1); if (!rt.url) { err = gpg_error_from_syserror (); goto leave; } for (i = 0; pktlen && i < namelen; pktlen--, i++) rt.url[i] = iobuf_get_noeof (inp); rt.url[i] = 0; } } if (list_mode) { if (rt.subtype == RING_TRUST_SIG) es_fprintf (listfp, ":trust packet: sig flag=%02x sigcache=%02x\n", rt.trustval, rt.sigcache); else if (rt.subtype == RING_TRUST_UID || rt.subtype == RING_TRUST_KEY) { unsigned char *p; es_fprintf (listfp, ":trust packet: %s upd=%lu src=%d%s", (rt.subtype == RING_TRUST_UID? "uid" : "key"), (unsigned long)rt.keyupdate, rt.keyorg, (rt.url? " url=":"")); if (rt.url) { for (p = rt.url; *p; p++) { if (*p >= ' ' && *p <= 'z') es_putc (*p, listfp); else es_fprintf (listfp, "\\x%02x", *p); } } es_putc ('\n', listfp); } else if (not_gpg) es_fprintf (listfp, ":trust packet: not created by gpg\n"); else es_fprintf (listfp, ":trust packet: subtype=%02x\n", rt.subtype); } /* Now transfer the data to the respective packet. Do not do this * if SKIP_META is set. */ if (!ctx->last_pkt.pkt.generic || ctx->skip_meta) ; else if (rt.subtype == RING_TRUST_SIG && ctx->last_pkt.pkttype == PKT_SIGNATURE) { PKT_signature *sig = ctx->last_pkt.pkt.signature; if ((rt.sigcache & 1)) { sig->flags.checked = 1; sig->flags.valid = !!(rt.sigcache & 2); } } else if (rt.subtype == RING_TRUST_UID && (ctx->last_pkt.pkttype == PKT_USER_ID || ctx->last_pkt.pkttype == PKT_ATTRIBUTE)) { PKT_user_id *uid = ctx->last_pkt.pkt.user_id; uid->keyorg = rt.keyorg; uid->keyupdate = rt.keyupdate; uid->updateurl = rt.url; rt.url = NULL; } else if (rt.subtype == RING_TRUST_KEY && (ctx->last_pkt.pkttype == PKT_PUBLIC_KEY || ctx->last_pkt.pkttype == PKT_SECRET_KEY)) { PKT_public_key *pk = ctx->last_pkt.pkt.public_key; pk->keyorg = rt.keyorg; pk->keyupdate = rt.keyupdate; pk->updateurl = rt.url; rt.url = NULL; } err = 0; leave: xfree (rt.url); free_packet (NULL, ctx); /* This sets ctx->last_pkt to NULL. */ iobuf_skip_rest (inp, pktlen, 0); return err; } 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); if (list_mode) es_fputs (":literal data packet: [too short]\n", listfp); 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; } /* Fill up NAME so that a check with valgrind won't complain about * reading from uninitalized memory. This case may be triggred by * corrupted packets. */ for (; i < namelen; i++) pt->name[i] = 0; pt->timestamp = read_32 (inp); if (pktlen) pktlen -= 4; pt->len = pktlen; pt->buf = inp; 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; ed->aead_algo = 0; ed->cipher_algo = 0; /* Only used with AEAD. */ ed->chunkbyte = 0; /* Only used with AEAD. */ 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); if (list_mode) es_fputs (":encrypted data packet: [unknown version]\n", listfp); /*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); if (list_mode) es_fputs (":encrypted data packet: [too short]\n", listfp); rc = GPG_ERR_INV_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; } static gpg_error_t parse_encrypted_aead (iobuf_t inp, int pkttype, unsigned long pktlen, PACKET *pkt, int partial) { int rc = 0; PKT_encrypted *ed; unsigned long orig_pktlen = pktlen; int version; ed = pkt->pkt.encrypted = xtrymalloc (sizeof *pkt->pkt.encrypted); if (!ed) return gpg_error_from_syserror (); ed->len = 0; ed->extralen = 0; /* (only used in build_packet.) */ ed->buf = NULL; ed->new_ctb = 1; /* (packet number requires a new CTB anyway.) */ ed->is_partial = partial; ed->mdc_method = 0; /* A basic sanity check. We need one version byte, one algo byte, * one aead algo byte, one chunkbyte, at least 15 byte IV. */ if (orig_pktlen && pktlen < 19) { log_error ("packet(%d) too short\n", pkttype); if (list_mode) es_fputs (":aead encrypted packet: [too short]\n", listfp); rc = gpg_error (GPG_ERR_INV_PACKET); iobuf_skip_rest (inp, pktlen, partial); goto leave; } version = iobuf_get_noeof (inp); if (orig_pktlen) pktlen--; if (version != 1) { log_error ("aead encrypted packet with unknown version %d\n", version); if (list_mode) es_fputs (":aead encrypted packet: [unknown version]\n", listfp); /*skip_rest(inp, pktlen); should we really do this? */ rc = gpg_error (GPG_ERR_INV_PACKET); goto leave; } ed->cipher_algo = iobuf_get_noeof (inp); if (orig_pktlen) pktlen--; ed->aead_algo = iobuf_get_noeof (inp); if (orig_pktlen) pktlen--; ed->chunkbyte = iobuf_get_noeof (inp); if (orig_pktlen) pktlen--; /* Store the remaining length of the encrypted data. We read the * rest during decryption. */ ed->len = pktlen; if (list_mode) { es_fprintf (listfp, ":aead encrypted packet: cipher=%u aead=%u cb=%u\n", ed->cipher_algo, ed->aead_algo, ed->chunkbyte); if (orig_pktlen) es_fprintf (listfp, "\tlength: %lu\n", orig_pktlen); else es_fprintf (listfp, "\tlength: unknown\n"); } ed->buf = inp; leave: return rc; } /* * This packet is internally generated by us (in 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 coming 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) es_fputs ("- gpg control packet", listfp); 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/sign.c b/g10/sign.c index 7045e8cad..df71ccce1 100644 --- a/g10/sign.c +++ b/g10/sign.c @@ -1,1667 +1,1670 @@ /* sign.c - sign data * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, * 2007, 2010, 2012 Free Software Foundation, Inc. * * This file is part of GnuPG. * * GnuPG is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * GnuPG is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . */ #include #include #include #include #include #include "gpg.h" #include "options.h" #include "packet.h" #include "../common/status.h" #include "../common/iobuf.h" #include "keydb.h" #include "../common/util.h" #include "main.h" #include "filter.h" #include "../common/ttyio.h" #include "trustdb.h" #include "../common/status.h" #include "../common/i18n.h" #include "pkglue.h" #include "../common/sysutils.h" #include "call-agent.h" #include "../common/mbox-util.h" #include "../common/compliance.h" #ifdef HAVE_DOSISH_SYSTEM #define LF "\r\n" #else #define LF "\n" #endif 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 *p = NULL; strlist_t pu = NULL; struct notation *nd = NULL; struct expando_args args; log_assert (sig->version >= 4); memset (&args, 0, sizeof(args)); args.pk = pk; args.pksk = pksk; /* Notation data. */ if (IS_SIG(sig) && opt.sig_notations) nd = opt.sig_notations; else if (IS_CERT(sig) && opt.cert_notations) nd = opt.cert_notations; if (nd) { struct notation *item; for (item = nd; item; item = item->next) { item->altvalue = pct_expando (item->value,&args); if (!item->altvalue) log_error (_("WARNING: unable to %%-expand notation " "(too large). Using unexpanded.\n")); } keygen_add_notations (sig, nd); for (item = nd; item; item = item->next) { xfree (item->altvalue); item->altvalue = NULL; } } /* Set policy URL. */ if (IS_SIG(sig) && opt.sig_policy_url) pu = opt.sig_policy_url; else if (IS_CERT(sig) && opt.cert_policy_url) pu = opt.cert_policy_url; for (; pu; pu = pu->next) { string = pu->d; p = pct_expando (string, &args); if (!p) { log_error(_("WARNING: unable to %%-expand policy URL " "(too large). Using unexpanded.\n")); p = xstrdup(string); } build_sig_subpkt (sig, (SIGSUBPKT_POLICY | ((pu->flags & 1)?SIGSUBPKT_FLAG_CRITICAL:0)), p, strlen (p)); xfree (p); } /* Preferred keyserver URL. */ if (IS_SIG(sig) && opt.sig_keyserver_url) pu = opt.sig_keyserver_url; for (; pu; pu = pu->next) { string = pu->d; p = pct_expando (string, &args); if (!p) { log_error (_("WARNING: unable to %%-expand preferred keyserver URL" " (too large). Using unexpanded.\n")); p = xstrdup (string); } build_sig_subpkt (sig, (SIGSUBPKT_PREF_KS | ((pu->flags & 1)?SIGSUBPKT_FLAG_CRITICAL:0)), p, strlen (p)); xfree (p); } /* Set signer's user id. */ if (IS_SIG (sig) && !opt.flags.disable_signer_uid) { char *mbox; /* For now we use the uid which was used to locate the key. */ if (pksk->user_id && (mbox = mailbox_from_userid (pksk->user_id->name))) { if (DBG_LOOKUP) log_debug ("setting Signer's UID to '%s'\n", mbox); build_sig_subpkt (sig, SIGSUBPKT_SIGNERS_UID, mbox, strlen (mbox)); xfree (mbox); } else if (opt.sender_list) { /* If a list of --sender was given we scan that list and use * the first one matching a user id of the current key. */ /* FIXME: We need to get the list of user ids for the PKSK * packet. That requires either a function to look it up * again or we need to extend the key packet struct to link * to the primary key which in turn could link to the user * ids. Too much of a change right now. Let's take just * one from the supplied list and hope that the caller * passed a matching one. */ build_sig_subpkt (sig, SIGSUBPKT_SIGNERS_UID, opt.sender_list->d, strlen (opt.sender_list->d)); } } } /* * Helper to hash a user ID packet. */ static void hash_uid (gcry_md_hd_t md, int sigversion, const PKT_user_id *uid) { byte buf[5]; (void)sigversion; if (uid->attrib_data) { buf[0] = 0xd1; /* Indicates an attribute packet. */ buf[1] = uid->attrib_len >> 24; /* Always use 4 length bytes. */ buf[2] = uid->attrib_len >> 16; buf[3] = uid->attrib_len >> 8; buf[4] = uid->attrib_len; } else { buf[0] = 0xb4; /* Indicates a userid packet. */ buf[1] = uid->len >> 24; /* Always use 4 length bytes. */ buf[2] = uid->len >> 16; buf[3] = uid->len >> 8; buf[4] = uid->len; } gcry_md_write( md, buf, 5 ); if (uid->attrib_data) gcry_md_write (md, uid->attrib_data, uid->attrib_len ); else gcry_md_write (md, uid->name, uid->len ); } /* * Helper to hash some parts from the signature */ static void hash_sigversion_to_magic (gcry_md_hd_t md, const PKT_signature *sig) { byte buf[6]; size_t n; gcry_md_putc (md, sig->version); gcry_md_putc (md, sig->sig_class); gcry_md_putc (md, sig->pubkey_algo); gcry_md_putc (md, sig->digest_algo); if (sig->hashed) { n = sig->hashed->len; gcry_md_putc (md, (n >> 8) ); gcry_md_putc (md, n ); gcry_md_write (md, sig->hashed->data, n ); n += 6; } else { gcry_md_putc (md, 0); /* Always hash the length of the subpacket. */ gcry_md_putc (md, 0); n = 6; } /* Add some magic. */ buf[0] = sig->version; buf[1] = 0xff; buf[2] = n >> 24; /* (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 for the key. */ static int do_sign (ctrl_t ctrl, PKT_public_key *pksk, PKT_signature *sig, gcry_md_hd_t md, int mdalgo, const char *cache_nonce) { gpg_error_t err; byte *dp; char *hexgrip; if (pksk->timestamp > sig->timestamp ) { ulong d = pksk->timestamp - sig->timestamp; log_info (ngettext("key %s was created %lu second" " in the future (time warp or clock problem)\n", "key %s was created %lu seconds" " in the future (time warp or clock problem)\n", d), keystr_from_pk (pksk), d); if (!opt.ignore_time_conflict) return gpg_error (GPG_ERR_TIME_CONFLICT); } print_pubkey_algo_note (pksk->pubkey_algo); if (!mdalgo) mdalgo = gcry_md_get_algo (md); /* Check compliance. */ if (! gnupg_digest_is_allowed (opt.compliance, 1, mdalgo)) { log_error (_("digest algorithm '%s' may not be used in %s mode\n"), gcry_md_algo_name (mdalgo), gnupg_compliance_option_string (opt.compliance)); err = gpg_error (GPG_ERR_DIGEST_ALGO); goto leave; } if (! gnupg_pk_is_allowed (opt.compliance, PK_USE_SIGNING, pksk->pubkey_algo, pksk->pkey, nbits_from_pk (pksk), NULL)) { log_error (_("key %s may not be used for signing in %s mode\n"), keystr_from_pk (pksk), gnupg_compliance_option_string (opt.compliance)); err = gpg_error (GPG_ERR_PUBKEY_ALGO); goto leave; } if (!gnupg_rng_is_compliant (opt.compliance)) { err = gpg_error (GPG_ERR_FORBIDDEN); log_error (_("%s is not compliant with %s mode\n"), "RNG", gnupg_compliance_option_string (opt.compliance)); write_status_error ("random-compliance", err); goto leave; } print_digest_algo_note (mdalgo); dp = gcry_md_read (md, mdalgo); sig->digest_algo = mdalgo; sig->digest_start[0] = dp[0]; sig->digest_start[1] = dp[1]; mpi_release (sig->data[0]); sig->data[0] = NULL; mpi_release (sig->data[1]); sig->data[1] = NULL; err = hexkeygrip_from_pk (pksk, &hexgrip); if (!err) { char *desc; gcry_sexp_t s_sigval; desc = gpg_format_keydesc (ctrl, pksk, FORMAT_KEYDESC_NORMAL, 1); err = agent_pksign (NULL/*ctrl*/, cache_nonce, hexgrip, desc, pksk->keyid, pksk->main_keyid, pksk->pubkey_algo, dp, gcry_md_get_algo_dlen (mdalgo), mdalgo, &s_sigval); xfree (desc); if (err) ; else if (pksk->pubkey_algo == GCRY_PK_RSA || pksk->pubkey_algo == GCRY_PK_RSA_S) sig->data[0] = get_mpi_from_sexp (s_sigval, "s", GCRYMPI_FMT_USG); else if (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); leave: if (err) log_error (_("signing failed: %s\n"), gpg_strerror (err)); else { if (opt.verbose) { char *ustr = get_user_id_string_native (ctrl, sig->keyid); log_info (_("%s/%s signature from: \"%s\"\n"), openpgp_pk_algo_name (pksk->pubkey_algo), openpgp_md_algo_name (sig->digest_algo), ustr); xfree (ustr); } } return err; } static int complete_sig (ctrl_t ctrl, PKT_signature *sig, PKT_public_key *pksk, gcry_md_hd_t md, const char *cache_nonce) { int rc; /* if (!(rc = check_secret_key (pksk, 0))) */ rc = do_sign (ctrl, 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, NULL); xfree (hexgrip); pk->flags.serialno_valid = 1; } if (!pk->serialno) result = 0; /* Error from a past agent_get_keyinfo or no card. */ else { /* The version number of the card is included in the serialno. */ result = !strncmp (pk->serialno, "D2760001240101", 14); } return result; } static int match_dsa_hash (unsigned int qbytes) { if (qbytes <= 20) return DIGEST_ALGO_SHA1; if (qbytes <= 28) return DIGEST_ALGO_SHA224; if (qbytes <= 32) return DIGEST_ALGO_SHA256; if (qbytes <= 48) return DIGEST_ALGO_SHA384; if (qbytes <= 66 ) /* 66 corresponds to 521 (64 to 512) */ return DIGEST_ALGO_SHA512; return DEFAULT_DIGEST_ALGO; /* DEFAULT_DIGEST_ALGO will certainly fail, but it's the best wrong answer we have if a digest larger than 512 bits is requested. */ } /* First try --digest-algo. If that isn't set, see if the recipient has a preferred algorithm (which is also filtered through --personal-digest-prefs). If we're making a signature without a particular recipient (i.e. signing, rather than signing+encrypting) then take the first algorithm in --personal-digest-prefs that is usable for the pubkey algorithm. If --personal-digest-prefs isn't set, then take the OpenPGP default (i.e. SHA-1). Note that Ed25519+EdDSA takes an input of arbitrary length and thus we don't enforce any particular algorithm like we do for standard ECDSA. However, we use SHA256 as the default algorithm. Possible improvement: Use the highest-ranked usable algorithm from the signing key prefs either before or after using the personal list? */ static int hash_for (PKT_public_key *pk) { if (opt.def_digest_algo) { return opt.def_digest_algo; } else if (recipient_digest_algo) { return recipient_digest_algo; } else if (pk->pubkey_algo == PUBKEY_ALGO_EDDSA && openpgp_oid_is_ed25519 (pk->pkey[0])) { 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 (opt.personal_digest_prefs) { /* It's not DSA, so we can use whatever the first hash algorithm is in the pref list */ return opt.personal_digest_prefs[0].value; } else return DEFAULT_DIGEST_ALGO; } static void print_status_sig_created (PKT_public_key *pk, PKT_signature *sig, int what) { byte array[MAX_FINGERPRINT_LEN]; char buf[100+MAX_FINGERPRINT_LEN*2]; size_t n; snprintf (buf, sizeof buf - 2*MAX_FINGERPRINT_LEN, "%c %d %d %02x %lu ", what, sig->pubkey_algo, sig->digest_algo, sig->sig_class, (ulong)sig->timestamp ); fingerprint_from_pk (pk, array, &n); bin2hex (array, n, buf + strlen (buf)); write_status_text( STATUS_SIG_CREATED, buf ); } /* * Loop over the secret certificates in SK_LIST and build the one pass * signature packets. OpenPGP says that the data should be bracket by * the onepass-sig and signature-packet; so we build these onepass * packet here in reverse order */ static int write_onepass_sig_packets (SK_LIST sk_list, IOBUF out, int sigclass ) { int skcount; SK_LIST sk_rover; for (skcount=0, sk_rover=sk_list; sk_rover; sk_rover = sk_rover->next) skcount++; for (; skcount; skcount--) { PKT_public_key *pk; PKT_onepass_sig *ops; PACKET pkt; int i, rc; for (i=0, sk_rover = sk_list; sk_rover; sk_rover = sk_rover->next ) { if (++i == skcount) break; } pk = sk_rover->pk; ops = xmalloc_clear (sizeof *ops); ops->sig_class = sigclass; ops->digest_algo = hash_for (pk); ops->pubkey_algo = pk->pubkey_algo; keyid_from_pk (pk, ops->keyid); ops->last = (skcount == 1); init_packet(&pkt); pkt.pkttype = PKT_ONEPASS_SIG; pkt.pkt.onepass_sig = ops; rc = build_packet (out, &pkt); free_packet (&pkt, NULL); if (rc) { log_error ("build onepass_sig packet failed: %s\n", gpg_strerror (rc)); return rc; } } return 0; } /* * Helper to write the plaintext (literal data) packet */ 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' || ptmode == 'u' || ptmode == 'm') filesize = 0; } else filesize = opt.set_filesize? opt.set_filesize : 0; /* stdin */ if (!opt.no_literal) { PACKET pkt; /* Note that PT has been initialized above in no_literal mode. */ pt->timestamp = make_timestamp (); pt->mode = ptmode; pt->len = filesize; pt->new_ctb = !pt->len; pt->buf = inp; init_packet(&pkt); pkt.pkttype = PKT_PLAINTEXT; pkt.pkt.plaintext = pt; /*cfx.datalen = filesize? calc_packet_length( &pkt ) : 0;*/ if( (rc = build_packet (out, &pkt)) ) log_error ("build_packet(PLAINTEXT) failed: %s\n", gpg_strerror (rc) ); pt->buf = NULL; free_packet (&pkt, 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 (ctrl_t ctrl, 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 = xtrycalloc (1, sizeof *sig); if (!sig) return gpg_error_from_syserror (); 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, pk); mk_notation_policy_etc (sig, NULL, pk); } hash_sigversion_to_magic (md, sig); gcry_md_final (md); rc = do_sign (ctrl, 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, NULL); if (rc) log_error ("build signature packet failed: %s\n", gpg_strerror (rc)); } else xfree (sig); 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); efx.ctrl = ctrl; init_packet( &pkt ); if( filenames ) { fname = filenames->d; multifile = !!filenames->next; } else fname = NULL; if( fname && filenames->next && (!detached || encryptflag) ) log_bug("multiple files can only be detached signed"); if(encryptflag==2 && (rc=setup_symkey(&efx.symkey_s2k,&efx.symkey_dek))) goto leave; if (opt.ask_sig_expire && !opt.batch) duration = ask_expire_interval(1,opt.def_sig_expire); else duration = parse_expire_string(opt.def_sig_expire); /* Note: In the old non-agent version the following call used to unprotect the secret key. This is now done on demand by the agent. */ if( (rc = build_sk_list (ctrl, locusr, &sk_list, PUBKEY_USAGE_SIG )) ) goto leave; if (encryptflag && (rc=build_pk_list (ctrl, remusr, &pk_list))) goto leave; /* prepare iobufs */ if( multifile ) /* have list of filenames */ inp = NULL; /* we do it later */ else { inp = iobuf_open(fname); if (inp && is_secured_file (iobuf_get_fd (inp))) { iobuf_close (inp); inp = NULL; gpg_err_set_errno (EPERM); } if( !inp ) { rc = gpg_error_from_syserror (); log_error (_("can't open '%s': %s\n"), fname? fname: "[stdin]", strerror(errno) ); goto leave; } handle_progress (pfx, inp, fname); } if( outfile ) { if (is_secured_filename ( outfile )) { out = NULL; gpg_err_set_errno (EPERM); } else out = iobuf_create (outfile, 0); if( !out ) { rc = gpg_error_from_syserror (); log_error(_("can't create '%s': %s\n"), outfile, strerror(errno) ); goto leave; } else if( opt.verbose ) log_info(_("writing to '%s'\n"), outfile ); } else if( (rc = open_outfile (-1, fname, opt.armor? 1: detached? 2:0, 0, &out))) goto leave; /* prepare to calculate the MD over the input */ if( opt.textmode && !outfile && !multifile ) { memset( &tfx, 0, sizeof tfx); iobuf_push_filter( inp, text_filter, &tfx ); } if ( gcry_md_open (&mfx.md, 0, 0) ) BUG (); if (DBG_HASHING) gcry_md_debug (mfx.md, "sign"); /* If we're encrypting and signing, it is reasonable to pick the hash algorithm to use out of the recipient key prefs. This is best effort only, as in a DSA2 and smartcard world there are cases where we cannot please everyone with a single hash (DSA2 wants >160 and smartcards want =160). In the future this could be more complex with different hashes for each sk, but the current design requires a single hash for all SKs. */ if(pk_list) { if(opt.def_digest_algo) { if(!opt.expert && select_algo_from_prefs(pk_list,PREFTYPE_HASH, opt.def_digest_algo, NULL)!=opt.def_digest_algo) log_info(_("WARNING: forcing digest algorithm %s (%d)" " violates recipient preferences\n"), gcry_md_algo_name (opt.def_digest_algo), opt.def_digest_algo ); } else { int algo, smartcard=0; union pref_hint hint; hint.digest_length = 0; /* Of course, if the recipient asks for something unreasonable (like the wrong hash for a DSA key) then don't do it. Check all sk's - if any are DSA or live on a smartcard, then the hash has restrictions and we may not be able to give the recipient what they want. For DSA, pass a hint for the largest q we have. Note that this means that a q>160 key will override a q=160 key and force the use of truncation for the q=160 key. The alternative would be to ignore the recipient prefs completely and get a different hash for each DSA key in hash_for(). The override behavior here is more or less reasonable as it is under the control of the user which keys they sign with for a given message and the fact that the message with multiple signatures won't be usable on an implementation that doesn't understand DSA2 anyway. */ for (sk_rover = sk_list; sk_rover; sk_rover = sk_rover->next ) { if (sk_rover->pk->pubkey_algo == PUBKEY_ALGO_DSA || sk_rover->pk->pubkey_algo == PUBKEY_ALGO_ECDSA) { int temp_hashlen = (gcry_mpi_get_nbits (sk_rover->pk->pkey[1])); if (sk_rover->pk->pubkey_algo == PUBKEY_ALGO_ECDSA) temp_hashlen = ecdsa_qbits_from_Q (temp_hashlen); temp_hashlen = (temp_hashlen+7)/8; /* Pick a hash that is large enough for our largest q */ if (hint.digest_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) afx->what = 2; if( opt.armor && !outfile ) push_armor_filter (afx, out); if( encryptflag ) { efx.pk_list = pk_list; /* fixme: set efx.cfx.datalen if known */ iobuf_push_filter( out, encrypt_filter, &efx ); } if (opt.compress_algo && !outfile && !detached) { int compr_algo=opt.compress_algo; /* If not forced by user */ if(compr_algo==-1) { /* If we're not encrypting, then select_algo_from_prefs will fail and we'll end up with the default. If we are encrypting, select_algo_from_prefs cannot fail since there is an assumed preference for uncompressed data. Still, if it did fail, we'll also end up with the default. */ if((compr_algo= select_algo_from_prefs(pk_list,PREFTYPE_ZIP,-1,NULL))==-1) compr_algo=default_compress_algo(); } else if(!opt.expert && pk_list && select_algo_from_prefs(pk_list,PREFTYPE_ZIP, compr_algo,NULL)!=compr_algo) log_info(_("WARNING: forcing compression algorithm %s (%d)" " violates recipient preferences\n"), compress_algo_to_string(compr_algo),compr_algo); /* algo 0 means no compression */ if( compr_algo ) push_compress_filter(out,&zfx,compr_algo); } /* Write the one-pass signature packets if needed */ if (!detached) { rc = write_onepass_sig_packets (sk_list, out, opt.textmode && !outfile ? 0x01:0x00); if (rc) goto leave; } write_status_begin_signing (mfx.md); /* Setup the inner packet. */ if( detached ) { if( multifile ) { strlist_t sl; if( opt.verbose ) log_info(_("signing:") ); /* must walk reverse trough this list */ for( sl = strlist_last(filenames); sl; sl = strlist_prev( filenames, sl ) ) { inp = iobuf_open(sl->d); if (inp && is_secured_file (iobuf_get_fd (inp))) { iobuf_close (inp); inp = NULL; gpg_err_set_errno (EPERM); } if( !inp ) { rc = gpg_error_from_syserror (); log_error(_("can't open '%s': %s\n"), sl->d,strerror(errno)); goto leave; } handle_progress (pfx, inp, sl->d); if( opt.verbose ) log_printf (" '%s'", sl->d ); if(opt.textmode) { memset( &tfx, 0, sizeof tfx); iobuf_push_filter( inp, text_filter, &tfx ); } iobuf_push_filter( inp, md_filter, &mfx ); while( iobuf_get(inp) != -1 ) ; iobuf_close(inp); inp = NULL; } if( opt.verbose ) log_printf ("\n"); } else { /* read, so that the filter can calculate the digest */ while( iobuf_get(inp) != -1 ) ; } } else { rc = write_plaintext_packet (out, inp, fname, opt.textmode && !outfile ? (opt.mimemode? 'm':'t'):'b'); } /* catch errors from above */ if (rc) goto leave; /* write the signatures */ rc = write_signature_packets (ctrl, 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 (ctrl_t ctrl, const char *fname, strlist_t locusr, const char *outfile ) { armor_filter_context_t *afx; progress_filter_context_t *pfx; gcry_md_hd_t textmd = NULL; IOBUF inp = NULL, out = NULL; PACKET pkt; int rc = 0; SK_LIST sk_list = NULL; SK_LIST sk_rover = NULL; u32 duration=0; pfx = new_progress_context (); afx = new_armor_context (); init_packet( &pkt ); if (opt.ask_sig_expire && !opt.batch) duration = ask_expire_interval (1,opt.def_sig_expire); else duration = parse_expire_string (opt.def_sig_expire); /* Note: In the old non-agent version the following call used to unprotect the secret key. This is now done on demand by the agent. */ if( (rc=build_sk_list (ctrl, locusr, &sk_list, PUBKEY_USAGE_SIG )) ) goto leave; /* prepare iobufs */ inp = iobuf_open(fname); if (inp && is_secured_file (iobuf_get_fd (inp))) { iobuf_close (inp); inp = NULL; gpg_err_set_errno (EPERM); } if( !inp ) { rc = gpg_error_from_syserror (); log_error (_("can't open '%s': %s\n"), fname? fname: "[stdin]", 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, 0); 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 (-1, fname, 1, 0, &out))) goto leave; iobuf_writestr(out, "-----BEGIN PGP SIGNED MESSAGE-----" LF ); { const char *s; int any = 0; byte hashs_seen[256]; memset( hashs_seen, 0, sizeof hashs_seen ); iobuf_writestr(out, "Hash: " ); for( sk_rover = sk_list; sk_rover; sk_rover = sk_rover->next ) { int i = hash_for (sk_rover->pk); if( !hashs_seen[ i & 0xff ] ) { s = gcry_md_algo_name ( i ); if( s ) { hashs_seen[ i & 0xff ] = 1; if( any ) iobuf_put(out, ',' ); iobuf_writestr(out, s ); any = 1; } } } log_assert(any); iobuf_writestr(out, LF ); } if( opt.not_dash_escaped ) iobuf_writestr( out, "NotDashEscaped: You need "GPG_NAME " to verify this message" LF ); iobuf_writestr(out, LF ); if ( gcry_md_open (&textmd, 0, 0) ) BUG (); for (sk_rover = sk_list; sk_rover; sk_rover = sk_rover->next) gcry_md_enable (textmd, hash_for(sk_rover->pk)); if ( DBG_HASHING ) gcry_md_debug ( textmd, "clearsign" ); copy_clearsig_text (out, inp, textmd, !opt.not_dash_escaped, opt.escape_from); /* fixme: check for read errors */ /* now write the armor */ afx->what = 2; push_armor_filter (afx, out); /* Write the signatures. */ rc = write_signature_packets (ctrl, sk_list, out, textmd, 0x01, 0, duration, 'C', NULL); if( rc ) goto leave; leave: if( rc ) iobuf_cancel(out); else iobuf_close(out); iobuf_close(inp); gcry_md_close ( textmd ); release_sk_list( sk_list ); release_progress_context (pfx); release_armor_context (afx); return rc; } /* * Sign and conventionally encrypt the given file. * FIXME: Far too much code is duplicated - revamp the whole file. */ int sign_symencrypt_file (ctrl_t ctrl, const char *fname, strlist_t locusr) { armor_filter_context_t *afx; progress_filter_context_t *pfx; compress_filter_context_t zfx; md_filter_context_t mfx; text_filter_context_t tfx; cipher_filter_context_t cfx; IOBUF 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.ask_sig_expire && !opt.batch) duration = ask_expire_interval (1, opt.def_sig_expire); else duration = parse_expire_string (opt.def_sig_expire); /* Note: In the old non-agent version the following call used to unprotect the secret key. This is now done on demand by the agent. */ rc = build_sk_list (ctrl, locusr, &sk_list, PUBKEY_USAGE_SIG); if (rc) goto leave; /* prepare iobufs */ inp = iobuf_open(fname); if (inp && is_secured_file (iobuf_get_fd (inp))) { iobuf_close (inp); inp = NULL; gpg_err_set_errno (EPERM); } if( !inp ) { rc = gpg_error_from_syserror (); log_error (_("can't open '%s': %s\n"), fname? fname: "[stdin]", strerror(errno) ); goto leave; } handle_progress (pfx, inp, fname); /* prepare key */ s2k = xmalloc_clear( sizeof *s2k ); s2k->mode = opt.s2k_mode; s2k->hash_algo = S2K_DIGEST_ALGO; algo = default_cipher_algo(); - if (!opt.quiet || !opt.batch) - log_info (_("%s encryption will be used\n"), - openpgp_cipher_algo_name (algo) ); cfx.dek = passphrase_to_dek (algo, s2k, 1, 1, NULL, &canceled); if (!cfx.dek || !cfx.dek->keylen) { rc = gpg_error (canceled?GPG_ERR_CANCELED:GPG_ERR_BAD_PASSPHRASE); log_error(_("error creating passphrase: %s\n"), gpg_strerror (rc) ); goto leave; } cfx.dek->use_aead = use_aead (NULL, cfx.dek->algo); if (!cfx.dek->use_aead) cfx.dek->use_mdc = !!use_mdc (NULL, cfx.dek->algo); + if (!opt.quiet || !opt.batch) + log_info (_("%s.%s encryption will be used\n"), + openpgp_cipher_algo_name (algo), + cfx.dek->use_aead? openpgp_aead_algo_name (cfx.dek->use_aead) + /**/ : "CFB"); + /* now create the outfile */ rc = open_outfile (-1, fname, opt.armor? 1:0, 0, &out); if (rc) goto leave; /* prepare to calculate the MD over the input */ if (opt.textmode) iobuf_push_filter (inp, text_filter, &tfx); if ( gcry_md_open (&mfx.md, 0, 0) ) BUG (); if ( DBG_HASHING ) gcry_md_debug (mfx.md, "symc-sign"); for (sk_rover = sk_list; sk_rover; sk_rover = sk_rover->next) gcry_md_enable (mfx.md, hash_for (sk_rover->pk)); iobuf_push_filter (inp, md_filter, &mfx); /* Push armor output filter */ if (opt.armor) push_armor_filter (afx, out); /* Write the symmetric key packet */ /*(current filters: armor)*/ { PKT_symkey_enc *enc = xmalloc_clear( sizeof *enc ); enc->version = 4; enc->cipher_algo = cfx.dek->algo; enc->s2k = *s2k; pkt.pkttype = PKT_SYMKEY_ENC; pkt.pkt.symkey_enc = enc; if( (rc = build_packet( out, &pkt )) ) log_error("build symkey packet failed: %s\n", gpg_strerror (rc) ); xfree(enc); } /* Push the encryption filter */ iobuf_push_filter (out, cfx.dek->use_aead? cipher_filter_aead /**/ : cipher_filter_cfb, &cfx); /* Push the compress filter */ if (default_compress_algo()) { if (cfx.dek && (cfx.dek->use_mdc || cfx.dek->use_aead)) zfx.new_ctb = 1; push_compress_filter (out, &zfx,default_compress_algo() ); } /* Write the one-pass signature packets */ /*(current filters: zip - encrypt - armor)*/ rc = write_onepass_sig_packets (sk_list, out, opt.textmode? 0x01:0x00); if (rc) goto leave; write_status_begin_signing (mfx.md); /* Pipe data through all filters; i.e. write the signed stuff */ /*(current filters: zip - encrypt - armor)*/ rc = write_plaintext_packet (out, inp, fname, opt.textmode ? (opt.mimemode?'m':'t'):'b'); if (rc) goto leave; /* Write the signatures */ /*(current filters: zip - encrypt - armor)*/ rc = write_signature_packets (ctrl, 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 v4 signature in *RET_SIG. * * PK is the primary key to sign (required for all sigs) * UID is the user id to sign (required for 0x10..0x13, 0x30) * SUBPK is subkey to sign (required for 0x18, 0x19, 0x28) * * PKSK is the signing key * * SIGCLASS is the type of signature to create. * * DIGEST_ALGO is the digest algorithm. If it is 0 the function * selects an appropriate one. * * TIMESTAMP is the timestamp to use for the signature. 0 means "now" * * DURATION is the amount of time (in seconds) until the signature * expires. * * This function creates the following subpackets: issuer, created, * and expire (if duration is not 0). Additional subpackets can be * added using MKSUBPKT, which is called after these subpackets are * added and before the signature is generated. OPAQUE is passed to * MKSUBPKT. */ int make_keysig_packet (ctrl_t ctrl, PKT_signature **ret_sig, PKT_public_key *pk, PKT_user_id *uid, PKT_public_key *subpk, PKT_public_key *pksk, int sigclass, int digest_algo, u32 timestamp, u32 duration, int (*mksubpkt)(PKT_signature *, void *), void *opaque, const char *cache_nonce) { PKT_signature *sig; int rc=0; int sigversion; gcry_md_hd_t md; log_assert ((sigclass >= 0x10 && sigclass <= 0x13) || sigclass == 0x1F || sigclass == 0x20 || sigclass == 0x18 || sigclass == 0x19 || sigclass == 0x30 || sigclass == 0x28 ); sigversion = 4; if (sigversion < pksk->version) sigversion = pksk->version; if( !digest_algo ) { /* Basically, this means use SHA1 always unless 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_DSA) digest_algo = match_dsa_hash (gcry_mpi_get_nbits (pksk->pkey[1])/8); 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 = DEFAULT_DIGEST_ALGO; } 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; build_sig_subpkt_from_sig (sig, pksk); 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 (mksubpkt) rc = (*mksubpkt)( sig, opaque ); if( !rc ) { hash_sigversion_to_magic (md, sig); gcry_md_final (md); rc = complete_sig (ctrl, 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. */ gpg_error_t update_keysig_packet (ctrl_t ctrl, PKT_signature **ret_sig, PKT_signature *orig_sig, PKT_public_key *pk, PKT_user_id *uid, PKT_public_key *subpk, PKT_public_key *pksk, int (*mksubpkt)(PKT_signature *, void *), void *opaque) { PKT_signature *sig; gpg_error_t rc = 0; int digest_algo; gcry_md_hd_t md; if ((!orig_sig || !pk || !pksk) || (orig_sig->sig_class >= 0x10 && orig_sig->sig_class <= 0x13 && !uid) || (orig_sig->sig_class == 0x18 && !subpk)) return GPG_ERR_GENERAL; 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. */ { int tmout = 0; while(sig->timestamp<=orig_sig->timestamp) { if (++tmout > 5 && !opt.ignore_time_conflict) { rc = gpg_error (GPG_ERR_TIME_CONFLICT); goto leave; } gnupg_sleep (1); sig->timestamp=make_timestamp(); } } /* Note that already expired sigs will remain expired (with a duration of 1) since build-packet.c:build_sig_subpkt_from_sig detects this case. */ /* Put the updated timestamp into the sig. Note that this will automagically lower any sig expiration dates to correctly correspond to the differences in the timestamps (i.e. the duration will shrink). */ build_sig_subpkt_from_sig (sig, pksk); if (mksubpkt) rc = (*mksubpkt)(sig, opaque); if (!rc) { hash_sigversion_to_magic (md, sig); gcry_md_final (md); rc = complete_sig (ctrl, sig, pksk, md, NULL); } leave: gcry_md_close (md); if( rc ) free_seckey_enc (sig); else *ret_sig = sig; return rc; }