Exemple #1
0
/*
 * Write a pubkey-enc packet for the public key PK to OUT.
 */
int
write_pubkey_enc (ctrl_t ctrl,
                  PKT_public_key *pk, int throw_keyid, DEK *dek, iobuf_t out)
{
  PACKET pkt;
  PKT_pubkey_enc *enc;
  int rc;
  gcry_mpi_t frame;

  print_pubkey_algo_note ( pk->pubkey_algo );
  enc = xmalloc_clear ( sizeof *enc );
  enc->pubkey_algo = pk->pubkey_algo;
  keyid_from_pk( pk, enc->keyid );
  enc->throw_keyid = throw_keyid;

  /* Okay, what's going on: We have the session key somewhere in
   * the structure DEK and want to encode this session key in an
   * integer value of n bits. pubkey_nbits gives us the number of
   * bits we have to use.  We then encode the session key in some
   * way and we get it back in the big intger value FRAME.  Then
   * we use FRAME, the public key PK->PKEY and the algorithm
   * number PK->PUBKEY_ALGO and pass it to pubkey_encrypt which
   * returns the encrypted value in the array ENC->DATA.  This
   * array has a size which depends on the used algorithm (e.g. 2
   * for Elgamal).  We don't need frame anymore because we have
   * everything now in enc->data which is the passed to
   * build_packet().  */
  frame = encode_session_key (pk->pubkey_algo, dek,
                              pubkey_nbits (pk->pubkey_algo, pk->pkey));
  rc = pk_encrypt (pk->pubkey_algo, enc->data, frame, pk, pk->pkey);
  gcry_mpi_release (frame);
  if (rc)
    log_error ("pubkey_encrypt failed: %s\n", gpg_strerror (rc) );
  else
    {
      if ( opt.verbose )
        {
          char *ustr = get_user_id_string_native (ctrl, enc->keyid);
          log_info (_("%s/%s.%s encrypted for: \"%s\"\n"),
                    openpgp_pk_algo_name (enc->pubkey_algo),
                    openpgp_cipher_algo_name (dek->algo),
                    dek->use_aead? openpgp_aead_algo_name (dek->use_aead)
                    /**/         : "CFB",
                    ustr );
          xfree (ustr);
        }
      /* And write it. */
      init_packet (&pkt);
      pkt.pkttype = PKT_PUBKEY_ENC;
      pkt.pkt.pubkey_enc = enc;
      rc = build_packet (out, &pkt);
      if (rc)
        log_error ("build_packet(pubkey_enc) failed: %s\n",
                   gpg_strerror (rc));
    }
  free_pubkey_enc(enc);
  return rc;
}
Exemple #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;
}
Exemple #3
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;
}
Exemple #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;
}
Exemple #5
0
/*
 * Write pubkey-enc packets from the list of PKs to OUT.
 */
static int
write_pubkey_enc_from_list (PK_LIST pk_list, DEK *dek, iobuf_t out)
{
  PACKET pkt;
  PKT_public_key *pk;
  PKT_pubkey_enc  *enc;
  int rc;

  for ( ; pk_list; pk_list = pk_list->next )
    {
      gcry_mpi_t frame;

      pk = pk_list->pk;

      print_pubkey_algo_note ( pk->pubkey_algo );
      enc = xmalloc_clear ( sizeof *enc );
      enc->pubkey_algo = pk->pubkey_algo;
      keyid_from_pk( pk, enc->keyid );
      enc->throw_keyid = (opt.throw_keyids || (pk_list->flags&1));

      if (opt.throw_keyids && (PGP6 || PGP7 || PGP8))
        {
          log_info(_("you may not use %s while in %s mode\n"),
                   "--throw-keyids",compliance_option_string());
          compliance_failure();
        }

      /* Okay, what's going on: We have the session key somewhere in
       * the structure DEK and want to encode this session key in an
       * integer value of n bits. pubkey_nbits gives us the number of
       * bits we have to use.  We then encode the session key in some
       * way and we get it back in the big intger value FRAME.  Then
       * we use FRAME, the public key PK->PKEY and the algorithm
       * number PK->PUBKEY_ALGO and pass it to pubkey_encrypt which
       * returns the encrypted value in the array ENC->DATA.  This
       * array has a size which depends on the used algorithm (e.g. 2
       * for Elgamal).  We don't need frame anymore because we have
       * everything now in enc->data which is the passed to
       * build_packet().  */
      frame = encode_session_key (pk->pubkey_algo, dek,
                                  pubkey_nbits (pk->pubkey_algo, pk->pkey));
      rc = pk_encrypt (pk->pubkey_algo, enc->data, frame, pk, pk->pkey);
      gcry_mpi_release (frame);
      if (rc)
        log_error ("pubkey_encrypt failed: %s\n", gpg_strerror (rc) );
      else
        {
          if ( opt.verbose )
            {
              char *ustr = get_user_id_string_native (enc->keyid);
              log_info (_("%s/%s encrypted for: \"%s\"\n"),
                        openpgp_pk_algo_name (enc->pubkey_algo),
                        openpgp_cipher_algo_name (dek->algo),
                        ustr );
              xfree (ustr);
	    }
          /* And write it. */
          init_packet (&pkt);
          pkt.pkttype = PKT_PUBKEY_ENC;
          pkt.pkt.pubkey_enc = enc;
          rc = build_packet (out, &pkt);
          if (rc)
            log_error ("build_packet(pubkey_enc) failed: %s\n",
                       gpg_strerror (rc));
	}
      free_pubkey_enc(enc);
      if (rc)
        return rc;
    }
  return 0;
}