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