/**************** * 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 ); } }
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 (); } }
/** * 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; }
/** * 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"); }
/* 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; }
/* 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; }
/* 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 }