/* 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 . * SPDX-License-Identifier: LGPL-2.1-or-later */ #if HAVE_CONFIG_H #include #endif #include #include #include #include #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; }