diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 16:14:06 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 16:14:06 +0000 |
commit | eee068778cb28ecf3c14e1bf843a95547d72c42d (patch) | |
tree | 0e07b30ddc5ea579d682d5dbe57998200d1c9ab7 /g13/g13tuple.c | |
parent | Initial commit. (diff) | |
download | gnupg2-eee068778cb28ecf3c14e1bf843a95547d72c42d.tar.xz gnupg2-eee068778cb28ecf3c14e1bf843a95547d72c42d.zip |
Adding upstream version 2.2.40.upstream/2.2.40upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | g13/g13tuple.c | 340 |
1 files changed, 340 insertions, 0 deletions
diff --git a/g13/g13tuple.c b/g13/g13tuple.c new file mode 100644 index 0000000..6693826 --- /dev/null +++ b/g13/g13tuple.c @@ -0,0 +1,340 @@ +/* g13tuple.c - Tuple handling + * Copyright (C) 2009 Free Software Foundation, Inc. + * Copyright (C) 2009, 2015, 2016 Werner Koch + * + * This file is part of GnuPG. + * + * GnuPG is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * GnuPG 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <assert.h> + +#include "g13.h" +#include "g13tuple.h" +#include "keyblob.h" /* Required for dump_tupledesc. */ + + +/* Definition of the tuple descriptor object. */ +struct tupledesc_s +{ + unsigned char *data; /* The tuple data. */ + size_t datalen; /* The length of the data. */ + size_t pos; /* The current position as used by next_tuple. */ + int refcount; /* Number of references hold. */ +}; + + + +/* Append the TAG and the VALUE to the MEMBUF. There is no error + checking here; this is instead done while getting the value back + from the membuf. */ +void +append_tuple (membuf_t *membuf, int tag, const void *value, size_t length) +{ + unsigned char buf[2]; + + assert (tag >= 0 && tag <= 0xffff); + assert (length <= 0xffff); + + buf[0] = tag >> 8; + buf[1] = tag; + put_membuf (membuf, buf, 2); + buf[0] = length >> 8; + buf[1] = length; + put_membuf (membuf, buf, 2); + if (length) + put_membuf (membuf, value, length); +} + + +/* Append the unsigned integer VALUE under TAG to MEMBUF. We make + * sure that the most significant bit is always cleared to explicitly + * flag the value as unsigned. */ +void +append_tuple_uint (membuf_t *membuf, int tag, unsigned long long value) +{ + unsigned char buf[16]; + unsigned char *p; + unsigned int len; + + p = buf + sizeof buf; + len = 0; + do + { + if (p == buf) + BUG () ; + *--p = (value & 0xff); + value >>= 8; + len++; + } + while (value); + + /* Prepend a zero byte if the first byte has its MSB set. */ + if ((*p & 0x80)) + { + if (p == buf) + BUG () ; + *--p = 0; + len++; + } + + append_tuple (membuf, tag, p, len); +} + + +/* Create a tuple object by moving the ownership of (DATA,DATALEN) to + * a new object. Returns 0 on success and stores the new object at + * R_TUPLEHD. The return object must be released using + * destroy_tuples(). */ +gpg_error_t +create_tupledesc (tupledesc_t *r_desc, void *data, size_t datalen) +{ + if (datalen < 5 || memcmp (data, "\x00\x00\x00\x01\x01", 5)) + return gpg_error (GPG_ERR_NOT_SUPPORTED); + + *r_desc = xtrymalloc (sizeof **r_desc); + if (!*r_desc) + return gpg_error_from_syserror (); + (*r_desc)->data = data; + (*r_desc)->datalen = datalen; + (*r_desc)->pos = 0; + (*r_desc)->refcount = 1; + return 0; +} + +/* Unref a tuple descriptor and if the refcount is down to 0 release + its allocated storage. */ +void +destroy_tupledesc (tupledesc_t tupledesc) +{ + if (!tupledesc) + return; + + if (!--tupledesc->refcount) + { + xfree (tupledesc->data); + xfree (tupledesc); + } +} + + +tupledesc_t +ref_tupledesc (tupledesc_t tupledesc) +{ + if (tupledesc) + tupledesc->refcount++; + return tupledesc; +} + + +/* Return a pointer to the memory used to store the tuples. This is + * the data originally provided to create_tupledesc. It is higly + * recommended that the callers uses ref_tupledesc before calling this + * function and unref_tupledesc when the return data will not anymore + * be used. */ +const void * +get_tupledesc_data (tupledesc_t tupledesc, size_t *r_datalen) +{ + *r_datalen = tupledesc->datalen; + return tupledesc->data; +} + +/* Find the first tuple with tag TAG. On success return a pointer to + its value and store the length of the value at R_LENGTH. If no + tuple was found return NULL. For use by next_tuple, the last + position is stored in the descriptor. */ +const void * +find_tuple (tupledesc_t tupledesc, unsigned int tag, size_t *r_length) +{ + const unsigned char *s; + const unsigned char *s_end; /* Points right behind the data. */ + unsigned int t; + size_t n; + + s = tupledesc->data; + if (!s) + return NULL; + s_end = s + tupledesc->datalen; + while (s < s_end) + { + /* We use addresses for the overflow check to avoid undefined + behaviour. size_t should work with all flat memory models. */ + if ((size_t)s+3 >= (size_t)s_end || (size_t)s + 3 < (size_t)s) + break; + t = s[0] << 8; + t |= s[1]; + n = s[2] << 8; + n |= s[3]; + s += 4; + if ((size_t)s + n > (size_t)s_end || (size_t)s + n < (size_t)s) + break; + if (t == tag) + { + tupledesc->pos = (s + n) - tupledesc->data; + *r_length = n; + return s; + } + s += n; + } + return NULL; +} + + +/* Helper for find_tuple_uint and others. */ +static gpg_error_t +convert_uint (const unsigned char *s, size_t n, unsigned long long *r_value) +{ + unsigned long long value = 0; + + *r_value = 0; + + if (!s) + return gpg_error (GPG_ERR_NOT_FOUND); + if (!n || (*s & 0x80)) /* No bytes or negative. */ + return gpg_error (GPG_ERR_ERANGE); + if (n && !*s) /* Skip a leading zero. */ + { + n--; + s++; + } + if (n > sizeof value) + return gpg_error (GPG_ERR_ERANGE); + for (; n; n--, s++) + { + value <<= 8; + value |= *s; + } + *r_value = value; + return 0; +} + + +/* Similar to find-tuple but expects an unsigned int value and stores + * that at R_VALUE. If the tag was not found GPG_ERR_NOT_FOUND is + * returned and 0 stored at R_VALUE. If the value cannot be converted + * to an unsigned integer GPG_ERR_ERANGE is returned. */ +gpg_error_t +find_tuple_uint (tupledesc_t tupledesc, unsigned int tag, + unsigned long long *r_value) +{ + const unsigned char *s; + size_t n; + + s = find_tuple (tupledesc, tag, &n); + return convert_uint (s, n, r_value); +} + + +const void * +next_tuple (tupledesc_t tupledesc, unsigned int *r_tag, size_t *r_length) +{ + const unsigned char *s; + const unsigned char *s_end; /* Points right behind the data. */ + unsigned int t; + size_t n; + + s = tupledesc->data; + if (!s) + return NULL; + s_end = s + tupledesc->datalen; + s += tupledesc->pos; + if (s < s_end + && !((size_t)s + 3 >= (size_t)s_end || (size_t)s + 3 < (size_t)s)) + { + t = s[0] << 8; + t |= s[1]; + n = s[2] << 8; + n |= s[3]; + s += 4; + if (!((size_t)s + n > (size_t)s_end || (size_t)s + n < (size_t)s)) + { + tupledesc->pos = (s + n) - tupledesc->data; + *r_tag = t; + *r_length = n; + return s; + } + } + + return NULL; +} + + +/* Return true if BUF has only printable characters. */ +static int +all_printable (const void *buf, size_t buflen) +{ + const unsigned char *s; + + for (s=buf ; buflen; s++, buflen--) + if (*s < 32 || *s > 126) + return 0; + return 1; +} + + +/* Print information about TUPLES to the log stream. */ +void +dump_tupledesc (tupledesc_t tuples) +{ + size_t n; + unsigned int tag; + const void *value; + unsigned long long uint; + + log_info ("keyblob dump:\n"); + tag = KEYBLOB_TAG_BLOBVERSION; + value = find_tuple (tuples, tag, &n); + while (value) + { + log_info (" tag: %-5u len: %-2u value: ", tag, (unsigned int)n); + if (!n) + log_printf ("[none]\n"); + else + { + switch (tag) + { + case KEYBLOB_TAG_ENCKEY: + case KEYBLOB_TAG_MACKEY: + log_printf ("[confidential]\n"); + break; + + case KEYBLOB_TAG_ALGOSTR: + if (n < 100 && all_printable (value, n)) + log_printf ("%.*s\n", (int)n, (const char*)value); + else + log_printhex (value, n, ""); + break; + + case KEYBLOB_TAG_CONT_NSEC: + case KEYBLOB_TAG_ENC_NSEC: + case KEYBLOB_TAG_ENC_OFF: + if (!convert_uint (value, n, &uint)) + log_printf ("%llu\n", uint); + else + log_printhex (value, n, ""); + break; + + default: + log_printhex (value, n, ""); + break; + } + } + value = next_tuple (tuples, &tag, &n); + } +} |