예제 #1
0
파일: cpr.c 프로젝트: randombit/hacrypto
/* Print the BEGIN_SIGNING status message.  If MD is not NULL it is
   used to retrieve the hash algorithms used for the message. */
void
write_status_begin_signing (gcry_md_hd_t md)
{
  if (md)
    {
      char buf[100];
      size_t buflen;
      int i;

      /* We use a hard coded list of possible algorithms.  Using other
         algorithms than specified by OpenPGP does not make sense
         anyway.  We do this out of performance reasons: Walking all
         the 110 allowed Ids is not a good idea given the way the
         check is implemented in libgcrypt.  Recall that the only use
         of this status code is to create the micalg algorithm for
         PGP/MIME. */
      buflen = 0;
      for (i=1; i <= 11; i++)
        if (i < 4 || i > 7)
          if ( gcry_md_is_enabled (md, i) && buflen < DIM(buf) )
            {
              snprintf (buf+buflen, DIM(buf) - buflen - 1,
                        "%sH%d", buflen? " ":"",i);
              buflen += strlen (buf+buflen);
            }
      write_status_text ( STATUS_BEGIN_SIGNING, buf );
    }
  else
    write_status ( STATUS_BEGIN_SIGNING );
}
예제 #2
0
파일: server.c 프로젝트: Juul/gnupg
/*  ENCRYPT

   Do the actual encryption process.  Takes the plaintext from the
   INPUT command, writes the ciphertext to the file descriptor set
   with the OUTPUT command, take the recipients from all the
   recipients set so far with RECIPIENTS.

   If this command fails the clients should try to delete all output
   currently done or otherwise mark it as invalid.  GPG does ensure
   that there won't be any security problem with leftover data on the
   output in this case.

   In most cases this command won't fail because most necessary checks
   have been done while setting the recipients.  However some checks
   can only be done right here and thus error may occur anyway (for
   example, no recipients at all).

   The input, output and message pipes are closed after this
   command.  */
static gpg_error_t
cmd_encrypt (assuan_context_t ctx, char *line)
{
  ctrl_t ctrl = assuan_get_pointer (ctx);
  gpg_error_t err;
  int inp_fd, out_fd;

  (void)line; /* LINE is not used.  */

  if ( !ctrl->server_local->recplist )
    {
      write_status_text (STATUS_NO_RECP, "0");
      err = gpg_error (GPG_ERR_NO_USER_ID);
      goto leave;
    }

  inp_fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
  if (inp_fd == -1)
    {
      err = set_error (GPG_ERR_ASS_NO_INPUT, NULL);
      goto leave;
    }
  out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
  if (out_fd == -1)
    {
      err = set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
      goto leave;
    }

  /* Fixme: Check that we are using real files and not pipes if in
     PGP-2 mode.  Do all the other checks we do in gpg.c for aEncr.
     Maybe we should drop the PGP2 compatibility. */


  /* FIXME: GPGSM does this here: Add all encrypt-to marked recipients
     from the default list. */

  /* fixme: err = ctrl->audit? 0 : start_audit_session (ctrl);*/

  err = encrypt_crypt (ctrl, inp_fd, NULL, NULL, 0,
                       ctrl->server_local->recplist,
                       out_fd);

 leave:
  /* Release the recipient list on success.  */
  if (!err)
    {
      release_pk_list (ctrl->server_local->recplist);
      ctrl->server_local->recplist = NULL;
    }

  /* Close and reset the fds. */
  close_message_fd (ctrl);
  assuan_close_input_fd (ctx);
  assuan_close_output_fd (ctx);

  if (err)
    log_error ("command '%s' failed: %s\n", "ENCRYPT", gpg_strerror (err));
  return err;
}
예제 #3
0
/* Status callback for the SCD GENKEY command. */
static gpg_error_t
scd_genkey_cb (void *opaque, const char *line)
{
    struct agent_card_genkey_s *parm = opaque;
    const char *keyword = line;
    int keywordlen;

    for (keywordlen=0; *line && !spacep (line); line++, keywordlen++)
        ;
    while (spacep (line))
        line++;

    if (keywordlen == 7 && !memcmp (keyword, "KEY-FPR", keywordlen))
    {
        parm->fprvalid = unhexify_fpr (line, parm->fpr);
    }
    else if (keywordlen == 14 && !memcmp (keyword,"KEY-CREATED-AT", keywordlen))
    {
        parm->created_at = (u32)strtoul (line, NULL, 10);
    }
    else if (keywordlen == 8 && !memcmp (keyword, "PROGRESS", keywordlen))
    {
        write_status_text (STATUS_PROGRESS, line);
    }

    return 0;
}
예제 #4
0
파일: delkey.c 프로젝트: randombit/hacrypto
/****************
 * Delete a public or secret key from a keyring.
 */
int
delete_keys( STRLIST names, int secret, int allow_both )
{
    int rc, avail, force=(!allow_both && !secret && opt.expert);

    /* Force allows us to delete a public key even if a secret key
       exists. */

    for(; names; names=names->next) {
        rc = do_delete_key (names->d, secret, force, &avail );
        if ( rc && avail ) {
            if ( allow_both ) {
                rc = do_delete_key (names->d, 1, 0, &avail );
                if ( !rc )
                    rc = do_delete_key (names->d, 0, 0, &avail );
            }
            else {
                log_error(_(
                              "there is a secret key for public key \"%s\"!\n"),names->d);
                log_info(_(
                             "use option \"--delete-secret-keys\" to delete it first.\n"));
                write_status_text( STATUS_DELETE_PROBLEM, "2" );
                return rc;
            }
        }

        if(rc) {
            log_error("%s: delete key failed: %s\n", names->d, g10_errstr(rc) );
            return rc;
        }
    }

    return 0;
}
예제 #5
0
파일: verify.c 프로젝트: Domikk/gnupg
void
print_file_status( int status, const char *name, int what )
{
    char *p = xmalloc(strlen(name)+10);
    sprintf(p, "%d %s", what, name );
    write_status_text( status, p );
    xfree(p);
}
예제 #6
0
/* If RC is not 0, write an appropriate status message. */
static void
status_sc_op_failure (int rc)
{
    switch (gpg_err_code (rc))
    {
    case 0:
        break;
    case GPG_ERR_CANCELED:
        write_status_text (STATUS_SC_OP_FAILURE, "1");
        break;
    case GPG_ERR_BAD_PIN:
        write_status_text (STATUS_SC_OP_FAILURE, "2");
        break;
    default:
        write_status (STATUS_SC_OP_FAILURE);
        break;
    }
}
예제 #7
0
파일: passphrase.c 프로젝트: cuidi/gnupg
/* Emit the USERID_HINT and the NEED_PASSPHRASE status messages.
   MAINKEYID may be NULL. */
void
emit_status_need_passphrase (u32 *keyid, u32 *mainkeyid, int pubkey_algo)
{
  char buf[50];
  char *us;

  us = get_long_user_id_string (keyid);
  write_status_text (STATUS_USERID_HINT, us);
  xfree (us);

  snprintf (buf, sizeof buf -1, "%08lX%08lX %08lX%08lX %d 0",
            (ulong)keyid[0],
            (ulong)keyid[1],
            (ulong)(mainkeyid? mainkeyid[0]:keyid[0]),
            (ulong)(mainkeyid? mainkeyid[1]:keyid[1]),
            pubkey_algo);

  write_status_text (STATUS_NEED_PASSPHRASE, buf);
}
예제 #8
0
파일: cipher.c 프로젝트: randombit/hacrypto
static void
write_header( cipher_filter_context_t *cfx, IOBUF a )
{
    PACKET pkt;
    PKT_encrypted ed;
    byte temp[18];
    unsigned blocksize;
    unsigned nprefix;

    blocksize = cipher_get_blocksize( cfx->dek->algo );
    if( blocksize < 8 || blocksize > 16 )
        log_fatal("unsupported blocksize %u\n", blocksize );

    memset( &ed, 0, sizeof ed );
    ed.len = cfx->datalen;
    ed.extralen = blocksize+2;
    ed.new_ctb = !ed.len && !RFC1991;
    if( cfx->dek->use_mdc ) {
        ed.mdc_method = DIGEST_ALGO_SHA1;
        cfx->mdc_hash = md_open( DIGEST_ALGO_SHA1, 0 );
        if ( DBG_HASHING )
            md_start_debug( cfx->mdc_hash, "creatmdc" );
    }

    {
        char buf[20];

        sprintf (buf, "%d %d", ed.mdc_method, cfx->dek->algo);
        write_status_text (STATUS_BEGIN_ENCRYPTION, buf);
    }

    init_packet( &pkt );
    pkt.pkttype = cfx->dek->use_mdc? PKT_ENCRYPTED_MDC : PKT_ENCRYPTED;
    pkt.pkt.encrypted = &ed;
    if( build_packet( a, &pkt ))
        log_bug("build_packet(ENCR_DATA) failed\n");
    nprefix = blocksize;
    randomize_buffer( temp, nprefix, 1 );
    temp[nprefix] = temp[nprefix-2];
    temp[nprefix+1] = temp[nprefix-1];
    print_cipher_algo_note( cfx->dek->algo );
    cfx->cipher_hd = cipher_open( cfx->dek->algo,
                                  cfx->dek->use_mdc? CIPHER_MODE_CFB
                                  : CIPHER_MODE_AUTO_CFB, 1 );
    /*   log_hexdump( "thekey", cfx->dek->key, cfx->dek->keylen );*/
    cipher_setkey( cfx->cipher_hd, cfx->dek->key, cfx->dek->keylen );
    cipher_setiv( cfx->cipher_hd, NULL, 0 );
    /*  log_hexdump( "prefix", temp, nprefix+2 ); */
    if( cfx->mdc_hash ) /* hash the "IV" */
        md_write( cfx->mdc_hash, temp, nprefix+2 );
    cipher_encrypt( cfx->cipher_hd, temp, temp, nprefix+2);
    cipher_sync( cfx->cipher_hd );
    iobuf_write(a, temp, nprefix+2);
    cfx->header=1;
}
예제 #9
0
파일: cpr.c 프로젝트: randombit/hacrypto
static void
progress_cb (void *ctx, const char *what, int printchar,
             int current, int total)
{
  char buf[50];

  (void)ctx;

  if ( printchar == '\n' && !strcmp (what, "primegen") )
    snprintf (buf, sizeof buf -1, "%.20s X 100 100", what );
  else
    snprintf (buf, sizeof buf -1, "%.20s %c %d %d",
              what, printchar=='\n'?'X':printchar, current, total );
  write_status_text (STATUS_PROGRESS, buf);
}
예제 #10
0
/****************
 * Check the secret key
 * Ask up to 3 (or n) times for a correct passphrase
 * If n is negative, disable the key info prompt and make n=abs(n)
 */
int
check_secret_key( PKT_secret_key *sk, int n )
{
    int rc = gpg_error (GPG_ERR_BAD_PASSPHRASE);
    int i,mode;

    if (sk && sk->is_protected && sk->protect.s2k.mode == 1002)
      return 0; /* Let the scdaemon handle this. */

    if(n<0)
      {
	n=abs(n);
	mode=1;
      }
    else
      mode=0;

    if( n < 1 )
	n = 3; /* Use the default value */

    for(i=0; i < n && gpg_err_code (rc) == GPG_ERR_BAD_PASSPHRASE; i++ ) {
        int canceled = 0;
        const char *tryagain = NULL;
	if (i) {
            tryagain = N_("Invalid passphrase; please try again");
            log_info (_("%s ...\n"), _(tryagain));
        }
	rc = do_check( sk, tryagain, mode, &canceled );
	if ( gpg_err_code (rc) == GPG_ERR_BAD_PASSPHRASE
             && is_status_enabled () ) {
	    u32 kid[2];
	    char buf[50];

	    keyid_from_sk( sk, kid );
	    sprintf(buf, "%08lX%08lX", (ulong)kid[0], (ulong)kid[1]);
	    write_status_text( STATUS_BAD_PASSPHRASE, buf );
	}
	if( have_static_passphrase() || canceled)
	    break;
    }

    if( !rc )
	write_status( STATUS_GOOD_PASSPHRASE );

    return rc;
}
예제 #11
0
파일: cpr.c 프로젝트: randombit/hacrypto
/* Request a string from the client over the command-fd.  If GETBOOL
   is set the function returns a static string (do not free) if the
   netered value was true or NULL if the entered value was false.  */
static char *
do_get_from_fd ( const char *keyword, int hidden, int getbool )
{
  int i, len;
  char *string;

  if (statusfp != stdout)
    fflush (stdout);

  write_status_text (getbool? STATUS_GET_BOOL :
                     hidden? STATUS_GET_HIDDEN : STATUS_GET_LINE, keyword);

  for (string = NULL, i = len = 200; ; i++ )
    {
      if (i >= len-1 )
        {
          char *save = string;
          len += 100;
          string = hidden? xmalloc_secure ( len ) : xmalloc ( len );
          if (save)
            memcpy (string, save, i );
          else
            i = 0;
	}
      /* Fixme: why not use our read_line function here? */
      if ( myread( opt.command_fd, string+i, 1) != 1 || string[i] == '\n'  )
        break;
      else if ( string[i] == CONTROL_D )
        {
          /* Found ETX - Cancel the line and return a sole ETX.  */
          string[0] = CONTROL_D;
          i = 1;
          break;
        }
    }
  string[i] = 0;

  write_status (STATUS_GOT_IT);

  if (getbool)	 /* Fixme: is this correct??? */
    return (string[0] == 'Y' || string[0] == 'y') ? "" : NULL;

  return string;
}
예제 #12
0
파일: pkclist.c 프로젝트: FMayzek/gnupg
/****************
 * wrapper around do_we_trust, so we can ask whether to use the
 * key anyway.
 */
static int
do_we_trust_pre( PKT_public_key *pk, unsigned int trustlevel )
{
  int rc;

  rc = do_we_trust( pk, trustlevel );

  if( !opt.batch && !rc )
    {
      print_pubkey_info(NULL,pk);
      print_fingerprint (pk, 2);
      tty_printf("\n");

      tty_printf(
	       _("It is NOT certain that the key belongs to the person named\n"
		 "in the user ID.  If you *really* know what you are doing,\n"
		 "you may answer the next question with yes.\n"));

      tty_printf("\n");


      if (is_status_enabled ())
        {
          u32 kid[2];
          char *hint_str;

          keyid_from_pk (pk, kid);
          hint_str = get_long_user_id_string ( kid );
          write_status_text ( STATUS_USERID_HINT, hint_str );
          xfree (hint_str);
        }

      if( cpr_get_answer_is_yes("untrusted_key.override",
				_("Use this key anyway? (y/N) "))  )
	rc = 1;

      /* Hmmm: Should we set a flag to tell the user about
       *	 his decision the next time he encrypts for this recipient?
       */
    }

  return rc;
}
예제 #13
0
파일: server.c 프로젝트: Distrotech/gnupg
/* Helper to notify the client about Pinentry events.  Because that
   might disturb some older clients, this is only done when enabled
   via an option.  If it is not enabled we tell Windows to allow
   setting the foreground window right here.  Returns an gpg error
   code. */
gpg_error_t
gpg_proxy_pinentry_notify (ctrl_t ctrl, const unsigned char *line)
{
  if (!ctrl || !ctrl->server_local
      || !ctrl->server_local->allow_pinentry_notify)
    {
      gnupg_allow_set_foregound_window ((pid_t)strtoul (line+17, NULL, 10));
      /* Client might be interested in that event - send as status line.  */
      if (!strncmp (line, "PINENTRY_LAUNCHED", 17)
          && (line[17]==' '||!line[17]))
        {
          for (line += 17; *line && spacep (line); line++)
            ;
          write_status_text (STATUS_PINENTRY_LAUNCHED, line);
        }
      return 0;
    }
  return assuan_inquire (ctrl->server_local->assuan_ctx, line, NULL, NULL, 0);
}
예제 #14
0
파일: progress.c 프로젝트: cuidi/gnupg
static void
write_status_progress (const char *what,
                       unsigned long current, unsigned long total)
{
  char buffer[50];

  /* Although we use an unsigned long for the values, 32 bit
   * applications using GPGME will use an "int" and thus are limited
   * in the total size which can be represented.  On Windows, where
   * sizeof(int)==sizeof(long), this is even worse and will lead to an
   * integer overflow for all files larger than 2 GiB.  Although, the
   * allowed value range of TOTAL and CURRENT is nowhere specified, we
   * better protect applications from the need to handle negative
   * values.  The common usage pattern of the progress information is
   * to display how many percent of the operation has been done and
   * thus scaling CURRENT and TOTAL down before they get to large,
   * should not have a noticeable effect except for rounding
   * imprecision. */
  if (total)
    {
      if (current > total)
        current = total;

      while (total > 1024*1024)
        {
          total /= 1024;
          current /= 1024;
        }
    }
  else
    {
      while (current > 1024*1024)
        {
          current /= 1024;
        }
    }

  snprintf (buffer, sizeof buffer, "%.20s ? %lu %lu",
            what? what : "?", current, total);
  write_status_text (STATUS_PROGRESS, buffer);
}
예제 #15
0
/* Try to connect to the agent via socket or fork it off and work by
   pipes.  Handle the server's initial greeting */
static int
start_agent (int for_card)
{
    int rc;

    /* Fixme: We need a context for each thread or serialize the access
       to the agent. */
    if (agent_ctx)
        rc = 0;
    else
    {
        rc = start_new_gpg_agent (&agent_ctx,
                                  GPG_ERR_SOURCE_DEFAULT,
                                  opt.homedir,
                                  opt.agent_program,
                                  opt.lc_ctype, opt.lc_messages,
                                  opt.session_env,
                                  opt.verbose, DBG_ASSUAN,
                                  NULL, NULL);
        if (!rc)
        {
            /* Tell the agent that we support Pinentry notifications.
               No error checking so that it will work also with older
               agents.  */
            assuan_transact (agent_ctx, "OPTION allow-pinentry-notify",
                             NULL, NULL, NULL, NULL, NULL, NULL);
        }
    }

    if (!rc && for_card && !did_early_card_test)
    {
        /* Request the serial number of the card for an early test.  */
        struct agent_card_info_s info;

        memset (&info, 0, sizeof info);
        rc = assuan_transact (agent_ctx, "SCD SERIALNO openpgp",
                              NULL, NULL, NULL, NULL,
                              learn_status_cb, &info);
        if (rc)
        {
            switch (gpg_err_code (rc))
            {
            case GPG_ERR_NOT_SUPPORTED:
            case GPG_ERR_NO_SCDAEMON:
                write_status_text (STATUS_CARDCTRL, "6");
                break;
            default:
                write_status_text (STATUS_CARDCTRL, "4");
                log_info ("selecting openpgp failed: %s\n", gpg_strerror (rc));
                break;
            }
        }

        if (!rc && is_status_enabled () && info.serialno)
        {
            char *buf;

            buf = xasprintf ("3 %s", info.serialno);
            write_status_text (STATUS_CARDCTRL, buf);
            xfree (buf);
        }

        agent_release_card_info (&info);

        if (!rc)
            did_early_card_test = 1;
    }


    return rc;
}
예제 #16
0
파일: passphrase.c 프로젝트: cuidi/gnupg
/* 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;
}
예제 #17
0
파일: cpr.c 프로젝트: randombit/hacrypto
void
write_status ( int no )
{
    write_status_text( no, NULL );
}
예제 #18
0
/****************
 * Decrypt the data, specified by ED with the key DEK.
 */
int
decrypt_data( void *procctx, PKT_encrypted *ed, DEK *dek )
{
  decode_filter_ctx_t dfx;
  byte *p;
  int rc=0, c, i;
  byte temp[32];
  unsigned blocksize;
  unsigned nprefix;

  dfx = xtrycalloc (1, sizeof *dfx);
  if (!dfx)
    return gpg_error_from_syserror ();
  dfx->refcount = 1;

  if ( opt.verbose && !dek->algo_info_printed )
    {
      if (!openpgp_cipher_test_algo (dek->algo))
        log_info (_("%s encrypted data\n"),
                  openpgp_cipher_algo_name (dek->algo));
      else
        log_info (_("encrypted with unknown algorithm %d\n"), dek->algo );
      dek->algo_info_printed = 1;
    }

  {
    char buf[20];

    snprintf (buf, sizeof buf, "%d %d", ed->mdc_method, dek->algo);
    write_status_text (STATUS_DECRYPTION_INFO, buf);
  }

  rc = openpgp_cipher_test_algo (dek->algo);
  if (rc)
    goto leave;
  blocksize = openpgp_cipher_get_algo_blklen (dek->algo);
  if ( !blocksize || blocksize > 16 )
    log_fatal ("unsupported blocksize %u\n", blocksize );
  nprefix = blocksize;
  if ( ed->len && ed->len < (nprefix+2) )
    BUG();

  if ( ed->mdc_method )
    {
      if (gcry_md_open (&dfx->mdc_hash, ed->mdc_method, 0 ))
        BUG ();
      if ( DBG_HASHING )
        gcry_md_debug (dfx->mdc_hash, "checkmdc");
    }

  rc = openpgp_cipher_open (&dfx->cipher_hd, dek->algo,
			    GCRY_CIPHER_MODE_CFB,
			    (GCRY_CIPHER_SECURE
			     | ((ed->mdc_method || dek->algo >= 100)?
				0 : GCRY_CIPHER_ENABLE_SYNC)));
  if (rc)
    {
      /* We should never get an error here cause we already checked
       * that the algorithm is available.  */
      BUG();
    }


  /* log_hexdump( "thekey", dek->key, dek->keylen );*/
  rc = gcry_cipher_setkey (dfx->cipher_hd, dek->key, dek->keylen);
  if ( gpg_err_code (rc) == GPG_ERR_WEAK_KEY )
    {
      log_info(_("WARNING: message was encrypted with"
                 " a weak key in the symmetric cipher.\n"));
      rc=0;
    }
  else if( rc )
    {
      log_error("key setup failed: %s\n", g10_errstr(rc) );
      goto leave;
    }

  if (!ed->buf)
    {
      log_error(_("problem handling encrypted packet\n"));
      goto leave;
    }

  gcry_cipher_setiv (dfx->cipher_hd, NULL, 0);

  if ( ed->len )
    {
      for (i=0; i < (nprefix+2) && ed->len; i++, ed->len-- )
        {
          if ( (c=iobuf_get(ed->buf)) == -1 )
            break;
          else
            temp[i] = c;
        }
    }
  else
    {
      for (i=0; i < (nprefix+2); i++ )
        if ( (c=iobuf_get(ed->buf)) == -1 )
          break;
        else
          temp[i] = c;
    }

  gcry_cipher_decrypt (dfx->cipher_hd, temp, nprefix+2, NULL, 0);
  gcry_cipher_sync (dfx->cipher_hd);
  p = temp;
  /* log_hexdump( "prefix", temp, nprefix+2 ); */
  if (dek->symmetric
      && (p[nprefix-2] != p[nprefix] || p[nprefix-1] != p[nprefix+1]) )
    {
      rc = gpg_error (GPG_ERR_BAD_KEY);
      goto leave;
    }

  if ( dfx->mdc_hash )
    gcry_md_write (dfx->mdc_hash, temp, nprefix+2);

  dfx->refcount++;
  if ( ed->mdc_method )
    iobuf_push_filter ( ed->buf, mdc_decode_filter, dfx );
  else
    iobuf_push_filter ( ed->buf, decode_filter, dfx );

  proc_packets ( procctx, ed->buf );
  ed->buf = NULL;
  if ( ed->mdc_method && dfx->eof_seen == 2 )
    rc = gpg_error (GPG_ERR_INV_PACKET);
  else if ( ed->mdc_method )
    {
      /* We used to let parse-packet.c handle the MDC packet but this
         turned out to be a problem with compressed packets: With old
         style packets there is no length information available and
         the decompressor uses an implicit end.  However we can't know
         this implicit end beforehand (:-) and thus may feed the
         decompressor with more bytes than actually needed.  It would
         be possible to unread the extra bytes but due to our weird
         iobuf system any unread is non reliable due to filters
         already popped off.  The easy and sane solution is to care
         about the MDC packet only here and never pass it to the
         packet parser.  Fortunatley the OpenPGP spec requires a
         strict format for the MDC packet so that we know that 22
         bytes are appended.  */
      int datalen = gcry_md_get_algo_dlen (ed->mdc_method);

      assert (dfx->cipher_hd);
      assert (dfx->mdc_hash);
      gcry_cipher_decrypt (dfx->cipher_hd, dfx->defer, 22, NULL, 0);
      gcry_md_write (dfx->mdc_hash, dfx->defer, 2);
      gcry_md_final (dfx->mdc_hash);

      if (dfx->defer[0] != '\xd3' || dfx->defer[1] != '\x14' )
        {
          log_error("mdc_packet with invalid encoding\n");
          rc = gpg_error (GPG_ERR_INV_PACKET);
        }
      else if (datalen != 20
               || memcmp (gcry_md_read (dfx->mdc_hash, 0),
                          dfx->defer+2,datalen ))
        rc = gpg_error (GPG_ERR_BAD_SIGNATURE);
      /* log_printhex("MDC message:", dfx->defer, 22); */
      /* log_printhex("MDC calc:", gcry_md_read (dfx->mdc_hash,0), datalen); */
    }


 leave:
  release_dfx_context (dfx);
  return rc;
}
예제 #19
0
파일: skclist.c 프로젝트: GroovIM/transport
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;
}
예제 #20
0
파일: sig-check.c 프로젝트: CSNW/gnupg
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);
    }
예제 #21
0
파일: skclist.c 프로젝트: codebam/gnupg
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;
}
예제 #22
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);
    }
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);
    }
/* 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;
}
예제 #26
0
파일: cipher.c 프로젝트: Distrotech/gnupg
static void
write_header( cipher_filter_context_t *cfx, IOBUF a )
{
    gcry_error_t err;
    PACKET pkt;
    PKT_encrypted ed;
    byte temp[18];
    unsigned int blocksize;
    unsigned int nprefix;

    blocksize = openpgp_cipher_get_algo_blklen (cfx->dek->algo);
    if ( blocksize < 8 || blocksize > 16 )
	log_fatal("unsupported blocksize %u\n", blocksize );

    memset( &ed, 0, sizeof ed );
    ed.len = cfx->datalen;
    ed.extralen = blocksize+2;
    ed.new_ctb = !ed.len;
    if( cfx->dek->use_mdc ) {
	ed.mdc_method = DIGEST_ALGO_SHA1;
	gcry_md_open (&cfx->mdc_hash, DIGEST_ALGO_SHA1, 0);
	if ( DBG_HASHING )
	    gcry_md_debug (cfx->mdc_hash, "creatmdc");
    }

    {
        char buf[20];

        sprintf (buf, "%d %d", ed.mdc_method, cfx->dek->algo);
        write_status_text (STATUS_BEGIN_ENCRYPTION, buf);
    }

    init_packet( &pkt );
    pkt.pkttype = cfx->dek->use_mdc? PKT_ENCRYPTED_MDC : PKT_ENCRYPTED;
    pkt.pkt.encrypted = &ed;
    if( build_packet( a, &pkt ))
	log_bug("build_packet(ENCR_DATA) failed\n");
    nprefix = blocksize;
    gcry_randomize (temp, nprefix, GCRY_STRONG_RANDOM );
    temp[nprefix] = temp[nprefix-2];
    temp[nprefix+1] = temp[nprefix-1];
    print_cipher_algo_note( cfx->dek->algo );
    err = openpgp_cipher_open (&cfx->cipher_hd,
			       cfx->dek->algo,
			       GCRY_CIPHER_MODE_CFB,
			       (GCRY_CIPHER_SECURE
				| ((cfx->dek->use_mdc || cfx->dek->algo >= 100)?
				   0 : GCRY_CIPHER_ENABLE_SYNC)));
    if (err) {
	/* We should never get an error here cause we already checked,
	 * that the algorithm is available.  */
	BUG();
    }


/*   log_hexdump( "thekey", cfx->dek->key, cfx->dek->keylen );*/
    gcry_cipher_setkey( cfx->cipher_hd, cfx->dek->key, cfx->dek->keylen );
    gcry_cipher_setiv( cfx->cipher_hd, NULL, 0 );
/*  log_hexdump( "prefix", temp, nprefix+2 ); */
    if (cfx->mdc_hash) /* Hash the "IV". */
	gcry_md_write (cfx->mdc_hash, temp, nprefix+2 );
    gcry_cipher_encrypt (cfx->cipher_hd, temp, nprefix+2, NULL, 0);
    gcry_cipher_sync (cfx->cipher_hd);
    iobuf_write(a, temp, nprefix+2);
    cfx->header=1;
}
예제 #27
0
파일: passphrase.c 프로젝트: larryv/gnupg
/* Return a new DEK object using the string-to-key specifier S2K.
 * Returns NULL if the user canceled the passphrase entry and if
 * CANCELED is not NULL, sets it to true.
 *
 * If CREATE is true a new passphrase sll be created.  If NOCACHE is
 * true the symmetric key caching will not be used.  */
DEK *
passphrase_to_dek (int cipher_algo, STRING2KEY *s2k,
                   int create, int nocache,
                   const char *tryagain_text, int *canceled)
{
  char *pw = NULL;
  DEK *dek;
  STRING2KEY help_s2k;
  int dummy_canceled;
  char s2k_cacheidbuf[1+16+1];
  char *s2k_cacheid = NULL;

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

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

  /* Create a new salt or what else to be filled into the s2k for a
     new key.  */
  if (create && (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];

      snprintf (buf, sizeof buf, "%d %d %d",
                cipher_algo, s2k->mode, s2k->hash_algo );
      write_status_text ( STATUS_NEED_PASSPHRASE_SYM, buf );
    }

  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 (!nocache && (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 (create && nocache, s2k_cacheid,
                           create? opt.passphrase_repeat : 0,
                           tryagain_text, 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) && create)
    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;
}
예제 #28
0
파일: delkey.c 프로젝트: randombit/hacrypto
/****************
 * Delete a public or secret key from a keyring.
 * r_sec_avail will be set if a secret key is available and the public
 * key can't be deleted for that reason.
 */
static int
do_delete_key( const char *username, int secret, int force, int *r_sec_avail )
{
    int rc = 0;
    KBNODE keyblock = NULL;
    KBNODE node;
    KEYDB_HANDLE hd = keydb_new (secret);
    PKT_public_key *pk = NULL;
    PKT_secret_key *sk = NULL;
    u32 keyid[2];
    int okay=0;
    int yes;
    KEYDB_SEARCH_DESC desc;
    int exactmatch;

    *r_sec_avail = 0;

    /* search the userid */
    classify_user_id (username, &desc);
    exactmatch = (desc.mode == KEYDB_SEARCH_MODE_FPR
                  || desc.mode == KEYDB_SEARCH_MODE_FPR16
                  || desc.mode == KEYDB_SEARCH_MODE_FPR20);
    rc = desc.mode? keydb_search (hd, &desc, 1):G10ERR_INV_USER_ID;
    if (rc) {
        log_error (_("key \"%s\" not found: %s\n"), username, g10_errstr (rc));
        write_status_text( STATUS_DELETE_PROBLEM, "1" );
        goto leave;
    }

    /* read the keyblock */
    rc = keydb_get_keyblock (hd, &keyblock );
    if (rc) {
        log_error (_("error reading keyblock: %s\n"), g10_errstr(rc) );
        goto leave;
    }

    /* get the keyid from the keyblock */
    node = find_kbnode( keyblock, secret? PKT_SECRET_KEY:PKT_PUBLIC_KEY );
    if( !node ) {
        log_error("Oops; key not found anymore!\n");
        rc = G10ERR_GENERAL;
        goto leave;
    }

    if( secret )
    {
        sk = node->pkt->pkt.secret_key;
        keyid_from_sk( sk, keyid );
    }
    else
    {
        /* public */
        pk = node->pkt->pkt.public_key;
        keyid_from_pk( pk, keyid );

        if(!force)
        {
            rc = seckey_available( keyid );
            if( !rc )
            {
                *r_sec_avail = 1;
                rc = -1;
                goto leave;
            }
            else if( rc != G10ERR_NO_SECKEY )
                log_error("%s: get secret key: %s\n", username, g10_errstr(rc) );
            else
                rc = 0;
        }
    }

    if( rc )
        rc = 0;
    else if (opt.batch && exactmatch)
        okay++;
    else if( opt.batch && secret )
    {
        log_error(_("can't do this in batch mode\n"));
        log_info (_("(unless you specify the key by fingerprint)\n"));
    }
    else if( opt.batch && opt.answer_yes )
        okay++;
    else if( opt.batch )
    {
        log_error(_("can't do this in batch mode without \"--yes\"\n"));
        log_info (_("(unless you specify the key by fingerprint)\n"));
    }
    else {
        if( secret )
            print_seckey_info( sk );
        else
            print_pubkey_info(NULL, pk );
        tty_printf( "\n" );

        yes = cpr_get_answer_is_yes( secret? "delete_key.secret.okay"
                                     : "delete_key.okay",
                                     _("Delete this key from the keyring? (y/N) "));
        if( !cpr_enabled() && secret && yes ) {
            /* I think it is not required to check a passphrase; if
             * the user is so stupid as to let others access his secret keyring
             * (and has no backup) - it is up him to read some very
             * basic texts about security.
             */
            yes = cpr_get_answer_is_yes("delete_key.secret.okay",
                                        _("This is a secret key! - really delete? (y/N) "));
        }
        if( yes )
            okay++;
    }


    if( okay ) {
        rc = keydb_delete_keyblock (hd);
        if (rc) {
            log_error (_("deleting keyblock failed: %s\n"), g10_errstr(rc) );
            goto leave;
        }

        /* Note that the ownertrust being cleared will trigger a
               revalidation_mark().  This makes sense - only deleting keys
               that have ownertrust set should trigger this. */

        if (!secret && pk && clear_ownertrusts (pk)) {
            if (opt.verbose)
                log_info (_("ownertrust information cleared\n"));
        }
    }

leave:
    keydb_release (hd);
    release_kbnode (keyblock);
    return rc;
}