/* Add the human-readable notation data with name NAME and value VALUE to the context CTX, using the flags FLAGS. If NAME is NULL, then VALUE should be a policy URL. The flag GPGME_SIG_NOTATION_HUMAN_READABLE is forced to be true for notation data, and false for policy URLs. */ gpgme_error_t gpgme_sig_notation_add (gpgme_ctx_t ctx, const char *name, const char *value, gpgme_sig_notation_flags_t flags) { gpgme_error_t err; gpgme_sig_notation_t notation; gpgme_sig_notation_t *lastp; TRACE_BEG3 (DEBUG_CTX, "gpgme_sig_notation_add", ctx, "name=%s, value=%s, flags=0x%x", name ? name : "(null)", value ? value : "(null)", flags); if (!ctx) return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE)); if (name) flags |= GPGME_SIG_NOTATION_HUMAN_READABLE; else flags &= ~GPGME_SIG_NOTATION_HUMAN_READABLE; err = _gpgme_sig_notation_create (¬ation, name, name ? strlen (name) : 0, value, value ? strlen (value) : 0, flags); if (err) return TRACE_ERR (err); lastp = &ctx->sig_notations; while (*lastp) lastp = &(*lastp)->next; *lastp = notation; return TRACE_ERR (0); }
/* 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 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 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 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; }
static gpgme_error_t parse_notation (gpgme_signature_t sig, gpgme_status_code_t code, char *args) { gpgme_error_t err; gpgme_sig_notation_t *lastp = &sig->notations; gpgme_sig_notation_t notation = sig->notations; char *p; if (code == GPGME_STATUS_NOTATION_NAME || code == GPGME_STATUS_POLICY_URL) { p = strchr (args, ' '); if (p) *p = '\0'; /* FIXME: We could keep a pointer to the last notation in the list. */ while (notation && notation->value) { lastp = ¬ation->next; notation = notation->next; } if (notation) /* There is another notation name without data for the previous one. The crypto backend misbehaves. */ return trace_gpg_error (GPG_ERR_INV_ENGINE); err = _gpgme_sig_notation_create (¬ation, NULL, 0, NULL, 0, 0); if (err) return err; if (code == GPGME_STATUS_NOTATION_NAME) { err = _gpgme_decode_percent_string (args, ¬ation->name, 0, 0); if (err) { _gpgme_sig_notation_free (notation); return err; } notation->name_len = strlen (notation->name); /* Set default flags for use with older gpg versions which * do not emit a NOTATIONS_FLAG line. */ notation->flags = GPGME_SIG_NOTATION_HUMAN_READABLE; notation->human_readable = 1; } else { /* This is a policy URL. */ err = _gpgme_decode_percent_string (args, ¬ation->value, 0, 0); if (err) { _gpgme_sig_notation_free (notation); return err; } notation->value_len = strlen (notation->value); } *lastp = notation; } else if (code == GPGME_STATUS_NOTATION_FLAGS) { char *field[2]; while (notation && notation->next) { lastp = ¬ation->next; notation = notation->next; } if (!notation || !notation->name) { /* There are notation flags without a previous notation name. * The crypto backend misbehaves. */ return trace_gpg_error (GPG_ERR_INV_ENGINE); } if (_gpgme_split_fields (args, field, DIM (field)) < 2) { /* Required args missing. */ return trace_gpg_error (GPG_ERR_INV_ENGINE); } notation->flags = 0; if (atoi (field[0])) { notation->flags |= GPGME_SIG_NOTATION_CRITICAL; notation->critical = 1; } if (atoi (field[1])) { notation->flags |= GPGME_SIG_NOTATION_HUMAN_READABLE; notation->human_readable = 1; } } else if (code == GPGME_STATUS_NOTATION_DATA) { int len = strlen (args) + 1; char *dest; /* FIXME: We could keep a pointer to the last notation in the list. */ while (notation && notation->next) { lastp = ¬ation->next; notation = notation->next; } if (!notation || !notation->name) /* There is notation data without a previous notation name. The crypto backend misbehaves. */ return trace_gpg_error (GPG_ERR_INV_ENGINE); if (!notation->value) { dest = notation->value = malloc (len); if (!dest) return gpg_error_from_syserror (); } else { int cur_len = strlen (notation->value); dest = realloc (notation->value, len + strlen (notation->value)); if (!dest) return gpg_error_from_syserror (); notation->value = dest; dest += cur_len; } err = _gpgme_decode_percent_string (args, &dest, len, 0); if (err) return err; notation->value_len += strlen (dest); } else return trace_gpg_error (GPG_ERR_INV_ENGINE); return 0; }
static gpgme_error_t parse_notation (gpgme_signature_t sig, gpgme_status_code_t code, char *args) { gpgme_error_t err; gpgme_sig_notation_t *lastp = &sig->notations; gpgme_sig_notation_t notation = sig->notations; char *end = strchr (args, ' '); if (end) *end = '\0'; if (code == GPGME_STATUS_NOTATION_NAME || code == GPGME_STATUS_POLICY_URL) { /* FIXME: We could keep a pointer to the last notation in the list. */ while (notation && notation->value) { lastp = ¬ation->next; notation = notation->next; } if (notation) /* There is another notation name without data for the previous one. The crypto backend misbehaves. */ return gpg_error (GPG_ERR_INV_ENGINE); err = _gpgme_sig_notation_create (¬ation, NULL, 0, NULL, 0, 0); if (err) return err; if (code == GPGME_STATUS_NOTATION_NAME) { err = _gpgme_decode_percent_string (args, ¬ation->name, 0, 0); if (err) { _gpgme_sig_notation_free (notation); return err; } notation->name_len = strlen (notation->name); /* FIXME: For now we fake the human-readable flag. The critical flag can not be reported as it is not provided. */ notation->flags = GPGME_SIG_NOTATION_HUMAN_READABLE; notation->human_readable = 1; } else { /* This is a policy URL. */ err = _gpgme_decode_percent_string (args, ¬ation->value, 0, 0); if (err) { _gpgme_sig_notation_free (notation); return err; } notation->value_len = strlen (notation->value); } *lastp = notation; } else if (code == GPGME_STATUS_NOTATION_DATA) { int len = strlen (args) + 1; char *dest; /* FIXME: We could keep a pointer to the last notation in the list. */ while (notation && notation->next) { lastp = ¬ation->next; notation = notation->next; } if (!notation || !notation->name) /* There is notation data without a previous notation name. The crypto backend misbehaves. */ return gpg_error (GPG_ERR_INV_ENGINE); if (!notation->value) { dest = notation->value = malloc (len); if (!dest) return gpg_error_from_errno (errno); } else { int cur_len = strlen (notation->value); dest = realloc (notation->value, len + strlen (notation->value)); if (!dest) return gpg_error_from_errno (errno); notation->value = dest; dest += cur_len; } err = _gpgme_decode_percent_string (args, &dest, len, 0); if (err) return err; notation->value_len += strlen (dest); } else return gpg_error (GPG_ERR_INV_ENGINE); return 0; }