diff --git a/g10/build-packet.c b/g10/build-packet.c index a1db0251d..268bd71b2 100644 --- a/g10/build-packet.c +++ b/g10/build-packet.c @@ -1,1957 +1,2050 @@ /* 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 keyblock image from KEYBLOCK. Returns 0 on success and * only then stores a new iobuf object at R_IOBUF; the returned iobuf * can be access with the iobuf_get_temp_buffer and * iobuf_get_temp_length macros. */ gpg_error_t build_keyblock_image (kbnode_t keyblock, iobuf_t *r_iobuf) { gpg_error_t err; iobuf_t iobuf; kbnode_t kbctx, node; *r_iobuf = NULL; iobuf = iobuf_temp (); for (kbctx = NULL; (node = walk_kbnode (keyblock, &kbctx, 0));) { /* Make sure to use only packets valid on a keyblock. */ switch (node->pkt->pkttype) { case PKT_PUBLIC_KEY: case PKT_PUBLIC_SUBKEY: case PKT_SIGNATURE: case PKT_USER_ID: case PKT_ATTRIBUTE: case PKT_RING_TRUST: break; default: continue; } err = build_packet_and_meta (iobuf, node->pkt); if (err) { iobuf_close (iobuf); return err; } } *r_iobuf = iobuf; return 0; } /* 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. If R_NWRITTEN is not NULL the number of * bytes written is stored there. To only get the number of bytes * which would be written NULL may be passed for OUT. */ gpg_error_t gpg_mpi_write (iobuf_t out, gcry_mpi_t a, unsigned int *r_nwritten) { gpg_error_t err; unsigned int nwritten = 0; 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; err = out? iobuf_write (out, lenhdr, 2) : 0; if (!err) { nwritten += 2; if (p) { err = out? iobuf_write (out, p, (nbits+7)/8) : 0; if (!err) nwritten += (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); err = gcry_mpi_print (GCRYMPI_FMT_PGP, buffer, nbytes, &nbytes, a ); if (!err) { err = out? iobuf_write (out, buffer, nbytes) : 0; if (!err) nwritten += nbytes; } else if (gpg_err_code (err) == 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. */ err = gpg_error (GPG_ERR_TOO_LARGE); } } if (r_nwritten) *r_nwritten = nwritten; return err; } /* - * Write an opaque MPI to the output stream without length info. + * Write the mpi A to the output stream OUT as "SOS" (Strange Octet + * String). If R_NWRITTEN is not NULL the number of bytes written is + * stored there. To only get the number of bytes which would be + * written, NULL may be passed for OUT. + */ +static gpg_error_t +sos_write (iobuf_t out, gcry_mpi_t a, unsigned int *r_nwritten) +{ + gpg_error_t err; + unsigned int nwritten = 0; + + 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); + /* gcry_log_debug (" [%u bit]\n", nbits); */ + /* gcry_log_debughex (" ", p, (nbits+7)/8); */ + + if (p && *p) + { + nbits = ((nbits + 7) / 8) * 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; + } + + lenhdr[0] = nbits >> 8; + lenhdr[1] = nbits; + err = out? iobuf_write (out, lenhdr, 2) : 0; + if (!err) + { + nwritten += 2; + if (p) + { + err = out? iobuf_write (out, p, (nbits+7)/8) : 0; + if (!err) + nwritten += (nbits+7)/8; + } + } + } + else + { + log_info ("non-opaque MPI (%u bits) for SOS\n", gcry_mpi_get_nbits (a)); + err = gpg_error (GPG_ERR_INV_DATA); + } + + if (r_nwritten) + *r_nwritten = nwritten; + return err; +} + + +/* + * Write an opaque string 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. We also check for the * maximum allowed packet size by the parser using an arbitrary * extra 10 bytes for header data. */ if (uid->attrib_data) { if (uid->attrib_len > MAX_ATTR_PACKET_LENGTH - 10) return gpg_error (GPG_ERR_TOO_LARGE); 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 { if (uid->len > MAX_UID_PACKET_LENGTH - 10) return gpg_error (GPG_ERR_TOO_LARGE); 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; iobuf_t a; int i, nskey, npkey; u32 pkbytes = 0; int is_v5; log_assert (pk->version == 0 || pk->version == 4 || pk->version == 5); 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); /* 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 content * of this buffer to OUT. */ a = iobuf_temp(); /* Note that the Version number, Timestamp, Algo, and the v5 Key * material count are written at the end of the function. */ is_v5 = (pk->version == 5); /* 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 if (pk->pubkey_algo == PUBKEY_ALGO_ECDSA + || pk->pubkey_algo == PUBKEY_ALGO_EDDSA + || pk->pubkey_algo == PUBKEY_ALGO_ECDH) + err = sos_write (a, pk->pkey[i], NULL); else err = gpg_mpi_write (a, pk->pkey[i], NULL); if (err) goto leave; } /* Record the length of the public key part. */ pkbytes = iobuf_get_temp_length (a); 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) { iobuf_put (a, ski->sha1chk? 0xfe : 0xff); /* S2k usage. */ if (is_v5) { /* For a v5 key determine the count of the following * key-protection material and write it. */ int count = 1; /* Pubkey algo octet. */ if (ski->s2k.mode >= 1000) count += 6; /* GNU specific mode descriptor. */ else count += 2; /* Mode and hash algo. */ if (ski->s2k.mode == 1 || ski->s2k.mode == 3) count += 8; /* Salt. */ if (ski->s2k.mode == 3) count++; /* S2K.COUNT */ if (ski->s2k.mode != 1001 && ski->s2k.mode != 1002) count += ski->ivlen; iobuf_put (a, count); } iobuf_put (a, ski->algo); /* Pubkey algo octet. */ 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 ); /* S2K usage = not protected. */ if (is_v5) iobuf_put (a, 0); /* Zero octets of key-protection * material follows. */ } if (ski->s2k.mode == 1001) { /* GnuPG extension - don't write a secret key at all. */ if (is_v5) write_32 (a, 0); /* Zero octets of key material. */ } else if (ski->s2k.mode == 1002) { /* GnuPG extension - divert to OpenPGP smartcard. */ if (is_v5) write_32 (a, 1 + ski->ivlen); /* 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); /* For v5 keys we first write the number of octets of the * following encrypted key material. */ if (is_v5) write_32 (a, p? (ndatabits+7)/8 : 0); if (p) iobuf_write (a, p, (ndatabits+7)/8 ); } else { /* Non-protected key. */ if (is_v5) { unsigned int skbytes = 0; unsigned int n; int j; for (j=i; j < nskey; j++ ) { - if ((err = gpg_mpi_write (NULL, pk->pkey[j], &n))) - goto leave; + if (pk->pubkey_algo == PUBKEY_ALGO_ECDSA + || pk->pubkey_algo == PUBKEY_ALGO_EDDSA + || pk->pubkey_algo == PUBKEY_ALGO_ECDH) + { + if ((err = sos_write (NULL, pk->pkey[j], &n))) + goto leave; + } + else + { + if ( (err = gpg_mpi_write (a, pk->pkey[i], NULL))) + goto leave; + } skbytes += n; } write_32 (a, skbytes); } for ( ; i < nskey; i++ ) - if ( (err = gpg_mpi_write (a, pk->pkey[i], NULL))) - goto leave; + if (pk->pubkey_algo == PUBKEY_ALGO_ECDSA + || pk->pubkey_algo == PUBKEY_ALGO_EDDSA + || pk->pubkey_algo == PUBKEY_ALGO_ECDH) + { + if ((err = sos_write (a, pk->pkey[i], NULL))) + goto leave; + } + else + if ((err = gpg_mpi_write (a, pk->pkey[i], NULL))) + 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 */ u32 len = iobuf_get_temp_length (a); len += 1; /* version number */ len += 4; /* timestamp */ len += 1; /* algo */ if (is_v5) len += 4; /* public key material count */ write_header2 (out, ctb, len, 0); /* And finally write it out to the real stream. */ iobuf_put (out, pk->version? pk->version : 4); /* version number */ write_32 (out, pk->timestamp ); iobuf_put (out, pk->pubkey_algo); /* algo */ if (is_v5) write_32 (out, pkbytes); /* public key material count */ err = iobuf_write_temp (out, a); /* pub and sec key material */ } 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); 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); 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); write_header (out, ctb, iobuf_get_temp_length(a)); rc = iobuf_write_temp (out, a); 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 if (enc->pubkey_algo == PUBKEY_ALGO_ECDH) + rc = sos_write (a, enc->data[i], NULL); else rc = gpg_mpi_write (a, enc->data[i], NULL); } 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 || fprlen == 32) { buf[0] = pksk->version; build_sig_subpkt (sig, SIGSUBPKT_ISSUER_FPR, buf, fprlen + 1); } /* 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); memcpy(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, 1, 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 used by pre-v4 signatures. */ 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], NULL); + if (sig->pubkey_algo == PUBKEY_ALGO_ECDSA + || sig->pubkey_algo == PUBKEY_ALGO_EDDSA) + for (i=0; i < n && !rc ; i++ ) + rc = sos_write (a, sig->data[i], NULL); + else + for (i=0; i < n && !rc ; i++ ) + rc = gpg_mpi_write (a, sig->data[i], NULL); 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/export.c b/g10/export.c index a76a7da84..d06896026 100644 --- a/g10/export.c +++ b/g10/export.c @@ -1,2497 +1,2495 @@ /* export.c - Export keys in the OpenPGP defined format. * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, * 2005, 2010 Free Software Foundation, Inc. * Copyright (C) 1998-2016 Werner Koch * * This file is part of GnuPG. * * GnuPG is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * GnuPG is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . */ #include #include #include #include #include #include "gpg.h" #include "options.h" #include "packet.h" #include "../common/status.h" #include "keydb.h" #include "../common/util.h" #include "main.h" #include "../common/i18n.h" #include "../common/membuf.h" #include "../common/host2net.h" #include "../common/zb32.h" #include "../common/recsel.h" #include "../common/mbox-util.h" #include "../common/init.h" #include "trustdb.h" #include "call-agent.h" #include "key-clean.h" +#include "pkglue.h" /* An object to keep track of subkeys. */ struct subkey_list_s { struct subkey_list_s *next; u32 kid[2]; }; typedef struct subkey_list_s *subkey_list_t; /* An object to track statistics for export operations. */ struct export_stats_s { ulong count; /* Number of processed keys. */ ulong secret_count; /* Number of secret keys seen. */ ulong exported; /* Number of actual exported keys. */ }; /* A global variable to store the selector created from * --export-filter keep-uid=EXPR. * --export-filter drop-subkey=EXPR. * * FIXME: We should put this into the CTRL object but that requires a * lot more changes right now. */ static recsel_expr_t export_keep_uid; static recsel_expr_t export_drop_subkey; /* An object used for a linked list to implement the * push_export_filter/pop_export_filters functions. */ struct export_filter_attic_s { struct export_filter_attic_s *next; recsel_expr_t export_keep_uid; recsel_expr_t export_drop_subkey; }; static struct export_filter_attic_s *export_filter_attic; /* Local prototypes. */ static int do_export (ctrl_t ctrl, strlist_t users, int secret, unsigned int options, export_stats_t stats); static int do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret, kbnode_t *keyblock_out, unsigned int options, export_stats_t stats, int *any); static gpg_error_t print_pka_or_dane_records /**/ (iobuf_t out, kbnode_t keyblock, PKT_public_key *pk, const void *data, size_t datalen, int print_pka, int print_dane); static void cleanup_export_globals (void) { recsel_release (export_keep_uid); export_keep_uid = NULL; recsel_release (export_drop_subkey); export_drop_subkey = NULL; } /* Option parser for export options. See parse_options for details. */ int parse_export_options(char *str,unsigned int *options,int noisy) { struct parse_options export_opts[]= { {"export-local-sigs",EXPORT_LOCAL_SIGS,NULL, N_("export signatures that are marked as local-only")}, {"export-attributes",EXPORT_ATTRIBUTES,NULL, N_("export attribute user IDs (generally photo IDs)")}, {"export-sensitive-revkeys",EXPORT_SENSITIVE_REVKEYS,NULL, N_("export revocation keys marked as \"sensitive\"")}, {"export-clean",EXPORT_CLEAN,NULL, N_("remove unusable parts from key during export")}, {"export-minimal",EXPORT_MINIMAL|EXPORT_CLEAN,NULL, N_("remove as much as possible from key during export")}, {"export-drop-uids", EXPORT_DROP_UIDS, NULL, N_("Do not export user id or attribute packets")}, {"export-pka", EXPORT_PKA_FORMAT, NULL, NULL }, {"export-dane", EXPORT_DANE_FORMAT, NULL, NULL }, {"backup", EXPORT_BACKUP, NULL, N_("use the GnuPG key backup format")}, {"export-backup", EXPORT_BACKUP, NULL, NULL }, /* Aliases for backward compatibility */ {"include-local-sigs",EXPORT_LOCAL_SIGS,NULL,NULL}, {"include-attributes",EXPORT_ATTRIBUTES,NULL,NULL}, {"include-sensitive-revkeys",EXPORT_SENSITIVE_REVKEYS,NULL,NULL}, /* dummy */ {"export-unusable-sigs",0,NULL,NULL}, {"export-clean-sigs",0,NULL,NULL}, {"export-clean-uids",0,NULL,NULL}, {NULL,0,NULL,NULL} /* add tags for include revoked and disabled? */ }; int rc; rc = parse_options (str, options, export_opts, noisy); if (!rc) return 0; /* Alter other options we want or don't want for restore. */ if ((*options & EXPORT_BACKUP)) { *options |= (EXPORT_LOCAL_SIGS | EXPORT_ATTRIBUTES | EXPORT_SENSITIVE_REVKEYS); *options &= ~(EXPORT_CLEAN | EXPORT_MINIMAL | EXPORT_PKA_FORMAT | EXPORT_DANE_FORMAT); } /* Dropping uids also means to drop attributes. */ if ((*options & EXPORT_DROP_UIDS)) *options &= ~(EXPORT_ATTRIBUTES); return rc; } /* Parse and set an export filter from string. STRING has the format * "NAME=EXPR" with NAME being the name of the filter. Spaces before * and after NAME are not allowed. If this function is called several * times all expressions for the same NAME are concatenated. * Supported filter names are: * * - keep-uid :: If the expression evaluates to true for a certain * user ID packet, that packet and all it dependencies * will be exported. The expression may use these * variables: * * - uid :: The entire user ID. * - mbox :: The mail box part of the user ID. * - primary :: Evaluate to true for the primary user ID. * * - drop-subkey :: If the expression evaluates to true for a subkey * packet that subkey and all it dependencies will be * remove from the keyblock. The expression may use these * variables: * * - secret :: 1 for a secret subkey, else 0. * - key_algo :: Public key algorithm id */ gpg_error_t parse_and_set_export_filter (const char *string) { gpg_error_t err; /* Auto register the cleanup function. */ register_mem_cleanup_func (cleanup_export_globals); if (!strncmp (string, "keep-uid=", 9)) err = recsel_parse_expr (&export_keep_uid, string+9); else if (!strncmp (string, "drop-subkey=", 12)) err = recsel_parse_expr (&export_drop_subkey, string+12); else err = gpg_error (GPG_ERR_INV_NAME); return err; } /* Push the current export filters onto a stack so that new export * filters can be defined which will be active until the next * pop_export_filters or another push_export_filters. */ void push_export_filters (void) { struct export_filter_attic_s *item; item = xcalloc (1, sizeof *item); item->export_keep_uid = export_keep_uid; export_keep_uid = NULL; item->export_drop_subkey = export_drop_subkey; export_drop_subkey = NULL; item->next = export_filter_attic; export_filter_attic = item; } /* Revert the last push_export_filters. */ void pop_export_filters (void) { struct export_filter_attic_s *item; item = export_filter_attic; if (!item) BUG (); /* No corresponding push. */ export_filter_attic = item->next; cleanup_export_globals (); export_keep_uid = item->export_keep_uid; export_drop_subkey = item->export_drop_subkey; } /* Create a new export stats object initialized to zero. On error returns NULL and sets ERRNO. */ export_stats_t export_new_stats (void) { export_stats_t stats; return xtrycalloc (1, sizeof *stats); } /* Release an export stats object. */ void export_release_stats (export_stats_t stats) { xfree (stats); } /* Print export statistics using the status interface. */ void export_print_stats (export_stats_t stats) { if (!stats) return; if (is_status_enabled ()) { char buf[15*20]; snprintf (buf, sizeof buf, "%lu %lu %lu", stats->count, stats->secret_count, stats->exported ); write_status_text (STATUS_EXPORT_RES, buf); } } /* * Export public keys (to stdout or to --output FILE). * * Depending on opt.armor the output is armored. OPTIONS are defined * in main.h. If USERS is NULL, all keys will be exported. STATS is * either an export stats object for update or NULL. * * This function is the core of "gpg --export". */ int export_pubkeys (ctrl_t ctrl, strlist_t users, unsigned int options, export_stats_t stats) { return do_export (ctrl, users, 0, options, stats); } /* * Export secret keys (to stdout or to --output FILE). * * Depending on opt.armor the output is armored. OPTIONS are defined * in main.h. If USERS is NULL, all secret keys will be exported. * STATS is either an export stats object for update or NULL. * * This function is the core of "gpg --export-secret-keys". */ int export_seckeys (ctrl_t ctrl, strlist_t users, unsigned int options, export_stats_t stats) { return do_export (ctrl, users, 1, options, stats); } /* * Export secret sub keys (to stdout or to --output FILE). * * This is the same as export_seckeys but replaces the primary key by * a stub key. Depending on opt.armor the output is armored. OPTIONS * are defined in main.h. If USERS is NULL, all secret subkeys will * be exported. STATS is either an export stats object for update or * NULL. * * This function is the core of "gpg --export-secret-subkeys". */ int export_secsubkeys (ctrl_t ctrl, strlist_t users, unsigned int options, export_stats_t stats) { return do_export (ctrl, users, 2, options, stats); } /* * Export a single key into a memory buffer. STATS is either an * export stats object for update or NULL. If PREFIX is not NULL * PREFIXLEN bytes from PREFIX are prepended to the R_DATA. */ gpg_error_t export_pubkey_buffer (ctrl_t ctrl, const char *keyspec, unsigned int options, const void *prefix, size_t prefixlen, export_stats_t stats, kbnode_t *r_keyblock, void **r_data, size_t *r_datalen) { gpg_error_t err; iobuf_t iobuf; int any; strlist_t helplist; *r_keyblock = NULL; *r_data = NULL; *r_datalen = 0; helplist = NULL; if (!add_to_strlist_try (&helplist, keyspec)) return gpg_error_from_syserror (); iobuf = iobuf_temp (); if (prefix && prefixlen) iobuf_write (iobuf, prefix, prefixlen); err = do_export_stream (ctrl, iobuf, helplist, 0, r_keyblock, options, stats, &any); if (!err && !any) err = gpg_error (GPG_ERR_NOT_FOUND); if (!err) { const void *src; size_t datalen; iobuf_flush_temp (iobuf); src = iobuf_get_temp_buffer (iobuf); datalen = iobuf_get_temp_length (iobuf); if (!datalen) err = gpg_error (GPG_ERR_NO_PUBKEY); else if (!(*r_data = xtrymalloc (datalen))) err = gpg_error_from_syserror (); else { memcpy (*r_data, src, datalen); *r_datalen = datalen; } } iobuf_close (iobuf); free_strlist (helplist); if (err && *r_keyblock) { release_kbnode (*r_keyblock); *r_keyblock = NULL; } return err; } /* Export the keys identified by the list of strings in USERS. If Secret is false public keys will be exported. With secret true secret keys will be exported; in this case 1 means the entire secret keyblock and 2 only the subkeys. OPTIONS are the export options to apply. */ static int do_export (ctrl_t ctrl, strlist_t users, int secret, unsigned int options, export_stats_t stats) { IOBUF out = NULL; int any, rc; armor_filter_context_t *afx = NULL; compress_filter_context_t zfx; memset( &zfx, 0, sizeof zfx); rc = open_outfile (-1, NULL, 0, !!secret, &out ); if (rc) return rc; if ( opt.armor && !(options & (EXPORT_PKA_FORMAT|EXPORT_DANE_FORMAT)) ) { afx = new_armor_context (); afx->what = secret? 5 : 1; push_armor_filter (afx, out); } rc = do_export_stream (ctrl, out, users, secret, NULL, options, stats, &any); if ( rc || !any ) iobuf_cancel (out); else iobuf_close (out); release_armor_context (afx); return rc; } /* Release an entire subkey list. */ static void release_subkey_list (subkey_list_t list) { while (list) { subkey_list_t tmp = list->next;; xfree (list); list = tmp; } } /* Returns true if NODE is a subkey and contained in LIST. */ static int subkey_in_list_p (subkey_list_t list, KBNODE node) { if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY || node->pkt->pkttype == PKT_SECRET_SUBKEY ) { u32 kid[2]; keyid_from_pk (node->pkt->pkt.public_key, kid); for (; list; list = list->next) if (list->kid[0] == kid[0] && list->kid[1] == kid[1]) return 1; } return 0; } /* Allocate a new subkey list item from NODE. */ static subkey_list_t new_subkey_list_item (KBNODE node) { subkey_list_t list = xcalloc (1, sizeof *list); if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY || node->pkt->pkttype == PKT_SECRET_SUBKEY) keyid_from_pk (node->pkt->pkt.public_key, list->kid); return list; } /* Helper function to check whether the subkey at NODE actually matches the description at DESC. The function returns true if the key under question has been specified by an exact specification (keyID or fingerprint) and does match the one at NODE. It is assumed that the packet at NODE is either a public or secret subkey. */ int exact_subkey_match_p (KEYDB_SEARCH_DESC *desc, kbnode_t node) { u32 kid[2]; byte fpr[MAX_FINGERPRINT_LEN]; size_t fprlen; int result = 0; switch(desc->mode) { case KEYDB_SEARCH_MODE_SHORT_KID: case KEYDB_SEARCH_MODE_LONG_KID: keyid_from_pk (node->pkt->pkt.public_key, kid); break; case KEYDB_SEARCH_MODE_FPR: fingerprint_from_pk (node->pkt->pkt.public_key, fpr, &fprlen); break; default: break; } switch(desc->mode) { case KEYDB_SEARCH_MODE_SHORT_KID: if (desc->u.kid[1] == kid[1]) result = 1; break; case KEYDB_SEARCH_MODE_LONG_KID: if (desc->u.kid[0] == kid[0] && desc->u.kid[1] == kid[1]) result = 1; break; case KEYDB_SEARCH_MODE_FPR: if (fprlen == desc->fprlen && !memcmp (desc->u.fpr, fpr, desc->fprlen)) result = 1; break; default: break; } return result; } /* Return an error if the key represented by the S-expression S_KEY * and the OpenPGP key represented by PK do not use the same curve. */ static gpg_error_t match_curve_skey_pk (gcry_sexp_t s_key, PKT_public_key *pk) { gcry_sexp_t curve = NULL; gcry_sexp_t flags = NULL; char *curve_str = NULL; char *flag; const char *oidstr = NULL; gcry_mpi_t curve_as_mpi = NULL; gpg_error_t err; int is_eddsa = 0; int idx = 0; if (!(pk->pubkey_algo==PUBKEY_ALGO_ECDH || pk->pubkey_algo==PUBKEY_ALGO_ECDSA || pk->pubkey_algo==PUBKEY_ALGO_EDDSA)) return gpg_error (GPG_ERR_PUBKEY_ALGO); curve = gcry_sexp_find_token (s_key, "curve", 0); if (!curve) { log_error ("no reported curve\n"); return gpg_error (GPG_ERR_UNKNOWN_CURVE); } curve_str = gcry_sexp_nth_string (curve, 1); gcry_sexp_release (curve); curve = NULL; if (!curve_str) { log_error ("no curve name\n"); return gpg_error (GPG_ERR_UNKNOWN_CURVE); } oidstr = openpgp_curve_to_oid (curve_str, NULL, NULL); if (!oidstr) { log_error ("no OID known for curve '%s'\n", curve_str); xfree (curve_str); return gpg_error (GPG_ERR_UNKNOWN_CURVE); } xfree (curve_str); err = openpgp_oid_from_str (oidstr, &curve_as_mpi); if (err) return err; if (gcry_mpi_cmp (pk->pkey[0], curve_as_mpi)) { log_error ("curves do not match\n"); gcry_mpi_release (curve_as_mpi); return gpg_error (GPG_ERR_INV_CURVE); } gcry_mpi_release (curve_as_mpi); flags = gcry_sexp_find_token (s_key, "flags", 0); if (flags) { for (idx = 1; idx < gcry_sexp_length (flags); idx++) { flag = gcry_sexp_nth_string (flags, idx); if (flag && (strcmp ("eddsa", flag) == 0)) is_eddsa = 1; gcry_free (flag); } } if (is_eddsa != (pk->pubkey_algo == PUBKEY_ALGO_EDDSA)) { log_error ("disagreement about EdDSA\n"); err = gpg_error (GPG_ERR_INV_CURVE); } return err; } /* Return a canonicalized public key algorithms. This is used to compare different flavors of algorithms (e.g. ELG and ELG_E are considered the same). */ static enum gcry_pk_algos canon_pk_algo (enum gcry_pk_algos algo) { switch (algo) { case GCRY_PK_RSA: case GCRY_PK_RSA_E: case GCRY_PK_RSA_S: return GCRY_PK_RSA; case GCRY_PK_ELG: case GCRY_PK_ELG_E: return GCRY_PK_ELG; case GCRY_PK_ECC: case GCRY_PK_ECDSA: case GCRY_PK_ECDH: return GCRY_PK_ECC; default: return algo; } } /* Take a cleartext dump of a secret key in PK and change the * parameter array in PK to include the secret parameters. */ static gpg_error_t cleartext_secret_key_to_openpgp (gcry_sexp_t s_key, PKT_public_key *pk) { gpg_error_t err; gcry_sexp_t top_list; gcry_sexp_t key = NULL; char *key_type = NULL; enum gcry_pk_algos pk_algo; struct seckey_info *ski; int idx, sec_start; gcry_mpi_t pub_params[10] = { NULL }; /* we look for a private-key, then the first element in it tells us the type */ top_list = gcry_sexp_find_token (s_key, "private-key", 0); if (!top_list) goto bad_seckey; /* ignore all S-expression after the first sublist -- we assume that they are comments or otherwise irrelevant to OpenPGP */ if (gcry_sexp_length(top_list) < 2) goto bad_seckey; key = gcry_sexp_nth (top_list, 1); if (!key) goto bad_seckey; key_type = gcry_sexp_nth_string(key, 0); pk_algo = gcry_pk_map_name (key_type); log_assert (!pk->seckey_info); pk->seckey_info = ski = xtrycalloc (1, sizeof *ski); if (!ski) { err = gpg_error_from_syserror (); goto leave; } switch (canon_pk_algo (pk_algo)) { case GCRY_PK_RSA: if (!is_RSA (pk->pubkey_algo)) goto bad_pubkey_algo; err = gcry_sexp_extract_param (key, NULL, "ne", &pub_params[0], &pub_params[1], NULL); for (idx=0; idx < 2 && !err; idx++) if (gcry_mpi_cmp(pk->pkey[idx], pub_params[idx])) err = gpg_error (GPG_ERR_BAD_PUBKEY); if (!err) { for (idx = 2; idx < 6 && !err; idx++) { gcry_mpi_release (pk->pkey[idx]); pk->pkey[idx] = NULL; } err = gcry_sexp_extract_param (key, NULL, "dpqu", &pk->pkey[2], &pk->pkey[3], &pk->pkey[4], &pk->pkey[5], NULL); } if (!err) { for (idx = 2; idx < 6; idx++) ski->csum += checksum_mpi (pk->pkey[idx]); } break; case GCRY_PK_DSA: if (!is_DSA (pk->pubkey_algo)) goto bad_pubkey_algo; err = gcry_sexp_extract_param (key, NULL, "pqgy", &pub_params[0], &pub_params[1], &pub_params[2], &pub_params[3], NULL); for (idx=0; idx < 4 && !err; idx++) if (gcry_mpi_cmp(pk->pkey[idx], pub_params[idx])) err = gpg_error (GPG_ERR_BAD_PUBKEY); if (!err) { gcry_mpi_release (pk->pkey[4]); pk->pkey[4] = NULL; err = gcry_sexp_extract_param (key, NULL, "x", &pk->pkey[4], NULL); } if (!err) ski->csum += checksum_mpi (pk->pkey[4]); break; case GCRY_PK_ELG: if (!is_ELGAMAL (pk->pubkey_algo)) goto bad_pubkey_algo; err = gcry_sexp_extract_param (key, NULL, "pgy", &pub_params[0], &pub_params[1], &pub_params[2], NULL); for (idx=0; idx < 3 && !err; idx++) if (gcry_mpi_cmp(pk->pkey[idx], pub_params[idx])) err = gpg_error (GPG_ERR_BAD_PUBKEY); if (!err) { gcry_mpi_release (pk->pkey[3]); pk->pkey[3] = NULL; err = gcry_sexp_extract_param (key, NULL, "x", &pk->pkey[3], NULL); } if (!err) ski->csum += checksum_mpi (pk->pkey[3]); break; case GCRY_PK_ECC: err = match_curve_skey_pk (key, pk); if (err) goto leave; - if (!err) - err = gcry_sexp_extract_param (key, NULL, "q", - &pub_params[0], - NULL); + else + err = sexp_extract_param_sos (key, "q", &pub_params[0]); if (!err && (gcry_mpi_cmp(pk->pkey[1], pub_params[0]))) err = gpg_error (GPG_ERR_BAD_PUBKEY); sec_start = 2; if (pk->pubkey_algo == PUBKEY_ALGO_ECDH) sec_start += 1; if (!err) { gcry_mpi_release (pk->pkey[sec_start]); pk->pkey[sec_start] = NULL; - err = gcry_sexp_extract_param (key, NULL, "d", - &pk->pkey[sec_start], - NULL); + err = sexp_extract_param_sos (key, "d", &pk->pkey[sec_start]); } if (!err) ski->csum += checksum_mpi (pk->pkey[sec_start]); break; default: pk->seckey_info = NULL; xfree (ski); err = gpg_error (GPG_ERR_NOT_IMPLEMENTED); break; } leave: gcry_sexp_release (top_list); gcry_sexp_release (key); gcry_free (key_type); for (idx=0; idx < DIM(pub_params); idx++) gcry_mpi_release (pub_params[idx]); return err; bad_pubkey_algo: err = gpg_error (GPG_ERR_PUBKEY_ALGO); goto leave; bad_seckey: err = gpg_error (GPG_ERR_BAD_SECKEY); goto leave; } /* Use the key transfer format given in S_PGP to create the secinfo structure in PK and change the parameter array in PK to include the secret parameters. */ static gpg_error_t transfer_format_to_openpgp (gcry_sexp_t s_pgp, PKT_public_key *pk) { gpg_error_t err; gcry_sexp_t top_list; gcry_sexp_t list = NULL; char *curve = NULL; const char *value; size_t valuelen; char *string; int idx; int is_v4, is_protected; enum gcry_pk_algos pk_algo; int protect_algo = 0; char iv[16]; int ivlen = 0; int s2k_mode = 0; int s2k_algo = 0; byte s2k_salt[8]; u32 s2k_count = 0; int is_ecdh = 0; size_t npkey, nskey; gcry_mpi_t skey[10]; /* We support up to 9 parameters. */ int skeyidx = 0; struct seckey_info *ski; /* gcry_log_debugsxp ("transferkey", s_pgp); */ top_list = gcry_sexp_find_token (s_pgp, "openpgp-private-key", 0); if (!top_list) goto bad_seckey; list = gcry_sexp_find_token (top_list, "version", 0); if (!list) goto bad_seckey; value = gcry_sexp_nth_data (list, 1, &valuelen); if (!value || valuelen != 1 || !(value[0] == '3' || value[0] == '4')) goto bad_seckey; is_v4 = (value[0] == '4'); gcry_sexp_release (list); list = gcry_sexp_find_token (top_list, "protection", 0); if (!list) goto bad_seckey; value = gcry_sexp_nth_data (list, 1, &valuelen); if (!value) goto bad_seckey; if (valuelen == 4 && !memcmp (value, "sha1", 4)) is_protected = 2; else if (valuelen == 3 && !memcmp (value, "sum", 3)) is_protected = 1; else if (valuelen == 4 && !memcmp (value, "none", 4)) is_protected = 0; else goto bad_seckey; if (is_protected) { string = gcry_sexp_nth_string (list, 2); if (!string) goto bad_seckey; protect_algo = gcry_cipher_map_name (string); xfree (string); value = gcry_sexp_nth_data (list, 3, &valuelen); if (!value || !valuelen || valuelen > sizeof iv) goto bad_seckey; memcpy (iv, value, valuelen); ivlen = valuelen; string = gcry_sexp_nth_string (list, 4); if (!string) goto bad_seckey; s2k_mode = strtol (string, NULL, 10); xfree (string); string = gcry_sexp_nth_string (list, 5); if (!string) goto bad_seckey; s2k_algo = gcry_md_map_name (string); xfree (string); value = gcry_sexp_nth_data (list, 6, &valuelen); if (!value || !valuelen || valuelen > sizeof s2k_salt) goto bad_seckey; memcpy (s2k_salt, value, valuelen); string = gcry_sexp_nth_string (list, 7); if (!string) goto bad_seckey; s2k_count = strtoul (string, NULL, 10); xfree (string); } /* Parse the gcrypt PK algo and check that it is okay. */ gcry_sexp_release (list); list = gcry_sexp_find_token (top_list, "algo", 0); if (!list) goto bad_seckey; string = gcry_sexp_nth_string (list, 1); if (!string) goto bad_seckey; pk_algo = gcry_pk_map_name (string); xfree (string); string = NULL; if (gcry_pk_algo_info (pk_algo, GCRYCTL_GET_ALGO_NPKEY, NULL, &npkey) || gcry_pk_algo_info (pk_algo, GCRYCTL_GET_ALGO_NSKEY, NULL, &nskey) || !npkey || npkey >= nskey) goto bad_seckey; /* Check that the pubkey algo matches the one from the public key. */ switch (canon_pk_algo (pk_algo)) { case GCRY_PK_RSA: if (!is_RSA (pk->pubkey_algo)) pk_algo = 0; /* Does not match. */ break; case GCRY_PK_DSA: if (!is_DSA (pk->pubkey_algo)) pk_algo = 0; /* Does not match. */ break; case GCRY_PK_ELG: if (!is_ELGAMAL (pk->pubkey_algo)) pk_algo = 0; /* Does not match. */ break; case GCRY_PK_ECC: if (pk->pubkey_algo == PUBKEY_ALGO_ECDSA) ; else if (pk->pubkey_algo == PUBKEY_ALGO_ECDH) is_ecdh = 1; else if (pk->pubkey_algo == PUBKEY_ALGO_EDDSA) ; else pk_algo = 0; /* Does not match. */ /* For ECC we do not have the domain parameters thus fix our info. */ npkey = 1; nskey = 2; break; default: pk_algo = 0; /* Oops. */ break; } if (!pk_algo) { err = gpg_error (GPG_ERR_PUBKEY_ALGO); goto leave; } /* This check has to go after the ecc adjustments. */ if (nskey > PUBKEY_MAX_NSKEY) goto bad_seckey; /* Parse the key parameters. */ gcry_sexp_release (list); list = gcry_sexp_find_token (top_list, "skey", 0); if (!list) goto bad_seckey; for (idx=0;;) { int is_enc; value = gcry_sexp_nth_data (list, ++idx, &valuelen); if (!value && skeyidx >= npkey) break; /* Ready. */ /* Check for too many parameters. Note that depending on the protection mode and version number we may see less than NSKEY (but at least NPKEY+1) parameters. */ if (idx >= 2*nskey) goto bad_seckey; if (skeyidx >= DIM (skey)-1) goto bad_seckey; if (!value || valuelen != 1 || !(value[0] == '_' || value[0] == 'e')) goto bad_seckey; is_enc = (value[0] == 'e'); value = gcry_sexp_nth_data (list, ++idx, &valuelen); if (!value || !valuelen) goto bad_seckey; - if (is_enc) + if (is_enc + || pk->pubkey_algo == PUBKEY_ALGO_ECDSA + || pk->pubkey_algo == PUBKEY_ALGO_EDDSA + || pk->pubkey_algo == PUBKEY_ALGO_ECDH) { - void *p = xtrymalloc (valuelen); - if (!p) - goto outofmem; - memcpy (p, value, valuelen); - skey[skeyidx] = gcry_mpi_set_opaque (NULL, p, valuelen*8); + skey[skeyidx] = gcry_mpi_set_opaque_copy (NULL, value, valuelen*8); if (!skey[skeyidx]) goto outofmem; + if (is_enc) + gcry_mpi_set_flag (skey[skeyidx], GCRYMPI_FLAG_USER1); } else { if (gcry_mpi_scan (skey + skeyidx, GCRYMPI_FMT_STD, value, valuelen, NULL)) goto bad_seckey; } skeyidx++; } skey[skeyidx++] = NULL; gcry_sexp_release (list); list = NULL; /* We have no need for the CSUM value thus we don't parse it. */ /* list = gcry_sexp_find_token (top_list, "csum", 0); */ /* if (list) */ /* { */ /* string = gcry_sexp_nth_string (list, 1); */ /* if (!string) */ /* goto bad_seckey; */ /* desired_csum = strtoul (string, NULL, 10); */ /* xfree (string); */ /* } */ /* else */ /* desired_csum = 0; */ /* gcry_sexp_release (list); list = NULL; */ /* Get the curve name if any, */ list = gcry_sexp_find_token (top_list, "curve", 0); if (list) { curve = gcry_sexp_nth_string (list, 1); gcry_sexp_release (list); list = NULL; } gcry_sexp_release (top_list); top_list = NULL; /* log_debug ("XXX is_v4=%d\n", is_v4); */ /* log_debug ("XXX pubkey_algo=%d\n", pubkey_algo); */ /* log_debug ("XXX is_protected=%d\n", is_protected); */ /* log_debug ("XXX protect_algo=%d\n", protect_algo); */ /* log_printhex ("XXX iv", iv, ivlen); */ /* log_debug ("XXX ivlen=%d\n", ivlen); */ /* log_debug ("XXX s2k_mode=%d\n", s2k_mode); */ /* log_debug ("XXX s2k_algo=%d\n", s2k_algo); */ /* log_printhex ("XXX s2k_salt", s2k_salt, sizeof s2k_salt); */ /* log_debug ("XXX s2k_count=%lu\n", (unsigned long)s2k_count); */ /* for (idx=0; skey[idx]; idx++) */ /* { */ /* int is_enc = gcry_mpi_get_flag (skey[idx], GCRYMPI_FLAG_OPAQUE); */ /* log_info ("XXX skey[%d]%s:", idx, is_enc? " (enc)":""); */ /* if (is_enc) */ /* { */ /* void *p; */ /* unsigned int nbits; */ /* p = gcry_mpi_get_opaque (skey[idx], &nbits); */ /* log_printhex (NULL, p, (nbits+7)/8); */ /* } */ /* else */ /* gcry_mpi_dump (skey[idx]); */ /* log_printf ("\n"); */ /* } */ if (!is_v4 || is_protected != 2 ) { /* We only support the v4 format and a SHA-1 checksum. */ err = gpg_error (GPG_ERR_NOT_IMPLEMENTED); goto leave; } /* We need to change the received parameters for ECC algorithms. The transfer format has the curve name and the parameters separate. We put them all into the SKEY array. */ if (canon_pk_algo (pk_algo) == GCRY_PK_ECC) { const char *oidstr; /* Assert that all required parameters are available. We also check that the array does not contain more parameters than needed (this was used by some beta versions of 2.1. */ if (!curve || !skey[0] || !skey[1] || skey[2]) { err = gpg_error (GPG_ERR_INTERNAL); goto leave; } oidstr = openpgp_curve_to_oid (curve, NULL, NULL); if (!oidstr) { log_error ("no OID known for curve '%s'\n", curve); err = gpg_error (GPG_ERR_UNKNOWN_CURVE); goto leave; } /* Put the curve's OID into the MPI array. This requires that we shift Q and D. For ECDH also insert the KDF parms. */ if (is_ecdh) { skey[4] = NULL; skey[3] = skey[1]; skey[2] = gcry_mpi_copy (pk->pkey[2]); } else { skey[3] = NULL; skey[2] = skey[1]; } skey[1] = skey[0]; skey[0] = NULL; err = openpgp_oid_from_str (oidstr, skey + 0); if (err) goto leave; /* Fixup the NPKEY and NSKEY to match OpenPGP reality. */ npkey = 2 + is_ecdh; nskey = 3 + is_ecdh; /* for (idx=0; skey[idx]; idx++) */ /* { */ /* log_info ("YYY skey[%d]:", idx); */ /* if (gcry_mpi_get_flag (skey[idx], GCRYMPI_FLAG_OPAQUE)) */ /* { */ /* void *p; */ /* unsigned int nbits; */ /* p = gcry_mpi_get_opaque (skey[idx], &nbits); */ /* log_printhex (NULL, p, (nbits+7)/8); */ /* } */ /* else */ /* gcry_mpi_dump (skey[idx]); */ /* log_printf ("\n"); */ /* } */ } /* Do some sanity checks. */ if (s2k_count > 255) { /* We expect an already encoded S2K count. */ err = gpg_error (GPG_ERR_INV_DATA); goto leave; } err = openpgp_cipher_test_algo (protect_algo); if (err) goto leave; err = openpgp_md_test_algo (s2k_algo); if (err) goto leave; /* Check that the public key parameters match. Note that since Libgcrypt 1.5 gcry_mpi_cmp handles opaque MPI correctly. */ for (idx=0; idx < npkey; idx++) if (gcry_mpi_cmp (pk->pkey[idx], skey[idx])) { err = gpg_error (GPG_ERR_BAD_PUBKEY); goto leave; } /* Check that the first secret key parameter in SKEY is encrypted and that there are no more secret key parameters. The latter is guaranteed by the v4 packet format. */ - if (!gcry_mpi_get_flag (skey[npkey], GCRYMPI_FLAG_OPAQUE)) + if (!gcry_mpi_get_flag (skey[npkey], GCRYMPI_FLAG_USER1)) goto bad_seckey; if (npkey+1 < DIM (skey) && skey[npkey+1]) goto bad_seckey; /* Check that the secret key parameters in PK are all set to NULL. */ for (idx=npkey; idx < nskey; idx++) if (pk->pkey[idx]) goto bad_seckey; /* Now build the protection info. */ pk->seckey_info = ski = xtrycalloc (1, sizeof *ski); if (!ski) { err = gpg_error_from_syserror (); goto leave; } ski->is_protected = 1; ski->sha1chk = 1; ski->algo = protect_algo; ski->s2k.mode = s2k_mode; ski->s2k.hash_algo = s2k_algo; log_assert (sizeof ski->s2k.salt == sizeof s2k_salt); memcpy (ski->s2k.salt, s2k_salt, sizeof s2k_salt); ski->s2k.count = s2k_count; log_assert (ivlen <= sizeof ski->iv); memcpy (ski->iv, iv, ivlen); ski->ivlen = ivlen; /* Store the protected secret key parameter. */ pk->pkey[npkey] = skey[npkey]; skey[npkey] = NULL; /* That's it. */ leave: gcry_free (curve); gcry_sexp_release (list); gcry_sexp_release (top_list); for (idx=0; idx < skeyidx; idx++) gcry_mpi_release (skey[idx]); return err; bad_seckey: err = gpg_error (GPG_ERR_BAD_SECKEY); goto leave; outofmem: err = gpg_error (GPG_ERR_ENOMEM); goto leave; } /* Print an "EXPORTED" status line. PK is the primary public key. */ static void print_status_exported (PKT_public_key *pk) { char *hexfpr; if (!is_status_enabled ()) return; hexfpr = hexfingerprint (pk, NULL, 0); write_status_text (STATUS_EXPORTED, hexfpr? hexfpr : "[?]"); xfree (hexfpr); } /* * Receive a secret key from agent specified by HEXGRIP. * * Since the key data from the agent is encrypted, decrypt it using * CIPHERHD context. Then, parse the decrypted key data into transfer * format, and put secret parameters into PK. * * If CLEARTEXT is 0, store the secret key material * passphrase-protected. Otherwise, store secret key material in the * clear. * * CACHE_NONCE_ADDR is used to share nonce for multiple key retrievals. */ gpg_error_t receive_seckey_from_agent (ctrl_t ctrl, gcry_cipher_hd_t cipherhd, int cleartext, char **cache_nonce_addr, const char *hexgrip, PKT_public_key *pk) { gpg_error_t err = 0; unsigned char *wrappedkey = NULL; size_t wrappedkeylen; unsigned char *key = NULL; size_t keylen, realkeylen; gcry_sexp_t s_skey; char *prompt; if (opt.verbose) log_info ("key %s: asking agent for the secret parts\n", hexgrip); prompt = gpg_format_keydesc (ctrl, pk, FORMAT_KEYDESC_EXPORT,1); err = agent_export_key (ctrl, hexgrip, prompt, !cleartext, cache_nonce_addr, &wrappedkey, &wrappedkeylen, pk->keyid, pk->main_keyid, pk->pubkey_algo); xfree (prompt); if (err) goto unwraperror; if (wrappedkeylen < 24) { err = gpg_error (GPG_ERR_INV_LENGTH); goto unwraperror; } keylen = wrappedkeylen - 8; key = xtrymalloc_secure (keylen); if (!key) { err = gpg_error_from_syserror (); goto unwraperror; } err = gcry_cipher_decrypt (cipherhd, key, keylen, wrappedkey, wrappedkeylen); if (err) goto unwraperror; realkeylen = gcry_sexp_canon_len (key, keylen, NULL, &err); if (!realkeylen) goto unwraperror; /* Invalid csexp. */ err = gcry_sexp_sscan (&s_skey, NULL, key, realkeylen); if (!err) { if (cleartext) err = cleartext_secret_key_to_openpgp (s_skey, pk); else err = transfer_format_to_openpgp (s_skey, pk); gcry_sexp_release (s_skey); } unwraperror: xfree (key); xfree (wrappedkey); if (err) { log_error ("key %s: error receiving key from agent:" " %s%s\n", hexgrip, gpg_strerror (err), gpg_err_code (err) == GPG_ERR_FULLY_CANCELED? "":_(" - skipped")); } return err; } /* Write KEYBLOCK either to stdout or to the file set with the * --output option. This is a simplified version of do_export_stream * which supports only a few export options. */ gpg_error_t write_keyblock_to_output (kbnode_t keyblock, int with_armor, unsigned int options) { gpg_error_t err; const char *fname; iobuf_t out; kbnode_t node; armor_filter_context_t *afx = NULL; iobuf_t out_help = NULL; PKT_public_key *pk = NULL; fname = opt.outfile? opt.outfile : "-"; if (is_secured_filename (fname) ) return gpg_error (GPG_ERR_EPERM); out = iobuf_create (fname, 0); if (!out) { err = gpg_error_from_syserror (); log_error(_("can't create '%s': %s\n"), fname, gpg_strerror (err)); return err; } if (opt.verbose) log_info (_("writing to '%s'\n"), iobuf_get_fname_nonnull (out)); if ((options & (EXPORT_PKA_FORMAT|EXPORT_DANE_FORMAT))) { with_armor = 0; out_help = iobuf_temp (); } if (with_armor) { afx = new_armor_context (); afx->what = 1; push_armor_filter (afx, out); } for (node = keyblock; node; node = node->next) { if (is_deleted_kbnode (node)) continue; if (node->pkt->pkttype == PKT_RING_TRUST) continue; /* Skip - they should not be here anyway. */ if (!pk && (node->pkt->pkttype == PKT_PUBLIC_KEY || node->pkt->pkttype == PKT_SECRET_KEY)) pk = node->pkt->pkt.public_key; if ((options & EXPORT_BACKUP)) err = build_packet_and_meta (out_help? out_help : out, node->pkt); else err = build_packet (out_help? out_help : out, node->pkt); if (err) { log_error ("build_packet(%d) failed: %s\n", node->pkt->pkttype, gpg_strerror (err) ); goto leave; } } err = 0; if (out_help && pk) { const void *data; size_t datalen; iobuf_flush_temp (out_help); data = iobuf_get_temp_buffer (out_help); datalen = iobuf_get_temp_length (out_help); err = print_pka_or_dane_records (out, keyblock, pk, data, datalen, (options & EXPORT_PKA_FORMAT), (options & EXPORT_DANE_FORMAT)); } leave: if (err) iobuf_cancel (out); else iobuf_close (out); iobuf_cancel (out_help); release_armor_context (afx); return err; } /* * Apply the keep-uid filter to the keyblock. The deleted nodes are * marked and thus the caller should call commit_kbnode afterwards. * KEYBLOCK must not have any blocks marked as deleted. */ static void apply_keep_uid_filter (ctrl_t ctrl, kbnode_t keyblock, recsel_expr_t selector) { kbnode_t node; struct impex_filter_parm_s parm; parm.ctrl = ctrl; for (node = keyblock->next; node; node = node->next ) { if (node->pkt->pkttype == PKT_USER_ID) { parm.node = node; if (!recsel_select (selector, impex_filter_getval, &parm)) { /* log_debug ("keep-uid: deleting '%s'\n", */ /* node->pkt->pkt.user_id->name); */ /* The UID packet and all following packets up to the * next UID or a subkey. */ delete_kbnode (node); for (; node->next && node->next->pkt->pkttype != PKT_USER_ID && node->next->pkt->pkttype != PKT_PUBLIC_SUBKEY && node->next->pkt->pkttype != PKT_SECRET_SUBKEY ; node = node->next) delete_kbnode (node->next); } /* else */ /* log_debug ("keep-uid: keeping '%s'\n", */ /* node->pkt->pkt.user_id->name); */ } } } /* * Apply the drop-subkey filter to the keyblock. The deleted nodes are * marked and thus the caller should call commit_kbnode afterwards. * KEYBLOCK must not have any blocks marked as deleted. */ static void apply_drop_subkey_filter (ctrl_t ctrl, kbnode_t keyblock, recsel_expr_t selector) { kbnode_t node; struct impex_filter_parm_s parm; parm.ctrl = ctrl; for (node = keyblock->next; node; node = node->next ) { if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY || node->pkt->pkttype == PKT_SECRET_SUBKEY) { parm.node = node; if (recsel_select (selector, impex_filter_getval, &parm)) { /*log_debug ("drop-subkey: deleting a key\n");*/ /* The subkey packet and all following packets up to the * next subkey. */ delete_kbnode (node); for (; node->next && node->next->pkt->pkttype != PKT_PUBLIC_SUBKEY && node->next->pkt->pkttype != PKT_SECRET_SUBKEY ; node = node->next) delete_kbnode (node->next); } } } } /* Print DANE or PKA records for all user IDs in KEYBLOCK to OUT. The * data for the record is taken from (DATA,DATELEN). PK is the public * key packet with the primary key. */ static gpg_error_t print_pka_or_dane_records (iobuf_t out, kbnode_t keyblock, PKT_public_key *pk, const void *data, size_t datalen, int print_pka, int print_dane) { gpg_error_t err = 0; kbnode_t kbctx, node; PKT_user_id *uid; char *mbox = NULL; char hashbuf[32]; char *hash = NULL; char *domain; const char *s; unsigned int len; estream_t fp = NULL; char *hexdata = NULL; char *hexfpr; hexfpr = hexfingerprint (pk, NULL, 0); if (!hexfpr) { err = gpg_error_from_syserror (); goto leave; } hexdata = bin2hex (data, datalen, NULL); if (!hexdata) { err = gpg_error_from_syserror (); goto leave; } ascii_strlwr (hexdata); fp = es_fopenmem (0, "rw,samethread"); if (!fp) { err = gpg_error_from_syserror (); goto leave; } for (kbctx = NULL; (node = walk_kbnode (keyblock, &kbctx, 0));) { if (node->pkt->pkttype != PKT_USER_ID) continue; uid = node->pkt->pkt.user_id; if (uid->flags.expired || uid->flags.revoked) continue; xfree (mbox); mbox = mailbox_from_userid (uid->name, 0); if (!mbox) continue; domain = strchr (mbox, '@'); *domain++ = 0; if (print_pka) { es_fprintf (fp, "$ORIGIN _pka.%s.\n; %s\n; ", domain, hexfpr); print_utf8_buffer (fp, uid->name, uid->len); es_putc ('\n', fp); gcry_md_hash_buffer (GCRY_MD_SHA1, hashbuf, mbox, strlen (mbox)); xfree (hash); hash = zb32_encode (hashbuf, 8*20); if (!hash) { err = gpg_error_from_syserror (); goto leave; } len = strlen (hexfpr)/2; es_fprintf (fp, "%s TYPE37 \\# %u 0006 0000 00 %02X %s\n\n", hash, 6 + len, len, hexfpr); } if (print_dane && hexdata) { es_fprintf (fp, "$ORIGIN _openpgpkey.%s.\n; %s\n; ", domain, hexfpr); print_utf8_buffer (fp, uid->name, uid->len); es_putc ('\n', fp); gcry_md_hash_buffer (GCRY_MD_SHA256, hashbuf, mbox, strlen (mbox)); xfree (hash); hash = bin2hex (hashbuf, 28, NULL); if (!hash) { err = gpg_error_from_syserror (); goto leave; } ascii_strlwr (hash); len = strlen (hexdata)/2; es_fprintf (fp, "%s TYPE61 \\# %u (\n", hash, len); for (s = hexdata; ;) { es_fprintf (fp, "\t%.64s\n", s); if (strlen (s) < 64) break; s += 64; } es_fputs ("\t)\n\n", fp); } } /* Make sure it is a string and write it. */ es_fputc (0, fp); { void *vp; if (es_fclose_snatch (fp, &vp, NULL)) { err = gpg_error_from_syserror (); goto leave; } fp = NULL; iobuf_writestr (out, vp); es_free (vp); } err = 0; leave: xfree (hash); xfree (mbox); es_fclose (fp); xfree (hexdata); xfree (hexfpr); return err; } /* Helper for do_export_stream which writes one keyblock to OUT. */ static gpg_error_t do_export_one_keyblock (ctrl_t ctrl, kbnode_t keyblock, u32 *keyid, iobuf_t out, int secret, unsigned int options, export_stats_t stats, int *any, KEYDB_SEARCH_DESC *desc, size_t ndesc, size_t descindex, gcry_cipher_hd_t cipherhd) { gpg_error_t err = gpg_error (GPG_ERR_NOT_FOUND); char *cache_nonce = NULL; subkey_list_t subkey_list = NULL; /* Track already processed subkeys. */ int skip_until_subkey = 0; int cleartext = 0; char *hexgrip = NULL; char *serialno = NULL; PKT_public_key *pk; u32 subkidbuf[2], *subkid; kbnode_t kbctx, node; /* NB: walk_kbnode skips packets marked as deleted. */ for (kbctx=NULL; (node = walk_kbnode (keyblock, &kbctx, 0)); ) { if (skip_until_subkey) { if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY) skip_until_subkey = 0; else continue; } /* We used to use comment packets, but not any longer. In * case we still have comments on a key, strip them here * before we call build_packet(). */ if (node->pkt->pkttype == PKT_COMMENT) continue; /* Skip ring trust packets - they should not be here anyway. */ if (node->pkt->pkttype == PKT_RING_TRUST) continue; /* If exact is set, then we only export what was requested * (plus the primary key, if the user didn't specifically * request it). */ if (desc[descindex].exact && node->pkt->pkttype == PKT_PUBLIC_SUBKEY) { if (!exact_subkey_match_p (desc+descindex, node)) { /* Before skipping this subkey, check whether any * other description wants an exact match on a * subkey and include that subkey into the output * too. Need to add this subkey to a list so that * it won't get processed a second time. * * So the first step here is to check that list and * skip in any case if the key is in that list. * * We need this whole mess because the import * function of GnuPG < 2.1 is not able to merge * secret keys and thus it is useless to output them * as two separate keys and have import merge them. */ if (subkey_in_list_p (subkey_list, node)) skip_until_subkey = 1; /* Already processed this one. */ else { size_t j; for (j=0; j < ndesc; j++) if (j != descindex && desc[j].exact && exact_subkey_match_p (desc+j, node)) break; if (!(j < ndesc)) skip_until_subkey = 1; /* No other one matching. */ } } if (skip_until_subkey) continue; /* Mark this one as processed. */ { subkey_list_t tmp = new_subkey_list_item (node); tmp->next = subkey_list; subkey_list = tmp; } } if (node->pkt->pkttype == PKT_SIGNATURE) { /* Do not export packets which are marked as not * exportable. */ if (!(options & EXPORT_LOCAL_SIGS) && !node->pkt->pkt.signature->flags.exportable) continue; /* not exportable */ /* Do not export packets with a "sensitive" revocation key * unless the user wants us to. Note that we do export * these when issuing the actual revocation (see revoke.c). */ if (!(options & EXPORT_SENSITIVE_REVKEYS) && node->pkt->pkt.signature->revkey) { int i; for (i = 0; i < node->pkt->pkt.signature->numrevkeys; i++) if ((node->pkt->pkt.signature->revkey[i].class & 0x40)) break; if (i < node->pkt->pkt.signature->numrevkeys) continue; } } /* Don't export user ids (and attributes)? This is not RFC-4880 * compliant but we allow it anyway. */ if ((options & EXPORT_DROP_UIDS) && node->pkt->pkttype == PKT_USER_ID) { /* Skip until we get to something that is not a user id (or * attrib) or a signature on it. */ while (kbctx->next && kbctx->next->pkt->pkttype == PKT_SIGNATURE) kbctx = kbctx->next; continue; } /* Don't export attribs? */ if (!(options & EXPORT_ATTRIBUTES) && node->pkt->pkttype == PKT_USER_ID && node->pkt->pkt.user_id->attrib_data) { /* Skip until we get to something that is not an attrib or a * signature on an attrib. */ while (kbctx->next && kbctx->next->pkt->pkttype == PKT_SIGNATURE) kbctx = kbctx->next; continue; } if (secret && (node->pkt->pkttype == PKT_PUBLIC_KEY || node->pkt->pkttype == PKT_PUBLIC_SUBKEY)) { pk = node->pkt->pkt.public_key; if (node->pkt->pkttype == PKT_PUBLIC_KEY) subkid = NULL; else { keyid_from_pk (pk, subkidbuf); subkid = subkidbuf; } if (pk->seckey_info) { log_error ("key %s: oops: seckey_info already set" " - skipped\n", keystr_with_sub (keyid, subkid)); skip_until_subkey = 1; continue; } xfree (hexgrip); err = hexkeygrip_from_pk (pk, &hexgrip); if (err) { log_error ("key %s: error computing keygrip: %s" " - skipped\n", keystr_with_sub (keyid, subkid), gpg_strerror (err)); skip_until_subkey = 1; err = 0; continue; } xfree (serialno); serialno = NULL; if (secret == 2 && node->pkt->pkttype == PKT_PUBLIC_KEY) { /* We are asked not to export the secret parts of the * primary key. Make up an error code to create the * stub. */ err = GPG_ERR_NOT_FOUND; } else err = agent_get_keyinfo (ctrl, hexgrip, &serialno, &cleartext); if ((!err && serialno) && secret == 2 && node->pkt->pkttype == PKT_PUBLIC_KEY) { /* It does not make sense to export a key with its * primary key on card using a non-key stub. Thus we * skip those keys when used with --export-secret-subkeys. */ log_info (_("key %s: key material on-card - skipped\n"), keystr_with_sub (keyid, subkid)); skip_until_subkey = 1; } else if (gpg_err_code (err) == GPG_ERR_NOT_FOUND || (!err && serialno)) { /* Create a key stub. */ struct seckey_info *ski; const char *s; pk->seckey_info = ski = xtrycalloc (1, sizeof *ski); if (!ski) { err = gpg_error_from_syserror (); goto leave; } ski->is_protected = 1; if (err) ski->s2k.mode = 1001; /* GNU dummy (no secret key). */ else { ski->s2k.mode = 1002; /* GNU-divert-to-card. */ for (s=serialno; sizeof (ski->ivlen) && *s && s[1]; ski->ivlen++, s += 2) ski->iv[ski->ivlen] = xtoi_2 (s); } if ((options & EXPORT_BACKUP)) err = build_packet_and_meta (out, node->pkt); else err = build_packet (out, node->pkt); if (!err && node->pkt->pkttype == PKT_PUBLIC_KEY) { stats->exported++; print_status_exported (node->pkt->pkt.public_key); } } else if (!err) { err = receive_seckey_from_agent (ctrl, cipherhd, cleartext, &cache_nonce, hexgrip, pk); if (err) { if (gpg_err_code (err) == GPG_ERR_FULLY_CANCELED) goto leave; skip_until_subkey = 1; err = 0; } else { if ((options & EXPORT_BACKUP)) err = build_packet_and_meta (out, node->pkt); else err = build_packet (out, node->pkt); if (node->pkt->pkttype == PKT_PUBLIC_KEY) { stats->exported++; print_status_exported (node->pkt->pkt.public_key); } } } else { log_error ("key %s: error getting keyinfo from agent: %s" " - skipped\n", keystr_with_sub (keyid, subkid), gpg_strerror (err)); skip_until_subkey = 1; err = 0; } xfree (pk->seckey_info); pk->seckey_info = NULL; { int i; for (i = pubkey_get_npkey (pk->pubkey_algo); i < pubkey_get_nskey (pk->pubkey_algo); i++) { gcry_mpi_release (pk->pkey[i]); pk->pkey[i] = NULL; } } } else /* Not secret or common packets. */ { if ((options & EXPORT_BACKUP)) err = build_packet_and_meta (out, node->pkt); else err = build_packet (out, node->pkt); if (!err && node->pkt->pkttype == PKT_PUBLIC_KEY) { stats->exported++; print_status_exported (node->pkt->pkt.public_key); } } if (err) { log_error ("build_packet(%d) failed: %s\n", node->pkt->pkttype, gpg_strerror (err)); goto leave; } if (!skip_until_subkey) *any = 1; } leave: release_subkey_list (subkey_list); xfree (serialno); xfree (hexgrip); xfree (cache_nonce); return err; } /* Export the keys identified by the list of strings in USERS to the stream OUT. If SECRET is false public keys will be exported. With secret true secret keys will be exported; in this case 1 means the entire secret keyblock and 2 only the subkeys. OPTIONS are the export options to apply. If KEYBLOCK_OUT is not NULL, AND the exit code is zero, a pointer to the first keyblock found and exported will be stored at this address; no other keyblocks are exported in this case. The caller must free the returned keyblock. If any key has been exported true is stored at ANY. */ static int do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret, kbnode_t *keyblock_out, unsigned int options, export_stats_t stats, int *any) { gpg_error_t err = 0; PACKET pkt; kbnode_t keyblock = NULL; kbnode_t node; size_t ndesc, descindex; KEYDB_SEARCH_DESC *desc = NULL; KEYDB_HANDLE kdbhd; strlist_t sl; gcry_cipher_hd_t cipherhd = NULL; struct export_stats_s dummystats; iobuf_t out_help = NULL; if (!stats) stats = &dummystats; *any = 0; init_packet (&pkt); kdbhd = keydb_new (ctrl); if (!kdbhd) return gpg_error_from_syserror (); /* For the PKA and DANE format open a helper iobuf and for DANE * enforce some options. */ if ((options & (EXPORT_PKA_FORMAT | EXPORT_DANE_FORMAT))) { out_help = iobuf_temp (); if ((options & EXPORT_DANE_FORMAT)) options |= EXPORT_MINIMAL | EXPORT_CLEAN; } if (!users) { ndesc = 1; desc = xcalloc (ndesc, sizeof *desc); desc[0].mode = KEYDB_SEARCH_MODE_FIRST; } else { for (ndesc=0, sl=users; sl; sl = sl->next, ndesc++) ; desc = xmalloc ( ndesc * sizeof *desc); for (ndesc=0, sl=users; sl; sl = sl->next) { if (!(err=classify_user_id (sl->d, desc+ndesc, 1))) ndesc++; else log_error (_("key \"%s\" not found: %s\n"), sl->d, gpg_strerror (err)); } keydb_disable_caching (kdbhd); /* We are looping the search. */ /* It would be nice to see which of the given users did actually match one in the keyring. To implement this we need to have a found flag for each entry in desc. To set this flag we must check all those entries after a match to mark all matched one - currently we stop at the first match. To do this we need an extra flag to enable this feature. */ } #ifdef ENABLE_SELINUX_HACKS if (secret) { log_error (_("exporting secret keys not allowed\n")); err = gpg_error (GPG_ERR_NOT_SUPPORTED); goto leave; } #endif /* For secret key export we need to setup a decryption context. */ if (secret) { void *kek = NULL; size_t keklen; err = agent_keywrap_key (ctrl, 1, &kek, &keklen); if (err) { log_error ("error getting the KEK: %s\n", gpg_strerror (err)); goto leave; } /* Prepare a cipher context. */ err = gcry_cipher_open (&cipherhd, GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_AESWRAP, 0); if (!err) err = gcry_cipher_setkey (cipherhd, kek, keklen); if (err) { log_error ("error setting up an encryption context: %s\n", gpg_strerror (err)); goto leave; } xfree (kek); kek = NULL; } for (;;) { u32 keyid[2]; PKT_public_key *pk; err = keydb_search (kdbhd, desc, ndesc, &descindex); if (!users) desc[0].mode = KEYDB_SEARCH_MODE_NEXT; if (err) break; /* Read the keyblock. */ release_kbnode (keyblock); keyblock = NULL; err = keydb_get_keyblock (kdbhd, &keyblock); if (err) { log_error (_("error reading keyblock: %s\n"), gpg_strerror (err)); goto leave; } node = find_kbnode (keyblock, PKT_PUBLIC_KEY); if (!node) { log_error ("public key packet not found in keyblock - skipped\n"); continue; } stats->count++; setup_main_keyids (keyblock); /* gpg_format_keydesc needs it. */ pk = node->pkt->pkt.public_key; keyid_from_pk (pk, keyid); /* If a secret key export is required we need to check whether we have a secret key at all and if so create the seckey_info structure. */ if (secret) { if (agent_probe_any_secret_key (ctrl, keyblock)) continue; /* No secret key (neither primary nor subkey). */ /* No v3 keys with GNU mode 1001. */ if (secret == 2 && pk->version == 3) { log_info (_("key %s: PGP 2.x style key - skipped\n"), keystr (keyid)); continue; } /* The agent does not yet allow export of v3 packets. It is actually questionable whether we should allow them at all. */ if (pk->version == 3) { log_info ("key %s: PGP 2.x style key (v3) export " "not yet supported - skipped\n", keystr (keyid)); continue; } stats->secret_count++; } /* Always do the cleaning on the public key part if requested. * A designated revocation is never stripped, even with * export-minimal set. */ if ((options & EXPORT_CLEAN)) { merge_keys_and_selfsig (ctrl, keyblock); clean_all_uids (ctrl, keyblock, opt.verbose, (options&EXPORT_MINIMAL), NULL, NULL); clean_all_subkeys (ctrl, keyblock, opt.verbose, (options&EXPORT_MINIMAL)? KEY_CLEAN_ALL /**/ : KEY_CLEAN_AUTHENCR, NULL, NULL); commit_kbnode (&keyblock); } if (export_keep_uid) { commit_kbnode (&keyblock); apply_keep_uid_filter (ctrl, keyblock, export_keep_uid); commit_kbnode (&keyblock); } if (export_drop_subkey) { commit_kbnode (&keyblock); apply_drop_subkey_filter (ctrl, keyblock, export_drop_subkey); commit_kbnode (&keyblock); } /* And write it. */ err = do_export_one_keyblock (ctrl, keyblock, keyid, out_help? out_help : out, secret, options, stats, any, desc, ndesc, descindex, cipherhd); if (err) break; if (keyblock_out) { *keyblock_out = keyblock; break; } if (out_help) { /* We want to write PKA or DANE records. OUT_HELP has the * keyblock and we print a record for each uid to OUT. */ const void *data; size_t datalen; iobuf_flush_temp (out_help); data = iobuf_get_temp_buffer (out_help); datalen = iobuf_get_temp_length (out_help); err = print_pka_or_dane_records (out, keyblock, pk, data, datalen, (options & EXPORT_PKA_FORMAT), (options & EXPORT_DANE_FORMAT)); if (err) goto leave; iobuf_close (out_help); out_help = iobuf_temp (); } } if (gpg_err_code (err) == GPG_ERR_NOT_FOUND) err = 0; leave: iobuf_cancel (out_help); gcry_cipher_close (cipherhd); xfree(desc); keydb_release (kdbhd); if (err || !keyblock_out) release_kbnode( keyblock ); if( !*any ) log_info(_("WARNING: nothing exported\n")); return err; } static gpg_error_t key_to_sshblob (membuf_t *mb, const char *identifier, ...) { va_list arg_ptr; gpg_error_t err = 0; unsigned char nbuf[4]; unsigned char *buf; size_t buflen; gcry_mpi_t a; ulongtobuf (nbuf, (ulong)strlen (identifier)); put_membuf (mb, nbuf, 4); put_membuf_str (mb, identifier); if (!strncmp (identifier, "ecdsa-sha2-", 11)) { ulongtobuf (nbuf, (ulong)strlen (identifier+11)); put_membuf (mb, nbuf, 4); put_membuf_str (mb, identifier+11); } va_start (arg_ptr, identifier); while ((a = va_arg (arg_ptr, gcry_mpi_t))) { err = gcry_mpi_aprint (GCRYMPI_FMT_SSH, &buf, &buflen, a); if (err) break; if (!strcmp (identifier, "ssh-ed25519") && buflen > 5 && buf[4] == 0x40) { /* We need to strip our 0x40 prefix. */ put_membuf (mb, "\x00\x00\x00\x20", 4); put_membuf (mb, buf+5, buflen-5); } else put_membuf (mb, buf, buflen); gcry_free (buf); } va_end (arg_ptr); return err; } static gpg_error_t export_one_ssh_key (estream_t fp, PKT_public_key *pk) { gpg_error_t err; const char *identifier = NULL; membuf_t mb; struct b64state b64_state; void *blob; size_t bloblen; init_membuf (&mb, 4096); switch (pk->pubkey_algo) { case PUBKEY_ALGO_DSA: identifier = "ssh-dss"; err = key_to_sshblob (&mb, identifier, pk->pkey[0], pk->pkey[1], pk->pkey[2], pk->pkey[3], NULL); break; case PUBKEY_ALGO_RSA: case PUBKEY_ALGO_RSA_S: identifier = "ssh-rsa"; err = key_to_sshblob (&mb, identifier, pk->pkey[1], pk->pkey[0], NULL); break; case PUBKEY_ALGO_ECDSA: { char *curveoid; const char *curve; curveoid = openpgp_oid_to_str (pk->pkey[0]); if (!curveoid) err = gpg_error_from_syserror (); else if (!(curve = openpgp_oid_to_curve (curveoid, 0))) err = gpg_error (GPG_ERR_UNKNOWN_CURVE); else { if (!strcmp (curve, "nistp256")) identifier = "ecdsa-sha2-nistp256"; else if (!strcmp (curve, "nistp384")) identifier = "ecdsa-sha2-nistp384"; else if (!strcmp (curve, "nistp521")) identifier = "ecdsa-sha2-nistp521"; if (!identifier) err = gpg_error (GPG_ERR_UNKNOWN_CURVE); else err = key_to_sshblob (&mb, identifier, pk->pkey[1], NULL); } xfree (curveoid); } break; case PUBKEY_ALGO_EDDSA: if (!openpgp_oid_is_ed25519 (pk->pkey[0])) err = gpg_error (GPG_ERR_UNKNOWN_CURVE); else { identifier = "ssh-ed25519"; err = key_to_sshblob (&mb, identifier, pk->pkey[1], NULL); } break; case PUBKEY_ALGO_ELGAMAL_E: case PUBKEY_ALGO_ELGAMAL: err = gpg_error (GPG_ERR_UNUSABLE_PUBKEY); break; default: err = GPG_ERR_PUBKEY_ALGO; break; } if (err) goto leave; err = b64enc_start_es (&b64_state, fp, ""); if (err) goto leave; blob = get_membuf (&mb, &bloblen); if (blob) { es_fprintf (fp, "%s ", identifier); err = b64enc_write (&b64_state, blob, bloblen); es_fprintf (fp, " openpgp:0x%08lX\n", (ulong)keyid_from_pk (pk, NULL)); xfree (blob); } b64enc_finish (&b64_state); leave: xfree (get_membuf (&mb, NULL)); return err; } /* Export the key identified by USERID in the SSH public key format. The function exports the latest subkey with Authentication capability unless the '!' suffix is used to export a specific key. */ gpg_error_t export_ssh_key (ctrl_t ctrl, const char *userid) { gpg_error_t err; kbnode_t keyblock = NULL; KEYDB_SEARCH_DESC desc; u32 latest_date; u32 curtime = make_timestamp (); kbnode_t latest_key, node; PKT_public_key *pk; estream_t fp = NULL; const char *fname = "-"; /* We need to know whether the key has been specified using the exact syntax ('!' suffix). Thus we need to run a classify_user_id on our own. */ err = classify_user_id (userid, &desc, 1); /* Get the public key. */ if (!err) { getkey_ctx_t getkeyctx; err = get_pubkey_byname (ctrl, GET_PUBKEY_NO_AKL, &getkeyctx, NULL, userid, &keyblock, NULL, 0 /* Only usable keys or given exact. */); if (!err) { err = getkey_next (ctrl, getkeyctx, NULL, NULL); if (!err) err = gpg_error (GPG_ERR_AMBIGUOUS_NAME); else if (gpg_err_code (err) == GPG_ERR_NO_PUBKEY) err = 0; } getkey_end (ctrl, getkeyctx); } if (err) { log_error (_("key \"%s\" not found: %s\n"), userid, gpg_strerror (err)); return err; } /* The finish_lookup code in getkey.c does not handle auth keys, thus we have to duplicate the code here to find the latest subkey. However, if the key has been found using an exact match ('!' notation) we use that key without any further checks and even allow the use of the primary key. */ latest_date = 0; latest_key = NULL; for (node = keyblock; node; node = node->next) { if ((node->pkt->pkttype == PKT_PUBLIC_SUBKEY || node->pkt->pkttype == PKT_PUBLIC_KEY) && node->pkt->pkt.public_key->flags.exact) { latest_key = node; break; } } if (!latest_key) { for (node = keyblock; node; node = node->next) { if (node->pkt->pkttype != PKT_PUBLIC_SUBKEY) continue; pk = node->pkt->pkt.public_key; if (DBG_LOOKUP) log_debug ("\tchecking subkey %08lX\n", (ulong) keyid_from_pk (pk, NULL)); if (!(pk->pubkey_usage & PUBKEY_USAGE_AUTH)) { if (DBG_LOOKUP) log_debug ("\tsubkey not usable for authentication\n"); continue; } if (!pk->flags.valid) { if (DBG_LOOKUP) log_debug ("\tsubkey not valid\n"); continue; } if (pk->flags.revoked) { if (DBG_LOOKUP) log_debug ("\tsubkey has been revoked\n"); continue; } if (pk->has_expired) { if (DBG_LOOKUP) log_debug ("\tsubkey has expired\n"); continue; } if (pk->timestamp > curtime && !opt.ignore_valid_from) { if (DBG_LOOKUP) log_debug ("\tsubkey not yet valid\n"); continue; } if (DBG_LOOKUP) log_debug ("\tsubkey might be fine\n"); /* In case a key has a timestamp of 0 set, we make sure that it is used. A better change would be to compare ">=" but that might also change the selected keys and is as such a more intrusive change. */ if (pk->timestamp > latest_date || (!pk->timestamp && !latest_date)) { latest_date = pk->timestamp; latest_key = node; } } /* If no subkey was suitable check the primary key. */ if (!latest_key && (node = keyblock) && node->pkt->pkttype == PKT_PUBLIC_KEY) { pk = node->pkt->pkt.public_key; if (DBG_LOOKUP) log_debug ("\tchecking primary key %08lX\n", (ulong) keyid_from_pk (pk, NULL)); if (!(pk->pubkey_usage & PUBKEY_USAGE_AUTH)) { if (DBG_LOOKUP) log_debug ("\tprimary key not usable for authentication\n"); } else if (!pk->flags.valid) { if (DBG_LOOKUP) log_debug ("\tprimary key not valid\n"); } else if (pk->flags.revoked) { if (DBG_LOOKUP) log_debug ("\tprimary key has been revoked\n"); } else if (pk->has_expired) { if (DBG_LOOKUP) log_debug ("\tprimary key has expired\n"); } else if (pk->timestamp > curtime && !opt.ignore_valid_from) { if (DBG_LOOKUP) log_debug ("\tprimary key not yet valid\n"); } else { if (DBG_LOOKUP) log_debug ("\tprimary key is fine\n"); latest_date = pk->timestamp; latest_key = node; } } } if (!latest_key) { err = gpg_error (GPG_ERR_UNUSABLE_PUBKEY); log_error (_("key \"%s\" not found: %s\n"), userid, gpg_strerror (err)); goto leave; } pk = latest_key->pkt->pkt.public_key; if (DBG_LOOKUP) log_debug ("\tusing key %08lX\n", (ulong) keyid_from_pk (pk, NULL)); if (opt.outfile && *opt.outfile && strcmp (opt.outfile, "-")) fp = es_fopen ((fname = opt.outfile), "w"); else fp = es_stdout; if (!fp) { err = gpg_error_from_syserror (); log_error (_("error creating '%s': %s\n"), fname, gpg_strerror (err)); goto leave; } err = export_one_ssh_key (fp, pk); if (err) goto leave; if (es_ferror (fp)) err = gpg_error_from_syserror (); else { if (es_fclose (fp)) err = gpg_error_from_syserror (); fp = NULL; } if (err) log_error (_("error writing '%s': %s\n"), fname, gpg_strerror (err)); leave: es_fclose (fp); release_kbnode (keyblock); return err; } diff --git a/g10/keygen.c b/g10/keygen.c index ab53a6573..e25d4d925 100644 --- a/g10/keygen.c +++ b/g10/keygen.c @@ -1,6135 +1,6126 @@ /* keygen.c - Generate a key pair * Copyright (C) 1998-2007, 2009-2011 Free Software Foundation, Inc. * Copyright (C) 2014, 2015, 2016, 2017, 2018 Werner Koch * Copyright (C) 2020 g10 Code GmbH * * This file is part of GnuPG. * * GnuPG is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * GnuPG is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . */ #include #include #include #include #include #include #include #include #include #include "gpg.h" #include "../common/util.h" #include "main.h" #include "packet.h" #include "../common/ttyio.h" #include "options.h" #include "keydb.h" #include "trustdb.h" #include "../common/status.h" #include "../common/i18n.h" #include "keyserver-internal.h" #include "call-agent.h" #include "pkglue.h" #include "../common/shareddefs.h" #include "../common/host2net.h" #include "../common/mbox-util.h" /* The default algorithms. If you change them, you should ensure the value is inside the bounds enforced by ask_keysize and gen_xxx. See also get_keysize_range which encodes the allowed ranges. */ #define DEFAULT_STD_KEY_PARAM "rsa3072/cert,sign+rsa3072/encr" #define FUTURE_STD_KEY_PARAM "ed25519/cert,sign+cv25519/encr" /* When generating keys using the streamlined key generation dialog, use this as a default expiration interval. */ const char *default_expiration_interval = "2y"; /* Flag bits used during key generation. */ #define KEYGEN_FLAG_NO_PROTECTION 1 #define KEYGEN_FLAG_TRANSIENT_KEY 2 #define KEYGEN_FLAG_CREATE_V5_KEY 4 /* Maximum number of supported algorithm preferences. */ #define MAX_PREFS 30 enum para_name { pKEYTYPE, pKEYLENGTH, pKEYCURVE, pKEYUSAGE, pSUBKEYTYPE, pSUBKEYLENGTH, pSUBKEYCURVE, pSUBKEYUSAGE, pAUTHKEYTYPE, pNAMEREAL, pNAMEEMAIL, pNAMECOMMENT, pPREFERENCES, pREVOKER, pUSERID, pCREATIONDATE, pKEYCREATIONDATE, /* Same in seconds since epoch. */ pEXPIREDATE, pKEYEXPIRE, /* in n seconds */ pSUBKEYCREATIONDATE, pSUBKEYEXPIRE, /* in n seconds */ pAUTHKEYCREATIONDATE, /* Not yet used. */ pPASSPHRASE, pSERIALNO, pCARDBACKUPKEY, pHANDLE, pKEYSERVER, pKEYGRIP, pSUBKEYGRIP, pVERSION, /* Desired version of the key packet. */ pSUBVERSION, /* Ditto for the subpacket. */ pCARDKEY /* The keygrips have been taken from active card (bool). */ }; struct para_data_s { struct para_data_s *next; int lnr; enum para_name key; union { u32 expire; u32 creation; int abool; unsigned int usage; struct revocation_key revkey; char value[1]; } u; }; struct output_control_s { int lnr; int dryrun; unsigned int keygen_flags; int use_files; struct { char *fname; char *newfname; IOBUF stream; armor_filter_context_t *afx; } pub; }; struct opaque_data_usage_and_pk { unsigned int usage; PKT_public_key *pk; }; /* FIXME: These globals vars are ugly. And using MAX_PREFS even for * aeads is useless, given that we don't expects more than a very few * algorithms. */ static int prefs_initialized = 0; static byte sym_prefs[MAX_PREFS]; static int nsym_prefs; static byte hash_prefs[MAX_PREFS]; static int nhash_prefs; static byte zip_prefs[MAX_PREFS]; static int nzip_prefs; static byte aead_prefs[MAX_PREFS]; static int naead_prefs; static int mdc_available; static int ks_modify; static int aead_available; static gpg_error_t parse_algo_usage_expire (ctrl_t ctrl, int for_subkey, const char *algostr, const char *usagestr, const char *expirestr, int *r_algo, unsigned int *r_usage, u32 *r_expire, unsigned int *r_nbits, const char **r_curve, int *r_version, char **r_keygrip, u32 *r_keytime); static void do_generate_keypair (ctrl_t ctrl, struct para_data_s *para, struct output_control_s *outctrl, int card ); static int write_keyblock (iobuf_t out, kbnode_t node); static gpg_error_t gen_card_key (int keyno, int algo, int is_primary, kbnode_t pub_root, u32 *timestamp, u32 expireval, int keygen_flags); static unsigned int get_keysize_range (int algo, unsigned int *min, unsigned int *max); /* Return the algo string for a default new key. */ const char * get_default_pubkey_algo (void) { if (opt.def_new_key_algo) { if (*opt.def_new_key_algo && !strchr (opt.def_new_key_algo, ':')) return opt.def_new_key_algo; /* To avoid checking that option every time we delay that until * here. The only thing we really need to make sure is that * there is no colon in the string so that the --gpgconf-list * command won't mess up its output. */ log_info (_("invalid value for option '%s'\n"), "--default-new-key-algo"); } return DEFAULT_STD_KEY_PARAM; } static void print_status_key_created (int letter, PKT_public_key *pk, const char *handle) { byte array[MAX_FINGERPRINT_LEN], *s; char *buf, *p; size_t i, n; if (!handle) handle = ""; buf = xmalloc (MAX_FINGERPRINT_LEN*2+31 + strlen (handle) + 1); p = buf; if (letter || pk) { *p++ = letter; if (pk) { *p++ = ' '; fingerprint_from_pk (pk, array, &n); s = array; /* Fixme: Use bin2hex */ for (i=0; i < n ; i++, s++, p += 2) snprintf (p, 3, "%02X", *s); } } if (*handle) { *p++ = ' '; for (i=0; handle[i] && i < 100; i++) *p++ = isspace ((unsigned int)handle[i])? '_':handle[i]; } *p = 0; write_status_text ((letter || pk)?STATUS_KEY_CREATED:STATUS_KEY_NOT_CREATED, buf); xfree (buf); } static void print_status_key_not_created (const char *handle) { print_status_key_created (0, NULL, handle); } static gpg_error_t write_uid (kbnode_t root, const char *s) { PACKET *pkt = xmalloc_clear (sizeof *pkt); size_t n = strlen (s); if (n > MAX_UID_PACKET_LENGTH - 10) return gpg_error (GPG_ERR_INV_USER_ID); pkt->pkttype = PKT_USER_ID; pkt->pkt.user_id = xmalloc_clear (sizeof *pkt->pkt.user_id + n); pkt->pkt.user_id->len = n; pkt->pkt.user_id->ref = 1; strcpy (pkt->pkt.user_id->name, s); add_kbnode (root, new_kbnode (pkt)); return 0; } static void do_add_key_flags (PKT_signature *sig, unsigned int use) { byte buf[1]; buf[0] = 0; /* The spec says that all primary keys MUST be able to certify. */ if(sig->sig_class!=0x18) buf[0] |= 0x01; if (use & PUBKEY_USAGE_SIG) buf[0] |= 0x02; if (use & PUBKEY_USAGE_ENC) buf[0] |= 0x04 | 0x08; if (use & PUBKEY_USAGE_AUTH) buf[0] |= 0x20; build_sig_subpkt (sig, SIGSUBPKT_KEY_FLAGS, buf, 1); } int keygen_add_key_expire (PKT_signature *sig, void *opaque) { PKT_public_key *pk = opaque; byte buf[8]; u32 u; if (pk->expiredate) { if (pk->expiredate > pk->timestamp) u = pk->expiredate - pk->timestamp; else u = 1; buf[0] = (u >> 24) & 0xff; buf[1] = (u >> 16) & 0xff; buf[2] = (u >> 8) & 0xff; buf[3] = u & 0xff; build_sig_subpkt (sig, SIGSUBPKT_KEY_EXPIRE, buf, 4); } else { /* Make sure we don't leave a key expiration subpacket lying around */ delete_sig_subpkt (sig->hashed, SIGSUBPKT_KEY_EXPIRE); } return 0; } /* Add the key usage (i.e. key flags) in SIG from the public keys * pubkey_usage field. OPAQUE has the public key. */ int keygen_add_key_flags (PKT_signature *sig, void *opaque) { PKT_public_key *pk = opaque; do_add_key_flags (sig, pk->pubkey_usage); return 0; } static int keygen_add_key_flags_and_expire (PKT_signature *sig, void *opaque) { struct opaque_data_usage_and_pk *oduap = opaque; do_add_key_flags (sig, oduap->usage); return keygen_add_key_expire (sig, oduap->pk); } static int set_one_pref (int val, int type, const char *item, byte *buf, int *nbuf) { int i; for (i=0; i < *nbuf; i++ ) if (buf[i] == val) { log_info (_("preference '%s' duplicated\n"), item); return -1; } if (*nbuf >= MAX_PREFS) { if(type==1) log_info(_("too many cipher preferences\n")); else if(type==2) log_info(_("too many digest preferences\n")); else if(type==3) log_info(_("too many compression preferences\n")); else if(type==4) log_info(_("too many AEAD preferences\n")); else BUG(); return -1; } buf[(*nbuf)++] = val; return 0; } /* * Parse the supplied string and use it to set the standard * preferences. The string may be in a form like the one printed by * "pref" (something like: "S10 S3 H3 H2 Z2 Z1") or the actual * cipher/hash/compress names. Use NULL to set the default * preferences. Returns: 0 = okay */ int keygen_set_std_prefs (const char *string,int personal) { byte sym[MAX_PREFS], hash[MAX_PREFS], zip[MAX_PREFS], aead[MAX_PREFS]; int nsym=0, nhash=0, nzip=0, naead=0, val, rc=0; int mdc=1, modify=0; /* mdc defaults on, modify defaults off. */ char dummy_string[25*4+1]; /* Enough for 25 items. */ if (!string || !ascii_strcasecmp (string, "default")) { if (opt.def_preference_list) string=opt.def_preference_list; else { int any_compress = 0; dummy_string[0]='\0'; /* The rationale why we use the order AES256,192,128 is for compatibility reasons with PGP. If gpg would define AES128 first, we would get the somewhat confusing situation: gpg -r pgpkey -r gpgkey ---gives--> AES256 gpg -r gpgkey -r pgpkey ---gives--> AES Note that by using --personal-cipher-preferences it is possible to prefer AES128. */ /* Make sure we do not add more than 15 items here, as we could overflow the size of dummy_string. We currently have at most 12. */ if ( !openpgp_cipher_test_algo (CIPHER_ALGO_AES256) ) strcat(dummy_string,"S9 "); if ( !openpgp_cipher_test_algo (CIPHER_ALGO_AES192) ) strcat(dummy_string,"S8 "); if ( !openpgp_cipher_test_algo (CIPHER_ALGO_AES) ) strcat(dummy_string,"S7 "); strcat(dummy_string,"S2 "); /* 3DES */ if (opt.flags.rfc4880bis && !openpgp_aead_test_algo (AEAD_ALGO_OCB)) strcat(dummy_string,"A2 "); if (opt.flags.rfc4880bis && !openpgp_aead_test_algo (AEAD_ALGO_EAX)) strcat(dummy_string,"A1 "); if (personal) { /* The default internal hash algo order is: * SHA-256, SHA-384, SHA-512, SHA-224, SHA-1. */ if (!openpgp_md_test_algo (DIGEST_ALGO_SHA256)) strcat (dummy_string, "H8 "); if (!openpgp_md_test_algo (DIGEST_ALGO_SHA384)) strcat (dummy_string, "H9 "); if (!openpgp_md_test_algo (DIGEST_ALGO_SHA512)) strcat (dummy_string, "H10 "); } else { /* The default advertised hash algo order is: * SHA-512, SHA-384, SHA-256, SHA-224, SHA-1. */ if (!openpgp_md_test_algo (DIGEST_ALGO_SHA512)) strcat (dummy_string, "H10 "); if (!openpgp_md_test_algo (DIGEST_ALGO_SHA384)) strcat (dummy_string, "H9 "); if (!openpgp_md_test_algo (DIGEST_ALGO_SHA256)) strcat (dummy_string, "H8 "); } if (!openpgp_md_test_algo (DIGEST_ALGO_SHA224)) strcat (dummy_string, "H11 "); strcat (dummy_string, "H2 "); /* SHA-1 */ if(!check_compress_algo(COMPRESS_ALGO_ZLIB)) { strcat(dummy_string,"Z2 "); any_compress = 1; } if(!check_compress_algo(COMPRESS_ALGO_BZIP2)) { strcat(dummy_string,"Z3 "); any_compress = 1; } if(!check_compress_algo(COMPRESS_ALGO_ZIP)) { strcat(dummy_string,"Z1 "); any_compress = 1; } /* In case we have no compress algo at all, declare that we prefer no compression. */ if (!any_compress) strcat(dummy_string,"Z0 "); /* Remove the trailing space. */ if (*dummy_string && dummy_string[strlen (dummy_string)-1] == ' ') dummy_string[strlen (dummy_string)-1] = 0; string=dummy_string; } } else if (!ascii_strcasecmp (string, "none")) string = ""; if(strlen(string)) { char *prefstringbuf; char *tok, *prefstring; /* We need a writable string. */ prefstring = prefstringbuf = xstrdup (string); while((tok=strsep(&prefstring," ,"))) { if((val=string_to_cipher_algo (tok))) { if(set_one_pref(val,1,tok,sym,&nsym)) rc=-1; } else if((val=string_to_digest_algo (tok))) { if(set_one_pref(val,2,tok,hash,&nhash)) rc=-1; } else if((val=string_to_compress_algo(tok))>-1) { if(set_one_pref(val,3,tok,zip,&nzip)) rc=-1; } else if ((val=string_to_aead_algo (tok))) { if (set_one_pref (val, 4, tok, aead, &naead)) rc = -1; } else if (ascii_strcasecmp(tok,"mdc")==0) mdc=1; else if (ascii_strcasecmp(tok,"no-mdc")==0) mdc=0; else if (ascii_strcasecmp(tok,"ks-modify")==0) modify=1; else if (ascii_strcasecmp(tok,"no-ks-modify")==0) modify=0; else { log_info (_("invalid item '%s' in preference string\n"),tok); rc=-1; } } xfree (prefstringbuf); } if(!rc) { if(personal) { if(personal==PREFTYPE_SYM) { xfree(opt.personal_cipher_prefs); if(nsym==0) opt.personal_cipher_prefs=NULL; else { int i; opt.personal_cipher_prefs= xmalloc(sizeof(prefitem_t *)*(nsym+1)); for (i=0; iref=1; uid->prefs = xmalloc ((sizeof(prefitem_t *)* (nsym_prefs+naead_prefs+nhash_prefs+nzip_prefs+1))); for(i=0;iprefs[j].type=PREFTYPE_SYM; uid->prefs[j].value=sym_prefs[i]; } for (i=0; i < naead_prefs; i++, j++) { uid->prefs[j].type = PREFTYPE_AEAD; uid->prefs[j].value = aead_prefs[i]; } for(i=0;iprefs[j].type=PREFTYPE_HASH; uid->prefs[j].value=hash_prefs[i]; } for(i=0;iprefs[j].type=PREFTYPE_ZIP; uid->prefs[j].value=zip_prefs[i]; } uid->prefs[j].type=PREFTYPE_NONE; uid->prefs[j].value=0; uid->flags.mdc = mdc_available; uid->flags.aead = aead_available; uid->flags.ks_modify = ks_modify; return uid; } static void add_feature_mdc (PKT_signature *sig,int enabled) { const byte *s; size_t n; int i; char *buf; s = parse_sig_subpkt (sig, 1, SIGSUBPKT_FEATURES, &n ); /* Already set or cleared */ if (s && n && ((enabled && (s[0] & 0x01)) || (!enabled && !(s[0] & 0x01)))) return; if (!s || !n) { /* create a new one */ n = 1; buf = xmalloc_clear (n); } else { buf = xmalloc (n); memcpy (buf, s, n); } if(enabled) buf[0] |= 0x01; /* MDC feature */ else buf[0] &= ~0x01; /* Are there any bits set? */ for(i=0;ihashed, SIGSUBPKT_FEATURES); else build_sig_subpkt (sig, SIGSUBPKT_FEATURES, buf, n); xfree (buf); } static void add_feature_aead (PKT_signature *sig, int enabled) { const byte *s; size_t n; int i; char *buf; s = parse_sig_subpkt (sig, 1, SIGSUBPKT_FEATURES, &n ); if (s && n && ((enabled && (s[0] & 0x02)) || (!enabled && !(s[0] & 0x02)))) return; /* Already set or cleared */ if (!s || !n) { /* Create a new one */ n = 1; buf = xmalloc_clear (n); } else { buf = xmalloc (n); memcpy (buf, s, n); } if (enabled) buf[0] |= 0x02; /* AEAD supported */ else buf[0] &= ~0x02; /* Are there any bits set? */ for (i=0; i < n; i++) if (buf[i]) break; if (i == n) delete_sig_subpkt (sig->hashed, SIGSUBPKT_FEATURES); else build_sig_subpkt (sig, SIGSUBPKT_FEATURES, buf, n); xfree (buf); } static void add_feature_v5 (PKT_signature *sig, int enabled) { const byte *s; size_t n; int i; char *buf; s = parse_sig_subpkt (sig, 1, SIGSUBPKT_FEATURES, &n ); if (s && n && ((enabled && (s[0] & 0x04)) || (!enabled && !(s[0] & 0x04)))) return; /* Already set or cleared */ if (!s || !n) { /* Create a new one */ n = 1; buf = xmalloc_clear (n); } else { buf = xmalloc (n); memcpy (buf, s, n); } if (enabled) buf[0] |= 0x04; /* v5 key supported */ else buf[0] &= ~0x04; /* Are there any bits set? */ for (i=0; i < n; i++) if (buf[i]) break; if (i == n) delete_sig_subpkt (sig->hashed, SIGSUBPKT_FEATURES); else build_sig_subpkt (sig, SIGSUBPKT_FEATURES, buf, n); xfree (buf); } static void add_keyserver_modify (PKT_signature *sig,int enabled) { const byte *s; size_t n; int i; char *buf; /* The keyserver modify flag is a negative flag (i.e. no-modify) */ enabled=!enabled; s = parse_sig_subpkt (sig, 1, SIGSUBPKT_KS_FLAGS, &n ); /* Already set or cleared */ if (s && n && ((enabled && (s[0] & 0x80)) || (!enabled && !(s[0] & 0x80)))) return; if (!s || !n) { /* create a new one */ n = 1; buf = xmalloc_clear (n); } else { buf = xmalloc (n); memcpy (buf, s, n); } if(enabled) buf[0] |= 0x80; /* no-modify flag */ else buf[0] &= ~0x80; /* Are there any bits set? */ for(i=0;ihashed, SIGSUBPKT_KS_FLAGS); else build_sig_subpkt (sig, SIGSUBPKT_KS_FLAGS, buf, n); xfree (buf); } int keygen_upd_std_prefs (PKT_signature *sig, void *opaque) { (void)opaque; if (!prefs_initialized) keygen_set_std_prefs (NULL, 0); if (nsym_prefs) build_sig_subpkt (sig, SIGSUBPKT_PREF_SYM, sym_prefs, nsym_prefs); else { delete_sig_subpkt (sig->hashed, SIGSUBPKT_PREF_SYM); delete_sig_subpkt (sig->unhashed, SIGSUBPKT_PREF_SYM); } if (naead_prefs) build_sig_subpkt (sig, SIGSUBPKT_PREF_AEAD, aead_prefs, naead_prefs); else { delete_sig_subpkt (sig->hashed, SIGSUBPKT_PREF_AEAD); delete_sig_subpkt (sig->unhashed, SIGSUBPKT_PREF_AEAD); } if (nhash_prefs) build_sig_subpkt (sig, SIGSUBPKT_PREF_HASH, hash_prefs, nhash_prefs); else { delete_sig_subpkt (sig->hashed, SIGSUBPKT_PREF_HASH); delete_sig_subpkt (sig->unhashed, SIGSUBPKT_PREF_HASH); } if (nzip_prefs) build_sig_subpkt (sig, SIGSUBPKT_PREF_COMPR, zip_prefs, nzip_prefs); else { delete_sig_subpkt (sig->hashed, SIGSUBPKT_PREF_COMPR); delete_sig_subpkt (sig->unhashed, SIGSUBPKT_PREF_COMPR); } /* Make sure that the MDC feature flag is set if needed. */ add_feature_mdc (sig,mdc_available); add_feature_aead (sig, aead_available); add_feature_v5 (sig, opt.flags.rfc4880bis); add_keyserver_modify (sig,ks_modify); keygen_add_keyserver_url(sig,NULL); return 0; } /**************** * Add preference to the self signature packet. * This is only called for packets with version > 3. */ int keygen_add_std_prefs (PKT_signature *sig, void *opaque) { PKT_public_key *pk = opaque; do_add_key_flags (sig, pk->pubkey_usage); keygen_add_key_expire (sig, opaque ); keygen_upd_std_prefs (sig, opaque); keygen_add_keyserver_url (sig,NULL); return 0; } int keygen_add_keyserver_url(PKT_signature *sig, void *opaque) { const char *url=opaque; if(!url) url=opt.def_keyserver_url; if(url) build_sig_subpkt(sig,SIGSUBPKT_PREF_KS,url,strlen(url)); else delete_sig_subpkt (sig->hashed,SIGSUBPKT_PREF_KS); return 0; } int keygen_add_notations(PKT_signature *sig,void *opaque) { struct notation *notation; /* We always start clean */ delete_sig_subpkt(sig->hashed,SIGSUBPKT_NOTATION); delete_sig_subpkt(sig->unhashed,SIGSUBPKT_NOTATION); sig->flags.notation=0; for(notation=opaque;notation;notation=notation->next) if(!notation->flags.ignore) { unsigned char *buf; unsigned int n1,n2; n1=strlen(notation->name); if(notation->altvalue) n2=strlen(notation->altvalue); else if(notation->bdat) n2=notation->blen; else n2=strlen(notation->value); buf = xmalloc( 8 + n1 + n2 ); /* human readable or not */ buf[0] = notation->bdat?0:0x80; buf[1] = buf[2] = buf[3] = 0; buf[4] = n1 >> 8; buf[5] = n1; buf[6] = n2 >> 8; buf[7] = n2; memcpy(buf+8, notation->name, n1 ); if(notation->altvalue) memcpy(buf+8+n1, notation->altvalue, n2 ); else if(notation->bdat) memcpy(buf+8+n1, notation->bdat, n2 ); else memcpy(buf+8+n1, notation->value, n2 ); build_sig_subpkt( sig, SIGSUBPKT_NOTATION | (notation->flags.critical?SIGSUBPKT_FLAG_CRITICAL:0), buf, 8+n1+n2 ); xfree(buf); } return 0; } int keygen_add_revkey (PKT_signature *sig, void *opaque) { struct revocation_key *revkey = opaque; byte buf[2+MAX_FINGERPRINT_LEN]; log_assert (revkey->fprlen <= MAX_FINGERPRINT_LEN); buf[0] = revkey->class; buf[1] = revkey->algid; memcpy (buf + 2, revkey->fpr, revkey->fprlen); memset (buf + 2 + revkey->fprlen, 0, sizeof (revkey->fpr) - revkey->fprlen); build_sig_subpkt (sig, SIGSUBPKT_REV_KEY, buf, 2+revkey->fprlen); /* All sigs with revocation keys set are nonrevocable. */ sig->flags.revocable = 0; buf[0] = 0; build_sig_subpkt (sig, SIGSUBPKT_REVOCABLE, buf, 1); parse_revkeys (sig); return 0; } /* Create a back-signature. If TIMESTAMP is not NULL, use it for the signature creation time. */ gpg_error_t make_backsig (ctrl_t ctrl, PKT_signature *sig, PKT_public_key *pk, PKT_public_key *sub_pk, PKT_public_key *sub_psk, u32 timestamp, const char *cache_nonce) { gpg_error_t err; PKT_signature *backsig; cache_public_key (sub_pk); err = make_keysig_packet (ctrl, &backsig, pk, NULL, sub_pk, sub_psk, 0x19, timestamp, 0, NULL, NULL, cache_nonce); if (err) log_error ("make_keysig_packet failed for backsig: %s\n", gpg_strerror (err)); else { /* Get it into a binary packed form. */ IOBUF backsig_out = iobuf_temp(); PACKET backsig_pkt; init_packet (&backsig_pkt); backsig_pkt.pkttype = PKT_SIGNATURE; backsig_pkt.pkt.signature = backsig; err = build_packet (backsig_out, &backsig_pkt); free_packet (&backsig_pkt, NULL); if (err) log_error ("build_packet failed for backsig: %s\n", gpg_strerror (err)); else { size_t pktlen = 0; byte *buf = iobuf_get_temp_buffer (backsig_out); /* Remove the packet header. */ if(buf[0]&0x40) { if (buf[1] < 192) { pktlen = buf[1]; buf += 2; } else if(buf[1] < 224) { pktlen = (buf[1]-192)*256; pktlen += buf[2]+192; buf += 3; } else if (buf[1] == 255) { pktlen = buf32_to_size_t (buf+2); buf += 6; } else BUG (); } else { int mark = 1; switch (buf[0]&3) { case 3: BUG (); break; case 2: pktlen = (size_t)buf[mark++] << 24; pktlen |= buf[mark++] << 16; /* fall through */ case 1: pktlen |= buf[mark++] << 8; /* fall through */ case 0: pktlen |= buf[mark++]; } buf += mark; } /* Now make the binary blob into a subpacket. */ build_sig_subpkt (sig, SIGSUBPKT_SIGNATURE, buf, pktlen); iobuf_close (backsig_out); } } return err; } /* Write a direct key signature to the first key in ROOT using the key PSK. REVKEY is describes the direct key signature and TIMESTAMP is the timestamp to set on the signature. */ static gpg_error_t write_direct_sig (ctrl_t ctrl, kbnode_t root, PKT_public_key *psk, struct revocation_key *revkey, u32 timestamp, const char *cache_nonce) { gpg_error_t err; PACKET *pkt; PKT_signature *sig; KBNODE node; PKT_public_key *pk; if (opt.verbose) log_info (_("writing direct signature\n")); /* Get the pk packet from the pub_tree. */ node = find_kbnode (root, PKT_PUBLIC_KEY); if (!node) BUG (); pk = node->pkt->pkt.public_key; /* We have to cache the key, so that the verification of the signature creation is able to retrieve the public key. */ cache_public_key (pk); /* Make the signature. */ err = make_keysig_packet (ctrl, &sig, pk, NULL,NULL, psk, 0x1F, timestamp, 0, keygen_add_revkey, revkey, cache_nonce); if (err) { log_error ("make_keysig_packet failed: %s\n", gpg_strerror (err) ); return err; } pkt = xmalloc_clear (sizeof *pkt); pkt->pkttype = PKT_SIGNATURE; pkt->pkt.signature = sig; add_kbnode (root, new_kbnode (pkt)); return err; } /* Write a self-signature to the first user id in ROOT using the key PSK. USE and TIMESTAMP give the extra data we need for the signature. */ static gpg_error_t write_selfsigs (ctrl_t ctrl, kbnode_t root, PKT_public_key *psk, unsigned int use, u32 timestamp, const char *cache_nonce) { gpg_error_t err; PACKET *pkt; PKT_signature *sig; PKT_user_id *uid; KBNODE node; PKT_public_key *pk; if (opt.verbose) log_info (_("writing self signature\n")); /* Get the uid packet from the list. */ node = find_kbnode (root, PKT_USER_ID); if (!node) BUG(); /* No user id packet in tree. */ uid = node->pkt->pkt.user_id; /* Get the pk packet from the pub_tree. */ node = find_kbnode (root, PKT_PUBLIC_KEY); if (!node) BUG(); pk = node->pkt->pkt.public_key; /* The usage has not yet been set - do it now. */ pk->pubkey_usage = use; /* We have to cache the key, so that the verification of the signature creation is able to retrieve the public key. */ cache_public_key (pk); /* Make the signature. */ err = make_keysig_packet (ctrl, &sig, pk, uid, NULL, psk, 0x13, timestamp, 0, keygen_add_std_prefs, pk, cache_nonce); if (err) { log_error ("make_keysig_packet failed: %s\n", gpg_strerror (err)); return err; } pkt = xmalloc_clear (sizeof *pkt); pkt->pkttype = PKT_SIGNATURE; pkt->pkt.signature = sig; add_kbnode (root, new_kbnode (pkt)); return err; } /* Write the key binding signature. If TIMESTAMP is not NULL use the signature creation time. PRI_PSK is the key use for signing. SUB_PSK is a key used to create a back-signature; that one is only used if USE has the PUBKEY_USAGE_SIG capability. */ static int write_keybinding (ctrl_t ctrl, kbnode_t root, PKT_public_key *pri_psk, PKT_public_key *sub_psk, unsigned int use, u32 timestamp, const char *cache_nonce) { gpg_error_t err; PACKET *pkt; PKT_signature *sig; KBNODE node; PKT_public_key *pri_pk, *sub_pk; struct opaque_data_usage_and_pk oduap; if (opt.verbose) log_info(_("writing key binding signature\n")); /* Get the primary pk packet from the tree. */ node = find_kbnode (root, PKT_PUBLIC_KEY); if (!node) BUG(); pri_pk = node->pkt->pkt.public_key; /* We have to cache the key, so that the verification of the * signature creation is able to retrieve the public key. */ cache_public_key (pri_pk); /* Find the last subkey. */ sub_pk = NULL; for (node = root; node; node = node->next ) { if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY) sub_pk = node->pkt->pkt.public_key; } if (!sub_pk) BUG(); /* Make the signature. */ oduap.usage = use; oduap.pk = sub_pk; err = make_keysig_packet (ctrl, &sig, pri_pk, NULL, sub_pk, pri_psk, 0x18, timestamp, 0, keygen_add_key_flags_and_expire, &oduap, cache_nonce); if (err) { log_error ("make_keysig_packeto failed: %s\n", gpg_strerror (err)); return err; } /* Make a backsig. */ if (use & PUBKEY_USAGE_SIG) { err = make_backsig (ctrl, sig, pri_pk, sub_pk, sub_psk, timestamp, cache_nonce); if (err) return err; } pkt = xmalloc_clear ( sizeof *pkt ); pkt->pkttype = PKT_SIGNATURE; pkt->pkt.signature = sig; add_kbnode (root, new_kbnode (pkt) ); return err; } static gpg_error_t ecckey_from_sexp (gcry_mpi_t *array, gcry_sexp_t sexp, int algo) { gpg_error_t err; gcry_sexp_t list, l2; char *curve = NULL; int i; const char *oidstr; unsigned int nbits; array[0] = NULL; array[1] = NULL; array[2] = NULL; list = gcry_sexp_find_token (sexp, "public-key", 0); if (!list) return gpg_error (GPG_ERR_INV_OBJ); l2 = gcry_sexp_cadr (list); gcry_sexp_release (list); list = l2; if (!list) return gpg_error (GPG_ERR_NO_OBJ); l2 = gcry_sexp_find_token (list, "curve", 0); if (!l2) { err = gpg_error (GPG_ERR_NO_OBJ); goto leave; } curve = gcry_sexp_nth_string (l2, 1); if (!curve) { err = gpg_error (GPG_ERR_NO_OBJ); goto leave; } gcry_sexp_release (l2); oidstr = openpgp_curve_to_oid (curve, &nbits, NULL); if (!oidstr) { /* That can't happen because we used one of the curves gpg_curve_to_oid knows about. */ err = gpg_error (GPG_ERR_INV_OBJ); goto leave; } err = openpgp_oid_from_str (oidstr, &array[0]); if (err) goto leave; - l2 = gcry_sexp_find_token (list, "q", 0); - if (!l2) - { - err = gpg_error (GPG_ERR_NO_OBJ); - goto leave; - } - array[1] = gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG); - gcry_sexp_release (l2); - if (!array[1]) - { - err = gpg_error (GPG_ERR_INV_OBJ); - goto leave; - } + err = sexp_extract_param_sos (list, "q", &array[1]); + if (err) + goto leave; + gcry_sexp_release (list); if (algo == PUBKEY_ALGO_ECDH) { array[2] = pk_ecdh_default_params (nbits); if (!array[2]) { err = gpg_error_from_syserror (); goto leave; } } leave: xfree (curve); if (err) { for (i=0; i < 3; i++) { gcry_mpi_release (array[i]); array[i] = NULL; } } return err; } /* Extract key parameters from SEXP and store them in ARRAY. ELEMS is a string where each character denotes a parameter name. TOPNAME is the name of the top element above the elements. */ static int key_from_sexp (gcry_mpi_t *array, gcry_sexp_t sexp, const char *topname, const char *elems) { gcry_sexp_t list, l2; const char *s; int i, idx; int rc = 0; list = gcry_sexp_find_token (sexp, topname, 0); if (!list) return gpg_error (GPG_ERR_INV_OBJ); l2 = gcry_sexp_cadr (list); gcry_sexp_release (list); list = l2; if (!list) return gpg_error (GPG_ERR_NO_OBJ); for (idx=0,s=elems; *s; s++, idx++) { l2 = gcry_sexp_find_token (list, s, 1); if (!l2) { rc = gpg_error (GPG_ERR_NO_OBJ); /* required parameter not found */ goto leave; } array[idx] = gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG); gcry_sexp_release (l2); if (!array[idx]) { rc = gpg_error (GPG_ERR_INV_OBJ); /* required parameter invalid */ goto leave; } } gcry_sexp_release (list); leave: if (rc) { for (i=0; itimestamp = timestamp; pk->version = (keygen_flags & KEYGEN_FLAG_CREATE_V5_KEY)? 5 : 4; if (expireval) pk->expiredate = pk->timestamp + expireval; pk->pubkey_algo = algo; if (algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_EDDSA || algo == PUBKEY_ALGO_ECDH ) err = ecckey_from_sexp (pk->pkey, s_key, algo); else err = key_from_sexp (pk->pkey, s_key, "public-key", algoelem); if (err) { log_error ("key_from_sexp failed: %s\n", gpg_strerror (err) ); gcry_sexp_release (s_key); free_public_key (pk); return err; } gcry_sexp_release (s_key); pkt = xtrycalloc (1, sizeof *pkt); if (!pkt) { err = gpg_error_from_syserror (); free_public_key (pk); return err; } pkt->pkttype = is_subkey ? PKT_PUBLIC_SUBKEY : PKT_PUBLIC_KEY; pkt->pkt.public_key = pk; add_kbnode (pub_root, new_kbnode (pkt)); return 0; } /* Common code for the key generation function gen_xxx. */ static int common_gen (const char *keyparms, int algo, const char *algoelem, kbnode_t pub_root, u32 timestamp, u32 expireval, int is_subkey, int keygen_flags, const char *passphrase, char **cache_nonce_addr, char **passwd_nonce_addr) { int err; PACKET *pkt; PKT_public_key *pk; gcry_sexp_t s_key; err = agent_genkey (NULL, cache_nonce_addr, passwd_nonce_addr, keyparms, !!(keygen_flags & KEYGEN_FLAG_NO_PROTECTION), passphrase, &s_key); if (err) { log_error ("agent_genkey failed: %s\n", gpg_strerror (err) ); return err; } pk = xtrycalloc (1, sizeof *pk); if (!pk) { err = gpg_error_from_syserror (); gcry_sexp_release (s_key); return err; } pk->timestamp = timestamp; pk->version = (keygen_flags & KEYGEN_FLAG_CREATE_V5_KEY)? 5 : 4; if (expireval) pk->expiredate = pk->timestamp + expireval; pk->pubkey_algo = algo; if (algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_EDDSA || algo == PUBKEY_ALGO_ECDH ) err = ecckey_from_sexp (pk->pkey, s_key, algo); else err = key_from_sexp (pk->pkey, s_key, "public-key", algoelem); if (err) { log_error ("key_from_sexp failed: %s\n", gpg_strerror (err) ); gcry_sexp_release (s_key); free_public_key (pk); return err; } gcry_sexp_release (s_key); pkt = xtrycalloc (1, sizeof *pkt); if (!pkt) { err = gpg_error_from_syserror (); free_public_key (pk); return err; } pkt->pkttype = is_subkey ? PKT_PUBLIC_SUBKEY : PKT_PUBLIC_KEY; pkt->pkt.public_key = pk; add_kbnode (pub_root, new_kbnode (pkt)); return 0; } /* * Generate an Elgamal key. */ static int gen_elg (int algo, unsigned int nbits, KBNODE pub_root, u32 timestamp, u32 expireval, int is_subkey, int keygen_flags, const char *passphrase, char **cache_nonce_addr, char **passwd_nonce_addr) { int err; char *keyparms; char nbitsstr[35]; log_assert (is_ELGAMAL (algo)); if (nbits < 1024) { nbits = 2048; log_info (_("keysize invalid; using %u bits\n"), nbits ); } else if (nbits > 4096) { nbits = 4096; log_info (_("keysize invalid; using %u bits\n"), nbits ); } if ((nbits % 32)) { nbits = ((nbits + 31) / 32) * 32; log_info (_("keysize rounded up to %u bits\n"), nbits ); } /* Note that we use transient-key only if no-protection has also been enabled. */ snprintf (nbitsstr, sizeof nbitsstr, "%u", nbits); keyparms = xtryasprintf ("(genkey(%s(nbits %zu:%s)%s))", algo == GCRY_PK_ELG_E ? "openpgp-elg" : algo == GCRY_PK_ELG ? "elg" : "x-oops" , strlen (nbitsstr), nbitsstr, ((keygen_flags & KEYGEN_FLAG_TRANSIENT_KEY) && (keygen_flags & KEYGEN_FLAG_NO_PROTECTION))? "(transient-key)" : "" ); if (!keyparms) err = gpg_error_from_syserror (); else { err = common_gen (keyparms, algo, "pgy", pub_root, timestamp, expireval, is_subkey, keygen_flags, passphrase, cache_nonce_addr, passwd_nonce_addr); xfree (keyparms); } return err; } /* * Generate an DSA key */ static gpg_error_t gen_dsa (unsigned int nbits, KBNODE pub_root, u32 timestamp, u32 expireval, int is_subkey, int keygen_flags, const char *passphrase, char **cache_nonce_addr, char **passwd_nonce_addr) { int err; unsigned int qbits; char *keyparms; char nbitsstr[35]; char qbitsstr[35]; if (nbits < 768) { nbits = 2048; log_info(_("keysize invalid; using %u bits\n"), nbits ); } else if ( nbits > 3072 ) { nbits = 3072; log_info(_("keysize invalid; using %u bits\n"), nbits ); } if( (nbits % 64) ) { nbits = ((nbits + 63) / 64) * 64; log_info(_("keysize rounded up to %u bits\n"), nbits ); } /* To comply with FIPS rules we round up to the next value unless in expert mode. */ if (!opt.expert && nbits > 1024 && (nbits % 1024)) { nbits = ((nbits + 1023) / 1024) * 1024; log_info(_("keysize rounded up to %u bits\n"), nbits ); } /* Figure out a q size based on the key size. FIPS 180-3 says: L = 1024, N = 160 L = 2048, N = 224 L = 2048, N = 256 L = 3072, N = 256 2048/256 is an odd pair since there is also a 2048/224 and 3072/256. Matching sizes is not a very exact science. We'll do 256 qbits for nbits over 2047, 224 for nbits over 1024 but less than 2048, and 160 for 1024 (DSA1). */ if (nbits > 2047) qbits = 256; else if ( nbits > 1024) qbits = 224; else qbits = 160; if (qbits != 160 ) log_info (_("WARNING: some OpenPGP programs can't" " handle a DSA key with this digest size\n")); snprintf (nbitsstr, sizeof nbitsstr, "%u", nbits); snprintf (qbitsstr, sizeof qbitsstr, "%u", qbits); keyparms = xtryasprintf ("(genkey(dsa(nbits %zu:%s)(qbits %zu:%s)%s))", strlen (nbitsstr), nbitsstr, strlen (qbitsstr), qbitsstr, ((keygen_flags & KEYGEN_FLAG_TRANSIENT_KEY) && (keygen_flags & KEYGEN_FLAG_NO_PROTECTION))? "(transient-key)" : "" ); if (!keyparms) err = gpg_error_from_syserror (); else { err = common_gen (keyparms, PUBKEY_ALGO_DSA, "pqgy", pub_root, timestamp, expireval, is_subkey, keygen_flags, passphrase, cache_nonce_addr, passwd_nonce_addr); xfree (keyparms); } return err; } /* * Generate an ECC key */ static gpg_error_t gen_ecc (int algo, const char *curve, kbnode_t pub_root, u32 timestamp, u32 expireval, int is_subkey, int keygen_flags, const char *passphrase, char **cache_nonce_addr, char **passwd_nonce_addr) { gpg_error_t err; char *keyparms; log_assert (algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_EDDSA || algo == PUBKEY_ALGO_ECDH); if (!curve || !*curve) return gpg_error (GPG_ERR_UNKNOWN_CURVE); /* Map the displayed short forms of some curves to their canonical * names. */ if (!ascii_strcasecmp (curve, "cv25519")) curve = "Curve25519"; else if (!ascii_strcasecmp (curve, "ed25519")) curve = "Ed25519"; /* Note that we use the "comp" flag with EdDSA to request the use of a 0x40 compression prefix octet. */ if (algo == PUBKEY_ALGO_EDDSA) keyparms = xtryasprintf ("(genkey(ecc(curve %zu:%s)(flags eddsa comp%s)))", strlen (curve), curve, (((keygen_flags & KEYGEN_FLAG_TRANSIENT_KEY) && (keygen_flags & KEYGEN_FLAG_NO_PROTECTION))? " transient-key" : "")); else if (algo == PUBKEY_ALGO_ECDH && !strcmp (curve, "Curve25519")) keyparms = xtryasprintf ("(genkey(ecc(curve %zu:%s)(flags djb-tweak comp%s)))", strlen (curve), curve, (((keygen_flags & KEYGEN_FLAG_TRANSIENT_KEY) && (keygen_flags & KEYGEN_FLAG_NO_PROTECTION))? " transient-key" : "")); else keyparms = xtryasprintf ("(genkey(ecc(curve %zu:%s)(flags nocomp%s)))", strlen (curve), curve, (((keygen_flags & KEYGEN_FLAG_TRANSIENT_KEY) && (keygen_flags & KEYGEN_FLAG_NO_PROTECTION))? " transient-key" : "")); if (!keyparms) err = gpg_error_from_syserror (); else { err = common_gen (keyparms, algo, "", pub_root, timestamp, expireval, is_subkey, keygen_flags, passphrase, cache_nonce_addr, passwd_nonce_addr); xfree (keyparms); } return err; } /* * Generate an RSA key. */ static int gen_rsa (int algo, unsigned int nbits, KBNODE pub_root, u32 timestamp, u32 expireval, int is_subkey, int keygen_flags, const char *passphrase, char **cache_nonce_addr, char **passwd_nonce_addr) { int err; char *keyparms; char nbitsstr[35]; const unsigned maxsize = (opt.flags.large_rsa ? 8192 : 4096); log_assert (is_RSA(algo)); if (!nbits) nbits = get_keysize_range (algo, NULL, NULL); if (nbits < 1024) { nbits = 3072; log_info (_("keysize invalid; using %u bits\n"), nbits ); } else if (nbits > maxsize) { nbits = maxsize; log_info (_("keysize invalid; using %u bits\n"), nbits ); } if ((nbits % 32)) { nbits = ((nbits + 31) / 32) * 32; log_info (_("keysize rounded up to %u bits\n"), nbits ); } snprintf (nbitsstr, sizeof nbitsstr, "%u", nbits); keyparms = xtryasprintf ("(genkey(rsa(nbits %zu:%s)%s))", strlen (nbitsstr), nbitsstr, ((keygen_flags & KEYGEN_FLAG_TRANSIENT_KEY) && (keygen_flags & KEYGEN_FLAG_NO_PROTECTION))? "(transient-key)" : "" ); if (!keyparms) err = gpg_error_from_syserror (); else { err = common_gen (keyparms, algo, "ne", pub_root, timestamp, expireval, is_subkey, keygen_flags, passphrase, cache_nonce_addr, passwd_nonce_addr); xfree (keyparms); } return err; } /**************** * check valid days: * return 0 on error or the multiplier */ static int check_valid_days( const char *s ) { if( !digitp(s) ) return 0; for( s++; *s; s++) if( !digitp(s) ) break; if( !*s ) return 1; if( s[1] ) return 0; /* e.g. "2323wc" */ if( *s == 'd' || *s == 'D' ) return 1; if( *s == 'w' || *s == 'W' ) return 7; if( *s == 'm' || *s == 'M' ) return 30; if( *s == 'y' || *s == 'Y' ) return 365; return 0; } static void print_key_flags(int flags) { if(flags&PUBKEY_USAGE_SIG) tty_printf("%s ",_("Sign")); if(flags&PUBKEY_USAGE_CERT) tty_printf("%s ",_("Certify")); if(flags&PUBKEY_USAGE_ENC) tty_printf("%s ",_("Encrypt")); if(flags&PUBKEY_USAGE_AUTH) tty_printf("%s ",_("Authenticate")); } /* Ask for the key flags and return them. CURRENT gives the current * usage which should normally be given as 0. MASK gives the allowed * flags. */ unsigned int ask_key_flags_with_mask (int algo, int subkey, unsigned int current, unsigned int mask) { /* TRANSLATORS: Please use only plain ASCII characters for the * translation. If this is not possible use single digits. The * string needs to 8 bytes long. Here is a description of the * functions: * * s = Toggle signing capability * e = Toggle encryption capability * a = Toggle authentication capability * q = Finish */ const char *togglers = _("SsEeAaQq"); char *answer = NULL; const char *s; unsigned int possible; if ( strlen(togglers) != 8 ) { tty_printf ("NOTE: Bad translation at %s:%d. " "Please report.\n", __FILE__, __LINE__); togglers = "11223300"; } /* Mask the possible usage flags. This is for example used for a * card based key. For ECDH we need to allows additional usages if * they are provided. */ possible = (openpgp_pk_algo_usage (algo) & mask); if (algo == PUBKEY_ALGO_ECDH) possible |= (current & (PUBKEY_USAGE_ENC |PUBKEY_USAGE_CERT |PUBKEY_USAGE_SIG |PUBKEY_USAGE_AUTH)); /* However, only primary keys may certify. */ if (subkey) possible &= ~PUBKEY_USAGE_CERT; /* Preload the current set with the possible set, without * authentication if CURRENT is 0. If CURRENT is non-zero we mask * with all possible usages. */ if (current) current &= possible; else current = (possible&~PUBKEY_USAGE_AUTH); for (;;) { tty_printf("\n"); tty_printf(_("Possible actions for this %s key: "), (algo == PUBKEY_ALGO_ECDH || algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_EDDSA) ? "ECC" : openpgp_pk_algo_name (algo)); print_key_flags(possible); tty_printf("\n"); tty_printf(_("Current allowed actions: ")); print_key_flags(current); tty_printf("\n\n"); if(possible&PUBKEY_USAGE_SIG) tty_printf(_(" (%c) Toggle the sign capability\n"), togglers[0]); if(possible&PUBKEY_USAGE_ENC) tty_printf(_(" (%c) Toggle the encrypt capability\n"), togglers[2]); if(possible&PUBKEY_USAGE_AUTH) tty_printf(_(" (%c) Toggle the authenticate capability\n"), togglers[4]); tty_printf(_(" (%c) Finished\n"),togglers[6]); tty_printf("\n"); xfree(answer); answer = cpr_get("keygen.flags",_("Your selection? ")); cpr_kill_prompt(); if (*answer == '=') { /* Hack to allow direct entry of the capabilities. */ current = 0; for (s=answer+1; *s; s++) { if ((*s == 's' || *s == 'S') && (possible&PUBKEY_USAGE_SIG)) current |= PUBKEY_USAGE_SIG; else if ((*s == 'e' || *s == 'E') && (possible&PUBKEY_USAGE_ENC)) current |= PUBKEY_USAGE_ENC; else if ((*s == 'a' || *s == 'A') && (possible&PUBKEY_USAGE_AUTH)) current |= PUBKEY_USAGE_AUTH; else if (!subkey && *s == 'c') { /* Accept 'c' for the primary key because USAGE_CERT will be set anyway. This is for folks who want to experiment with a cert-only primary key. */ current |= PUBKEY_USAGE_CERT; } } break; } else if (strlen(answer)>1) tty_printf(_("Invalid selection.\n")); else if(*answer=='\0' || *answer==togglers[6] || *answer==togglers[7]) break; else if((*answer==togglers[0] || *answer==togglers[1]) && possible&PUBKEY_USAGE_SIG) { if(current&PUBKEY_USAGE_SIG) current&=~PUBKEY_USAGE_SIG; else current|=PUBKEY_USAGE_SIG; } else if((*answer==togglers[2] || *answer==togglers[3]) && possible&PUBKEY_USAGE_ENC) { if(current&PUBKEY_USAGE_ENC) current&=~PUBKEY_USAGE_ENC; else current|=PUBKEY_USAGE_ENC; } else if((*answer==togglers[4] || *answer==togglers[5]) && possible&PUBKEY_USAGE_AUTH) { if(current&PUBKEY_USAGE_AUTH) current&=~PUBKEY_USAGE_AUTH; else current|=PUBKEY_USAGE_AUTH; } else tty_printf(_("Invalid selection.\n")); } xfree(answer); return current; } unsigned int ask_key_flags (int algo, int subkey, unsigned int current) { return ask_key_flags_with_mask (algo, subkey, current, ~0); } /* Check whether we have a key for the key with HEXGRIP. Returns 0 if there is no such key or the OpenPGP algo number for the key. */ static int check_keygrip (ctrl_t ctrl, const char *hexgrip) { gpg_error_t err; unsigned char *public; size_t publiclen; int algo; if (hexgrip[0] == '&') hexgrip++; err = agent_readkey (ctrl, 0, hexgrip, &public); if (err) return 0; publiclen = gcry_sexp_canon_len (public, 0, NULL, NULL); algo = get_pk_algo_from_canon_sexp (public, publiclen); xfree (public); return map_gcry_pk_to_openpgp (algo); } /* Ask for an algorithm. The function returns the algorithm id to * create. If ADDMODE is false the function won't show an option to * create the primary and subkey combined and won't set R_USAGE * either. If a combined algorithm has been selected, the subkey * algorithm is stored at R_SUBKEY_ALGO. If R_KEYGRIP is given, the * user has the choice to enter the keygrip of an existing key. That * keygrip is then stored at this address. The caller needs to free * it. If R_CARDKEY is not NULL and the keygrip has been taken from * an active card, true is stored there; if R_KEYTIME is not NULL the * creation time of that key is then stored there. */ static int ask_algo (ctrl_t ctrl, int addmode, int *r_subkey_algo, unsigned int *r_usage, char **r_keygrip, int *r_cardkey, u32 *r_keytime) { gpg_error_t err; char *keygrip = NULL; u32 keytime = 0; char *answer = NULL; int cardkey = 0; int algo; int dummy_algo; if (!r_subkey_algo) r_subkey_algo = &dummy_algo; tty_printf (_("Please select what kind of key you want:\n")); #if GPG_USE_RSA if (!addmode) tty_printf (_(" (%d) RSA and RSA (default)\n"), 1 ); #endif if (!addmode && opt.compliance != CO_DE_VS) tty_printf (_(" (%d) DSA and Elgamal\n"), 2 ); if (opt.compliance != CO_DE_VS) tty_printf (_(" (%d) DSA (sign only)\n"), 3 ); #if GPG_USE_RSA tty_printf (_(" (%d) RSA (sign only)\n"), 4 ); #endif if (addmode) { if (opt.compliance != CO_DE_VS) tty_printf (_(" (%d) Elgamal (encrypt only)\n"), 5 ); #if GPG_USE_RSA tty_printf (_(" (%d) RSA (encrypt only)\n"), 6 ); #endif } if (opt.expert) { if (opt.compliance != CO_DE_VS) tty_printf (_(" (%d) DSA (set your own capabilities)\n"), 7 ); #if GPG_USE_RSA tty_printf (_(" (%d) RSA (set your own capabilities)\n"), 8 ); #endif } #if GPG_USE_ECDSA || GPG_USE_ECDH || GPG_USE_EDDSA if (opt.expert && !addmode) tty_printf (_(" (%d) ECC and ECC\n"), 9 ); if (opt.expert) tty_printf (_(" (%d) ECC (sign only)\n"), 10 ); if (opt.expert) tty_printf (_(" (%d) ECC (set your own capabilities)\n"), 11 ); if (opt.expert && addmode) tty_printf (_(" (%d) ECC (encrypt only)\n"), 12 ); #endif if (opt.expert && r_keygrip) tty_printf (_(" (%d) Existing key\n"), 13 ); if (r_keygrip) tty_printf (_(" (%d) Existing key from card\n"), 14 ); for (;;) { *r_usage = 0; *r_subkey_algo = 0; xfree (answer); answer = cpr_get ("keygen.algo", _("Your selection? ")); cpr_kill_prompt (); algo = *answer? atoi (answer) : 1; if (opt.compliance == CO_DE_VS && (algo == 2 || algo == 3 || algo == 5 || algo == 7)) { tty_printf (_("Invalid selection.\n")); } else if ((algo == 1 || !strcmp (answer, "rsa+rsa")) && !addmode) { algo = PUBKEY_ALGO_RSA; *r_subkey_algo = PUBKEY_ALGO_RSA; break; } else if ((algo == 2 || !strcmp (answer, "dsa+elg")) && !addmode) { algo = PUBKEY_ALGO_DSA; *r_subkey_algo = PUBKEY_ALGO_ELGAMAL_E; break; } else if (algo == 3 || !strcmp (answer, "dsa")) { algo = PUBKEY_ALGO_DSA; *r_usage = PUBKEY_USAGE_SIG; break; } else if (algo == 4 || !strcmp (answer, "rsa/s")) { algo = PUBKEY_ALGO_RSA; *r_usage = PUBKEY_USAGE_SIG; break; } else if ((algo == 5 || !strcmp (answer, "elg")) && addmode) { algo = PUBKEY_ALGO_ELGAMAL_E; *r_usage = PUBKEY_USAGE_ENC; break; } else if ((algo == 6 || !strcmp (answer, "rsa/e")) && addmode) { algo = PUBKEY_ALGO_RSA; *r_usage = PUBKEY_USAGE_ENC; break; } else if ((algo == 7 || !strcmp (answer, "dsa/*")) && opt.expert) { algo = PUBKEY_ALGO_DSA; *r_usage = ask_key_flags (algo, addmode, 0); break; } else if ((algo == 8 || !strcmp (answer, "rsa/*")) && opt.expert) { algo = PUBKEY_ALGO_RSA; *r_usage = ask_key_flags (algo, addmode, 0); break; } else if ((algo == 9 || !strcmp (answer, "ecc+ecc")) && opt.expert && !addmode) { algo = PUBKEY_ALGO_ECDSA; *r_subkey_algo = PUBKEY_ALGO_ECDH; break; } else if ((algo == 10 || !strcmp (answer, "ecc/s")) && opt.expert) { algo = PUBKEY_ALGO_ECDSA; *r_usage = PUBKEY_USAGE_SIG; break; } else if ((algo == 11 || !strcmp (answer, "ecc/*")) && opt.expert) { algo = PUBKEY_ALGO_ECDSA; *r_usage = ask_key_flags (algo, addmode, 0); break; } else if ((algo == 12 || !strcmp (answer, "ecc/e")) && opt.expert && addmode) { algo = PUBKEY_ALGO_ECDH; *r_usage = PUBKEY_USAGE_ENC; break; } else if ((algo == 13 || !strcmp (answer, "keygrip")) && opt.expert && r_keygrip) { for (;;) { xfree (answer); answer = tty_get (_("Enter the keygrip: ")); tty_kill_prompt (); trim_spaces (answer); if (!*answer) { xfree (answer); answer = NULL; continue; } if (strlen (answer) != 40 && !(answer[0] == '&' && strlen (answer+1) == 40)) tty_printf (_("Not a valid keygrip (expecting 40 hex digits)\n")); else if (!(algo = check_keygrip (ctrl, answer)) ) tty_printf (_("No key with this keygrip\n")); else break; /* Okay. */ } xfree (keygrip); keygrip = answer; answer = NULL; *r_usage = ask_key_flags (algo, addmode, 0); break; } else if ((algo == 14 || !strcmp (answer, "cardkey")) && r_keygrip) { char *serialno; keypair_info_t keypairlist, kpi; int count, selection; err = agent_scd_serialno (&serialno, NULL); if (err) { tty_printf (_("error reading the card: %s\n"), gpg_strerror (err)); goto ask_again; } tty_printf (_("Serial number of the card: %s\n"), serialno); xfree (serialno); err = agent_scd_keypairinfo (ctrl, NULL, &keypairlist); if (err) { tty_printf (_("error reading the card: %s\n"), gpg_strerror (err)); goto ask_again; } do { char *authkeyref, *encrkeyref, *signkeyref; agent_scd_getattr_one ("$AUTHKEYID", &authkeyref); agent_scd_getattr_one ("$ENCRKEYID", &encrkeyref); agent_scd_getattr_one ("$SIGNKEYID", &signkeyref); tty_printf (_("Available keys:\n")); for (count=1, kpi=keypairlist; kpi; kpi = kpi->next, count++) { gcry_sexp_t s_pkey; char *algostr = NULL; enum gcry_pk_algos algoid = 0; const char *keyref = kpi->idstr; int any = 0; if (keyref && !agent_scd_readkey (ctrl, keyref, &s_pkey, NULL)) { algostr = pubkey_algo_string (s_pkey, &algoid); gcry_sexp_release (s_pkey); } /* We need to tweak the algo in case GCRY_PK_ECC is * returned because pubkey_algo_string is not aware * of the OpenPGP algo mapping. We need to * distinguish between ECDH and ECDSA but we can do * that only if we got usage flags. * Note: Keep this in sync with parse_key_parameter_part. */ if (algoid == GCRY_PK_ECC && algostr) { if (!strcmp (algostr, "ed25519")) kpi->algo = PUBKEY_ALGO_EDDSA; else if (!strcmp (algostr, "cv25519")) kpi->algo = PUBKEY_ALGO_ECDH; else if ((kpi->usage & GCRY_PK_USAGE_ENCR)) kpi->algo = PUBKEY_ALGO_ECDH; else kpi->algo = PUBKEY_ALGO_ECDSA; } else kpi->algo = map_gcry_pk_to_openpgp (algoid); tty_printf (" (%d) %s %s %s", count, kpi->keygrip, keyref, algostr); if ((kpi->usage & GCRY_PK_USAGE_CERT)) { tty_printf ("%scert", any?",":" ("); any = 1; } if ((kpi->usage & GCRY_PK_USAGE_SIGN)) { tty_printf ("%ssign%s", any?",":" (", (signkeyref && keyref && !strcmp (signkeyref, keyref))? "*":""); any = 1; } if ((kpi->usage & GCRY_PK_USAGE_AUTH)) { tty_printf ("%sauth%s", any?",":" (", (authkeyref && keyref && !strcmp (authkeyref, keyref))? "*":""); any = 1; } if ((kpi->usage & GCRY_PK_USAGE_ENCR)) { tty_printf ("%sencr%s", any?",":" (", (encrkeyref && keyref && !strcmp (encrkeyref, keyref))? "*":""); any = 1; } tty_printf ("%s\n", any?")":""); xfree (algostr); } xfree (answer); answer = cpr_get ("keygen.cardkey", _("Your selection? ")); cpr_kill_prompt (); trim_spaces (answer); selection = atoi (answer); xfree (authkeyref); xfree (encrkeyref); xfree (signkeyref); } while (!(selection > 0 && selection < count)); for (count=1,kpi=keypairlist; kpi; kpi = kpi->next, count++) if (count == selection) break; if (!kpi) { /* Just in case COUNT is zero (no keys). */ free_keypair_info (keypairlist); goto ask_again; } xfree (keygrip); keygrip = xstrdup (kpi->keygrip); cardkey = 1; algo = kpi->algo; keytime = kpi->keytime; /* In expert mode allow to change the usage flags. */ if (opt.expert) *r_usage = ask_key_flags_with_mask (algo, addmode, kpi->usage, kpi->usage); else { *r_usage = kpi->usage; if (addmode) *r_usage &= ~GCRY_PK_USAGE_CERT; } free_keypair_info (keypairlist); break; } else tty_printf (_("Invalid selection.\n")); ask_again: ; } xfree(answer); if (r_keygrip) *r_keygrip = keygrip; if (r_cardkey) *r_cardkey = cardkey; if (r_keytime) *r_keytime = keytime; return algo; } static unsigned int get_keysize_range (int algo, unsigned int *min, unsigned int *max) { unsigned int def; unsigned int dummy1, dummy2; if (!min) min = &dummy1; if (!max) max = &dummy2; switch(algo) { case PUBKEY_ALGO_DSA: *min = opt.expert? 768 : 1024; *max=3072; def=2048; break; case PUBKEY_ALGO_ECDSA: case PUBKEY_ALGO_ECDH: *min=256; *max=521; def=256; break; case PUBKEY_ALGO_EDDSA: *min=255; *max=441; def=255; break; default: *min = opt.compliance == CO_DE_VS ? 2048: 1024; *max = 4096; def = 3072; break; } return def; } /* Return a fixed up keysize depending on ALGO. */ static unsigned int fixup_keysize (unsigned int nbits, int algo, int silent) { if (algo == PUBKEY_ALGO_DSA && (nbits % 64)) { nbits = ((nbits + 63) / 64) * 64; if (!silent) tty_printf (_("rounded up to %u bits\n"), nbits); } else if (algo == PUBKEY_ALGO_EDDSA) { if (nbits != 255 && nbits != 441) { if (nbits < 256) nbits = 255; else nbits = 441; if (!silent) tty_printf (_("rounded to %u bits\n"), nbits); } } else if (algo == PUBKEY_ALGO_ECDH || algo == PUBKEY_ALGO_ECDSA) { if (nbits != 256 && nbits != 384 && nbits != 521) { if (nbits < 256) nbits = 256; else if (nbits < 384) nbits = 384; else nbits = 521; if (!silent) tty_printf (_("rounded to %u bits\n"), nbits); } } else if ((nbits % 32)) { nbits = ((nbits + 31) / 32) * 32; if (!silent) tty_printf (_("rounded up to %u bits\n"), nbits ); } return nbits; } /* Ask for the key size. ALGO is the algorithm. If PRIMARY_KEYSIZE is not 0, the function asks for the size of the encryption subkey. */ static unsigned ask_keysize (int algo, unsigned int primary_keysize) { unsigned int nbits; unsigned int min, def, max; int for_subkey = !!primary_keysize; int autocomp = 0; def = get_keysize_range (algo, &min, &max); if (primary_keysize && !opt.expert) { /* Deduce the subkey size from the primary key size. */ if (algo == PUBKEY_ALGO_DSA && primary_keysize > 3072) nbits = 3072; /* For performance reasons we don't support more than 3072 bit DSA. However we won't see this case anyway because DSA can't be used as an encryption subkey ;-). */ else nbits = primary_keysize; autocomp = 1; goto leave; } tty_printf(_("%s keys may be between %u and %u bits long.\n"), openpgp_pk_algo_name (algo), min, max); for (;;) { char *prompt, *answer; if (for_subkey) prompt = xasprintf (_("What keysize do you want " "for the subkey? (%u) "), def); else prompt = xasprintf (_("What keysize do you want? (%u) "), def); answer = cpr_get ("keygen.size", prompt); cpr_kill_prompt (); nbits = *answer? atoi (answer): def; xfree(prompt); xfree(answer); if(nbitsmax) tty_printf(_("%s keysizes must be in the range %u-%u\n"), openpgp_pk_algo_name (algo), min, max); else break; } tty_printf (_("Requested keysize is %u bits\n"), nbits); leave: nbits = fixup_keysize (nbits, algo, autocomp); return nbits; } /* Ask for the curve. ALGO is the selected algorithm which this function may adjust. Returns a const string of the name of the curve. */ const char * ask_curve (int *algo, int *subkey_algo, const char *current) { /* NB: We always use a complete algo list so that we have stable numbers in the menu regardless on how Gpg was configured. */ struct { const char *name; const char* eddsa_curve; /* Corresponding EdDSA curve. */ const char *pretty_name; unsigned int supported : 1; /* Supported by gpg. */ unsigned int de_vs : 1; /* Allowed in CO_DE_VS. */ unsigned int expert_only : 1; /* Only with --expert */ unsigned int available : 1; /* Available in Libycrypt (runtime checked) */ } curves[] = { #if GPG_USE_ECDSA || GPG_USE_ECDH # define MY_USE_ECDSADH 1 #else # define MY_USE_ECDSADH 0 #endif { "Curve25519", "Ed25519", "Curve 25519", !!GPG_USE_EDDSA, 0, 0, 0 }, { "Curve448", "Ed448", "Curve 448", 0/*reserved*/ , 0, 1, 0 }, { "NIST P-256", NULL, NULL, MY_USE_ECDSADH, 0, 1, 0 }, { "NIST P-384", NULL, NULL, MY_USE_ECDSADH, 0, 0, 0 }, { "NIST P-521", NULL, NULL, MY_USE_ECDSADH, 0, 1, 0 }, { "brainpoolP256r1", NULL, "Brainpool P-256", MY_USE_ECDSADH, 1, 1, 0 }, { "brainpoolP384r1", NULL, "Brainpool P-384", MY_USE_ECDSADH, 1, 1, 0 }, { "brainpoolP512r1", NULL, "Brainpool P-512", MY_USE_ECDSADH, 1, 1, 0 }, { "secp256k1", NULL, NULL, MY_USE_ECDSADH, 0, 1, 0 }, }; #undef MY_USE_ECDSADH int idx; char *answer; const char *result = NULL; gcry_sexp_t keyparms; tty_printf (_("Please select which elliptic curve you want:\n")); keyparms = NULL; for (idx=0; idx < DIM(curves); idx++) { int rc; curves[idx].available = 0; if (!curves[idx].supported) continue; if (opt.compliance==CO_DE_VS) { if (!curves[idx].de_vs) continue; /* Not allowed. */ } else if (!opt.expert && curves[idx].expert_only) continue; /* We need to switch from the ECDH name of the curve to the EDDSA name of the curve if we want a signing key. */ gcry_sexp_release (keyparms); rc = gcry_sexp_build (&keyparms, NULL, "(public-key(ecc(curve %s)))", curves[idx].eddsa_curve? curves[idx].eddsa_curve /**/ : curves[idx].name); if (rc) continue; if (!gcry_pk_get_curve (keyparms, 0, NULL)) continue; if (subkey_algo && curves[idx].eddsa_curve) { /* Both Curve 25519 (or 448) keys are to be created. Check that Libgcrypt also supports the real Curve25519 (or 448). */ gcry_sexp_release (keyparms); rc = gcry_sexp_build (&keyparms, NULL, "(public-key(ecc(curve %s)))", curves[idx].name); if (rc) continue; if (!gcry_pk_get_curve (keyparms, 0, NULL)) continue; } curves[idx].available = 1; tty_printf (" (%d) %s\n", idx + 1, curves[idx].pretty_name? curves[idx].pretty_name:curves[idx].name); } gcry_sexp_release (keyparms); for (;;) { answer = cpr_get ("keygen.curve", _("Your selection? ")); cpr_kill_prompt (); idx = *answer? atoi (answer) : 1; if (!*answer && current) { xfree(answer); return NULL; } else if (*answer && !idx) { /* See whether the user entered the name of the curve. */ for (idx=0; idx < DIM(curves); idx++) { if (!opt.expert && curves[idx].expert_only) continue; if (!stricmp (curves[idx].name, answer) || (curves[idx].pretty_name && !stricmp (curves[idx].pretty_name, answer))) break; } if (idx == DIM(curves)) idx = -1; } else idx--; xfree(answer); answer = NULL; if (idx < 0 || idx >= DIM (curves) || !curves[idx].available) tty_printf (_("Invalid selection.\n")); else { /* If the user selected a signing algorithm and Curve25519 we need to set the algo to EdDSA and update the curve name. If switching away from EdDSA, we need to set the algo back to ECDSA. */ if (*algo == PUBKEY_ALGO_ECDSA || *algo == PUBKEY_ALGO_EDDSA) { if (curves[idx].eddsa_curve) { if (subkey_algo && *subkey_algo == PUBKEY_ALGO_ECDSA) *subkey_algo = PUBKEY_ALGO_EDDSA; *algo = PUBKEY_ALGO_EDDSA; result = curves[idx].eddsa_curve; } else { if (subkey_algo && *subkey_algo == PUBKEY_ALGO_EDDSA) *subkey_algo = PUBKEY_ALGO_ECDSA; *algo = PUBKEY_ALGO_ECDSA; result = curves[idx].name; } } else result = curves[idx].name; break; } } if (!result) result = curves[0].name; return result; } /**************** * Parse an expire string and return its value in seconds. * Returns (u32)-1 on error. * This isn't perfect since scan_isodatestr returns unix time, and * OpenPGP actually allows a 32-bit time *plus* a 32-bit offset. * Because of this, we only permit setting expirations up to 2106, but * OpenPGP could theoretically allow up to 2242. I think we'll all * just cope for the next few years until we get a 64-bit time_t or * similar. */ u32 parse_expire_string( const char *string ) { int mult; u32 seconds; u32 abs_date = 0; u32 curtime = make_timestamp (); time_t tt; if (!string || !*string || !strcmp (string, "none") || !strcmp (string, "never") || !strcmp (string, "-")) seconds = 0; else if (!strncmp (string, "seconds=", 8)) seconds = atoi (string+8); else if ((abs_date = scan_isodatestr(string)) && (abs_date+86400/2) > curtime) seconds = (abs_date+86400/2) - curtime; else if ((tt = isotime2epoch (string)) != (time_t)(-1)) seconds = (u32)tt - curtime; else if ((mult = check_valid_days (string))) seconds = atoi (string) * 86400L * mult; else seconds = (u32)(-1); return seconds; } /* Parse a Creation-Date string which is either "1986-04-26" or "19860426T042640". Returns 0 on error. */ static u32 parse_creation_string (const char *string) { u32 seconds; if (!*string) seconds = 0; else if ( !strncmp (string, "seconds=", 8) ) seconds = atoi (string+8); else if ( !(seconds = scan_isodatestr (string))) { time_t tmp = isotime2epoch (string); seconds = (tmp == (time_t)(-1))? 0 : tmp; } return seconds; } /* object == 0 for a key, and 1 for a sig */ u32 ask_expire_interval(int object,const char *def_expire) { u32 interval; char *answer; switch(object) { case 0: if(def_expire) BUG(); tty_printf(_("Please specify how long the key should be valid.\n" " 0 = key does not expire\n" " = key expires in n days\n" " w = key expires in n weeks\n" " m = key expires in n months\n" " y = key expires in n years\n")); break; case 1: if(!def_expire) BUG(); tty_printf(_("Please specify how long the signature should be valid.\n" " 0 = signature does not expire\n" " = signature expires in n days\n" " w = signature expires in n weeks\n" " m = signature expires in n months\n" " y = signature expires in n years\n")); break; default: BUG(); } /* Note: The elgamal subkey for DSA has no expiration date because * it must be signed with the DSA key and this one has the expiration * date */ answer = NULL; for(;;) { u32 curtime; xfree(answer); if(object==0) answer = cpr_get("keygen.valid",_("Key is valid for? (0) ")); else { char *prompt; prompt = xasprintf (_("Signature is valid for? (%s) "), def_expire); answer = cpr_get("siggen.valid",prompt); xfree(prompt); if(*answer=='\0') answer=xstrdup(def_expire); } cpr_kill_prompt(); trim_spaces(answer); curtime = make_timestamp (); interval = parse_expire_string( answer ); if( interval == (u32)-1 ) { tty_printf(_("invalid value\n")); continue; } if( !interval ) { tty_printf((object==0) ? _("Key does not expire at all\n") : _("Signature does not expire at all\n")); } else { tty_printf(object==0 ? _("Key expires at %s\n") : _("Signature expires at %s\n"), asctimestamp((ulong)(curtime + interval) ) ); #if SIZEOF_TIME_T <= 4 && !defined (HAVE_UNSIGNED_TIME_T) if ( (time_t)((ulong)(curtime+interval)) < 0 ) tty_printf (_("Your system can't display dates beyond 2038.\n" "However, it will be correctly handled up to" " 2106.\n")); else #endif /*SIZEOF_TIME_T*/ if ( (time_t)((unsigned long)(curtime+interval)) < curtime ) { tty_printf (_("invalid value\n")); continue; } } if( cpr_enabled() || cpr_get_answer_is_yes("keygen.valid.okay", _("Is this correct? (y/N) ")) ) break; } xfree(answer); return interval; } u32 ask_expiredate() { u32 x = ask_expire_interval(0,NULL); return x? make_timestamp() + x : 0; } static PKT_user_id * uid_from_string (const char *string) { size_t n; PKT_user_id *uid; n = strlen (string); uid = xmalloc_clear (sizeof *uid + n); uid->len = n; strcpy (uid->name, string); uid->ref = 1; return uid; } /* Return true if the user id UID already exists in the keyblock. */ static int uid_already_in_keyblock (kbnode_t keyblock, const char *uid) { PKT_user_id *uidpkt = uid_from_string (uid); kbnode_t node; int result = 0; for (node=keyblock; node && !result; node=node->next) if (!is_deleted_kbnode (node) && node->pkt->pkttype == PKT_USER_ID && !cmp_user_ids (uidpkt, node->pkt->pkt.user_id)) result = 1; free_user_id (uidpkt); return result; } /* Ask for a user ID. With a MODE of 1 an extra help prompt is printed for use during a new key creation. If KEYBLOCK is not NULL the function prevents the creation of an already existing user ID. IF FULL is not set some prompts are not shown. */ static char * ask_user_id (int mode, int full, KBNODE keyblock) { char *answer; char *aname, *acomment, *amail, *uid; if ( !mode ) { /* TRANSLATORS: This is the new string telling the user what gpg is now going to do (i.e. ask for the parts of the user ID). Note that if you do not translate this string, a different string will be used, which might still have a correct translation. */ const char *s1 = N_("\n" "GnuPG needs to construct a user ID to identify your key.\n" "\n"); const char *s2 = _(s1); if (!strcmp (s1, s2)) { /* There is no translation for the string thus we to use the old info text. gettext has no way to tell whether a translation is actually available, thus we need to to compare again. */ /* TRANSLATORS: This string is in general not anymore used but you should keep your existing translation. In case the new string is not translated this old string will be used. */ const char *s3 = N_("\n" "You need a user ID to identify your key; " "the software constructs the user ID\n" "from the Real Name, Comment and Email Address in this form:\n" " \"Heinrich Heine (Der Dichter) \"\n\n"); const char *s4 = _(s3); if (strcmp (s3, s4)) s2 = s3; /* A translation exists - use it. */ } tty_printf ("%s", s2) ; } uid = aname = acomment = amail = NULL; for(;;) { char *p; int fail=0; if( !aname ) { for(;;) { xfree(aname); aname = cpr_get("keygen.name",_("Real name: ")); trim_spaces(aname); cpr_kill_prompt(); if( opt.allow_freeform_uid ) break; if( strpbrk( aname, "<>" ) ) { tty_printf(_("Invalid character in name\n")); tty_printf(_("The characters '%s' and '%s' may not " "appear in name\n"), "<", ">"); } else if( digitp(aname) ) tty_printf(_("Name may not start with a digit\n")); else if (*aname && strlen (aname) < 5) { tty_printf(_("Name must be at least 5 characters long\n")); /* However, we allow an empty name. */ } else break; } } if( !amail ) { for(;;) { xfree(amail); amail = cpr_get("keygen.email",_("Email address: ")); trim_spaces(amail); cpr_kill_prompt(); if( !*amail || opt.allow_freeform_uid ) break; /* no email address is okay */ else if ( !is_valid_mailbox (amail) ) tty_printf(_("Not a valid email address\n")); else break; } } if (!acomment) { if (full) { for(;;) { xfree(acomment); acomment = cpr_get("keygen.comment",_("Comment: ")); trim_spaces(acomment); cpr_kill_prompt(); if( !*acomment ) break; /* no comment is okay */ else if( strpbrk( acomment, "()" ) ) tty_printf(_("Invalid character in comment\n")); else break; } } else { xfree (acomment); acomment = xstrdup (""); } } xfree(uid); uid = p = xmalloc(strlen(aname)+strlen(amail)+strlen(acomment)+12+10); if (!*aname && *amail && !*acomment && !random_is_faked ()) { /* Empty name and comment but with mail address. Use simplified form with only the non-angle-bracketed mail address. */ p = stpcpy (p, amail); } else { p = stpcpy (p, aname ); if (*acomment) p = stpcpy(stpcpy(stpcpy(p," ("), acomment),")"); if (*amail) p = stpcpy(stpcpy(stpcpy(p," <"), amail),">"); } /* Append a warning if the RNG is switched into fake mode. */ if ( random_is_faked () ) strcpy(p, " (insecure!)" ); /* print a note in case that UTF8 mapping has to be done */ for(p=uid; *p; p++ ) { if( *p & 0x80 ) { tty_printf(_("You are using the '%s' character set.\n"), get_native_charset() ); break; } } tty_printf(_("You selected this USER-ID:\n \"%s\"\n\n"), uid); if( !*amail && !opt.allow_freeform_uid && (strchr( aname, '@' ) || strchr( acomment, '@'))) { fail = 1; tty_printf(_("Please don't put the email address " "into the real name or the comment\n") ); } if (!fail && keyblock) { if (uid_already_in_keyblock (keyblock, uid)) { tty_printf (_("Such a user ID already exists on this key!\n")); fail = 1; } } for(;;) { /* TRANSLATORS: These are the allowed answers in lower and uppercase. Below you will find the matching string which should be translated accordingly and the letter changed to match the one in the answer string. n = Change name c = Change comment e = Change email o = Okay (ready, continue) q = Quit */ const char *ansstr = _("NnCcEeOoQq"); if( strlen(ansstr) != 10 ) BUG(); if( cpr_enabled() ) { answer = xstrdup (ansstr + (fail?8:6)); answer[1] = 0; } else if (full) { answer = cpr_get("keygen.userid.cmd", fail? _("Change (N)ame, (C)omment, (E)mail or (Q)uit? ") : _("Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? ")); cpr_kill_prompt(); } else { answer = cpr_get("keygen.userid.cmd", fail? _("Change (N)ame, (E)mail, or (Q)uit? ") : _("Change (N)ame, (E)mail, or (O)kay/(Q)uit? ")); cpr_kill_prompt(); } if( strlen(answer) > 1 ) ; else if( *answer == ansstr[0] || *answer == ansstr[1] ) { xfree(aname); aname = NULL; break; } else if( *answer == ansstr[2] || *answer == ansstr[3] ) { xfree(acomment); acomment = NULL; break; } else if( *answer == ansstr[4] || *answer == ansstr[5] ) { xfree(amail); amail = NULL; break; } else if( *answer == ansstr[6] || *answer == ansstr[7] ) { if( fail ) { tty_printf(_("Please correct the error first\n")); } else { xfree(aname); aname = NULL; xfree(acomment); acomment = NULL; xfree(amail); amail = NULL; break; } } else if( *answer == ansstr[8] || *answer == ansstr[9] ) { xfree(aname); aname = NULL; xfree(acomment); acomment = NULL; xfree(amail); amail = NULL; xfree(uid); uid = NULL; break; } xfree(answer); } xfree(answer); if (!amail && !acomment) break; xfree(uid); uid = NULL; } if( uid ) { char *p = native_to_utf8( uid ); xfree( uid ); uid = p; } return uid; } /* Basic key generation. Here we divert to the actual generation routines based on the requested algorithm. */ static int do_create (int algo, unsigned int nbits, const char *curve, kbnode_t pub_root, u32 timestamp, u32 expiredate, int is_subkey, int keygen_flags, const char *passphrase, char **cache_nonce_addr, char **passwd_nonce_addr) { gpg_error_t err; /* Fixme: The entropy collecting message should be moved to a libgcrypt progress handler. */ if (!opt.batch) tty_printf (_( "We need to generate a lot of random bytes. It is a good idea to perform\n" "some other action (type on the keyboard, move the mouse, utilize the\n" "disks) during the prime generation; this gives the random number\n" "generator a better chance to gain enough entropy.\n") ); if (algo == PUBKEY_ALGO_ELGAMAL_E) err = gen_elg (algo, nbits, pub_root, timestamp, expiredate, is_subkey, keygen_flags, passphrase, cache_nonce_addr, passwd_nonce_addr); else if (algo == PUBKEY_ALGO_DSA) err = gen_dsa (nbits, pub_root, timestamp, expiredate, is_subkey, keygen_flags, passphrase, cache_nonce_addr, passwd_nonce_addr); else if (algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_EDDSA || algo == PUBKEY_ALGO_ECDH) err = gen_ecc (algo, curve, pub_root, timestamp, expiredate, is_subkey, keygen_flags, passphrase, cache_nonce_addr, passwd_nonce_addr); else if (algo == PUBKEY_ALGO_RSA) err = gen_rsa (algo, nbits, pub_root, timestamp, expiredate, is_subkey, keygen_flags, passphrase, cache_nonce_addr, passwd_nonce_addr); else BUG(); return err; } /* Generate a new user id packet or return NULL if canceled. If KEYBLOCK is not NULL the function prevents the creation of an already existing user ID. If UIDSTR is not NULL the user is not asked but UIDSTR is used to create the user id packet; if the user id already exists NULL is returned. UIDSTR is expected to be utf-8 encoded and should have already been checked for a valid length etc. */ PKT_user_id * generate_user_id (KBNODE keyblock, const char *uidstr) { PKT_user_id *uid; char *p; if (uidstr) { if (uid_already_in_keyblock (keyblock, uidstr)) return NULL; /* Already exists. */ uid = uid_from_string (uidstr); } else { p = ask_user_id (1, 1, keyblock); if (!p) return NULL; /* Canceled. */ uid = uid_from_string (p); xfree (p); } return uid; } /* Helper for parse_key_parameter_part_parameter_string for one part of the * specification string; i.e. ALGO/FLAGS. If STRING is NULL or empty * success is returned. On error an error code is returned. Note * that STRING may be modified by this function. NULL may be passed * for any parameter. FOR_SUBKEY shall be true if this is used as a * subkey. If CLEAR_CERT is set a default CERT usage will be cleared; * this is useful if for example the default algorithm is used for a * subkey. If R_KEYVERSION is not NULL it will receive the version of * the key; this is currently 4 but can be changed with the flag "v5" * to create a v5 key. If R_KEYTIME is not NULL and the key has been * taken from active OpenPGP card, its creation time is stored * there. */ static gpg_error_t parse_key_parameter_part (ctrl_t ctrl, char *string, int for_subkey, int clear_cert, int *r_algo, unsigned int *r_size, unsigned int *r_keyuse, char const **r_curve, int *r_keyversion, char **r_keygrip, u32 *r_keytime) { gpg_error_t err; char *flags; int algo; char *endp; const char *curve = NULL; int ecdh_or_ecdsa = 0; unsigned int size; int keyuse; int keyversion = 4; int i; const char *s; int from_card = 0; char *keygrip = NULL; u32 keytime = 0; if (!string || !*string) return 0; /* Success. */ flags = strchr (string, '/'); if (flags) *flags++ = 0; algo = 0; if (!ascii_strcasecmp (string, "card")) from_card = 1; else if (strlen (string) >= 3 && (digitp (string+3) || !string[3])) { if (!ascii_memcasecmp (string, "rsa", 3)) algo = PUBKEY_ALGO_RSA; else if (!ascii_memcasecmp (string, "dsa", 3)) algo = PUBKEY_ALGO_DSA; else if (!ascii_memcasecmp (string, "elg", 3)) algo = PUBKEY_ALGO_ELGAMAL_E; } if (from_card) ; /* We need the flags before we can figure out the key to use. */ else if (algo) { if (!string[3]) size = get_keysize_range (algo, NULL, NULL); else { size = strtoul (string+3, &endp, 10); if (size < 512 || size > 16384 || *endp) return gpg_error (GPG_ERR_INV_VALUE); } } else if ((curve = openpgp_is_curve_supported (string, &algo, &size))) { if (!algo) { algo = PUBKEY_ALGO_ECDH; /* Default ECC algorithm. */ ecdh_or_ecdsa = 1; /* We may need to switch the algo. */ } } else return gpg_error (GPG_ERR_UNKNOWN_CURVE); /* Parse the flags. */ keyuse = 0; if (flags) { char **tokens = NULL; tokens = strtokenize (flags, ","); if (!tokens) return gpg_error_from_syserror (); for (i=0; (s = tokens[i]); i++) { if (!*s) ; else if (!ascii_strcasecmp (s, "sign")) keyuse |= PUBKEY_USAGE_SIG; else if (!ascii_strcasecmp (s, "encrypt") || !ascii_strcasecmp (s, "encr")) keyuse |= PUBKEY_USAGE_ENC; else if (!ascii_strcasecmp (s, "auth")) keyuse |= PUBKEY_USAGE_AUTH; else if (!ascii_strcasecmp (s, "cert")) keyuse |= PUBKEY_USAGE_CERT; else if (!ascii_strcasecmp (s, "ecdsa") && !from_card) { if (algo == PUBKEY_ALGO_ECDH || algo == PUBKEY_ALGO_ECDSA) algo = PUBKEY_ALGO_ECDSA; else { xfree (tokens); return gpg_error (GPG_ERR_INV_FLAG); } ecdh_or_ecdsa = 0; } else if (!ascii_strcasecmp (s, "ecdh") && !from_card) { if (algo == PUBKEY_ALGO_ECDH || algo == PUBKEY_ALGO_ECDSA) algo = PUBKEY_ALGO_ECDH; else { xfree (tokens); return gpg_error (GPG_ERR_INV_FLAG); } ecdh_or_ecdsa = 0; } else if (!ascii_strcasecmp (s, "eddsa") && !from_card) { /* Not required but we allow it for consistency. */ if (algo == PUBKEY_ALGO_EDDSA) ; else { xfree (tokens); return gpg_error (GPG_ERR_INV_FLAG); } } else if (!ascii_strcasecmp (s, "v5")) { if (opt.flags.rfc4880bis) keyversion = 5; } else if (!ascii_strcasecmp (s, "v4")) keyversion = 4; else { xfree (tokens); return gpg_error (GPG_ERR_UNKNOWN_FLAG); } } xfree (tokens); } /* If not yet decided switch between ecdh and ecdsa unless we want * to read the algo from the current card. */ if (from_card) { keypair_info_t keypairlist, kpi; char *reqkeyref; if (!keyuse) keyuse = (for_subkey? PUBKEY_USAGE_ENC /* */ : (PUBKEY_USAGE_CERT|PUBKEY_USAGE_SIG)); /* Access the card to make sure we have one and to show the S/N. */ { char *serialno; err = agent_scd_serialno (&serialno, NULL); if (err) { log_error (_("error reading the card: %s\n"), gpg_strerror (err)); return err; } if (!opt.quiet) log_info (_("Serial number of the card: %s\n"), serialno); xfree (serialno); } err = agent_scd_keypairinfo (ctrl, NULL, &keypairlist); if (err) { log_error (_("error reading the card: %s\n"), gpg_strerror (err)); return err; } agent_scd_getattr_one ((keyuse & (PUBKEY_USAGE_SIG|PUBKEY_USAGE_CERT)) ? "$SIGNKEYID":"$ENCRKEYID", &reqkeyref); algo = 0; /* Should already be the case. */ for (kpi=keypairlist; kpi && !algo; kpi = kpi->next) { gcry_sexp_t s_pkey; char *algostr = NULL; enum gcry_pk_algos algoid = 0; const char *keyref = kpi->idstr; if (!reqkeyref) continue; /* Card does not provide the info (skip all). */ if (!keyref) continue; /* Ooops. */ if (strcmp (reqkeyref, keyref)) continue; /* This is not the requested keyref. */ if ((keyuse & (PUBKEY_USAGE_SIG|PUBKEY_USAGE_CERT)) && (kpi->usage & (GCRY_PK_USAGE_SIGN|GCRY_PK_USAGE_CERT))) ; /* Okay */ else if ((keyuse & PUBKEY_USAGE_ENC) && (kpi->usage & GCRY_PK_USAGE_ENCR)) ; /* Okay */ else continue; /* Not usable for us. */ if (agent_scd_readkey (ctrl, keyref, &s_pkey, NULL)) continue; /* Could not read the key. */ algostr = pubkey_algo_string (s_pkey, &algoid); gcry_sexp_release (s_pkey); /* Map to OpenPGP algo number. * We need to tweak the algo in case GCRY_PK_ECC is * returned because pubkey_algo_string is not aware * of the OpenPGP algo mapping. We need to * distinguish between ECDH and ECDSA but we can do * that only if we got usage flags. * Note: Keep this in sync with ask_algo. */ if (algoid == GCRY_PK_ECC && algostr) { if (!strcmp (algostr, "ed25519")) algo = PUBKEY_ALGO_EDDSA; else if (!strcmp (algostr, "cv25519")) algo = PUBKEY_ALGO_ECDH; else if ((kpi->usage & GCRY_PK_USAGE_ENCR)) algo = PUBKEY_ALGO_ECDH; else algo = PUBKEY_ALGO_ECDSA; } else algo = map_gcry_pk_to_openpgp (algoid); xfree (algostr); xfree (keygrip); keygrip = xtrystrdup (kpi->keygrip); if (!keygrip) { err = gpg_error_from_syserror (); xfree (reqkeyref); free_keypair_info (keypairlist); return err; } keytime = kpi->keytime; } xfree (reqkeyref); free_keypair_info (keypairlist); if (!algo || !keygrip) { err = gpg_error (GPG_ERR_PUBKEY_ALGO); log_error ("no usable key on the card: %s\n", gpg_strerror (err)); xfree (keygrip); return err; } } else if (ecdh_or_ecdsa && keyuse) algo = (keyuse & PUBKEY_USAGE_ENC)? PUBKEY_ALGO_ECDH : PUBKEY_ALGO_ECDSA; else if (ecdh_or_ecdsa) algo = for_subkey? PUBKEY_ALGO_ECDH : PUBKEY_ALGO_ECDSA; /* Set or fix key usage. */ if (!keyuse) { if (algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_EDDSA || algo == PUBKEY_ALGO_DSA) keyuse = PUBKEY_USAGE_SIG; else if (algo == PUBKEY_ALGO_RSA) keyuse = for_subkey? PUBKEY_USAGE_ENC : PUBKEY_USAGE_SIG; else keyuse = PUBKEY_USAGE_ENC; } else if (algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_EDDSA || algo == PUBKEY_ALGO_DSA) { keyuse &= ~PUBKEY_USAGE_ENC; /* Forbid encryption. */ } else if (algo == PUBKEY_ALGO_ECDH || algo == PUBKEY_ALGO_ELGAMAL_E) { keyuse = PUBKEY_USAGE_ENC; /* Allow only encryption. */ } /* Make sure a primary key can certify. */ if (!for_subkey) keyuse |= PUBKEY_USAGE_CERT; /* But if requested remove th cert usage. */ if (clear_cert) keyuse &= ~PUBKEY_USAGE_CERT; /* Check that usage is actually possible. */ if (/**/((keyuse & (PUBKEY_USAGE_SIG|PUBKEY_USAGE_AUTH|PUBKEY_USAGE_CERT)) && !pubkey_get_nsig (algo)) || ((keyuse & PUBKEY_USAGE_ENC) && !pubkey_get_nenc (algo)) || (for_subkey && (keyuse & PUBKEY_USAGE_CERT))) { xfree (keygrip); return gpg_error (GPG_ERR_WRONG_KEY_USAGE); } /* Return values. */ if (r_algo) *r_algo = algo; if (r_size) { unsigned int min, def, max; /* Make sure the keysize is in the allowed range. */ def = get_keysize_range (algo, &min, &max); if (!size) size = def; else if (size < min) size = min; else if (size > max) size = max; *r_size = fixup_keysize (size, algo, 1); } if (r_keyuse) *r_keyuse = keyuse; if (r_curve) *r_curve = curve; if (r_keyversion) *r_keyversion = keyversion; if (r_keygrip) *r_keygrip = keygrip; else xfree (keygrip); if (r_keytime) *r_keytime = keytime; return 0; } /* Parse and return the standard key generation parameter. * The string is expected to be in this format: * * ALGO[/FLAGS][+SUBALGO[/FLAGS]] * * Here ALGO is a string in the same format as printed by the * keylisting. For example: * * rsa3072 := RSA with 3072 bit. * dsa2048 := DSA with 2048 bit. * elg2048 := Elgamal with 2048 bit. * ed25519 := EDDSA using curve Ed25519. * cv25519 := ECDH using curve Curve25519. * nistp256:= ECDSA or ECDH using curve NIST P-256 * * All strings with an unknown prefix are considered an elliptic * curve. Curves which have no implicit algorithm require that FLAGS * is given to select whether ECDSA or ECDH is used; this can either * be done using an algorithm keyword or usage keywords. * * FLAGS is a comma delimited string of keywords: * * cert := Allow usage Certify * sign := Allow usage Sign * encr := Allow usage Encrypt * auth := Allow usage Authentication * encrypt := Alias for "encr" * ecdsa := Use algorithm ECDSA. * eddsa := Use algorithm EdDSA. * ecdh := Use algorithm ECDH. * v5 := Create version 5 key (requires option --rfc4880bis) * * There are several defaults and fallbacks depending on the * algorithm. PART can be used to select which part of STRING is * used: * -1 := Both parts * 0 := Only the part of the primary key * 1 := If there is one part parse that one, if there are * two parts parse the part which best matches the * SUGGESTED_USE or in case that can't be evaluated the second part. * Always return using the args for the primary key (R_ALGO,....). * */ gpg_error_t parse_key_parameter_string (ctrl_t ctrl, const char *string, int part, unsigned int suggested_use, int *r_algo, unsigned int *r_size, unsigned int *r_keyuse, char const **r_curve, int *r_version, char **r_keygrip, u32 *r_keytime, int *r_subalgo, unsigned int *r_subsize, unsigned int *r_subkeyuse, char const **r_subcurve, int *r_subversion, char **r_subkeygrip, u32 *r_subkeytime) { gpg_error_t err = 0; char *primary, *secondary; if (r_algo) *r_algo = 0; if (r_size) *r_size = 0; if (r_keyuse) *r_keyuse = 0; if (r_curve) *r_curve = NULL; if (r_version) *r_version = 4; if (r_keygrip) *r_keygrip = NULL; if (r_keytime) *r_keytime = 0; if (r_subalgo) *r_subalgo = 0; if (r_subsize) *r_subsize = 0; if (r_subkeyuse) *r_subkeyuse = 0; if (r_subcurve) *r_subcurve = NULL; if (r_subversion) *r_subversion = 4; if (r_subkeygrip) *r_subkeygrip = NULL; if (r_subkeytime) *r_subkeytime = 0; if (!string || !*string || !ascii_strcasecmp (string, "default") || !strcmp (string, "-")) string = get_default_pubkey_algo (); else if (!ascii_strcasecmp (string, "future-default") || !ascii_strcasecmp (string, "futuredefault")) string = FUTURE_STD_KEY_PARAM; else if (!ascii_strcasecmp (string, "card")) string = "card/cert,sign+card/encr"; primary = xstrdup (string); secondary = strchr (primary, '+'); if (secondary) *secondary++ = 0; if (part == -1 || part == 0) { err = parse_key_parameter_part (ctrl, primary, 0, 0, r_algo, r_size, r_keyuse, r_curve, r_version, r_keygrip, r_keytime); if (!err && part == -1) err = parse_key_parameter_part (ctrl, secondary, 1, 0, r_subalgo, r_subsize, r_subkeyuse, r_subcurve, r_subversion, r_subkeygrip, r_subkeytime); } else if (part == 1) { /* If we have SECONDARY, use that part. If there is only one * part consider this to be the subkey algo. In case a * SUGGESTED_USE has been given and the usage of the secondary * part does not match SUGGESTED_USE try again using the primary * part. Note that when falling back to the primary key we need * to force clearing the cert usage. */ if (secondary) { err = parse_key_parameter_part (ctrl, secondary, 1, 0, r_algo, r_size, r_keyuse, r_curve, r_version, r_keygrip, r_keytime); if (!err && suggested_use && r_keyuse && !(suggested_use & *r_keyuse)) err = parse_key_parameter_part (ctrl, primary, 1, 1 /*(clear cert)*/, r_algo, r_size, r_keyuse, r_curve, r_version, r_keygrip, r_keytime); } else err = parse_key_parameter_part (ctrl, primary, 1, 0, r_algo, r_size, r_keyuse, r_curve, r_version, r_keygrip, r_keytime); } xfree (primary); return err; } /* Append R to the linked list PARA. */ static void append_to_parameter (struct para_data_s *para, struct para_data_s *r) { log_assert (para); while (para->next) para = para->next; para->next = r; } /* Release the parameter list R. */ static void release_parameter_list (struct para_data_s *r) { struct para_data_s *r2; for (; r ; r = r2) { r2 = r->next; if (r->key == pPASSPHRASE && *r->u.value) wipememory (r->u.value, strlen (r->u.value)); xfree (r); } } static struct para_data_s * get_parameter( struct para_data_s *para, enum para_name key ) { struct para_data_s *r; for( r = para; r && r->key != key; r = r->next ) ; return r; } static const char * get_parameter_value( struct para_data_s *para, enum para_name key ) { struct para_data_s *r = get_parameter( para, key ); return (r && *r->u.value)? r->u.value : NULL; } /* This is similar to get_parameter_value but also returns the empty string. This is required so that quick_generate_keypair can use an empty Passphrase to specify no-protection. */ static const char * get_parameter_passphrase (struct para_data_s *para) { struct para_data_s *r = get_parameter (para, pPASSPHRASE); return r ? r->u.value : NULL; } static int get_parameter_algo (ctrl_t ctrl, struct para_data_s *para, enum para_name key, int *r_default) { int i; struct para_data_s *r = get_parameter( para, key ); if (r_default) *r_default = 0; if (!r) return -1; /* Note that we need to handle the ECC algorithms specified as strings directly because Libgcrypt folds them all to ECC. */ if (!ascii_strcasecmp (r->u.value, "default")) { /* Note: If you change this default algo, remember to change it * also in gpg.c:gpgconf_list. */ /* FIXME: We only allow the algo here and have a separate thing * for the curve etc. That is a ugly but demanded for backward * compatibility with the batch key generation. It would be * better to make full use of parse_key_parameter_string. */ parse_key_parameter_string (ctrl, NULL, 0, 0, &i, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); if (r_default) *r_default = 1; } else if (digitp (r->u.value)) i = atoi( r->u.value ); else if (!strcmp (r->u.value, "ELG-E") || !strcmp (r->u.value, "ELG")) i = PUBKEY_ALGO_ELGAMAL_E; else if (!ascii_strcasecmp (r->u.value, "EdDSA")) i = PUBKEY_ALGO_EDDSA; else if (!ascii_strcasecmp (r->u.value, "ECDSA")) i = PUBKEY_ALGO_ECDSA; else if (!ascii_strcasecmp (r->u.value, "ECDH")) i = PUBKEY_ALGO_ECDH; else i = map_gcry_pk_to_openpgp (gcry_pk_map_name (r->u.value)); if (i == PUBKEY_ALGO_RSA_E || i == PUBKEY_ALGO_RSA_S) i = 0; /* we don't want to allow generation of these algorithms */ return i; } /* Parse a usage string. The usage keywords "auth", "sign", "encr" * may be delimited by space, tab, or comma. On error -1 is returned * instead of the usage flags. */ static int parse_usagestr (const char *usagestr) { gpg_error_t err; char **tokens = NULL; const char *s; int i; unsigned int use = 0; tokens = strtokenize (usagestr, " \t,"); if (!tokens) { err = gpg_error_from_syserror (); log_error ("strtokenize failed: %s\n", gpg_strerror (err)); return -1; } for (i=0; (s = tokens[i]); i++) { if (!*s) ; else if (!ascii_strcasecmp (s, "sign")) use |= PUBKEY_USAGE_SIG; else if (!ascii_strcasecmp (s, "encrypt") || !ascii_strcasecmp (s, "encr")) use |= PUBKEY_USAGE_ENC; else if (!ascii_strcasecmp (s, "auth")) use |= PUBKEY_USAGE_AUTH; else if (!ascii_strcasecmp (s, "cert")) use |= PUBKEY_USAGE_CERT; else { xfree (tokens); return -1; /* error */ } } xfree (tokens); return use; } /* * Parse the usage parameter and set the keyflags. Returns -1 on * error, 0 for no usage given or 1 for usage available. */ static int parse_parameter_usage (const char *fname, struct para_data_s *para, enum para_name key) { struct para_data_s *r = get_parameter( para, key ); int i; if (!r) return 0; /* none (this is an optional parameter)*/ i = parse_usagestr (r->u.value); if (i == -1) { log_error ("%s:%d: invalid usage list\n", fname, r->lnr ); return -1; /* error */ } r->u.usage = i; return 1; } static int parse_revocation_key (const char *fname, struct para_data_s *para, enum para_name key) { struct para_data_s *r = get_parameter( para, key ); struct revocation_key revkey; char *pn; int i; if( !r ) return 0; /* none (this is an optional parameter) */ pn = r->u.value; revkey.class=0x80; revkey.algid=atoi(pn); if(!revkey.algid) goto fail; /* Skip to the fpr */ while(*pn && *pn!=':') pn++; if(*pn!=':') goto fail; pn++; for(i=0;iu.revkey,&revkey,sizeof(struct revocation_key)); return 0; fail: log_error("%s:%d: invalid revocation key\n", fname, r->lnr ); return -1; /* error */ } static u32 get_parameter_u32( struct para_data_s *para, enum para_name key ) { struct para_data_s *r = get_parameter( para, key ); if( !r ) return 0; if (r->key == pKEYCREATIONDATE || r->key == pSUBKEYCREATIONDATE || r->key == pAUTHKEYCREATIONDATE) return r->u.creation; if( r->key == pKEYEXPIRE || r->key == pSUBKEYEXPIRE ) return r->u.expire; if( r->key == pKEYUSAGE || r->key == pSUBKEYUSAGE ) return r->u.usage; return (unsigned int)strtoul( r->u.value, NULL, 10 ); } static unsigned int get_parameter_uint( struct para_data_s *para, enum para_name key ) { return get_parameter_u32( para, key ); } static struct revocation_key * get_parameter_revkey( struct para_data_s *para, enum para_name key ) { struct para_data_s *r = get_parameter( para, key ); return r? &r->u.revkey : NULL; } static int get_parameter_bool (struct para_data_s *para, enum para_name key) { struct para_data_s *r = get_parameter (para, key); return (r && r->u.abool); } static int proc_parameter_file (ctrl_t ctrl, struct para_data_s *para, const char *fname, struct output_control_s *outctrl, int card ) { struct para_data_s *r; const char *s1, *s2, *s3; size_t n; char *p; int is_default = 0; int have_user_id = 0; int err, algo; /* Check that we have all required parameters. */ r = get_parameter( para, pKEYTYPE ); if(r) { algo = get_parameter_algo (ctrl, para, pKEYTYPE, &is_default); if (openpgp_pk_test_algo2 (algo, PUBKEY_USAGE_SIG)) { log_error ("%s:%d: invalid algorithm\n", fname, r->lnr ); return -1; } } else { log_error ("%s: no Key-Type specified\n",fname); return -1; } err = parse_parameter_usage (fname, para, pKEYUSAGE); if (!err) { /* Default to algo capabilities if key-usage is not provided and no default algorithm has been requested. */ r = xmalloc_clear(sizeof(*r)); r->key = pKEYUSAGE; r->u.usage = (is_default ? (PUBKEY_USAGE_CERT | PUBKEY_USAGE_SIG) : openpgp_pk_algo_usage(algo)); append_to_parameter (para, r); } else if (err == -1) return -1; else { r = get_parameter (para, pKEYUSAGE); if (r && (r->u.usage & ~openpgp_pk_algo_usage (algo))) { log_error ("%s:%d: specified Key-Usage not allowed for algo %d\n", fname, r->lnr, algo); return -1; } } is_default = 0; r = get_parameter( para, pSUBKEYTYPE ); if(r) { algo = get_parameter_algo (ctrl, para, pSUBKEYTYPE, &is_default); if (openpgp_pk_test_algo (algo)) { log_error ("%s:%d: invalid algorithm\n", fname, r->lnr ); return -1; } err = parse_parameter_usage (fname, para, pSUBKEYUSAGE); if (!err) { /* Default to algo capabilities if subkey-usage is not provided */ r = xmalloc_clear (sizeof(*r)); r->key = pSUBKEYUSAGE; r->u.usage = (is_default ? PUBKEY_USAGE_ENC : openpgp_pk_algo_usage (algo)); append_to_parameter (para, r); } else if (err == -1) return -1; else { r = get_parameter (para, pSUBKEYUSAGE); if (r && (r->u.usage & ~openpgp_pk_algo_usage (algo))) { log_error ("%s:%d: specified Subkey-Usage not allowed" " for algo %d\n", fname, r->lnr, algo); return -1; } } } if( get_parameter_value( para, pUSERID ) ) have_user_id=1; else { /* create the formatted user ID */ s1 = get_parameter_value( para, pNAMEREAL ); s2 = get_parameter_value( para, pNAMECOMMENT ); s3 = get_parameter_value( para, pNAMEEMAIL ); if( s1 || s2 || s3 ) { n = (s1?strlen(s1):0) + (s2?strlen(s2):0) + (s3?strlen(s3):0); r = xmalloc_clear( sizeof *r + n + 20 ); r->key = pUSERID; p = r->u.value; if( s1 ) p = stpcpy(p, s1 ); if( s2 ) p = stpcpy(stpcpy(stpcpy(p," ("), s2 ),")"); if( s3 ) { /* If we have only the email part, do not add the space * and the angle brackets. */ if (*r->u.value) p = stpcpy(stpcpy(stpcpy(p," <"), s3 ),">"); else p = stpcpy (p, s3); } append_to_parameter (para, r); have_user_id=1; } } if(!have_user_id) { log_error("%s: no User-ID specified\n",fname); return -1; } /* Set preferences, if any. */ keygen_set_std_prefs(get_parameter_value( para, pPREFERENCES ), 0); /* Set keyserver, if any. */ s1=get_parameter_value( para, pKEYSERVER ); if(s1) { struct keyserver_spec *spec; spec = parse_keyserver_uri (s1, 1); if(spec) { free_keyserver_spec(spec); opt.def_keyserver_url=s1; } else { r = get_parameter (para, pKEYSERVER); log_error("%s:%d: invalid keyserver url\n", fname, r->lnr ); return -1; } } /* Set revoker, if any. */ if (parse_revocation_key (fname, para, pREVOKER)) return -1; /* Make KEYCREATIONDATE from Creation-Date. We ignore this if the * key has been taken from a card and a keycreationtime has already * been set. This is so that we don't generate a key with a * fingerprint different from the one stored on the OpenPGP card. */ r = get_parameter (para, pCREATIONDATE); if (r && *r->u.value && !(get_parameter_bool (para, pCARDKEY) && get_parameter_u32 (para, pKEYCREATIONDATE))) { u32 seconds; seconds = parse_creation_string (r->u.value); if (!seconds) { log_error ("%s:%d: invalid creation date\n", fname, r->lnr ); return -1; } r->u.creation = seconds; r->key = pKEYCREATIONDATE; /* Change that entry. */ } /* Make KEYEXPIRE from Expire-Date. */ r = get_parameter( para, pEXPIREDATE ); if( r && *r->u.value ) { u32 seconds; seconds = parse_expire_string( r->u.value ); if( seconds == (u32)-1 ) { log_error("%s:%d: invalid expire date\n", fname, r->lnr ); return -1; } r->u.expire = seconds; r->key = pKEYEXPIRE; /* change hat entry */ /* also set it for the subkey */ r = xmalloc_clear( sizeof *r + 20 ); r->key = pSUBKEYEXPIRE; r->u.expire = seconds; append_to_parameter (para, r); } do_generate_keypair (ctrl, para, outctrl, card ); return 0; } /**************** * Kludge to allow non interactive key generation controlled * by a parameter file. * Note, that string parameters are expected to be in UTF-8 */ static void read_parameter_file (ctrl_t ctrl, const char *fname ) { static struct { const char *name; enum para_name key; } keywords[] = { { "Key-Type", pKEYTYPE}, { "Key-Length", pKEYLENGTH }, { "Key-Curve", pKEYCURVE }, { "Key-Usage", pKEYUSAGE }, { "Subkey-Type", pSUBKEYTYPE }, { "Subkey-Length", pSUBKEYLENGTH }, { "Subkey-Curve", pSUBKEYCURVE }, { "Subkey-Usage", pSUBKEYUSAGE }, { "Name-Real", pNAMEREAL }, { "Name-Email", pNAMEEMAIL }, { "Name-Comment", pNAMECOMMENT }, { "Expire-Date", pEXPIREDATE }, { "Creation-Date", pCREATIONDATE }, { "Passphrase", pPASSPHRASE }, { "Preferences", pPREFERENCES }, { "Revoker", pREVOKER }, { "Handle", pHANDLE }, { "Keyserver", pKEYSERVER }, { "Keygrip", pKEYGRIP }, { "Key-Grip", pKEYGRIP }, { "Subkey-grip", pSUBKEYGRIP }, { "Key-Version", pVERSION }, { "Subkey-Version", pSUBVERSION }, { NULL, 0 } }; IOBUF fp; byte *line; unsigned int maxlen, nline; char *p; int lnr; const char *err = NULL; struct para_data_s *para, *r; int i; struct output_control_s outctrl; memset( &outctrl, 0, sizeof( outctrl ) ); outctrl.pub.afx = new_armor_context (); if( !fname || !*fname) fname = "-"; fp = iobuf_open (fname); if (fp && is_secured_file (iobuf_get_fd (fp))) { iobuf_close (fp); fp = NULL; gpg_err_set_errno (EPERM); } if (!fp) { log_error (_("can't open '%s': %s\n"), fname, strerror(errno) ); return; } iobuf_ioctl (fp, IOBUF_IOCTL_NO_CACHE, 1, NULL); lnr = 0; err = NULL; para = NULL; maxlen = 1024; line = NULL; while ( iobuf_read_line (fp, &line, &nline, &maxlen) ) { char *keyword, *value; lnr++; if( !maxlen ) { err = "line too long"; break; } for( p = line; isspace(*(byte*)p); p++ ) ; if( !*p || *p == '#' ) continue; keyword = p; if( *keyword == '%' ) { for( ; !isspace(*(byte*)p); p++ ) ; if( *p ) *p++ = 0; for( ; isspace(*(byte*)p); p++ ) ; value = p; trim_trailing_ws( value, strlen(value) ); if( !ascii_strcasecmp( keyword, "%echo" ) ) log_info("%s\n", value ); else if( !ascii_strcasecmp( keyword, "%dry-run" ) ) outctrl.dryrun = 1; else if( !ascii_strcasecmp( keyword, "%ask-passphrase" ) ) ; /* Dummy for backward compatibility. */ else if( !ascii_strcasecmp( keyword, "%no-ask-passphrase" ) ) ; /* Dummy for backward compatibility. */ else if( !ascii_strcasecmp( keyword, "%no-protection" ) ) outctrl.keygen_flags |= KEYGEN_FLAG_NO_PROTECTION; else if( !ascii_strcasecmp( keyword, "%transient-key" ) ) outctrl.keygen_flags |= KEYGEN_FLAG_TRANSIENT_KEY; else if( !ascii_strcasecmp( keyword, "%commit" ) ) { outctrl.lnr = lnr; if (proc_parameter_file (ctrl, para, fname, &outctrl, 0 )) print_status_key_not_created (get_parameter_value (para, pHANDLE)); release_parameter_list( para ); para = NULL; } else if( !ascii_strcasecmp( keyword, "%pubring" ) ) { if( outctrl.pub.fname && !strcmp( outctrl.pub.fname, value ) ) ; /* still the same file - ignore it */ else { xfree( outctrl.pub.newfname ); outctrl.pub.newfname = xstrdup( value ); outctrl.use_files = 1; } } else if( !ascii_strcasecmp( keyword, "%secring" ) ) { /* Ignore this command. */ } else log_info("skipping control '%s' (%s)\n", keyword, value ); continue; } if( !(p = strchr( p, ':' )) || p == keyword ) { err = "missing colon"; break; } if( *p ) *p++ = 0; for( ; isspace(*(byte*)p); p++ ) ; if( !*p ) { err = "missing argument"; break; } value = p; trim_trailing_ws( value, strlen(value) ); for(i=0; keywords[i].name; i++ ) { if( !ascii_strcasecmp( keywords[i].name, keyword ) ) break; } if( !keywords[i].name ) { err = "unknown keyword"; break; } if( keywords[i].key != pKEYTYPE && !para ) { err = "parameter block does not start with \"Key-Type\""; break; } if( keywords[i].key == pKEYTYPE && para ) { outctrl.lnr = lnr; if (proc_parameter_file (ctrl, para, fname, &outctrl, 0 )) print_status_key_not_created (get_parameter_value (para, pHANDLE)); release_parameter_list( para ); para = NULL; } else { for( r = para; r; r = r->next ) { if( r->key == keywords[i].key ) break; } if( r ) { err = "duplicate keyword"; break; } } if (!opt.flags.rfc4880bis && (keywords[i].key == pVERSION || keywords[i].key == pSUBVERSION)) ; /* Ignore version unless --rfc4880bis is active. */ else { r = xmalloc_clear( sizeof *r + strlen( value ) ); r->lnr = lnr; r->key = keywords[i].key; strcpy( r->u.value, value ); r->next = para; para = r; } } if( err ) log_error("%s:%d: %s\n", fname, lnr, err ); else if( iobuf_error (fp) ) { log_error("%s:%d: read error\n", fname, lnr); } else if( para ) { outctrl.lnr = lnr; if (proc_parameter_file (ctrl, para, fname, &outctrl, 0 )) print_status_key_not_created (get_parameter_value (para, pHANDLE)); } if( outctrl.use_files ) { /* close open streams */ iobuf_close( outctrl.pub.stream ); /* Must invalidate that ugly cache to actually close it. */ if (outctrl.pub.fname) iobuf_ioctl (NULL, IOBUF_IOCTL_INVALIDATE_CACHE, 0, (char*)outctrl.pub.fname); xfree( outctrl.pub.fname ); xfree( outctrl.pub.newfname ); } xfree (line); release_parameter_list( para ); iobuf_close (fp); release_armor_context (outctrl.pub.afx); } /* Helper for quick_generate_keypair. */ static struct para_data_s * quickgen_set_para (struct para_data_s *para, int for_subkey, int algo, int nbits, const char *curve, unsigned int use, int version, const char *keygrip, u32 keytime) { struct para_data_s *r; r = xmalloc_clear (sizeof *r + 30); r->key = for_subkey? pSUBKEYUSAGE : pKEYUSAGE; if (use) snprintf (r->u.value, 30, "%s%s%s%s", (use & PUBKEY_USAGE_ENC)? "encr " : "", (use & PUBKEY_USAGE_SIG)? "sign " : "", (use & PUBKEY_USAGE_AUTH)? "auth " : "", (use & PUBKEY_USAGE_CERT)? "cert " : ""); else strcpy (r->u.value, for_subkey ? "encr" : "sign"); r->next = para; para = r; r = xmalloc_clear (sizeof *r + 20); r->key = for_subkey? pSUBKEYTYPE : pKEYTYPE; snprintf (r->u.value, 20, "%d", algo); r->next = para; para = r; if (keygrip) { r = xmalloc_clear (sizeof *r + strlen (keygrip)); r->key = for_subkey? pSUBKEYGRIP : pKEYGRIP; strcpy (r->u.value, keygrip); r->next = para; para = r; } else if (curve) { r = xmalloc_clear (sizeof *r + strlen (curve)); r->key = for_subkey? pSUBKEYCURVE : pKEYCURVE; strcpy (r->u.value, curve); r->next = para; para = r; } else { r = xmalloc_clear (sizeof *r + 20); r->key = for_subkey? pSUBKEYLENGTH : pKEYLENGTH; sprintf (r->u.value, "%u", nbits); r->next = para; para = r; } if (opt.flags.rfc4880bis) { r = xmalloc_clear (sizeof *r + 20); r->key = for_subkey? pSUBVERSION : pVERSION; snprintf (r->u.value, 20, "%d", version); r->next = para; para = r; } if (keytime) { r = xmalloc_clear (sizeof *r); r->key = for_subkey? pSUBKEYCREATIONDATE : pKEYCREATIONDATE; r->u.creation = keytime; r->next = para; para = r; } return para; } /* * Unattended generation of a standard key. */ void quick_generate_keypair (ctrl_t ctrl, const char *uid, const char *algostr, const char *usagestr, const char *expirestr) { gpg_error_t err; struct para_data_s *para = NULL; struct para_data_s *r; struct output_control_s outctrl; int use_tty; u32 keytime = 0; memset (&outctrl, 0, sizeof outctrl); use_tty = (!opt.batch && !opt.answer_yes && !*algostr && !*usagestr && !*expirestr && !cpr_enabled () && gnupg_isatty (fileno (stdin)) && gnupg_isatty (fileno (stdout)) && gnupg_isatty (fileno (stderr))); r = xmalloc_clear (sizeof *r + strlen (uid)); r->key = pUSERID; strcpy (r->u.value, uid); r->next = para; para = r; uid = trim_spaces (r->u.value); if (!*uid || (!opt.allow_freeform_uid && !is_valid_user_id (uid))) { log_error (_("Key generation failed: %s\n"), gpg_strerror (GPG_ERR_INV_USER_ID)); goto leave; } /* If gpg is directly used on the console ask whether a key with the given user id shall really be created. */ if (use_tty) { tty_printf (_("About to create a key for:\n \"%s\"\n\n"), uid); if (!cpr_get_answer_is_yes_def ("quick_keygen.okay", _("Continue? (Y/n) "), 1)) goto leave; } /* Check whether such a user ID already exists. */ { KEYDB_HANDLE kdbhd; KEYDB_SEARCH_DESC desc; memset (&desc, 0, sizeof desc); desc.mode = KEYDB_SEARCH_MODE_EXACT; desc.u.name = uid; kdbhd = keydb_new (ctrl); if (!kdbhd) goto leave; err = keydb_search (kdbhd, &desc, 1, NULL); keydb_release (kdbhd); if (gpg_err_code (err) != GPG_ERR_NOT_FOUND) { log_info (_("A key for \"%s\" already exists\n"), uid); if (opt.answer_yes) ; else if (!use_tty || !cpr_get_answer_is_yes_def ("quick_keygen.force", _("Create anyway? (y/N) "), 0)) { write_status_error ("genkey", gpg_error (304)); log_inc_errorcount (); /* we used log_info */ goto leave; } log_info (_("creating anyway\n")); } } if (!*expirestr || strcmp (expirestr, "-") == 0) expirestr = default_expiration_interval; if ((!*algostr || !ascii_strcasecmp (algostr, "default") || !ascii_strcasecmp (algostr, "future-default") || !ascii_strcasecmp (algostr, "futuredefault") || !ascii_strcasecmp (algostr, "card")) && (!*usagestr || !ascii_strcasecmp (usagestr, "default") || !strcmp (usagestr, "-"))) { /* Use default key parameters. */ int algo, subalgo, version, subversion; unsigned int size, subsize; unsigned int keyuse, subkeyuse; const char *curve, *subcurve; char *keygrip, *subkeygrip; u32 subkeytime; err = parse_key_parameter_string (ctrl, algostr, -1, 0, &algo, &size, &keyuse, &curve, &version, &keygrip, &keytime, &subalgo, &subsize, &subkeyuse, &subcurve, &subversion, &subkeygrip, &subkeytime); if (err) { log_error (_("Key generation failed: %s\n"), gpg_strerror (err)); goto leave; } para = quickgen_set_para (para, 0, algo, size, curve, keyuse, version, keygrip, keytime); if (subalgo) para = quickgen_set_para (para, 1, subalgo, subsize, subcurve, subkeyuse, subversion, subkeygrip, subkeytime); if (*expirestr) { u32 expire; expire = parse_expire_string (expirestr); if (expire == (u32)-1 ) { err = gpg_error (GPG_ERR_INV_VALUE); log_error (_("Key generation failed: %s\n"), gpg_strerror (err)); goto leave; } r = xmalloc_clear (sizeof *r + 20); r->key = pKEYEXPIRE; r->u.expire = expire; r->next = para; para = r; } xfree (keygrip); xfree (subkeygrip); } else { /* Extended unattended mode. Creates only the primary key. */ int algo, version; unsigned int use; u32 expire; unsigned int nbits; const char *curve; char *keygrip; err = parse_algo_usage_expire (ctrl, 0, algostr, usagestr, expirestr, &algo, &use, &expire, &nbits, &curve, &version, &keygrip, &keytime); if (err) { log_error (_("Key generation failed: %s\n"), gpg_strerror (err) ); goto leave; } para = quickgen_set_para (para, 0, algo, nbits, curve, use, version, keygrip, keytime); r = xmalloc_clear (sizeof *r + 20); r->key = pKEYEXPIRE; r->u.expire = expire; r->next = para; para = r; xfree (keygrip); } /* If the pinentry loopback mode is not and we have a static passphrase (i.e. set with --passphrase{,-fd,-file} while in batch mode), we use that passphrase for the new key. */ if (opt.pinentry_mode != PINENTRY_MODE_LOOPBACK && have_static_passphrase ()) { const char *s = get_static_passphrase (); r = xmalloc_clear (sizeof *r + strlen (s)); r->key = pPASSPHRASE; strcpy (r->u.value, s); r->next = para; para = r; } /* If KEYTIME is set we know that the key has been taken from the * card. Store that flag in the parameters. */ if (keytime) { r = xmalloc_clear (sizeof *r); r->key = pCARDKEY; r->u.abool = 1; r->next = para; para = r; } proc_parameter_file (ctrl, para, "[internal]", &outctrl, 0); leave: release_parameter_list (para); } /* * Generate a keypair (fname is only used in batch mode) If * CARD_SERIALNO is not NULL the function will create the keys on an * OpenPGP Card. If CARD_BACKUP_KEY has been set and CARD_SERIALNO is * NOT NULL, the encryption key for the card is generated on the host, * imported to the card and a backup file created by gpg-agent. If * FULL is not set only the basic prompts are used (except for batch * mode). */ void generate_keypair (ctrl_t ctrl, int full, const char *fname, const char *card_serialno, int card_backup_key) { gpg_error_t err; unsigned int nbits; char *uid = NULL; int algo; unsigned int use; int both = 0; u32 expire; struct para_data_s *para = NULL; struct para_data_s *r; struct output_control_s outctrl; #ifndef ENABLE_CARD_SUPPORT (void)card_backup_key; #endif memset( &outctrl, 0, sizeof( outctrl ) ); if (opt.batch && card_serialno) { /* We don't yet support unattended key generation with a card * serial number. */ log_error (_("can't do this in batch mode\n")); print_further_info ("key generation with card serial number"); return; } if (opt.batch) { read_parameter_file (ctrl, fname); return; } if (card_serialno) { #ifdef ENABLE_CARD_SUPPORT struct agent_card_info_s info; memset (&info, 0, sizeof (info)); err = agent_scd_getattr ("KEY-ATTR", &info); if (err) { log_error (_("error getting current key info: %s\n"), gpg_strerror (err)); return; } r = xcalloc (1, sizeof *r + strlen (card_serialno) ); r->key = pSERIALNO; strcpy( r->u.value, card_serialno); r->next = para; para = r; r = xcalloc (1, sizeof *r + 20 ); r->key = pKEYTYPE; sprintf( r->u.value, "%d", info.key_attr[0].algo ); r->next = para; para = r; r = xcalloc (1, sizeof *r + 20 ); r->key = pKEYUSAGE; strcpy (r->u.value, "sign"); r->next = para; para = r; r = xcalloc (1, sizeof *r + 20 ); r->key = pSUBKEYTYPE; sprintf( r->u.value, "%d", info.key_attr[1].algo ); r->next = para; para = r; r = xcalloc (1, sizeof *r + 20 ); r->key = pSUBKEYUSAGE; strcpy (r->u.value, "encrypt"); r->next = para; para = r; if (info.key_attr[1].algo == PUBKEY_ALGO_RSA) { r = xcalloc (1, sizeof *r + 20 ); r->key = pSUBKEYLENGTH; sprintf( r->u.value, "%u", info.key_attr[1].nbits); r->next = para; para = r; } else if (info.key_attr[1].algo == PUBKEY_ALGO_ECDSA || info.key_attr[1].algo == PUBKEY_ALGO_EDDSA || info.key_attr[1].algo == PUBKEY_ALGO_ECDH) { r = xcalloc (1, sizeof *r + strlen (info.key_attr[1].curve)); r->key = pSUBKEYCURVE; strcpy (r->u.value, info.key_attr[1].curve); r->next = para; para = r; } r = xcalloc (1, sizeof *r + 20 ); r->key = pAUTHKEYTYPE; sprintf( r->u.value, "%d", info.key_attr[2].algo ); r->next = para; para = r; if (card_backup_key) { r = xcalloc (1, sizeof *r + 1); r->key = pCARDBACKUPKEY; strcpy (r->u.value, "1"); r->next = para; para = r; } #endif /*ENABLE_CARD_SUPPORT*/ } else if (full) /* Full featured key generation. */ { int subkey_algo; char *key_from_hexgrip = NULL; int cardkey; u32 keytime; algo = ask_algo (ctrl, 0, &subkey_algo, &use, &key_from_hexgrip, &cardkey, &keytime); if (key_from_hexgrip) { r = xmalloc_clear( sizeof *r + 20 ); r->key = pKEYTYPE; sprintf( r->u.value, "%d", algo); r->next = para; para = r; if (use) { r = xmalloc_clear( sizeof *r + 25 ); r->key = pKEYUSAGE; sprintf( r->u.value, "%s%s%s", (use & PUBKEY_USAGE_SIG)? "sign ":"", (use & PUBKEY_USAGE_ENC)? "encrypt ":"", (use & PUBKEY_USAGE_AUTH)? "auth":"" ); r->next = para; para = r; } r = xmalloc_clear( sizeof *r + 40 ); r->key = pKEYGRIP; strcpy (r->u.value, key_from_hexgrip); r->next = para; para = r; r = xmalloc_clear (sizeof *r); r->key = pCARDKEY; r->u.abool = cardkey; r->next = para; para = r; if (cardkey) { r = xmalloc_clear (sizeof *r); r->key = pKEYCREATIONDATE; r->u.creation = keytime; r->next = para; para = r; } xfree (key_from_hexgrip); } else { const char *curve = NULL; if (subkey_algo) { /* Create primary and subkey at once. */ both = 1; if (algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_EDDSA || algo == PUBKEY_ALGO_ECDH) { curve = ask_curve (&algo, &subkey_algo, NULL); r = xmalloc_clear( sizeof *r + 20 ); r->key = pKEYTYPE; sprintf( r->u.value, "%d", algo); r->next = para; para = r; nbits = 0; r = xmalloc_clear (sizeof *r + strlen (curve)); r->key = pKEYCURVE; strcpy (r->u.value, curve); r->next = para; para = r; } else { r = xmalloc_clear( sizeof *r + 20 ); r->key = pKEYTYPE; sprintf( r->u.value, "%d", algo); r->next = para; para = r; nbits = ask_keysize (algo, 0); r = xmalloc_clear( sizeof *r + 20 ); r->key = pKEYLENGTH; sprintf( r->u.value, "%u", nbits); r->next = para; para = r; } r = xmalloc_clear( sizeof *r + 20 ); r->key = pKEYUSAGE; strcpy( r->u.value, "sign" ); r->next = para; para = r; r = xmalloc_clear( sizeof *r + 20 ); r->key = pSUBKEYTYPE; sprintf( r->u.value, "%d", subkey_algo); r->next = para; para = r; r = xmalloc_clear( sizeof *r + 20 ); r->key = pSUBKEYUSAGE; strcpy( r->u.value, "encrypt" ); r->next = para; para = r; if (algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_EDDSA || algo == PUBKEY_ALGO_ECDH) { if (algo == PUBKEY_ALGO_EDDSA && subkey_algo == PUBKEY_ALGO_ECDH) { /* Need to switch to a different curve for the encryption key. */ curve = "Curve25519"; } r = xmalloc_clear (sizeof *r + strlen (curve)); r->key = pSUBKEYCURVE; strcpy (r->u.value, curve); r->next = para; para = r; } } else /* Create only a single key. */ { /* For ECC we need to ask for the curve before storing the algo because ask_curve may change the algo. */ if (algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_EDDSA || algo == PUBKEY_ALGO_ECDH) { curve = ask_curve (&algo, NULL, NULL); r = xmalloc_clear (sizeof *r + strlen (curve)); r->key = pKEYCURVE; strcpy (r->u.value, curve); r->next = para; para = r; } r = xmalloc_clear( sizeof *r + 20 ); r->key = pKEYTYPE; sprintf( r->u.value, "%d", algo ); r->next = para; para = r; if (use) { r = xmalloc_clear( sizeof *r + 25 ); r->key = pKEYUSAGE; sprintf( r->u.value, "%s%s%s", (use & PUBKEY_USAGE_SIG)? "sign ":"", (use & PUBKEY_USAGE_ENC)? "encrypt ":"", (use & PUBKEY_USAGE_AUTH)? "auth":"" ); r->next = para; para = r; } nbits = 0; } if (algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_EDDSA || algo == PUBKEY_ALGO_ECDH) { /* The curve has already been set. */ } else { nbits = ask_keysize (both? subkey_algo : algo, nbits); r = xmalloc_clear( sizeof *r + 20 ); r->key = both? pSUBKEYLENGTH : pKEYLENGTH; sprintf( r->u.value, "%u", nbits); r->next = para; para = r; } } } else /* Default key generation. */ { int subalgo, version, subversion; unsigned int size, subsize; unsigned int keyuse, subkeyuse; const char *curve, *subcurve; char *keygrip, *subkeygrip; u32 keytime, subkeytime; tty_printf ( _("Note: Use \"%s %s\"" " for a full featured key generation dialog.\n"), #if USE_GPG2_HACK GPG_NAME "2" #else GPG_NAME #endif , "--full-generate-key" ); err = parse_key_parameter_string (ctrl, NULL, -1, 0, &algo, &size, &keyuse, &curve, &version, &keygrip, &keytime, &subalgo, &subsize, &subkeyuse, &subcurve, &subversion, &subkeygrip, &subkeytime); if (err) { log_error (_("Key generation failed: %s\n"), gpg_strerror (err)); return; } para = quickgen_set_para (para, 0, algo, size, curve, keyuse, version, keygrip, keytime); if (subalgo) para = quickgen_set_para (para, 1, subalgo, subsize, subcurve, subkeyuse, subversion, subkeygrip, subkeytime); xfree (keygrip); xfree (subkeygrip); } expire = full? ask_expire_interval (0, NULL) : parse_expire_string (default_expiration_interval); r = xcalloc (1, sizeof *r + 20); r->key = pKEYEXPIRE; r->u.expire = expire; r->next = para; para = r; r = xcalloc (1, sizeof *r + 20); r->key = pSUBKEYEXPIRE; r->u.expire = expire; r->next = para; para = r; uid = ask_user_id (0, full, NULL); if (!uid) { log_error(_("Key generation canceled.\n")); release_parameter_list( para ); return; } r = xcalloc (1, sizeof *r + strlen (uid)); r->key = pUSERID; strcpy (r->u.value, uid); r->next = para; para = r; proc_parameter_file (ctrl, para, "[internal]", &outctrl, !!card_serialno); release_parameter_list (para); } /* Create and delete a dummy packet to start off a list of kbnodes. */ static void start_tree(KBNODE *tree) { PACKET *pkt; pkt=xmalloc_clear(sizeof(*pkt)); pkt->pkttype=PKT_NONE; *tree=new_kbnode(pkt); delete_kbnode(*tree); } /* Write the *protected* secret key to the file. */ static gpg_error_t card_write_key_to_backup_file (PKT_public_key *sk, const char *backup_dir) { gpg_error_t err = 0; int rc; char keyid_buffer[2 * 8 + 1]; char name_buffer[50]; char *fname; IOBUF fp; mode_t oldmask; PACKET *pkt = NULL; format_keyid (pk_keyid (sk), KF_LONG, keyid_buffer, sizeof (keyid_buffer)); snprintf (name_buffer, sizeof name_buffer, "sk_%s.gpg", keyid_buffer); fname = make_filename (backup_dir, name_buffer, NULL); /* Note that the umask call is not anymore needed because iobuf_create now takes care of it. However, it does not harm and thus we keep it. */ oldmask = umask (077); if (is_secured_filename (fname)) { fp = NULL; gpg_err_set_errno (EPERM); } else fp = iobuf_create (fname, 1); umask (oldmask); if (!fp) { err = gpg_error_from_syserror (); log_error (_("can't create backup file '%s': %s\n"), fname, strerror (errno) ); goto leave; } pkt = xcalloc (1, sizeof *pkt); pkt->pkttype = PKT_SECRET_KEY; pkt->pkt.secret_key = sk; rc = build_packet (fp, pkt); if (rc) { log_error ("build packet failed: %s\n", gpg_strerror (rc)); iobuf_cancel (fp); } else { char *fprbuf; iobuf_close (fp); iobuf_ioctl (NULL, IOBUF_IOCTL_INVALIDATE_CACHE, 0, (char*)fname); log_info (_("Note: backup of card key saved to '%s'\n"), fname); fprbuf = hexfingerprint (sk, NULL, 0); if (!fprbuf) { err = gpg_error_from_syserror (); goto leave; } write_status_text_and_buffer (STATUS_BACKUP_KEY_CREATED, fprbuf, fname, strlen (fname), 0); xfree (fprbuf); } leave: xfree (pkt); xfree (fname); return err; } /* Store key to card and make a backup file in OpenPGP format. */ static gpg_error_t card_store_key_with_backup (ctrl_t ctrl, PKT_public_key *sub_psk, const char *backup_dir) { PKT_public_key *sk; gnupg_isotime_t timestamp; gpg_error_t err; char *hexgrip; int rc; struct agent_card_info_s info; gcry_cipher_hd_t cipherhd = NULL; char *cache_nonce = NULL; void *kek = NULL; size_t keklen; sk = copy_public_key (NULL, sub_psk); if (!sk) return gpg_error_from_syserror (); epoch2isotime (timestamp, (time_t)sk->timestamp); err = hexkeygrip_from_pk (sk, &hexgrip); if (err) return err; memset(&info, 0, sizeof (info)); rc = agent_scd_getattr ("SERIALNO", &info); if (rc) return (gpg_error_t)rc; rc = agent_keytocard (hexgrip, 2, 1, info.serialno, timestamp); xfree (info.serialno); if (rc) { err = (gpg_error_t)rc; goto leave; } err = agent_keywrap_key (ctrl, 1, &kek, &keklen); if (err) { log_error ("error getting the KEK: %s\n", gpg_strerror (err)); goto leave; } err = gcry_cipher_open (&cipherhd, GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_AESWRAP, 0); if (!err) err = gcry_cipher_setkey (cipherhd, kek, keklen); if (err) { log_error ("error setting up an encryption context: %s\n", gpg_strerror (err)); goto leave; } err = receive_seckey_from_agent (ctrl, cipherhd, 0, &cache_nonce, hexgrip, sk); if (err) { log_error ("error getting secret key from agent: %s\n", gpg_strerror (err)); goto leave; } err = card_write_key_to_backup_file (sk, backup_dir); if (err) log_error ("writing card key to backup file: %s\n", gpg_strerror (err)); else /* Remove secret key data in agent side. */ agent_scd_learn (NULL, 1); leave: xfree (cache_nonce); gcry_cipher_close (cipherhd); xfree (kek); xfree (hexgrip); free_public_key (sk); return err; } static void do_generate_keypair (ctrl_t ctrl, struct para_data_s *para, struct output_control_s *outctrl, int card) { gpg_error_t err; KBNODE pub_root = NULL; const char *s; PKT_public_key *pri_psk = NULL; PKT_public_key *sub_psk = NULL; struct revocation_key *revkey; int did_sub = 0; u32 keytimestamp, subkeytimestamp, authkeytimestamp, signtimestamp; char *cache_nonce = NULL; int algo; u32 expire; const char *key_from_hexgrip = NULL; int cardkey; unsigned int keygen_flags; if (outctrl->dryrun) { log_info("dry-run mode - key generation skipped\n"); return; } if ( outctrl->use_files ) { if ( outctrl->pub.newfname ) { iobuf_close(outctrl->pub.stream); outctrl->pub.stream = NULL; if (outctrl->pub.fname) iobuf_ioctl (NULL, IOBUF_IOCTL_INVALIDATE_CACHE, 0, (char*)outctrl->pub.fname); xfree( outctrl->pub.fname ); outctrl->pub.fname = outctrl->pub.newfname; outctrl->pub.newfname = NULL; if (is_secured_filename (outctrl->pub.fname) ) { outctrl->pub.stream = NULL; gpg_err_set_errno (EPERM); } else outctrl->pub.stream = iobuf_create (outctrl->pub.fname, 0); if (!outctrl->pub.stream) { log_error(_("can't create '%s': %s\n"), outctrl->pub.newfname, strerror(errno) ); return; } if (opt.armor) { outctrl->pub.afx->what = 1; push_armor_filter (outctrl->pub.afx, outctrl->pub.stream); } } log_assert( outctrl->pub.stream ); if (opt.verbose) log_info (_("writing public key to '%s'\n"), outctrl->pub.fname ); } /* We create the packets as a tree of kbnodes. Because the structure we create is known in advance we simply generate a linked list. The first packet is a dummy packet which we flag as deleted. The very first packet must always be a KEY packet. */ start_tree (&pub_root); cardkey = get_parameter_bool (para, pCARDKEY); /* In the case that the keys are created from the card we need to * take the timestamps from the card. Only in this case a * pSUBKEYCREATIONDATE or pAUTHKEYCREATIONDATE might be defined and * then we need to use that so that the fingerprint of the subkey * also matches the pre-computed and stored one on the card. In * this case we also use the current time to create the * self-signatures. */ keytimestamp = get_parameter_u32 (para, pKEYCREATIONDATE); if (!keytimestamp) keytimestamp = make_timestamp (); subkeytimestamp = cardkey? get_parameter_u32 (para, pSUBKEYCREATIONDATE) : 0; if (!subkeytimestamp) subkeytimestamp = keytimestamp; authkeytimestamp = cardkey? get_parameter_u32 (para, pAUTHKEYCREATIONDATE): 0; if (!authkeytimestamp) authkeytimestamp = keytimestamp; signtimestamp = cardkey? make_timestamp () : keytimestamp; /* log_debug ("XXX: cardkey ..: %d\n", cardkey); */ /* log_debug ("XXX: keytime ..: %s\n", isotimestamp (keytimestamp)); */ /* log_debug ("XXX: subkeytime: %s\n", isotimestamp (subkeytimestamp)); */ /* log_debug ("XXX: authkeytim: %s\n", isotimestamp (authkeytimestamp)); */ /* log_debug ("XXX: signtime .: %s\n", isotimestamp (signtimestamp)); */ /* Fixme: Check that this comment is still valid: Note that, depending on the backend (i.e. the used scdaemon version), the card key generation may update TIMESTAMP for each key. Thus we need to pass TIMESTAMP to all signing function to make sure that the binding signature is done using the timestamp of the corresponding (sub)key and not that of the primary key. An alternative implementation could tell the signing function the node of the subkey but that is more work than just to pass the current timestamp. */ algo = get_parameter_algo (ctrl, para, pKEYTYPE, NULL ); expire = get_parameter_u32( para, pKEYEXPIRE ); key_from_hexgrip = get_parameter_value (para, pKEYGRIP); if (cardkey && !key_from_hexgrip) BUG (); keygen_flags = outctrl->keygen_flags; if (get_parameter_uint (para, pVERSION) == 5) keygen_flags |= KEYGEN_FLAG_CREATE_V5_KEY; if (key_from_hexgrip) err = do_create_from_keygrip (ctrl, algo, key_from_hexgrip, cardkey, pub_root, keytimestamp, expire, 0, keygen_flags); else if (!card) err = do_create (algo, get_parameter_uint( para, pKEYLENGTH ), get_parameter_value (para, pKEYCURVE), pub_root, keytimestamp, expire, 0, keygen_flags, get_parameter_passphrase (para), &cache_nonce, NULL); else err = gen_card_key (1, algo, 1, pub_root, &keytimestamp, expire, keygen_flags); /* Get the pointer to the generated public key packet. */ if (!err) { pri_psk = pub_root->next->pkt->pkt.public_key; log_assert (pri_psk); /* Make sure a few fields are correctly set up before going further. */ pri_psk->flags.primary = 1; keyid_from_pk (pri_psk, NULL); /* We don't use pk_keyid to get keyid, because it also asserts that main_keyid is set! */ keyid_copy (pri_psk->main_keyid, pri_psk->keyid); } if (!err && (revkey = get_parameter_revkey (para, pREVOKER))) err = write_direct_sig (ctrl, pub_root, pri_psk, revkey, signtimestamp, cache_nonce); if (!err && (s = get_parameter_value (para, pUSERID))) { err = write_uid (pub_root, s ); if (!err) err = write_selfsigs (ctrl, pub_root, pri_psk, get_parameter_uint (para, pKEYUSAGE), signtimestamp, cache_nonce); } /* Write the auth key to the card before the encryption key. This is a partial workaround for a PGP bug (as of this writing, all versions including 8.1), that causes it to try and encrypt to the most recent subkey regardless of whether that subkey is actually an encryption type. In this case, the auth key is an RSA key so it succeeds. */ if (!err && card && get_parameter (para, pAUTHKEYTYPE)) { err = gen_card_key (3, get_parameter_algo (ctrl, para, pAUTHKEYTYPE, NULL ), 0, pub_root, &authkeytimestamp, expire, keygen_flags); if (!err) err = write_keybinding (ctrl, pub_root, pri_psk, NULL, PUBKEY_USAGE_AUTH, signtimestamp, cache_nonce); } if (!err && get_parameter (para, pSUBKEYTYPE)) { int subkey_algo = get_parameter_algo (ctrl, para, pSUBKEYTYPE, NULL); s = NULL; key_from_hexgrip = get_parameter_value (para, pSUBKEYGRIP); keygen_flags = outctrl->keygen_flags; if (get_parameter_uint (para, pSUBVERSION) == 5) keygen_flags |= KEYGEN_FLAG_CREATE_V5_KEY; if (key_from_hexgrip) err = do_create_from_keygrip (ctrl, subkey_algo, key_from_hexgrip, cardkey, pub_root, subkeytimestamp, get_parameter_u32 (para, pSUBKEYEXPIRE), 1, keygen_flags); else if (!card || (s = get_parameter_value (para, pCARDBACKUPKEY))) { err = do_create (subkey_algo, get_parameter_uint (para, pSUBKEYLENGTH), get_parameter_value (para, pSUBKEYCURVE), pub_root, subkeytimestamp, get_parameter_u32 (para, pSUBKEYEXPIRE), 1, s? KEYGEN_FLAG_NO_PROTECTION : keygen_flags, get_parameter_passphrase (para), &cache_nonce, NULL); /* Get the pointer to the generated public subkey packet. */ if (!err) { kbnode_t node; for (node = pub_root; node; node = node->next) if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY) sub_psk = node->pkt->pkt.public_key; log_assert (sub_psk); if (s) err = card_store_key_with_backup (ctrl, sub_psk, gnupg_homedir ()); } } else { err = gen_card_key (2, subkey_algo, 0, pub_root, &subkeytimestamp, expire, keygen_flags); } if (!err) err = write_keybinding (ctrl, pub_root, pri_psk, sub_psk, get_parameter_uint (para, pSUBKEYUSAGE), signtimestamp, cache_nonce); did_sub = 1; } if (!err && outctrl->use_files) /* Direct write to specified files. */ { err = write_keyblock (outctrl->pub.stream, pub_root); if (err) log_error ("can't write public key: %s\n", gpg_strerror (err)); } else if (!err) /* Write to the standard keyrings. */ { KEYDB_HANDLE pub_hd; pub_hd = keydb_new (ctrl); if (!pub_hd) err = gpg_error_from_syserror (); else { err = keydb_locate_writable (pub_hd); if (err) log_error (_("no writable public keyring found: %s\n"), gpg_strerror (err)); } if (!err && opt.verbose) { log_info (_("writing public key to '%s'\n"), keydb_get_resource_name (pub_hd)); } if (!err) { err = keydb_insert_keyblock (pub_hd, pub_root); if (err) log_error (_("error writing public keyring '%s': %s\n"), keydb_get_resource_name (pub_hd), gpg_strerror (err)); } keydb_release (pub_hd); if (!err) { int no_enc_rsa; PKT_public_key *pk; no_enc_rsa = ((get_parameter_algo (ctrl, para, pKEYTYPE, NULL) == PUBKEY_ALGO_RSA) && get_parameter_uint (para, pKEYUSAGE) && !((get_parameter_uint (para, pKEYUSAGE) & PUBKEY_USAGE_ENC)) ); pk = find_kbnode (pub_root, PKT_PUBLIC_KEY)->pkt->pkt.public_key; keyid_from_pk (pk, pk->main_keyid); register_trusted_keyid (pk->main_keyid); update_ownertrust (ctrl, pk, ((get_ownertrust (ctrl, pk) & ~TRUST_MASK) | TRUST_ULTIMATE )); gen_standard_revoke (ctrl, pk, cache_nonce); /* Get rid of the first empty packet. */ commit_kbnode (&pub_root); if (!opt.batch) { tty_printf (_("public and secret key created and signed.\n") ); tty_printf ("\n"); merge_keys_and_selfsig (ctrl, pub_root); list_keyblock_direct (ctrl, pub_root, 0, 1, opt.fingerprint || opt.with_fingerprint, 1); } if (!opt.batch && (get_parameter_algo (ctrl, para, pKEYTYPE, NULL) == PUBKEY_ALGO_DSA || no_enc_rsa ) && !get_parameter (para, pSUBKEYTYPE) ) { tty_printf(_("Note that this key cannot be used for " "encryption. You may want to use\n" "the command \"--edit-key\" to generate a " "subkey for this purpose.\n") ); } } } if (err) { if (opt.batch) log_error ("key generation failed: %s\n", gpg_strerror (err) ); else tty_printf (_("Key generation failed: %s\n"), gpg_strerror (err) ); write_status_error (card? "card_key_generate":"key_generate", err); print_status_key_not_created ( get_parameter_value (para, pHANDLE) ); } else { PKT_public_key *pk = find_kbnode (pub_root, PKT_PUBLIC_KEY)->pkt->pkt.public_key; print_status_key_created (did_sub? 'B':'P', pk, get_parameter_value (para, pHANDLE)); } release_kbnode (pub_root); xfree (cache_nonce); } static gpg_error_t parse_algo_usage_expire (ctrl_t ctrl, int for_subkey, const char *algostr, const char *usagestr, const char *expirestr, int *r_algo, unsigned int *r_usage, u32 *r_expire, unsigned int *r_nbits, const char **r_curve, int *r_version, char **r_keygrip, u32 *r_keytime) { gpg_error_t err; int algo; unsigned int use, nbits; u32 expire; int wantuse; int version = 4; const char *curve = NULL; *r_curve = NULL; if (r_keygrip) *r_keygrip = NULL; if (r_keytime) *r_keytime = 0; nbits = 0; /* Parse the algo string. */ if (algostr && *algostr == '&' && strlen (algostr) == 41) { /* Take algo from existing key. */ algo = check_keygrip (ctrl, algostr+1); /* FIXME: We need the curve name as well. */ return gpg_error (GPG_ERR_NOT_IMPLEMENTED); } err = parse_key_parameter_string (ctrl, algostr, for_subkey? 1 : 0, usagestr? parse_usagestr (usagestr):0, &algo, &nbits, &use, &curve, &version, r_keygrip, r_keytime, NULL, NULL, NULL, NULL, NULL, NULL, NULL); if (err) { if (r_keygrip) { xfree (*r_keygrip); *r_keygrip = NULL; } return err; } /* Parse the usage string. */ if (!usagestr || !*usagestr || !ascii_strcasecmp (usagestr, "default") || !strcmp (usagestr, "-")) ; /* Keep usage from parse_key_parameter_string. */ else if ((wantuse = parse_usagestr (usagestr)) != -1) use = wantuse; else { if (r_keygrip) { xfree (*r_keygrip); *r_keygrip = NULL; } return gpg_error (GPG_ERR_INV_VALUE); } /* Make sure a primary key has the CERT usage. */ if (!for_subkey) use |= PUBKEY_USAGE_CERT; /* Check that usage is possible. NB: We have the same check in * parse_key_parameter_string but need it here again in case the * separate usage value has been given. */ if (/**/((use & (PUBKEY_USAGE_SIG|PUBKEY_USAGE_AUTH|PUBKEY_USAGE_CERT)) && !pubkey_get_nsig (algo)) || ((use & PUBKEY_USAGE_ENC) && !pubkey_get_nenc (algo)) || (for_subkey && (use & PUBKEY_USAGE_CERT))) { if (r_keygrip) { xfree (*r_keygrip); *r_keygrip = NULL; } return gpg_error (GPG_ERR_WRONG_KEY_USAGE); } /* Parse the expire string. */ expire = parse_expire_string (expirestr); if (expire == (u32)-1 ) { if (r_keygrip) { xfree (*r_keygrip); *r_keygrip = NULL; } return gpg_error (GPG_ERR_INV_VALUE); } if (curve) *r_curve = curve; *r_algo = algo; *r_usage = use; *r_expire = expire; *r_nbits = nbits; *r_version = version; return 0; } /* Add a new subkey to an existing key. Returns 0 if a new key has been generated and put into the keyblocks. If any of ALGOSTR, USAGESTR, or EXPIRESTR is NULL interactive mode is used. */ gpg_error_t generate_subkeypair (ctrl_t ctrl, kbnode_t keyblock, const char *algostr, const char *usagestr, const char *expirestr) { gpg_error_t err = 0; int interactive; kbnode_t node; PKT_public_key *pri_psk = NULL; PKT_public_key *sub_psk = NULL; int algo; unsigned int use; u32 expire; unsigned int nbits = 0; const char *curve = NULL; u32 cur_time; char *key_from_hexgrip = NULL; u32 keytime = 0; int cardkey = 0; char *hexgrip = NULL; char *serialno = NULL; char *cache_nonce = NULL; char *passwd_nonce = NULL; int keygen_flags = 0; interactive = (!algostr || !usagestr || !expirestr); /* Break out the primary key. */ node = find_kbnode (keyblock, PKT_PUBLIC_KEY); if (!node) { log_error ("Oops; primary key missing in keyblock!\n"); err = gpg_error (GPG_ERR_BUG); goto leave; } pri_psk = node->pkt->pkt.public_key; cur_time = make_timestamp (); if (pri_psk->timestamp > cur_time) { ulong d = pri_psk->timestamp - cur_time; log_info ( d==1 ? _("key has been created %lu second " "in future (time warp or clock problem)\n") : _("key has been created %lu seconds " "in future (time warp or clock problem)\n"), d ); if (!opt.ignore_time_conflict) { err = gpg_error (GPG_ERR_TIME_CONFLICT); goto leave; } } if (pri_psk->version < 4) { log_info (_("Note: creating subkeys for v3 keys " "is not OpenPGP compliant\n")); err = gpg_error (GPG_ERR_CONFLICT); goto leave; } err = hexkeygrip_from_pk (pri_psk, &hexgrip); if (err) goto leave; if (agent_get_keyinfo (NULL, hexgrip, &serialno, NULL)) { if (interactive) tty_printf (_("Secret parts of primary key are not available.\n")); else log_info ( _("Secret parts of primary key are not available.\n")); err = gpg_error (GPG_ERR_NO_SECKEY); goto leave; } if (serialno) { if (interactive) tty_printf (_("Secret parts of primary key are stored on-card.\n")); else log_info ( _("Secret parts of primary key are stored on-card.\n")); } if (interactive) { algo = ask_algo (ctrl, 1, NULL, &use, &key_from_hexgrip, &cardkey, &keytime); log_assert (algo); if (key_from_hexgrip) nbits = 0; else if (algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_EDDSA || algo == PUBKEY_ALGO_ECDH) curve = ask_curve (&algo, NULL, NULL); else nbits = ask_keysize (algo, 0); expire = ask_expire_interval (0, NULL); if (!cpr_enabled() && !cpr_get_answer_is_yes("keygen.sub.okay", _("Really create? (y/N) "))) { err = gpg_error (GPG_ERR_CANCELED); goto leave; } } else /* Unattended mode. */ { int version; err = parse_algo_usage_expire (ctrl, 1, algostr, usagestr, expirestr, &algo, &use, &expire, &nbits, &curve, &version, &key_from_hexgrip, &keytime); if (err) goto leave; if (version == 5) keygen_flags |= KEYGEN_FLAG_CREATE_V5_KEY; } /* Verify the passphrase now so that we get a cache item for the * primary key passphrase. The agent also returns a passphrase * nonce, which we can use to set the passphrase for the subkey to * that of the primary key. */ { char *desc = gpg_format_keydesc (ctrl, pri_psk, FORMAT_KEYDESC_NORMAL, 1); err = agent_passwd (ctrl, hexgrip, desc, 1 /*=verify*/, &cache_nonce, &passwd_nonce); xfree (desc); if (gpg_err_code (err) == GPG_ERR_NOT_IMPLEMENTED && gpg_err_source (err) == GPG_ERR_SOURCE_GPGAGENT) err = 0; /* Very likely that the key is on a card. */ if (err) goto leave; } /* Start creation. */ if (key_from_hexgrip) { err = do_create_from_keygrip (ctrl, algo, key_from_hexgrip, cardkey, keyblock, keytime? keytime : cur_time, expire, 1, keygen_flags); } else { const char *passwd; /* If the pinentry loopback mode is not and we have a static passphrase (i.e. set with --passphrase{,-fd,-file} while in batch mode), we use that passphrase for the new subkey. */ if (opt.pinentry_mode != PINENTRY_MODE_LOOPBACK && have_static_passphrase ()) passwd = get_static_passphrase (); else passwd = NULL; err = do_create (algo, nbits, curve, keyblock, cur_time, expire, 1, keygen_flags, passwd, &cache_nonce, &passwd_nonce); } if (err) goto leave; /* Get the pointer to the generated public subkey packet. */ for (node = keyblock; node; node = node->next) if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY) sub_psk = node->pkt->pkt.public_key; /* Write the binding signature. */ err = write_keybinding (ctrl, keyblock, pri_psk, sub_psk, use, cur_time, cache_nonce); if (err) goto leave; print_status_key_created ('S', sub_psk, NULL); leave: xfree (key_from_hexgrip); xfree (hexgrip); xfree (serialno); xfree (cache_nonce); xfree (passwd_nonce); if (err) log_error (_("Key generation failed: %s\n"), gpg_strerror (err) ); return err; } #ifdef ENABLE_CARD_SUPPORT /* Generate a subkey on a card. */ gpg_error_t generate_card_subkeypair (ctrl_t ctrl, kbnode_t pub_keyblock, int keyno, const char *serialno) { gpg_error_t err = 0; kbnode_t node; PKT_public_key *pri_pk = NULL; unsigned int use; u32 expire; u32 cur_time; struct para_data_s *para = NULL; PKT_public_key *sub_pk = NULL; int algo; struct agent_card_info_s info; int keygen_flags = 0; /* FIXME!!! */ log_assert (keyno >= 1 && keyno <= 3); memset (&info, 0, sizeof (info)); err = agent_scd_getattr ("KEY-ATTR", &info); if (err) { log_error (_("error getting current key info: %s\n"), gpg_strerror (err)); return err; } algo = info.key_attr[keyno-1].algo; para = xtrycalloc (1, sizeof *para + strlen (serialno) ); if (!para) { err = gpg_error_from_syserror (); goto leave; } para->key = pSERIALNO; strcpy (para->u.value, serialno); /* Break out the primary secret key */ node = find_kbnode (pub_keyblock, PKT_PUBLIC_KEY); if (!node) { log_error ("Oops; public key lost!\n"); err = gpg_error (GPG_ERR_INTERNAL); goto leave; } pri_pk = node->pkt->pkt.public_key; cur_time = make_timestamp(); if (pri_pk->timestamp > cur_time) { ulong d = pri_pk->timestamp - cur_time; log_info (d==1 ? _("key has been created %lu second " "in future (time warp or clock problem)\n") : _("key has been created %lu seconds " "in future (time warp or clock problem)\n"), d ); if (!opt.ignore_time_conflict) { err = gpg_error (GPG_ERR_TIME_CONFLICT); goto leave; } } if (pri_pk->version < 4) { log_info (_("Note: creating subkeys for v3 keys " "is not OpenPGP compliant\n")); err = gpg_error (GPG_ERR_NOT_SUPPORTED); goto leave; } expire = ask_expire_interval (0, NULL); if (keyno == 1) use = PUBKEY_USAGE_SIG; else if (keyno == 2) use = PUBKEY_USAGE_ENC; else use = PUBKEY_USAGE_AUTH; if (!cpr_enabled() && !cpr_get_answer_is_yes("keygen.cardsub.okay", _("Really create? (y/N) "))) { err = gpg_error (GPG_ERR_CANCELED); goto leave; } /* Note, that depending on the backend, the card key generation may update CUR_TIME. */ err = gen_card_key (keyno, algo, 0, pub_keyblock, &cur_time, expire, keygen_flags); /* Get the pointer to the generated public subkey packet. */ if (!err) { for (node = pub_keyblock; node; node = node->next) if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY) sub_pk = node->pkt->pkt.public_key; log_assert (sub_pk); err = write_keybinding (ctrl, pub_keyblock, pri_pk, sub_pk, use, cur_time, NULL); } leave: if (err) log_error (_("Key generation failed: %s\n"), gpg_strerror (err) ); else print_status_key_created ('S', sub_pk, NULL); release_parameter_list (para); return err; } #endif /* !ENABLE_CARD_SUPPORT */ /* * Write a keyblock to an output stream */ static int write_keyblock( IOBUF out, KBNODE node ) { for( ; node ; node = node->next ) { if(!is_deleted_kbnode(node)) { int rc = build_packet( out, node->pkt ); if( rc ) { log_error("build_packet(%d) failed: %s\n", node->pkt->pkttype, gpg_strerror (rc) ); return rc; } } } return 0; } /* Note that timestamp is an in/out arg. * FIXME: Does not yet support v5 keys. */ static gpg_error_t gen_card_key (int keyno, int algo, int is_primary, kbnode_t pub_root, u32 *timestamp, u32 expireval, int keygen_flags) { #ifdef ENABLE_CARD_SUPPORT gpg_error_t err; PACKET *pkt; PKT_public_key *pk; char keyid[10]; unsigned char *public; gcry_sexp_t s_key; snprintf (keyid, DIM(keyid), "OPENPGP.%d", keyno); pk = xtrycalloc (1, sizeof *pk ); if (!pk) return gpg_error_from_syserror (); pkt = xtrycalloc (1, sizeof *pkt); if (!pkt) { xfree (pk); return gpg_error_from_syserror (); } /* Note: SCD knows the serialnumber, thus there is no point in passing it. */ err = agent_scd_genkey (keyno, 1, timestamp); /* The code below is not used because we force creation of * the a card key (3rd arg). * if (gpg_err_code (rc) == GPG_ERR_EEXIST) * { * tty_printf ("\n"); * log_error ("WARNING: key does already exists!\n"); * tty_printf ("\n"); * if ( cpr_get_answer_is_yes( "keygen.card.replace_key", * _("Replace existing key? "))) * rc = agent_scd_genkey (keyno, 1, timestamp); * } */ if (err) { log_error ("key generation failed: %s\n", gpg_strerror (err)); xfree (pkt); xfree (pk); return err; } /* Send the READKEY command so that the agent creates a shadow key for card key. We need to do that now so that we are able to create the self-signatures. */ err = agent_readkey (NULL, 1, keyid, &public); if (err) return err; err = gcry_sexp_sscan (&s_key, NULL, public, gcry_sexp_canon_len (public, 0, NULL, NULL)); xfree (public); if (err) return err; if (algo == PUBKEY_ALGO_RSA) err = key_from_sexp (pk->pkey, s_key, "public-key", "ne"); else if (algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_EDDSA || algo == PUBKEY_ALGO_ECDH ) err = ecckey_from_sexp (pk->pkey, s_key, algo); else err = gpg_error (GPG_ERR_PUBKEY_ALGO); gcry_sexp_release (s_key); if (err) { log_error ("key_from_sexp failed: %s\n", gpg_strerror (err) ); free_public_key (pk); return err; } pk->timestamp = *timestamp; pk->version = (keygen_flags & KEYGEN_FLAG_CREATE_V5_KEY)? 5 : 4; if (expireval) pk->expiredate = pk->timestamp + expireval; pk->pubkey_algo = algo; pkt->pkttype = is_primary ? PKT_PUBLIC_KEY : PKT_PUBLIC_SUBKEY; pkt->pkt.public_key = pk; add_kbnode (pub_root, new_kbnode (pkt)); return 0; #else (void)keyno; (void)is_primary; (void)pub_root; (void)timestamp; (void)expireval; return gpg_error (GPG_ERR_NOT_SUPPORTED); #endif /*!ENABLE_CARD_SUPPORT*/ } diff --git a/g10/keyid.c b/g10/keyid.c index 0fdb18d88..d3fc29a98 100644 --- a/g10/keyid.c +++ b/g10/keyid.c @@ -1,1078 +1,1087 @@ /* keyid.c - key ID and fingerprint handling * Copyright (C) 1998, 1999, 2000, 2001, 2003, * 2004, 2006, 2010 Free Software Foundation, Inc. * Copyright (C) 2014 Werner Koch * 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 #include "gpg.h" #include "../common/util.h" #include "main.h" #include "packet.h" #include "options.h" #include "keydb.h" #include "../common/i18n.h" #include "rmd160.h" #include "../common/host2net.h" #define KEYID_STR_SIZE 19 #ifdef HAVE_UNSIGNED_TIME_T # define IS_INVALID_TIME_T(a) ((a) == (time_t)(-1)) #else /* Error or 32 bit time_t and value after 2038-01-19. */ # define IS_INVALID_TIME_T(a) ((a) < 0) #endif /* Return a letter describing the public key algorithms. */ int pubkey_letter( int algo ) { switch (algo) { case PUBKEY_ALGO_RSA: return 'R' ; case PUBKEY_ALGO_RSA_E: return 'r' ; case PUBKEY_ALGO_RSA_S: return 's' ; case PUBKEY_ALGO_ELGAMAL_E: return 'g' ; case PUBKEY_ALGO_ELGAMAL: return 'G' ; case PUBKEY_ALGO_DSA: return 'D' ; case PUBKEY_ALGO_ECDH: return 'e' ; /* ECC DH (encrypt only) */ case PUBKEY_ALGO_ECDSA: return 'E' ; /* ECC DSA (sign only) */ case PUBKEY_ALGO_EDDSA: return 'E' ; /* ECC EdDSA (sign only) */ default: return '?'; } } /* Return a string describing the public key algorithm and the keysize. For elliptic curves the function prints the name of the curve because the keysize is a property of the curve. The string is copied to the supplied buffer up a length of BUFSIZE-1. Examples for the output are: "rsa3072" - RSA with 3072 bit "elg1024" - Elgamal with 1024 bit "ed25519" - ECC using the curve Ed25519. "E_1.2.3.4" - ECC using the unsupported curve with OID "1.2.3.4". "E_1.3.6.1.4.1.11591.2.12242973" ECC with a bogus OID. "unknown_N" - Unknown OpenPGP algorithm N. If the option --legacy-list-mode is active, the output use the legacy format: "3072R" - RSA with 3072 bit "1024g" - Elgamal with 1024 bit "256E" - ECDSA using a curve with 256 bit The macro PUBKEY_STRING_SIZE may be used to allocate a buffer with a suitable size. Note that a more general version of this function exists as get_keyalgo_string. However, that has no special treatment for the old and unsupported Elgamal which we here print as xxxNNNN. */ char * pubkey_string (PKT_public_key *pk, char *buffer, size_t bufsize) { const char *prefix = NULL; if (opt.legacy_list_mode) { snprintf (buffer, bufsize, "%4u%c", nbits_from_pk (pk), pubkey_letter (pk->pubkey_algo)); return buffer; } switch (pk->pubkey_algo) { case PUBKEY_ALGO_RSA: case PUBKEY_ALGO_RSA_E: case PUBKEY_ALGO_RSA_S: prefix = "rsa"; break; case PUBKEY_ALGO_ELGAMAL_E: prefix = "elg"; break; case PUBKEY_ALGO_DSA: prefix = "dsa"; break; case PUBKEY_ALGO_ELGAMAL: prefix = "xxx"; break; case PUBKEY_ALGO_ECDH: case PUBKEY_ALGO_ECDSA: case PUBKEY_ALGO_EDDSA: prefix = ""; break; } if (prefix && *prefix) snprintf (buffer, bufsize, "%s%u", prefix, nbits_from_pk (pk)); else if (prefix) { char *curve = openpgp_oid_to_str (pk->pkey[0]); const char *name = openpgp_oid_to_curve (curve, 0); if (name) snprintf (buffer, bufsize, "%s", name); else if (curve) snprintf (buffer, bufsize, "E_%s", curve); else snprintf (buffer, bufsize, "E_error"); xfree (curve); } else snprintf (buffer, bufsize, "unknown_%u", (unsigned int)pk->pubkey_algo); return buffer; } /* Hash a public key. This function is useful for v4 and v5 * fingerprints and for v3 or v4 key signing. */ void hash_public_key (gcry_md_hd_t md, PKT_public_key *pk) { unsigned int n; unsigned int nn[PUBKEY_MAX_NPKEY]; byte *pp[PUBKEY_MAX_NPKEY]; int i; unsigned int nbits; size_t nbytes; int npkey = pubkey_get_npkey (pk->pubkey_algo); int is_v5 = pk->version == 5; n = is_v5? 10 : 6; /* FIXME: We can avoid the extra malloc by calling only the first mpi_print here which computes the required length and calling the real mpi_print only at the end. The speed advantage would only be for ECC (opaque MPIs) or if we could implement an mpi_print variant with a callback handler to do the hashing. */ if (npkey==0 && pk->pkey[0] && gcry_mpi_get_flag (pk->pkey[0], GCRYMPI_FLAG_OPAQUE)) { pp[0] = gcry_mpi_get_opaque (pk->pkey[0], &nbits); nn[0] = (nbits+7)/8; n+=nn[0]; } else { for (i=0; i < npkey; i++ ) { if (!pk->pkey[i]) { /* This case may only happen if the parsing of the MPI failed but the key was anyway created. May happen during "gpg KEYFILE". */ pp[i] = NULL; nn[i] = 0; } else if (gcry_mpi_get_flag (pk->pkey[i], GCRYMPI_FLAG_OPAQUE)) { const void *p; + int is_sos = 0; + + if (gcry_mpi_get_flag (pk->pkey[i], GCRYMPI_FLAG_USER2)) + is_sos = 2; p = gcry_mpi_get_opaque (pk->pkey[i], &nbits); - pp[i] = xmalloc ((nbits+7)/8); + pp[i] = xmalloc ((nbits+7)/8 + is_sos); if (p) - memcpy (pp[i], p, (nbits+7)/8); + memcpy (pp[i] + is_sos, p, (nbits+7)/8); else pp[i] = NULL; - nn[i] = (nbits+7)/8; + if (is_sos) + { + pp[i][0] = (nbits >> 8); + pp[i][1] = nbits; + } + nn[i] = (nbits+7)/8 + is_sos; n += nn[i]; } else { if (gcry_mpi_print (GCRYMPI_FMT_PGP, NULL, 0, &nbytes, pk->pkey[i])) BUG (); pp[i] = xmalloc (nbytes); if (gcry_mpi_print (GCRYMPI_FMT_PGP, pp[i], nbytes, &nbytes, pk->pkey[i])) BUG (); nn[i] = nbytes; n += nn[i]; } } } if (is_v5) { gcry_md_putc ( md, 0x9a ); /* ctb */ gcry_md_putc ( md, n >> 24 ); /* 4 byte length header */ gcry_md_putc ( md, n >> 16 ); gcry_md_putc ( md, n >> 8 ); gcry_md_putc ( md, n ); gcry_md_putc ( md, pk->version ); } else { gcry_md_putc ( md, 0x99 ); /* ctb */ gcry_md_putc ( md, n >> 8 ); /* 2 byte length header */ gcry_md_putc ( md, n ); gcry_md_putc ( md, pk->version ); } gcry_md_putc ( md, pk->timestamp >> 24 ); gcry_md_putc ( md, pk->timestamp >> 16 ); gcry_md_putc ( md, pk->timestamp >> 8 ); gcry_md_putc ( md, pk->timestamp ); gcry_md_putc ( md, pk->pubkey_algo ); if (is_v5) { n -= 10; gcry_md_putc ( md, n >> 24 ); gcry_md_putc ( md, n >> 16 ); gcry_md_putc ( md, n >> 8 ); gcry_md_putc ( md, n ); } if(npkey==0 && pk->pkey[0] && gcry_mpi_get_flag (pk->pkey[0], GCRYMPI_FLAG_OPAQUE)) { if (pp[0]) gcry_md_write (md, pp[0], nn[0]); } else { for(i=0; i < npkey; i++ ) { if (pp[i]) gcry_md_write ( md, pp[i], nn[i] ); xfree(pp[i]); } } } /* fixme: Check whether we can replace this function or if not describe why we need it. */ u32 v3_keyid (gcry_mpi_t a, u32 *ki) { byte *buffer, *p; size_t nbytes; if (gcry_mpi_print (GCRYMPI_FMT_USG, NULL, 0, &nbytes, a )) BUG (); /* fixme: allocate it on the stack */ buffer = xmalloc (nbytes); if (gcry_mpi_print( GCRYMPI_FMT_USG, buffer, nbytes, NULL, a )) BUG (); if (nbytes < 8) /* oops */ ki[0] = ki[1] = 0; else { p = buffer + nbytes - 8; ki[0] = buf32_to_u32 (p); p += 4; ki[1] = buf32_to_u32 (p); } xfree (buffer); return ki[1]; } /* Return PK's keyid. The memory is owned by PK. */ u32 * pk_keyid (PKT_public_key *pk) { keyid_from_pk (pk, NULL); /* Uncomment this for help tracking down bugs related to keyid or main_keyid not being set correctly. */ #if 0 if (! (pk->main_keyid[0] || pk->main_keyid[1])) log_bug ("pk->main_keyid not set!\n"); if (keyid_cmp (pk->keyid, pk->main_keyid) == 0 && ! pk->flags.primary) log_bug ("keyid and main_keyid are the same, but primary flag not set!\n"); if (keyid_cmp (pk->keyid, pk->main_keyid) != 0 && pk->flags.primary) log_bug ("keyid and main_keyid are different, but primary flag set!\n"); #endif return pk->keyid; } /* Return the keyid of the primary key associated with PK. The memory is owned by PK. */ u32 * pk_main_keyid (PKT_public_key *pk) { /* Uncomment this for help tracking down bugs related to keyid or main_keyid not being set correctly. */ #if 0 if (! (pk->main_keyid[0] || pk->main_keyid[1])) log_bug ("pk->main_keyid not set!\n"); #endif return pk->main_keyid; } /* Copy the keyid in SRC to DEST and return DEST. */ u32 * keyid_copy (u32 *dest, const u32 *src) { dest[0] = src[0]; dest[1] = src[1]; return dest; } char * format_keyid (u32 *keyid, int format, char *buffer, int len) { char tmp[KEYID_STR_SIZE]; if (! buffer) { buffer = tmp; len = sizeof (tmp); } if (format == KF_DEFAULT) format = opt.keyid_format; if (format == KF_DEFAULT) format = KF_NONE; switch (format) { case KF_NONE: if (len) *buffer = 0; break; case KF_SHORT: snprintf (buffer, len, "%08lX", (ulong)keyid[1]); break; case KF_LONG: snprintf (buffer, len, "%08lX%08lX", (ulong)keyid[0], (ulong)keyid[1]); break; case KF_0xSHORT: snprintf (buffer, len, "0x%08lX", (ulong)keyid[1]); break; case KF_0xLONG: snprintf (buffer, len, "0x%08lX%08lX", (ulong)keyid[0],(ulong)keyid[1]); break; default: BUG(); } if (buffer == tmp) return xstrdup (buffer); return buffer; } size_t keystrlen(void) { int format = opt.keyid_format; if (format == KF_DEFAULT) format = KF_NONE; switch(format) { case KF_NONE: return 0; case KF_SHORT: return 8; case KF_LONG: return 16; case KF_0xSHORT: return 10; case KF_0xLONG: return 18; default: BUG(); } } const char * keystr (u32 *keyid) { static char keyid_str[KEYID_STR_SIZE]; int format = opt.keyid_format; if (format == KF_DEFAULT) format = KF_NONE; if (format == KF_NONE) format = KF_LONG; return format_keyid (keyid, format, keyid_str, sizeof (keyid_str)); } /* This function returns the key id of the main and possible the * subkey as one string. It is used by error messages. */ const char * keystr_with_sub (u32 *main_kid, u32 *sub_kid) { static char buffer[KEYID_STR_SIZE+1+KEYID_STR_SIZE]; char *p; int format = opt.keyid_format; if (format == KF_NONE) format = KF_LONG; format_keyid (main_kid, format, buffer, KEYID_STR_SIZE); if (sub_kid) { p = buffer + strlen (buffer); *p++ = '/'; format_keyid (sub_kid, format, p, KEYID_STR_SIZE); } return buffer; } const char * keystr_from_pk(PKT_public_key *pk) { keyid_from_pk(pk,NULL); return keystr(pk->keyid); } const char * keystr_from_pk_with_sub (PKT_public_key *main_pk, PKT_public_key *sub_pk) { keyid_from_pk (main_pk, NULL); if (sub_pk) keyid_from_pk (sub_pk, NULL); return keystr_with_sub (main_pk->keyid, sub_pk? sub_pk->keyid:NULL); } /* Return PK's key id as a string using the default format. PK owns the storage. */ const char * pk_keyid_str (PKT_public_key *pk) { return keystr (pk_keyid (pk)); } const char * keystr_from_desc(KEYDB_SEARCH_DESC *desc) { switch(desc->mode) { case KEYDB_SEARCH_MODE_LONG_KID: case KEYDB_SEARCH_MODE_SHORT_KID: return keystr(desc->u.kid); case KEYDB_SEARCH_MODE_FPR: { u32 keyid[2]; if (desc->fprlen == 32) { keyid[0] = buf32_to_u32 (desc->u.fpr); keyid[1] = buf32_to_u32 (desc->u.fpr+4); } else if (desc->fprlen == 20) { keyid[0] = buf32_to_u32 (desc->u.fpr+12); keyid[1] = buf32_to_u32 (desc->u.fpr+16); } else if (desc->fprlen == 16) return "?v3 fpr?"; else /* oops */ return "?vx fpr?"; return keystr(keyid); } default: BUG(); } } /* Compute the fingerprint and keyid and store it in PK. */ static void compute_fingerprint (PKT_public_key *pk) { const byte *dp; gcry_md_hd_t md; size_t len; if (gcry_md_open (&md, pk->version == 5 ? GCRY_MD_SHA256 : GCRY_MD_SHA1, 0)) BUG (); hash_public_key (md, pk); gcry_md_final (md); dp = gcry_md_read (md, 0); len = gcry_md_get_algo_dlen (gcry_md_get_algo (md)); log_assert (len <= MAX_FINGERPRINT_LEN); memcpy (pk->fpr, dp, len); pk->fprlen = len; if (pk->version == 5) { pk->keyid[0] = buf32_to_u32 (dp); pk->keyid[1] = buf32_to_u32 (dp+4); } else { pk->keyid[0] = buf32_to_u32 (dp+12); pk->keyid[1] = buf32_to_u32 (dp+16); } gcry_md_close( md); } /* * Get the keyid from the public key PK and store it at KEYID unless * this is NULL. Returns the 32 bit short keyid. */ u32 keyid_from_pk (PKT_public_key *pk, u32 *keyid) { u32 dummy_keyid[2]; if (!keyid) keyid = dummy_keyid; if (!pk->fprlen) compute_fingerprint (pk); keyid[0] = pk->keyid[0]; keyid[1] = pk->keyid[1]; return keyid[1]; /*FIXME:shortkeyid is different for v5*/ } /* * Get the keyid from the fingerprint. This function is simple for * most keys, but has to do a key lookup for old v3 keys where the * keyid is not part of the fingerprint. */ u32 keyid_from_fingerprint (ctrl_t ctrl, const byte *fprint, size_t fprint_len, u32 *keyid) { u32 dummy_keyid[2]; if( !keyid ) keyid = dummy_keyid; if (fprint_len != 20 && fprint_len != 32) { /* This is special as we have to lookup the key first. */ PKT_public_key pk; int rc; memset (&pk, 0, sizeof pk); rc = get_pubkey_byfprint (ctrl, &pk, NULL, fprint, fprint_len); if( rc ) { log_printhex (fprint, fprint_len, "Oops: keyid_from_fingerprint: no pubkey; fpr:"); keyid[0] = 0; keyid[1] = 0; } else keyid_from_pk (&pk, keyid); } else { const byte *dp = fprint; if (fprint_len == 20) /* v4 key */ { keyid[0] = buf32_to_u32 (dp+12); keyid[1] = buf32_to_u32 (dp+16); } else /* v5 key */ { keyid[0] = buf32_to_u32 (dp); keyid[1] = buf32_to_u32 (dp+4); } } return keyid[1]; } u32 keyid_from_sig (PKT_signature *sig, u32 *keyid) { if( keyid ) { keyid[0] = sig->keyid[0]; keyid[1] = sig->keyid[1]; } return sig->keyid[1]; /*FIXME:shortkeyid*/ } byte * namehash_from_uid (PKT_user_id *uid) { if (!uid->namehash) { uid->namehash = xmalloc (20); if (uid->attrib_data) rmd160_hash_buffer (uid->namehash, uid->attrib_data, uid->attrib_len); else rmd160_hash_buffer (uid->namehash, uid->name, uid->len); } return uid->namehash; } /* * Return the number of bits used in PK. */ unsigned int nbits_from_pk (PKT_public_key *pk) { return pubkey_nbits (pk->pubkey_algo, pk->pkey); } /* Convert an UTC TIMESTAMP into an UTC yyyy-mm-dd string. Return * that string. The caller should pass a buffer with at least a size * of MK_DATESTR_SIZE. */ char * mk_datestr (char *buffer, size_t bufsize, u32 timestamp) { time_t atime = timestamp; struct tm *tp; if (IS_INVALID_TIME_T (atime)) strcpy (buffer, "????" "-??" "-??"); /* Mark this as invalid. */ else { tp = gmtime (&atime); snprintf (buffer, bufsize, "%04d-%02d-%02d", 1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday ); } return buffer; } /* * return a string with the creation date of the pk * Note: this is alloced in a static buffer. * Format is: yyyy-mm-dd */ const char * dateonlystr_from_pk (PKT_public_key *pk) { static char buffer[MK_DATESTR_SIZE]; return mk_datestr (buffer, sizeof buffer, pk->timestamp); } /* Same as dateonlystr_from_pk but with a global option a full iso * timestamp is returned. In this case it shares a static buffer with * isotimestamp(). */ const char * datestr_from_pk (PKT_public_key *pk) { if (opt.flags.full_timestrings) return isotimestamp (pk->timestamp); else return dateonlystr_from_pk (pk); } const char * dateonlystr_from_sig (PKT_signature *sig ) { static char buffer[MK_DATESTR_SIZE]; return mk_datestr (buffer, sizeof buffer, sig->timestamp); } const char * datestr_from_sig (PKT_signature *sig ) { if (opt.flags.full_timestrings) return isotimestamp (sig->timestamp); else return dateonlystr_from_sig (sig); } const char * expirestr_from_pk (PKT_public_key *pk) { static char buffer[MK_DATESTR_SIZE]; if (!pk->expiredate) return _("never "); if (opt.flags.full_timestrings) return isotimestamp (pk->expiredate); return mk_datestr (buffer, sizeof buffer, pk->expiredate); } const char * expirestr_from_sig (PKT_signature *sig) { static char buffer[MK_DATESTR_SIZE]; if (!sig->expiredate) return _("never "); if (opt.flags.full_timestrings) return isotimestamp (sig->expiredate); return mk_datestr (buffer, sizeof buffer, sig->expiredate); } const char * revokestr_from_pk( PKT_public_key *pk ) { static char buffer[MK_DATESTR_SIZE]; if(!pk->revoked.date) return _("never "); if (opt.flags.full_timestrings) return isotimestamp (pk->revoked.date); return mk_datestr (buffer, sizeof buffer, pk->revoked.date); } const char * usagestr_from_pk (PKT_public_key *pk, int fill) { static char buffer[10]; int i = 0; unsigned int use = pk->pubkey_usage; if ( use & PUBKEY_USAGE_SIG ) buffer[i++] = 'S'; if ( use & PUBKEY_USAGE_CERT ) buffer[i++] = 'C'; if ( use & PUBKEY_USAGE_ENC ) buffer[i++] = 'E'; if ( (use & PUBKEY_USAGE_AUTH) ) buffer[i++] = 'A'; while (fill && i < 4) buffer[i++] = ' '; buffer[i] = 0; return buffer; } const char * colon_strtime (u32 t) { static char buf[20]; if (!t) return ""; snprintf (buf, sizeof buf, "%lu", (ulong)t); return buf; } const char * colon_datestr_from_pk (PKT_public_key *pk) { static char buf[20]; snprintf (buf, sizeof buf, "%lu", (ulong)pk->timestamp); return buf; } const char * colon_datestr_from_sig (PKT_signature *sig) { static char buf[20]; snprintf (buf, sizeof buf, "%lu", (ulong)sig->timestamp); return buf; } const char * colon_expirestr_from_sig (PKT_signature *sig) { static char buf[20]; if (!sig->expiredate) return ""; snprintf (buf, sizeof buf,"%lu", (ulong)sig->expiredate); return buf; } /* * Return a byte array with the fingerprint for the given PK/SK * The length of the array is returned in ret_len. Caller must free * the array or provide an array of length MAX_FINGERPRINT_LEN. */ byte * fingerprint_from_pk (PKT_public_key *pk, byte *array, size_t *ret_len) { if (!pk->fprlen) compute_fingerprint (pk); if (!array) array = xmalloc (pk->fprlen); memcpy (array, pk->fpr, pk->fprlen); if (ret_len) *ret_len = pk->fprlen; return array; } /* Return an allocated buffer with the fingerprint of PK formatted as * a plain hexstring. If BUFFER is NULL the result is a malloc'd * string. If BUFFER is not NULL the result will be copied into this * buffer. In the latter case BUFLEN describes the length of the * buffer; if this is too short the function terminates the process. * Returns a malloc'ed string or BUFFER. A suitable length for BUFFER * is (2*MAX_FINGERPRINT_LEN + 1). */ char * hexfingerprint (PKT_public_key *pk, char *buffer, size_t buflen) { if (!pk->fprlen) compute_fingerprint (pk); if (!buffer) { buffer = xtrymalloc (2 * pk->fprlen + 1); if (!buffer) return NULL; } else if (buflen < 2 * pk->fprlen + 1) log_fatal ("%s: buffer too short (%zu)\n", __func__, buflen); bin2hex (pk->fpr, pk->fprlen, buffer); return buffer; } /* Pretty print a hex fingerprint. If BUFFER is NULL the result is a malloc'd string. If BUFFER is not NULL the result will be copied into this buffer. In the latter case BUFLEN describes the length of the buffer; if this is too short the function terminates the process. Returns a malloc'ed string or BUFFER. A suitable length for BUFFER is (MAX_FORMATTED_FINGERPRINT_LEN + 1). */ char * format_hexfingerprint (const char *fingerprint, char *buffer, size_t buflen) { int hexlen = strlen (fingerprint); int space; int i, j; if (hexlen == 40) /* v4 fingerprint */ { space = (/* The characters and the NUL. */ 40 + 1 /* After every fourth character, we add a space (except the last). */ + 40 / 4 - 1 /* Half way through we add a second space. */ + 1); } else if (hexlen == 64 || hexlen == 50) /* v5 fingerprint */ { /* The v5 fingerprint is commonly printed truncated to 25 * octets. We accept the truncated as well as the full hex * version here and format it like this: * 19347 BC987 24640 25F99 DF3EC 2E000 0ED98 84892 E1F7B 3EA4C */ hexlen = 50; space = 10 * 5 + 9 + 1; } else /* Other fingerprint versions - print as is. */ { /* We truncated here so that we do not need to provide a buffer * of a length which is in reality never used. */ if (hexlen > MAX_FORMATTED_FINGERPRINT_LEN - 1) hexlen = MAX_FORMATTED_FINGERPRINT_LEN - 1; space = hexlen + 1; } if (!buffer) buffer = xmalloc (space); else if (buflen < space) log_fatal ("%s: buffer too short (%zu)\n", __func__, buflen); if (hexlen == 40) /* v4 fingerprint */ { for (i = 0, j = 0; i < 40; i ++) { if (i && !(i % 4)) buffer[j ++] = ' '; if (i == 40 / 2) buffer[j ++] = ' '; buffer[j ++] = fingerprint[i]; } buffer[j ++] = 0; log_assert (j == space); } else if (hexlen == 50) /* v5 fingerprint */ { for (i=j=0; i < 50; i++) { if (i && !(i % 5)) buffer[j++] = ' '; buffer[j++] = fingerprint[i]; } buffer[j++] = 0; log_assert (j == space); } else { mem2str (buffer, fingerprint, space); } return buffer; } /* Return the so called KEYGRIP which is the SHA-1 hash of the public key parameters expressed as an canonical encoded S-Exp. ARRAY must be 20 bytes long. Returns 0 on success or an error code. */ gpg_error_t keygrip_from_pk (PKT_public_key *pk, unsigned char *array) { gpg_error_t err; gcry_sexp_t s_pkey; if (DBG_PACKET) log_debug ("get_keygrip for public key\n"); switch (pk->pubkey_algo) { case GCRY_PK_DSA: err = gcry_sexp_build (&s_pkey, NULL, "(public-key(dsa(p%m)(q%m)(g%m)(y%m)))", pk->pkey[0], pk->pkey[1], pk->pkey[2], pk->pkey[3]); break; case GCRY_PK_ELG: case GCRY_PK_ELG_E: err = gcry_sexp_build (&s_pkey, NULL, "(public-key(elg(p%m)(g%m)(y%m)))", pk->pkey[0], pk->pkey[1], pk->pkey[2]); break; case GCRY_PK_RSA: case GCRY_PK_RSA_S: case GCRY_PK_RSA_E: err = gcry_sexp_build (&s_pkey, NULL, "(public-key(rsa(n%m)(e%m)))", pk->pkey[0], pk->pkey[1]); break; case PUBKEY_ALGO_EDDSA: case PUBKEY_ALGO_ECDSA: case PUBKEY_ALGO_ECDH: { char *curve = openpgp_oid_to_str (pk->pkey[0]); if (!curve) err = gpg_error_from_syserror (); else { err = gcry_sexp_build (&s_pkey, NULL, pk->pubkey_algo == PUBKEY_ALGO_EDDSA? "(public-key(ecc(curve%s)(flags eddsa)(q%m)))": (pk->pubkey_algo == PUBKEY_ALGO_ECDH && openpgp_oid_is_cv25519 (pk->pkey[0]))? "(public-key(ecc(curve%s)(flags djb-tweak)(q%m)))": "(public-key(ecc(curve%s)(q%m)))", curve, pk->pkey[1]); xfree (curve); } } break; default: err = gpg_error (GPG_ERR_PUBKEY_ALGO); break; } if (err) return err; if (!gcry_pk_get_keygrip (s_pkey, array)) { char *hexfpr; hexfpr = hexfingerprint (pk, NULL, 0); log_info ("error computing keygrip (fpr=%s)\n", hexfpr); xfree (hexfpr); memset (array, 0, 20); err = gpg_error (GPG_ERR_GENERAL); } else { if (DBG_PACKET) log_printhex (array, 20, "keygrip="); /* FIXME: Save the keygrip in PK. */ } gcry_sexp_release (s_pkey); return err; } /* Store an allocated buffer with the keygrip of PK encoded as a hexstring at r_GRIP. Returns 0 on success. */ gpg_error_t hexkeygrip_from_pk (PKT_public_key *pk, char **r_grip) { gpg_error_t err; unsigned char grip[KEYGRIP_LEN]; *r_grip = NULL; err = keygrip_from_pk (pk, grip); if (!err) { char * buf = xtrymalloc (KEYGRIP_LEN * 2 + 1); if (!buf) err = gpg_error_from_syserror (); else { bin2hex (grip, KEYGRIP_LEN, buf); *r_grip = buf; } } return err; } diff --git a/g10/parse-packet.c b/g10/parse-packet.c index fc37c095d..c3f6b544d 100644 --- a/g10/parse-packet.c +++ b/g10/parse-packet.c @@ -1,3664 +1,3759 @@ /* 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" #include "../common/mbox-util.h" static int mpi_print_mode; static int list_mode; static estream_t listfp; /* A linked list of known notation names. Note that the FLAG is used * to store the length of the name to speed up the check. */ static strlist_t known_notations_list; 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; } +/* Read an external representation of an SOS and return the opaque MPI + with GCRYMPI_FLAG_USER2. The external format is a 16-bit unsigned + value stored in network byte order giving information for the + following octets. + + 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 +sos_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) : gcry_xmalloc (nbytes); + p = buf; + for (i = 0; i < nbytes; i++) + { + if (nread == nmax) + goto overflow; + + c = iobuf_get (inp); + if (c == -1) + goto leave; + + p[i] = c; + nread ++; + } + + a = gcry_mpi_set_opaque (NULL, buf, nbits); + gcry_mpi_set_flag (a, GCRYMPI_FLAG_USER2); + *ret_nread = nread; + return a; + + overflow: + log_error ("mpi larger than indicated length (%u bits)\n", 8*nmax); + leave: + *ret_nread = nread; + gcry_free(buf); + return a; +} + + /* Register STRING as a known critical notation name. */ void register_known_notation (const char *string) { strlist_t sl; if (!known_notations_list) { sl = add_to_strlist (&known_notations_list, "preferred-email-encoding@pgp.com"); sl->flags = 32; sl = add_to_strlist (&known_notations_list, "pka-address@gnupg.org"); sl->flags = 21; } if (!string) return; /* Only initialized the default known notations. */ /* In --set-notation we use an exclamation mark to indicate a * critical notation. As a convenience skip this here. */ if (*string == '!') string++; if (!*string || strlist_find (known_notations_list, string)) return; /* Empty string or already registered. */ sl = add_to_strlist (&known_notations_list, string); sl->flags = strlen (string); } 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 && !glo_ctrl.silence_parse_warnings) { 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 && !glo_ctrl.silence_parse_warnings) 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 from 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, aead_algo, hash_algo, seskeylen, minlen; if (pktlen < 4) goto too_short; version = iobuf_get_noeof (inp); pktlen--; 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; if (pktlen < 2) goto too_short; 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_noeof (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, aead %d," " s2k %d, hash %d", version, cipher_algo, aead_algo, s2kmode, hash_algo); if (seskeylen) { /* 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 size 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; too_short: 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; } 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) + if (k->pubkey_algo == PUBKEY_ALGO_ECDH) { - size_t n; - rc = read_size_body (inp, pktlen, &n, k->data+i); - pktlen -= n; + if (i == 1) + { + size_t n; + rc = read_size_body (inp, pktlen, &n, k->data+i); + pktlen -= n; + } + else + { + int n = pktlen; + k->data[i] = sos_read (inp, &n, 0); + pktlen -= n; + if (!k->data[i]) + rc = gpg_error (GPG_ERR_INV_PACKET); + } } 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. DIGEST_ALGO is the * digest algo of the signature. */ static void dump_sig_subpkt (int hashed, int type, int critical, const byte * buffer, size_t buflen, size_t length, int digest_algo) { const char *p = NULL; int i; int nprinted; /* 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--; nprinted = es_fprintf (listfp, "\t%s%ssubpkt %d len %u (", /*) */ critical ? "critical " : "", hashed ? "hashed " : "", type, (unsigned) length); if (nprinted < 1) nprinted = 1; /*(we use (nprinted-1) later.)*/ 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; case SIGSUBPKT_ATTST_SIGS: { unsigned int hlen; es_fputs ("attst-sigs: ", listfp); hlen = gcry_md_get_algo_dlen (map_md_openpgp_to_gcry (digest_algo)); if (!hlen) p = "[unknown digest algo]"; else if ((length % hlen)) p = "[invalid length]"; else { es_fprintf (listfp, "%u", (unsigned int)length/hlen); while (length) { es_fprintf (listfp, "\n\t%*s", nprinted-1, ""); es_write_hexstring (listfp, buffer, hlen, 0, NULL); buffer += hlen; length -= hlen; } } } break; case SIGSUBPKT_KEY_BLOCK: es_fputs ("key-block: ", listfp); if (length && buffer[0]) p = "[unknown reserved octet]"; else if (length < 50) /* 50 is an arbitrary min. length. */ p = "[invalid subpacket]"; else { /* estream_t fp; */ /* fp = es_fopen ("a.key-block", "wb"); */ /* log_assert (fp); */ /* es_fwrite ( buffer+1, length-1, 1, fp); */ /* es_fclose (fp); */ es_fprintf (listfp, "[%u octets]", (unsigned int)length-1); } 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: case SIGSUBPKT_ATTST_SIGS: 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 fingerprint */ 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; case SIGSUBPKT_KEY_BLOCK: if (n && buffer[0]) return -1; /* Unknown version - ignore. */ if (n < 50) break; /* Definitely too short to carry a key block. */ 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) { strlist_t sl; register_known_notation (NULL); /* Make sure it is initialized. */ for (sl = known_notations_list; sl; sl = sl->next) if (sl->flags == len && !memcmp (sl->d, name, len)) return 1; /* Known */ if (opt.verbose && !glo_ctrl.silence_parse_warnings) { log_info(_("Unknown critical signature notation: ") ); print_utf8_buffer (log_get_stream(), name, len); log_printf ("\n"); } return 0; /* Unknown. */ } 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: case SIGSUBPKT_ATTST_SIGS: /* 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; case SIGSUBPKT_KEY_BLOCK: if (n && !buffer[0]) return 1; else return 0; default: return 0; } } const byte * enum_sig_subpkt (PKT_signature *sig, int want_hashed, 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; const subpktarea_t *pktbuf = want_hashed? sig->hashed : sig->unhashed; 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; if (!buflen) goto no_type_byte; 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 && !glo_ctrl.silence_parse_warnings) 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, sig->digest_algo); 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 && !glo_ctrl.silence_parse_warnings) log_printhex (pktbuf->data, pktbuf->len > 16? 16 : pktbuf->len, "buffer shorter than subpacket (%zu/%d/%zu); dump:", pktbuf->len, buflen, n); if (start) *start = -1; return NULL; no_type_byte: if (opt.verbose && !glo_ctrl.silence_parse_warnings) log_info ("type octet missing in subpacket\n"); if (start) *start = -1; return NULL; } const byte * parse_sig_subpkt (PKT_signature *sig, int want_hashed, sigsubpkttype_t reqtype, size_t *ret_n) { return enum_sig_subpkt (sig, want_hashed, reqtype, ret_n, NULL, NULL); } const byte * parse_sig_subpkt2 (PKT_signature *sig, sigsubpkttype_t reqtype) { const byte *p; p = parse_sig_subpkt (sig, 1, reqtype, NULL); if (!p) p = parse_sig_subpkt (sig, 0, 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, 1, SIGSUBPKT_REV_KEY, &len, &seq, NULL))) { /* Consider only valid packets. They must have a length of * either 2+20 or 2+32 octets and bit 7 of the class octet must * be set. */ if ((len == 22 || len == 34) && (revkey[0] & 0x80)) { sig->revkey = xrealloc (sig->revkey, sizeof (struct revocation_key) * (sig->numrevkeys + 1)); sig->revkey[sig->numrevkeys].class = revkey[0]; sig->revkey[sig->numrevkeys].algid = revkey[1]; len -= 2; sig->revkey[sig->numrevkeys].fprlen = len; memcpy (sig->revkey[sig->numrevkeys].fpr, revkey+2, len); memset (sig->revkey[sig->numrevkeys].fpr+len, 0, sizeof (sig->revkey[sig->numrevkeys].fpr) - len); sig->numrevkeys++; } } } int parse_signature (IOBUF inp, int pkttype, unsigned long pktlen, PKT_signature * sig) { int md5_len = 0; unsigned n; int is_v4or5 = 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 || sig->version == 5) is_v4or5 = 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_v4or5) { 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_v4or5) { 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_v4or5) /* 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_v4or5 && 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, 1, SIGSUBPKT_TEST_CRITICAL, NULL) || !parse_sig_subpkt (sig, 0, SIGSUBPKT_TEST_CRITICAL, NULL)) sig->flags.unknown_critical = 1; p = parse_sig_subpkt (sig, 1, SIGSUBPKT_SIG_CREATED, NULL); if (p) sig->timestamp = buf32_to_u32 (p); else if (!(sig->pubkey_algo >= 100 && sig->pubkey_algo <= 110) && opt.verbose && !glo_ctrl.silence_parse_warnings) log_info ("signature packet without timestamp\n"); /* Set the key id. We first try the issuer fingerprint and if * it is a v4 signature the fallback to the issuer. Note that * only the issuer packet is also searched in the unhashed area. */ p = parse_sig_subpkt (sig, 1, SIGSUBPKT_ISSUER_FPR, &len); if (p && len == 21 && p[0] == 4) { sig->keyid[0] = buf32_to_u32 (p + 1 + 12); sig->keyid[1] = buf32_to_u32 (p + 1 + 16); } else if (p && len == 33 && p[0] == 5) { sig->keyid[0] = buf32_to_u32 (p + 1 ); sig->keyid[1] = buf32_to_u32 (p + 1 + 4); } else if ((p = parse_sig_subpkt2 (sig, SIGSUBPKT_ISSUER))) { 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 && !glo_ctrl.silence_parse_warnings) log_info ("signature packet without keyid\n"); p = parse_sig_subpkt (sig, 1, 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, 1, SIGSUBPKT_POLICY, NULL); if (p) sig->flags.policy_url = 1; p = parse_sig_subpkt (sig, 1, SIGSUBPKT_PREF_KS, NULL); if (p) sig->flags.pref_ks = 1; p = parse_sig_subpkt (sig, 1, SIGSUBPKT_SIGNERS_UID, &len); if (p && len) { char *mbox; sig->signers_uid = try_make_printable_string (p, len, 0); if (!sig->signers_uid) { rc = gpg_error_from_syserror (); goto leave; } mbox = mailbox_from_userid (sig->signers_uid, 0); if (mbox) { xfree (sig->signers_uid); sig->signers_uid = mbox; } } p = parse_sig_subpkt (sig, 1, SIGSUBPKT_KEY_BLOCK, NULL); if (p) sig->flags.key_block = 1; p = parse_sig_subpkt (sig, 1, SIGSUBPKT_NOTATION, NULL); if (p) sig->flags.notation = 1; p = parse_sig_subpkt (sig, 1, SIGSUBPKT_REVOCABLE, NULL); if (p && *p == 0) sig->flags.revocable = 0; p = parse_sig_subpkt (sig, 1, 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, 1, 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_v4or5) { parse_sig_subpkt (sig, 1, SIGSUBPKT_LIST_HASHED, NULL); parse_sig_subpkt (sig, 0, 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); + if (sig->pubkey_algo == PUBKEY_ALGO_ECDSA + || sig->pubkey_algo == PUBKEY_ALGO_EDDSA) + sig->data[i] = sos_read (inp, &n, 0); + else + 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; int is_v5; unsigned int pkbytes; /* For v5 keys: Number of bytes in the public * key material. For v4 keys: 0. */ (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) is_v5 = 0; else if (version == 5) is_v5 = 1; else if (version == 2 || version == 3) { /* Not anymore supported since 2.1. Use an older gpg version * (i.e. gpg 1.4) to parse v3 packets. */ if (opt.verbose > 1 && !glo_ctrl.silence_parse_warnings) 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 < (is_v5? 15: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 large]\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 (is_v5) { pkbytes = read_32 (inp); pktlen -= 4; } else pkbytes = 0; if (list_mode) { es_fprintf (listfp, ":%s key packet:\n" "\tversion %d, algo %d, created %lu, expires %lu", 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); if (is_v5) es_fprintf (listfp, ", pkbytes %u\n", pkbytes); else es_fprintf (listfp, "\n"); } 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). */ + /* Read the OID (i==0) 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); + if (algorithm == PUBKEY_ALGO_ECDSA + || algorithm == PUBKEY_ALGO_EDDSA + || algorithm == PUBKEY_ALGO_ECDH) + pk->pkey[i] = sos_read (inp, &n, 0); + else + 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; unsigned int skbytes; 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 (is_v5) { unsigned int protcount = 0; /* Read the one octet count of the following key-protection * material. Only required in case of unknown values. */ if (!pktlen) { err = gpg_error (GPG_ERR_INV_PACKET); goto leave; } protcount = iobuf_get_noeof (inp); pktlen--; if (list_mode) es_fprintf (listfp, "\tprotbytes: %u\n", protcount); } 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 out 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. */ if (ski->s2k.mode == 3 || ski->s2k.mode == 1) { 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); } /* 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_noeof (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. * FIXME: For v5 keys we can deduce this info! */ 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); } /* Skip count of secret key material. */ if (is_v5) { if (pktlen < 4) { err = gpg_error (GPG_ERR_INV_PACKET); goto leave; } skbytes = read_32 (inp); pktlen -= 4; if (list_mode) es_fprintf (listfp, "\tskbytes: %u\n", skbytes); } /* 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. * FIXME: We can do better for v5 keys. */ 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); + if (algorithm == PUBKEY_ALGO_ECDSA + || algorithm == PUBKEY_ALGO_EDDSA + || algorithm == PUBKEY_ALGO_ECDH) + pk->pkey[i] = sos_read (inp, &n, 0); + else + 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 && !glo_ctrl.silence_parse_warnings) 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 uninitialized 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; if (!data) datalen = 0; packet = xmalloc (sizeof *packet); init_packet (packet); packet->pkttype = PKT_GPG_CONTROL; packet->pkt.gpg_control = xmalloc (sizeof *packet->pkt.gpg_control + datalen); packet->pkt.gpg_control->control = type; packet->pkt.gpg_control->datalen = datalen; p = packet->pkt.gpg_control->data; for (; datalen; datalen--, p++) *p = *data++; return packet; } diff --git a/g10/pkglue.c b/g10/pkglue.c index d266fef61..741a93735 100644 --- a/g10/pkglue.c +++ b/g10/pkglue.c @@ -1,422 +1,496 @@ /* pkglue.c - public key operations glue code * Copyright (C) 2000, 2003, 2010 Free Software Foundation, Inc. * Copyright (C) 2014 Werner Koch * * This file is part of GnuPG. * * GnuPG is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * GnuPG is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . */ #include #include #include #include #include #include "gpg.h" #include "../common/util.h" #include "pkglue.h" #include "main.h" #include "options.h" /* FIXME: Better change the function name because mpi_ is used by gcrypt macros. */ gcry_mpi_t get_mpi_from_sexp (gcry_sexp_t sexp, const char *item, int mpifmt) { gcry_sexp_t list; gcry_mpi_t data; list = gcry_sexp_find_token (sexp, item, 0); log_assert (list); data = gcry_sexp_nth_mpi (list, 1, mpifmt); log_assert (data); gcry_sexp_release (list); return data; } +/* Extract SOS representation from SEXP for PARAM, return the result + in R_SOS. */ +gpg_error_t +sexp_extract_param_sos (gcry_sexp_t sexp, const char *param, gcry_mpi_t *r_sos) +{ + gpg_error_t err; + gcry_sexp_t l2 = gcry_sexp_find_token (sexp, param, 0); + + *r_sos = NULL; + if (!l2) + err = gpg_error (GPG_ERR_NO_OBJ); + else + { + size_t buflen; + void *p0 = gcry_sexp_nth_buffer (l2, 1, &buflen); + + if (!p0) + err = gpg_error_from_syserror (); + else + { + gcry_mpi_t sos; + unsigned int nbits = buflen*8; + unsigned char *p = p0; + + if (nbits >= 8 && !(*p & 0x80)) + if (--nbits >= 7 && !(*p & 0x40)) + if (--nbits >= 6 && !(*p & 0x20)) + if (--nbits >= 5 && !(*p & 0x10)) + if (--nbits >= 4 && !(*p & 0x08)) + if (--nbits >= 3 && !(*p & 0x04)) + if (--nbits >= 2 && !(*p & 0x02)) + if (--nbits >= 1 && !(*p & 0x01)) + --nbits; + + sos = gcry_mpi_set_opaque (NULL, p0, nbits); + if (sos) + { + gcry_mpi_set_flag (sos, GCRYMPI_FLAG_USER2); + *r_sos = sos; + err = 0; + } + else + err = gpg_error_from_syserror (); + } + gcry_sexp_release (l2); + } + + return err; +} + /**************** * Emulate our old PK interface here - sometime in the future we might * change the internal design to directly fit to libgcrypt. */ int pk_verify (pubkey_algo_t pkalgo, gcry_mpi_t hash, gcry_mpi_t *data, gcry_mpi_t *pkey) { gcry_sexp_t s_sig, s_hash, s_pkey; int rc; unsigned int neededfixedlen = 0; /* Make a sexp from pkey. */ if (pkalgo == PUBKEY_ALGO_DSA) { rc = gcry_sexp_build (&s_pkey, NULL, "(public-key(dsa(p%m)(q%m)(g%m)(y%m)))", pkey[0], pkey[1], pkey[2], pkey[3]); } else if (pkalgo == PUBKEY_ALGO_ELGAMAL_E || pkalgo == PUBKEY_ALGO_ELGAMAL) { rc = gcry_sexp_build (&s_pkey, NULL, "(public-key(elg(p%m)(g%m)(y%m)))", pkey[0], pkey[1], pkey[2]); } else if (pkalgo == PUBKEY_ALGO_RSA || pkalgo == PUBKEY_ALGO_RSA_S) { rc = gcry_sexp_build (&s_pkey, NULL, "(public-key(rsa(n%m)(e%m)))", pkey[0], pkey[1]); } else if (pkalgo == PUBKEY_ALGO_ECDSA) { char *curve = openpgp_oid_to_str (pkey[0]); if (!curve) rc = gpg_error_from_syserror (); else { rc = gcry_sexp_build (&s_pkey, NULL, "(public-key(ecdsa(curve %s)(q%m)))", curve, pkey[1]); xfree (curve); } } else if (pkalgo == PUBKEY_ALGO_EDDSA) { char *curve = openpgp_oid_to_str (pkey[0]); if (!curve) rc = gpg_error_from_syserror (); else { rc = gcry_sexp_build (&s_pkey, NULL, "(public-key(ecc(curve %s)" "(flags eddsa)(q%m)))", curve, pkey[1]); xfree (curve); } if (openpgp_oid_is_ed25519 (pkey[0])) neededfixedlen = 256 / 8; } else return GPG_ERR_PUBKEY_ALGO; if (rc) BUG (); /* gcry_sexp_build should never fail. */ /* Put hash into a S-Exp s_hash. */ if (pkalgo == PUBKEY_ALGO_EDDSA) { if (gcry_sexp_build (&s_hash, NULL, "(data(flags eddsa)(hash-algo sha512)(value %m))", hash)) BUG (); /* gcry_sexp_build should never fail. */ } else { if (gcry_sexp_build (&s_hash, NULL, "%m", hash)) BUG (); /* gcry_sexp_build should never fail. */ } /* Put data into a S-Exp s_sig. */ s_sig = NULL; if (pkalgo == PUBKEY_ALGO_DSA) { if (!data[0] || !data[1]) rc = gpg_error (GPG_ERR_BAD_MPI); else rc = gcry_sexp_build (&s_sig, NULL, "(sig-val(dsa(r%m)(s%m)))", data[0], data[1]); } else if (pkalgo == PUBKEY_ALGO_ECDSA) { if (!data[0] || !data[1]) rc = gpg_error (GPG_ERR_BAD_MPI); else rc = gcry_sexp_build (&s_sig, NULL, "(sig-val(ecdsa(r%m)(s%m)))", data[0], data[1]); } else if (pkalgo == PUBKEY_ALGO_EDDSA) { gcry_mpi_t r = data[0]; gcry_mpi_t s = data[1]; size_t rlen, slen, n; /* (bytes) */ char buf[64]; + unsigned int nbits; log_assert (neededfixedlen <= sizeof buf); if (!r || !s) rc = gpg_error (GPG_ERR_BAD_MPI); else if ((rlen = (gcry_mpi_get_nbits (r)+7)/8) > neededfixedlen || !rlen) rc = gpg_error (GPG_ERR_BAD_MPI); else if ((slen = (gcry_mpi_get_nbits (s)+7)/8) > neededfixedlen || !slen) rc = gpg_error (GPG_ERR_BAD_MPI); else { /* We need to fixup the length in case of leading zeroes. * OpenPGP does not allow leading zeroes and the parser for * the signature packet has no information on the use curve, * thus we need to do it here. We won't do it for opaque * MPIs under the assumption that they are known to be fine; * we won't see them here anyway but the check is anyway * required. Fixme: A nifty feature for gcry_sexp_build * would be a format to left pad the value (e.g. "%*M"). */ rc = 0; if (rlen < neededfixedlen && !gcry_mpi_get_flag (r, GCRYMPI_FLAG_OPAQUE) && !(rc=gcry_mpi_print (GCRYMPI_FMT_USG, buf, sizeof buf, &n, r))) { log_assert (n < neededfixedlen); memmove (buf + (neededfixedlen - n), buf, n); memset (buf, 0, neededfixedlen - n); r = gcry_mpi_set_opaque_copy (NULL, buf, neededfixedlen * 8); } + else if (rlen < neededfixedlen + && gcry_mpi_get_flag (r, GCRYMPI_FLAG_OPAQUE)) + { + const unsigned char *p; + + p = gcry_mpi_get_opaque (r, &nbits); + n = (nbits+7)/8; + memcpy (buf + (neededfixedlen - n), p, n); + memset (buf, 0, neededfixedlen - n); + gcry_mpi_set_opaque_copy (r, buf, neededfixedlen * 8); + } if (slen < neededfixedlen && !gcry_mpi_get_flag (s, GCRYMPI_FLAG_OPAQUE) && !(rc=gcry_mpi_print (GCRYMPI_FMT_USG, buf, sizeof buf, &n, s))) { log_assert (n < neededfixedlen); memmove (buf + (neededfixedlen - n), buf, n); memset (buf, 0, neededfixedlen - n); s = gcry_mpi_set_opaque_copy (NULL, buf, neededfixedlen * 8); } + else if (slen < neededfixedlen + && gcry_mpi_get_flag (s, GCRYMPI_FLAG_OPAQUE)) + { + const unsigned char *p; + + p = gcry_mpi_get_opaque (s, &nbits); + n = (nbits+7)/8; + memcpy (buf + (neededfixedlen - n), p, n); + memset (buf, 0, neededfixedlen - n); + gcry_mpi_set_opaque_copy (s, buf, neededfixedlen * 8); + } if (!rc) rc = gcry_sexp_build (&s_sig, NULL, "(sig-val(eddsa(r%M)(s%M)))", r, s); if (r != data[0]) gcry_mpi_release (r); if (s != data[1]) gcry_mpi_release (s); } } else if (pkalgo == PUBKEY_ALGO_ELGAMAL || pkalgo == PUBKEY_ALGO_ELGAMAL_E) { if (!data[0] || !data[1]) rc = gpg_error (GPG_ERR_BAD_MPI); else rc = gcry_sexp_build (&s_sig, NULL, "(sig-val(elg(r%m)(s%m)))", data[0], data[1]); } else if (pkalgo == PUBKEY_ALGO_RSA || pkalgo == PUBKEY_ALGO_RSA_S) { if (!data[0]) rc = gpg_error (GPG_ERR_BAD_MPI); else rc = gcry_sexp_build (&s_sig, NULL, "(sig-val(rsa(s%m)))", data[0]); } else BUG (); if (!rc) rc = gcry_pk_verify (s_sig, s_hash, s_pkey); gcry_sexp_release (s_sig); gcry_sexp_release (s_hash); gcry_sexp_release (s_pkey); return rc; } /**************** * Emulate our old PK interface here - sometime in the future we might * change the internal design to directly fit to libgcrypt. * PK is only required to compute the fingerprint for ECDH. */ int pk_encrypt (pubkey_algo_t algo, gcry_mpi_t *resarr, gcry_mpi_t data, PKT_public_key *pk, gcry_mpi_t *pkey) { gcry_sexp_t s_ciph = NULL; gcry_sexp_t s_data = NULL; gcry_sexp_t s_pkey = NULL; int rc; /* Make a sexp from pkey. */ if (algo == PUBKEY_ALGO_ELGAMAL || algo == PUBKEY_ALGO_ELGAMAL_E) { rc = gcry_sexp_build (&s_pkey, NULL, "(public-key(elg(p%m)(g%m)(y%m)))", pkey[0], pkey[1], pkey[2]); /* Put DATA into a simplified S-expression. */ if (!rc) rc = gcry_sexp_build (&s_data, NULL, "%m", data); } else if (algo == PUBKEY_ALGO_RSA || algo == PUBKEY_ALGO_RSA_E) { rc = gcry_sexp_build (&s_pkey, NULL, "(public-key(rsa(n%m)(e%m)))", pkey[0], pkey[1]); /* Put DATA into a simplified S-expression. */ if (!rc) rc = gcry_sexp_build (&s_data, NULL, "%m", data); } else if (algo == PUBKEY_ALGO_ECDH) { gcry_mpi_t k; rc = pk_ecdh_generate_ephemeral_key (pkey, &k); if (!rc) { char *curve; curve = openpgp_oid_to_str (pkey[0]); if (!curve) rc = gpg_error_from_syserror (); else { int with_djb_tweak_flag = openpgp_oid_is_cv25519 (pkey[0]); /* Now use the ephemeral secret to compute the shared point. */ rc = gcry_sexp_build (&s_pkey, NULL, with_djb_tweak_flag ? "(public-key(ecdh(curve%s)(flags djb-tweak)(q%m)))" : "(public-key(ecdh(curve%s)(q%m)))", curve, pkey[1]); xfree (curve); /* Put K into a simplified S-expression. */ if (!rc) rc = gcry_sexp_build (&s_data, NULL, "%m", k); } gcry_mpi_release (k); } } else rc = gpg_error (GPG_ERR_PUBKEY_ALGO); /* Pass it to libgcrypt. */ if (!rc) rc = gcry_pk_encrypt (&s_ciph, s_data, s_pkey); gcry_sexp_release (s_data); gcry_sexp_release (s_pkey); if (rc) ; else if (algo == PUBKEY_ALGO_ECDH) { gcry_mpi_t shared, public, result; byte fp[MAX_FINGERPRINT_LEN]; size_t fpn; /* Get the shared point and the ephemeral public key. */ shared = get_mpi_from_sexp (s_ciph, "s", GCRYMPI_FMT_USG); - public = get_mpi_from_sexp (s_ciph, "e", GCRYMPI_FMT_USG); + rc = sexp_extract_param_sos (s_ciph, "e", &public); gcry_sexp_release (s_ciph); s_ciph = NULL; if (DBG_CRYPTO) { log_debug ("ECDH ephemeral key:"); gcry_mpi_dump (public); log_printf ("\n"); } result = NULL; fingerprint_from_pk (pk, fp, &fpn); if (fpn != 20) rc = gpg_error (GPG_ERR_INV_LENGTH); - else + + if (!rc) rc = pk_ecdh_encrypt_with_shared_point (shared, fp, data, pkey, &result); gcry_mpi_release (shared); if (!rc) { resarr[0] = public; resarr[1] = result; } else { gcry_mpi_release (public); gcry_mpi_release (result); } } else /* Elgamal or RSA case. */ { /* Fixme: Add better error handling or make gnupg use S-expressions directly. */ resarr[0] = get_mpi_from_sexp (s_ciph, "a", GCRYMPI_FMT_USG); if (!is_RSA (algo)) resarr[1] = get_mpi_from_sexp (s_ciph, "b", GCRYMPI_FMT_USG); } gcry_sexp_release (s_ciph); return rc; } /* Check whether SKEY is a suitable secret key. */ int pk_check_secret_key (pubkey_algo_t pkalgo, gcry_mpi_t *skey) { gcry_sexp_t s_skey; int rc; if (pkalgo == PUBKEY_ALGO_DSA) { rc = gcry_sexp_build (&s_skey, NULL, "(private-key(dsa(p%m)(q%m)(g%m)(y%m)(x%m)))", skey[0], skey[1], skey[2], skey[3], skey[4]); } else if (pkalgo == PUBKEY_ALGO_ELGAMAL || pkalgo == PUBKEY_ALGO_ELGAMAL_E) { rc = gcry_sexp_build (&s_skey, NULL, "(private-key(elg(p%m)(g%m)(y%m)(x%m)))", skey[0], skey[1], skey[2], skey[3]); } else if (is_RSA (pkalgo)) { rc = gcry_sexp_build (&s_skey, NULL, "(private-key(rsa(n%m)(e%m)(d%m)(p%m)(q%m)(u%m)))", skey[0], skey[1], skey[2], skey[3], skey[4], skey[5]); } else if (pkalgo == PUBKEY_ALGO_ECDSA || pkalgo == PUBKEY_ALGO_ECDH) { char *curve = openpgp_oid_to_str (skey[0]); if (!curve) rc = gpg_error_from_syserror (); else { rc = gcry_sexp_build (&s_skey, NULL, "(private-key(ecc(curve%s)(q%m)(d%m)))", curve, skey[1], skey[2]); xfree (curve); } } else if (pkalgo == PUBKEY_ALGO_EDDSA) { char *curve = openpgp_oid_to_str (skey[0]); if (!curve) rc = gpg_error_from_syserror (); else { rc = gcry_sexp_build (&s_skey, NULL, "(private-key(ecc(curve %s)" "(flags eddsa)(q%m)(d%m)))", curve, skey[1], skey[2]); xfree (curve); } } else return GPG_ERR_PUBKEY_ALGO; if (!rc) { rc = gcry_pk_testkey (s_skey); gcry_sexp_release (s_skey); } return rc; } diff --git a/g10/pkglue.h b/g10/pkglue.h index 57a963353..099337959 100644 --- a/g10/pkglue.h +++ b/g10/pkglue.h @@ -1,50 +1,52 @@ /* pkglue.h - public key operations definitions * Copyright (C) 2003, 2010 Free Software Foundation, Inc. * * This file is part of GnuPG. * * GnuPG is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * GnuPG is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . */ #ifndef GNUPG_G10_PKGLUE_H #define GNUPG_G10_PKGLUE_H #include "packet.h" /* For PKT_public_key. */ /*-- pkglue.c --*/ gcry_mpi_t get_mpi_from_sexp (gcry_sexp_t sexp, const char *item, int mpifmt); +gpg_error_t sexp_extract_param_sos (gcry_sexp_t sexp, const char *param, + gcry_mpi_t *r_sos); int pk_verify (pubkey_algo_t algo, gcry_mpi_t hash, gcry_mpi_t *data, gcry_mpi_t *pkey); int pk_encrypt (pubkey_algo_t algo, gcry_mpi_t *resarr, gcry_mpi_t data, PKT_public_key *pk, gcry_mpi_t *pkey); int pk_check_secret_key (pubkey_algo_t algo, gcry_mpi_t *skey); /*-- ecdh.c --*/ gcry_mpi_t pk_ecdh_default_params (unsigned int qbits); gpg_error_t pk_ecdh_generate_ephemeral_key (gcry_mpi_t *pkey, gcry_mpi_t *r_k); gpg_error_t pk_ecdh_encrypt_with_shared_point /* */ (gcry_mpi_t shared_mpi, const byte pk_fp[MAX_FINGERPRINT_LEN], gcry_mpi_t data, gcry_mpi_t *pkey, gcry_mpi_t *out); int pk_ecdh_encrypt (gcry_mpi_t *resarr, const byte pk_fp[MAX_FINGERPRINT_LEN], gcry_mpi_t data, gcry_mpi_t * pkey); int pk_ecdh_decrypt (gcry_mpi_t *result, const byte sk_fp[MAX_FINGERPRINT_LEN], gcry_mpi_t data, gcry_mpi_t shared, gcry_mpi_t * skey); #endif /*GNUPG_G10_PKGLUE_H*/ diff --git a/g10/seskey.c b/g10/seskey.c index fb71ad5cd..15c210b78 100644 --- a/g10/seskey.c +++ b/g10/seskey.c @@ -1,359 +1,352 @@ /* seskey.c - make session keys etc. * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, * 2006, 2009, 2010 Free Software Foundation, Inc. * * This file is part of GnuPG. * * GnuPG is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * GnuPG is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . */ #include #include #include #include #include "gpg.h" #include "../common/util.h" #include "options.h" #include "main.h" #include "../common/i18n.h" /* Generate a new session key in *DEK that is appropriate for the * algorithm DEK->ALGO (i.e., ensure that the key is not weak). * * This function overwrites DEK->KEYLEN, DEK->KEY. The rest of the * fields are left as is. */ void make_session_key( DEK *dek ) { gcry_cipher_hd_t chd; int i, rc; dek->keylen = openpgp_cipher_get_algo_keylen (dek->algo); if (openpgp_cipher_open (&chd, dek->algo, GCRY_CIPHER_MODE_CFB, (GCRY_CIPHER_SECURE | (dek->algo >= 100 ? 0 : GCRY_CIPHER_ENABLE_SYNC))) ) BUG(); gcry_randomize (dek->key, dek->keylen, GCRY_STRONG_RANDOM ); for (i=0; i < 16; i++ ) { rc = gcry_cipher_setkey (chd, dek->key, dek->keylen); if (!rc) { gcry_cipher_close (chd); return; } if (gpg_err_code (rc) != GPG_ERR_WEAK_KEY) BUG(); log_info(_("weak key created - retrying\n") ); /* Renew the session key until we get a non-weak key. */ gcry_randomize (dek->key, dek->keylen, GCRY_STRONG_RANDOM); } log_fatal (_("cannot avoid weak key for symmetric cipher; " "tried %d times!\n"), i); } /* Encode the session key stored in DEK as an MPI in preparation to * encrypt it with the public key algorithm OPENPGP_PK_ALGO with a key * whose length (the size of the public key) is NBITS. * * On success, returns an MPI, which the caller must free using * gcry_mpi_release(). */ gcry_mpi_t encode_session_key (int openpgp_pk_algo, DEK *dek, unsigned int nbits) { size_t nframe = (nbits+7) / 8; byte *p; byte *frame; int i,n; u16 csum; - gcry_mpi_t a; if (DBG_CRYPTO) log_debug ("encode_session_key: encoding %d byte DEK", dek->keylen); csum = 0; for (p = dek->key, i=0; i < dek->keylen; i++) csum += *p++; /* Shortcut for ECDH. It's padding is minimal to simply make the output be a multiple of 8 bytes. */ if (openpgp_pk_algo == PUBKEY_ALGO_ECDH) { /* Pad to 8 byte granularity; the padding byte is the number of * padded bytes. * * A DEK(k bytes) CSUM(2 bytes) 0x 0x 0x 0x ... 0x * +---- x times ---+ */ nframe = (( 1 + dek->keylen + 2 /* The value so far is always odd. */ + 7 ) & (~7)); /* alg+key+csum fit and the size is congruent to 8. */ log_assert (!(nframe%8) && nframe > 1 + dek->keylen + 2 ); frame = xmalloc_secure (nframe); n = 0; frame[n++] = dek->algo; memcpy (frame+n, dek->key, dek->keylen); n += dek->keylen; frame[n++] = csum >> 8; frame[n++] = csum; i = nframe - n; /* Number of padded bytes. */ memset (frame+n, i, i); /* Use it as the value of each padded byte. */ log_assert (n+i == nframe); if (DBG_CRYPTO) log_debug ("encode_session_key: " "[%d] %02x %02x %02x ... %02x %02x %02x\n", (int) nframe, frame[0], frame[1], frame[2], frame[nframe-3], frame[nframe-2], frame[nframe-1]); - if (gcry_mpi_scan (&a, GCRYMPI_FMT_USG, frame, nframe, &nframe)) - BUG(); - xfree(frame); - return a; + return gcry_mpi_set_opaque (NULL, frame, 8*nframe); } /* The current limitation is that we can only use a session key * whose length is a multiple of BITS_PER_MPI_LIMB * I think we can live with that. */ if (dek->keylen + 7 > nframe || !nframe) log_bug ("can't encode a %d bit key in a %d bits frame\n", dek->keylen*8, nbits ); /* We encode the session key according to PKCS#1 v1.5 (see section * 13.1.1 of RFC 4880): * * 0 2 RND(i bytes) 0 A DEK(k bytes) CSUM(2 bytes) * * (But how can we store the leading 0 - the external representation * of MPIs doesn't allow leading zeroes =:-) * * RND are (at least 1) non-zero random bytes. * A is the cipher algorithm * DEK is the encryption key (session key) length k depends on the * cipher algorithm (20 is used with blowfish160). * CSUM is the 16 bit checksum over the DEK */ frame = xmalloc_secure( nframe ); n = 0; frame[n++] = 0; frame[n++] = 2; /* The number of random bytes are the number of otherwise unused bytes. See diagram above. */ i = nframe - 6 - dek->keylen; log_assert( i > 0 ); p = gcry_random_bytes_secure (i, GCRY_STRONG_RANDOM); /* Replace zero bytes by new values. */ for (;;) { int j, k; byte *pp; /* Count the zero bytes. */ for (j=k=0; j < i; j++ ) if (!p[j]) k++; if (!k) break; /* Okay: no zero bytes. */ k += k/128 + 3; /* Better get some more. */ pp = gcry_random_bytes_secure (k, GCRY_STRONG_RANDOM); for (j=0; j < i && k ;) { if (!p[j]) p[j] = pp[--k]; if (p[j]) j++; } xfree (pp); } memcpy (frame+n, p, i); xfree (p); n += i; frame[n++] = 0; frame[n++] = dek->algo; memcpy (frame+n, dek->key, dek->keylen ); n += dek->keylen; frame[n++] = csum >>8; frame[n++] = csum; log_assert (n == nframe); - if (gcry_mpi_scan( &a, GCRYMPI_FMT_USG, frame, n, &nframe)) - BUG(); - xfree (frame); - return a; + return gcry_mpi_set_opaque (NULL, frame, 8*n); } static gcry_mpi_t do_encode_md( gcry_md_hd_t md, int algo, size_t len, unsigned nbits, const byte *asn, size_t asnlen ) { size_t nframe = (nbits+7) / 8; byte *frame; int i,n; gcry_mpi_t a; if (len + asnlen + 4 > nframe) { log_error ("can't encode a %d bit MD into a %d bits frame, algo=%d\n", (int)(len*8), (int)nbits, algo); return NULL; } /* We encode the MD in this way: * * 0 1 PAD(n bytes) 0 ASN(asnlen bytes) MD(len bytes) * * PAD consists of FF bytes. */ frame = gcry_md_is_secure (md)? xmalloc_secure (nframe) : xmalloc (nframe); n = 0; frame[n++] = 0; frame[n++] = 1; /* block type */ i = nframe - len - asnlen -3 ; log_assert( i > 1 ); memset( frame+n, 0xff, i ); n += i; frame[n++] = 0; memcpy( frame+n, asn, asnlen ); n += asnlen; memcpy( frame+n, gcry_md_read (md, algo), len ); n += len; log_assert( n == nframe ); if (gcry_mpi_scan( &a, GCRYMPI_FMT_USG, frame, n, &nframe )) BUG(); xfree(frame); /* Note that PGP before version 2.3 encoded the MD as: * * 0 1 MD(16 bytes) 0 PAD(n bytes) 1 * * The MD is always 16 bytes here because it's always MD5. We do * not support pre-v2.3 signatures, but I'm including this comment * so the information is easily found in the future. */ return a; } /**************** * Encode a message digest into an MPI. * If it's for a DSA signature, make sure that the hash is large * enough to fill up q. If the hash is too big, take the leftmost * bits. */ gcry_mpi_t encode_md_value (PKT_public_key *pk, gcry_md_hd_t md, int hash_algo) { gcry_mpi_t frame; size_t mdlen; log_assert (hash_algo); log_assert (pk); if (pk->pubkey_algo == PUBKEY_ALGO_EDDSA) { /* EdDSA signs data of arbitrary length. Thus no special treatment is required. */ frame = gcry_mpi_set_opaque_copy (NULL, gcry_md_read (md, hash_algo), 8*gcry_md_get_algo_dlen (hash_algo)); } else if (pk->pubkey_algo == PUBKEY_ALGO_DSA || pk->pubkey_algo == PUBKEY_ALGO_ECDSA) { /* It's a DSA signature, so find out the size of q. */ size_t qbits = gcry_mpi_get_nbits (pk->pkey[1]); /* pkey[1] is Q for ECDSA, which is an uncompressed point, i.e. 04 */ if (pk->pubkey_algo == PUBKEY_ALGO_ECDSA) qbits = ecdsa_qbits_from_Q (qbits); /* Make sure it is a multiple of 8 bits. */ if ((qbits%8)) { log_error(_("DSA requires the hash length to be a" " multiple of 8 bits\n")); return NULL; } /* Don't allow any q smaller than 160 bits. This might need a revisit as the DSA2 design firms up, but for now, we don't want someone to issue signatures from a key with a 16-bit q or something like that, which would look correct but allow trivial forgeries. Yes, I know this rules out using MD5 with DSA. ;) */ if (qbits < 160) { log_error (_("%s key %s uses an unsafe (%zu bit) hash\n"), openpgp_pk_algo_name (pk->pubkey_algo), keystr_from_pk (pk), qbits); return NULL; } /* ECDSA 521 is special has it is larger than the largest hash we have (SHA-512). Thus we change the size for further processing to 512. */ if (pk->pubkey_algo == PUBKEY_ALGO_ECDSA && qbits > 512) qbits = 512; /* Check if we're too short. Too long is safe as we'll automatically left-truncate. */ mdlen = gcry_md_get_algo_dlen (hash_algo); if (mdlen < qbits/8) { log_error (_("%s key %s requires a %zu bit or larger hash " "(hash is %s)\n"), openpgp_pk_algo_name (pk->pubkey_algo), keystr_from_pk (pk), qbits, gcry_md_algo_name (hash_algo)); return NULL; } /* Note that we do the truncation by passing QBITS/8 as length to mpi_scan. */ if (gcry_mpi_scan (&frame, GCRYMPI_FMT_USG, gcry_md_read (md, hash_algo), qbits/8, NULL)) BUG(); } else { gpg_error_t rc; byte *asn; size_t asnlen; rc = gcry_md_algo_info (hash_algo, GCRYCTL_GET_ASNOID, NULL, &asnlen); if (rc) log_fatal ("can't get OID of digest algorithm %d: %s\n", hash_algo, gpg_strerror (rc)); asn = xtrymalloc (asnlen); if (!asn) return NULL; if ( gcry_md_algo_info (hash_algo, GCRYCTL_GET_ASNOID, asn, &asnlen) ) BUG(); frame = do_encode_md (md, hash_algo, gcry_md_get_algo_dlen (hash_algo), gcry_mpi_get_nbits (pk->pkey[0]), asn, asnlen); xfree (asn); } return frame; } diff --git a/g10/sign.c b/g10/sign.c index e5a3b0a29..8f72d8102 100644 --- a/g10/sign.c +++ b/g10/sign.c @@ -1,1932 +1,1934 @@ /* sign.c - sign data * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, * 2007, 2010, 2012 Free Software Foundation, Inc. * * This file is part of GnuPG. * * GnuPG is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * GnuPG is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . */ #include #include #include #include #include #include "gpg.h" #include "options.h" #include "packet.h" #include "../common/status.h" #include "../common/iobuf.h" #include "keydb.h" #include "../common/util.h" #include "main.h" #include "filter.h" #include "../common/ttyio.h" #include "trustdb.h" #include "../common/status.h" #include "../common/i18n.h" #include "pkglue.h" #include "../common/sysutils.h" #include "call-agent.h" #include "../common/mbox-util.h" #include "../common/compliance.h" #ifdef HAVE_DOSISH_SYSTEM #define LF "\r\n" #else #define LF "\n" #endif /* Bitflags to convey hints on what kind of signayire is created. */ #define SIGNHINT_KEYSIG 1 #define SIGNHINT_SELFSIG 2 /* Hack */ static int recipient_digest_algo; /* A type for the extra data we hash into v5 signature packets. */ struct pt_extra_hash_data_s { unsigned char mode; u32 timestamp; unsigned char namelen; char name[1]; }; typedef struct pt_extra_hash_data_s *pt_extra_hash_data_t; /* * Create notations and other stuff. It is assumed that the strings in * STRLIST are already checked to contain only printable data and have * a valid NAME=VALUE format. */ static void mk_notation_policy_etc (ctrl_t ctrl, PKT_signature *sig, PKT_public_key *pk, PKT_public_key *pksk) { const char *string; char *p = NULL; strlist_t pu = NULL; struct notation *nd = NULL; struct expando_args args; log_assert (sig->version >= 4); memset (&args, 0, sizeof(args)); args.pk = pk; args.pksk = pksk; /* Notation data. */ if (IS_ATTST_SIGS(sig)) ; else if (IS_SIG(sig) && opt.sig_notations) nd = opt.sig_notations; else if (IS_CERT(sig) && opt.cert_notations) nd = opt.cert_notations; if (nd) { struct notation *item; for (item = nd; item; item = item->next) { item->altvalue = pct_expando (ctrl, item->value,&args); if (!item->altvalue) log_error (_("WARNING: unable to %%-expand notation " "(too large). Using unexpanded.\n")); } keygen_add_notations (sig, nd); for (item = nd; item; item = item->next) { xfree (item->altvalue); item->altvalue = NULL; } } /* Set policy URL. */ if (IS_ATTST_SIGS(sig)) ; else if (IS_SIG(sig) && opt.sig_policy_url) pu = opt.sig_policy_url; else if (IS_CERT(sig) && opt.cert_policy_url) pu = opt.cert_policy_url; for (; pu; pu = pu->next) { string = pu->d; p = pct_expando (ctrl, string, &args); if (!p) { log_error(_("WARNING: unable to %%-expand policy URL " "(too large). Using unexpanded.\n")); p = xstrdup(string); } build_sig_subpkt (sig, (SIGSUBPKT_POLICY | ((pu->flags & 1)?SIGSUBPKT_FLAG_CRITICAL:0)), p, strlen (p)); xfree (p); } /* Preferred keyserver URL. */ if (IS_SIG(sig) && opt.sig_keyserver_url) pu = opt.sig_keyserver_url; for (; pu; pu = pu->next) { string = pu->d; p = pct_expando (ctrl, string, &args); if (!p) { log_error (_("WARNING: unable to %%-expand preferred keyserver URL" " (too large). Using unexpanded.\n")); p = xstrdup (string); } build_sig_subpkt (sig, (SIGSUBPKT_PREF_KS | ((pu->flags & 1)?SIGSUBPKT_FLAG_CRITICAL:0)), p, strlen (p)); xfree (p); } /* Set signer's user id. */ if (IS_SIG (sig) && !opt.flags.disable_signer_uid) { char *mbox; /* For now we use the uid which was used to locate the key. */ if (pksk->user_id && (mbox = mailbox_from_userid (pksk->user_id->name, 0))) { if (DBG_LOOKUP) log_debug ("setting Signer's UID to '%s'\n", mbox); build_sig_subpkt (sig, SIGSUBPKT_SIGNERS_UID, mbox, strlen (mbox)); xfree (mbox); } else if (opt.sender_list) { /* If a list of --sender was given we scan that list and use * the first one matching a user id of the current key. */ /* FIXME: We need to get the list of user ids for the PKSK * packet. That requires either a function to look it up * again or we need to extend the key packet struct to link * to the primary key which in turn could link to the user * ids. Too much of a change right now. Let's take just * one from the supplied list and hope that the caller * passed a matching one. */ build_sig_subpkt (sig, SIGSUBPKT_SIGNERS_UID, opt.sender_list->d, strlen (opt.sender_list->d)); } } } /* * Put the Key Block subpacket into SIG for key PKSK. Returns an * error code on failure. */ static gpg_error_t mk_sig_subpkt_key_block (ctrl_t ctrl, PKT_signature *sig, PKT_public_key *pksk) { gpg_error_t err; char *mbox; char *filterexp = NULL; int save_opt_armor = opt.armor; int save_opt_verbose = opt.verbose; char hexfpr[2*MAX_FINGERPRINT_LEN + 1]; void *data = NULL; size_t datalen; kbnode_t keyblock = NULL; push_export_filters (); opt.armor = 0; hexfingerprint (pksk, hexfpr, sizeof hexfpr); /* Get the user id so that we know which one to insert into the * key. */ if (pksk->user_id && (mbox = mailbox_from_userid (pksk->user_id->name, 0))) { if (DBG_LOOKUP) log_debug ("including key with UID '%s' (specified)\n", mbox); filterexp = xasprintf ("keep-uid= -- mbox = %s", mbox); xfree (mbox); } else if (opt.sender_list) { /* If --sender was given we use the first one from that list. */ if (DBG_LOOKUP) log_debug ("including key with UID '%s' (--sender)\n", opt.sender_list->d); filterexp = xasprintf ("keep-uid= -- mbox = %s", opt.sender_list->d); } else /* Use the primary user id. */ { if (DBG_LOOKUP) log_debug ("including key with primary UID\n"); filterexp = xstrdup ("keep-uid= primary -t"); } if (DBG_LOOKUP) log_debug ("export filter expression: %s\n", filterexp); err = parse_and_set_export_filter (filterexp); if (err) goto leave; xfree (filterexp); filterexp = xasprintf ("drop-subkey= fpr <> %s && usage !~ e", hexfpr); if (DBG_LOOKUP) log_debug ("export filter expression: %s\n", filterexp); err = parse_and_set_export_filter (filterexp); if (err) goto leave; opt.verbose = 0; err = export_pubkey_buffer (ctrl, hexfpr, EXPORT_MINIMAL|EXPORT_CLEAN, "", 1, /* Prefix with the reserved byte. */ NULL, &keyblock, &data, &datalen); opt.verbose = save_opt_verbose; if (err) { log_error ("failed to get to be included key: %s\n", gpg_strerror (err)); goto leave; } build_sig_subpkt (sig, SIGSUBPKT_KEY_BLOCK, data, datalen); leave: xfree (data); release_kbnode (keyblock); xfree (filterexp); opt.armor = save_opt_armor; pop_export_filters (); return err; } /* * Helper to hash a user ID packet. */ static void hash_uid (gcry_md_hd_t md, int sigversion, const PKT_user_id *uid) { byte buf[5]; (void)sigversion; if (uid->attrib_data) { buf[0] = 0xd1; /* Indicates an attribute packet. */ buf[1] = uid->attrib_len >> 24; /* Always use 4 length bytes. */ buf[2] = uid->attrib_len >> 16; buf[3] = uid->attrib_len >> 8; buf[4] = uid->attrib_len; } else { buf[0] = 0xb4; /* Indicates a userid packet. */ buf[1] = uid->len >> 24; /* Always use 4 length bytes. */ buf[2] = uid->len >> 16; buf[3] = uid->len >> 8; buf[4] = uid->len; } gcry_md_write( md, buf, 5 ); if (uid->attrib_data) gcry_md_write (md, uid->attrib_data, uid->attrib_len ); else gcry_md_write (md, uid->name, uid->len ); } /* * Helper to hash some parts from the signature. EXTRAHASH gives the * extra data to be hashed into v5 signatures; it may by NULL for * detached signatures. */ static void hash_sigversion_to_magic (gcry_md_hd_t md, const PKT_signature *sig, pt_extra_hash_data_t extrahash) { byte buf[10]; int i; size_t n; gcry_md_putc (md, sig->version); gcry_md_putc (md, sig->sig_class); gcry_md_putc (md, sig->pubkey_algo); gcry_md_putc (md, sig->digest_algo); if (sig->hashed) { n = sig->hashed->len; gcry_md_putc (md, (n >> 8) ); gcry_md_putc (md, n ); gcry_md_write (md, sig->hashed->data, n ); n += 6; } else { gcry_md_putc (md, 0); /* Always hash the length of the subpacket. */ gcry_md_putc (md, 0); n = 6; } /* Hash data from the literal data packet. */ if (sig->version >= 5 && (sig->sig_class == 0x00 || sig->sig_class == 0x01)) { /* - One octet content format * - File name (one octet length followed by the name) * - Four octet timestamp */ if (extrahash) { buf[0] = extrahash->mode; buf[1] = extrahash->namelen; gcry_md_write (md, buf, 2); if (extrahash->namelen) gcry_md_write (md, extrahash->name, extrahash->namelen); buf[0] = extrahash->timestamp >> 24; buf[1] = extrahash->timestamp >> 16; buf[2] = extrahash->timestamp >> 8; buf[3] = extrahash->timestamp; gcry_md_write (md, buf, 4); } else /* Detached signatures */ { memset (buf, 0, 6); gcry_md_write (md, buf, 6); } } /* Add some magic aka known as postscript. The idea was to make it * impossible to make up a document with a v3 signature and then * turn this into a v4 signature for another document. The last * hashed 5 bytes of a v4 signature should never look like a the * last 5 bytes of a v3 signature. The length can be used to parse * from the end. */ i = 0; buf[i++] = sig->version; /* Hash convention version. */ buf[i++] = 0xff; /* Not any sig type value. */ if (sig->version >= 5) { /* Note: We don't hashed any data larger than 2^32 and thus we * can always use 0 here. See also note below. */ buf[i++] = 0; buf[i++] = 0; buf[i++] = 0; buf[i++] = 0; } buf[i++] = n >> 24; /* (n is only 16 bit, so this is always 0) */ buf[i++] = n >> 16; buf[i++] = n >> 8; buf[i++] = n; gcry_md_write (md, buf, i); } /* Perform the sign operation. If CACHE_NONCE is given the agent is * advised to use that cached passphrase for the key. SIGNHINTS has * hints so that we can do some additional checks. */ static int do_sign (ctrl_t ctrl, PKT_public_key *pksk, PKT_signature *sig, gcry_md_hd_t md, int mdalgo, const char *cache_nonce, unsigned int signhints) { gpg_error_t err; byte *dp; char *hexgrip; if (pksk->timestamp > sig->timestamp ) { ulong d = pksk->timestamp - sig->timestamp; log_info (ngettext("key %s was created %lu second" " in the future (time warp or clock problem)\n", "key %s was created %lu seconds" " in the future (time warp or clock problem)\n", d), keystr_from_pk (pksk), d); if (!opt.ignore_time_conflict) return gpg_error (GPG_ERR_TIME_CONFLICT); } print_pubkey_algo_note (pksk->pubkey_algo); if (!mdalgo) mdalgo = gcry_md_get_algo (md); if ((signhints & SIGNHINT_KEYSIG) && !(signhints & SIGNHINT_SELFSIG) && mdalgo == GCRY_MD_SHA1 && !opt.flags.allow_weak_key_signatures) { /* We do not allow the creation of third-party key signatures * using SHA-1 because we also reject them when verifying. Note * that this will render dsa1024 keys unsuitable for such * keysigs and in turn the WoT. */ print_sha1_keysig_rejected_note (); err = gpg_error (GPG_ERR_DIGEST_ALGO); goto leave; } /* Check compliance. */ if (! gnupg_digest_is_allowed (opt.compliance, 1, mdalgo)) { log_error (_("digest algorithm '%s' may not be used in %s mode\n"), gcry_md_algo_name (mdalgo), gnupg_compliance_option_string (opt.compliance)); err = gpg_error (GPG_ERR_DIGEST_ALGO); goto leave; } if (! gnupg_pk_is_allowed (opt.compliance, PK_USE_SIGNING, pksk->pubkey_algo, pksk->pkey, nbits_from_pk (pksk), NULL)) { log_error (_("key %s may not be used for signing in %s mode\n"), keystr_from_pk (pksk), gnupg_compliance_option_string (opt.compliance)); err = gpg_error (GPG_ERR_PUBKEY_ALGO); goto leave; } if (!gnupg_rng_is_compliant (opt.compliance)) { err = gpg_error (GPG_ERR_FORBIDDEN); log_error (_("%s is not compliant with %s mode\n"), "RNG", gnupg_compliance_option_string (opt.compliance)); write_status_error ("random-compliance", err); goto leave; } print_digest_algo_note (mdalgo); dp = gcry_md_read (md, mdalgo); sig->digest_algo = mdalgo; sig->digest_start[0] = dp[0]; sig->digest_start[1] = dp[1]; mpi_release (sig->data[0]); sig->data[0] = NULL; mpi_release (sig->data[1]); sig->data[1] = NULL; err = hexkeygrip_from_pk (pksk, &hexgrip); if (!err) { char *desc; gcry_sexp_t s_sigval; desc = gpg_format_keydesc (ctrl, pksk, FORMAT_KEYDESC_NORMAL, 1); err = agent_pksign (NULL/*ctrl*/, cache_nonce, hexgrip, desc, pksk->keyid, pksk->main_keyid, pksk->pubkey_algo, dp, gcry_md_get_algo_dlen (mdalgo), mdalgo, &s_sigval); xfree (desc); if (err) ; else if (pksk->pubkey_algo == GCRY_PK_RSA || pksk->pubkey_algo == GCRY_PK_RSA_S) sig->data[0] = get_mpi_from_sexp (s_sigval, "s", GCRYMPI_FMT_USG); - else if (openpgp_oid_is_ed25519 (pksk->pkey[0])) + else if (pksk->pubkey_algo == PUBKEY_ALGO_ECDSA + || pksk->pubkey_algo == PUBKEY_ALGO_EDDSA) { - 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); + err = sexp_extract_param_sos (s_sigval, "r", &sig->data[0]); + if (!err) + err = sexp_extract_param_sos (s_sigval, "s", &sig->data[1]); } else { sig->data[0] = get_mpi_from_sexp (s_sigval, "r", GCRYMPI_FMT_USG); sig->data[1] = get_mpi_from_sexp (s_sigval, "s", GCRYMPI_FMT_USG); } gcry_sexp_release (s_sigval); } xfree (hexgrip); leave: if (err) log_error (_("signing failed: %s\n"), gpg_strerror (err)); else { if (opt.verbose) { char *ustr = get_user_id_string_native (ctrl, sig->keyid); log_info (_("%s/%s signature from: \"%s\"\n"), openpgp_pk_algo_name (pksk->pubkey_algo), openpgp_md_algo_name (sig->digest_algo), ustr); xfree (ustr); } } return err; } static int complete_sig (ctrl_t ctrl, PKT_signature *sig, PKT_public_key *pksk, gcry_md_hd_t md, const char *cache_nonce, unsigned int signhints) { int rc; /* if (!(rc = check_secret_key (pksk, 0))) */ rc = do_sign (ctrl, pksk, sig, md, 0, cache_nonce, signhints); return rc; } /* Return true if the key seems to be on a version 1 OpenPGP card. This works by asking the agent and may fail if the card has not yet been used with the agent. */ static int openpgp_card_v1_p (PKT_public_key *pk) { gpg_error_t err; int result; /* Shortcut if we are not using RSA: The v1 cards only support RSA thus there is no point in looking any further. */ if (!is_RSA (pk->pubkey_algo)) return 0; if (!pk->flags.serialno_valid) { char *hexgrip; err = hexkeygrip_from_pk (pk, &hexgrip); if (err) { log_error ("error computing a keygrip: %s\n", gpg_strerror (err)); return 0; /* Ooops. */ } xfree (pk->serialno); agent_get_keyinfo (NULL, hexgrip, &pk->serialno, NULL); xfree (hexgrip); pk->flags.serialno_valid = 1; } if (!pk->serialno) result = 0; /* Error from a past agent_get_keyinfo or no card. */ else { /* The version number of the card is included in the serialno. */ result = !strncmp (pk->serialno, "D2760001240101", 14); } return result; } static int match_dsa_hash (unsigned int qbytes) { if (qbytes <= 20) return DIGEST_ALGO_SHA1; if (qbytes <= 28) return DIGEST_ALGO_SHA224; if (qbytes <= 32) return DIGEST_ALGO_SHA256; if (qbytes <= 48) return DIGEST_ALGO_SHA384; if (qbytes <= 66 ) /* 66 corresponds to 521 (64 to 512) */ return DIGEST_ALGO_SHA512; return DEFAULT_DIGEST_ALGO; /* DEFAULT_DIGEST_ALGO will certainly fail, but it's the best wrong answer we have if a digest larger than 512 bits is requested. */ } /* First try --digest-algo. If that isn't set, see if the recipient has a preferred algorithm (which is also filtered through --personal-digest-prefs). If we're making a signature without a particular recipient (i.e. signing, rather than signing+encrypting) then take the first algorithm in --personal-digest-prefs that is usable for the pubkey algorithm. If --personal-digest-prefs isn't set, then take the OpenPGP default (i.e. SHA-1). Note that Ed25519+EdDSA takes an input of arbitrary length and thus 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. At * R_EXTRAHASH a malloced object with the with the extra data hashed * into v5 signatures is stored. */ static int write_plaintext_packet (iobuf_t out, iobuf_t inp, const char *fname, int ptmode, pt_extra_hash_data_t *r_extrahash) { PKT_plaintext *pt = NULL; u32 filesize; int rc = 0; if (!opt.no_literal) pt = setup_plaintext_name (fname, inp); /* Try to calculate the length of the data. */ if ( !iobuf_is_pipe_filename (fname) && *fname) { off_t tmpsize; int overflow; if (!(tmpsize = iobuf_get_filelength (inp, &overflow)) && !overflow && opt.verbose) log_info (_("WARNING: '%s' is an empty file\n"), fname); /* We can't encode the length of very large files because * OpenPGP uses only 32 bit for file sizes. So if the size of a * file is larger than 2^32 minus some bytes for packet headers, * we switch to partial length encoding. */ if (tmpsize < (IOBUF_FILELENGTH_LIMIT - 65536)) filesize = tmpsize; else filesize = 0; /* Because the text_filter modifies the length of the * data, it is not possible to know the used length * without a double read of the file - to avoid that * we simple use partial length packets. */ if (ptmode == 't' || ptmode == 'u' || ptmode == 'm') filesize = 0; } else filesize = opt.set_filesize? opt.set_filesize : 0; /* stdin */ if (!opt.no_literal) { PACKET pkt; /* Note that PT has been initialized above in no_literal mode. */ pt->timestamp = make_timestamp (); pt->mode = ptmode; pt->len = filesize; pt->new_ctb = !pt->len; pt->buf = inp; init_packet (&pkt); pkt.pkttype = PKT_PLAINTEXT; pkt.pkt.plaintext = pt; /*cfx.datalen = filesize? calc_packet_length( &pkt ) : 0;*/ if ((rc = build_packet (out, &pkt))) log_error ("build_packet(PLAINTEXT) failed: %s\n", gpg_strerror (rc) ); *r_extrahash = xtrymalloc (sizeof **r_extrahash + pt->namelen); if (!*r_extrahash) rc = gpg_error_from_syserror (); else { (*r_extrahash)->mode = pt->mode; (*r_extrahash)->timestamp = pt->timestamp; (*r_extrahash)->namelen = pt->namelen; /* Note that the last byte of NAME won't be initialized * because we don't need it. */ memcpy ((*r_extrahash)->name, pt->name, pt->namelen); } pt->buf = NULL; free_packet (&pkt, NULL); } else { byte copy_buffer[4096]; int bytes_copied; *r_extrahash = xtrymalloc (sizeof **r_extrahash); if (!*r_extrahash) { rc = gpg_error_from_syserror (); goto leave; } /* FIXME: We need to parse INP to get the to be hashed data from * it. */ (*r_extrahash)->mode = 0; (*r_extrahash)->timestamp = 0; (*r_extrahash)->namelen = 0; while ((bytes_copied = iobuf_read (inp, copy_buffer, 4096)) != -1) if ((rc = iobuf_write (out, copy_buffer, bytes_copied))) { log_error ("copying input to output failed: %s\n", gpg_strerror (rc)); break; } wipememory (copy_buffer, 4096); /* burn buffer */ } leave: return rc; } /* * Write the signatures from the SK_LIST to OUT. HASH must be a * non-finalized hash which will not be changes here. EXTRAHASH is * either NULL or the extra data tro be hashed into v5 signatures. */ static int write_signature_packets (ctrl_t ctrl, SK_LIST sk_list, IOBUF out, gcry_md_hd_t hash, pt_extra_hash_data_t extrahash, int sigclass, u32 timestamp, u32 duration, int status_letter, const char *cache_nonce) { SK_LIST sk_rover; /* Loop over the certificates with secret keys. */ for (sk_rover = sk_list; sk_rover; sk_rover = sk_rover->next) { PKT_public_key *pk; PKT_signature *sig; gcry_md_hd_t md; gpg_error_t err; pk = sk_rover->pk; /* Build the signature packet. */ sig = xtrycalloc (1, sizeof *sig); if (!sig) return gpg_error_from_syserror (); if (pk->version >= 5) sig->version = 5; /* Required for v5 keys. */ else sig->version = 4; /* Required. */ keyid_from_pk (pk, sig->keyid); sig->digest_algo = hash_for (pk); sig->pubkey_algo = pk->pubkey_algo; if (timestamp) sig->timestamp = timestamp; else sig->timestamp = make_timestamp(); if (duration) sig->expiredate = sig->timestamp + duration; sig->sig_class = sigclass; if (gcry_md_copy (&md, hash)) BUG (); build_sig_subpkt_from_sig (sig, pk); mk_notation_policy_etc (ctrl, sig, NULL, pk); if (opt.flags.include_key_block && IS_SIG (sig)) err = mk_sig_subpkt_key_block (ctrl, sig, pk); else err = 0; hash_sigversion_to_magic (md, sig, extrahash); gcry_md_final (md); if (!err) err = do_sign (ctrl, pk, sig, md, hash_for (pk), cache_nonce, 0); gcry_md_close (md); if (!err) { /* Write the packet. */ PACKET pkt; init_packet (&pkt); pkt.pkttype = PKT_SIGNATURE; pkt.pkt.signature = sig; err = build_packet (out, &pkt); if (!err && is_status_enabled()) print_status_sig_created (pk, sig, status_letter); free_packet (&pkt, NULL); if (err) log_error ("build signature packet failed: %s\n", gpg_strerror (err)); } else free_seckey_enc (sig); if (err) return err; } return 0; } /* * Sign the files whose names are in FILENAME. * If DETACHED has the value true, * make a detached signature. If FILENAMES->d is NULL read from stdin * and ignore the detached mode. Sign the file with all secret keys * which can be taken from LOCUSR, if this is NULL, use the default one * If ENCRYPTFLAG is true, use REMUSER (or ask if it is NULL) to encrypt the * signed data for these users. * If OUTFILE is not NULL; this file is used for output and the function * does not ask for overwrite permission; output is then always * uncompressed, non-armored and in binary mode. */ int sign_file (ctrl_t ctrl, strlist_t filenames, int detached, strlist_t locusr, int encryptflag, strlist_t remusr, const char *outfile ) { const char *fname; armor_filter_context_t *afx; compress_filter_context_t zfx; md_filter_context_t mfx; text_filter_context_t tfx; progress_filter_context_t *pfx; encrypt_filter_context_t efx; iobuf_t inp = NULL; iobuf_t out = NULL; PACKET pkt; int rc = 0; PK_LIST pk_list = NULL; SK_LIST sk_list = NULL; SK_LIST sk_rover = NULL; int multifile = 0; u32 duration=0; pt_extra_hash_data_t extrahash = NULL; pfx = new_progress_context (); afx = new_armor_context (); memset (&zfx, 0, sizeof zfx); memset (&mfx, 0, sizeof mfx); memset (&efx, 0, sizeof efx); efx.ctrl = ctrl; init_packet (&pkt); if (filenames) { fname = filenames->d; multifile = !!filenames->next; } else fname = NULL; if (fname && filenames->next && (!detached || encryptflag)) log_bug ("multiple files can only be detached signed"); if (encryptflag == 2 && (rc = setup_symkey (&efx.symkey_s2k, &efx.symkey_dek))) goto leave; if (opt.ask_sig_expire && !opt.batch) duration = ask_expire_interval(1,opt.def_sig_expire); else duration = parse_expire_string(opt.def_sig_expire); /* Note: In the old non-agent version the following call used to * unprotect the secret key. This is now done on demand by the agent. */ if ((rc = build_sk_list (ctrl, locusr, &sk_list, PUBKEY_USAGE_SIG ))) goto leave; if (encryptflag && (rc = build_pk_list (ctrl, remusr, &pk_list))) goto leave; /* Prepare iobufs. */ if (multifile) /* have list of filenames */ inp = NULL; /* we do it later */ else { inp = iobuf_open(fname); if (inp && is_secured_file (iobuf_get_fd (inp))) { iobuf_close (inp); inp = NULL; gpg_err_set_errno (EPERM); } if (!inp) { rc = gpg_error_from_syserror (); log_error (_("can't open '%s': %s\n"), fname? fname: "[stdin]", strerror (errno)); goto leave; } handle_progress (pfx, inp, fname); } if (outfile) { if (is_secured_filename (outfile)) { out = NULL; gpg_err_set_errno (EPERM); } else out = iobuf_create (outfile, 0); if (!out) { rc = gpg_error_from_syserror (); log_error (_("can't create '%s': %s\n"), outfile, gpg_strerror (rc)); goto leave; } else if (opt.verbose) log_info (_("writing to '%s'\n"), outfile); } else if ((rc = open_outfile (-1, fname, opt.armor? 1 : detached? 2 : 0, 0, &out))) { goto leave; } /* Prepare to calculate the MD over the input. */ if (opt.textmode && !outfile && !multifile) { memset (&tfx, 0, sizeof tfx); iobuf_push_filter (inp, text_filter, &tfx); } if (gcry_md_open (&mfx.md, 0, 0)) BUG (); if (DBG_HASHING) gcry_md_debug (mfx.md, "sign"); /* If we're encrypting and signing, it is reasonable to pick the * hash algorithm to use out of the recipient key prefs. This is * best effort only, as in a DSA2 and smartcard world there are * cases where we cannot please everyone with a single hash (DSA2 * wants >160 and smartcards want =160). In the future this could * be more complex with different hashes for each sk, but the * current design requires a single hash for all SKs. */ if (pk_list) { if (opt.def_digest_algo) { if (!opt.expert && select_algo_from_prefs (pk_list,PREFTYPE_HASH, opt.def_digest_algo, NULL) != opt.def_digest_algo) { log_info (_("WARNING: forcing digest algorithm %s (%d)" " violates recipient preferences\n"), gcry_md_algo_name (opt.def_digest_algo), opt.def_digest_algo); } } else { int algo; int smartcard=0; union pref_hint hint; hint.digest_length = 0; /* Of course, if the recipient asks for something * unreasonable (like the wrong hash for a DSA key) then * don't do it. Check all sk's - if any are DSA or live * on a smartcard, then the hash has restrictions and we * may not be able to give the recipient what they want. * For DSA, pass a hint for the largest q we have. Note * that this means that a q>160 key will override a q=160 * key and force the use of truncation for the q=160 key. * The alternative would be to ignore the recipient prefs * completely and get a different hash for each DSA key in * hash_for(). The override behavior here is more or less * reasonable as it is under the control of the user which * keys they sign with for a given message and the fact * that the message with multiple signatures won't be * usable on an implementation that doesn't understand * DSA2 anyway. */ for (sk_rover = sk_list; sk_rover; sk_rover = sk_rover->next ) { if (sk_rover->pk->pubkey_algo == PUBKEY_ALGO_DSA || sk_rover->pk->pubkey_algo == PUBKEY_ALGO_ECDSA) { int temp_hashlen = gcry_mpi_get_nbits (sk_rover->pk->pkey[1]); if (sk_rover->pk->pubkey_algo == PUBKEY_ALGO_ECDSA) temp_hashlen = ecdsa_qbits_from_Q (temp_hashlen); temp_hashlen = (temp_hashlen+7)/8; /* Pick a hash that is large enough for our largest Q */ if (hint.digest_length < temp_hashlen) hint.digest_length = temp_hashlen; } /* FIXME: need to check gpg-agent for this. */ /* else if (sk_rover->pk->is_protected */ /* && sk_rover->pk->protect.s2k.mode == 1002) */ /* smartcard = 1; */ } /* Current smartcards only do 160-bit hashes. If we have * to have a >160-bit hash, then we can't use the * recipient prefs as we'd need both =160 and >160 at the * same time and recipient prefs currently require a * single hash for all signatures. All this may well have * to change as the cards add algorithms. */ if ((!smartcard || (smartcard && hint.digest_length==20)) && ((algo = select_algo_from_prefs (pk_list, PREFTYPE_HASH, -1, &hint)) > 0)) { recipient_digest_algo = algo; } } } for (sk_rover = sk_list; sk_rover; sk_rover = sk_rover->next) gcry_md_enable (mfx.md, hash_for (sk_rover->pk)); if (!multifile) iobuf_push_filter (inp, md_filter, &mfx); if (detached && !encryptflag) afx->what = 2; if (opt.armor && !outfile) push_armor_filter (afx, out); if (encryptflag) { efx.pk_list = pk_list; /* fixme: set efx.cfx.datalen if known */ iobuf_push_filter (out, encrypt_filter, &efx); } if (opt.compress_algo && !outfile && !detached) { int compr_algo = opt.compress_algo; /* If not forced by user */ if (compr_algo==-1) { /* If we're not encrypting, then select_algo_from_prefs * will fail and we'll end up with the default. If we are * encrypting, select_algo_from_prefs cannot fail since * there is an assumed preference for uncompressed data. * Still, if it did fail, we'll also end up with the * default. */ if ((compr_algo = select_algo_from_prefs (pk_list, PREFTYPE_ZIP, -1, NULL)) == -1) { compr_algo = default_compress_algo(); } } else if (!opt.expert && pk_list && select_algo_from_prefs (pk_list, PREFTYPE_ZIP, compr_algo, NULL) != compr_algo) { log_info (_("WARNING: forcing compression algorithm %s (%d)" " violates recipient preferences\n"), compress_algo_to_string (compr_algo), compr_algo); } /* Algo 0 means no compression. */ if (compr_algo) push_compress_filter (out, &zfx, compr_algo); } /* Write the one-pass signature packets if needed */ if (!detached) { rc = write_onepass_sig_packets (sk_list, out, opt.textmode && !outfile ? 0x01:0x00); if (rc) goto leave; } write_status_begin_signing (mfx.md); /* Setup the inner packet. */ if (detached) { if (multifile) { strlist_t sl; if (opt.verbose) log_info (_("signing:") ); /* Must walk reverse trough this list. */ for (sl = strlist_last(filenames); sl; sl = strlist_prev( filenames, sl)) { inp = iobuf_open (sl->d); if (inp && is_secured_file (iobuf_get_fd (inp))) { iobuf_close (inp); inp = NULL; gpg_err_set_errno (EPERM); } if (!inp) { rc = gpg_error_from_syserror (); log_error (_("can't open '%s': %s\n"), sl->d, gpg_strerror (rc)); goto leave; } handle_progress (pfx, inp, sl->d); if (opt.verbose) log_printf (" '%s'", sl->d ); if (opt.textmode) { memset (&tfx, 0, sizeof tfx); iobuf_push_filter (inp, text_filter, &tfx); } iobuf_push_filter (inp, md_filter, &mfx); while (iobuf_get (inp) != -1) ; iobuf_close (inp); inp = NULL; } if (opt.verbose) log_printf ("\n"); } else { /* Read, so that the filter can calculate the digest. */ while (iobuf_get(inp) != -1) ; } } else { rc = write_plaintext_packet (out, inp, fname, (opt.textmode && !outfile) ? (opt.mimemode? 'm' : 't') : 'b', &extrahash); } /* Catch errors from above. */ if (rc) goto leave; /* Write the signatures. */ rc = write_signature_packets (ctrl, sk_list, out, mfx.md, extrahash, opt.textmode && !outfile? 0x01 : 0x00, 0, duration, detached ? 'D':'S', NULL); if (rc) goto leave; leave: if (rc) iobuf_cancel (out); else { iobuf_close (out); if (encryptflag) write_status (STATUS_END_ENCRYPTION); } iobuf_close (inp); gcry_md_close (mfx.md); release_sk_list (sk_list); release_pk_list (pk_list); recipient_digest_algo = 0; release_progress_context (pfx); release_armor_context (afx); xfree (extrahash); return rc; } /* * Make a clear signature. Note that opt.armor is not needed. */ int clearsign_file (ctrl_t ctrl, const char *fname, strlist_t locusr, const char *outfile) { armor_filter_context_t *afx; progress_filter_context_t *pfx; gcry_md_hd_t textmd = NULL; iobuf_t inp = NULL; iobuf_t out = NULL; PACKET pkt; int rc = 0; SK_LIST sk_list = NULL; SK_LIST sk_rover = NULL; u32 duration = 0; pfx = new_progress_context (); afx = new_armor_context (); init_packet( &pkt ); if (opt.ask_sig_expire && !opt.batch) duration = ask_expire_interval (1, opt.def_sig_expire); else duration = parse_expire_string (opt.def_sig_expire); /* Note: In the old non-agent version the following call used to * unprotect the secret key. This is now done on demand by the agent. */ if ((rc=build_sk_list (ctrl, locusr, &sk_list, PUBKEY_USAGE_SIG))) goto leave; /* Prepare iobufs. */ inp = iobuf_open (fname); if (inp && is_secured_file (iobuf_get_fd (inp))) { iobuf_close (inp); inp = NULL; gpg_err_set_errno (EPERM); } if (!inp) { rc = gpg_error_from_syserror (); log_error (_("can't open '%s': %s\n"), fname? fname: "[stdin]", gpg_strerror (rc)); goto leave; } handle_progress (pfx, inp, fname); if (outfile) { if (is_secured_filename (outfile)) { outfile = NULL; gpg_err_set_errno (EPERM); } else out = iobuf_create (outfile, 0); if (!out) { rc = gpg_error_from_syserror (); log_error (_("can't create '%s': %s\n"), outfile, gpg_strerror (rc)); goto leave; } else if (opt.verbose) log_info (_("writing to '%s'\n"), outfile); } else if ((rc = open_outfile (-1, fname, 1, 0, &out))) { goto leave; } iobuf_writestr (out, "-----BEGIN PGP SIGNED MESSAGE-----" LF); { const char *s; int any = 0; byte hashs_seen[256]; memset (hashs_seen, 0, sizeof hashs_seen); iobuf_writestr (out, "Hash: " ); for (sk_rover = sk_list; sk_rover; sk_rover = sk_rover->next) { int i = hash_for (sk_rover->pk); if (!hashs_seen[ i & 0xff ]) { s = gcry_md_algo_name (i); if (s) { hashs_seen[ i & 0xff ] = 1; if (any) iobuf_put (out, ','); iobuf_writestr (out, s); any = 1; } } } log_assert (any); iobuf_writestr (out, LF); } if (opt.not_dash_escaped) iobuf_writestr (out, "NotDashEscaped: You need "GPG_NAME " to verify this message" LF); iobuf_writestr (out, LF ); if (gcry_md_open (&textmd, 0, 0)) BUG (); for (sk_rover = sk_list; sk_rover; sk_rover = sk_rover->next) gcry_md_enable (textmd, hash_for(sk_rover->pk)); if (DBG_HASHING) gcry_md_debug (textmd, "clearsign"); copy_clearsig_text (out, inp, textmd, !opt.not_dash_escaped, opt.escape_from); /* fixme: check for read errors */ /* Now write the armor. */ afx->what = 2; push_armor_filter (afx, out); /* Write the signatures. */ rc = write_signature_packets (ctrl, sk_list, out, textmd, NULL, 0x01, 0, duration, 'C', NULL); if (rc) goto leave; leave: if (rc) iobuf_cancel (out); else iobuf_close (out); iobuf_close (inp); gcry_md_close (textmd); release_sk_list (sk_list); release_progress_context (pfx); release_armor_context (afx); return rc; } /* * Sign and conventionally encrypt the given file. * FIXME: Far too much code is duplicated - revamp the whole file. */ int sign_symencrypt_file (ctrl_t ctrl, const char *fname, strlist_t locusr) { armor_filter_context_t *afx; progress_filter_context_t *pfx; compress_filter_context_t zfx; md_filter_context_t mfx; text_filter_context_t tfx; cipher_filter_context_t cfx; iobuf_t inp = NULL; iobuf_t out = NULL; PACKET pkt; STRING2KEY *s2k = NULL; int rc = 0; SK_LIST sk_list = NULL; SK_LIST sk_rover = NULL; int algo; u32 duration = 0; int canceled; pt_extra_hash_data_t extrahash = NULL; pfx = new_progress_context (); afx = new_armor_context (); memset (&zfx, 0, sizeof zfx); memset (&mfx, 0, sizeof mfx); memset (&tfx, 0, sizeof tfx); memset (&cfx, 0, sizeof cfx); init_packet (&pkt); if (opt.ask_sig_expire && !opt.batch) duration = ask_expire_interval (1, opt.def_sig_expire); else duration = parse_expire_string (opt.def_sig_expire); /* Note: In the old non-agent version the following call used to * unprotect the secret key. This is now done on demand by the agent. */ rc = build_sk_list (ctrl, locusr, &sk_list, PUBKEY_USAGE_SIG); if (rc) goto leave; /* Prepare iobufs. */ inp = iobuf_open (fname); if (inp && is_secured_file (iobuf_get_fd (inp))) { iobuf_close (inp); inp = NULL; gpg_err_set_errno (EPERM); } if (!inp) { rc = gpg_error_from_syserror (); log_error (_("can't open '%s': %s\n"), fname? fname: "[stdin]", gpg_strerror (rc)); goto leave; } handle_progress (pfx, inp, fname); /* Prepare key. */ s2k = xmalloc_clear (sizeof *s2k); s2k->mode = opt.s2k_mode; s2k->hash_algo = S2K_DIGEST_ALGO; algo = default_cipher_algo (); cfx.dek = passphrase_to_dek (algo, s2k, 1, 1, NULL, &canceled); if (!cfx.dek || !cfx.dek->keylen) { rc = gpg_error (canceled?GPG_ERR_CANCELED:GPG_ERR_BAD_PASSPHRASE); log_error (_("error creating passphrase: %s\n"), gpg_strerror (rc)); goto leave; } cfx.dek->use_aead = use_aead (NULL, cfx.dek->algo); if (!cfx.dek->use_aead) cfx.dek->use_mdc = !!use_mdc (NULL, cfx.dek->algo); if (!opt.quiet || !opt.batch) log_info (_("%s.%s encryption will be used\n"), openpgp_cipher_algo_name (algo), cfx.dek->use_aead? openpgp_aead_algo_name (cfx.dek->use_aead) /**/ : "CFB"); /* Now create the outfile. */ rc = open_outfile (-1, fname, opt.armor? 1:0, 0, &out); if (rc) goto leave; /* Prepare to calculate the MD over the input. */ if (opt.textmode) iobuf_push_filter (inp, text_filter, &tfx); if (gcry_md_open (&mfx.md, 0, 0)) BUG (); if (DBG_HASHING) gcry_md_debug (mfx.md, "symc-sign"); for (sk_rover = sk_list; sk_rover; sk_rover = sk_rover->next) gcry_md_enable (mfx.md, hash_for (sk_rover->pk)); iobuf_push_filter (inp, md_filter, &mfx); /* Push armor output filter */ if (opt.armor) push_armor_filter (afx, out); /* Write the symmetric key packet */ /* (current filters: armor)*/ { PKT_symkey_enc *enc = xmalloc_clear( sizeof *enc ); enc->version = 4; enc->cipher_algo = cfx.dek->algo; enc->s2k = *s2k; pkt.pkttype = PKT_SYMKEY_ENC; pkt.pkt.symkey_enc = enc; if ((rc = build_packet (out, &pkt))) log_error ("build symkey packet failed: %s\n", gpg_strerror (rc)); xfree (enc); } /* Push the encryption filter */ iobuf_push_filter (out, cfx.dek->use_aead? cipher_filter_aead /**/ : cipher_filter_cfb, &cfx); /* Push the compress filter */ if (default_compress_algo()) { if (cfx.dek && (cfx.dek->use_mdc || cfx.dek->use_aead)) zfx.new_ctb = 1; push_compress_filter (out, &zfx,default_compress_algo() ); } /* Write the one-pass signature packets */ /* (current filters: zip - encrypt - armor) */ rc = write_onepass_sig_packets (sk_list, out, opt.textmode? 0x01:0x00); if (rc) goto leave; write_status_begin_signing (mfx.md); /* Pipe data through all filters; i.e. write the signed stuff. */ /* (current filters: zip - encrypt - armor) */ rc = write_plaintext_packet (out, inp, fname, opt.textmode ? (opt.mimemode?'m':'t'):'b', &extrahash); if (rc) goto leave; /* Write the signatures. */ /* (current filters: zip - encrypt - armor) */ rc = write_signature_packets (ctrl, sk_list, out, mfx.md, extrahash, opt.textmode? 0x01 : 0x00, 0, duration, 'S', NULL); if (rc) goto leave; leave: if (rc) iobuf_cancel (out); else { iobuf_close (out); write_status (STATUS_END_ENCRYPTION); } iobuf_close (inp); release_sk_list (sk_list); gcry_md_close (mfx.md); xfree (cfx.dek); xfree (s2k); release_progress_context (pfx); release_armor_context (afx); xfree (extrahash); return rc; } /* * Create a v4 signature in *RET_SIG. * * PK is the primary key to sign (required for all sigs) * UID is the user id to sign (required for 0x10..0x13, 0x30) * SUBPK is subkey to sign (required for 0x18, 0x19, 0x28) * * PKSK is the signing key * * SIGCLASS is the type of signature to create. * * DIGEST_ALGO is the digest algorithm. If it is 0 the function * selects an appropriate one. * * TIMESTAMP is the timestamp to use for the signature. 0 means "now" * * DURATION is the amount of time (in seconds) until the signature * expires. * * This function creates the following subpackets: issuer, created, * and expire (if duration is not 0). Additional subpackets can be * added using MKSUBPKT, which is called after these subpackets are * added and before the signature is generated. OPAQUE is passed to * MKSUBPKT. */ int make_keysig_packet (ctrl_t ctrl, PKT_signature **ret_sig, PKT_public_key *pk, PKT_user_id *uid, PKT_public_key *subpk, PKT_public_key *pksk, int sigclass, u32 timestamp, u32 duration, int (*mksubpkt)(PKT_signature *, void *), void *opaque, const char *cache_nonce) { PKT_signature *sig; int rc = 0; int sigversion; int digest_algo; gcry_md_hd_t md; u32 pk_keyid[2], pksk_keyid[2]; unsigned int signhints; log_assert ((sigclass >= 0x10 && sigclass <= 0x13) || sigclass == 0x1F || sigclass == 0x20 || sigclass == 0x18 || sigclass == 0x19 || sigclass == 0x30 || sigclass == 0x28 ); if (pksk->version >= 5) sigversion = 5; else sigversion = 4; /* Select the digest algo to use. */ if (opt.cert_digest_algo) /* Forceful override by the user. */ digest_algo = opt.cert_digest_algo; else if (pksk->pubkey_algo == PUBKEY_ALGO_DSA) /* Meet DSA requirements. */ digest_algo = match_dsa_hash (gcry_mpi_get_nbits (pksk->pkey[1])/8); else if (pksk->pubkey_algo == PUBKEY_ALGO_ECDSA /* Meet ECDSA requirements. */ || pksk->pubkey_algo == PUBKEY_ALGO_EDDSA) { 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 /* Use the default. */ digest_algo = DEFAULT_DIGEST_ALGO; signhints = SIGNHINT_KEYSIG; keyid_from_pk (pk, pk_keyid); keyid_from_pk (pksk, pksk_keyid); if (pk_keyid[0] == pksk_keyid[0] && pk_keyid[1] == pksk_keyid[1]) signhints |= SIGNHINT_SELFSIG; if (gcry_md_open (&md, digest_algo, 0)) BUG (); /* Hash the public key certificate. */ hash_public_key (md, pk); if (sigclass == 0x18 || sigclass == 0x19 || sigclass == 0x28) { /* Hash the subkey binding/backsig/revocation. */ hash_public_key (md, subpk); } else if (sigclass != 0x1F && sigclass != 0x20) { /* Hash the user id. */ hash_uid (md, sigversion, uid); } /* Make the signature packet. */ sig = xmalloc_clear (sizeof *sig); sig->version = sigversion; sig->flags.exportable = 1; sig->flags.revocable = 1; keyid_from_pk (pksk, sig->keyid); sig->pubkey_algo = pksk->pubkey_algo; sig->digest_algo = digest_algo; sig->timestamp = timestamp? timestamp : make_timestamp (); if (duration) sig->expiredate = sig->timestamp + duration; sig->sig_class = sigclass; build_sig_subpkt_from_sig (sig, pksk); mk_notation_policy_etc (ctrl, sig, pk, pksk); /* Crucial that the call to mksubpkt comes LAST before the calls * to finalize the sig as that makes it possible for the mksubpkt * function to get a reliable pointer to the subpacket area. */ if (mksubpkt) rc = (*mksubpkt)(sig, opaque); if (!rc) { hash_sigversion_to_magic (md, sig, NULL); gcry_md_final (md); rc = complete_sig (ctrl, sig, pksk, md, cache_nonce, signhints); } gcry_md_close (md); if (rc) free_seckey_enc (sig); else *ret_sig = sig; return rc; } /* * Create a new signature packet based on an existing one. * Only user ID signatures are supported for now. * PK is the public key to work on. * PKSK is the key used to make the signature. * * TODO: Merge this with make_keysig_packet. */ gpg_error_t update_keysig_packet (ctrl_t ctrl, PKT_signature **ret_sig, PKT_signature *orig_sig, PKT_public_key *pk, PKT_user_id *uid, PKT_public_key *subpk, PKT_public_key *pksk, int (*mksubpkt)(PKT_signature *, void *), void *opaque) { PKT_signature *sig; gpg_error_t rc = 0; int digest_algo; gcry_md_hd_t md; u32 pk_keyid[2], pksk_keyid[2]; unsigned int signhints = 0; if ((!orig_sig || !pk || !pksk) || (orig_sig->sig_class >= 0x10 && orig_sig->sig_class <= 0x13 && !uid) || (orig_sig->sig_class == 0x18 && !subpk)) return GPG_ERR_GENERAL; /* Either use the override digest algo or in the normal case the * original digest algorithm. However, iff the original digest * algorithms is SHA-1 and we are in gnupg or de-vs compliance mode * we switch to SHA-256 (done by the macro). */ if (opt.cert_digest_algo) digest_algo = opt.cert_digest_algo; else if (pksk->pubkey_algo == PUBKEY_ALGO_DSA || pksk->pubkey_algo == PUBKEY_ALGO_ECDSA || pksk->pubkey_algo == PUBKEY_ALGO_EDDSA) digest_algo = orig_sig->digest_algo; else if (orig_sig->digest_algo == DIGEST_ALGO_SHA1 || orig_sig->digest_algo == DIGEST_ALGO_RMD160) digest_algo = DEFAULT_DIGEST_ALGO; else digest_algo = orig_sig->digest_algo; signhints = SIGNHINT_KEYSIG; keyid_from_pk (pk, pk_keyid); keyid_from_pk (pksk, pksk_keyid); if (pk_keyid[0] == pksk_keyid[0] && pk_keyid[1] == pksk_keyid[1]) signhints |= SIGNHINT_SELFSIG; if (gcry_md_open (&md, digest_algo, 0)) BUG (); /* Hash the public key certificate and the user id. */ hash_public_key (md, pk); if (orig_sig->sig_class == 0x18) hash_public_key (md, subpk); else hash_uid (md, orig_sig->version, uid); /* Create a new signature packet. */ sig = copy_signature (NULL, orig_sig); sig->digest_algo = digest_algo; /* We need to create a new timestamp so that new sig expiration * calculations are done correctly... */ sig->timestamp = make_timestamp(); /* ... but we won't make a timestamp earlier than the existing * one. */ { int tmout = 0; while (sig->timestamp <= orig_sig->timestamp) { if (++tmout > 5 && !opt.ignore_time_conflict) { rc = gpg_error (GPG_ERR_TIME_CONFLICT); goto leave; } gnupg_sleep (1); sig->timestamp = make_timestamp(); } } /* Note that already expired sigs will remain expired (with a * duration of 1) since build-packet.c:build_sig_subpkt_from_sig * detects this case. */ /* Put the updated timestamp into the sig. Note that this will * automagically lower any sig expiration dates to correctly * correspond to the differences in the timestamps (i.e. the * duration will shrink). */ build_sig_subpkt_from_sig (sig, pksk); if (mksubpkt) rc = (*mksubpkt)(sig, opaque); if (!rc) { hash_sigversion_to_magic (md, sig, NULL); gcry_md_final (md); rc = complete_sig (ctrl, sig, pksk, md, NULL, signhints); } leave: gcry_md_close (md); if (rc) free_seckey_enc (sig); else *ret_sig = sig; return rc; }