Blame src/sig-notation.c

Packit Service 672cf4
/* sig-notation.c - Signature notation data support.
Packit Service 0ef63b
 * Copyright (C) 2005 g10 Code GmbH
Packit Service 0ef63b
 *
Packit Service 0ef63b
 * This file is part of GPGME.
Packit Service 0ef63b
 *
Packit Service 0ef63b
 * GPGME is free software; you can redistribute it and/or modify it
Packit Service 0ef63b
 * under the terms of the GNU Lesser General Public License as
Packit Service 0ef63b
 * published by the Free Software Foundation; either version 2.1 of
Packit Service 0ef63b
 * the License, or (at your option) any later version.
Packit Service 0ef63b
 *
Packit Service 0ef63b
 * GPGME is distributed in the hope that it will be useful, but
Packit Service 0ef63b
 * WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 0ef63b
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service 0ef63b
 * Lesser General Public License for more details.
Packit Service 0ef63b
 *
Packit Service 0ef63b
 * You should have received a copy of the GNU Lesser General Public
Packit Service 0ef63b
 * License along with this program; if not, see <https://gnu.org/licenses/>.
Packit Service 0ef63b
 * SPDX-License-Identifier: LGPL-2.1-or-later
Packit Service 0ef63b
 */
Packit Service 672cf4
Packit Service 672cf4
#if HAVE_CONFIG_H
Packit Service 672cf4
#include <config.h>
Packit Service 672cf4
#endif
Packit Service 672cf4
#include <stdlib.h>
Packit Service 672cf4
#include <string.h>
Packit Service 672cf4
#include <errno.h>
Packit Service 672cf4
#include <assert.h>
Packit Service 672cf4
Packit Service 672cf4
#include "gpgme.h"
Packit Service 672cf4
#include "util.h"
Packit Service 672cf4
#include "context.h"
Packit Service 672cf4
#include "ops.h"
Packit Service 672cf4
#include "debug.h"
Packit Service 672cf4
Packit Service 672cf4

Packit Service 672cf4
/* Free the signature notation object and all associated resources.
Packit Service 672cf4
   The object must already be removed from any linked list as the next
Packit Service 672cf4
   pointer is ignored.  */
Packit Service 672cf4
void
Packit Service 672cf4
_gpgme_sig_notation_free (gpgme_sig_notation_t notation)
Packit Service 672cf4
{
Packit Service 672cf4
  if (notation->name)
Packit Service 672cf4
    free (notation->name);
Packit Service 672cf4
Packit Service 672cf4
  if (notation->value)
Packit Service 672cf4
    free (notation->value);
Packit Service 672cf4
Packit Service 672cf4
  free (notation);
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4

Packit Service 672cf4
/* Set the flags of NOTATION to FLAGS.  */
Packit Service 672cf4
static void
Packit Service 672cf4
sig_notation_set_flags (gpgme_sig_notation_t notation,
Packit Service 672cf4
			gpgme_sig_notation_flags_t flags)
Packit Service 672cf4
{
Packit Service 672cf4
  /* We copy the flags into individual bits to make them easier
Packit Service 672cf4
     accessible individually for the user.  */
Packit Service 672cf4
  notation->human_readable = flags & GPGME_SIG_NOTATION_HUMAN_READABLE ? 1 : 0;
Packit Service 672cf4
  notation->critical = flags & GPGME_SIG_NOTATION_CRITICAL ? 1 : 0;
Packit Service 672cf4
Packit Service 672cf4
  notation->flags = flags;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
/* Create a new, empty signature notation data object.  */
Packit Service 672cf4
gpgme_error_t
Packit Service 672cf4
_gpgme_sig_notation_create (gpgme_sig_notation_t *notationp,
Packit Service 672cf4
			    const char *name, int name_len,
Packit Service 672cf4
			    const char *value, int value_len,
Packit Service 672cf4
			    gpgme_sig_notation_flags_t flags)
Packit Service 672cf4
{
Packit Service 672cf4
  gpgme_error_t err = 0;
Packit Service 672cf4
  gpgme_sig_notation_t notation;
Packit Service 672cf4
Packit Service 672cf4
  /* Currently, we require all notations to be human-readable.  */
Packit Service 672cf4
  if (name && !(flags & GPGME_SIG_NOTATION_HUMAN_READABLE))
Packit Service 672cf4
    return gpg_error (GPG_ERR_INV_VALUE);
Packit Service 672cf4
Packit Service 672cf4
  notation = calloc (1, sizeof (*notation));
Packit Service 672cf4
  if (!notation)
Packit Service 672cf4
    return gpg_error_from_syserror ();
Packit Service 672cf4
Packit Service 672cf4
  /* This is critical.  We want to reliably identify policy URLs by
Packit Service 672cf4
     using a NULL pointer for NAME.  So all notations must have a NAME
Packit Service 672cf4
     string, even if it is empty.  */
Packit Service 672cf4
  if (name)
Packit Service 672cf4
    {
Packit Service 672cf4
      /* We add a trailing '\0' for stringification in the good
Packit Service 672cf4
	 case.  */
Packit Service 672cf4
      notation->name = malloc (name_len + 1);
Packit Service 672cf4
      if (!notation->name)
Packit Service 672cf4
	{
Packit Service 672cf4
	  err = gpg_error_from_syserror ();
Packit Service 672cf4
	  goto err;
Packit Service 672cf4
	}
Packit Service 672cf4
Packit Service 672cf4
      memcpy (notation->name, name, name_len);
Packit Service 672cf4
      notation->name[name_len] = '\0';
Packit Service 672cf4
      notation->name_len = name_len;
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  if (value)
Packit Service 672cf4
    {
Packit Service 672cf4
      /* We add a trailing '\0' for stringification in the good
Packit Service 672cf4
	 case.  */
Packit Service 672cf4
      notation->value = malloc (value_len + 1);
Packit Service 672cf4
      if (!notation->value)
Packit Service 672cf4
	{
Packit Service 672cf4
	  err = gpg_error_from_syserror ();
Packit Service 672cf4
	  goto err;
Packit Service 672cf4
	}
Packit Service 672cf4
Packit Service 672cf4
      memcpy (notation->value, value, value_len);
Packit Service 672cf4
      notation->value[value_len] = '\0';
Packit Service 672cf4
      notation->value_len = value_len;
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  sig_notation_set_flags (notation, flags);
Packit Service 672cf4
Packit Service 672cf4
  *notationp = notation;
Packit Service 672cf4
  return 0;
Packit Service 672cf4
Packit Service 672cf4
 err:
Packit Service 672cf4
  _gpgme_sig_notation_free (notation);
Packit Service 672cf4
  return err;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4

Packit Service 672cf4
/* GnuPG subpacket flags.  */
Packit Service 672cf4
Packit Service 672cf4
/* This subpacket data is part of the hashed data.  */
Packit Service 672cf4
#define GNUPG_SPK_HASHED	0x01
Packit Service 672cf4
Packit Service 672cf4
/* This subpacket is marked critical.  */
Packit Service 672cf4
#define GNUPG_SPK_CRITICAL	0x02
Packit Service 672cf4
Packit Service 672cf4
/* Parse a notation or policy URL subpacket.  If the packet type is
Packit Service 672cf4
   not known, return no error but NULL in NOTATION.  */
Packit Service 672cf4
gpgme_error_t
Packit Service 672cf4
_gpgme_parse_notation (gpgme_sig_notation_t *notationp,
Packit Service 672cf4
		       int type, int pkflags, int len, char *data)
Packit Service 672cf4
{
Packit Service 672cf4
  gpgme_error_t err;
Packit Service 672cf4
  char *name = NULL;
Packit Service 672cf4
  int name_len = 0;
Packit Service 672cf4
  char *value = NULL;
Packit Service 672cf4
  int value_len = 0;
Packit Service 672cf4
  gpgme_sig_notation_flags_t flags = 0;
Packit Service 672cf4
  char *decoded_data;
Packit Service 672cf4
  unsigned char *bdata;
Packit Service 672cf4
Packit Service 672cf4
  /* Type 20: Notation data.  */
Packit Service 672cf4
  /* Type 26: Policy URL.  */
Packit Service 672cf4
  if (type != 20 && type != 26)
Packit Service 672cf4
    {
Packit Service 672cf4
      *notationp = NULL;
Packit Service 672cf4
      return 0;
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  /* A few simple sanity checks.  */
Packit Service 672cf4
  if (len > strlen (data))
Packit Service 672cf4
    return trace_gpg_error (GPG_ERR_INV_ENGINE);
Packit Service 672cf4
Packit Service 672cf4
  /* See below for the format of a notation subpacket.  It has at
Packit Service 672cf4
     least four octets of flags and two times two octets of length
Packit Service 672cf4
     information.  */
Packit Service 672cf4
  if (type == 20 && len < 4 + 2 + 2)
Packit Service 672cf4
    return trace_gpg_error (GPG_ERR_INV_ENGINE);
Packit Service 672cf4
Packit Service 672cf4
  err = _gpgme_decode_percent_string (data, &decoded_data, 0, 1);
Packit Service 672cf4
  if (err)
Packit Service 672cf4
    return err;
Packit Service 672cf4
  bdata = (unsigned char *) decoded_data;
Packit Service 672cf4
Packit Service 672cf4
  /* Flags common to notation data and policy URL.  */
Packit Service 672cf4
  if (pkflags & GNUPG_SPK_CRITICAL)
Packit Service 672cf4
    flags |= GPGME_SIG_NOTATION_CRITICAL;
Packit Service 672cf4
Packit Service 672cf4
  /* This information is relevant in parsing multi-octet numbers below:
Packit Service 672cf4
Packit Service 672cf4
     3.1. Scalar numbers
Packit Service 672cf4
Packit Service 672cf4
     Scalar numbers are unsigned, and are always stored in big-endian
Packit Service 672cf4
     format.  Using n[k] to refer to the kth octet being interpreted,
Packit Service 672cf4
     the value of a two-octet scalar is ((n[0] << 8) + n[1]).  The
Packit Service 672cf4
     value of a four-octet scalar is ((n[0] << 24) + (n[1] << 16) +
Packit Service 672cf4
     (n[2] << 8) + n[3]).
Packit Service 672cf4
Packit Service 672cf4
     From RFC2440: OpenPGP Message Format.  Copyright (C) The Internet
Packit Service 672cf4
     Society (1998).  All Rights Reserved.  */
Packit Service 672cf4
#define RFC2440_GET_WORD(chr) ((((int)((unsigned char *)(chr))[0]) << 8) \
Packit Service 672cf4
			       + ((int)((unsigned char *)(chr))[1]))
Packit Service 672cf4
Packit Service 672cf4
  if (type == 20)
Packit Service 672cf4
    {
Packit Service 672cf4
      /* 5.2.3.15. Notation Data
Packit Service 672cf4
Packit Service 672cf4
	 (4 octets of flags, 2 octets of name length (M),
Packit Service 672cf4
	 2 octets of value length (N), M octets of name data,
Packit Service 672cf4
	 N octets of value data)
Packit Service 672cf4
Packit Service 672cf4
	 [...] The "flags" field holds four octets of flags.
Packit Service 672cf4
	 All undefined flags MUST be zero. Defined flags are:
Packit Service 672cf4
Packit Service 672cf4
	 First octet: 0x80 = human-readable. [...]
Packit Service 672cf4
	 Other octets:  none.
Packit Service 672cf4
Packit Service 672cf4
	 From RFC2440: OpenPGP Message Format.  Copyright (C) The
Packit Service 672cf4
	 Internet Society (1998).  All Rights Reserved.  */
Packit Service 672cf4
Packit Service 672cf4
      int chr;
Packit Service 672cf4
Packit Service 672cf4
      /* First octet of flags.  */
Packit Service 672cf4
#define RFC2440_SPK20_FLAG1_HUMAN_READABLE 0x80
Packit Service 672cf4
Packit Service 672cf4
      chr = *bdata;
Packit Service 672cf4
      bdata++;
Packit Service 672cf4
Packit Service 672cf4
      if (chr & RFC2440_SPK20_FLAG1_HUMAN_READABLE)
Packit Service 672cf4
	flags |= GPGME_SIG_NOTATION_HUMAN_READABLE;
Packit Service 672cf4
Packit Service 672cf4
      /* The second, third and four octet of flags are unused.  */
Packit Service 672cf4
      bdata++;
Packit Service 672cf4
      bdata++;
Packit Service 672cf4
      bdata++;
Packit Service 672cf4
Packit Service 672cf4
      name_len = RFC2440_GET_WORD (bdata);
Packit Service 672cf4
      bdata += 2;
Packit Service 672cf4
Packit Service 672cf4
      value_len = RFC2440_GET_WORD (bdata);
Packit Service 672cf4
      bdata += 2;
Packit Service 672cf4
Packit Service 672cf4
      /* Small sanity check.  */
Packit Service 672cf4
      if (4 + 2 + 2 + name_len + value_len > len)
Packit Service 672cf4
	{
Packit Service 672cf4
	  free (decoded_data);
Packit Service 672cf4
	  return trace_gpg_error (GPG_ERR_INV_ENGINE);
Packit Service 672cf4
	}
Packit Service 672cf4
Packit Service 672cf4
      name = (char *) bdata;
Packit Service 672cf4
      bdata += name_len;
Packit Service 672cf4
Packit Service 672cf4
      value = (char *) bdata;
Packit Service 672cf4
    }
Packit Service 672cf4
  else
Packit Service 672cf4
    {
Packit Service 672cf4
      /* Type is 26.  */
Packit Service 672cf4
Packit Service 672cf4
      /* NAME is NULL, name_len is 0.  */
Packit Service 672cf4
Packit Service 672cf4
      value = (char *) bdata;
Packit Service 672cf4
      value_len = strlen (value);
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  err = _gpgme_sig_notation_create (notationp, name, name_len,
Packit Service 672cf4
				    value, value_len, flags);
Packit Service 672cf4
Packit Service 672cf4
  free (decoded_data);
Packit Service 672cf4
  return err;
Packit Service 672cf4
}