LCOV - code coverage report
Current view: top level - agent - cache.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 138 207 66.7 %
Date: 2016-09-12 12:29:17 Functions: 10 11 90.9 %

          Line data    Source code
       1             : /* cache.c - keep a cache of passphrases
       2             :  * Copyright (C) 2002, 2010 Free Software Foundation, Inc.
       3             :  *
       4             :  * This file is part of GnuPG.
       5             :  *
       6             :  * GnuPG is free software; you can redistribute it and/or modify
       7             :  * it under the terms of the GNU General Public License as published by
       8             :  * the Free Software Foundation; either version 3 of the License, or
       9             :  * (at your option) any later version.
      10             :  *
      11             :  * GnuPG is distributed in the hope that it will be useful,
      12             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      13             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14             :  * GNU General Public License for more details.
      15             :  *
      16             :  * You should have received a copy of the GNU General Public License
      17             :  * along with this program; if not, see <http://www.gnu.org/licenses/>.
      18             :  */
      19             : 
      20             : #include <config.h>
      21             : 
      22             : #include <stdio.h>
      23             : #include <stdlib.h>
      24             : #include <string.h>
      25             : #include <time.h>
      26             : #include <assert.h>
      27             : #include <npth.h>
      28             : 
      29             : #include "agent.h"
      30             : 
      31             : /* The size of the encryption key in bytes.  */
      32             : #define ENCRYPTION_KEYSIZE (128/8)
      33             : 
      34             : /* A mutex used to protect the encryption.  This is required because
      35             :    we use one context to do all encryption and decryption.  */
      36             : static npth_mutex_t encryption_lock;
      37             : /* The encryption context.  This is the only place where the
      38             :    encryption key for all cached entries is available.  It would be nice
      39             :    to keep this (or just the key) in some hardware device, for example
      40             :    a TPM.  Libgcrypt could be extended to provide such a service.
      41             :    With the current scheme it is easy to retrieve the cached entries
      42             :    if access to Libgcrypt's memory is available.  The encryption
      43             :    merely avoids grepping for clear texts in the memory.  Nevertheless
      44             :    the encryption provides the necessary infrastructure to make it
      45             :    more secure.  */
      46             : static gcry_cipher_hd_t encryption_handle;
      47             : 
      48             : 
      49             : struct secret_data_s {
      50             :   int  totallen; /* This includes the padding and space for AESWRAP. */
      51             :   char data[1];  /* A string.  */
      52             : };
      53             : 
      54             : typedef struct cache_item_s *ITEM;
      55             : struct cache_item_s {
      56             :   ITEM next;
      57             :   time_t created;
      58             :   time_t accessed;
      59             :   int ttl;  /* max. lifetime given in seconds, -1 one means infinite */
      60             :   struct secret_data_s *pw;
      61             :   cache_mode_t cache_mode;
      62             :   char key[1];
      63             : };
      64             : 
      65             : /* The cache himself.  */
      66             : static ITEM thecache;
      67             : 
      68             : /* NULL or the last cache key stored by agent_store_cache_hit.  */
      69             : static char *last_stored_cache_key;
      70             : 
      71             : 
      72             : /* This function must be called once to initialize this module. It
      73             :    has to be done before a second thread is spawned.  */
      74             : void
      75          48 : initialize_module_cache (void)
      76             : {
      77             :   int err;
      78             : 
      79          48 :   err = npth_mutex_init (&encryption_lock, NULL);
      80             : 
      81          48 :   if (err)
      82           0 :     log_fatal ("error initializing cache module: %s\n", strerror (err));
      83          48 : }
      84             : 
      85             : 
      86             : void
      87          93 : deinitialize_module_cache (void)
      88             : {
      89          93 :   gcry_cipher_close (encryption_handle);
      90          93 :   encryption_handle = NULL;
      91          93 : }
      92             : 
      93             : 
      94             : /* We do the encryption init on the fly.  We can't do it in the module
      95             :    init code because that is run before we listen for connections and
      96             :    in case we are started on demand by gpg etc. it will only wait for
      97             :    a few seconds to decide whether the agent may now accept
      98             :    connections.  Thus we should get into listen state as soon as
      99             :    possible.  */
     100             : static gpg_error_t
     101         316 : init_encryption (void)
     102             : {
     103             :   gpg_error_t err;
     104             :   void *key;
     105             :   int res;
     106             : 
     107         316 :   if (encryption_handle)
     108         275 :     return 0; /* Shortcut - Already initialized.  */
     109             : 
     110          41 :   res = npth_mutex_lock (&encryption_lock);
     111          41 :   if (res)
     112           0 :     log_fatal ("failed to acquire cache encryption mutex: %s\n", strerror (res));
     113             : 
     114          41 :   err = gcry_cipher_open (&encryption_handle, GCRY_CIPHER_AES128,
     115             :                           GCRY_CIPHER_MODE_AESWRAP, GCRY_CIPHER_SECURE);
     116          41 :   if (!err)
     117             :     {
     118          41 :       key = gcry_random_bytes (ENCRYPTION_KEYSIZE, GCRY_STRONG_RANDOM);
     119          41 :       if (!key)
     120           0 :         err = gpg_error_from_syserror ();
     121             :       else
     122             :         {
     123          41 :           err = gcry_cipher_setkey (encryption_handle, key, ENCRYPTION_KEYSIZE);
     124          41 :           xfree (key);
     125             :         }
     126          41 :       if (err)
     127             :         {
     128           0 :           gcry_cipher_close (encryption_handle);
     129           0 :           encryption_handle = NULL;
     130             :         }
     131             :     }
     132          41 :   if (err)
     133           0 :     log_error ("error initializing cache encryption context: %s\n",
     134             :                gpg_strerror (err));
     135             : 
     136          41 :   res = npth_mutex_unlock (&encryption_lock);
     137          41 :   if (res)
     138           0 :     log_fatal ("failed to release cache encryption mutex: %s\n", strerror (res));
     139             : 
     140          41 :   return err? gpg_error (GPG_ERR_NOT_INITIALIZED) : 0;
     141             : }
     142             : 
     143             : 
     144             : 
     145             : static void
     146           2 : release_data (struct secret_data_s *data)
     147             : {
     148           2 :    xfree (data);
     149           2 : }
     150             : 
     151             : static gpg_error_t
     152         177 : new_data (const char *string, struct secret_data_s **r_data)
     153             : {
     154             :   gpg_error_t err;
     155             :   struct secret_data_s *d, *d_enc;
     156             :   size_t length;
     157             :   int total;
     158             :   int res;
     159             : 
     160         177 :   *r_data = NULL;
     161             : 
     162         177 :   err = init_encryption ();
     163         177 :   if (err)
     164           0 :     return err;
     165             : 
     166         177 :   length = strlen (string) + 1;
     167             : 
     168             :   /* We pad the data to 32 bytes so that it get more complicated
     169             :      finding something out by watching allocation patterns.  This is
     170             :      usually not possible but we better assume nothing about our secure
     171             :      storage provider.  To support the AESWRAP mode we need to add 8
     172             :      extra bytes as well. */
     173         177 :   total = (length + 8) + 32 - ((length+8) % 32);
     174             : 
     175         177 :   d = xtrymalloc_secure (sizeof *d + total - 1);
     176         177 :   if (!d)
     177           0 :     return gpg_error_from_syserror ();
     178         177 :   memcpy (d->data, string, length);
     179             : 
     180         177 :   d_enc = xtrymalloc (sizeof *d_enc + total - 1);
     181         177 :   if (!d_enc)
     182             :     {
     183           0 :       err = gpg_error_from_syserror ();
     184           0 :       xfree (d);
     185           0 :       return err;
     186             :     }
     187             : 
     188         177 :   d_enc->totallen = total;
     189         177 :   res = npth_mutex_lock (&encryption_lock);
     190         177 :   if (res)
     191           0 :     log_fatal ("failed to acquire cache encryption mutex: %s\n",
     192             :                strerror (res));
     193             : 
     194         354 :   err = gcry_cipher_encrypt (encryption_handle, d_enc->data, total,
     195         354 :                              d->data, total - 8);
     196         177 :   xfree (d);
     197         177 :   res = npth_mutex_unlock (&encryption_lock);
     198         177 :   if (res)
     199           0 :     log_fatal ("failed to release cache encryption mutex: %s\n", strerror (res));
     200         177 :   if (err)
     201             :     {
     202           0 :       xfree (d_enc);
     203           0 :       return err;
     204             :     }
     205         177 :   *r_data = d_enc;
     206         177 :   return 0;
     207             : }
     208             : 
     209             : 
     210             : 
     211             : /* Check whether there are items to expire.  */
     212             : static void
     213         345 : housekeeping (void)
     214             : {
     215             :   ITEM r, rprev;
     216         345 :   time_t current = gnupg_get_time ();
     217             : 
     218             :   /* First expire the actual data */
     219        1574 :   for (r=thecache; r; r = r->next)
     220             :     {
     221        1229 :       if (r->pw && r->ttl >= 0 && r->accessed + r->ttl < current)
     222             :         {
     223           0 :           if (DBG_CACHE)
     224           0 :             log_debug ("  expired '%s' (%ds after last access)\n",
     225           0 :                        r->key, r->ttl);
     226           0 :           release_data (r->pw);
     227           0 :           r->pw = NULL;
     228           0 :           r->accessed = current;
     229             :         }
     230             :     }
     231             : 
     232             :   /* Second, make sure that we also remove them based on the created stamp so
     233             :      that the user has to enter it from time to time. */
     234        1574 :   for (r=thecache; r; r = r->next)
     235             :     {
     236             :       unsigned long maxttl;
     237             : 
     238        1229 :       switch (r->cache_mode)
     239             :         {
     240           6 :         case CACHE_MODE_SSH: maxttl = opt.max_cache_ttl_ssh; break;
     241        1223 :         default: maxttl = opt.max_cache_ttl; break;
     242             :         }
     243        1229 :       if (r->pw && r->created + maxttl < current)
     244             :         {
     245           0 :           if (DBG_CACHE)
     246           0 :             log_debug ("  expired '%s' (%lus after creation)\n",
     247           0 :                        r->key, opt.max_cache_ttl);
     248           0 :           release_data (r->pw);
     249           0 :           r->pw = NULL;
     250           0 :           r->accessed = current;
     251             :         }
     252             :     }
     253             : 
     254             :   /* Third, make sure that we don't have too many items in the list.
     255             :      Expire old and unused entries after 30 minutes */
     256        1919 :   for (rprev=NULL, r=thecache; r; )
     257             :     {
     258        1229 :       if (!r->pw && r->ttl >= 0 && r->accessed + 60*30 < current)
     259           0 :         {
     260           0 :           ITEM r2 = r->next;
     261           0 :           if (DBG_CACHE)
     262           0 :             log_debug ("  removed '%s' (mode %d) (slot not used for 30m)\n",
     263           0 :                        r->key, r->cache_mode);
     264           0 :           xfree (r);
     265           0 :           if (!rprev)
     266           0 :             thecache = r2;
     267             :           else
     268           0 :             rprev->next = r2;
     269           0 :           r = r2;
     270             :         }
     271             :       else
     272             :         {
     273        1229 :           rprev = r;
     274        1229 :           r = r->next;
     275             :         }
     276             :     }
     277         345 : }
     278             : 
     279             : 
     280             : void
     281           0 : agent_flush_cache (void)
     282             : {
     283             :   ITEM r;
     284             : 
     285           0 :   if (DBG_CACHE)
     286           0 :     log_debug ("agent_flush_cache\n");
     287             : 
     288           0 :   for (r=thecache; r; r = r->next)
     289             :     {
     290           0 :       if (r->pw)
     291             :         {
     292           0 :           if (DBG_CACHE)
     293           0 :             log_debug ("  flushing '%s'\n", r->key);
     294           0 :           release_data (r->pw);
     295           0 :           r->pw = NULL;
     296           0 :           r->accessed = 0;
     297             :         }
     298             :     }
     299           0 : }
     300             : 
     301             : 
     302             : /* Compare two cache modes.  */
     303             : static int
     304           8 : cache_mode_equal (cache_mode_t a, cache_mode_t b)
     305             : {
     306             :   /* CACHE_MODE_ANY matches any mode other than CACHE_MODE_IGNORE.  */
     307          13 :   return ((a == CACHE_MODE_ANY && b != CACHE_MODE_IGNORE)
     308          11 :           || (b == CACHE_MODE_ANY && a != CACHE_MODE_IGNORE) || a == b);
     309             : }
     310             : 
     311             : 
     312             : /* Store the string DATA in the cache under KEY and mark it with a
     313             :    maximum lifetime of TTL seconds.  If there is already data under
     314             :    this key, it will be replaced.  Using a DATA of NULL deletes the
     315             :    entry.  A TTL of 0 is replaced by the default TTL and a TTL of -1
     316             :    set infinite timeout.  CACHE_MODE is stored with the cache entry
     317             :    and used to select different timeouts.  */
     318             : int
     319         179 : agent_put_cache (const char *key, cache_mode_t cache_mode,
     320             :                  const char *data, int ttl)
     321             : {
     322         179 :   gpg_error_t err = 0;
     323             :   ITEM r;
     324             : 
     325         179 :   if (DBG_CACHE)
     326           0 :     log_debug ("agent_put_cache '%s' (mode %d) requested ttl=%d\n",
     327             :                key, cache_mode, ttl);
     328         179 :   housekeeping ();
     329             : 
     330         179 :   if (!ttl)
     331             :     {
     332           6 :       switch(cache_mode)
     333             :         {
     334           4 :         case CACHE_MODE_SSH: ttl = opt.def_cache_ttl_ssh; break;
     335           2 :         default: ttl = opt.def_cache_ttl; break;
     336             :         }
     337             :     }
     338         179 :   if ((!ttl && data) || cache_mode == CACHE_MODE_IGNORE)
     339           1 :     return 0;
     340             : 
     341         493 :   for (r=thecache; r; r = r->next)
     342             :     {
     343         317 :       if (((cache_mode != CACHE_MODE_USER
     344         317 :             && cache_mode != CACHE_MODE_NONCE)
     345           6 :            || cache_mode_equal (r->cache_mode, cache_mode))
     346         317 :           && !strcmp (r->key, key))
     347           2 :         break;
     348             :     }
     349         178 :   if (r) /* Replace.  */
     350             :     {
     351           2 :       if (r->pw)
     352             :         {
     353           2 :           release_data (r->pw);
     354           2 :           r->pw = NULL;
     355             :         }
     356           2 :       if (data)
     357             :         {
     358           1 :           r->created = r->accessed = gnupg_get_time ();
     359           1 :           r->ttl = ttl;
     360           1 :           r->cache_mode = cache_mode;
     361           1 :           err = new_data (data, &r->pw);
     362           1 :           if (err)
     363           0 :             log_error ("error replacing cache item: %s\n", gpg_strerror (err));
     364             :         }
     365             :     }
     366         176 :   else if (data) /* Insert.  */
     367             :     {
     368         176 :       r = xtrycalloc (1, sizeof *r + strlen (key));
     369         176 :       if (!r)
     370           0 :         err = gpg_error_from_syserror ();
     371             :       else
     372             :         {
     373         176 :           strcpy (r->key, key);
     374         176 :           r->created = r->accessed = gnupg_get_time ();
     375         176 :           r->ttl = ttl;
     376         176 :           r->cache_mode = cache_mode;
     377         176 :           err = new_data (data, &r->pw);
     378         176 :           if (err)
     379           0 :             xfree (r);
     380             :           else
     381             :             {
     382         176 :               r->next = thecache;
     383         176 :               thecache = r;
     384             :             }
     385             :         }
     386         176 :       if (err)
     387           0 :         log_error ("error inserting cache item: %s\n", gpg_strerror (err));
     388             :     }
     389         178 :   return err;
     390             : }
     391             : 
     392             : 
     393             : /* Try to find an item in the cache.  Note that we currently don't
     394             :    make use of CACHE_MODE except for CACHE_MODE_NONCE and
     395             :    CACHE_MODE_USER.  */
     396             : char *
     397         166 : agent_get_cache (const char *key, cache_mode_t cache_mode)
     398             : {
     399             :   gpg_error_t err;
     400             :   ITEM r;
     401         166 :   char *value = NULL;
     402             :   int res;
     403         166 :   int last_stored = 0;
     404             : 
     405         166 :   if (cache_mode == CACHE_MODE_IGNORE)
     406           0 :     return NULL;
     407             : 
     408         166 :   if (!key)
     409             :     {
     410           0 :       key = last_stored_cache_key;
     411           0 :       if (!key)
     412           0 :         return NULL;
     413           0 :       last_stored = 1;
     414             :     }
     415             : 
     416             : 
     417         166 :   if (DBG_CACHE)
     418           0 :     log_debug ("agent_get_cache '%s' (mode %d)%s ...\n",
     419             :                key, cache_mode,
     420             :                last_stored? " (stored cache key)":"");
     421         166 :   housekeeping ();
     422             : 
     423         447 :   for (r=thecache; r; r = r->next)
     424             :     {
     425         420 :       if (r->pw
     426         417 :           && ((cache_mode != CACHE_MODE_USER
     427         416 :                && cache_mode != CACHE_MODE_NONCE)
     428           2 :               || cache_mode_equal (r->cache_mode, cache_mode))
     429         417 :           && !strcmp (r->key, key))
     430             :         {
     431             :           /* Note: To avoid races KEY may not be accessed anymore below.  */
     432         139 :           r->accessed = gnupg_get_time ();
     433         139 :           if (DBG_CACHE)
     434           0 :             log_debug ("... hit\n");
     435         139 :           if (r->pw->totallen < 32)
     436           0 :             err = gpg_error (GPG_ERR_INV_LENGTH);
     437         139 :           else if ((err = init_encryption ()))
     438             :             ;
     439         139 :           else if (!(value = xtrymalloc_secure (r->pw->totallen - 8)))
     440           0 :             err = gpg_error_from_syserror ();
     441             :           else
     442             :             {
     443         139 :               res = npth_mutex_lock (&encryption_lock);
     444         139 :               if (res)
     445           0 :                 log_fatal ("failed to acquire cache encryption mutex: %s\n",
     446             :                            strerror (res));
     447         278 :               err = gcry_cipher_decrypt (encryption_handle,
     448         139 :                                          value, r->pw->totallen - 8,
     449         278 :                                          r->pw->data, r->pw->totallen);
     450         139 :               res = npth_mutex_unlock (&encryption_lock);
     451         139 :               if (res)
     452           0 :                 log_fatal ("failed to release cache encryption mutex: %s\n",
     453             :                            strerror (res));
     454             :             }
     455         139 :           if (err)
     456             :             {
     457           0 :               xfree (value);
     458           0 :               value = NULL;
     459           0 :               log_error ("retrieving cache entry '%s' failed: %s\n",
     460             :                          key, gpg_strerror (err));
     461             :             }
     462         139 :           return value;
     463             :         }
     464             :     }
     465          27 :   if (DBG_CACHE)
     466           0 :     log_debug ("... miss\n");
     467             : 
     468          27 :   return NULL;
     469             : }
     470             : 
     471             : 
     472             : /* Store the key for the last successful cache hit.  That value is
     473             :    used by agent_get_cache if the requested KEY is given as NULL.
     474             :    NULL may be used to remove that key. */
     475             : void
     476         136 : agent_store_cache_hit (const char *key)
     477             : {
     478         136 :   xfree (last_stored_cache_key);
     479         136 :   last_stored_cache_key = key? xtrystrdup (key) : NULL;
     480         136 : }

Generated by: LCOV version 1.11