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

Generated by: LCOV version 1.11