Blame src/sig-notation.c

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