diff --git a/g13/Makefile.am b/g13/Makefile.am index 62437e567..5a2ffb252 100644 --- a/g13/Makefile.am +++ b/g13/Makefile.am @@ -23,6 +23,9 @@ EXTRA_DIST = ChangeLog-2011 bin_PROGRAMS = g13 sbin_PROGRAMS = g13-syshelp +noinst_PROGRAMS = $(module_tests) +TESTS = $(module_tests) + AM_CPPFLAGS = -I$(top_srcdir)/common include $(top_srcdir)/am/cmacros.am @@ -61,3 +64,14 @@ g13_syshelp_SOURCES = \ g13_syshelp_LDADD = $(libcommon) \ $(LIBGCRYPT_LIBS) $(LIBASSUAN_LIBS) \ $(GPG_ERROR_LIBS) $(LIBINTL) $(LIBICONV) + + +module_tests = t-utils +t_common_ldadd = $(libcommon) $(LIBGCRYPT_LIBS) \ + $(LIBASSUAN_LIBS) + +t_utils_SOURCES = t-utils.c utils.c +t_utils_LDADD = $(t_common_ldadd) + + +$(PROGRAMS) : $(libcommon) $(libcommonpth) diff --git a/g13/t-utils.c b/g13/t-utils.c new file mode 100644 index 000000000..5605216ec --- /dev/null +++ b/g13/t-utils.c @@ -0,0 +1,223 @@ +/* t-utils.c - Module test for utils.c + * Copyright (C) 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 . + */ + +#include +#include +#include +#include + + +#include "util.h" +#include "keyblob.h" +#include "utils.h" + +#define PGM "t-utils" + +static int verbose; +static int debug; +static int errcount; + +/* Test for the functions append_tuple_uint and find_tuple_unit. */ +static void +test_tuple_uint (void) +{ + static struct { + int tag; + int len; + char *data; + unsigned long long val; + gpg_err_code_t ec; + } tv[] = { + { 1, 0, "", 0, GPG_ERR_ERANGE }, + { 2, 1, "\x00", 0, 0}, + { 3, 1, "\x7f", 127ull, 0}, + { 4, 1, "\x80", 0, GPG_ERR_ERANGE }, + { 5, 1, "\x81", 0, GPG_ERR_ERANGE }, + { 6, 2, "\x80\x01", 0, GPG_ERR_ERANGE }, + { 7, 2, "\x00\x80", 128ull, 0 }, + { 8, 1, "\x01", 1, 0 }, + { 9, 1, "\x40", 64, 0 }, + { 10, 2, "\x40\x00", 16384, 0 }, + { 11, 8, "\x7f\xff\xff\xff\xff\xff\xff\xff", 0x7fffffffffffffffull, 0 }, + { 12, 9, "\x00\xff\xff\xff\xff\xff\xff\xff\xff", 0xffffffffffffffffull, 0}, + { 13, 9, "\x01\xff\xff\xff\xff\xff\xff\xff\xff", 0, GPG_ERR_ERANGE } + }; + int tidx; + gpg_error_t err; + membuf_t mb, mb2; + void *p; + const void *s; + size_t n; + tupledesc_t tuples; + tupledesc_t tuples2; + unsigned long long value; + int i; + + init_membuf (&mb, 512); + init_membuf (&mb2, 512); + append_tuple (&mb, KEYBLOB_TAG_BLOBVERSION, "\x01", 1); + append_tuple (&mb2, KEYBLOB_TAG_BLOBVERSION, "\x01", 1); + for (tidx=0; tidx < DIM (tv); tidx++) + { + append_tuple (&mb, tv[tidx].tag, tv[tidx].data, tv[tidx].len); + if (!tv[tidx].ec) + append_tuple_uint (&mb2, tv[tidx].tag, tv[tidx].val); + } + + p = get_membuf (&mb, &n); + if (!p) + { + err = gpg_error_from_syserror (); + fprintf (stderr, PGM ":%s: get_membuf failed: %s\n", + __func__, gpg_strerror (err)); + exit (1); + } + err = create_tupledesc (&tuples, p, n); + if (err) + { + fprintf (stderr, PGM ":%s: create_tupledesc failed: %s\n", + __func__, gpg_strerror (err)); + exit (1); + } + p = get_membuf (&mb2, &n); + if (!p) + { + err = gpg_error_from_syserror (); + fprintf (stderr, PGM ":%s: get_membuf failed: %s\n", + __func__, gpg_strerror (err)); + exit (1); + } + err = create_tupledesc (&tuples2, p, n); + if (err) + { + fprintf (stderr, PGM ":%s: create_tupledesc failed: %s\n", + __func__, gpg_strerror (err)); + exit (1); + } + + for (tidx=0; tidx < DIM (tv); tidx++) + { + err = find_tuple_uint (tuples, tv[tidx].tag, &value); + if (tv[tidx].ec != gpg_err_code (err)) + { + fprintf (stderr, PGM ":%s:tidx=%d: wrong error returned; " + "expected(%s) got(%s)\n", + __func__, tidx, + gpg_strerror (tv[tidx].ec), gpg_strerror (err)); + errcount++; + } + else if (!err && tv[tidx].val != value) + { + fprintf (stderr, PGM ":%s:tidx=%d: wrong value returned; " + "expected(%llx) got(%llx)\n", + __func__, tidx, tv[tidx].val, value); + errcount++; + } + + err = find_tuple_uint (tuples2, tv[tidx].tag, &value); + if (gpg_err_code (err) == GPG_ERR_NOT_FOUND) + { + if (!tv[tidx].ec) + { + fprintf (stderr, PGM ":%s:tidx=%d: find_tuple failed: %s\n", + __func__, tidx, gpg_strerror (err)); + errcount++; + } + } + else if (tv[tidx].ec != gpg_err_code (err)) + { + fprintf (stderr, PGM ":%s:tidx=%d: wrong error returned (2); " + "expected(%s) got(%s)\n", + __func__, tidx, + gpg_strerror (tv[tidx].ec), gpg_strerror (err)); + errcount++; + } + else if (!err && tv[tidx].val != value) + { + fprintf (stderr, PGM ":%s:tidx=%d: wrong value returned (2); " + "expected(%llx) got(%llx)\n", + __func__, tidx, tv[tidx].val, value); + errcount++; + } + + s = find_tuple (tuples2, tv[tidx].tag, &n); + if (!s) + ; + else if (tv[tidx].len != n) + { + fprintf (stderr, PGM ":%s:tidx=%d: wrong string length returned; " + "expected(%d) got(%zu)\n", + __func__, tidx, tv[tidx].len, n); + errcount++; + } + else if (memcmp (tv[tidx].data, s, n)) + { + fprintf (stderr, PGM ":%s:tidx=%d: wrong string returned:", + __func__, tidx); + for (i=0; i < n; i++) + fprintf (stderr, " %02x", ((unsigned char*)s)[i]); + fputc ('\n', stderr); + errcount++; + } + } + + destroy_tupledesc (tuples); + destroy_tupledesc (tuples2); +} + + + +int +main (int argc, char **argv) +{ + int last_argc = -1; + + gpgrt_init (); + if (argc) + { argc--; argv++; } + while (argc && last_argc != argc ) + { + last_argc = argc; + if (!strcmp (*argv, "--")) + { + argc--; argv++; + break; + } + else if (!strcmp (*argv, "--verbose")) + { + verbose++; + argc--; argv++; + } + else if (!strcmp (*argv, "--debug")) + { + verbose += 2; + debug++; + argc--; argv++; + } + else if (!strncmp (*argv, "--", 2)) + { + fprintf (stderr, PGM ": unknown option '%s'\n", *argv); + exit (1); + } + } + + test_tuple_uint (); + + return !!errcount; +} diff --git a/g13/utils.c b/g13/utils.c index 4ab4799cd..dbbaa0d8b 100644 --- a/g13/utils.c +++ b/g13/utils.c @@ -1,5 +1,6 @@ /* utils.c - Utility functions * Copyright (C) 2009 Free Software Foundation, Inc. + * Copyright (C) 2009, 2015, 2016 Werner Koch * * This file is part of GnuPG. * @@ -61,10 +62,45 @@ append_tuple (membuf_t *membuf, int tag, const void *value, size_t 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(). */ + * 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) { @@ -108,7 +144,7 @@ ref_tupledesc (tupledesc_t tupledesc) /* 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 return NULL. For future use by next_tupe, the last + 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) @@ -147,6 +183,43 @@ find_tuple (tupledesc_t tupledesc, unsigned int tag, size_t *r_length) } +/* 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; + unsigned long long value = 0; + + *r_value = 0; + + s = find_tuple (tupledesc, tag, &n); + 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; +} + + const void * next_tuple (tupledesc_t tupledesc, unsigned int *r_tag, size_t *r_length) { diff --git a/g13/utils.h b/g13/utils.h index 914b2cf3e..6c3902b90 100644 --- a/g13/utils.h +++ b/g13/utils.h @@ -25,6 +25,8 @@ /* Append a new tuple to a memory buffer. */ void append_tuple (membuf_t *membuf, int tag, const void *value, size_t length); +void append_tuple_uint (membuf_t *membuf, int tag, + unsigned long long value); /* The tuple descriptor object. */ struct tupledesc_s; @@ -36,6 +38,8 @@ void destroy_tupledesc (tupledesc_t tupledesc); tupledesc_t ref_tupledesc (tupledesc_t tupledesc); const void *find_tuple (tupledesc_t tupledesc, unsigned int tag, size_t *r_length); +gpg_error_t find_tuple_uint (tupledesc_t tupledesc, unsigned int tag, + unsigned long long *r_value); const void *next_tuple (tupledesc_t tupledesc, unsigned int *r_tag, size_t *r_length);