Beispiel #1
0
static void
do_test (int argc, char *argv[])
{
  char *fname;
  int rc;
  KEYDB_HANDLE hd1;
  KEYDB_SEARCH_DESC desc1;
  KBNODE kb1;

  (void) argc;
  (void) argv;

  /* t-keydb-get-keyblock.gpg contains two keys: a modern key followed
     by a legacy key.  If we get the keyblock for the modern key, we
     shouldn't get

     - */
  fname = prepend_srcdir ("t-keydb-get-keyblock.gpg");
  rc = keydb_add_resource (fname, 0);
  test_free (fname);
  if (rc)
    ABORT ("Failed to open keyring.");

  hd1 = keydb_new ();
  if (!hd1)
    ABORT ("");

  rc = classify_user_id ("8061 5870 F5BA D690 3336  86D0 F2AD 85AC 1E42 B367",
			 &desc1, 0);
  if (rc)
    ABORT ("Failed to convert fingerprint for 1E42B367");

  rc = keydb_search (hd1, &desc1, 1, NULL);
  if (rc)
    ABORT ("Failed to lookup key associated with 1E42B367");

  rc = keydb_get_keyblock (hd1, &kb1);
  TEST_P ("", ! rc);
}
Beispiel #2
0
/* Reset all the certificate flags we have stored with the certificates
   for performance reasons. */
void
keydb_clear_some_cert_flags (ctrl_t ctrl, strlist_t names)
{
  gpg_error_t err;
  KEYDB_HANDLE hd = NULL;
  KEYDB_SEARCH_DESC *desc = NULL;
  int ndesc;
  strlist_t sl;
  int rc=0;
  unsigned int old_value, value;

  (void)ctrl;

  hd = keydb_new (0);
  if (!hd)
    {
      log_error ("keydb_new failed\n");
      goto leave;
    }

  if (!names)
    ndesc = 1;
  else
    {
      for (sl=names, ndesc=0; sl; sl = sl->next, ndesc++)
        ;
    }

  desc = xtrycalloc (ndesc, sizeof *desc);
  if (!ndesc)
    {
      log_error ("allocating memory failed: %s\n",
                 gpg_strerror (out_of_core ()));
      goto leave;
    }

  if (!names)
    desc[0].mode = KEYDB_SEARCH_MODE_FIRST;
  else
    {
      for (ndesc=0, sl=names; sl; sl = sl->next)
        {
          rc = classify_user_id (sl->d, desc+ndesc, 0);
          if (rc)
            {
              log_error ("key '%s' not found: %s\n",
                         sl->d, gpg_strerror (rc));
              rc = 0;
            }
          else
            ndesc++;
        }
    }

  err = keydb_lock (hd);
  if (err)
    {
      log_error (_("error locking keybox: %s\n"), gpg_strerror (err));
      goto leave;
    }

  while (!(rc = keydb_search (hd, desc, ndesc)))
    {
      if (!names)
        desc[0].mode = KEYDB_SEARCH_MODE_NEXT;

      err = keydb_get_flags (hd, KEYBOX_FLAG_VALIDITY, 0, &old_value);
      if (err)
        {
          log_error (_("error getting stored flags: %s\n"),
                     gpg_strerror (err));
          goto leave;
        }

      value = (old_value & ~VALIDITY_REVOKED);
      if (value != old_value)
        {
          err = keydb_set_flags (hd, KEYBOX_FLAG_VALIDITY, 0, value);
          if (err)
            {
              log_error (_("error storing flags: %s\n"), gpg_strerror (err));
              goto leave;
            }
        }
    }
  if (rc && rc != -1)
    log_error ("keydb_search failed: %s\n", gpg_strerror (rc));

 leave:
  xfree (desc);
  keydb_release (hd);
}
Beispiel #3
0
/* Perform an encrypt operation.  

   Encrypt the data received on DATA-FD and write it to OUT_FP.  The
   recipients are take from the certificate given in recplist; if this
   is NULL it will be encrypted for a default recipient */
int
gpgsm_encrypt (ctrl_t ctrl, certlist_t recplist, int data_fd, FILE *out_fp)
{
  int rc = 0;
  Base64Context b64writer = NULL;
  gpg_error_t err;
  ksba_writer_t writer;
  ksba_reader_t reader = NULL;
  ksba_cms_t cms = NULL;
  ksba_stop_reason_t stopreason;
  KEYDB_HANDLE kh = NULL;
  struct encrypt_cb_parm_s encparm;
  DEK dek = NULL;
  int recpno;
  FILE *data_fp = NULL;
  certlist_t cl;
  int count;

  memset (&encparm, 0, sizeof encparm);

  audit_set_type (ctrl->audit, AUDIT_TYPE_ENCRYPT);

  /* Check that the certificate list is not empty and that at least
     one certificate is not flagged as encrypt_to; i.e. is a real
     recipient. */
  for (cl = recplist; cl; cl = cl->next)
    if (!cl->is_encrypt_to)
      break;
  if (!cl)
    {
      log_error(_("no valid recipients given\n"));
      gpgsm_status (ctrl, STATUS_NO_RECP, "0");
      audit_log_i (ctrl->audit, AUDIT_GOT_RECIPIENTS, 0);
      rc = gpg_error (GPG_ERR_NO_PUBKEY);
      goto leave;
    }

  for (count = 0, cl = recplist; cl; cl = cl->next)
    count++;
  audit_log_i (ctrl->audit, AUDIT_GOT_RECIPIENTS, count);

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

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

  err = ksba_reader_new (&reader);
  if (err)
      rc = err;
  if (!rc)
    rc = ksba_reader_set_cb (reader, encrypt_cb, &encparm);
  if (rc)
      goto leave;

  encparm.fp = data_fp;

  ctrl->pem_name = "ENCRYPTED MESSAGE";
  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;
    }

  err = ksba_cms_new (&cms);
  if (err)
    {
      rc = err;
      goto leave;
    }

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

  audit_log (ctrl->audit, AUDIT_GOT_DATA);

  /* We are going to create enveloped data with uninterpreted data as
     inner content */
  err = ksba_cms_set_content_type (cms, 0, KSBA_CT_ENVELOPED_DATA);
  if (!err)
    err = ksba_cms_set_content_type (cms, 1, KSBA_CT_DATA);
  if (err)
    {
      log_debug ("ksba_cms_set_content_type failed: %s\n",
                 gpg_strerror (err));
      rc = err;
      goto leave;
    }

  /* Create a session key */
  dek = xtrycalloc_secure (1, sizeof *dek); 
  if (!dek)
    rc = out_of_core ();
  else
  {
    dek->algoid = opt.def_cipher_algoid;
    rc = init_dek (dek);
  }
  if (rc)
    {
      log_error ("failed to create the session key: %s\n",
                 gpg_strerror (rc));
      goto leave;
    }

  err = ksba_cms_set_content_enc_algo (cms, dek->algoid, dek->iv, dek->ivlen);
  if (err)
    {
      log_error ("ksba_cms_set_content_enc_algo failed: %s\n",
                 gpg_strerror (err));
      rc = err;
      goto leave;
    }

  encparm.dek = dek;
  /* Use a ~8k (AES) or ~4k (3DES) buffer */
  encparm.bufsize = 500 * dek->ivlen;
  encparm.buffer = xtrymalloc (encparm.bufsize);
  if (!encparm.buffer)
    {
      rc = out_of_core ();
      goto leave;
    }
  
  audit_log_s (ctrl->audit, AUDIT_SESSION_KEY, dek->algoid);

  /* Gather certificates of recipients, encrypt the session key for
     each and store them in the CMS object */
  for (recpno = 0, cl = recplist; cl; recpno++, cl = cl->next)
    {
      unsigned char *encval;
      
      rc = encrypt_dek (dek, cl->cert, &encval);
      if (rc)
        {
          audit_log_cert (ctrl->audit, AUDIT_ENCRYPTED_TO, cl->cert, rc);
          log_error ("encryption failed for recipient no. %d: %s\n",
                     recpno, gpg_strerror (rc));
          goto leave;
        }
      
      err = ksba_cms_add_recipient (cms, cl->cert);
      if (err)
        {
          audit_log_cert (ctrl->audit, AUDIT_ENCRYPTED_TO, cl->cert, err);
          log_error ("ksba_cms_add_recipient failed: %s\n",
                     gpg_strerror (err));
          rc = err;
          xfree (encval);
          goto leave;
        }
      
      err = ksba_cms_set_enc_val (cms, recpno, encval);
      xfree (encval);
      audit_log_cert (ctrl->audit, AUDIT_ENCRYPTED_TO, cl->cert, err);
      if (err)
        {
          log_error ("ksba_cms_set_enc_val failed: %s\n",
                     gpg_strerror (err));
          rc = err;
          goto leave;
        }
    }

  /* Main control loop for encryption. */
  recpno = 0;
  do 
    {
      err = ksba_cms_build (cms, &stopreason);
      if (err)
        {
          log_debug ("ksba_cms_build failed: %s\n", gpg_strerror (err));
          rc = err;
          goto leave;
        }
    }
  while (stopreason != KSBA_SR_READY);   

  if (encparm.readerror)
    {
      log_error ("error reading input: %s\n", strerror (encparm.readerror));
      rc = gpg_error (gpg_err_code_from_errno (encparm.readerror));
      goto leave;
    }


  rc = gpgsm_finish_writer (b64writer);
  if (rc) 
    {
      log_error ("write failed: %s\n", gpg_strerror (rc));
      goto leave;
    }
  audit_log (ctrl->audit, AUDIT_ENCRYPTION_DONE);
  log_info ("encrypted data created\n");

 leave:
  ksba_cms_release (cms);
  gpgsm_destroy_writer (b64writer);
  ksba_reader_release (reader);
  keydb_release (kh); 
  xfree (dek);
  if (data_fp)
    fclose (data_fp);
  xfree (encparm.buffer);
  return rc;
}
Beispiel #4
0
/* Store the certificate in the key DB but make sure that it does not
   already exists.  We do this simply by comparing the fingerprint.
   If EXISTED is not NULL it will be set to true if the certificate
   was already in the DB. */
int
keydb_store_cert (ksba_cert_t cert, int ephemeral, int *existed)
{
  KEYDB_HANDLE kh;
  int rc;
  unsigned char fpr[20];

  if (existed)
    *existed = 0;

  if (!gpgsm_get_fingerprint (cert, 0, fpr, NULL))
    {
      log_error (_("failed to get the fingerprint\n"));
      return gpg_error (GPG_ERR_GENERAL);
    }

  kh = keydb_new (0);
  if (!kh)
    {
      log_error (_("failed to allocate keyDB handle\n"));
      return gpg_error (GPG_ERR_ENOMEM);;
    }

  /* Set the ephemeral flag so that the search looks at all
     records.  */
  keydb_set_ephemeral (kh, 1);

  rc = lock_all (kh);
  if (rc)
    return rc;

  rc = keydb_search_fpr (kh, fpr);
  if (rc != -1)
    {
      keydb_release (kh);
      if (!rc)
        {
          if (existed)
            *existed = 1;
          if (!ephemeral)
            {
              /* Remove ephemeral flags from existing certificate to "store"
                 it permanently. */
              rc = keydb_set_cert_flags (cert, 1, KEYBOX_FLAG_BLOB, 0,
                                         KEYBOX_FLAG_BLOB_EPHEMERAL, 0);
              if (rc)
                {
                  log_error ("clearing ephemeral flag failed: %s\n",
                             gpg_strerror (rc));
                  return rc;
                }
            }
          return 0; /* okay */
        }
      log_error (_("problem looking for existing certificate: %s\n"),
                 gpg_strerror (rc));
      return rc;
    }

  /* Reset the ephemeral flag if not requested.  */
  if (!ephemeral)
    keydb_set_ephemeral (kh, 0);

  rc = keydb_locate_writable (kh, 0);
  if (rc)
    {
      log_error (_("error finding writable keyDB: %s\n"), gpg_strerror (rc));
      keydb_release (kh);
      return rc;
    }

  rc = keydb_insert_cert (kh, cert);
  if (rc)
    {
      log_error (_("error storing certificate: %s\n"), gpg_strerror (rc));
      keydb_release (kh);
      return rc;
    }
  keydb_release (kh);
  return 0;
}
Beispiel #5
0
/* This is basically keydb_set_flags but it implements a complete
   transaction by locating the certificate in the DB and updating the
   flags. */
gpg_error_t
keydb_set_cert_flags (ksba_cert_t cert, int ephemeral,
                      int which, int idx,
                      unsigned int mask, unsigned int value)
{
  KEYDB_HANDLE kh;
  gpg_error_t err;
  unsigned char fpr[20];
  unsigned int old_value;

  if (!gpgsm_get_fingerprint (cert, 0, fpr, NULL))
    {
      log_error (_("failed to get the fingerprint\n"));
      return gpg_error (GPG_ERR_GENERAL);
    }

  kh = keydb_new (0);
  if (!kh)
    {
      log_error (_("failed to allocate keyDB handle\n"));
      return gpg_error (GPG_ERR_ENOMEM);;
    }

  if (ephemeral)
    keydb_set_ephemeral (kh, 1);

  err = keydb_lock (kh);
  if (err)
    {
      log_error (_("error locking keybox: %s\n"), gpg_strerror (err));
      keydb_release (kh);
      return err;
    }

  err = keydb_search_fpr (kh, fpr);
  if (err)
    {
      if (err == -1)
        err = gpg_error (GPG_ERR_NOT_FOUND);
      else
        log_error (_("problem re-searching certificate: %s\n"),
                   gpg_strerror (err));
      keydb_release (kh);
      return err;
    }

  err = keydb_get_flags (kh, which, idx, &old_value);
  if (err)
    {
      log_error (_("error getting stored flags: %s\n"), gpg_strerror (err));
      keydb_release (kh);
      return err;
    }

  value = ((old_value & ~mask) | (value & mask));

  if (value != old_value)
    {
      err = keydb_set_flags (kh, which, idx, value);
      if (err)
        {
          log_error (_("error storing flags: %s\n"), gpg_strerror (err));
          keydb_release (kh);
          return err;
        }
    }

  keydb_release (kh);
  return 0;
}
Beispiel #6
0
/* If keyblock_out is non-NULL, AND the exit code is zero, then it
   contains a pointer to the first keyblock found and exported.  No
   other keyblocks are exported.  The caller must free it. */
static int
do_export_stream( IOBUF out, strlist_t users, int secret,
		  KBNODE *keyblock_out, unsigned int options, int *any )
{
    int rc = 0;
    PACKET pkt;
    KBNODE keyblock = NULL;
    KBNODE kbctx, node;
    size_t ndesc, descindex;
    KEYDB_SEARCH_DESC *desc = NULL;
    subkey_list_t subkey_list = NULL;  /* Track alreay processed subkeys. */
    KEYDB_HANDLE kdbhd;
    strlist_t sl;
    int indent = 0;

    *any = 0;
    init_packet( &pkt );
    kdbhd = keydb_new (secret);

    if (!users) {
        ndesc = 1;
        desc = xcalloc ( ndesc, sizeof *desc );
        desc[0].mode = KEYDB_SEARCH_MODE_FIRST;
    }
    else {
        for (ndesc=0, sl=users; sl; sl = sl->next, ndesc++) 
            ;
        desc = xmalloc ( ndesc * sizeof *desc);
        
        for (ndesc=0, sl=users; sl; sl = sl->next) {
	    if (classify_user_id (sl->d, desc+ndesc))
                ndesc++;
            else
                log_error (_("key \"%s\" not found: %s\n"),
                           sl->d, g10_errstr (G10ERR_INV_USER_ID));
        }

        /* It would be nice to see which of the given users did
           actually match one in the keyring.  To implement this we
           need to have a found flag for each entry in desc and to set
           this we must check all those entries after a match to mark
           all matched one - currently we stop at the first match.  To
           do this we need an extra flag to enable this feature so */
    }

#ifdef ENABLE_SELINUX_HACKS
    if (secret) {
        log_error (_("exporting secret keys not allowed\n"));
        rc = G10ERR_GENERAL;
        goto leave;
    }
#endif

    while (!(rc = keydb_search2 (kdbhd, desc, ndesc, &descindex))) {
        int sha1_warned=0,skip_until_subkey=0;
	u32 sk_keyid[2];

	if (!users) 
            desc[0].mode = KEYDB_SEARCH_MODE_NEXT;

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

	if((node=find_kbnode(keyblock,PKT_SECRET_KEY)))
	  {
	    PKT_secret_key *sk=node->pkt->pkt.secret_key;

	    keyid_from_sk(sk,sk_keyid);

	    /* We can't apply GNU mode 1001 on an unprotected key. */
	    if( secret == 2 && !sk->is_protected )
	      {
		log_info(_("key %s: not protected - skipped\n"),
			 keystr(sk_keyid));
		continue;
	      }

	    /* No v3 keys with GNU mode 1001. */
	    if( secret == 2 && sk->version == 3 )
	      {
		log_info(_("key %s: PGP 2.x style key - skipped\n"),
			 keystr(sk_keyid));
		continue;
	      }

            /* It does not make sense to export a key with a primary
               key on card using a non-key stub.  We simply skip those
               keys when used with --export-secret-subkeys. */
            if (secret == 2 && sk->is_protected
                && sk->protect.s2k.mode == 1002 ) 
              {
		log_info(_("key %s: key material on-card - skipped\n"),
			 keystr(sk_keyid));
		continue;
              }
	  }
	else
	  {
	    /* It's a public key export, so do the cleaning if
	       requested.  Note that both export-clean and
	       export-minimal only apply to UID sigs (0x10, 0x11,
	       0x12, and 0x13).  A designated revocation is never
	       stripped, even with export-minimal set. */

	    if(options&EXPORT_CLEAN)
	      clean_key(keyblock,opt.verbose,options&EXPORT_MINIMAL,NULL,NULL);
	  }

	/* And write it. */
	for( kbctx=NULL; (node = walk_kbnode( keyblock, &kbctx, 0 )); ) {
	    if( skip_until_subkey )
	      {
		if(node->pkt->pkttype==PKT_PUBLIC_SUBKEY
		   || node->pkt->pkttype==PKT_SECRET_SUBKEY)
		  skip_until_subkey=0;
		else
		  continue;
	      }

	    /* We used to use comment packets, but not any longer.  In
	       case we still have comments on a key, strip them here
	       before we call build_packet(). */
	    if( node->pkt->pkttype == PKT_COMMENT )
	      continue;

            /* Make sure that ring_trust packets never get exported. */
            if (node->pkt->pkttype == PKT_RING_TRUST)
              continue;

	    /* If exact is set, then we only export what was requested
	       (plus the primary key, if the user didn't specifically
	       request it). */
	    if(desc[descindex].exact
	       && (node->pkt->pkttype==PKT_PUBLIC_SUBKEY
		   || node->pkt->pkttype==PKT_SECRET_SUBKEY))
	      {
                if (!exact_subkey_match_p (desc+descindex, node))
                  {
                    /* Before skipping this subkey, check whether any
                       other description wants an exact match on a
                       subkey and include that subkey into the output
                       too.  Need to add this subkey to a list so that
                       it won't get processed a second time.
                   
                       So the first step here is to check that list and
                       skip in any case if the key is in that list.

                       We need this whole mess because the import
                       function is not able to merge secret keys and
                       thus it is useless to output them as two
                       separate keys and have import merge them.  */
                    if (subkey_in_list_p (subkey_list, node))  
                      skip_until_subkey = 1; /* Already processed this one. */
                    else
                      {
                        size_t j;

                        for (j=0; j < ndesc; j++)
                          if (j != descindex && desc[j].exact
                              && exact_subkey_match_p (desc+j, node))
                            break;
                        if (!(j < ndesc))
                          skip_until_subkey = 1; /* No other one matching. */ 
                      }
                  }

		if(skip_until_subkey)
		  continue;

                /* Mark this one as processed. */
                {
                  subkey_list_t tmp = new_subkey_list_item (node);
                  tmp->next = subkey_list;
                  subkey_list = tmp;
                }
	      }

	    if(node->pkt->pkttype==PKT_SIGNATURE)
	      {
		/* do not export packets which are marked as not
		   exportable */
		if(!(options&EXPORT_LOCAL_SIGS)
		   && !node->pkt->pkt.signature->flags.exportable)
		  continue; /* not exportable */

		/* Do not export packets with a "sensitive" revocation
		   key unless the user wants us to.  Note that we do
		   export these when issuing the actual revocation
		   (see revoke.c). */
		if(!(options&EXPORT_SENSITIVE_REVKEYS)
		   && node->pkt->pkt.signature->revkey)
		  {
		    int i;

		    for(i=0;i<node->pkt->pkt.signature->numrevkeys;i++)
		      if(node->pkt->pkt.signature->revkey[i]->class & 0x40)
			break;

		    if(i<node->pkt->pkt.signature->numrevkeys)
		      continue;
		  }
	      }

	    /* Don't export attribs? */
	    if( !(options&EXPORT_ATTRIBUTES) &&
		node->pkt->pkttype == PKT_USER_ID &&
		node->pkt->pkt.user_id->attrib_data ) {
	      /* Skip until we get to something that is not an attrib
		 or a signature on an attrib */
	      while(kbctx->next && kbctx->next->pkt->pkttype==PKT_SIGNATURE) {
		kbctx=kbctx->next;
	      }
 
	      continue;
	    }

	    if( secret == 2 && node->pkt->pkttype == PKT_SECRET_KEY )
	      {
		/* We don't want to export the secret parts of the
		 * primary key, this is done by using GNU protection mode 1001
		 */
		int save_mode = node->pkt->pkt.secret_key->protect.s2k.mode;
		node->pkt->pkt.secret_key->protect.s2k.mode = 1001;
                if ((options&EXPORT_SEXP_FORMAT))
                  rc = build_sexp (out, node->pkt, &indent);
                else
                  rc = build_packet (out, node->pkt);
		node->pkt->pkt.secret_key->protect.s2k.mode = save_mode;
	      }
	    else if (secret == 2 && node->pkt->pkttype == PKT_SECRET_SUBKEY
                     && (opt.export_options&EXPORT_RESET_SUBKEY_PASSWD))
              {
                /* If the subkey is protected reset the passphrase to
                   export an unprotected subkey.  This feature is
                   useful in cases of a subkey copied to an unattended
                   machine where a passphrase is not required. */
                PKT_secret_key *sk_save, *sk;

                sk_save = node->pkt->pkt.secret_key;
                sk = copy_secret_key (NULL, sk_save);
                node->pkt->pkt.secret_key = sk;

                log_info (_("about to export an unprotected subkey\n"));
                switch (is_secret_key_protected (sk))
                  {
                  case -1:
                    rc = G10ERR_PUBKEY_ALGO;
                    break;
                  case 0:
                    break;
                  default:
                    if (sk->protect.s2k.mode == 1001)
                      ; /* No secret parts. */
                    else if( sk->protect.s2k.mode == 1002 ) 
                      ; /* Card key stub. */
                    else 
                      {
                        rc = check_secret_key( sk, 0 );
                      }
                    break;
                  }
                if (rc)
                  {
                    node->pkt->pkt.secret_key = sk_save;
                    free_secret_key (sk);
                    log_error (_("failed to unprotect the subkey: %s\n"),
                               g10_errstr (rc));
                    goto leave;
                  }

                if ((options&EXPORT_SEXP_FORMAT))
                  rc = build_sexp (out, node->pkt, &indent);
                else
                  rc = build_packet (out, node->pkt);

                node->pkt->pkt.secret_key = sk_save;
                free_secret_key (sk);
              }
	    else
	      {
		/* Warn the user if the secret key or any of the secret
		   subkeys are protected with SHA1 and we have
		   simple_sk_checksum set. */
		if(!sha1_warned && opt.simple_sk_checksum &&
		   (node->pkt->pkttype==PKT_SECRET_KEY ||
		    node->pkt->pkttype==PKT_SECRET_SUBKEY) &&
		   node->pkt->pkt.secret_key->protect.sha1chk)
		  {
		    /* I hope this warning doesn't confuse people. */
		    log_info(_("WARNING: secret key %s does not have a "
			       "simple SK checksum\n"),keystr(sk_keyid));

		    sha1_warned=1;
		  }

                if ((options&EXPORT_SEXP_FORMAT))
                  rc = build_sexp (out, node->pkt, &indent);
                else
                  rc = build_packet (out, node->pkt);
	      }

	    if( rc ) {
		log_error("build_packet(%d) failed: %s\n",
			    node->pkt->pkttype, g10_errstr(rc) );
		goto leave;
	    }
	}

        if ((options&EXPORT_SEXP_FORMAT) && indent)
          {
            for (; indent; indent--)
              iobuf_put (out, ')');
            iobuf_put (out, '\n');
          }

	++*any;
	if(keyblock_out)
	  {
	    *keyblock_out=keyblock;
	    break;
	  }
    }
Beispiel #7
0
/* Call the directory manager to check whether the certificate is valid
   Returns 0 for valid or usually one of the errors:

  GPG_ERR_CERTIFICATE_REVOKED
  GPG_ERR_NO_CRL_KNOWN
  GPG_ERR_CRL_TOO_OLD

  Values for USE_OCSP:
     0 = Do CRL check.
     1 = Do an OCSP check.
     2 = Do an OCSP check using only the default responder.
 */
int
gpgsm_dirmngr_isvalid (ctrl_t ctrl,
                       ksba_cert_t cert, ksba_cert_t issuer_cert, int use_ocsp)
{
  static int did_options;
  int rc;
  char *certid;
  char line[ASSUAN_LINELENGTH];
  struct inq_certificate_parm_s parm;
  struct isvalid_status_parm_s stparm;

  rc = start_dirmngr (ctrl);
  if (rc)
    return rc;

  if (use_ocsp)
    {
      certid = gpgsm_get_fingerprint_hexstring (cert, GCRY_MD_SHA1);
    }
  else
    {
      certid = gpgsm_get_certid (cert);
      if (!certid)
        {
          log_error ("error getting the certificate ID\n");
	  release_dirmngr (ctrl);
          return gpg_error (GPG_ERR_GENERAL);
        }
    }

  if (opt.verbose > 1)
    {
      char *fpr = gpgsm_get_fingerprint_string (cert, GCRY_MD_SHA1);
      log_info ("asking dirmngr about %s%s\n", fpr,
                use_ocsp? " (using OCSP)":"");
      xfree (fpr);
    }

  parm.ctx = dirmngr_ctx;
  parm.ctrl = ctrl;
  parm.cert = cert;
  parm.issuer_cert = issuer_cert;

  stparm.ctrl = ctrl;
  stparm.seen = 0;
  memset (stparm.fpr, 0, 20);

  /* FIXME: If --disable-crl-checks has been set, we should pass an
     option to dirmngr, so that no fallback CRL check is done after an
     ocsp check.  It is not a problem right now as dirmngr does not
     fallback to CRL checking.  */

  /* It is sufficient to send the options only once because we have
     one connection per process only. */
  if (!did_options)
    {
      if (opt.force_crl_refresh)
        assuan_transact (dirmngr_ctx, "OPTION force-crl-refresh=1",
                         NULL, NULL, NULL, NULL, NULL, NULL);
      did_options = 1;
    }
  snprintf (line, DIM(line)-1, "ISVALID%s %s", 
            use_ocsp == 2? " --only-ocsp --force-default-responder":"",
            certid);
  line[DIM(line)-1] = 0;
  xfree (certid);

  rc = assuan_transact (dirmngr_ctx, line, NULL, NULL,
                        inq_certificate, &parm,
                        isvalid_status_cb, &stparm);
  if (opt.verbose > 1)
    log_info ("response of dirmngr: %s\n", rc? gpg_strerror (rc): "okay");
  rc = rc;

  if (!rc && stparm.seen)
    {
      /* Need to also check the certificate validity. */
      if (stparm.seen != 1)
        {
          log_error ("communication problem with dirmngr detected\n");
          rc = gpg_error (GPG_ERR_INV_CRL);
        }
      else
        {
          KEYDB_HANDLE kh;
          ksba_cert_t rspcert = NULL;

          /* Fixme: First try to get the certificate from the
             dirmngr's cache - it should be there. */
          kh = keydb_new (0);
          if (!kh)
            rc = gpg_error (GPG_ERR_ENOMEM);
          if (!rc)
            rc = keydb_search_fpr (kh, stparm.fpr);
          if (!rc)
            rc = keydb_get_cert (kh, &rspcert);
          if (rc)
            {
              log_error ("unable to find the certificate used "
                         "by the dirmngr: %s\n", gpg_strerror (rc));
              rc = gpg_error (GPG_ERR_INV_CRL);
            }
          keydb_release (kh);

          if (!rc)
            {
              rc = gpgsm_cert_use_ocsp_p (rspcert);
              if (rc)
                rc = gpg_error (GPG_ERR_INV_CRL);
              else
                {
                  /* Note the no_dirmngr flag: This avoids checking
                     this certificate over and over again. */
                  rc = gpgsm_validate_chain (ctrl, rspcert, "", NULL, 0, NULL, 
                                             VALIDATE_FLAG_NO_DIRMNGR, NULL);
                  if (rc)
                    {
                      log_error ("invalid certificate used for CRL/OCSP: %s\n",
                                 gpg_strerror (rc));
                      rc = gpg_error (GPG_ERR_INV_CRL);
                    }
                }
            }
          ksba_cert_release (rspcert);
        }
    }
  release_dirmngr (ctrl);
  return rc;
}
Beispiel #8
0
/* Re-import certifciates.  IN_FD is a list of linefeed delimited
   fingerprints t re-import.  The actual re-import is done by clearing
   the ephemeral flag.  */
static int
reimport_one (ctrl_t ctrl, struct stats_s *stats, int in_fd)
{
  gpg_error_t err = 0;
  estream_t fp = NULL;
  char line[100];  /* Sufficient for a fingerprint.  */
  KEYDB_HANDLE kh;
  KEYDB_SEARCH_DESC desc;
  ksba_cert_t cert = NULL;
  unsigned int flags;

  kh = keydb_new (0);
  if (!kh)
    {
      err = gpg_error (GPG_ERR_ENOMEM);;
      log_error (_("failed to allocate keyDB handle\n"));
      goto leave;
    }
  keydb_set_ephemeral (kh, 1);
   
  fp = es_fdopen_nc (in_fd, "r");
  if (!fp)
    {
      err = gpg_error_from_syserror ();
      log_error ("es_fdopen(%d) failed: %s\n", in_fd, gpg_strerror (err));
      goto leave;
    }

  while (es_fgets (line, DIM(line)-1, fp) )
    {
      if (*line && line[strlen(line)-1] != '\n')
        {
          err = gpg_error (GPG_ERR_LINE_TOO_LONG);
          goto leave;
	}
      trim_spaces (line);
      if (!*line)
        continue;
    
      stats->count++;

      err = keydb_classify_name (line, &desc);
      if (err)
        {
          print_import_problem (ctrl, NULL, 0);
          stats->not_imported++;
          continue;
        }

      keydb_search_reset (kh);
      err = keydb_search (kh, &desc, 1);
      if (err)
        {
          print_import_problem (ctrl, NULL, 0);
          stats->not_imported++;
          continue;
        }

      ksba_cert_release (cert);
      cert = NULL;
      err = keydb_get_cert (kh, &cert);
      if (err)
        {
          log_error ("keydb_get_cert() failed: %s\n", gpg_strerror (err));
          print_import_problem (ctrl, NULL, 1);
          stats->not_imported++;
          continue;
        }

      err = keydb_get_flags (kh, KEYBOX_FLAG_BLOB, 0, &flags);
      if (err)
        {
          log_error (_("error getting stored flags: %s\n"), gpg_strerror (err));
          print_imported_status (ctrl, cert, 0);
          stats->not_imported++;
          continue;
        }
      if ( !(flags & KEYBOX_FLAG_BLOB_EPHEMERAL) )
        {
          print_imported_status (ctrl, cert, 0);
          stats->unchanged++;
          continue;
        }

      err = keydb_set_cert_flags (cert, 1, KEYBOX_FLAG_BLOB, 0,
                                  KEYBOX_FLAG_BLOB_EPHEMERAL, 0);
      if (err)
        {
          log_error ("clearing ephemeral flag failed: %s\n",
                     gpg_strerror (err)); 
          print_import_problem (ctrl, cert, 0);
          stats->not_imported++;
          continue;
        }

      print_imported_status (ctrl, cert, 1);
      stats->imported++;
    }
  err = 0;
  if (es_ferror (fp))
    {
      err = gpg_error_from_syserror ();
      log_error ("error reading fd %d: %s\n", in_fd, gpg_strerror (err));
      goto leave;
    }

 leave:
  ksba_cert_release (cert);
  keydb_release (kh);
  es_fclose (fp);
  return err;
}
Beispiel #9
0
/****************
 * 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;
}
Beispiel #10
0
static void
do_test (int argc, char *argv[])
{
  int rc;
  KEYDB_HANDLE hd1, hd2;
  KEYDB_SEARCH_DESC desc1, desc2;
  KBNODE kb1, kb2, p;
  char *uid1;
  char *uid2;
  char *fname;

  (void) argc;
  (void) argv;

  fname = prepend_srcdir ("t-keydb-keyring.kbx");
  rc = keydb_add_resource (fname, 0);
  test_free (fname);
  if (rc)
    ABORT ("Failed to open keyring.");

  hd1 = keydb_new ();
  if (!hd1)
    ABORT ("");
  hd2 = keydb_new ();
  if (!hd2)
    ABORT ("");

  rc = classify_user_id ("2689 5E25 E844 6D44 A26D  8FAF 2F79 98F3 DBFC 6AD9",
			 &desc1, 0);
  if (rc)
    ABORT ("Failed to convert fingerprint for DBFC6AD9");

  rc = keydb_search (hd1, &desc1, 1, NULL);
  if (rc)
    ABORT ("Failed to lookup key associated with DBFC6AD9");


  classify_user_id ("8061 5870 F5BA D690 3336  86D0 F2AD 85AC 1E42 B367",
		    &desc2, 0);
  if (rc)
    ABORT ("Failed to convert fingerprint for 1E42B367");

  rc = keydb_search (hd2, &desc2, 1, NULL);
  if (rc)
    ABORT ("Failed to lookup key associated with 1E42B367");

  rc = keydb_get_keyblock (hd2, &kb2);
  if (rc)
    ABORT ("Failed to get keyblock for 1E42B367");

  rc = keydb_get_keyblock (hd1, &kb1);
  if (rc)
    ABORT ("Failed to get keyblock for DBFC6AD9");

  p = kb1;
  while (p && p->pkt->pkttype != PKT_USER_ID)
    p = p->next;
  if (! p)
    ABORT ("DBFC6AD9 has no user id packet");
  uid1 = p->pkt->pkt.user_id->name;

  p = kb2;
  while (p && p->pkt->pkttype != PKT_USER_ID)
    p = p->next;
  if (! p)
    ABORT ("1E42B367 has no user id packet");
  uid2 = p->pkt->pkt.user_id->name;

  if (verbose)
    {
      printf ("user id for DBFC6AD9: %s\n", uid1);
      printf ("user id for 1E42B367: %s\n", uid2);
    }

  TEST_P ("cache consistency", strcmp (uid1, uid2) != 0);

  release_kbnode (kb1);
  release_kbnode (kb2);
  keydb_release (hd1);
  keydb_release (hd2);
}
Beispiel #11
0
/* code mostly stolen from do_export_stream */
static int
keyidlist(strlist_t users,KEYDB_SEARCH_DESC **klist,int *count,int fakev3)
{
  int rc=0,ndesc,num=100;
  KBNODE keyblock=NULL,node;
  KEYDB_HANDLE kdbhd;
  KEYDB_SEARCH_DESC *desc;
  strlist_t sl;

  *count=0;

  *klist=xmalloc(sizeof(KEYDB_SEARCH_DESC)*num);

  kdbhd=keydb_new ();

  if(!users)
    {
      ndesc = 1;
      desc = xmalloc_clear ( ndesc * sizeof *desc);
      desc[0].mode = KEYDB_SEARCH_MODE_FIRST;
    }
  else
    {
      for (ndesc=0, sl=users; sl; sl = sl->next, ndesc++)
	;
      desc = xmalloc ( ndesc * sizeof *desc);

      for (ndesc=0, sl=users; sl; sl = sl->next)
	{
          gpg_error_t err;
	  if (!(err = classify_user_id (sl->d, desc+ndesc, 1)))
	    ndesc++;
	  else
	    log_error (_("key \"%s\" not found: %s\n"),
		       sl->d, gpg_strerror (err));
	}
    }

  while (!(rc = keydb_search (kdbhd, desc, ndesc)))
    {
      if (!users)
	desc[0].mode = KEYDB_SEARCH_MODE_NEXT;

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

      if((node=find_kbnode(keyblock,PKT_PUBLIC_KEY)))
	{
	  /* This is to work around a bug in some keyservers (pksd and
             OKS) that calculate v4 RSA keyids as if they were v3 RSA.
             The answer is to refresh both the correct v4 keyid
             (e.g. 99242560) and the fake v3 keyid (e.g. 68FDDBC7).
             This only happens for key refresh using the HKP scheme
             and if the refresh-add-fake-v3-keyids keyserver option is
             set. */
	  if(fakev3 && is_RSA(node->pkt->pkt.public_key->pubkey_algo) &&
	     node->pkt->pkt.public_key->version>=4)
	    {
	      (*klist)[*count].mode=KEYDB_SEARCH_MODE_LONG_KID;
	      v3_keyid (node->pkt->pkt.public_key->pkey[0],
                        (*klist)[*count].u.kid);
	      (*count)++;

	      if(*count==num)
		{
		  num+=100;
		  *klist=xrealloc(*klist,sizeof(KEYDB_SEARCH_DESC)*num);
		}
	    }

	  /* v4 keys get full fingerprints.  v3 keys get long keyids.
             This is because it's easy to calculate any sort of keyid
             from a v4 fingerprint, but not a v3 fingerprint. */

	  if(node->pkt->pkt.public_key->version<4)
	    {
	      (*klist)[*count].mode=KEYDB_SEARCH_MODE_LONG_KID;
	      keyid_from_pk(node->pkt->pkt.public_key,
			    (*klist)[*count].u.kid);
	    }
	  else
	    {
	      size_t dummy;

	      (*klist)[*count].mode=KEYDB_SEARCH_MODE_FPR20;
	      fingerprint_from_pk(node->pkt->pkt.public_key,
				  (*klist)[*count].u.fpr,&dummy);
	    }

	  /* This is a little hackish, using the skipfncvalue as a
	     void* pointer to the keyserver spec, but we don't need
	     the skipfnc here, and it saves having an additional field
	     for this (which would be wasted space most of the
	     time). */

	  (*klist)[*count].skipfncvalue=NULL;

	  /* Are we honoring preferred keyservers? */
	  if(opt.keyserver_options.options&KEYSERVER_HONOR_KEYSERVER_URL)
	    {
	      PKT_user_id *uid=NULL;
	      PKT_signature *sig=NULL;

	      merge_keys_and_selfsig(keyblock);

	      for(node=node->next;node;node=node->next)
		{
		  if(node->pkt->pkttype==PKT_USER_ID
		     && node->pkt->pkt.user_id->is_primary)
		    uid=node->pkt->pkt.user_id;
		  else if(node->pkt->pkttype==PKT_SIGNATURE
			  && node->pkt->pkt.signature->
			  flags.chosen_selfsig && uid)
		    {
		      sig=node->pkt->pkt.signature;
		      break;
		    }
		}

	      /* Try and parse the keyserver URL.  If it doesn't work,
		 then we end up writing NULL which indicates we are
		 the same as any other key. */
	      if(sig)
		(*klist)[*count].skipfncvalue=parse_preferred_keyserver(sig);
	    }

	  (*count)++;

	  if(*count==num)
	    {
	      num+=100;
	      *klist=xrealloc(*klist,sizeof(KEYDB_SEARCH_DESC)*num);
	    }
	}
    }

  if (gpg_err_code (rc) == GPG_ERR_NOT_FOUND)
    rc = 0;

 leave:
  if(rc)
    xfree(*klist);
  xfree(desc);
  keydb_release(kdbhd);
  release_kbnode(keyblock);

  return rc;
}
Beispiel #12
0
/* Store the certificate in the key DB but make sure that it does not
   already exists.  We do this simply by comparing the fingerprint.
   If EXISTED is not NULL it will be set to true if the certificate
   was already in the DB. */
int
keydb_store_cert (ksba_cert_t cert, int ephemeral, int *existed)
{
  KEYDB_HANDLE kh;
  int rc;
  unsigned char fpr[20];

  if (existed)
    *existed = 0;

  if (!gpgsm_get_fingerprint (cert, 0, fpr, NULL))
    {
      log_error (_("failed to get the fingerprint\n"));
      return gpg_error (GPG_ERR_GENERAL);
    }

  kh = keydb_new (0);
  if (!kh)
    {
      log_error (_("failed to allocate keyDB handle\n"));
      return gpg_error (GPG_ERR_ENOMEM);;
    }

  if (ephemeral)
    keydb_set_ephemeral (kh, 1);

  rc = lock_all (kh);
  if (rc)
    return rc;

  rc = keydb_search_fpr (kh, fpr);
  if (rc != -1)
    {
      keydb_release (kh);
      if (!rc)
        {
          if (existed)
            *existed = 1;
          return 0; /* okay */
        }
      log_error (_("problem looking for existing certificate: %s\n"),
                 gpg_strerror (rc));
      return rc;
    }

  rc = keydb_locate_writable (kh, 0);
  if (rc)
    {
      log_error (_("error finding writable keyDB: %s\n"), gpg_strerror (rc));
      keydb_release (kh);
      return rc;
    }

  rc = keydb_insert_cert (kh, cert);
  if (rc)
    {
      log_error (_("error storing certificate: %s\n"), gpg_strerror (rc));
      keydb_release (kh);
      return rc;
    }
  keydb_release (kh);
  return 0;
}
Beispiel #13
0
/* Delete a certificate or an secret key from a key database. */
static int
delete_one (ctrl_t ctrl, const char *username)
{
  int rc = 0;
  KEYDB_SEARCH_DESC desc;
  KEYDB_HANDLE kh = NULL;
  ksba_cert_t cert = NULL;
  int duplicates = 0;
  int is_ephem = 0;
  
  rc = keydb_classify_name (username, &desc);
  if (rc)
    {
      log_error (_("certificate `%s' not found: %s\n"),
                 username, gpg_strerror (rc));
      gpgsm_status2 (ctrl, STATUS_DELETE_PROBLEM, "1", NULL);
      goto leave;
    }

  kh = keydb_new (0);
  if (!kh)
    {
      log_error ("keydb_new failed\n");
      goto leave;
    }

  /* If the key is specified in a unique way, include ephemeral keys
     in the search.  */
  if ( desc.mode == KEYDB_SEARCH_MODE_FPR
       || desc.mode == KEYDB_SEARCH_MODE_FPR20
       || desc.mode == KEYDB_SEARCH_MODE_FPR16
       || desc.mode == KEYDB_SEARCH_MODE_KEYGRIP )
    {
      is_ephem = 1;
      keydb_set_ephemeral (kh, 1);
    }

  rc = keydb_search (kh, &desc, 1);
  if (!rc)
    rc = keydb_get_cert (kh, &cert);
  if (!rc && !is_ephem)
    {
      unsigned char fpr[20];

      gpgsm_get_fingerprint (cert, 0, fpr, NULL);

    next_ambigious:
      rc = keydb_search (kh, &desc, 1);
      if (rc == -1)
        rc = 0;
      else if (!rc)
        {
          ksba_cert_t cert2 = NULL;
          unsigned char fpr2[20];

          /* We ignore all duplicated certificates which might have
             been inserted due to program bugs. */
          if (!keydb_get_cert (kh, &cert2))
            {
              gpgsm_get_fingerprint (cert2, 0, fpr2, NULL);
              ksba_cert_release (cert2);
              if (!memcmp (fpr, fpr2, 20))
                {
                  duplicates++;
                  goto next_ambigious;
                }
            }
          rc = gpg_error (GPG_ERR_AMBIGUOUS_NAME);
        }
    }
  if (rc)
    {
      if (rc == -1)
        rc = gpg_error (GPG_ERR_NO_PUBKEY);
      log_error (_("certificate `%s' not found: %s\n"),
                 username, gpg_strerror (rc));
      gpgsm_status2 (ctrl, STATUS_DELETE_PROBLEM, "3", NULL);
      goto leave;
    }

  /* We need to search again to get back to the right position. */
  rc = keydb_lock (kh);
  if (rc)
    {
      log_error (_("error locking keybox: %s\n"), gpg_strerror (rc));
      goto leave;
    }
                   
  do 
    {
      keydb_search_reset (kh);
      rc = keydb_search (kh, &desc, 1);
      if (rc)
        {
          log_error ("problem re-searching certificate: %s\n",
                     gpg_strerror (rc));
          goto leave;
        }
      
      rc = keydb_delete (kh, duplicates ? 0 : 1);
      if (rc) 
        goto leave;
      if (opt.verbose)
        {
          if (duplicates)
            log_info (_("duplicated certificate `%s' deleted\n"), username);
          else
            log_info (_("certificate `%s' deleted\n"), username);
        }
    }
  while (duplicates--);

 leave:
  keydb_release (kh);
  ksba_cert_release (cert);
  return rc;
}
Beispiel #14
0
/* Export a certificate and its private key. */
void
gpgsm_p12_export (ctrl_t ctrl, const char *name, estream_t stream)
{
  gpg_error_t err = 0;
  KEYDB_HANDLE hd;
  KEYDB_SEARCH_DESC *desc = NULL;
  Base64Context b64writer = NULL;
  ksba_writer_t writer;
  ksba_cert_t cert = NULL;
  const unsigned char *image;
  size_t imagelen;
  char *keygrip = NULL;
  char *prompt;
  void *data;
  size_t datalen;


  hd = keydb_new (0);
  if (!hd)
    {
      log_error ("keydb_new failed\n");
      goto leave;
    }

  desc = xtrycalloc (1, sizeof *desc);
  if (!desc)
    {
      log_error ("allocating memory for export failed: %s\n",
                 gpg_strerror (out_of_core ()));
      goto leave;
    }

  err = classify_user_id (name, desc, 0);
  if (err)
    {
      log_error ("key '%s' not found: %s\n",
                 name, gpg_strerror (err));
      goto leave;
    }

  /* Lookup the certificate and make sure that it is unique. */
  err = keydb_search (hd, desc, 1);
  if (!err)
    {
      err = keydb_get_cert (hd, &cert);
      if (err)
        {
          log_error ("keydb_get_cert failed: %s\n", gpg_strerror (err));
          goto leave;
        }

    next_ambiguous:
      err = keydb_search (hd, desc, 1);
      if (!err)
        {
          ksba_cert_t cert2 = NULL;

          if (!keydb_get_cert (hd, &cert2))
            {
              if (gpgsm_certs_identical_p (cert, cert2))
                {
                  ksba_cert_release (cert2);
                  goto next_ambiguous;
                }
              ksba_cert_release (cert2);
            }
          err = gpg_error (GPG_ERR_AMBIGUOUS_NAME);
        }
      else if (err == -1 || gpg_err_code (err) == GPG_ERR_EOF)
        err = 0;
      if (err)
        {
          log_error ("key '%s' not found: %s\n",
                     name, gpg_strerror (err));
          goto leave;
        }
    }

  keygrip = gpgsm_get_keygrip_hexstring (cert);
  if (!keygrip || gpgsm_agent_havekey (ctrl, keygrip))
    {
      /* Note, that the !keygrip case indicates a bad certificate. */
      err = gpg_error (GPG_ERR_NO_SECKEY);
      log_error ("can't export key '%s': %s\n", name, gpg_strerror (err));
      goto leave;
    }

  image = ksba_cert_get_image (cert, &imagelen);
  if (!image)
    {
      log_error ("ksba_cert_get_image failed\n");
      goto leave;
    }

  if (ctrl->create_pem)
    {
      print_short_info (cert, stream);
      es_putc ('\n', stream);
    }

  if (opt.p12_charset && ctrl->create_pem)
    {
      es_fprintf (stream, "The passphrase is %s encoded.\n\n",
                  opt.p12_charset);
    }

  ctrl->pem_name = "PKCS12";
  err = gpgsm_create_writer (&b64writer, ctrl, stream, &writer);
  if (err)
    {
      log_error ("can't create writer: %s\n", gpg_strerror (err));
      goto leave;
    }

  prompt = gpgsm_format_keydesc (cert);
  err = export_p12 (ctrl, image, imagelen, prompt, keygrip, &data, &datalen);
  xfree (prompt);
  if (err)
    goto leave;
  err = ksba_writer_write (writer, data, datalen);
  xfree (data);
  if (err)
    {
      log_error ("write failed: %s\n", gpg_strerror (err));
      goto leave;
    }

  if (ctrl->create_pem)
    {
      /* We want one certificate per PEM block */
      err = gpgsm_finish_writer (b64writer);
      if (err)
        {
          log_error ("write failed: %s\n", gpg_strerror (err));
          goto leave;
        }
      gpgsm_destroy_writer (b64writer);
      b64writer = NULL;
    }

  ksba_cert_release (cert);
  cert = NULL;

 leave:
  gpgsm_destroy_writer (b64writer);
  ksba_cert_release (cert);
  xfree (desc);
  keydb_release (hd);
}
Beispiel #15
0
/* Export all certificates or just those given in NAMES.  The output
   is written to STREAM.  */
void
gpgsm_export (ctrl_t ctrl, strlist_t names, estream_t stream)
{
  KEYDB_HANDLE hd = NULL;
  KEYDB_SEARCH_DESC *desc = NULL;
  int ndesc;
  Base64Context b64writer = NULL;
  ksba_writer_t writer;
  strlist_t sl;
  ksba_cert_t cert = NULL;
  int rc=0;
  int count = 0;
  int i;
  duptable_t *dtable;


  dtable = create_duptable ();
  if (!dtable)
    {
      log_error ("creating duplicates table failed: %s\n", strerror (errno));
      goto leave;
    }

  hd = keydb_new (0);
  if (!hd)
    {
      log_error ("keydb_new failed\n");
      goto leave;
    }

  if (!names)
    ndesc = 1;
  else
    {
      for (sl=names, ndesc=0; sl; sl = sl->next, ndesc++)
        ;
    }

  desc = xtrycalloc (ndesc, sizeof *desc);
  if (!ndesc)
    {
      log_error ("allocating memory for export failed: %s\n",
                 gpg_strerror (out_of_core ()));
      goto leave;
    }

  if (!names)
    desc[0].mode = KEYDB_SEARCH_MODE_FIRST;
  else
    {
      for (ndesc=0, sl=names; sl; sl = sl->next)
        {
          rc = classify_user_id (sl->d, desc+ndesc, 0);
          if (rc)
            {
              log_error ("key '%s' not found: %s\n",
                         sl->d, gpg_strerror (rc));
              rc = 0;
            }
          else
            ndesc++;
        }
    }

  /* If all specifications are done by fingerprint or keygrip, we
     switch to ephemeral mode so that _all_ currently available and
     matching certificates are exported.  */
  if (names && ndesc)
    {
      for (i=0; (i < ndesc
                 && (desc[i].mode == KEYDB_SEARCH_MODE_FPR
                     || desc[i].mode == KEYDB_SEARCH_MODE_FPR20
                     || desc[i].mode == KEYDB_SEARCH_MODE_FPR16
                     || desc[i].mode == KEYDB_SEARCH_MODE_KEYGRIP)); i++)
        ;
      if (i == ndesc)
        keydb_set_ephemeral (hd, 1);
    }

  while (!(rc = keydb_search (hd, desc, ndesc)))
    {
      unsigned char fpr[20];
      int exists;

      if (!names)
        desc[0].mode = KEYDB_SEARCH_MODE_NEXT;

      rc = keydb_get_cert (hd, &cert);
      if (rc)
        {
          log_error ("keydb_get_cert failed: %s\n", gpg_strerror (rc));
          goto leave;
        }

      gpgsm_get_fingerprint (cert, 0, fpr, NULL);
      rc = insert_duptable (dtable, fpr, &exists);
      if (rc)
        {
          log_error ("inserting into duplicates table failed: %s\n",
                     gpg_strerror (rc));
          goto leave;
        }

      if (!exists && count && !ctrl->create_pem)
        {
          log_info ("exporting more than one certificate "
                    "is not possible in binary mode\n");
          log_info ("ignoring other certificates\n");
          break;
        }

      if (!exists)
        {
          const unsigned char *image;
          size_t imagelen;

          image = ksba_cert_get_image (cert, &imagelen);
          if (!image)
            {
              log_error ("ksba_cert_get_image failed\n");
              goto leave;
            }


          if (ctrl->create_pem)
            {
              if (count)
                es_putc ('\n', stream);
              print_short_info (cert, stream);
              es_putc ('\n', stream);
            }
          count++;

          if (!b64writer)
            {
              ctrl->pem_name = "CERTIFICATE";
              rc = gpgsm_create_writer (&b64writer, ctrl, stream, &writer);
              if (rc)
                {
                  log_error ("can't create writer: %s\n", gpg_strerror (rc));
                  goto leave;
                }
            }

          rc = ksba_writer_write (writer, image, imagelen);
          if (rc)
            {
              log_error ("write error: %s\n", gpg_strerror (rc));
              goto leave;
            }

          if (ctrl->create_pem)
            {
              /* We want one certificate per PEM block */
              rc = gpgsm_finish_writer (b64writer);
              if (rc)
                {
                  log_error ("write failed: %s\n", gpg_strerror (rc));
                  goto leave;
                }
              gpgsm_destroy_writer (b64writer);
              b64writer = NULL;
            }
        }

      ksba_cert_release (cert);
      cert = NULL;
    }
  if (rc && rc != -1)
    log_error ("keydb_search failed: %s\n", gpg_strerror (rc));
  else if (b64writer)
    {
      rc = gpgsm_finish_writer (b64writer);
      if (rc)
        {
          log_error ("write failed: %s\n", gpg_strerror (rc));
          goto leave;
        }
    }

 leave:
  gpgsm_destroy_writer (b64writer);
  ksba_cert_release (cert);
  xfree (desc);
  keydb_release (hd);
  destroy_duptable (dtable);
}
Beispiel #16
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;
}