LCOV - code coverage report
Current view: top level - src - sign.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 126 207 60.9 %
Date: 2015-11-05 17:14:26 Functions: 10 11 90.9 %

          Line data    Source code
       1             : /* sign.c - Signing function.
       2             :    Copyright (C) 2000 Werner Koch (dd9jn)
       3             :    Copyright (C) 2001, 2002, 2003, 2004, 2007 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             : /* Suppress warning for accessing deprecated member "class".  */
      30             : #define _GPGME_IN_GPGME 1
      31             : #include "gpgme.h"
      32             : #include "context.h"
      33             : #include "ops.h"
      34             : #include "util.h"
      35             : #include "debug.h"
      36             : 
      37             : 
      38             : typedef struct
      39             : {
      40             :   struct _gpgme_op_sign_result result;
      41             : 
      42             :   /* The error code from a FAILURE status line or 0.  */
      43             :   gpg_error_t failure_code;
      44             : 
      45             :   /* A pointer to the next pointer of the last invalid signer in
      46             :      the list.  This makes appending new invalid signers painless
      47             :      while preserving the order.  */
      48             :   gpgme_invalid_key_t *last_signer_p;
      49             : 
      50             :   /* Likewise for signature information.  */
      51             :   gpgme_new_signature_t *last_sig_p;
      52             : 
      53             :   /* Flags used while processing the status lines.  */
      54             :   unsigned int ignore_inv_recp:1;
      55             :   unsigned int inv_sgnr_seen:1;
      56             :   unsigned int sig_created_seen:1;
      57             : } *op_data_t;
      58             : 
      59             : 
      60             : static void
      61          11 : release_signatures (gpgme_new_signature_t sig)
      62             : {
      63          36 :   while (sig)
      64             :     {
      65          14 :       gpgme_new_signature_t next = sig->next;
      66          14 :       free (sig->fpr);
      67          14 :       free (sig);
      68          14 :       sig = next;
      69             :     }
      70          11 : }
      71             : 
      72             : 
      73             : static void
      74          11 : release_op_data (void *hook)
      75             : {
      76          11 :   op_data_t opd = (op_data_t) hook;
      77          11 :   gpgme_invalid_key_t invalid_signer = opd->result.invalid_signers;
      78             : 
      79          22 :   while (invalid_signer)
      80             :     {
      81           0 :       gpgme_invalid_key_t next = invalid_signer->next;
      82           0 :       if (invalid_signer->fpr)
      83           0 :         free (invalid_signer->fpr);
      84           0 :       free (invalid_signer);
      85           0 :       invalid_signer = next;
      86             :     }
      87             : 
      88          11 :   release_signatures (opd->result.signatures);
      89          11 : }
      90             : 
      91             : 
      92             : gpgme_sign_result_t
      93          10 : gpgme_op_sign_result (gpgme_ctx_t ctx)
      94             : {
      95             :   void *hook;
      96             :   op_data_t opd;
      97             :   gpgme_error_t err;
      98             :   gpgme_invalid_key_t inv_key, key;
      99             :   gpgme_new_signature_t sig;
     100          10 :   unsigned int inv_signers = 0;
     101          10 :   unsigned int signatures = 0;
     102             : 
     103          10 :   TRACE_BEG (DEBUG_CTX, "gpgme_op_sign_result", ctx);
     104             : 
     105          10 :   err = _gpgme_op_data_lookup (ctx, OPDATA_SIGN, &hook, -1, NULL);
     106          10 :   opd = hook;
     107          10 :   if (err || !opd)
     108             :     {
     109           0 :       TRACE_SUC0 ("result=(null)");
     110           0 :       return NULL;
     111             :     }
     112             : 
     113          10 :   for (inv_key = opd->result.invalid_signers; inv_key; inv_key = inv_key->next)
     114           0 :     inv_signers++;
     115          23 :   for (sig = opd->result.signatures; sig; sig = sig->next)
     116          13 :     signatures++;
     117             : 
     118          10 :   if (gpgme_signers_count (ctx)
     119           3 :       && signatures + inv_signers != gpgme_signers_count (ctx))
     120             :     {
     121             :       /* In this case at least one signatures was not created perhaps
     122             :          due to a bad passphrase etc.  Thus the entire message is
     123             :          broken and should not be used.  We add the already created
     124             :          signatures to the invalid signers list and thus this case can
     125             :          be detected.  */
     126           0 :       TRACE_LOG3 ("result: invalid signers: %u, signatures: %u, count: %u",
     127             :                   inv_signers, signatures, gpgme_signers_count (ctx));
     128             : 
     129           0 :       for (sig = opd->result.signatures; sig; sig = sig->next)
     130             :         {
     131           0 :           key = calloc (1, sizeof *key);
     132           0 :           if (!key)
     133             :             {
     134           0 :               TRACE_SUC0 ("out of core; result=(null)");
     135           0 :               return NULL;
     136             :             }
     137           0 :           if (sig->fpr)
     138             :             {
     139           0 :               key->fpr = strdup (sig->fpr);
     140           0 :               if (!key->fpr)
     141             :                 {
     142           0 :                   free (key);
     143           0 :                   TRACE_SUC0 ("out of core; result=(null)");
     144           0 :                   return NULL;
     145             :                 }
     146             :             }
     147           0 :           key->reason = GPG_ERR_GENERAL;
     148             : 
     149           0 :           inv_key = opd->result.invalid_signers;
     150           0 :           if (inv_key)
     151             :             {
     152           0 :               for (; inv_key->next; inv_key = inv_key->next)
     153             :                 ;
     154           0 :               inv_key->next = key;
     155             :             }
     156             :           else
     157           0 :             opd->result.invalid_signers = key;
     158             :         }
     159             : 
     160           0 :       release_signatures (opd->result.signatures);
     161           0 :       opd->result.signatures = NULL;
     162             :     }
     163             : 
     164             :   if (_gpgme_debug_trace())
     165             :     {
     166          10 :       TRACE_LOG2 ("result: invalid signers: %i, signatures: %i",
     167             :                   inv_signers, signatures);
     168          10 :       for (inv_key=opd->result.invalid_signers; inv_key; inv_key=inv_key->next)
     169             :         {
     170           0 :           TRACE_LOG3 ("result: invalid signer: fpr=%s, reason=%s <%s>",
     171             :                       inv_key->fpr, gpgme_strerror (inv_key->reason),
     172             :                       gpgme_strsource (inv_key->reason));
     173             :         }
     174          23 :       for (sig = opd->result.signatures; sig; sig = sig->next)
     175             :         {
     176          13 :           TRACE_LOG6 ("result: signature: type=%i, pubkey_algo=%i, "
     177             :                       "hash_algo=%i, timestamp=%li, fpr=%s, sig_class=%i",
     178             :                       sig->type, sig->pubkey_algo, sig->hash_algo,
     179             :                       sig->timestamp, sig->fpr, sig->sig_class);
     180             :         }
     181             :    }
     182             : 
     183          10 :   TRACE_SUC1 ("result=%p", &opd->result);
     184          10 :   return &opd->result;
     185             : }
     186             : 
     187             : 
     188             : 
     189             : static gpgme_error_t
     190          14 : parse_sig_created (char *args, gpgme_new_signature_t *sigp,
     191             :                    gpgme_protocol_t protocol)
     192             : {
     193             :   gpgme_new_signature_t sig;
     194             :   char *tail;
     195             : 
     196          14 :   sig = malloc (sizeof (*sig));
     197          14 :   if (!sig)
     198           0 :     return gpg_error_from_syserror ();
     199             : 
     200          14 :   sig->next = NULL;
     201          14 :   switch (*args)
     202             :     {
     203             :     case 'S':
     204           7 :       sig->type = GPGME_SIG_MODE_NORMAL;
     205           7 :       break;
     206             : 
     207             :     case 'D':
     208           4 :       sig->type = GPGME_SIG_MODE_DETACH;
     209           4 :       break;
     210             : 
     211             :     case 'C':
     212           3 :       sig->type = GPGME_SIG_MODE_CLEAR;
     213           3 :       break;
     214             : 
     215             :     default:
     216             :       /* The backend engine is not behaving.  */
     217           0 :       free (sig);
     218           0 :       return trace_gpg_error (GPG_ERR_INV_ENGINE);
     219             :     }
     220             : 
     221          14 :   args++;
     222          14 :   if (*args != ' ')
     223             :     {
     224           0 :       free (sig);
     225           0 :       return trace_gpg_error (GPG_ERR_INV_ENGINE);
     226             :     }
     227             : 
     228          14 :   gpg_err_set_errno (0);
     229          14 :   sig->pubkey_algo = _gpgme_map_pk_algo (strtol (args, &tail, 0), protocol);
     230          14 :   if (errno || args == tail || *tail != ' ')
     231             :     {
     232             :       /* The crypto backend does not behave.  */
     233           0 :       free (sig);
     234           0 :       return trace_gpg_error (GPG_ERR_INV_ENGINE);
     235             :     }
     236          14 :   args = tail;
     237             : 
     238          14 :   sig->hash_algo = strtol (args, &tail, 0);
     239          14 :   if (errno || args == tail || *tail != ' ')
     240             :     {
     241             :       /* The crypto backend does not behave.  */
     242           0 :       free (sig);
     243           0 :       return trace_gpg_error (GPG_ERR_INV_ENGINE);
     244             :     }
     245          14 :   args = tail;
     246             : 
     247          14 :   sig->sig_class = strtol (args, &tail, 0);
     248          14 :   sig->class = sig->sig_class;
     249          14 :   sig->_obsolete_class = sig->sig_class;
     250          14 :   if (errno || args == tail || *tail != ' ')
     251             :     {
     252             :       /* The crypto backend does not behave.  */
     253           0 :       free (sig);
     254           0 :       return trace_gpg_error (GPG_ERR_INV_ENGINE);
     255             :     }
     256          14 :   args = tail;
     257             : 
     258          14 :   sig->timestamp = _gpgme_parse_timestamp (args, &tail);
     259          14 :   if (sig->timestamp == -1 || args == tail || *tail != ' ')
     260             :     {
     261             :       /* The crypto backend does not behave.  */
     262           0 :       free (sig);
     263           0 :       return trace_gpg_error (GPG_ERR_INV_ENGINE);
     264             :     }
     265          14 :   args = tail;
     266          42 :   while (*args == ' ')
     267          14 :     args++;
     268             : 
     269          14 :   if (!*args)
     270             :     {
     271             :       /* The crypto backend does not behave.  */
     272           0 :       free (sig);
     273           0 :       return trace_gpg_error (GPG_ERR_INV_ENGINE);
     274             :     }
     275             : 
     276          14 :   tail = strchr (args, ' ');
     277          14 :   if (tail)
     278           0 :     *tail = '\0';
     279             : 
     280          14 :   sig->fpr = strdup (args);
     281          14 :   if (!sig->fpr)
     282             :     {
     283           0 :       free (sig);
     284           0 :       return gpg_error_from_syserror ();
     285             :     }
     286          14 :   *sigp = sig;
     287          14 :   return 0;
     288             : }
     289             : 
     290             : 
     291             : gpgme_error_t
     292          61 : _gpgme_sign_status_handler (void *priv, gpgme_status_code_t code, char *args)
     293             : {
     294          61 :   gpgme_ctx_t ctx = (gpgme_ctx_t) priv;
     295             :   gpgme_error_t err;
     296             :   void *hook;
     297             :   op_data_t opd;
     298             : 
     299          61 :   err = _gpgme_passphrase_status_handler (priv, code, args);
     300          61 :   if (err)
     301           0 :     return err;
     302             : 
     303          61 :   err = _gpgme_op_data_lookup (ctx, OPDATA_SIGN, &hook, -1, NULL);
     304          61 :   opd = hook;
     305          61 :   if (err)
     306           0 :     return err;
     307             : 
     308          61 :   switch (code)
     309             :     {
     310             :     case GPGME_STATUS_SIG_CREATED:
     311          14 :       opd->sig_created_seen = 1;
     312          14 :       err = parse_sig_created (args, opd->last_sig_p, ctx->protocol);
     313          14 :       if (err)
     314           0 :         return err;
     315             : 
     316          14 :       opd->last_sig_p = &(*opd->last_sig_p)->next;
     317          14 :       break;
     318             : 
     319             :     case GPGME_STATUS_INV_RECP:
     320           0 :       if (opd->inv_sgnr_seen && opd->ignore_inv_recp)
     321           0 :         break;
     322             :       /* FALLTROUGH */
     323             :     case GPGME_STATUS_INV_SGNR:
     324           0 :       if (code == GPGME_STATUS_INV_SGNR)
     325           0 :         opd->inv_sgnr_seen = 1;
     326           0 :       err = _gpgme_parse_inv_recp (args, opd->last_signer_p);
     327           0 :       if (err)
     328           0 :         return err;
     329             : 
     330           0 :       opd->last_signer_p = &(*opd->last_signer_p)->next;
     331           0 :       break;
     332             : 
     333             :     case GPGME_STATUS_FAILURE:
     334           0 :       opd->failure_code = _gpgme_parse_failure (args);
     335           0 :       break;
     336             : 
     337             :     case GPGME_STATUS_EOF:
     338             :       /* The UI server does not send information about the created
     339             :          signature.  This is irrelevant for this protocol and thus we
     340             :          should not check for that.  */
     341          11 :       if (opd->result.invalid_signers)
     342           0 :         err = gpg_error (GPG_ERR_UNUSABLE_SECKEY);
     343          11 :       else if (!opd->sig_created_seen
     344           0 :                && ctx->protocol != GPGME_PROTOCOL_UISERVER)
     345           0 :         err = opd->failure_code? opd->failure_code:gpg_error (GPG_ERR_GENERAL);
     346          11 :       break;
     347             : 
     348             :     case GPGME_STATUS_INQUIRE_MAXLEN:
     349           0 :       if (ctx->status_cb)
     350           0 :         err = ctx->status_cb (ctx->status_cb_value, "INQUIRE_MAXLEN", args);
     351           0 :       break;
     352             : 
     353             :     default:
     354          36 :       break;
     355             :     }
     356          61 :   return err;
     357             : }
     358             : 
     359             : 
     360             : static gpgme_error_t
     361          43 : sign_status_handler (void *priv, gpgme_status_code_t code, char *args)
     362             : {
     363             :   gpgme_error_t err;
     364             : 
     365          43 :   err = _gpgme_progress_status_handler (priv, code, args);
     366          43 :   if (!err)
     367          43 :     err = _gpgme_sign_status_handler (priv, code, args);
     368          43 :   return err;
     369             : }
     370             : 
     371             : 
     372             : static gpgme_error_t
     373          11 : sign_init_result (gpgme_ctx_t ctx, int ignore_inv_recp)
     374             : {
     375             :   gpgme_error_t err;
     376             :   void *hook;
     377             :   op_data_t opd;
     378             : 
     379          11 :   err = _gpgme_op_data_lookup (ctx, OPDATA_SIGN, &hook,
     380             :                                sizeof (*opd), release_op_data);
     381          11 :   opd = hook;
     382          11 :   if (err)
     383           0 :     return err;
     384          11 :   opd->failure_code = 0;
     385          11 :   opd->last_signer_p = &opd->result.invalid_signers;
     386          11 :   opd->last_sig_p = &opd->result.signatures;
     387          11 :   opd->ignore_inv_recp = !!ignore_inv_recp;
     388          11 :   opd->inv_sgnr_seen = 0;
     389          11 :   opd->sig_created_seen = 0;
     390          11 :   return 0;
     391             : }
     392             : 
     393             : gpgme_error_t
     394           2 : _gpgme_op_sign_init_result (gpgme_ctx_t ctx)
     395             : {
     396           2 :   return sign_init_result (ctx, 0);
     397             : }
     398             : 
     399             : 
     400             : static gpgme_error_t
     401           9 : sign_start (gpgme_ctx_t ctx, int synchronous, gpgme_data_t plain,
     402             :             gpgme_data_t sig, gpgme_sig_mode_t mode)
     403             : {
     404             :   gpgme_error_t err;
     405             : 
     406           9 :   err = _gpgme_op_reset (ctx, synchronous);
     407           9 :   if (err)
     408           0 :     return err;
     409             : 
     410             :   /* If we are using the CMS protocol, we ignore the INV_RECP status
     411             :      code if a newer GPGSM is in use.  GPGMS does not support combined
     412             :      sign+encrypt and thus this can't harm.  */
     413           9 :   err = sign_init_result (ctx, (ctx->protocol == GPGME_PROTOCOL_CMS));
     414           9 :   if (err)
     415           0 :     return err;
     416             : 
     417           9 :   if (mode != GPGME_SIG_MODE_NORMAL && mode != GPGME_SIG_MODE_DETACH
     418           2 :       && mode != GPGME_SIG_MODE_CLEAR)
     419           0 :     return gpg_error (GPG_ERR_INV_VALUE);
     420             : 
     421           9 :   if (!plain)
     422           0 :     return gpg_error (GPG_ERR_NO_DATA);
     423           9 :   if (!sig)
     424           0 :     return gpg_error (GPG_ERR_INV_VALUE);
     425             : 
     426           9 :   if (ctx->passphrase_cb)
     427             :     {
     428           7 :       err = _gpgme_engine_set_command_handler
     429             :         (ctx->engine, _gpgme_passphrase_command_handler, ctx, NULL);
     430           7 :       if (err)
     431           0 :         return err;
     432             :     }
     433             : 
     434           9 :   _gpgme_engine_set_status_handler (ctx->engine, sign_status_handler,
     435             :                                     ctx);
     436             : 
     437          18 :   return _gpgme_engine_op_sign (ctx->engine, plain, sig, mode, ctx->use_armor,
     438          18 :                                 ctx->use_textmode, ctx->include_certs,
     439             :                                 ctx /* FIXME */);
     440             : }
     441             : 
     442             : 
     443             : /* Sign the plaintext PLAIN and store the signature in SIG.  */
     444             : gpgme_error_t
     445           0 : gpgme_op_sign_start (gpgme_ctx_t ctx, gpgme_data_t plain, gpgme_data_t sig,
     446             :                      gpgme_sig_mode_t mode)
     447             : {
     448             :   gpg_error_t err;
     449           0 :   TRACE_BEG3 (DEBUG_CTX, "gpgme_op_sign_start", ctx,
     450             :               "plain=%p, sig=%p, mode=%i", plain, sig, mode);
     451             : 
     452           0 :   if (!ctx)
     453           0 :     return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
     454             : 
     455           0 :   err = sign_start (ctx, 0, plain, sig, mode);
     456           0 :   return TRACE_ERR (err);
     457             : }
     458             : 
     459             : 
     460             : /* Sign the plaintext PLAIN and store the signature in SIG.  */
     461             : gpgme_error_t
     462           9 : gpgme_op_sign (gpgme_ctx_t ctx, gpgme_data_t plain, gpgme_data_t sig,
     463             :                gpgme_sig_mode_t mode)
     464             : {
     465             :   gpgme_error_t err;
     466             : 
     467           9 :   TRACE_BEG3 (DEBUG_CTX, "gpgme_op_sign", ctx,
     468             :               "plain=%p, sig=%p, mode=%i", plain, sig, mode);
     469             : 
     470           9 :   if (!ctx)
     471           0 :     return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
     472             : 
     473           9 :   err = sign_start (ctx, 1, plain, sig, mode);
     474           9 :   if (!err)
     475           9 :     err = _gpgme_wait_one (ctx);
     476           9 :   return TRACE_ERR (err);
     477             : }

Generated by: LCOV version 1.11