示例#1
0
文件: certdump.c 项目: FMayzek/gnupg
void
gpgsm_dump_string (const char *string)
{

  if (!string)
    log_printf ("[error]");
  else
    {
      const unsigned char *s;

      for (s=(const unsigned char*)string; *s; s++)
        {
          if (*s < ' ' || (*s >= 0x7f && *s <= 0xa0))
            break;
        }
      if (!*s && *string != '[')
        log_printf ("%s", string);
      else
        {
          log_printf ( "[ ");
          log_printhex (NULL, string, strlen (string));
          log_printf ( " ]");
        }
    }
}
/* Put the DIGEST into an DER encoded container and return it in R_VAL. */
static int
encode_md_for_card (const unsigned char *digest, size_t digestlen, int algo,
                    unsigned char **r_val, size_t *r_len)
{
  unsigned char *frame;
  unsigned char asn[100];
  size_t asnlen;

  *r_val = NULL;
  *r_len = 0;

  asnlen = DIM(asn);
  if (!algo || gcry_md_test_algo (algo))
    return gpg_error (GPG_ERR_DIGEST_ALGO);
  if (gcry_md_algo_info (algo, GCRYCTL_GET_ASNOID, asn, &asnlen))
    {
      log_error ("no object identifier for algo %d\n", algo);
      return gpg_error (GPG_ERR_INTERNAL);
    }

  frame = xtrymalloc (asnlen + digestlen);
  if (!frame)
    return out_of_core ();
  memcpy (frame, asn, asnlen);
  memcpy (frame+asnlen, digest, digestlen);
  if (DBG_CRYPTO)
    log_printhex ("encoded hash:", frame, asnlen+digestlen);
      
  *r_val = frame;
  *r_len = asnlen+digestlen;
  return 0;
}
示例#3
0
/* Return the so called KEYGRIP which is the SHA-1 hash of the public
   key parameters expressed as an canoncial encoded S-Exp.  ARRAY must
   be 20 bytes long.  Returns ARRAY or a newly allocated buffer if ARRAY was
   given as NULL.  May return NULL on error.  */
unsigned char *
gpgsm_get_keygrip (ksba_cert_t cert, unsigned char *array)
{
  gcry_sexp_t s_pkey;
  int rc;
  ksba_sexp_t p;
  size_t n;

  p = ksba_cert_get_public_key (cert);
  if (!p)
    return NULL; /* oops */

  if (DBG_X509)
    log_debug ("get_keygrip for public key\n");
  n = gcry_sexp_canon_len (p, 0, NULL, NULL);
  if (!n)
    {
      log_error ("libksba did not return a proper S-Exp\n");
      return NULL;
    }
  rc = gcry_sexp_sscan ( &s_pkey, NULL, (char*)p, n);
  xfree (p);
  if (rc)
    {
      log_error ("gcry_sexp_scan failed: %s\n", gpg_strerror (rc));
      return NULL;
    }
  array = gcry_pk_get_keygrip (s_pkey, array);
  gcry_sexp_release (s_pkey);
  if (!array)
    {
      rc = gpg_error (GPG_ERR_GENERAL);
      log_error ("can't calculate keygrip\n");
      return NULL;
    }
  if (DBG_X509)
    log_printhex ("keygrip=", array, 20);

  return array;
}
示例#4
0
static void
dump_keyblob (tupledesc_t tuples)
{
  size_t n;
  unsigned int tag;
  const void *value;

  log_info ("keyblob dump:\n");
  tag = KEYBLOB_TAG_BLOBVERSION;
  value = find_tuple (tuples, tag, &n);
  while (value)
    {
      log_info ("   tag: %-5u len: %-2u value: ", tag, (unsigned int)n);
      if (tag == KEYBLOB_TAG_ENCKEY
          ||  tag == KEYBLOB_TAG_MACKEY)
        log_printf ("[confidential]\n");
      else if (!n)
        log_printf ("[none]\n");
      else
        log_printhex ("", value, n);
      value = next_tuple (tuples, &tag, &n);
    }
}
示例#5
0
static int
get_it( PKT_pubkey_enc *enc, DEK *dek, PKT_secret_key *sk, u32 *keyid )
{
  int rc;
  gcry_mpi_t plain_dek  = NULL;
  byte *frame = NULL;
  unsigned int n;
  size_t nframe;
  u16 csum, csum2;
  
  int card = 0;

  if (sk->is_protected && sk->protect.s2k.mode == 1002)
    { /* Note, that we only support RSA for now. */
#ifdef ENABLE_CARD_SUPPORT
      unsigned char *rbuf;
      size_t rbuflen;
      char *snbuf;
      unsigned char *indata = NULL;
      size_t indatalen;

      snbuf = serialno_and_fpr_from_sk (sk->protect.iv, sk->protect.ivlen, sk);

      if (gcry_mpi_aprint (GCRYMPI_FMT_USG, &indata, &indatalen, enc->data[0]))
        BUG ();

      rc = agent_scd_pkdecrypt (snbuf, indata, indatalen, &rbuf, &rbuflen);
      xfree (snbuf);
      xfree (indata);
      if (rc)
        goto leave;

      frame = rbuf;
      nframe = rbuflen;
      card = 1;
#else
      rc = gpg_error (GPG_ERR_NOT_SUPPORTED);
      goto leave;
#endif /*!ENABLE_CARD_SUPPORT*/
    }
  else
    {
      rc = pk_decrypt (sk->pubkey_algo, &plain_dek, enc->data, sk->skey );
      if( rc )
	goto leave;
      if (gcry_mpi_aprint (GCRYMPI_FMT_USG, &frame, &nframe, plain_dek))
        BUG();
      gcry_mpi_release (plain_dek); plain_dek = NULL;
    }

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

    if( n + 4 > nframe )
	{ rc = G10ERR_WRONG_SECKEY; goto leave; }

    dek->keylen = nframe - (n+1) - 2;
    dek->algo = frame[n++];
    if( dek->algo ==  CIPHER_ALGO_IDEA )
	write_status(STATUS_RSA_OR_IDEA);
    rc = openpgp_cipher_test_algo (dek->algo);
    if( rc ) {
	if( !opt.quiet && gpg_err_code (rc) == GPG_ERR_CIPHER_ALGO ) {
	    log_info(_("cipher algorithm %d%s is unknown or disabled\n"),
                     dek->algo, dek->algo == CIPHER_ALGO_IDEA? " (IDEA)":"");
	    if(dek->algo==CIPHER_ALGO_IDEA)
	      idea_cipher_warn (0);
	}
	dek->algo = 0;
	goto leave;
    }
    if ( dek->keylen != openpgp_cipher_get_algo_keylen (dek->algo) ) {
	rc = GPG_ERR_WRONG_SECKEY;
	goto leave;
    }

    /* copy the key to DEK and compare the checksum */
    csum  = frame[nframe-2] << 8;
    csum |= frame[nframe-1];
    memcpy( dek->key, frame+n, dek->keylen );
    for( csum2=0, n=0; n < dek->keylen; n++ )
	csum2 += dek->key[n];
    if( csum != csum2 ) {
	rc = G10ERR_WRONG_SECKEY;
	goto leave;
    }
    if( DBG_CIPHER )
        log_printhex ("DEK is:", dek->key, dek->keylen );
    /* check that the algo is in the preferences and whether it has expired */
    {
	PKT_public_key *pk = NULL;
        KBNODE pkb = get_pubkeyblock (keyid);

	if( !pkb ) {
            rc = -1;
	    log_error("oops: public key not found for preference check\n");
        }
	else if(pkb->pkt->pkt.public_key->selfsigversion > 3
		&& dek->algo != CIPHER_ALGO_3DES
		&& !opt.quiet
		&& !is_algo_in_prefs( pkb, PREFTYPE_SYM, dek->algo ))
	  log_info (_("WARNING: cipher algorithm %s not found in recipient"
                      " preferences\n"), openpgp_cipher_algo_name (dek->algo));
        if (!rc) {
            KBNODE k;
            
            for (k=pkb; k; k = k->next) {
                if (k->pkt->pkttype == PKT_PUBLIC_KEY 
                    || k->pkt->pkttype == PKT_PUBLIC_SUBKEY){
                    u32 aki[2];
        	    keyid_from_pk(k->pkt->pkt.public_key, aki);

                    if (aki[0]==keyid[0] && aki[1]==keyid[1]) {
                        pk = k->pkt->pkt.public_key;
                        break;
                    }
                }
            }
            if (!pk)
                BUG ();
            if ( pk->expiredate && pk->expiredate <= make_timestamp() ) {
                log_info(_("NOTE: secret key %s expired at %s\n"),
                         keystr(keyid), asctimestamp( pk->expiredate) );
            }
        }

        if ( pk &&  pk->is_revoked ) {
            log_info( _("NOTE: key has been revoked") );
            log_printf ("\n");
            show_revocation_reason( pk, 1 );
        }

	release_kbnode (pkb);
	rc = 0;
    }


  leave:
    gcry_mpi_release (plain_dek);
    xfree (frame);
    return rc;
}
示例#6
0
/*
 * Filter to do a complete public key encryption.
 */
int
encrypt_filter (void *opaque, int control,
                iobuf_t a, byte *buf, size_t *ret_len)
{
  size_t size = *ret_len;
  encrypt_filter_context_t *efx = opaque;
  int rc = 0;

  if (control == IOBUFCTRL_UNDERFLOW) /* decrypt */
    {
      BUG(); /* not used */
    }
  else if ( control == IOBUFCTRL_FLUSH ) /* encrypt */
    {
      if ( !efx->header_okay )
        {
          efx->cfx.dek = xmalloc_secure_clear ( sizeof *efx->cfx.dek );
          if ( !opt.def_cipher_algo  )
            {
              /* Try to get it from the prefs. */
              efx->cfx.dek->algo =
                select_algo_from_prefs (efx->pk_list, PREFTYPE_SYM, -1, NULL);
              if (efx->cfx.dek->algo == -1 )
                {
                  /* Because 3DES is implicitly in the prefs, this can
                     only happen if we do not have any public keys in
                     the list.  */
                  efx->cfx.dek->algo = DEFAULT_CIPHER_ALGO;
                }

              /* In case 3DES has been selected, print a warning if
                 any key does not have a preference for AES.  This
                 should help to indentify why encrypting to several
                 recipients falls back to 3DES. */
              if (opt.verbose
                  && efx->cfx.dek->algo == CIPHER_ALGO_3DES)
                warn_missing_aes_from_pklist (efx->pk_list);
	    }
          else
            {
	      if (!opt.expert
                  && select_algo_from_prefs (efx->pk_list,PREFTYPE_SYM,
                                             opt.def_cipher_algo,
                                             NULL) != opt.def_cipher_algo)
		log_info(_("forcing symmetric cipher %s (%d) "
			   "violates recipient preferences\n"),
			 openpgp_cipher_algo_name (opt.def_cipher_algo),
			 opt.def_cipher_algo);

	      efx->cfx.dek->algo = opt.def_cipher_algo;
	    }

          efx->cfx.dek->use_mdc = use_mdc (efx->pk_list,efx->cfx.dek->algo);

          make_session_key ( efx->cfx.dek );
          if (DBG_CRYPTO)
            log_printhex ("DEK is: ", efx->cfx.dek->key, efx->cfx.dek->keylen);

          rc = write_pubkey_enc_from_list (efx->pk_list, efx->cfx.dek, a);
          if (rc)
            return rc;

	    if(efx->symkey_s2k && efx->symkey_dek)
	      {
		rc=write_symkey_enc(efx->symkey_s2k,efx->symkey_dek,
				    efx->cfx.dek,a);
		if(rc)
		  return rc;
	      }

	    iobuf_push_filter (a, cipher_filter, &efx->cfx);

	    efx->header_okay = 1;
	}
      rc = iobuf_write (a, buf, size);

    }
  else if (control == IOBUFCTRL_FREE)
    {
      xfree (efx->symkey_dek);
      xfree (efx->symkey_s2k);
    }
  else if ( control == IOBUFCTRL_DESC )
    {
      *(char**)buf = "encrypt_filter";
    }
  return rc;
}
示例#7
0
/*
 * Encrypt the file with the given userids (or ask if none is
 * supplied).  Either FILENAME or FILEFD must be given, but not both.
 * The caller may provide a checked list of public keys in
 * PROVIDED_PKS; if not the function builds a list of keys on its own.
 *
 * Note that FILEFD is currently only used by cmd_encrypt in the the
 * not yet finished server.c.
 */
int
encrypt_crypt (ctrl_t ctrl, int filefd, const char *filename,
               strlist_t remusr, int use_symkey, pk_list_t provided_keys,
               int outputfd)
{
  iobuf_t inp = NULL;
  iobuf_t out = NULL;
  PACKET pkt;
  PKT_plaintext *pt = NULL;
  DEK *symkey_dek = NULL;
  STRING2KEY *symkey_s2k = NULL;
  int rc = 0, rc2 = 0;
  u32 filesize;
  cipher_filter_context_t cfx;
  armor_filter_context_t *afx = NULL;
  compress_filter_context_t zfx;
  text_filter_context_t tfx;
  progress_filter_context_t *pfx;
  PK_LIST pk_list;
  int do_compress;

  if (filefd != -1 && filename)
    return gpg_error (GPG_ERR_INV_ARG);  /* Both given.  */

  do_compress = !!opt.compress_algo;

  pfx = new_progress_context ();
  memset( &cfx, 0, sizeof cfx);
  memset( &zfx, 0, sizeof zfx);
  memset( &tfx, 0, sizeof tfx);
  init_packet(&pkt);

  if (use_symkey
      && (rc=setup_symkey(&symkey_s2k,&symkey_dek)))
    {
      release_progress_context (pfx);
      return rc;
    }

  if (provided_keys)
    pk_list = provided_keys;
  else
    {
      if ((rc = build_pk_list (ctrl, remusr, &pk_list, PUBKEY_USAGE_ENC)))
        {
          release_progress_context (pfx);
          return rc;
        }
    }

  /* Prepare iobufs. */
#ifdef HAVE_W32_SYSTEM
  if (filefd == -1)
    inp = iobuf_open_fd_or_name (GNUPG_INVALID_FD, filename, "rb");
  else
    {
      inp = NULL;
      gpg_err_set_errno (ENOSYS);
    }
#else
  inp = iobuf_open_fd_or_name (filefd, filename, "rb");
#endif
  if (inp)
    iobuf_ioctl (inp, IOBUF_IOCTL_NO_CACHE, 1, NULL);
  if (inp && is_secured_file (iobuf_get_fd (inp)))
    {
      iobuf_close (inp);
      inp = NULL;
      gpg_err_set_errno (EPERM);
    }
  if (!inp)
    {
      char xname[64];

      rc = gpg_error_from_syserror ();
      if (filefd != -1)
        snprintf (xname, sizeof xname, "[fd %d]", filefd);
      else if (!filename)
        strcpy (xname, "[stdin]");
      else
        *xname = 0;
      log_error (_("can't open '%s': %s\n"),
                 *xname? xname : filename, gpg_strerror (rc) );
      goto leave;
    }

  if (opt.verbose)
    log_info (_("reading from '%s'\n"), iobuf_get_fname_nonnull (inp));

  handle_progress (pfx, inp, filename);

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

  rc = open_outfile (outputfd, filename, opt.armor? 1:0, 0, &out);
  if (rc)
    goto leave;

  if (opt.armor)
    {
      afx = new_armor_context ();
      push_armor_filter (afx, out);
    }

  /* Create a session key. */
  cfx.dek = xmalloc_secure_clear (sizeof *cfx.dek);
  if (!opt.def_cipher_algo)
    {
      /* Try to get it from the prefs.  */
      cfx.dek->algo = select_algo_from_prefs (pk_list, PREFTYPE_SYM, -1, NULL);
      /* The only way select_algo_from_prefs can fail here is when
         mixing v3 and v4 keys, as v4 keys have an implicit preference
         entry for 3DES, and the pk_list cannot be empty.  In this
         case, use 3DES anyway as it's the safest choice - perhaps the
         v3 key is being used in an OpenPGP implementation and we know
         that the implementation behind any v4 key can handle 3DES. */
      if (cfx.dek->algo == -1)
        {
          cfx.dek->algo = CIPHER_ALGO_3DES;
        }

      /* In case 3DES has been selected, print a warning if any key
         does not have a preference for AES.  This should help to
         indentify why encrypting to several recipients falls back to
         3DES. */
      if (opt.verbose && cfx.dek->algo == CIPHER_ALGO_3DES)
        warn_missing_aes_from_pklist (pk_list);
    }
  else
    {
      if (!opt.expert
          && (select_algo_from_prefs (pk_list, PREFTYPE_SYM,
                                      opt.def_cipher_algo, NULL)
              != opt.def_cipher_algo))
        {
          log_info(_("WARNING: forcing symmetric cipher %s (%d)"
                     " violates recipient preferences\n"),
                   openpgp_cipher_algo_name (opt.def_cipher_algo),
                   opt.def_cipher_algo);
        }

      cfx.dek->algo = opt.def_cipher_algo;
    }

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

  /* Only do the is-file-already-compressed check if we are using a
     MDC.  This forces compressed files to be re-compressed if we do
     not have a MDC to give some protection against chosen ciphertext
     attacks. */

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

  make_session_key (cfx.dek);
  if (DBG_CRYPTO)
    log_printhex ("DEK is: ", cfx.dek->key, cfx.dek->keylen );

  rc = write_pubkey_enc_from_list (pk_list, cfx.dek, out);
  if (rc)
    goto leave;

  /* We put the passphrase (if any) after any public keys as this
     seems to be the most useful on the recipient side - there is no
     point in prompting a user for a passphrase if they have the
     secret key needed to decrypt.  */
  if(use_symkey && (rc = write_symkey_enc(symkey_s2k,symkey_dek,cfx.dek,out)))
    goto leave;

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

  /* Get the size of the file if possible, i.e., if it is a real file.  */
  if (filename && *filename
      && !iobuf_is_pipe_filename (filename) && !opt.textmode )
    {
      off_t tmpsize;
      int overflow;

      if ( !(tmpsize = iobuf_get_filelength(inp, &overflow))
           && !overflow && opt.verbose)
        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;
      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;

  /* Register the cipher filter. */
  iobuf_push_filter (out, cipher_filter, &cfx);

  /* Register the compress filter. */
  if (do_compress)
    {
      int compr_algo = opt.compress_algo;

      if (compr_algo == -1)
        {
          compr_algo = select_algo_from_prefs (pk_list, PREFTYPE_ZIP, -1, NULL);
          if (compr_algo == -1)
            compr_algo = DEFAULT_COMPRESS_ALGO;
          /* Theoretically impossible to get here since uncompressed
             is implicit.  */
        }
      else if (!opt.expert
               && select_algo_from_prefs(pk_list, PREFTYPE_ZIP,
                                         compr_algo, NULL) != compr_algo)
        {
          log_info (_("WARNING: forcing compression algorithm %s (%d)"
                      " violates recipient preferences\n"),
                    compress_algo_to_string(compr_algo), compr_algo);
        }

      /* Algo 0 means no compression. */
      if (compr_algo)
        {
          if (cfx.dek && cfx.dek->use_mdc)
            zfx.new_ctb = 1;
          push_compress_filter (out,&zfx,compr_algo);
        }
    }

  /* Do the work. */
  if (!opt.no_literal)
    {
      if ((rc = build_packet( out, &pkt )))
        log_error ("build_packet failed: %s\n", gpg_strerror (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)
        {
          rc = iobuf_write (out, copy_buffer, bytes_copied);
          if (rc)
            {
              log_error ("copying input to output failed: %s\n",
                         gpg_strerror (rc));
              break;
            }
        }
      wipememory (copy_buffer, 4096); /* Burn the buffer. */
    }

  /* Finish the stuff. */
 leave:
  iobuf_close (inp);
  if (rc)
    iobuf_cancel (out);
  else
    {
      iobuf_close (out); /* fixme: check returncode */
      write_status (STATUS_END_ENCRYPTION);
    }
  if (pt)
    pt->buf = NULL;
  free_packet (&pkt);
  xfree (cfx.dek);
  xfree (symkey_dek);
  xfree (symkey_s2k);
  if (!provided_keys)
    release_pk_list (pk_list);
  release_armor_context (afx);
  release_progress_context (pfx);
  return rc;
}
示例#8
0
/* Verify an EdDSA signature.  See sign_eddsa for the reference.
 * Check if R_IN and S_IN verifies INPUT.  PKEY has the curve
 * parameters and PK is the EdDSA style encoded public key.
 */
gpg_err_code_t
_gcry_ecc_eddsa_verify (gcry_mpi_t input, ECC_public_key *pkey,
                        gcry_mpi_t r_in, gcry_mpi_t s_in, int hashalgo,
                        gcry_mpi_t pk)
{
  int rc;
  mpi_ec_t ctx = NULL;
  int b;
  unsigned int tmp;
  mpi_point_struct Q;          /* Public key.  */
  unsigned char *encpk = NULL; /* Encoded public key.  */
  unsigned int encpklen;
  const void *mbuf, *rbuf;
  unsigned char *tbuf = NULL;
  size_t mlen, rlen;
  unsigned int tlen;
  unsigned char digest[64];
  gcry_buffer_t hvec[3];
  gcry_mpi_t h, s;
  mpi_point_struct Ia, Ib;

  if (!mpi_is_opaque (input) || !mpi_is_opaque (r_in) || !mpi_is_opaque (s_in))
    return GPG_ERR_INV_DATA;
  if (hashalgo != GCRY_MD_SHA512)
    return GPG_ERR_DIGEST_ALGO;

  point_init (&Q);
  point_init (&Ia);
  point_init (&Ib);
  h = mpi_new (0);
  s = mpi_new (0);

  ctx = _gcry_mpi_ec_p_internal_new (pkey->E.model, pkey->E.dialect, 0,
                                     pkey->E.p, pkey->E.a, pkey->E.b);
  b = ctx->nbits/8;
  if (b != 256/8)
    return GPG_ERR_INTERNAL; /* We only support 256 bit. */

  /* Decode and check the public key.  */
  rc = _gcry_ecc_eddsa_decodepoint (pk, ctx, &Q, &encpk, &encpklen);
  if (rc)
    goto leave;
  if (!_gcry_mpi_ec_curve_point (&Q, ctx))
    {
      rc = GPG_ERR_BROKEN_PUBKEY;
      goto leave;
    }
  if (DBG_CIPHER)
    log_printhex ("  e_pk", encpk, encpklen);
  if (encpklen != b)
    {
      rc = GPG_ERR_INV_LENGTH;
      goto leave;
    }

  /* Convert the other input parameters.  */
  mbuf = mpi_get_opaque (input, &tmp);
  mlen = (tmp +7)/8;
  if (DBG_CIPHER)
    log_printhex ("     m", mbuf, mlen);
  rbuf = mpi_get_opaque (r_in, &tmp);
  rlen = (tmp +7)/8;
  if (DBG_CIPHER)
    log_printhex ("     r", rbuf, rlen);
  if (rlen != b)
    {
      rc = GPG_ERR_INV_LENGTH;
      goto leave;
    }

  /* h = H(encodepoint(R) + encodepoint(pk) + m)  */
  hvec[0].data = (char*)rbuf;
  hvec[0].off  = 0;
  hvec[0].len  = rlen;
  hvec[1].data = encpk;
  hvec[1].off  = 0;
  hvec[1].len  = encpklen;
  hvec[2].data = (char*)mbuf;
  hvec[2].off  = 0;
  hvec[2].len  = mlen;
  rc = _gcry_md_hash_buffers (hashalgo, 0, digest, hvec, 3);
  if (rc)
    goto leave;
  reverse_buffer (digest, 64);
  if (DBG_CIPHER)
    log_printhex (" H(R+)", digest, 64);
  _gcry_mpi_set_buffer (h, digest, 64, 0);

  /* According to the paper the best way for verification is:
         encodepoint(sG - h·Q) = encodepoint(r)
     because we don't need to decode R. */
  {
    void *sbuf;
    unsigned int slen;

    sbuf = _gcry_mpi_get_opaque_copy (s_in, &tmp);
    slen = (tmp +7)/8;
    reverse_buffer (sbuf, slen);
    if (DBG_CIPHER)
      log_printhex ("     s", sbuf, slen);
    _gcry_mpi_set_buffer (s, sbuf, slen, 0);
    xfree (sbuf);
    if (slen != b)
      {
        rc = GPG_ERR_INV_LENGTH;
        goto leave;
      }
  }

  _gcry_mpi_ec_mul_point (&Ia, s, &pkey->E.G, ctx);
  _gcry_mpi_ec_mul_point (&Ib, h, &Q, ctx);
  _gcry_mpi_neg (Ib.x, Ib.x);
  _gcry_mpi_ec_add_points (&Ia, &Ia, &Ib, ctx);
  rc = _gcry_ecc_eddsa_encodepoint (&Ia, ctx, s, h, 0, &tbuf, &tlen);
  if (rc)
    goto leave;
  if (tlen != rlen || memcmp (tbuf, rbuf, tlen))
    {
      rc = GPG_ERR_BAD_SIGNATURE;
      goto leave;
    }

  rc = 0;

 leave:
  xfree (encpk);
  xfree (tbuf);
  _gcry_mpi_ec_free (ctx);
  _gcry_mpi_release (s);
  _gcry_mpi_release (h);
  point_free (&Ia);
  point_free (&Ib);
  point_free (&Q);
  return rc;
}
示例#9
0
/* Assume that the reader is at a pkcs#12 message and try to import
   certificates from that stupid format.  We will transfer secret
   keys to the agent.  */
static gpg_error_t
parse_p12 (ctrl_t ctrl, ksba_reader_t reader, struct stats_s *stats)
{
  gpg_error_t err = 0;
  char buffer[1024];
  size_t ntotal, nread;
  membuf_t p12mbuf;
  char *p12buffer = NULL;
  size_t p12buflen;
  size_t p12bufoff;
  gcry_mpi_t *kparms = NULL;
  struct rsa_secret_key_s sk;
  char *passphrase = NULL;
  unsigned char *key = NULL;
  size_t keylen;
  void *kek = NULL;
  size_t keklen;
  unsigned char *wrappedkey = NULL;
  size_t wrappedkeylen;
  gcry_cipher_hd_t cipherhd = NULL;
  gcry_sexp_t s_key = NULL;
  unsigned char grip[20];
  int bad_pass = 0;
  int i;
  struct store_cert_parm_s store_cert_parm;

  memset (&store_cert_parm, 0, sizeof store_cert_parm);
  store_cert_parm.ctrl = ctrl;
  store_cert_parm.stats = stats;

  init_membuf (&p12mbuf, 4096);
  ntotal = 0;
  while (!(err = ksba_reader_read (reader, buffer, sizeof buffer, &nread)))
    {
      if (ntotal >= MAX_P12OBJ_SIZE*1024)
        {
          /* Arbitrary limit to avoid DoS attacks. */
          err = gpg_error (GPG_ERR_TOO_LARGE);
          log_error ("pkcs#12 object is larger than %dk\n", MAX_P12OBJ_SIZE);
          break;
        }
      put_membuf (&p12mbuf, buffer, nread);
      ntotal += nread;
    }
  if (gpg_err_code (err) == GPG_ERR_EOF)
    err = 0;
  if (!err)
    {
      p12buffer = get_membuf (&p12mbuf, &p12buflen);
      if (!p12buffer)
        err = gpg_error_from_syserror ();
    }
  if (err)
    {
      log_error (_("error reading input: %s\n"), gpg_strerror (err));
      goto leave;
    }

  /* GnuPG 2.0.4 accidently created binary P12 files with the string
     "The passphrase is %s encoded.\n\n" prepended to the ASN.1 data.
     We fix that here.  */
  if (p12buflen > 29 && !memcmp (p12buffer, "The passphrase is ", 18))
    {
      for (p12bufoff=18;
           p12bufoff < p12buflen && p12buffer[p12bufoff] != '\n';
           p12bufoff++)
        ;
      p12bufoff++;
      if (p12bufoff < p12buflen && p12buffer[p12bufoff] == '\n')
        p12bufoff++;
    }
  else
    p12bufoff = 0;


  err = gpgsm_agent_ask_passphrase
    (ctrl,
     i18n_utf8 ("Please enter the passphrase to unprotect the PKCS#12 object."),
     0, &passphrase);
  if (err)
    goto leave;

  kparms = p12_parse (p12buffer + p12bufoff, p12buflen - p12bufoff,
                      passphrase, store_cert_cb, &store_cert_parm, &bad_pass);

  xfree (passphrase);
  passphrase = NULL;

  if (!kparms)
    {
      log_error ("error parsing or decrypting the PKCS#12 file\n");
      err = gpg_error (GPG_ERR_INV_OBJ);
      goto leave;
    }

/*    print_mpi ("   n", kparms[0]); */
/*    print_mpi ("   e", kparms[1]); */
/*    print_mpi ("   d", kparms[2]); */
/*    print_mpi ("   p", kparms[3]); */
/*    print_mpi ("   q", kparms[4]); */
/*    print_mpi ("dmp1", kparms[5]); */
/*    print_mpi ("dmq1", kparms[6]); */
/*    print_mpi ("   u", kparms[7]); */

  sk.n = kparms[0];
  sk.e = kparms[1];
  sk.d = kparms[2];
  sk.q = kparms[3];
  sk.p = kparms[4];
  sk.u = kparms[7];
  err = rsa_key_check (&sk);
  if (err)
    goto leave;
/*    print_mpi ("   n", sk.n); */
/*    print_mpi ("   e", sk.e); */
/*    print_mpi ("   d", sk.d); */
/*    print_mpi ("   p", sk.p); */
/*    print_mpi ("   q", sk.q); */
/*    print_mpi ("   u", sk.u); */

  /* Create an S-expresion from the parameters. */
  err = gcry_sexp_build (&s_key, NULL,
                         "(private-key(rsa(n%m)(e%m)(d%m)(p%m)(q%m)(u%m)))",
                         sk.n, sk.e, sk.d, sk.p, sk.q, sk.u, NULL);
  for (i=0; i < 8; i++)
    gcry_mpi_release (kparms[i]);
  gcry_free (kparms);
  kparms = NULL;
  if (err)
    {
      log_error ("failed to create S-expression from key: %s\n",
                 gpg_strerror (err));
      goto leave;
    }

  /* Compute the keygrip. */
  if (!gcry_pk_get_keygrip (s_key, grip))
    {
      err = gpg_error (GPG_ERR_GENERAL);
      log_error ("can't calculate keygrip\n");
      goto leave;
    }
  log_printhex ("keygrip=", grip, 20);

  /* Convert to canonical encoding using a function which pads it to a
     multiple of 64 bits.  We need this padding for AESWRAP.  */
  err = make_canon_sexp_pad (s_key, 1, &key, &keylen);
  if (err)
    {
      log_error ("error creating canonical S-expression\n");
      goto leave;
    }
  gcry_sexp_release (s_key);
  s_key = NULL;

  /* Get the current KEK.  */
  err = gpgsm_agent_keywrap_key (ctrl, 0, &kek, &keklen);
  if (err)
    {
      log_error ("error getting the KEK: %s\n", gpg_strerror (err));
      goto leave;
    }

  /* Wrap the key.  */
  err = gcry_cipher_open (&cipherhd, GCRY_CIPHER_AES128,
                          GCRY_CIPHER_MODE_AESWRAP, 0);
  if (err)
    goto leave;
  err = gcry_cipher_setkey (cipherhd, kek, keklen);
  if (err)
    goto leave;
  xfree (kek);
  kek = NULL;

  wrappedkeylen = keylen + 8;
  wrappedkey = xtrymalloc (wrappedkeylen);
  if (!wrappedkey)
    {
      err = gpg_error_from_syserror ();
      goto leave;
    }

  err = gcry_cipher_encrypt (cipherhd, wrappedkey, wrappedkeylen, key, keylen);
  if (err)
    goto leave;
  xfree (key);
  key = NULL;
  gcry_cipher_close (cipherhd);
  cipherhd = NULL;

  /* Send the wrapped key to the agent.  */
  err = gpgsm_agent_import_key (ctrl, wrappedkey, wrappedkeylen);
  if (!err)
    {
      stats->count++;
      stats->secret_read++;
      stats->secret_imported++;
    }
  else if ( gpg_err_code (err) == GPG_ERR_EEXIST )
    {
      err = 0;
      stats->count++;
      stats->secret_read++;
      stats->secret_dups++;
    }

  /* If we did not get an error from storing the secret key we return
     a possible error from parsing the certificates.  We do this after
     storing the secret keys so that a bad certificate does not
     inhibit our chance to store the secret key.  */
  if (!err && store_cert_parm.err)
    err = store_cert_parm.err;

 leave:
  if (kparms)
    {
      for (i=0; i < 8; i++)
        gcry_mpi_release (kparms[i]);
      gcry_free (kparms);
      kparms = NULL;
    }
  xfree (key);
  gcry_sexp_release (s_key);
  xfree (passphrase);
  gcry_cipher_close (cipherhd);
  xfree (wrappedkey);
  xfree (kek);
  xfree (get_membuf (&p12mbuf, NULL));
  xfree (p12buffer);

  if (bad_pass)
    {
      /* We only write a plain error code and not direct
         BAD_PASSPHRASE because the pkcs12 parser might issue this
         message multiple times, BAD_PASSPHRASE in general requires a
         keyID and parts of the import might actually succeed so that
         IMPORT_PROBLEM is also not appropriate. */
      gpgsm_status_with_err_code (ctrl, STATUS_ERROR,
                                  "import.parsep12", GPG_ERR_BAD_PASSPHRASE);
    }

  return err;
}
示例#10
0
/* Compute an EdDSA signature. See:
 *   [ed25519] 23pp. (PDF) Daniel J. Bernstein, Niels Duif, Tanja
 *   Lange, Peter Schwabe, Bo-Yin Yang. High-speed high-security
 *   signatures.  Journal of Cryptographic Engineering 2 (2012), 77-89.
 *   Document ID: a1a62a2f76d23f65d622484ddd09caf8.
 *   URL: http://cr.yp.to/papers.html#ed25519. Date: 2011.09.26.
 *
 * Despite that this function requires the specification of a hash
 * algorithm, we only support what has been specified by the paper.
 * This may change in the future.  Note that we don't check the used
 * curve; the user is responsible to use Ed25519.
 *
 * Return the signature struct (r,s) from the message hash.  The caller
 * must have allocated R_R and S.
 */
gpg_err_code_t
_gcry_ecc_eddsa_sign (gcry_mpi_t input, ECC_secret_key *skey,
                      gcry_mpi_t r_r, gcry_mpi_t s, int hashalgo, gcry_mpi_t pk)
{
  int rc;
  mpi_ec_t ctx = NULL;
  int b;
  unsigned int tmp;
  unsigned char *digest;
  gcry_buffer_t hvec[3];
  const void *mbuf;
  size_t mlen;
  unsigned char *rawmpi = NULL;
  unsigned int rawmpilen;
  unsigned char *encpk = NULL; /* Encoded public key.  */
  unsigned int encpklen;
  mpi_point_struct I;          /* Intermediate value.  */
  mpi_point_struct Q;          /* Public key.  */
  gcry_mpi_t a, x, y, r;

  memset (hvec, 0, sizeof hvec);

  if (!mpi_is_opaque (input))
    return GPG_ERR_INV_DATA;

  /* Initialize some helpers.  */
  point_init (&I);
  point_init (&Q);
  a = mpi_snew (0);
  x = mpi_new (0);
  y = mpi_new (0);
  r = mpi_new (0);
  ctx = _gcry_mpi_ec_p_internal_new (skey->E.model, skey->E.dialect, 0,
                                     skey->E.p, skey->E.a, skey->E.b);
  b = (ctx->nbits+7)/8;
  if (b != 256/8)
    return GPG_ERR_INTERNAL; /* We only support 256 bit. */

  rc = _gcry_ecc_eddsa_compute_h_d (&digest, skey->d, ctx);
  if (rc)
    goto leave;
  _gcry_mpi_set_buffer (a, digest, 32, 0);

  /* Compute the public key if it has not been supplied as optional
     parameter.  */
  if (pk)
    {
      rc = _gcry_ecc_eddsa_decodepoint (pk, ctx, &Q,  &encpk, &encpklen);
      if (rc)
        goto leave;
      if (DBG_CIPHER)
        log_printhex ("* e_pk", encpk, encpklen);
      if (!_gcry_mpi_ec_curve_point (&Q, ctx))
        {
          rc = GPG_ERR_BROKEN_PUBKEY;
          goto leave;
        }
    }
  else
    {
      _gcry_mpi_ec_mul_point (&Q, a, &skey->E.G, ctx);
      rc = _gcry_ecc_eddsa_encodepoint (&Q, ctx, x, y, 0, &encpk, &encpklen);
      if (rc)
        goto leave;
      if (DBG_CIPHER)
        log_printhex ("  e_pk", encpk, encpklen);
    }

  /* Compute R.  */
  mbuf = mpi_get_opaque (input, &tmp);
  mlen = (tmp +7)/8;
  if (DBG_CIPHER)
    log_printhex ("     m", mbuf, mlen);

  hvec[0].data = digest;
  hvec[0].off  = 32;
  hvec[0].len  = 32;
  hvec[1].data = (char*)mbuf;
  hvec[1].len  = mlen;
  rc = _gcry_md_hash_buffers (hashalgo, 0, digest, hvec, 2);
  if (rc)
    goto leave;
  reverse_buffer (digest, 64);
  if (DBG_CIPHER)
    log_printhex ("     r", digest, 64);
  _gcry_mpi_set_buffer (r, digest, 64, 0);
  _gcry_mpi_ec_mul_point (&I, r, &skey->E.G, ctx);
  if (DBG_CIPHER)
    log_printpnt ("   r", &I, ctx);

  /* Convert R into affine coordinates and apply encoding.  */
  rc = _gcry_ecc_eddsa_encodepoint (&I, ctx, x, y, 0, &rawmpi, &rawmpilen);
  if (rc)
    goto leave;
  if (DBG_CIPHER)
    log_printhex ("   e_r", rawmpi, rawmpilen);

  /* S = r + a * H(encodepoint(R) + encodepoint(pk) + m) mod n  */
  hvec[0].data = rawmpi;  /* (this is R) */
  hvec[0].off  = 0;
  hvec[0].len  = rawmpilen;
  hvec[1].data = encpk;
  hvec[1].off  = 0;
  hvec[1].len  = encpklen;
  hvec[2].data = (char*)mbuf;
  hvec[2].off  = 0;
  hvec[2].len  = mlen;
  rc = _gcry_md_hash_buffers (hashalgo, 0, digest, hvec, 3);
  if (rc)
    goto leave;

  /* No more need for RAWMPI thus we now transfer it to R_R.  */
  mpi_set_opaque (r_r, rawmpi, rawmpilen*8);
  rawmpi = NULL;

  reverse_buffer (digest, 64);
  if (DBG_CIPHER)
    log_printhex (" H(R+)", digest, 64);
  _gcry_mpi_set_buffer (s, digest, 64, 0);
  mpi_mulm (s, s, a, skey->E.n);
  mpi_addm (s, s, r, skey->E.n);
  rc = eddsa_encodempi (s, b, &rawmpi, &rawmpilen);
  if (rc)
    goto leave;
  if (DBG_CIPHER)
    log_printhex ("   e_s", rawmpi, rawmpilen);
  mpi_set_opaque (s, rawmpi, rawmpilen*8);
  rawmpi = NULL;

  rc = 0;

 leave:
  _gcry_mpi_release (a);
  _gcry_mpi_release (x);
  _gcry_mpi_release (y);
  _gcry_mpi_release (r);
  xfree (digest);
  _gcry_mpi_ec_free (ctx);
  point_free (&I);
  point_free (&Q);
  xfree (encpk);
  xfree (rawmpi);
  return rc;
}
示例#11
0
static gpg_error_t
get_it (PKT_pubkey_enc *enc, DEK *dek, PKT_public_key *sk, u32 *keyid)
{
  gpg_error_t err;
  byte *frame = NULL;
  unsigned int n;
  size_t nframe;
  u16 csum, csum2;
  int card = 0;
  gcry_sexp_t s_data;
  char *desc;
  char *keygrip;
  byte fp[MAX_FINGERPRINT_LEN];
  size_t fpn;
  const int pkalgo = map_pk_openpgp_to_gcry (sk->pubkey_algo);

  /* Get the keygrip.  */
  err = hexkeygrip_from_pk (sk, &keygrip);
  if (err)
    goto leave;

  /* Convert the data to an S-expression.  */
  if (pkalgo == GCRY_PK_ELG || pkalgo == GCRY_PK_ELG_E)
    {
      if (!enc->data[0] || !enc->data[1])
        err = gpg_error (GPG_ERR_BAD_MPI);
      else
        err = gcry_sexp_build (&s_data, NULL, "(enc-val(elg(a%m)(b%m)))",
                               enc->data[0], enc->data[1]);
    }
  else if (pkalgo == GCRY_PK_RSA || pkalgo == GCRY_PK_RSA_E)
    {
      if (!enc->data[0])
        err = gpg_error (GPG_ERR_BAD_MPI);
      else
        err = gcry_sexp_build (&s_data, NULL, "(enc-val(rsa(a%m)))",
                               enc->data[0]);
    }
  else if (pkalgo == GCRY_PK_ECDH)
    {
      if (!enc->data[0] || !enc->data[1])
        err = gpg_error (GPG_ERR_BAD_MPI);
      else
        err = gcry_sexp_build (&s_data, NULL, "(enc-val(ecdh(s%m)(e%m)))",
                               enc->data[0], enc->data[1]);
    }
  else
    err = gpg_error (GPG_ERR_BUG);

  if (err)
    goto leave;

  if (sk->pubkey_algo == PUBKEY_ALGO_ECDH)
    {
      fingerprint_from_pk (sk, fp, &fpn);
      assert (fpn == 20);
    }

  /* Decrypt. */
  desc = gpg_format_keydesc (sk, 0, 1);
  err = agent_pkdecrypt (NULL, keygrip, desc, s_data, &frame, &nframe);
  xfree (desc);
  gcry_sexp_release (s_data);
  if (err)
    goto leave;

  /* Now get the DEK (data encryption key) from the frame
   *
   * Old versions encode the DEK in in this format (msb is left):
   *
   *     0  1  DEK(16 bytes)  CSUM(2 bytes)  0  RND(n bytes) 2
   *
   * Later versions encode the DEK like this:
   *
   *     0  2  RND(n bytes)  0  A  DEK(k bytes)  CSUM(2 bytes)
   *
   * (mpi_get_buffer already removed the leading zero).
   *
   * RND are non-zero randow bytes.
   * A   is the cipher algorithm
   * DEK is the encryption key (session key) with length k
   * CSUM
   */
  if (DBG_CIPHER)
    log_printhex ("DEK frame:", frame, nframe);
  n = 0;

  if (sk->pubkey_algo == PUBKEY_ALGO_ECDH)
    {
      gcry_mpi_t shared_mpi;
      gcry_mpi_t decoded;

      /* At the beginning the frame are the bytes of shared point MPI.  */
      err = gcry_mpi_scan (&shared_mpi, GCRYMPI_FMT_USG, frame, nframe, NULL);
      if (err)
        {
          err = gpg_error (GPG_ERR_WRONG_SECKEY);
          goto leave;
        }

      err = pk_ecdh_decrypt (&decoded, fp, enc->data[1]/*encr data as an MPI*/,
                             shared_mpi, sk->pkey);
      mpi_release (shared_mpi);
      if(err)
        goto leave;

      /* Reuse NFRAME, which size is sufficient to include the session key.  */
      err = gcry_mpi_print (GCRYMPI_FMT_USG, frame, nframe, &nframe, decoded);
      mpi_release (decoded);
      if (err)
        goto leave;

      /* Now the frame are the bytes decrypted but padded session key.  */

      /* Allow double padding for the benefit of DEK size concealment.
         Higher than this is wasteful. */
      if (!nframe || frame[nframe-1] > 8*2 || nframe <= 8
          || frame[nframe-1] > nframe)
        {
          err = gpg_error (GPG_ERR_WRONG_SECKEY);
          goto leave;
        }
      nframe -= frame[nframe-1]; /* Remove padding.  */
      assert (!n); /* (used just below) */
    }
  else
    {
      if (!card)
        {
          if (n + 7 > nframe)
            {
              err = gpg_error (GPG_ERR_WRONG_SECKEY);
              goto leave;
            }
          if (frame[n] == 1 && frame[nframe - 1] == 2)
            {
              log_info (_("old encoding of the DEK is not supported\n"));
              err = gpg_error (GPG_ERR_CIPHER_ALGO);
              goto leave;
            }
          if (frame[n] != 2) /* Something went wrong.  */
            {
              err = gpg_error (GPG_ERR_WRONG_SECKEY);
              goto leave;
            }
          for (n++; n < nframe && frame[n]; n++) /* Skip the random bytes.  */
            ;
          n++; /* Skip the zero byte.  */
        }
    }

  if (n + 4 > nframe)
    {
      err = gpg_error (GPG_ERR_WRONG_SECKEY);
      goto leave;
    }

  dek->keylen = nframe - (n + 1) - 2;
  dek->algo = frame[n++];
  if (dek->algo == CIPHER_ALGO_IDEA)
    write_status (STATUS_RSA_OR_IDEA);
  err = openpgp_cipher_test_algo (dek->algo);
  if (err)
    {
      if (!opt.quiet && gpg_err_code (err) == GPG_ERR_CIPHER_ALGO)
        {
          log_info (_("cipher algorithm %d%s is unknown or disabled\n"),
                    dek->algo,
                    dek->algo == CIPHER_ALGO_IDEA ? " (IDEA)" : "");
          if (dek->algo == CIPHER_ALGO_IDEA)
            idea_cipher_warn (0);
        }
      dek->algo = 0;
      goto leave;
    }
  if (dek->keylen != openpgp_cipher_get_algo_keylen (dek->algo))
    {
      err = gpg_error (GPG_ERR_WRONG_SECKEY);
      goto leave;
    }

  /* Copy the key to DEK and compare the checksum.  */
  csum = frame[nframe - 2] << 8;
  csum |= frame[nframe - 1];
  memcpy (dek->key, frame + n, dek->keylen);
  for (csum2 = 0, n = 0; n < dek->keylen; n++)
    csum2 += dek->key[n];
  if (csum != csum2)
    {
      err = gpg_error (GPG_ERR_WRONG_SECKEY);
      goto leave;
    }
  if (DBG_CIPHER)
    log_printhex ("DEK is:", dek->key, dek->keylen);

  /* Check that the algo is in the preferences and whether it has expired.  */
  {
    PKT_public_key *pk = NULL;
    KBNODE pkb = get_pubkeyblock (keyid);

    if (!pkb)
      {
        err = -1;
        log_error ("oops: public key not found for preference check\n");
      }
    else if (pkb->pkt->pkt.public_key->selfsigversion > 3
             && dek->algo != CIPHER_ALGO_3DES
             && !opt.quiet
             && !is_algo_in_prefs (pkb, PREFTYPE_SYM, dek->algo))
      log_info (_("WARNING: cipher algorithm %s not found in recipient"
                  " preferences\n"), openpgp_cipher_algo_name (dek->algo));
    if (!err)
      {
        KBNODE k;

        for (k = pkb; k; k = k->next)
          {
            if (k->pkt->pkttype == PKT_PUBLIC_KEY
                || k->pkt->pkttype == PKT_PUBLIC_SUBKEY)
              {
                u32 aki[2];
                keyid_from_pk (k->pkt->pkt.public_key, aki);

                if (aki[0] == keyid[0] && aki[1] == keyid[1])
                  {
                    pk = k->pkt->pkt.public_key;
                    break;
                  }
              }
          }
        if (!pk)
          BUG ();
        if (pk->expiredate && pk->expiredate <= make_timestamp ())
          {
            log_info (_("NOTE: secret key %s expired at %s\n"),
                      keystr (keyid), asctimestamp (pk->expiredate));
          }
      }

    if (pk && pk->flags.revoked)
      {
        log_info (_("NOTE: key has been revoked"));
        log_printf ("\n");
        show_revocation_reason (pk, 1);
      }

    release_kbnode (pkb);
    err = 0;
  }

 leave:
  xfree (frame);
  xfree (keygrip);
  return err;
}
示例#12
0
文件: pubkey-enc.c 项目: larryv/gnupg
static gpg_error_t
get_it (ctrl_t ctrl,
        PKT_pubkey_enc *enc, DEK *dek, PKT_public_key *sk, u32 *keyid)
{
  gpg_error_t err;
  byte *frame = NULL;
  unsigned int n;
  size_t nframe;
  u16 csum, csum2;
  int padding;
  gcry_sexp_t s_data;
  char *desc;
  char *keygrip;
  byte fp[MAX_FINGERPRINT_LEN];
  size_t fpn;

  if (DBG_CLOCK)
    log_clock ("decryption start");

  /* Get the keygrip.  */
  err = hexkeygrip_from_pk (sk, &keygrip);
  if (err)
    goto leave;

  /* Convert the data to an S-expression.  */
  if (sk->pubkey_algo == PUBKEY_ALGO_ELGAMAL
      || sk->pubkey_algo == PUBKEY_ALGO_ELGAMAL_E)
    {
      if (!enc->data[0] || !enc->data[1])
        err = gpg_error (GPG_ERR_BAD_MPI);
      else
        err = gcry_sexp_build (&s_data, NULL, "(enc-val(elg(a%m)(b%m)))",
                               enc->data[0], enc->data[1]);
    }
  else if (sk->pubkey_algo == PUBKEY_ALGO_RSA
           || sk->pubkey_algo == PUBKEY_ALGO_RSA_E)
    {
      if (!enc->data[0])
        err = gpg_error (GPG_ERR_BAD_MPI);
      else
        err = gcry_sexp_build (&s_data, NULL, "(enc-val(rsa(a%m)))",
                               enc->data[0]);
    }
  else if (sk->pubkey_algo == PUBKEY_ALGO_ECDH)
    {
      if (!enc->data[0] || !enc->data[1])
        err = gpg_error (GPG_ERR_BAD_MPI);
      else
        err = gcry_sexp_build (&s_data, NULL, "(enc-val(ecdh(s%m)(e%m)))",
                               enc->data[1], enc->data[0]);
    }
  else
    err = gpg_error (GPG_ERR_BUG);

  if (err)
    goto leave;

  if (sk->pubkey_algo == PUBKEY_ALGO_ECDH)
    {
      fingerprint_from_pk (sk, fp, &fpn);
      log_assert (fpn == 20);
    }

  /* Decrypt. */
  desc = gpg_format_keydesc (ctrl, sk, FORMAT_KEYDESC_NORMAL, 1);
  err = agent_pkdecrypt (NULL, keygrip,
                         desc, sk->keyid, sk->main_keyid, sk->pubkey_algo,
                         s_data, &frame, &nframe, &padding);
  xfree (desc);
  gcry_sexp_release (s_data);
  if (err)
    goto leave;

  /* Now get the DEK (data encryption key) from the frame
   *
   * Old versions encode the DEK in this format (msb is left):
   *
   *     0  1  DEK(16 bytes)  CSUM(2 bytes)  0  RND(n bytes) 2
   *
   * Later versions encode the DEK like this:
   *
   *     0  2  RND(n bytes)  0  A  DEK(k bytes)  CSUM(2 bytes)
   *
   * (mpi_get_buffer already removed the leading zero).
   *
   * RND are non-zero randow bytes.
   * A   is the cipher algorithm
   * DEK is the encryption key (session key) with length k
   * CSUM
   */
  if (DBG_CRYPTO)
    log_printhex (frame, nframe, "DEK frame:");
  n = 0;

  if (sk->pubkey_algo == PUBKEY_ALGO_ECDH)
    {
      gcry_mpi_t shared_mpi;
      gcry_mpi_t decoded;

      /* At the beginning the frame are the bytes of shared point MPI.  */
      err = gcry_mpi_scan (&shared_mpi, GCRYMPI_FMT_USG, frame, nframe, NULL);
      if (err)
        {
          err = gpg_error (GPG_ERR_WRONG_SECKEY);
          goto leave;
        }

      err = pk_ecdh_decrypt (&decoded, fp, enc->data[1]/*encr data as an MPI*/,
                             shared_mpi, sk->pkey);
      mpi_release (shared_mpi);
      if(err)
        goto leave;

      xfree (frame);
      err = gcry_mpi_aprint (GCRYMPI_FMT_USG, &frame, &nframe, decoded);
      mpi_release (decoded);
      if (err)
        goto leave;

      /* Now the frame are the bytes decrypted but padded session key.  */

      /* Allow double padding for the benefit of DEK size concealment.
         Higher than this is wasteful. */
      if (!nframe || frame[nframe-1] > 8*2 || nframe <= 8
          || frame[nframe-1] > nframe)
        {
          err = gpg_error (GPG_ERR_WRONG_SECKEY);
          goto leave;
        }
      nframe -= frame[nframe-1]; /* Remove padding.  */
      log_assert (!n); /* (used just below) */
    }
  else
    {
      if (padding)
        {
          if (n + 7 > nframe)
            {
              err = gpg_error (GPG_ERR_WRONG_SECKEY);
              goto leave;
            }
          if (frame[n] == 1 && frame[nframe - 1] == 2)
            {
              log_info (_("old encoding of the DEK is not supported\n"));
              err = gpg_error (GPG_ERR_CIPHER_ALGO);
              goto leave;
            }
          if (frame[n] != 2) /* Something went wrong.  */
            {
              err = gpg_error (GPG_ERR_WRONG_SECKEY);
              goto leave;
            }
          for (n++; n < nframe && frame[n]; n++) /* Skip the random bytes.  */
            ;
          n++; /* Skip the zero byte.  */
        }
    }

  if (n + 4 > nframe)
    {
      err = gpg_error (GPG_ERR_WRONG_SECKEY);
      goto leave;
    }

  dek->keylen = nframe - (n + 1) - 2;
  dek->algo = frame[n++];
  err = openpgp_cipher_test_algo (dek->algo);
  if (err)
    {
      if (!opt.quiet && gpg_err_code (err) == GPG_ERR_CIPHER_ALGO)
        {
          log_info (_("cipher algorithm %d%s is unknown or disabled\n"),
                    dek->algo,
                    dek->algo == CIPHER_ALGO_IDEA ? " (IDEA)" : "");
        }
      dek->algo = 0;
      goto leave;
    }
  if (dek->keylen != openpgp_cipher_get_algo_keylen (dek->algo))
    {
      err = gpg_error (GPG_ERR_WRONG_SECKEY);
      goto leave;
    }

  /* Copy the key to DEK and compare the checksum.  */
  csum = buf16_to_u16 (frame+nframe-2);
  memcpy (dek->key, frame + n, dek->keylen);
  for (csum2 = 0, n = 0; n < dek->keylen; n++)
    csum2 += dek->key[n];
  if (csum != csum2)
    {
      err = gpg_error (GPG_ERR_WRONG_SECKEY);
      goto leave;
    }
  if (DBG_CLOCK)
    log_clock ("decryption ready");
  if (DBG_CRYPTO)
    log_printhex (dek->key, dek->keylen, "DEK is:");

  /* Check that the algo is in the preferences and whether it has
   * expired.  Also print a status line with the key's fingerprint.  */
  {
    PKT_public_key *pk = NULL;
    PKT_public_key *mainpk = NULL;
    KBNODE pkb = get_pubkeyblock (ctrl, keyid);

    if (!pkb)
      {
        err = -1;
        log_error ("oops: public key not found for preference check\n");
      }
    else if (pkb->pkt->pkt.public_key->selfsigversion > 3
             && dek->algo != CIPHER_ALGO_3DES
             && !opt.quiet
             && !is_algo_in_prefs (pkb, PREFTYPE_SYM, dek->algo))
      log_info (_("WARNING: cipher algorithm %s not found in recipient"
                  " preferences\n"), openpgp_cipher_algo_name (dek->algo));

    if (!err)
      {
        kbnode_t k;
        int first = 1;

        for (k = pkb; k; k = k->next)
          {
            if (k->pkt->pkttype == PKT_PUBLIC_KEY
                || k->pkt->pkttype == PKT_PUBLIC_SUBKEY)
              {
                u32 aki[2];

                if (first)
                  {
                    first = 0;
                    mainpk = k->pkt->pkt.public_key;
                  }

                keyid_from_pk (k->pkt->pkt.public_key, aki);
                if (aki[0] == keyid[0] && aki[1] == keyid[1])
                  {
                    pk = k->pkt->pkt.public_key;
                    break;
                  }
              }
          }
        if (!pk)
          BUG ();
        if (pk->expiredate && pk->expiredate <= make_timestamp ())
          {
            log_info (_("Note: secret key %s expired at %s\n"),
                      keystr (keyid), asctimestamp (pk->expiredate));
          }
      }

    if (pk && pk->flags.revoked)
      {
        log_info (_("Note: key has been revoked"));
        log_printf ("\n");
        show_revocation_reason (ctrl, pk, 1);
      }

    if (is_status_enabled () && pk && mainpk)
      {
        char pkhex[MAX_FINGERPRINT_LEN*2+1];
        char mainpkhex[MAX_FINGERPRINT_LEN*2+1];

        hexfingerprint (pk, pkhex, sizeof pkhex);
        hexfingerprint (mainpk, mainpkhex, sizeof mainpkhex);

        /* Note that we do not want to create a trustdb just for
         * getting the ownertrust: If there is no trustdb there can't
         * be ulitmately trusted key anyway and thus the ownertrust
         * value is irrelevant.  */
        write_status_printf (STATUS_DECRYPTION_KEY, "%s %s %c",
                             pkhex, mainpkhex,
                             get_ownertrust_info (ctrl, mainpk, 1));

      }

    release_kbnode (pkb);
    err = 0;
  }

 leave:
  xfree (frame);
  xfree (keygrip);
  return err;
}
示例#13
0
文件: certcheck.c 项目: 0ndorio/gnupg
int
gpgsm_check_cms_signature (ksba_cert_t cert, ksba_const_sexp_t sigval,
                           gcry_md_hd_t md, int mdalgo, int *r_pkalgo)
{
  int rc;
  ksba_sexp_t p;
  gcry_mpi_t frame;
  gcry_sexp_t s_sig, s_hash, s_pkey;
  size_t n;
  int pkalgo;

  if (r_pkalgo)
    *r_pkalgo = 0;

  n = gcry_sexp_canon_len (sigval, 0, NULL, NULL);
  if (!n)
    {
      log_error ("libksba did not return a proper S-Exp\n");
      return gpg_error (GPG_ERR_BUG);
    }
  rc = gcry_sexp_sscan (&s_sig, NULL, (char*)sigval, n);
  if (rc)
    {
      log_error ("gcry_sexp_scan failed: %s\n", gpg_strerror (rc));
      return rc;
    }

  p = ksba_cert_get_public_key (cert);
  n = gcry_sexp_canon_len (p, 0, NULL, NULL);
  if (!n)
    {
      log_error ("libksba did not return a proper S-Exp\n");
      ksba_free (p);
      gcry_sexp_release (s_sig);
      return gpg_error (GPG_ERR_BUG);
    }
  if (DBG_CRYPTO)
    log_printhex ("public key: ", p, n);

  rc = gcry_sexp_sscan ( &s_pkey, NULL, (char*)p, n);
  ksba_free (p);
  if (rc)
    {
      log_error ("gcry_sexp_scan failed: %s\n", gpg_strerror (rc));
      gcry_sexp_release (s_sig);
      return rc;
    }

  pkalgo = pk_algo_from_sexp (s_pkey);
  if (r_pkalgo)
    *r_pkalgo = pkalgo;
  rc = do_encode_md (md, mdalgo, pkalgo,
                     gcry_pk_get_nbits (s_pkey), s_pkey, &frame);
  if (rc)
    {
      gcry_sexp_release (s_sig);
      gcry_sexp_release (s_pkey);
      return rc;
    }
  /* put hash into the S-Exp s_hash */
  if ( gcry_sexp_build (&s_hash, NULL, "%m", frame) )
    BUG ();
  gcry_mpi_release (frame);

  rc = gcry_pk_verify (s_sig, s_hash, s_pkey);
  if (DBG_X509)
      log_debug ("gcry_pk_verify: %s\n", gpg_strerror (rc));
  gcry_sexp_release (s_sig);
  gcry_sexp_release (s_hash);
  gcry_sexp_release (s_pkey);
  return rc;
}
示例#14
0
/* Perform a verify operation.  To verify detached signatures, data_fd
   must be different than -1.  With OUT_FP given and a non-detached
   signature, the signed material is written to that stream. */
int
gpgsm_verify (ctrl_t ctrl, int in_fd, int data_fd, FILE *out_fp)
{
  int i, rc;
  Base64Context b64reader = NULL;
  Base64Context b64writer = NULL;
  ksba_reader_t reader;
  ksba_writer_t writer = NULL;
  ksba_cms_t cms = NULL;
  ksba_stop_reason_t stopreason;
  ksba_cert_t cert;
  KEYDB_HANDLE kh;
  gcry_md_hd_t data_md = NULL;
  int signer;
  const char *algoid;
  int algo;
  int is_detached;
  FILE *fp = NULL;
  char *p;

  audit_set_type (ctrl->audit, AUDIT_TYPE_VERIFY);

  kh = keydb_new (0);
  if (!kh)
    {
      log_error (_("failed to allocated keyDB handle\n"));
      rc = gpg_error (GPG_ERR_GENERAL);
      goto leave;
    }


  fp = fdopen ( dup (in_fd), "rb");
  if (!fp)
    {
      rc = gpg_error (gpg_err_code_from_errno (errno));
      log_error ("fdopen() failed: %s\n", strerror (errno));
      goto leave;
    }

  rc = gpgsm_create_reader (&b64reader, ctrl, fp, 0, &reader);
  if (rc)
    {
      log_error ("can't create reader: %s\n", gpg_strerror (rc));
      goto leave;
    }

  if (out_fp)
    {
      rc = gpgsm_create_writer (&b64writer, ctrl, out_fp, NULL, &writer);
      if (rc)
        {
          log_error ("can't create writer: %s\n", gpg_strerror (rc));
          goto leave;
        }
    }

  rc = ksba_cms_new (&cms);
  if (rc)
    goto leave;

  rc = ksba_cms_set_reader_writer (cms, reader, writer);
  if (rc)
    {
      log_error ("ksba_cms_set_reader_writer failed: %s\n",
                 gpg_strerror (rc));
      goto leave;
    }

  rc = gcry_md_open (&data_md, 0, 0);
  if (rc)
    {
      log_error ("md_open failed: %s\n", gpg_strerror (rc));
      goto leave;
    }
  if (DBG_HASHING)
    gcry_md_start_debug (data_md, "vrfy.data");

  audit_log (ctrl->audit, AUDIT_SETUP_READY);

  is_detached = 0;
  do 
    {
      rc = ksba_cms_parse (cms, &stopreason);
      if (rc)
        {
          log_error ("ksba_cms_parse failed: %s\n", gpg_strerror (rc));
          goto leave;
        }

      if (stopreason == KSBA_SR_NEED_HASH)
        {
          is_detached = 1;
          audit_log (ctrl->audit, AUDIT_DETACHED_SIGNATURE);
          if (opt.verbose)
            log_info ("detached signature\n");
        }

      if (stopreason == KSBA_SR_NEED_HASH
          || stopreason == KSBA_SR_BEGIN_DATA)
        { 
          audit_log (ctrl->audit, AUDIT_GOT_DATA);

          /* We are now able to enable the hash algorithms */
          for (i=0; (algoid=ksba_cms_get_digest_algo_list (cms, i)); i++)
            {
              algo = gcry_md_map_name (algoid);
              if (!algo)
                {
                  log_error ("unknown hash algorithm `%s'\n",
                             algoid? algoid:"?");
                  if (algoid
                      && (  !strcmp (algoid, "1.2.840.113549.1.1.2")
                          ||!strcmp (algoid, "1.2.840.113549.2.2")))
                    log_info (_("(this is the MD2 algorithm)\n"));
                  audit_log_s (ctrl->audit, AUDIT_BAD_DATA_HASH_ALGO, algoid);
                }
              else
                {
                  if (DBG_X509)
                    log_debug ("enabling hash algorithm %d (%s)\n",
                               algo, algoid? algoid:"");
                  gcry_md_enable (data_md, algo);
                  audit_log_i (ctrl->audit, AUDIT_DATA_HASH_ALGO, algo);
                }
            }
          if (opt.extra_digest_algo)
            {
              if (DBG_X509)
                log_debug ("enabling extra hash algorithm %d\n", 
                           opt.extra_digest_algo);
              gcry_md_enable (data_md, opt.extra_digest_algo);
              audit_log_i (ctrl->audit, AUDIT_DATA_HASH_ALGO,
                           opt.extra_digest_algo);
            }
          if (is_detached)
            {
              if (data_fd == -1)
                {
                  log_info ("detached signature w/o data "
                            "- assuming certs-only\n");
                  audit_log (ctrl->audit, AUDIT_CERT_ONLY_SIG);
                }
              else
                audit_log_ok (ctrl->audit, AUDIT_DATA_HASHING,
                              hash_data (data_fd, data_md));
            }
          else
            {
              ksba_cms_set_hash_function (cms, HASH_FNC, data_md);
            }
        }
      else if (stopreason == KSBA_SR_END_DATA)
        { /* The data bas been hashed */
          audit_log_ok (ctrl->audit, AUDIT_DATA_HASHING, 0);
        }
    }
  while (stopreason != KSBA_SR_READY);   

  if (b64writer)
    {
      rc = gpgsm_finish_writer (b64writer);
      if (rc) 
        {
          log_error ("write failed: %s\n", gpg_strerror (rc));
          audit_log_ok (ctrl->audit, AUDIT_WRITE_ERROR, rc);
          goto leave;
        }
    }

  if (data_fd != -1 && !is_detached)
    {
      log_error ("data given for a non-detached signature\n");
      rc = gpg_error (GPG_ERR_CONFLICT);
      audit_log (ctrl->audit, AUDIT_USAGE_ERROR);
      goto leave;
    }

  for (i=0; (cert=ksba_cms_get_cert (cms, i)); i++)
    {
      /* Fixme: it might be better to check the validity of the
         certificate first before entering it into the DB.  This way
         we would avoid cluttering the DB with invalid
         certificates. */
      audit_log_cert (ctrl->audit, AUDIT_SAVE_CERT, cert, 
                      keydb_store_cert (cert, 0, NULL));
      ksba_cert_release (cert);
    }

  cert = NULL;
  for (signer=0; ; signer++)
    {
      char *issuer = NULL;
      ksba_sexp_t sigval = NULL;
      ksba_isotime_t sigtime, keyexptime;
      ksba_sexp_t serial;
      char *msgdigest = NULL;
      size_t msgdigestlen;
      char *ctattr;
      int sigval_hash_algo;
      int info_pkalgo;
      unsigned int verifyflags;

      rc = ksba_cms_get_issuer_serial (cms, signer, &issuer, &serial);
      if (!signer && gpg_err_code (rc) == GPG_ERR_NO_DATA
          && data_fd == -1 && is_detached)
        {
          log_info ("certs-only message accepted\n");
          rc = 0;
          break;
        }
      if (rc)
        {
          if (signer && rc == -1)
            rc = 0;
          break;
        }

      gpgsm_status (ctrl, STATUS_NEWSIG, NULL);
      audit_log_i (ctrl->audit, AUDIT_NEW_SIG, signer);

      if (DBG_X509)
        {
          log_debug ("signer %d - issuer: `%s'\n",
                     signer, issuer? issuer:"[NONE]");
          log_debug ("signer %d - serial: ", signer);
          gpgsm_dump_serial (serial);
          log_printf ("\n");
        }
      if (ctrl->audit)
        {
          char *tmpstr = gpgsm_format_sn_issuer (serial, issuer);
          audit_log_s (ctrl->audit, AUDIT_SIG_NAME, tmpstr);
          xfree (tmpstr);
        }

      rc = ksba_cms_get_signing_time (cms, signer, sigtime);
      if (gpg_err_code (rc) == GPG_ERR_NO_DATA)
        *sigtime = 0;
      else if (rc)
        {
          log_error ("error getting signing time: %s\n", gpg_strerror (rc));
          *sigtime = 0; /* (we can't encode an error in the time string.) */
        }

      rc = ksba_cms_get_message_digest (cms, signer,
                                        &msgdigest, &msgdigestlen);
      if (!rc)
        {
          size_t is_enabled;

          algoid = ksba_cms_get_digest_algo (cms, signer);
          algo = gcry_md_map_name (algoid);
          if (DBG_X509)
            log_debug ("signer %d - digest algo: %d\n", signer, algo);
          is_enabled = sizeof algo;
          if ( gcry_md_info (data_md, GCRYCTL_IS_ALGO_ENABLED,
                             &algo, &is_enabled)
               || !is_enabled)
            {
              log_error ("digest algo %d (%s) has not been enabled\n", 
                         algo, algoid?algoid:"");
              audit_log_s (ctrl->audit, AUDIT_SIG_STATUS, "unsupported");
              goto next_signer;
            }
        }
      else if (gpg_err_code (rc) == GPG_ERR_NO_DATA)
        {
          assert (!msgdigest);
          rc = 0;
          algoid = NULL;
          algo = 0; 
        }
      else /* real error */
        {
          audit_log_s (ctrl->audit, AUDIT_SIG_STATUS, "error");
          break;
        }

      rc = ksba_cms_get_sigattr_oids (cms, signer,
                                      "1.2.840.113549.1.9.3", &ctattr);
      if (!rc) 
        {
          const char *s;

          if (DBG_X509)
            log_debug ("signer %d - content-type attribute: %s",
                       signer, ctattr);

          s = ksba_cms_get_content_oid (cms, 1);
          if (!s || strcmp (ctattr, s))
            {
              log_error ("content-type attribute does not match "
                         "actual content-type\n");
              ksba_free (ctattr);
              ctattr = NULL;
              audit_log_s (ctrl->audit, AUDIT_SIG_STATUS, "bad");
              goto next_signer;
            }
          ksba_free (ctattr);
          ctattr = NULL;
        }
      else if (rc != -1)
        {
          log_error ("error getting content-type attribute: %s\n",
                     gpg_strerror (rc));
          audit_log_s (ctrl->audit, AUDIT_SIG_STATUS, "bad");
          goto next_signer;
        }
      rc = 0;


      sigval = ksba_cms_get_sig_val (cms, signer);
      if (!sigval)
        {
          log_error ("no signature value available\n");
          audit_log_s (ctrl->audit, AUDIT_SIG_STATUS, "bad");
          goto next_signer;
        }
      sigval_hash_algo = hash_algo_from_sigval (sigval);
      if (DBG_X509)
        {
          log_debug ("signer %d - signature available (sigval hash=%d)",
                     signer, sigval_hash_algo);
/*           log_printhex ("sigval    ", sigval, */
/*                         gcry_sexp_canon_len (sigval, 0, NULL, NULL)); */
        }
      if (!sigval_hash_algo)
        sigval_hash_algo = algo; /* Fallback used e.g. with old libksba. */

      /* Find the certificate of the signer */
      keydb_search_reset (kh);
      rc = keydb_search_issuer_sn (kh, issuer, serial);
      if (rc)
        {
          if (rc == -1)
            {
              log_error ("certificate not found\n");
              rc = gpg_error (GPG_ERR_NO_PUBKEY);
            }
          else
            log_error ("failed to find the certificate: %s\n",
                       gpg_strerror(rc));
          {
            char numbuf[50];
            sprintf (numbuf, "%d", rc);

            gpgsm_status2 (ctrl, STATUS_ERROR, "verify.findkey",
                           numbuf, NULL);
          }
          audit_log_s (ctrl->audit, AUDIT_SIG_STATUS, "no-cert");
          goto next_signer;
        }

      rc = keydb_get_cert (kh, &cert);
      if (rc)
        {
          log_error ("failed to get cert: %s\n", gpg_strerror (rc));
          audit_log_s (ctrl->audit, AUDIT_SIG_STATUS, "error");
          goto next_signer;
        }

      log_info (_("Signature made "));
      if (*sigtime)
        dump_isotime (sigtime);
      else
        log_printf (_("[date not given]"));
      log_printf (_(" using certificate ID 0x%08lX\n"),
                  gpgsm_get_short_fingerprint (cert, NULL));

      audit_log_i (ctrl->audit, AUDIT_DATA_HASH_ALGO, algo);

      if (msgdigest)
        { /* Signed attributes are available. */
          gcry_md_hd_t md;
          unsigned char *s;

          /* Check that the message digest in the signed attributes
             matches the one we calculated on the data.  */
          s = gcry_md_read (data_md, algo);
          if ( !s || !msgdigestlen
               || gcry_md_get_algo_dlen (algo) != msgdigestlen
               || !s || memcmp (s, msgdigest, msgdigestlen) )
            {
              char *fpr;

              log_error (_("invalid signature: message digest attribute "
                           "does not match computed one\n"));
              if (DBG_X509)
                {
                  if (msgdigest)
                    log_printhex ("message:  ", msgdigest, msgdigestlen);
                  if (s)
                    log_printhex ("computed: ",
                                  s, gcry_md_get_algo_dlen (algo));
                }
              fpr = gpgsm_fpr_and_name_for_status (cert);
              gpgsm_status (ctrl, STATUS_BADSIG, fpr);
              xfree (fpr);
              audit_log_s (ctrl->audit, AUDIT_SIG_STATUS, "bad");
              goto next_signer; 
            }
            
          audit_log_i (ctrl->audit, AUDIT_ATTR_HASH_ALGO, sigval_hash_algo);
          rc = gcry_md_open (&md, sigval_hash_algo, 0);
          if (rc)
            {
              log_error ("md_open failed: %s\n", gpg_strerror (rc));
              audit_log_s (ctrl->audit, AUDIT_SIG_STATUS, "error");
              goto next_signer;
            }
          if (DBG_HASHING)
            gcry_md_start_debug (md, "vrfy.attr");

          ksba_cms_set_hash_function (cms, HASH_FNC, md);
          rc = ksba_cms_hash_signed_attrs (cms, signer);
          if (rc)
            {
              log_error ("hashing signed attrs failed: %s\n",
                         gpg_strerror (rc));
              gcry_md_close (md);
              audit_log_s (ctrl->audit, AUDIT_SIG_STATUS, "error");
              goto next_signer;
            }
          rc = gpgsm_check_cms_signature (cert, sigval, md, 
                                          sigval_hash_algo, &info_pkalgo);
          gcry_md_close (md);
        }
      else
        {
          rc = gpgsm_check_cms_signature (cert, sigval, data_md, 
                                          algo, &info_pkalgo);
        }

      if (rc)
        {
          char *fpr;

          log_error ("invalid signature: %s\n", gpg_strerror (rc));
          fpr = gpgsm_fpr_and_name_for_status (cert);
          gpgsm_status (ctrl, STATUS_BADSIG, fpr);
          xfree (fpr);
          audit_log_s (ctrl->audit, AUDIT_SIG_STATUS, "bad");
          goto next_signer;
        }
      rc = gpgsm_cert_use_verify_p (cert); /*(this displays an info message)*/
      if (rc)
        {
          gpgsm_status_with_err_code (ctrl, STATUS_ERROR, "verify.keyusage",
                                      gpg_err_code (rc));
          rc = 0;
        }

      if (DBG_X509)
        log_debug ("signature okay - checking certs\n");
      audit_log (ctrl->audit, AUDIT_VALIDATE_CHAIN);
      rc = gpgsm_validate_chain (ctrl, cert,
                                 *sigtime? sigtime : "19700101T000000",
                                 keyexptime, 0, 
                                 NULL, 0, &verifyflags);
      {
        char *fpr, *buf, *tstr;

        fpr = gpgsm_fpr_and_name_for_status (cert);
        if (gpg_err_code (rc) == GPG_ERR_CERT_EXPIRED)
          {
            gpgsm_status (ctrl, STATUS_EXPKEYSIG, fpr);
            rc = 0;
          }
        else
          gpgsm_status (ctrl, STATUS_GOODSIG, fpr);
        
        xfree (fpr);

        fpr = gpgsm_get_fingerprint_hexstring (cert, GCRY_MD_SHA1);
        tstr = strtimestamp_r (sigtime);
        buf = xasprintf ("%s %s %s %s 0 0 %d %d 00", fpr, tstr,
                         *sigtime? sigtime : "0",
                         *keyexptime? keyexptime : "0",
                         info_pkalgo, algo);
        xfree (tstr);
        xfree (fpr);
        gpgsm_status (ctrl, STATUS_VALIDSIG, buf);
        xfree (buf);
      }

      audit_log_ok (ctrl->audit, AUDIT_CHAIN_STATUS, rc);
      if (rc) /* of validate_chain */
        {
          log_error ("invalid certification chain: %s\n", gpg_strerror (rc));
          if (gpg_err_code (rc) == GPG_ERR_BAD_CERT_CHAIN
              || gpg_err_code (rc) == GPG_ERR_BAD_CERT
              || gpg_err_code (rc) == GPG_ERR_BAD_CA_CERT
              || gpg_err_code (rc) == GPG_ERR_CERT_REVOKED)
            gpgsm_status_with_err_code (ctrl, STATUS_TRUST_NEVER, NULL,
                                        gpg_err_code (rc));
          else
            gpgsm_status_with_err_code (ctrl, STATUS_TRUST_UNDEFINED, NULL, 
                                        gpg_err_code (rc));
          audit_log_s (ctrl->audit, AUDIT_SIG_STATUS, "bad");
          goto next_signer;
        }

      audit_log_s (ctrl->audit, AUDIT_SIG_STATUS, "good");

      for (i=0; (p = ksba_cert_get_subject (cert, i)); i++)
        {
          log_info (!i? _("Good signature from")
                      : _("                aka"));
          log_printf (" \"");
          gpgsm_print_name (log_get_stream (), p);
          log_printf ("\"\n");
          ksba_free (p);
        }

      /* Print a note if this is a qualified signature.  */
      {
        size_t qualbuflen;
        char qualbuffer[1];
        
        rc = ksba_cert_get_user_data (cert, "is_qualified", &qualbuffer,
                                      sizeof (qualbuffer), &qualbuflen);
        if (!rc && qualbuflen)
          {
            if (*qualbuffer)
              {
                log_info (_("This is a qualified signature\n"));
                if (!opt.qualsig_approval)
                  log_info 
                    (_("Note, that this software is not officially approved "
                       "to create or verify such signatures.\n"));
              }
          }    
        else if (gpg_err_code (rc) != GPG_ERR_NOT_FOUND)
          log_error ("get_user_data(is_qualified) failed: %s\n",
                     gpg_strerror (rc)); 
      }

      gpgsm_status (ctrl, STATUS_TRUST_FULLY, 
                    (verifyflags & VALIDATE_FLAG_CHAIN_MODEL)?
                    "0 chain": "0 shell");
          

    next_signer:
      rc = 0;
      xfree (issuer);
      xfree (serial);
      xfree (sigval);
      xfree (msgdigest);
      ksba_cert_release (cert);
      cert = NULL;
    }
  rc = 0;

 leave:
  ksba_cms_release (cms);
  gpgsm_destroy_reader (b64reader);
  gpgsm_destroy_writer (b64writer);
  keydb_release (kh); 
  gcry_md_close (data_md);
  if (fp)
    fclose (fp);

  if (rc)
    {
      char numbuf[50];
      sprintf (numbuf, "%d", rc );
      gpgsm_status2 (ctrl, STATUS_ERROR, "verify.leave",
                     numbuf, NULL);
    }

  return rc;
}
示例#15
0
/* Map the host name NAME to the actual to be used host name.  This
   allows us to manage round robin DNS names.  We use our own strategy
   to choose one of the hosts.  For example we skip those hosts which
   failed for some time and we stick to one host for a time
   independent of DNS retry times.  */
static char *
map_host (const char *name)
{
  hostinfo_t hi;
  int idx;

  /* No hostname means localhost.  */
  if (!name || !*name)
    return xtrystrdup ("localhost");

  /* See whether the host is in our table.  */
  idx = find_hostinfo (name);
  if (idx == -1)
    {
      /* We never saw this host.  Allocate a new entry.  */
      struct addrinfo hints, *aibuf, *ai;
      int *reftbl;
      size_t reftblsize;
      int refidx;

      reftblsize = 100;
      reftbl = xtrymalloc (reftblsize * sizeof *reftbl);
      if (!reftbl)
        return NULL;
      refidx = 0;

      idx = create_new_hostinfo (name);
      if (idx == -1)
        {
          xfree (reftbl);
          return NULL;
        }
      hi = hosttable[idx];

      /* Find all A records for this entry and put them into the pool
         list - if any.  */
      memset (&hints, 0, sizeof (hints));
      hints.ai_socktype = SOCK_STREAM;
      if (!getaddrinfo (name, NULL, &hints, &aibuf))
        {
          for (ai = aibuf; ai; ai = ai->ai_next)
            {
              char tmphost[NI_MAXHOST];
              int tmpidx;
              int ec;
              int i;

              if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6)
                continue;

              log_printhex ("getaddrinfo returned", ai->ai_addr,ai->ai_addrlen);
              if ((ec=getnameinfo (ai->ai_addr, ai->ai_addrlen,
                                   tmphost, sizeof tmphost,
                                   NULL, 0, NI_NAMEREQD)))
                log_info ("getnameinfo failed while checking '%s': %s\n",
                          name, gai_strerror (ec));
              else if (refidx+1 >= reftblsize)
                {
                  log_error ("getnameinfo returned for '%s': '%s'"
                            " [index table full - ignored]\n", name, tmphost);
                }
              else
                {

                  if ((tmpidx = find_hostinfo (tmphost)) != -1)
                    {
                      log_info ("getnameinfo returned for '%s': '%s'"
                                " [already known]\n", name, tmphost);
                      if (ai->ai_family == AF_INET)
                        hosttable[tmpidx]->v4 = 1;
                      if (ai->ai_family == AF_INET6)
                        hosttable[tmpidx]->v6 = 1;

                      for (i=0; i < refidx; i++)
                        if (reftbl[i] == tmpidx)
                      break;
                      if (!(i < refidx) && tmpidx != idx)
                        reftbl[refidx++] = tmpidx;
                    }
                  else
                    {
                      log_info ("getnameinfo returned for '%s': '%s'\n",
                                name, tmphost);
                      /* Create a new entry.  */
                      tmpidx = create_new_hostinfo (tmphost);
                      if (tmpidx == -1)
                        log_error ("map_host for '%s' problem: %s - '%s'"
                                   " [ignored]\n",
                                   name, strerror (errno), tmphost);
                      else
                        {
                          if (ai->ai_family == AF_INET)
                            hosttable[tmpidx]->v4 = 1;
                          if (ai->ai_family == AF_INET6)
                            hosttable[tmpidx]->v6 = 1;

                          for (i=0; i < refidx; i++)
                            if (reftbl[i] == tmpidx)
                              break;
                          if (!(i < refidx) && tmpidx != idx)
                            reftbl[refidx++] = tmpidx;
                        }
                    }
                }
            }
        }
      reftbl[refidx] = -1;
      if (refidx)
        {
          assert (!hi->pool);
          hi->pool = xtryrealloc (reftbl, (refidx+1) * sizeof *reftbl);
          if (!hi->pool)
            {
              log_error ("shrinking index table in map_host failed: %s\n",
                         strerror (errno));
              xfree (reftbl);
            }
          qsort (reftbl, refidx, sizeof *reftbl, sort_hostpool);
        }
      else
        xfree (reftbl);
    }

  hi = hosttable[idx];
  if (hi->pool)
    {
      /* If the currently selected host is now marked dead, force a
         re-selection .  */
      if (hi->poolidx >= 0 && hi->poolidx < hosttable_size
          && hosttable[hi->poolidx] && hosttable[hi->poolidx]->dead)
        hi->poolidx = -1;

      /* Select a host if needed.  */
      if (hi->poolidx == -1)
        {
          hi->poolidx = select_random_host (hi->pool);
          if (hi->poolidx == -1)
            {
              log_error ("no alive host found in pool '%s'\n", name);
              return NULL;
            }
        }

      assert (hi->poolidx >= 0 && hi->poolidx < hosttable_size);
      hi = hosttable[hi->poolidx];
      assert (hi);
    }

  if (hi->dead)
    {
      log_error ("host '%s' marked as dead\n", hi->name);
      return NULL;
    }

  return xtrystrdup (hi->name);
}