LCOV - code coverage report
Current view: top level - sm - call-dirmngr.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 428 0.0 %
Date: 2016-09-12 12:29:17 Functions: 0 24 0.0 %

          Line data    Source code
       1             : /* call-dirmngr.c - Communication with the dirmngr
       2             :  * Copyright (C) 2002, 2003, 2005, 2007, 2008,
       3             :  *               2010  Free Software Foundation, Inc.
       4             :  *
       5             :  * This file is part of GnuPG.
       6             :  *
       7             :  * GnuPG is free software; you can redistribute it and/or modify
       8             :  * it under the terms of the GNU General Public License as published by
       9             :  * the Free Software Foundation; either version 3 of the License, or
      10             :  * (at your option) any later version.
      11             :  *
      12             :  * GnuPG is distributed in the hope that it will be useful,
      13             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      14             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      15             :  * GNU General Public License for more details.
      16             :  *
      17             :  * You should have received a copy of the GNU General Public License
      18             :  * along with this program; if not, see <http://www.gnu.org/licenses/>.
      19             :  */
      20             : 
      21             : #include <config.h>
      22             : #include <stdio.h>
      23             : #include <stdlib.h>
      24             : #include <string.h>
      25             : #include <errno.h>
      26             : #include <unistd.h>
      27             : #include <time.h>
      28             : #include <assert.h>
      29             : #include <ctype.h>
      30             : 
      31             : #include "gpgsm.h"
      32             : #include <gcrypt.h>
      33             : #include <assuan.h>
      34             : 
      35             : #include "i18n.h"
      36             : #include "keydb.h"
      37             : #include "asshelp.h"
      38             : 
      39             : 
      40             : struct membuf {
      41             :   size_t len;
      42             :   size_t size;
      43             :   char *buf;
      44             :   int out_of_core;
      45             : };
      46             : 
      47             : 
      48             : 
      49             : /* fixme: We need a context for each thread or serialize the access to
      50             :    the dirmngr.  */
      51             : static assuan_context_t dirmngr_ctx = NULL;
      52             : static assuan_context_t dirmngr2_ctx = NULL;
      53             : 
      54             : static int dirmngr_ctx_locked;
      55             : static int dirmngr2_ctx_locked;
      56             : 
      57             : struct inq_certificate_parm_s {
      58             :   ctrl_t ctrl;
      59             :   assuan_context_t ctx;
      60             :   ksba_cert_t cert;
      61             :   ksba_cert_t issuer_cert;
      62             : };
      63             : 
      64             : struct isvalid_status_parm_s {
      65             :   ctrl_t ctrl;
      66             :   int seen;
      67             :   unsigned char fpr[20];
      68             : };
      69             : 
      70             : 
      71             : struct lookup_parm_s {
      72             :   ctrl_t ctrl;
      73             :   assuan_context_t ctx;
      74             :   void (*cb)(void *, ksba_cert_t);
      75             :   void *cb_value;
      76             :   struct membuf data;
      77             :   int error;
      78             : };
      79             : 
      80             : struct run_command_parm_s {
      81             :   assuan_context_t ctx;
      82             : };
      83             : 
      84             : 
      85             : 
      86             : static gpg_error_t get_cached_cert (assuan_context_t ctx,
      87             :                                     const unsigned char *fpr,
      88             :                                     ksba_cert_t *r_cert);
      89             : 
      90             : 
      91             : 
      92             : /* A simple implementation of a dynamic buffer.  Use init_membuf() to
      93             :    create a buffer, put_membuf to append bytes and get_membuf to
      94             :    release and return the buffer.  Allocation errors are detected but
      95             :    only returned at the final get_membuf(), this helps not to clutter
      96             :    the code with out of core checks.  */
      97             : 
      98             : static void
      99           0 : init_membuf (struct membuf *mb, int initiallen)
     100             : {
     101           0 :   mb->len = 0;
     102           0 :   mb->size = initiallen;
     103           0 :   mb->out_of_core = 0;
     104           0 :   mb->buf = xtrymalloc (initiallen);
     105           0 :   if (!mb->buf)
     106           0 :       mb->out_of_core = 1;
     107           0 : }
     108             : 
     109             : static void
     110           0 : put_membuf (struct membuf *mb, const void *buf, size_t len)
     111             : {
     112           0 :   if (mb->out_of_core)
     113           0 :     return;
     114             : 
     115           0 :   if (mb->len + len >= mb->size)
     116             :     {
     117             :       char *p;
     118             : 
     119           0 :       mb->size += len + 1024;
     120           0 :       p = xtryrealloc (mb->buf, mb->size);
     121           0 :       if (!p)
     122             :         {
     123           0 :           mb->out_of_core = 1;
     124           0 :           return;
     125             :         }
     126           0 :       mb->buf = p;
     127             :     }
     128           0 :   memcpy (mb->buf + mb->len, buf, len);
     129           0 :   mb->len += len;
     130             : }
     131             : 
     132             : static void *
     133           0 : get_membuf (struct membuf *mb, size_t *len)
     134             : {
     135             :   char *p;
     136             : 
     137           0 :   if (mb->out_of_core)
     138             :     {
     139           0 :       xfree (mb->buf);
     140           0 :       mb->buf = NULL;
     141           0 :       return NULL;
     142             :     }
     143             : 
     144           0 :   p = mb->buf;
     145           0 :   *len = mb->len;
     146           0 :   mb->buf = NULL;
     147           0 :   mb->out_of_core = 1; /* don't allow a reuse */
     148           0 :   return p;
     149             : }
     150             : 
     151             : 
     152             : /* Print a warning if the server's version number is less than our
     153             :    version number.  Returns an error code on a connection problem.  */
     154             : static gpg_error_t
     155           0 : warn_version_mismatch (ctrl_t ctrl, assuan_context_t ctx,
     156             :                        const char *servername, int mode)
     157             : {
     158             :   gpg_error_t err;
     159             :   char *serverversion;
     160           0 :   const char *myversion = strusage (13);
     161             : 
     162           0 :   err = get_assuan_server_version (ctx, mode, &serverversion);
     163           0 :   if (err)
     164           0 :     log_error (_("error getting version from '%s': %s\n"),
     165             :                servername, gpg_strerror (err));
     166           0 :   else if (!compare_version_strings (serverversion, myversion))
     167             :     {
     168             :       char *warn;
     169             : 
     170           0 :       warn = xtryasprintf (_("server '%s' is older than us (%s < %s)"),
     171             :                            servername, serverversion, myversion);
     172           0 :       if (!warn)
     173           0 :         err = gpg_error_from_syserror ();
     174             :       else
     175             :         {
     176           0 :           log_info (_("WARNING: %s\n"), warn);
     177           0 :           gpgsm_status2 (ctrl, STATUS_WARNING, "server_version_mismatch 0",
     178             :                          warn, NULL);
     179           0 :           xfree (warn);
     180             :         }
     181             :     }
     182           0 :   xfree (serverversion);
     183           0 :   return err;
     184             : }
     185             : 
     186             : 
     187             : /* This function prepares the dirmngr for a new session.  The
     188             :    audit-events option is used so that other dirmngr clients won't get
     189             :    disturbed by such events.  */
     190             : static void
     191           0 : prepare_dirmngr (ctrl_t ctrl, assuan_context_t ctx, gpg_error_t err)
     192             : {
     193             :   struct keyserver_spec *server;
     194             : 
     195           0 :   if (!err)
     196           0 :     err = warn_version_mismatch (ctrl, ctx, DIRMNGR_NAME, 0);
     197             : 
     198           0 :   if (!err)
     199             :     {
     200           0 :       err = assuan_transact (ctx, "OPTION audit-events=1",
     201             :                              NULL, NULL, NULL, NULL, NULL, NULL);
     202           0 :       if (gpg_err_code (err) == GPG_ERR_UNKNOWN_OPTION)
     203           0 :         err = 0;  /* Allow the use of old dirmngr versions.  */
     204             :     }
     205           0 :   audit_log_ok (ctrl->audit, AUDIT_DIRMNGR_READY, err);
     206             : 
     207           0 :   if (!ctx || err)
     208           0 :     return;
     209             : 
     210           0 :   server = opt.keyserver;
     211           0 :   while (server)
     212             :     {
     213             :       char line[ASSUAN_LINELENGTH];
     214           0 :       char *user = server->user ? server->user : "";
     215           0 :       char *pass = server->pass ? server->pass : "";
     216           0 :       char *base = server->base ? server->base : "";
     217             : 
     218           0 :       snprintf (line, DIM (line) - 1, "LDAPSERVER %s:%i:%s:%s:%s",
     219             :                 server->host, server->port, user, pass, base);
     220           0 :       line[DIM (line) - 1] = 0;
     221             : 
     222           0 :       assuan_transact (ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
     223             :       /* The code below is not required becuase we don't return an error.  */
     224             :       /* err = [above call]  */
     225             :       /* if (gpg_err_code (err) == GPG_ERR_ASS_UNKNOWN_CMD) */
     226             :       /*   err = 0;  /\* Allow the use of old dirmngr versions.  *\/ */
     227             : 
     228           0 :       server = server->next;
     229             :     }
     230             : }
     231             : 
     232             : 
     233             : 
     234             : /* Return a new assuan context for a Dirmngr connection.  */
     235             : static gpg_error_t
     236           0 : start_dirmngr_ext (ctrl_t ctrl, assuan_context_t *ctx_r)
     237             : {
     238             :   gpg_error_t err;
     239             :   assuan_context_t ctx;
     240             : 
     241           0 :   if (opt.disable_dirmngr || ctrl->offline)
     242           0 :     return gpg_error (GPG_ERR_NO_DIRMNGR);
     243             : 
     244           0 :   if (*ctx_r)
     245           0 :     return 0;
     246             : 
     247             :   /* Note: if you change this to multiple connections, you also need
     248             :      to take care of the implicit option sending caching. */
     249             : 
     250           0 :   err = start_new_dirmngr (&ctx, GPG_ERR_SOURCE_DEFAULT,
     251             :                            opt.dirmngr_program,
     252           0 :                            opt.autostart, opt.verbose, DBG_IPC,
     253             :                            gpgsm_status2, ctrl);
     254           0 :   if (!opt.autostart && gpg_err_code (err) == GPG_ERR_NO_DIRMNGR)
     255             :     {
     256             :       static int shown;
     257             : 
     258           0 :       if (!shown)
     259             :         {
     260           0 :           shown = 1;
     261           0 :           log_info (_("no dirmngr running in this session\n"));
     262             :         }
     263             :     }
     264           0 :   prepare_dirmngr (ctrl, ctx, err);
     265           0 :   if (err)
     266           0 :     return err;
     267             : 
     268           0 :   *ctx_r = ctx;
     269           0 :   return 0;
     270             : }
     271             : 
     272             : 
     273             : static int
     274           0 : start_dirmngr (ctrl_t ctrl)
     275             : {
     276             :   gpg_error_t err;
     277             : 
     278           0 :   assert (! dirmngr_ctx_locked);
     279           0 :   dirmngr_ctx_locked = 1;
     280             : 
     281           0 :   err = start_dirmngr_ext (ctrl, &dirmngr_ctx);
     282             :   /* We do not check ERR but the existence of a context because the
     283             :      error might come from a failed command send to the dirmngr.
     284             :      Fixme: Why don't we close the drimngr context if we encountered
     285             :      an error in prepare_dirmngr?  */
     286           0 :   if (!dirmngr_ctx)
     287           0 :     dirmngr_ctx_locked = 0;
     288           0 :   return err;
     289             : }
     290             : 
     291             : 
     292             : static void
     293           0 : release_dirmngr (ctrl_t ctrl)
     294             : {
     295             :   (void)ctrl;
     296             : 
     297           0 :   if (!dirmngr_ctx_locked)
     298           0 :     log_error ("WARNING: trying to release a non-locked dirmngr ctx\n");
     299           0 :   dirmngr_ctx_locked = 0;
     300           0 : }
     301             : 
     302             : 
     303             : static int
     304           0 : start_dirmngr2 (ctrl_t ctrl)
     305             : {
     306             :   gpg_error_t err;
     307             : 
     308           0 :   assert (! dirmngr2_ctx_locked);
     309           0 :   dirmngr2_ctx_locked = 1;
     310             : 
     311           0 :   err = start_dirmngr_ext (ctrl, &dirmngr2_ctx);
     312           0 :   if (!dirmngr2_ctx)
     313           0 :     dirmngr2_ctx_locked = 0;
     314           0 :   return err;
     315             : }
     316             : 
     317             : 
     318             : static void
     319           0 : release_dirmngr2 (ctrl_t ctrl)
     320             : {
     321             :   (void)ctrl;
     322             : 
     323           0 :   if (!dirmngr2_ctx_locked)
     324           0 :     log_error ("WARNING: trying to release a non-locked dirmngr2 ctx\n");
     325           0 :   dirmngr2_ctx_locked = 0;
     326           0 : }
     327             : 
     328             : 
     329             : 
     330             : /* Handle a SENDCERT inquiry. */
     331             : static gpg_error_t
     332           0 : inq_certificate (void *opaque, const char *line)
     333             : {
     334           0 :   struct inq_certificate_parm_s *parm = opaque;
     335             :   const char *s;
     336             :   int rc;
     337             :   size_t n;
     338             :   const unsigned char *der;
     339             :   size_t derlen;
     340           0 :   int issuer_mode = 0;
     341           0 :   ksba_sexp_t ski = NULL;
     342             : 
     343           0 :   if ((s = has_leading_keyword (line, "SENDCERT")))
     344             :     {
     345           0 :       line = s;
     346             :     }
     347           0 :   else if ((s = has_leading_keyword (line, "SENDCERT_SKI")))
     348             :     {
     349             :       /* Send a certificate where a sourceKeyIdentifier is included. */
     350           0 :       line = s;
     351           0 :       ski = make_simple_sexp_from_hexstr (line, &n);
     352           0 :       line += n;
     353           0 :       while (*line == ' ')
     354           0 :         line++;
     355             :     }
     356           0 :   else if ((s = has_leading_keyword (line, "SENDISSUERCERT")))
     357             :     {
     358           0 :       line = s;
     359           0 :       issuer_mode = 1;
     360             :     }
     361           0 :   else if ((s = has_leading_keyword (line, "ISTRUSTED")))
     362             :     {
     363             :       /* The server is asking us whether the certificate is a trusted
     364             :          root certificate.  */
     365             :       char fpr[41];
     366             :       struct rootca_flags_s rootca_flags;
     367             : 
     368           0 :       line = s;
     369             : 
     370           0 :       for (s=line,n=0; hexdigitp (s); s++, n++)
     371             :         ;
     372           0 :       if (*s || n != 40)
     373           0 :         return gpg_error (GPG_ERR_ASS_PARAMETER);
     374           0 :       for (s=line, n=0; n < 40; s++, n++)
     375           0 :         fpr[n] = (*s >= 'a')? (*s & 0xdf): *s;
     376           0 :       fpr[n] = 0;
     377             : 
     378           0 :       if (!gpgsm_agent_istrusted (parm->ctrl, NULL, fpr, &rootca_flags))
     379           0 :         rc = assuan_send_data (parm->ctx, "1", 1);
     380             :       else
     381           0 :         rc = 0;
     382           0 :       return rc;
     383             :     }
     384             :   else
     385             :     {
     386           0 :       log_error ("unsupported inquiry '%s'\n", line);
     387           0 :       return gpg_error (GPG_ERR_ASS_UNKNOWN_INQUIRE);
     388             :     }
     389             : 
     390           0 :   if (!*line)
     391             :     { /* Send the current certificate. */
     392           0 :       der = ksba_cert_get_image (issuer_mode? parm->issuer_cert : parm->cert,
     393             :                                  &derlen);
     394           0 :       if (!der)
     395           0 :         rc = gpg_error (GPG_ERR_INV_CERT_OBJ);
     396             :       else
     397           0 :         rc = assuan_send_data (parm->ctx, der, derlen);
     398             :     }
     399           0 :   else if (issuer_mode)
     400             :     {
     401           0 :       log_error ("sending specific issuer certificate back "
     402             :                  "is not yet implemented\n");
     403           0 :       rc = gpg_error (GPG_ERR_ASS_UNKNOWN_INQUIRE);
     404             :     }
     405             :   else
     406             :     { /* Send the given certificate. */
     407             :       int err;
     408             :       ksba_cert_t cert;
     409             : 
     410             : 
     411           0 :       err = gpgsm_find_cert (line, ski, &cert);
     412           0 :       if (err)
     413             :         {
     414           0 :           log_error ("certificate not found: %s\n", gpg_strerror (err));
     415           0 :           rc = gpg_error (GPG_ERR_NOT_FOUND);
     416             :         }
     417             :       else
     418             :         {
     419           0 :           der = ksba_cert_get_image (cert, &derlen);
     420           0 :           if (!der)
     421           0 :             rc = gpg_error (GPG_ERR_INV_CERT_OBJ);
     422             :           else
     423           0 :             rc = assuan_send_data (parm->ctx, der, derlen);
     424           0 :           ksba_cert_release (cert);
     425             :         }
     426             :     }
     427             : 
     428           0 :   xfree (ski);
     429           0 :   return rc;
     430             : }
     431             : 
     432             : 
     433             : /* Take a 20 byte hexencoded string and put it into the the provided
     434             :    20 byte buffer FPR in binary format. */
     435             : static int
     436           0 : unhexify_fpr (const char *hexstr, unsigned char *fpr)
     437             : {
     438             :   const char *s;
     439             :   int n;
     440             : 
     441           0 :   for (s=hexstr, n=0; hexdigitp (s); s++, n++)
     442             :     ;
     443           0 :   if (*s || (n != 40))
     444           0 :     return 0; /* no fingerprint (invalid or wrong length). */
     445           0 :   for (s=hexstr, n=0; *s; s += 2, n++)
     446           0 :     fpr[n] = xtoi_2 (s);
     447           0 :   return 1; /* okay */
     448             : }
     449             : 
     450             : 
     451             : static gpg_error_t
     452           0 : isvalid_status_cb (void *opaque, const char *line)
     453             : {
     454           0 :   struct isvalid_status_parm_s *parm = opaque;
     455             :   const char *s;
     456             : 
     457           0 :   if ((s = has_leading_keyword (line, "PROGRESS")))
     458             :     {
     459           0 :       if (parm->ctrl)
     460             :         {
     461           0 :           line = s;
     462           0 :           if (gpgsm_status (parm->ctrl, STATUS_PROGRESS, line))
     463           0 :             return gpg_error (GPG_ERR_ASS_CANCELED);
     464             :         }
     465             :     }
     466           0 :   else if ((s = has_leading_keyword (line, "ONLY_VALID_IF_CERT_VALID")))
     467             :     {
     468           0 :       parm->seen++;
     469           0 :       if (!*s || !unhexify_fpr (s, parm->fpr))
     470           0 :         parm->seen++; /* Bumb it to indicate an error. */
     471             :     }
     472           0 :   return 0;
     473             : }
     474             : 
     475             : 
     476             : 
     477             : 
     478             : /* Call the directory manager to check whether the certificate is valid
     479             :    Returns 0 for valid or usually one of the errors:
     480             : 
     481             :   GPG_ERR_CERTIFICATE_REVOKED
     482             :   GPG_ERR_NO_CRL_KNOWN
     483             :   GPG_ERR_CRL_TOO_OLD
     484             : 
     485             :   Values for USE_OCSP:
     486             :      0 = Do CRL check.
     487             :      1 = Do an OCSP check.
     488             :      2 = Do an OCSP check using only the default responder.
     489             :  */
     490             : int
     491           0 : gpgsm_dirmngr_isvalid (ctrl_t ctrl,
     492             :                        ksba_cert_t cert, ksba_cert_t issuer_cert, int use_ocsp)
     493             : {
     494             :   static int did_options;
     495             :   int rc;
     496             :   char *certid;
     497             :   char line[ASSUAN_LINELENGTH];
     498             :   struct inq_certificate_parm_s parm;
     499             :   struct isvalid_status_parm_s stparm;
     500             : 
     501           0 :   rc = start_dirmngr (ctrl);
     502           0 :   if (rc)
     503           0 :     return rc;
     504             : 
     505           0 :   if (use_ocsp)
     506             :     {
     507           0 :       certid = gpgsm_get_fingerprint_hexstring (cert, GCRY_MD_SHA1);
     508             :     }
     509             :   else
     510             :     {
     511           0 :       certid = gpgsm_get_certid (cert);
     512           0 :       if (!certid)
     513             :         {
     514           0 :           log_error ("error getting the certificate ID\n");
     515           0 :           release_dirmngr (ctrl);
     516           0 :           return gpg_error (GPG_ERR_GENERAL);
     517             :         }
     518             :     }
     519             : 
     520           0 :   if (opt.verbose > 1)
     521             :     {
     522           0 :       char *fpr = gpgsm_get_fingerprint_string (cert, GCRY_MD_SHA1);
     523           0 :       log_info ("asking dirmngr about %s%s\n", fpr,
     524             :                 use_ocsp? " (using OCSP)":"");
     525           0 :       xfree (fpr);
     526             :     }
     527             : 
     528           0 :   parm.ctx = dirmngr_ctx;
     529           0 :   parm.ctrl = ctrl;
     530           0 :   parm.cert = cert;
     531           0 :   parm.issuer_cert = issuer_cert;
     532             : 
     533           0 :   stparm.ctrl = ctrl;
     534           0 :   stparm.seen = 0;
     535           0 :   memset (stparm.fpr, 0, 20);
     536             : 
     537             :   /* FIXME: If --disable-crl-checks has been set, we should pass an
     538             :      option to dirmngr, so that no fallback CRL check is done after an
     539             :      ocsp check.  It is not a problem right now as dirmngr does not
     540             :      fallback to CRL checking.  */
     541             : 
     542             :   /* It is sufficient to send the options only once because we have
     543             :      one connection per process only. */
     544           0 :   if (!did_options)
     545             :     {
     546           0 :       if (opt.force_crl_refresh)
     547           0 :         assuan_transact (dirmngr_ctx, "OPTION force-crl-refresh=1",
     548             :                          NULL, NULL, NULL, NULL, NULL, NULL);
     549           0 :       did_options = 1;
     550             :     }
     551           0 :   snprintf (line, DIM(line)-1, "ISVALID%s %s",
     552             :             use_ocsp == 2? " --only-ocsp --force-default-responder":"",
     553             :             certid);
     554           0 :   line[DIM(line)-1] = 0;
     555           0 :   xfree (certid);
     556             : 
     557           0 :   rc = assuan_transact (dirmngr_ctx, line, NULL, NULL,
     558             :                         inq_certificate, &parm,
     559             :                         isvalid_status_cb, &stparm);
     560           0 :   if (opt.verbose > 1)
     561           0 :     log_info ("response of dirmngr: %s\n", rc? gpg_strerror (rc): "okay");
     562           0 :   rc = rc;
     563             : 
     564           0 :   if (!rc && stparm.seen)
     565             :     {
     566             :       /* Need to also check the certificate validity. */
     567           0 :       if (stparm.seen != 1)
     568             :         {
     569           0 :           log_error ("communication problem with dirmngr detected\n");
     570           0 :           rc = gpg_error (GPG_ERR_INV_CRL);
     571             :         }
     572             :       else
     573             :         {
     574           0 :           ksba_cert_t rspcert = NULL;
     575             : 
     576           0 :           if (get_cached_cert (dirmngr_ctx, stparm.fpr, &rspcert))
     577             :             {
     578             :               /* Ooops: Something went wrong getting the certificate
     579             :                  from the dirmngr.  Try our own cert store now.  */
     580             :               KEYDB_HANDLE kh;
     581             : 
     582           0 :               kh = keydb_new (0);
     583           0 :               if (!kh)
     584           0 :                 rc = gpg_error (GPG_ERR_ENOMEM);
     585           0 :               if (!rc)
     586           0 :                 rc = keydb_search_fpr (kh, stparm.fpr);
     587           0 :               if (!rc)
     588           0 :                 rc = keydb_get_cert (kh, &rspcert);
     589           0 :               if (rc)
     590             :                 {
     591           0 :                   log_error ("unable to find the certificate used "
     592             :                              "by the dirmngr: %s\n", gpg_strerror (rc));
     593           0 :                   rc = gpg_error (GPG_ERR_INV_CRL);
     594             :                 }
     595           0 :               keydb_release (kh);
     596             :             }
     597             : 
     598           0 :           if (!rc)
     599             :             {
     600           0 :               rc = gpgsm_cert_use_ocsp_p (rspcert);
     601           0 :               if (rc)
     602           0 :                 rc = gpg_error (GPG_ERR_INV_CRL);
     603             :               else
     604             :                 {
     605             :                   /* Note the no_dirmngr flag: This avoids checking
     606             :                      this certificate over and over again. */
     607           0 :                   rc = gpgsm_validate_chain (ctrl, rspcert, "", NULL, 0, NULL,
     608             :                                              VALIDATE_FLAG_NO_DIRMNGR, NULL);
     609           0 :                   if (rc)
     610             :                     {
     611           0 :                       log_error ("invalid certificate used for CRL/OCSP: %s\n",
     612             :                                  gpg_strerror (rc));
     613           0 :                       rc = gpg_error (GPG_ERR_INV_CRL);
     614             :                     }
     615             :                 }
     616             :             }
     617           0 :           ksba_cert_release (rspcert);
     618             :         }
     619             :     }
     620           0 :   release_dirmngr (ctrl);
     621           0 :   return rc;
     622             : }
     623             : 
     624             : 
     625             : 
     626             : /* Lookup helpers*/
     627             : static gpg_error_t
     628           0 : lookup_cb (void *opaque, const void *buffer, size_t length)
     629             : {
     630           0 :   struct lookup_parm_s *parm = opaque;
     631             :   size_t len;
     632             :   char *buf;
     633             :   ksba_cert_t cert;
     634             :   int rc;
     635             : 
     636           0 :   if (parm->error)
     637           0 :     return 0;
     638             : 
     639           0 :   if (buffer)
     640             :     {
     641           0 :       put_membuf (&parm->data, buffer, length);
     642           0 :       return 0;
     643             :     }
     644             :   /* END encountered - process what we have */
     645           0 :   buf = get_membuf (&parm->data, &len);
     646           0 :   if (!buf)
     647             :     {
     648           0 :       parm->error = gpg_error (GPG_ERR_ENOMEM);
     649           0 :       return 0;
     650             :     }
     651             : 
     652           0 :   rc = ksba_cert_new (&cert);
     653           0 :   if (rc)
     654             :     {
     655           0 :       parm->error = rc;
     656           0 :       return 0;
     657             :     }
     658           0 :   rc = ksba_cert_init_from_mem (cert, buf, len);
     659           0 :   if (rc)
     660             :     {
     661           0 :       log_error ("failed to parse a certificate: %s\n", gpg_strerror (rc));
     662             :     }
     663             :   else
     664             :     {
     665           0 :       parm->cb (parm->cb_value, cert);
     666             :     }
     667             : 
     668           0 :   ksba_cert_release (cert);
     669           0 :   init_membuf (&parm->data, 4096);
     670           0 :   return 0;
     671             : }
     672             : 
     673             : /* Return a properly escaped pattern from NAMES.  The only error
     674             :    return is NULL to indicate a malloc failure. */
     675             : static char *
     676           0 : pattern_from_strlist (strlist_t names)
     677             : {
     678             :   strlist_t sl;
     679             :   int n;
     680             :   const char *s;
     681             :   char *pattern, *p;
     682             : 
     683           0 :   for (n=0, sl=names; sl; sl = sl->next)
     684             :     {
     685           0 :       for (s=sl->d; *s; s++, n++)
     686             :         {
     687           0 :           if (*s == '%' || *s == ' ' || *s == '+')
     688           0 :             n += 2;
     689             :         }
     690           0 :       n++;
     691             :     }
     692             : 
     693           0 :   p = pattern = xtrymalloc (n+1);
     694           0 :   if (!pattern)
     695           0 :     return NULL;
     696             : 
     697           0 :   for (sl=names; sl; sl = sl->next)
     698             :     {
     699           0 :       for (s=sl->d; *s; s++)
     700             :         {
     701           0 :           switch (*s)
     702             :             {
     703             :             case '%':
     704           0 :               *p++ = '%';
     705           0 :               *p++ = '2';
     706           0 :               *p++ = '5';
     707           0 :               break;
     708             :             case ' ':
     709           0 :               *p++ = '%';
     710           0 :               *p++ = '2';
     711           0 :               *p++ = '0';
     712           0 :               break;
     713             :             case '+':
     714           0 :               *p++ = '%';
     715           0 :               *p++ = '2';
     716           0 :               *p++ = 'B';
     717           0 :               break;
     718             :             default:
     719           0 :               *p++ = *s;
     720           0 :               break;
     721             :             }
     722             :         }
     723           0 :       *p++ = ' ';
     724             :     }
     725           0 :   if (p == pattern)
     726           0 :     *pattern = 0; /* is empty */
     727             :   else
     728           0 :     p[-1] = '\0'; /* remove trailing blank */
     729             : 
     730           0 :   return pattern;
     731             : }
     732             : 
     733             : static gpg_error_t
     734           0 : lookup_status_cb (void *opaque, const char *line)
     735             : {
     736           0 :   struct lookup_parm_s *parm = opaque;
     737             :   const char *s;
     738             : 
     739           0 :   if ((s = has_leading_keyword (line, "PROGRESS")))
     740             :     {
     741           0 :       if (parm->ctrl)
     742             :         {
     743           0 :           line = s;
     744           0 :           if (gpgsm_status (parm->ctrl, STATUS_PROGRESS, line))
     745           0 :             return gpg_error (GPG_ERR_ASS_CANCELED);
     746             :         }
     747             :     }
     748           0 :   else if ((s = has_leading_keyword (line, "TRUNCATED")))
     749             :     {
     750           0 :       if (parm->ctrl)
     751             :         {
     752           0 :           line = s;
     753           0 :           gpgsm_status (parm->ctrl, STATUS_TRUNCATED, line);
     754             :         }
     755             :     }
     756           0 :   return 0;
     757             : }
     758             : 
     759             : 
     760             : /* Run the Directory Manager's lookup command using the pattern
     761             :    compiled from the strings given in NAMES.  The caller must provide
     762             :    the callback CB which will be passed cert by cert.  Note that CTRL
     763             :    is optional.  With CACHE_ONLY the dirmngr will search only its own
     764             :    key cache. */
     765             : int
     766           0 : gpgsm_dirmngr_lookup (ctrl_t ctrl, strlist_t names, int cache_only,
     767             :                       void (*cb)(void*, ksba_cert_t), void *cb_value)
     768             : {
     769             :   int rc;
     770             :   char *pattern;
     771             :   char line[ASSUAN_LINELENGTH];
     772             :   struct lookup_parm_s parm;
     773             :   size_t len;
     774             :   assuan_context_t ctx;
     775             : 
     776             :   /* The lookup function can be invoked from the callback of a lookup
     777             :      function, for example to walk the chain.  */
     778           0 :   if (!dirmngr_ctx_locked)
     779             :     {
     780           0 :       rc = start_dirmngr (ctrl);
     781           0 :       if (rc)
     782           0 :         return rc;
     783           0 :       ctx = dirmngr_ctx;
     784             :     }
     785           0 :   else if (!dirmngr2_ctx_locked)
     786             :     {
     787           0 :       rc = start_dirmngr2 (ctrl);
     788           0 :       if (rc)
     789           0 :         return rc;
     790           0 :       ctx = dirmngr2_ctx;
     791             :     }
     792             :   else
     793             :     {
     794           0 :       log_fatal ("both dirmngr contexts are in use\n");
     795             :     }
     796             : 
     797           0 :   pattern = pattern_from_strlist (names);
     798           0 :   if (!pattern)
     799             :     {
     800           0 :       if (ctx == dirmngr_ctx)
     801           0 :         release_dirmngr (ctrl);
     802             :       else
     803           0 :         release_dirmngr2 (ctrl);
     804             : 
     805           0 :       return out_of_core ();
     806             :     }
     807           0 :   snprintf (line, DIM(line)-1, "LOOKUP%s %s",
     808             :             cache_only? " --cache-only":"", pattern);
     809           0 :   line[DIM(line)-1] = 0;
     810           0 :   xfree (pattern);
     811             : 
     812           0 :   parm.ctrl = ctrl;
     813           0 :   parm.ctx = ctx;
     814           0 :   parm.cb = cb;
     815           0 :   parm.cb_value = cb_value;
     816           0 :   parm.error = 0;
     817           0 :   init_membuf (&parm.data, 4096);
     818             : 
     819           0 :   rc = assuan_transact (ctx, line, lookup_cb, &parm,
     820             :                         NULL, NULL, lookup_status_cb, &parm);
     821           0 :   xfree (get_membuf (&parm.data, &len));
     822             : 
     823           0 :   if (ctx == dirmngr_ctx)
     824           0 :     release_dirmngr (ctrl);
     825             :   else
     826           0 :     release_dirmngr2 (ctrl);
     827             : 
     828           0 :   if (rc)
     829           0 :       return rc;
     830           0 :   return parm.error;
     831             : }
     832             : 
     833             : 
     834             : 
     835             : static gpg_error_t
     836           0 : get_cached_cert_data_cb (void *opaque, const void *buffer, size_t length)
     837             : {
     838           0 :   struct membuf *mb = opaque;
     839             : 
     840           0 :   if (buffer)
     841           0 :     put_membuf (mb, buffer, length);
     842           0 :   return 0;
     843             : }
     844             : 
     845             : /* Return a certificate from the Directory Manager's cache.  This
     846             :    function only returns one certificate which must be specified using
     847             :    the fingerprint FPR and will be stored at R_CERT.  On error NULL is
     848             :    stored at R_CERT and an error code returned.  Note that the caller
     849             :    must provide the locked dirmngr context CTX. */
     850             : static gpg_error_t
     851           0 : get_cached_cert (assuan_context_t ctx,
     852             :                  const unsigned char *fpr, ksba_cert_t *r_cert)
     853             : {
     854             :   gpg_error_t err;
     855             :   char line[ASSUAN_LINELENGTH];
     856             :   char hexfpr[2*20+1];
     857             :   struct membuf mb;
     858             :   char *buf;
     859           0 :   size_t buflen = 0;
     860             :   ksba_cert_t cert;
     861             : 
     862           0 :   *r_cert = NULL;
     863             : 
     864           0 :   bin2hex (fpr, 20, hexfpr);
     865           0 :   snprintf (line, DIM(line)-1, "LOOKUP --single --cache-only 0x%s", hexfpr);
     866             : 
     867           0 :   init_membuf (&mb, 4096);
     868           0 :   err = assuan_transact (ctx, line, get_cached_cert_data_cb, &mb,
     869             :                          NULL, NULL, NULL, NULL);
     870           0 :   buf = get_membuf (&mb, &buflen);
     871           0 :   if (err)
     872             :     {
     873           0 :       xfree (buf);
     874           0 :       return err;
     875             :     }
     876           0 :   if (!buf)
     877           0 :     return gpg_error (GPG_ERR_ENOMEM);
     878             : 
     879           0 :   err = ksba_cert_new (&cert);
     880           0 :   if (err)
     881             :     {
     882           0 :       xfree (buf);
     883           0 :       return err;
     884             :     }
     885           0 :   err = ksba_cert_init_from_mem (cert, buf, buflen);
     886           0 :   xfree (buf);
     887           0 :   if (err)
     888             :     {
     889           0 :       log_error ("failed to parse a certificate: %s\n", gpg_strerror (err));
     890           0 :       ksba_cert_release (cert);
     891           0 :       return err;
     892             :     }
     893             : 
     894           0 :   *r_cert = cert;
     895           0 :   return 0;
     896             : }
     897             : 
     898             : 
     899             : 
     900             : /* Run Command helpers*/
     901             : 
     902             : /* Fairly simple callback to write all output of dirmngr to stdout. */
     903             : static gpg_error_t
     904           0 : run_command_cb (void *opaque, const void *buffer, size_t length)
     905             : {
     906             :   (void)opaque;
     907             : 
     908           0 :   if (buffer)
     909             :     {
     910           0 :       if ( fwrite (buffer, length, 1, stdout) != 1 )
     911           0 :         log_error ("error writing to stdout: %s\n", strerror (errno));
     912             :     }
     913           0 :   return 0;
     914             : }
     915             : 
     916             : /* Handle inquiries from the dirmngr COMMAND. */
     917             : static gpg_error_t
     918           0 : run_command_inq_cb (void *opaque, const char *line)
     919             : {
     920           0 :   struct run_command_parm_s *parm = opaque;
     921             :   const char *s;
     922           0 :   int rc = 0;
     923             : 
     924           0 :   if ((s = has_leading_keyword (line, "SENDCERT")))
     925             :     { /* send the given certificate */
     926             :       int err;
     927             :       ksba_cert_t cert;
     928             :       const unsigned char *der;
     929             :       size_t derlen;
     930             : 
     931           0 :       line = s;
     932           0 :       if (!*line)
     933           0 :         return gpg_error (GPG_ERR_ASS_PARAMETER);
     934             : 
     935           0 :       err = gpgsm_find_cert (line, NULL, &cert);
     936           0 :       if (err)
     937             :         {
     938           0 :           log_error ("certificate not found: %s\n", gpg_strerror (err));
     939           0 :           rc = gpg_error (GPG_ERR_NOT_FOUND);
     940             :         }
     941             :       else
     942             :         {
     943           0 :           der = ksba_cert_get_image (cert, &derlen);
     944           0 :           if (!der)
     945           0 :             rc = gpg_error (GPG_ERR_INV_CERT_OBJ);
     946             :           else
     947           0 :             rc = assuan_send_data (parm->ctx, der, derlen);
     948           0 :           ksba_cert_release (cert);
     949             :         }
     950             :     }
     951           0 :   else if ((s = has_leading_keyword (line, "PRINTINFO")))
     952             :     { /* Simply show the message given in the argument. */
     953           0 :       line = s;
     954           0 :       log_info ("dirmngr: %s\n", line);
     955             :     }
     956             :   else
     957             :     {
     958           0 :       log_error ("unsupported inquiry '%s'\n", line);
     959           0 :       rc = gpg_error (GPG_ERR_ASS_UNKNOWN_INQUIRE);
     960             :     }
     961             : 
     962           0 :   return rc;
     963             : }
     964             : 
     965             : static gpg_error_t
     966           0 : run_command_status_cb (void *opaque, const char *line)
     967             : {
     968           0 :   ctrl_t ctrl = opaque;
     969             :   const char *s;
     970             : 
     971           0 :   if (opt.verbose)
     972             :     {
     973           0 :       log_info ("dirmngr status: %s\n", line);
     974             :     }
     975           0 :   if ((s = has_leading_keyword (line, "PROGRESS")))
     976             :     {
     977           0 :       if (ctrl)
     978             :         {
     979           0 :           line = s;
     980           0 :           if (gpgsm_status (ctrl, STATUS_PROGRESS, line))
     981           0 :             return gpg_error (GPG_ERR_ASS_CANCELED);
     982             :         }
     983             :     }
     984           0 :   return 0;
     985             : }
     986             : 
     987             : 
     988             : 
     989             : /* Pass COMMAND to dirmngr and print all output generated by Dirmngr
     990             :    to stdout.  A couple of inquiries are defined (see above).  ARGC
     991             :    arguments in ARGV are given to the Dirmngr.  Spaces, plus and
     992             :    percent characters within the argument strings are percent escaped
     993             :    so that blanks can act as delimiters. */
     994             : int
     995           0 : gpgsm_dirmngr_run_command (ctrl_t ctrl, const char *command,
     996             :                            int argc, char **argv)
     997             : {
     998             :   int rc;
     999             :   int i;
    1000             :   const char *s;
    1001             :   char *line, *p;
    1002             :   size_t len;
    1003             :   struct run_command_parm_s parm;
    1004             : 
    1005           0 :   rc = start_dirmngr (ctrl);
    1006           0 :   if (rc)
    1007           0 :     return rc;
    1008             : 
    1009           0 :   parm.ctx = dirmngr_ctx;
    1010             : 
    1011           0 :   len = strlen (command) + 1;
    1012           0 :   for (i=0; i < argc; i++)
    1013           0 :     len += 1 + 3*strlen (argv[i]); /* enough space for percent escaping */
    1014           0 :   line = xtrymalloc (len);
    1015           0 :   if (!line)
    1016             :     {
    1017           0 :       release_dirmngr (ctrl);
    1018           0 :       return out_of_core ();
    1019             :     }
    1020             : 
    1021           0 :   p = stpcpy (line, command);
    1022           0 :   for (i=0; i < argc; i++)
    1023             :     {
    1024           0 :       *p++ = ' ';
    1025           0 :       for (s=argv[i]; *s; s++)
    1026             :         {
    1027           0 :           if (!isascii (*s))
    1028           0 :             *p++ = *s;
    1029           0 :           else if (*s == ' ')
    1030           0 :             *p++ = '+';
    1031           0 :           else if (!isprint (*s) || *s == '+')
    1032             :             {
    1033           0 :               sprintf (p, "%%%02X", *(const unsigned char *)s);
    1034           0 :               p += 3;
    1035             :             }
    1036             :           else
    1037           0 :             *p++ = *s;
    1038             :         }
    1039             :     }
    1040           0 :   *p = 0;
    1041             : 
    1042           0 :   rc = assuan_transact (dirmngr_ctx, line,
    1043             :                         run_command_cb, NULL,
    1044             :                         run_command_inq_cb, &parm,
    1045             :                         run_command_status_cb, ctrl);
    1046           0 :   xfree (line);
    1047           0 :   log_info ("response of dirmngr: %s\n", rc? gpg_strerror (rc): "okay");
    1048           0 :   release_dirmngr (ctrl);
    1049           0 :   return rc;
    1050             : }

Generated by: LCOV version 1.11