Exemplo n.º 1
0
/****************
 * Show the revocation reason as it is stored with the given signature
 */
static void
do_show_revocation_reason( PKT_signature *sig )
{
    size_t n, nn;
    const byte *p, *pp;
    int seq = 0;
    const char *text;

    while( (p = enum_sig_subpkt (sig->hashed, SIGSUBPKT_REVOC_REASON,
				 &n, &seq, NULL )) ) {
	if( !n )
	    continue; /* invalid - just skip it */

	if( *p == 0 )
	    text = _("No reason specified");
	else if( *p == 0x01 )
	    text = _("Key is superseded");
	else if( *p == 0x02 )
	    text = _("Key has been compromised");
	else if( *p == 0x03 )
	    text = _("Key is no longer used");
	else if( *p == 0x20 )
	    text = _("User ID is no longer valid");
	else
	    text = NULL;

	log_info ( _("reason for revocation: "));
	if (text)
          log_printf ("%s\n", text);
	else
          log_printf ("code=%02x\n", *p );
	n--; p++;
	pp = NULL;
	do {
	    /* We don't want any empty lines, so skip them */
	    while( n && *p == '\n' ) {
		p++;
		n--;
	    }
	    if( n ) {
		pp = memchr( p, '\n', n );
		nn = pp? pp - p : n;
		log_info ( _("revocation comment: ") );
		es_write_sanitized (log_get_stream(), p, nn, NULL, NULL);
		log_printf ("\n");
		p += nn; n -= nn;
	    }
	} while( pp );
    }
}
Exemplo n.º 2
0
void
dump_kbnode (KBNODE node)
{
  for (; node; node = node->next )
    {
      const char *s;
      switch (node->pkt->pkttype)
        {
        case 0:		s="empty"; break;
        case PKT_PUBLIC_KEY:	s="public-key"; break;
        case PKT_SECRET_KEY:	s="secret-key"; break;
        case PKT_SECRET_SUBKEY: s= "secret-subkey"; break;
        case PKT_PUBKEY_ENC:	s="public-enc"; break;
        case PKT_SIGNATURE:	s="signature"; break;
        case PKT_ONEPASS_SIG: s="onepass-sig"; break;
        case PKT_USER_ID:	s="user-id"; break;
        case PKT_PUBLIC_SUBKEY: s="public-subkey"; break;
        case PKT_COMMENT:	s="comment"; break;
        case PKT_RING_TRUST:	s="trust"; break;
        case PKT_PLAINTEXT:	s="plaintext"; break;
        case PKT_COMPRESSED:	s="compressed"; break;
        case PKT_ENCRYPTED:	s="encrypted"; break;
        case PKT_GPG_CONTROL: s="gpg-control"; break;
        default:		s="unknown"; break;
	}
      log_debug ("node %p %02x/%02x type=%s",
                 node, node->flag, node->private_flag, s);
      if (node->pkt->pkttype == PKT_USER_ID)
        {
          PKT_user_id *uid = node->pkt->pkt.user_id;
          log_printf ("  \"");
          es_write_sanitized (log_get_stream (), uid->name, uid->len,
                              NULL, NULL);
          log_printf ("\" %c%c%c%c\n",
                      uid->is_expired? 'e':'.',
                      uid->is_revoked? 'r':'.',
                      uid->created?    'v':'.',
                      uid->is_primary? 'p':'.' );
        }
      else if (node->pkt->pkttype == PKT_SIGNATURE)
        {
          log_printf ("  class=%02x keyid=%08lX ts=%lu\n",
                      node->pkt->pkt.signature->sig_class,
                      (ulong)node->pkt->pkt.signature->keyid[1],
                      (ulong)node->pkt->pkt.signature->timestamp);
        }
      else if (node->pkt->pkttype == PKT_GPG_CONTROL)
        {
          log_printf (" ctrl=%d len=%u\n",
                      node->pkt->pkt.gpg_control->control,
                      (unsigned int)node->pkt->pkt.gpg_control->datalen);
        }
      else if (node->pkt->pkttype == PKT_PUBLIC_KEY
               || node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
        {
          PKT_public_key *pk = node->pkt->pkt.public_key;

          log_printf ("  keyid=%08lX a=%d u=%d %c%c%c%c\n",
                      (ulong)keyid_from_pk( pk, NULL ),
                      pk->pubkey_algo, pk->pubkey_usage,
                      pk->has_expired? 'e':'.',
                      pk->flags.revoked? 'r':'.',
                      pk->flags.valid?    'v':'.',
                      pk->flags.mdc?   'm':'.');
        }

      log_flush ();
    }
}
Exemplo n.º 3
0
/**
 * Phase I - Calculate degree of preference (LOCAL_PREF) for each
 *           single route. Operate on separate Adj-RIB-Ins.
 *           This phase is carried by 'peer_handle_message' (peer.c).
 *
 * Phase II - Selection of best route on the basis of the degree of
 *            preference and then on tie-breaking rules (AS-Path
 *            length, Origin, MED, ...).
 *
 * Phase III - Dissemination of routes.
 *
 * In our implementation, we distinguish two main cases:
 * - a withdraw has been received from a peer for a given prefix. In
 * this case, if the best route towards this prefix was received by
 * the given peer, the complete decision process has to be
 * run. Otherwise, nothing more is done (the route has been removed
 * from the peer's Adj-RIB-In by 'peer_handle_message');
 * - an update has been received. The complete decision process has to
 * be run.
 */
int qos_decision_process(SBGPRouter * pRouter, SPeer * pOriginPeer,
			 SPrefix sPrefix)
{
#ifndef __EXPERIMENTAL_WALTON__
  SRoutes * pRoutes= routes_list_create();
  SRoutes * pEBGPRoutes= routes_list_create();
  int iIndex;
  SPeer * pPeer;
  SRoute * pRoute, * pOldRoute;

  AS_LOG_DEBUG(pRouter, " > qos_decision_process.begin\n");

  LOG_DEBUG("\t<-peer: AS%d\n", pOriginPeer->uRemoteAS);

  pOldRoute= rib_find_exact(pRouter->pLocRIB, sPrefix);
  LOG_DEBUG("\tbest: ");
  LOG_ENABLED_DEBUG() route_dump(log_get_stream(pMainLog), pOldRoute);
  LOG_DEBUG("\n");

  // *** lock all Adj-RIB-Ins ***

  // Build list of eligible routes and list of eligible eBGP routes
  for (iIndex= 0; iIndex < ptr_array_length(pRouter->pPeers); iIndex++) {
    pPeer= (SPeer*) pRouter->pPeers->data[iIndex];
    pRoute= rib_find_exact(pPeer->pAdjRIBIn, sPrefix);
    if ((pRoute != NULL) &&
	(route_flag_get(pRoute, ROUTE_FLAG_FEASIBLE))) {
      assert(ptr_array_append(pRoutes, pRoute) >= 0);
      LOG_DEBUG("\teligible: ");
      LOG_ENABLED_DEBUG() route_dump(log_get_stream(pMainLog), pRoute);
      LOG_DEBUG("\n");
      if (route_peer_get(pRoute)->uRemoteAS != pRouter->uNumber)
	assert(ptr_array_append(pEBGPRoutes, pRoute) >= 0);
    }
  }

  // Keep routes with highest degree of preference
  if (ptr_array_length(pRoutes) > 1)
    as_decision_process_dop(pRouter, pRoutes);

  // Tie-break
  if (ptr_array_length(pRoutes) > 1)
    qos_decision_process_delay(pRouter, pRoutes, BGP_OPTIONS_QOS_AGGR_LIMIT);

  assert(ptr_array_length(pRoutes) <= 1);

  if (ptr_array_length(pRoutes) == 1) {

    LOG_DEBUG("\tselected: ");
    LOG_ENABLED_DEBUG()
      route_dump(log_get_stream(pMainLog), (SRoute *) pRoutes->data[0]);
    LOG_DEBUG("\n");

    // Carry aggregated route ?
    if (((SRoute *) pRoutes->data[0])->pAggrRoute != NULL) {
      LOG_DEBUG("\taggregated: ");
      LOG_ENABLED_DEBUG()
	route_dump(log_get_stream(pMainLog),
		    ((SRoute *) pRoutes->data[0])->pAggrRoute);

      LOG_DEBUG("\n");
    }

    // If best route is iBGP or aggregate contains an iBGP route, then
    // find the best eBGP route (and aggregate: optional)
    if (qos_route_is_ibgp(pRouter, (SRoute *) pRoutes->data[0])) {

      // Keep eBGP routes with highest degree of preference
      if (ptr_array_length(pEBGPRoutes) > 1)
	as_decision_process_dop(pRouter, pEBGPRoutes);

      // Tie-break for eBGP routes
      if (ptr_array_length(pEBGPRoutes) > 1)
	qos_decision_process_delay(pRouter, pEBGPRoutes,
				   BGP_OPTIONS_QOS_AGGR_LIMIT);

      assert(ptr_array_length(pRoutes) <= 1);

      if (ptr_array_length(pEBGPRoutes) == 1)
	((SRoute *) pRoutes->data[0])->pEBGPRoute=
	  (SRoute *) pEBGPRoutes->data[0];

    }

    route_copy_count++;
    pRoute= route_copy((SRoute *) pRoutes->data[0]);
    route_flag_set(pRoute, ROUTE_FLAG_BEST, 1);
    
    LOG_DEBUG("\tnew best: ");
    LOG_ENABLED_DEBUG() route_dump(log_get_stream(pMainLog), pRoute);
    LOG_DEBUG("\n");
    
    // New/updated route
    // => install in Loc-RIB
    // => advertise to peers
    if ((pOldRoute == NULL) || !route_equals(pOldRoute, pRoute)) {
      if (pOldRoute != NULL)
	route_flag_set(pOldRoute, ROUTE_FLAG_BEST, 0);
      assert(rib_add_route(pRouter->pLocRIB, pRoute) == 0);
      qos_decision_process_disseminate(pRouter, sPrefix, pRoute);
    } else {
      route_destroy(&pRoute);
      pRoute= pOldRoute;
    }
  } else if (ptr_array_length(pRoutes) == 0) {
    LOG_DEBUG("no best\n");
    // If a route towards this prefix was previously installed, then
    // withdraw it. Otherwise, do nothing...
    if (pOldRoute != NULL) {
      //LOG_DEBUG("there was a previous best-route\n");
      rib_remove_route(pRouter->pLocRIB, sPrefix);
      //LOG_DEBUG("previous best-route removed\n");
      route_flag_set(pOldRoute, ROUTE_FLAG_BEST, 0);
      // Withdraw should ideally only be sent to peers that already
      // have received this route. Since we do not maintain
      // Adj-RIB-Outs, the 'withdraw' message is sent to all peers...
      qos_decision_process_disseminate(pRouter, sPrefix, NULL);
    }
  }

  // *** unlock all Adj-RIB-Ins ***
  
  routes_list_destroy(&pRoutes);
  routes_list_destroy(&pEBGPRoutes);
  
  AS_LOG_DEBUG(pRouter, " < qos_decision_process.end\n");
#endif
  return 0;
}
Exemplo n.º 4
0
/**
 * Disseminate route to Adj-RIB-Outs.
 *
 * If there is no best route, then
 *   - if a route was previously announced, send an explicit withdraw
 *   - otherwise do nothing
 *
 * If there is one best route, then send an update. If a route was
 * previously announced, it will be implicitly withdrawn.
 */
void qos_decision_process_disseminate(SBGPRouter * pRouter, SPrefix sPrefix,
				      SRoute * pRoute)
{
#define QOS_REDISTRIBUTE_NOT  0
#define QOS_REDISTRIBUTE_BEST 1
#define QOS_REDISTRIBUTE_EBGP 2

  int iIndex, iIndex2;
  SPeer * pPeer;
  SRoutes * pAggrRoutes= NULL;
  SRoute * pEBGPRoute= NULL;
  int iRedistributionType;
  int iAggregateIBGP;

  AS_LOG_DEBUG(pRouter, " > qos_decision_process_disseminate.begin\n");

  iAggregateIBGP= qos_route_is_ibgp(pRouter, pRoute);

  if (pRoute->pAggrRoute != NULL) {
    pAggrRoutes= pRoute->pAggrRoutes;
    pEBGPRoute= pRoute->pEBGPRoute;
    pRoute= pRoute->pAggrRoute;
  }

  for (iIndex= 0; iIndex < ptr_array_length(pRouter->pPeers); iIndex++) {
    pPeer= (SPeer *) pRouter->pPeers->data[iIndex];

    iRedistributionType= QOS_REDISTRIBUTE_BEST;

    // If one route of the aggregate was learned through the iBGP,
    // prevent the redistribution to all the iBGP peer.
    // Announce the eBGP route if it exists
    if ((pPeer->uRemoteAS == pRouter->uNumber) &&
	(iAggregateIBGP)) {
      if (pEBGPRoute != NULL)
	iRedistributionType= QOS_REDISTRIBUTE_EBGP;
      else
	iRedistributionType= QOS_REDISTRIBUTE_NOT;
    }

    // If the route is an aggregate, check every peer which has
    // announced a route in the aggregate and prevent the
    // redistribution
    if ((iRedistributionType != QOS_REDISTRIBUTE_NOT) &&
	(pAggrRoutes != NULL)) {
      for (iIndex2= 0; iIndex2 < ptr_array_length(pAggrRoutes); iIndex2++)
	if (((SRoute *) pAggrRoutes->data[iIndex2])->tNextHop ==
	    pPeer->tAddr) {
	  iRedistributionType= QOS_REDISTRIBUTE_NOT;
	  break;
	}
    }

    switch (iRedistributionType) {
    case QOS_REDISTRIBUTE_BEST:
      LOG_DEBUG("\tredistribution allowed to %d:", pPeer->uRemoteAS);
      LOG_ENABLED_DEBUG()
	ip_address_dump(log_get_stream(pMainLog), pPeer->tAddr);
      LOG_DEBUG("\n");
      qos_decision_process_disseminate_to_peer(pRouter, sPrefix, pRoute,
					       pPeer);
      break;
    case QOS_REDISTRIBUTE_EBGP:
      LOG_DEBUG("\tredistribution of eBGP allowed to %d:", pPeer->uRemoteAS);
      LOG_ENABLED_DEBUG()
	ip_address_dump(log_get_stream(pMainLog), pPeer->tAddr);
      LOG_DEBUG("\n");
      qos_decision_process_disseminate_to_peer(pRouter, sPrefix, pEBGPRoute,
					       pPeer);      
      break;
    default:
      LOG_DEBUG("\tredistribution refused to %d:", pPeer->uRemoteAS);
      LOG_ENABLED_DEBUG()
	ip_address_dump(log_get_stream(pMainLog), pPeer->tAddr);
      LOG_DEBUG("\n");
      qos_decision_process_disseminate_to_peer(pRouter, sPrefix, NULL,
					       pPeer);
    }
  }

  AS_LOG_DEBUG(pRouter, " < qos_decision_process_disseminate.end\n");

}
Exemplo n.º 5
0
/* Startup the server.  CTRL must have been allocated by the caller
   and set to the default values. */
int
gpg_server (ctrl_t ctrl)
{
  int rc;
  int filedes[2];
  assuan_context_t ctx = NULL;
  static const char hello[] = ("GNU Privacy Guard's OpenPGP server "
                               VERSION " ready");

  /* We use a pipe based server so that we can work from scripts.
     assuan_init_pipe_server will automagically detect when we are
     called with a socketpair and ignore FILEDES in this case.  */
  filedes[0] = assuan_fdopen (0);
  filedes[1] = assuan_fdopen (1);
  rc = assuan_new (&ctx);
  if (rc)
    {
      log_error ("failed to allocate the assuan context: %s\n",
		 gpg_strerror (rc));
      goto leave;
    }
  
  rc = assuan_init_pipe_server (ctx, filedes);
  if (rc)
    {
      log_error ("failed to initialize the server: %s\n", gpg_strerror (rc));
      goto leave;
    }

  rc = register_commands (ctx);
  if (rc)
    {
      log_error ("failed to the register commands with Assuan: %s\n",
                 gpg_strerror(rc));
      goto leave;
    }

  assuan_set_pointer (ctx, ctrl);
  if (opt.verbose || opt.debug)
    {
      char *tmp = NULL;
      const char *s1 = getenv ("GPG_AGENT_INFO");

      if (asprintf (&tmp,
                    "Home: %s\n"
                    "Config: %s\n"
                    "AgentInfo: %s\n"
                    "%s",
                    opt.homedir,
                    "fixme: need config filename",
                    s1?s1:"[not set]",
                    hello) > 0)
        {
          assuan_set_hello_line (ctx, tmp);
          free (tmp);
        }
    }
  else
    assuan_set_hello_line (ctx, hello);
  assuan_register_reset_notify (ctx, reset_notify);
  assuan_register_input_notify (ctx, input_notify);
  assuan_register_output_notify (ctx, output_notify);
  assuan_register_option_handler (ctx, option_handler);

  ctrl->server_local = xtrycalloc (1, sizeof *ctrl->server_local);
  if (!ctrl->server_local)
    {
      rc = gpg_error_from_syserror ();
      goto leave;
    }
  ctrl->server_local->assuan_ctx = ctx;
  ctrl->server_local->message_fd = GNUPG_INVALID_FD;

  if (DBG_ASSUAN)
    assuan_set_log_stream (ctx, log_get_stream ());

  for (;;)
    {
      rc = assuan_accept (ctx);
      if (rc == -1)
        {
          rc = 0;
          break;
        }
      else if (rc)
        {
          log_info ("Assuan accept problem: %s\n", gpg_strerror (rc));
          break;
        }
      
      rc = assuan_process (ctx);
      if (rc)
        {
          log_info ("Assuan processing failed: %s\n", gpg_strerror (rc));
          continue;
        }
    }

 leave:
  xfree (ctrl->server_local);
  ctrl->server_local = NULL;
  assuan_release (ctx);
  return rc;
}
Exemplo n.º 6
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;
}
Exemplo n.º 7
0
/* Create a new context for the card and figures out some basic
   information of the card.  Detects whether a PKCS_15 application is
   stored.

   Common errors: GPG_ERR_CARD_NOT_PRESENT */
int
card_open (CARD *rcard)
{
#ifdef HAVE_OPENSC
  CARD card;
  int rc;

  if (opt.disable_opensc)
    return gpg_error (GPG_ERR_NOT_SUPPORTED);

  card = xtrycalloc (1, sizeof *card);
  if (!card)
    return gpg_error (gpg_err_code_from_errno (errno));
  card->reader = 0;

  rc = sc_establish_context (&card->ctx, "scdaemon");
  if (rc)
    {
      log_error ("failed to establish SC context: %s\n", sc_strerror (rc));
      rc = map_sc_err (rc);
      goto leave;
    }
  if (card->reader >= card->ctx->reader_count)
    {
      log_error ("no card reader available\n");
      rc = gpg_error (GPG_ERR_CARD);
      goto leave;
    }
  card->ctx->error_file = log_get_stream ();
  card->ctx->debug = opt.debug_sc;
  card->ctx->debug_file = log_get_stream ();

  if (sc_detect_card_presence (card->ctx->reader[card->reader], 0) != 1)
    {
      rc = gpg_error (GPG_ERR_CARD_NOT_PRESENT);
      goto leave;
    }

  rc = sc_connect_card (card->ctx->reader[card->reader], 0, &card->scard);
  if (rc)
    {
      log_error ("failed to connect card in reader %d: %s\n",
                 card->reader, sc_strerror (rc));
      rc = map_sc_err (rc);
      goto leave;
    }
  if (opt.verbose)
    log_info ("connected to card in reader %d using driver '%s'\n",
              card->reader, card->scard->driver->name);

  rc = sc_lock (card->scard);
  if (rc)
    {
      log_error ("can't lock card in reader %d: %s\n",
                 card->reader, sc_strerror (rc));
      rc = map_sc_err (rc);
      goto leave;
    }


 leave:
  if (rc)
    card_close (card);
  else
    *rcard = card;

  return rc;
#else
  return gpg_error (GPG_ERR_NOT_SUPPORTED);
#endif
}