gpgme/src/sig-notation.c

262 lines
6.9 KiB
C
Raw Normal View History

/* sig-notation.c - Signature notation data support.
* Copyright (C) 2005 g10 Code GmbH
*
* This file is part of GPGME.
*
* GPGME is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* GPGME is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, see <https://gnu.org/licenses/>.
* SPDX-License-Identifier: LGPL-2.1-or-later
*/
#if HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <assert.h>
#include "gpgme.h"
#include "util.h"
#include "context.h"
#include "ops.h"
#include "debug.h"
/* Free the signature notation object and all associated resources.
The object must already be removed from any linked list as the next
pointer is ignored. */
void
_gpgme_sig_notation_free (gpgme_sig_notation_t notation)
{
if (notation->name)
free (notation->name);
if (notation->value)
free (notation->value);
free (notation);
}
/* Set the flags of NOTATION to FLAGS. */
static void
sig_notation_set_flags (gpgme_sig_notation_t notation,
gpgme_sig_notation_flags_t flags)
{
/* We copy the flags into individual bits to make them easier
accessible individually for the user. */
notation->human_readable = flags & GPGME_SIG_NOTATION_HUMAN_READABLE ? 1 : 0;
notation->critical = flags & GPGME_SIG_NOTATION_CRITICAL ? 1 : 0;
notation->flags = flags;
}
/* Create a new, empty signature notation data object. */
gpgme_error_t
_gpgme_sig_notation_create (gpgme_sig_notation_t *notationp,
const char *name, int name_len,
const char *value, int value_len,
gpgme_sig_notation_flags_t flags)
{
gpgme_error_t err = 0;
gpgme_sig_notation_t notation;
/* Currently, we require all notations to be human-readable. */
if (name && !(flags & GPGME_SIG_NOTATION_HUMAN_READABLE))
return gpg_error (GPG_ERR_INV_VALUE);
notation = calloc (1, sizeof (*notation));
if (!notation)
return gpg_error_from_syserror ();
/* This is critical. We want to reliably identify policy URLs by
using a NULL pointer for NAME. So all notations must have a NAME
string, even if it is empty. */
if (name)
{
/* We add a trailing '\0' for stringification in the good
case. */
notation->name = malloc (name_len + 1);
if (!notation->name)
{
err = gpg_error_from_syserror ();
goto err;
}
memcpy (notation->name, name, name_len);
notation->name[name_len] = '\0';
notation->name_len = name_len;
}
if (value)
{
/* We add a trailing '\0' for stringification in the good
case. */
notation->value = malloc (value_len + 1);
if (!notation->value)
{
err = gpg_error_from_syserror ();
goto err;
}
memcpy (notation->value, value, value_len);
notation->value[value_len] = '\0';
notation->value_len = value_len;
}
sig_notation_set_flags (notation, flags);
*notationp = notation;
return 0;
err:
_gpgme_sig_notation_free (notation);
return err;
}
/* GnuPG subpacket flags. */
/* This subpacket data is part of the hashed data. */
#define GNUPG_SPK_HASHED 0x01
/* This subpacket is marked critical. */
#define GNUPG_SPK_CRITICAL 0x02
/* 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;
}