Esempio n. 1
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 (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;
}
Esempio n. 2
0
static void
initialize(void)
{
    /* The data buffer is allocated somewhat larger, so that
     * we can use this extra space (which is allocated in secure memory)
     * as a temporary hash buffer */
    rndpool = secure_alloc ? xmalloc_secure_clear(POOLSIZE+BLOCKLEN)
              : xmalloc_clear(POOLSIZE+BLOCKLEN);
    keypool = secure_alloc ? xmalloc_secure_clear(POOLSIZE+BLOCKLEN)
              : xmalloc_clear(POOLSIZE+BLOCKLEN);
    is_initialized = 1;
}
static void
encode_seskey( DEK *dek, DEK **seskey, byte *enckey )
{
    CIPHER_HANDLE hd;
    byte buf[33];

    assert ( dek->keylen <= 32 );
    if(!*seskey)
      {
	*seskey=xmalloc_clear(sizeof(DEK));
	(*seskey)->keylen=dek->keylen;
	(*seskey)->algo=dek->algo;
	make_session_key(*seskey);
	/*log_hexdump( "thekey", c->key, c->keylen );*/
      }

    buf[0] = (*seskey)->algo;
    memcpy( buf + 1, (*seskey)->key, (*seskey)->keylen );
    
    hd = cipher_open( dek->algo, CIPHER_MODE_CFB, 1 );
    cipher_setkey( hd, dek->key, dek->keylen );
    cipher_setiv( hd, NULL, 0 );
    cipher_encrypt( hd, buf, buf, (*seskey)->keylen + 1 );
    cipher_close( hd );

    memcpy( enckey, buf, (*seskey)->keylen + 1 );
    wipememory( buf, sizeof buf ); /* burn key */
}
/****************
 * Return a malloced string with a default reciepient if there is any
 */
static char *
default_recipient(void)
{
    PKT_secret_key *sk;
    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;
    sk = xmalloc_clear( sizeof *sk );
    i = get_seckey_byname( sk, NULL, 0 );
    if( i ) {
	free_secret_key( sk );
	return NULL;
    }
    n = MAX_FINGERPRINT_LEN;
    fingerprint_from_sk( sk, fpr, &n );
    free_secret_key( sk );
    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;
}
static int
write_symkey_enc(STRING2KEY *symkey_s2k,DEK *symkey_dek,DEK *dek,IOBUF out)
{
  int rc,seskeylen=cipher_get_keylen(dek->algo)/8;

  PKT_symkey_enc *enc;
  byte enckey[33];
  PACKET pkt;

  enc=xmalloc_clear(sizeof(PKT_symkey_enc)+seskeylen+1);
  encode_seskey(symkey_dek,&dek,enckey);

  enc->version = 4;
  enc->cipher_algo = opt.s2k_cipher_algo;
  enc->s2k = *symkey_s2k;
  enc->seskeylen = seskeylen + 1; /* algo id */
  memcpy( enc->seskey, enckey, seskeylen + 1 );

  pkt.pkttype = PKT_SYMKEY_ENC;
  pkt.pkt.symkey_enc = enc;

  if((rc=build_packet(out,&pkt)))
    log_error("build symkey_enc packet failed: %s\n",g10_errstr(rc));

  xfree(enc);
  return rc;
}
Esempio n. 6
0
static void
encrypt_seskey (DEK *dek, DEK **seskey, byte *enckey)
{
  gcry_cipher_hd_t hd;
  byte buf[33];

  assert ( dek->keylen <= 32 );
  if (!*seskey)
    {
      *seskey=xmalloc_clear(sizeof(DEK));
      (*seskey)->keylen=dek->keylen;
      (*seskey)->algo=dek->algo;
      make_session_key(*seskey);
      /*log_hexdump( "thekey", c->key, c->keylen );*/
    }

  /* The encrypted session key is prefixed with a one-octet algorithm id.  */
  buf[0] = (*seskey)->algo;
  memcpy( buf + 1, (*seskey)->key, (*seskey)->keylen );

  /* We only pass already checked values to the following fucntion,
     thus we consider any failure as fatal.  */
  if (openpgp_cipher_open (&hd, dek->algo, GCRY_CIPHER_MODE_CFB, 1))
    BUG ();
  if (gcry_cipher_setkey (hd, dek->key, dek->keylen))
    BUG ();
  gcry_cipher_setiv (hd, NULL, 0);
  gcry_cipher_encrypt (hd, buf, (*seskey)->keylen + 1, NULL, 0);
  gcry_cipher_close (hd);

  memcpy( enckey, buf, (*seskey)->keylen + 1 );
  wipememory( buf, sizeof buf ); /* burn key */
}
Esempio n. 7
0
static struct off_item *
new_offset_item (void)
{
  struct off_item *k;
  
  k = xmalloc_clear (sizeof *k);
  return k;
}
Esempio n. 8
0
/* Allocate a new value for a key present hash table.  */
static struct key_present *
key_present_value_new (void)
{
  struct key_present *k;

  k = xmalloc_clear (sizeof *k);
  return k;
}
Esempio n. 9
0
static OffsetHashTable 
new_offset_hash_table (void)
{
  struct off_item **tbl;

  tbl = xmalloc_clear (2048 * sizeof *tbl);
  return tbl;
}
Esempio n. 10
0
/* Allocate a new key present hash table.  */
static key_present_hash_t
key_present_hash_new (void)
{
  struct key_present **tbl;

  tbl = xmalloc_clear (KEY_PRESENT_HASH_BUCKETS * sizeof *tbl);
  return tbl;
}
Esempio n. 11
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;
}
/* This is actually not used anymore but we keep a list of already 
 * set extensions modules here.   
 *
 * Here is the ancient comment:
 * Register an extension module.  The last registered module will
 * be loaded first.  A name may have a list of classes
 * appended; e.g:
 *	mymodule.so(1:17,3:20,3:109)
 * means that this module provides digest algorithm 17 and public key
 * algorithms 20 and 109.  This is only a hint but if it is there the
 * loader may decide to only load a module which claims to have a
 * requested algorithm.
 *
 * mainpgm is the path to the program which wants to load a module
 * it is only used in some environments.
 */
void
register_cipher_extension( const char *mainpgm, const char *fname )
{
    EXTLIST r, el, intex;
    char *p, *pe;

    if( *fname != DIRSEP_C ) { /* do tilde expansion etc */
	char *tmp;

	if( strchr(fname, DIRSEP_C) )
	    tmp = make_filename(fname, NULL);
	else
	    tmp = make_filename(GNUPG_LIBDIR, fname, NULL);
	el = xmalloc_clear( sizeof *el + strlen(tmp) );
	strcpy(el->name, tmp );
	xfree(tmp);
    }
    else {
	el = xmalloc_clear( sizeof *el + strlen(fname) );
	strcpy(el->name, fname );
    }
    /* check whether we have a class hint */
    if( (p=strchr(el->name,'(')) && (pe=strchr(p+1,')')) && !pe[1] )
	*p = *pe = 0;

    /* check that it is not already registered */
    intex = NULL;
    for(r = extensions; r; r = r->next ) {
	if( !compare_filenames(r->name, el->name) ) {
	    log_info("extension `%s' already registered\n", el->name );
	    xfree(el);
	    return;
	}
    }
    /* and register */
    el->next = extensions;
    extensions = el;
}
Esempio n. 13
0
/* Create a new handle for the resource associated with TOKEN.  SECRET
   is just just as a cross-check.
   
   The returned handle must be released using keyring_release (). */
KEYRING_HANDLE
keyring_new (void *token, int secret)
{
  KEYRING_HANDLE hd;
  KR_NAME resource = token;

  assert (resource && !resource->secret == !secret);
  
  hd = xmalloc_clear (sizeof *hd);
  hd->resource = resource;
  hd->secret = !!secret;
  active_handles++;
  return hd;
}
Esempio n. 14
0
KEYDB_HANDLE
keydb_new (void)
{
  KEYDB_HANDLE hd;
  int i, j;

  if (DBG_CLOCK)
    log_clock ("keydb_new");

  hd = xmalloc_clear (sizeof *hd);
  hd->found = -1;

  assert (used_resources <= MAX_KEYDB_RESOURCES);
  for (i=j=0; i < used_resources; i++)
    {
      switch (all_resources[i].type)
        {
        case KEYDB_RESOURCE_TYPE_NONE: /* ignore */
          break;
        case KEYDB_RESOURCE_TYPE_KEYRING:
          hd->active[j].type   = all_resources[i].type;
          hd->active[j].token  = all_resources[i].token;
          hd->active[j].u.kr = keyring_new (all_resources[i].token);
          if (!hd->active[j].u.kr) {
            xfree (hd);
            return NULL; /* fixme: release all previously allocated handles*/
          }
          j++;
          break;
        case KEYDB_RESOURCE_TYPE_KEYBOX:
          hd->active[j].type   = all_resources[i].type;
          hd->active[j].token  = all_resources[i].token;
          hd->active[j].u.kb   = keybox_new (all_resources[i].token, 0);
          if (!hd->active[j].u.kb)
            {
              xfree (hd);
              return NULL; /* fixme: release all previously allocated handles*/
            }
          j++;
          break;
        }
    }
  hd->used = j;

  active_handles++;
  return hd;
}
Esempio n. 15
0
int
child_deliver(struct child *child, struct io *pio)
{
	struct child_deliver_data	*data = child->data;
	struct account			*a = data->account;
	struct mail			*m = data->mail;
	struct msg			 msg;
	struct msgbuf			 msgbuf;
	int				 error = 0;

#ifdef DEBUG
	xmalloc_clear();
	COUNTFDS(a->name);
#endif

	log_debug2("%s: deliver started, pid %ld", a->name, (long) getpid());

#ifdef HAVE_SETPROCTITLE
	setproctitle("%s[%lu]", data->name, (u_long) geteuid());
#endif

	/* Call the hook. */
	memset(&msg, 0, sizeof msg);
	data->hook(0, a, &msg, data, &msg.data.error);

	/* Inform parent we're done. */
	msg.type = MSG_DONE;
	msg.id = 0;

	msgbuf.buf = m->tags;
	msgbuf.len = STRB_SIZE(m->tags);

	if (privsep_send(pio, &msg, &msgbuf) != 0)
		fatalx("privsep_send error");
	do {
		if (privsep_recv(pio, &msg, NULL) != 0)
			fatalx("privsep_recv error");
	} while (msg.type != MSG_EXIT);

#ifdef DEBUG
	COUNTFDS(a->name);
	xmalloc_report(getpid(), a->name);
#endif

	return (error);
}
Esempio n. 16
0
/****************
 * Open a cipher handle for use with algorithm ALGO, in mode MODE
 * and put it into secure memory if SECURE is true.
 */
CIPHER_HANDLE
cipher_open( int algo, int mode, int secure )
{
    CIPHER_HANDLE hd;
    int i;

    fast_random_poll();
    do {
        for(i=0; cipher_table[i].name; i++ )
            if( cipher_table[i].algo == algo )
                break;
    } while( !cipher_table[i].name && load_cipher_modules() );
    if( !cipher_table[i].name ) {
        log_fatal("cipher_open: algorithm %d not available\n", algo );
        return NULL;
    }

    /* ? perform selftest here and mark this with a flag in cipher_table ? */

    hd = secure ? xmalloc_secure_clear( sizeof *hd
                                        + cipher_table[i].contextsize
                                        - sizeof(PROPERLY_ALIGNED_TYPE) )
         : xmalloc_clear( sizeof *hd + cipher_table[i].contextsize
                          - sizeof(PROPERLY_ALIGNED_TYPE)  );
    hd->algo = algo;
    hd->blocksize = cipher_table[i].blocksize;
    hd->setkey	= cipher_table[i].setkey;
    hd->encrypt = cipher_table[i].encrypt;
    hd->decrypt = cipher_table[i].decrypt;

    if( mode == CIPHER_MODE_AUTO_CFB ) {
        if( algo >= 100 )
            hd->mode = CIPHER_MODE_CFB;
        else
            hd->mode = CIPHER_MODE_PHILS_CFB;
    }
    else
        hd->mode = mode;

#ifdef ALLOW_DUMMY
    if( algo == CIPHER_ALGO_DUMMY )
        hd->mode = CIPHER_MODE_DUMMY;
#endif

    return hd;
}
int
setup_symkey(STRING2KEY **symkey_s2k,DEK **symkey_dek)
{
  *symkey_s2k=xmalloc_clear(sizeof(STRING2KEY));
  (*symkey_s2k)->mode = opt.s2k_mode;
  (*symkey_s2k)->hash_algo = S2K_DIGEST_ALGO;

  *symkey_dek=passphrase_to_dek(NULL,0,opt.s2k_cipher_algo,
				*symkey_s2k,2,NULL,NULL);
  if(!*symkey_dek || !(*symkey_dek)->keylen)
    {
      xfree(*symkey_dek);
      xfree(*symkey_s2k);
      return G10ERR_PASSPHRASE;
    }

  return 0;
}
Esempio n. 18
0
int
setup_symkey (STRING2KEY **symkey_s2k,DEK **symkey_dek)
{
  int canceled;

  *symkey_s2k=xmalloc_clear(sizeof(STRING2KEY));
  (*symkey_s2k)->mode = opt.s2k_mode;
  (*symkey_s2k)->hash_algo = S2K_DIGEST_ALGO;

  *symkey_dek=passphrase_to_dek(NULL,0,opt.s2k_cipher_algo,
				*symkey_s2k, 4, NULL, &canceled);
  if(!*symkey_dek || !(*symkey_dek)->keylen)
    {
      xfree(*symkey_dek);
      xfree(*symkey_s2k);
      return gpg_error (canceled?GPG_ERR_CANCELED:GPG_ERR_BAD_PASSPHRASE);
    }

  return 0;
}
Esempio n. 19
0
mpi_resize( MPI a, unsigned nlimbs )
#endif
{
    if( nlimbs <= a->alloced )
	return; /* no need to do it */
    /* Note: a->secure is not used - instead the realloc functions
     * take care of it. Maybe we should drop a->secure completely
     * and rely on a mpi_is_secure function, which would be
     * a wrapper around m_is_secure
     */
#ifdef M_DEBUG
    if( a->d )
	a->d = m_debug_realloc(a->d, nlimbs * sizeof(mpi_limb_t), info );
    else
	a->d = m_debug_alloc_clear( nlimbs * sizeof(mpi_limb_t), info );
#else
    if( a->d )
	a->d = xrealloc(a->d, nlimbs * sizeof(mpi_limb_t) );
    else
	a->d = xmalloc_clear( nlimbs * sizeof(mpi_limb_t) );
#endif
    a->alloced = nlimbs;
}
Esempio n. 20
0
KEYDB_HANDLE
keydb_new (int secret)
{
  KEYDB_HANDLE hd;
  int i, j;

  hd = xmalloc_clear (sizeof *hd);
  hd->found = -1;

  assert (used_resources <= MAX_KEYDB_RESOURCES);
  for (i=j=0; i < used_resources; i++)
    {
      if (!all_resources[i].secret != !secret)
        continue;
      switch (all_resources[i].type)
        {
        case KEYDB_RESOURCE_TYPE_NONE: /* ignore */
        case KEYDB_RESOURCE_TYPE_KEYBOX: /* ignore */
          break;
        case KEYDB_RESOURCE_TYPE_KEYRING:
          hd->active[j].type   = all_resources[i].type;
          hd->active[j].token  = all_resources[i].token;
          hd->active[j].secret = all_resources[i].secret;
          hd->active[j].u.kr = keyring_new (all_resources[i].token, secret);
          if (!hd->active[j].u.kr) {
            xfree (hd);
            return NULL; /* fixme: release all previously allocated handles*/
          }
          j++;
          break;
        }
    }
  hd->used = j;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

      dek->keylen = openpgp_cipher_get_algo_keylen (dek->algo);
      if (!(dek->keylen > 0 && dek->keylen <= DIM(dek->key)))
        BUG ();
      err = gcry_kdf_derive (pw, strlen (pw),
                             s2k->mode == 3? GCRY_KDF_ITERSALTED_S2K :
                             s2k->mode == 1? GCRY_KDF_SALTED_S2K :
                             /* */           GCRY_KDF_SIMPLE_S2K,
                             s2k->hash_algo, s2k->salt, 8,
                             S2K_DECODE_COUNT(s2k->count),
                             dek->keylen, dek->key);
      if (err)
        {
          log_error ("gcry_kdf_derive failed: %s", gpg_strerror (err));
          xfree (pw);
          xfree (dek);
	  write_status( STATUS_MISSING_PASSPHRASE );
          return NULL;
        }
    }
  if (s2k_cacheid)
    memcpy (dek->s2k_cacheid, s2k_cacheid, sizeof dek->s2k_cacheid);
  xfree(last_pw);
  last_pw = pw;
  return dek;
}
Esempio n. 22
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;
}
Esempio n. 23
0
int
build_sk_list( strlist_t locusr, SK_LIST *ret_sk_list,
               int unlock, unsigned int use )
{
    SK_LIST sk_list = NULL;
    int rc;

    if( !locusr )
      { /* use the default one */
	PKT_secret_key *sk;

	sk = xmalloc_clear( sizeof *sk );
	sk->req_usage = use;
	if( (rc = get_seckey_byname( sk, NULL, unlock )) ) {
	  free_secret_key( sk ); sk = NULL;
	  log_error("no default secret key: %s\n", g10_errstr(rc) );
          write_status_text (STATUS_INV_SGNR,
                             get_inv_recpsgnr_code (GPG_ERR_NO_SECKEY));
	}
	else if( !(rc=openpgp_pk_test_algo2 (sk->pubkey_algo, use)) )
	  {
	    SK_LIST r;

	    if( random_is_faked() && !is_insecure( sk ) )
	      {
		log_info(_("key is not flagged as insecure - "
			   "can't use it with the faked RNG!\n"));
		free_secret_key( sk ); sk = NULL;
                write_status_text (STATUS_INV_SGNR, 
                                   get_inv_recpsgnr_code (GPG_ERR_NOT_TRUSTED));
	      }
	    else
	      {
		r = xmalloc( sizeof *r );
		r->sk = sk; sk = NULL;
		r->next = sk_list;
		r->mark = 0;
		sk_list = r;
	      }
	  }
	else
	  {
	    free_secret_key( sk ); sk = NULL;
	    log_error("invalid default secret key: %s\n", g10_errstr(rc) );
            write_status_text (STATUS_INV_SGNR, get_inv_recpsgnr_code (rc));
	  }
      }
    else {
        strlist_t locusr_orig = locusr;
	for(; locusr; locusr = locusr->next ) {
	    PKT_secret_key *sk;
            
            rc = 0;
            /* Do an early check agains 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;
	      }
	    sk = xmalloc_clear( sizeof *sk );
	    sk->req_usage = use;
	    if( (rc = get_seckey_byname( sk, locusr->d, 0 )) )
	      {
		free_secret_key( sk ); sk = NULL;
		log_error(_("skipped \"%s\": %s\n"),
			  locusr->d, g10_errstr(rc) );
                write_status_text_and_buffer 
                  (STATUS_INV_SGNR, get_inv_recpsgnr_code (rc), 
                   locusr->d, strlen (locusr->d), -1);
	      }
            else if ( key_present_in_sk_list(sk_list, sk) == 0) {
                free_secret_key(sk); sk = NULL;
                log_info(_("skipped: secret key already present\n"));
            }
            else if ( unlock && (rc = check_secret_key( sk, 0 )) )
	      {
		free_secret_key( sk ); sk = NULL;
		log_error(_("skipped \"%s\": %s\n"),
			  locusr->d, g10_errstr(rc) );
                write_status_text_and_buffer 
                  (STATUS_INV_SGNR, get_inv_recpsgnr_code (rc), 
                   locusr->d, strlen (locusr->d), -1);
	      }
	    else if( !(rc=openpgp_pk_test_algo2 (sk->pubkey_algo, use)) ) {
		SK_LIST r;

		if( sk->version == 4 && (use & PUBKEY_USAGE_SIG)
		    && sk->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_secret_key( sk ); sk = 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( sk ) ) {
		    log_info(_("key is not flagged as insecure - "
			       "can't use it with the faked RNG!\n"));
		    free_secret_key( sk ); sk = 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->sk = sk; sk = NULL;
		    r->next = sk_list;
		    r->mark = 0;
		    sk_list = r;
		}
	    }
	    else {
		free_secret_key( sk ); sk = NULL;
		log_error("skipped \"%s\": %s\n", locusr->d, g10_errstr(rc) );
                write_status_text_and_buffer 
                  (STATUS_INV_SGNR, get_inv_recpsgnr_code (rc), 
                   locusr->d, strlen (locusr->d), -1);
	    }
	}
    }


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

    if( rc )
	release_sk_list( sk_list );
    else
	*ret_sk_list = sk_list;
    return rc;
}
Esempio n. 24
0
/* Generate a new photo id packet, or return NULL if canceled.
   FIXME:  Should we add a duplicates check similar to generate_user_id? */
PKT_user_id *
generate_photo_id(PKT_public_key *pk,const char *photo_name)
{
  PKT_user_id *uid;
  int error=1,i;
  unsigned int len;
  char *filename;
  byte *photo=NULL;
  byte header[16];
  IOBUF file;
  int overflow;

  header[0]=0x10; /* little side of photo header length */
  header[1]=0;    /* big side of photo header length */
  header[2]=1;    /* 1 == version of photo header */
  header[3]=1;    /* 1 == JPEG */

  for(i=4;i<16;i++) /* The reserved bytes */
    header[i]=0;

#define EXTRA_UID_NAME_SPACE 71
  uid=xmalloc_clear(sizeof(*uid)+71);

  if(photo_name && *photo_name)
    filename=make_filename(photo_name,(void *)NULL);
  else
    {
      tty_printf(_("\nPick an image to use for your photo ID."
		   "  The image must be a JPEG file.\n"
		   "Remember that the image is stored within your public key."
		   "  If you use a\n"
		   "very large picture, your key will become very large"
		   " as well!\n"
		   "Keeping the image close to 240x288 is a good size"
		   " to use.\n"));
      filename=NULL;
    }

  while(photo==NULL)
    {
      if(filename==NULL)
	{
	  char *tempname;

	  tty_printf("\n");

	  tty_enable_completion(NULL);

	  tempname=cpr_get("photoid.jpeg.add",
			   _("Enter JPEG filename for photo ID: "));

	  tty_disable_completion();

	  filename=make_filename(tempname,(void *)NULL);

	  xfree(tempname);

	  if(strlen(filename)==0)
	    goto scram;
	}

      file=iobuf_open(filename);
      if (file && is_secured_file (iobuf_get_fd (file)))
        {
          iobuf_close (file);
          file = NULL;
          errno = EPERM;
        }
      if(!file)
	{
	  log_error(_("unable to open JPEG file `%s': %s\n"),
		    filename,strerror(errno));
	  xfree(filename);
	  filename=NULL;
	  continue;
	}

      
      len=iobuf_get_filelength(file, &overflow);
      if(len>6144 || overflow)
	{
	  tty_printf( _("This JPEG is really large (%d bytes) !\n"),len);
	  if(!cpr_get_answer_is_yes("photoid.jpeg.size",
			    _("Are you sure you want to use it? (y/N) ")))
	  {
	    iobuf_close(file);
	    xfree(filename);
	    filename=NULL;
	    continue;
	  }
	}

      photo=xmalloc(len);
      iobuf_read(file,photo,len);
      iobuf_close(file);

      /* Is it a JPEG? */
      if(photo[0]!=0xFF || photo[1]!=0xD8 ||
	 photo[6]!='J' || photo[7]!='F' || photo[8]!='I' || photo[9]!='F')
	{
	  log_error(_("`%s' is not a JPEG file\n"),filename);
	  xfree(photo);
	  photo=NULL;
	  xfree(filename);
	  filename=NULL;
	  continue;
	}

      /* Build the packet */
      build_attribute_subpkt(uid,1,photo,len,header,16);
      parse_attribute_subpkts(uid);
      make_attribute_uidname(uid, EXTRA_UID_NAME_SPACE);

      /* Showing the photo is not safe when noninteractive since the
         "user" may not be able to dismiss a viewer window! */
      if(opt.command_fd==-1)
	{
	  show_photos(uid->attribs,uid->numattribs,pk,NULL,uid);
	  switch(cpr_get_answer_yes_no_quit("photoid.jpeg.okay",
					 _("Is this photo correct (y/N/q)? ")))
	    {
	    case -1:
	      goto scram;
	    case 0:
	      free_attributes(uid);
	      xfree(photo);
	      photo=NULL;
	      xfree(filename);
	      filename=NULL;
	      continue;
	    }
	}
    }

  error=0;
  uid->ref=1;

 scram:
  xfree(filename);
  xfree(photo);

  if(error)
    {
      free_attributes(uid);
      xfree(uid);
      return NULL;
    }

  return uid;
}
Esempio n. 25
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;
}
Esempio n. 26
0
int
signature_check2 (PKT_signature *sig, gcry_md_hd_t digest, u32 *r_expiredate,
		  int *r_expired, int *r_revoked, PKT_public_key *pk )
{
    int rc=0;
    int pk_internal;

    if (pk)
      pk_internal = 0;
    else
      {
	pk_internal = 1;
	pk = xmalloc_clear( sizeof *pk );
      }

    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 = GPG_ERR_GENERAL;
      }
    else if( get_pubkey( pk, sig->keyid ) )
	rc = GPG_ERR_NO_PUBKEY;
    else if(!pk->flags.valid && !pk->flags.primary)
      {
        /* You cannot have a good sig from an invalid subkey.  */
        rc = GPG_ERR_BAD_PUBKEY;
      }
    else
      {
        if(r_expiredate)
	  *r_expiredate = pk->expiredate;

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

	/* 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->flags.primary && pk->flags.backsig < 2)
	  {
	    if (!pk->flags.backsig)
	      {
		log_info(_("WARNING: signing subkey %s is not"
			   " cross-certified\n"),keystr_from_pk(pk));
		log_info(_("please see %s for more information\n"),
			 "https://gnupg.org/faq/subkey-cross-certify.html");
		/* --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 = GPG_ERR_GENERAL;
	      }
	    else if(pk->flags.backsig == 1)
	      {
		log_info(_("WARNING: signing subkey %s has an invalid"
			   " cross-certification\n"),keystr_from_pk(pk));
		rc = GPG_ERR_GENERAL;
	      }
	  }
      }

    if (pk_internal || rc)
      {
	release_public_key_parts (pk);
	if (pk_internal)
	  xfree (pk);
	else
	  /* Be very sure that the caller doesn't try to use *PK.  */
	  memset (pk, 0, sizeof (*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);
    }
Esempio n. 27
0
int 
exec_write(struct exec_info **info,const char *program,
           const char *args_in,const char *name,int writeonly,int binary)
{
  int ret=G10ERR_GENERAL;

  if(opt.exec_disable && !opt.no_perm_warn)
    {
      log_info(_("external program calls are disabled due to unsafe "
		 "options file permissions\n"));

      return ret;
    }

#if defined(HAVE_GETUID) && defined(HAVE_GETEUID)
  /* There should be no way to get to this spot while still carrying
     setuid privs.  Just in case, bomb out if we are. */
  if ( getuid () != geteuid ())
    BUG ();
#endif

  if(program==NULL && args_in==NULL)
    BUG();

  *info=xmalloc_clear(sizeof(struct exec_info));

  if(name)
    (*info)->name=xstrdup(name);
  (*info)->flags.binary=binary;
  (*info)->flags.writeonly=writeonly;

  /* Expand the args, if any */
  if(args_in && expand_args(*info,args_in))
    goto fail;

#ifdef EXEC_TEMPFILE_ONLY
  if(!(*info)->flags.use_temp_files)
    {
      log_error(_("this platform requires temporary files when calling"
		  " external programs\n"));
      goto fail;
    }

#else /* !EXEC_TEMPFILE_ONLY */

  /* If there are no args, or there are args, but no temp files, we
     can use fork/exec/pipe */
  if(args_in==NULL || (*info)->flags.use_temp_files==0)
    {
      int to[2],from[2];

      if(pipe(to)==-1)
	goto fail;

      if(pipe(from)==-1)
	{
	  close(to[0]);
	  close(to[1]);
	  goto fail;
	}

      if(((*info)->child=fork())==-1)
	{
	  close(to[0]);
	  close(to[1]);
	  close(from[0]);
	  close(from[1]);
	  goto fail;
	}

      if((*info)->child==0)
	{
	  char *shell=getenv("SHELL");

	  if(shell==NULL)
	    shell="/bin/sh";

	  /* I'm the child */

	  /* If the program isn't going to respond back, they get to
             keep their stdout/stderr */
	  if(!(*info)->flags.writeonly)
	    {
	      /* implied close of STDERR */
	      if(dup2(STDOUT_FILENO,STDERR_FILENO)==-1)
		_exit(1);

	      /* implied close of STDOUT */
	      close(from[0]);
	      if(dup2(from[1],STDOUT_FILENO)==-1)
		_exit(1);
	    }

	  /* implied close of STDIN */
	  close(to[1]);
	  if(dup2(to[0],STDIN_FILENO)==-1)
	    _exit(1);

	  if(args_in==NULL)
	    {
	      if(DBG_EXTPROG)
		log_debug("execlp: %s\n",program);

	      execlp(program,program,(void *)NULL);
	    }
	  else
	    {
	      if(DBG_EXTPROG)
		log_debug("execlp: %s -c %s\n",shell,(*info)->command);

	      execlp(shell,shell,"-c",(*info)->command,(void *)NULL);
	    }

	  /* If we get this far the exec failed.  Clean up and return. */

	  if(args_in==NULL)
	    log_error(_("unable to execute program `%s': %s\n"),
		      program,strerror(errno));
	  else
	    log_error(_("unable to execute shell `%s': %s\n"),
		      shell,strerror(errno));

	  /* This mimics the POSIX sh behavior - 127 means "not found"
             from the shell. */
	  if(errno==ENOENT)
	    _exit(127);

	  _exit(1);
	}

      /* I'm the parent */

      close(to[0]);

      (*info)->tochild=fdopen(to[1],binary?"wb":"w");
      if((*info)->tochild==NULL)
	{
          ret = gpg_error_from_syserror ();
	  close(to[1]);
	  goto fail;
	}

      close(from[1]);

      (*info)->fromchild=iobuf_fdopen(from[0],"r");
      if((*info)->fromchild==NULL)
	{
          ret = gpg_error_from_syserror ();
	  close(from[0]);
	  goto fail;
	}

      /* fd iobufs are cached?! */
      iobuf_ioctl((*info)->fromchild,3,1,NULL);

      return 0;
    }
#endif /* !EXEC_TEMPFILE_ONLY */

  if(DBG_EXTPROG)
    log_debug("using temp file `%s'\n",(*info)->tempfile_in);

  /* It's not fork/exec/pipe, so create a temp file */
  if( is_secured_filename ((*info)->tempfile_in) )
    {
      (*info)->tochild = NULL;
      errno = EPERM;
    }
  else
    (*info)->tochild=fopen((*info)->tempfile_in,binary?"wb":"w");
  if((*info)->tochild==NULL)
    {
      ret = gpg_error_from_syserror ();
      log_error(_("can't create `%s': %s\n"),
		(*info)->tempfile_in,strerror(errno));
      goto fail;
    }

  ret=0;

 fail:
  if (ret)
    {
      xfree (*info);
      *info = NULL;
    }
  return ret;
}
/* We don't want to use use_seskey yet because older gnupg versions
   can't handle it, and there isn't really any point unless we're
   making a message that can be decrypted by a public key or
   passphrase. */
static int
encode_simple( const char *filename, int mode, int use_seskey )
{
    IOBUF inp, out;
    PACKET pkt;
    PKT_plaintext *pt = NULL;
    STRING2KEY *s2k = NULL;
    byte enckey[33];
    int rc = 0;
    int seskeylen = 0;
    u32 filesize;
    cipher_filter_context_t cfx;
    armor_filter_context_t afx;
    compress_filter_context_t zfx;
    text_filter_context_t tfx;
    progress_filter_context_t pfx;
    int do_compress = !RFC1991 && default_compress_algo();

    memset( &cfx, 0, sizeof cfx);
    memset( &afx, 0, sizeof afx);
    memset( &zfx, 0, sizeof zfx);
    memset( &tfx, 0, sizeof tfx);
    init_packet(&pkt);
    
    /* prepare iobufs */
    inp = iobuf_open(filename);
    if (inp)
      iobuf_ioctl (inp,3,1,NULL); /* disable fd caching */
    if (inp && is_secured_file (iobuf_get_fd (inp)))
      {
        iobuf_close (inp);
        inp = NULL;
        errno = EPERM;
      }
    if( !inp ) {
	log_error(_("can't open `%s': %s\n"), filename? filename: "[stdin]",
                  strerror(errno) );
	return G10ERR_OPEN_FILE;
    }

    handle_progress (&pfx, inp, filename);

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

    /* Due the the fact that we use don't use an IV to encrypt the
       session key we can't use the new mode with RFC1991 because
       it has no S2K salt. RFC1991 always uses simple S2K. */
    if ( RFC1991 && use_seskey )
        use_seskey = 0;
    
    cfx.dek = NULL;
    if( mode ) {
	s2k = xmalloc_clear( sizeof *s2k );
	s2k->mode = RFC1991? 0:opt.s2k_mode;
	s2k->hash_algo=S2K_DIGEST_ALGO;
	cfx.dek = passphrase_to_dek( NULL, 0,
				     default_cipher_algo(), s2k, 2,
                                     NULL, NULL);
	if( !cfx.dek || !cfx.dek->keylen ) {
	    rc = G10ERR_PASSPHRASE;
	    xfree(cfx.dek);
	    xfree(s2k);
	    iobuf_close(inp);
	    log_error(_("error creating passphrase: %s\n"), g10_errstr(rc) );
	    return rc;
	}
        if (use_seskey && s2k->mode != 1 && s2k->mode != 3) {
            use_seskey = 0;
            log_info (_("can't use a symmetric ESK packet "
                        "due to the S2K mode\n"));
        }

        if ( use_seskey )
	  {
	    DEK *dek = NULL;
            seskeylen = cipher_get_keylen( default_cipher_algo() ) / 8;
            encode_seskey( cfx.dek, &dek, enckey );
            xfree( cfx.dek ); cfx.dek = dek;
	  }

	if(opt.verbose)
	  log_info(_("using cipher %s\n"),
		   cipher_algo_to_string(cfx.dek->algo));

	cfx.dek->use_mdc=use_mdc(NULL,cfx.dek->algo);
    }

    if (do_compress && cfx.dek && cfx.dek->use_mdc
	&& is_file_compressed(filename, &rc))
      {
        if (opt.verbose)
          log_info(_("`%s' already compressed\n"), filename);
        do_compress = 0;        
      }

    if( rc || (rc = open_outfile( filename, opt.armor? 1:0, &out )) ) {
	iobuf_cancel(inp);
	xfree(cfx.dek);
	xfree(s2k);
	return rc;
    }

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

    if( s2k && !RFC1991 ) {
	PKT_symkey_enc *enc = xmalloc_clear( sizeof *enc + seskeylen + 1 );
	enc->version = 4;
	enc->cipher_algo = cfx.dek->algo;
	enc->s2k = *s2k;
        if ( use_seskey && seskeylen ) {
            enc->seskeylen = seskeylen + 1; /* algo id */
            memcpy( enc->seskey, enckey, seskeylen + 1 );
        }
	pkt.pkttype = PKT_SYMKEY_ENC;
	pkt.pkt.symkey_enc = enc;
	if( (rc = build_packet( out, &pkt )) )
	    log_error("build symkey packet failed: %s\n", g10_errstr(rc) );
	xfree(enc);
    }

    if (!opt.no_literal)
      pt=setup_plaintext_name(filename,inp);

    /* Note that PGP 5 has problems decrypting symmetrically encrypted
       data if the file length is in the inner packet. It works when
       only partial length headers are use.  In the past, we always
       used partial body length here, but since PGP 2, PGP 6, and PGP
       7 need the file length, and nobody should be using PGP 5
       nowadays anyway, this is now set to the file length.  Note also
       that this only applies to the RFC-1991 style symmetric
       messages, and not the RFC-2440 style.  PGP 6 and 7 work with
       either partial length or fixed length with the new style
       messages. */

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

	if ( !(tmpsize = iobuf_get_filelength(inp, &overflow))
             && !overflow )
          log_info(_("WARNING: `%s' is an empty file\n"), filename );
        /* We can't encode the length of very large files because
           OpenPGP uses only 32 bit for file sizes.  So if the the
           size of a file is larger than 2^32 minus some bytes for
           packet headers, we switch to partial length encoding. */
        if ( tmpsize < (IOBUF_FILELENGTH_LIMIT - 65536) )
          filesize = tmpsize;
        else
          filesize = 0;
      }
    else
      filesize = opt.set_filesize ? opt.set_filesize : 0; /* stdin */

    if (!opt.no_literal) {
	pt->timestamp = make_timestamp();
	pt->mode = opt.textmode? 't' : 'b';
	pt->len = filesize;
	pt->new_ctb = !pt->len && !RFC1991;
	pt->buf = inp;
	pkt.pkttype = PKT_PLAINTEXT;
	pkt.pkt.plaintext = pt;
	cfx.datalen = filesize && !do_compress ? calc_packet_length( &pkt ) : 0;
    }
    else
      {
        cfx.datalen = filesize && !do_compress ? filesize : 0;
        pkt.pkttype = 0;
        pkt.pkt.generic = NULL;
      }

    /* register the cipher filter */
    if( mode )
	iobuf_push_filter( out, cipher_filter, &cfx );
    /* register the compress filter */
    if( do_compress )
      {
        if (cfx.dek && cfx.dek->use_mdc)
          zfx.new_ctb = 1;
	push_compress_filter(out,&zfx,default_compress_algo());
      }

    /* do the work */
    if (!opt.no_literal) {
	if( (rc = build_packet( out, &pkt )) )
	    log_error("build_packet failed: %s\n", g10_errstr(rc) );
    }
    else {
	/* user requested not to create a literal packet,
	 * so we copy the plain data */
	byte copy_buffer[4096];
	int  bytes_copied;
	while ((bytes_copied = iobuf_read(inp, copy_buffer, 4096)) != -1)
	    if (iobuf_write(out, copy_buffer, bytes_copied) == -1) {
		rc = G10ERR_WRITE_FILE;
		log_error("copying input to output failed: %s\n", g10_errstr(rc) );
		break;
	    }
	wipememory(copy_buffer, 4096); /* burn buffer */
    }

    /* finish the stuff */
    iobuf_close(inp);
    if (rc)
	iobuf_cancel(out);
    else {
	iobuf_close(out); /* fixme: check returncode */
        if (mode)
            write_status( STATUS_END_ENCRYPTION );
    }
    if (pt)
	pt->buf = NULL;
    free_packet(&pkt);
    xfree(cfx.dek);
    xfree(s2k);
    return rc;
}
Esempio n. 29
0
/****************
 * Get the session key from a pubkey enc packet and return
 * it in DEK, which should have been allocated in secure memory.
 */
int
get_session_key( PKT_pubkey_enc *k, DEK *dek )
{
    PKT_secret_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 { /* anonymous receiver: Try all available secret keys */
	void *enum_context = NULL;
	u32 keyid[2];
	char *p;

	for(;;) {
	    if( sk )
		free_secret_key( sk );
	    sk = xmalloc_clear( sizeof *sk );
	    rc=enum_secret_keys( &enum_context, sk, 1, 0);
	    if( rc ) {
		rc = G10ERR_NO_SECKEY;
		break;
	    }
	    if( sk->pubkey_algo != k->pubkey_algo )
		continue;
	    keyid_from_sk( sk, keyid );
	    log_info(_("anonymous recipient; trying secret key %s ...\n"),
                     keystr(keyid));

	    if(!opt.try_all_secrets && !is_status_enabled())
	      {
		p=get_last_passphrase();
		set_next_passphrase(p);
		xfree(p);
	      }

	    rc = check_secret_key( sk, opt.try_all_secrets?1:-1 ); /* ask
								      only
								      once */
	    if( !rc )
	      {
		rc = get_it( k, dek, sk, keyid );
		/* Successfully checked the secret key (either it was
		   a card, had no passphrase, or had the right
		   passphrase) but couldn't decrypt the session key,
		   so thus that key is not the anonymous recipient.
		   Move the next passphrase into last for the next
		   round.  We only do this if the secret key was
		   successfully checked as in the normal case,
		   check_secret_key handles this for us via
		   passphrase_to_dek */
		if(rc)
		  next_to_last_passphrase();
	      }

	    if( !rc )
	      {
		log_info(_("okay, we are the anonymous recipient.\n") );
		break;
	      }
	}
	enum_secret_keys( &enum_context, NULL, 0, 0 ); /* free context */
    }

  leave:
    if( sk )
	free_secret_key( sk );
    return rc;
}
/****************
 * 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 out )
{
    PACKET pkt;
    PKT_public_key *pk;
    PKT_pubkey_enc  *enc;
    int rc;

    for( ; pk_list; pk_list = pk_list->next ) {
	MPI 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_keyid || (pk_list->flags&1));

	if(opt.throw_keyid && (PGP2 || PGP6 || PGP7 || PGP8))
	  {
	    log_info(_("you may not use %s while in %s mode\n"),
		     "--throw-keyid",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( dek, pubkey_nbits( pk->pubkey_algo,
							  pk->pkey ) );
	rc = pubkey_encrypt( pk->pubkey_algo, enc->data, frame, pk->pkey );
	mpi_free( frame );
	if( rc )
	    log_error("pubkey_encrypt failed: %s\n", g10_errstr(rc) );
	else {
	    if( opt.verbose ) {
		char *ustr = get_user_id_string_native (enc->keyid);
		log_info(_("%s/%s encrypted for: \"%s\"\n"),
		    pubkey_algo_to_string(enc->pubkey_algo),
		    cipher_algo_to_string(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", g10_errstr(rc));
	}
	free_pubkey_enc(enc);
	if( rc )
	    return rc;
    }
    return 0;
}