Esempio n. 1
0
/* Return a new DEK object using the string-to-key specifier S2K.  Use
   KEYID and PUBKEY_ALGO to prompt the user.  Returns NULL is the user
   selected to cancel the passphrase entry and if CANCELED is not
   NULL, sets it to true.

   MODE 0:  Allow cached passphrase
        1:  Ignore cached passphrase
        2:  Ditto, but create a new key
        3:  Allow cached passphrase; use the S2K salt as the cache ID
        4:  Ditto, but create a new key
*/
DEK *
passphrase_to_dek_ext (u32 *keyid, int pubkey_algo,
                       int cipher_algo, STRING2KEY *s2k, int mode,
                       const char *tryagain_text,
                       const char *custdesc, const char *custprompt,
                       int *canceled)
{
  char *pw = NULL;
  DEK *dek;
  STRING2KEY help_s2k;
  int dummy_canceled;
  char s2k_cacheidbuf[1+16+1], *s2k_cacheid = NULL;

  if (!canceled)
    canceled = &dummy_canceled;
  *canceled = 0;

  if ( !s2k )
    {
      log_assert (mode != 3 && mode != 4);
      /* This is used for the old rfc1991 mode
       * Note: This must match the code in encode.c with opt.rfc1991 set */
      s2k = &help_s2k;
      s2k->mode = 0;
      s2k->hash_algo = S2K_DIGEST_ALGO;
    }

  /* Create a new salt or what else to be filled into the s2k for a
     new key.  */
  if ((mode == 2 || mode == 4) && (s2k->mode == 1 || s2k->mode == 3))
    {
      gcry_randomize (s2k->salt, 8, GCRY_STRONG_RANDOM);
      if ( s2k->mode == 3 )
        {
          /* We delay the encoding until it is really needed.  This is
             if we are going to dynamically calibrate it, we need to
             call out to gpg-agent and that should not be done during
             option processing in main().  */
          if (!opt.s2k_count)
            opt.s2k_count = encode_s2k_iterations (0);
          s2k->count = opt.s2k_count;
        }
    }

  /* If we do not have a passphrase available in NEXT_PW and status
     information are request, we print them now. */
  if ( !next_pw && is_status_enabled() )
    {
      char buf[50];

      if ( keyid )
        {
          emit_status_need_passphrase (keyid,
                                       keyid[2] && keyid[3]? keyid+2:NULL,
                                       pubkey_algo);
	}
      else
        {
          snprintf (buf, sizeof buf -1, "%d %d %d",
                    cipher_algo, s2k->mode, s2k->hash_algo );
          write_status_text ( STATUS_NEED_PASSPHRASE_SYM, buf );
	}
    }

  /* If we do have a keyID, we do not have a passphrase available in
     NEXT_PW, we are not running in batch mode and we do not want to
     ignore the passphrase cache (mode!=1), print a prompt with
     information on that key. */
  if ( keyid && !opt.batch && !next_pw && mode!=1 )
    {
      PKT_public_key *pk = xmalloc_clear( sizeof *pk );
      char *p;

      p = get_user_id_native(keyid);
      tty_printf ("\n");
      tty_printf (_("You need a passphrase to unlock the secret key for\n"
                    "user: \"%s\"\n"),p);
      xfree(p);

      if ( !get_pubkey( pk, keyid ) )
        {
          const char *s = openpgp_pk_algo_name ( pk->pubkey_algo );

          tty_printf (_("%u-bit %s key, ID %s, created %s"),
                      nbits_from_pk( pk ), s?s:"?", keystr(keyid),
                      strtimestamp(pk->timestamp) );
          if ( keyid[2] && keyid[3]
               && keyid[0] != keyid[2] && keyid[1] != keyid[3] )
            {
              if ( keystrlen () > 10 )
                {
                  tty_printf ("\n");
                  tty_printf (_("         (subkey on main key ID %s)"),
                              keystr(&keyid[2]) );
                }
              else
                tty_printf ( _(" (main key ID %s)"), keystr(&keyid[2]) );
            }
          tty_printf("\n");
	}

      tty_printf("\n");
      free_public_key (pk);
    }

  if ( next_pw )
    {
      /* Simply return the passphrase we already have in NEXT_PW. */
      pw = next_pw;
      next_pw = NULL;
    }
  else if ( have_static_passphrase () )
    {
      /* Return the passphrase we have stored in FD_PASSWD. */
      pw = xmalloc_secure ( strlen(fd_passwd)+1 );
      strcpy ( pw, fd_passwd );
    }
  else
    {
      if ((mode == 3 || mode == 4) && (s2k->mode == 1 || s2k->mode == 3))
	{
	  memset (s2k_cacheidbuf, 0, sizeof s2k_cacheidbuf);
	  *s2k_cacheidbuf = 'S';
	  bin2hex (s2k->salt, 8, s2k_cacheidbuf + 1);
	  s2k_cacheid = s2k_cacheidbuf;
	}

      if (opt.pinentry_mode == PINENTRY_MODE_LOOPBACK)
        {
          char buf[32];

          snprintf (buf, sizeof (buf), "%u", 100);
          write_status_text (STATUS_INQUIRE_MAXLEN, buf);
        }

      /* Divert to the gpg-agent. */
      pw = passphrase_get (keyid, mode == 2, s2k_cacheid,
                           (mode == 2 || mode == 4)? opt.passphrase_repeat : 0,
                           tryagain_text, custdesc, custprompt, canceled);
      if (*canceled)
        {
          xfree (pw);
	  write_status( STATUS_MISSING_PASSPHRASE );
          return NULL;
        }
    }

  if ( !pw || !*pw )
    write_status( STATUS_MISSING_PASSPHRASE );

  /* Hash the passphrase and store it in a newly allocated DEK object.
     Keep a copy of the passphrase in LAST_PW for use by
     get_last_passphrase(). */
  dek = xmalloc_secure_clear ( sizeof *dek );
  dek->algo = cipher_algo;
  if ( (!pw || !*pw) && (mode == 2 || mode == 4))
    dek->keylen = 0;
  else
    {
      gpg_error_t err;

      dek->keylen = openpgp_cipher_get_algo_keylen (dek->algo);
      if (!(dek->keylen > 0 && dek->keylen <= DIM(dek->key)))
        BUG ();
      err = gcry_kdf_derive (pw, strlen (pw),
                             s2k->mode == 3? GCRY_KDF_ITERSALTED_S2K :
                             s2k->mode == 1? GCRY_KDF_SALTED_S2K :
                             /* */           GCRY_KDF_SIMPLE_S2K,
                             s2k->hash_algo, s2k->salt, 8,
                             S2K_DECODE_COUNT(s2k->count),
                             dek->keylen, dek->key);
      if (err)
        {
          log_error ("gcry_kdf_derive failed: %s", gpg_strerror (err));
          xfree (pw);
          xfree (dek);
	  write_status( STATUS_MISSING_PASSPHRASE );
          return NULL;
        }
    }
  if (s2k_cacheid)
    memcpy (dek->s2k_cacheid, s2k_cacheid, sizeof dek->s2k_cacheid);
  xfree(last_pw);
  last_pw = pw;
  return dek;
}
Esempio n. 2
0
/* Return an allocated utf-8 string describing the key PK.  If ESCAPED
   is true spaces and control characters are percent or plus escaped.
   MODE describes the use of the key description; use one of the
   FORMAT_KEYDESC_ macros. */
char *
gpg_format_keydesc (PKT_public_key *pk, int mode, int escaped)
{
  char *uid;
  size_t uidlen;
  const char *algo_name;
  const char *timestr;
  char *orig_codeset;
  char *maink;
  char *desc;
  const char *prompt;
  const char *trailer = "";
  int is_subkey;

  is_subkey = (pk->main_keyid[0] && pk->main_keyid[1]
               && pk->keyid[0] != pk->main_keyid[0]
               && pk->keyid[1] != pk->main_keyid[1]);
  algo_name = openpgp_pk_algo_name (pk->pubkey_algo);
  timestr = strtimestamp (pk->timestamp);
  uid = get_user_id (is_subkey? pk->main_keyid:pk->keyid, &uidlen);

  orig_codeset = i18n_switchto_utf8 ();

  if (is_subkey)
    maink = xtryasprintf (_(" (main key ID %s)"), keystr (pk->main_keyid));
  else
    maink = NULL;

  switch (mode)
    {
    case FORMAT_KEYDESC_NORMAL:
      prompt = _("Please enter the passphrase to unlock the"
                 " OpenPGP secret key:");
      break;
    case FORMAT_KEYDESC_IMPORT:
      prompt = _("Please enter the passphrase to import the"
                 " OpenPGP secret key:");
      break;
    case FORMAT_KEYDESC_EXPORT:
      if (is_subkey)
        prompt = _("Please enter the passphrase to export the"
                   " OpenPGP secret subkey:");
      else
        prompt = _("Please enter the passphrase to export the"
                   " OpenPGP secret key:");
      break;
    case FORMAT_KEYDESC_DELKEY:
      if (is_subkey)
        prompt = _("Do you really want to permanently delete the"
                   " OpenPGP secret subkey key:");
      else
        prompt = _("Do you really want to permanently delete the"
                   " OpenPGP secret key:");
      trailer = "?";
      break;
    default:
      prompt = "?";
      break;
    }

  desc = xtryasprintf (_("%s\n"
                         "\"%.*s\"\n"
                         "%u-bit %s key, ID %s,\n"
                         "created %s%s.\n%s"),
                       prompt,
                       (int)uidlen, uid,
                       nbits_from_pk (pk), algo_name,
                       keystr (pk->keyid), timestr,
                       maink?maink:"", trailer);
  xfree (maink);
  xfree (uid);

  i18n_switchback (orig_codeset);

  if (escaped)
    {
      char *tmp = percent_plus_escape (desc);
      xfree (desc);
      desc = tmp;
    }

  return desc;
}
/****************
 * Encrypt the file with the given userids (or ask if none
 * is supplied).
 */
int
encode_crypt( const char *filename, STRLIST remusr, int use_symkey )
{
    IOBUF inp = NULL, 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;
    compress_filter_context_t zfx;
    text_filter_context_t tfx;
    progress_filter_context_t pfx;
    PK_LIST pk_list,work_list;
    int do_compress = opt.compress_algo && !RFC1991;

    memset( &cfx, 0, sizeof cfx);
    memset( &afx, 0, sizeof afx);
    memset( &zfx, 0, sizeof zfx);
    memset( &tfx, 0, sizeof tfx);
    init_packet(&pkt);

    if(use_symkey
       && (rc=setup_symkey(&symkey_s2k,&symkey_dek)))
      return rc;

    if( (rc=build_pk_list( remusr, &pk_list, PUBKEY_USAGE_ENC)) )
	return rc;

    if(PGP2) {
      for(work_list=pk_list; work_list; work_list=work_list->next)
	if(!(is_RSA(work_list->pk->pubkey_algo) &&
	     nbits_from_pk(work_list->pk)<=2048))
	  {
	    log_info(_("you can only encrypt to RSA keys of 2048 bits or "
		       "less in --pgp2 mode\n"));
	    compliance_failure();
	    break;
	  }
    }

    /* prepare iobufs */
    inp = iobuf_open(filename);
    if (inp)
      iobuf_ioctl (inp,3,1,NULL); /* disable fd caching */
    if (inp && is_secured_file (iobuf_get_fd (inp)))
      {
        iobuf_close (inp);
        inp = NULL;
        errno = EPERM;
      }
    if( !inp ) {
	log_error(_("can't open `%s': %s\n"), filename? filename: "[stdin]",
					strerror(errno) );
	rc = G10ERR_OPEN_FILE;
	goto leave;
    }
    else if( opt.verbose )
	log_info(_("reading from `%s'\n"), filename? filename: "[stdin]");

    handle_progress (&pfx, inp, filename);

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

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

    if( opt.armor )
	iobuf_push_filter( out, armor_filter, &afx );

    /* 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;

	    if( PGP2 ) {
	      log_info(_("unable to use the IDEA cipher for all of the keys "
			 "you are encrypting to.\n"));
	      compliance_failure();
	    }
	}
    }
    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"),
		 cipher_algo_to_string(opt.def_cipher_algo),
		 opt.def_cipher_algo);

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

    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.  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 && 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_CIPHER )
	log_hexdump("DEK is: ", cfx.dek->key, cfx.dek->keylen );

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

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

    if (!opt.no_literal) {
	/* setup the inner packet */
	if( filename || opt.set_filename ) {
	    char *s = make_basename( opt.set_filename ? opt.set_filename
						      : filename,
				     iobuf_get_real_fname( inp ) );
	    pt = xmalloc( sizeof *pt + strlen(s) - 1 );
	    pt->namelen = strlen(s);
	    memcpy(pt->name, s, pt->namelen );
	    xfree(s);
	}
	else { /* no filename */
	    pt = xmalloc( sizeof *pt - 1 );
	    pt->namelen = 0;
	}
    }

    if (!iobuf_is_pipe_filename (filename) && *filename && !opt.textmode )
      {
        off_t tmpsize;
        int overflow;

	if ( !(tmpsize = iobuf_get_filelength(inp, &overflow))
             && !overflow )
          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 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.textmode ? 't' : 'b';
	pt->len = filesize;
	pt->new_ctb = !pt->len && !RFC1991;
	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, cipher_filter, &cfx );

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

	if(compr_algo==-1)
	  {
	    if((compr_algo=
		select_algo_from_prefs(pk_list,PREFTYPE_ZIP,-1,NULL))==-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)
              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", g10_errstr(rc) );
    }
    else {
	/* user requested not to create a literal packet, so we copy
           the plain data */
	byte copy_buffer[4096];
	int  bytes_copied;
	while ((bytes_copied = iobuf_read(inp, copy_buffer, 4096)) != -1)
	    if (iobuf_write(out, copy_buffer, bytes_copied) == -1) {
		rc = G10ERR_WRITE_FILE;
		log_error("copying input to output failed: %s\n",
                          g10_errstr(rc) );
		break;
	    }
	wipememory(copy_buffer, 4096); /* burn 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);
    xfree(cfx.dek);
    xfree(symkey_dek);
    xfree(symkey_s2k);
    release_pk_list( pk_list );
    return rc;
}
Esempio n. 4
0
/*
 * Ask the GPG Agent for the passphrase.
 * Mode 0:  Allow cached passphrase
 *      1:  No cached passphrase; that is we are asking for a new passphrase
 *          FIXME: Only partially implemented
 *
 * Note that TRYAGAIN_TEXT must not be translated.  If CANCELED is not
 * NULL, the function does set it to 1 if the user canceled the
 * operation.  If CACHEID is not NULL, it will be used as the cacheID
 * for the gpg-agent; if is NULL and a key fingerprint can be
 * computed, this will be used as the cacheid.
 */
static char *
passphrase_get ( u32 *keyid, int mode, const char *cacheid, int repeat,
                 const char *tryagain_text,
                 const char *custom_description,
                 const char *custom_prompt, int *canceled)
{
  int rc;
  char *atext = NULL;
  char *pw = NULL;
  PKT_public_key *pk = xmalloc_clear( sizeof *pk );
  byte fpr[MAX_FINGERPRINT_LEN];
  int have_fpr = 0;
  char *orig_codeset;
  char *my_prompt;
  char hexfprbuf[20*2+1];
  const char *my_cacheid;
  int check = (mode == 1);

  if (canceled)
    *canceled = 0;

#if MAX_FINGERPRINT_LEN < 20
#error agent needs a 20 byte fingerprint
#endif

  memset (fpr, 0, MAX_FINGERPRINT_LEN );
  if( keyid && get_pubkey( pk, keyid ) )
    {
      free_public_key (pk);
      pk = NULL; /* oops: no key for some reason */
    }

  orig_codeset = i18n_switchto_utf8 ();

  if (custom_description)
    atext = native_to_utf8 (custom_description);
  else if ( !mode && pk && keyid )
    {
      char *uid;
      size_t uidlen;
      const char *algo_name = openpgp_pk_algo_name ( pk->pubkey_algo );
      const char *timestr;
      char *maink;

      if ( !algo_name )
        algo_name = "?";

      if (keyid[2] && keyid[3]
          && keyid[0] != keyid[2]
          && keyid[1] != keyid[3] )
        maink = xasprintf (_(" (main key ID %s)"), keystr (&keyid[2]));
      else
        maink = xstrdup ("");

      uid = get_user_id ( keyid, &uidlen );
      timestr = strtimestamp (pk->timestamp);

      atext = xasprintf (_("Please enter the passphrase to unlock the"
                           " secret key for the OpenPGP certificate:\n"
                           "\"%.*s\"\n"
                           "%u-bit %s key, ID %s,\n"
                           "created %s%s.\n"),
                         (int)uidlen, uid,
                         nbits_from_pk (pk), algo_name, keystr(&keyid[0]),
                         timestr, maink);
      xfree (uid);
      xfree (maink);

      {
        size_t dummy;
        fingerprint_from_pk( pk, fpr, &dummy );
        have_fpr = 1;
      }

    }
  else
    atext = xstrdup ( _("Enter passphrase\n") );


  if (!mode && cacheid)
    my_cacheid = cacheid;
  else if (!mode && have_fpr)
    my_cacheid = bin2hex (fpr, 20, hexfprbuf);
  else
    my_cacheid = NULL;

  if (tryagain_text)
    tryagain_text = _(tryagain_text);

  my_prompt = custom_prompt ? native_to_utf8 (custom_prompt): NULL;

  rc = agent_get_passphrase (my_cacheid, tryagain_text, my_prompt, atext,
                             repeat, check, &pw);

  xfree (my_prompt);
  xfree (atext); atext = NULL;

  i18n_switchback (orig_codeset);


  if (!rc)
    ;
  else if (gpg_err_code (rc) == GPG_ERR_CANCELED
            || gpg_err_code (rc) == GPG_ERR_FULLY_CANCELED)
    {
      log_info (_("cancelled by user\n") );
      if (canceled)
        *canceled = 1;
    }
  else
    {
      log_error (_("problem with the agent: %s\n"), gpg_strerror (rc));
      /* Due to limitations in the API of the upper layers they
         consider an error as no passphrase entered.  This works in
         most cases but not during key creation where this should
         definitely not happen and let it continue without requiring a
         passphrase.  Given that now all the upper layers handle a
         cancel correctly, we simply set the cancel flag now for all
         errors from the agent.  */
      if (canceled)
        *canceled = 1;

      write_status_errcode ("get_passphrase", rc);
    }

  free_public_key (pk);
  if (rc)
    {
      xfree (pw);
      return NULL;
    }
  return pw;
}
/****************
 * mode: 0 = standard
 *       1 = Without key info and additional menu option 'm'
 *           this does also add an option to set the key to ultimately trusted.
 * Returns: 
 *      -2 = nothing changed - caller should show some additional info
 *      -1 = quit operation
 *       0 = nothing changed
 *       1 = new ownertrust now in new_trust
 */
static int
do_edit_ownertrust (PKT_public_key *pk, int mode,
                    unsigned *new_trust, int defer_help )
{
  char *p;
  u32 keyid[2];
  int changed=0;
  int quit=0;
  int show=0;
  int min_num;
  int did_help=defer_help;
  unsigned int minimum=get_min_ownertrust(pk);

  switch(minimum)
    {
    default:
    case TRUST_UNDEFINED: min_num=1; break;
    case TRUST_NEVER:     min_num=2; break;
    case TRUST_MARGINAL:  min_num=3; break;
    case TRUST_FULLY:     min_num=4; break;
    }

  keyid_from_pk (pk, keyid);
  for(;;) {
    /* A string with valid answers.

       Note to translators: These are the allowed answers in lower and
       uppercase.  Below you will find the matching strings which
       should be translated accordingly and the letter changed to
       match the one in the answer string.
    
         i = please show me more information
         m = back to the main menu
         s = skip this key
	 q = quit
    */
    const char *ans = _("iImMqQsS");

    if( !did_help ) 
      {
        if( !mode ) 
          {
            KBNODE keyblock, un;

            tty_printf(_("No trust value assigned to:\n"));
	    tty_printf("%4u%c/%s %s\n",nbits_from_pk( pk ),
		       pubkey_letter( pk->pubkey_algo ),
                       keystr(keyid), datestr_from_pk( pk ) );
	    p=get_user_id_native(keyid);
	    tty_printf(_("      \"%s\"\n"),p);
	    xfree(p);

            keyblock = get_pubkeyblock (keyid);
            if (!keyblock)
                BUG ();
            for (un=keyblock; un; un = un->next)
	      {
                if (un->pkt->pkttype != PKT_USER_ID )
		  continue;
                if (un->pkt->pkt.user_id->is_revoked )
		  continue;
                if (un->pkt->pkt.user_id->is_expired )
		  continue;
		/* Only skip textual primaries */
                if (un->pkt->pkt.user_id->is_primary
		    && !un->pkt->pkt.user_id->attrib_data )
		  continue;
                
		if((opt.verify_options&VERIFY_SHOW_PHOTOS)
		   && un->pkt->pkt.user_id->attrib_data)
		  show_photos(un->pkt->pkt.user_id->attribs,
			      un->pkt->pkt.user_id->numattribs,pk,NULL);

		p=utf8_to_native(un->pkt->pkt.user_id->name,
				 un->pkt->pkt.user_id->len,0);

		tty_printf(_("  aka \"%s\"\n"),p);
	      }
        
            print_fingerprint (pk, NULL, 2);
            tty_printf("\n");
	    release_kbnode (keyblock);
          }

	if(opt.trust_model==TM_DIRECT)
	  {
	    tty_printf(_("How much do you trust that this key actually "
			 "belongs to the named user?\n"));
	    tty_printf("\n");
	  }
	else
	  {
	    /* This string also used in keyedit.c:trustsig_prompt */
	    tty_printf(_("Please decide how far you trust this user to"
			 " correctly verify other users' keys\n"
			 "(by looking at passports, checking fingerprints from"
			 " different sources, etc.)\n"));
	    tty_printf("\n");
	  }

	if(min_num<=1)
	  tty_printf (_("  %d = I don't know or won't say\n"), 1);
	if(min_num<=2)
	  tty_printf (_("  %d = I do NOT trust\n"), 2);
	if(min_num<=3)
	  tty_printf (_("  %d = I trust marginally\n"), 3);
	if(min_num<=4)
	  tty_printf (_("  %d = I trust fully\n"), 4);
        if (mode)
          tty_printf (_("  %d = I trust ultimately\n"), 5);
#if 0
	/* not yet implemented */
        tty_printf ("  i = please show me more information\n");
#endif
        if( mode )
          tty_printf(_("  m = back to the main menu\n"));
        else
	  {
	    tty_printf(_("  s = skip this key\n"));
	    tty_printf(_("  q = quit\n"));
	  }
        tty_printf("\n");
	if(minimum)
	  tty_printf(_("The minimum trust level for this key is: %s\n\n"),
		     trust_value_to_string(minimum));
        did_help = 1;
      }
    if( strlen(ans) != 8 )
      BUG();
    p = cpr_get("edit_ownertrust.value",_("Your decision? "));
    trim_spaces(p);
    cpr_kill_prompt();
    if( !*p )
      did_help = 0;
    else if( *p && p[1] )
      ;
    else if( !p[1] && ((*p >= '0'+min_num) && *p <= (mode?'5':'4')) ) 
      {
        unsigned int trust;
        switch( *p )
          {
          case '1': trust = TRUST_UNDEFINED; break;
          case '2': trust = TRUST_NEVER    ; break;
          case '3': trust = TRUST_MARGINAL ; break;
          case '4': trust = TRUST_FULLY    ; break;
          case '5': trust = TRUST_ULTIMATE ; break;
          default: BUG();
          }
        if (trust == TRUST_ULTIMATE
            && !cpr_get_answer_is_yes ("edit_ownertrust.set_ultimate.okay",
                                       _("Do you really want to set this key"
                                         " to ultimate trust? (y/N) ")))
          ; /* no */
        else
          {
            *new_trust = trust;
            changed = 1;
            break;
          }
      }
#if 0
    /* not yet implemented */
    else if( *p == ans[0] || *p == ans[1] ) 
      {
        tty_printf(_("Certificates leading to an ultimately trusted key:\n"));
        show = 1;
        break;
      }
#endif
    else if( mode && (*p == ans[2] || *p == ans[3] || *p == CONTROL_D ) ) 
      {
        break ; /* back to the menu */
      }
    else if( !mode && (*p == ans[6] || *p == ans[7] ) )
      {
	break; /* skip */
      }
    else if( !mode && (*p == ans[4] || *p == ans[5] ) )
      {
        quit = 1;
        break ; /* back to the menu */
      }
    xfree(p); p = NULL;
  }
  xfree(p);
  return show? -2: quit? -1 : changed;
}
/* This is the central function to collect the keys for recipients.
   It is thus used to prepare a public key encryption. encrypt-to
   keys, default keys and the keys for the actual recipients are all
   collected here.  When not in batch mode and no recipient has been
   passed on the commandline, the function will also ask for
   recipients.

   RCPTS is a string list with the recipients; NULL is an allowed
   value but not very useful.  Group expansion is done on these names;
   they may be in any of the user Id formats we can handle.  The flags
   bits for each string in the string list are used for:
     Bit 0: This is an encrypt-to recipient.
     Bit 1: This is a hidden recipient.

   USE is the desired use for the key - usually PUBKEY_USAGE_ENC.
   RET_PK_LIST.

   On success a list of keys is stored at the address RET_PK_LIST; the
   caller must free this list.  On error the value at this address is
   not changed.
 */
int
build_pk_list( STRLIST rcpts, PK_LIST *ret_pk_list, unsigned int use )
{
  PK_LIST pk_list = NULL;
  PKT_public_key *pk=NULL;
  int rc=0;
  int any_recipients=0;
  STRLIST rov,remusr;
  char *def_rec = NULL;

  /* Try to expand groups if any have been defined. */
  if (opt.grouplist)
    remusr = expand_group (rcpts);
  else
    remusr = rcpts;

  /* Check whether there are any recipients in the list and build the
   * list of the encrypt-to ones (we always trust them). */
  for ( rov = remusr; rov; rov = rov->next ) 
    {
      if ( !(rov->flags & 1) )
        {
          /* This is a regular recipient; i.e. not an encrypt-to
             one. */
          any_recipients = 1;

          /* Hidden recipients are not allowed while in PGP mode,
             issue a warning and switch into GnuPG mode. */
          if ((rov->flags&2) && (PGP2 || PGP6 || PGP7 || PGP8))
            {
              log_info(_("you may not use %s while in %s mode\n"),
                       "--hidden-recipient",
                       compliance_option_string());

              compliance_failure();
            }
        }
      else if ( (use & PUBKEY_USAGE_ENC) && !opt.no_encrypt_to ) 
        {
          /* Encryption has been requested and --encrypt-to has not
             been disabled.  Check this encrypt-to key. */
          pk = xmalloc_clear( sizeof *pk );
          pk->req_usage = use;

          /* We explicitly allow encrypt-to to an disabled key; thus
             we pass 1 as last argument. */
          if ( (rc = get_pubkey_byname ( pk, rov->d, NULL, NULL, 1 )) ) 
            {
              free_public_key ( pk ); pk = NULL;
              log_error (_("%s: skipped: %s\n"), rov->d, g10_errstr(rc) );
              write_status_text_and_buffer (STATUS_INV_RECP, "0 ",
                                            rov->d, strlen (rov->d), -1);
              goto fail;
            }
          else if ( !(rc=check_pubkey_algo2 (pk->pubkey_algo, use )) ) 
            {
              /* Skip the actual key if the key is already present
               * in the list.  Add it to our list if not. */
              if (key_present_in_pk_list(pk_list, pk) == 0)
                {
                  free_public_key (pk); pk = NULL;
                  log_info (_("%s: skipped: public key already present\n"),
                            rov->d);
                }
              else
                {
                  PK_LIST r;
                  r = xmalloc( sizeof *r );
                  r->pk = pk; pk = NULL;
                  r->next = pk_list;
                  r->flags = (rov->flags&2)?1:0;
                  pk_list = r;

                  /* Hidden encrypt-to recipients are not allowed while
                     in PGP mode, issue a warning and switch into
                     GnuPG mode. */
                  if ((r->flags&1) && (PGP2 || PGP6 || PGP7 || PGP8))
                    {
                      log_info(_("you may not use %s while in %s mode\n"),
                               "--hidden-encrypt-to",
                               compliance_option_string());

                      compliance_failure();
                    }
                }
            }
          else 
            {
              /* The public key is not usable for encryption or not
                 available. */
              free_public_key( pk ); pk = NULL;
              log_error(_("%s: skipped: %s\n"), rov->d, g10_errstr(rc) );
              write_status_text_and_buffer (STATUS_INV_RECP, "0 ",
                                            rov->d, strlen (rov->d), -1);
              goto fail;
            }
        }
    }

  /* If we don't have any recipients yet and we are not in batch mode
     drop into interactive selection mode. */
  if ( !any_recipients && !opt.batch ) 
    { 
      int have_def_rec;
      char *answer = NULL;
      STRLIST backlog = NULL;

      if (pk_list)
        any_recipients = 1;
      def_rec = default_recipient();
      have_def_rec = !!def_rec;
      if ( !have_def_rec )
        tty_printf(_("You did not specify a user ID. (you may use \"-r\")\n"));

      for (;;) 
        {
          rc = 0;
          xfree(answer);
          if ( have_def_rec )
            {
              /* A default recipient is taken as the first entry. */
              answer = def_rec;
              def_rec = NULL;
            }
          else if (backlog) 
            {
              /* This is part of our trick to expand and display groups. */
              answer = pop_strlist (&backlog);
            }
          else
            {
              /* Show the list of already collected recipients and ask
                 for more. */
              PK_LIST iter;

              tty_printf("\n");
              tty_printf(_("Current recipients:\n"));
              for (iter=pk_list;iter;iter=iter->next)
                {
                  u32 keyid[2];

                  keyid_from_pk(iter->pk,keyid);
                  tty_printf("%4u%c/%s %s \"",
                             nbits_from_pk(iter->pk),
                             pubkey_letter(iter->pk->pubkey_algo),
                             keystr(keyid),
                             datestr_from_pk(iter->pk));

                  if (iter->pk->user_id)
                    tty_print_utf8_string(iter->pk->user_id->name,
                                          iter->pk->user_id->len);
                  else
                    {
                      size_t n;
                      char *p = get_user_id( keyid, &n );
                      tty_print_utf8_string( p, n );
                      xfree(p);
                    }
                  tty_printf("\"\n");
                }

              answer = cpr_get_utf8("pklist.user_id.enter",
                                    _("\nEnter the user ID.  "
                                      "End with an empty line: "));
              trim_spaces(answer);
              cpr_kill_prompt();
            }
          
          if ( !answer || !*answer ) 
            {
              xfree(answer);
              break;  /* No more recipients entered - get out of loop. */
            }

          /* Do group expand here too.  The trick here is to continue
             the loop if any expansion occured.  The code above will
             then list all expanded keys. */
          if (expand_id(answer,&backlog,0))
            continue;

          /* Get and check key for the current name. */
          if (pk)
            free_public_key (pk);
          pk = xmalloc_clear( sizeof *pk );
          pk->req_usage = use;
          rc = get_pubkey_byname( pk, answer, NULL, NULL, 0 );
          if (rc)
            tty_printf(_("No such user ID.\n"));
          else if ( !(rc=check_pubkey_algo2(pk->pubkey_algo, use)) ) 
            {
              if ( have_def_rec )
                {
                  /* No validation for a default recipient. */
                  if (!key_present_in_pk_list(pk_list, pk)) 
                    {
                      free_public_key (pk); pk = NULL;
                      log_info (_("skipped: public key "
                                  "already set as default recipient\n") );
                    }
                  else
                    {
                      PK_LIST r = xmalloc (sizeof *r);
                      r->pk = pk; pk = NULL;
                      r->next = pk_list;
                      r->flags = 0; /* No throwing default ids. */
                      pk_list = r;
                    }
                  any_recipients = 1;
                  continue;
                }
              else
                { /* Check validity of this key. */
                  int trustlevel;
		    
                  trustlevel = get_validity (pk, pk->user_id);
                  if ( (trustlevel & TRUST_FLAG_DISABLED) ) 
                    {
                      tty_printf (_("Public key is disabled.\n") );
                    }
                  else if ( do_we_trust_pre (pk, trustlevel) ) 
                    {
                      /* Skip the actual key if the key is already
                       * present in the list */
                      if (!key_present_in_pk_list(pk_list, pk))
                        {
                          free_public_key(pk); pk = NULL;
                          log_info(_("skipped: public key already set\n") );
                        }
                      else
                        {
                          PK_LIST r;
                          r = xmalloc( sizeof *r );
                          r->pk = pk; pk = NULL;
                          r->next = pk_list;
                          r->flags = 0; /* No throwing interactive ids. */
                          pk_list = r;
                        }
                      any_recipients = 1;
                      continue;
                    }
                }
            }
          xfree(def_rec); def_rec = NULL;
          have_def_rec = 0;
        }
      if ( pk )
        {
          free_public_key( pk );
          pk = NULL;
        }
    }
  else if ( !any_recipients && (def_rec = default_recipient()) ) 
    {
      /* We are in batch mode and have only a default recipient. */
      pk = xmalloc_clear( sizeof *pk );
      pk->req_usage = use;

      /* The default recipient is allowed to be disabled; thus pass 1
         as last argument. */
      rc = get_pubkey_byname (pk, def_rec, NULL, NULL, 1);
      if (rc)
        log_error(_("unknown default recipient \"%s\"\n"), def_rec );
      else if ( !(rc=check_pubkey_algo2(pk->pubkey_algo, use)) ) 
        {
          /* Mark any_recipients here since the default recipient
             would have been used if it wasn't already there.  It
             doesn't really matter if we got this key from the default
             recipient or an encrypt-to. */
          any_recipients = 1;
          if (!key_present_in_pk_list(pk_list, pk))
            log_info (_("skipped: public key already set "
                        "as default recipient\n"));
          else 
            {
              PK_LIST r = xmalloc( sizeof *r );
              r->pk = pk; pk = NULL;
              r->next = pk_list;
              r->flags = 0; /* No throwing default ids. */
              pk_list = r;
            }
        }
      if ( pk )
        {
          free_public_key( pk );
          pk = NULL;
        }
      xfree(def_rec); def_rec = NULL;
    }
  else 
    {
      /* General case: Check all keys. */
      any_recipients = 0;
      for (; remusr; remusr = remusr->next ) 
        {
          if ( (remusr->flags & 1) )
            continue; /* encrypt-to keys are already handled. */

          pk = xmalloc_clear( sizeof *pk );
          pk->req_usage = use;
          if ( (rc = get_pubkey_byname( pk, remusr->d, NULL, NULL, 0 )) ) 
            {
              /* Key not found or other error. */
              free_public_key( pk ); pk = NULL;
              log_error(_("%s: skipped: %s\n"), remusr->d, g10_errstr(rc) );
              write_status_text_and_buffer (STATUS_INV_RECP, "0 ",
                                            remusr->d, strlen (remusr->d),
                                            -1);
              goto fail;
            }
          else if ( !(rc=check_pubkey_algo2(pk->pubkey_algo, use )) ) 
            {
              /* Key found and usable.  Check validity. */
              int trustlevel;
              
              trustlevel = get_validity (pk, pk->user_id);
              if ( (trustlevel & TRUST_FLAG_DISABLED) ) 
                {
                  /*Key has been disabled. */
                  free_public_key(pk); pk = NULL;
                  log_info(_("%s: skipped: public key is disabled\n"),
                           remusr->d);
                  write_status_text_and_buffer (STATUS_INV_RECP, "0 ",
                                                remusr->d,
                                                strlen (remusr->d),
                                                -1);
                  rc=G10ERR_UNU_PUBKEY;
                  goto fail;
                }
              else if ( do_we_trust_pre( pk, trustlevel ) ) 
                {
                  /* Note: do_we_trust may have changed the trustlevel */

                  /* We have at least one valid recipient. It doesn't
                   * matters if this recipient is already present. */
                  any_recipients = 1;

                  /* Skip the actual key if the key is already present
                   * in the list */
                  if (!key_present_in_pk_list(pk_list, pk)) 
                    {
                      free_public_key(pk); pk = NULL;
                      log_info(_("%s: skipped: public key already present\n"),
                               remusr->d);
                    }
                  else
                    {
                      PK_LIST r;
                      r = xmalloc( sizeof *r );
                      r->pk = pk; pk = NULL;
                      r->next = pk_list;
                      r->flags = (remusr->flags&2)?1:0;
                      pk_list = r;
                    }
                }
              else
                { /* We don't trust this key. */
                  free_public_key( pk ); pk = NULL;
                  write_status_text_and_buffer (STATUS_INV_RECP, "10 ",
                                                remusr->d,
                                                strlen (remusr->d),
                                                -1);
                  rc=G10ERR_UNU_PUBKEY;
                  goto fail;
                }
            }
          else
            {
              /* Key found but not usable for us (e.g. sign-only key). */
              free_public_key( pk ); pk = NULL;
              write_status_text_and_buffer (STATUS_INV_RECP, "0 ",
                                            remusr->d,
                                            strlen (remusr->d),
                                            -1);
              log_error(_("%s: skipped: %s\n"), remusr->d, g10_errstr(rc) );
              goto fail;
            }
        }
    }
  
  if ( !rc && !any_recipients ) 
    {
      log_error(_("no valid addressees\n"));
      write_status_text (STATUS_NO_RECP, "0");
      rc = G10ERR_NO_USER_ID;
    }
  
 fail:

  if ( rc )
    release_pk_list( pk_list );
  else
    *ret_pk_list = pk_list;
  if (opt.grouplist)
    free_strlist(remusr);
  return rc;
}
Esempio n. 7
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;
}
Esempio n. 8
0
static void
list_keyblock_colon( KBNODE keyblock, int secret )
{
    int rc = 0;
    KBNODE kbctx;
    KBNODE node;
    PKT_public_key *pk;
    PKT_secret_key *sk;
    u32 keyid[2];
    int any=0;
    int trustletter = 0;
    int ulti_hack = 0;

    /* get the keyid from the keyblock */
    node = find_kbnode( keyblock, secret? PKT_SECRET_KEY : PKT_PUBLIC_KEY );
    if( !node ) {
	log_error("Oops; key lost!\n");
	dump_kbnode( keyblock );
	return;
    }

    if( secret ) {
	pk = NULL;
	sk = node->pkt->pkt.secret_key;
	keyid_from_sk( sk, keyid );
        printf("sec:u:%u:%d:%08lX%08lX:%s:%s:::",
		    nbits_from_sk( sk ),
		    sk->pubkey_algo,
		    (ulong)keyid[0],(ulong)keyid[1],
		    colon_datestr_from_sk( sk ),
		    colon_strtime (sk->expiredate)
		    /* fixme: add LID here */ );
    }
    else {
	pk = node->pkt->pkt.public_key;
	sk = NULL;
	keyid_from_pk( pk, keyid );
        fputs( "pub:", stdout );
        trustletter = 0;
        if ( !pk->is_valid )
            putchar ('i');
        else if ( pk->is_revoked )
            putchar ('r');
        else if ( pk->has_expired )
            putchar ('e');
        else if ( opt.fast_list_mode || opt.no_expensive_trust_checks ) 
            ;
        else {
            trustletter = query_trust_info( pk, NULL );
            if( trustletter == 'u' )
                ulti_hack = 1;
            putchar(trustletter);
        }
        printf(":%u:%d:%08lX%08lX:%s:%s:",
		    nbits_from_pk( pk ),
		    pk->pubkey_algo,
		    (ulong)keyid[0],(ulong)keyid[1],
		    colon_datestr_from_pk( pk ),
		    colon_strtime (pk->expiredate) );
        if( pk->local_id )
            printf("%lu", pk->local_id );
        putchar(':');
        if( pk->local_id && !opt.fast_list_mode
            && !opt.no_expensive_trust_checks  )
            putchar( get_ownertrust_info( pk->local_id ) );
	    putchar(':');
    }
    
    if (opt.fixed_list_mode) {
        /* do not merge the first uid with the primary key */
        putchar(':');
        putchar(':');
        print_capabilities (pk, sk, keyblock);
        putchar('\n');
        if( opt.fingerprint )
            fingerprint( pk, sk );
        if( opt.with_key_data )
            print_key_data( pk, keyid );
        any = 1;
    }


    for( kbctx=NULL; (node=walk_kbnode( keyblock, &kbctx, 0)) ; ) {
	if( node->pkt->pkttype == PKT_USER_ID && !opt.fast_list_mode ) {
            /*
             * Fixme: We need a is_valid flag here too 
             */
	    if( any ) {
                if ( node->pkt->pkt.user_id->is_revoked )
        	    printf("uid:r::::::::");
		else if ( opt.no_expensive_trust_checks ) {
        	    printf("uid:::::::::");
	        }
                else {
		    byte namehash[20];

		    if( pk && !ulti_hack ) {
			if( node->pkt->pkt.user_id->photo )
			    rmd160_hash_buffer( namehash,
					    node->pkt->pkt.user_id->photo,
					    node->pkt->pkt.user_id->photolen);
			else
			    rmd160_hash_buffer( namehash,
					    node->pkt->pkt.user_id->name,
					    node->pkt->pkt.user_id->len  );
			trustletter = query_trust_info( pk, namehash );
		    }
		    else
			trustletter = 'u';
		    printf("uid:%c::::::::", trustletter);
                }
	    }
            print_string( stdout,  node->pkt->pkt.user_id->name,
                          node->pkt->pkt.user_id->len, ':' );
            putchar(':');
	    if (any)
                putchar('\n');
            else {
                putchar(':');
                print_capabilities (pk, sk, keyblock);
                putchar('\n');
		if( opt.fingerprint )
		    fingerprint( pk, sk );
		if( opt.with_key_data )
		    print_key_data( pk, keyid );
		any = 1;
	    }
	}
	else if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY ) {
	    u32 keyid2[2];
	    PKT_public_key *pk2 = node->pkt->pkt.public_key;

	    if( !any ) {
                putchar(':');
                putchar(':');
                print_capabilities (pk, sk, keyblock);
                putchar('\n');
		if( opt.fingerprint )
		    fingerprint( pk, sk ); /* of the main key */
		any = 1;
	    }

	    keyid_from_pk( pk2, keyid2 );
            fputs ("sub:", stdout );
            if ( !pk2->is_valid )
                putchar ('i');
            else if ( pk2->is_revoked )
                putchar ('r');
            else if ( pk2->has_expired )
                putchar ('e');
            else if ( opt.fast_list_mode || opt.no_expensive_trust_checks )
                ;
            else {
                printf("%c", trustletter );
            }
            printf(":%u:%d:%08lX%08lX:%s:%s:",
			nbits_from_pk( pk2 ),
			pk2->pubkey_algo,
			(ulong)keyid2[0],(ulong)keyid2[1],
			colon_datestr_from_pk( pk2 ),
			colon_strtime (pk2->expiredate)
			/* fixme: add LID and ownertrust here */
						);
            if( pk->local_id ) /* use the local_id of the main key??? */
                printf("%lu", pk->local_id );
            putchar(':');
            putchar(':');
            putchar(':');
            putchar(':');
            print_capabilities (pk2, NULL, NULL);
            putchar('\n');
	    if( opt.fingerprint > 1 )
		fingerprint( pk2, NULL );
	    if( opt.with_key_data )
		print_key_data( pk2, keyid2 );
	}
	else if( node->pkt->pkttype == PKT_SECRET_SUBKEY ) {
	    u32 keyid2[2];
	    PKT_secret_key *sk2 = node->pkt->pkt.secret_key;

	    if( !any ) {
                putchar(':');
                putchar(':');
                print_capabilities (pk, sk, keyblock);
		putchar('\n');
		if( opt.fingerprint )
		    fingerprint( pk, sk ); /* of the main key */
		any = 1;
	    }

	    keyid_from_sk( sk2, keyid2 );
            printf("ssb::%u:%d:%08lX%08lX:%s:%s:::::",
			nbits_from_sk( sk2 ),
			sk2->pubkey_algo,
			(ulong)keyid2[0],(ulong)keyid2[1],
			colon_datestr_from_sk( sk2 ),
			colon_strtime (sk2->expiredate)
                   /* fixme: add LID */ );
            print_capabilities (NULL, sk2, NULL);
            putchar ('\n');
	    if( opt.fingerprint > 1 )
		fingerprint( NULL, sk2 );
	}
	else if( opt.list_sigs && node->pkt->pkttype == PKT_SIGNATURE ) {
	    PKT_signature *sig = node->pkt->pkt.signature;
	    int sigrc;
            char *sigstr;

	    if( !any ) { /* no user id, (maybe a revocation follows)*/
		if( sig->sig_class == 0x20 )
		    fputs("[revoked]:", stdout);
		else if( sig->sig_class == 0x18 )
		    fputs("[key binding]:", stdout);
		else if( sig->sig_class == 0x28 )
		    fputs("[subkey revoked]:", stdout);
                else
                    putchar (':');
                putchar(':');
                print_capabilities (pk, sk, keyblock);
                putchar('\n');
		if( opt.fingerprint )
		    fingerprint( pk, sk );
		any=1;
	    }

	    if( sig->sig_class == 0x20 || sig->sig_class == 0x28
				       || sig->sig_class == 0x30 )
	       sigstr = "rev";
	    else if( (sig->sig_class&~3) == 0x10 )
	       sigstr = "sig";
	    else if( sig->sig_class == 0x18 )
	       sigstr = "sig";
	    else {
                printf("sig::::::::::%02x:\n",sig->sig_class );
		continue;
	    }
	    if( opt.check_sigs ) {
		fflush(stdout);
		rc = check_key_signature( keyblock, node, NULL );
		switch( rc ) {
		  case 0:		   sigrc = '!'; break;
		  case G10ERR_BAD_SIGN:    sigrc = '-'; break;
		  case G10ERR_NO_PUBKEY: 
		  case G10ERR_UNU_PUBKEY:  sigrc = '?'; break;
		  default:		   sigrc = '%'; break;
		}
	    }
	    else {
		rc = 0;
		sigrc = ' ';
	    }
            fputs( sigstr, stdout );
            putchar(':');
            if( sigrc != ' ' )
                putchar(sigrc);
            printf("::%d:%08lX%08lX:%s::::", sig->pubkey_algo,
						 (ulong)sig->keyid[0],
			   (ulong)sig->keyid[1], colon_datestr_from_sig(sig));
	    if( sigrc == '%' )
		printf("[%s] ", g10_errstr(rc) );
	    else if( sigrc == '?' )
		;
	    else if ( !opt.fast_list_mode ) {
		size_t n;
		char *p = get_user_id( sig->keyid, &n );
                print_string( stdout, p, n, ':' );
		m_free(p);
	    }
            printf(":%02x:\n", sig->sig_class );
	    /* fixme: check or list other sigs here */
	}
    }
    if( !any ) {/* oops, no user id */
        putchar(':');
        putchar(':');
        print_capabilities (pk, sk, keyblock);
	putchar('\n');
    }
}
Esempio n. 9
0
static void
list_keyblock_print ( KBNODE keyblock, int secret )
{
    int rc = 0;
    KBNODE kbctx;
    KBNODE node;
    PKT_public_key *pk;
    PKT_secret_key *sk;
    u32 keyid[2];
    int any=0;

    /* get the keyid from the keyblock */
    node = find_kbnode( keyblock, secret? PKT_SECRET_KEY : PKT_PUBLIC_KEY );
    if( !node ) {
	log_error("Oops; key lost!\n");
	dump_kbnode( keyblock );
	return;
    }

    if( secret ) {
	pk = NULL;
	sk = node->pkt->pkt.secret_key;
	keyid_from_sk( sk, keyid );
        printf("sec  %4u%c/%08lX %s ", nbits_from_sk( sk ),
				       pubkey_letter( sk->pubkey_algo ),
				       (ulong)keyid[1],
				       datestr_from_sk( sk ) );
    }
    else {
	pk = node->pkt->pkt.public_key;
	sk = NULL;
	keyid_from_pk( pk, keyid );
        printf("pub  %4u%c/%08lX %s ", nbits_from_pk( pk ),
				       pubkey_letter( pk->pubkey_algo ),
				       (ulong)keyid[1],
				       datestr_from_pk( pk ) );
    }

    for( kbctx=NULL; (node=walk_kbnode( keyblock, &kbctx, 0)) ; ) {
	if( node->pkt->pkttype == PKT_USER_ID && !opt.fast_list_mode ) {
	    if( any ) 
                printf("uid%*s", 28, "");

            if ( node->pkt->pkt.user_id->is_revoked )
                fputs ("[revoked] ", stdout);
            print_utf8_string( stdout,  node->pkt->pkt.user_id->name,
                               node->pkt->pkt.user_id->len );
	    putchar('\n');
	    if( !any ) {
		if( opt.fingerprint )
		    fingerprint( pk, sk );
		if( opt.with_key_data )
		    print_key_data( pk, keyid );
		any = 1;
	    }
	}
	else if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY ) {
	    u32 keyid2[2];
	    PKT_public_key *pk2 = node->pkt->pkt.public_key;

	    if( !any ) {
		putchar('\n');
		if( opt.fingerprint )
		    fingerprint( pk, sk ); /* of the main key */
		any = 1;
	    }

	    keyid_from_pk( pk2, keyid2 );
            printf("sub  %4u%c/%08lX %s", nbits_from_pk( pk2 ),
                   pubkey_letter( pk2->pubkey_algo ),
                   (ulong)keyid2[1],
                   datestr_from_pk( pk2 ) );
            if( pk2->expiredate ) {
                printf(_(" [expires: %s]"), expirestr_from_pk( pk2 ) );
            }
            putchar('\n');
	    if( opt.fingerprint > 1 )
		fingerprint( pk2, NULL );
	    if( opt.with_key_data )
		print_key_data( pk2, keyid2 );
	}
	else if( node->pkt->pkttype == PKT_SECRET_SUBKEY ) {
	    u32 keyid2[2];
	    PKT_secret_key *sk2 = node->pkt->pkt.secret_key;

	    if( !any ) {
		putchar('\n');
		if( opt.fingerprint )
		    fingerprint( pk, sk ); /* of the main key */
		any = 1;
	    }

	    keyid_from_sk( sk2, keyid2 );
            printf("ssb  %4u%c/%08lX %s\n", nbits_from_sk( sk2 ),
					   pubkey_letter( sk2->pubkey_algo ),
					   (ulong)keyid2[1],
					   datestr_from_sk( sk2 ) );
	    if( opt.fingerprint > 1 )
		fingerprint( NULL, sk2 );
	}
	else if( opt.list_sigs && node->pkt->pkttype == PKT_SIGNATURE ) {
	    PKT_signature *sig = node->pkt->pkt.signature;
	    int sigrc;
            char *sigstr;

	    if( !any ) { /* no user id, (maybe a revocation follows)*/
		if( sig->sig_class == 0x20 )
		    puts("[revoked]");
		else if( sig->sig_class == 0x18 )
		    puts("[key binding]");
		else if( sig->sig_class == 0x28 )
		    puts("[subkey revoked]");
		else
		    putchar('\n');
		if( opt.fingerprint )
		    fingerprint( pk, sk );
		any=1;
	    }

	    if( sig->sig_class == 0x20 || sig->sig_class == 0x28
				       || sig->sig_class == 0x30 )
	       sigstr = "rev";
	    else if( (sig->sig_class&~3) == 0x10 )
	       sigstr = "sig";
	    else if( sig->sig_class == 0x18 )
	       sigstr = "sig";
	    else {
                printf("sig                             "
		       "[unexpected signature class 0x%02x]\n",sig->sig_class );
		continue;
	    }
	    if( opt.check_sigs ) {
		fflush(stdout);
		rc = check_key_signature( keyblock, node, NULL );
		switch( rc ) {
		  case 0:		   sigrc = '!'; break;
		  case G10ERR_BAD_SIGN:    sigrc = '-'; break;
		  case G10ERR_NO_PUBKEY: 
		  case G10ERR_UNU_PUBKEY:  sigrc = '?'; break;
		  default:		   sigrc = '%'; break;
		}
	    }
	    else {
		rc = 0;
		sigrc = ' ';
	    }
            fputs( sigstr, stdout );
            printf("%c       %08lX %s  ",
		    sigrc, (ulong)sig->keyid[1], datestr_from_sig(sig));
	    if( sigrc == '%' )
		printf("[%s] ", g10_errstr(rc) );
	    else if( sigrc == '?' )
		;
	    else if ( !opt.fast_list_mode ) {
		size_t n;
		char *p = get_user_id( sig->keyid, &n );
                print_utf8_string( stdout, p, n );
		m_free(p);
	    }
	    putchar('\n');
	    /* fixme: check or list other sigs here */
	}
    }
    putchar('\n');
}
Esempio n. 10
0
/* Check a signature.
 *
 * Looks up the public key that created the signature (SIG->KEYID)
 * from the key db.  Makes sure that the signature is valid (it was
 * not created prior to the key, the public key was created in the
 * past, and the signature does not include any unsupported critical
 * features), finishes computing the hash of the signature data, and
 * checks that the signature verifies the digest.  If the key that
 * generated the signature is a subkey, this function also verifies
 * that there is a valid backsig from the subkey to the primary key.
 * Finally, if status fd is enabled and the signature class is 0x00 or
 * 0x01, then a STATUS_SIG_ID is emitted on the status fd.
 *
 * SIG is the signature to check.
 *
 * DIGEST contains a valid hash context that already includes the
 * signed data.  This function adds the relevant meta-data from the
 * signature packet to compute the final hash.  (See Section 5.2 of
 * RFC 4880: "The concatenation of the data being signed and the
 * signature data from the version number through the hashed subpacket
 * data (inclusive) is hashed.")
 *
 * If R_EXPIREDATE is not NULL, R_EXPIREDATE is set to the key's
 * expiry.
 *
 * If R_EXPIRED is not NULL, *R_EXPIRED is set to 1 if PK has expired
 * (0 otherwise).  Note: PK being expired does not cause this function
 * to fail.
 *
 * If R_REVOKED is not NULL, *R_REVOKED is set to 1 if PK has been
 * revoked (0 otherwise).  Note: PK being revoked does not cause this
 * function to fail.
 *
 * If R_PK is not NULL, the public key is stored at that address if it
 * was found; other wise NULL is stored.
 *
 * Returns 0 on success.  An error code otherwise.  */
gpg_error_t
check_signature2 (ctrl_t ctrl,
                  PKT_signature *sig, gcry_md_hd_t digest, u32 *r_expiredate,
		  int *r_expired, int *r_revoked, PKT_public_key **r_pk)
{
  int rc=0;
  PKT_public_key *pk;

  if (r_expiredate)
    *r_expiredate = 0;
  if (r_expired)
    *r_expired = 0;
  if (r_revoked)
    *r_revoked = 0;
  if (r_pk)
    *r_pk = NULL;

  pk = xtrycalloc (1, sizeof *pk);
  if (!pk)
    return gpg_error_from_syserror ();

  if  ((rc=openpgp_md_test_algo(sig->digest_algo)))
    {
      /* We don't have this digest. */
    }
  else if (!gnupg_digest_is_allowed (opt.compliance, 0, sig->digest_algo))
    {
      /* Compliance failure.  */
      log_info (_("digest algorithm '%s' may not be used in %s mode\n"),
                gcry_md_algo_name (sig->digest_algo),
                gnupg_compliance_option_string (opt.compliance));
      rc = gpg_error (GPG_ERR_DIGEST_ALGO);
    }
  else if ((rc=openpgp_pk_test_algo(sig->pubkey_algo)))
    {
      /* We don't have this pubkey algo. */
    }
  else if (!gcry_md_is_enabled (digest,sig->digest_algo))
    {
      /* Sanity check that the md has a context for the hash that the
       * sig is expecting.  This can happen if a onepass sig header
       * does not match the actual sig, and also if the clearsign
       * "Hash:" header is missing or does not match the actual sig. */
      log_info(_("WARNING: signature digest conflict in message\n"));
      rc = gpg_error (GPG_ERR_GENERAL);
    }
  else if (get_pubkey_for_sig (ctrl, pk, sig))
    rc = gpg_error (GPG_ERR_NO_PUBKEY);
  else if (!gnupg_pk_is_allowed (opt.compliance, PK_USE_VERIFICATION,
                                 pk->pubkey_algo, pk->pkey,
                                 nbits_from_pk (pk),
                                 NULL))
    {
      /* Compliance failure.  */
      log_error (_("key %s may not be used for signing in %s mode\n"),
                 keystr_from_pk (pk),
                 gnupg_compliance_option_string (opt.compliance));
      rc = gpg_error (GPG_ERR_PUBKEY_ALGO);
    }
  else if (!pk->flags.valid)
    {
      /* You cannot have a good sig from an invalid key.  */
      rc = gpg_error (GPG_ERR_BAD_PUBKEY);
    }
  else
    {
      if (r_expiredate)
        *r_expiredate = pk->expiredate;

      rc = check_signature_end (pk, sig, digest, r_expired, r_revoked, NULL);

      /* Check the backsig.  This is a back signature (0x19) from
       * the subkey on the primary key.  The idea here is that it
       * should not be possible for someone to "steal" subkeys and
       * claim them as their own.  The attacker couldn't actually
       * use the subkey, but they could try and claim ownership of
       * any signatures issued by it.  */
      if (!rc && !pk->flags.primary && pk->flags.backsig < 2)
        {
          if (!pk->flags.backsig)
            {
              log_info (_("WARNING: signing subkey %s is not"
                          " cross-certified\n"),keystr_from_pk(pk));
              log_info (_("please see %s for more information\n"),
                        "https://gnupg.org/faq/subkey-cross-certify.html");
              /* The default option --require-cross-certification
               * makes this warning an error.  */
              if (opt.flags.require_cross_cert)
                rc = gpg_error (GPG_ERR_GENERAL);
            }
          else if(pk->flags.backsig == 1)
            {
              log_info (_("WARNING: signing subkey %s has an invalid"
                          " cross-certification\n"), keystr_from_pk(pk));
              rc = gpg_error (GPG_ERR_GENERAL);
            }
        }

    }

    if( !rc && sig->sig_class < 2 && is_status_enabled() ) {
	/* This signature id works best with DLP algorithms because
	 * they use a random parameter for every signature.  Instead of
	 * this sig-id we could have also used the hash of the document
	 * and the timestamp, but the drawback of this is, that it is
	 * not possible to sign more than one identical document within
	 * one second.	Some remote batch processing applications might
	 * like this feature here.
         *
         * Note that before 2.0.10, we used RIPE-MD160 for the hash
         * and accidentally didn't include the timestamp and algorithm
         * information in the hash.  Given that this feature is not
         * commonly used and that a replay attacks detection should
         * not solely be based on this feature (because it does not
         * work with RSA), we take the freedom and switch to SHA-1
         * with 2.0.10 to take advantage of hardware supported SHA-1
         * implementations.  We also include the missing information
         * in the hash.  Note also the SIG_ID as computed by gpg 1.x
         * and gpg 2.x didn't matched either because 2.x used to print
         * MPIs not in PGP format.  */
	u32 a = sig->timestamp;
	int nsig = pubkey_get_nsig( sig->pubkey_algo );
	unsigned char *p, *buffer;
        size_t n, nbytes;
        int i;
        char hashbuf[20];  /* We use SHA-1 here.  */

      nbytes = 6;
      for (i=0; i < nsig; i++ )
        {
          if (gcry_mpi_print (GCRYMPI_FMT_USG, NULL, 0, &n, sig->data[i]))
            BUG();
          nbytes += n;
        }

      /* Make buffer large enough to be later used as output buffer.  */
      if (nbytes < 100)
        nbytes = 100;
      nbytes += 10;  /* Safety margin.  */

      /* Fill and hash buffer.  */
      buffer = p = xmalloc (nbytes);
      *p++ = sig->pubkey_algo;
      *p++ = sig->digest_algo;
      *p++ = (a >> 24) & 0xff;
      *p++ = (a >> 16) & 0xff;
      *p++ = (a >>  8) & 0xff;
      *p++ =  a & 0xff;
      nbytes -= 6;
      for (i=0; i < nsig; i++ )
        {
          if (gcry_mpi_print (GCRYMPI_FMT_PGP, p, nbytes, &n, sig->data[i]))
            BUG();
          p += n;
          nbytes -= n;
        }
      gcry_md_hash_buffer (GCRY_MD_SHA1, hashbuf, buffer, p-buffer);

      p = make_radix64_string (hashbuf, 20);
      sprintf (buffer, "%s %s %lu",
               p, strtimestamp (sig->timestamp), (ulong)sig->timestamp);
      xfree (p);
      write_status_text (STATUS_SIG_ID, buffer);
      xfree (buffer);
    }
Esempio n. 11
0
/*
 * Get the session key from a pubkey enc packet and return it in DEK,
 * which should have been allocated in secure memory by the caller.
 */
gpg_error_t
get_session_key (ctrl_t ctrl, PKT_pubkey_enc * k, DEK * dek)
{
  PKT_public_key *sk = NULL;
  int rc;

  if (DBG_CLOCK)
    log_clock ("get_session_key enter");

  rc = openpgp_pk_test_algo2 (k->pubkey_algo, PUBKEY_USAGE_ENC);
  if (rc)
    goto leave;

  if ((k->keyid[0] || k->keyid[1]) && !opt.try_all_secrets)
    {
      sk = xmalloc_clear (sizeof *sk);
      sk->pubkey_algo = k->pubkey_algo; /* We want a pubkey with this algo.  */
      if (!(rc = get_seckey (ctrl, sk, k->keyid)))
        {
          /* Check compliance.  */
          if (! gnupg_pk_is_allowed (opt.compliance, PK_USE_DECRYPTION,
                                     sk->pubkey_algo,
                                     sk->pkey, nbits_from_pk (sk), NULL))
            {
              log_info (_("key %s is not suitable for decryption"
                          " in %s mode\n"),
                        keystr_from_pk (sk),
                        gnupg_compliance_option_string (opt.compliance));
              rc = gpg_error (GPG_ERR_PUBKEY_ALGO);
            }
          else
            rc = get_it (ctrl, k, dek, sk, k->keyid);
        }
    }
  else if (opt.skip_hidden_recipients)
    rc = gpg_error (GPG_ERR_NO_SECKEY);
  else  /* Anonymous receiver: Try all available secret keys.  */
    {
      void *enum_context = NULL;
      u32 keyid[2];

      for (;;)
        {
          free_public_key (sk);
          sk = xmalloc_clear (sizeof *sk);
          rc = enum_secret_keys (ctrl, &enum_context, sk);
          if (rc)
            {
              rc = GPG_ERR_NO_SECKEY;
              break;
            }
          if (sk->pubkey_algo != k->pubkey_algo)
            continue;
          if (!(sk->pubkey_usage & PUBKEY_USAGE_ENC))
            continue;
          keyid_from_pk (sk, keyid);
          if (!opt.quiet)
            log_info (_("anonymous recipient; trying secret key %s ...\n"),
                      keystr (keyid));

          /* Check compliance.  */
          if (! gnupg_pk_is_allowed (opt.compliance, PK_USE_DECRYPTION,
                                     sk->pubkey_algo,
                                     sk->pkey, nbits_from_pk (sk), NULL))
            {
              log_info (_("key %s is not suitable for decryption"
                          " in %s mode\n"),
                          keystr_from_pk (sk),
                          gnupg_compliance_option_string (opt.compliance));
              continue;
            }

          rc = get_it (ctrl, k, dek, sk, keyid);
          if (!rc)
            {
              if (!opt.quiet)
                log_info (_("okay, we are the anonymous recipient.\n"));
              break;
            }
          else if (gpg_err_code (rc) == GPG_ERR_FULLY_CANCELED)
            break; /* Don't try any more secret keys.  */
        }
      enum_secret_keys (ctrl, &enum_context, NULL);  /* free context */
    }

 leave:
  free_public_key (sk);
  if (DBG_CLOCK)
    log_clock ("get_session_key leave");
  return rc;
}