Exemple #1
0
/* Callback function to try the unprotection from the passpharse query
   code. */
static int
try_unprotect_cb (struct pin_entry_info_s *pi)
{
  struct try_unprotect_arg_s *arg = pi->check_cb_arg;
  size_t dummy;
  gpg_error_t err;
  gnupg_isotime_t now, protected_at, tmptime;
  char *desc = NULL;

  assert (!arg->unprotected_key);

  arg->change_required = 0;
  err = agent_unprotect (arg->protected_key, pi->pin, protected_at,
                         &arg->unprotected_key, &dummy);
  if (err)
    return err;
  if (!opt.max_passphrase_days || arg->ctrl->in_passwd)
    return 0;  /* No regular passphrase change required.  */

  if (!*protected_at)
    {
      /* No protection date known - must force passphrase change.  */
      desc = xtrystrdup (_("Note: This passphrase has never been changed.%0A"
                           "Please change it now."));
      if (!desc)
        return gpg_error_from_syserror ();
    }
  else
    {
      gnupg_get_isotime (now);
      gnupg_copy_time (tmptime, protected_at);
      err = add_days_to_isotime (tmptime, opt.max_passphrase_days);
      if (err)
        return err;
      if (strcmp (now, tmptime) > 0 )
        {
          /* Passphrase "expired".  */
          desc = xtryasprintf
            (_("This passphrase has not been changed%%0A"
               "since %.4s-%.2s-%.2s.  Please change it now."),
             protected_at, protected_at+4, protected_at+6);
          if (!desc)
            return gpg_error_from_syserror ();
        }
    }

  if (desc)
    {
      /* Change required.  */
      if (opt.enforce_passphrase_constraints)
        {
          err = agent_get_confirmation (arg->ctrl, desc,
                                        _("Change passphrase"), NULL, 0);
          if (!err)
            arg->change_required = 1;
        }
      else
        {
          err = agent_get_confirmation (arg->ctrl, desc,
                                        _("Change passphrase"),
                                        _("I'll change it later"), 0);
          if (!err)
            arg->change_required = 1;
          else if (gpg_err_code (err) == GPG_ERR_CANCELED)
            err = 0;
        }
      xfree (desc);
    }

  return 0;
}
Exemple #2
0
/* Insert the given fpr into our trustdb.  We expect FPR to be an all
   uppercase hexstring of 40 characters. FLAG is either 'P' or 'C'.
   This function does first check whether that key has already been put
   into the trustdb and returns success in this case.  Before a FPR
   actually gets inserted, the user is asked by means of the Pinentry
   whether this is actual want he wants to do.  */
gpg_error_t
agent_marktrusted (ctrl_t ctrl, const char *name, const char *fpr, int flag)
{
  gpg_error_t err = 0;
  char *desc;
  char *fname;
  estream_t fp;
  char *fprformatted;
  char *nameformatted;
  int is_disabled;
  int yes_i_trust;

  /* Check whether we are at all allowed to modify the trustlist.
     This is useful so that the trustlist may be a symlink to a global
     trustlist with only admin priviliges to modify it.  Of course
     this is not a secure way of denying access, but it avoids the
     usual clicking on an Okay button most users are used to. */
  fname = make_filename (opt.homedir, "trustlist.txt", NULL);
  if ( access (fname, W_OK) && errno != ENOENT)
    {
      xfree (fname);
      return gpg_error (GPG_ERR_EPERM);
    }
  xfree (fname);

  if (!agent_istrusted (ctrl, fpr, &is_disabled))
    {
      return 0; /* We already got this fingerprint.  Silently return
                   success. */
    }

  /* This feature must explicitly been enabled. */
  if (!opt.allow_mark_trusted)
    return gpg_error (GPG_ERR_NOT_SUPPORTED);

  if (is_disabled)
    {
      /* There is an disabled entry in the trustlist.  Return an error
         so that the user won't be asked again for that one.  Changing
         this flag with the integrated marktrusted feature is and will
         not be made possible.  */
      return gpg_error (GPG_ERR_NOT_TRUSTED);
    }


  /* Insert a new one. */
  nameformatted = reformat_name (name, "%0A   ");
  if (!nameformatted)
    return gpg_error_from_syserror ();

  /* First a general question whether this is trusted.  */
  desc = xtryasprintf (
                /* TRANSLATORS: This prompt is shown by the Pinentry
                   and has one special property: A "%%0A" is used by
                   Pinentry to insert a line break.  The double
                   percent sign is actually needed because it is also
                   a printf format string.  If you need to insert a
                   plain % sign, you need to encode it as "%%25".  The
                   "%s" gets replaced by the name as stored in the
                   certificate. */
                _("Do you ultimately trust%%0A"
                  "  \"%s\"%%0A"
                  "to correctly certify user certificates?"),
                nameformatted);
  if (!desc)
    {
      xfree (nameformatted);
      return out_of_core ();
    }
  err = agent_get_confirmation (ctrl, desc, _("Yes"), _("No"), 1);
  xfree (desc);
  if (!err)
    yes_i_trust = 1;
  else if (gpg_err_code (err) == GPG_ERR_NOT_CONFIRMED)
    yes_i_trust = 0;
  else
    {
      xfree (nameformatted);
      return err;
    }


  fprformatted = insert_colons (fpr);
  if (!fprformatted)
    {
      xfree (nameformatted);
      return out_of_core ();
    }

  /* If the user trusts this certificate he has to verify the
     fingerprint of course.  */
  if (yes_i_trust)
    {
      desc = xtryasprintf
        (
         /* TRANSLATORS: This prompt is shown by the Pinentry and has
            one special property: A "%%0A" is used by Pinentry to
            insert a line break.  The double percent sign is actually
            needed because it is also a printf format string.  If you
            need to insert a plain % sign, you need to encode it as
            "%%25".  The second "%s" gets replaced by a hexdecimal
            fingerprint string whereas the first one receives the name
            as stored in the certificate. */
         _("Please verify that the certificate identified as:%%0A"
           "  \"%s\"%%0A"
           "has the fingerprint:%%0A"
           "  %s"), nameformatted, fprformatted);
      if (!desc)
        {
          xfree (fprformatted);
          xfree (nameformatted);
          return out_of_core ();
        }

      /* TRANSLATORS: "Correct" is the label of a button and intended
         to be hit if the fingerprint matches the one of the CA.  The
         other button is "the default "Cancel" of the Pinentry. */
      err = agent_get_confirmation (ctrl, desc, _("Correct"), _("Wrong"), 1);
      xfree (desc);
      if (gpg_err_code (err) == GPG_ERR_NOT_CONFIRMED)
        yes_i_trust = 0;
      else if (err)
        {
          xfree (fprformatted);
          xfree (nameformatted);
          return err;
        }
    }


  /* Now check again to avoid duplicates.  We take the lock to make
     sure that nobody else plays with our file and force a reread.  */
  lock_trusttable ();
  agent_reload_trustlist ();
  if (!agent_istrusted (ctrl, fpr, &is_disabled) || is_disabled)
    {
      unlock_trusttable ();
      xfree (fprformatted);
      xfree (nameformatted);
      return is_disabled? gpg_error (GPG_ERR_NOT_TRUSTED) : 0;
    }

  fname = make_filename (opt.homedir, "trustlist.txt", NULL);
  if ( access (fname, F_OK) && errno == ENOENT)
    {
      fp = es_fopen (fname, "wx,mode=-rw-r");
      if (!fp)
        {
          err = gpg_error_from_syserror ();
          log_error ("can't create `%s': %s\n", fname, gpg_strerror (err));
          xfree (fname);
          unlock_trusttable ();
          xfree (fprformatted);
          xfree (nameformatted);
          return err;
        }
      es_fputs (headerblurb, fp);
      es_fclose (fp);
    }
  fp = es_fopen (fname, "a+,mode=-rw-r");
  if (!fp)
    {
      err = gpg_error_from_syserror ();
      log_error ("can't open `%s': %s\n", fname, gpg_strerror (err));
      xfree (fname);
      unlock_trusttable ();
      xfree (fprformatted);
      xfree (nameformatted);
      return err;
    }

  /* Append the key. */
  es_fputs ("\n# ", fp);
  xfree (nameformatted);
  nameformatted = reformat_name (name, "\n# ");
  if (!nameformatted || strchr (name, '\n'))
    {
      /* Note that there should never be a LF in NAME but we better
         play safe and print a sanitized version in this case.  */
      es_write_sanitized (fp, name, strlen (name), NULL, NULL);
    }
  else
    es_fputs (nameformatted, fp);
  es_fprintf (fp, "\n%s%s %c\n", yes_i_trust?"":"!", fprformatted, flag);
  if (es_ferror (fp))
    err = gpg_error_from_syserror ();

  if (es_fclose (fp))
    err = gpg_error_from_syserror ();

  agent_reload_trustlist ();
  xfree (fname);
  unlock_trusttable ();
  xfree (fprformatted);
  xfree (nameformatted);
  return err;
}
static int
ask_for_card (ctrl_t ctrl, const unsigned char *shadow_info, char **r_kid)
{
  int rc, i;
  char *serialno;
  int no_card = 0;
  char *desc;
  char *want_sn, *want_kid;
  int want_sn_displen;

  *r_kid = NULL;

  rc = parse_shadow_info (shadow_info, &want_sn, &want_kid);
  if (rc)
    return rc;

  /* We assume that a 20 byte serial number is a standard one which
     has the property to have a zero in the last nibble (Due to BCD
     representation).  We don't display this '0' because it may
     confuse the user.  */
  want_sn_displen = strlen (want_sn);
  if (want_sn_displen == 20 && want_sn[19] == '0')
    want_sn_displen--;

  for (;;)
    {
      rc = agent_card_serialno (ctrl, &serialno);
      if (!rc)
        {
          log_debug ("detected card with S/N %s\n", serialno);
          i = strcmp (serialno, want_sn);
          xfree (serialno);
          serialno = NULL;
          if (!i)
            {
              xfree (want_sn);
              *r_kid = want_kid;
              return 0; /* yes, we have the correct card */
            }
        }
      else if (gpg_err_code (rc) == GPG_ERR_CARD_NOT_PRESENT)
        {
          log_debug ("no card present\n");
          rc = 0;
          no_card = 1;
        }
      else
        {
          log_error ("error accessing card: %s\n", gpg_strerror (rc));
        }

      if (!rc)
        {
          if (asprintf (&desc,
                    "%s:%%0A%%0A"
                    "  \"%.*s\"",
                        no_card
                        ? _("Please insert the card with serial number")
                        : _("Please remove the current card and "
                            "insert the one with serial number"),
                    want_sn_displen, want_sn) < 0)
            {
              rc = out_of_core ();
            }
          else
            {
              rc = agent_get_confirmation (ctrl, desc, NULL, NULL, 0);
              xfree (desc);
            }
        }
      if (rc)
        {
          xfree (want_sn);
          xfree (want_kid);
          return rc;
        }
    }
}
Exemple #4
0
/* Delete the key with GRIP from the disk after having asked for
   confirmation using DESC_TEXT.  If FORCE is set the function won't
   require a confirmation via Pinentry or warns if the key is also
   used by ssh.

   Common error codes are:
     GPG_ERR_NO_SECKEY
     GPG_ERR_KEY_ON_CARD
     GPG_ERR_NOT_CONFIRMED
*/
gpg_error_t
agent_delete_key (ctrl_t ctrl, const char *desc_text,
                  const unsigned char *grip, int force)
{
  gpg_error_t err;
  gcry_sexp_t s_skey = NULL;
  unsigned char *buf = NULL;
  size_t len;
  char *desc_text_final = NULL;
  char *comment = NULL;
  ssh_control_file_t cf = NULL;
  char hexgrip[40+4+1];
  char *default_desc = NULL;

  err = read_key_file (grip, &s_skey);
  if (gpg_err_code (err) == GPG_ERR_ENOENT)
    err = gpg_error (GPG_ERR_NO_SECKEY);
  if (err)
    goto leave;

  err = make_canon_sexp (s_skey, &buf, &len);
  if (err)
    goto leave;

  switch (agent_private_key_type (buf))
    {
    case PRIVATE_KEY_CLEAR:
    case PRIVATE_KEY_OPENPGP_NONE:
    case PRIVATE_KEY_PROTECTED:
      bin2hex (grip, 20, hexgrip);
      if (!force)
        {
          if (!desc_text)
            {
              default_desc = xtryasprintf
          (L_("Do you really want to delete the key identified by keygrip%%0A"
              "  %s%%0A  %%C%%0A?"), hexgrip);
              desc_text = default_desc;
            }

          /* Note, that we will take the comment as a C string for
             display purposes; i.e. all stuff beyond a Nul character is
             ignored.  */
          {
            gcry_sexp_t comment_sexp;

            comment_sexp = gcry_sexp_find_token (s_skey, "comment", 0);
            if (comment_sexp)
              comment = gcry_sexp_nth_string (comment_sexp, 1);
            gcry_sexp_release (comment_sexp);
          }

          if (desc_text)
            err = modify_description (desc_text, comment? comment:"", s_skey,
                                      &desc_text_final);
          if (err)
            goto leave;

          err = agent_get_confirmation (ctrl, desc_text_final,
                                        L_("Delete key"), L_("No"), 0);
          if (err)
            goto leave;

          cf = ssh_open_control_file ();
          if (cf)
            {
              if (!ssh_search_control_file (cf, hexgrip, NULL, NULL, NULL))
                {
                  err = agent_get_confirmation
                    (ctrl,
                     L_("Warning: This key is also listed for use with SSH!\n"
                        "Deleting the key might remove your ability to "
                        "access remote machines."),
                     L_("Delete key"), L_("No"), 0);
                  if (err)
                    goto leave;
                }
            }
        }
      err = remove_key_file (grip);
      break;

    case PRIVATE_KEY_SHADOWED:
      err = remove_key_file (grip);
      break;

    default:
      log_error ("invalid private key format\n");
      err = gpg_error (GPG_ERR_BAD_SECKEY);
      break;
    }

 leave:
  ssh_close_control_file (cf);
  gcry_free (comment);
  xfree (desc_text_final);
  xfree (default_desc);
  xfree (buf);
  gcry_sexp_release (s_skey);
  return err;
}