diff options
Diffstat (limited to 'comm/third_party/libgcrypt/tests/t-sexp.c')
-rw-r--r-- | comm/third_party/libgcrypt/tests/t-sexp.c | 1344 |
1 files changed, 1344 insertions, 0 deletions
diff --git a/comm/third_party/libgcrypt/tests/t-sexp.c b/comm/third_party/libgcrypt/tests/t-sexp.c new file mode 100644 index 0000000000..96d5f97ec4 --- /dev/null +++ b/comm/third_party/libgcrypt/tests/t-sexp.c @@ -0,0 +1,1344 @@ +/* t-sexp.c - S-expression regression tests + * Copyright (C) 2001, 2002, 2003, 2005 Free Software Foundation, Inc. + * Copyright (C) 2014 g10 Code GmbH + * + * This file is part of Libgcrypt. + * + * Libgcrypt 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. + * + * Libgcrypt 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 <http://www.gnu.org/licenses/>. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> +#include <assert.h> +#include "../src/gcrypt-int.h" + +#define PGM "t-sexp" +#include "t-common.h" + + +/* Convert STRING consisting of hex characters into its binary + representation and return it as an allocated buffer. The valid + length of the buffer is returned at R_LENGTH. The string is + delimited by end of string. The function returns NULL on + error. */ +static void * +hex2buffer (const char *string, size_t *r_length) +{ + const char *s; + unsigned char *buffer; + size_t length; + + buffer = xmalloc (strlen(string)/2+1); + length = 0; + for (s=string; *s; s +=2 ) + { + if (!hexdigitp (s) || !hexdigitp (s+1)) + return NULL; /* Invalid hex digits. */ + ((unsigned char*)buffer)[length++] = xtoi_2 (s); + } + *r_length = length; + return buffer; +} + + +static gcry_mpi_t +hex2mpi (const char *string) +{ + gpg_error_t err; + gcry_mpi_t val; + + err = gcry_mpi_scan (&val, GCRYMPI_FMT_HEX, string, 0, NULL); + if (err) + die ("hex2mpi '%s' failed: %s\n", string, gpg_strerror (err)); + return val; +} + +static gcry_mpi_t +hex2mpiopa (const char *string) +{ + char *buffer; + size_t buflen; + gcry_mpi_t val; + + buffer = hex2buffer (string, &buflen); + if (!buffer) + die ("hex2mpiopa '%s' failed: parser error\n", string); + val = gcry_mpi_set_opaque (NULL, buffer, buflen*8); + if (!buffer) + die ("hex2mpiopa '%s' failed: set_opaque error\n", string); + return val; +} + + +/* Compare A to B, where B is given as a hex string. */ +static int +cmp_mpihex (gcry_mpi_t a, const char *b) +{ + gcry_mpi_t bval; + int res; + + if (gcry_mpi_get_flag (a, GCRYMPI_FLAG_OPAQUE)) + bval = hex2mpiopa (b); + else + bval = hex2mpi (b); + res = gcry_mpi_cmp (a, bval); + gcry_mpi_release (bval); + return res; +} + +/* Compare A to B, where A is a buffer and B a hex string. */ +static int +cmp_bufhex (const void *a, size_t alen, const char *b) +{ + void *bbuf; + size_t blen; + int res; + + if (!a && !b) + return 0; + if (a && !b) + return 1; + if (!a && b) + return -1; + + bbuf = hex2buffer (b, &blen); + if (!bbuf) + die ("cmp_bufhex: error converting hex string\n"); + if (alen != blen) + return alen < blen? -1 : 1; + res = memcmp (a, bbuf, alen); + xfree (bbuf); + return res; +} + + + +/* fixme: we need better tests */ +static void +basic (void) +{ + int pass; + gcry_sexp_t sexp; + int idx; + char *secure_buffer; + size_t secure_buffer_len; + const char *string; + static struct { + const char *token; + const char *parm; + } values[] = { + { "public-key", NULL }, + { "dsa", NULL }, + { "dsa", "p" }, + { "dsa", "y" }, + { "dsa", "q" }, + { "dsa", "g" }, + { NULL } + }; + + info ("doing some pretty pointless tests\n"); + + secure_buffer_len = 99; + secure_buffer = gcry_xmalloc_secure (secure_buffer_len); + memset (secure_buffer, 'G', secure_buffer_len); + + for (pass=0;;pass++) + { + gcry_mpi_t m; + + switch (pass) + { + case 0: + string = ("(public-key (dsa (p #41424344#) (y this_is_y) " + "(q #61626364656667#) (g %m)))"); + + m = gcry_mpi_set_ui (NULL, 42); + if ( gcry_sexp_build (&sexp, NULL, string, m ) ) + { + gcry_mpi_release (m); + fail (" scanning `%s' failed\n", string); + return; + } + gcry_mpi_release (m); + break; + + case 1: + string = ("(public-key (dsa (p #41424344#) (y this_is_y) " + "(q %b) (g %m)))"); + + m = gcry_mpi_set_ui (NULL, 42); + if ( gcry_sexp_build (&sexp, NULL, string, + 15, "foo\0\x01\0x02789012345", m) ) + { + gcry_mpi_release (m); + fail (" scanning `%s' failed\n", string); + return; + } + gcry_mpi_release (m); + break; + + case 2: + string = ("(public-key (dsa (p #41424344#) (y silly_y_value) " + "(q %b) (g %m)))"); + + m = gcry_mpi_set_ui (NULL, 17); + if ( gcry_sexp_build (&sexp, NULL, string, + secure_buffer_len, secure_buffer, m) ) + { + gcry_mpi_release (m); + fail (" scanning `%s' failed\n", string); + return; + } + gcry_mpi_release (m); + if (!gcry_is_secure (sexp)) + fail ("gcry_sexp_build did not switch to secure memory\n"); + break; + + case 3: + { + gcry_sexp_t help_sexp; + + if (gcry_sexp_new (&help_sexp, + "(foobar-parms (xp #1234#)(xq #03#))", 0, 1)) + { + fail (" scanning fixed string failed\n"); + return; + } + + string = ("(public-key (dsa (p #41424344#) (parm %S) " + "(y dummy)(q %b) (g %m)))"); + m = gcry_mpi_set_ui (NULL, 17); + if ( gcry_sexp_build (&sexp, NULL, string, help_sexp, + secure_buffer_len, secure_buffer, m) ) + { + gcry_mpi_release (m); + fail (" scanning `%s' failed\n", string); + return; + } + gcry_mpi_release (m); + gcry_sexp_release (help_sexp); + } + break; + + + default: + return; /* Ready. */ + } + + + /* now find something */ + for (idx=0; values[idx].token; idx++) + { + const char *token = values[idx].token; + const char *parm = values[idx].parm; + gcry_sexp_t s1, s2; + gcry_mpi_t a; + const char *p; + size_t n; + + s1 = gcry_sexp_find_token (sexp, token, strlen(token) ); + if (!s1) + { + fail ("didn't found `%s'\n", token); + continue; + } + + p = gcry_sexp_nth_data (s1, 0, &n); + if (!p) + { + gcry_sexp_release (s1); + fail ("no car for `%s'\n", token); + continue; + } + /* info ("car=`%.*s'\n", (int)n, p); */ + + s2 = gcry_sexp_cdr (s1); + if (!s2) + { + gcry_sexp_release (s1); + fail ("no cdr for `%s'\n", token); + continue; + } + + p = gcry_sexp_nth_data (s2, 0, &n); + gcry_sexp_release (s2); + if (p) + { + gcry_sexp_release (s1); + fail ("data at car of `%s'\n", token); + continue; + } + + if (parm) + { + s2 = gcry_sexp_find_token (s1, parm, strlen (parm)); + gcry_sexp_release (s1); + if (!s2) + { + fail ("didn't found `%s'\n", parm); + continue; + } + p = gcry_sexp_nth_data (s2, 0, &n); + if (!p) + { + gcry_sexp_release (s2); + fail("no car for `%s'\n", parm ); + continue; + } + /* info ("car=`%.*s'\n", (int)n, p); */ + p = gcry_sexp_nth_data (s2, 1, &n); + if (!p) + { + gcry_sexp_release (s2); + fail("no cdr for `%s'\n", parm ); + continue; + } + /* info ("cdr=`%.*s'\n", (int)n, p); */ + + a = gcry_sexp_nth_mpi (s2, 0, GCRYMPI_FMT_USG); + gcry_sexp_release (s2); + if (!a) + { + fail("failed to cdr the mpi for `%s'\n", parm); + continue; + } + gcry_mpi_release (a); + } + else + gcry_sexp_release (s1); + } + + gcry_sexp_release (sexp); + sexp = NULL; + } + gcry_free (secure_buffer); +} + + +static void +canon_len (void) +{ + static struct { + size_t textlen; /* length of the buffer */ + size_t expected;/* expected length or 0 on error and then ... */ + size_t erroff; /* ... and at this offset */ + gcry_error_t errcode; /* ... with this error code */ + const char *text; + } values[] = { + { 14, 13, 0, GPG_ERR_NO_ERROR, "(9:abcdefghi) " }, + { 16, 15, 0, GPG_ERR_NO_ERROR, "(10:abcdefghix)" }, + { 14, 0,14, GPG_ERR_SEXP_STRING_TOO_LONG, "(10:abcdefghi)" }, + { 15, 0, 1, GPG_ERR_SEXP_ZERO_PREFIX, "(010:abcdefghi)" }, + { 2, 0, 0, GPG_ERR_SEXP_NOT_CANONICAL, "1:"}, + { 4, 0, 4, GPG_ERR_SEXP_STRING_TOO_LONG, "(1:)"}, + { 5, 5, 0, GPG_ERR_NO_ERROR, "(1:x)"}, + { 2, 2, 0, GPG_ERR_NO_ERROR, "()"}, + { 4, 2, 0, GPG_ERR_NO_ERROR, "()()"}, + { 4, 4, 0, GPG_ERR_NO_ERROR, "(())"}, + { 3, 0, 3, GPG_ERR_SEXP_STRING_TOO_LONG, "(()"}, + { 3, 0, 1, GPG_ERR_SEXP_BAD_CHARACTER, "( )"}, + { 9, 9, 0, GPG_ERR_NO_ERROR, "(3:abc())"}, + { 10, 0, 6, GPG_ERR_SEXP_BAD_CHARACTER, "(3:abc ())"}, + /* fixme: we need much more cases */ + { 0 }, + }; + int idx; + gcry_error_t errcode; + size_t n, erroff; + + info ("checking canoncial length test function\n"); + for (idx=0; values[idx].text; idx++) + { + n = gcry_sexp_canon_len ((const unsigned char*)values[idx].text, + values[idx].textlen, + &erroff, &errcode); + + if (n && n == values[idx].expected) + ; /* success */ + else if (!n && !values[idx].expected) + { /* we expected an error - check that this is the right one */ + if (values[idx].erroff != erroff) + fail ("canonical length test %d - wrong error offset %u\n", + idx, (unsigned int)erroff); + if (gcry_err_code (errcode) != values[idx].errcode) + fail ("canonical length test %d - wrong error code %d\n", + idx, errcode); + } + else + fail ("canonical length test %d failed - n=%u, off=%u, err=%d\n", + idx, (unsigned int)n, (unsigned int)erroff, errcode); + } +} + + +/* Compare SE to the canonical formatted expression in + * (CANON,CANONLEN). This is done by a converting SE to canonical + * format and doing a byte compare. Returns 0 if they match. */ +static int +compare_to_canon (gcry_sexp_t se, const unsigned char *canon, size_t canonlen) +{ + size_t n, n1; + char *p1; + + n1 = gcry_sexp_sprint (se, GCRYSEXP_FMT_CANON, NULL, 0); + if (!n1) + { + fail ("get required length in compare_to_canon failed\n"); + return -1; + } + p1 = gcry_xmalloc (n1); + n = gcry_sexp_sprint (se, GCRYSEXP_FMT_CANON, p1, n1); + if (n1 != n+1) + { + fail ("length mismatch in compare_to_canon detected\n"); + xfree (p1); + return -1; + } + if (n1 != canonlen || memcmp (p1, canon, canonlen)) + { + xfree (p1); + return -1; + } + xfree (p1); + return 0; +} + + +static void +back_and_forth_one (int testno, const char *buffer, size_t length) +{ + gcry_error_t rc; + gcry_sexp_t se, se1; + unsigned char *canon; + size_t canonlen; /* Including the hidden nul suffix. */ + size_t n, n1; + char *p1; + + rc = gcry_sexp_new (&se, buffer, length, 1); + if (rc) + { + fail ("baf %d: gcry_sexp_new failed: %s\n", testno, gpg_strerror (rc)); + return; + } + n1 = gcry_sexp_sprint (se, GCRYSEXP_FMT_CANON, NULL, 0); + if (!n1) + { + fail ("baf %d: get required length for canon failed\n", testno); + return; + } + p1 = gcry_xmalloc (n1); + n = gcry_sexp_sprint (se, GCRYSEXP_FMT_CANON, p1, n1); + if (n1 != n+1) /* sprints adds an extra 0 but does not return it. */ + { + fail ("baf %d: length mismatch for canon\n", testno); + return; + } + canonlen = n1; + canon = gcry_malloc (canonlen); + memcpy (canon, p1, canonlen); + rc = gcry_sexp_create (&se1, p1, n, 0, gcry_free); + if (rc) + { + fail ("baf %d: gcry_sexp_create failed: %s\n", + testno, gpg_strerror (rc)); + return; + } + gcry_sexp_release (se1); + + /* Again but with memory checking. */ + p1 = gcry_xmalloc (n1+2); + *p1 = '\x55'; + p1[n1+1] = '\xaa'; + n = gcry_sexp_sprint (se, GCRYSEXP_FMT_CANON, p1+1, n1); + if (n1 != n+1) /* sprints adds an extra 0 but does not return it */ + { + fail ("baf %d: length mismatch for canon\n", testno); + return; + } + if (*p1 != '\x55' || p1[n1+1] != '\xaa') + fail ("baf %d: memory corrupted (1)\n", testno); + rc = gcry_sexp_create (&se1, p1+1, n, 0, NULL); + if (rc) + { + fail ("baf %d: gcry_sexp_create failed: %s\n", + testno, gpg_strerror (rc)); + return; + } + if (*p1 != '\x55' || p1[n1+1] != '\xaa') + fail ("baf %d: memory corrupted (2)\n", testno); + gcry_sexp_release (se1); + if (*p1 != '\x55' || p1[n1+1] != '\xaa') + fail ("baf %d: memory corrupted (3)\n", testno); + gcry_free (p1); + + /* Check converting to advanced format. */ + n1 = gcry_sexp_sprint (se, GCRYSEXP_FMT_ADVANCED, NULL, 0); + if (!n1) + { + fail ("baf %d: get required length for advanced failed\n", testno); + return; + } + p1 = gcry_xmalloc (n1); + n = gcry_sexp_sprint (se, GCRYSEXP_FMT_ADVANCED, p1, n1); + if (n1 != n+1) /* sprints adds an extra 0 but does not return it */ + { + fail ("baf %d: length mismatch for advanced\n", testno); + return; + } + rc = gcry_sexp_create (&se1, p1, n, 0, gcry_free); + if (rc) + { + fail ("baf %d: gcry_sexp_create failed: %s\n", + testno, gpg_strerror (rc)); + return; + } + if (compare_to_canon (se1, canon, canonlen)) + { + fail ("baf %d: converting to advanced failed: %s\n", + testno, gpg_strerror (rc)); + return; + } + gcry_sexp_release (se1); + + + /* FIXME: we need a lot more tests */ + + gcry_sexp_release (se); + xfree (canon); +} + + + +static void +back_and_forth (void) +{ + static struct { const char *buf; int len; } tests[] = { + { "(7:g34:fgh1::2:())", 0 }, + { "(7:g34:fgh1::2:())", 18 }, + { +"(protected-private-key \n" +" (rsa \n" +" (n #00BE8A536204687149A48FF9F1715FF3530AD9A836D62102BF4065E5CF5953236DB94F1DF2FF4D525CD4CE7966DDC3C839968E8BAC2948934DF047CC65287CD79F6C23C93E55D7F9231E3942BD496DE383469977635A51ADF4AF747DB958CA02E9940DFC1DC0FC7FC755E7EB6618FEE6DA54B8A06E0CBF9D9257443F9992261435#)\n" +" (e #010001#)\n" +" (protected openpgp-s2k3-sha1-aes-cbc \n" +" (\n" +" (sha1 #C2A5673BD3882405# \"96\")\n" +" #8D08AAF6A9209ED69D71EB7E64D78715#)\n" +" #F7B0B535F8F8E22F4F3DA031224070303F82F9207D42952F1ACF21A4AB1C50304EBB25527992C7B265A9E9FF702826FB88759BDD55E4759E9FCA6C879538C9D043A9C60A326CB6681090BAA731289BD880A7D5774D9999F026E5E7963BFC8C0BDC9F061393CB734B4F259725C0A0A0B15BA39C39146EF6A1B3DC4DF30A22EBE09FD05AE6CB0C8C6532951A925F354F4E26A51964F5BBA50081690C421C8385C4074E9BAB9297D081B857756607EAE652415275A741C89E815558A50AC638EDC5F5030210B4395E3E1A40FF38DCCCB333A19EA88EFE7E4D51B54128C6DF27395646836679AC21B1B25C1DA6F0A7CE9F9BE078EFC7934FA9AE202CBB0AA06C20DFAF9A66FAB7E9073FBE96B9A7F25C3BA45EC3EECA65796AEE313BA148DE5314F30345B452B50B17C4D841A7F27397126E8C10BD0CE3B50A82C0425AAEE7798031671407B681F52916256F78CAF92A477AC27BCBE26DAFD1BCE386A853E2A036F8314BB2E8E5BB1F196434232EFB0288331C2AB16DBC5457CC295EB966CAC5CE73D5DA5D566E469F0EFA82F9A12B8693E0#)\n" +" )\n" +" )\n", 0 }, + { "((sha1 #8B98CBF4A9823CA7# \"2097\") #3B6FC9#)", 0 }, + { "((4:sha18:\x8B\x98\xCB\xF4\xA9\x82\x3C\xA7""4:2097)3:\x3B\x6F\xC9)", 0}, + { "((4:sha18:\x8B\x98\xCB\x22\xA9\x82\x3C\xA7""4:2097)3:\x3B\x6F\xC9)", 0}, + { "((sha1 #64652267686970C9# \"2097\") #3B6FC9#)", 0 }, + { "((4:sha18:\x64\x65\x22\x67\x68\xc3\xa4\x71""4:2097)3:\x3B\x6F\xC9)", 0}, + { "((sha1 \"defghäq\" \"2097\") #3B6FC9#)", 0 }, + { "((sha1 \"de\\\"ghäq\" \"2097\") #3B6FC9#)", 0 }, + { NULL, 0 } + }; + int idx; + + for (idx=0; tests[idx].buf; idx++) + back_and_forth_one (idx, tests[idx].buf, tests[idx].len); +} + + +static void +check_sscan (void) +{ + static struct { + const char *text; + gcry_error_t expected_err; + } values[] = { + /* Bug reported by Olivier L'Heureux 2003-10-07 */ + { "(7:sig-val(3:dsa" + "(1:r20:\x7e\xff\xd5\xba\xc9\xc9\xa4\x9b\xd4\x26\x8b\x64" + "\x06\x7a\xcf\x42\x7b\x6c\x51\xfb)" + "(1:s21:\x01\x8c\x6c\x6f\x37\x1a\x8d\xfd\x5a\xb3\x2a\x3d" + "\xc5\xae\x23\xed\x32\x62\x30\x62\x3e)))", + GPG_ERR_NO_ERROR }, + { "(7:sig-val(3:dsa" + "(1:r20:\x7e\xff\xd5\xba\xc9\xc9\xa4\x9b\xd4\x26\x8b\x64" + "\x06\x7a\xcf\x42\x7b\x6c\x51\xfb)" + "(1:s21:\x01\x8c\x6c\x6f\x37\x1a\x8d\xfd\x5a\xb3\x2a\x3d" + "\xc5\xae\x23\xed\x32\x62\x30\x62\x3e))", + GPG_ERR_SEXP_UNMATCHED_PAREN }, + { "(7:sig-val(3:dsa" + "(1:r20:\x7e\xff\xd5\xba\xc9\xc9\xa4\x9b\xd4\x26\x8b\x64" + "\x06\x7a\xcf\x42\x7b\x6c\x51\xfb)" + "(1:s21:\x01\x8c\x6c\x6f\x37\x1a\x8d\xfd\x5a\xb3\x2a\x3d" + "\xc5\xae\x23\xed\x32\x62\x30\x62\x3e))))", + GPG_ERR_SEXP_UNMATCHED_PAREN }, + { NULL, 0 } + }; + int idx; + gcry_error_t err; + gcry_sexp_t s; + + info ("checking gcry_sexp_sscan\n"); + for (idx=0; values[idx].text; idx++) + { + err = gcry_sexp_sscan (&s, NULL, + values[idx].text, + strlen (values[idx].text)); + if (gpg_err_code (err) != values[idx].expected_err) + fail ("gcry_sexp_sscan test %d failed: %s\n", idx, gpg_strerror (err)); + gcry_sexp_release (s); + } +} + + +static void +check_extract_param (void) +{ + /* This sample data is a real key but with some parameters of the + public key modified. u,i,I are used for direct extraction tests. */ + static char sample1[] = + "(key-data" + " (public-key" + " (ecc" + " (curve Ed25519)" + " (p #6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFED#)" + " (a #EF#)" + " (b #C2036CEE2B6FFE738CC740797779E89800700A4D4141D8AB75EB4DCA135978B6#)" + " (g #14" + " 216936D3CD6E53FEC0A4E231FDD6DC5C692CC7609525A7B2C9562D608F25D51A" + " 6666666666666666666666666666666666666666666666666666666666666658#)" + " (n #0000000000000000000000000000000014DEF9DEA2F79CD65812631A5CF5D3ED#)" + " (q #20B37806015CA06B3AEB9423EE84A41D7F31AA65F4148553755206D679F8BF62#)" + "))" + " (private-key" + " (u +65537)" + " (i +65537)" + " (I -65535)" + " (i0 1:0)" + " (flaglist foo bar (sublist x) test 2:42)" + " (noflags)" + " (ecc" + " (curve Ed25519)" + " (p #7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFED#)" + " (a #FF#)" + " (b #D2036CEE2B6FFE738CC740797779E89800700A4D4141D8AB75EB4DCA135978B6#)" + " (g #04" + " 216936D3CD6E53FEC0A4E231FDD6DC5C692CC7609525A7B2C9562D608F25D51A" + " 6666666666666666666666666666666666666666666666666666666666666658#)" + " (n #1000000000000000000000000000000014DEF9DEA2F79CD65812631A5CF5D3ED#)" + " (q #30B37806015CA06B3AEB9423EE84A41D7F31AA65F4148553755206D679F8BF62#)" + " (d #56BEA284A22F443A7AEA8CEFA24DA5055CDF1D490C94D8C568FE0802C9169276#)" + " (comment |QWxsIHlvdXIgYmFzZTY0IGFyZSBiZWxvbmcgdG8gdXM=|)" + ")))"; + + static char sample1_p[] = + "7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFED"; + static char sample1_px[] = + "6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFED"; + static char sample1_a[] = "FF"; + static char sample1_ax[] = "EF"; + static char sample1_b[] = + "D2036CEE2B6FFE738CC740797779E89800700A4D4141D8AB75EB4DCA135978B6"; + static char sample1_bx[] = + "C2036CEE2B6FFE738CC740797779E89800700A4D4141D8AB75EB4DCA135978B6"; + static char sample1_g[] = + "04" + "216936D3CD6E53FEC0A4E231FDD6DC5C692CC7609525A7B2C9562D608F25D51A" + "6666666666666666666666666666666666666666666666666666666666666658"; + static char sample1_gx[] = + "14" + "216936D3CD6E53FEC0A4E231FDD6DC5C692CC7609525A7B2C9562D608F25D51A" + "6666666666666666666666666666666666666666666666666666666666666658"; + static char sample1_n[] = + "1000000000000000000000000000000014DEF9DEA2F79CD65812631A5CF5D3ED"; + static char sample1_nx[] = + "0000000000000000000000000000000014DEF9DEA2F79CD65812631A5CF5D3ED"; + static char sample1_q[] = + "30B37806015CA06B3AEB9423EE84A41D7F31AA65F4148553755206D679F8BF62"; + static char sample1_qx[] = + "20B37806015CA06B3AEB9423EE84A41D7F31AA65F4148553755206D679F8BF62"; + static char sample1_d[] = + "56BEA284A22F443A7AEA8CEFA24DA5055CDF1D490C94D8C568FE0802C9169276"; + static char sample1_comment[] = "All your base64 are belong to us"; + + static struct { + const char *sexp_str; + const char *path; + const char *list; + int nparam; + gpg_err_code_t expected_err; + const char *exp_p; + const char *exp_a; + const char *exp_b; + const char *exp_g; + const char *exp_n; + const char *exp_q; + const char *exp_d; + } tests[] = { + { + sample1, + NULL, + "pabgnqd", 6, + GPG_ERR_MISSING_VALUE, + }, + { + sample1, + NULL, + "pabgnq", 7, + GPG_ERR_INV_ARG + }, + { + sample1, + NULL, + "pab'gnq", 7, + GPG_ERR_SYNTAX + }, + { + sample1, + NULL, + "pab''gnq", 7, + GPG_ERR_SYNTAX + }, + { + sample1, + NULL, + "pabgnqd", 7, + 0, + sample1_px, sample1_ax, sample1_bx, sample1_gx, sample1_nx, + sample1_qx, sample1_d + }, + { + sample1, + NULL, + " pab\tg nq\nd ", 7, + 0, + sample1_px, sample1_ax, sample1_bx, sample1_gx, sample1_nx, + sample1_qx, sample1_d + }, + { + sample1, + NULL, + "abg", 3, + 0, + sample1_ax, sample1_bx, sample1_gx + }, + { + sample1, + NULL, + "ab'g'", 3, + 0, + sample1_ax, sample1_bx, sample1_gx + }, + { + sample1, + NULL, + "x?abg", 4, + 0, + NULL, sample1_ax, sample1_bx, sample1_gx + }, + { + sample1, + NULL, + "p?abg", 4, + GPG_ERR_USER_1, + NULL, sample1_ax, sample1_bx, sample1_gx + }, + { + sample1, + NULL, + "pax?gnqd", 7, + 0, + sample1_px, sample1_ax, NULL, sample1_gx, sample1_nx, + sample1_qx, sample1_d + }, + { + sample1, + "public-key", + "pabgnqd", 7, + GPG_ERR_NO_OBJ, /* d is not in public key. */ + sample1_px, sample1_ax, sample1_bx, sample1_gx, sample1_nx, + sample1_qx, sample1_d + }, + { + sample1, + "private-key", + "pabgnqd", 7, + 0, + sample1_p, sample1_a, sample1_b, sample1_g, sample1_n, + sample1_q, sample1_d + }, + { + sample1, + "public-key!ecc", + "pabgnq", 6, + 0, + sample1_px, sample1_ax, sample1_bx, sample1_gx, sample1_nx, + sample1_qx + }, + { + sample1, + "public-key!ecc!foo", + "pabgnq", 6, + GPG_ERR_NOT_FOUND + }, + { + sample1, + "public-key!!ecc", + "pabgnq", 6, + GPG_ERR_NOT_FOUND + }, + { + sample1, + "private-key", + "pa/bgnqd", 7, + 0, + sample1_p, sample1_a, sample1_b, sample1_g, sample1_n, + sample1_q, sample1_d + }, + { + sample1, + "private-key", + "p-a+bgnqd", 7, + 0, + sample1_p, "-01", sample1_b, sample1_g, sample1_n, + sample1_q, sample1_d + }, + {NULL} + }; + int idx, i; + const char *paramstr; + int paramidx; + gpg_error_t err; + gcry_sexp_t sxp, sxp1; + gcry_mpi_t mpis[7]; + gcry_buffer_t ioarray[7]; + char iobuffer[200]; + char *string1, *string2; + int aint0, aint1, aint2; + unsigned int auint; + long along1, along2; + unsigned long aulong; + size_t asize; + + info ("checking gcry_sexp_extract_param\n"); + for (idx=0; tests[idx].sexp_str; idx++) + { + err = gcry_sexp_new (&sxp, tests[idx].sexp_str, 0, 1); + if (err) + die ("converting string to sexp failed: %s", gpg_strerror (err)); + + memset (mpis, 0, sizeof mpis); + switch (tests[idx].nparam) + { + case 0: + err = gcry_sexp_extract_param (sxp, tests[idx].path, tests[idx].list, + NULL); + break; + case 1: + err = gcry_sexp_extract_param (sxp, tests[idx].path, tests[idx].list, + mpis+0, NULL); + break; + case 2: + err = gcry_sexp_extract_param (sxp, tests[idx].path, tests[idx].list, + mpis+0, mpis+1, NULL); + break; + case 3: + err = gcry_sexp_extract_param (sxp, tests[idx].path, tests[idx].list, + mpis+0, mpis+1, mpis+2, NULL); + break; + case 4: + err = gcry_sexp_extract_param (sxp, tests[idx].path, tests[idx].list, + mpis+0, mpis+1, mpis+2, mpis+3, NULL); + break; + case 5: + err = gcry_sexp_extract_param (sxp, tests[idx].path, tests[idx].list, + mpis+0, mpis+1, mpis+2, mpis+3, mpis+4, + NULL); + break; + case 6: + err = gcry_sexp_extract_param (sxp, tests[idx].path, tests[idx].list, + mpis+0, mpis+1, mpis+2, mpis+3, mpis+4, + mpis+5, NULL); + break; + case 7: + err = gcry_sexp_extract_param (sxp, tests[idx].path, tests[idx].list, + mpis+0, mpis+1, mpis+2, mpis+3, mpis+4, + mpis+5, mpis+6, NULL); + break; + default: + die ("test %d: internal error", idx); + } + + if (tests[idx].expected_err + && tests[idx].expected_err != GPG_ERR_USER_1) + { + if (tests[idx].expected_err != gpg_err_code (err)) + fail ("gcry_sexp_extract_param test %d failed: " + "expected error '%s' - got '%s'", idx, + gpg_strerror (tests[idx].expected_err),gpg_strerror (err)); + + } + else if (err) + { + fail ("gcry_sexp_extract_param test %d failed: %s", + idx, gpg_strerror (err)); + } + else /* No error - check the extracted values. */ + { + for (paramidx=0; paramidx < DIM (mpis); paramidx++) + { + switch (paramidx) + { + case 0: paramstr = tests[idx].exp_p; break; + case 1: paramstr = tests[idx].exp_a; break; + case 2: paramstr = tests[idx].exp_b; break; + case 3: paramstr = tests[idx].exp_g; break; + case 4: paramstr = tests[idx].exp_n; break; + case 5: paramstr = tests[idx].exp_q; break; + case 6: paramstr = tests[idx].exp_d; break; + default: + die ("test %d: internal error: bad param %d", + idx, paramidx); + } + + if (tests[idx].expected_err == GPG_ERR_USER_1 + && mpis[paramidx] && !paramstr && paramidx == 0) + ; /* Okay Special case error for param 0. */ + else if (!mpis[paramidx] && !paramstr) + ; /* Okay. */ + else if (!mpis[paramidx] && paramstr) + fail ("test %d: value for param %d expected but not returned", + idx, paramidx); + else if (mpis[paramidx] && !paramstr) + fail ("test %d: value for param %d not expected", + idx, paramidx); + else if (cmp_mpihex (mpis[paramidx], paramstr)) + { + fail ("test %d: param %d mismatch", idx, paramidx); + gcry_log_debug ("expected: %s\n", paramstr); + gcry_log_debugmpi (" got", mpis[paramidx]); + } + else if (tests[idx].expected_err && paramidx == 0) + fail ("test %d: param %d: expected error '%s' - got 'Success'", + idx, paramidx, gpg_strerror (tests[idx].expected_err)); + } + + } + + for (i=0; i < DIM (mpis); i++) + gcry_mpi_release (mpis[i]); + gcry_sexp_release (sxp); + } + + info ("checking gcry_sexp_extract_param/desc\n"); + + memset (ioarray, 0, sizeof ioarray); + + err = gcry_sexp_new (&sxp, sample1, 0, 1); + if (err) + die ("converting string to sexp failed: %s", gpg_strerror (err)); + + ioarray[1].size = sizeof iobuffer; + ioarray[1].data = iobuffer; + ioarray[1].off = 0; + ioarray[2].size = sizeof iobuffer; + ioarray[2].data = iobuffer; + ioarray[2].off = 50; + assert (ioarray[2].off < sizeof iobuffer); + err = gcry_sexp_extract_param (sxp, "key-data!private-key", "&pab", + ioarray+0, ioarray+1, ioarray+2, NULL); + if (err) + fail ("gcry_sexp_extract_param with desc failed: %s", gpg_strerror (err)); + else + { + if (!ioarray[0].data) + fail ("gcry_sexp_extract_param/desc failed: no P"); + else if (ioarray[0].size != 32) + fail ("gcry_sexp_extract_param/desc failed: P has wrong size"); + else if (ioarray[0].len != 32) + fail ("gcry_sexp_extract_param/desc failed: P has wrong length"); + else if (ioarray[0].off) + fail ("gcry_sexp_extract_param/desc failed: P has OFF set"); + else if (cmp_bufhex (ioarray[0].data, ioarray[0].len, sample1_p)) + { + fail ("gcry_sexp_extract_param/desc failed: P mismatch"); + gcry_log_debug ("expected: %s\n", sample1_p); + gcry_log_debughex (" got", ioarray[0].data, ioarray[0].len); + } + + if (!ioarray[1].data) + fail ("gcry_sexp_extract_param/desc failed: A buffer lost"); + else if (ioarray[1].size != sizeof iobuffer) + fail ("gcry_sexp_extract_param/desc failed: A size changed"); + else if (ioarray[1].off != 0) + fail ("gcry_sexp_extract_param/desc failed: A off changed"); + else if (ioarray[1].len != 1) + fail ("gcry_sexp_extract_param/desc failed: A has wrong length"); + else if (cmp_bufhex ((char *)ioarray[1].data + ioarray[1].off, + ioarray[1].len, sample1_a)) + { + fail ("gcry_sexp_extract_param/desc failed: A mismatch"); + gcry_log_debug ("expected: %s\n", sample1_a); + gcry_log_debughex (" got", + (char *)ioarray[1].data + ioarray[1].off, + ioarray[1].len); + } + + if (!ioarray[2].data) + fail ("gcry_sexp_extract_param/desc failed: B buffer lost"); + else if (ioarray[2].size != sizeof iobuffer) + fail ("gcry_sexp_extract_param/desc failed: B size changed"); + else if (ioarray[2].off != 50) + fail ("gcry_sexp_extract_param/desc failed: B off changed"); + else if (ioarray[2].len != 32) + fail ("gcry_sexp_extract_param/desc failed: B has wrong length"); + else if (cmp_bufhex ((char *)ioarray[2].data + ioarray[2].off, + ioarray[2].len, sample1_b)) + { + fail ("gcry_sexp_extract_param/desc failed: B mismatch"); + gcry_log_debug ("expected: %s\n", sample1_b); + gcry_log_debughex (" got", + (char *)ioarray[2].data + ioarray[2].off, + ioarray[2].len); + } + + xfree (ioarray[0].data); + } + + gcry_sexp_release (sxp); + + info ("checking gcry_sexp_extract_param long name\n"); + + memset (ioarray, 0, sizeof ioarray); + memset (mpis, 0, sizeof mpis); + + err = gcry_sexp_new (&sxp, sample1, 0, 1); + if (err) + die ("converting string to sexp failed: %s", gpg_strerror (err)); + + err = gcry_sexp_extract_param (sxp, "key-data!private-key", + "&'curve'+p", + ioarray+0, mpis+0, NULL); + if (err) + fail ("gcry_sexp_extract_param long name failed: %s", gpg_strerror (err)); + + if (!ioarray[0].data) + fail ("gcry_sexp_extract_param long name failed: no curve"); + else if (ioarray[0].size != 7) + fail ("gcry_sexp_extract_param long name failed: curve has wrong size"); + else if (ioarray[0].len != 7) + fail ("gcry_sexp_extract_param long name failed: curve has wrong length"); + else if (ioarray[0].off) + fail ("gcry_sexp_extract_param long name failed: curve has OFF set"); + else if (strncmp (ioarray[0].data, "Ed25519", 7)) + { + fail ("gcry_sexp_extract_param long name failed: curve mismatch"); + gcry_log_debug ("expected: %s\n", "Ed25519"); + gcry_log_debug (" got: %.*s\n", + (int)ioarray[0].len, (char*)ioarray[0].data); + } + + if (!mpis[0]) + fail ("gcry_sexp_extract_param long name failed: p not returned"); + else if (cmp_mpihex (mpis[0], sample1_p)) + { + fail ("gcry_sexp_extract_param long name failed: p mismatch"); + gcry_log_debug ("expected: %s\n", sample1_p); + gcry_log_debugmpi (" got", mpis[0]); + } + + gcry_free (ioarray[0].data); + gcry_mpi_release (mpis[0]); + + sxp1 = gcry_sexp_find_token (sxp, "comment", 7); + if (!sxp1) + fail ("gcry_sexp_nth_string faild: no SEXP for comment found"); + else + { + char *comment = gcry_sexp_nth_string (sxp1, 1); + + if (!comment) + fail ("gcry_sexp_nth_string faild: no comment found"); + else + { + if (strcmp (comment, sample1_comment)) + fail ("gcry_sexp_sscan faild for base64"); + xfree (comment); + } + + gcry_sexp_release (sxp1); + } + + info ("checking gcry_sexp_extract_param new modes\n"); + + memset (mpis, 0, sizeof mpis); + + gcry_sexp_release (sxp); + err = gcry_sexp_new (&sxp, sample1, 0, 1); + if (err) + die ("converting string to sexp failed: %s", gpg_strerror (err)); + + err = gcry_sexp_extract_param (sxp, "key-data!private-key", + "%s'curve'+p%s'comment'" + "%uu%di%dI%d'i0'" + "%luu%ldi %ldI" + "%zui", + &string1, mpis+0, &string2, + &auint, &aint1, &aint2, &aint0, + &aulong, &along1, &along2, + &asize, + NULL); + if (err) + fail ("gcry_sexp_extract_param new modes failed: %s", gpg_strerror (err)); + + if (!string1) + fail ("gcry_sexp_extract_param new modes: no curve"); + else if (strcmp (string1, "Ed25519")) + { + fail ("gcry_sexp_extract_param new modes failed: curve mismatch"); + gcry_log_debug ("expected: %s\n", "Ed25519"); + gcry_log_debug (" got: %s\n", string1); + } + + if (!mpis[0]) + fail ("gcry_sexp_extract_param new modes failed: p not returned"); + else if (cmp_mpihex (mpis[0], sample1_p)) + { + fail ("gcry_sexp_extract_param new modes failed: p mismatch"); + gcry_log_debug ("expected: %s\n", sample1_p); + gcry_log_debugmpi (" got", mpis[0]); + } + + if (auint != 65537) + fail ("gcry_sexp_extract_param new modes failed: auint mismatch"); + if (aint1 != 65537) + fail ("gcry_sexp_extract_param new modes failed: aint1 mismatch"); + if (aint2 != -65535) + fail ("gcry_sexp_extract_param new modes failed: aint2 mismatch"); + if (aint0) + fail ("gcry_sexp_extract_param new modes failed: aint0 mismatch"); + if (aulong != 65537) + fail ("gcry_sexp_extract_param new modes failed: aulong mismatch"); + if (along1 != 65537) + fail ("gcry_sexp_extract_param new modes failed: along1 mismatch"); + if (along2 != -65535) + fail ("gcry_sexp_extract_param new modes failed: along2 mismatch"); + if (asize != 65537) + fail ("gcry_sexp_extract_param new modes failed: asize mismatch"); + + + gcry_free (string1); + gcry_free (string2); + gcry_mpi_release (mpis[0]); + + + info ("checking gcry_sexp_extract_param flag list\n"); + + gcry_sexp_release (sxp); + err = gcry_sexp_new (&sxp, sample1, 0, 1); + if (err) + die ("converting string to sexp failed: %s", gpg_strerror (err)); + + err = gcry_sexp_extract_param (sxp, "key-data!private-key", + "%#s'flaglist''noflags'", + &string1, &string2, + NULL); + if (err) + fail ("gcry_sexp_extract_param flag list failed: %s", gpg_strerror (err)); + + if (!string1) + fail ("gcry_sexp_extract_param flaglist: no flaglist"); + else if (strcmp (string1, "foo bar () test 42")) + { + fail ("gcry_sexp_extract_param flag list failed: wrong list"); + gcry_log_debug ("expected: %s\n", "foo bar ( ) test 42"); + gcry_log_debug (" got: %s\n", string1); + } + + if (!string2) + fail ("gcry_sexp_extract_param flaglist: no second flaglist"); + else if (strcmp (string2, "")) + { + fail ("gcry_sexp_extract_param flag list failed: wrong list"); + gcry_log_debug ("expected: '%s'\n", ""); + gcry_log_debug (" got: '%s'\n", string2); + } + + gcry_free (string1); + gcry_free (string2); + + + gcry_sexp_release (sxp); +} + + +/* A test based on bug 1594. */ +static void +bug_1594 (void) +{ +static char thing[] = + "(signature" + " (public-key" + " (rsa" + " (n #00A53A6B3A50BE571F805BD98ECE1FCE4CE291C3D4D3E971740E1EE6D447F526" + " 6AC8973DDC82F0ADD234CC82E0A0A3F48B81ACC8B038DB8ACC3E78DC2ED2642F" + " 6BA353FCA60F47C2801DEB477B37FB8B2F5508AA1C6D922780DB142DEA19B812" + " C4E64F1138AD3BD61C58DB2D2591BE0BF36A1AC588AA45763BCDFF581050ABA8" + " CA47BD9723ADD6A308AE28471EDD2B16D03C941D4F2B7E019C43AF8972880633" + " 54E97B7E19F1677D84B69A26B184A77B719DD72C48E0EE36107046F786566A9D" + " 13BAD724D6D78F24700FC22FC000E1B2A8C1B08ED62008395B0764CD9B55E80D" + " A0A2B61C698DC27EA98E68BB576ACFC2B91B4D7283E7D960948D049D6E3C4CB1" + " F489B460A120A4BB6C04A843FD3A67454136DE61CF68A927871EFFA9141BD372" + " A748593C703E0301F039A9E674C50301BFC385BABE5B154250E7D57B82DB31F1" + " E1AC696F870DCD8FE8DEC75608B988FCA3B484F1FD7755BF452F99597269AF02" + " E8AF87D0F93DB427291659183D077254C835BFB6DDFD87CD0B5E0738682FCD34" + " 923F22551F73944E6CBE3ED6879B4414676B5DA0F30ED21DFA12BD2230C3C5D2" + " EA116A3EFEB4AEC21C58E63FAFA549A63190F01859445E9B80F427B80FD4C884" + " 2AD41FE760A3E9DEDFB56CEBE8EA783838B2B392CACDDC760CCE212E388AFBC1" + " 95DC6D0ED87E9091F82A82CE372738C8DE8ABD76ACD06AC8B80AA0597162DF59" + " 67#)" + " (e #010001#))))"; + gcry_sexp_t sig, pubkey, n, n_val; + + info ("checking fix for bug 1594\n"); + + if (gcry_sexp_new (&sig, thing, 0, 1)) + die ("scanning fixed string failed\n"); + pubkey = gcry_sexp_find_token (sig, "public-key", 0); + gcry_sexp_release (sig); + if (!pubkey) + { + fail ("'public-key' token not found"); + return; + } + n = gcry_sexp_find_token (pubkey, "n", 0); + if (!n) + { + fail ("'n' token not found"); + gcry_sexp_release (pubkey); + return; + } + n_val = gcry_sexp_nth (n, 1); + /* Bug 1594 would require the following test: + * if (n_val) + * fail ("extracting 1-th of 'n' list did not fail"); + * However, we meanwhile modified the S-expression functions to + * behave like Scheme to allow the access of any element of a list. + */ + if (!n_val) + fail ("extracting 1-th of 'n' list failed"); + /*gcry_log_debugsxp ("1-th", n_val); => "(#00A5...#)" */ + gcry_sexp_release (n_val); + n_val = gcry_sexp_nth (n, 2); + if (n_val) + fail ("extracting 2-th of 'n' list did not fail"); + n_val = gcry_sexp_nth (n, 0); + if (!n_val) + fail ("extracting 0-th of 'n' list failed"); + /*gcry_log_debugsxp ("0-th", n_val); => "(n)" */ + if (gcry_sexp_nth (n_val, 1)) + fail ("extracting 1-th of car of 'n' list did not fail"); + gcry_sexp_release (n_val); + gcry_sexp_release (n); + gcry_sexp_release (pubkey); +} + + +int +main (int argc, char **argv) +{ + int last_argc = -1; + int loop = 0; + + if (argc) + { + argc--; argv++; + } + while (argc && last_argc != argc ) + { + last_argc = argc; + if (!strcmp (*argv, "--")) + { + argc--; argv++; + break; + } + else if (!strcmp (*argv, "--help")) + { + puts ( +"usage: " PGM " [options]\n" +"\n" +"Options:\n" +" --verbose Show what is going on\n" +" --debug Flyswatter\n" +); + exit (0); + } + else if (!strcmp (*argv, "--verbose")) + { + verbose = 1; + argc--; argv++; + } + else if (!strcmp (*argv, "--debug")) + { + verbose = debug = 1; + argc--; argv++; + } + else if (!strcmp (*argv, "--loop")) + { + argc--; argv++; + if (argc) + { + loop = atoi (*argv); + argc--; argv++; + } + } + else if (!strncmp (*argv, "--", 2)) + die ("unknown option '%s'", *argv); + } + + if (debug) + xgcry_control ((GCRYCTL_SET_DEBUG_FLAGS, 1u, 0)); + xgcry_control ((GCRYCTL_DISABLE_SECMEM_WARN)); + if (getenv ("GCRYPT_IN_ASAN_TEST")) + { + fputs ("Note: " PGM " not using secmem as running with ASAN.\n", stdout); + } + else + { + xgcry_control ((GCRYCTL_INIT_SECMEM, 16384, 0)); + } + if (!gcry_check_version (GCRYPT_VERSION)) + die ("version mismatch"); + /* #include "../src/gcrypt-int.h" indicates that internal interfaces + may be used; thus better do an exact version check. */ + if (strcmp (gcry_check_version (NULL), GCRYPT_VERSION)) + die ("exact version match failed"); + xgcry_control ((GCRYCTL_ENABLE_QUICK_RANDOM, 0)); + xgcry_control ((GCRYCTL_INITIALIZATION_FINISHED, 0)); + + do + { + basic (); + canon_len (); + back_and_forth (); + check_sscan (); + check_extract_param (); + bug_1594 (); + } + while (!error_count && loop--); + + return error_count? 1:0; +} |