diff --git a/g10/decrypt-data.c b/g10/decrypt-data.c index 89d7c9a70..f9fc1d2c7 100644 --- a/g10/decrypt-data.c +++ b/g10/decrypt-data.c @@ -1,1025 +1,1025 @@ /* decrypt-data.c - Decrypt an encrypted data packet * Copyright (C) 1998-2001, 2005-2006, 2009 Free Software Foundation, Inc. * Copyright (C) 1998-2001, 2005-2006, 2009, 2018 Werner Koch * 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 . * SPDX-License-Identifier: GPL-3.0-or-later */ #include #include #include #include #include "gpg.h" #include "../common/util.h" #include "packet.h" #include "options.h" #include "../common/i18n.h" #include "../common/status.h" #include "../common/compliance.h" static int aead_decode_filter (void *opaque, int control, iobuf_t a, byte *buf, size_t *ret_len); static int mdc_decode_filter ( void *opaque, int control, IOBUF a, byte *buf, size_t *ret_len); static int decode_filter ( void *opaque, int control, IOBUF a, byte *buf, size_t *ret_len); /* Our context object. */ struct decode_filter_context_s { /* Recounter (max value is 2). We need it because we do not know * whether the iobuf or the outer control code frees this object * first. */ int refcount; /* The cipher handle. */ gcry_cipher_hd_t cipher_hd; /* The hash handle for use in MDC mode. */ gcry_md_hd_t mdc_hash; /* The start IV for AEAD encryption. */ byte startiv[16]; /* The holdback buffer and its used length. For AEAD we need 32+1 * bytes but we use 48 byte. For MDC we need 22 bytes; here * holdbacklen will either 0 or 22. */ char holdback[48]; unsigned int holdbacklen; /* Working on a partial length packet. */ unsigned int partial : 1; /* EOF indicator with these true values: * 1 = normal EOF * 2 = premature EOF (tag or hash incomplete) * 3 = premature EOF (general) */ unsigned int eof_seen : 2; /* The actually used cipher algo for AEAD. */ byte cipher_algo; /* The AEAD algo. */ byte aead_algo; /* The encoded chunk byte for AEAD. */ byte chunkbyte; /* The decoded CHUNKBYTE. */ uint64_t chunksize; /* The chunk index for AEAD. */ uint64_t chunkindex; /* The number of bytes in the current chunk. */ uint64_t chunklen; /* The total count of decrypted plaintext octets. */ uint64_t total; /* Remaining bytes in the packet according to the packet header. * Not used if PARTIAL is true. */ size_t length; }; typedef struct decode_filter_context_s *decode_filter_ctx_t; /* Helper to release the decode context. */ static void release_dfx_context (decode_filter_ctx_t dfx) { if (!dfx) return; log_assert (dfx->refcount); if ( !--dfx->refcount ) { gcry_cipher_close (dfx->cipher_hd); dfx->cipher_hd = NULL; gcry_md_close (dfx->mdc_hash); dfx->mdc_hash = NULL; xfree (dfx); } } /* Set the nonce and the additional data for the current chunk. This * also reset the decryption machinery so that the handle can be * used for a new chunk. If FINAL is set the final AEAD chunk is * processed. */ static gpg_error_t aead_set_nonce_and_ad (decode_filter_ctx_t dfx, int final) { gpg_error_t err; unsigned char ad[21]; unsigned char nonce[16]; int i; switch (dfx->aead_algo) { case AEAD_ALGO_OCB: memcpy (nonce, dfx->startiv, 15); i = 7; break; case AEAD_ALGO_EAX: memcpy (nonce, dfx->startiv, 16); i = 8; break; default: BUG (); } nonce[i++] ^= dfx->chunkindex >> 56; nonce[i++] ^= dfx->chunkindex >> 48; nonce[i++] ^= dfx->chunkindex >> 40; nonce[i++] ^= dfx->chunkindex >> 32; nonce[i++] ^= dfx->chunkindex >> 24; nonce[i++] ^= dfx->chunkindex >> 16; nonce[i++] ^= dfx->chunkindex >> 8; nonce[i++] ^= dfx->chunkindex; if (DBG_CRYPTO) log_printhex (nonce, i, "nonce:"); err = gcry_cipher_setiv (dfx->cipher_hd, nonce, i); if (err) return err; ad[0] = (0xc0 | PKT_ENCRYPTED_AEAD); ad[1] = 1; ad[2] = dfx->cipher_algo; ad[3] = dfx->aead_algo; ad[4] = dfx->chunkbyte; ad[5] = dfx->chunkindex >> 56; ad[6] = dfx->chunkindex >> 48; ad[7] = dfx->chunkindex >> 40; ad[8] = dfx->chunkindex >> 32; ad[9] = dfx->chunkindex >> 24; ad[10]= dfx->chunkindex >> 16; ad[11]= dfx->chunkindex >> 8; ad[12]= dfx->chunkindex; if (final) { ad[13] = dfx->total >> 56; ad[14] = dfx->total >> 48; ad[15] = dfx->total >> 40; ad[16] = dfx->total >> 32; ad[17] = dfx->total >> 24; ad[18] = dfx->total >> 16; ad[19] = dfx->total >> 8; ad[20] = dfx->total; } if (DBG_CRYPTO) log_printhex (ad, final? 21 : 13, "authdata:"); return gcry_cipher_authenticate (dfx->cipher_hd, ad, final? 21 : 13); } /* Helper to check the 16 byte tag in TAGBUF. The FINAL flag is only * for debug messages. */ static gpg_error_t aead_checktag (decode_filter_ctx_t dfx, int final, const void *tagbuf) { gpg_error_t err; if (DBG_FILTER) log_printhex (tagbuf, 16, "tag:"); err = gcry_cipher_checktag (dfx->cipher_hd, tagbuf, 16); if (err) { log_error ("gcry_cipher_checktag%s failed: %s\n", final? " (final)":"", gpg_strerror (err)); return err; } if (DBG_FILTER) log_debug ("%stag is valid\n", final?"final ":""); return 0; } /**************** * Decrypt the data, specified by ED with the key DEK. On return * COMPLIANCE_ERROR is set to true iff the decryption can claim that * it was compliant in the current mode; otherwise this flag is set to * false. */ int decrypt_data (ctrl_t ctrl, void *procctx, PKT_encrypted *ed, DEK *dek, int *compliance_error) { decode_filter_ctx_t dfx; enum gcry_cipher_modes ciphermode; unsigned int startivlen; byte *p; int rc=0, c, i; byte temp[32]; unsigned blocksize; unsigned nprefix; *compliance_error = 0; dfx = xtrycalloc (1, sizeof *dfx); if (!dfx) return gpg_error_from_syserror (); dfx->refcount = 1; if ( opt.verbose && !dek->algo_info_printed ) { if (!openpgp_cipher_test_algo (dek->algo)) log_info (_("%s encrypted data\n"), - openpgp_cipher_algo_name (dek->algo)); + openpgp_cipher_algo_mode_name (dek->algo, ed->aead_algo)); else log_info (_("encrypted with unknown algorithm %d\n"), dek->algo ); dek->algo_info_printed = 1; } if (ed->aead_algo) { rc = openpgp_aead_algo_info (ed->aead_algo, &ciphermode, &startivlen); if (rc) goto leave; log_assert (startivlen <= sizeof dfx->startiv); } else ciphermode = GCRY_CIPHER_MODE_CFB; /* Check compliance. */ if (!gnupg_cipher_is_allowed (opt.compliance, 0, dek->algo, ciphermode)) { log_error (_("cipher algorithm '%s' may not be used in %s mode\n"), - openpgp_cipher_algo_name (dek->algo), + openpgp_cipher_algo_mode_name (dek->algo,ed->aead_algo), gnupg_compliance_option_string (opt.compliance)); *compliance_error = 1; if (opt.flags.require_compliance) { /* We fail early in this case because it does not make sense * to first decrypt everything. */ rc = gpg_error (GPG_ERR_CIPHER_ALGO); goto leave; } } write_status_printf (STATUS_DECRYPTION_INFO, "%d %d %d", ed->mdc_method, dek->algo, 0); if (opt.show_session_key) { char numbuf[25]; char *hexbuf; snprintf (numbuf, sizeof numbuf, "%d:", dek->algo); hexbuf = bin2hex (dek->key, dek->keylen, NULL); if (!hexbuf) { rc = gpg_error_from_syserror (); goto leave; } log_info ("session key: '%s%s'\n", numbuf, hexbuf); write_status_strings (STATUS_SESSION_KEY, numbuf, hexbuf, NULL); xfree (hexbuf); } rc = openpgp_cipher_test_algo (dek->algo); if (rc) goto leave; blocksize = openpgp_cipher_get_algo_blklen (dek->algo); if ( !blocksize || blocksize > 16 ) log_fatal ("unsupported blocksize %u\n", blocksize ); if (ed->aead_algo) { if (blocksize != 16) { rc = gpg_error (GPG_ERR_CIPHER_ALGO); goto leave; } if (ed->chunkbyte > 56) { log_error ("invalid AEAD chunkbyte %u\n", ed->chunkbyte); rc = gpg_error (GPG_ERR_INV_PACKET); goto leave; } /* Read the Start-IV. */ if (ed->len) { for (i=0; i < startivlen && ed->len; i++, ed->len--) { if ((c=iobuf_get (ed->buf)) == -1) break; dfx->startiv[i] = c; } } else { for (i=0; i < startivlen; i++ ) if ( (c=iobuf_get (ed->buf)) == -1 ) break; else dfx->startiv[i] = c; } if (i != startivlen) { log_error ("Start-IV in AEAD packet too short (%d/%u)\n", i, startivlen); rc = gpg_error (GPG_ERR_TOO_SHORT); goto leave; } dfx->cipher_algo = ed->cipher_algo; dfx->aead_algo = ed->aead_algo; dfx->chunkbyte = ed->chunkbyte; dfx->chunksize = (uint64_t)1 << (dfx->chunkbyte + 6); if (dek->algo != dfx->cipher_algo) log_info ("Note: different cipher algorithms used (%s/%s)\n", openpgp_cipher_algo_name (dek->algo), openpgp_cipher_algo_name (dfx->cipher_algo)); rc = openpgp_cipher_open (&dfx->cipher_hd, dfx->cipher_algo, ciphermode, GCRY_CIPHER_SECURE); if (rc) goto leave; /* Should never happen. */ if (DBG_CRYPTO) log_printhex (dek->key, dek->keylen, "thekey:"); rc = gcry_cipher_setkey (dfx->cipher_hd, dek->key, dek->keylen); if (gpg_err_code (rc) == GPG_ERR_WEAK_KEY) { log_info (_("WARNING: message was encrypted with" " a weak key in the symmetric cipher.\n")); rc = 0; } else if (rc) { log_error("key setup failed: %s\n", gpg_strerror (rc)); goto leave; } if (!ed->buf) { log_error(_("problem handling encrypted packet\n")); goto leave; } } else /* CFB encryption. */ { nprefix = blocksize; if ( ed->len && ed->len < (nprefix+2) ) { /* An invalid message. We can't check that during parsing * because we may not know the used cipher then. */ rc = gpg_error (GPG_ERR_INV_PACKET); goto leave; } if ( ed->mdc_method ) { if (gcry_md_open (&dfx->mdc_hash, ed->mdc_method, 0 )) BUG (); if ( DBG_HASHING ) gcry_md_debug (dfx->mdc_hash, "checkmdc"); } rc = openpgp_cipher_open (&dfx->cipher_hd, dek->algo, GCRY_CIPHER_MODE_CFB, (GCRY_CIPHER_SECURE | ((ed->mdc_method || dek->algo >= 100)? 0 : GCRY_CIPHER_ENABLE_SYNC))); if (rc) { /* We should never get an error here cause we already checked * that the algorithm is available. */ BUG(); } /* log_hexdump( "thekey", dek->key, dek->keylen );*/ rc = gcry_cipher_setkey (dfx->cipher_hd, dek->key, dek->keylen); if ( gpg_err_code (rc) == GPG_ERR_WEAK_KEY ) { log_info (_("WARNING: message was encrypted with" " a weak key in the symmetric cipher.\n")); rc = 0; } else if (rc) { log_error("key setup failed: %s\n", gpg_strerror (rc) ); goto leave; } if (!ed->buf) { log_error (_("problem handling encrypted packet\n")); rc = gpg_error (GPG_ERR_INV_PACKET); goto leave; } gcry_cipher_setiv (dfx->cipher_hd, NULL, 0); if ( ed->len ) { for (i=0; i < (nprefix+2) && ed->len; i++, ed->len-- ) { if ( (c=iobuf_get(ed->buf)) == -1 ) break; else temp[i] = c; } } else { for (i=0; i < (nprefix+2); i++ ) if ( (c=iobuf_get(ed->buf)) == -1 ) break; else temp[i] = c; } gcry_cipher_decrypt (dfx->cipher_hd, temp, nprefix+2, NULL, 0); gcry_cipher_sync (dfx->cipher_hd); p = temp; /* log_hexdump( "prefix", temp, nprefix+2 ); */ if (dek->symmetric && (p[nprefix-2] != p[nprefix] || p[nprefix-1] != p[nprefix+1]) ) { rc = gpg_error (GPG_ERR_BAD_KEY); goto leave; } if ( dfx->mdc_hash ) gcry_md_write (dfx->mdc_hash, temp, nprefix+2); } dfx->refcount++; dfx->partial = !!ed->is_partial; dfx->length = ed->len; if (ed->aead_algo) iobuf_push_filter ( ed->buf, aead_decode_filter, dfx ); else if (ed->mdc_method) iobuf_push_filter ( ed->buf, mdc_decode_filter, dfx ); else iobuf_push_filter ( ed->buf, decode_filter, dfx ); if (opt.unwrap_encryption) { char *filename = NULL; estream_t fp; rc = get_output_file ("", 0, ed->buf, &filename, &fp); if (! rc) { iobuf_t output = iobuf_esopen (fp, "w", 0); armor_filter_context_t *afx = NULL; if (opt.armor) { afx = new_armor_context (); push_armor_filter (afx, output); } iobuf_copy (output, ed->buf); if ((rc = iobuf_error (ed->buf))) log_error (_("error reading '%s': %s\n"), filename, gpg_strerror (rc)); else if ((rc = iobuf_error (output))) log_error (_("error writing '%s': %s\n"), filename, gpg_strerror (rc)); iobuf_close (output); if (afx) release_armor_context (afx); } xfree (filename); } else proc_packets (ctrl, procctx, ed->buf ); ed->buf = NULL; if (dfx->eof_seen > 1 ) rc = gpg_error (GPG_ERR_INV_PACKET); else if ( ed->mdc_method ) { /* We used to let parse-packet.c handle the MDC packet but this turned out to be a problem with compressed packets: With old style packets there is no length information available and the decompressor uses an implicit end. However we can't know this implicit end beforehand (:-) and thus may feed the decompressor with more bytes than actually needed. It would be possible to unread the extra bytes but due to our weird iobuf system any unread is non reliable due to filters already popped off. The easy and sane solution is to care about the MDC packet only here and never pass it to the packet parser. Fortunatley the OpenPGP spec requires a strict format for the MDC packet so that we know that 22 bytes are appended. */ int datalen = gcry_md_get_algo_dlen (ed->mdc_method); log_assert (dfx->cipher_hd); log_assert (dfx->mdc_hash); gcry_cipher_decrypt (dfx->cipher_hd, dfx->holdback, 22, NULL, 0); gcry_md_write (dfx->mdc_hash, dfx->holdback, 2); gcry_md_final (dfx->mdc_hash); if ( dfx->holdback[0] != '\xd3' || dfx->holdback[1] != '\x14' || datalen != 20 || memcmp (gcry_md_read (dfx->mdc_hash, 0), dfx->holdback+2, datalen)) rc = gpg_error (GPG_ERR_BAD_SIGNATURE); /* log_printhex(dfx->holdback, 22, "MDC message:"); */ /* log_printhex(gcry_md_read (dfx->mdc_hash,0), datalen, "MDC calc:"); */ } leave: release_dfx_context (dfx); return rc; } /* Fill BUFFER with up to NBYTES-OFFSET from STREAM utilizing * information from the context DFX. Returns the new offset which is * the number of bytes read plus the original offset. On EOF the * respective flag in DFX is set. */ static size_t fill_buffer (decode_filter_ctx_t dfx, iobuf_t stream, byte *buffer, size_t nbytes, size_t offset) { size_t nread = offset; size_t curr; int ret; if (dfx->partial) { while (nread < nbytes) { curr = nbytes - nread; ret = iobuf_read (stream, &buffer[nread], curr); if (ret == -1) { dfx->eof_seen = 1; /* Normal EOF. */ break; } nread += ret; } } else { while (nread < nbytes && dfx->length) { curr = nbytes - nread; if (curr > dfx->length) curr = dfx->length; ret = iobuf_read (stream, &buffer[nread], curr); if (ret == -1) { dfx->eof_seen = 3; /* Premature EOF. */ break; } nread += ret; dfx->length -= ret; } if (!dfx->length) dfx->eof_seen = 1; /* Normal EOF. */ } return nread; } /* The core of the AEAD decryption. This is the underflow function of * the aead_decode_filter. */ static gpg_error_t aead_underflow (decode_filter_ctx_t dfx, iobuf_t a, byte *buf, size_t *ret_len) { const size_t size = *ret_len; /* The allocated size of BUF. */ gpg_error_t err; size_t totallen = 0; /* The number of bytes to return on success or EOF. */ size_t off = 0; /* The offset into the buffer. */ size_t len; /* The current number of bytes in BUF+OFF. */ log_assert (size > 48); /* Our code requires at least this size. */ /* Copy the rest from the last call of this function into BUF. */ len = dfx->holdbacklen; dfx->holdbacklen = 0; memcpy (buf, dfx->holdback, len); if (DBG_FILTER) log_debug ("aead_underflow: size=%zu len=%zu%s%s\n", size, len, dfx->partial? " partial":"", dfx->eof_seen? " eof":""); /* Read and fill up BUF. We need to watch out for an EOF so that we * can detect the last chunk which is commonly shorter than the * chunksize. After the last data byte from the last chunk 32 more * bytes are expected for the last chunk's tag and the following * final chunk's tag. To detect the EOF we need to try reading at least * one further byte; however we try to read 16 extra bytes to avoid * single byte reads in some lower layers. The outcome is that we * have up to 48 extra extra octets which we will later put into the * holdback buffer for the next invocation (which handles the EOF * case). */ len = fill_buffer (dfx, a, buf, size, len); if (len < 32) { /* Not enough data for the last two tags. */ err = gpg_error (GPG_ERR_TRUNCATED); goto leave; } if (dfx->eof_seen) { /* If have seen an EOF we copy only the last two auth tags into * the holdback buffer. */ dfx->holdbacklen = 32; memcpy (dfx->holdback, buf+len-32, 32); len -= 32; } else { /* If have not seen an EOF we copy the entire extra 48 bytes * into the holdback buffer for processing at the next call of * this function. */ dfx->holdbacklen = len > 48? 48 : len; memcpy (dfx->holdback, buf+len-dfx->holdbacklen, dfx->holdbacklen); len -= dfx->holdbacklen; } /* log_printhex (dfx->holdback, dfx->holdbacklen, "holdback:"); */ /* Decrypt the buffer. This first requires a loop to handle the * case when a chunk ends within the buffer. */ if (DBG_FILTER) log_debug ("decrypt: chunklen=%ju total=%ju size=%zu len=%zu%s\n", dfx->chunklen, dfx->total, size, len, dfx->eof_seen? " eof":""); while (len && dfx->chunklen + len >= dfx->chunksize) { size_t n = dfx->chunksize - dfx->chunklen; byte tagbuf[16]; if (DBG_FILTER) log_debug ("chunksize will be reached: n=%zu\n", n); if (!dfx->chunklen) { /* First data for this chunk - prepare. */ err = aead_set_nonce_and_ad (dfx, 0); if (err) goto leave; } /* log_printhex (buf, n, "ciph:"); */ gcry_cipher_final (dfx->cipher_hd); err = gcry_cipher_decrypt (dfx->cipher_hd, buf+off, n, NULL, 0); if (err) { log_error ("gcry_cipher_decrypt failed (1): %s\n", gpg_strerror (err)); goto leave; } /* log_printhex (buf, n, "plai:"); */ totallen += n; dfx->chunklen += n; dfx->total += n; off += n; len -= n; if (DBG_FILTER) log_debug ("ndecrypted: %zu (nchunk=%ju) bytes left: %zu at off=%zu\n", totallen, dfx->chunklen, len, off); /* Check the tag. */ if (len < 16) { /* The tag is not entirely in the buffer. Read the rest of * the tag from the holdback buffer. Then shift the holdback * buffer and fill it up again. */ memcpy (tagbuf, buf+off, len); memcpy (tagbuf + len, dfx->holdback, 16 - len); dfx->holdbacklen -= 16-len; memmove (dfx->holdback, dfx->holdback + (16-len), dfx->holdbacklen); if (dfx->eof_seen) { /* We should have the last chunk's tag in TAGBUF and the * final tag in HOLDBACKBUF. */ if (len || dfx->holdbacklen != 16) { /* Not enough data for the last two tags. */ err = gpg_error (GPG_ERR_TRUNCATED); goto leave; } } else { len = 0; dfx->holdbacklen = fill_buffer (dfx, a, dfx->holdback, 48, dfx->holdbacklen); if (dfx->holdbacklen < 32) { /* Not enough data for the last two tags. */ err = gpg_error (GPG_ERR_TRUNCATED); goto leave; } } } else /* We already have the full tag. */ { memcpy (tagbuf, buf+off, 16); /* Remove that tag from the output. */ memmove (buf + off, buf + off + 16, len - 16); len -= 16; } err = aead_checktag (dfx, 0, tagbuf); if (err) goto leave; dfx->chunklen = 0; dfx->chunkindex++; continue; } /* The bulk decryption of our buffer. */ if (len) { if (!dfx->chunklen) { /* First data for this chunk - prepare. */ err = aead_set_nonce_and_ad (dfx, 0); if (err) goto leave; } if (dfx->eof_seen) { /* This is the last block of the last chunk. Its length may * not be a multiple of the block length. */ gcry_cipher_final (dfx->cipher_hd); } err = gcry_cipher_decrypt (dfx->cipher_hd, buf + off, len, NULL, 0); if (err) { log_error ("gcry_cipher_decrypt failed (2): %s\n", gpg_strerror (err)); goto leave; } totallen += len; dfx->chunklen += len; dfx->total += len; if (DBG_FILTER) log_debug ("ndecrypted: %zu (nchunk=%ju)\n", totallen, dfx->chunklen); } if (dfx->eof_seen) { if (dfx->chunklen) { if (DBG_FILTER) log_debug ("eof seen: holdback has the last and final tag\n"); log_assert (dfx->holdbacklen >= 32); err = aead_checktag (dfx, 0, dfx->holdback); if (err) goto leave; dfx->chunklen = 0; dfx->chunkindex++; off = 16; } else { if (DBG_FILTER) log_debug ("eof seen: holdback has the final tag\n"); log_assert (dfx->holdbacklen >= 16); off = 0; } /* Check the final chunk. */ err = aead_set_nonce_and_ad (dfx, 1); if (err) goto leave; gcry_cipher_final (dfx->cipher_hd); /* Decrypt an empty string (using HOLDBACK as a dummy). */ err = gcry_cipher_decrypt (dfx->cipher_hd, dfx->holdback, 0, NULL, 0); if (err) { log_error ("gcry_cipher_decrypt failed (final): %s\n", gpg_strerror (err)); goto leave; } err = aead_checktag (dfx, 1, dfx->holdback+off); if (err) goto leave; err = gpg_error (GPG_ERR_EOF); } leave: if (DBG_FILTER) log_debug ("aead_underflow: returning %zu (%s)\n", totallen, gpg_strerror (err)); /* In case of an auth error we map the error code to the same as * used by the MDC decryption. */ if (gpg_err_code (err) == GPG_ERR_CHECKSUM) err = gpg_error (GPG_ERR_BAD_SIGNATURE); /* In case of an error we better wipe out the buffer than to convey * partly decrypted data. */ if (err && gpg_err_code (err) != GPG_ERR_EOF) memset (buf, 0, size); *ret_len = totallen; return err; } /* The IOBUF filter used to decrypt AEAD encrypted data. */ static int aead_decode_filter (void *opaque, int control, IOBUF a, byte *buf, size_t *ret_len) { decode_filter_ctx_t dfx = opaque; int rc = 0; if ( control == IOBUFCTRL_UNDERFLOW && dfx->eof_seen ) { *ret_len = 0; rc = -1; } else if ( control == IOBUFCTRL_UNDERFLOW ) { log_assert (a); rc = aead_underflow (dfx, a, buf, ret_len); if (gpg_err_code (rc) == GPG_ERR_EOF) rc = -1; /* We need to use the old convention in the filter. */ } else if ( control == IOBUFCTRL_FREE ) { release_dfx_context (dfx); } else if ( control == IOBUFCTRL_DESC ) { mem2str (buf, "aead_decode_filter", *ret_len); } return rc; } static int mdc_decode_filter (void *opaque, int control, IOBUF a, byte *buf, size_t *ret_len) { decode_filter_ctx_t dfx = opaque; size_t n, size = *ret_len; int rc = 0; /* Note: We need to distinguish between a partial and a fixed length packet. The first is the usual case as created by GPG. However for short messages the format degrades to a fixed length packet and other implementations might use fixed length as well. Only looking for the EOF on fixed data works only if the encrypted packet is not followed by other data. This used to be a long standing bug which was fixed on 2009-10-02. */ if ( control == IOBUFCTRL_UNDERFLOW && dfx->eof_seen ) { *ret_len = 0; rc = -1; } else if( control == IOBUFCTRL_UNDERFLOW ) { log_assert (a); log_assert (size > 44); /* Our code requires at least this size. */ /* Get at least 22 bytes and put it ahead in the buffer. */ n = fill_buffer (dfx, a, buf, 44, 22); if (n == 44) { /* We have enough stuff - flush the deferred stuff. */ if ( !dfx->holdbacklen ) /* First time. */ { memcpy (buf, buf+22, 22); n = 22; } else { memcpy (buf, dfx->holdback, 22); } /* Fill up the buffer. */ n = fill_buffer (dfx, a, buf, size, n); /* Move the trailing 22 bytes back to the holdback buffer. We have at least 44 bytes thus a memmove is not needed. */ n -= 22; memcpy (dfx->holdback, buf+n, 22 ); dfx->holdbacklen = 22; } else if ( !dfx->holdbacklen ) /* EOF seen but empty holdback buffer. */ { /* This is bad because it means an incomplete hash. */ n -= 22; memcpy (buf, buf+22, n ); dfx->eof_seen = 2; /* EOF with incomplete hash. */ } else /* EOF seen (i.e. read less than 22 bytes). */ { memcpy (buf, dfx->holdback, 22 ); n -= 22; memcpy (dfx->holdback, buf+n, 22 ); dfx->eof_seen = 1; /* Normal EOF. */ } if ( n ) { if ( dfx->cipher_hd ) gcry_cipher_decrypt (dfx->cipher_hd, buf, n, NULL, 0); if ( dfx->mdc_hash ) gcry_md_write (dfx->mdc_hash, buf, n); } else { log_assert ( dfx->eof_seen ); rc = -1; /* Return EOF. */ } *ret_len = n; } else if ( control == IOBUFCTRL_FREE ) { release_dfx_context (dfx); } else if ( control == IOBUFCTRL_DESC ) { mem2str (buf, "mdc_decode_filter", *ret_len); } return rc; } static int decode_filter( void *opaque, int control, IOBUF a, byte *buf, size_t *ret_len) { decode_filter_ctx_t fc = opaque; size_t size = *ret_len; size_t n; int rc = 0; if ( control == IOBUFCTRL_UNDERFLOW && fc->eof_seen ) { *ret_len = 0; rc = -1; } else if ( control == IOBUFCTRL_UNDERFLOW ) { log_assert (a); n = fill_buffer (fc, a, buf, size, 0); if (n) { if (fc->cipher_hd) gcry_cipher_decrypt (fc->cipher_hd, buf, n, NULL, 0); } else { if (!fc->eof_seen) fc->eof_seen = 1; rc = -1; /* Return EOF. */ } *ret_len = n; } else if ( control == IOBUFCTRL_FREE ) { release_dfx_context (fc); } else if ( control == IOBUFCTRL_DESC ) { mem2str (buf, "decode_filter", *ret_len); } return rc; } diff --git a/g10/main.h b/g10/main.h index 68360e218..273ddaaaf 100644 --- a/g10/main.h +++ b/g10/main.h @@ -1,516 +1,518 @@ /* main.h * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, * 2008, 2009, 2010 Free Software Foundation, Inc. * * This file is part of GnuPG. * * GnuPG is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * GnuPG is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . */ #ifndef G10_MAIN_H #define G10_MAIN_H #include "../common/types.h" #include "../common/iobuf.h" #include "../common/util.h" #include "keydb.h" #include "keyedit.h" /* It could be argued that the default cipher should be 3DES rather than AES128, and the default compression should be 0 (i.e. uncompressed) rather than 1 (zip). However, the real world issues of speed and size come into play here. */ #if GPG_USE_AES128 # define DEFAULT_CIPHER_ALGO CIPHER_ALGO_AES #elif GPG_USE_CAST5 # define DEFAULT_CIPHER_ALGO CIPHER_ALGO_CAST5 #else # define DEFAULT_CIPHER_ALGO CIPHER_ALGO_3DES #endif #define DEFAULT_DIGEST_ALGO ((GNUPG)? DIGEST_ALGO_SHA256:DIGEST_ALGO_SHA1) #define DEFAULT_S2K_DIGEST_ALGO DIGEST_ALGO_SHA1 #ifdef HAVE_ZIP # define DEFAULT_COMPRESS_ALGO COMPRESS_ALGO_ZIP #else # define DEFAULT_COMPRESS_ALGO COMPRESS_ALGO_NONE #endif #define S2K_DIGEST_ALGO (opt.s2k_digest_algo?opt.s2k_digest_algo:DEFAULT_S2K_DIGEST_ALGO) /* Various data objects. */ typedef struct { ctrl_t ctrl; int header_okay; PK_LIST pk_list; DEK *symkey_dek; STRING2KEY *symkey_s2k; cipher_filter_context_t cfx; } encrypt_filter_context_t; struct groupitem { char *name; strlist_t values; struct groupitem *next; }; struct weakhash { enum gcry_md_algos algo; int rejection_shown; struct weakhash *next; }; /*-- gpg.c --*/ extern int g10_errors_seen; #if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 5 ) void g10_exit(int rc) __attribute__ ((noreturn)); #else void g10_exit(int rc); #endif void print_pubkey_algo_note (pubkey_algo_t algo); void print_cipher_algo_note (cipher_algo_t algo); void print_digest_algo_note (digest_algo_t algo); void print_digest_rejected_note (enum gcry_md_algos algo); void print_sha1_keysig_rejected_note (void); void print_reported_error (gpg_error_t err, gpg_err_code_t skip_if_ec); void print_further_info (const char *format, ...) GPGRT_ATTR_PRINTF(1,2); void additional_weak_digest (const char* digestname); int is_weak_digest (digest_algo_t algo); /*-- armor.c --*/ char *make_radix64_string( const byte *data, size_t len ); /*-- misc.c --*/ void trap_unaligned(void); void register_secured_file (const char *fname); void unregister_secured_file (const char *fname); int is_secured_file (int fd); int is_secured_filename (const char *fname); u16 checksum_u16( unsigned n ); u16 checksum( byte *p, unsigned n ); u16 checksum_mpi( gcry_mpi_t a ); u32 buffer_to_u32( const byte *buffer ); const byte *get_session_marker( size_t *rlen ); enum gcry_cipher_algos map_cipher_openpgp_to_gcry (cipher_algo_t algo); #define openpgp_cipher_open(_a,_b,_c,_d) \ gcry_cipher_open((_a),map_cipher_openpgp_to_gcry((_b)),(_c),(_d)) #define openpgp_cipher_get_algo_keylen(_a) \ gcry_cipher_get_algo_keylen(map_cipher_openpgp_to_gcry((_a))) #define openpgp_cipher_get_algo_blklen(_a) \ gcry_cipher_get_algo_blklen(map_cipher_openpgp_to_gcry((_a))) int openpgp_cipher_blocklen (cipher_algo_t algo); int openpgp_cipher_test_algo(cipher_algo_t algo); const char *openpgp_cipher_algo_name (cipher_algo_t algo); +const char *openpgp_cipher_algo_mode_name (cipher_algo_t algo, + aead_algo_t aead); gpg_error_t openpgp_aead_test_algo (aead_algo_t algo); const char *openpgp_aead_algo_name (aead_algo_t algo); gpg_error_t openpgp_aead_algo_info (aead_algo_t algo, enum gcry_cipher_modes *r_mode, unsigned int *r_noncelen); pubkey_algo_t map_pk_gcry_to_openpgp (enum gcry_pk_algos algo); int openpgp_pk_test_algo (pubkey_algo_t algo); int openpgp_pk_test_algo2 (pubkey_algo_t algo, unsigned int use); int openpgp_pk_algo_usage ( int algo ); const char *openpgp_pk_algo_name (pubkey_algo_t algo); enum gcry_md_algos map_md_openpgp_to_gcry (digest_algo_t algo); int openpgp_md_test_algo (digest_algo_t algo); const char *openpgp_md_algo_name (int algo); struct expando_args { PKT_public_key *pk; PKT_public_key *pksk; byte imagetype; int validity_info; const char *validity_string; const byte *namehash; }; char *pct_expando(const char *string,struct expando_args *args); void deprecated_warning(const char *configname,unsigned int configlineno, const char *option,const char *repl1,const char *repl2); void deprecated_command (const char *name); void obsolete_scdaemon_option (const char *configname, unsigned int configlineno, const char *name); int string_to_cipher_algo (const char *string); int string_to_digest_algo (const char *string); const char *compress_algo_to_string(int algo); int string_to_compress_algo(const char *string); int check_compress_algo(int algo); int default_cipher_algo(void); int default_compress_algo(void); void compliance_failure(void); struct parse_options { char *name; unsigned int bit; char **value; char *help; }; char *optsep(char **stringp); char *argsplit(char *string); int parse_options(char *str,unsigned int *options, struct parse_options *opts,int noisy); const char *get_libexecdir (void); int path_access(const char *file,int mode); int pubkey_get_npkey (pubkey_algo_t algo); int pubkey_get_nskey (pubkey_algo_t algo); int pubkey_get_nsig (pubkey_algo_t algo); int pubkey_get_nenc (pubkey_algo_t algo); /* Temporary helpers. */ unsigned int pubkey_nbits( int algo, gcry_mpi_t *pkey ); int mpi_print (estream_t stream, gcry_mpi_t a, int mode); unsigned int ecdsa_qbits_from_Q (unsigned int qbits); /*-- cpr.c --*/ void set_status_fd ( int fd ); int is_status_enabled ( void ); void write_status ( int no ); void write_status_error (const char *where, gpg_error_t err); void write_status_errcode (const char *where, int errcode); void write_status_failure (const char *where, gpg_error_t err); void write_status_text ( int no, const char *text ); void write_status_printf (int no, const char *format, ...) GPGRT_ATTR_PRINTF(2,3); void write_status_strings (int no, const char *text, ...) GPGRT_ATTR_SENTINEL(0); void write_status_buffer ( int no, const char *buffer, size_t len, int wrap ); void write_status_text_and_buffer ( int no, const char *text, const char *buffer, size_t len, int wrap ); void write_status_begin_signing (gcry_md_hd_t md); int cpr_enabled(void); char *cpr_get( const char *keyword, const char *prompt ); char *cpr_get_no_help( const char *keyword, const char *prompt ); char *cpr_get_utf8( const char *keyword, const char *prompt ); char *cpr_get_hidden( const char *keyword, const char *prompt ); void cpr_kill_prompt(void); int cpr_get_answer_is_yes_def (const char *keyword, const char *prompt, int def_yes); int cpr_get_answer_is_yes( const char *keyword, const char *prompt ); int cpr_get_answer_yes_no_quit( const char *keyword, const char *prompt ); int cpr_get_answer_okay_cancel (const char *keyword, const char *prompt, int def_answer); /*-- helptext.c --*/ void display_online_help( const char *keyword ); /*-- encode.c --*/ gpg_error_t setup_symkey (STRING2KEY **symkey_s2k,DEK **symkey_dek); void encrypt_seskey (DEK *dek, DEK **seskey, byte *enckey); int use_mdc (pk_list_t pk_list,int algo); int encrypt_symmetric (const char *filename ); int encrypt_store (const char *filename ); int encrypt_crypt (ctrl_t ctrl, int filefd, const char *filename, strlist_t remusr, int use_symkey, pk_list_t provided_keys, int outputfd); void encrypt_crypt_files (ctrl_t ctrl, int nfiles, char **files, strlist_t remusr); int encrypt_filter (void *opaque, int control, iobuf_t a, byte *buf, size_t *ret_len); int write_pubkey_enc (ctrl_t ctrl, PKT_public_key *pk, int throw_keyid, DEK *dek, iobuf_t out); /*-- sign.c --*/ int sign_file (ctrl_t ctrl, strlist_t filenames, int detached, strlist_t locusr, int do_encrypt, strlist_t remusr, const char *outfile ); int clearsign_file (ctrl_t ctrl, const char *fname, strlist_t locusr, const char *outfile); int sign_symencrypt_file (ctrl_t ctrl, const char *fname, strlist_t locusr); /*-- sig-check.c --*/ void sig_check_dump_stats (void); /* SIG is a revocation signature. Check if any of PK's designated revokers generated it. If so, return 0. Note: this function (correctly) doesn't care if the designated revoker is revoked. */ int check_revocation_keys (ctrl_t ctrl, PKT_public_key *pk, PKT_signature *sig); /* Check that the backsig BACKSIG from the subkey SUB_PK to its primary key MAIN_PK is valid. */ int check_backsig(PKT_public_key *main_pk,PKT_public_key *sub_pk, PKT_signature *backsig); /* Check that the signature SIG over a key (e.g., a key binding or a key revocation) is valid. (To check signatures over data, use check_signature.) */ int check_key_signature (ctrl_t ctrl, kbnode_t root, kbnode_t sig, int *is_selfsig ); /* Like check_key_signature, but with the ability to specify some additional parameters and get back additional information. See the documentation for the implementation for details. */ int check_key_signature2 (ctrl_t ctrl, kbnode_t root, kbnode_t node, PKT_public_key *check_pk, PKT_public_key *ret_pk, int *is_selfsig, u32 *r_expiredate, int *r_expired); /* Returns whether SIGNER generated the signature SIG over the packet PACKET, which is a key, subkey or uid, and comes from the key block KB. If SIGNER is NULL, it is looked up based on the information in SIG. If not NULL, sets *IS_SELFSIG to indicate whether the signature is a self-signature and *RET_PK to a copy of the signer's key. */ gpg_error_t check_signature_over_key_or_uid (ctrl_t ctrl, PKT_public_key *signer, PKT_signature *sig, KBNODE kb, PACKET *packet, int *is_selfsig, PKT_public_key *ret_pk); /*-- delkey.c --*/ gpg_error_t delete_keys (ctrl_t ctrl, strlist_t names, int secret, int allow_both); /*-- keygen.c --*/ const char *get_default_pubkey_algo (void); u32 parse_expire_string(const char *string); u32 ask_expire_interval(int object,const char *def_expire); u32 ask_expiredate(void); unsigned int ask_key_flags (int algo, int subkey, unsigned int current); const char *ask_curve (int *algo, int *subkey_algo, const char *current); void quick_generate_keypair (ctrl_t ctrl, const char *uid, const char *algostr, const char *usagestr, const char *expirestr); void generate_keypair (ctrl_t ctrl, int full, const char *fname, const char *card_serialno, int card_backup_key); int keygen_set_std_prefs (const char *string,int personal); PKT_user_id *keygen_get_std_prefs (void); int keygen_add_key_expire( PKT_signature *sig, void *opaque ); int keygen_add_key_flags (PKT_signature *sig, void *opaque); int keygen_add_std_prefs( PKT_signature *sig, void *opaque ); int keygen_upd_std_prefs( PKT_signature *sig, void *opaque ); int keygen_add_keyserver_url(PKT_signature *sig, void *opaque); int keygen_add_notations(PKT_signature *sig,void *opaque); int keygen_add_revkey(PKT_signature *sig, void *opaque); gpg_error_t make_backsig (ctrl_t ctrl, PKT_signature *sig, PKT_public_key *pk, PKT_public_key *sub_pk, PKT_public_key *sub_psk, u32 timestamp, const char *cache_nonce); gpg_error_t generate_subkeypair (ctrl_t ctrl, kbnode_t keyblock, const char *algostr, const char *usagestr, const char *expirestr); #ifdef ENABLE_CARD_SUPPORT gpg_error_t generate_card_subkeypair (ctrl_t ctrl, kbnode_t pub_keyblock, int keyno, const char *serialno); #endif /*-- openfile.c --*/ int overwrite_filep( const char *fname ); char *make_outfile_name( const char *iname ); char *ask_outfile_name( const char *name, size_t namelen ); int open_outfile (int inp_fd, const char *iname, int mode, int restrictedperm, iobuf_t *a); char *get_matching_datafile (const char *sigfilename); iobuf_t open_sigfile (const char *sigfilename, progress_filter_context_t *pfx); void try_make_homedir( const char *fname ); char *get_openpgp_revocdir (const char *home); /*-- seskey.c --*/ void make_session_key( DEK *dek ); gcry_mpi_t encode_session_key( int openpgp_pk_algo, DEK *dek, unsigned nbits ); gcry_mpi_t encode_md_value (PKT_public_key *pk, gcry_md_hd_t md, int hash_algo ); /*-- import.c --*/ struct import_stats_s; typedef struct import_stats_s *import_stats_t; struct import_filter_s; typedef struct import_filter_s *import_filter_t; typedef gpg_error_t (*import_screener_t)(kbnode_t keyblock, void *arg); int parse_import_options(char *str,unsigned int *options,int noisy); gpg_error_t parse_and_set_import_filter (const char *string); import_filter_t save_and_clear_import_filter (void); void restore_import_filter (import_filter_t filt); gpg_error_t read_key_from_file_or_buffer (ctrl_t ctrl, const char *fname, const void *buffer, size_t buflen, kbnode_t *r_keyblock); gpg_error_t import_included_key_block (ctrl_t ctrl, kbnode_t keyblock); void import_keys (ctrl_t ctrl, char **fnames, int nnames, import_stats_t stats_hd, unsigned int options, int origin, const char *url); gpg_error_t import_keys_es_stream (ctrl_t ctrl, estream_t fp, import_stats_t stats_handle, unsigned char **fpr, size_t *fpr_len, unsigned int options, import_screener_t screener, void *screener_arg, int origin, const char *url); gpg_error_t import_old_secring (ctrl_t ctrl, const char *fname); import_stats_t import_new_stats_handle (void); void import_release_stats_handle (import_stats_t hd); void import_print_stats (import_stats_t hd); /* Communication for impex_filter_getval */ struct impex_filter_parm_s { ctrl_t ctrl; kbnode_t node; char hexfpr[2*MAX_FINGERPRINT_LEN + 1]; }; const char *impex_filter_getval (void *cookie, const char *propname); gpg_error_t transfer_secret_keys (ctrl_t ctrl, struct import_stats_s *stats, kbnode_t sec_keyblock, int batch, int force, int only_marked); int collapse_uids( KBNODE *keyblock ); int get_revocation_reason (PKT_signature *sig, char **r_reason, char **r_comment, size_t *r_commentlen); /*-- export.c --*/ struct export_stats_s; typedef struct export_stats_s *export_stats_t; export_stats_t export_new_stats (void); void export_release_stats (export_stats_t stats); void export_print_stats (export_stats_t stats); int parse_export_options(char *str,unsigned int *options,int noisy); gpg_error_t parse_and_set_export_filter (const char *string); void push_export_filters (void); void pop_export_filters (void); int exact_subkey_match_p (KEYDB_SEARCH_DESC *desc, kbnode_t node); int export_pubkeys (ctrl_t ctrl, strlist_t users, unsigned int options, export_stats_t stats); int export_seckeys (ctrl_t ctrl, strlist_t users, unsigned int options, export_stats_t stats); int export_secsubkeys (ctrl_t ctrl, strlist_t users, unsigned int options, export_stats_t stats); gpg_error_t export_pubkey_buffer (ctrl_t ctrl, const char *keyspec, unsigned int options, const void *prefix, size_t prefixlen, export_stats_t stats, kbnode_t *r_keyblock, void **r_data, size_t *r_datalen); gpg_error_t receive_seckey_from_agent (ctrl_t ctrl, gcry_cipher_hd_t cipherhd, int cleartext, char **cache_nonce_addr, const char *hexgrip, PKT_public_key *pk); gpg_error_t write_keyblock_to_output (kbnode_t keyblock, int with_armor, unsigned int options); gpg_error_t export_ssh_key (ctrl_t ctrl, const char *userid); /*-- dearmor.c --*/ int dearmor_file( const char *fname ); int enarmor_file( const char *fname ); /*-- revoke.c --*/ struct revocation_reason_info; int gen_standard_revoke (ctrl_t ctrl, PKT_public_key *psk, const char *cache_nonce); int gen_revoke (ctrl_t ctrl, const char *uname); int gen_desig_revoke (ctrl_t ctrl, const char *uname, strlist_t locusr); int revocation_reason_build_cb( PKT_signature *sig, void *opaque ); struct revocation_reason_info * ask_revocation_reason( int key_rev, int cert_rev, int hint ); struct revocation_reason_info * get_default_uid_revocation_reason (void); struct revocation_reason_info * get_default_sig_revocation_reason (void); void release_revocation_reason_info (struct revocation_reason_info *reason); /*-- keylist.c --*/ void public_key_list (ctrl_t ctrl, strlist_t list, int locate_mode, int no_local); void secret_key_list (ctrl_t ctrl, strlist_t list ); void print_subpackets_colon(PKT_signature *sig); void reorder_keyblock (KBNODE keyblock); void list_keyblock_direct (ctrl_t ctrl, kbnode_t keyblock, int secret, int has_secret, int fpr, int no_validity); int cmp_signodes (const void *av, const void *bv); void print_fingerprint (ctrl_t ctrl, estream_t fp, PKT_public_key *pk, int mode); void print_revokers (estream_t fp, PKT_public_key *pk); void show_policy_url(PKT_signature *sig,int indent,int mode); void show_keyserver_url(PKT_signature *sig,int indent,int mode); void show_notation(PKT_signature *sig,int indent,int mode,int which); void dump_attribs (const PKT_user_id *uid, PKT_public_key *pk); void set_attrib_fd(int fd); char *format_seckey_info (ctrl_t ctrl, PKT_public_key *pk); void print_seckey_info (ctrl_t ctrl, PKT_public_key *pk); void print_pubkey_info (ctrl_t ctrl, estream_t fp, PKT_public_key *pk); void print_card_key_info (estream_t fp, KBNODE keyblock); void print_key_line (ctrl_t ctrl, estream_t fp, PKT_public_key *pk, int secret); /*-- verify.c --*/ void print_file_status( int status, const char *name, int what ); int verify_signatures (ctrl_t ctrl, int nfiles, char **files ); int verify_files (ctrl_t ctrl, int nfiles, char **files ); int gpg_verify (ctrl_t ctrl, int sig_fd, int data_fd, estream_t out_fp); /*-- decrypt.c --*/ int decrypt_message (ctrl_t ctrl, const char *filename ); gpg_error_t decrypt_message_fd (ctrl_t ctrl, int input_fd, int output_fd); void decrypt_messages (ctrl_t ctrl, int nfiles, char *files[]); /*-- plaintext.c --*/ int hash_datafiles( gcry_md_hd_t md, gcry_md_hd_t md2, strlist_t files, const char *sigfilename, int textmode); int hash_datafile_by_fd ( gcry_md_hd_t md, gcry_md_hd_t md2, int data_fd, int textmode ); PKT_plaintext *setup_plaintext_name(const char *filename,IOBUF iobuf); /*-- server.c --*/ int gpg_server (ctrl_t); gpg_error_t gpg_proxy_pinentry_notify (ctrl_t ctrl, const unsigned char *line); #ifdef ENABLE_CARD_SUPPORT /*-- card-util.c --*/ void change_pin (int no, int allow_admin); void card_status (ctrl_t ctrl, estream_t fp, const char *serialno); void card_edit (ctrl_t ctrl, strlist_t commands); gpg_error_t card_generate_subkey (ctrl_t ctrl, kbnode_t pub_keyblock); int card_store_subkey (KBNODE node, int use); #endif #define S2K_DECODE_COUNT(_val) ((16ul + ((_val) & 15)) << (((_val) >> 4) + 6)) /*-- migrate.c --*/ void migrate_secring (ctrl_t ctrl); #endif /*G10_MAIN_H*/ diff --git a/g10/misc.c b/g10/misc.c index 634d30387..1d30bbc6d 100644 --- a/g10/misc.c +++ b/g10/misc.c @@ -1,1883 +1,1901 @@ /* misc.c - miscellaneous functions * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, * 2008, 2009, 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 #if defined(__linux__) && defined(__alpha__) && __GLIBC__ < 2 #include #include #endif #ifdef HAVE_SETRLIMIT #include #include #include #endif #ifdef ENABLE_SELINUX_HACKS #include #endif #ifdef HAVE_W32_SYSTEM #include #include #ifdef HAVE_WINSOCK2_H # define WIN32_LEAN_AND_MEAN 1 # include #endif #include #include #ifndef CSIDL_APPDATA #define CSIDL_APPDATA 0x001a #endif #ifndef CSIDL_LOCAL_APPDATA #define CSIDL_LOCAL_APPDATA 0x001c #endif #ifndef CSIDL_FLAG_CREATE #define CSIDL_FLAG_CREATE 0x8000 #endif #endif /*HAVE_W32_SYSTEM*/ #include "gpg.h" #ifdef HAVE_W32_SYSTEM # include "../common/status.h" #endif /*HAVE_W32_SYSTEM*/ #include "../common/util.h" #include "main.h" #include "photoid.h" #include "options.h" #include "call-agent.h" #include "../common/i18n.h" #include "../common/zb32.h" /* FIXME: Libgcrypt 1.9 will support EAX. Until we name this a * requirement we hardwire the enum used for EAX. */ #define MY_GCRY_CIPHER_MODE_EAX 14 #ifdef ENABLE_SELINUX_HACKS /* A object and a global variable to keep track of files marked as secured. */ struct secured_file_item { struct secured_file_item *next; ino_t ino; dev_t dev; }; static struct secured_file_item *secured_files; #endif /*ENABLE_SELINUX_HACKS*/ /* For the sake of SELinux we want to restrict access through gpg to certain files we keep under our own control. This function registers such a file and is_secured_file may then be used to check whether a file has ben registered as secured. */ void register_secured_file (const char *fname) { #ifdef ENABLE_SELINUX_HACKS struct stat buf; struct secured_file_item *sf; /* Note that we stop immediately if something goes wrong here. */ if (gnupg_stat (fname, &buf)) log_fatal (_("fstat of '%s' failed in %s: %s\n"), fname, "register_secured_file", strerror (errno)); /* log_debug ("registering '%s' i=%lu.%lu\n", fname, */ /* (unsigned long)buf.st_dev, (unsigned long)buf.st_ino); */ for (sf=secured_files; sf; sf = sf->next) { if (sf->ino == buf.st_ino && sf->dev == buf.st_dev) return; /* Already registered. */ } sf = xmalloc (sizeof *sf); sf->ino = buf.st_ino; sf->dev = buf.st_dev; sf->next = secured_files; secured_files = sf; #else /*!ENABLE_SELINUX_HACKS*/ (void)fname; #endif /*!ENABLE_SELINUX_HACKS*/ } /* Remove a file registered as secure. */ void unregister_secured_file (const char *fname) { #ifdef ENABLE_SELINUX_HACKS struct stat buf; struct secured_file_item *sf, *sfprev; if (gnupg_stat (fname, &buf)) { log_error (_("fstat of '%s' failed in %s: %s\n"), fname, "unregister_secured_file", strerror (errno)); return; } /* log_debug ("unregistering '%s' i=%lu.%lu\n", fname, */ /* (unsigned long)buf.st_dev, (unsigned long)buf.st_ino); */ for (sfprev=NULL,sf=secured_files; sf; sfprev=sf, sf = sf->next) { if (sf->ino == buf.st_ino && sf->dev == buf.st_dev) { if (sfprev) sfprev->next = sf->next; else secured_files = sf->next; xfree (sf); return; } } #else /*!ENABLE_SELINUX_HACKS*/ (void)fname; #endif /*!ENABLE_SELINUX_HACKS*/ } /* Return true if FD is corresponds to a secured file. Using -1 for FS is allowed and will return false. */ int is_secured_file (int fd) { #ifdef ENABLE_SELINUX_HACKS struct stat buf; struct secured_file_item *sf; if (fd == -1) return 0; /* No file descriptor so it can't be secured either. */ /* Note that we print out a error here and claim that a file is secure if something went wrong. */ if (fstat (fd, &buf)) { log_error (_("fstat(%d) failed in %s: %s\n"), fd, "is_secured_file", strerror (errno)); return 1; } /* log_debug ("is_secured_file (%d) i=%lu.%lu\n", fd, */ /* (unsigned long)buf.st_dev, (unsigned long)buf.st_ino); */ for (sf=secured_files; sf; sf = sf->next) { if (sf->ino == buf.st_ino && sf->dev == buf.st_dev) return 1; /* Yes. */ } #else /*!ENABLE_SELINUX_HACKS*/ (void)fd; #endif /*!ENABLE_SELINUX_HACKS*/ return 0; /* No. */ } /* Return true if FNAME is corresponds to a secured file. Using NULL, "" or "-" for FS is allowed and will return false. This function is used before creating a file, thus it won't fail if the file does not exist. */ int is_secured_filename (const char *fname) { #ifdef ENABLE_SELINUX_HACKS struct stat buf; struct secured_file_item *sf; if (iobuf_is_pipe_filename (fname) || !*fname) return 0; /* Note that we print out a error here and claim that a file is secure if something went wrong. */ if (gnupg_stat (fname, &buf)) { if (errno == ENOENT || errno == EPERM || errno == EACCES) return 0; log_error (_("fstat of '%s' failed in %s: %s\n"), fname, "is_secured_filename", strerror (errno)); return 1; } /* log_debug ("is_secured_filename (%s) i=%lu.%lu\n", fname, */ /* (unsigned long)buf.st_dev, (unsigned long)buf.st_ino); */ for (sf=secured_files; sf; sf = sf->next) { if (sf->ino == buf.st_ino && sf->dev == buf.st_dev) return 1; /* Yes. */ } #else /*!ENABLE_SELINUX_HACKS*/ (void)fname; #endif /*!ENABLE_SELINUX_HACKS*/ return 0; /* No. */ } u16 checksum_u16( unsigned n ) { u16 a; a = (n >> 8) & 0xff; a += n & 0xff; return a; } u16 checksum( byte *p, unsigned n ) { u16 a; for(a=0; n; n-- ) a += *p++; return a; } u16 checksum_mpi (gcry_mpi_t a) { u16 csum; byte *buffer; size_t nbytes; if ( gcry_mpi_print (GCRYMPI_FMT_PGP, NULL, 0, &nbytes, a) ) BUG (); /* Fixme: For numbers not in secure memory we should use a stack * based buffer and only allocate a larger one if mpi_print returns * an error. */ buffer = (gcry_is_secure(a)? gcry_xmalloc_secure (nbytes) : gcry_xmalloc (nbytes)); if ( gcry_mpi_print (GCRYMPI_FMT_PGP, buffer, nbytes, NULL, a) ) BUG (); csum = checksum (buffer, nbytes); xfree (buffer); return csum; } void print_pubkey_algo_note (pubkey_algo_t algo) { if(algo >= 100 && algo <= 110) { static int warn=0; if(!warn) { warn=1; es_fflush (es_stdout); log_info (_("WARNING: using experimental public key algorithm %s\n"), openpgp_pk_algo_name (algo)); } } else if (algo == PUBKEY_ALGO_ELGAMAL) { es_fflush (es_stdout); log_info (_("WARNING: Elgamal sign+encrypt keys are deprecated\n")); } } void print_cipher_algo_note (cipher_algo_t algo) { if(algo >= 100 && algo <= 110) { static int warn=0; if(!warn) { warn=1; es_fflush (es_stdout); log_info (_("WARNING: using experimental cipher algorithm %s\n"), openpgp_cipher_algo_name (algo)); } } } void print_digest_algo_note (digest_algo_t algo) { if(algo >= 100 && algo <= 110) { static int warn=0; const enum gcry_md_algos galgo = map_md_openpgp_to_gcry (algo); if(!warn) { warn=1; es_fflush (es_stdout); log_info (_("WARNING: using experimental digest algorithm %s\n"), gcry_md_algo_name (galgo)); } } else if (is_weak_digest (algo)) { const enum gcry_md_algos galgo = map_md_openpgp_to_gcry (algo); es_fflush (es_stdout); log_info (_("WARNING: digest algorithm %s is deprecated\n"), gcry_md_algo_name (galgo)); } } void print_digest_rejected_note (enum gcry_md_algos algo) { struct weakhash* weak; int show = 1; if (opt.quiet) return; for (weak = opt.weak_digests; weak; weak = weak->next) if (weak->algo == algo) { if (weak->rejection_shown) show = 0; else weak->rejection_shown = 1; break; } if (show) { es_fflush (es_stdout); log_info (_("Note: signatures using the %s algorithm are rejected\n"), gcry_md_algo_name(algo)); } } void print_sha1_keysig_rejected_note (void) { static int shown; if (shown || opt.quiet) return; shown = 1; es_fflush (es_stdout); log_info (_("Note: third-party key signatures using" " the %s algorithm are rejected\n"), gcry_md_algo_name (GCRY_MD_SHA1)); print_further_info ("use option \"%s\" to override", "--allow-weak-key-signatures"); } /* Print a message * "(reported error: %s)\n * in verbose mode to further explain an error. If the error code has * the value IGNORE_EC no message is printed. A message is also not * printed if ERR is 0. */ void print_reported_error (gpg_error_t err, gpg_err_code_t ignore_ec) { if (!opt.verbose) return; if (!gpg_err_code (err)) ; else if (gpg_err_code (err) == ignore_ec) ; else if (gpg_err_source (err) == GPG_ERR_SOURCE_DEFAULT) log_info (_("(reported error: %s)\n"), gpg_strerror (err)); else log_info (_("(reported error: %s <%s>)\n"), gpg_strerror (err), gpg_strsource (err)); } /* Print a message * "(further info: %s)\n * in verbose mode to further explain an error. That message is * intended to help debug a problem and should not be translated. */ void print_further_info (const char *format, ...) { va_list arg_ptr; if (!opt.verbose) return; log_info (_("(further info: ")); va_start (arg_ptr, format); log_logv (GPGRT_LOG_CONT, format, arg_ptr); va_end (arg_ptr); log_printf (")\n"); } /* Map OpenPGP algo numbers to those used by Libgcrypt. We need to do this for algorithms we implemented in Libgcrypt after they become part of OpenPGP. */ enum gcry_cipher_algos map_cipher_openpgp_to_gcry (cipher_algo_t algo) { switch (algo) { case CIPHER_ALGO_NONE: return GCRY_CIPHER_NONE; #ifdef GPG_USE_IDEA case CIPHER_ALGO_IDEA: return GCRY_CIPHER_IDEA; #else case CIPHER_ALGO_IDEA: return 0; #endif case CIPHER_ALGO_3DES: return GCRY_CIPHER_3DES; #ifdef GPG_USE_CAST5 case CIPHER_ALGO_CAST5: return GCRY_CIPHER_CAST5; #else case CIPHER_ALGO_CAST5: return 0; #endif #ifdef GPG_USE_BLOWFISH case CIPHER_ALGO_BLOWFISH: return GCRY_CIPHER_BLOWFISH; #else case CIPHER_ALGO_BLOWFISH: return 0; #endif #ifdef GPG_USE_AES128 case CIPHER_ALGO_AES: return GCRY_CIPHER_AES; #else case CIPHER_ALGO_AES: return 0; #endif #ifdef GPG_USE_AES192 case CIPHER_ALGO_AES192: return GCRY_CIPHER_AES192; #else case CIPHER_ALGO_AES192: return 0; #endif #ifdef GPG_USE_AES256 case CIPHER_ALGO_AES256: return GCRY_CIPHER_AES256; #else case CIPHER_ALGO_AES256: return 0; #endif #ifdef GPG_USE_TWOFISH case CIPHER_ALGO_TWOFISH: return GCRY_CIPHER_TWOFISH; #else case CIPHER_ALGO_TWOFISH: return 0; #endif #ifdef GPG_USE_CAMELLIA128 case CIPHER_ALGO_CAMELLIA128: return GCRY_CIPHER_CAMELLIA128; #else case CIPHER_ALGO_CAMELLIA128: return 0; #endif #ifdef GPG_USE_CAMELLIA192 case CIPHER_ALGO_CAMELLIA192: return GCRY_CIPHER_CAMELLIA192; #else case CIPHER_ALGO_CAMELLIA192: return 0; #endif #ifdef GPG_USE_CAMELLIA256 case CIPHER_ALGO_CAMELLIA256: return GCRY_CIPHER_CAMELLIA256; #else case CIPHER_ALGO_CAMELLIA256: return 0; #endif default: return 0; } } /* The inverse function of above. */ static cipher_algo_t map_cipher_gcry_to_openpgp (enum gcry_cipher_algos algo) { switch (algo) { case GCRY_CIPHER_NONE: return CIPHER_ALGO_NONE; case GCRY_CIPHER_IDEA: return CIPHER_ALGO_IDEA; case GCRY_CIPHER_3DES: return CIPHER_ALGO_3DES; case GCRY_CIPHER_CAST5: return CIPHER_ALGO_CAST5; case GCRY_CIPHER_BLOWFISH: return CIPHER_ALGO_BLOWFISH; case GCRY_CIPHER_AES: return CIPHER_ALGO_AES; case GCRY_CIPHER_AES192: return CIPHER_ALGO_AES192; case GCRY_CIPHER_AES256: return CIPHER_ALGO_AES256; case GCRY_CIPHER_TWOFISH: return CIPHER_ALGO_TWOFISH; case GCRY_CIPHER_CAMELLIA128: return CIPHER_ALGO_CAMELLIA128; case GCRY_CIPHER_CAMELLIA192: return CIPHER_ALGO_CAMELLIA192; case GCRY_CIPHER_CAMELLIA256: return CIPHER_ALGO_CAMELLIA256; default: return 0; } } /* Map Gcrypt public key algorithm numbers to those used by OpenPGP. FIXME: This mapping is used at only two places - we should get rid of it. */ pubkey_algo_t map_pk_gcry_to_openpgp (enum gcry_pk_algos algo) { switch (algo) { case GCRY_PK_EDDSA: return PUBKEY_ALGO_EDDSA; case GCRY_PK_ECDSA: return PUBKEY_ALGO_ECDSA; case GCRY_PK_ECDH: return PUBKEY_ALGO_ECDH; default: return algo < 110 ? (pubkey_algo_t)algo : 0; } } /* Return the block length of an OpenPGP cipher algorithm. */ int openpgp_cipher_blocklen (cipher_algo_t algo) { /* We use the numbers from OpenPGP to be sure that we get the right block length. This is so that the packet parsing code works even for unknown algorithms (for which we assume 8 due to tradition). NOTE: If you change the returned blocklen above 16, check the callers because they may use a fixed size buffer of that size. */ switch (algo) { case CIPHER_ALGO_AES: case CIPHER_ALGO_AES192: case CIPHER_ALGO_AES256: case CIPHER_ALGO_TWOFISH: case CIPHER_ALGO_CAMELLIA128: case CIPHER_ALGO_CAMELLIA192: case CIPHER_ALGO_CAMELLIA256: return 16; default: return 8; } } /**************** * Wrapper around the libgcrypt function with additional checks on * the OpenPGP contraints for the algo ID. */ int openpgp_cipher_test_algo (cipher_algo_t algo) { enum gcry_cipher_algos ga; ga = map_cipher_openpgp_to_gcry (algo); if (!ga) return gpg_error (GPG_ERR_CIPHER_ALGO); return gcry_cipher_test_algo (ga); } /* Map the OpenPGP cipher algorithm whose ID is contained in ALGORITHM to a string representation of the algorithm name. For unknown algorithm IDs this function returns "?". */ const char * openpgp_cipher_algo_name (cipher_algo_t algo) { switch (algo) { case CIPHER_ALGO_IDEA: return "IDEA"; case CIPHER_ALGO_3DES: return "3DES"; case CIPHER_ALGO_CAST5: return "CAST5"; case CIPHER_ALGO_BLOWFISH: return "BLOWFISH"; case CIPHER_ALGO_AES: return "AES"; case CIPHER_ALGO_AES192: return "AES192"; case CIPHER_ALGO_AES256: return "AES256"; case CIPHER_ALGO_TWOFISH: return "TWOFISH"; case CIPHER_ALGO_CAMELLIA128: return "CAMELLIA128"; case CIPHER_ALGO_CAMELLIA192: return "CAMELLIA192"; case CIPHER_ALGO_CAMELLIA256: return "CAMELLIA256"; case CIPHER_ALGO_NONE: default: return "?"; } } +/* Same as openpgp_cipher_algo_name but returns a string in the form + * "ALGO.MODE" if AEAD is not 0. Note that in this version we do not + * print "ALGO.CFB" as we do in 2.3 to avoid confusing users. */ +const char * +openpgp_cipher_algo_mode_name (cipher_algo_t algo, aead_algo_t aead) +{ + + if (aead == AEAD_ALGO_NONE) + return openpgp_cipher_algo_name (algo); + + return map_static_strings ("openpgp_cipher_algo_mode_name", algo, aead, + openpgp_cipher_algo_name (algo), + ".", + openpgp_aead_algo_name (aead), + NULL); +} + + /* Return 0 if ALGO is supported. Return an error if not. */ gpg_error_t openpgp_aead_test_algo (aead_algo_t algo) { /* FIXME: We currently have no easy way to test whether libgcrypt * implements a mode. The only way we can do this is to open a * cipher context with that mode and close it immediately. That is * a bit costly. So we look at the libgcrypt version and assume * nothing has been patched out. */ switch (algo) { case AEAD_ALGO_NONE: break; case AEAD_ALGO_EAX: #if GCRYPT_VERSION_NUMBER < 0x010900 break; #else return 0; #endif case AEAD_ALGO_OCB: return 0; } return gpg_error (GPG_ERR_INV_CIPHER_MODE); } /* Map the OpenPGP AEAD algorithm with ID ALGO to a string * representation of the algorithm name. For unknown algorithm IDs * this function returns "?". */ const char * openpgp_aead_algo_name (aead_algo_t algo) { switch (algo) { case AEAD_ALGO_NONE: break; case AEAD_ALGO_EAX: return "EAX"; case AEAD_ALGO_OCB: return "OCB"; } return "?"; } /* Return information for the AEAD algorithm ALGO. The corresponding * Libgcrypt ciphermode is stored at R_MODE and the required number of * octets for the nonce at R_NONCELEN. On error and error code is * returned. Note that the taglen is always 128 bits. */ gpg_error_t openpgp_aead_algo_info (aead_algo_t algo, enum gcry_cipher_modes *r_mode, unsigned int *r_noncelen) { switch (algo) { case AEAD_ALGO_OCB: *r_mode = GCRY_CIPHER_MODE_OCB; *r_noncelen = 15; break; case AEAD_ALGO_EAX: *r_mode = MY_GCRY_CIPHER_MODE_EAX; *r_noncelen = 16; break; default: log_error ("unsupported AEAD algo %d\n", algo); return gpg_error (GPG_ERR_INV_CIPHER_MODE); } return 0; } /* Return 0 if ALGO is a supported OpenPGP public key algorithm. */ int openpgp_pk_test_algo (pubkey_algo_t algo) { return openpgp_pk_test_algo2 (algo, 0); } /* Return 0 if ALGO is a supported OpenPGP public key algorithm and allows the usage USE. */ int openpgp_pk_test_algo2 (pubkey_algo_t algo, unsigned int use) { enum gcry_pk_algos ga = 0; size_t use_buf = use; switch (algo) { #ifdef GPG_USE_RSA case PUBKEY_ALGO_RSA: ga = GCRY_PK_RSA; break; case PUBKEY_ALGO_RSA_E: ga = GCRY_PK_RSA_E; break; case PUBKEY_ALGO_RSA_S: ga = GCRY_PK_RSA_S; break; #else case PUBKEY_ALGO_RSA: break; case PUBKEY_ALGO_RSA_E: break; case PUBKEY_ALGO_RSA_S: break; #endif case PUBKEY_ALGO_ELGAMAL_E: ga = GCRY_PK_ELG; break; case PUBKEY_ALGO_DSA: ga = GCRY_PK_DSA; break; #ifdef GPG_USE_ECDH case PUBKEY_ALGO_ECDH: ga = GCRY_PK_ECC; break; #else case PUBKEY_ALGO_ECDH: break; #endif #ifdef GPG_USE_ECDSA case PUBKEY_ALGO_ECDSA: ga = GCRY_PK_ECC; break; #else case PUBKEY_ALGO_ECDSA: break; #endif #ifdef GPG_USE_EDDSA case PUBKEY_ALGO_EDDSA: ga = GCRY_PK_ECC; break; #else case PUBKEY_ALGO_EDDSA: break; #endif case PUBKEY_ALGO_ELGAMAL: /* Dont't allow type 20 keys unless in rfc2440 mode. */ if (RFC2440) ga = GCRY_PK_ELG; break; default: break; } if (!ga) return gpg_error (GPG_ERR_PUBKEY_ALGO); /* Elgamal in OpenPGP used to support signing and Libgcrypt still * does. However, we removed the signing capability from gpg ages * ago. This function should reflect this so that errors are thrown * early and not only when we try to sign using Elgamal. */ if (ga == GCRY_PK_ELG && (use & (PUBKEY_USAGE_CERT | PUBKEY_USAGE_SIG))) return gpg_error (GPG_ERR_WRONG_PUBKEY_ALGO); /* Now check whether Libgcrypt has support for the algorithm. */ return gcry_pk_algo_info (ga, GCRYCTL_TEST_ALGO, NULL, &use_buf); } int openpgp_pk_algo_usage ( int algo ) { int use = 0; /* They are hardwired in gpg 1.0. */ switch ( algo ) { case PUBKEY_ALGO_RSA: use = (PUBKEY_USAGE_CERT | PUBKEY_USAGE_SIG | PUBKEY_USAGE_ENC | PUBKEY_USAGE_AUTH); break; case PUBKEY_ALGO_RSA_E: case PUBKEY_ALGO_ECDH: use = PUBKEY_USAGE_ENC; break; case PUBKEY_ALGO_RSA_S: use = PUBKEY_USAGE_CERT | PUBKEY_USAGE_SIG; break; case PUBKEY_ALGO_ELGAMAL: if (RFC2440) use = PUBKEY_USAGE_ENC; break; case PUBKEY_ALGO_ELGAMAL_E: use = PUBKEY_USAGE_ENC; break; case PUBKEY_ALGO_DSA: use = PUBKEY_USAGE_CERT | PUBKEY_USAGE_SIG | PUBKEY_USAGE_AUTH; break; case PUBKEY_ALGO_ECDSA: case PUBKEY_ALGO_EDDSA: use = PUBKEY_USAGE_CERT | PUBKEY_USAGE_SIG | PUBKEY_USAGE_AUTH; default: break; } return use; } /* Map the OpenPGP pubkey algorithm whose ID is contained in ALGO to a string representation of the algorithm name. For unknown algorithm IDs this function returns "?". */ const char * openpgp_pk_algo_name (pubkey_algo_t algo) { switch (algo) { case PUBKEY_ALGO_RSA: case PUBKEY_ALGO_RSA_E: case PUBKEY_ALGO_RSA_S: return "RSA"; case PUBKEY_ALGO_ELGAMAL: case PUBKEY_ALGO_ELGAMAL_E: return "ELG"; case PUBKEY_ALGO_DSA: return "DSA"; case PUBKEY_ALGO_ECDH: return "ECDH"; case PUBKEY_ALGO_ECDSA: return "ECDSA"; case PUBKEY_ALGO_EDDSA: return "EDDSA"; default: return "?"; } } /* Explicit mapping of OpenPGP digest algos to Libgcrypt. */ /* FIXME: We do not yes use it everywhere. */ enum gcry_md_algos map_md_openpgp_to_gcry (digest_algo_t algo) { switch (algo) { #ifdef GPG_USE_MD5 case DIGEST_ALGO_MD5: return GCRY_MD_MD5; #else case DIGEST_ALGO_MD5: return 0; #endif case DIGEST_ALGO_SHA1: return GCRY_MD_SHA1; #ifdef GPG_USE_RMD160 case DIGEST_ALGO_RMD160: return GCRY_MD_RMD160; #else case DIGEST_ALGO_RMD160: return 0; #endif #ifdef GPG_USE_SHA224 case DIGEST_ALGO_SHA224: return GCRY_MD_SHA224; #else case DIGEST_ALGO_SHA224: return 0; #endif case DIGEST_ALGO_SHA256: return GCRY_MD_SHA256; #ifdef GPG_USE_SHA384 case DIGEST_ALGO_SHA384: return GCRY_MD_SHA384; #else case DIGEST_ALGO_SHA384: return 0; #endif #ifdef GPG_USE_SHA512 case DIGEST_ALGO_SHA512: return GCRY_MD_SHA512; #else case DIGEST_ALGO_SHA512: return 0; #endif default: return 0; } } /* Return 0 if ALGO is suitable and implemented OpenPGP hash algorithm. */ int openpgp_md_test_algo (digest_algo_t algo) { enum gcry_md_algos ga; ga = map_md_openpgp_to_gcry (algo); if (!ga) return gpg_error (GPG_ERR_DIGEST_ALGO); return gcry_md_test_algo (ga); } /* Map the OpenPGP digest algorithm whose ID is contained in ALGO to a string representation of the algorithm name. For unknown algorithm IDs this function returns "?". */ const char * openpgp_md_algo_name (int algo) { switch (algo) { case DIGEST_ALGO_MD5: return "MD5"; case DIGEST_ALGO_SHA1: return "SHA1"; case DIGEST_ALGO_RMD160: return "RIPEMD160"; case DIGEST_ALGO_SHA256: return "SHA256"; case DIGEST_ALGO_SHA384: return "SHA384"; case DIGEST_ALGO_SHA512: return "SHA512"; case DIGEST_ALGO_SHA224: return "SHA224"; } return "?"; } static unsigned long get_signature_count (PKT_public_key *pk) { #ifdef ENABLE_CARD_SUPPORT struct agent_card_info_s info; (void)pk; if (!agent_scd_getattr ("SIG-COUNTER",&info)) return info.sig_counter; else return 0; #else (void)pk; return 0; #endif } /* Expand %-strings. Returns a string which must be xfreed. Returns NULL if the string cannot be expanded (too large). */ char * pct_expando(const char *string,struct expando_args *args) { const char *ch=string; int idx=0,maxlen=0,done=0; u32 pk_keyid[2]={0,0},sk_keyid[2]={0,0}; char *ret=NULL; /* The parser below would return NULL for an empty string, thus we * catch it here. Also catch NULL here. */ if (!string || !*string) return xstrdup (""); if(args->pk) keyid_from_pk(args->pk,pk_keyid); if(args->pksk) keyid_from_pk (args->pksk, sk_keyid); /* This is used so that %k works in photoid command strings in --list-secret-keys (which of course has a sk, but no pk). */ if(!args->pk && args->pksk) keyid_from_pk (args->pksk, pk_keyid); while(*ch!='\0') { if(!done) { /* 8192 is way bigger than we'll need here */ if(maxlen>=8192) goto fail; maxlen+=1024; ret=xrealloc(ret,maxlen); } done=0; if(*ch=='%') { switch(*(ch+1)) { case 's': /* short key id */ if(idx+8namehash) { char *tmp = zb32_encode (args->namehash, 8*20); if (tmp) { if (idx + strlen (tmp) < maxlen) { strcpy (ret+idx, tmp); idx += strlen (tmp); } xfree (tmp); done = 1; } } break; case 'c': /* signature count from card, if any. */ if(idx+10pksk)); idx+=strlen(&ret[idx]); done=1; } break; case 'f': /* Fingerprint of key being signed */ case 'p': /* Fingerprint of the primary key making the signature. */ case 'g': /* Fingerprint of the key making the signature. */ { byte array[MAX_FINGERPRINT_LEN]; size_t len; int i; if ((*(ch+1))=='f' && args->pk) fingerprint_from_pk (args->pk, array, &len); else if ((*(ch+1))=='p' && args->pksk) { if(args->pksk->flags.primary) fingerprint_from_pk (args->pksk, array, &len); else if (args->pksk->main_keyid[0] || args->pksk->main_keyid[1]) { /* Not the primary key: Find the fingerprint of the primary key. */ PKT_public_key *pk= xmalloc_clear(sizeof(PKT_public_key)); if (!get_pubkey_fast (pk,args->pksk->main_keyid)) fingerprint_from_pk (pk, array, &len); else memset (array, 0, (len=MAX_FINGERPRINT_LEN)); free_public_key (pk); } else /* Oops: info about the primary key missing. */ memset(array,0,(len=MAX_FINGERPRINT_LEN)); } else if((*(ch+1))=='g' && args->pksk) fingerprint_from_pk (args->pksk, array, &len); else memset(array,0,(len=MAX_FINGERPRINT_LEN)); if(idx+(len*2)validity_info && idx+1validity_info; ret[idx]='\0'; done=1; } break; /* The text string types */ case 't': case 'T': case 'V': { const char *str=NULL; switch(*(ch+1)) { case 't': /* e.g. "jpg" */ str=image_type_to_string(args->imagetype,0); break; case 'T': /* e.g. "image/jpeg" */ str=image_type_to_string(args->imagetype,2); break; case 'V': /* e.g. "full", "expired", etc. */ str=args->validity_string; break; } if(str && idx+strlen(str)='A' && file[0]<='Z') || (file[0]>='a' && file[0]<='z')) && file[1]==':') #else || file[0]=='/' #endif ) return access(file,mode); else { /* At least as large as, but most often larger than we need. */ char *buffer=xmalloc(strlen(envpath)+1+strlen(file)+1); char *split,*item,*path=xstrdup(envpath); split=path; while((item=strsep(&split,PATHSEP_S))) { strcpy(buffer,item); strcat(buffer,"/"); strcat(buffer,file); ret=access(buffer,mode); if(ret==0) break; } xfree(path); xfree(buffer); } return ret; } /* Return the number of public key parameters as used by OpenPGP. */ int pubkey_get_npkey (pubkey_algo_t algo) { switch (algo) { case PUBKEY_ALGO_RSA: case PUBKEY_ALGO_RSA_E: case PUBKEY_ALGO_RSA_S: return 2; case PUBKEY_ALGO_ELGAMAL_E: return 3; case PUBKEY_ALGO_DSA: return 4; case PUBKEY_ALGO_ECDH: return 3; case PUBKEY_ALGO_ECDSA: return 2; case PUBKEY_ALGO_ELGAMAL: return 3; case PUBKEY_ALGO_EDDSA: return 2; default: return 0; } } /* Return the number of secret key parameters as used by OpenPGP. */ int pubkey_get_nskey (pubkey_algo_t algo) { switch (algo) { case PUBKEY_ALGO_RSA: case PUBKEY_ALGO_RSA_E: case PUBKEY_ALGO_RSA_S: return 6; case PUBKEY_ALGO_ELGAMAL_E: return 4; case PUBKEY_ALGO_DSA: return 5; case PUBKEY_ALGO_ECDH: return 4; case PUBKEY_ALGO_ECDSA: return 3; case PUBKEY_ALGO_ELGAMAL: return 4; case PUBKEY_ALGO_EDDSA: return 3; default: return 0; } } /* Temporary helper. */ int pubkey_get_nsig (pubkey_algo_t algo) { switch (algo) { case PUBKEY_ALGO_RSA: case PUBKEY_ALGO_RSA_E: case PUBKEY_ALGO_RSA_S: return 1; case PUBKEY_ALGO_ELGAMAL_E: return 0; case PUBKEY_ALGO_DSA: return 2; case PUBKEY_ALGO_ECDH: return 0; case PUBKEY_ALGO_ECDSA: return 2; case PUBKEY_ALGO_ELGAMAL: return 2; case PUBKEY_ALGO_EDDSA: return 2; default: return 0; } } /* Temporary helper. */ int pubkey_get_nenc (pubkey_algo_t algo) { switch (algo) { case PUBKEY_ALGO_RSA: case PUBKEY_ALGO_RSA_E: case PUBKEY_ALGO_RSA_S: return 1; case PUBKEY_ALGO_ELGAMAL_E: return 2; case PUBKEY_ALGO_DSA: return 0; case PUBKEY_ALGO_ECDH: return 2; case PUBKEY_ALGO_ECDSA: return 0; case PUBKEY_ALGO_ELGAMAL: return 2; case PUBKEY_ALGO_EDDSA: return 0; default: return 0; } } /* Temporary helper. */ unsigned int pubkey_nbits( int algo, gcry_mpi_t *key ) { int rc, nbits; gcry_sexp_t sexp; if (algo == PUBKEY_ALGO_DSA && key[0] && key[1] && key[2] && key[3]) { rc = gcry_sexp_build (&sexp, NULL, "(public-key(dsa(p%m)(q%m)(g%m)(y%m)))", key[0], key[1], key[2], key[3] ); } else if ((algo == PUBKEY_ALGO_ELGAMAL || algo == PUBKEY_ALGO_ELGAMAL_E) && key[0] && key[1] && key[2]) { rc = gcry_sexp_build (&sexp, NULL, "(public-key(elg(p%m)(g%m)(y%m)))", key[0], key[1], key[2] ); } else if (is_RSA (algo) && key[0] && key[1]) { rc = gcry_sexp_build (&sexp, NULL, "(public-key(rsa(n%m)(e%m)))", key[0], key[1] ); } else if ((algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_ECDH || algo == PUBKEY_ALGO_EDDSA) && key[0] && key[1]) { char *curve = openpgp_oid_to_str (key[0]); if (!curve) rc = gpg_error_from_syserror (); else { rc = gcry_sexp_build (&sexp, NULL, "(public-key(ecc(curve%s)(q%m)))", curve, key[1]); xfree (curve); } } else return 0; if (rc) BUG (); nbits = gcry_pk_get_nbits (sexp); gcry_sexp_release (sexp); return nbits; } int mpi_print (estream_t fp, gcry_mpi_t a, int mode) { int n = 0; size_t nwritten; if (!a) return es_fprintf (fp, "[MPI_NULL]"); if (!mode) { unsigned int n1; n1 = gcry_mpi_get_nbits(a); n += es_fprintf (fp, "[%u bits]", n1); } else if (gcry_mpi_get_flag (a, GCRYMPI_FLAG_OPAQUE)) { unsigned int nbits; unsigned char *p = gcry_mpi_get_opaque (a, &nbits); if (!p) n += es_fprintf (fp, "[invalid opaque value]"); else { if (!es_write_hexstring (fp, p, (nbits + 7)/8, 0, &nwritten)) n += nwritten; } } else { unsigned char *buffer; size_t buflen; if (gcry_mpi_aprint (GCRYMPI_FMT_USG, &buffer, &buflen, a)) BUG (); if (!es_write_hexstring (fp, buffer, buflen, 0, &nwritten)) n += nwritten; gcry_free (buffer); } return n; } /* pkey[1] or skey[1] is Q for ECDSA, which is an uncompressed point, i.e. 04 */ unsigned int ecdsa_qbits_from_Q (unsigned int qbits) { if ((qbits%8) > 3) { log_error (_("ECDSA public key is expected to be in SEC encoding " "multiple of 8 bits\n")); return 0; } qbits -= qbits%8; qbits /= 2; return qbits; } /* Ignore signatures and certifications made over certain digest * algorithms by default, MD5 is considered weak. This allows users * to deprecate support for other algorithms as well. */ void additional_weak_digest (const char* digestname) { struct weakhash *weak = NULL; const enum gcry_md_algos algo = string_to_digest_algo(digestname); if (algo == GCRY_MD_NONE) { log_error (_("unknown weak digest '%s'\n"), digestname); return; } /* Check to ensure it's not already present. */ for (weak = opt.weak_digests; weak; weak = weak->next) if (algo == weak->algo) return; /* Add it to the head of the list. */ weak = xmalloc(sizeof(*weak)); weak->algo = algo; weak->rejection_shown = 0; weak->next = opt.weak_digests; opt.weak_digests = weak; } /* Return true if ALGO is in the list of weak digests. */ int is_weak_digest (digest_algo_t algo) { const enum gcry_md_algos galgo = map_md_openpgp_to_gcry (algo); const struct weakhash *weak; for (weak = opt.weak_digests; weak; weak = weak->next) if (weak->algo == galgo) return 1; return 0; }