LCOV - code coverage report
Current view: top level - src - decrypt.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 113 183 61.7 %
Date: 2016-11-29 15:07:43 Functions: 8 9 88.9 %

          Line data    Source code
       1             : /* decrypt.c - Decrypt function.
       2             :    Copyright (C) 2000 Werner Koch (dd9jn)
       3             :    Copyright (C) 2001, 2002, 2003, 2004 g10 Code GmbH
       4             : 
       5             :    This file is part of GPGME.
       6             : 
       7             :    GPGME is free software; you can redistribute it and/or modify it
       8             :    under the terms of the GNU Lesser General Public License as
       9             :    published by the Free Software Foundation; either version 2.1 of
      10             :    the License, or (at your option) any later version.
      11             : 
      12             :    GPGME is distributed in the hope that it will be useful, but
      13             :    WITHOUT ANY WARRANTY; without even the implied warranty of
      14             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      15             :    Lesser General Public License for more details.
      16             : 
      17             :    You should have received a copy of the GNU Lesser General Public
      18             :    License along with this program; if not, write to the Free Software
      19             :    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
      20             :    02111-1307, USA.  */
      21             : 
      22             : #if HAVE_CONFIG_H
      23             : #include <config.h>
      24             : #endif
      25             : #include <stdlib.h>
      26             : #include <string.h>
      27             : #include <errno.h>
      28             : 
      29             : #include "debug.h"
      30             : #include "gpgme.h"
      31             : #include "util.h"
      32             : #include "context.h"
      33             : #include "ops.h"
      34             : 
      35             : 
      36             : 
      37             : typedef struct
      38             : {
      39             :   struct _gpgme_op_decrypt_result result;
      40             : 
      41             :   /* The error code from a FAILURE status line or 0.  */
      42             :   gpg_error_t failure_code;
      43             : 
      44             :   int okay;
      45             :   int failed;
      46             : 
      47             :   /* A pointer to the next pointer of the last recipient in the list.
      48             :      This makes appending new invalid signers painless while
      49             :      preserving the order.  */
      50             :   gpgme_recipient_t *last_recipient_p;
      51             : } *op_data_t;
      52             : 
      53             : 
      54             : static void
      55          48 : release_op_data (void *hook)
      56             : {
      57          48 :   op_data_t opd = (op_data_t) hook;
      58          48 :   gpgme_recipient_t recipient = opd->result.recipients;
      59             : 
      60          48 :   if (opd->result.unsupported_algorithm)
      61           0 :     free (opd->result.unsupported_algorithm);
      62             : 
      63          48 :   if (opd->result.file_name)
      64          10 :     free (opd->result.file_name);
      65             : 
      66          48 :   if (opd->result.session_key)
      67           0 :     free (opd->result.session_key);
      68             : 
      69         134 :   while (recipient)
      70             :     {
      71          38 :       gpgme_recipient_t next = recipient->next;
      72          38 :       free (recipient);
      73          38 :       recipient = next;
      74             :     }
      75          48 : }
      76             : 
      77             : 
      78             : gpgme_decrypt_result_t
      79          43 : gpgme_op_decrypt_result (gpgme_ctx_t ctx)
      80             : {
      81             :   void *hook;
      82             :   op_data_t opd;
      83             :   gpgme_error_t err;
      84             : 
      85          43 :   TRACE_BEG (DEBUG_CTX, "gpgme_op_decrypt_result", ctx);
      86             : 
      87          43 :   err = _gpgme_op_data_lookup (ctx, OPDATA_DECRYPT, &hook, -1, NULL);
      88          43 :   opd = hook;
      89          43 :   if (err || !opd)
      90             :     {
      91           0 :       TRACE_SUC0 ("result=(null)");
      92           0 :       return NULL;
      93             :     }
      94             : 
      95             :   if (_gpgme_debug_trace ())
      96             :     {
      97             :       gpgme_recipient_t rcp;
      98             : 
      99          43 :       if (opd->result.unsupported_algorithm)
     100             :         {
     101           0 :           TRACE_LOG1 ("result: unsupported_algorithm: %s",
     102             :                       opd->result.unsupported_algorithm);
     103             :         }
     104          43 :       if (opd->result.wrong_key_usage)
     105             :         {
     106           0 :           TRACE_LOG ("result: wrong key usage");
     107             :         }
     108          43 :       rcp = opd->result.recipients;
     109         124 :       while (rcp)
     110             :         {
     111          38 :           TRACE_LOG3 ("result: recipient: keyid=%s, pubkey_algo=%i, "
     112             :                       "status=%s", rcp->keyid, rcp->pubkey_algo,
     113             :                       gpg_strerror (rcp->status));
     114          38 :           rcp = rcp->next;
     115             :         }
     116          43 :       if (opd->result.file_name)
     117             :         {
     118          10 :           TRACE_LOG1 ("result: original file name: %s", opd->result.file_name);
     119             :         }
     120             :     }
     121             : 
     122          43 :   TRACE_SUC1 ("result=%p", &opd->result);
     123          43 :   return &opd->result;
     124             : }
     125             : 
     126             : 
     127             : static gpgme_error_t
     128          38 : parse_enc_to (char *args, gpgme_recipient_t *recp, gpgme_protocol_t protocol)
     129             : {
     130             :   gpgme_recipient_t rec;
     131             :   char *tail;
     132             :   int i;
     133             : 
     134          38 :   rec = malloc (sizeof (*rec));
     135          38 :   if (!rec)
     136           0 :     return gpg_error_from_syserror ();
     137             : 
     138          38 :   rec->next = NULL;
     139          38 :   rec->keyid = rec->_keyid;
     140          38 :   rec->status = 0;
     141             : 
     142         646 :   for (i = 0; i < sizeof (rec->_keyid) - 1; i++)
     143             :     {
     144         608 :       if (args[i] == '\0' || args[i] == ' ')
     145             :         break;
     146             : 
     147         608 :       rec->_keyid[i] = args[i];
     148             :     }
     149          38 :   rec->_keyid[i] = '\0';
     150             : 
     151          38 :   args = &args[i];
     152          38 :   if (*args != '\0' && *args != ' ')
     153             :     {
     154           0 :       free (rec);
     155           0 :       return trace_gpg_error (GPG_ERR_INV_ENGINE);
     156             :     }
     157             : 
     158         114 :   while (*args == ' ')
     159          38 :     args++;
     160             : 
     161          38 :   if (*args)
     162             :     {
     163          38 :       gpg_err_set_errno (0);
     164          38 :       rec->pubkey_algo = _gpgme_map_pk_algo (strtol (args, &tail, 0), protocol);
     165          38 :       if (errno || args == tail || *tail != ' ')
     166             :         {
     167             :           /* The crypto backend does not behave.  */
     168           0 :           free (rec);
     169           0 :           return trace_gpg_error (GPG_ERR_INV_ENGINE);
     170             :         }
     171             :     }
     172             : 
     173             :   /* FIXME: The key length is always 0 right now, so no need to parse
     174             :      it.  */
     175             : 
     176          38 :   *recp = rec;
     177          38 :   return 0;
     178             : }
     179             : 
     180             : 
     181             : gpgme_error_t
     182         689 : _gpgme_decrypt_status_handler (void *priv, gpgme_status_code_t code,
     183             :                                char *args)
     184             : {
     185         689 :   gpgme_ctx_t ctx = (gpgme_ctx_t) priv;
     186             :   gpgme_error_t err;
     187             :   void *hook;
     188             :   op_data_t opd;
     189             : 
     190         689 :   err = _gpgme_passphrase_status_handler (priv, code, args);
     191         689 :   if (err)
     192           0 :     return err;
     193             : 
     194         689 :   err = _gpgme_op_data_lookup (ctx, OPDATA_DECRYPT, &hook, -1, NULL);
     195         689 :   opd = hook;
     196         689 :   if (err)
     197           0 :     return err;
     198             : 
     199         689 :   switch (code)
     200             :     {
     201             :     case GPGME_STATUS_FAILURE:
     202           0 :       opd->failure_code = _gpgme_parse_failure (args);
     203           0 :       break;
     204             : 
     205             :     case GPGME_STATUS_EOF:
     206             :       /* FIXME: These error values should probably be attributed to
     207             :          the underlying crypto engine (as error source).  */
     208          48 :       if (opd->failed)
     209           0 :         return gpg_error (GPG_ERR_DECRYPT_FAILED);
     210          48 :       else if (!opd->okay)
     211           0 :         return gpg_error (GPG_ERR_NO_DATA);
     212          48 :       else if (opd->failure_code)
     213           0 :         return opd->failure_code;
     214          48 :       break;
     215             : 
     216             :     case GPGME_STATUS_DECRYPTION_INFO:
     217             :       /* Fixme: Provide a way to return the used symmetric algorithm. */
     218          46 :       break;
     219             : 
     220             :     case GPGME_STATUS_DECRYPTION_OKAY:
     221          47 :       opd->okay = 1;
     222          47 :       break;
     223             : 
     224             :     case GPGME_STATUS_DECRYPTION_FAILED:
     225           0 :       opd->failed = 1;
     226           0 :       break;
     227             : 
     228             :     case GPGME_STATUS_ERROR:
     229             :       /* Note that this is an informational status code which should
     230             :          not lead to an error return unless it is something not
     231             :          related to the backend.  */
     232             :       {
     233           0 :         const char d_alg[] = "decrypt.algorithm";
     234           0 :         const char k_alg[] = "decrypt.keyusage";
     235             : 
     236           0 :         if (!strncmp (args, d_alg, sizeof (d_alg) - 1))
     237             :           {
     238           0 :             args += sizeof (d_alg) - 1;
     239           0 :             while (*args == ' ')
     240           0 :               args++;
     241             : 
     242           0 :             if (gpg_err_code (atoi (args)) == GPG_ERR_UNSUPPORTED_ALGORITHM)
     243             :               {
     244             :                 char *end;
     245             : 
     246           0 :                 while (*args && *args != ' ')
     247           0 :                   args++;
     248           0 :                 while (*args == ' ')
     249           0 :                   args++;
     250             : 
     251           0 :                 end = strchr (args, ' ');
     252           0 :                 if (end)
     253           0 :                   *end = '\0';
     254             : 
     255           0 :                 if (!(*args == '?' && *(args + 1) == '\0'))
     256             :                   {
     257           0 :                     opd->result.unsupported_algorithm = strdup (args);
     258           0 :                     if (!opd->result.unsupported_algorithm)
     259           0 :                       return gpg_error_from_syserror ();
     260             :                   }
     261             :               }
     262             :           }
     263           0 :         else if (!strncmp (args, k_alg, sizeof (k_alg) - 1))
     264             :           {
     265           0 :             args += sizeof (k_alg) - 1;
     266           0 :             while (*args == ' ')
     267           0 :               args++;
     268             : 
     269           0 :             if (gpg_err_code (atoi (args)) == GPG_ERR_WRONG_KEY_USAGE)
     270           0 :               opd->result.wrong_key_usage = 1;
     271             :           }
     272             :       }
     273           0 :       break;
     274             : 
     275             :     case GPGME_STATUS_ENC_TO:
     276          38 :       err = parse_enc_to (args, opd->last_recipient_p, ctx->protocol);
     277          38 :       if (err)
     278           0 :         return err;
     279             : 
     280          38 :       opd->last_recipient_p = &(*opd->last_recipient_p)->next;
     281          38 :       break;
     282             : 
     283             :     case GPGME_STATUS_SESSION_KEY:
     284           0 :       if (opd->result.session_key)
     285           0 :         free (opd->result.session_key);
     286           0 :       opd->result.session_key = strdup(args);
     287           0 :       break;
     288             : 
     289             :     case GPGME_STATUS_NO_SECKEY:
     290             :       {
     291           1 :         gpgme_recipient_t rec = opd->result.recipients;
     292             : 
     293           2 :         while (rec)
     294             :           {
     295           1 :             if (!strcmp (rec->keyid, args))
     296             :               {
     297           1 :                 rec->status = gpg_error (GPG_ERR_NO_SECKEY);
     298           1 :                 break;
     299             :               }
     300           0 :             rec = rec->next;
     301             :           }
     302             :         /* FIXME: Is this ok?  */
     303           1 :         if (!rec)
     304           0 :           return trace_gpg_error (GPG_ERR_INV_ENGINE);
     305             :       }
     306           1 :       break;
     307             : 
     308             :     case GPGME_STATUS_PLAINTEXT:
     309          46 :       err = _gpgme_parse_plaintext (args, &opd->result.file_name);
     310          46 :       if (err)
     311           0 :         return err;
     312          46 :       break;
     313             : 
     314             :     case GPGME_STATUS_INQUIRE_MAXLEN:
     315          11 :       if (ctx->status_cb && !ctx->full_status)
     316             :         {
     317           0 :           err = ctx->status_cb (ctx->status_cb_value, "INQUIRE_MAXLEN", args);
     318           0 :           if (err)
     319           0 :             return err;
     320             :         }
     321          11 :       break;
     322             : 
     323             :     default:
     324         452 :       break;
     325             :     }
     326             : 
     327         689 :   return 0;
     328             : }
     329             : 
     330             : 
     331             : static gpgme_error_t
     332         466 : decrypt_status_handler (void *priv, gpgme_status_code_t code, char *args)
     333             : {
     334             :   gpgme_error_t err;
     335             : 
     336         466 :   err = _gpgme_progress_status_handler (priv, code, args);
     337         466 :   if (!err)
     338         466 :     err = _gpgme_decrypt_status_handler (priv, code, args);
     339         466 :   return err;
     340             : }
     341             : 
     342             : 
     343             : gpgme_error_t
     344          48 : _gpgme_op_decrypt_init_result (gpgme_ctx_t ctx)
     345             : {
     346             :   gpgme_error_t err;
     347             :   void *hook;
     348             :   op_data_t opd;
     349             : 
     350          48 :   err = _gpgme_op_data_lookup (ctx, OPDATA_DECRYPT, &hook,
     351             :                                sizeof (*opd), release_op_data);
     352          48 :   opd = hook;
     353          48 :   if (err)
     354           0 :     return err;
     355             : 
     356          48 :   opd->last_recipient_p = &opd->result.recipients;
     357          48 :   return 0;
     358             : }
     359             : 
     360             : 
     361             : static gpgme_error_t
     362          35 : decrypt_start (gpgme_ctx_t ctx, int synchronous,
     363             :                gpgme_data_t cipher, gpgme_data_t plain)
     364             : {
     365             :   gpgme_error_t err;
     366             : 
     367          35 :   err = _gpgme_op_reset (ctx, synchronous);
     368          35 :   if (err)
     369           0 :     return err;
     370             : 
     371          35 :   err = _gpgme_op_decrypt_init_result (ctx);
     372          35 :   if (err)
     373           0 :     return err;
     374             : 
     375          35 :   if (!cipher)
     376           0 :     return gpg_error (GPG_ERR_NO_DATA);
     377          35 :   if (!plain)
     378           0 :     return gpg_error (GPG_ERR_INV_VALUE);
     379             : 
     380          35 :   if (err)
     381           0 :     return err;
     382             : 
     383          35 :   if (ctx->passphrase_cb)
     384             :     {
     385          30 :       err = _gpgme_engine_set_command_handler
     386             :         (ctx->engine, _gpgme_passphrase_command_handler, ctx, NULL);
     387          30 :       if (err)
     388           0 :         return err;
     389             :     }
     390             : 
     391          35 :   _gpgme_engine_set_status_handler (ctx->engine, decrypt_status_handler, ctx);
     392             : 
     393          35 :   return _gpgme_engine_op_decrypt (ctx->engine, cipher, plain,
     394          35 :                                    ctx->export_session_keys,
     395          35 :                                    ctx->override_session_key);
     396             : }
     397             : 
     398             : 
     399             : gpgme_error_t
     400           0 : gpgme_op_decrypt_start (gpgme_ctx_t ctx, gpgme_data_t cipher,
     401             :                         gpgme_data_t plain)
     402             : {
     403             :   gpgme_error_t err;
     404             : 
     405           0 :   TRACE_BEG2 (DEBUG_CTX, "gpgme_op_decrypt_start", ctx,
     406             :               "cipher=%p, plain=%p", cipher, plain);
     407             : 
     408           0 :   if (!ctx)
     409           0 :     return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
     410             : 
     411           0 :   err = decrypt_start (ctx, 0, cipher, plain);
     412           0 :   return TRACE_ERR (err);
     413             : }
     414             : 
     415             : 
     416             : /* Decrypt ciphertext CIPHER within CTX and store the resulting
     417             :    plaintext in PLAIN.  */
     418             : gpgme_error_t
     419          35 : gpgme_op_decrypt (gpgme_ctx_t ctx, gpgme_data_t cipher, gpgme_data_t plain)
     420             : {
     421             :   gpgme_error_t err;
     422             : 
     423          35 :   TRACE_BEG2 (DEBUG_CTX, "gpgme_op_decrypt", ctx,
     424             :               "cipher=%p, plain=%p", cipher, plain);
     425             : 
     426          35 :   if (!ctx)
     427           0 :     return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
     428             : 
     429          35 :   err = decrypt_start (ctx, 1, cipher, plain);
     430          34 :   if (!err)
     431          34 :     err = _gpgme_wait_one (ctx);
     432          35 :   return TRACE_ERR (err);
     433             : }

Generated by: LCOV version 1.11