LCOV - code coverage report
Current view: top level - sm - call-dirmngr.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 425 0.0 %
Date: 2016-12-01 18:37:21 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 <https://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             :   ctrl_t ctrl;
      82             :   assuan_context_t ctx;
      83             : };
      84             : 
      85             : 
      86             : 
      87             : static gpg_error_t get_cached_cert (assuan_context_t ctx,
      88             :                                     const unsigned char *fpr,
      89             :                                     ksba_cert_t *r_cert);
      90             : 
      91             : 
      92             : 
      93             : /* A simple implementation of a dynamic buffer.  Use init_membuf() to
      94             :    create a buffer, put_membuf to append bytes and get_membuf to
      95             :    release and return the buffer.  Allocation errors are detected but
      96             :    only returned at the final get_membuf(), this helps not to clutter
      97             :    the code with out of core checks.  */
      98             : 
      99             : static void
     100           0 : init_membuf (struct membuf *mb, int initiallen)
     101             : {
     102           0 :   mb->len = 0;
     103           0 :   mb->size = initiallen;
     104           0 :   mb->out_of_core = 0;
     105           0 :   mb->buf = xtrymalloc (initiallen);
     106           0 :   if (!mb->buf)
     107           0 :       mb->out_of_core = 1;
     108           0 : }
     109             : 
     110             : static void
     111           0 : put_membuf (struct membuf *mb, const void *buf, size_t len)
     112             : {
     113           0 :   if (mb->out_of_core)
     114           0 :     return;
     115             : 
     116           0 :   if (mb->len + len >= mb->size)
     117             :     {
     118             :       char *p;
     119             : 
     120           0 :       mb->size += len + 1024;
     121           0 :       p = xtryrealloc (mb->buf, mb->size);
     122           0 :       if (!p)
     123             :         {
     124           0 :           mb->out_of_core = 1;
     125           0 :           return;
     126             :         }
     127           0 :       mb->buf = p;
     128             :     }
     129           0 :   memcpy (mb->buf + mb->len, buf, len);
     130           0 :   mb->len += len;
     131             : }
     132             : 
     133             : static void *
     134           0 : get_membuf (struct membuf *mb, size_t *len)
     135             : {
     136             :   char *p;
     137             : 
     138           0 :   if (mb->out_of_core)
     139             :     {
     140           0 :       xfree (mb->buf);
     141           0 :       mb->buf = NULL;
     142           0 :       return NULL;
     143             :     }
     144             : 
     145           0 :   p = mb->buf;
     146           0 :   *len = mb->len;
     147           0 :   mb->buf = NULL;
     148           0 :   mb->out_of_core = 1; /* don't allow a reuse */
     149           0 :   return p;
     150             : }
     151             : 
     152             : 
     153             : /* Print a warning if the server's version number is less than our
     154             :    version number.  Returns an error code on a connection problem.  */
     155             : static gpg_error_t
     156           0 : warn_version_mismatch (ctrl_t ctrl, assuan_context_t ctx,
     157             :                        const char *servername, int mode)
     158             : {
     159             :   gpg_error_t err;
     160             :   char *serverversion;
     161           0 :   const char *myversion = strusage (13);
     162             : 
     163           0 :   err = get_assuan_server_version (ctx, mode, &serverversion);
     164           0 :   if (err)
     165           0 :     log_error (_("error getting version from '%s': %s\n"),
     166             :                servername, gpg_strerror (err));
     167           0 :   else if (compare_version_strings (serverversion, myversion) < 0)
     168             :     {
     169             :       char *warn;
     170             : 
     171           0 :       warn = xtryasprintf (_("server '%s' is older than us (%s < %s)"),
     172             :                            servername, serverversion, myversion);
     173           0 :       if (!warn)
     174           0 :         err = gpg_error_from_syserror ();
     175             :       else
     176             :         {
     177           0 :           log_info (_("WARNING: %s\n"), warn);
     178           0 :           gpgsm_status2 (ctrl, STATUS_WARNING, "server_version_mismatch 0",
     179             :                          warn, NULL);
     180           0 :           xfree (warn);
     181             :         }
     182             :     }
     183           0 :   xfree (serverversion);
     184           0 :   return err;
     185             : }
     186             : 
     187             : 
     188             : /* This function prepares the dirmngr for a new session.  The
     189             :    audit-events option is used so that other dirmngr clients won't get
     190             :    disturbed by such events.  */
     191             : static void
     192           0 : prepare_dirmngr (ctrl_t ctrl, assuan_context_t ctx, gpg_error_t err)
     193             : {
     194             :   struct keyserver_spec *server;
     195             : 
     196           0 :   if (!err)
     197           0 :     err = warn_version_mismatch (ctrl, ctx, DIRMNGR_NAME, 0);
     198             : 
     199           0 :   if (!err)
     200             :     {
     201           0 :       err = assuan_transact (ctx, "OPTION audit-events=1",
     202             :                              NULL, NULL, NULL, NULL, NULL, NULL);
     203           0 :       if (gpg_err_code (err) == GPG_ERR_UNKNOWN_OPTION)
     204           0 :         err = 0;  /* Allow the use of old dirmngr versions.  */
     205             :     }
     206           0 :   audit_log_ok (ctrl->audit, AUDIT_DIRMNGR_READY, err);
     207             : 
     208           0 :   if (!ctx || err)
     209           0 :     return;
     210             : 
     211           0 :   server = opt.keyserver;
     212           0 :   while (server)
     213             :     {
     214             :       char line[ASSUAN_LINELENGTH];
     215           0 :       char *user = server->user ? server->user : "";
     216           0 :       char *pass = server->pass ? server->pass : "";
     217           0 :       char *base = server->base ? server->base : "";
     218             : 
     219           0 :       snprintf (line, DIM (line), "LDAPSERVER %s:%i:%s:%s:%s",
     220             :                 server->host, server->port, user, pass, base);
     221             : 
     222           0 :       assuan_transact (ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
     223             :       /* The code below is not required because 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 (parm->ctrl, 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), "ISVALID%s %s",
     552             :             use_ocsp == 2? " --only-ocsp --force-default-responder":"",
     553             :             certid);
     554           0 :   xfree (certid);
     555             : 
     556           0 :   rc = assuan_transact (dirmngr_ctx, line, NULL, NULL,
     557             :                         inq_certificate, &parm,
     558             :                         isvalid_status_cb, &stparm);
     559           0 :   if (opt.verbose > 1)
     560           0 :     log_info ("response of dirmngr: %s\n", rc? gpg_strerror (rc): "okay");
     561             : 
     562           0 :   if (!rc && stparm.seen)
     563             :     {
     564             :       /* Need to also check the certificate validity. */
     565           0 :       if (stparm.seen != 1)
     566             :         {
     567           0 :           log_error ("communication problem with dirmngr detected\n");
     568           0 :           rc = gpg_error (GPG_ERR_INV_CRL);
     569             :         }
     570             :       else
     571             :         {
     572           0 :           ksba_cert_t rspcert = NULL;
     573             : 
     574           0 :           if (get_cached_cert (dirmngr_ctx, stparm.fpr, &rspcert))
     575             :             {
     576             :               /* Ooops: Something went wrong getting the certificate
     577             :                  from the dirmngr.  Try our own cert store now.  */
     578             :               KEYDB_HANDLE kh;
     579             : 
     580           0 :               kh = keydb_new ();
     581           0 :               if (!kh)
     582           0 :                 rc = gpg_error (GPG_ERR_ENOMEM);
     583           0 :               if (!rc)
     584           0 :                 rc = keydb_search_fpr (ctrl, kh, stparm.fpr);
     585           0 :               if (!rc)
     586           0 :                 rc = keydb_get_cert (kh, &rspcert);
     587           0 :               if (rc)
     588             :                 {
     589           0 :                   log_error ("unable to find the certificate used "
     590             :                              "by the dirmngr: %s\n", gpg_strerror (rc));
     591           0 :                   rc = gpg_error (GPG_ERR_INV_CRL);
     592             :                 }
     593           0 :               keydb_release (kh);
     594             :             }
     595             : 
     596           0 :           if (!rc)
     597             :             {
     598           0 :               rc = gpgsm_cert_use_ocsp_p (rspcert);
     599           0 :               if (rc)
     600           0 :                 rc = gpg_error (GPG_ERR_INV_CRL);
     601             :               else
     602             :                 {
     603             :                   /* Note the no_dirmngr flag: This avoids checking
     604             :                      this certificate over and over again. */
     605           0 :                   rc = gpgsm_validate_chain (ctrl, rspcert, "", NULL, 0, NULL,
     606             :                                              VALIDATE_FLAG_NO_DIRMNGR, NULL);
     607           0 :                   if (rc)
     608             :                     {
     609           0 :                       log_error ("invalid certificate used for CRL/OCSP: %s\n",
     610             :                                  gpg_strerror (rc));
     611           0 :                       rc = gpg_error (GPG_ERR_INV_CRL);
     612             :                     }
     613             :                 }
     614             :             }
     615           0 :           ksba_cert_release (rspcert);
     616             :         }
     617             :     }
     618           0 :   release_dirmngr (ctrl);
     619           0 :   return rc;
     620             : }
     621             : 
     622             : 
     623             : 
     624             : /* Lookup helpers*/
     625             : static gpg_error_t
     626           0 : lookup_cb (void *opaque, const void *buffer, size_t length)
     627             : {
     628           0 :   struct lookup_parm_s *parm = opaque;
     629             :   size_t len;
     630             :   char *buf;
     631             :   ksba_cert_t cert;
     632             :   int rc;
     633             : 
     634           0 :   if (parm->error)
     635           0 :     return 0;
     636             : 
     637           0 :   if (buffer)
     638             :     {
     639           0 :       put_membuf (&parm->data, buffer, length);
     640           0 :       return 0;
     641             :     }
     642             :   /* END encountered - process what we have */
     643           0 :   buf = get_membuf (&parm->data, &len);
     644           0 :   if (!buf)
     645             :     {
     646           0 :       parm->error = gpg_error (GPG_ERR_ENOMEM);
     647           0 :       return 0;
     648             :     }
     649             : 
     650           0 :   rc = ksba_cert_new (&cert);
     651           0 :   if (rc)
     652             :     {
     653           0 :       parm->error = rc;
     654           0 :       return 0;
     655             :     }
     656           0 :   rc = ksba_cert_init_from_mem (cert, buf, len);
     657           0 :   if (rc)
     658             :     {
     659           0 :       log_error ("failed to parse a certificate: %s\n", gpg_strerror (rc));
     660             :     }
     661             :   else
     662             :     {
     663           0 :       parm->cb (parm->cb_value, cert);
     664             :     }
     665             : 
     666           0 :   ksba_cert_release (cert);
     667           0 :   init_membuf (&parm->data, 4096);
     668           0 :   return 0;
     669             : }
     670             : 
     671             : /* Return a properly escaped pattern from NAMES.  The only error
     672             :    return is NULL to indicate a malloc failure. */
     673             : static char *
     674           0 : pattern_from_strlist (strlist_t names)
     675             : {
     676             :   strlist_t sl;
     677             :   int n;
     678             :   const char *s;
     679             :   char *pattern, *p;
     680             : 
     681           0 :   for (n=0, sl=names; sl; sl = sl->next)
     682             :     {
     683           0 :       for (s=sl->d; *s; s++, n++)
     684             :         {
     685           0 :           if (*s == '%' || *s == ' ' || *s == '+')
     686           0 :             n += 2;
     687             :         }
     688           0 :       n++;
     689             :     }
     690             : 
     691           0 :   p = pattern = xtrymalloc (n+1);
     692           0 :   if (!pattern)
     693           0 :     return NULL;
     694             : 
     695           0 :   for (sl=names; sl; sl = sl->next)
     696             :     {
     697           0 :       for (s=sl->d; *s; s++)
     698             :         {
     699           0 :           switch (*s)
     700             :             {
     701             :             case '%':
     702           0 :               *p++ = '%';
     703           0 :               *p++ = '2';
     704           0 :               *p++ = '5';
     705           0 :               break;
     706             :             case ' ':
     707           0 :               *p++ = '%';
     708           0 :               *p++ = '2';
     709           0 :               *p++ = '0';
     710           0 :               break;
     711             :             case '+':
     712           0 :               *p++ = '%';
     713           0 :               *p++ = '2';
     714           0 :               *p++ = 'B';
     715           0 :               break;
     716             :             default:
     717           0 :               *p++ = *s;
     718           0 :               break;
     719             :             }
     720             :         }
     721           0 :       *p++ = ' ';
     722             :     }
     723           0 :   if (p == pattern)
     724           0 :     *pattern = 0; /* is empty */
     725             :   else
     726           0 :     p[-1] = '\0'; /* remove trailing blank */
     727             : 
     728           0 :   return pattern;
     729             : }
     730             : 
     731             : static gpg_error_t
     732           0 : lookup_status_cb (void *opaque, const char *line)
     733             : {
     734           0 :   struct lookup_parm_s *parm = opaque;
     735             :   const char *s;
     736             : 
     737           0 :   if ((s = has_leading_keyword (line, "PROGRESS")))
     738             :     {
     739           0 :       if (parm->ctrl)
     740             :         {
     741           0 :           line = s;
     742           0 :           if (gpgsm_status (parm->ctrl, STATUS_PROGRESS, line))
     743           0 :             return gpg_error (GPG_ERR_ASS_CANCELED);
     744             :         }
     745             :     }
     746           0 :   else if ((s = has_leading_keyword (line, "TRUNCATED")))
     747             :     {
     748           0 :       if (parm->ctrl)
     749             :         {
     750           0 :           line = s;
     751           0 :           gpgsm_status (parm->ctrl, STATUS_TRUNCATED, line);
     752             :         }
     753             :     }
     754           0 :   return 0;
     755             : }
     756             : 
     757             : 
     758             : /* Run the Directory Manager's lookup command using the pattern
     759             :    compiled from the strings given in NAMES.  The caller must provide
     760             :    the callback CB which will be passed cert by cert.  Note that CTRL
     761             :    is optional.  With CACHE_ONLY the dirmngr will search only its own
     762             :    key cache. */
     763             : int
     764           0 : gpgsm_dirmngr_lookup (ctrl_t ctrl, strlist_t names, int cache_only,
     765             :                       void (*cb)(void*, ksba_cert_t), void *cb_value)
     766             : {
     767             :   int rc;
     768             :   char *pattern;
     769             :   char line[ASSUAN_LINELENGTH];
     770             :   struct lookup_parm_s parm;
     771             :   size_t len;
     772             :   assuan_context_t ctx;
     773             : 
     774             :   /* The lookup function can be invoked from the callback of a lookup
     775             :      function, for example to walk the chain.  */
     776           0 :   if (!dirmngr_ctx_locked)
     777             :     {
     778           0 :       rc = start_dirmngr (ctrl);
     779           0 :       if (rc)
     780           0 :         return rc;
     781           0 :       ctx = dirmngr_ctx;
     782             :     }
     783           0 :   else if (!dirmngr2_ctx_locked)
     784             :     {
     785           0 :       rc = start_dirmngr2 (ctrl);
     786           0 :       if (rc)
     787           0 :         return rc;
     788           0 :       ctx = dirmngr2_ctx;
     789             :     }
     790             :   else
     791             :     {
     792           0 :       log_fatal ("both dirmngr contexts are in use\n");
     793             :     }
     794             : 
     795           0 :   pattern = pattern_from_strlist (names);
     796           0 :   if (!pattern)
     797             :     {
     798           0 :       if (ctx == dirmngr_ctx)
     799           0 :         release_dirmngr (ctrl);
     800             :       else
     801           0 :         release_dirmngr2 (ctrl);
     802             : 
     803           0 :       return out_of_core ();
     804             :     }
     805           0 :   snprintf (line, DIM(line), "LOOKUP%s %s",
     806             :             cache_only? " --cache-only":"", pattern);
     807           0 :   xfree (pattern);
     808             : 
     809           0 :   parm.ctrl = ctrl;
     810           0 :   parm.ctx = ctx;
     811           0 :   parm.cb = cb;
     812           0 :   parm.cb_value = cb_value;
     813           0 :   parm.error = 0;
     814           0 :   init_membuf (&parm.data, 4096);
     815             : 
     816           0 :   rc = assuan_transact (ctx, line, lookup_cb, &parm,
     817             :                         NULL, NULL, lookup_status_cb, &parm);
     818           0 :   xfree (get_membuf (&parm.data, &len));
     819             : 
     820           0 :   if (ctx == dirmngr_ctx)
     821           0 :     release_dirmngr (ctrl);
     822             :   else
     823           0 :     release_dirmngr2 (ctrl);
     824             : 
     825           0 :   if (rc)
     826           0 :       return rc;
     827           0 :   return parm.error;
     828             : }
     829             : 
     830             : 
     831             : 
     832             : static gpg_error_t
     833           0 : get_cached_cert_data_cb (void *opaque, const void *buffer, size_t length)
     834             : {
     835           0 :   struct membuf *mb = opaque;
     836             : 
     837           0 :   if (buffer)
     838           0 :     put_membuf (mb, buffer, length);
     839           0 :   return 0;
     840             : }
     841             : 
     842             : /* Return a certificate from the Directory Manager's cache.  This
     843             :    function only returns one certificate which must be specified using
     844             :    the fingerprint FPR and will be stored at R_CERT.  On error NULL is
     845             :    stored at R_CERT and an error code returned.  Note that the caller
     846             :    must provide the locked dirmngr context CTX. */
     847             : static gpg_error_t
     848           0 : get_cached_cert (assuan_context_t ctx,
     849             :                  const unsigned char *fpr, ksba_cert_t *r_cert)
     850             : {
     851             :   gpg_error_t err;
     852             :   char line[ASSUAN_LINELENGTH];
     853             :   char hexfpr[2*20+1];
     854             :   struct membuf mb;
     855             :   char *buf;
     856           0 :   size_t buflen = 0;
     857             :   ksba_cert_t cert;
     858             : 
     859           0 :   *r_cert = NULL;
     860             : 
     861           0 :   bin2hex (fpr, 20, hexfpr);
     862           0 :   snprintf (line, DIM(line), "LOOKUP --single --cache-only 0x%s", hexfpr);
     863             : 
     864           0 :   init_membuf (&mb, 4096);
     865           0 :   err = assuan_transact (ctx, line, get_cached_cert_data_cb, &mb,
     866             :                          NULL, NULL, NULL, NULL);
     867           0 :   buf = get_membuf (&mb, &buflen);
     868           0 :   if (err)
     869             :     {
     870           0 :       xfree (buf);
     871           0 :       return err;
     872             :     }
     873           0 :   if (!buf)
     874           0 :     return gpg_error (GPG_ERR_ENOMEM);
     875             : 
     876           0 :   err = ksba_cert_new (&cert);
     877           0 :   if (err)
     878             :     {
     879           0 :       xfree (buf);
     880           0 :       return err;
     881             :     }
     882           0 :   err = ksba_cert_init_from_mem (cert, buf, buflen);
     883           0 :   xfree (buf);
     884           0 :   if (err)
     885             :     {
     886           0 :       log_error ("failed to parse a certificate: %s\n", gpg_strerror (err));
     887           0 :       ksba_cert_release (cert);
     888           0 :       return err;
     889             :     }
     890             : 
     891           0 :   *r_cert = cert;
     892           0 :   return 0;
     893             : }
     894             : 
     895             : 
     896             : 
     897             : /* Run Command helpers*/
     898             : 
     899             : /* Fairly simple callback to write all output of dirmngr to stdout. */
     900             : static gpg_error_t
     901           0 : run_command_cb (void *opaque, const void *buffer, size_t length)
     902             : {
     903             :   (void)opaque;
     904             : 
     905           0 :   if (buffer)
     906             :     {
     907           0 :       if ( fwrite (buffer, length, 1, stdout) != 1 )
     908           0 :         log_error ("error writing to stdout: %s\n", strerror (errno));
     909             :     }
     910           0 :   return 0;
     911             : }
     912             : 
     913             : /* Handle inquiries from the dirmngr COMMAND. */
     914             : static gpg_error_t
     915           0 : run_command_inq_cb (void *opaque, const char *line)
     916             : {
     917           0 :   struct run_command_parm_s *parm = opaque;
     918             :   const char *s;
     919           0 :   int rc = 0;
     920             : 
     921           0 :   if ((s = has_leading_keyword (line, "SENDCERT")))
     922             :     { /* send the given certificate */
     923             :       int err;
     924             :       ksba_cert_t cert;
     925             :       const unsigned char *der;
     926             :       size_t derlen;
     927             : 
     928           0 :       line = s;
     929           0 :       if (!*line)
     930           0 :         return gpg_error (GPG_ERR_ASS_PARAMETER);
     931             : 
     932           0 :       err = gpgsm_find_cert (parm->ctrl, line, NULL, &cert);
     933           0 :       if (err)
     934             :         {
     935           0 :           log_error ("certificate not found: %s\n", gpg_strerror (err));
     936           0 :           rc = gpg_error (GPG_ERR_NOT_FOUND);
     937             :         }
     938             :       else
     939             :         {
     940           0 :           der = ksba_cert_get_image (cert, &derlen);
     941           0 :           if (!der)
     942           0 :             rc = gpg_error (GPG_ERR_INV_CERT_OBJ);
     943             :           else
     944           0 :             rc = assuan_send_data (parm->ctx, der, derlen);
     945           0 :           ksba_cert_release (cert);
     946             :         }
     947             :     }
     948           0 :   else if ((s = has_leading_keyword (line, "PRINTINFO")))
     949             :     { /* Simply show the message given in the argument. */
     950           0 :       line = s;
     951           0 :       log_info ("dirmngr: %s\n", line);
     952             :     }
     953             :   else
     954             :     {
     955           0 :       log_error ("unsupported inquiry '%s'\n", line);
     956           0 :       rc = gpg_error (GPG_ERR_ASS_UNKNOWN_INQUIRE);
     957             :     }
     958             : 
     959           0 :   return rc;
     960             : }
     961             : 
     962             : static gpg_error_t
     963           0 : run_command_status_cb (void *opaque, const char *line)
     964             : {
     965           0 :   ctrl_t ctrl = opaque;
     966             :   const char *s;
     967             : 
     968           0 :   if (opt.verbose)
     969             :     {
     970           0 :       log_info ("dirmngr status: %s\n", line);
     971             :     }
     972           0 :   if ((s = has_leading_keyword (line, "PROGRESS")))
     973             :     {
     974           0 :       if (ctrl)
     975             :         {
     976           0 :           line = s;
     977           0 :           if (gpgsm_status (ctrl, STATUS_PROGRESS, line))
     978           0 :             return gpg_error (GPG_ERR_ASS_CANCELED);
     979             :         }
     980             :     }
     981           0 :   return 0;
     982             : }
     983             : 
     984             : 
     985             : 
     986             : /* Pass COMMAND to dirmngr and print all output generated by Dirmngr
     987             :    to stdout.  A couple of inquiries are defined (see above).  ARGC
     988             :    arguments in ARGV are given to the Dirmngr.  Spaces, plus and
     989             :    percent characters within the argument strings are percent escaped
     990             :    so that blanks can act as delimiters. */
     991             : int
     992           0 : gpgsm_dirmngr_run_command (ctrl_t ctrl, const char *command,
     993             :                            int argc, char **argv)
     994             : {
     995             :   int rc;
     996             :   int i;
     997             :   const char *s;
     998             :   char *line, *p;
     999             :   size_t len;
    1000             :   struct run_command_parm_s parm;
    1001             : 
    1002           0 :   rc = start_dirmngr (ctrl);
    1003           0 :   if (rc)
    1004           0 :     return rc;
    1005             : 
    1006           0 :   parm.ctrl = ctrl;
    1007           0 :   parm.ctx = dirmngr_ctx;
    1008             : 
    1009           0 :   len = strlen (command) + 1;
    1010           0 :   for (i=0; i < argc; i++)
    1011           0 :     len += 1 + 3*strlen (argv[i]); /* enough space for percent escaping */
    1012           0 :   line = xtrymalloc (len);
    1013           0 :   if (!line)
    1014             :     {
    1015           0 :       release_dirmngr (ctrl);
    1016           0 :       return out_of_core ();
    1017             :     }
    1018             : 
    1019           0 :   p = stpcpy (line, command);
    1020           0 :   for (i=0; i < argc; i++)
    1021             :     {
    1022           0 :       *p++ = ' ';
    1023           0 :       for (s=argv[i]; *s; s++)
    1024             :         {
    1025           0 :           if (!isascii (*s))
    1026           0 :             *p++ = *s;
    1027           0 :           else if (*s == ' ')
    1028           0 :             *p++ = '+';
    1029           0 :           else if (!isprint (*s) || *s == '+')
    1030             :             {
    1031           0 :               sprintf (p, "%%%02X", *(const unsigned char *)s);
    1032           0 :               p += 3;
    1033             :             }
    1034             :           else
    1035           0 :             *p++ = *s;
    1036             :         }
    1037             :     }
    1038           0 :   *p = 0;
    1039             : 
    1040           0 :   rc = assuan_transact (dirmngr_ctx, line,
    1041             :                         run_command_cb, NULL,
    1042             :                         run_command_inq_cb, &parm,
    1043             :                         run_command_status_cb, ctrl);
    1044           0 :   xfree (line);
    1045           0 :   log_info ("response of dirmngr: %s\n", rc? gpg_strerror (rc): "okay");
    1046           0 :   release_dirmngr (ctrl);
    1047           0 :   return rc;
    1048             : }

Generated by: LCOV version 1.11