Blame src/sig-notation.c

Packit d7e8d0
/* sig-notation.c - Signature notation data support.
Packit d7e8d0
   Copyright (C) 2005 g10 Code GmbH
Packit d7e8d0
Packit d7e8d0
   This file is part of GPGME.
Packit d7e8d0
Packit d7e8d0
   GPGME is free software; you can redistribute it and/or modify it
Packit d7e8d0
   under the terms of the GNU Lesser General Public License as
Packit d7e8d0
   published by the Free Software Foundation; either version 2.1 of
Packit d7e8d0
   the License, or (at your option) any later version.
Packit d7e8d0
Packit d7e8d0
   GPGME is distributed in the hope that it will be useful, but
Packit d7e8d0
   WITHOUT ANY WARRANTY; without even the implied warranty of
Packit d7e8d0
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit d7e8d0
   Lesser General Public License for more details.
Packit d7e8d0
Packit d7e8d0
   You should have received a copy of the GNU Lesser General Public
Packit d7e8d0
   License along with this program; if not, write to the Free Software
Packit d7e8d0
   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
Packit d7e8d0
   02111-1307, USA.  */
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
}