diff --git a/tests/t-common.h b/tests/t-common.h index 288963df..35469860 100644 --- a/tests/t-common.h +++ b/tests/t-common.h @@ -1,99 +1,122 @@ /* t-common.h - Common code for the tests. * Copyright (C) 2013 g10 Code GmbH * * This file is part of libgpg-error. * * libgpg-error 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. * * libgpg-error 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 . */ #include #include "../src/gcrypt.h" -#ifndef PGM -# error Macro PGM not defined. +#ifndef PGMNAME +# error Macro PGMNAME not defined. #endif +#ifndef _GCRYPT_CONFIG_H_INCLUDED +# error config.h not included +#endif + +/* A couple of useful macros. */ +#ifndef DIM +# define DIM(v) (sizeof(v)/sizeof((v)[0])) +#endif +#define my_isascii(c) (!((c) & 0x80)) +#define digitp(p) (*(p) >= '0' && *(p) <= '9') +#define hexdigitp(a) (digitp (a) \ + || (*(a) >= 'A' && *(a) <= 'F') \ + || (*(a) >= 'a' && *(a) <= 'f')) +#define xtoi_1(p) (*(p) <= '9'? (*(p)- '0'): \ + *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10)) +#define xtoi_2(p) ((xtoi_1(p) * 16) + xtoi_1((p)+1)) +#define xmalloc(a) gcry_xmalloc ((a)) +#define xcalloc(a,b) gcry_xcalloc ((a),(b)) +#define xstrdup(a) gcry_xstrdup ((a)) +#define xfree(a) gcry_free ((a)) +#define pass() do { ; } while (0) +/* Standard global variables. */ static int verbose; static int debug; static int errorcount; +/* Reporting functions. */ static void die (const char *format, ...) { va_list arg_ptr ; fflush (stdout); #ifdef HAVE_FLOCKFILE flockfile (stderr); #endif - fprintf (stderr, "%s: ", PGM); + fprintf (stderr, "%s: ", PGMNAME); va_start (arg_ptr, format) ; vfprintf (stderr, format, arg_ptr); va_end (arg_ptr); if (*format && format[strlen(format)-1] != '\n') putc ('\n', stderr); #ifdef HAVE_FLOCKFILE funlockfile (stderr); #endif exit (1); } static void fail (const char *format, ...) { va_list arg_ptr; fflush (stdout); #ifdef HAVE_FLOCKFILE flockfile (stderr); #endif - fprintf (stderr, "%s: ", PGM); + fprintf (stderr, "%s: ", PGMNAME); va_start (arg_ptr, format); vfprintf (stderr, format, arg_ptr); va_end (arg_ptr); if (*format && format[strlen(format)-1] != '\n') putc ('\n', stderr); #ifdef HAVE_FLOCKFILE funlockfile (stderr); #endif errorcount++; if (errorcount >= 50) die ("stopped after 50 errors."); } static void -show (const char *format, ...) +info (const char *format, ...) { va_list arg_ptr; if (!verbose) return; #ifdef HAVE_FLOCKFILE flockfile (stderr); #endif - fprintf (stderr, "%s: ", PGM); + fprintf (stderr, "%s: ", PGMNAME); va_start (arg_ptr, format); vfprintf (stderr, format, arg_ptr); if (*format && format[strlen(format)-1] != '\n') putc ('\n', stderr); va_end (arg_ptr); #ifdef HAVE_FLOCKFILE funlockfile (stderr); #endif } diff --git a/tests/t-lock.c b/tests/t-lock.c index c6c1e418..22b67ef5 100644 --- a/tests/t-lock.c +++ b/tests/t-lock.c @@ -1,460 +1,463 @@ /* t-lock.c - Check the lock functions * 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 . */ #if HAVE_CONFIG_H # include #endif #include #include #include #include #include #include #if HAVE_PTHREAD # include #endif -#define PGM "t-lock" +#define PGMNAME "t-lock" #include "t-common.h" /* Mingw requires us to include windows.h after winsock2.h which is included by gcrypt.h. */ #ifdef _WIN32 # include #endif #ifdef _WIN32 # define THREAD_RET_TYPE DWORD WINAPI # define THREAD_RET_VALUE 0 #else # define THREAD_RET_TYPE void * # define THREAD_RET_VALUE NULL #endif #define PRIV_CTL_EXTERNAL_LOCK_TEST 61 #define EXTERNAL_LOCK_TEST_INIT 30111 #define EXTERNAL_LOCK_TEST_LOCK 30112 #define EXTERNAL_LOCK_TEST_UNLOCK 30113 #define EXTERNAL_LOCK_TEST_DESTROY 30114 /* Number of threads to run. */ #define N_NONCE_THREADS 8 /* Number of interations. */ #define N_NONCE_ITERATIONS 1000 /* Requested nonce size. */ #define NONCE_SIZE 11 /* This tests works by having a a couple of accountant threads which do random transactions between accounts and a revision threads which checks that the balance of all accounts is invariant. The idea for this check is due to Bruno Haible. */ #define N_ACCOUNT 8 #define ACCOUNT_VALUE 42 static int account[N_ACCOUNT]; /* Number of transactions done by each accountant. */ #define N_TRANSACTIONS 1000 /* Number of accountants to run. */ #define N_ACCOUNTANTS 5 /* Maximum transaction value. A quite low value is used so that we would get an integer overflow. */ #define MAX_TRANSACTION_VALUE 50 /* Flag to tell the revision thread to finish. */ static volatile int stop_revision_thread; struct thread_arg_s { int no; }; /* Wrapper functions to access Libgcrypt's internal test lock. */ static void external_lock_test_init (int line) { gpg_error_t err; err = gcry_control (PRIV_CTL_EXTERNAL_LOCK_TEST, EXTERNAL_LOCK_TEST_INIT); if (err) fail ("init lock failed at %d: %s", line, gpg_strerror (err)); } static void external_lock_test_lock (int line) { gpg_error_t err; err = gcry_control (PRIV_CTL_EXTERNAL_LOCK_TEST, EXTERNAL_LOCK_TEST_LOCK); if (err) fail ("taking lock failed at %d: %s", line, gpg_strerror (err)); } static void external_lock_test_unlock (int line) { gpg_error_t err; err = gcry_control (PRIV_CTL_EXTERNAL_LOCK_TEST, EXTERNAL_LOCK_TEST_UNLOCK); if (err) fail ("releasing lock failed at %d: %s", line, gpg_strerror (err)); } static void external_lock_test_destroy (int line) { gpg_error_t err; err = gcry_control (PRIV_CTL_EXTERNAL_LOCK_TEST, EXTERNAL_LOCK_TEST_DESTROY); if (err) fail ("destroying lock failed at %d: %s", line, gpg_strerror (err)); } /* The nonce thread. We simply request a couple of nonces and return. */ static THREAD_RET_TYPE nonce_thread (void *argarg) { struct thread_arg_s *arg = argarg; int i; char nonce[NONCE_SIZE]; for (i = 0; i < N_NONCE_ITERATIONS; i++) { gcry_create_nonce (nonce, sizeof nonce); if (i && !(i%100)) - show ("thread %d created %d nonces so far", arg->no, i); + info ("thread %d created %d nonces so far", arg->no, i); } gcry_free (arg); return THREAD_RET_VALUE; } /* To check our locking function we run several threads all accessing the nonce functions. If this function returns we know that there are no obvious deadlocks or failed lock initialization. */ static void check_nonce_lock (void) { struct thread_arg_s *arg; #ifdef _WIN32 HANDLE threads[N_NONCE_THREADS]; int i; int rc; for (i=0; i < N_NONCE_THREADS; i++) { arg = gcry_xmalloc (sizeof *arg); arg->no = i; threads[i] = CreateThread (NULL, 0, nonce_thread, arg, 0, NULL); if (!threads[i]) die ("error creating nonce thread %d: rc=%d", i, (int)GetLastError ()); } for (i=0; i < N_NONCE_THREADS; i++) { rc = WaitForSingleObject (threads[i], INFINITE); if (rc == WAIT_OBJECT_0) - show ("nonce thread %d has terminated", i); + info ("nonce thread %d has terminated", i); else fail ("waiting for nonce thread %d failed: %d", i, (int)GetLastError ()); CloseHandle (threads[i]); } #elif HAVE_PTHREAD pthread_t threads[N_NONCE_THREADS]; int rc, i; for (i=0; i < N_NONCE_THREADS; i++) { arg = gcry_xmalloc (sizeof *arg); arg->no = i; pthread_create (&threads[i], NULL, nonce_thread, arg); } for (i=0; i < N_NONCE_THREADS; i++) { rc = pthread_join (threads[i], NULL); if (rc) fail ("pthread_join failed for nonce thread %d: %s", i, strerror (errno)); else - show ("nonce thread %d has terminated", i); + info ("nonce thread %d has terminated", i); } #endif /*!_WIN32*/ } /* Initialze all accounts. */ static void init_accounts (void) { int i; for (i=0; i < N_ACCOUNT; i++) account[i] = ACCOUNT_VALUE; } /* Check that the sum of all accounts matches the intial sum. */ static void check_accounts (void) { int i, sum; sum = 0; for (i = 0; i < N_ACCOUNT; i++) sum += account[i]; if (sum != N_ACCOUNT * ACCOUNT_VALUE) die ("accounts out of balance"); } static void print_accounts (void) { int i; for (i=0; i < N_ACCOUNT; i++) printf ("account %d: %6d\n", i, account[i]); } /* Get a a random integer value in the range 0 to HIGH. */ static unsigned int get_rand (int high) { return (unsigned int)(1+(int)((double)(high+1)*rand ()/(RAND_MAX+1.0))) - 1; } /* Pick a random account. Note that this fucntion is not thread-safe. */ static int pick_account (void) { return get_rand (N_ACCOUNT - 1); } /* Pick a random value for a transaction. This is not thread-safe. */ static int pick_value (void) { return get_rand (MAX_TRANSACTION_VALUE); } /* This is the revision department. */ static THREAD_RET_TYPE revision_thread (void *arg) { (void)arg; while (!stop_revision_thread) { external_lock_test_lock (__LINE__); check_accounts (); external_lock_test_unlock (__LINE__); } return THREAD_RET_VALUE; } /* This is one of our accountants. */ static THREAD_RET_TYPE accountant_thread (void *arg) { int i; int acc1, acc2; int value; (void)arg; for (i = 0; i < N_TRANSACTIONS; i++) { external_lock_test_lock (__LINE__); acc1 = pick_account (); acc2 = pick_account (); value = pick_value (); account[acc1] += value; account[acc2] -= value; external_lock_test_unlock (__LINE__); } return THREAD_RET_VALUE; } static void run_test (void) { #ifdef _WIN32 HANDLE rthread; HANDLE athreads[N_ACCOUNTANTS]; int i; int rc; external_lock_test_init (__LINE__); stop_revision_thread = 0; rthread = CreateThread (NULL, 0, revision_thread, NULL, 0, NULL); if (!rthread) die ("error creating revision thread: rc=%d", (int)GetLastError ()); for (i=0; i < N_ACCOUNTANTS; i++) { athreads[i] = CreateThread (NULL, 0, accountant_thread, NULL, 0, NULL); if (!athreads[i]) die ("error creating accountant thread %d: rc=%d", i, (int)GetLastError ()); } for (i=0; i < N_ACCOUNTANTS; i++) { rc = WaitForSingleObject (athreads[i], INFINITE); if (rc == WAIT_OBJECT_0) - show ("accountant thread %d has terminated", i); + info ("accountant thread %d has terminated", i); else fail ("waiting for accountant thread %d failed: %d", i, (int)GetLastError ()); CloseHandle (athreads[i]); } stop_revision_thread = 1; rc = WaitForSingleObject (rthread, INFINITE); if (rc == WAIT_OBJECT_0) - show ("revision thread has terminated"); + info ("revision thread has terminated"); else fail ("waiting for revision thread failed: %d", (int)GetLastError ()); CloseHandle (rthread); #else /*!_WIN32*/ pthread_t rthread; pthread_t athreads[N_ACCOUNTANTS]; int rc, i; external_lock_test_init (__LINE__); stop_revision_thread = 0; pthread_create (&rthread, NULL, revision_thread, NULL); for (i=0; i < N_ACCOUNTANTS; i++) pthread_create (&athreads[i], NULL, accountant_thread, NULL); for (i=0; i < N_ACCOUNTANTS; i++) { rc = pthread_join (athreads[i], NULL); if (rc) fail ("pthread_join failed for accountant thread %d: %s", i, strerror (errno)); else - show ("accountant thread %d has terminated", i); + info ("accountant thread %d has terminated", i); } stop_revision_thread = 1; rc = pthread_join (rthread, NULL); if (rc) fail ("pthread_join failed for the revision thread: %s", strerror (errno)); else - show ("revision thread has terminated"); + info ("revision thread has terminated"); #endif /*!_WIN32*/ external_lock_test_destroy (__LINE__); } int main (int argc, char **argv) { int last_argc = -1; if (argc) { argc--; argv++; } while (argc && last_argc != argc ) { last_argc = argc; if (!strcmp (*argv, "--help")) { puts ( "usage: ./t-lock [options]\n" "\n" "Options:\n" " --verbose Show what is going on\n" " --debug Flyswatter\n" ); exit (0); } if (!strcmp (*argv, "--verbose")) { verbose = 1; argc--; argv++; } else if (!strcmp (*argv, "--debug")) { verbose = debug = 1; argc--; argv++; } } srand (time(NULL)*getpid()); if (debug) gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1u, 0); gcry_control (GCRYCTL_DISABLE_SECMEM, 0); if (!gcry_check_version (GCRYPT_VERSION)) die ("version mismatch"); + /* We are using non-public interfaces - check the exact version. */ + if (strcmp (gcry_check_version (NULL), GCRYPT_VERSION)) + die ("exact version match failed"); gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0); gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0); check_nonce_lock (); init_accounts (); check_accounts (); run_test (); check_accounts (); /* Run a second time to check deinit code. */ run_test (); check_accounts (); if (verbose) print_accounts (); return errorcount ? 1 : 0; } diff --git a/tests/t-sexp.c b/tests/t-sexp.c index 4c482776..35103822 100644 --- a/tests/t-sexp.c +++ b/tests/t-sexp.c @@ -1,1062 +1,1045 @@ /* t-sexp.c - S-expression regression tests - * Copyright (C) 2001, 2002, 2003, 2005 Free Software Foundation, Inc. + * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * License along with this program; if not, see . */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include "../src/gcrypt-int.h" #define PGMNAME "t-sexp" - -#ifndef DIM -# define DIM(v) (sizeof(v)/sizeof((v)[0])) -#endif -#define my_isascii(c) (!((c) & 0x80)) -#define digitp(p) (*(p) >= '0' && *(p) <= '9') -#define hexdigitp(a) (digitp (a) \ - || (*(a) >= 'A' && *(a) <= 'F') \ - || (*(a) >= 'a' && *(a) <= 'f')) -#define xtoi_1(p) (*(p) <= '9'? (*(p)- '0'): \ - *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10)) -#define xtoi_2(p) ((xtoi_1(p) * 16) + xtoi_1((p)+1)) -#define xmalloc(a) gcry_xmalloc ((a)) -#define xcalloc(a,b) gcry_xcalloc ((a),(b)) -#define xstrdup(a) gcry_xstrdup ((a)) -#define xfree(a) gcry_free ((a)) -#define pass() do { ; } while (0) - - -static int verbose; -static int error_count; - -static void -die (const char *format, ...) -{ - va_list arg_ptr ; - - fflush (stdout); - fprintf (stderr, "%s: ", PGMNAME); - va_start( arg_ptr, format ) ; - vfprintf (stderr, format, arg_ptr ); - va_end(arg_ptr); - if (*format && format[strlen(format)-1] != '\n') - putc ('\n', stderr); - exit (1); -} - -static void -info (const char *format, ...) -{ - va_list arg_ptr; - - if (verbose) - { - va_start( arg_ptr, format ) ; - vfprintf (stderr, format, arg_ptr ); - va_end(arg_ptr); - if (*format && format[strlen(format)-1] != '\n') - putc ('\n', stderr); - } -} - -static void -fail ( const char *format, ... ) -{ - va_list arg_ptr ; - - fputs (PGMNAME ": ", stderr); - va_start( arg_ptr, format ) ; - vfprintf (stderr, format, arg_ptr ); - va_end(arg_ptr); - if (*format && format[strlen(format)-1] != '\n') - putc ('\n', stderr); - error_count++; -} - +#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%s\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); } } static void back_and_forth_one (int testno, const char *buffer, size_t length) { gcry_error_t rc; gcry_sexp_t se, se1; 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 dies not return it */ { fail ("baf %d: length mismatch for canon\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; } 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); /* FIXME: we need a lot more tests */ gcry_sexp_release (se); } 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 }, { 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. */ 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" " (ecc" " (curve Ed25519)" " (p #7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFED#)" " (a #FF#)" " (b #D2036CEE2B6FFE738CC740797779E89800700A4D4141D8AB75EB4DCA135978B6#)" " (g #04" " 216936D3CD6E53FEC0A4E231FDD6DC5C692CC7609525A7B2C9562D608F25D51A" " 6666666666666666666666666666666666666666666666666666666666666658#)" " (n #1000000000000000000000000000000014DEF9DEA2F79CD65812631A5CF5D3ED#)" " (q #30B37806015CA06B3AEB9423EE84A41D7F31AA65F4148553755206D679F8BF62#)" " (d #56BEA284A22F443A7AEA8CEFA24DA5055CDF1D490C94D8C568FE0802C9169276#)" ")))"; 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 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; gcry_mpi_t mpis[7]; gcry_buffer_t ioarray[7]; char iobuffer[200]; 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]); gcry_sexp_release (sxp); } + + int main (int argc, char **argv) { - if (argc > 1 && !strcmp (argv[1], "--verbose")) - verbose = 1; + int last_argc = -1; + + 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: " PGMNAME " [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 (!strncmp (*argv, "--", 2)) + die ("unknown option '%s'", *argv); + } + if (debug) + gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1u, 0); gcry_control (GCRYCTL_DISABLE_SECMEM_WARN); gcry_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"); + gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0); + gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0); basic (); canon_len (); back_and_forth (); check_sscan (); check_extract_param (); - return error_count? 1:0; + return errorcount? 1:0; }