Пример #1
0
Файл: verify.c Проект: gpg/gpgme
/* Parse a TOFU_STATS_LONG line and store it in the last tofu info of SIG.  */
static gpgme_error_t
parse_tofu_stats_long (gpgme_signature_t sig, char *args, int raw)
{
  gpgme_error_t err;
  gpgme_tofu_info_t ti;
  char *p;

  if (!sig->tofu)
    return trace_gpg_error (GPG_ERR_INV_ENGINE); /* No TOFU_USER seen.  */
  for (ti = sig->tofu; ti->next; ti = ti->next)
    ;
  if (ti->description)
    return trace_gpg_error (GPG_ERR_INV_ENGINE); /* Already seen.  */

  err = _gpgme_decode_percent_string (args, &ti->description, 0, 0);
  if (err)
    return err;

  /* Remove the non-breaking spaces.  */
  if (!raw)
    {
      for (p = ti->description; *p; p++)
        if (*p == '~')
          *p = ' ';
    }
  return 0;
}
Пример #2
0
static gpgme_error_t
parse_enc_to (char *args, gpgme_recipient_t *recp, gpgme_protocol_t protocol)
{
  gpgme_recipient_t rec;
  char *tail;
  int i;

  rec = malloc (sizeof (*rec));
  if (!rec)
    return gpg_error_from_syserror ();

  rec->next = NULL;
  rec->keyid = rec->_keyid;
  rec->status = 0;

  for (i = 0; i < sizeof (rec->_keyid) - 1; i++)
    {
      if (args[i] == '\0' || args[i] == ' ')
	break;

      rec->_keyid[i] = args[i];
    }
  rec->_keyid[i] = '\0';

  args = &args[i];
  if (*args != '\0' && *args != ' ')
    {
      free (rec);
      return trace_gpg_error (GPG_ERR_INV_ENGINE);
    }

  while (*args == ' ')
    args++;

  if (*args)
    {
      gpg_err_set_errno (0);
      rec->pubkey_algo = _gpgme_map_pk_algo (strtol (args, &tail, 0), protocol);
      if (errno || args == tail || *tail != ' ')
	{
	  /* The crypto backend does not behave.  */
	  free (rec);
	  return trace_gpg_error (GPG_ERR_INV_ENGINE);
	}
    }

  /* FIXME: The key length is always 0 right now, so no need to parse
     it.  */

  *recp = rec;
  return 0;
}
Пример #3
0
Файл: verify.c Проект: gpg/gpgme
/* Parse a TOFU_USER line and put the info into SIG.  */
static gpgme_error_t
parse_tofu_user (gpgme_signature_t sig, char *args)
{
  gpg_error_t err;
  char *tail;
  gpgme_tofu_info_t ti, ti2;

  tail = strchr (args, ' ');
  if (!tail || tail == args)
    return trace_gpg_error (GPG_ERR_INV_ENGINE);  /* No fingerprint.  */
  *tail++ = 0;

  ti = calloc (1, sizeof *ti);
  if (!ti)
    return gpg_error_from_syserror ();

  ti->fpr = strdup (args);
  if (!ti->fpr)
    {
      free (ti);
      return gpg_error_from_syserror ();
    }

  args = tail;
  tail = strchr (args, ' ');
  if (tail == args)
    return trace_gpg_error (GPG_ERR_INV_ENGINE);  /* No addr-spec.  */
  if (tail)
    *tail = 0;

  err = _gpgme_decode_percent_string (args, &ti->address, 0, 0);
  if (err)
    {
      free (ti);
      return err;
    }

  /* Append to the tofu info list.  */
  if (!sig->tofu)
    sig->tofu = ti;
  else
    {
      for (ti2 = sig->tofu; ti2->next; ti2 = ti2->next)
        ;
      ti2->next = ti;
    }

  return 0;
}
Пример #4
0
static gpgme_error_t
gpgconf_config_load_cb (void *hook, char *line)
{
  gpgme_conf_comp_t *comp_p = hook;
  gpgme_conf_comp_t comp = *comp_p;
#define NR_FIELDS 16
  char *field[NR_FIELDS];
  int fields = 0;

  while (line && fields < NR_FIELDS)
    {
      field[fields++] = line;
      line = strchr (line, ':');
      if (line)
	*(line++) = '\0';
    }

  /* We require at least the first 3 fields.  */
  if (fields < 2)
    return trace_gpg_error (GPG_ERR_INV_ENGINE);

  /* Find the pointer to the new component in the list.  */
  while (comp && comp->next)
    comp = comp->next;
  if (comp)
    comp_p = &comp->next;

  comp = calloc (1, sizeof (*comp));
  if (!comp)
    return gpg_error_from_syserror ();
  /* Prepare return value.  */
  comp->_last_opt_p = &comp->options;
  *comp_p = comp;

  comp->name = strdup (field[0]);
  if (!comp->name)
    return gpg_error_from_syserror ();

  comp->description = strdup (field[1]);
  if (!comp->description)
    return gpg_error_from_syserror ();

  if (fields >= 3)
    {
      comp->program_name = strdup (field[2]);
      if (!comp->program_name)
	return gpg_error_from_syserror ();
    }

  return 0;
}
Пример #5
0
/* Parse a FAILURE status line and return the error code.  ARGS is
   modified to contain the location part.  */
gpgme_error_t
_gpgme_parse_failure (char *args)
{
  char *where, *which;

  where = strchr (args, ' ');
  if (!where)
    return trace_gpg_error (GPG_ERR_INV_ENGINE);

  *where = '\0';
  which = where + 1;

  where = strchr (which, ' ');
  if (where)
    *where = '\0';

  where = args;

  return atoi (which);
}
Пример #6
0
Файл: verify.c Проект: gpg/gpgme
/* Parse an error status line and if SET_STATUS is true update the
   result status as appropriate.  With SET_STATUS being false, only
   check for an error.  */
static gpgme_error_t
parse_error (gpgme_signature_t sig, char *args, int set_status)
{
  gpgme_error_t err;
  char *where = strchr (args, ' ');
  char *which;

  if (where)
    {
      *where = '\0';
      which = where + 1;

      where = strchr (which, ' ');
      if (where)
	*where = '\0';

      where = args;
    }
  else
    return trace_gpg_error (GPG_ERR_INV_ENGINE);

  err = atoi (which);

  if (!strcmp (where, "proc_pkt.plaintext")
      && gpg_err_code (err) == GPG_ERR_BAD_DATA)
    {
      /* This indicates a double plaintext.  The only solid way to
         handle this is by failing the oepration.  */
      return gpg_error (GPG_ERR_BAD_DATA);
    }
  else if (!set_status)
    ;
  else if (!strcmp (where, "verify.findkey"))
    sig->status = err;
  else if (!strcmp (where, "verify.keyusage")
	   && gpg_err_code (err) == GPG_ERR_WRONG_KEY_USAGE)
    sig->wrong_key_usage = 1;

  return 0;
}
Пример #7
0
Файл: verify.c Проект: gpg/gpgme
gpgme_error_t
_gpgme_verify_status_handler (void *priv, gpgme_status_code_t code, char *args)
{
  gpgme_ctx_t ctx = (gpgme_ctx_t) priv;
  gpgme_error_t err;
  void *hook;
  op_data_t opd;
  gpgme_signature_t sig;
  char *end;

  err = _gpgme_op_data_lookup (ctx, OPDATA_VERIFY, &hook, -1, NULL);
  opd = hook;
  if (err)
    return err;

  sig = opd->current_sig;

  switch (code)
    {
    case GPGME_STATUS_NEWSIG:
      if (sig)
        calc_sig_summary (sig);
      err = prepare_new_sig (opd);
      opd->only_newsig_seen = 1;
      return err;

    case GPGME_STATUS_GOODSIG:
    case GPGME_STATUS_EXPSIG:
    case GPGME_STATUS_EXPKEYSIG:
    case GPGME_STATUS_BADSIG:
    case GPGME_STATUS_ERRSIG:
    case GPGME_STATUS_REVKEYSIG:
      if (sig && !opd->did_prepare_new_sig)
	calc_sig_summary (sig);
      opd->only_newsig_seen = 0;
      return parse_new_sig (opd, code, args, ctx->protocol);

    case GPGME_STATUS_VALIDSIG:
      opd->only_newsig_seen = 0;
      return sig ? parse_valid_sig (sig, args, ctx->protocol)
	: trace_gpg_error (GPG_ERR_INV_ENGINE);

    case GPGME_STATUS_NODATA:
      opd->only_newsig_seen = 0;
      if (!sig)
	return gpg_error (GPG_ERR_NO_DATA);
      sig->status = gpg_error (GPG_ERR_NO_DATA);
      break;

    case GPGME_STATUS_UNEXPECTED:
      opd->only_newsig_seen = 0;
      if (!sig)
	return gpg_error (GPG_ERR_GENERAL);
      sig->status = gpg_error (GPG_ERR_NO_DATA);
      break;

    case GPGME_STATUS_NOTATION_NAME:
    case GPGME_STATUS_NOTATION_FLAGS:
    case GPGME_STATUS_NOTATION_DATA:
    case GPGME_STATUS_POLICY_URL:
      opd->only_newsig_seen = 0;
      return sig ? parse_notation (sig, code, args)
	: trace_gpg_error (GPG_ERR_INV_ENGINE);

    case GPGME_STATUS_TRUST_UNDEFINED:
    case GPGME_STATUS_TRUST_NEVER:
    case GPGME_STATUS_TRUST_MARGINAL:
    case GPGME_STATUS_TRUST_FULLY:
    case GPGME_STATUS_TRUST_ULTIMATE:
      opd->only_newsig_seen = 0;
      return sig ? parse_trust (sig, code, args)
	: trace_gpg_error (GPG_ERR_INV_ENGINE);

    case GPGME_STATUS_PKA_TRUST_BAD:
    case GPGME_STATUS_PKA_TRUST_GOOD:
      opd->only_newsig_seen = 0;
      /* Check that we only get one of these status codes per
         signature; if not the crypto backend misbehaves.  */
      if (!sig || sig->pka_trust || sig->pka_address)
        return trace_gpg_error (GPG_ERR_INV_ENGINE);
      sig->pka_trust = code == GPGME_STATUS_PKA_TRUST_GOOD? 2 : 1;
      end = strchr (args, ' ');
      if (end)
        *end = 0;
      sig->pka_address = strdup (args);
      break;

    case GPGME_STATUS_TOFU_USER:
      opd->only_newsig_seen = 0;
      return sig ? parse_tofu_user (sig, args)
        /*    */ : trace_gpg_error (GPG_ERR_INV_ENGINE);

    case GPGME_STATUS_TOFU_STATS:
      opd->only_newsig_seen = 0;
      return sig ? parse_tofu_stats (sig, args)
        /*    */ : trace_gpg_error (GPG_ERR_INV_ENGINE);

    case GPGME_STATUS_TOFU_STATS_LONG:
      opd->only_newsig_seen = 0;
      return sig ? parse_tofu_stats_long (sig, args, ctx->raw_description)
        /*    */ : trace_gpg_error (GPG_ERR_INV_ENGINE);

    case GPGME_STATUS_ERROR:
      opd->only_newsig_seen = 0;
      /* Some  error stati are informational, so we don't return an
         error code if we are not ready to process this status.  */
      return parse_error (sig, args, !!sig );

    case GPGME_STATUS_FAILURE:
      opd->failure_code = _gpgme_parse_failure (args);
      break;

    case GPGME_STATUS_EOF:
      if (sig && !opd->did_prepare_new_sig)
	calc_sig_summary (sig);
      if (opd->only_newsig_seen && sig)
        {
          gpgme_signature_t sig2;
          /* The last signature has no valid information - remove it
             from the list. */
          assert (!sig->next);
          if (sig == opd->result.signatures)
            opd->result.signatures = NULL;
          else
            {
              for (sig2 = opd->result.signatures; sig2; sig2 = sig2->next)
                if (sig2->next == sig)
                  {
                    sig2->next = NULL;
                    break;
                  }
            }
          /* Note that there is no need to release the members of SIG
             because we won't be here if they have been set. */
          free (sig);
          opd->current_sig = NULL;
        }
      opd->only_newsig_seen = 0;
      if (opd->failure_code)
        return opd->failure_code;
      break;

    case GPGME_STATUS_PLAINTEXT:
      if (++opd->plaintext_seen > 1)
        return gpg_error (GPG_ERR_BAD_DATA);
      err = _gpgme_parse_plaintext (args, &opd->result.file_name);
      if (err)
	return err;

    default:
      break;
    }
  return 0;
}
Пример #8
0
Файл: verify.c Проект: gpg/gpgme
/* Parse a TOFU_STATS line and store it in the last tofu info of SIG.
 *
 *   TOFU_STATS <validity> <sign-count> 0 [<policy> [<tm1> <tm2>]]
 */
static gpgme_error_t
parse_tofu_stats (gpgme_signature_t sig, char *args)
{
  gpgme_error_t err;
  gpgme_tofu_info_t ti;
  char *field[6];
  int nfields;
  unsigned long uval;

  if (!sig->tofu)
    return trace_gpg_error (GPG_ERR_INV_ENGINE); /* No TOFU_USER seen.  */
  for (ti = sig->tofu; ti->next; ti = ti->next)
    ;
  if (ti->firstseen || ti->signcount || ti->validity || ti->policy)
    return trace_gpg_error (GPG_ERR_INV_ENGINE); /* Already seen.  */

  nfields = _gpgme_split_fields (args, field, DIM (field));
  if (nfields < 3)
    return trace_gpg_error (GPG_ERR_INV_ENGINE); /* Required args missing.  */

  /* Note that we allow a value of up to 7 which is what we can store
   * in the ti->validity.  */
  err = _gpgme_strtoul_field (field[0], &uval);
  if (err || uval > 7)
    return trace_gpg_error (GPG_ERR_INV_ENGINE);
  ti->validity = uval;

  /* Parse the sign-count.  */
  err = _gpgme_strtoul_field (field[1], &uval);
  if (err)
    return trace_gpg_error (GPG_ERR_INV_ENGINE);
  if (uval > USHRT_MAX)
    uval = USHRT_MAX;
  ti->signcount = uval;

  /* We skip the 0, which is RFU.  */

  if (nfields == 3)
    return 0; /* All mandatory fields parsed.  */

  /* Parse the policy.  */
  if (!strcmp (field[3], "none"))
    ti->policy = GPGME_TOFU_POLICY_NONE;
  else if (!strcmp (field[3], "auto"))
    ti->policy = GPGME_TOFU_POLICY_AUTO;
  else if (!strcmp (field[3], "good"))
    ti->policy = GPGME_TOFU_POLICY_GOOD;
  else if (!strcmp (field[3], "bad"))
    ti->policy = GPGME_TOFU_POLICY_BAD;
  else if (!strcmp (field[3], "ask"))
    ti->policy = GPGME_TOFU_POLICY_ASK;
  else /* "unknown" and invalid policy strings.  */
    ti->policy = GPGME_TOFU_POLICY_UNKNOWN;

  if (nfields == 4)
    return 0; /* No more optional fields.  */

  /* Parse first and last seen (none or both are required).  */
  if (nfields < 6)
    return trace_gpg_error (GPG_ERR_INV_ENGINE); /* "tm2" missing.  */
  err = _gpgme_strtoul_field (field[4], &uval);
  if (err)
    return trace_gpg_error (GPG_ERR_INV_ENGINE);
  if (uval > UINT_MAX)
    uval = UINT_MAX;
  ti->firstseen = uval;
  err = _gpgme_strtoul_field (field[5], &uval);
  if (err)
    return trace_gpg_error (GPG_ERR_INV_ENGINE);
  if (uval > UINT_MAX)
    uval = UINT_MAX;
  ti->lastseen = uval;

  return 0;
}
Пример #9
0
Файл: verify.c Проект: gpg/gpgme
static gpgme_error_t
parse_notation (gpgme_signature_t sig, gpgme_status_code_t code, char *args)
{
  gpgme_error_t err;
  gpgme_sig_notation_t *lastp = &sig->notations;
  gpgme_sig_notation_t notation = sig->notations;
  char *p;

  if (code == GPGME_STATUS_NOTATION_NAME || code == GPGME_STATUS_POLICY_URL)
    {
      p = strchr (args, ' ');
      if (p)
        *p = '\0';

      /* FIXME: We could keep a pointer to the last notation in the list.  */
      while (notation && notation->value)
	{
	  lastp = &notation->next;
	  notation = notation->next;
	}

      if (notation)
	/* There is another notation name without data for the
	   previous one.  The crypto backend misbehaves.  */
	return trace_gpg_error (GPG_ERR_INV_ENGINE);

      err = _gpgme_sig_notation_create (&notation, NULL, 0, NULL, 0, 0);
      if (err)
	return err;

      if (code == GPGME_STATUS_NOTATION_NAME)
	{
	  err = _gpgme_decode_percent_string (args, &notation->name, 0, 0);
	  if (err)
	    {
	      _gpgme_sig_notation_free (notation);
	      return err;
	    }

	  notation->name_len = strlen (notation->name);

	  /* Set default flags for use with older gpg versions which
           * do not emit a NOTATIONS_FLAG line.  */
	  notation->flags = GPGME_SIG_NOTATION_HUMAN_READABLE;
	  notation->human_readable = 1;
	}
      else
	{
	  /* This is a policy URL.  */

	  err = _gpgme_decode_percent_string (args, &notation->value, 0, 0);
	  if (err)
	    {
	      _gpgme_sig_notation_free (notation);
	      return err;
	    }

	  notation->value_len = strlen (notation->value);
	}
      *lastp = notation;
    }
  else if (code == GPGME_STATUS_NOTATION_FLAGS)
    {
      char *field[2];

      while (notation && notation->next)
	{
	  lastp = &notation->next;
	  notation = notation->next;
	}

      if (!notation || !notation->name)
        { /* There are notation flags without a previous notation name.
           * The crypto backend misbehaves.  */
          return trace_gpg_error (GPG_ERR_INV_ENGINE);
        }
      if (_gpgme_split_fields (args, field, DIM (field)) < 2)
        { /* Required args missing.  */
          return trace_gpg_error (GPG_ERR_INV_ENGINE);
        }
      notation->flags = 0;
      if (atoi (field[0]))
        {
          notation->flags |= GPGME_SIG_NOTATION_CRITICAL;
          notation->critical = 1;
        }
      if (atoi (field[1]))
        {
          notation->flags |= GPGME_SIG_NOTATION_HUMAN_READABLE;
          notation->human_readable = 1;
        }
    }
  else if (code == GPGME_STATUS_NOTATION_DATA)
    {
      int len = strlen (args) + 1;
      char *dest;

      /* FIXME: We could keep a pointer to the last notation in the list.  */
      while (notation && notation->next)
	{
	  lastp = &notation->next;
	  notation = notation->next;
	}

      if (!notation || !notation->name)
	/* There is notation data without a previous notation
	   name.  The crypto backend misbehaves.  */
	return trace_gpg_error (GPG_ERR_INV_ENGINE);

      if (!notation->value)
	{
	  dest = notation->value = malloc (len);
	  if (!dest)
	    return gpg_error_from_syserror ();
	}
      else
	{
	  int cur_len = strlen (notation->value);
	  dest = realloc (notation->value, len + strlen (notation->value));
	  if (!dest)
	    return gpg_error_from_syserror ();
	  notation->value = dest;
	  dest += cur_len;
	}

      err = _gpgme_decode_percent_string (args, &dest, len, 0);
      if (err)
	return err;

      notation->value_len += strlen (dest);
    }
  else
    return trace_gpg_error (GPG_ERR_INV_ENGINE);
  return 0;
}
Пример #10
0
Файл: verify.c Проект: gpg/gpgme
static gpgme_error_t
parse_valid_sig (gpgme_signature_t sig, char *args, gpgme_protocol_t protocol)
{
  char *end = strchr (args, ' ');
  if (end)
    {
      *end = '\0';
      end++;
    }

  if (!*args)
    /* We require at least the fingerprint.  */
    return gpg_error (GPG_ERR_GENERAL);

  if (sig->fpr)
    free (sig->fpr);
  sig->fpr = strdup (args);
  if (!sig->fpr)
    return gpg_error_from_syserror ();

  /* Skip the creation date.  */
  end = strchr (end, ' ');
  if (end)
    {
      char *tail;

      sig->timestamp = _gpgme_parse_timestamp (end, &tail);
      if (sig->timestamp == -1 || end == tail || (*tail && *tail != ' '))
	return trace_gpg_error (GPG_ERR_INV_ENGINE);
      end = tail;

      sig->exp_timestamp = _gpgme_parse_timestamp (end, &tail);
      if (sig->exp_timestamp == -1 || end == tail || (*tail && *tail != ' '))
	return trace_gpg_error (GPG_ERR_INV_ENGINE);
      end = tail;

      while (*end == ' ')
	end++;
      /* Skip the signature version.  */
      end = strchr (end, ' ');
      if (end)
	{
	  while (*end == ' ')
	    end++;

	  /* Skip the reserved field.  */
	  end = strchr (end, ' ');
	  if (end)
	    {
	      /* Parse the pubkey algo.  */
	      gpg_err_set_errno (0);
	      sig->pubkey_algo = _gpgme_map_pk_algo (strtol (end, &tail, 0),
                                                     protocol);
	      if (errno || end == tail || *tail != ' ')
		return trace_gpg_error (GPG_ERR_INV_ENGINE);
	      end = tail;

	      while (*end == ' ')
		end++;

	      if (*end)
		{
		  /* Parse the hash algo.  */

		  gpg_err_set_errno (0);
		  sig->hash_algo = strtol (end, &tail, 0);
		  if (errno || end == tail || *tail != ' ')
		    return trace_gpg_error (GPG_ERR_INV_ENGINE);
		  end = tail;
		}
	    }
	}
    }
  return 0;
}
Пример #11
0
Файл: verify.c Проект: gpg/gpgme
static gpgme_error_t
parse_new_sig (op_data_t opd, gpgme_status_code_t code, char *args,
               gpgme_protocol_t protocol)
{
  gpgme_signature_t sig;
  char *end = strchr (args, ' ');
  char *tail;

  if (end)
    {
      *end = '\0';
      end++;
    }

  if (!opd->did_prepare_new_sig)
    {
      gpg_error_t err;

      err = prepare_new_sig (opd);
      if (err)
        return err;
    }
  assert (opd->did_prepare_new_sig);
  opd->did_prepare_new_sig = 0;

  assert (opd->current_sig);
  sig = opd->current_sig;

  /* FIXME: We should set the source of the state.  */
  switch (code)
    {
    case GPGME_STATUS_GOODSIG:
      sig->status = gpg_error (GPG_ERR_NO_ERROR);
      break;

    case GPGME_STATUS_EXPSIG:
      sig->status = gpg_error (GPG_ERR_SIG_EXPIRED);
      break;

    case GPGME_STATUS_EXPKEYSIG:
      sig->status = gpg_error (GPG_ERR_KEY_EXPIRED);
      break;

    case GPGME_STATUS_BADSIG:
      sig->status = gpg_error (GPG_ERR_BAD_SIGNATURE);
      break;

    case GPGME_STATUS_REVKEYSIG:
      sig->status = gpg_error (GPG_ERR_CERT_REVOKED);
      break;

    case GPGME_STATUS_ERRSIG:
      /* Parse the pubkey algo.  */
      if (!end)
	goto parse_err_sig_fail;
      gpg_err_set_errno (0);
      sig->pubkey_algo = _gpgme_map_pk_algo (strtol (end, &tail, 0), protocol);
      if (errno || end == tail || *tail != ' ')
	goto parse_err_sig_fail;
      end = tail;
      while (*end == ' ')
	end++;

      /* Parse the hash algo.  */
      if (!*end)
	goto parse_err_sig_fail;
      gpg_err_set_errno (0);
      sig->hash_algo = strtol (end, &tail, 0);
      if (errno || end == tail || *tail != ' ')
	goto parse_err_sig_fail;
      end = tail;
      while (*end == ' ')
	end++;

      /* Skip the sig class.  */
      end = strchr (end, ' ');
      if (!end)
	goto parse_err_sig_fail;
      while (*end == ' ')
	end++;

      /* Parse the timestamp.  */
      sig->timestamp = _gpgme_parse_timestamp (end, &tail);
      if (sig->timestamp == -1 || end == tail || (*tail && *tail != ' '))
	return trace_gpg_error (GPG_ERR_INV_ENGINE);
      end = tail;
      while (*end == ' ')
	end++;

      /* Parse the return code.  */
      if (end[0] && (!end[1] || end[1] == ' '))
	{
	  switch (end[0])
	    {
	    case '4':
	      sig->status = gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM);
	      break;

	    case '9':
	      sig->status = gpg_error (GPG_ERR_NO_PUBKEY);
	      break;

	    default:
	      sig->status = gpg_error (GPG_ERR_GENERAL);
	    }
	}
      else
	goto parse_err_sig_fail;

      goto parse_err_sig_ok;

    parse_err_sig_fail:
      sig->status = gpg_error (GPG_ERR_GENERAL);
    parse_err_sig_ok:
      break;

    default:
      return gpg_error (GPG_ERR_GENERAL);
    }

  if (*args)
    {
      sig->fpr = strdup (args);
      if (!sig->fpr)
	return gpg_error_from_syserror ();
    }
  return 0;
}
Пример #12
0
static gpgme_error_t
gpgconf_config_load_cb2 (void *hook, char *line)
{
  gpgme_error_t err;
  gpgme_conf_comp_t comp = hook;
  gpgme_conf_opt_t *opt_p = comp->_last_opt_p;
  gpgme_conf_opt_t opt;
#define NR_FIELDS 16
  char *field[NR_FIELDS];
  int fields = 0;

  while (line && fields < NR_FIELDS)
    {
      field[fields++] = line;
      line = strchr (line, ':');
      if (line)
	*(line++) = '\0';
    }

  /* We require at least the first 10 fields.  */
  if (fields < 10)
    return trace_gpg_error (GPG_ERR_INV_ENGINE);

  opt = calloc (1, sizeof (*opt));
  if (!opt)
    return gpg_error_from_syserror ();

  comp->_last_opt_p = &opt->next;
  *opt_p = opt;

  if (field[0][0])
    {
      opt->name = strdup (field[0]);
      if (!opt->name)
	return gpg_error_from_syserror ();
    }

  opt->flags = strtoul (field[1], NULL, 0);

  opt->level = strtoul (field[2], NULL, 0);

  if (field[3][0])
    {
      opt->description = strdup (field[3]);
      if (!opt->description)
	return gpg_error_from_syserror ();
    }

  opt->type = strtoul (field[4], NULL, 0);

  opt->alt_type = strtoul (field[5], NULL, 0);

  if (field[6][0])
    {
      opt->argname = strdup (field[6]);
      if (!opt->argname)
	return gpg_error_from_syserror ();
    }

  if (opt->flags & GPGME_CONF_DEFAULT)
    {
      err = gpgconf_parse_option (opt, &opt->default_value, field[7]);
      if (err)
	return err;
    }
  else if ((opt->flags & GPGME_CONF_DEFAULT_DESC) && field[7][0])
    {
      opt->default_description = strdup (field[7]);
      if (!opt->default_description)
	return gpg_error_from_syserror ();
    }

  if (opt->flags & GPGME_CONF_NO_ARG_DESC)
    {
      opt->no_arg_description = strdup (field[8]);
      if (!opt->no_arg_description)
	return gpg_error_from_syserror ();
    }
  else
    {
      err = gpgconf_parse_option (opt, &opt->no_arg_value, field[8]);
      if (err)
	return err;
    }

  err = gpgconf_parse_option (opt, &opt->value, field[9]);
  if (err)
    return err;

  return 0;
}
Пример #13
0
gpgme_error_t
_gpgme_decrypt_status_handler (void *priv, gpgme_status_code_t code,
			       char *args)
{
  gpgme_ctx_t ctx = (gpgme_ctx_t) priv;
  gpgme_error_t err;
  void *hook;
  op_data_t opd;

  err = _gpgme_passphrase_status_handler (priv, code, args);
  if (err)
    return err;

  err = _gpgme_op_data_lookup (ctx, OPDATA_DECRYPT, &hook, -1, NULL);
  opd = hook;
  if (err)
    return err;

  switch (code)
    {
    case GPGME_STATUS_FAILURE:
      opd->failure_code = _gpgme_parse_failure (args);
      break;

    case GPGME_STATUS_EOF:
      /* FIXME: These error values should probably be attributed to
	 the underlying crypto engine (as error source).  */
      if (opd->failed)
	return gpg_error (GPG_ERR_DECRYPT_FAILED);
      else if (!opd->okay)
	return gpg_error (GPG_ERR_NO_DATA);
      else if (opd->failure_code)
        return opd->failure_code;
      break;

    case GPGME_STATUS_DECRYPTION_INFO:
      /* Fixme: Provide a way to return the used symmetric algorithm. */
      break;

    case GPGME_STATUS_DECRYPTION_OKAY:
      opd->okay = 1;
      break;

    case GPGME_STATUS_DECRYPTION_FAILED:
      opd->failed = 1;
      break;

    case GPGME_STATUS_ERROR:
      /* Note that this is an informational status code which should
         not lead to an error return unless it is something not
         related to the backend.  */
      {
	const char d_alg[] = "decrypt.algorithm";
	const char k_alg[] = "decrypt.keyusage";

	if (!strncmp (args, d_alg, sizeof (d_alg) - 1))
	  {
	    args += sizeof (d_alg) - 1;
	    while (*args == ' ')
	      args++;

	    if (gpg_err_code (atoi (args)) == GPG_ERR_UNSUPPORTED_ALGORITHM)
	      {
		char *end;

		while (*args && *args != ' ')
		  args++;
		while (*args == ' ')
		  args++;

		end = strchr (args, ' ');
		if (end)
		  *end = '\0';

		if (!(*args == '?' && *(args + 1) == '\0'))
		  {
		    opd->result.unsupported_algorithm = strdup (args);
		    if (!opd->result.unsupported_algorithm)
		      return gpg_error_from_syserror ();
		  }
	      }
	  }
	else if (!strncmp (args, k_alg, sizeof (k_alg) - 1))
	  {
	    args += sizeof (k_alg) - 1;
	    while (*args == ' ')
	      args++;

	    if (gpg_err_code (atoi (args)) == GPG_ERR_WRONG_KEY_USAGE)
	      opd->result.wrong_key_usage = 1;
	  }
      }
      break;

    case GPGME_STATUS_ENC_TO:
      err = parse_enc_to (args, opd->last_recipient_p, ctx->protocol);
      if (err)
	return err;

      opd->last_recipient_p = &(*opd->last_recipient_p)->next;
      break;

    case GPGME_STATUS_NO_SECKEY:
      {
	gpgme_recipient_t rec = opd->result.recipients;

	while (rec)
	  {
	    if (!strcmp (rec->keyid, args))
	      {
		rec->status = gpg_error (GPG_ERR_NO_SECKEY);
		break;
	      }
	    rec = rec->next;
	  }
	/* FIXME: Is this ok?  */
	if (!rec)
	  return trace_gpg_error (GPG_ERR_INV_ENGINE);
      }
      break;

    case GPGME_STATUS_PLAINTEXT:
      err = _gpgme_parse_plaintext (args, &opd->result.file_name);
      if (err)
	return err;
      break;

    case GPGME_STATUS_INQUIRE_MAXLEN:
      if (ctx->status_cb)
        {
          err = ctx->status_cb (ctx->status_cb_value, "INQUIRE_MAXLEN", args);
          if (err)
            return err;
        }
      break;

    default:
      break;
    }

  return 0;
}
Пример #14
0
/* Parse a notation or policy URL subpacket.  If the packet type is
   not known, return no error but NULL in NOTATION.  */
gpgme_error_t
_gpgme_parse_notation (gpgme_sig_notation_t *notationp,
		       int type, int pkflags, int len, char *data)
{
  gpgme_error_t err;
  char *name = NULL;
  int name_len = 0;
  char *value = NULL;
  int value_len = 0;
  gpgme_sig_notation_flags_t flags = 0;
  char *decoded_data;
  unsigned char *bdata;

  /* Type 20: Notation data.  */
  /* Type 26: Policy URL.  */
  if (type != 20 && type != 26)
    {
      *notationp = NULL;
      return 0;
    }

  /* A few simple sanity checks.  */
  if (len > strlen (data))
    return trace_gpg_error (GPG_ERR_INV_ENGINE);

  /* See below for the format of a notation subpacket.  It has at
     least four octets of flags and two times two octets of length
     information.  */
  if (type == 20 && len < 4 + 2 + 2)
    return trace_gpg_error (GPG_ERR_INV_ENGINE);

  err = _gpgme_decode_percent_string (data, &decoded_data, 0, 1);
  if (err)
    return err;
  bdata = (unsigned char *) decoded_data;

  /* Flags common to notation data and policy URL.  */
  if (pkflags & GNUPG_SPK_CRITICAL)
    flags |= GPGME_SIG_NOTATION_CRITICAL;

  /* This information is relevant in parsing multi-octet numbers below:

     3.1. Scalar numbers

     Scalar numbers are unsigned, and are always stored in big-endian
     format.  Using n[k] to refer to the kth octet being interpreted,
     the value of a two-octet scalar is ((n[0] << 8) + n[1]).  The
     value of a four-octet scalar is ((n[0] << 24) + (n[1] << 16) +
     (n[2] << 8) + n[3]).

     From RFC2440: OpenPGP Message Format.  Copyright (C) The Internet
     Society (1998).  All Rights Reserved.  */
#define RFC2440_GET_WORD(chr) ((((int)((unsigned char *)(chr))[0]) << 8) \
			       + ((int)((unsigned char *)(chr))[1]))

  if (type == 20)
    {
      /* 5.2.3.15. Notation Data

	 (4 octets of flags, 2 octets of name length (M),
	 2 octets of value length (N), M octets of name data,
	 N octets of value data)

	 [...] The "flags" field holds four octets of flags.
	 All undefined flags MUST be zero. Defined flags are:

	 First octet: 0x80 = human-readable. [...]
	 Other octets:  none.

	 From RFC2440: OpenPGP Message Format.  Copyright (C) The
	 Internet Society (1998).  All Rights Reserved.  */

      int chr;

      /* First octet of flags.  */
#define RFC2440_SPK20_FLAG1_HUMAN_READABLE 0x80

      chr = *bdata;
      bdata++;

      if (chr & RFC2440_SPK20_FLAG1_HUMAN_READABLE)
	flags |= GPGME_SIG_NOTATION_HUMAN_READABLE;

      /* The second, third and four octet of flags are unused.  */
      bdata++;
      bdata++;
      bdata++;

      name_len = RFC2440_GET_WORD (bdata);
      bdata += 2;

      value_len = RFC2440_GET_WORD (bdata);
      bdata += 2;

      /* Small sanity check.  */
      if (4 + 2 + 2 + name_len + value_len > len)
	{
	  free (decoded_data);
	  return trace_gpg_error (GPG_ERR_INV_ENGINE);
	}

      name = (char *) bdata;
      bdata += name_len;

      value = (char *) bdata;
    }
  else
    {
      /* Type is 26.  */

      /* NAME is NULL, name_len is 0.  */

      value = (char *) bdata;
      value_len = strlen (value);
    }

  err = _gpgme_sig_notation_create (notationp, name, name_len,
				    value, value_len, flags);

  free (decoded_data);
  return err;
}
Пример #15
0
static gpgme_error_t
parse_import (char *args, gpgme_import_status_t *import_status, int problem)
{
  gpgme_import_status_t import;
  char *tail;
  long int nr;

  import = malloc (sizeof (*import));
  if (!import)
    return gpg_error_from_syserror ();
  import->next = NULL;

  gpg_err_set_errno (0);
  nr = strtol (args, &tail, 0);
  if (errno || args == tail || *tail != ' ')
    {
      /* The crypto backend does not behave.  */
      free (import);
      return trace_gpg_error (GPG_ERR_INV_ENGINE);
    }
  args = tail;

  if (problem)
    {
      switch (nr)
	{
	case 0:
	case 4:
	default:
	  import->result = gpg_error (GPG_ERR_GENERAL);
	  break;

	case 1:
	  import->result = gpg_error (GPG_ERR_BAD_CERT);
	  break;

	case 2:
	  import->result = gpg_error (GPG_ERR_MISSING_ISSUER_CERT);
	  break;

	case 3:
	  import->result = gpg_error (GPG_ERR_BAD_CERT_CHAIN);
	  break;
	}
      import->status = 0;
    }
  else
    {
      import->result = gpg_error (GPG_ERR_NO_ERROR);
      import->status = nr;
    }

  while (*args == ' ')
    args++;
  tail = strchr (args, ' ');
  if (tail)
    *tail = '\0';

  import->fpr = strdup (args);
  if (!import->fpr)
    {
      free (import);
      return gpg_error_from_syserror ();
    }

  *import_status = import;
  return 0;
}
Пример #16
0
/* Parse the INV_RECP or INV-SNDR status line in ARGS and return the
   result in KEY.  */
gpgme_error_t
_gpgme_parse_inv_recp (char *args, gpgme_invalid_key_t *key)
{
  gpgme_invalid_key_t inv_key;
  char *tail;
  long int reason;

  inv_key = malloc (sizeof (*inv_key));
  if (!inv_key)
    return gpg_error_from_syserror ();
  inv_key->next = NULL;
  gpg_err_set_errno (0);
  reason = strtol (args, &tail, 0);
  if (errno || args == tail || (*tail && *tail != ' '))
    {
      /* The crypto backend does not behave.  */
      free (inv_key);
      return trace_gpg_error (GPG_ERR_INV_ENGINE);
    }

  switch (reason)
    {
    default:
    case 0:
      inv_key->reason = gpg_error (GPG_ERR_GENERAL);
      break;

    case 1:
      inv_key->reason = gpg_error (GPG_ERR_NO_PUBKEY);
      break;

    case 2:
      inv_key->reason = gpg_error (GPG_ERR_AMBIGUOUS_NAME);
      break;

    case 3:
      inv_key->reason = gpg_error (GPG_ERR_WRONG_KEY_USAGE);
      break;

    case 4:
      inv_key->reason = gpg_error (GPG_ERR_CERT_REVOKED);
      break;

    case 5:
      inv_key->reason = gpg_error (GPG_ERR_CERT_EXPIRED);
      break;

    case 6:
      inv_key->reason = gpg_error (GPG_ERR_NO_CRL_KNOWN);
      break;

    case 7:
      inv_key->reason = gpg_error (GPG_ERR_CRL_TOO_OLD);
      break;

    case 8:
      inv_key->reason = gpg_error (GPG_ERR_NO_POLICY_MATCH);
      break;

    case 9:
      inv_key->reason = gpg_error (GPG_ERR_NO_SECKEY);
      break;

    case 10:
      inv_key->reason = gpg_error (GPG_ERR_PUBKEY_NOT_TRUSTED);
      break;

    case 11:
      inv_key->reason = gpg_error (GPG_ERR_MISSING_CERT);
      break;

    case 12:
      inv_key->reason = gpg_error (GPG_ERR_MISSING_ISSUER_CERT);
      break;

    case 13:
      inv_key->reason = gpg_error (252); /*GPG_ERR_KEY_DISABLED*/
      break;

    case 14:
      inv_key->reason = gpg_error (GPG_ERR_INV_USER_ID);
      break;
    }

  while (*tail && *tail == ' ')
    tail++;
  if (*tail)
    {
      inv_key->fpr = strdup (tail);
      if (!inv_key->fpr)
	{
	  free (inv_key);
	  return gpg_error_from_syserror ();
	}
    }
  else
    inv_key->fpr = NULL;

  *key = inv_key;
  return 0;
}