Exemplo n.º 1
0
/* Perform a verify operation.  To verify detached signatures, DATA_FD
   shall be the descriptor of the signed data; for regular signatures
   it needs to be -1.  If OUT_FP is not NULL and DATA_FD is not -1 the
   the signed material gets written that stream.

   FIXME: OUTFP is not yet implemented.
*/
int
gpg_verify (ctrl_t ctrl, int sig_fd, int data_fd, estream_t out_fp)
{
  int rc;
  iobuf_t fp;
  armor_filter_context_t *afx = NULL;
  progress_filter_context_t *pfx = new_progress_context ();

  (void)ctrl;
  (void)out_fp;

  if (is_secured_file (sig_fd))
    {
      fp = NULL;
      gpg_err_set_errno (EPERM);
    }
  else
    fp = iobuf_fdopen_nc (sig_fd, "rb");
  if (!fp)
    {
      rc = gpg_error_from_syserror ();
      log_error (_("can't open fd %d: %s\n"), sig_fd, strerror (errno));
      goto leave;
    }

  handle_progress (pfx, fp, NULL);

  if ( !opt.no_armor && use_armor_filter (fp) )
    {
      afx = new_armor_context ();
      push_armor_filter (afx, fp);
    }

  rc = proc_signature_packets_by_fd (ctrl, NULL, fp, data_fd);

  if ( afx && afx->no_openpgp_data
       && (rc == -1 || gpg_err_code (rc) == GPG_ERR_EOF) )
    rc = gpg_error (GPG_ERR_NO_DATA);

 leave:
  iobuf_close (fp);
  release_progress_context (pfx);
  release_armor_context (afx);
  return rc;
}
Exemplo n.º 2
0
/*
 * Encrypt the file with the given userids (or ask if none is
 * supplied).  Either FILENAME or FILEFD must be given, but not both.
 * The caller may provide a checked list of public keys in
 * PROVIDED_PKS; if not the function builds a list of keys on its own.
 *
 * Note that FILEFD is currently only used by cmd_encrypt in the
 * not yet finished server.c.
 */
int
encrypt_crypt (ctrl_t ctrl, int filefd, const char *filename,
               strlist_t remusr, int use_symkey, pk_list_t provided_keys,
               int outputfd)
{
  iobuf_t inp = NULL;
  iobuf_t out = NULL;
  PACKET pkt;
  PKT_plaintext *pt = NULL;
  DEK *symkey_dek = NULL;
  STRING2KEY *symkey_s2k = NULL;
  int rc = 0, rc2 = 0;
  u32 filesize;
  cipher_filter_context_t cfx;
  armor_filter_context_t *afx = NULL;
  compress_filter_context_t zfx;
  text_filter_context_t tfx;
  progress_filter_context_t *pfx;
  PK_LIST pk_list;
  int do_compress;
  int compliant;

  if (filefd != -1 && filename)
    return gpg_error (GPG_ERR_INV_ARG);  /* Both given.  */

  do_compress = !!opt.compress_algo;

  pfx = new_progress_context ();
  memset( &cfx, 0, sizeof cfx);
  memset( &zfx, 0, sizeof zfx);
  memset( &tfx, 0, sizeof tfx);
  init_packet(&pkt);

  if (use_symkey
      && (rc=setup_symkey(&symkey_s2k,&symkey_dek)))
    {
      release_progress_context (pfx);
      return rc;
    }

  if (provided_keys)
    pk_list = provided_keys;
  else
    {
      if ((rc = build_pk_list (ctrl, remusr, &pk_list)))
        {
          release_progress_context (pfx);
          return rc;
        }
    }

  /* Prepare iobufs. */
#ifdef HAVE_W32_SYSTEM
  if (filefd == -1)
    inp = iobuf_open (filename);
  else
    {
      inp = NULL;
      gpg_err_set_errno (ENOSYS);
    }
#else
  if (filefd == GNUPG_INVALID_FD)
    inp = iobuf_open (filename);
  else
    inp = iobuf_fdopen_nc (FD2INT(filefd), "rb");
#endif
  if (inp)
    iobuf_ioctl (inp, IOBUF_IOCTL_NO_CACHE, 1, NULL);
  if (inp && is_secured_file (iobuf_get_fd (inp)))
    {
      iobuf_close (inp);
      inp = NULL;
      gpg_err_set_errno (EPERM);
    }
  if (!inp)
    {
      char xname[64];

      rc = gpg_error_from_syserror ();
      if (filefd != -1)
        snprintf (xname, sizeof xname, "[fd %d]", filefd);
      else if (!filename)
        strcpy (xname, "[stdin]");
      else
        *xname = 0;
      log_error (_("can't open '%s': %s\n"),
                 *xname? xname : filename, gpg_strerror (rc) );
      goto leave;
    }

  if (opt.verbose)
    log_info (_("reading from '%s'\n"), iobuf_get_fname_nonnull (inp));

  handle_progress (pfx, inp, filename);

  if (opt.textmode)
    iobuf_push_filter (inp, text_filter, &tfx);

  rc = open_outfile (outputfd, filename, opt.armor? 1:0, 0, &out);
  if (rc)
    goto leave;

  if (opt.armor)
    {
      afx = new_armor_context ();
      push_armor_filter (afx, out);
    }

  /* Create a session key. */
  cfx.dek = xmalloc_secure_clear (sizeof *cfx.dek);
  if (!opt.def_cipher_algo)
    {
      /* Try to get it from the prefs.  */
      cfx.dek->algo = select_algo_from_prefs (pk_list, PREFTYPE_SYM, -1, NULL);
      /* The only way select_algo_from_prefs can fail here is when
         mixing v3 and v4 keys, as v4 keys have an implicit preference
         entry for 3DES, and the pk_list cannot be empty.  In this
         case, use 3DES anyway as it's the safest choice - perhaps the
         v3 key is being used in an OpenPGP implementation and we know
         that the implementation behind any v4 key can handle 3DES. */
      if (cfx.dek->algo == -1)
        {
          cfx.dek->algo = CIPHER_ALGO_3DES;
        }

      /* In case 3DES has been selected, print a warning if any key
         does not have a preference for AES.  This should help to
         indentify why encrypting to several recipients falls back to
         3DES. */
      if (opt.verbose && cfx.dek->algo == CIPHER_ALGO_3DES)
        warn_missing_aes_from_pklist (pk_list);
    }
  else
    {
      if (!opt.expert
          && (select_algo_from_prefs (pk_list, PREFTYPE_SYM,
                                      opt.def_cipher_algo, NULL)
              != opt.def_cipher_algo))
        {
          log_info(_("WARNING: forcing symmetric cipher %s (%d)"
                     " violates recipient preferences\n"),
                   openpgp_cipher_algo_name (opt.def_cipher_algo),
                   opt.def_cipher_algo);
        }

      cfx.dek->algo = opt.def_cipher_algo;
    }

  /* Check compliance.  */
  if (! gnupg_cipher_is_allowed (opt.compliance, 1, cfx.dek->algo,
                                 GCRY_CIPHER_MODE_CFB))
    {
      log_error (_("cipher algorithm '%s' may not be used in %s mode\n"),
		 openpgp_cipher_algo_name (cfx.dek->algo),
		 gnupg_compliance_option_string (opt.compliance));
      rc = gpg_error (GPG_ERR_CIPHER_ALGO);
      goto leave;
    }

  if (!gnupg_rng_is_compliant (opt.compliance))
    {
      rc = gpg_error (GPG_ERR_FORBIDDEN);
      log_error (_("%s is not compliant with %s mode\n"),
                 "RNG",
                 gnupg_compliance_option_string (opt.compliance));
      write_status_error ("random-compliance", rc);
      goto leave;
    }

  compliant = gnupg_cipher_is_compliant (CO_DE_VS, cfx.dek->algo,
                                         GCRY_CIPHER_MODE_CFB);

  {
    pk_list_t pkr;

    for (pkr = pk_list; pkr; pkr = pkr->next)
      {
        PKT_public_key *pk = pkr->pk;
        unsigned int nbits = nbits_from_pk (pk);

        if (!gnupg_pk_is_compliant (opt.compliance,
                                    pk->pubkey_algo, pk->pkey, nbits, NULL))
          log_info (_("WARNING: key %s is not suitable for encryption"
                      " in %s mode\n"),
                    keystr_from_pk (pk),
                    gnupg_compliance_option_string (opt.compliance));

        if (compliant
            && !gnupg_pk_is_compliant (CO_DE_VS, pk->pubkey_algo, pk->pkey,
                                       nbits, NULL))
          compliant = 0;
      }

  }

  if (compliant)
    write_status_strings (STATUS_ENCRYPTION_COMPLIANCE_MODE,
                          gnupg_status_compliance_flag (CO_DE_VS),
                          NULL);

  cfx.dek->use_aead = use_aead (pk_list, cfx.dek->algo);
  if (!cfx.dek->use_aead)
    cfx.dek->use_mdc = !!use_mdc (pk_list, cfx.dek->algo);

  /* Only do the is-file-already-compressed check if we are using a
   * MDC or AEAD.  This forces compressed files to be re-compressed if
   * we do not have a MDC to give some protection against chosen
   * ciphertext attacks. */
  if (do_compress
      && (cfx.dek->use_mdc || cfx.dek->use_aead)
      && is_file_compressed (filename, &rc2))
    {
      if (opt.verbose)
        log_info(_("'%s' already compressed\n"), filename);
      do_compress = 0;
    }
  if (rc2)
    {
      rc = rc2;
      goto leave;
    }

  make_session_key (cfx.dek);
  if (DBG_CRYPTO)
    log_printhex (cfx.dek->key, cfx.dek->keylen, "DEK is: ");

  rc = write_pubkey_enc_from_list (ctrl, pk_list, cfx.dek, out);
  if (rc)
    goto leave;

  /* We put the passphrase (if any) after any public keys as this
   * seems to be the most useful on the recipient side - there is no
   * point in prompting a user for a passphrase if they have the
   * secret key needed to decrypt.  */
  if (use_symkey && (rc = write_symkey_enc (symkey_s2k, cfx.dek->use_aead,
                                            symkey_dek, cfx.dek, out)))
    goto leave;

  if (!opt.no_literal)
    pt = setup_plaintext_name (filename, inp);

  /* Get the size of the file if possible, i.e., if it is a real file.  */
  if (filename && *filename
      && !iobuf_is_pipe_filename (filename) && !opt.textmode )
    {
      off_t tmpsize;
      int overflow;

      if ( !(tmpsize = iobuf_get_filelength(inp, &overflow))
           && !overflow && opt.verbose)
        log_info(_("WARNING: '%s' is an empty file\n"), filename );
      /* We can't encode the length of very large files because
         OpenPGP uses only 32 bit for file sizes.  So if the size
         of a file is larger than 2^32 minus some bytes for packet
         headers, we switch to partial length encoding. */
      if (tmpsize < (IOBUF_FILELENGTH_LIMIT - 65536) )
        filesize = tmpsize;
      else
        filesize = 0;
    }
  else
    filesize = opt.set_filesize ? opt.set_filesize : 0; /* stdin */

  if (!opt.no_literal)
    {
      pt->timestamp = make_timestamp();
      pt->mode = opt.mimemode? 'm' : opt.textmode ? 't' : 'b';
      pt->len = filesize;
      pt->new_ctb = !pt->len;
      pt->buf = inp;
      pkt.pkttype = PKT_PLAINTEXT;
      pkt.pkt.plaintext = pt;
      cfx.datalen = filesize && !do_compress? calc_packet_length( &pkt ) : 0;
    }
  else
    cfx.datalen = filesize && !do_compress ? filesize : 0;

  /* Register the cipher filter. */
  iobuf_push_filter (out,
                     cfx.dek->use_aead? cipher_filter_aead
                     /**/             : cipher_filter_cfb,
                     &cfx);

  /* Register the compress filter. */
  if (do_compress)
    {
      int compr_algo = opt.compress_algo;

      if (compr_algo == -1)
        {
          compr_algo = select_algo_from_prefs (pk_list, PREFTYPE_ZIP, -1, NULL);
          if (compr_algo == -1)
            compr_algo = DEFAULT_COMPRESS_ALGO;
          /* Theoretically impossible to get here since uncompressed
             is implicit.  */
        }
      else if (!opt.expert
               && select_algo_from_prefs(pk_list, PREFTYPE_ZIP,
                                         compr_algo, NULL) != compr_algo)
        {
          log_info (_("WARNING: forcing compression algorithm %s (%d)"
                      " violates recipient preferences\n"),
                    compress_algo_to_string(compr_algo), compr_algo);
        }

      /* Algo 0 means no compression. */
      if (compr_algo)
        {
          if (cfx.dek && (cfx.dek->use_mdc || cfx.dek->use_aead))
            zfx.new_ctb = 1;
          push_compress_filter (out,&zfx,compr_algo);
        }
    }

  /* Do the work. */
  if (!opt.no_literal)
    {
      if ((rc = build_packet( out, &pkt )))
        log_error ("build_packet failed: %s\n", gpg_strerror (rc));
    }
  else
    {
      /* User requested not to create a literal packet, so we copy the
         plain data. */
      byte copy_buffer[4096];
      int  bytes_copied;
      while ((bytes_copied = iobuf_read (inp, copy_buffer, 4096)) != -1)
        {
          rc = iobuf_write (out, copy_buffer, bytes_copied);
          if (rc)
            {
              log_error ("copying input to output failed: %s\n",
                         gpg_strerror (rc));
              break;
            }
        }
      wipememory (copy_buffer, 4096); /* Burn the buffer. */
    }

  /* Finish the stuff. */
 leave:
  iobuf_close (inp);
  if (rc)
    iobuf_cancel (out);
  else
    {
      iobuf_close (out); /* fixme: check returncode */
      write_status (STATUS_END_ENCRYPTION);
    }
  if (pt)
    pt->buf = NULL;
  free_packet (&pkt, NULL);
  xfree (cfx.dek);
  xfree (symkey_dek);
  xfree (symkey_s2k);
  if (!provided_keys)
    release_pk_list (pk_list);
  release_armor_context (afx);
  release_progress_context (pfx);
  return rc;
}
Exemplo n.º 3
0
/*
 * Make an output filename for the inputfile INAME.
 * Returns an IOBUF and an errorcode
 * Mode 0 = use ".gpg"
 *	1 = use ".asc"
 *	2 = use ".sig"
 *      3 = use ".rev"
 *
 * If INP_FD is not -1 the function simply creates an IOBUF for that
 * file descriptor and ignore INAME and MODE.  Note that INP_FD won't
 * be closed if the returned IOBUF is closed.  With RESTRICTEDPERM a
 * file will be created with mode 700 if possible.
 */
int
open_outfile (int inp_fd, const char *iname, int mode, int restrictedperm,
              iobuf_t *a)
{
  int rc = 0;

  *a = NULL;
  if (inp_fd != -1)
    {
      char xname[64];

      *a = iobuf_fdopen_nc (inp_fd, "wb");
      if (!*a)
        {
          rc = gpg_error_from_syserror ();
          snprintf (xname, sizeof xname, "[fd %d]", inp_fd);
          log_error (_("can't open '%s': %s\n"), xname, gpg_strerror (rc));
        }
      else if (opt.verbose)
        {
          snprintf (xname, sizeof xname, "[fd %d]", inp_fd);
          log_info (_("writing to '%s'\n"), xname);
        }
    }
  else if (iobuf_is_pipe_filename (iname) && !opt.outfile)
    {
      *a = iobuf_create (NULL, 0);
      if ( !*a )
        {
          rc = gpg_error_from_syserror ();
          log_error (_("can't open '%s': %s\n"), "[stdout]", strerror(errno) );
        }
      else if ( opt.verbose )
        log_info (_("writing to stdout\n"));
    }
  else
    {
      char *buf = NULL;
      const char *name;

      if (opt.dry_run)
        name = NAME_OF_DEV_NULL;
      else if (opt.outfile)
        name = opt.outfile;
      else
        {
#ifdef USE_ONLY_8DOT3
          if (opt.mangle_dos_filenames)
            {
              /* It is quite common for DOS systems to have only one
                 dot in a filename.  If we have something like this,
                 we simple replace the suffix except in cases where
                 the suffix is larger than 3 characters and not the
                 same as the new one.  We don't map the filenames to
                 8.3 because this is a duty of the file system.  */
              char *dot;
              const char *newsfx;

              newsfx = (mode==1 ? ".asc" :
                        mode==2 ? ".sig" :
                        mode==3 ? ".rev" : ".gpg");

              buf = xmalloc (strlen(iname)+4+1);
              strcpy (buf, iname);
              dot = strchr (buf, '.' );
              if ( dot && dot > buf && dot[1] && strlen(dot) <= 4
                   && CMP_FILENAME (newsfx, dot) )
                strcpy (dot, newsfx);
              else if (dot && !dot[1]) /* Do not duplicate a dot.  */
                strcpy (dot, newsfx+1);
              else
                strcat (buf, newsfx);
            }
          if (!buf)
#endif /* USE_ONLY_8DOT3 */
            {
              buf = xstrconcat (iname,
                                (mode==1 ? EXTSEP_S "asc" :
                                 mode==2 ? EXTSEP_S "sig" :
                                 mode==3 ? EXTSEP_S "rev" :
                                 /*     */ EXTSEP_S GPGEXT_GPG),
                                NULL);
            }
          name = buf;
        }

      rc = 0;
      while ( !overwrite_filep (name) )
        {
          char *tmp = ask_outfile_name (NULL, 0);
          if ( !tmp || !*tmp )
            {
              xfree (tmp);
              rc = gpg_error (GPG_ERR_EEXIST);
              break;
            }
          xfree (buf);
          name = buf = tmp;
        }

      if ( !rc )
        {
          if (is_secured_filename (name) )
            {
              *a = NULL;
              gpg_err_set_errno (EPERM);
            }
          else
            *a = iobuf_create (name, restrictedperm);
          if (!*a)
            {
              rc = gpg_error_from_syserror ();
              log_error(_("can't create '%s': %s\n"), name, strerror(errno) );
            }
          else if( opt.verbose )
            log_info (_("writing to '%s'\n"), name );
        }
      xfree(buf);
    }

  if (*a)
    iobuf_ioctl (*a, IOBUF_IOCTL_NO_CACHE, 1, NULL);

  return rc;
}