Exemple #1
0
/****************
 * Return a malloced string with a default recipient if there is any
 */
static char *
default_recipient(void)
{
    PKT_public_key *pk;
    byte fpr[MAX_FINGERPRINT_LEN+1];
    size_t n;
    char *p;
    int i;

    if( opt.def_recipient )
	return xstrdup( opt.def_recipient );
    if( !opt.def_recipient_self )
	return NULL;
    pk = xmalloc_clear( sizeof *pk );
    i = get_seckey_byname (pk, NULL);
    if( i ) {
	free_public_key( pk );
	return NULL;
    }
    n = MAX_FINGERPRINT_LEN;
    fingerprint_from_pk( pk, fpr, &n );
    free_public_key( pk );
    p = xmalloc( 2*n+3 );
    *p++ = '0';
    *p++ = 'x';
    for(i=0; i < n; i++ )
	sprintf( p+2*i, "%02X", fpr[i] );
    p -= 2;
    return p;
}
/*
 * 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 (PKT_pubkey_enc * k, DEK * dek)
{
  PKT_public_key *sk = NULL;
  int rc;

  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 (sk, k->keyid)))
        rc = get_it (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 (;;)
        {
          if (sk)
            free_public_key (sk);
          sk = xmalloc_clear (sizeof *sk);
          rc = enum_secret_keys (&enum_context, sk);
          if (rc)
            {
              rc = G10ERR_NO_SECKEY;
              break;
            }
          if (sk->pubkey_algo != k->pubkey_algo)
            continue;
          if (!(sk->pubkey_usage & PUBKEY_USAGE_ENC))
            continue;
          keyid_from_pk (sk, keyid);
          log_info (_("anonymous recipient; trying secret key %s ...\n"),
                    keystr (keyid));

          rc = get_it (k, dek, sk, keyid);
          if (!rc)
            {
              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 (&enum_context, NULL);  /* free context */
    }

leave:
  if (sk)
    free_public_key (sk);
  return rc;
}
Exemple #3
0
/*  when a X.509 certificate gets revoked, all instances of
 *  the corresponding public key must be removed
 */
void
remove_x509_public_key(/*const*/ x509cert_t *cert)
{
    const cert_t c = {FALSE, CERT_X509_SIGNATURE, {cert}};
    struct pubkey_list *p, **pp;
    struct pubkey *revoked_pk;

    revoked_pk = allocate_RSA_public_key(c);
    p          = pluto_pubkeys;
    pp         = &pluto_pubkeys;

    while(p != NULL)
   {
	if (same_RSA_public_key(&p->key->u.rsa, &revoked_pk->u.rsa))
	{
	    /* remove p from list and free memory */
	    *pp = free_public_keyentry(p);
	    loglog(RC_LOG_SERIOUS,
		"invalid RSA public key deleted");
	}
	else
	{
	    pp = &p->next;
	}
	p =*pp;
    }
    free_public_key(revoked_pk);
}
void
release_pk_list( PK_LIST pk_list )
{
    PK_LIST pk_rover;

    for( ; pk_list; pk_list = pk_rover ) {
	pk_rover = pk_list->next;
	free_public_key( pk_list->pk );
	xfree( pk_list );
    }
}
Exemple #5
0
void
release_sk_list (SK_LIST sk_list)
{
  SK_LIST sk_rover;

  for (; sk_list; sk_list = sk_rover)
    {
      sk_rover = sk_list->next;
      free_public_key (sk_list->pk);
      xfree (sk_list);
    }
}
Exemple #6
0
/*
 * Clear the cached passphrase.  If CACHEID is not NULL, it will be
 * used instead of a cache ID derived from KEYID.
 */
void
passphrase_clear_cache ( u32 *keyid, const char *cacheid, int algo )
{
  int rc;

  (void)algo;

  if (!cacheid)
    {
      PKT_public_key *pk;
#     if MAX_FINGERPRINT_LEN < 20
#       error agent needs a 20 byte fingerprint
#     endif
      byte fpr[MAX_FINGERPRINT_LEN];
      char hexfprbuf[2*20+1];
      size_t dummy;

      pk = xcalloc (1, sizeof *pk);
      if ( !keyid || get_pubkey( pk, keyid ) )
        {
          log_error ("key not found in passphrase_clear_cache\n");
          free_public_key (pk);
          return;
        }
      memset (fpr, 0, MAX_FINGERPRINT_LEN );
      fingerprint_from_pk ( pk, fpr, &dummy );
      bin2hex (fpr, 20, hexfprbuf);
      rc = agent_clear_passphrase (hexfprbuf);
      free_public_key ( pk );
    }
  else
    rc = agent_clear_passphrase (cacheid);

  if (rc)
    log_error (_("problem with the agent: %s\n"), gpg_strerror (rc));
}
Exemple #7
0
void set_up_domain_manager(domain_manager* who, public_key parent) {
  // printf("[ SETUP_DM ");
  if (parent.level == 0) {
    printf(" if %s ]\n", who->name);
    public_key temp = init_public_key(&parent);
    who->pk.ID_tuple = temp.ID_tuple;
    who->pk.level = temp.level;
    who -> MK =  create_DM(ROOT.MK, who->pk, *(ROOT.param));
    param_copy_PP(&(who->param), ROOT.param);    
  }
  else{
    // printf(" else  %s ]\n", who->name);
    domain_manager x;
    domain_manager* y = dm_from_publickey(parent);
    public_key temp1 = init_public_key(&parent);
    who->pk.ID_tuple = temp1.ID_tuple;
    who->pk.level = temp1.level;
    //x.MK
    who->MK= create_DM(y->MK, who->pk, *(ROOT.param) );
    //who->MK = x.MK;
    param_copy_PP(&(who->param),ROOT.param);
    //updateparentchildren
    
    public_key* temp = (public_key* ) malloc(sizeof(public_key) * (y->number_of_children + 1) );
    int i;
    for (i = 0; i < y->number_of_children; ++i) {
      public_key_copy(temp + i, y->children_dm  + i);
    }
    y->children_dm += 1;
    public_key_copy(temp + i, &(who->pk));

    
    for(i = 0; i < y->number_of_children  - 1; ++i) {
      free_public_key(y->children_dm  + i);
    }
    
    y->children_dm = temp;
    
  }
}
Exemple #8
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 #9
0
gpg_error_t
build_sk_list (ctrl_t ctrl,
               strlist_t locusr, SK_LIST *ret_sk_list, unsigned int use)
{
  gpg_error_t err;
  SK_LIST sk_list = NULL;

  /* XXX: Change this function to use get_pubkeys instead of
     getkey_byname to detect ambiguous key specifications and warn
     about duplicate keyblocks.  For ambiguous key specifications on
     the command line or provided interactively, prompt the user to
     select the best key.  If a key specification is ambiguous and we
     are in batch mode, die.  */

  if (!locusr) /* No user ids given - use the default key.  */
    {
      PKT_public_key *pk;

      pk = xmalloc_clear (sizeof *pk);
      pk->req_usage = use;
      if ((err = getkey_byname (ctrl, NULL, pk, NULL, 1, NULL)))
	{
	  free_public_key (pk);
	  pk = NULL;
	  log_error ("no default secret key: %s\n", gpg_strerror (err));
	  write_status_text (STATUS_INV_SGNR, get_inv_recpsgnr_code (err));
	}
      else if ((err = openpgp_pk_test_algo2 (pk->pubkey_algo, use)))
	{
	  free_public_key (pk);
	  pk = NULL;
	  log_error ("invalid default secret key: %s\n", gpg_strerror (err));
	  write_status_text (STATUS_INV_SGNR, get_inv_recpsgnr_code (err));
	}
      else
	{
	  SK_LIST r;

	  if (random_is_faked () && !is_insecure (pk))
	    {
	      log_info (_("key is not flagged as insecure - "
			  "can't use it with the faked RNG!\n"));
	      free_public_key (pk);
	      pk = NULL;
	      write_status_text (STATUS_INV_SGNR,
				 get_inv_recpsgnr_code (GPG_ERR_NOT_TRUSTED));
	    }
	  else
	    {
	      r = xmalloc (sizeof *r);
	      r->pk = pk;
	      pk = NULL;
	      r->next = sk_list;
	      r->mark = 0;
	      sk_list = r;
	    }
	}
    }
  else /* Check the given user ids.  */
    {
      strlist_t locusr_orig = locusr;

      for (; locusr; locusr = locusr->next)
	{
	  PKT_public_key *pk;

	  err = 0;
	  /* Do an early check against duplicated entries.  However
	   * this won't catch all duplicates because the user IDs may
	   * be specified in different ways.  */
	  if (is_duplicated_entry (locusr_orig, locusr))
	    {
	      log_info (_("skipped \"%s\": duplicated\n"), locusr->d);
	      continue;
	    }
	  pk = xmalloc_clear (sizeof *pk);
	  pk->req_usage = use;
          if ((err = getkey_byname (ctrl, NULL, pk, locusr->d, 1, NULL)))
	    {
	      free_public_key (pk);
	      pk = NULL;
	      log_error (_("skipped \"%s\": %s\n"),
			 locusr->d, gpg_strerror (err));
	      write_status_text_and_buffer
		(STATUS_INV_SGNR, get_inv_recpsgnr_code (err),
		 locusr->d, strlen (locusr->d), -1);
	    }
	  else if (!key_present_in_sk_list (sk_list, pk))
	    {
	      free_public_key (pk);
	      pk = NULL;
	      log_info (_("skipped: secret key already present\n"));
	    }
	  else if ((err = openpgp_pk_test_algo2 (pk->pubkey_algo, use)))
	    {
	      free_public_key (pk);
	      pk = NULL;
	      log_error ("skipped \"%s\": %s\n", locusr->d, gpg_strerror (err));
	      write_status_text_and_buffer
		(STATUS_INV_SGNR, get_inv_recpsgnr_code (err),
		 locusr->d, strlen (locusr->d), -1);
	    }
	  else
	    {
	      SK_LIST r;

	      if (pk->version == 4 && (use & PUBKEY_USAGE_SIG)
		  && pk->pubkey_algo == PUBKEY_ALGO_ELGAMAL_E)
		{
		  log_info (_("skipped \"%s\": %s\n"), locusr->d,
			    _("this is a PGP generated Elgamal key which"
			      " is not secure for signatures!"));
		  free_public_key (pk);
		  pk = NULL;
		  write_status_text_and_buffer
		    (STATUS_INV_SGNR,
		     get_inv_recpsgnr_code (GPG_ERR_WRONG_KEY_USAGE),
		     locusr->d, strlen (locusr->d), -1);
		}
	      else if (random_is_faked () && !is_insecure (pk))
		{
		  log_info (_("key is not flagged as insecure - "
			      "can't use it with the faked RNG!\n"));
		  free_public_key (pk);
		  pk = NULL;
		  write_status_text_and_buffer
		    (STATUS_INV_SGNR,
		     get_inv_recpsgnr_code (GPG_ERR_NOT_TRUSTED),
		     locusr->d, strlen (locusr->d), -1);
		}
	      else
		{
		  r = xmalloc (sizeof *r);
		  r->pk = pk;
		  pk = NULL;
		  r->next = sk_list;
		  r->mark = 0;
		  sk_list = r;
		}
	    }
	}
    }

  if (!err && !sk_list)
    {
      log_error ("no valid signators\n");
      write_status_text (STATUS_NO_SGNR, "0");
      err = gpg_error (GPG_ERR_NO_USER_ID);
    }

  if (err)
    release_sk_list (sk_list);
  else
    *ret_sk_list = sk_list;
  return err;
}
/* 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;
}
/****************
 * Check whether we can trust this signature.
 * Returns: Error if we shall not trust this signatures.
 */
int
check_signatures_trust( PKT_signature *sig )
{
  PKT_public_key *pk = xmalloc_clear( sizeof *pk );
  unsigned int trustlevel;
  int rc=0;

  rc = get_pubkey( pk, sig->keyid );
  if (rc) 
    { /* this should not happen */
      log_error("Ooops; the key vanished  - can't check the trust\n");
      rc = G10ERR_NO_PUBKEY;
      goto leave;
    }

  if ( opt.trust_model==TM_ALWAYS )
    {
      if( !opt.quiet )
        log_info(_("WARNING: Using untrusted key!\n"));
      if (opt.with_fingerprint)
        print_fingerprint (pk, NULL, 1);
      goto leave;
    }

  if(pk->maybe_revoked && !pk->is_revoked)
    log_info(_("WARNING: this key might be revoked (revocation key"
	       " not present)\n"));

  trustlevel = get_validity (pk, NULL);

  if ( (trustlevel & TRUST_FLAG_REVOKED) ) 
    {
      write_status( STATUS_KEYREVOKED );
      if(pk->is_revoked==2)
	log_info(_("WARNING: This key has been revoked by its"
		   " designated revoker!\n"));
      else
	log_info(_("WARNING: This key has been revoked by its owner!\n"));
      log_info(_("         This could mean that the signature is forged.\n"));
      show_revocation_reason( pk, 0 );
    }
  else if ((trustlevel & TRUST_FLAG_SUB_REVOKED) ) 
    {
      write_status( STATUS_KEYREVOKED );
      log_info(_("WARNING: This subkey has been revoked by its owner!\n"));
      show_revocation_reason( pk, 0 );
    }
  
  if ((trustlevel & TRUST_FLAG_DISABLED))
    log_info (_("Note: This key has been disabled.\n"));

  /* If we have PKA information adjust the trustlevel. */
  if (sig->pka_info && sig->pka_info->valid)
    {
      unsigned char fpr[MAX_FINGERPRINT_LEN];
      PKT_public_key *primary_pk;
      size_t fprlen;
      int okay;


      primary_pk = xmalloc_clear (sizeof *primary_pk);
      get_pubkey (primary_pk, pk->main_keyid);
      fingerprint_from_pk (primary_pk, fpr, &fprlen);
      free_public_key (primary_pk);

      if ( fprlen == 20 && !memcmp (sig->pka_info->fpr, fpr, 20) )
        {
          okay = 1;
          write_status_text (STATUS_PKA_TRUST_GOOD, sig->pka_info->email);
          log_info (_("Note: Verified signer's address is `%s'\n"),
                    sig->pka_info->email);
        }
      else
        {
          okay = 0;
          write_status_text (STATUS_PKA_TRUST_BAD, sig->pka_info->email);
          log_info (_("Note: Signer's address `%s' "
                      "does not match DNS entry\n"), sig->pka_info->email);
        }

      switch ( (trustlevel & TRUST_MASK) ) 
        {
        case TRUST_UNKNOWN: 
        case TRUST_UNDEFINED:
        case TRUST_MARGINAL:
          if (okay && opt.verify_options&VERIFY_PKA_TRUST_INCREASE)
            {
              trustlevel = ((trustlevel & ~TRUST_MASK) | TRUST_FULLY);
              log_info (_("trustlevel adjusted to FULL"
                          " due to valid PKA info\n"));
            }
          /* (fall through) */
        case TRUST_FULLY:
          if (!okay)
            {
              trustlevel = ((trustlevel & ~TRUST_MASK) | TRUST_NEVER);
              log_info (_("trustlevel adjusted to NEVER"
                          " due to bad PKA info\n"));
            }
          break;
        }
    }

  /* Now let the user know what up with the trustlevel. */
  switch ( (trustlevel & TRUST_MASK) ) 
    {
    case TRUST_EXPIRED:
      log_info(_("Note: This key has expired!\n"));
      print_fingerprint (pk, NULL, 1);
      break;
        
    default:
      log_error ("invalid trustlevel %u returned from validation layer\n",
                 trustlevel);
      /* fall thru */
    case TRUST_UNKNOWN: 
    case TRUST_UNDEFINED:
      write_status( STATUS_TRUST_UNDEFINED );
      log_info(_("WARNING: This key is not certified with"
                 " a trusted signature!\n"));
      log_info(_("         There is no indication that the "
                 "signature belongs to the owner.\n" ));
      print_fingerprint (pk, NULL, 1);
      break;

    case TRUST_NEVER:
      /* currently we won't get that status */
      write_status( STATUS_TRUST_NEVER );
      log_info(_("WARNING: We do NOT trust this key!\n"));
      log_info(_("         The signature is probably a FORGERY.\n"));
      if (opt.with_fingerprint)
        print_fingerprint (pk, NULL, 1);
      rc = G10ERR_BAD_SIGN;
      break;

    case TRUST_MARGINAL:
      write_status( STATUS_TRUST_MARGINAL );
      log_info(_("WARNING: This key is not certified with"
                 " sufficiently trusted signatures!\n"));
      log_info(_("         It is not certain that the"
                 " signature belongs to the owner.\n" ));
      print_fingerprint (pk, NULL, 1);
      break;

    case TRUST_FULLY:
      write_status( STATUS_TRUST_FULLY );
      if (opt.with_fingerprint)
        print_fingerprint (pk, NULL, 1);
      break;

    case TRUST_ULTIMATE:
      write_status( STATUS_TRUST_ULTIMATE );
      if (opt.with_fingerprint)
        print_fingerprint (pk, NULL, 1);
      break;
    }

 leave:
  free_public_key( pk );
  return rc;
}
int
signature_check2( PKT_signature *sig, MD_HANDLE digest, u32 *r_expiredate, 
		  int *r_expired, int *r_revoked, PKT_public_key *ret_pk )
{
    PKT_public_key *pk = xmalloc_clear( sizeof *pk );
    int rc=0;

    if( (rc=check_digest_algo(sig->digest_algo)) )
      ; /* we don't have this digest */
    else if((rc=check_pubkey_algo(sig->pubkey_algo)))
      ; /* we don't have this pubkey algo */
    else if(!md_algo_present(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=G10ERR_GENERAL;
      }
    else if( get_pubkey( pk, sig->keyid ) )
	rc = G10ERR_NO_PUBKEY;
    else if(!pk->is_valid && !pk->is_primary)
        rc=G10ERR_BAD_PUBKEY; /* you cannot have a good sig from an
				 invalid subkey */
    else
      {
        if(r_expiredate)
	  *r_expiredate = pk->expiredate;

	rc = do_check( pk, sig, digest, r_expired, r_revoked, ret_pk );

	/* Check the backsig.  This is a 0x19 signature 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
	   signaures issued by it. */
	if(rc==0 && !pk->is_primary && pk->backsig<2)
	  {
	    if(pk->backsig==0)
	      {
		log_info(_("WARNING: signing subkey %s is not"
			   " cross-certified\n"),keystr_from_pk(pk));
		log_info(_("please see %s for more information\n"),
			 "http://www.gnupg.org/faq/subkey-cross-certify.html");
		/* --require-cross-certification makes this warning an
                     error.  TODO: change the default to require this
                     after more keys have backsigs. */
		if(opt.flags.require_cross_cert)
		  rc=G10ERR_GENERAL;
	      }
	    else if(pk->backsig==1)
	      {
		log_info(_("WARNING: signing subkey %s has an invalid"
			   " cross-certification\n"),keystr_from_pk(pk));
		rc=G10ERR_GENERAL;
	      }
	  }
      }

    free_public_key( pk );

    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 */
	MD_HANDLE md;
	u32 a = sig->timestamp;
	int i, nsig = pubkey_get_nsig( sig->pubkey_algo );
	byte *p, *buffer;

	md = md_open( DIGEST_ALGO_RMD160, 0);
	md_putc( digest, sig->pubkey_algo );
	md_putc( digest, sig->digest_algo );
	md_putc( digest, (a >> 24) & 0xff );
	md_putc( digest, (a >> 16) & 0xff );
	md_putc( digest, (a >>	8) & 0xff );
	md_putc( digest,  a	   & 0xff );
	for(i=0; i < nsig; i++ ) {
	    unsigned n = mpi_get_nbits( sig->data[i]);

	    md_putc( md, n>>8);
	    md_putc( md, n );
	    p = mpi_get_buffer( sig->data[i], &n, NULL );
	    md_write( md, p, n );
	    xfree(p);
	}
	md_final( md );
	p = make_radix64_string( md_read( md, 0 ), 20 );
	buffer = xmalloc( strlen(p) + 60 );
	sprintf( buffer, "%s %s %lu",
		 p, strtimestamp( sig->timestamp ), (ulong)sig->timestamp );
	write_status_text( STATUS_SIG_ID, buffer );
	xfree(buffer);
	xfree(p);
	md_close(md);
    }
Exemple #13
0
int
signature_check2 (PKT_signature *sig, gcry_md_hd_t digest, u32 *r_expiredate, 
		  int *r_expired, int *r_revoked, PKT_public_key *ret_pk )
{
    PKT_public_key *pk = xmalloc_clear( sizeof *pk );
    int rc=0;

    if ( (rc=openpgp_md_test_algo(sig->digest_algo)) )
      ; /* We don't have this digest. */
    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=G10ERR_GENERAL;
      }
    else if( get_pubkey( pk, sig->keyid ) )
	rc = G10ERR_NO_PUBKEY;
    else if(!pk->is_valid && !pk->is_primary)
        rc=G10ERR_BAD_PUBKEY; /* you cannot have a good sig from an
				 invalid subkey */
    else
      {
        if(r_expiredate)
	  *r_expiredate = pk->expiredate;

	rc = do_check( pk, sig, digest, r_expired, r_revoked, ret_pk );

	/* Check the backsig.  This is a 0x19 signature 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
	   signaures issued by it. */
	if(rc==0 && !pk->is_primary && pk->backsig<2)
	  {
	    if(pk->backsig==0)
	      {
		log_info(_("WARNING: signing subkey %s is not"
			   " cross-certified\n"),keystr_from_pk(pk));
		log_info(_("please see %s for more information\n"),
			 "http://www.gnupg.org/faq/subkey-cross-certify.html");
		/* --require-cross-certification makes this warning an
                     error.  TODO: change the default to require this
                     after more keys have backsigs. */
		if(opt.flags.require_cross_cert)
		  rc=G10ERR_GENERAL;
	      }
	    else if(pk->backsig==1)
	      {
		log_info(_("WARNING: signing subkey %s has an invalid"
			   " cross-certification\n"),keystr_from_pk(pk));
		rc=G10ERR_GENERAL;
	      }
	  }
      }

    free_public_key( pk );

    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 accidently 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];

        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);
    }
Exemple #14
0
static int
get_it( PKT_pubkey_enc *k, DEK *dek, PKT_secret_key *sk, u32 *keyid )
{
    int rc;
    MPI plain_dek  = NULL;
    byte *frame = NULL;
    unsigned n, nframe;
    u16 csum, csum2;

    rc = pubkey_decrypt(sk->pubkey_algo, &plain_dek, k->data, sk->skey );
    if( rc )
	goto leave;
    frame = mpi_get_buffer( plain_dek, &nframe, NULL );
    mpi_free( plain_dek ); plain_dek = NULL;

    /* Now get the DEK (data encryption key) from the frame
     *
     * Old versions encode the DEK in in this format (msb is left):
     *
     *	   0  1  DEK(16 bytes)	CSUM(2 bytes)  0  RND(n bytes) 2
     *
     * Later versions encode the DEK like this:
     *
     *	   0  2  RND(n bytes)  0  A  DEK(k bytes)  CSUM(2 bytes)
     *
     * (mpi_get_buffer already removed the leading zero).
     *
     * RND are non-zero randow bytes.
     * A   is the cipher algorithm
     * DEK is the encryption key (session key) with length k
     * CSUM
     */
    if( DBG_CIPHER )
	log_hexdump("DEK frame:", frame, nframe );
    n=0;
    if( n + 7 > nframe )
	{ rc = G10ERR_WRONG_SECKEY; goto leave; }
    if( frame[n] == 1 && frame[nframe-1] == 2 ) {
	log_info(_("old encoding of the DEK is not supported\n"));
	rc = G10ERR_CIPHER_ALGO;
	goto leave;
    }
    if( frame[n] != 2 )  /* somethink is wrong */
	{ rc = G10ERR_WRONG_SECKEY; goto leave; }
    for(n++; n < nframe && frame[n]; n++ ) /* skip the random bytes */
	;
    n++; /* and the zero byte */
    if( n + 4 > nframe )
	{ rc = G10ERR_WRONG_SECKEY; goto leave; }

    dek->keylen = nframe - (n+1) - 2;
    dek->algo = frame[n++];
    if( dek->algo ==  CIPHER_ALGO_IDEA )
	write_status(STATUS_RSA_OR_IDEA);
    rc = check_cipher_algo( dek->algo );
    if( rc ) {
	if( !opt.quiet && rc == G10ERR_CIPHER_ALGO ) {
	    log_info(_("cipher algorithm %d is unknown or disabled\n"),
							    dek->algo);
	}
	dek->algo = 0;
	goto leave;
    }
    if( (dek->keylen*8) != cipher_get_keylen( dek->algo ) ) {
	rc = G10ERR_WRONG_SECKEY;
	goto leave;
    }

    /* copy the key to DEK and compare the checksum */
    csum  = frame[nframe-2] << 8;
    csum |= frame[nframe-1];
    memcpy( dek->key, frame+n, dek->keylen );
    for( csum2=0, n=0; n < dek->keylen; n++ )
	csum2 += dek->key[n];
    if( csum != csum2 ) {
	rc = G10ERR_WRONG_SECKEY;
	goto leave;
    }
    if( DBG_CIPHER )
	log_hexdump("DEK is:", dek->key, dek->keylen );
    /* check that the algo is in the preferences and whether it has expired */
    {
	PKT_public_key *pk = m_alloc_clear( sizeof *pk );
	if( (rc = get_pubkey( pk, keyid )) )
	    log_error("public key problem: %s\n", g10_errstr(rc) );
	else if( !pk->local_id && query_trust_record(pk) )
	    log_error("can't check algorithm against preferences\n");
	else if( dek->algo != CIPHER_ALGO_3DES
	    && !is_algo_in_prefs( pk->local_id, PREFTYPE_SYM, dek->algo ) ) {
	    /* Don't print a note while we are not on verbose mode,
	     * the cipher is blowfish and the preferences have twofish
	     * listed */
	    if( opt.verbose || dek->algo != CIPHER_ALGO_BLOWFISH
		|| !is_algo_in_prefs( pk->local_id, PREFTYPE_SYM,
						    CIPHER_ALGO_TWOFISH ) )
		log_info(_(
		    "NOTE: cipher algorithm %d not found in preferences\n"),
								 dek->algo );
	}


	if( !rc && pk->expiredate && pk->expiredate <= make_timestamp() ) {
	    log_info(_("NOTE: secret key %08lX expired at %s\n"),
			   (ulong)keyid[1], asctimestamp( pk->expiredate) );
	}

	/* FIXME: check wheter the key has been revoked and display
	 * the revocation reason.  Actually the user should know this himself,
	 * but the sender might not know already and therefor the user
	 * should get a notice that an revoked key has been used to decode
	 * the message.  The user can than watch out for snakes send by
	 * one of those Eves outside his paradise :-)
	 */
	free_public_key( pk );
	rc = 0;
    }


  leave:
    mpi_free(plain_dek);
    m_free(frame);
    return rc;
}
Exemple #15
0
/* Helper for build_pk_list to find and check one key.  This helper is
   also used directly in server mode by the RECIPIENTS command.  On
   success the new key is added to PK_LIST_ADDR.  NAME is the user id
   of the key. USE the requested usage and a set MARK_HIDDEN will mark
   the key in the updated list as a hidden recipient. */
gpg_error_t
find_and_check_key (ctrl_t ctrl, const char *name, unsigned int use,
                    int mark_hidden, pk_list_t *pk_list_addr)
{
  int rc;
  PKT_public_key *pk;
  int trustlevel;

  if (!name || !*name)
    return gpg_error (GPG_ERR_INV_USER_ID);

  pk = xtrycalloc (1, sizeof *pk);
  if (!pk)
    return gpg_error_from_syserror ();
  pk->req_usage = use;

  rc = get_pubkey_byname (ctrl, NULL, pk, name, NULL, NULL, 0, 0);
  if (rc)
    {
      /* Key not found or other error. */
      log_error (_("%s: skipped: %s\n"), name, g10_errstr(rc) );
      send_status_inv_recp (0, name);
      free_public_key (pk);
      return rc;
    }

  rc = openpgp_pk_test_algo2 (pk->pubkey_algo, use);
  if (rc)
    {
      /* Key found but not usable for us (e.g. sign-only key). */
      send_status_inv_recp (0, name);
      log_error (_("%s: skipped: %s\n"), name, g10_errstr(rc) );
      free_public_key (pk);
      return rc;
    }

  /* Key found and usable.  Check validity. */
  trustlevel = get_validity (pk, pk->user_id);
  if ( (trustlevel & TRUST_FLAG_DISABLED) )
    {
      /* Key has been disabled. */
      send_status_inv_recp (0, name);
      log_info (_("%s: skipped: public key is disabled\n"), name);
      free_public_key (pk);
      return G10ERR_UNU_PUBKEY;
    }

  if ( !do_we_trust_pre (pk, trustlevel) )
    {
      /* We don't trust this key.  */
      send_status_inv_recp (10, name);
      free_public_key (pk);
      return G10ERR_UNU_PUBKEY;
    }
  /* Note: do_we_trust may have changed the trustlevel. */

  /* Skip the actual key if the key is already present in the
     list.  */
  if (!key_present_in_pk_list (*pk_list_addr, pk))
    {
      log_info (_("%s: skipped: public key already present\n"), name);
      free_public_key (pk);
    }
  else
    {
      pk_list_t r;

      r = xtrymalloc (sizeof *r);
      if (!r)
        {
          rc = gpg_error_from_syserror ();
          free_public_key (pk);
          return rc;
        }
      r->pk = pk;
      r->next = *pk_list_addr;
      r->flags = mark_hidden? 1:0;
      *pk_list_addr = r;
    }

  return 0;
}
Exemple #16
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;
}
Exemple #17
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 #18
0
int
signature_check2( PKT_signature *sig, MD_HANDLE digest,
		  u32 *r_expiredate, int *r_expired )
{
    PKT_public_key *pk = m_alloc_clear( sizeof *pk );
    int rc=0;

    *r_expiredate = 0;

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

    if(!md_algo_present(digest,sig->digest_algo)) {
        log_info(_("WARNING: signature digest conflict in message\n"));
	rc=G10ERR_BAD_SIGN;
    }
    else if( get_pubkey( pk, sig->keyid ) )
	rc = G10ERR_NO_PUBKEY;
    else if(!pk->is_valid && !pk->is_primary)
        rc=G10ERR_BAD_PUBKEY; /* you cannot have a good sig from an
				 invalid subkey */
    else {
	*r_expiredate = pk->expiredate;
	rc = do_check( pk, sig, digest, r_expired );
    }

    free_public_key( pk );

    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 */
	MD_HANDLE md;
	u32 a = sig->timestamp;
	int i, nsig = pubkey_get_nsig( sig->pubkey_algo );
	byte *p, *buffer;

	md = md_open( DIGEST_ALGO_RMD160, 0);
	md_putc( digest, sig->pubkey_algo );
	md_putc( digest, sig->digest_algo );
	md_putc( digest, (a >> 24) & 0xff );
	md_putc( digest, (a >> 16) & 0xff );
	md_putc( digest, (a >>	8) & 0xff );
	md_putc( digest,  a	   & 0xff );
	for(i=0; i < nsig; i++ ) {
	    unsigned n = mpi_get_nbits( sig->data[i]);

	    md_putc( md, n>>8);
	    md_putc( md, n );
	    p = mpi_get_buffer( sig->data[i], &n, NULL );
	    md_write( md, p, n );
	    m_free(p);
	}
	md_final( md );
	p = make_radix64_string( md_read( md, 0 ), 20 );
	buffer = m_alloc( strlen(p) + 60 );
	sprintf( buffer, "%s %s %lu",
		 p, strtimestamp( sig->timestamp ), (ulong)sig->timestamp );
	write_status_text( STATUS_SIG_ID, buffer );
	m_free(buffer);
	m_free(p);
	md_close(md);
    }