diff options
-rw-r--r-- | ChangeLog | 4 | ||||
-rw-r--r-- | NEWS | 9 | ||||
-rw-r--r-- | configure.ac | 2 | ||||
-rw-r--r-- | random/ChangeLog | 13 | ||||
-rw-r--r-- | random/rand-internal.h | 10 | ||||
-rw-r--r-- | random/random-fips.c | 124 | ||||
-rw-r--r-- | random/random.c | 38 | ||||
-rw-r--r-- | random/random.h | 12 | ||||
-rw-r--r-- | src/ChangeLog | 15 | ||||
-rw-r--r-- | src/fips.c | 47 | ||||
-rw-r--r-- | src/g10lib.h | 3 | ||||
-rw-r--r-- | src/gcrypt.h.in | 1 | ||||
-rw-r--r-- | src/global.c | 78 | ||||
-rw-r--r-- | tests/ChangeLog | 4 | ||||
-rw-r--r-- | tests/Makefile.am | 2 | ||||
-rw-r--r-- | tests/fipsrngdrv.c | 119 |
16 files changed, 468 insertions, 13 deletions
@@ -1,3 +1,7 @@ +2008-09-15 Werner Koch <wk@g10code.com> + + * configure.ac: Cehck for syslog. + 2008-09-08 Werner Koch <wk@g10code.com> Release 1.4.2. @@ -1,6 +1,15 @@ Noteworthy changes in version 1.4.3 ------------------------------------------------ + * Try to auto-initialize Libgcrypt to minimize the effect of + applications not doing that correctly. This is not a perfect + solution but given that many applicationion would totally fail + without such a hack, we try to help at least with the most common + cases. Folks, please read the manual to learn how to properly + initialize Libgcrypt! + + * Log fatal error via syslog. + * More self-tests. * Documentation cleanups. diff --git a/configure.ac b/configure.ac index a4dd27cf..e8faa318 100644 --- a/configure.ac +++ b/configure.ac @@ -700,7 +700,7 @@ AC_CHECK_FUNCS(stpcpy strcasecmp) AC_CHECK_FUNCS(strtoul memmove stricmp atexit raise) # Other checks AC_CHECK_FUNCS(strerror rand mmap getpagesize sysconf waitpid wait4) -AC_CHECK_FUNCS(gettimeofday getrusage gethrtime clock_gettime) +AC_CHECK_FUNCS(gettimeofday getrusage gethrtime clock_gettime syslog) AC_CHECK_FUNCS(fcntl ftruncate) GNUPG_CHECK_MLOCK diff --git a/random/ChangeLog b/random/ChangeLog index 19042680..ed101f68 100644 --- a/random/ChangeLog +++ b/random/ChangeLog @@ -1,3 +1,16 @@ +2008-09-15 Werner Koch <wk@g10code.com> + + * random.c (_gcry_random_init_external_test): New. + (_gcry_random_run_external_test): New. + (_gcry_random_deinit_external_test): New. + * random-fips.c (struct rng_context): Turn TEST_DT_COUNTER into a + 32 bit integer. + (x931_get_dt): Ditto. + (selftest_kat): Intialize it accordingly. + (_gcry_rngfips_init_external_test): New. + (_gcry_rngfips_run_external_test): New. + (_gcry_rngfips_deinit_external_test): New. + 2008-09-05 Werner Koch <wk@g10code.com> * random.c (_gcry_random_selftest): Return success if not in fips diff --git a/random/rand-internal.h b/random/rand-internal.h index e3c01920..269fad95 100644 --- a/random/rand-internal.h +++ b/random/rand-internal.h @@ -79,6 +79,16 @@ void _gcry_rngfips_create_nonce (void *buffer, size_t length); gcry_error_t _gcry_rngfips_selftest (selftest_report_func_t report); +gcry_err_code_t _gcry_rngfips_init_external_test (void **r_context, + const void *key, + size_t keylen, + const void *seed, + size_t seedlen, + const void *dt, + size_t dtlen); +gcry_err_code_t _gcry_rngfips_run_external_test (void *context, + char *buffer, size_t buflen); +void _gcry_rngfips_deinit_external_test (void *context); diff --git a/random/random-fips.c b/random/random-fips.c index f81ab466..90499db2 100644 --- a/random/random-fips.c +++ b/random/random-fips.c @@ -144,12 +144,12 @@ struct rng_context /* To implement a KAT we need to provide a know DT value. To accomplish this the x931_get_dt function checks whether this field is not NULL and then uses the 16 bytes at this address for - the DT value. However the last byte is will be replaced by the - value of field TEST_DT_COUNTER which will be incremented with + the DT value. However the last 4 bytes are replaced by the + value of field TEST_DT_COUNTER which will be incremented after each invocation of x931_get_dt. We use a pointer and not a buffer because there is no need to put this value into secure memory. */ const unsigned char *test_dt_ptr; - unsigned char test_dt_counter; + u32 test_dt_counter; /* We need to keep track of the process which did the initialization so that we can detect a fork. The volatile modifier is required @@ -283,8 +283,12 @@ x931_get_dt (unsigned char *buffer, size_t length, rng_context_t rng_ctx) && rng_ctx != std_rng_context && rng_ctx != strong_rng_context) { - memcpy (buffer, rng_ctx->test_dt_ptr, 15); - buffer[15] = rng_ctx->test_dt_counter++; + memcpy (buffer, rng_ctx->test_dt_ptr, 16); + buffer[12] = (rng_ctx->test_dt_counter >> 24); + buffer[13] = (rng_ctx->test_dt_counter >> 16); + buffer[14] = (rng_ctx->test_dt_counter >> 8); + buffer[15] = rng_ctx->test_dt_counter; + rng_ctx->test_dt_counter++; return; } @@ -792,7 +796,7 @@ _gcry_rngfips_add_bytes (const void *buf, size_t buflen, int quality) /* Public function to fill the buffer with LENGTH bytes of cryptographically strong random bytes. Level GCRY_WEAK_RANDOM is - here mapped to GCRY_STRING_RANDOM, GCRY_STRONG_RANDOM is strong + here mapped to GCRY_STRONG_RANDOM, GCRY_STRONG_RANDOM is strong enough for most usage, GCRY_VERY_STRONG_RANDOM is good for key generation stuff but may be very slow. */ void @@ -915,9 +919,12 @@ selftest_kat (selftest_report_func_t report) /* Setup a DT value. */ test_ctx->test_dt_ptr = tv[tvidx].dt; - test_ctx->test_dt_counter = tv[tvidx].dt[15]; + test_ctx->test_dt_counter = ( (tv[tvidx].dt[12] << 24) + |(tv[tvidx].dt[13] << 16) + |(tv[tvidx].dt[14] << 8) + |(tv[tvidx].dt[15]) ); - /* Get ant compare the first three results. */ + /* Get and compare the first three results. */ for (ridx=0; ridx < 3; ridx++) { /* Compute the next value. */ @@ -989,3 +996,104 @@ _gcry_rngfips_selftest (selftest_report_func_t report) return gpg_error (ec); } + +/* Create a new test context for an external RNG test driver. On + success the test context is stored at R_CONTEXT; on failure NULL is + stored at R_CONTEXT and an error code is returned. */ +gcry_err_code_t +_gcry_rngfips_init_external_test (void **r_context, + const void *key, size_t keylen, + const void *seed, size_t seedlen, + const void *dt, size_t dtlen) +{ + gpg_error_t err; + rng_context_t test_ctx; + + _gcry_rngfips_initialize (1); /* Auto-initialize if needed. */ + + if (!r_context + || !key || keylen != 16 + || !seed || seedlen != 16 + || !dt || dtlen != 16 ) + return GPG_ERR_INV_ARG; + + test_ctx = gcry_calloc (1, sizeof *test_ctx + dtlen); + if (!test_ctx) + return gpg_err_code_from_syserror (); + setup_guards (test_ctx); + + /* Setup the key. */ + err = gcry_cipher_open (&test_ctx->cipher_hd, + GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_ECB, + GCRY_CIPHER_SECURE); + if (err) + goto leave; + + err = gcry_cipher_setkey (test_ctx->cipher_hd, key, keylen); + if (err) + goto leave; + + test_ctx->key_init_pid = getpid (); + + /* Setup the seed. */ + memcpy (test_ctx->seed_V, seed, seedlen); + test_ctx->is_seeded = 1; + test_ctx->seed_init_pid = getpid (); + + /* Setup a DT value. Because our context structure only stores a + pointer we copy the DT value to the extra space we allocated in + the test_ctx and set the pointer to tehre. */ + memcpy ((char*)test_ctx + sizeof *test_ctx, dt, dtlen); + test_ctx->test_dt_ptr = (unsigned char*)test_ctx + sizeof test_ctx; + test_ctx->test_dt_counter = ( (test_ctx->test_dt_ptr[12] << 24) + |(test_ctx->test_dt_ptr[13] << 16) + |(test_ctx->test_dt_ptr[14] << 8) + |(test_ctx->test_dt_ptr[15]) ); + + check_guards (test_ctx); + /* All fine. */ + err = 0; + + leave: + if (err) + { + gcry_cipher_close (test_ctx->cipher_hd); + gcry_free (test_ctx); + *r_context = NULL; + } + else + *r_context = test_ctx; + return gcry_err_code (err); +} + + +/* Get BUFLEN bytes from the RNG using the test CONTEXT and store them + at BUFFER. Return 0 on success or an error code. */ +gcry_err_code_t +_gcry_rngfips_run_external_test (void *context, char *buffer, size_t buflen) +{ + rng_context_t test_ctx = context; + + if (!test_ctx || !buffer || buflen != 16) + return GPG_ERR_INV_ARG; + + lock_rng (); + get_random (buffer, buflen, test_ctx); + unlock_rng (); + return 0; +} + +/* Release the test CONTEXT. */ +void +_gcry_rngfips_deinit_external_test (void *context) +{ + rng_context_t test_ctx = context; + + if (test_ctx) + { + gcry_cipher_close (test_ctx->cipher_hd); + gcry_free (test_ctx); + } +} + + diff --git a/random/random.c b/random/random.c index 7a286b8e..9da83cf0 100644 --- a/random/random.c +++ b/random/random.c @@ -283,3 +283,41 @@ _gcry_random_selftest (selftest_report_func_t report) return 0; /* No selftests yet. */ } + +/* Create a new test context for an external RNG test driver. On + success the test context is stored at R_CONTEXT; on failure NULL is + stored at R_CONTEXT and an error code is returned. */ +gcry_err_code_t +_gcry_random_init_external_test (void **r_context, + unsigned int flags, + const void *key, size_t keylen, + const void *seed, size_t seedlen, + const void *dt, size_t dtlen) +{ + (void)flags; + if (fips_mode ()) + return _gcry_rngfips_init_external_test (r_context, key, keylen, + seed, seedlen, + dt, dtlen); + else + return GPG_ERR_NOT_SUPPORTED; +} + +/* Get BUFLEN bytes from the RNG using the test CONTEXT and store them + at BUFFER. Return 0 on success or an error code. */ +gcry_err_code_t +_gcry_random_run_external_test (void *context, char *buffer, size_t buflen) +{ + if (fips_mode ()) + return _gcry_rngfips_run_external_test (context, buffer, buflen); + else + return GPG_ERR_NOT_SUPPORTED; +} + +/* Release the test CONTEXT. */ +void +_gcry_random_deinit_external_test (void *context) +{ + if (fips_mode ()) + return _gcry_rngfips_deinit_external_test (context); +} diff --git a/random/random.h b/random/random.h index eda44d36..9075d9a3 100644 --- a/random/random.h +++ b/random/random.h @@ -39,6 +39,18 @@ void _gcry_update_random_seed_file (void); byte *_gcry_get_random_bits( size_t nbits, int level, int secure ); void _gcry_fast_random_poll( void ); +gcry_err_code_t _gcry_random_init_external_test (void **r_context, + unsigned int flags, + const void *key, + size_t keylen, + const void *seed, + size_t seedlen, + const void *dt, + size_t dtlen); +gcry_err_code_t _gcry_random_run_external_test (void *context, + char *buffer, size_t buflen); +void _gcry_random_deinit_external_test (void *context); + /*-- rndegd.c --*/ gpg_error_t _gcry_rndegd_set_socket_name (const char *name); diff --git a/src/ChangeLog b/src/ChangeLog index d860b543..b9028818 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,18 @@ +2008-09-15 Werner Koch <wk@g10code.com> + + * fips.c [HAVE_SYSLOG]: Include syslog.h. + (_gcry_initialize_fips_mode, lock_fsm, unlock_fsm) + (_gcry_fips_signal_error, fips_new_state) + (_gcry_fips_noreturn) [HAVE_SYSLOG]: Also log via syslog. + * global.h [HAVE_SYSLOG]: Include syslog.h. + (_gcry_global_is_operational) [HAVE_SYSLOG]: Print warning. + + * global.c (_gcry_vcontrol): Use GCRYCTL_INITIALIZATION_FINISHED + to run power-up tests. Add unpublished control commands 58-60. + + * global.c (_gcry_global_is_operational): New. + * g10lib.h (fips_is_operational): Change to call this function. + 2008-09-12 Werner Koch <wk@g10code.com> * fips.c (_gcry_fips_run_selftests): Add arg EXTENDED. @@ -26,6 +26,9 @@ #ifdef ENABLE_HMAC_BINARY_CHECK # include <dlfcn.h> #endif +#ifdef HAVE_SYSLOG +# include <syslog.h> +#endif /*HAVE_SYSLOG*/ #include "g10lib.h" #include "ath.h" @@ -148,6 +151,11 @@ _gcry_initialize_fips_mode (int force) file system. We better stop right away. */ log_info ("FATAL: error reading `%s' in libgcrypt: %s\n", procfname, strerror (saved_errno)); +#ifdef HAVE_SYSLOG + syslog (LOG_USER|LOG_ERR, "Libgcrypt error: " + "reading `%s' failed: %s - abort", + procfname, strerror (saved_errno)); +#endif /*HAVE_SYSLOG*/ abort (); } } @@ -169,6 +177,11 @@ _gcry_initialize_fips_mode (int force) get involved. */ log_info ("FATAL: failed to create the FSM lock in libgcrypt: %s\n", strerror (err)); +#ifdef HAVE_SYSLOG + syslog (LOG_USER|LOG_ERR, "Libgcrypt error: " + "creating FSM lock failed: %s - abort", + strerror (err)); +#endif /*HAVE_SYSLOG*/ abort (); } @@ -189,6 +202,11 @@ lock_fsm (void) { log_info ("FATAL: failed to acquire the FSM lock in libgrypt: %s\n", strerror (err)); +#ifdef HAVE_SYSLOG + syslog (LOG_USER|LOG_ERR, "Libgcrypt error: " + "acquiring FSM lock failed: %s - abort", + strerror (err)); +#endif /*HAVE_SYSLOG*/ abort (); } } @@ -203,6 +221,11 @@ unlock_fsm (void) { log_info ("FATAL: failed to release the FSM lock in libgrypt: %s\n", strerror (err)); +#ifdef HAVE_SYSLOG + syslog (LOG_USER|LOG_ERR, "Libgcrypt error: " + "releasing FSM lock failed: %s - abort", + strerror (err)); +#endif /*HAVE_SYSLOG*/ abort (); } } @@ -619,6 +642,14 @@ _gcry_fips_signal_error (const char *srcfile, int srcline, const char *srcfunc, srcfile, srcline, srcfunc? ", function ":"", srcfunc? srcfunc:"", description? description : "no description available"); +#ifdef HAVE_SYSLOG + syslog (LOG_USER|LOG_ERR, "Libgcrypt error: " + "%serror in file %s, line %d%s%s: %s", + is_fatal? "fatal ":"", + srcfile, srcline, + srcfunc? ", function ":"", srcfunc? srcfunc:"", + description? description : "no description available"); +#endif /*HAVE_SYSLOG*/ } @@ -697,8 +728,21 @@ fips_new_state (enum module_states new_state) if (!ok) { /* Invalid state transition. Halting library. */ +#ifdef HAVE_SYSLOG + syslog (LOG_USER|LOG_ERR, + "Libgcrypt error: invalid state transition %s => %s", + state2str (last_state), state2str (new_state)); +#endif /*HAVE_SYSLOG*/ fips_noreturn (); } + else if (new_state == STATE_ERROR || new_state == STATE_FATALERROR) + { +#ifdef HAVE_SYSLOG + syslog (LOG_USER|LOG_WARNING, + "Libgcrypt notice: state transition %s => %s", + state2str (last_state), state2str (new_state)); +#endif /*HAVE_SYSLOG*/ + } } @@ -709,6 +753,9 @@ fips_new_state (enum module_states new_state) void _gcry_fips_noreturn (void) { +#ifdef HAVE_SYSLOG + syslog (LOG_USER|LOG_ERR, "Libgcrypt terminated the application"); +#endif /*HAVE_SYSLOG*/ fflush (NULL); abort (); /*NOTREACHED*/ diff --git a/src/g10lib.h b/src/g10lib.h index 3ef7c94b..0d0aea68 100644 --- a/src/g10lib.h +++ b/src/g10lib.h @@ -74,6 +74,7 @@ /*-- src/global.c -*/ +int _gcry_global_is_operational (void); gcry_error_t _gcry_vcontrol (enum gcry_ctl_cmds cmd, va_list arg_ptr); void _gcry_check_heap (const void *a); int _gcry_get_debug_flag (unsigned int mask); @@ -310,7 +311,7 @@ void _gcry_fips_signal_error (const char *srcfile, #endif int _gcry_fips_is_operational (void); -#define fips_is_operational() (_gcry_fips_is_operational ()) +#define fips_is_operational() (_gcry_global_is_operational ()) #define fips_not_operational() (GCRY_GPG_ERR_NOT_OPERATIONAL) int _gcry_fips_test_operational (void); diff --git a/src/gcrypt.h.in b/src/gcrypt.h.in index 4d8bcd0a..af6f85db 100644 --- a/src/gcrypt.h.in +++ b/src/gcrypt.h.in @@ -410,6 +410,7 @@ enum gcry_ctl_cmds GCRYCTL_FIPS_MODE_P = 55, GCRYCTL_FORCE_FIPS_MODE = 56, GCRYCTL_SELFTEST = 57 + /* Note: 58, 59 and 60 are used internally. */ }; /* Perform various operations defined by CMD. */ diff --git a/src/global.c b/src/global.c index 09664ab1..ce54f0d3 100644 --- a/src/global.c +++ b/src/global.c @@ -28,6 +28,9 @@ #include <limits.h> #include <errno.h> #include <unistd.h> +#ifdef HAVE_SYSLOG +# include <syslog.h> +#endif /*HAVE_SYSLOG*/ #include "g10lib.h" #include "cipher.h" @@ -80,7 +83,7 @@ global_init (void) return; any_init_done = 1; - /* Initialize our portable theead/mutex wrapper. */ + /* Initialize our portable thread/mutex wrapper. */ err = ath_init (); if (err) goto fail; @@ -119,6 +122,39 @@ global_init (void) } +/* This function is called by the macro fips_is_operational and makes + sure that the minimal initialization has been done. This is far + from a perfect solution and hides problems with an improper + initialization but at least in single-threaded mode it should work + reliable. + + The reason we need this is that a lot of applications don't use + Libgcrypt properly by not running any initialization code at all. + They just call a Libgcrypt function and that is all what they want. + Now with the FIPS mode, that has the side effect of entering FIPS + mode (for security reasons, FIPS mode is the default if no + initialization has been done) and bailing out immediately because + the FSM is in the wrong state. If we always run the init code, + Libgcrypt can test for FIPS mode and at least if not in FIPS mode, + it will behave as before. Note that this on-the-fly initialization + is only done for the cryptographic functions subject to FIPS mode + and thus not all API calls will do such an initialization. */ +int +_gcry_global_is_operational (void) +{ + if (!any_init_done) + { +#ifdef HAVE_SYSLOG + syslog (LOG_USER|LOG_WARNING, "Libgcrypt warning: " + "missing initialization - please fix the application"); +#endif /*HAVE_SYSLOG*/ + global_init (); + } + return _gcry_fips_is_operational (); +} + + + /* Version number parsing. */ @@ -392,6 +428,8 @@ _gcry_vcontrol (enum gcry_ctl_cmds cmd, va_list arg_ptr) mutexes. */ _gcry_random_initialize (0); init_finished = 1; + /* Force us into operational state if in FIPS mode. */ + (void)fips_is_operational (); } break; @@ -478,12 +516,48 @@ _gcry_vcontrol (enum gcry_ctl_cmds cmd, va_list arg_ptr) case GCRYCTL_SELFTEST: /* Run a selftest. This works in fips mode as well as in standard mode. In contrast to the power-up tests, we use an - extended version ofthe selftests. Returns 0 on success or an + extended version of the selftests. Returns 0 on success or an error code. */ global_init (); err = _gcry_fips_run_selftests (1); break; + case 58: + { + void **rctx = va_arg (arg_ptr, void **); + unsigned int flags = va_arg (arg_ptr, unsigned int); + const void *key = va_arg (arg_ptr, const void *); + size_t keylen = va_arg (arg_ptr, size_t); + const void *seed = va_arg (arg_ptr, const void *); + size_t seedlen = va_arg (arg_ptr, size_t); + const void *dt = va_arg (arg_ptr, const void *); + size_t dtlen = va_arg (arg_ptr, size_t); + if (!fips_is_operational ()) + err = fips_not_operational (); + else + err = _gcry_random_init_external_test (rctx, flags, key, keylen, + seed, seedlen, dt, dtlen); + } + break; + case 59: + { + void *ctx = va_arg (arg_ptr, void *); + void *buffer = va_arg (arg_ptr, void *); + size_t buflen = va_arg (arg_ptr, size_t); + if (!fips_is_operational ()) + err = fips_not_operational (); + else + err = _gcry_random_run_external_test (ctx, buffer, buflen); + } + break; + case 60: + { + void *ctx = va_arg (arg_ptr, void *); + _gcry_random_deinit_external_test (ctx); + } + break; + + default: err = GPG_ERR_INV_OP; } diff --git a/tests/ChangeLog b/tests/ChangeLog index bf3b6b21..f4efdd14 100644 --- a/tests/ChangeLog +++ b/tests/ChangeLog @@ -1,3 +1,7 @@ +2008-09-15 Werner Koch <wk@g10code.com> + + * fipsrngdrv.c: New. + 2008-09-09 Werner Koch <wk@g10code.com> * basic.c (main): New option --selftest. diff --git a/tests/Makefile.am b/tests/Makefile.am index 6c39d219..509647a5 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -39,7 +39,7 @@ AM_CFLAGS = $(GPG_ERROR_CFLAGS) LDADD = ../src/libgcrypt.la $(DL_LIBS) EXTRA_PROGRAMS = testapi pkbench -noinst_PROGRAMS = $(TESTS) +noinst_PROGRAMS = $(TESTS) fipsrngdrv EXTRA_DIST = README rsa-16k.key diff --git a/tests/fipsrngdrv.c b/tests/fipsrngdrv.c new file mode 100644 index 00000000..6100f909 --- /dev/null +++ b/tests/fipsrngdrv.c @@ -0,0 +1,119 @@ +/* fipsrngdrv.c - A driver to test the FIPS RNG. + Copyright (C) 2008 Free Software Foundation, Inc. + + 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 "../src/gcrypt.h" + +#define PGM "fipsrngdrv" + + +static void +die (const char *format, ...) +{ + va_list arg_ptr; + + va_start (arg_ptr, format); + fputs (PGM ": ", stderr); + vfprintf (stderr, format, arg_ptr); + va_end (arg_ptr); + exit (1); +} + + +static gcry_error_t +init_external_test (void **r_context, + unsigned int flags, + const void *key, size_t keylen, + const void *seed, size_t seedlen, + const void *dt, size_t dtlen) +{ + return gcry_control (58, + r_context, flags, + key, keylen, + seed, seedlen, + dt, dtlen); +} + +static gcry_error_t +run_external_test (void *context, void *buffer, size_t buflen) +{ + return gcry_control (59, context, buffer, buflen); +} + +static void +deinit_external_test (void *context) +{ + gcry_control (60, context); +} + + +static void +print_buffer (const unsigned char *buffer, size_t length) +{ + while (length--) + printf ("%02X", *buffer++); +} + + +int +main (int argc, char **argv) +{ + void *context; + gpg_error_t err; + int block; + unsigned char buffer[16]; + + (void)argc; + (void)argv; + + gcry_control (GCRYCTL_FORCE_FIPS_MODE, 0); + if (!gcry_check_version (GCRYPT_VERSION)) + die ("version mismatch\n"); + gcry_control (GCRYCTL_DISABLE_SECMEM, 0); + gcry_control (GCRYCTL_SET_VERBOSITY, 2); + gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0); + + err = init_external_test (&context, 0, + "1234567890123456", 16, + "abcdefghijklmnop", 16, + "XXXXXXXXXXXXXXXX", 16); + if (err) + die ("init external test failed: %s\n", gpg_strerror (err)); + + for (block=0; block < 10; block++) + { + err = run_external_test (context, buffer, sizeof buffer); + if (err) + die ("run external test failed: %s\n", gpg_strerror (err)); + print_buffer (buffer, sizeof buffer); + putchar ('\n'); + } + + deinit_external_test (context); + + return 0; +} + |