summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--BUGS0
-rw-r--r--ChangeLog8
-rw-r--r--Makefile.am2
-rw-r--r--NEWS19
-rw-r--r--cipher/ChangeLog93
-rw-r--r--cipher/Makefile.am2
-rw-r--r--cipher/ac.c92
-rw-r--r--cipher/cipher.c322
-rw-r--r--cipher/des.c87
-rw-r--r--cipher/dsa.c60
-rw-r--r--cipher/ecc.c90
-rw-r--r--cipher/md.c219
-rw-r--r--cipher/pubkey.c178
-rw-r--r--cipher/rijndael.c432
-rw-r--r--cipher/rsa.c116
-rw-r--r--cipher/sha1.c55
-rw-r--r--cipher/sha256.c88
-rw-r--r--cipher/sha512.c134
-rw-r--r--configure.ac4
-rw-r--r--doc/ChangeLog18
-rw-r--r--doc/Makefile.am24
-rw-r--r--doc/gcrypt.texi1646
-rw-r--r--random/ChangeLog31
-rw-r--r--random/Makefile.am6
-rw-r--r--random/rand-internal.h54
-rw-r--r--random/random-csprng.c1388
-rw-r--r--random/random-fips.c102
-rw-r--r--random/random.c1342
-rw-r--r--random/random.h3
-rw-r--r--src/ChangeLog59
-rw-r--r--src/Makefile.am12
-rw-r--r--src/ath.c17
-rw-r--r--src/ath.h8
-rw-r--r--src/cipher-proto.h83
-rw-r--r--src/cipher.h20
-rw-r--r--src/g10lib.h47
-rw-r--r--src/gcrypt-module.h2
-rw-r--r--src/gcrypt.h.in200
-rw-r--r--src/global.c117
-rw-r--r--src/hmac256.c687
-rw-r--r--src/hmac256.h33
-rw-r--r--src/libgcrypt.def6
-rw-r--r--src/libgcrypt.vers6
-rw-r--r--src/misc.c4
-rw-r--r--src/module.c8
-rw-r--r--src/visibility.c170
-rw-r--r--src/visibility.h65
-rw-r--r--tests/ChangeLog14
-rw-r--r--tests/basic.c104
-rw-r--r--tests/benchmark.c8
-rw-r--r--tests/register.c25
51 files changed, 5775 insertions, 2535 deletions
diff --git a/BUGS b/BUGS
deleted file mode 100644
index e69de29b..00000000
--- a/BUGS
+++ /dev/null
diff --git a/ChangeLog b/ChangeLog
index 5e62403b..384b3393 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2008-08-18 Werner Koch <wk@g10code.com>
+
+ * Makefile.am (EXTRA_DIST): Remove the unused BUGS file.
+
+2008-08-15 Werner Koch <wk@g10code.com>
+
+ * configure.ac (AH_BOTTOM): Define GCRY_GPG_ERR_NOT_OPERATIONAL.
+
2008-07-05 Werner Koch <wk@g10code.com>
* random/: New.
diff --git a/Makefile.am b/Makefile.am
index 87eeff00..61ae90e0 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -24,7 +24,7 @@ DISTCHECK_CONFIGURE_FLAGS = --enable-random-daemon \
DIST_SUBDIRS = m4 mpi cipher random src doc tests
SUBDIRS = mpi cipher random src doc tests
-EXTRA_DIST = BUGS autogen.sh README.SVN
+EXTRA_DIST = autogen.sh README.SVN
DISTCLEANFILES =
diff --git a/NEWS b/NEWS
index 53eff08e..60118e7b 100644
--- a/NEWS
+++ b/NEWS
@@ -1,6 +1,25 @@
Noteworthy changes in version 1.4.2
------------------------------------------------
+ * The library may now be switched into a FIPS mode.
+
+ * More runtime selftests.
+
+ * A few macros have been replaced by functions for better type
+ checking.
+
+ * The thread initialiation structure now carries version information.
+
+ * Interface changes relative to the 1.3.0 release:
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ GCRYCTL_OPERATIONAL_P NEW.
+ GCRYCTL_FIPS_MODE_P NEW.
+ GCRYCTL_FORCE_FIPS_MODE NEW.
+ gcry_cipher_setkey NEW: Replaces macro.
+ gcry_cipher_setiv NEW: Replaces macro.
+ gcry_cipher_setctr NEW: Replaces macro.
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
Noteworthy changes in version 1.4.1 (2008-04-25)
------------------------------------------------
diff --git a/cipher/ChangeLog b/cipher/ChangeLog
index b5b52161..4549fc4d 100644
--- a/cipher/ChangeLog
+++ b/cipher/ChangeLog
@@ -1,3 +1,96 @@
+2008-08-19 Werner Koch <wk@g10code.com>
+
+ * pubkey.c (sexp_elements_extract_ecc) [!USE_ECC]: Do not allow
+ allow "curve" parameter.
+
+2008-08-15 Werner Koch <wk@g10code.com>
+
+ * pubkey.c (_gcry_pk_selftest): New.
+ * dsa.c (selftests_dsa, run_selftests): New.
+ * rsa.c (selftests_rsa, run_selftests): New.
+ * ecc.c (selftests_ecdsa, run_selftests): New.
+
+ * md.c (_gcry_md_selftest): New.
+ * sha1.c (run_selftests, selftests_sha1): New.
+ * sha256.c (selftests_sha224, selftests_sha256, run_selftests): New.
+ * sha512.c (selftests_sha384, selftests_sha512, run_selftests): New.
+
+ * des.c (selftest): Remove static variable form selftest.
+ (des_setkey): No on-the-fly self test in fips mode.
+ (tripledes_set3keys): Ditto.
+
+ * cipher.c (_gcry_cipher_setkey, _gcry_cipher_setiv):
+
+ * dsa.c (generate): Bail out in fips mode if NBITS is less than 1024.
+ * rsa.c (generate): Return an error code if the the requested size
+ is less than 1024 and we are in fpis mode.
+ (_gcry_rsa_generate): Take care of that error code.
+
+ * ecc.c (generate_curve): In fips mode enable only NIST curves.
+
+ * cipher.c (_gcry_cipher_selftest): New.
+
+ * sha512.c (_gcry_digest_extraspec_sha384)
+ (_gcry_digest_extraspec_sha512): New.
+ * sha256.c (_gcry_digest_extraspec_sha224)
+ (_gcry_digest_extraspec_sha256): New.
+ * sha1.c (_gcry_digest_extraspec_sha1): New.
+ * ecc.c (_gcry_pubkey_extraspec_ecdsa): New.
+ * dsa.c (_gcry_pubkey_extraspec_dsa): New.
+ * rsa.c (_gcry_pubkey_extraspec_rsa): New.
+ * rijndael.c (_gcry_cipher_extraspec_aes)
+ (_gcry_cipher_extraspec_aes192, _gcry_cipher_extraspec_aes256): New.
+ * des.c (_gcry_cipher_extraspec_tripledes): New.
+
+ * cipher.c (gcry_cipher_register): Rename to _gcry_cipher_register.
+ Add arg EXTRASPEC.
+ (dummy_extra_spec): New.
+ (cipher_table_entry): Add extraspec field.
+ * md.c (_gcry_md_register): Rename to _gcry_md_register. Add
+ arg EXTRASPEC.
+ (dummy_extra_spec): New.
+ (digest_table_entry): Add extraspec field.
+ * pubkey.c (gcry_pk_register): Rename to _gcry_pk_register. Add
+ arg EXTRASPEC.
+ (dummy_extra_spec): New.
+ (pubkey_table_entry): Add extraspec field.
+
+ * ac.c: Let most public functions return GPG_ERR_UNSUPPORTED in
+ fips mode.
+
+ * pubkey.c (pubkey_table_entry): Add field FIPS_ALLOWED and mark
+ appropriate algorithms.
+ (dummy_generate, dummy_check_secret_key, dummy_encrypt)
+ (dummy_decrypt, dummy_sign, dummy_verify, dummy_get_nbits): Signal
+ a fips error when used.
+ (gcry_pk_register): In fips mode do not allow to register new
+ algorithms.
+
+ * md.c (digest_table): Add field FIPS_ALLOWED and mark appropriate
+ algorithms.
+ (md_register_default): In fips mode register only fips algorithms.
+ (gcry_md_register): In fips mode do not allow to register new
+ algorithms.
+ (gcry_md_get): Signal a fips error if called.
+ (gcry_md_hash_buffer): Do not allow rmd160 when not in fips mode.
+ (md_start_debug): Disable in fips_mode.
+
+ * md.c (gcry_md_register_default): Rename to ..
+ (md_register_default): .. this.
+ (md_digest): Remove this commented fucntion.
+ * pubkey.c (gcry_pk_register_default): Rename to ..
+ (pk_register_default): .. this.
+
+ * cipher.c (cipher_table_entry): Add field FIPS_ALLOWED.
+ (gcry_cipher_register_default): Register only fips approved
+ algorithms.
+ (gcry_cipher_register): Do not allow to register new ciphers.
+ (cipher_setiv): Signal fips error.
+
+ * cipher (gcry_cipher_register_default): Rename to ..
+ (cipher_register_default): .. this.
+ (REGISTER_DEFAULT_CIPHERS): Adjust for that change.
+
2008-07-05 Werner Koch <wk@g10code.com>
* random-daemon.c, random.h, rndhw.c, rndunix.c, rand-internal.h
diff --git a/cipher/Makefile.am b/cipher/Makefile.am
index 40ece5a6..f1c313cc 100644
--- a/cipher/Makefile.am
+++ b/cipher/Makefile.am
@@ -36,6 +36,7 @@ libcipher_la_LIBADD = $(GCRYPT_MODULES)
libcipher_la_SOURCES = \
cipher.c pubkey.c ac.c md.c \
+hmac-tests.c \
bithelp.h \
primegen.c \
rmd.h
@@ -65,6 +66,7 @@ twofish.c \
rfc2268.c \
camellia.c camellia.h camellia-glue.c
+
# We need to lower the optimization for this module.
tiger.o: $(srcdir)/tiger.c
`echo $(COMPILE) -c $(srcdir)/tiger.c | sed -e 's/-O[2-9s]*/-O1/g' `
diff --git a/cipher/ac.c b/cipher/ac.c
index f65de09b..04a3b282 100644
--- a/cipher/ac.c
+++ b/cipher/ac.c
@@ -127,6 +127,9 @@ _gcry_ac_data_new (gcry_ac_data_t *data)
gcry_ac_data_t data_new;
gcry_error_t err;
+ if (fips_mode ())
+ return gpg_error (GPG_ERR_NOT_SUPPORTED);
+
data_new = gcry_malloc (sizeof (*data_new));
if (! data_new)
{
@@ -240,6 +243,9 @@ _gcry_ac_data_copy (gcry_ac_data_t *data_cp, gcry_ac_data_t data)
gcry_ac_data_t data_new;
gcry_error_t err;
+ if (fips_mode ())
+ return gpg_error (GPG_ERR_NOT_SUPPORTED);
+
/* Allocate data set. */
data_new = gcry_malloc (sizeof (*data_new));
if (! data_new)
@@ -290,6 +296,9 @@ _gcry_ac_data_set (gcry_ac_data_t data, unsigned int flags,
name_cp = NULL;
mpi_cp = NULL;
+ if (fips_mode ())
+ return gpg_error (GPG_ERR_NOT_SUPPORTED);
+
if (flags & ~(GCRY_AC_FLAG_DEALLOC | GCRY_AC_FLAG_COPY))
{
err = gcry_error (GPG_ERR_INV_ARG);
@@ -370,6 +379,9 @@ _gcry_ac_data_get_name (gcry_ac_data_t data, unsigned int flags,
gcry_error_t err;
unsigned int i;
+ if (fips_mode ())
+ return gpg_error (GPG_ERR_NOT_SUPPORTED);
+
if (flags & ~(GCRY_AC_FLAG_COPY))
{
err = gcry_error (GPG_ERR_INV_ARG);
@@ -421,6 +433,9 @@ _gcry_ac_data_get_index (gcry_ac_data_t data, unsigned int flags,
name_cp = NULL;
mpi_cp = NULL;
+ if (fips_mode ())
+ return gpg_error (GPG_ERR_NOT_SUPPORTED);
+
if (flags & ~(GCRY_AC_FLAG_COPY))
{
err = gcry_error (GPG_ERR_INV_ARG);
@@ -496,6 +511,9 @@ _gcry_ac_data_to_sexp (gcry_ac_data_t data, gcry_sexp_t *sexp,
arg_list = NULL;
err = 0;
+ if (fips_mode ())
+ return gpg_error (GPG_ERR_NOT_SUPPORTED);
+
/* Calculate size of S-expression representation. */
i = 0;
@@ -626,6 +644,9 @@ _gcry_ac_data_from_sexp (gcry_ac_data_t *data_set, gcry_sexp_t sexp,
mpi = NULL;
err = 0;
+ if (fips_mode ())
+ return gpg_error (GPG_ERR_NOT_SUPPORTED);
+
/* Process S-expression/identifiers. */
if (identifiers)
@@ -795,6 +816,9 @@ _gcry_ac_data_dump (const char *prefix, gcry_ac_data_t data)
if (! data)
return;
+ if (fips_mode ())
+ return;
+
mpi_buffer = NULL;
data_n = _gcry_ac_data_length (data);
@@ -859,6 +883,9 @@ _gcry_ac_io_init_va (gcry_ac_io_t *ac_io,
{
memset (ac_io, 0, sizeof (*ac_io));
+ if (fips_mode ())
+ return;
+
assert ((mode == GCRY_AC_IO_READABLE) || (mode == GCRY_AC_IO_WRITABLE));
assert ((type == GCRY_AC_IO_STRING) || (type == GCRY_AC_IO_STRING));
@@ -1362,6 +1389,9 @@ _gcry_ac_open (gcry_ac_handle_t *handle,
*handle = NULL;
module = NULL;
+ if (fips_mode ())
+ return gpg_error (GPG_ERR_NOT_SUPPORTED);
+
/* Get name. */
algorithm_name = _gcry_pk_aliased_algo_name (algorithm);
if (! algorithm_name)
@@ -1431,6 +1461,9 @@ _gcry_ac_key_init (gcry_ac_key_t *key, gcry_ac_handle_t handle,
(void)handle;
+ if (fips_mode ())
+ return gpg_error (GPG_ERR_NOT_SUPPORTED);
+
/* Allocate. */
key_new = gcry_malloc (sizeof (*key_new));
if (! key_new)
@@ -1488,6 +1521,9 @@ _gcry_ac_key_pair_generate (gcry_ac_handle_t handle, unsigned int nbits,
(void)misc_data;
+ if (fips_mode ())
+ return gpg_error (GPG_ERR_NOT_SUPPORTED);
+
key_data_secret = NULL;
key_data_public = NULL;
key_secret = NULL;
@@ -1652,6 +1688,9 @@ _gcry_ac_key_pair_extract (gcry_ac_key_pair_t key_pair,
{
gcry_ac_key_t key;
+ if (fips_mode ())
+ return NULL;
+
switch (which)
{
case GCRY_AC_KEY_SECRET:
@@ -1710,6 +1749,8 @@ _gcry_ac_key_pair_destroy (gcry_ac_key_pair_t key_pair)
gcry_ac_data_t
_gcry_ac_key_data_get (gcry_ac_key_t key)
{
+ if (fips_mode ())
+ return NULL;
return key->data;
}
@@ -1720,6 +1761,9 @@ _gcry_ac_key_test (gcry_ac_handle_t handle, gcry_ac_key_t key)
gcry_sexp_t key_sexp;
gcry_error_t err;
+ if (fips_mode ())
+ return gpg_error (GPG_ERR_NOT_SUPPORTED);
+
key_sexp = NULL;
err = ac_data_construct (ac_key_identifiers[key->type], 0, 0,
handle->algorithm_name, key->data, &key_sexp);
@@ -1744,6 +1788,9 @@ _gcry_ac_key_get_nbits (gcry_ac_handle_t handle,
gcry_error_t err;
unsigned int n;
+ if (fips_mode ())
+ return gpg_error (GPG_ERR_NOT_SUPPORTED);
+
key_sexp = NULL;
err = ac_data_construct (ac_key_identifiers[key->type],
@@ -1777,6 +1824,9 @@ _gcry_ac_key_get_grip (gcry_ac_handle_t handle,
gcry_error_t err;
unsigned char *ret;
+ if (fips_mode ())
+ return gpg_error (GPG_ERR_NOT_SUPPORTED);
+
key_sexp = NULL;
err = ac_data_construct (ac_key_identifiers[key->type], 0, 0,
handle->algorithm_name, key->data, &key_sexp);
@@ -1823,6 +1873,9 @@ _gcry_ac_data_encrypt (gcry_ac_handle_t handle,
gcry_sexp_t sexp_key;
gcry_error_t err;
+ if (fips_mode ())
+ return gpg_error (GPG_ERR_NOT_SUPPORTED);
+
data_encrypted_new = NULL;
sexp_request = NULL;
sexp_reply = NULL;
@@ -1897,6 +1950,9 @@ _gcry_ac_data_decrypt (gcry_ac_handle_t handle,
gcry_sexp_t sexp_key;
gcry_error_t err;
+ if (fips_mode ())
+ return gpg_error (GPG_ERR_NOT_SUPPORTED);
+
sexp_request = NULL;
sexp_reply = NULL;
sexp_value = NULL;
@@ -1969,6 +2025,9 @@ _gcry_ac_data_sign (gcry_ac_handle_t handle,
gcry_sexp_t sexp_key;
gcry_error_t err;
+ if (fips_mode ())
+ return gpg_error (GPG_ERR_NOT_SUPPORTED);
+
data_signed = NULL;
data_value = NULL;
sexp_request = NULL;
@@ -2039,6 +2098,9 @@ _gcry_ac_data_verify (gcry_ac_handle_t handle,
gcry_sexp_t sexp_key;
gcry_error_t err;
+ if (fips_mode ())
+ return gpg_error (GPG_ERR_NOT_SUPPORTED);
+
sexp_signature = NULL;
data_value = NULL;
sexp_data = NULL;
@@ -2509,6 +2571,9 @@ _gcry_ac_data_encode (gcry_ac_em_t method,
gcry_ac_io_t *ac_io_read,
gcry_ac_io_t *ac_io_write)
{
+ if (fips_mode ())
+ return gpg_error (GPG_ERR_NOT_SUPPORTED);
+
return ac_data_dencode (method, DATA_ENCODE, flags, options,
ac_io_read, ac_io_write);
}
@@ -2522,6 +2587,9 @@ _gcry_ac_data_decode (gcry_ac_em_t method,
gcry_ac_io_t *ac_io_read,
gcry_ac_io_t *ac_io_write)
{
+ if (fips_mode ())
+ return gpg_error (GPG_ERR_NOT_SUPPORTED);
+
return ac_data_dencode (method, DATA_DECODE, flags, options,
ac_io_read, ac_io_write);
}
@@ -2537,6 +2605,9 @@ _gcry_ac_mpi_to_os (gcry_mpi_t mpi, unsigned char *os, size_t os_n)
gcry_mpi_t m;
gcry_mpi_t d;
+ if (fips_mode ())
+ return;
+
base = gcry_mpi_new (0);
gcry_mpi_set_ui (base, 256);
@@ -2575,6 +2646,9 @@ _gcry_ac_mpi_to_os_alloc (gcry_mpi_t mpi, unsigned char **os, size_t *os_n)
gcry_error_t err;
unsigned int nbits;
+ if (fips_mode ())
+ return gpg_error (GPG_ERR_NOT_SUPPORTED);
+
nbits = gcry_mpi_get_nbits (mpi);
buffer_n = (nbits + 7) / 8;
buffer = gcry_malloc (buffer_n);
@@ -2604,6 +2678,9 @@ _gcry_ac_os_to_mpi (gcry_mpi_t mpi, unsigned char *os, size_t os_n)
gcry_mpi_t x;
gcry_mpi_t a;
+ if (fips_mode ())
+ return;
+
a = gcry_mpi_new (0);
gcry_mpi_set_ui (a, 1);
x = gcry_mpi_new (0);
@@ -2822,6 +2899,9 @@ _gcry_ac_data_encrypt_scheme (gcry_ac_handle_t handle,
(void)flags;
+ if (fips_mode ())
+ return gpg_error (GPG_ERR_NOT_SUPPORTED);
+
data_encrypted = NULL;
mpi_encrypted = NULL;
mpi_plain = NULL;
@@ -2913,6 +2993,9 @@ _gcry_ac_data_decrypt_scheme (gcry_ac_handle_t handle,
(void)flags;
+ if (fips_mode ())
+ return gpg_error (GPG_ERR_NOT_SUPPORTED);
+
data_encrypted = NULL;
mpi_encrypted = NULL;
mpi_decrypted = NULL;
@@ -3024,6 +3107,9 @@ _gcry_ac_data_sign_scheme (gcry_ac_handle_t handle,
(void)flags;
+ if (fips_mode ())
+ return gpg_error (GPG_ERR_NOT_SUPPORTED);
+
data_signed = NULL;
mpi_signed = NULL;
opts_em = NULL;
@@ -3116,6 +3202,9 @@ _gcry_ac_data_verify_scheme (gcry_ac_handle_t handle,
(void)flags;
+ if (fips_mode ())
+ return gpg_error (GPG_ERR_NOT_SUPPORTED);
+
mpi_signature = NULL;
elements_sig = NULL;
data_signed = NULL;
@@ -3206,5 +3295,8 @@ _gcry_ac_data_verify_scheme (gcry_ac_handle_t handle,
gcry_err_code_t
_gcry_ac_init (void)
{
+ if (fips_mode ())
+ return GPG_ERR_NOT_SUPPORTED;
+
return 0;
}
diff --git a/cipher/cipher.c b/cipher/cipher.c
index 66470ee6..e3284355 100644
--- a/cipher/cipher.c
+++ b/cipher/cipher.c
@@ -1,6 +1,6 @@
/* cipher.c - cipher dispatcher
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003
- * 2005, 2007 Free Software Foundation, Inc.
+ * 2005, 2007, 2008 Free Software Foundation, Inc.
*
* This file is part of Libgcrypt.
*
@@ -38,51 +38,76 @@
#define NEED_16BYTE_ALIGNED_CONTEXT 1
#endif
+/* A dummy extraspec so that we do not need to tests the extraspec
+ field from the module specification against NULL and instead
+ directly test the respective fields of extraspecs. */
+static cipher_extra_spec_t dummy_extra_spec;
+
/* This is the list of the default ciphers, which are included in
libgcrypt. */
static struct cipher_table_entry
{
gcry_cipher_spec_t *cipher;
+ cipher_extra_spec_t *extraspec;
unsigned int algorithm;
+ int fips_allowed;
} cipher_table[] =
{
#if USE_BLOWFISH
- { &_gcry_cipher_spec_blowfish, GCRY_CIPHER_BLOWFISH },
+ { &_gcry_cipher_spec_blowfish,
+ &dummy_extra_spec, GCRY_CIPHER_BLOWFISH },
#endif
#if USE_DES
- { &_gcry_cipher_spec_des, GCRY_CIPHER_DES },
- { &_gcry_cipher_spec_tripledes, GCRY_CIPHER_3DES },
+ { &_gcry_cipher_spec_des,
+ &dummy_extra_spec, GCRY_CIPHER_DES },
+ { &_gcry_cipher_spec_tripledes,
+ &_gcry_cipher_extraspec_tripledes, GCRY_CIPHER_3DES, 1 },
#endif
#if USE_ARCFOUR
- { &_gcry_cipher_spec_arcfour, GCRY_CIPHER_ARCFOUR },
+ { &_gcry_cipher_spec_arcfour,
+ &dummy_extra_spec, GCRY_CIPHER_ARCFOUR },
#endif
#if USE_CAST5
- { &_gcry_cipher_spec_cast5, GCRY_CIPHER_CAST5 },
+ { &_gcry_cipher_spec_cast5,
+ &dummy_extra_spec, GCRY_CIPHER_CAST5 },
#endif
#if USE_AES
- { &_gcry_cipher_spec_aes, GCRY_CIPHER_AES},
- { &_gcry_cipher_spec_aes192, GCRY_CIPHER_AES192},
- { &_gcry_cipher_spec_aes256, GCRY_CIPHER_AES256},
+ { &_gcry_cipher_spec_aes,
+ &_gcry_cipher_extraspec_aes, GCRY_CIPHER_AES, 1 },
+ { &_gcry_cipher_spec_aes192,
+ &_gcry_cipher_extraspec_aes192, GCRY_CIPHER_AES192, 1 },
+ { &_gcry_cipher_spec_aes256,
+ &_gcry_cipher_extraspec_aes256, GCRY_CIPHER_AES256, 1 },
#endif
#if USE_TWOFISH
- { &_gcry_cipher_spec_twofish, GCRY_CIPHER_TWOFISH },
- { &_gcry_cipher_spec_twofish128, GCRY_CIPHER_TWOFISH128 },
+ { &_gcry_cipher_spec_twofish,
+ &dummy_extra_spec, GCRY_CIPHER_TWOFISH },
+ { &_gcry_cipher_spec_twofish128,
+ &dummy_extra_spec, GCRY_CIPHER_TWOFISH128 },
#endif
#if USE_SERPENT
- { &_gcry_cipher_spec_serpent128, GCRY_CIPHER_SERPENT128 },
- { &_gcry_cipher_spec_serpent192, GCRY_CIPHER_SERPENT192 },
- { &_gcry_cipher_spec_serpent256, GCRY_CIPHER_SERPENT256 },
+ { &_gcry_cipher_spec_serpent128,
+ &dummy_extra_spec, GCRY_CIPHER_SERPENT128 },
+ { &_gcry_cipher_spec_serpent192,
+ &dummy_extra_spec, GCRY_CIPHER_SERPENT192 },
+ { &_gcry_cipher_spec_serpent256,
+ &dummy_extra_spec, GCRY_CIPHER_SERPENT256 },
#endif
#if USE_RFC2268
- { &_gcry_cipher_spec_rfc2268_40, GCRY_CIPHER_RFC2268_40 },
+ { &_gcry_cipher_spec_rfc2268_40,
+ &dummy_extra_spec, GCRY_CIPHER_RFC2268_40 },
#endif
#if USE_SEED
- { &_gcry_cipher_spec_seed, GCRY_CIPHER_SEED },
+ { &_gcry_cipher_spec_seed,
+ &dummy_extra_spec, GCRY_CIPHER_SEED },
#endif
#if USE_CAMELLIA
- { &_gcry_cipher_spec_camellia128, GCRY_CIPHER_CAMELLIA128 },
- { &_gcry_cipher_spec_camellia192, GCRY_CIPHER_CAMELLIA192 },
- { &_gcry_cipher_spec_camellia256, GCRY_CIPHER_CAMELLIA256 },
+ { &_gcry_cipher_spec_camellia128,
+ &dummy_extra_spec, GCRY_CIPHER_CAMELLIA128 },
+ { &_gcry_cipher_spec_camellia192,
+ &dummy_extra_spec, GCRY_CIPHER_CAMELLIA192 },
+ { &_gcry_cipher_spec_camellia256,
+ &dummy_extra_spec, GCRY_CIPHER_CAMELLIA256 },
#endif
{ NULL }
};
@@ -104,7 +129,7 @@ static int default_ciphers_registered;
ath_mutex_lock (&ciphers_registered_lock); \
if (! default_ciphers_registered) \
{ \
- gcry_cipher_register_default (); \
+ cipher_register_default (); \
default_ciphers_registered = 1; \
} \
ath_mutex_unlock (&ciphers_registered_lock); \
@@ -251,7 +276,7 @@ dummy_decrypt_stream (void *c,
CIPHER_TABLE. Note, that this function gets only used by the macro
REGISTER_DEFAULT_CIPHERS which protects it using a mutex. */
static void
-gcry_cipher_register_default (void)
+cipher_register_default (void)
{
gcry_err_code_t err = GPG_ERR_NO_ERROR;
int i;
@@ -269,9 +294,13 @@ gcry_cipher_register_default (void)
if (! cipher_table[i].cipher->stdecrypt)
cipher_table[i].cipher->stdecrypt = dummy_decrypt_stream;
+ if ( fips_mode () && !cipher_table[i].fips_allowed )
+ continue;
+
err = _gcry_module_add (&ciphers_registered,
cipher_table[i].algorithm,
(void *) cipher_table[i].cipher,
+ (void *) cipher_table[i].extraspec,
NULL);
}
@@ -340,16 +369,23 @@ gcry_cipher_lookup_oid (const char *oid)
CIPHER. On success, a new algorithm ID is stored in ALGORITHM_ID
and a pointer representhing this module is stored in MODULE. */
gcry_error_t
-gcry_cipher_register (gcry_cipher_spec_t *cipher,
- int *algorithm_id,
- gcry_module_t *module)
+_gcry_cipher_register (gcry_cipher_spec_t *cipher,
+ cipher_extra_spec_t *extraspec,
+ int *algorithm_id,
+ gcry_module_t *module)
{
gcry_err_code_t err = 0;
gcry_module_t mod;
+ /* We do not support module loading in fips mode. */
+ if (fips_mode ())
+ return gpg_error (GPG_ERR_NOT_SUPPORTED);
+
ath_mutex_lock (&ciphers_registered_lock);
err = _gcry_module_add (&ciphers_registered, 0,
- (void *) cipher, &mod);
+ (void *)cipher,
+ (void *)(extraspec? extraspec : &dummy_extra_spec),
+ &mod);
ath_mutex_unlock (&ciphers_registered_lock);
if (! err)
@@ -529,8 +565,9 @@ disable_cipher_algo (int algorithm)
}
-/* Return 0 if the cipher algorithm with indentifier ALGORITHM is
- available. Returns a basic error code value if it is not available. */
+/* Return 0 if the cipher algorithm with identifier ALGORITHM is
+ available. Returns a basic error code value if it is not
+ available. */
static gcry_err_code_t
check_cipher_algo (int algorithm)
{
@@ -572,7 +609,7 @@ cipher_get_keylen (int algorithm)
if (cipher)
{
len = ((gcry_cipher_spec_t *) cipher->spec)->keylen;
- if (! len)
+ if (!len)
log_bug ("cipher %d w/o key length\n", algorithm);
_gcry_module_release (cipher);
}
@@ -793,7 +830,7 @@ gcry_cipher_close (gcry_cipher_hd_t h)
{
size_t off;
- if (! h)
+ if (!h)
return;
if ((h->magic != CTX_MAGIC_SECURE)
@@ -824,16 +861,18 @@ gcry_cipher_close (gcry_cipher_hd_t h)
/* Set the key to be used for the encryption context C to KEY with
length KEYLEN. The length should match the required length. */
static gcry_error_t
-cipher_setkey (gcry_cipher_hd_t c, byte *key, unsigned keylen)
+cipher_setkey (gcry_cipher_hd_t c, byte *key, unsigned int keylen)
{
gcry_err_code_t ret;
ret = (*c->cipher->setkey) (&c->context.c, key, keylen);
- if (! ret)
- /* Duplicate initial context. */
- memcpy ((void *) ((char *) &c->context.c + c->cipher->contextsize),
- (void *) &c->context.c,
- c->cipher->contextsize);
+ if (!ret)
+ {
+ /* Duplicate initial context. */
+ memcpy ((void *) ((char *) &c->context.c + c->cipher->contextsize),
+ (void *) &c->context.c,
+ c->cipher->contextsize);
+ }
return gcry_error (ret);
}
@@ -848,8 +887,11 @@ cipher_setiv( gcry_cipher_hd_t c, const byte *iv, unsigned ivlen )
if (iv)
{
if (ivlen != c->cipher->blocksize)
- log_info ("WARNING: cipher_setiv: ivlen=%u blklen=%u\n",
- ivlen, (unsigned int)c->cipher->blocksize);
+ {
+ log_info ("WARNING: cipher_setiv: ivlen=%u blklen=%u\n",
+ ivlen, (unsigned int)c->cipher->blocksize);
+ fips_signal_error ("IV length does not match blocklength");
+ }
if (ivlen > c->cipher->blocksize)
ivlen = c->cipher->blocksize;
memcpy (c->u_iv.iv, iv, ivlen);
@@ -876,12 +918,13 @@ static void
do_ecb_encrypt( gcry_cipher_hd_t c, byte *outbuf, const byte *inbuf,
unsigned int nblocks )
{
- unsigned int n;
-
- for(n=0; n < nblocks; n++ ) {
- c->cipher->encrypt ( &c->context.c, outbuf, (byte*)/*arggg*/inbuf );
- inbuf += c->cipher->blocksize;
- outbuf += c->cipher->blocksize;
+ unsigned int n;
+
+ for (n=0; n < nblocks; n++ )
+ {
+ c->cipher->encrypt ( &c->context.c, outbuf, (byte*)/*arggg*/inbuf );
+ inbuf += c->cipher->blocksize;
+ outbuf += c->cipher->blocksize;
}
}
@@ -889,12 +932,13 @@ static void
do_ecb_decrypt( gcry_cipher_hd_t c, byte *outbuf, const byte *inbuf,
unsigned int nblocks )
{
- unsigned n;
+ unsigned int n;
- for(n=0; n < nblocks; n++ ) {
- c->cipher->decrypt ( &c->context.c, outbuf, (byte*)/*arggg*/inbuf );
- inbuf += c->cipher->blocksize;
- outbuf += c->cipher->blocksize;
+ for (n=0; n < nblocks; n++ )
+ {
+ c->cipher->decrypt ( &c->context.c, outbuf, (byte*)/*arggg*/inbuf );
+ inbuf += c->cipher->blocksize;
+ outbuf += c->cipher->blocksize;
}
}
@@ -994,7 +1038,7 @@ do_cbc_decrypt (gcry_cipher_hd_t c, unsigned char *outbuf,
for (n=0; n < nblocks; n++ )
{
/* Because outbuf and inbuf might be the same, we have to
- * save the original ciphertext block. We use lastiv for
+ * save the original ciphertext block. We use LASTIV for
* this here because it is not used otherwise. */
memcpy (c->lastiv, inbuf, blocksize);
c->cipher->decrypt ( &c->context.c, outbuf, inbuf );
@@ -1400,10 +1444,12 @@ gcry_cipher_encrypt (gcry_cipher_hd_t h, void *out, size_t outsize,
gcry_err_code_t err;
if (!in)
- /* Caller requested in-place encryption. */
- /* Actually cipher_encrypt() does not need to know about it, but
- * we may change it in the future to get better performance. */
- err = cipher_encrypt (h, out, out, outsize);
+ {
+ /* Caller requested in-place encryption. */
+ /* Actually cipher_encrypt() does not need to know about it, but
+ * we may change it in the future to get better performance. */
+ err = cipher_encrypt (h, out, out, outsize);
+ }
else if (outsize < ((h->flags & GCRY_CIPHER_CBC_MAC) ?
h->cipher->blocksize : inlen))
err = GPG_ERR_TOO_SHORT;
@@ -1485,10 +1531,12 @@ gcry_cipher_decrypt (gcry_cipher_hd_t h, void *out, size_t outsize,
gcry_err_code_t err = 0;
if (!in)
- /* Caller requested in-place encryption. */
- /* Actually cipher_encrypt() does not need to know about it, but
- * we may change it in the future to get better performance. */
- err = cipher_decrypt (h, out, out, outsize);
+ {
+ /* Caller requested in-place encryption. */
+ /* Actually cipher_encrypt() does not need to know about it, but
+ * we may change it in the future to get better performance. */
+ err = cipher_decrypt (h, out, out, outsize);
+ }
else if (outsize < inlen)
err = GPG_ERR_TOO_SHORT;
else if (((h->mode == GCRY_CIPHER_MODE_ECB)
@@ -1510,7 +1558,7 @@ gcry_cipher_decrypt (gcry_cipher_hd_t h, void *out, size_t outsize,
* the corresponding flag is set.
*/
static void
-cipher_sync( gcry_cipher_hd_t c )
+cipher_sync (gcry_cipher_hd_t c)
{
if ((c->flags & GCRY_CIPHER_ENABLE_SYNC) && c->unused)
{
@@ -1524,24 +1572,58 @@ cipher_sync( gcry_cipher_hd_t c )
gcry_error_t
+_gcry_cipher_setkey (gcry_cipher_hd_t hd, const void *key, size_t keylen)
+{
+ return cipher_setkey (hd, (void*)key, keylen);
+}
+
+
+gcry_error_t
+_gcry_cipher_setiv (gcry_cipher_hd_t hd, const void *iv, size_t ivlen)
+{
+ cipher_setiv (hd, iv, ivlen);
+ return 0;
+}
+
+/* Set counter for CTR mode. (CTR,CTRLEN) must denote a buffer of
+ block size length, or (NULL,0) to set the CTR to the all-zero
+ block. */
+gpg_error_t
+_gcry_cipher_setctr (gcry_cipher_hd_t hd, const void *ctr, size_t ctrlen)
+{
+ if (ctr && ctrlen == hd->cipher->blocksize)
+ memcpy (hd->ctr, ctr, hd->cipher->blocksize);
+ else if (!ctr || !ctrlen)
+ memset (hd->ctr, 0, hd->cipher->blocksize);
+ else
+ return gpg_error (GPG_ERR_INV_ARG);
+ return 0;
+}
+
+
+gcry_error_t
gcry_cipher_ctl( gcry_cipher_hd_t h, int cmd, void *buffer, size_t buflen)
{
gcry_err_code_t rc = GPG_ERR_NO_ERROR;
switch (cmd)
{
- case GCRYCTL_SET_KEY:
+ case GCRYCTL_SET_KEY: /* Deprecated; use gcry_cipher_setkey. */
rc = cipher_setkey( h, buffer, buflen );
break;
- case GCRYCTL_SET_IV:
+
+ case GCRYCTL_SET_IV: /* Deprecated; use gcry_cipher_setiv. */
cipher_setiv( h, buffer, buflen );
break;
+
case GCRYCTL_RESET:
cipher_reset (h);
break;
+
case GCRYCTL_CFB_SYNC:
cipher_sync( h );
break;
+
case GCRYCTL_SET_CBC_CTS:
if (buflen)
if (h->flags & GCRY_CIPHER_CBC_MAC)
@@ -1551,6 +1633,7 @@ gcry_cipher_ctl( gcry_cipher_hd_t h, int cmd, void *buffer, size_t buflen)
else
h->flags &= ~GCRY_CIPHER_CBC_CTS;
break;
+
case GCRYCTL_SET_CBC_MAC:
if (buflen)
if (h->flags & GCRY_CIPHER_CBC_CTS)
@@ -1560,15 +1643,16 @@ gcry_cipher_ctl( gcry_cipher_hd_t h, int cmd, void *buffer, size_t buflen)
else
h->flags &= ~GCRY_CIPHER_CBC_MAC;
break;
+
case GCRYCTL_DISABLE_ALGO:
- /* this one expects a NULL handle and buffer pointing to an
- * integer with the algo number.
- */
+ /* This command expects NULL for H and BUFFER to point to an
+ integer with the algo number. */
if( h || !buffer || buflen != sizeof(int) )
return gcry_error (GPG_ERR_CIPHER_ALGO);
disable_cipher_algo( *(int*)buffer );
break;
- case GCRYCTL_SET_CTR:
+
+ case GCRYCTL_SET_CTR: /* Deprecated; use gcry_cipher_setctr. */
if (buffer && buflen == h->cipher->blocksize)
memcpy (h->ctr, buffer, h->cipher->blocksize);
else if (buffer == NULL || buflen == 0)
@@ -1585,11 +1669,16 @@ gcry_cipher_ctl( gcry_cipher_hd_t h, int cmd, void *buffer, size_t buflen)
}
-/****************
- * Return information about the cipher handle.
+/* Return information about the cipher handle H. CMD is the kind of
+ information requested. BUFFER and NBYTES are reserved for now.
+
+ There are no values for CMD yet defined.
+
+ The fucntion always returns GPG_ERR_INV_OP.
+
*/
gcry_error_t
-gcry_cipher_info( gcry_cipher_hd_t h, int cmd, void *buffer, size_t *nbytes)
+gcry_cipher_info (gcry_cipher_hd_t h, int cmd, void *buffer, size_t *nbytes)
{
gcry_err_code_t err = GPG_ERR_NO_ERROR;
@@ -1606,27 +1695,29 @@ gcry_cipher_info( gcry_cipher_hd_t h, int cmd, void *buffer, size_t *nbytes)
return gcry_error (err);
}
-/****************
- * Return information about the given cipher algorithm
- * WHAT select the kind of information returned:
- * GCRYCTL_GET_KEYLEN:
- * Return the length of the key, if the algorithm
- * supports multiple key length, the maximum supported value
- * is returnd. The length is return as number of octets.
- * buffer and nbytes must be zero.
- * The keylength is returned in _bytes_.
- * GCRYCTL_GET_BLKLEN:
- * Return the blocklength of the algorithm counted in octets.
- * buffer and nbytes must be zero.
- * GCRYCTL_TEST_ALGO:
- * Returns 0 when the specified algorithm is available for use.
- * buffer and nbytes must be zero.
- *
- * Note: Because this function is in most cases used to return an
- * integer value, we can make it easier for the caller to just look at
- * the return value. The caller will in all cases consult the value
- * and thereby detecting whether a error occured or not (i.e. while checking
- * the block size)
+/* Return information about the given cipher algorithm ALGO.
+
+ WHAT select the kind of information returned:
+
+ GCRYCTL_GET_KEYLEN:
+ Return the length of the key. If the algorithm ALGO
+ supports multiple key lengths, the maximum supported key length
+ is returned. The key length is returned as number of octets.
+ BUFFER and NBYTES must be zero.
+
+ GCRYCTL_GET_BLKLEN:
+ Return the blocklength of the algorithm ALGO counted in octets.
+ BUFFER and NBYTES must be zero.
+
+ GCRYCTL_TEST_ALGO:
+ Returns 0 if the specified algorithm ALGO is available for use.
+ BUFFER and NBYTES must be zero.
+
+ Note: Because this function is in most cases used to return an
+ integer value, we can make it easier for the caller to just look at
+ the return value. The caller will in all cases consult the value
+ and thereby detecting whether a error occured or not (i.e. while
+ checking the block size)
*/
gcry_error_t
gcry_cipher_algo_info (int algo, int what, void *buffer, size_t *nbytes)
@@ -1681,17 +1772,30 @@ gcry_cipher_algo_info (int algo, int what, void *buffer, size_t *nbytes)
}
+/* This function returns length of the key for algorithm ALGO. If the
+ algorithm supports multiple key lengths, the maximum supported key
+ length is returned. On error 0 is returned. The key length is
+ returned as number of octets.
+
+ This is a convenience functions which should be preferred over
+ gcry_cipher_algo_info because it allows for proper type
+ checking. */
size_t
gcry_cipher_get_algo_keylen (int algo)
{
size_t n;
- if (gcry_cipher_algo_info( algo, GCRYCTL_GET_KEYLEN, NULL, &n))
+ if (gcry_cipher_algo_info (algo, GCRYCTL_GET_KEYLEN, NULL, &n))
n = 0;
return n;
}
+/* This functions returns the blocklength of the algorithm ALGO
+ counted in octets. On error 0 is returned.
+ This is a convenience functions which should be preferred over
+ gcry_cipher_algo_info because it allows for proper type
+ checking. */
size_t
gcry_cipher_get_algo_blklen (int algo)
{
@@ -1702,7 +1806,7 @@ gcry_cipher_get_algo_blklen (int algo)
return n;
}
-
+/* Explicitly initialize this module. */
gcry_err_code_t
_gcry_cipher_init (void)
{
@@ -1730,3 +1834,41 @@ gcry_cipher_list (int *list, int *list_length)
return err;
}
+
+
+/* Run the selftests for cipher algorithm ALGO with optional reporting
+ function REPORT. */
+gpg_error_t
+_gcry_cipher_selftest (int algo, selftest_report_func_t report)
+{
+ gcry_module_t module = NULL;
+ cipher_extra_spec_t *extraspec = NULL;
+ gcry_err_code_t ec = 0;
+
+ REGISTER_DEFAULT_CIPHERS;
+
+ ath_mutex_lock (&ciphers_registered_lock);
+ module = _gcry_module_lookup_id (ciphers_registered, algo);
+ if (module && !(module->flags & FLAG_MODULE_DISABLED))
+ extraspec = module->extraspec;
+ ath_mutex_unlock (&ciphers_registered_lock);
+ if (extraspec && extraspec->selftest)
+ ec = extraspec->selftest (algo, report);
+ else
+ {
+ ec = GPG_ERR_CIPHER_ALGO;
+ if (report)
+ report ("cipher", algo, "module",
+ module && !(module->flags & FLAG_MODULE_DISABLED)?
+ "no selftest available" :
+ module? "algorithm disabled" : "algorithm not found");
+ }
+
+ if (module)
+ {
+ ath_mutex_lock (&ciphers_registered_lock);
+ _gcry_module_release (module);
+ ath_mutex_unlock (&ciphers_registered_lock);
+ }
+ return gpg_error (ec);
+}
diff --git a/cipher/des.c b/cipher/des.c
index 81b5337e..dcc4a6bf 100644
--- a/cipher/des.c
+++ b/cipher/des.c
@@ -100,7 +100,7 @@
* char *error_msg;
*
* * To perform a selftest of this DES/Triple-DES implementation use the
- * function selftest(). It will return an error string if their are
+ * function selftest(). It will return an error string if there are
* some problems with this library. *
*
* if ( (error_msg = selftest()) )
@@ -310,7 +310,7 @@ static byte encrypt_rotate_tab[16] =
/*
* Table with weak DES keys sorted in ascending order.
- * In DES their are 64 known keys wich are weak. They are weak
+ * In DES their are 64 known keys which are weak. They are weak
* because they produce only one, two or four different
* subkeys in the subkey scheduling process.
* The keys in this table have all their parity bits cleared.
@@ -584,7 +584,7 @@ des_setkey (struct _des_ctx *ctx, const byte * key)
static const char *selftest_failed;
int i;
- if (! initialized)
+ if (!fips_mode () && !initialized)
{
initialized = 1;
selftest_failed = selftest ();
@@ -691,7 +691,7 @@ tripledes_set3keys (struct _tripledes_ctx *ctx,
static const char *selftest_failed;
int i;
- if (! initialized)
+ if (!fips_mode () && !initialized)
{
initialized = 1;
selftest_failed = selftest ();
@@ -956,7 +956,6 @@ selftest (void)
byte result[8];
int i;
- static char error[80];
tripledes_ctx des3;
for (i=0; i<sizeof(testdata)/sizeof(*testdata); ++i)
@@ -966,19 +965,11 @@ selftest (void)
tripledes_ecb_encrypt (des3, testdata[i].plain, result);
if (memcmp (testdata[i].cipher, result, 8))
- {
- sprintf (error, "Triple-DES SSLeay test pattern no. %d "
- "failed on encryption.", i+1);
- return error;
- }
+ return "Triple-DES SSLeay test failed on encryption.";
tripledes_ecb_decrypt (des3, testdata[i].cipher, result);
if (memcmp (testdata[i].plain, result, 8))
- {
- sprintf (error, "Triple-DES SSLeay test pattern no. %d "
- "failed on decryption.", i+1);
- return error;
- }
+ return "Triple-DES SSLeay test failed on decryption.";;
}
}
@@ -992,14 +983,14 @@ selftest (void)
unsigned char *p;
gcry_md_hd_t h;
- if (gcry_md_open (&h, GCRY_MD_SHA1, 0))
+ if (_gcry_md_open (&h, GCRY_MD_SHA1, 0))
return "SHA1 not available";
for (i = 0; i < 64; ++i)
- gcry_md_write (h, weak_keys[i], 8);
- p = gcry_md_read (h, GCRY_MD_SHA1);
+ _gcry_md_write (h, weak_keys[i], 8);
+ p = _gcry_md_read (h, GCRY_MD_SHA1);
i = memcmp (p, weak_keys_chksum, 20);
- gcry_md_close (h);
+ _gcry_md_close (h);
if (i)
return "weak key table defect";
@@ -1088,6 +1079,59 @@ do_des_decrypt( void *context, byte *outbuf, const byte *inbuf )
_gcry_burn_stack (32);
}
+
+
+
+/*
+ Self-test section.
+ */
+
+
+/* Complete selftest for TripleDES with all modes and driver code. */
+static gpg_err_code_t
+selftest_fips (selftest_report_func_t report)
+{
+ const char *what;
+ const char *errtxt;
+
+ what = "low-level";
+ errtxt = selftest ();
+ if (errtxt)
+ goto failed;
+
+ /* FIXME: need more tests. */
+
+ return 0; /* Succeeded. */
+
+ failed:
+ if (report)
+ report ("cipher", GCRY_CIPHER_3DES, what, errtxt);
+ return GPG_ERR_SELFTEST_FAILED;
+}
+
+
+
+/* Run a full self-test for ALGO and return 0 on success. */
+static gpg_err_code_t
+run_selftests (int algo, selftest_report_func_t report)
+{
+ gpg_err_code_t ec;
+
+ switch (algo)
+ {
+ case GCRY_CIPHER_3DES:
+ ec = selftest_fips (report);
+ break;
+ default:
+ ec = GPG_ERR_CIPHER_ALGO;
+ break;
+
+ }
+ return ec;
+}
+
+
+
gcry_cipher_spec_t _gcry_cipher_spec_des =
{
"DES", NULL, NULL, 8, 64, sizeof (struct _des_ctx),
@@ -1109,3 +1153,8 @@ gcry_cipher_spec_t _gcry_cipher_spec_tripledes =
"3DES", NULL, oids_tripledes, 8, 192, sizeof (struct _tripledes_ctx),
do_tripledes_setkey, do_tripledes_encrypt, do_tripledes_decrypt
};
+
+cipher_extra_spec_t _gcry_cipher_extraspec_tripledes =
+ {
+ run_selftests
+ };
diff --git a/cipher/dsa.c b/cipher/dsa.c
index bf5bf6d9..ccfd6860 100644
--- a/cipher/dsa.c
+++ b/cipher/dsa.c
@@ -1,6 +1,6 @@
/* dsa.c - DSA signature scheme
* Copyright (C) 1998, 2000, 2001, 2002, 2003,
- * 2006 Free Software Foundation, Inc.
+ * 2006, 2008 Free Software Foundation, Inc.
*
* This file is part of Libgcrypt.
*
@@ -207,6 +207,9 @@ generate (DSA_secret_key *sk, unsigned int nbits, unsigned int qbits,
if (nbits < 2*qbits || nbits > 15360)
return GPG_ERR_INV_VALUE;
+ if (nbits < 1024 && fips_mode ())
+ return GPG_ERR_INV_VALUE;
+
p = _gcry_generate_elg_prime( 1, nbits, qbits, NULL, ret_factors );
/* get q out of factors */
q = mpi_copy((*ret_factors)[0]);
@@ -531,6 +534,57 @@ _gcry_dsa_get_nbits (int algo, gcry_mpi_t *pkey)
return mpi_get_nbits (pkey[0]);
}
+
+
+/*
+ Self-test section.
+ */
+
+
+static gpg_err_code_t
+selftests_dsa (selftest_report_func_t report)
+{
+ const char *what;
+ const char *errtxt;
+
+ what = "low-level";
+ errtxt = NULL; /*selftest ();*/
+ if (errtxt)
+ goto failed;
+
+ /* FIXME: need more tests. */
+
+ return 0; /* Succeeded. */
+
+ failed:
+ if (report)
+ report ("pubkey", GCRY_PK_DSA, what, errtxt);
+ return GPG_ERR_SELFTEST_FAILED;
+}
+
+
+/* Run a full self-test for ALGO and return 0 on success. */
+static gpg_err_code_t
+run_selftests (int algo, selftest_report_func_t report)
+{
+ gpg_err_code_t ec;
+
+ switch (algo)
+ {
+ case GCRY_PK_DSA:
+ ec = selftests_dsa (report);
+ break;
+ default:
+ ec = GPG_ERR_PUBKEY_ALGO;
+ break;
+
+ }
+ return ec;
+}
+
+
+
+
static const char *dsa_names[] =
{
"dsa",
@@ -551,4 +605,8 @@ gcry_pk_spec_t _gcry_pubkey_spec_dsa =
_gcry_dsa_verify,
_gcry_dsa_get_nbits,
};
+pk_extra_spec_t _gcry_pubkey_extraspec_dsa =
+ {
+ run_selftests
+ };
diff --git a/cipher/ecc.c b/cipher/ecc.c
index b93e8098..d1da75ac 100644
--- a/cipher/ecc.c
+++ b/cipher/ecc.c
@@ -1,5 +1,5 @@
/* ecc.c - Elliptic Curve Cryptography
- Copyright (C) 2007 Free Software Foundation, Inc.
+ Copyright (C) 2007, 2008 Free Software Foundation, Inc.
This file is part of Libgcrypt.
@@ -128,6 +128,7 @@ static const struct
{
const char *desc; /* Description of the curve. */
unsigned int nbits; /* Number of bits. */
+ unsigned int fips:1; /* True if this is a FIPS140-2 approved curve. */
const char *p; /* Order of the prime field. */
const char *a, *b; /* The coefficients. */
const char *n; /* The order of the base point. */
@@ -135,7 +136,7 @@ static const struct
} domain_parms[] =
{
{
- "NIST P-192", 192,
+ "NIST P-192", 192, 1,
"0xfffffffffffffffffffffffffffffffeffffffffffffffff",
"0xfffffffffffffffffffffffffffffffefffffffffffffffc",
"0x64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1",
@@ -145,7 +146,7 @@ static const struct
"0x07192b95ffc8da78631011ed6b24cdd573f977a11e794811"
},
{
- "NIST P-224", 224,
+ "NIST P-224", 224, 1,
"0xffffffffffffffffffffffffffffffff000000000000000000000001",
"0xfffffffffffffffffffffffffffffffefffffffffffffffffffffffe",
"0xb4050a850c04b3abf54132565044b0b7d7bfd8ba270b39432355ffb4",
@@ -155,7 +156,7 @@ static const struct
"0xbd376388b5f723fb4c22dfe6cd4375a05a07476444d5819985007e34"
},
{
- "NIST P-256", 256,
+ "NIST P-256", 256, 1,
"0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff",
"0xffffffff00000001000000000000000000000000fffffffffffffffffffffffc",
"0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b",
@@ -165,7 +166,7 @@ static const struct
"0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5"
},
{
- "NIST P-384", 384,
+ "NIST P-384", 384, 1,
"0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe"
"ffffffff0000000000000000ffffffff",
"0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe"
@@ -181,7 +182,7 @@ static const struct
"0a60b1ce1d7e819d7a431d7c90ea0e5f"
},
{
- "NIST P-521", 521,
+ "NIST P-521", 521, 1,
"0x01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"0x01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
@@ -197,7 +198,7 @@ static const struct
"62c97ee72995ef42640c550b9013fad0761353c7086a272c24088be94769fd16650"
},
- { "brainpoolP160r1", 160,
+ { "brainpoolP160r1", 160, 0,
"0xe95e4a5f737059dc60dfc7ad95b3d8139515620f",
"0x340e7be2a280eb74e2be61bada745d97e8f7c300",
"0x1e589a8595423412134faa2dbdec95c8d8675e58",
@@ -206,7 +207,7 @@ static const struct
"0x1667cb477a1a8ec338f94741669c976316da6321"
},
- { "brainpoolP192r1", 192,
+ { "brainpoolP192r1", 192, 0,
"0xc302f41d932a36cda7a3463093d18db78fce476de1a86297",
"0x6a91174076b1e0e19c39c031fe8685c1cae040e5c69a28ef",
"0x469a28ef7c28cca3dc721d044f4496bcca7ef4146fbf25c9",
@@ -215,7 +216,7 @@ static const struct
"0x14b690866abd5bb88b5f4828c1490002e6773fa2fa299b8f"
},
- { "brainpoolP224r1", 224,
+ { "brainpoolP224r1", 224, 0,
"0xd7c134aa264366862a18302575d1d787b09f075797da89f57ec8c0ff",
"0x68a5e62ca9ce6c1c299803a6c1530b514e182ad8b0042a59cad29f43",
"0x2580f63ccfe44138870713b1a92369e33e2135d266dbb372386c400b",
@@ -224,7 +225,7 @@ static const struct
"0x58aa56f772c0726f24c6b89e4ecdac24354b9e99caa3f6d3761402cd"
},
- { "brainpoolP256r1", 256,
+ { "brainpoolP256r1", 256, 0,
"0xa9fb57dba1eea9bc3e660a909d838d726e3bf623d52620282013481d1f6e5377",
"0x7d5a0975fc2c3057eef67530417affe7fb8055c126dc5c6ce94a4b44f330b5d9",
"0x26dc5c6ce94a4b44f330b5d9bbd77cbf958416295cf7e1ce6bccdc18ff8c07b6",
@@ -233,7 +234,7 @@ static const struct
"0x547ef835c3dac4fd97f8461a14611dc9c27745132ded8e545c1d54c72f046997"
},
- { "brainpoolP320r1", 320,
+ { "brainpoolP320r1", 320, 0,
"0xd35e472036bc4fb7e13c785ed201e065f98fcfa6f6f40def4f92b9ec7893ec28"
"fcd412b1f1b32e27",
"0x3ee30b568fbab0f883ccebd46d3f3bb8a2a73513f5eb79da66190eb085ffa9f4"
@@ -248,7 +249,7 @@ static const struct
"d35245d1692e8ee1"
},
- { "brainpoolP384r1", 384,
+ { "brainpoolP384r1", 384, 0,
"0x8cb91e82a3386d280f5d6f7e50e641df152f7109ed5456b412b1da197fb71123"
"acd3a729901d1a71874700133107ec53",
"0x7bc382c63d8c150c3c72080ace05afa0c2bea28e4fb22787139165efba91f90f"
@@ -263,7 +264,7 @@ static const struct
"0e4646217791811142820341263c5315"
},
- { "brainpoolP512r1", 512,
+ { "brainpoolP512r1", 512, 0,
"0xaadd9db8dbe9c48b3fd4e6ae33c9fc07cb308db3b3c9d20ed6639cca70330871"
"7d4d9b009bc66842aecda12ae6a380e62881ff2f2d82c68528aa6056583a48f3",
"0x7830a3318b603b89e2327145ac234cc594cbdd8d3df91610a83441caea9863bc"
@@ -278,7 +279,7 @@ static const struct
"b2dcde494a5f485e5bca4bd88a2763aed1ca2b2fa8f0540678cd1e0f3ad80892"
},
- { NULL, 0, NULL, NULL, NULL, NULL }
+ { NULL, 0, 0, NULL, NULL, NULL, NULL }
};
@@ -478,6 +479,13 @@ generate_curve (unsigned int nbits, const char *name,
if (!domain_parms[idx].desc)
return GPG_ERR_INV_VALUE;
+ /* In fips mode we only support NIST curves. Note that it is
+ possible to bypass this check by specifying the curve parameters
+ directly. */
+ if (fips_mode () && !domain_parms[idx].fips )
+ return GPG_ERR_NOT_SUPPORTED;
+
+
*r_nbits = domain_parms[idx].nbits;
curve->p = scanval (domain_parms[idx].p);
curve->a = scanval (domain_parms[idx].a);
@@ -1175,6 +1183,56 @@ ecc_get_nbits (int algo, gcry_mpi_t *pkey)
}
+
+/*
+ Self-test section.
+ */
+
+
+static gpg_err_code_t
+selftests_ecdsa (selftest_report_func_t report)
+{
+ const char *what;
+ const char *errtxt;
+
+ what = "low-level";
+ errtxt = NULL; /*selftest ();*/
+ if (errtxt)
+ goto failed;
+
+ /* FIXME: need more tests. */
+
+ return 0; /* Succeeded. */
+
+ failed:
+ if (report)
+ report ("pubkey", GCRY_PK_ECDSA, what, errtxt);
+ return GPG_ERR_SELFTEST_FAILED;
+}
+
+
+/* Run a full self-test for ALGO and return 0 on success. */
+static gpg_err_code_t
+run_selftests (int algo, selftest_report_func_t report)
+{
+ gpg_err_code_t ec;
+
+ switch (algo)
+ {
+ case GCRY_PK_ECDSA:
+ ec = selftests_ecdsa (report);
+ break;
+ default:
+ ec = GPG_ERR_PUBKEY_ALGO;
+ break;
+
+ }
+ return ec;
+}
+
+
+
+
static const char *ecdsa_names[] =
{
"ecdsa",
@@ -1195,4 +1253,8 @@ gcry_pk_spec_t _gcry_pubkey_spec_ecdsa =
ecc_verify,
ecc_get_nbits
};
+pk_extra_spec_t _gcry_pubkey_extraspec_ecdsa =
+ {
+ run_selftests
+ };
diff --git a/cipher/md.c b/cipher/md.c
index e1cb27dd..2cc25b77 100644
--- a/cipher/md.c
+++ b/cipher/md.c
@@ -1,5 +1,6 @@
/* md.c - message digest dispatcher
- * Copyright (C) 1998, 1999, 2002, 2003, 2006 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 1999, 2002, 2003, 2006,
+ * 2008 Free Software Foundation, Inc.
*
* This file is part of Libgcrypt.
*
@@ -14,8 +15,7 @@
* 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 <http://www.gnu.org/licenses/>.
*/
#include <config.h>
@@ -31,42 +31,67 @@
#include "rmd.h"
+/* A dummy extraspec so that we do not need to tests the extraspec
+ field from the module specification against NULL and instead
+ directly test the respective fields of extraspecs. */
+static md_extra_spec_t dummy_extra_spec;
+
+
+/* This is the list of the digest implementations included in
+ libgcrypt. */
static struct digest_table_entry
{
gcry_md_spec_t *digest;
+ md_extra_spec_t *extraspec;
unsigned int algorithm;
+ int fips_allowed;
} digest_table[] =
{
#if USE_CRC
- { &_gcry_digest_spec_crc32, GCRY_MD_CRC32 },
- { &_gcry_digest_spec_crc32_rfc1510, GCRY_MD_CRC32_RFC1510 },
- { &_gcry_digest_spec_crc24_rfc2440, GCRY_MD_CRC24_RFC2440 },
+ /* We allow the CRC algorithms even in FIPS mode because they are
+ actually no cryptographic primitives. */
+ { &_gcry_digest_spec_crc32,
+ &dummy_extra_spec, GCRY_MD_CRC32, 1 },
+ { &_gcry_digest_spec_crc32_rfc1510,
+ &dummy_extra_spec, GCRY_MD_CRC32_RFC1510, 1 },
+ { &_gcry_digest_spec_crc24_rfc2440,
+ &dummy_extra_spec, GCRY_MD_CRC24_RFC2440, 1 },
#endif
#if USE_MD4
- { &_gcry_digest_spec_md4, GCRY_MD_MD4 },
+ { &_gcry_digest_spec_md4,
+ &dummy_extra_spec, GCRY_MD_MD4 },
#endif
#if USE_MD5
- { &_gcry_digest_spec_md5, GCRY_MD_MD5 },
+ { &_gcry_digest_spec_md5,
+ &dummy_extra_spec, GCRY_MD_MD5 },
#endif
#if USE_RMD160
- { &_gcry_digest_spec_rmd160, GCRY_MD_RMD160 },
+ { &_gcry_digest_spec_rmd160,
+ &dummy_extra_spec, GCRY_MD_RMD160 },
#endif
#if USE_SHA1
- { &_gcry_digest_spec_sha1, GCRY_MD_SHA1 },
+ { &_gcry_digest_spec_sha1,
+ &_gcry_digest_extraspec_sha1, GCRY_MD_SHA1, 1 },
#endif
#if USE_SHA256
- { &_gcry_digest_spec_sha256, GCRY_MD_SHA256 },
- { &_gcry_digest_spec_sha224, GCRY_MD_SHA224 },
+ { &_gcry_digest_spec_sha256,
+ &_gcry_digest_extraspec_sha256, GCRY_MD_SHA256, 1 },
+ { &_gcry_digest_spec_sha224,
+ &_gcry_digest_extraspec_sha224, GCRY_MD_SHA224, 1 },
#endif
#if USE_SHA512
- { &_gcry_digest_spec_sha512, GCRY_MD_SHA512 },
- { &_gcry_digest_spec_sha384, GCRY_MD_SHA384 },
+ { &_gcry_digest_spec_sha512,
+ &_gcry_digest_extraspec_sha512, GCRY_MD_SHA512, 1 },
+ { &_gcry_digest_spec_sha384,
+ &_gcry_digest_extraspec_sha384, GCRY_MD_SHA384, 1 },
#endif
#if USE_TIGER
- { &_gcry_digest_spec_tiger, GCRY_MD_TIGER },
+ { &_gcry_digest_spec_tiger,
+ &dummy_extra_spec, GCRY_MD_TIGER },
#endif
#if USE_WHIRLPOOL
- { &_gcry_digest_spec_whirlpool, GCRY_MD_WHIRLPOOL },
+ { &_gcry_digest_spec_whirlpool,
+ &dummy_extra_spec, GCRY_MD_WHIRLPOOL },
#endif
{ NULL },
};
@@ -115,7 +140,7 @@ struct gcry_md_context
ath_mutex_lock (&digests_registered_lock); \
if (! default_digests_registered) \
{ \
- gcry_md_register_default (); \
+ md_register_default (); \
default_digests_registered = 1; \
} \
ath_mutex_unlock (&digests_registered_lock); \
@@ -145,16 +170,22 @@ static void md_stop_debug ( gcry_md_hd_t a );
/* Internal function. Register all the ciphers included in
CIPHER_TABLE. Returns zero on success or an error code. */
static void
-gcry_md_register_default (void)
+md_register_default (void)
{
gcry_err_code_t err = 0;
int i;
- for (i = 0; (! err) && digest_table[i].digest; i++)
- err = _gcry_module_add (&digests_registered,
- digest_table[i].algorithm,
- (void *) digest_table[i].digest,
- NULL);
+ for (i = 0; !err && digest_table[i].digest; i++)
+ {
+ if ( fips_mode () && !digest_table[i].fips_allowed )
+ continue;
+
+ err = _gcry_module_add (&digests_registered,
+ digest_table[i].algorithm,
+ (void *) digest_table[i].digest,
+ (void *) digest_table[i].extraspec,
+ NULL);
+ }
if (err)
BUG ();
@@ -217,16 +248,23 @@ gcry_md_lookup_oid (const char *oid)
DIGEST. On success, a new algorithm ID is stored in ALGORITHM_ID
and a pointer representhing this module is stored in MODULE. */
gcry_error_t
-gcry_md_register (gcry_md_spec_t *digest,
- unsigned int *algorithm_id,
- gcry_module_t *module)
+_gcry_md_register (gcry_md_spec_t *digest,
+ md_extra_spec_t *extraspec,
+ unsigned int *algorithm_id,
+ gcry_module_t *module)
{
gcry_err_code_t err = 0;
gcry_module_t mod;
+ /* We do not support module loading in fips mode. */
+ if (fips_mode ())
+ return gpg_error (GPG_ERR_NOT_SUPPORTED);
+
ath_mutex_lock (&digests_registered_lock);
err = _gcry_module_add (&digests_registered, 0,
- (void *) digest, &mod);
+ (void *) digest,
+ (void *)(extraspec? extraspec : &dummy_extra_spec),
+ &mod);
ath_mutex_unlock (&digests_registered_lock);
if (! err)
@@ -448,7 +486,7 @@ md_open (gcry_md_hd_t *h, int algo, int secure, int hmac)
if (! err)
{
- /* FIXME: should we really do that? - yes [-wk] */
+ /* Hmmm, should we really do that? - yes [-wk] */
_gcry_fast_random_poll ();
if (algo)
@@ -560,8 +598,7 @@ md_enable (gcry_md_hd_t hd, int algorithm)
gcry_error_t
gcry_md_enable (gcry_md_hd_t hd, int algorithm)
{
- gcry_err_code_t err = md_enable (hd, algorithm);
- return gcry_error (err);
+ return gcry_error (md_enable (hd, algorithm));
}
static gcry_err_code_t
@@ -655,7 +692,9 @@ md_copy (gcry_md_hd_t ahd, gcry_md_hd_t *b_hd)
gcry_error_t
gcry_md_copy (gcry_md_hd_t *handle, gcry_md_hd_t hd)
{
- gcry_err_code_t err = md_copy (hd, handle);
+ gcry_err_code_t err;
+
+ err = md_copy (hd, handle);
if (err)
*handle = NULL;
return gcry_error (err);
@@ -669,7 +708,9 @@ void
gcry_md_reset (gcry_md_hd_t a)
{
GcryDigestEntry *r;
-
+
+ /* Note: We allow this even in fips non operational mode. */
+
a->bufpos = a->ctx->finalized = 0;
for (r = a->ctx->list; r; r = r->next)
@@ -713,6 +754,7 @@ md_close (gcry_md_hd_t a)
void
gcry_md_close (gcry_md_hd_t hd)
{
+ /* Note: We allow this even in fips non operational mode. */
md_close (hd);
}
@@ -771,7 +813,9 @@ md_final (gcry_md_hd_t a)
if (err)
_gcry_fatal_error (err, NULL);
- md_write (om, (a->ctx->macpads)+(a->ctx->macpads_Bsize), a->ctx->macpads_Bsize);
+ md_write (om,
+ (a->ctx->macpads)+(a->ctx->macpads_Bsize),
+ a->ctx->macpads_Bsize);
md_write (om, p, dlen);
md_final (om);
/* Replace our digest with the mac (they have the same size). */
@@ -847,7 +891,7 @@ gcry_md_setkey (gcry_md_hd_t hd, const void *key, size_t keylen)
{
gcry_err_code_t rc = GPG_ERR_NO_ERROR;
- if (! hd->ctx->macpads)
+ if (!hd->ctx->macpads)
rc = GPG_ERR_CONFLICT;
else
{
@@ -905,64 +949,16 @@ md_read( gcry_md_hd_t a, int algo )
byte *
gcry_md_read (gcry_md_hd_t hd, int algo)
{
+ /* This function is expected to always return a digest, thus we
+ can't return an error which we actually should do in
+ non-operational state. */
gcry_md_ctl (hd, GCRYCTL_FINALIZE, NULL, 0);
return md_read (hd, algo);
}
-/****************
- * This function combines md_final and md_read but keeps the context
- * intact. This function can be used to calculate intermediate
- * digests. The digest is copied into buffer and the digestlength is
- * returned. If buffer is NULL only the needed size for buffer is returned.
- * buflen gives the max size of buffer. If the buffer is too shourt to
- * hold the complete digest, the buffer is filled with as many bytes are
- * possible and this value is returned.
- */
-#if 0
-static int
-md_digest( gcry_md_hd_t a, int algo, byte *buffer, int buflen )
-{
- struct md_digest_list_s *r = NULL;
- char *context;
- char *digest;
-
- if( a->bufpos )
- md_write( a, NULL, 0 );
-
- if( !algo ) { /* return digest for the first algorithm */
- if( (r=a->ctx->list) && r->next )
- log_debug("more than algorithm in md_digest(0)\n");
- }
- else {
- for(r=a->ctx->list; r; r = r->next )
- if( r->algo == algo )
- break;
- }
- if( !r )
- BUG();
-
- if( !buffer )
- return r->mdlen;
-
- /* I don't want to change the interface, so I simply work on a copy
- * of the context (extra overhead - should be fixed)*/
- context = a->ctx->secure ? gcry_xmalloc_secure( r->contextsize )
- : gcry_xmalloc( r->contextsize );
- memcpy( context, r->context.c, r->contextsize );
- (*r->digest->final)( context );
- digest = (*r->digest->read)( context );
-
- if( buflen > r->mdlen )
- buflen = r->mdlen;
- memcpy( buffer, digest, buflen );
-
- gcry_free(context);
- return buflen;
-}
-#endif
/*
- * Read out an intermediate digest. Not yet fucntional.
+ * Read out an intermediate digest. Not yet functional.
*/
gcry_err_code_t
gcry_md_get (gcry_md_hd_t hd, int algo, byte *buffer, int buflen)
@@ -973,6 +969,7 @@ gcry_md_get (gcry_md_hd_t hd, int algo, byte *buffer, int buflen)
(void)buflen;
/*md_digest ... */
+ fips_signal_error ("unimplemented function called");
return GPG_ERR_INTERNAL;
}
@@ -989,7 +986,7 @@ gcry_md_hash_buffer (int algo, void *digest,
{
if (algo == GCRY_MD_SHA1)
_gcry_sha1_hash_buffer (digest, buffer, length);
- else if (algo == GCRY_MD_RMD160)
+ else if (algo == GCRY_MD_RMD160 && !fips_mode () )
_gcry_rmd160_hash_buffer (digest, buffer, length);
else
{
@@ -1013,7 +1010,10 @@ md_get_algo (gcry_md_hd_t a)
GcryDigestEntry *r = a->ctx->list;
if (r && r->next)
- log_error("WARNING: more than algorithm in md_get_algo()\n");
+ {
+ fips_signal_error ("possible usage error");
+ log_error ("WARNING: more than algorithm in md_get_algo()\n");
+ }
return r ? r->module->mod_id : 0;
}
@@ -1158,6 +1158,9 @@ md_start_debug ( gcry_md_hd_t md, const char *suffix )
{
static int idx=0;
char buf[50];
+
+ if (fips_mode ())
+ return;
if ( md->ctx->debug )
{
@@ -1244,6 +1247,8 @@ gcry_md_info (gcry_md_hd_t h, int cmd, void *buffer, size_t *nbytes)
return gcry_error (err);
}
+
+/* Explicitly initialize this module. */
gcry_err_code_t
_gcry_md_init (void)
{
@@ -1296,3 +1301,41 @@ gcry_md_list (int *list, int *list_length)
return err;
}
+
+
+/* Run the selftests for digest algorithm ALGO with optional reporting
+ function REPORT. */
+gpg_error_t
+_gcry_md_selftest (int algo, selftest_report_func_t report)
+{
+ gcry_module_t module = NULL;
+ cipher_extra_spec_t *extraspec = NULL;
+ gcry_err_code_t ec = 0;
+
+ REGISTER_DEFAULT_DIGESTS;
+
+ ath_mutex_lock (&digests_registered_lock);
+ module = _gcry_module_lookup_id (digests_registered, algo);
+ if (module && !(module->flags & FLAG_MODULE_DISABLED))
+ extraspec = module->extraspec;
+ ath_mutex_unlock (&digests_registered_lock);
+ if (extraspec && extraspec->selftest)
+ ec = extraspec->selftest (algo, report);
+ else
+ {
+ ec = GPG_ERR_DIGEST_ALGO;
+ if (report)
+ report ("digest", algo, "module",
+ module && !(module->flags & FLAG_MODULE_DISABLED)?
+ "no selftest available" :
+ module? "algorithm disabled" : "algorithm not found");
+ }
+
+ if (module)
+ {
+ ath_mutex_lock (&digests_registered_lock);
+ _gcry_module_release (module);
+ ath_mutex_unlock (&digests_registered_lock);
+ }
+ return gpg_error (ec);
+}
diff --git a/cipher/pubkey.c b/cipher/pubkey.c
index 5a39f3e7..ad5f89b7 100644
--- a/cipher/pubkey.c
+++ b/cipher/pubkey.c
@@ -1,6 +1,6 @@
/* pubkey.c - pubkey dispatcher
- * Copyright (C) 1998, 1999, 2000, 2002, 2003,
- * 2005, 2007 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 1999, 2000, 2002, 2003, 2005,
+ * 2007, 2008 Free Software Foundation, Inc.
*
* This file is part of Libgcrypt.
*
@@ -15,8 +15,7 @@
* 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 <http://www.gnu.org/licenses/>.
*/
#include <config.h>
@@ -41,26 +40,41 @@ static gcry_err_code_t pubkey_verify (int algo, gcry_mpi_t hash,
int (*cmp) (void *, gcry_mpi_t),
void *opaque);
+
+/* A dummy extraspec so that we do not need to tests the extraspec
+ field from the module specification against NULL and instead
+ directly test the respective fields of extraspecs. */
+static pk_extra_spec_t dummy_extra_spec;
+
+
/* This is the list of the default public-key ciphers included in
- libgcrypt. */
+ libgcrypt. FIPS_ALLOWED indicated whether the algorithm is used in
+ FIPS mode. */
static struct pubkey_table_entry
{
gcry_pk_spec_t *pubkey;
+ pk_extra_spec_t *extraspec;
unsigned int algorithm;
+ int fips_allowed;
} pubkey_table[] =
{
#if USE_RSA
- { &_gcry_pubkey_spec_rsa, GCRY_PK_RSA },
+ { &_gcry_pubkey_spec_rsa,
+ &_gcry_pubkey_extraspec_rsa, GCRY_PK_RSA, 1},
#endif
#if USE_ELGAMAL
- { &_gcry_pubkey_spec_elg, GCRY_PK_ELG },
- { &_gcry_pubkey_spec_elg, GCRY_PK_ELG_E },
+ { &_gcry_pubkey_spec_elg,
+ &dummy_extra_spec, GCRY_PK_ELG },
+ { &_gcry_pubkey_spec_elg,
+ &dummy_extra_spec, GCRY_PK_ELG_E },
#endif
#if USE_DSA
- { &_gcry_pubkey_spec_dsa, GCRY_PK_DSA },
+ { &_gcry_pubkey_spec_dsa,
+ &_gcry_pubkey_extraspec_dsa, GCRY_PK_DSA, 1 },
#endif
#if USE_ECC
- { &_gcry_pubkey_spec_ecdsa, GCRY_PK_ECDSA },
+ { &_gcry_pubkey_spec_ecdsa,
+ &_gcry_pubkey_extraspec_ecdsa, GCRY_PK_ECDSA, 0 },
#endif
{ NULL, 0 },
};
@@ -82,7 +96,7 @@ static int default_pubkeys_registered;
ath_mutex_lock (&pubkeys_registered_lock); \
if (! default_pubkeys_registered) \
{ \
- gcry_pk_register_default (); \
+ pk_register_default (); \
default_pubkeys_registered = 1; \
} \
ath_mutex_unlock (&pubkeys_registered_lock); \
@@ -101,6 +115,7 @@ dummy_generate (int algorithm, unsigned int nbits, unsigned long dummy,
(void)dummy;
(void)skey;
(void)retfactors;
+ fips_signal_error ("using dummy public key function");
return GPG_ERR_NOT_IMPLEMENTED;
}
@@ -109,6 +124,7 @@ dummy_check_secret_key (int algorithm, gcry_mpi_t *skey)
{
(void)algorithm;
(void)skey;
+ fips_signal_error ("using dummy public key function");
return GPG_ERR_NOT_IMPLEMENTED;
}
@@ -121,6 +137,7 @@ dummy_encrypt (int algorithm, gcry_mpi_t *resarr, gcry_mpi_t data,
(void)data;
(void)pkey;
(void)flags;
+ fips_signal_error ("using dummy public key function");
return GPG_ERR_NOT_IMPLEMENTED;
}
@@ -133,6 +150,7 @@ dummy_decrypt (int algorithm, gcry_mpi_t *result, gcry_mpi_t *data,
(void)data;
(void)skey;
(void)flags;
+ fips_signal_error ("using dummy public key function");
return GPG_ERR_NOT_IMPLEMENTED;
}
@@ -144,6 +162,7 @@ dummy_sign (int algorithm, gcry_mpi_t *resarr, gcry_mpi_t data,
(void)resarr;
(void)data;
(void)skey;
+ fips_signal_error ("using dummy public key function");
return GPG_ERR_NOT_IMPLEMENTED;
}
@@ -158,6 +177,7 @@ dummy_verify (int algorithm, gcry_mpi_t hash, gcry_mpi_t *data,
(void)pkey;
(void)cmp;
(void)opaquev;
+ fips_signal_error ("using dummy public key function");
return GPG_ERR_NOT_IMPLEMENTED;
}
@@ -166,13 +186,14 @@ dummy_get_nbits (int algorithm, gcry_mpi_t *pkey)
{
(void)algorithm;
(void)pkey;
+ fips_signal_error ("using dummy public key function");
return 0;
}
/* Internal function. Register all the pubkeys included in
PUBKEY_TABLE. Returns zero on success or an error code. */
static void
-gcry_pk_register_default (void)
+pk_register_default (void)
{
gcry_err_code_t err = 0;
int i;
@@ -191,9 +212,12 @@ gcry_pk_register_default (void)
pubkey_use_dummy (verify);
pubkey_use_dummy (get_nbits);
#undef pubkey_use_dummy
+
err = _gcry_module_add (&pubkeys_registered,
pubkey_table[i].algorithm,
- (void *) pubkey_table[i].pubkey, NULL);
+ (void *) pubkey_table[i].pubkey,
+ (void *) pubkey_table[i].extraspec,
+ NULL);
}
if (err)
@@ -231,16 +255,23 @@ gcry_pk_lookup_name (const char *name)
PUBKEY. On success, a new algorithm ID is stored in ALGORITHM_ID
and a pointer representhing this module is stored in MODULE. */
gcry_error_t
-gcry_pk_register (gcry_pk_spec_t *pubkey,
- unsigned int *algorithm_id,
- gcry_module_t *module)
+_gcry_pk_register (gcry_pk_spec_t *pubkey,
+ pk_extra_spec_t *extraspec,
+ unsigned int *algorithm_id,
+ gcry_module_t *module)
{
gcry_err_code_t err = GPG_ERR_NO_ERROR;
gcry_module_t mod;
+ /* We do not support module loading in fips mode. */
+ if (fips_mode ())
+ return gpg_error (GPG_ERR_NOT_SUPPORTED);
+
ath_mutex_lock (&pubkeys_registered_lock);
err = _gcry_module_add (&pubkeys_registered, 0,
- (void *) pubkey, &mod);
+ (void *) pubkey,
+ (void *)(extraspec? extraspec : &dummy_extra_spec),
+ &mod);
ath_mutex_unlock (&pubkeys_registered_lock);
if (! err)
@@ -498,6 +529,13 @@ pubkey_get_nenc (int algorithm)
}
+/* Generate a new public key with algorithm ALGORITHM of size NBITS
+ and return it at SKEY. The use of the arguments QBITS, USE_E,
+ XVALUE and CURVE+_NAME depend onthe ALGORITHM. RETFACTOR is used
+ by some algorithms to return certain additional information which
+ are in general not required.
+
+ The function returns ther error code number or 0 on success. */
static gcry_err_code_t
pubkey_generate (int algorithm, unsigned int nbits, unsigned int qbits,
unsigned long use_e, gcry_mpi_t xvalue,
@@ -582,7 +620,10 @@ pubkey_encrypt (int algorithm, gcry_mpi_t *resarr, gcry_mpi_t data,
gcry_err_code_t rc;
int i;
- if (DBG_CIPHER)
+ /* Note: In fips mode DBG_CIPHER will enver evaluate to true but as
+ an extra failsafe protection we explicitly test for fips mode
+ here. */
+ if (DBG_CIPHER && !fips_mode ())
{
log_debug ("pubkey_encrypt: algo=%d\n", algorithm);
for(i = 0; i < pubkey_get_npkey (algorithm); i++)
@@ -604,7 +645,7 @@ pubkey_encrypt (int algorithm, gcry_mpi_t *resarr, gcry_mpi_t data,
ready:
ath_mutex_unlock (&pubkeys_registered_lock);
- if (!rc && DBG_CIPHER)
+ if (!rc && DBG_CIPHER && !fips_mode ())
{
for(i = 0; i < pubkey_get_nenc (algorithm); i++)
log_mpidump(" encr:", resarr[i] );
@@ -630,7 +671,7 @@ pubkey_decrypt (int algorithm, gcry_mpi_t *result, gcry_mpi_t *data,
int i;
*result = NULL; /* so the caller can always do a mpi_free */
- if (DBG_CIPHER)
+ if (DBG_CIPHER && !fips_mode ())
{
log_debug ("pubkey_decrypt: algo=%d\n", algorithm);
for(i = 0; i < pubkey_get_nskey (algorithm); i++)
@@ -654,7 +695,7 @@ pubkey_decrypt (int algorithm, gcry_mpi_t *result, gcry_mpi_t *data,
ready:
ath_mutex_unlock (&pubkeys_registered_lock);
- if (! rc && DBG_CIPHER)
+ if (!rc && DBG_CIPHER && !fips_mode ())
log_mpidump (" plain:", *result);
return rc;
@@ -676,7 +717,7 @@ pubkey_sign (int algorithm, gcry_mpi_t *resarr, gcry_mpi_t data,
gcry_err_code_t rc;
int i;
- if (DBG_CIPHER)
+ if (DBG_CIPHER && !fips_mode ())
{
log_debug ("pubkey_sign: algo=%d\n", algorithm);
for(i = 0; i < pubkey_get_nskey (algorithm); i++)
@@ -699,7 +740,7 @@ pubkey_sign (int algorithm, gcry_mpi_t *resarr, gcry_mpi_t data,
ready:
ath_mutex_unlock (&pubkeys_registered_lock);
- if (! rc && DBG_CIPHER)
+ if (!rc && DBG_CIPHER && !fips_mode ())
for (i = 0; i < pubkey_get_nsig (algorithm); i++)
log_mpidump (" sig:", resarr[i]);
@@ -720,7 +761,7 @@ pubkey_verify (int algorithm, gcry_mpi_t hash, gcry_mpi_t *data,
gcry_err_code_t rc;
int i;
- if (DBG_CIPHER)
+ if (DBG_CIPHER && !fips_mode ())
{
log_debug ("pubkey_verify: algo=%d\n", algorithm);
for (i = 0; i < pubkey_get_npkey (algorithm); i++)
@@ -844,6 +885,7 @@ sexp_elements_extract_ecc (gcry_sexp_t key_sexp, const char *element_names,
list = gcry_sexp_find_token (key_sexp, "curve", 5);
if (list)
{
+#if USE_ECC
char *curve;
gcry_mpi_t params[6];
@@ -868,6 +910,10 @@ sexp_elements_extract_ecc (gcry_sexp_t key_sexp, const char *element_names,
else
mpi_free (params[idx]);
}
+#else /* !USE_ECC */
+ err = GPG_ERR_INV_OBJ; /* "curve" given but ECC not supported. */
+ goto leave;
+#endif /* !USE_ECC */
}
/* Check that all parameters are known. */
@@ -1322,7 +1368,8 @@ sexp_data_to_mpi (gcry_sexp_t input, unsigned int nbits, gcry_mpi_t *ret_mpi,
rc = GPG_ERR_INV_OBJ;
}
else if (is_pkcs1 && lvalue && for_encryption)
- { /* Create pkcs#1 block type 2 padding. */
+ {
+ /* Create pkcs#1 block type 2 padding. */
unsigned char *frame = NULL;
size_t nframe = (nbits+7) / 8;
const void * value;
@@ -1388,7 +1435,8 @@ sexp_data_to_mpi (gcry_sexp_t input, unsigned int nbits, gcry_mpi_t *ret_mpi,
gcry_free(frame);
}
else if (is_pkcs1 && lhash && !for_encryption)
- { /* Create pkcs#1 block type 1 padding. */
+ {
+ /* Create pkcs#1 block type 1 padding. */
if (gcry_sexp_length (lhash) != 3)
rc = GPG_ERR_INV_OBJ;
else if ( !(s=gcry_sexp_nth_data (lhash, 1, &n)) || !n )
@@ -1489,7 +1537,7 @@ sexp_data_to_mpi (gcry_sexp_t input, unsigned int nbits, gcry_mpi_t *ret_mpi,
n += valuelen;
assert (n == nframe);
- /* convert it into an MPI, FIXME: error checking? */
+ /* Convert it into an MPI. FIXME: error checking? */
gcry_mpi_scan (ret_mpi, GCRYMPI_FMT_USG, frame, n, &nframe);
}
@@ -1542,10 +1590,11 @@ gcry_pk_encrypt (gcry_sexp_t *r_ciph, gcry_sexp_t s_data, gcry_sexp_t s_pkey)
gcry_pk_spec_t *pubkey = NULL;
gcry_module_t module = NULL;
+ *r_ciph = NULL;
+
REGISTER_DEFAULT_PUBKEYS;
- *r_ciph = NULL;
- /* get the key */
+ /* Get the key. */
rc = sexp_to_key (s_pkey, 0, &pkey, &module);
if (rc)
goto leave;
@@ -1610,7 +1659,7 @@ gcry_pk_encrypt (gcry_sexp_t *r_ciph, gcry_sexp_t s_data, gcry_sexp_t s_pkey)
/* And now the ugly part: We don't have a function to pass an
* array to a format string, so we have to do it this way :-(. */
- /* FIXME: There is now such a format spefier, so we can could
+ /* FIXME: There is now such a format specifier, so we can
change the code to be more clear. */
arg_list = malloc (nelem * sizeof *arg_list);
if (!arg_list)
@@ -1685,9 +1734,10 @@ gcry_pk_decrypt (gcry_sexp_t *r_plain, gcry_sexp_t s_data, gcry_sexp_t s_skey)
gcry_module_t module_enc = NULL, module_key = NULL;
gcry_pk_spec_t *pubkey = NULL;
+ *r_plain = NULL;
+
REGISTER_DEFAULT_PUBKEYS;
- *r_plain = NULL;
rc = sexp_to_key (s_skey, 1, &skey, &module_key);
if (rc)
goto leave;
@@ -1780,9 +1830,10 @@ gcry_pk_sign (gcry_sexp_t *r_sig, gcry_sexp_t s_hash, gcry_sexp_t s_skey)
int i;
gcry_err_code_t rc;
+ *r_sig = NULL;
+
REGISTER_DEFAULT_PUBKEYS;
- *r_sig = NULL;
rc = sexp_to_key (s_skey, 1, &skey, &module);
if (rc)
goto leave;
@@ -2026,11 +2077,11 @@ gcry_pk_genkey (gcry_sexp_t *r_key, gcry_sexp_t s_parms)
gcry_mpi_t xvalue = NULL;
char *curve = NULL;
- REGISTER_DEFAULT_PUBKEYS;
-
skey[0] = NULL;
*r_key = NULL;
+ REGISTER_DEFAULT_PUBKEYS;
+
list = gcry_sexp_find_token (s_parms, "genkey", 0);
if (!list)
{
@@ -2398,6 +2449,12 @@ gcry_pk_get_keygrip (gcry_sexp_t key, unsigned char *array)
if (gcry_md_open (&md, GCRY_MD_SHA1, 0))
goto fail;
+#if USE_ECC
+# ifdef __GNUC__
+# warning needs to be fixed for ECC.
+# endif
+#endif
+
for (idx = 0, s = elems; *s; s++, idx++)
{
const char *data;
@@ -2418,8 +2475,8 @@ gcry_pk_get_keygrip (gcry_sexp_t key, unsigned char *array)
}
/* PKCS-15 says that for RSA only the modulus should be hashed -
- however, it is not clear wether this is meant to has the raw
- bytes assuming this is an unsigned integer or whether the DER
+ however, it is not clear wether this is meant to use the raw
+ bytes (assuming this is an unsigned integer) or whether the DER
required 0 should be prefixed. We hash the raw bytes. For
non-RSA we hash S-expressions. */
gcry_md_write (md, data, datalen);
@@ -2475,14 +2532,16 @@ gcry_pk_ctl (int cmd, void *buffer, size_t buflen)
}
-/*
- Return information about the given algorithm
- WHAT select the kind of information returned:
+/* Return information about the given algorithm
+
+ WHAT selects the kind of information returned:
+
GCRYCTL_TEST_ALGO:
Returns 0 when the specified algorithm is available for use.
Buffer must be NULL, nbytes may have the address of a variable
with the required usage of the algorithm. It may be 0 for don't
care or a combination of the GCRY_PK_USAGE_xxx flags;
+
GCRYCTL_GET_ALGO_USAGE:
Return the usage glafs for the give algo. An invalid alog
does return 0. Disabled algos are ignored here becuase we
@@ -2570,6 +2629,7 @@ gcry_pk_algo_info (int algorithm, int what, void *buffer, size_t *nbytes)
}
+/* Explicitly initialize this module. */
gcry_err_code_t
_gcry_pk_init (void)
{
@@ -2627,6 +2687,46 @@ gcry_pk_list (int *list, int *list_length)
return err;
}
+
+/* Run the selftests for pubkey algorithm ALGO with optional reporting
+ function REPORT. */
+gpg_error_t
+_gcry_pk_selftest (int algo, selftest_report_func_t report)
+{
+ gcry_module_t module = NULL;
+ cipher_extra_spec_t *extraspec = NULL;
+ gcry_err_code_t ec = 0;
+
+ REGISTER_DEFAULT_PUBKEYS;
+
+ ath_mutex_lock (&pubkeys_registered_lock);
+ module = _gcry_module_lookup_id (pubkeys_registered, algo);
+ if (module && !(module->flags & FLAG_MODULE_DISABLED))
+ extraspec = module->extraspec;
+ ath_mutex_unlock (&pubkeys_registered_lock);
+ if (extraspec && extraspec->selftest)
+ ec = extraspec->selftest (algo, report);
+ else
+ {
+ ec = GPG_ERR_PUBKEY_ALGO;
+ if (report)
+ report ("pubkey", algo, "module",
+ module && !(module->flags & FLAG_MODULE_DISABLED)?
+ "no selftest available" :
+ module? "algorithm disabled" : "algorithm not found");
+ }
+
+ if (module)
+ {
+ ath_mutex_lock (&pubkeys_registered_lock);
+ _gcry_module_release (module);
+ ath_mutex_unlock (&pubkeys_registered_lock);
+ }
+ return gpg_error (ec);
+}
+
+
+/* This function is only used by ac.c! */
gcry_err_code_t
_gcry_pk_get_elements (int algo, char **enc, char **sig)
{
diff --git a/cipher/rijndael.c b/cipher/rijndael.c
index 7f3fc7b9..b54e069d 100644
--- a/cipher/rijndael.c
+++ b/cipher/rijndael.c
@@ -31,12 +31,17 @@
*
* This code is placed in the public domain.
*------------------------------------------
+ *
+ * The SP800-38a document is available at:
+ * http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf
+ *
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h> /* for memcmp() */
+#include <assert.h>
#include "types.h" /* for byte and u32 typedefs */
#include "g10lib.h"
@@ -98,14 +103,21 @@ do_setkey (RIJNDAEL_context *ctx, const byte *key, const unsigned keylen)
byte tk[MAXKC][4];
int KC;
- if (!initialized)
+ /* The on-the-fly self tests are only run in non-fips mode. In fips
+ mode explicit self-tests are required. Actually the on-the-fly
+ self-tests are not fully thread-safe and it might happen that a
+ failed self-test won't get noticed in another thread.
+
+ FIXME: We might want to have a central registry of succeeded
+ self-tests. */
+ if (!fips_mode () && !initialized)
{
initialized = 1;
selftest_failed = selftest ();
- if( selftest_failed )
+ if (selftest_failed)
log_error ("%s\n", selftest_failed );
}
- if( selftest_failed )
+ if (selftest_failed)
return GPG_ERR_SELFTEST_FAILED;
ctx->decryption_prepared = 0;
@@ -774,85 +786,368 @@ _gcry_aes_cbc_dec (void *context, unsigned char *iv,
-/* Test a single encryption and decryption with each key size. */
+/* Run the self-tests for AES 128. Returns NULL on success. */
static const char*
-selftest (void)
+selftest_basic_128 (void)
{
RIJNDAEL_context ctx;
- byte scratch[16];
-
- /* The test vectors are from the AES supplied ones; more or less
- * randomly taken from ecb_tbl.txt (I=42,81,14)
- */
- static byte plaintext[16] = {
- 0x01,0x4B,0xAF,0x22,0x78,0xA6,0x9D,0x33,
- 0x1D,0x51,0x80,0x10,0x36,0x43,0xE9,0x9A
- };
- static byte key[16] = {
- 0xE8,0xE9,0xEA,0xEB,0xED,0xEE,0xEF,0xF0,
- 0xF2,0xF3,0xF4,0xF5,0xF7,0xF8,0xF9,0xFA
- };
- static const byte ciphertext[16] = {
- 0x67,0x43,0xC3,0xD1,0x51,0x9A,0xB4,0xF2,
- 0xCD,0x9A,0x78,0xAB,0x09,0xA5,0x11,0xBD
- };
-
- static byte plaintext_192[16] = {
- 0x76,0x77,0x74,0x75,0xF1,0xF2,0xF3,0xF4,
- 0xF8,0xF9,0xE6,0xE7,0x77,0x70,0x71,0x72
- };
- static byte key_192[24] = {
- 0x04,0x05,0x06,0x07,0x09,0x0A,0x0B,0x0C,
- 0x0E,0x0F,0x10,0x11,0x13,0x14,0x15,0x16,
- 0x18,0x19,0x1A,0x1B,0x1D,0x1E,0x1F,0x20
- };
- static const byte ciphertext_192[16] = {
- 0x5D,0x1E,0xF2,0x0D,0xCE,0xD6,0xBC,0xBC,
- 0x12,0x13,0x1A,0xC7,0xC5,0x47,0x88,0xAA
- };
-
- static byte plaintext_256[16] = {
- 0x06,0x9A,0x00,0x7F,0xC7,0x6A,0x45,0x9F,
- 0x98,0xBA,0xF9,0x17,0xFE,0xDF,0x95,0x21
- };
- static byte key_256[32] = {
- 0x08,0x09,0x0A,0x0B,0x0D,0x0E,0x0F,0x10,
- 0x12,0x13,0x14,0x15,0x17,0x18,0x19,0x1A,
- 0x1C,0x1D,0x1E,0x1F,0x21,0x22,0x23,0x24,
- 0x26,0x27,0x28,0x29,0x2B,0x2C,0x2D,0x2E
- };
- static const byte ciphertext_256[16] = {
- 0x08,0x0E,0x95,0x17,0xEB,0x16,0x77,0x71,
- 0x9A,0xCF,0x72,0x80,0x86,0x04,0x0A,0xE3
- };
+ unsigned char scratch[16];
- rijndael_setkey (&ctx, key, sizeof(key));
- rijndael_encrypt (&ctx, scratch, plaintext);
- if (memcmp (scratch, ciphertext, sizeof (ciphertext)))
- return "Rijndael-128 test encryption failed.";
+ /* The test vectors are from the AES supplied ones; more or less
+ randomly taken from ecb_tbl.txt (I=42,81,14) */
+ static const unsigned char plaintext_128[16] =
+ {
+ 0x01,0x4B,0xAF,0x22,0x78,0xA6,0x9D,0x33,
+ 0x1D,0x51,0x80,0x10,0x36,0x43,0xE9,0x9A
+ };
+ static const unsigned char key_128[16] =
+ {
+ 0xE8,0xE9,0xEA,0xEB,0xED,0xEE,0xEF,0xF0,
+ 0xF2,0xF3,0xF4,0xF5,0xF7,0xF8,0xF9,0xFA
+ };
+ static const unsigned char ciphertext_128[16] =
+ {
+ 0x67,0x43,0xC3,0xD1,0x51,0x9A,0xB4,0xF2,
+ 0xCD,0x9A,0x78,0xAB,0x09,0xA5,0x11,0xBD
+ };
+
+ rijndael_setkey (&ctx, key_128, sizeof (key_128));
+ rijndael_encrypt (&ctx, scratch, plaintext_128);
+ if (memcmp (scratch, ciphertext_128, sizeof (ciphertext_128)))
+ return "AES-128 test encryption failed.";
rijndael_decrypt (&ctx, scratch, scratch);
- if (memcmp (scratch, plaintext, sizeof (plaintext)))
- return "Rijndael-128 test decryption failed.";
+ if (memcmp (scratch, plaintext_128, sizeof (plaintext_128)))
+ return "AES-128 test decryption failed.";
+
+ return NULL;
+}
+/* Run the self-tests for AES 192. Returns NULL on success. */
+static const char*
+selftest_basic_192 (void)
+{
+ RIJNDAEL_context ctx;
+ unsigned char scratch[16];
+
+ static unsigned char plaintext_192[16] =
+ {
+ 0x76,0x77,0x74,0x75,0xF1,0xF2,0xF3,0xF4,
+ 0xF8,0xF9,0xE6,0xE7,0x77,0x70,0x71,0x72
+ };
+ static unsigned char key_192[24] =
+ {
+ 0x04,0x05,0x06,0x07,0x09,0x0A,0x0B,0x0C,
+ 0x0E,0x0F,0x10,0x11,0x13,0x14,0x15,0x16,
+ 0x18,0x19,0x1A,0x1B,0x1D,0x1E,0x1F,0x20
+ };
+ static const unsigned char ciphertext_192[16] =
+ {
+ 0x5D,0x1E,0xF2,0x0D,0xCE,0xD6,0xBC,0xBC,
+ 0x12,0x13,0x1A,0xC7,0xC5,0x47,0x88,0xAA
+ };
+
rijndael_setkey (&ctx, key_192, sizeof(key_192));
rijndael_encrypt (&ctx, scratch, plaintext_192);
if (memcmp (scratch, ciphertext_192, sizeof (ciphertext_192)))
- return "Rijndael-192 test encryption failed.";
+ return "AES-192 test encryption failed.";
rijndael_decrypt (&ctx, scratch, scratch);
if (memcmp (scratch, plaintext_192, sizeof (plaintext_192)))
- return "Rijndael-192 test decryption failed.";
-
+ return "AES-192 test decryption failed.";
+
+ return NULL;
+}
+
+
+/* Run the self-tests for AES 256. Returns NULL on success. */
+static const char*
+selftest_basic_256 (void)
+{
+ RIJNDAEL_context ctx;
+ unsigned char scratch[16];
+
+ static unsigned char plaintext_256[16] =
+ {
+ 0x06,0x9A,0x00,0x7F,0xC7,0x6A,0x45,0x9F,
+ 0x98,0xBA,0xF9,0x17,0xFE,0xDF,0x95,0x21
+ };
+ static unsigned char key_256[32] =
+ {
+ 0x08,0x09,0x0A,0x0B,0x0D,0x0E,0x0F,0x10,
+ 0x12,0x13,0x14,0x15,0x17,0x18,0x19,0x1A,
+ 0x1C,0x1D,0x1E,0x1F,0x21,0x22,0x23,0x24,
+ 0x26,0x27,0x28,0x29,0x2B,0x2C,0x2D,0x2E
+ };
+ static const unsigned char ciphertext_256[16] =
+ {
+ 0x08,0x0E,0x95,0x17,0xEB,0x16,0x77,0x71,
+ 0x9A,0xCF,0x72,0x80,0x86,0x04,0x0A,0xE3
+ };
+
rijndael_setkey (&ctx, key_256, sizeof(key_256));
rijndael_encrypt (&ctx, scratch, plaintext_256);
if (memcmp (scratch, ciphertext_256, sizeof (ciphertext_256)))
- return "Rijndael-256 test encryption failed.";
+ return "AES-256 test encryption failed.";
rijndael_decrypt (&ctx, scratch, scratch);
if (memcmp (scratch, plaintext_256, sizeof (plaintext_256)))
- return "Rijndael-256 test decryption failed.";
+ return "AES-256 test decryption failed.";
return NULL;
}
+/* Run all the self-tests and return NULL on success. This function
+ is used for the on-the-fly self-tests. */
+static const char *
+selftest (void)
+{
+ const char *r;
+
+ if ( (r = selftest_basic_128 ())
+ || (r = selftest_basic_192 ())
+ || (r = selftest_basic_256 ()) )
+ return r;
+
+ return r;
+}
+
+
+/* SP800-38a.pdf for AES-128. */
+static const char *
+selftest_fips_128_38a (int requested_mode)
+{
+ struct tv
+ {
+ int mode;
+ const unsigned char key[16];
+ const unsigned char iv[16];
+ struct
+ {
+ const unsigned char input[16];
+ const unsigned char output[16];
+ } data[4];
+ } tv[2] =
+ {
+ {
+ GCRY_CIPHER_MODE_CFB, /* F.3.13, CFB128-AES128 */
+ { 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
+ 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c },
+ { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f },
+ {
+ { { 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
+ 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a },
+ { 0x3b, 0x3f, 0xd9, 0x2e, 0xb7, 0x2d, 0xad, 0x20,
+ 0x33, 0x34, 0x49, 0xf8, 0xe8, 0x3c, 0xfb, 0x4a } },
+
+ { { 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c,
+ 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51 },
+ { 0xc8, 0xa6, 0x45, 0x37, 0xa0, 0xb3, 0xa9, 0x3f,
+ 0xcd, 0xe3, 0xcd, 0xad, 0x9f, 0x1c, 0xe5, 0x8b } },
+
+ { { 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11,
+ 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef },
+ { 0x26, 0x75, 0x1f, 0x67, 0xa3, 0xcb, 0xb1, 0x40,
+ 0xb1, 0x80, 0x8c, 0xf1, 0x87, 0xa4, 0xf4, 0xdf } },
+
+ { { 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17,
+ 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10 },
+ { 0xc0, 0x4b, 0x05, 0x35, 0x7c, 0x5d, 0x1c, 0x0e,
+ 0xea, 0xc4, 0xc6, 0x6f, 0x9f, 0xf7, 0xf2, 0xe6 } }
+ }
+ },
+ {
+ GCRY_CIPHER_MODE_OFB,
+ { 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
+ 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c },
+ { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f },
+ {
+ { { 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
+ 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a },
+ { 0x3b, 0x3f, 0xd9, 0x2e, 0xb7, 0x2d, 0xad, 0x20,
+ 0x33, 0x34, 0x49, 0xf8, 0xe8, 0x3c, 0xfb, 0x4a } },
+
+ { { 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c,
+ 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51 },
+ { 0x77, 0x89, 0x50, 0x8d, 0x16, 0x91, 0x8f, 0x03,
+ 0xf5, 0x3c, 0x52, 0xda, 0xc5, 0x4e, 0xd8, 0x25 } },
+
+ { { 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11,
+ 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef },
+ { 0x97, 0x40, 0x05, 0x1e, 0x9c, 0x5f, 0xec, 0xf6,
+ 0x43, 0x44, 0xf7, 0xa8, 0x22, 0x60, 0xed, 0xcc } },
+
+ { { 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17,
+ 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10 },
+ { 0x30, 0x4c, 0x65, 0x28, 0xf6, 0x59, 0xc7, 0x78,
+ 0x66, 0xa5, 0x10, 0xd9, 0xc1, 0xd6, 0xae, 0x5e } },
+ }
+ }
+ };
+ unsigned char scratch[16];
+ gpg_error_t err;
+ int tvi, idx;
+ gcry_cipher_hd_t hdenc = NULL;
+ gcry_cipher_hd_t hddec = NULL;
+
+#define Fail(a) do { \
+ _gcry_cipher_close (hdenc); \
+ _gcry_cipher_close (hddec); \
+ return a; \
+ } while (0)
+
+ assert (sizeof tv[0].data[0].input == sizeof scratch);
+ assert (sizeof tv[0].data[0].output == sizeof scratch);
+
+ for (tvi=0; tvi < DIM (tv); tvi++)
+ if (tv[tvi].mode == requested_mode)
+ break;
+ if (tvi == DIM (tv))
+ Fail ("no test data for this mode");
+
+ err = _gcry_cipher_open (&hdenc, GCRY_CIPHER_AES, tv[tvi].mode, 0);
+ if (err)
+ Fail ("open");
+ err = _gcry_cipher_open (&hddec, GCRY_CIPHER_AES, tv[tvi].mode, 0);
+ if (err)
+ Fail ("open");
+ err = _gcry_cipher_setkey (hdenc, tv[tvi].key, sizeof tv[tvi].key);
+ if (!err)
+ err = _gcry_cipher_setkey (hddec, tv[tvi].key, sizeof tv[tvi].key);
+ if (err)
+ Fail ("set key");
+ err = _gcry_cipher_setiv (hdenc, tv[tvi].iv, sizeof tv[tvi].iv);
+ if (!err)
+ err = _gcry_cipher_setiv (hddec, tv[tvi].iv, sizeof tv[tvi].iv);
+ if (err)
+ Fail ("set IV");
+ for (idx=0; idx < DIM (tv[tvi].data); idx++)
+ {
+ err = _gcry_cipher_encrypt (hdenc, scratch, sizeof scratch,
+ tv[tvi].data[idx].input,
+ sizeof tv[tvi].data[idx].input);
+ if (err)
+ Fail ("encrypt command");
+ if (memcmp (scratch, tv[tvi].data[idx].output, sizeof scratch))
+ Fail ("encrypt mismatch");
+ err = _gcry_cipher_decrypt (hddec, scratch, sizeof scratch,
+ tv[tvi].data[idx].output,
+ sizeof tv[tvi].data[idx].output);
+ if (err)
+ Fail ("decrypt command");
+ if (memcmp (scratch, tv[tvi].data[idx].input, sizeof scratch))
+ Fail ("decrypt mismatch");
+ }
+
+#undef Fail
+ _gcry_cipher_close (hdenc);
+ _gcry_cipher_close (hddec);
+ return NULL;
+}
+
+
+/* Complete selftest for AES-128 with all modes and driver code. */
+static gpg_err_code_t
+selftest_fips_128 (selftest_report_func_t report)
+{
+ const char *what;
+ const char *errtxt;
+
+ what = "low-level";
+ errtxt = selftest_basic_128 ();
+ if (errtxt)
+ goto failed;
+
+ what = "cfb";
+ errtxt = selftest_fips_128_38a (GCRY_CIPHER_MODE_CFB);
+ if (errtxt)
+ goto failed;
+
+ what = "ofb";
+ errtxt = selftest_fips_128_38a (GCRY_CIPHER_MODE_OFB);
+ if (errtxt)
+ goto failed;
+
+
+ return 0; /* Succeeded. */
+
+ failed:
+ if (report)
+ report ("cipher", GCRY_CIPHER_AES128, what, errtxt);
+ return GPG_ERR_SELFTEST_FAILED;
+}
+
+/* Complete selftest for AES-192 with all modes and driver code. */
+static gpg_err_code_t
+selftest_fips_192 (selftest_report_func_t report)
+{
+ const char *what;
+ const char *errtxt;
+
+ what = "low-level";
+ errtxt = selftest_basic_192 ();
+ if (errtxt)
+ goto failed;
+
+
+
+
+ return 0; /* Succeeded. */
+
+ failed:
+ if (report)
+ report ("cipher", GCRY_CIPHER_AES192, what, errtxt);
+ return GPG_ERR_SELFTEST_FAILED;
+}
+
+
+/* Complete selftest for AES-256 with all modes and driver code. */
+static gpg_err_code_t
+selftest_fips_256 (selftest_report_func_t report)
+{
+ const char *what;
+ const char *errtxt;
+
+ what = "low-level";
+ errtxt = selftest_basic_256 ();
+ if (errtxt)
+ goto failed;
+
+ return 0; /* Succeeded. */
+
+ failed:
+ if (report)
+ report ("cipher", GCRY_CIPHER_AES256, what, errtxt);
+ return GPG_ERR_SELFTEST_FAILED;
+}
+
+
+
+/* Run a full self-test for ALGO and return 0 on success. */
+static gpg_err_code_t
+run_selftests (int algo, selftest_report_func_t report)
+{
+ gpg_err_code_t ec;
+
+ switch (algo)
+ {
+ case GCRY_CIPHER_AES128:
+ ec = selftest_fips_128 (report);
+ break;
+ case GCRY_CIPHER_AES192:
+ ec = selftest_fips_192 (report);
+ break;
+ case GCRY_CIPHER_AES256:
+ ec = selftest_fips_256 (report);
+ break;
+ default:
+ ec = GPG_ERR_CIPHER_ALGO;
+ break;
+
+ }
+ return ec;
+}
+
+
static const char *rijndael_names[] =
@@ -875,6 +1170,10 @@ gcry_cipher_spec_t _gcry_cipher_spec_aes =
"AES", rijndael_names, rijndael_oids, 16, 128, sizeof (RIJNDAEL_context),
rijndael_setkey, rijndael_encrypt, rijndael_decrypt
};
+cipher_extra_spec_t _gcry_cipher_extraspec_aes =
+ {
+ run_selftests
+ };
static const char *rijndael192_names[] =
{
@@ -896,6 +1195,10 @@ gcry_cipher_spec_t _gcry_cipher_spec_aes192 =
"AES192", rijndael192_names, rijndael192_oids, 16, 192, sizeof (RIJNDAEL_context),
rijndael_setkey, rijndael_encrypt, rijndael_decrypt
};
+cipher_extra_spec_t _gcry_cipher_extraspec_aes192 =
+ {
+ run_selftests
+ };
static const char *rijndael256_names[] =
{
@@ -918,3 +1221,8 @@ gcry_cipher_spec_t _gcry_cipher_spec_aes256 =
sizeof (RIJNDAEL_context),
rijndael_setkey, rijndael_encrypt, rijndael_decrypt
};
+
+cipher_extra_spec_t _gcry_cipher_extraspec_aes256 =
+ {
+ run_selftests
+ };
diff --git a/cipher/rsa.c b/cipher/rsa.c
index 0971eaa4..370a8f77 100644
--- a/cipher/rsa.c
+++ b/cipher/rsa.c
@@ -1,6 +1,6 @@
/* rsa.c - RSA function
* Copyright (C) 1997, 1998, 1999 by Werner Koch (dd9jn)
- * Copyright (C) 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+ * Copyright (C) 2000, 2001, 2002, 2003, 2008 Free Software Foundation, Inc.
*
* This file is part of Libgcrypt.
*
@@ -53,8 +53,8 @@ typedef struct
static void test_keys (RSA_secret_key *sk, unsigned nbits);
-static void generate (RSA_secret_key *sk,
- unsigned int nbits, unsigned long use_e);
+static gpg_err_code_t generate (RSA_secret_key *sk,
+ unsigned int nbits, unsigned long use_e);
static int check_secret_key (RSA_secret_key *sk);
static void public (gcry_mpi_t output, gcry_mpi_t input, RSA_public_key *skey);
static void secret (gcry_mpi_t output, gcry_mpi_t input, RSA_secret_key *skey);
@@ -111,7 +111,7 @@ check_exponent (void *arg, gcry_mpi_t a)
* > 2 Try starting at this value until a working exponent is found.
* Returns: 2 structures filled with all needed values
*/
-static void
+static gpg_err_code_t
generate (RSA_secret_key *sk, unsigned int nbits, unsigned long use_e)
{
gcry_mpi_t p, q; /* the two primes */
@@ -124,7 +124,10 @@ generate (RSA_secret_key *sk, unsigned int nbits, unsigned long use_e)
gcry_mpi_t g;
gcry_mpi_t f;
- /* make sure that nbits is even so that we generate p, q of equal size */
+ if ( nbits < 1024 && fips_mode ())
+ return GPG_ERR_INV_VALUE;
+
+ /* Make sure that nbits is even so that we generate p, q of equal size. */
if ( (nbits&1) )
nbits++;
@@ -232,6 +235,8 @@ generate (RSA_secret_key *sk, unsigned int nbits, unsigned long use_e)
/* now we can test our keys (this should never fail!) */
test_keys( sk, nbits - 64 );
+
+ return 0;
}
@@ -441,34 +446,37 @@ _gcry_rsa_generate (int algo, unsigned int nbits, unsigned long use_e,
gcry_mpi_t *skey, gcry_mpi_t **retfactors)
{
RSA_secret_key sk;
- gpg_err_code_t rc;
+ gpg_err_code_t ec;
int i;
(void)algo;
- generate (&sk, nbits, use_e);
- skey[0] = sk.n;
- skey[1] = sk.e;
- skey[2] = sk.d;
- skey[3] = sk.p;
- skey[4] = sk.q;
- skey[5] = sk.u;
-
- /* Make an empty list of factors. */
- *retfactors = gcry_calloc ( 1, sizeof **retfactors );
- if (!*retfactors)
+ ec = generate (&sk, nbits, use_e);
+ if (!ec)
{
- rc = gpg_err_code_from_errno (errno);
- for (i=0; i <= 5; i++)
+ skey[0] = sk.n;
+ skey[1] = sk.e;
+ skey[2] = sk.d;
+ skey[3] = sk.p;
+ skey[4] = sk.q;
+ skey[5] = sk.u;
+
+ /* Make an empty list of factors. */
+ *retfactors = gcry_calloc ( 1, sizeof **retfactors );
+ if (!*retfactors)
{
- gcry_mpi_release (skey[i]);
- skey[i] = NULL;
+ ec = gpg_err_code_from_syserror ();
+ for (i=0; i <= 5; i++)
+ {
+ gcry_mpi_release (skey[i]);
+ skey[i] = NULL;
+ }
}
+ else
+ ec = 0;
}
- else
- rc = 0;
- return rc;
+ return ec;
}
@@ -537,6 +545,9 @@ _gcry_rsa_decrypt (int algo, gcry_mpi_t *result, gcry_mpi_t *data,
y = gcry_mpi_snew (gcry_mpi_get_nbits (sk.n));
+ /* We use blinding by default to mitigate timing attacks which can
+ be practically mounted over the network as shown by Brumley and
+ Boney in 2003. */
if (! (flags & PUBKEY_FLAG_NO_BLINDING))
{
/* Initialize blinding. */
@@ -650,6 +661,58 @@ _gcry_rsa_get_nbits (int algo, gcry_mpi_t *pkey)
return mpi_get_nbits (pkey[0]);
}
+
+
+
+/*
+ Self-test section.
+ */
+
+
+static gpg_err_code_t
+selftests_rsa (selftest_report_func_t report)
+{
+ const char *what;
+ const char *errtxt;
+
+ what = "low-level";
+ errtxt = NULL; /*selftest ();*/
+ if (errtxt)
+ goto failed;
+
+ /* FIXME: need more tests. */
+
+ return 0; /* Succeeded. */
+
+ failed:
+ if (report)
+ report ("pubkey", GCRY_PK_RSA, what, errtxt);
+ return GPG_ERR_SELFTEST_FAILED;
+}
+
+
+/* Run a full self-test for ALGO and return 0 on success. */
+static gpg_err_code_t
+run_selftests (int algo, selftest_report_func_t report)
+{
+ gpg_err_code_t ec;
+
+ switch (algo)
+ {
+ case GCRY_PK_RSA:
+ ec = selftests_rsa (report);
+ break;
+ default:
+ ec = GPG_ERR_PUBKEY_ALGO;
+ break;
+
+ }
+ return ec;
+}
+
+
+
+
static const char *rsa_names[] =
{
"rsa",
@@ -671,3 +734,8 @@ gcry_pk_spec_t _gcry_pubkey_spec_rsa =
_gcry_rsa_verify,
_gcry_rsa_get_nbits,
};
+pk_extra_spec_t _gcry_pubkey_extraspec_rsa =
+ {
+ run_selftests
+ };
+
diff --git a/cipher/sha1.c b/cipher/sha1.c
index 2c1bda20..caf1c9a0 100644
--- a/cipher/sha1.c
+++ b/cipher/sha1.c
@@ -373,6 +373,56 @@ _gcry_sha1_hash_buffer (void *outbuf, const void *buffer, size_t length)
}
+
+/*
+ Self-test section.
+ */
+
+
+static gpg_err_code_t
+selftests_sha1 (selftest_report_func_t report)
+{
+ const char *what;
+ const char *errtxt;
+
+ what = "low-level";
+ errtxt = NULL; /*selftest ();*/
+ if (errtxt)
+ goto failed;
+
+ /* FIXME: need more tests. */
+
+ return 0; /* Succeeded. */
+
+ failed:
+ if (report)
+ report ("digest", GCRY_MD_SHA1, what, errtxt);
+ return GPG_ERR_SELFTEST_FAILED;
+}
+
+
+/* Run a full self-test for ALGO and return 0 on success. */
+static gpg_err_code_t
+run_selftests (int algo, selftest_report_func_t report)
+{
+ gpg_err_code_t ec;
+
+ switch (algo)
+ {
+ case GCRY_MD_SHA1:
+ ec = selftests_sha1 (report);
+ break;
+ default:
+ ec = GPG_ERR_DIGEST_ALGO;
+ break;
+
+ }
+ return ec;
+}
+
+
+
+
static unsigned char asn[15] = /* Object ID is 1.3.14.3.2.26 */
{ 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03,
0x02, 0x1a, 0x05, 0x00, 0x04, 0x14 };
@@ -398,3 +448,8 @@ gcry_md_spec_t _gcry_digest_spec_sha1 =
sha1_init, sha1_write, sha1_final, sha1_read,
sizeof (SHA1_CONTEXT)
};
+md_extra_spec_t _gcry_digest_extraspec_sha1 =
+ {
+ run_selftests
+ };
+
diff --git a/cipher/sha256.c b/cipher/sha256.c
index bc439c3d..b0a5629d 100644
--- a/cipher/sha256.c
+++ b/cipher/sha256.c
@@ -1,5 +1,5 @@
/* sha256.c - SHA256 hash function
- * Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+ * Copyright (C) 2003, 2006, 2008 Free Software Foundation, Inc.
*
* This file is part of Libgcrypt.
*
@@ -14,8 +14,7 @@
* 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 <http://www.gnu.org/licenses/>.
*/
@@ -313,6 +312,81 @@ sha256_read (void *context)
return hd->buf;
}
+
+
+/*
+ Self-test section.
+ */
+
+
+static gpg_err_code_t
+selftests_sha224 (selftest_report_func_t report)
+{
+ const char *what;
+ const char *errtxt;
+
+ what = "low-level";
+ errtxt = NULL; /*selftest ();*/
+ if (errtxt)
+ goto failed;
+
+ /* FIXME: need more tests. */
+
+ return 0; /* Succeeded. */
+
+ failed:
+ if (report)
+ report ("digest", GCRY_MD_SHA224, what, errtxt);
+ return GPG_ERR_SELFTEST_FAILED;
+}
+
+static gpg_err_code_t
+selftests_sha256 (selftest_report_func_t report)
+{
+ const char *what;
+ const char *errtxt;
+
+ what = "low-level";
+ errtxt = NULL; /*selftest ();*/
+ if (errtxt)
+ goto failed;
+
+ /* FIXME: need more tests. */
+
+ return 0; /* Succeeded. */
+
+ failed:
+ if (report)
+ report ("digest", GCRY_MD_SHA256, what, errtxt);
+ return GPG_ERR_SELFTEST_FAILED;
+}
+
+
+/* Run a full self-test for ALGO and return 0 on success. */
+static gpg_err_code_t
+run_selftests (int algo, selftest_report_func_t report)
+{
+ gpg_err_code_t ec;
+
+ switch (algo)
+ {
+ case GCRY_MD_SHA224:
+ ec = selftests_sha224 (report);
+ break;
+ case GCRY_MD_SHA256:
+ ec = selftests_sha256 (report);
+ break;
+ default:
+ ec = GPG_ERR_DIGEST_ALGO;
+ break;
+
+ }
+ return ec;
+}
+
+
+
+
static byte asn224[19] = /* Object ID is 2.16.840.1.101.3.4.2.4 */
{ 0x30, 0x2D, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48,
0x01, 0x65, 0x03, 0x04, 0x02, 0x04, 0x05, 0x00, 0x04,
@@ -347,6 +421,10 @@ gcry_md_spec_t _gcry_digest_spec_sha224 =
sha224_init, sha256_write, sha256_final, sha256_read,
sizeof (SHA256_CONTEXT)
};
+md_extra_spec_t _gcry_digest_extraspec_sha224 =
+ {
+ run_selftests
+ };
gcry_md_spec_t _gcry_digest_spec_sha256 =
{
@@ -354,3 +432,7 @@ gcry_md_spec_t _gcry_digest_spec_sha256 =
sha256_init, sha256_write, sha256_final, sha256_read,
sizeof (SHA256_CONTEXT)
};
+md_extra_spec_t _gcry_digest_extraspec_sha256 =
+ {
+ run_selftests
+ };
diff --git a/cipher/sha512.c b/cipher/sha512.c
index b70b175b..e1ba517b 100644
--- a/cipher/sha512.c
+++ b/cipher/sha512.c
@@ -1,7 +1,5 @@
/* sha512.c - SHA384 and SHA512 hash functions
- * Copyright (C) 2003 Free Software Foundation, Inc.
- *
- * Please see below for more legal information!
+ * Copyright (C) 2003, 2008 Free Software Foundation, Inc.
*
* This file is part of Libgcrypt.
*
@@ -15,9 +13,8 @@
* 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
+ * 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/>.
*/
@@ -362,12 +359,87 @@ sha512_read (void *context)
return hd->buf;
}
-static byte sha512_asn[] = /* Object ID is 2.16.840.1.101.3.4.2.3 */
+
+
+/*
+ Self-test section.
+ */
+
+
+static gpg_err_code_t
+selftests_sha384 (selftest_report_func_t report)
+{
+ const char *what;
+ const char *errtxt;
+
+ what = "low-level";
+ errtxt = NULL; /*selftest ();*/
+ if (errtxt)
+ goto failed;
+
+ /* FIXME: need more tests. */
+
+ return 0; /* Succeeded. */
+
+ failed:
+ if (report)
+ report ("digest", GCRY_MD_SHA384, what, errtxt);
+ return GPG_ERR_SELFTEST_FAILED;
+}
+
+static gpg_err_code_t
+selftests_sha512 (selftest_report_func_t report)
{
- 0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
- 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05,
- 0x00, 0x04, 0x40
-};
+ const char *what;
+ const char *errtxt;
+
+ what = "low-level";
+ errtxt = NULL; /*selftest ();*/
+ if (errtxt)
+ goto failed;
+
+ /* FIXME: need more tests. */
+
+ return 0; /* Succeeded. */
+
+ failed:
+ if (report)
+ report ("digest", GCRY_MD_SHA512, what, errtxt);
+ return GPG_ERR_SELFTEST_FAILED;
+}
+
+
+/* Run a full self-test for ALGO and return 0 on success. */
+static gpg_err_code_t
+run_selftests (int algo, selftest_report_func_t report)
+{
+ gpg_err_code_t ec;
+
+ switch (algo)
+ {
+ case GCRY_MD_SHA384:
+ ec = selftests_sha384 (report);
+ break;
+ case GCRY_MD_SHA512:
+ ec = selftests_sha512 (report);
+ break;
+ default:
+ ec = GPG_ERR_DIGEST_ALGO;
+ break;
+
+ }
+ return ec;
+}
+
+
+
+
+static byte sha512_asn[] = /* Object ID is 2.16.840.1.101.3.4.2.3 */
+ {
+ 0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
+ 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05,
+ 0x00, 0x04, 0x40
+ };
static gcry_md_oid_spec_t oid_spec_sha512[] =
{
@@ -379,18 +451,23 @@ static gcry_md_oid_spec_t oid_spec_sha512[] =
{ NULL }
};
-gcry_md_spec_t _gcry_digest_spec_sha512 = {
- "SHA512", sha512_asn, DIM (sha512_asn), oid_spec_sha512, 64,
- sha512_init, sha512_write, sha512_final, sha512_read,
- sizeof (SHA512_CONTEXT),
-};
+gcry_md_spec_t _gcry_digest_spec_sha512 =
+ {
+ "SHA512", sha512_asn, DIM (sha512_asn), oid_spec_sha512, 64,
+ sha512_init, sha512_write, sha512_final, sha512_read,
+ sizeof (SHA512_CONTEXT),
+ };
+md_extra_spec_t _gcry_digest_extraspec_sha512 =
+ {
+ run_selftests
+ };
static byte sha384_asn[] = /* Object ID is 2.16.840.1.101.3.4.2.2 */
-{
- 0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
- 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05,
- 0x00, 0x04, 0x30
-};
+ {
+ 0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
+ 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05,
+ 0x00, 0x04, 0x30
+ };
static gcry_md_oid_spec_t oid_spec_sha384[] =
{
@@ -402,8 +479,13 @@ static gcry_md_oid_spec_t oid_spec_sha384[] =
{ NULL },
};
-gcry_md_spec_t _gcry_digest_spec_sha384 = {
- "SHA384", sha384_asn, DIM (sha384_asn), oid_spec_sha384, 48,
- sha384_init, sha512_write, sha512_final, sha512_read,
- sizeof (SHA512_CONTEXT),
-};
+gcry_md_spec_t _gcry_digest_spec_sha384 =
+ {
+ "SHA384", sha384_asn, DIM (sha384_asn), oid_spec_sha384, 48,
+ sha384_init, sha512_write, sha512_final, sha512_read,
+ sizeof (SHA512_CONTEXT),
+ };
+md_extra_spec_t _gcry_digest_extraspec_sha384 =
+ {
+ run_selftests
+ };
diff --git a/configure.ac b/configure.ac
index c81903f1..04d91842 100644
--- a/configure.ac
+++ b/configure.ac
@@ -86,6 +86,10 @@ AH_BOTTOM([
properly prefixed. */
#define CAMELLIA_EXT_SYM_PREFIX _gcry_
+/* This error code is only available with gpg-error 1.7. Thus
+ we define it here with the usual gcry prefix. */
+#define GCRY_GPG_ERR_NOT_OPERATIONAL 176
+
#endif /*_GCRYPT_CONFIG_H_INCLUDED*/
])
diff --git a/doc/ChangeLog b/doc/ChangeLog
index b9cb198d..193ac2ea 100644
--- a/doc/ChangeLog
+++ b/doc/ChangeLog
@@ -1,3 +1,21 @@
+2008-08-18 Werner Koch <wk@g10code.com>
+
+ * gcrypt.texi (Top): Remove the detailmenu.
+ (Public Key Cryptographi (II)): Move into a section of the PK
+ interface description.
+ (Hashing): Move after the encryption chapters.
+
+2008-08-15 Werner Koch <wk@g10code.com>
+
+ * gcrypt.texi (Controlling the library): Remove
+ GCRYCTL_DUMP_CONFIG because it is not implemented.
+ (Initializing the library): Describe initialization steps with
+ regard to secure memory.
+
+ * gcrypt.texi (Working with cipher handles): Adjust for
+ implementation changes of gcry_cipher_setkey, gcry_cipher_setiv and
+ gcry_cipher_setctr.
+
2008-01-04 Werner Koch <wk@g10code.com>
* gcrypt.texi (Controlling the library): Add remark that the
diff --git a/doc/Makefile.am b/doc/Makefile.am
index 0589891c..d715e630 100644
--- a/doc/Makefile.am
+++ b/doc/Makefile.am
@@ -17,12 +17,32 @@
# License along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
-EXTRA_DIST = README.apichanges HACKING
+EXTRA_DIST = README.apichanges HACKING \
+ libgcrypt-modules.eps \
+ libgcrypt-modules.png \
+ libgcrypt-modules.pdf
DISTCLEANFILES = gcrypt.cps
+BUILT_SOURCES = libgcrypt-modules.eps \
+ libgcrypt-modules.png \
+ libgcrypt-modules.pdf
+
info_TEXINFOS = gcrypt.texi
-gcrypt_TEXINFOS = lgpl.texi gpl.texi
+gcrypt_TEXINFOS = lgpl.texi gpl.texi libgcrypt-modules.fig
+
+
+.fig.png:
+ fig2dev -L png `test -f '$<' || echo '$(srcdir)/'`$< $@
+
+.fig.jpg:
+ fig2dev -L jpg `test -f '$<' || echo '$(srcdir)/'`$< $@
+
+.fig.eps:
+ fig2dev -L eps `test -f '$<' || echo '$(srcdir)/'`$< $@
+
+.fig.pdf:
+ fig2dev -L pdf `test -f '$<' || echo '$(srcdir)/'`$< $@
online: gcrypt.html gcrypt.pdf gcrypt.info
diff --git a/doc/gcrypt.texi b/doc/gcrypt.texi
index b6d36214..d281ae84 100644
--- a/doc/gcrypt.texi
+++ b/doc/gcrypt.texi
@@ -12,7 +12,7 @@ This manual is for Libgcrypt
(version @value{VERSION}, @value{UPDATED}),
which is GNU's library of cryptographic building blocks.
-Copyright @copyright{} 2000, 2002, 2003, 2004, 2006, 2007 Free Software Foundation, Inc.
+Copyright @copyright{} 2000, 2002, 2003, 2004, 2006, 2007, 2008 Free Software Foundation, Inc.
@quotation
Permission is granted to copy, distribute and/or modify this document
@@ -66,17 +66,18 @@ section entitled ``Copying''.
* Generalities:: General library functions and data types.
* Handler Functions:: Working with handler functions.
* Symmetric cryptography:: How to use symmetric cryptography.
+* Public Key cryptography:: How to use public key cryptography.
* Hashing:: How to use hashing.
-* Public Key cryptography (I):: How to use public key cryptography.
-* Public Key cryptography (II):: How to use public key cryptography, alternatively.
* Random Numbers:: How to work with random numbers.
* S-expressions:: How to manage S-expressions.
* MPI library:: How to work with multi-precision-integers.
* Prime numbers:: How to use the Prime number related functions.
* Utilities:: Utility functions.
+* Architecture:: How Libgcrypt works internally.
Appendices
+* FIPS Restrictions:: Restrictions in FIPS mode.
* Library Copying:: The GNU Lesser General Public License
says how you can copy and share Libgcrypt.
* Copying:: The GNU General Public License says how you
@@ -87,86 +88,6 @@ Indices
* Concept Index:: Index of concepts and programs.
* Function and Data Index:: Index of functions, variables and data types.
-@detailmenu
- --- The Detailed Node Listing ---
-
-Introduction
-* Getting Started:: How to use this manual.
-* Features:: A glance at Libgcrypt's features.
-* Overview:: Overview about the library.
-
-Preparation
-* Header:: What header file you need to include.
-* Building sources:: How to build sources using the library.
-* Building sources using Automake:: How to build sources with the help of Automake.
-* Initializing the library:: How to initialize the library.
-* Multi-Threading:: How Libgcrypt can be used in a MT environment.
-
-Generalities
-* Controlling the library:: Controlling Libgcrypt's behavior.
-* Modules:: Description of extension modules.
-* Error Handling:: Error codes and such.
-
-Handler Functions
-* Progress handler:: Using a progress handler function.
-* Allocation handler:: Using special memory allocation functions.
-* Error handler:: Using error handler functions.
-* Logging handler:: Using a special logging function.
-
-Symmetric cryptography
-* Available ciphers:: List of ciphers supported by the library.
-* Cipher modules:: How to work with cipher modules.
-* Available cipher modes:: List of cipher modes supported by the library.
-* Working with cipher handles:: How to perform operations related to cipher handles.
-* General cipher functions:: General cipher functions independent of cipher handles.
-
-Hashing
-* Available hash algorithms:: List of hash algorithms supported by the library.
-* Hash algorithm modules:: How to work with hash algorithm modules.
-* Working with hash algorithms:: List of functions related to hashing.
-
-Public Key cryptography (I)
-* Used S-expressions:: Introduction into the used S-expression.
-* Available algorithms:: Algorithms supported by the library.
-* Public key modules:: How to work with public key modules.
-* Cryptographic Functions:: Functions for performing the cryptographic actions.
-* General public-key related Functions:: General functions, not implementing any cryptography.
-
-Public Key cryptography (II)
-* Available asymmetric algorithms:: List of algorithms supported by the library.
-* Working with sets of data:: How to work with sets of data.
-* Working with handles:: How to use handles.
-* Working with keys:: How to work with keys.
-* Using cryptographic functions:: How to perform cryptographic operations.
-* Handle-independent functions:: General functions independent of handles.
-
-Random Numbers
-* Quality of random numbers:: Libgcrypt uses different quality levels.
-* Retrieving random numbers:: How to retrieve random numbers.
-
-S-expressions
-* Data types for S-expressions:: Data types related with S-expressions.
-* Working with S-expressions:: How to work with S-expressions.
-
-MPI library
-* Data types:: MPI related data types.
-* Basic functions:: First steps with MPI numbers.
-* MPI formats:: External representation of MPIs.
-* Calculations:: Performing MPI calculations.
-* Comparisons:: How to compare MPI values.
-* Bit manipulations:: How to access single bits of MPI values.
-* Miscellaneous:: Miscellaneous MPI functions.
-
-Prime numbers
-* Generation:: Generation of new prime numbers.
-* Checking:: Checking if a given number is prime.
-
-Utilities
-* Memory allocation:: Functions related with memory allocation.
-
-@end detailmenu
-
-
@end menu
@ifhtml
@@ -220,10 +141,9 @@ a similar job.
@item It's Free Software
Anybody can use, modify, and redistribute it under the terms of the GNU
Lesser General Public License (@pxref{Library Copying}). Note, that
-some parts (which are not needed on a GNU or GNU/Linux system) are
-subject to the terms of the GNU General Public License
-(@pxref{Copying}); please see the README file of the distribution for of
-list of these parts.
+some parts (which are in general not needed by applications) are subject
+to the terms of the GNU General Public License (@pxref{Copying}); please
+see the README file of the distribution for of list of these parts.
@item It encapsulates the low level cryptography
Libgcrypt provides a high level interface to cryptographic
@@ -264,6 +184,7 @@ of the library are verified.
* Building sources using Automake:: How to build sources with the help of Automake.
* Initializing the library:: How to initialize the library.
* Multi-Threading:: How Libgcrypt can be used in a MT environment.
+* FIPS mode:: How to enable the FIPS mode.
@end menu
@@ -295,10 +216,10 @@ Certain parts of gcrypt.h may be excluded by defining these macros:
Do not define the shorthand macros @code{mpi_*} for @code{gcry_mpi_*}.
@item GCRYPT_NO_DEPRECATED
-Do not include defintions for deprecated features.
+Do not include defintions for deprecated features. This is useful to
+make sure that no deprecated features are used.
@end table
-
@node Building sources
@section Building sources
@@ -394,10 +315,10 @@ after program startup.
@deftypefun const char *gcry_check_version (const char *@var{req_version})
-The function @code{gcry_check_version} initializes the sub-systems
-used by Libgcrypt and must be invoked before any other function in the
-library, with the exception of the @code{GCRYCTL_SET_THREAD_CBS}
-command (called via the @code{gcry_control} function), see
+The function @code{gcry_check_version} initializes some subsystems used
+by Libgcrypt and must be invoked before any other function in the
+library, with the exception of the @code{GCRYCTL_SET_THREAD_CBS} command
+(called via the @code{gcry_control} function).
@xref{Multi-Threading}.
Furthermore, this function returns the version number of the library.
@@ -406,6 +327,94 @@ required version number @var{req_version}, if this value is not a null
pointer.
@end deftypefun
+Libgcrypt uses a concept known as secure memory, which is a region of
+memory set aside for storing sensitive data. Because such memory is a
+scare resource, it needs to be setup in advanced to a fixed size.
+Further, most operating systems have special requirements on how that
+secure memory can be used. For example, it might be required to install
+an application as ``setuid(root)'' to allow allocating such memory.
+Libgcrypt requires a sequence of initialization steps to make sure that
+this works correctly. The following examples show the necessary steps.
+
+If you don't have a need for secure memory, for example if your
+application does not use secret keys or other confidential data or it
+runs in a controlled environment where key material floating around in
+memory is not a problem, you should initialize Libgcrypt this way:
+
+@example
+ /* Version check should be the very first call because it
+ makes sure that important subsystems are intialized. */
+ if (!gcry_check_version (GCRYPT_VERSION))
+ @{
+ fputs ("libgcrypt version mismatch\n", stderr);
+ exit (2);
+ @}
+
+ /* Disable secure memory. */
+ gcry_control (GCRYCTL_DISABLE_SECMEM, 0);
+
+ /* ... If required, other initialization goes here. */
+
+ /* Tell Libgcrypt that initialization has completed. */
+ gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
+@end example
+
+
+If you have to protect your keys or other information in memory against
+being swapped out to disk and to enable an automatic overwrite of used
+and freed memory, you need to initialize Libgcrypt this way:
+
+@example
+ /* Version check should be the very first call because it
+ makes sure that important subsystems are intialized. */
+ if (!gcry_check_version (GCRYPT_VERSION))
+ @{
+ fputs ("libgcrypt version mismatch\n", stderr);
+ exit (2);
+ @}
+
+@anchor{sample-use-suspend-secmem}
+ /* We don't want to see any warnings, e.g. because we have not yet
+ parsed program options which might be used to suppress such
+ warnings. */
+ gcry_control (GCRYCTL_SUSPEND_SECMEM_WARN);
+
+ /* ... If required, other initialization goes here. Note that the
+ process might still be running with increased privileges and that
+ the secure memory has not been intialized. */
+
+ /* Allocate a pool of 16k secure memory. This make the secure memory
+ available and also drops privileges where needed. */
+ gcry_control (GCRYCTL_INIT_SECMEM, 16384, 0);
+
+@anchor{sample-use-resume-secmem}
+ /* It is now okay to let Libgcrypt complain when there was/is a problem
+ with the secure memory. */
+ gcry_control (GCRYCTL_RESUME_SECMEM_WARN);
+
+ /* ... If required, other initialization goes here. */
+
+ /* Tell Libgcrypt that initialization has completed. */
+ gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
+@end example
+
+It is important that these initialization steps are not done by a
+library but by the actual application. A library using Libgcrypt might
+want to check for finished initialization using:
+
+@example
+ if (!gcry_control (GCRYCTL_INITIALIZATION_FINISHED_P))
+ @{
+ fputs ("libgcrypt has not been initialized\n", stderr);
+ abort ();
+ @}
+@end example
+
+Instead of terminating the process, the library may instead print a
+warning and try to initialize Libgcrypt itself. See also the section on
+multi-threading below for more pitfalls.
+
+
@node Multi-Threading
@section Multi-Threading
@@ -500,6 +509,45 @@ Note that these macros need to be terminated with a semicolon. Keep
in mind that these are convenient macros for C programmers; C++
programmers might have to wrap these macros in an ``extern C'' body.
+
+
+@node FIPS mode
+@section FIPS Mode
+
+Libgcrypt may be used in a FIPS 140 mode. Note, that this does not
+necessary mean that Libcgrypt is n appoved FIPS 140-2 module. Check the
+NIST database at @url{http://csrc.nist.gov/groups/STM/cmvp/} to see what
+versions of Libgcrypt are approved.
+
+Because FIPS 140 has certain restrictions on the use of cryptography
+which are not always wanted, Libgcrypt needs to be put into FIPS mode
+explicitly. Three alternative mechanisms are provided to switch
+Libgcrypt into this mode:
+
+@itemize
+@item
+If the file @file{/proc/fips140} exists and contains the string value
+@code{1}, Libgcrypt is put into FIPS mode at initialization time.
+Obviously this works only on systems with a @code{proc} file system
+(ie.e GNU/Linux).
+
+@item
+If the file @file{/etc/gcrypt/fips140.force} exists, Libgcrypt is put
+into FIPS mode at initialization time. Note that this filename is
+hardwired and does not depend on any configuration options.
+
+@item
+If the applications requests FIPS mode using the control command
+@code{GCRYCTL_FORCE_FIPS_MODE}. This may be done at any time.
+
+@end itemize
+
+Note that once Libgcrypt has been put into FIPS mode, it is not possible
+to switch back to standard mode without terminating the process first.
+
+
+
+
@c **********************************************************
@c ******************* General ****************************
@c **********************************************************
@@ -541,49 +589,72 @@ your application.
This option can only be used at initialization time.
-@item GCRYCTL_DUMP_RANDOM_STATS
-This command dumps PRNG related statistics to the librarys logging
-stream.
+@item GCRYCTL_DUMP_RANDOM_STATS; Arguments: none
+This command dumps randum number generator related statistics to the
+library's logging stream.
-@item GCRYCTL_DUMP_MEMORY_STATS
-This command dumps memory manamgent related statistics to the librarys
+@item GCRYCTL_DUMP_MEMORY_STATS; Arguments: none
+This command dumps memory managment related statistics to the library's
logging stream.
-@item GCRYCTL_DUMP_SECMEM_STATS
+@item GCRYCTL_DUMP_SECMEM_STATS; Arguments: none
This command dumps secure memory manamgent related statistics to the
-librarys logging stream.
-
-@item GCRYCTL_DUMP_CONFIG; Arguments: none
-This command dumps information pertaining to the configuration of
-libgcrypt to the logging stream. It may be used before the
-intialization has been finished but not before a gcry_version_check.
+library's logging stream.
-@item GCRYCTL_DROP_PRIVS
+@item GCRYCTL_DROP_PRIVS; Arguments: none
This command disables the use of secure memory and drops the priviliges
-of the current process. FIXME.
+of the current process. This command has not much use; the suggested way
+to disable secure memory is to use @code{GCRYCTL_DISABLE_SECMEM} right
+after initialization.
-@item GCRYCTL_DISABLE_SECMEM
+@item GCRYCTL_DISABLE_SECMEM; Arguments: none
This command disables the use of secure memory.
Many applications do not require secure memory, so they should disable
it right away. There won't be a problem if not disabling it unless one
makes use of a feature which requires secure memory - in that case the
-process will abort because the secmem is not initialized.
-
-
-@item GCRYCTL_INIT_SECMEM
-@item GCRYCTL_TERM_SECMEM
-@item GCRYCTL_DISABLE_SECMEM_WARN
-@item GCRYCTL_SUSPEND_SECMEM_WARN
-@item GCRYCTL_RESUME_SECMEM_WARN
+process will abort because the secmem is not initialized. This command
+should be executed right after @code{gcry_check_version}.
+
+@item GCRYCTL_INIT_SECMEM; Arguments: int nbytes
+This command is used to allocate a pool of secure memory and thus
+enabling the use of secure memory. It also drops all extra privileges
+the process has (i.e. if it is run as setuid (root)). If the argument
+@var{nbytes} is 0, secure memory will be disabled. The minimum amount
+of secure memory allocated is currently 16384 bytes; you may thus use a
+value of 1 to request that default size.
+
+@item GCRYCTL_TERM_SECMEM; Arguments: none
+This command zeroises the secure memory and destroys the handler. The
+secure memory pool may not be used anymore after running this command.
+If the secure memory pool as already been destroyed, this command has no
+effect. Applications might want to run this command from their exit
+handler to make sure that the secure memory gets properly destroyed.
+This command is not necessary thread-safe but that should not be needed
+in cleanup code. It may be called from a signal handler.
+
+@item GCRYCTL_DISABLE_SECMEM_WARN; Arguments: none
+Disable warning messages about problems with the secure memory
+subsystem. This command should be run right after
+@code{gcry_check_version}.
+
+@item GCRYCTL_SUSPEND_SECMEM_WARN; Arguments: none
+Postpone warning messages from the secure memory subsystem.
+@xref{sample-use-suspend-secmem,,the initialization example}, on how to
+use it.
+
+@item GCRYCTL_RESUME_SECMEM_WARN; Arguments: none
+Resume warning messages from the secure memory subsystem.
+@xref{sample-use-resume-secmem,,the initialization example}, on how to
+use it.
@item GCRYCTL_USE_SECURE_RNDPOOL; Arguments: none
-
This command tells the PRNG to store random numbers in secure memory.
-FIXME: what about initialization time?
+This command should be run right after @code{gcry_check_version} and not
+later than the command GCRYCTL_INIT_SECMEM. Note that in FIPS mode the
+secure memory is always used.
@item GCRYCTL_SET_RANDOM_SEED_FILE; Arguments: const char *filename
-
This command specifies the file, which is to be used as seed file for
the PRNG. If the seed file is registered prior to initialization of the
PRNG, the seed file's content (if it exists and seems to be valid) is
@@ -593,7 +664,6 @@ file with the following command.
@item GCRYCTL_UPDATE_RANDOM_SEED_FILE; Arguments: none
-
Write out the PRNG pool's content into the registered seed file.
Multiple instances of the applications sharing the same random seed file
@@ -613,36 +683,86 @@ not an issue when using Linux (rndlinux driver), because this one
guarantees to read full 16 bytes from /dev/urandom and thus there is no
way for an attacker without kernel access to conrol these 16 bytes.
-@item GCRYCTL_SET_VERBOSITY
-
-
-@item GCRYCTL_SET_DEBUG_FLAGS
-@item GCRYCTL_CLEAR_DEBUG_FLAGS
-@item GCRYCTL_DISABLE_INTERNAL_LOCKING
-@item GCRYCTL_ANY_INITIALIZATION_P
-@item GCRYCTL_INITIALIZATION_FINISHED_P
-@item GCRYCTL_INITIALIZATION_FINISHED
+@item GCRYCTL_SET_VERBOSITY; Arguments: int level
+This command sets the verbosity of the logging. A level of 0 disables
+all extra logging whereas positive numbers enable more verbose logging.
+The level may be changed at any time but be aware that no memory
+syncronization is done so the effect of this command might not
+immediately show up in other threads.
+
+@item GCRYCTL_SET_DEBUG_FLAGS; Arguments: unsigned int flags
+Set the debug flag bits as given by the argument. Be aware that that no
+memory syncronization is done so the effect of this command might not
+immediately show up in other threads. The debug flags are not
+considered part of the API and thus may change without notice. As of
+now bit 0 enables debugging of cipher functions and bit 1 debugging of
+multi-precision-integers.
+
+@item GCRYCTL_CLEAR_DEBUG_FLAGS; Arguments: unsigned int flags
+Set the debug flag bits as given by the argument. Be aware that that no
+memory syncronization is done so the effect of this command might not
+immediately show up in other threads.
+
+@item GCRYCTL_DISABLE_INTERNAL_LOCKING; Arguments: none
+This command does nothing. It exists only for backward compatibility.
+
+@item GCRYCTL_ANY_INITIALIZATION_P; Arguments: none
+This command returns true if the library has been basically initialized.
+Such a basic initialization happens implicitly with many commands to get
+certain internal subsystems running. The common and suggested way to
+do this basic intialization is by calling gcry_check_version.
+
+@item GCRYCTL_INITIALIZATION_FINISHED; Arguments: none
+This command tells the libray that the application has finished the
+intialization.
+
+@item GCRYCTL_INITIALIZATION_FINISHED_P; Arguments: none
+This command returns true if the command@*
+GCRYCTL_INITIALIZATION_FINISHED has already been run.
@item GCRYCTL_SET_THREAD_CBS; Arguments: struct ath_ops *ath_ops
+This command registers a thread-callback structure.
+@xref{Multi-Threading}.
-This command registers a thread-callback structure. See section ``multi
-threading'' for more information on this command.
-
-@item GCRYCTL_FAST_POLL
-
+@item GCRYCTL_FAST_POLL; Arguments: none
Run a fast random poll.
-
@item GCRYCTL_SET_RNDEGD_SOCKET; Arguments: const char *filename
-
This command may be used to override the default name of the EGD socket
to connect to. It may be used only during initialization as it is not
thread safe. Changing the socket name again is not supported. The
function may return an error if the given filename is too long for a
local socket name.
-EGD is an alternative random gatherer, used only on a few systems.
-
+EGD is an alternative random gatherer, used only on systems lacking a
+proper random device.
+
+@item GCRYCTL_PRINT_CONFIG; Arguments: FILE *stream
+This command dumps information pertaining to the configuration of the
+library to the given stream. If NULL is given for @var{stream}, the log
+system is used. This command may be used before the intialization has
+been finished but not before a gcry_version_check.
+
+@item GCRYCTL_OPERATIONAL_P; Arguments: none
+This command returns true if the library is in an operational state.
+This information makes only sense in FIPS mode. In contrast to other
+functions, this is a pure test function and won't put the library into
+FIPS mode or change the internal state. This command may be used before
+the intialization has been finished but not before a gcry_version_check.
+
+@item GCRYCTL_FIPS_MODE_P; Arguments: none
+This command returns true if the library is in FIPS mode. Note, that
+this is no indication about the current state of the library. This
+command may be used before the intialization has been finished but not
+before a gcry_version_check.
+
+@item GCRYCTL_FORCE_FIPS_MODE; Arguments: none
+Running this command puts the library into FIPS mode. If the library
+has already been initialized or is already in FIPS mode, a selftest is
+triggered and thus the library will be put into operational state. This
+command may even be used before a call to gcry_check_version and that is
+actually the recommended way to let an application switch the library
+into FIPS mode.
@end table
@@ -855,7 +975,7 @@ value will be @code{0}. In this case the error source part is of
course @code{GPG_ERR_SOURCE_UNKNOWN}.
The list of error sources that might occur in applications using
-@acronym{Libgctypt} is:
+@acronym{Libgcrypt} is:
@table @code
@item GPG_ERR_SOURCE_UNKNOWN
@@ -980,6 +1100,16 @@ This value means a verification failed because the signature is bad.
This value means a verification failed because the public key is not
available.
+@item GPG_ERR_NOT_OPERATIONAL
+This value means that the library is not yet in state which allows to
+use this function. This error code is in particular returned if
+Libgcrypt is operated in FIPS mode and the internal state of the
+library does not yet or not anymore allow the use of a service.
+
+This error code is only available with newer libgpg-error versions, thus
+you might see ``invalid error code'' when passing this to
+@code{gpg_strerror}. The numeric value of this error code is 176.
+
@item GPG_ERR_USER_1
@item GPG_ERR_USER_2
@item ...
@@ -1486,7 +1616,7 @@ This function releases the context created by @code{gcry_cipher_open}.
In order to use a handle for performing cryptographic operations, a
`key' has to be set first:
-@deftypefun gcry_error_t gcry_cipher_setkey (gcry_cipher_hd_t @var{h}, void *@var{k}, size_t @var{l})
+@deftypefun gcry_error_t gcry_cipher_setkey (gcry_cipher_hd_t @var{h}, const void *@var{k}, size_t @var{l})
Set the key @var{k} used for encryption or decryption in the context
denoted by the handle @var{h}. The length @var{l} of the key @var{k}
@@ -1495,8 +1625,6 @@ be in the allowed range for algorithms with variable key size. The
function checks this and returns an error if there is a problem. A
caller should always check for an error.
-Note that this is currently implemented as a macro but may be changed
-to a function in the future.
@end deftypefun
Most crypto modes requires an initialization vector (IV), which
@@ -1504,23 +1632,21 @@ usually is a non-secret random string acting as a kind of salt value.
The CTR mode requires a counter, which is also similar to a salt
value. To set the IV or CTR, use these functions:
-@deftypefun gcry_error_t gcry_cipher_setiv (gcry_cipher_hd_t @var{h}, void *@var{k}, size_t @var{l})
+@deftypefun gcry_error_t gcry_cipher_setiv (gcry_cipher_hd_t @var{h}, const void *@var{k}, size_t @var{l})
Set the initialization vector used for encryption or decryption. The
vector is passed as the buffer @var{K} of length @var{l} and copied to
internal data structures. The function checks that the IV matches the
-requirement of the selected algorithm and mode. Note that this is
-implemented as a macro.
+requirement of the selected algorithm and mode.
@end deftypefun
-@deftypefun gcry_error_t gcry_cipher_setctr (gcry_cipher_hd_t @var{h}, void *@var{c}, size_t @var{l})
+@deftypefun gcry_error_t gcry_cipher_setctr (gcry_cipher_hd_t @var{h}, const void *@var{c}, size_t @var{l})
Set the counter vector used for encryption or decryption. The counter
is passed as the buffer @var{c} of length @var{l} and copied to
internal data structures. The function checks that the counter
matches the requirement of the selected algorithm (i.e., it must be
-the same size as the block size). Note that this is implemented as a
-macro.
+the same size as the block size).
@end deftypefun
@deftypefun gcry_error_t gcry_cipher_reset (gcry_cipher_hd_t @var{h})
@@ -1674,494 +1800,10 @@ with it.
@c **********************************************************
-@c ******************* Hash Functions *********************
-@c **********************************************************
-@node Hashing
-@chapter Hashing
-
-Libgcrypt provides an easy and consistent to use interface
-for hashing. Hashing is buffered and several hash algorithms can be
-updated at once. It is possible to calculate a MAC using the same
-routines. The programming model follows an open/process/close
-paradigm and is in that similar to other building blocks provided by
-Libgcrypt.
-
-For convenience reasons, a few cyclic redundancy check value operations
-are also supported.
-
-@menu
-* Available hash algorithms:: List of hash algorithms supported by the library.
-* Hash algorithm modules:: How to work with hash algorithm modules.
-* Working with hash algorithms:: List of functions related to hashing.
-@end menu
-
-@node Available hash algorithms
-@section Available hash algorithms
-
-@c begin table of hash algorithms
-@table @code
-@item GCRY_MD_NONE
-This is not a real algorithm but used by some functions as an error
-return value. This constant is guaranteed to have the value @code{0}.
-
-@item GCRY_MD_SHA1
-This is the SHA-1 algorithm which yields a message digest of 20 bytes.
-
-@item GCRY_MD_RMD160
-This is the 160 bit version of the RIPE message digest (RIPE-MD-160).
-Like SHA-1 it also yields a digest of 20 bytes.
-
-@item GCRY_MD_MD5
-This is the well known MD5 algorithm, which yields a message digest of
-16 bytes.
-
-@item GCRY_MD_MD4
-This is the MD4 algorithm, which yields a message digest of 16 bytes.
-
-@item GCRY_MD_MD2
-This is an reserved identifier for MD-2; there is no implementation yet.
-
-@item GCRY_MD_TIGER
-This is the TIGER/192 algorithm which yields a message digest of 24 bytes.
-
-@item GCRY_MD_HAVAL
-This is an reserved for the HAVAL algorithm with 5 passes and 160
-bit. It yields a message digest of 20 bytes. Note that there is no
-implementation yet available.
-
-@item GCRY_MD_SHA224
-This is the SHA-224 algorithm which yields a message digest of 28 bytes.
-See Change Notice 1 for FIPS 180-2 for the specification.
-
-@item GCRY_MD_SHA256
-This is the SHA-256 algorithm which yields a message digest of 32 bytes.
-See FIPS 180-2 for the specification.
-
-@item GCRY_MD_SHA384
-This is the SHA-384 algorithm which yields a message digest of 48 bytes.
-See FIPS 180-2 for the specification.
-
-@item GCRY_MD_SHA512
-This is the SHA-384 algorithm which yields a message digest of 64 bytes.
-See FIPS 180-2 for the specification.
-
-@item GCRY_MD_CRC32
-This is the ISO 3309 and ITU-T V.42 cyclic redundancy check. It
-yields an output of 4 bytes.
-
-@item GCRY_MD_CRC32_RFC1510
-This is the above cyclic redundancy check function, as modified by RFC
-1510. It yields an output of 4 bytes.
-
-@item GCRY_MD_CRC24_RFC2440
-This is the OpenPGP cyclic redundancy check function. It yields an
-output of 3 bytes.
-
-@item GCRY_MD_WHIRLPOOL
-This is the Whirlpool algorithm which yields a message digest of 64
-bytes.
-
-@end table
-@c end table of hash algorithms
-
-@node Hash algorithm modules
-@section Hash algorithm modules
-
-Libgcrypt makes it possible to load additional `message
-digest modules'; these digests can be used just like the message digest
-algorithms that are built into the library directly. For an
-introduction into extension modules, see @xref{Modules}.
-
-@deftp {Data type} gcry_md_spec_t
-This is the `module specification structure' needed for registering
-message digest modules, which has to be filled in by the user before
-it can be used to register a module. It contains the following
-members:
-
-@table @code
-@item const char *name
-The primary name of this algorithm.
-@item unsigned char *asnoid
-Array of bytes that form the ASN OID.
-@item int asnlen
-Length of bytes in `asnoid'.
-@item gcry_md_oid_spec_t *oids
-A list of OIDs that are to be associated with the algorithm. The
-list's last element must have it's `oid' member set to NULL. See
-below for an explanation of this type. See below for an explanation
-of this type.
-@item int mdlen
-Length of the message digest algorithm. See below for an explanation
-of this type.
-@item gcry_md_init_t init
-The function responsible for initializing a handle. See below for an
-explanation of this type.
-@item gcry_md_write_t write
-The function responsible for writing data into a message digest
-context. See below for an explanation of this type.
-@item gcry_md_final_t final
-The function responsible for `finalizing' a message digest context.
-See below for an explanation of this type.
-@item gcry_md_read_t read
-The function responsible for reading out a message digest result. See
-below for an explanation of this type.
-@item size_t contextsize
-The size of the algorithm-specific `context', that should be
-allocated for each handle.
-@end table
-@end deftp
-
-@deftp {Data type} gcry_md_oid_spec_t
-This type is used for associating a user-provided algorithm
-implementation with certain OIDs. It contains the following members:
-
-@table @code
-@item const char *oidstring
-Textual representation of the OID.
-@end table
-@end deftp
-
-@deftp {Data type} gcry_md_init_t
-Type for the `init' function, defined as: void (*gcry_md_init_t) (void
-*c)
-@end deftp
-
-@deftp {Data type} gcry_md_write_t
-Type for the `write' function, defined as: void (*gcry_md_write_t)
-(void *c, unsigned char *buf, size_t nbytes)
-@end deftp
-
-@deftp {Data type} gcry_md_final_t
-Type for the `final' function, defined as: void (*gcry_md_final_t)
-(void *c)
-@end deftp
-
-@deftp {Data type} gcry_md_read_t
-Type for the `read' function, defined as: unsigned char
-*(*gcry_md_read_t) (void *c)
-@end deftp
-
-@deftypefun gcry_error_t gcry_md_register (gcry_md_spec_t *@var{digest}, unsigned int *algorithm_id, gcry_module_t *@var{module})
-
-Register a new digest module whose specification can be found in
-@var{digest}. On success, a new algorithm ID is stored in
-@var{algorithm_id} and a pointer representing this module is stored
-in @var{module}.
-@end deftypefun
-
-@deftypefun void gcry_md_unregister (gcry_module_t @var{module})
-Unregister the digest identified by @var{module}, which must have been
-registered with gcry_md_register.
-@end deftypefun
-
-@deftypefun gcry_error_t gcry_md_list (int *@var{list}, int *@var{list_length})
-Get a list consisting of the IDs of the loaded message digest modules.
-If @var{list} is zero, write the number of loaded message digest
-modules to @var{list_length} and return. If @var{list} is non-zero,
-the first *@var{list_length} algorithm IDs are stored in @var{list},
-which must be of according size. In case there are less message
-digests modules than *@var{list_length}, *@var{list_length} is updated
-to the correct number.
-@end deftypefun
-
-@node Working with hash algorithms
-@section Working with hash algorithms
-
-To use most of these function it is necessary to create a context;
-this is done using:
-
-@deftypefun gcry_error_t gcry_md_open (gcry_md_hd_t *@var{hd}, int @var{algo}, unsigned int @var{flags})
-
-Create a message digest object for algorithm @var{algo}. @var{flags}
-may be given as an bitwise OR of constants described below. @var{algo}
-may be given as @code{0} if the algorithms to use are later set using
-@code{gcry_md_enable}. @var{hd} is guaranteed to either receive a valid
-handle or NULL.
-
-For a list of supported algorithms, see @xref{Available hash
-algorithms}.
-
-The flags allowed for @var{mode} are:
-
-@c begin table of hash flags
-@table @code
-@item GCRY_MD_FLAG_SECURE
-Allocate all buffers and the resulting digest in "secure memory". Use
-this is the hashed data is highly confidential.
-
-@item GCRY_MD_FLAG_HMAC
-Turn the algorithm into a HMAC message authentication algorithm. This
-only works if just one algorithm is enabled for the handle. Note that the function
-@code{gcry_md_setkey} must be used to set the MAC key. If you want CBC
-message authentication codes based on a cipher, see @xref{Working with
-cipher handles}.
-
-@end table
-@c begin table of hash flags
-
-You may use the function @code{gcry_md_is_enabled} to later check
-whether an algorithm has been enabled.
-
-@end deftypefun
-@c end function gcry_md_open
-
-If you want to calculate several hash algorithms at the same time, you
-have to use the following function right after the @code{gcry_md_open}:
-
-@deftypefun gcry_error_t gcry_md_enable (gcry_md_hd_t @var{h}, int @var{algo})
-
-Add the message digest algorithm @var{algo} to the digest object
-described by handle @var{h}. Duplicated enabling of algorithms is
-detected and ignored.
-@end deftypefun
-
-If the flag @code{GCRY_MD_FLAG_HMAC} was used, the key for the MAC must
-be set using the function:
-
-@deftypefun gcry_error_t gcry_md_setkey (gcry_md_hd_t @var{h}, const void *@var{key}, size_t @var{keylen})
-
-For use with the HMAC feature, set the MAC key to the value of @var{key}
-of length @var{keylen}.
-@end deftypefun
-
-
-After you are done with the hash calculation, you should release the
-resources by using:
-
-@deftypefun void gcry_md_close (gcry_md_hd_t @var{h})
-
-Release all resources of hash context @var{h}. @var{h} should not be
-used after a call to this function. A @code{NULL} passed as @var{h} is
-ignored.
-
-@end deftypefun
-
-Often you have to do several hash operations using the same algorithm.
-To avoid the overhead of creating and releasing context, a reset function
-is provided:
-
-@deftypefun void gcry_md_reset (gcry_md_hd_t @var{h})
-
-Reset the current context to its initial state. This is effectively
-identical to a close followed by an open and enabling all currently
-active algorithms.
-@end deftypefun
-
-
-Often it is necessary to start hashing some data and then continue to
-hash different data. To avoid hashing the same data several times (which
-might not even be possible if the data is received from a pipe), a
-snapshot of the current hash context can be taken and turned into a new
-context:
-
-@deftypefun gcry_error_t gcry_md_copy (gcry_md_hd_t *@var{handle_dst}, gcry_md_hd_t @var{handle_src})
-
-Create a new digest object as an exact copy of the object described by
-handle @var{handle_src} and store it in @var{handle_dst}. The context
-is not reset and you can continue to hash data using this context and
-independently using the original context.
-@end deftypefun
-
-
-Now that we have prepared everything to calculate hashes, it is time to
-see how it is actually done. There are two ways for this, one to
-update the hash with a block of memory and one macro to update the hash
-by just one character. Both methods can be used on the same hash context.
-
-@deftypefun void gcry_md_write (gcry_md_hd_t @var{h}, const void *@var{buffer}, size_t @var{length})
-
-Pass @var{length} bytes of the data in @var{buffer} to the digest object
-with handle @var{h} to update the digest values. This
-function should be used for large blocks of data.
-@end deftypefun
-
-@deftypefun void gcry_md_putc (gcry_md_hd_t @var{h}, int @var{c})
-
-Pass the byte in @var{c} to the digest object with handle @var{h} to
-update the digest value. This is an efficient function, implemented as
-a macro to buffer the data before an actual update.
-@end deftypefun
-
-The semantics of the hash functions do not provide for reading out intermediate
-message digests because the calculation must be finalized first. This
-finalization may for example include the number of bytes hashed in the
-message digest or some padding.
-
-@deftypefun void gcry_md_final (gcry_md_hd_t @var{h})
-
-Finalize the message digest calculation. This is not really needed
-because @code{gcry_md_read} does this implicitly. After this has been
-done no further updates (by means of @code{gcry_md_write} or
-@code{gcry_md_putc} are allowed. Only the first call to this function
-has an effect. It is implemented as a macro.
-@end deftypefun
-
-The way to read out the calculated message digest is by using the
-function:
-
-@deftypefun unsigned char *gcry_md_read (gcry_md_hd_t @var{h}, int @var{algo})
-
-@code{gcry_md_read} returns the message digest after finalizing the
-calculation. This function may be used as often as required but it will
-always return the same value for one handle. The returned message digest
-is allocated within the message context and therefore valid until the
-handle is released or reseted (using @code{gcry_md_close} or
-@code{gcry_md_reset}. @var{algo} may be given as 0 to return the only
-enabled message digest or it may specify one of the enabled algorithms.
-The function does return @code{NULL} if the requested algorithm has not
-been enabled.
-@end deftypefun
-
-Because it is often necessary to get the message digest of one block of
-memory, a fast convenience function is available for this task:
-
-@deftypefun void gcry_md_hash_buffer (int @var{algo}, void *@var{digest}, const void *@var{buffer}, size_t @var{length});
-
-@code{gcry_md_hash_buffer} is a shortcut function to calculate a message
-digest of a buffer. This function does not require a context and
-immediately returns the message digest of the @var{length} bytes at
-@var{buffer}. @var{digest} must be allocated by the caller, large
-enough to hold the message digest yielded by the the specified algorithm
-@var{algo}. This required size may be obtained by using the function
-@code{gcry_md_get_algo_dlen}.
-
-Note that this function will abort the process if an unavailable
-algorithm is used.
-@end deftypefun
-
-@c ***********************************
-@c ***** MD info functions ***********
-@c ***********************************
-
-Hash algorithms are identified by internal algorithm numbers (see
-@code{gcry_md_open} for a list). However, in most applications they are
-used by names, so two functions are available to map between string
-representations and hash algorithm identifiers.
-
-@deftypefun const char *gcry_md_algo_name (int @var{algo})
-
-Map the digest algorithm id @var{algo} to a string representation of the
-algorithm name. For unknown algorithms this function returns the
-string @code{"?"}. This function should not be used to test for the
-availability of an algorithm.
-@end deftypefun
-
-@deftypefun int gcry_md_map_name (const char *@var{name})
-
-Map the algorithm with @var{name} to a digest algorithm identifier.
-Returns 0 if the algorithm name is not known. Names representing
-@acronym{ASN.1} object identifiers are recognized if the @acronym{IETF}
-dotted format is used and the OID is prefixed with either "@code{oid.}"
-or "@code{OID.}". For a list of supported OIDs, see the source code at
-@file{cipher/md.c}. This function should not be used to test for the
-availability of an algorithm.
-@end deftypefun
-
-@deftypefun gcry_error_t gcry_md_get_asnoid (int @var{algo}, void *@var{buffer}, size_t *@var{length})
-
-Return an DER encoded ASN.1 OID for the algorithm @var{algo} in the
-user allocated @var{buffer}. @var{length} must point to variable with
-the available size of @var{buffer} and receives after return the
-actual size of the returned OID. The returned error code may be
-@code{GPG_ERR_TOO_SHORT} if the provided buffer is to short to receive
-the OID; it is possible to call the function with @code{NULL} for
-@var{buffer} to have it only return the required size. The function
-returns 0 on success.
-
-@end deftypefun
-
-
-To test whether an algorithm is actually available for use, the
-following macro should be used:
-
-@deftypefun gcry_error_t gcry_md_test_algo (int @var{algo})
-
-The macro returns 0 if the algorithm @var{algo} is available for use.
-@end deftypefun
-
-If the length of a message digest is not known, it can be retrieved
-using the following function:
-
-@deftypefun unsigned int gcry_md_get_algo_dlen (int @var{algo})
-
-Retrieve the length in bytes of the digest yielded by algorithm
-@var{algo}. This is often used prior to @code{gcry_md_read} to allocate
-sufficient memory for the digest.
-@end deftypefun
-
-
-In some situations it might be hard to remember the algorithm used for
-the ongoing hashing. The following function might be used to get that
-information:
-
-@deftypefun int gcry_md_get_algo (gcry_md_hd_t @var{h})
-
-Retrieve the algorithm used with the handle @var{h}. Note that this
-does not work reliable if more than one algorithm is enabled in @var{h}.
-@end deftypefun
-
-The following macro might also be useful:
-
-@deftypefun int gcry_md_is_secure (gcry_md_hd_t @var{h})
-
-This function returns true when the digest object @var{h} is allocated
-in "secure memory"; i.e. @var{h} was created with the
-@code{GCRY_MD_FLAG_SECURE}.
-@end deftypefun
-
-@deftypefun int gcry_md_is_enabled (gcry_md_hd_t @var{h}, int @var{algo})
-
-This function returns true when the algorithm @var{algo} has been
-enabled for the digest object @var{h}.
-@end deftypefun
-
-
-
-Tracking bugs related to hashing is often a cumbersome task which
-requires to add a lot of printf statements into the code.
-Libgcrypt provides an easy way to avoid this. The actual data
-hashed can be written to files on request.
-
-@deftypefun void gcry_md_debug (gcry_md_hd_t @var{h}, const char *@var{suffix})
-
-Enable debugging for the digest object with handle @var{h}. This
-creates create files named @file{dbgmd-<n>.<string>} while doing the
-actual hashing. @var{suffix} is the string part in the filename. The
-number is a counter incremented for each new hashing. The data in the
-file is the raw data as passed to @code{gcry_md_write} or
-@code{gcry_md_putc}. If @code{NULL} is used for @var{suffix}, the
-debugging is stopped and the file closed. This is only rarely required
-because @code{gcry_md_close} implicitly stops debugging.
-@end deftypefun
-
-
-The following two deprecated macros are used for debugging by old code.
-They shopuld be replaced by @code{gcry_md_debug}.
-
-@deftypefun void gcry_md_start_debug (gcry_md_hd_t @var{h}, const char *@var{suffix})
-
-Enable debugging for the digest object with handle @var{h}. This
-creates create files named @file{dbgmd-<n>.<string>} while doing the
-actual hashing. @var{suffix} is the string part in the filename. The
-number is a counter incremented for each new hashing. The data in the
-file is the raw data as passed to @code{gcry_md_write} or
-@code{gcry_md_putc}.
-@end deftypefun
-
-
-@deftypefun void gcry_md_stop_debug (gcry_md_hd_t @var{h}, int @var{reserved})
-
-Stop debugging on handle @var{h}. @var{reserved} should be specified as
-0. This function is usually not required because @code{gcry_md_close}
-does implicitly stop debugging.
-@end deftypefun
-
-
-@c **********************************************************
@c ******************* Public Key *************************
@c **********************************************************
-@node Public Key cryptography (I)
-@chapter Public Key cryptography (I)
+@node Public Key cryptography
+@chapter Public Key cryptography
Public key cryptography, also known as asymmetric cryptography, is an
easy way for key management and to provide digital signatures.
@@ -2175,6 +1817,8 @@ S-expressions.
* Public key modules:: How to work with public key modules.
* Cryptographic Functions:: Functions for performing the cryptographic actions.
* General public-key related Functions:: General functions, not implementing any cryptography.
+
+* AC Interface:: Alternative interface to public key functions.
@end menu
@node Available algorithms
@@ -2216,7 +1860,7 @@ italics
@end iftex
indicate parameters whereas lowercase words are literals.
-Note that all MPI (big integer) values are expected to be in
+Note that all MPI (multi-precision-integers) values are expected to be in
@code{GCRYMPI_FMT_USG} format. An easy way to create S-expressions is
by using @code{gcry_sexp_build} which allows to pass a string with
printf-like escapes to insert MPI values.
@@ -2833,7 +2477,7 @@ values for @var{what} are:
@table @code
@item GCRYCTL_TEST_ALGO:
-Return 0 when the specified algorithm is available for use.
+Return 0 if the specified algorithm is available for use.
@var{buffer} must be @code{NULL}, @var{nbytes} may be passed as
@code{NULL} or point to a variable with the required usage of the
algorithm. This may be 0 for "don't care" or the bit-wise OR of these
@@ -2846,6 +2490,9 @@ Algorithm is usable for signing.
Algorithm is usable for encryption.
@end table
+Unless you need to test for the allowed usage, it is in general better
+to use the macro gcry_pk_test_algo instead.
+
@item GCRYCTL_GET_ALGO_USAGE:
Return the usage flags for the given algorithm. An invalid algorithm
return 0. Disabled algorithms are ignored here because we
@@ -3011,10 +2658,10 @@ useful information.
@end deftypefun
@c end gcry_pk_genkey
-@node Public Key cryptography (II)
-@chapter Public Key cryptography (II)
+@node AC Interface
+@section Alternative Public Key Interface
-This chapter documents the alternative interface to asymmetric
+This section documents the alternative interface to asymmetric
cryptography (ac) that is not based on S-expressions, but on native C
data structures. As opposed to the pk interface described in the
former chapter, this one follows an open/use/close paradigm like other
@@ -3036,7 +2683,7 @@ forthcoming versions Libgcrypt.}
@end menu
@node Available asymmetric algorithms
-@section Available asymmetric algorithms
+@subsection Available asymmetric algorithms
Libgcrypt supports the RSA (Rivest-Shamir-Adleman)
algorithms as well as DSA (Digital Signature Algorithm) and Elgamal.
@@ -3059,7 +2706,7 @@ Elgamal, encryption only.
@end deftp
@node Working with sets of data
-@section Working with sets of data
+@subsection Working with sets of data
In the context of this interface the term `data set' refers to a list
of `named MPI values' that is used by functions performing
@@ -3164,7 +2811,7 @@ function fails.
@end deftypefun
@node Working with IO objects
-@section Working with IO objects
+@subsection Working with IO objects
Note: IO objects are currently only used in the context of message
encoding/decoding and encryption/signature schemes.
@@ -3239,7 +2886,7 @@ Opaque argument to provide to the callback function
@end table
@node Working with handles
-@section Working with handles
+@subsection Working with handles
In order to use an algorithm, an according handle must be created.
This is done using the following function:
@@ -3261,7 +2908,7 @@ Destroys the handle @var{handle}.
@end deftypefun
@node Working with keys
-@section Working with keys
+@subsection Working with keys
@deftp {Data type} gcry_ac_key_type_t
Defined constants:
@@ -3375,7 +3022,7 @@ Writes the 20 byte long key grip of the key @var{key} to
@end deftypefun
@node Using cryptographic functions
-@section Using cryptographic functions
+@subsection Using cryptographic functions
The following flags might be relevant:
@@ -3532,7 +3179,7 @@ public key @var{key} according to @var{scheme} and @var{opts}. If
@end deftypefun
@node Handle-independent functions
-@section Handle-independent functions
+@subsection Handle-independent functions
These two functions are deprecated; do not use them for new code.
@@ -3548,6 +3195,490 @@ contained in @var{name} in @var{algorithm}. Deprecated; use
@end deftypefun
@c **********************************************************
+@c ******************* Hash Functions *********************
+@c **********************************************************
+@node Hashing
+@chapter Hashing
+
+Libgcrypt provides an easy and consistent to use interface
+for hashing. Hashing is buffered and several hash algorithms can be
+updated at once. It is possible to calculate a MAC using the same
+routines. The programming model follows an open/process/close
+paradigm and is in that similar to other building blocks provided by
+Libgcrypt.
+
+For convenience reasons, a few cyclic redundancy check value operations
+are also supported.
+
+@menu
+* Available hash algorithms:: List of hash algorithms supported by the library.
+* Hash algorithm modules:: How to work with hash algorithm modules.
+* Working with hash algorithms:: List of functions related to hashing.
+@end menu
+
+@node Available hash algorithms
+@section Available hash algorithms
+
+@c begin table of hash algorithms
+@table @code
+@item GCRY_MD_NONE
+This is not a real algorithm but used by some functions as an error
+return value. This constant is guaranteed to have the value @code{0}.
+
+@item GCRY_MD_SHA1
+This is the SHA-1 algorithm which yields a message digest of 20 bytes.
+
+@item GCRY_MD_RMD160
+This is the 160 bit version of the RIPE message digest (RIPE-MD-160).
+Like SHA-1 it also yields a digest of 20 bytes.
+
+@item GCRY_MD_MD5
+This is the well known MD5 algorithm, which yields a message digest of
+16 bytes.
+
+@item GCRY_MD_MD4
+This is the MD4 algorithm, which yields a message digest of 16 bytes.
+
+@item GCRY_MD_MD2
+This is an reserved identifier for MD-2; there is no implementation yet.
+
+@item GCRY_MD_TIGER
+This is the TIGER/192 algorithm which yields a message digest of 24 bytes.
+
+@item GCRY_MD_HAVAL
+This is an reserved for the HAVAL algorithm with 5 passes and 160
+bit. It yields a message digest of 20 bytes. Note that there is no
+implementation yet available.
+
+@item GCRY_MD_SHA224
+This is the SHA-224 algorithm which yields a message digest of 28 bytes.
+See Change Notice 1 for FIPS 180-2 for the specification.
+
+@item GCRY_MD_SHA256
+This is the SHA-256 algorithm which yields a message digest of 32 bytes.
+See FIPS 180-2 for the specification.
+
+@item GCRY_MD_SHA384
+This is the SHA-384 algorithm which yields a message digest of 48 bytes.
+See FIPS 180-2 for the specification.
+
+@item GCRY_MD_SHA512
+This is the SHA-384 algorithm which yields a message digest of 64 bytes.
+See FIPS 180-2 for the specification.
+
+@item GCRY_MD_CRC32
+This is the ISO 3309 and ITU-T V.42 cyclic redundancy check. It
+yields an output of 4 bytes.
+
+@item GCRY_MD_CRC32_RFC1510
+This is the above cyclic redundancy check function, as modified by RFC
+1510. It yields an output of 4 bytes.
+
+@item GCRY_MD_CRC24_RFC2440
+This is the OpenPGP cyclic redundancy check function. It yields an
+output of 3 bytes.
+
+@item GCRY_MD_WHIRLPOOL
+This is the Whirlpool algorithm which yields a message digest of 64
+bytes.
+
+@end table
+@c end table of hash algorithms
+
+@node Hash algorithm modules
+@section Hash algorithm modules
+
+Libgcrypt makes it possible to load additional `message
+digest modules'; these digests can be used just like the message digest
+algorithms that are built into the library directly. For an
+introduction into extension modules, see @xref{Modules}.
+
+@deftp {Data type} gcry_md_spec_t
+This is the `module specification structure' needed for registering
+message digest modules, which has to be filled in by the user before
+it can be used to register a module. It contains the following
+members:
+
+@table @code
+@item const char *name
+The primary name of this algorithm.
+@item unsigned char *asnoid
+Array of bytes that form the ASN OID.
+@item int asnlen
+Length of bytes in `asnoid'.
+@item gcry_md_oid_spec_t *oids
+A list of OIDs that are to be associated with the algorithm. The
+list's last element must have it's `oid' member set to NULL. See
+below for an explanation of this type. See below for an explanation
+of this type.
+@item int mdlen
+Length of the message digest algorithm. See below for an explanation
+of this type.
+@item gcry_md_init_t init
+The function responsible for initializing a handle. See below for an
+explanation of this type.
+@item gcry_md_write_t write
+The function responsible for writing data into a message digest
+context. See below for an explanation of this type.
+@item gcry_md_final_t final
+The function responsible for `finalizing' a message digest context.
+See below for an explanation of this type.
+@item gcry_md_read_t read
+The function responsible for reading out a message digest result. See
+below for an explanation of this type.
+@item size_t contextsize
+The size of the algorithm-specific `context', that should be
+allocated for each handle.
+@end table
+@end deftp
+
+@deftp {Data type} gcry_md_oid_spec_t
+This type is used for associating a user-provided algorithm
+implementation with certain OIDs. It contains the following members:
+
+@table @code
+@item const char *oidstring
+Textual representation of the OID.
+@end table
+@end deftp
+
+@deftp {Data type} gcry_md_init_t
+Type for the `init' function, defined as: void (*gcry_md_init_t) (void
+*c)
+@end deftp
+
+@deftp {Data type} gcry_md_write_t
+Type for the `write' function, defined as: void (*gcry_md_write_t)
+(void *c, unsigned char *buf, size_t nbytes)
+@end deftp
+
+@deftp {Data type} gcry_md_final_t
+Type for the `final' function, defined as: void (*gcry_md_final_t)
+(void *c)
+@end deftp
+
+@deftp {Data type} gcry_md_read_t
+Type for the `read' function, defined as: unsigned char
+*(*gcry_md_read_t) (void *c)
+@end deftp
+
+@deftypefun gcry_error_t gcry_md_register (gcry_md_spec_t *@var{digest}, unsigned int *algorithm_id, gcry_module_t *@var{module})
+
+Register a new digest module whose specification can be found in
+@var{digest}. On success, a new algorithm ID is stored in
+@var{algorithm_id} and a pointer representing this module is stored
+in @var{module}.
+@end deftypefun
+
+@deftypefun void gcry_md_unregister (gcry_module_t @var{module})
+Unregister the digest identified by @var{module}, which must have been
+registered with gcry_md_register.
+@end deftypefun
+
+@deftypefun gcry_error_t gcry_md_list (int *@var{list}, int *@var{list_length})
+Get a list consisting of the IDs of the loaded message digest modules.
+If @var{list} is zero, write the number of loaded message digest
+modules to @var{list_length} and return. If @var{list} is non-zero,
+the first *@var{list_length} algorithm IDs are stored in @var{list},
+which must be of according size. In case there are less message
+digests modules than *@var{list_length}, *@var{list_length} is updated
+to the correct number.
+@end deftypefun
+
+@node Working with hash algorithms
+@section Working with hash algorithms
+
+To use most of these function it is necessary to create a context;
+this is done using:
+
+@deftypefun gcry_error_t gcry_md_open (gcry_md_hd_t *@var{hd}, int @var{algo}, unsigned int @var{flags})
+
+Create a message digest object for algorithm @var{algo}. @var{flags}
+may be given as an bitwise OR of constants described below. @var{algo}
+may be given as @code{0} if the algorithms to use are later set using
+@code{gcry_md_enable}. @var{hd} is guaranteed to either receive a valid
+handle or NULL.
+
+For a list of supported algorithms, see @xref{Available hash
+algorithms}.
+
+The flags allowed for @var{mode} are:
+
+@c begin table of hash flags
+@table @code
+@item GCRY_MD_FLAG_SECURE
+Allocate all buffers and the resulting digest in "secure memory". Use
+this is the hashed data is highly confidential.
+
+@item GCRY_MD_FLAG_HMAC
+Turn the algorithm into a HMAC message authentication algorithm. This
+only works if just one algorithm is enabled for the handle. Note that the function
+@code{gcry_md_setkey} must be used to set the MAC key. If you want CBC
+message authentication codes based on a cipher, see @xref{Working with
+cipher handles}.
+
+@end table
+@c begin table of hash flags
+
+You may use the function @code{gcry_md_is_enabled} to later check
+whether an algorithm has been enabled.
+
+@end deftypefun
+@c end function gcry_md_open
+
+If you want to calculate several hash algorithms at the same time, you
+have to use the following function right after the @code{gcry_md_open}:
+
+@deftypefun gcry_error_t gcry_md_enable (gcry_md_hd_t @var{h}, int @var{algo})
+
+Add the message digest algorithm @var{algo} to the digest object
+described by handle @var{h}. Duplicated enabling of algorithms is
+detected and ignored.
+@end deftypefun
+
+If the flag @code{GCRY_MD_FLAG_HMAC} was used, the key for the MAC must
+be set using the function:
+
+@deftypefun gcry_error_t gcry_md_setkey (gcry_md_hd_t @var{h}, const void *@var{key}, size_t @var{keylen})
+
+For use with the HMAC feature, set the MAC key to the value of @var{key}
+of length @var{keylen}.
+@end deftypefun
+
+
+After you are done with the hash calculation, you should release the
+resources by using:
+
+@deftypefun void gcry_md_close (gcry_md_hd_t @var{h})
+
+Release all resources of hash context @var{h}. @var{h} should not be
+used after a call to this function. A @code{NULL} passed as @var{h} is
+ignored.
+
+@end deftypefun
+
+Often you have to do several hash operations using the same algorithm.
+To avoid the overhead of creating and releasing context, a reset function
+is provided:
+
+@deftypefun void gcry_md_reset (gcry_md_hd_t @var{h})
+
+Reset the current context to its initial state. This is effectively
+identical to a close followed by an open and enabling all currently
+active algorithms.
+@end deftypefun
+
+
+Often it is necessary to start hashing some data and then continue to
+hash different data. To avoid hashing the same data several times (which
+might not even be possible if the data is received from a pipe), a
+snapshot of the current hash context can be taken and turned into a new
+context:
+
+@deftypefun gcry_error_t gcry_md_copy (gcry_md_hd_t *@var{handle_dst}, gcry_md_hd_t @var{handle_src})
+
+Create a new digest object as an exact copy of the object described by
+handle @var{handle_src} and store it in @var{handle_dst}. The context
+is not reset and you can continue to hash data using this context and
+independently using the original context.
+@end deftypefun
+
+
+Now that we have prepared everything to calculate hashes, it is time to
+see how it is actually done. There are two ways for this, one to
+update the hash with a block of memory and one macro to update the hash
+by just one character. Both methods can be used on the same hash context.
+
+@deftypefun void gcry_md_write (gcry_md_hd_t @var{h}, const void *@var{buffer}, size_t @var{length})
+
+Pass @var{length} bytes of the data in @var{buffer} to the digest object
+with handle @var{h} to update the digest values. This
+function should be used for large blocks of data.
+@end deftypefun
+
+@deftypefun void gcry_md_putc (gcry_md_hd_t @var{h}, int @var{c})
+
+Pass the byte in @var{c} to the digest object with handle @var{h} to
+update the digest value. This is an efficient function, implemented as
+a macro to buffer the data before an actual update.
+@end deftypefun
+
+The semantics of the hash functions do not provide for reading out intermediate
+message digests because the calculation must be finalized first. This
+finalization may for example include the number of bytes hashed in the
+message digest or some padding.
+
+@deftypefun void gcry_md_final (gcry_md_hd_t @var{h})
+
+Finalize the message digest calculation. This is not really needed
+because @code{gcry_md_read} does this implicitly. After this has been
+done no further updates (by means of @code{gcry_md_write} or
+@code{gcry_md_putc} are allowed. Only the first call to this function
+has an effect. It is implemented as a macro.
+@end deftypefun
+
+The way to read out the calculated message digest is by using the
+function:
+
+@deftypefun unsigned char *gcry_md_read (gcry_md_hd_t @var{h}, int @var{algo})
+
+@code{gcry_md_read} returns the message digest after finalizing the
+calculation. This function may be used as often as required but it will
+always return the same value for one handle. The returned message digest
+is allocated within the message context and therefore valid until the
+handle is released or reseted (using @code{gcry_md_close} or
+@code{gcry_md_reset}. @var{algo} may be given as 0 to return the only
+enabled message digest or it may specify one of the enabled algorithms.
+The function does return @code{NULL} if the requested algorithm has not
+been enabled.
+@end deftypefun
+
+Because it is often necessary to get the message digest of one block of
+memory, a fast convenience function is available for this task:
+
+@deftypefun void gcry_md_hash_buffer (int @var{algo}, void *@var{digest}, const void *@var{buffer}, size_t @var{length});
+
+@code{gcry_md_hash_buffer} is a shortcut function to calculate a message
+digest of a buffer. This function does not require a context and
+immediately returns the message digest of the @var{length} bytes at
+@var{buffer}. @var{digest} must be allocated by the caller, large
+enough to hold the message digest yielded by the the specified algorithm
+@var{algo}. This required size may be obtained by using the function
+@code{gcry_md_get_algo_dlen}.
+
+Note that this function will abort the process if an unavailable
+algorithm is used.
+@end deftypefun
+
+@c ***********************************
+@c ***** MD info functions ***********
+@c ***********************************
+
+Hash algorithms are identified by internal algorithm numbers (see
+@code{gcry_md_open} for a list). However, in most applications they are
+used by names, so two functions are available to map between string
+representations and hash algorithm identifiers.
+
+@deftypefun const char *gcry_md_algo_name (int @var{algo})
+
+Map the digest algorithm id @var{algo} to a string representation of the
+algorithm name. For unknown algorithms this function returns the
+string @code{"?"}. This function should not be used to test for the
+availability of an algorithm.
+@end deftypefun
+
+@deftypefun int gcry_md_map_name (const char *@var{name})
+
+Map the algorithm with @var{name} to a digest algorithm identifier.
+Returns 0 if the algorithm name is not known. Names representing
+@acronym{ASN.1} object identifiers are recognized if the @acronym{IETF}
+dotted format is used and the OID is prefixed with either "@code{oid.}"
+or "@code{OID.}". For a list of supported OIDs, see the source code at
+@file{cipher/md.c}. This function should not be used to test for the
+availability of an algorithm.
+@end deftypefun
+
+@deftypefun gcry_error_t gcry_md_get_asnoid (int @var{algo}, void *@var{buffer}, size_t *@var{length})
+
+Return an DER encoded ASN.1 OID for the algorithm @var{algo} in the
+user allocated @var{buffer}. @var{length} must point to variable with
+the available size of @var{buffer} and receives after return the
+actual size of the returned OID. The returned error code may be
+@code{GPG_ERR_TOO_SHORT} if the provided buffer is to short to receive
+the OID; it is possible to call the function with @code{NULL} for
+@var{buffer} to have it only return the required size. The function
+returns 0 on success.
+
+@end deftypefun
+
+
+To test whether an algorithm is actually available for use, the
+following macro should be used:
+
+@deftypefun gcry_error_t gcry_md_test_algo (int @var{algo})
+
+The macro returns 0 if the algorithm @var{algo} is available for use.
+@end deftypefun
+
+If the length of a message digest is not known, it can be retrieved
+using the following function:
+
+@deftypefun unsigned int gcry_md_get_algo_dlen (int @var{algo})
+
+Retrieve the length in bytes of the digest yielded by algorithm
+@var{algo}. This is often used prior to @code{gcry_md_read} to allocate
+sufficient memory for the digest.
+@end deftypefun
+
+
+In some situations it might be hard to remember the algorithm used for
+the ongoing hashing. The following function might be used to get that
+information:
+
+@deftypefun int gcry_md_get_algo (gcry_md_hd_t @var{h})
+
+Retrieve the algorithm used with the handle @var{h}. Note that this
+does not work reliable if more than one algorithm is enabled in @var{h}.
+@end deftypefun
+
+The following macro might also be useful:
+
+@deftypefun int gcry_md_is_secure (gcry_md_hd_t @var{h})
+
+This function returns true when the digest object @var{h} is allocated
+in "secure memory"; i.e. @var{h} was created with the
+@code{GCRY_MD_FLAG_SECURE}.
+@end deftypefun
+
+@deftypefun int gcry_md_is_enabled (gcry_md_hd_t @var{h}, int @var{algo})
+
+This function returns true when the algorithm @var{algo} has been
+enabled for the digest object @var{h}.
+@end deftypefun
+
+
+
+Tracking bugs related to hashing is often a cumbersome task which
+requires to add a lot of printf statements into the code.
+Libgcrypt provides an easy way to avoid this. The actual data
+hashed can be written to files on request.
+
+@deftypefun void gcry_md_debug (gcry_md_hd_t @var{h}, const char *@var{suffix})
+
+Enable debugging for the digest object with handle @var{h}. This
+creates create files named @file{dbgmd-<n>.<string>} while doing the
+actual hashing. @var{suffix} is the string part in the filename. The
+number is a counter incremented for each new hashing. The data in the
+file is the raw data as passed to @code{gcry_md_write} or
+@code{gcry_md_putc}. If @code{NULL} is used for @var{suffix}, the
+debugging is stopped and the file closed. This is only rarely required
+because @code{gcry_md_close} implicitly stops debugging.
+@end deftypefun
+
+
+The following two deprecated macros are used for debugging by old code.
+They shopuld be replaced by @code{gcry_md_debug}.
+
+@deftypefun void gcry_md_start_debug (gcry_md_hd_t @var{h}, const char *@var{suffix})
+
+Enable debugging for the digest object with handle @var{h}. This
+creates create files named @file{dbgmd-<n>.<string>} while doing the
+actual hashing. @var{suffix} is the string part in the filename. The
+number is a counter incremented for each new hashing. The data in the
+file is the raw data as passed to @code{gcry_md_write} or
+@code{gcry_md_putc}.
+@end deftypefun
+
+
+@deftypefun void gcry_md_stop_debug (gcry_md_hd_t @var{h}, int @var{reserved})
+
+Stop debugging on handle @var{h}. @var{reserved} should be specified as
+0. This function is usually not required because @code{gcry_md_close}
+does implicitly stop debugging.
+@end deftypefun
+
+
+@c **********************************************************
@c ******************* Random *****************************
@c **********************************************************
@node Random Numbers
@@ -3588,16 +3719,18 @@ as defined by @var{level}.
@deftypefun void * gcry_random_bytes (size_t @var{nbytes}, enum gcry_random_level @var{level})
-Allocate a memory block consisting of @var{nbytes} fresh random bytes
-using a random quality as defined by @var{level}.
+Convenience function to allocate a memory block consisting of
+@var{nbytes} fresh random bytes using a random quality as defined by
+@var{level}.
@end deftypefun
@deftypefun void * gcry_random_bytes_secure (size_t @var{nbytes}, enum gcry_random_level @var{level})
-Allocate a memory block consisting of @var{nbytes} fresh random bytes
-using a random quality as defined by @var{level}. This function
-differs from @code{gcry_random_bytes} in that the returned buffer is
-allocated in a ``secure'' area of the memory.
+Convenience function to allocate a memory block consisting of
+@var{nbytes} fresh random bytes using a random quality as defined by
+@var{level}. This function differs from @code{gcry_random_bytes} in
+that the returned buffer is allocated in a ``secure'' area of the
+memory.
@end deftypefun
@deftypefun void gcry_create_nonce (unsigned char *@var{buffer}, size_t @var{length})
@@ -4132,16 +4265,16 @@ The next 2 functions are used to compare MPIs:
@deftypefun int gcry_mpi_cmp (@w{const gcry_mpi_t @var{u}}, @w{const gcry_mpi_t @var{v}})
-Compare the big integer number @var{u} and @var{v} returning 0 for
-equality, a positive value for @var{u} > @var{v} and a negative for
-@var{u} < @var{v}.
+Compare the multi-precision-integers number @var{u} and @var{v}
+returning 0 for equality, a positive value for @var{u} > @var{v} and a
+negative for @var{u} < @var{v}.
@end deftypefun
@deftypefun int gcry_mpi_cmp_ui (@w{const gcry_mpi_t @var{u}}, @w{unsigned long @var{v}})
-Compare the big integer number @var{u} with the unsigned integer @var{v}
-returning 0 for equality, a positive value for @var{u} > @var{v} and a
-negative for @var{u} < @var{v}.
+Compare the multi-precision-integers number @var{u} with the unsigned
+integer @var{v} returning 0 for equality, a positive value for @var{u} >
+@var{v} and a negative for @var{u} < @var{v}.
@end deftypefun
@@ -4221,8 +4354,8 @@ stored in "secure memory".
@deftypefun void gcry_mpi_clear_flag (@w{gcry_mpi_t @var{a}}, @w{enum gcry_mpi_flag @var{flag}})
-Clear @var{flag} for the big integer @var{a}. Note that this function is
-currently useless as no flags are allowed.
+Clear @var{flag} for the multi-precision-integers @var{a}. Note that
+this function is currently useless as no flags are allowed.
@end deftypefun
@deftypefun int gcry_mpi_get_flag (@w{gcry_mpi_t @var{a}}, @w{enum gcry_mpi_flag @var{flag}})
@@ -4232,10 +4365,10 @@ Return true when the @var{flag} is set for @var{a}.
@deftypefun void gcry_mpi_randomize (@w{gcry_mpi_t @var{w}}, @w{unsigned int @var{nbits}}, @w{enum gcry_random_level @var{level}})
-Set the big integer @var{w} to a random value of @var{nbits}, using
-random data quality of level @var{level}. In case @var{nbits} is not
-a multiple of a byte, @var{nbits} is rounded up to the next byte
-boundary.
+Set the multi-precision-integers @var{w} to a random value of
+@var{nbits}, using random data quality of level @var{level}. In case
+@var{nbits} is not a multiple of a byte, @var{nbits} is rounded up to
+the next byte boundary.
@end deftypefun
@c **********************************************************
@@ -4337,74 +4470,167 @@ Release the memory area pointed to by @var{p}.
@end deftypefun
@c **********************************************************
-@c ******************* Appendices *************************
+@c ***************** Architecure Overview *****************
@c **********************************************************
+@node Architecture
+@chapter Architecture
+
+This chapter describes the internal architecture of Libgcrypt.
+
+Libgcrypt is a function library written in ISO C-90. Any compliant
+compiler should be able to build Libgcrypt as long as the target is
+either a POSIX platform or compatible to the API used by Windows NT.
+Provisions have been take so that the library can be directly used from
+C++ applications; however building with a C++ compiler is not supported.
+
+Building libgcrypt is done by using the common @code{./configure && make}
+approach. The configure command is included in the source distribution
+and as a portable shell script it works on any Unix-alike system. The
+result of running the configure script are a C header file
+(@file{config.h}), customized Makefiles, the setup of symbolic links and
+a few other things. After that the make tool builds and optionally
+installs the library and the documentation. See the files
+@file{INSTALL} and @file{README} in the source distribution on how to do
+this.
+
+Libgcrypt is developed using a Subversion@footnote{A version control
+system available for many platforms} repository. Although all released
+versions are tagged in this repository, they should not be used to build
+production versions of Libgcrypt. Instead released tarballs should be
+used. These tarballs are available from several places with the master
+copy at @indicateurl{ftp://ftp.gnupg.org/gcrypt/libgcrypt/}.
+Announcements of new releases are posted to the
+@indicateurl{gnupg-announce@@gnupg.org} mailing list@footnote{See
+@url{http://www.gnupg.org/documentation/mailing-lists.en.html} for
+details.}.
-@include lgpl.texi
+@noindent
+Libgcrypt consists of several subsystems as shown by this diagram:
-@include gpl.texi
+@center @image{libgcrypt-modules, 10cm,,Module Overview}
-@node Concept Index
-@unnumbered Concept Index
+All of these subsystems provide a public API including the helper
+systesm like S-expression. The API style depends on the subsystem; in
+general an open, use, close approach is implemented. The open returns a
+handle to a context used for all futher operations on this handle,
+several functions may then be used on this handle and a final close
+function releases all resources associated with the handle.
-@printindex cp
+@menu
+* Public-Key Subsystem Architecture:: All about public keys.
+* Symmetric Encryption Subsystem Architecture:: All about standard ciphers.
+* Hashing and MACing Subsystem Architecture:: All about hashing.
+* Multi-Precision-Integer Subsystem Architecture:: All about big integers.
+* Prime-Number-Generator Subsystem Architecture:: All about prime numbers.
+* Random-Number Subsystem Architecture:: All about random stuff.
+* Helper Subsystems Architecture:: All about other stuff.
+@end menu
-@node Function and Data Index
-@unnumbered Function and Data Index
-@printindex fn
-@bye
+@node Public-Key Subsystem Architecture
+@section Public-Key Architecture
- /* Version check should be the very first gcry call because it
- makes sure that constructor functions are run. */
- if (!gcry_check_version (GCRYPT_VERSION))
- die ("version mismatch\n");
- /* Many applications don't require secure memory, so they should
- disable it right away. There won't be a problem unless one makes
- use of a feature which requires secure memory - in that case the
- process would abort because the secmem is not initialized. */
- gcry_control (GCRYCTL_DISABLE_SECMEM, 0);
+TBD.
- /* .. add whatever initialization you want, but better don't make calls
- to libgcrypt from more than one thread ... */
+@node Symmetric Encryption Subsystem Architecture
+@section Symmetric Encryption Subsystem Architecturen
- /* Tell Libgcrypt that initialization has completed. */
- gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
+TBD.
+@node Hashing and MACing Subsystem Architecture
+@section Hashing and MACing Subsystem Architecture
-If you require secure memory, this code should be used:
+TBD.
- if (!gcry_check_version (GCRYPT_VERSION))
- die ("version mismatch\n");
- /* We don't want to see any warnings, e.g. because we have not yet
- parsed options which might be used to suppress such warnings */
- gcry_control (GCRYCTL_SUSPEND_SECMEM_WARN);
- /* ... */
+@node Multi-Precision-Integer Subsystem Architecture
+@section Multi-Precision-Integer Subsystem Architecture
- /* Allocate a pool of 16k secure memory. This also drops privileges
- on some systems. */
- gcry_control (GCRYCTL_INIT_SECMEM, 16384, 0);
+TBD.
- /* It is now okay to let Libgcrypt complain when there was/is a problem
- with the secure memory. */
- gcry_control (GCRYCTL_RESUME_SECMEM_WARN);
+@node Prime-Number-Generator Subsystem Architecture
+@section Prime-Number-Generator Subsystem Architecture
- /* Tell Libgcrypt that initialization has completed. */
- gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
+TBD.
+@node Random-Number Subsystem Architecture
+@section Random-Number Subsystem Architecture
-This sounds a bit complicated but has the advantage that the caller
-must decide whether he wants secure memory or not - there is no
-default.
+TBD.
-It is important that this initialization is not done by a library but
-in the application. The library might want to check for finished
-initialization using:
- if (!gcry_control (GCRYCTL_INITIALIZATION_FINISHED_P))
- return MYLIB_ERROR_LIBGCRYPT_NOT_INITIALIZED;
+@node Helper Subsystems Architecture
+@section Helper Subsystems Architecture
+
+There are a few smaller subsystems which are mainly used internally by
+Libgcrypt but also available to applications.
+
+@menu
+* S-expression Subsystem Architecture:: Details about the S-expression architecture.
+* Memory Subsystem Architecture:: Details about the memory allocation architecture.
+* Miscellaneous Subsystems Architecture:: Details about other subsystems.
+@end menu
+
+@node S-expression Subsystem Architecture
+@subsection S-expression Subsystem Architecture
+
+TBD.
+
+
+@node Memory Subsystem Architecture
+@subsection Memory Subsystem Architecture
+
+TBD.
+
+
+@node Miscellaneous Subsystems Architecture
+@subsection Miscellaneous Subsystems Architecture
+
+TBD.
+
+
+
+
+
+@c **********************************************************
+@c ******************* Appendices *************************
+@c **********************************************************
+
+@node FIPS Restrictions
+@appendix Restrictions in FIPS mode
+
+If Libgcrypt is used FIPS mode these restrictions are effective:
+
+@itemize
+
+@item TBD
+
+
+
+@end itemize
+
+
+
+
+@c **********************************************************
+@c ************* Appendices (license etc.) ****************
+@c **********************************************************
+@include lgpl.texi
+
+@include gpl.texi
+
+@node Concept Index
+@unnumbered Concept Index
+
+@printindex cp
+
+@node Function and Data Index
+@unnumbered Function and Data Index
+
+@printindex fn
+
+@bye
@c LocalWords: int HD
diff --git a/random/ChangeLog b/random/ChangeLog
index f3e685de..c99eb2d7 100644
--- a/random/ChangeLog
+++ b/random/ChangeLog
@@ -1,3 +1,34 @@
+2008-08-15 Werner Koch <wk@g10code.com>
+
+ * random-fips.c: New.
+
+ * random-csprng.c (process-cb, progress_cb_data): Move to
+ random.c.
+ (_gcry_register_random_progress, _gcry_random_progress): Ditto.
+ (_gcry_random_initialize): Rename to _gcry_rngcsprng_initialize.
+ (_gcry_random_dump_stats): Rename to _gcry_rngcsprng_dump_stats.
+ (_gcry_secure_random_alloc): Rename to
+ _gcry_rngcsprng_secure_alloc.
+ (_gcry_enable_quick_random_gen): Rename to
+ _gcry_rngcsprng_enable_quick_gen.
+ (_gcry_set_random_daemon_socket): Rename to
+ _gcry_rngcsprng_set_daemon_socket.
+ (_gcry_use_random_daemon): Rename to _gcry_rngcsprng_use_daemon.
+ (_gcry_random_is_faked): Rename to _gcry_rngcsprng_is_faked.
+ (gcry_random_add_bytes): Rename to _gcry_rngcsprng_add_bytes.
+ (gcry_random_bytes): Remove
+ (gcry_random_bytes_secure): Remove.
+ (gcry_randomize): Rename to _gcry_rngcsprng_randomize.
+ (_gcry_set_random_seed_file): Rename to
+ _gcry_rngcsprng_set_seed_file.
+ (_gcry_update_random_seed_file): Rename to
+ _gcry_rngcsprng_update_seed_file.
+ (_gcry_fast_random_poll): Rename to _gcry_rngcsprng_fast_poll.
+ (gcry_create_nonce): Rename to _gcry_rngcsprng_create_nonce.
+
+ * random.c: Factor all code out to random-csprng.c and implement
+ wrapper functions.
+
2008-07-05 Werner Koch <wk@g10code.com>
* random-daemon.c, random.h, rndhw.c, rndunix.c, rand-internal.h *
diff --git a/random/Makefile.am b/random/Makefile.am
index b5a7c457..336109a6 100644
--- a/random/Makefile.am
+++ b/random/Makefile.am
@@ -32,8 +32,10 @@ librandom_la_LIBADD = $(GCRYPT_MODULES)
librandom_la_SOURCES = \
random.c random.h \
-rndhw.c \
-rand-internal.h
+rand-internal.h \
+random-csprng.c \
+random-fips.c \
+rndhw.c
if USE_RANDOM_DAEMON
librandom_la_SOURCES += random-daemon.c
diff --git a/random/rand-internal.h b/random/rand-internal.h
index 9ba40229..7a2edf5b 100644
--- a/random/rand-internal.h
+++ b/random/rand-internal.h
@@ -14,9 +14,9 @@
* 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 <http://www.gnu.org/licenses/>.
*/
+
#ifndef G10_RAND_INTERNAL_H
#define G10_RAND_INTERNAL_H
@@ -36,24 +36,71 @@ enum random_origins
-
+/*-- random.c --*/
void _gcry_random_progress (const char *what, int printchar,
int current, int total);
+/*-- random-csprng.c --*/
+void _gcry_rngcsprng_initialize (int full);
+void _gcry_rngcsprng_dump_stats (void);
+void _gcry_rngcsprng_secure_alloc (void);
+void _gcry_rngcsprng_enable_quick_gen (void);
+void _gcry_rngcsprng_set_daemon_socket (const char *socketname);
+int _gcry_rngcsprng_use_daemon (int onoff);
+int _gcry_rngcsprng_is_faked (void);
+gcry_error_t _gcry_rngcsprng_add_bytes (const void *buf, size_t buflen,
+ int quality);
+void *_gcry_rngcsprng_get_bytes (size_t nbytes,
+ enum gcry_random_level level);
+void *_gcry_rngcsprng_get_bytes_secure (size_t nbytes,
+ enum gcry_random_level level);
+void _gcry_rngcsprng_randomize (void *buffer, size_t length,
+ enum gcry_random_level level);
+void _gcry_rngcsprng_set_seed_file (const char *name);
+void _gcry_rngcsprng_update_seed_file (void);
+void _gcry_rngcsprng_fast_poll (void);
+void _gcry_rngcsprng_create_nonce (void *buffer, size_t length);
+
+/*-- random-rngcsprng.c --*/
+void _gcry_rngfips_initialize (int full);
+void _gcry_rngfips_dump_stats (void);
+int _gcry_rngfips_is_faked (void);
+gcry_error_t _gcry_rngfips_add_bytes (const void *buf, size_t buflen,
+ int quality);
+void *_gcry_rngfips_get_bytes (size_t nbytes,
+ enum gcry_random_level level);
+void *_gcry_rngfips_get_bytes_secure (size_t nbytes,
+ enum gcry_random_level level);
+void _gcry_rngfips_randomize (void *buffer, size_t length,
+ enum gcry_random_level level);
+void _gcry_rngfips_create_nonce (void *buffer, size_t length);
+
+
+
+
+
+
+/*-- rndlinux.c --*/
int _gcry_rndlinux_gather_random (void (*add) (const void *, size_t,
enum random_origins),
enum random_origins origin,
size_t length, int level);
+
+/*-- rndunix.c --*/
int _gcry_rndunix_gather_random (void (*add) (const void *, size_t,
enum random_origins),
enum random_origins origin,
size_t length, int level);
+
+/*-- rndelg.c --*/
int _gcry_rndegd_gather_random (void (*add) (const void *, size_t,
enum random_origins),
enum random_origins origin,
size_t length, int level);
int _gcry_rndegd_connect_socket (int nofail);
+
+/*-- rndw32.c --*/
int _gcry_rndw32_gather_random (void (*add) (const void *, size_t,
enum random_origins),
enum random_origins origin,
@@ -62,6 +109,7 @@ void _gcry_rndw32_gather_random_fast (void (*add)(const void*, size_t,
enum random_origins),
enum random_origins origin );
+/*-- rndhw.c --*/
int _gcry_rndhw_failed_p (void);
void _gcry_rndhw_poll_fast (void (*add)(const void*, size_t,
enum random_origins),
diff --git a/random/random-csprng.c b/random/random-csprng.c
new file mode 100644
index 00000000..ef168056
--- /dev/null
+++ b/random/random-csprng.c
@@ -0,0 +1,1388 @@
+/* random-csprng.c - CSPRNG style random number generator (libgcrypt clssic)
+ * Copyright (C) 1998, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
+ * 2007, 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/>.
+ */
+
+/*
+ This random number generator is modelled after the one described in
+ Peter Gutmann's paper: "Software Generation of Practically Strong
+ Random Numbers". See also chapter 6 in his book "Cryptographic
+ Security Architecture", New York, 2004, ISBN 0-387-95387-6.
+ */
+
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <time.h>
+#ifdef HAVE_GETHRTIME
+#include <sys/times.h>
+#endif
+#ifdef HAVE_GETTIMEOFDAY
+#include <sys/time.h>
+#endif
+#ifdef HAVE_GETRUSAGE
+#include <sys/resource.h>
+#endif
+#ifdef __MINGW32__
+#include <process.h>
+#endif
+#include "g10lib.h"
+#include "../cipher/rmd.h"
+#include "random.h"
+#include "rand-internal.h"
+#include "cipher.h" /* Required for the rmd160_hash_buffer() prototype. */
+#include "ath.h"
+
+#ifndef RAND_MAX /* For SunOS. */
+#define RAND_MAX 32767
+#endif
+
+/* Check whether we can lock the seed file read write. */
+#if defined(HAVE_FCNTL) && defined(HAVE_FTRUNCATE) && !defined(HAVE_W32_SYSTEM)
+#define LOCK_SEED_FILE 1
+#else
+#define LOCK_SEED_FILE 0
+#endif
+
+/* Define the constant we use for transforming the pool at read-out. */
+#if SIZEOF_UNSIGNED_LONG == 8
+#define ADD_VALUE 0xa5a5a5a5a5a5a5a5
+#elif SIZEOF_UNSIGNED_LONG == 4
+#define ADD_VALUE 0xa5a5a5a5
+#else
+#error weird size for an unsigned long
+#endif
+
+/* Contstants pertaining to the hash pool. */
+#define BLOCKLEN 64 /* Hash this amount of bytes... */
+#define DIGESTLEN 20 /* ... into a digest of this length (rmd160). */
+/* POOLBLOCKS is the number of digests which make up the pool. */
+#define POOLBLOCKS 30
+/* POOLSIZE must be a multiple of the digest length to make the AND
+ operations faster, the size should also be a multiple of unsigned
+ long. */
+#define POOLSIZE (POOLBLOCKS*DIGESTLEN)
+#if (POOLSIZE % SIZEOF_UNSIGNED_LONG)
+#error Please make sure that poolsize is a multiple of unsigned long
+#endif
+#define POOLWORDS (POOLSIZE / SIZEOF_UNSIGNED_LONG)
+
+
+/* RNDPOOL is the pool we use to collect the entropy and to stir it
+ up. Its allocated size is POOLSIZE+BLOCKLEN. Note that this is
+ also an indication on whether the module has been fully
+ initialized. */
+static unsigned char *rndpool;
+
+/* KEYPOOL is used as a scratch copy to read out random from RNDPOOL.
+ Its allocated size is also POOLSIZE+BLOCKLEN. */
+static unsigned char *keypool;
+
+/* This is the offset into RNDPOOL where the next random bytes are to
+ be mixed in. */
+static size_t pool_writepos;
+
+/* When reading data out of KEYPOOL, we start the read at different
+ positions. This variable keeps track on where to read next. */
+static size_t pool_readpos;
+
+/* This flag is set to true as soon as the pool has been completely
+ filled the first time. This may happen either by rereading a seed
+ file or by adding enough entropy. */
+static int pool_filled;
+
+/* This counter is used to track whether the initial seeding has been
+ done with enough bytes from a reliable entropy source. */
+static size_t pool_filled_counter;
+
+/* If random of level GCRY_VERY_STRONG_RANDOM has been requested we
+ have stricter requirements on what kind of entropy is in the pool.
+ In particular POOL_FILLED is not sufficient. Thus we add some
+ extra seeding and set this flag to true if the extra seeding has
+ been done. */
+static int did_initial_extra_seeding;
+
+/* This variable is used to estimated the amount of fresh entropy
+ available in RNDPOOL. */
+static int pool_balance;
+
+/* After a mixing operation this variable will be set to true and
+ cleared if new entropy has been added or a remix is required for
+ otehr reasons. */
+static int just_mixed;
+
+/* The name of the seed file or NULL if no seed file has been defined.
+ The seed file needs to be regsitered at initialiation time. We
+ keep a malloced copy here. */
+static char *seed_file_name;
+
+/* If a seed file has been registered and maybe updated on exit this
+ flag set. */
+static int allow_seed_file_update;
+
+/* Option flag set at initialiation time to force allocation of the
+ pool in secure memory. */
+static int secure_alloc;
+
+/* This function pointer is set to the actual entropy gathering
+ function during initailization. After initialization it is
+ guaranteed to point to function. (On systems without a random
+ gatherer module a dummy function is used).*/
+static int (*slow_gather_fnc)(void (*)(const void*, size_t,
+ enum random_origins),
+ enum random_origins, size_t, int);
+
+/* This function is set to the actual fast entropy gathering fucntion
+ during initialization. If it is NULL, no such function is
+ available. */
+static void (*fast_gather_fnc)(void (*)(const void*, size_t,
+ enum random_origins),
+ enum random_origins);
+
+
+/* Option flag useful for debugging and the test suite. If set
+ requests for very strong random are degraded to strong random. Not
+ used by regular applications. */
+static int quick_test;
+
+/* On systems without entropy gathering modules, this flag is set to
+ indicate that the random generator is not working properly. A
+ warning message is issued as well. This is useful only for
+ debugging and during development. */
+static int faked_rng;
+
+/* This is the lock we use to protect all pool operations. */
+static ath_mutex_t pool_lock = ATH_MUTEX_INITIALIZER;
+
+/* This is a helper for assert calls. These calls are used to assert
+ that functions are called in a locked state. It is not meant to be
+ thread-safe but as a method to get aware of missing locks in the
+ test suite. */
+static int pool_is_locked;
+
+/* This is the lock we use to protect the buffer used by the nonce
+ generation. */
+static ath_mutex_t nonce_buffer_lock = ATH_MUTEX_INITIALIZER;
+
+
+/* We keep some counters in this structure for the sake of the
+ _gcry_random_dump_stats () function. */
+static struct
+{
+ unsigned long mixrnd;
+ unsigned long mixkey;
+ unsigned long slowpolls;
+ unsigned long fastpolls;
+ unsigned long getbytes1;
+ unsigned long ngetbytes1;
+ unsigned long getbytes2;
+ unsigned long ngetbytes2;
+ unsigned long addbytes;
+ unsigned long naddbytes;
+} rndstats;
+
+
+
+/* --- Stuff pertaining to the random daemon support. --- */
+#ifdef USE_RANDOM_DAEMON
+
+/* If ALLOW_DAEMON is true, the module will try to use the random
+ daemon first. If the daemon has failed, this variable is set to
+ back to false and the code continues as normal. Note, we don't
+ test this flag in a locked state because a wrong value does not
+ harm and the trhead will find out itself that the daemon does not
+ work and set it (again) to false. */
+static int allow_daemon;
+
+/* During initialization, the user may set a non-default socket name
+ for accessing the random daemon. If this value is NULL, the
+ default name will be used. */
+static char *daemon_socket_name;
+
+#endif /*USE_RANDOM_DAEMON*/
+
+
+
+/* --- Prototypes --- */
+static void read_pool (byte *buffer, size_t length, int level );
+static void add_randomness (const void *buffer, size_t length,
+ enum random_origins origin);
+static void random_poll (void);
+static void do_fast_random_poll (void);
+static int (*getfnc_gather_random (void))(void (*)(const void*, size_t,
+ enum random_origins),
+ enum random_origins, size_t, int);
+static void (*getfnc_fast_random_poll (void))(void (*)(const void*, size_t,
+ enum random_origins),
+ enum random_origins);
+static void read_random_source (enum random_origins origin,
+ size_t length, int level);
+static int gather_faked (void (*add)(const void*, size_t, enum random_origins),
+ enum random_origins, size_t length, int level );
+
+
+
+/* --- Functions --- */
+
+
+/* Basic initialization which is required to initialize mutexes and
+ such. It does not run a full initialization so that the filling of
+ the random pool can be delayed until it is actually needed. We
+ assume that this function is used before any concurrent access
+ happens. */
+static void
+initialize_basics(void)
+{
+ static int initialized;
+ int err;
+
+ if (!initialized)
+ {
+ initialized = 1;
+ err = ath_mutex_init (&pool_lock);
+ if (err)
+ log_fatal ("failed to create the pool lock: %s\n", strerror (err) );
+
+ err = ath_mutex_init (&nonce_buffer_lock);
+ if (err)
+ log_fatal ("failed to create the nonce buffer lock: %s\n",
+ strerror (err) );
+
+#ifdef USE_RANDOM_DAEMON
+ _gcry_daemon_initialize_basics ();
+#endif /*USE_RANDOM_DAEMON*/
+
+ /* Make sure that we are still using the values we have
+ traditionally used for the random levels. */
+ assert ( GCRY_WEAK_RANDOM == 0
+ && GCRY_STRONG_RANDOM == 1
+ && GCRY_VERY_STRONG_RANDOM == 2);
+ }
+}
+
+/* Take the pool lock. */
+static void
+lock_pool (void)
+{
+ int err;
+
+ err = ath_mutex_lock (&pool_lock);
+ if (err)
+ log_fatal ("failed to acquire the pool lock: %s\n", strerror (err));
+ pool_is_locked = 1;
+}
+
+/* Release the pool lock. */
+static void
+unlock_pool (void)
+{
+ int err;
+
+ pool_is_locked = 0;
+ err = ath_mutex_unlock (&pool_lock);
+ if (err)
+ log_fatal ("failed to release the pool lock: %s\n", strerror (err));
+}
+
+
+/* Full initialization of this module. */
+static void
+initialize(void)
+{
+ /* Although the basic initialization should have happened already,
+ we call it here to make sure that all prerequisites are met. */
+ initialize_basics ();
+
+ /* Now we can look the pool and complete the initialization if
+ necessary. */
+ lock_pool ();
+ if (!rndpool)
+ {
+ /* The data buffer is allocated somewhat larger, so that we can
+ use this extra space (which is allocated in secure memory) as
+ a temporary hash buffer */
+ rndpool = (secure_alloc
+ ? gcry_xcalloc_secure (1, POOLSIZE + BLOCKLEN)
+ : gcry_xcalloc (1, POOLSIZE + BLOCKLEN));
+ keypool = (secure_alloc
+ ? gcry_xcalloc_secure (1, POOLSIZE + BLOCKLEN)
+ : gcry_xcalloc (1, POOLSIZE + BLOCKLEN));
+
+ /* Setup the slow entropy gathering function. The code requires
+ that this function exists. */
+ slow_gather_fnc = getfnc_gather_random ();
+ if (!slow_gather_fnc)
+ {
+ faked_rng = 1;
+ slow_gather_fnc = gather_faked;
+ }
+
+ /* Setup the fast entropy gathering function. */
+ fast_gather_fnc = getfnc_fast_random_poll ();
+
+ }
+ unlock_pool ();
+}
+
+
+
+
+/* Initialize this random subsystem. If FULL is false, this function
+ merely calls the initialize and does not do anything more. Doing
+ this is not really required but when running in a threaded
+ environment we might get a race condition otherwise. */
+void
+_gcry_rngcsprng_initialize (int full)
+{
+ if (!full)
+ initialize_basics ();
+ else
+ initialize ();
+}
+
+
+void
+_gcry_rngcsprng_dump_stats (void)
+{
+ /* FIXME: don't we need proper locking here? -mo.
+ Yes. However this is usually called during cleanup and thenwe _
+ might_ run into problems. Needs to be checked. -wk */
+
+ log_info ("random usage: poolsize=%d mixed=%lu polls=%lu/%lu added=%lu/%lu\n"
+ " outmix=%lu getlvl1=%lu/%lu getlvl2=%lu/%lu%s\n",
+ POOLSIZE, rndstats.mixrnd, rndstats.slowpolls, rndstats.fastpolls,
+ rndstats.naddbytes, rndstats.addbytes,
+ rndstats.mixkey, rndstats.ngetbytes1, rndstats.getbytes1,
+ rndstats.ngetbytes2, rndstats.getbytes2,
+ _gcry_rndhw_failed_p()? " (hwrng failed)":"");
+}
+
+
+/* This function should be called during initialization and before
+ intialization of this module to place the random pools into secure
+ memory. */
+void
+_gcry_rngcsprng_secure_alloc (void)
+{
+ secure_alloc = 1;
+}
+
+
+/* This may be called before full initialization to degrade the
+ quality of the RNG for the sake of a faster running test suite. */
+void
+_gcry_rngcsprng_enable_quick_gen (void)
+{
+ quick_test = 1;
+}
+
+
+void
+_gcry_rngcsprng_set_daemon_socket (const char *socketname)
+{
+#ifdef USE_RANDOM_DAEMON
+ if (daemon_socket_name)
+ BUG ();
+
+ daemon_socket_name = gcry_xstrdup (socketname);
+#else /*!USE_RANDOM_DAEMON*/
+ (void)socketname;
+#endif /*!USE_RANDOM_DAEMON*/
+}
+
+/* With ONOFF set to 1, enable the use of the daemon. With ONOFF set
+ to 0, disable the use of the daemon. With ONOF set to -1, return
+ whether the daemon has been enabled. */
+int
+_gcry_rngcsprng_use_daemon (int onoff)
+{
+#ifdef USE_RANDOM_DAEMON
+ int last;
+
+ /* FIXME: This is not really thread safe. */
+ last = allow_daemon;
+ if (onoff != -1)
+ allow_daemon = onoff;
+
+ return last;
+#else /*!USE_RANDOM_DAEMON*/
+ (void)onoff;
+ return 0;
+#endif /*!USE_RANDOM_DAEMON*/
+}
+
+
+/* This function returns true if no real RNG is available or the
+ quality of the RNG has been degraded for test purposes. */
+int
+_gcry_rngcsprng_is_faked (void)
+{
+ /* We need to initialize due to the runtime determination of
+ available entropy gather modules. */
+ initialize();
+ return (faked_rng || quick_test);
+}
+
+
+/* Add BUFLEN bytes from BUF to the internal random pool. QUALITY
+ should be in the range of 0..100 to indicate the goodness of the
+ entropy added, or -1 for goodness not known. */
+gcry_error_t
+_gcry_rngcsprng_add_bytes (const void *buf, size_t buflen, int quality)
+{
+ size_t nbytes;
+ const char *bufptr;
+
+ if (quality == -1)
+ quality = 35;
+ else if (quality > 100)
+ quality = 100;
+ else if (quality < 0)
+ quality = 0;
+
+ if (!buf)
+ return gpg_error (GPG_ERR_INV_ARG);
+
+ if (!buflen || quality < 10)
+ return 0; /* Take a shortcut. */
+
+ /* Because we don't increment the entropy estimation with FASTPOLL,
+ we don't need to take lock that estimation while adding from an
+ external source. This limited entropy estimation also means that
+ we can't take QUALITY into account. */
+ initialize_basics ();
+ bufptr = buf;
+ while (buflen)
+ {
+ nbytes = buflen > POOLSIZE? POOLSIZE : buflen;
+ lock_pool ();
+ if (rndpool)
+ add_randomness (bufptr, nbytes, RANDOM_ORIGIN_EXTERNAL);
+ unlock_pool ();
+ bufptr += nbytes;
+ buflen -= nbytes;
+ }
+ return 0;
+}
+
+
+/* Public function to fill the buffer with LENGTH bytes of
+ cryptographically strong random bytes. Level GCRY_WEAK_RANDOM is
+ not very strong, 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
+_gcry_rngcsprng_randomize (void *buffer, size_t length,
+ enum gcry_random_level level)
+{
+ unsigned char *p;
+
+ /* Make sure we are initialized. */
+ initialize ();
+
+ /* Handle our hack used for regression tests of Libgcrypt. */
+ if ( quick_test && level > GCRY_STRONG_RANDOM )
+ level = GCRY_STRONG_RANDOM;
+
+ /* Make sure the level is okay. */
+ level &= 3;
+
+#ifdef USE_RANDOM_DAEMON
+ if (allow_daemon
+ && !_gcry_daemon_randomize (daemon_socket_name, buffer, length, level))
+ return; /* The daemon succeeded. */
+ allow_daemon = 0; /* Daemon failed - switch off. */
+#endif /*USE_RANDOM_DAEMON*/
+
+ /* Acquire the pool lock. */
+ lock_pool ();
+
+ /* Update the statistics. */
+ if (level >= GCRY_VERY_STRONG_RANDOM)
+ {
+ rndstats.getbytes2 += length;
+ rndstats.ngetbytes2++;
+ }
+ else
+ {
+ rndstats.getbytes1 += length;
+ rndstats.ngetbytes1++;
+ }
+
+ /* Read the random into the provided buffer. */
+ for (p = buffer; length > 0;)
+ {
+ size_t n;
+
+ n = length > POOLSIZE? POOLSIZE : length;
+ read_pool (p, n, level);
+ length -= n;
+ p += n;
+ }
+
+ /* Release the pool lock. */
+ unlock_pool ();
+}
+
+
+
+
+/*
+ Mix the pool:
+
+ |........blocks*20byte........|20byte|..44byte..|
+ <..44byte..> <20byte>
+ | |
+ | +------+
+ +---------------------------|----------+
+ v v
+ |........blocks*20byte........|20byte|..44byte..|
+ <.....64bytes.....>
+ |
+ +----------------------------------+
+ Hash
+ v
+ |.............................|20byte|..44byte..|
+ <20byte><20byte><..44byte..>
+ | |
+ | +---------------------+
+ +-----------------------------+ |
+ v v
+ |.............................|20byte|..44byte..|
+ <.....64byte......>
+ |
+ +-------------------------+
+ Hash
+ v
+ |.............................|20byte|..44byte..|
+ <20byte><20byte><..44byte..>
+
+ and so on until we did this for all blocks.
+
+ To better protect against implementation errors in this code, we
+ xor a digest of the entire pool into the pool before mixing.
+
+ Note: this function must only be called with a locked pool.
+ */
+static void
+mix_pool(unsigned char *pool)
+{
+ static unsigned char failsafe_digest[DIGESTLEN];
+ static int failsafe_digest_valid;
+
+ unsigned char *hashbuf = pool + POOLSIZE;
+ unsigned char *p, *pend;
+ int i, n;
+ RMD160_CONTEXT md;
+
+#if DIGESTLEN != 20
+#error must have a digest length of 20 for ripe-md-160
+#endif
+
+ assert (pool_is_locked);
+ _gcry_rmd160_init( &md );
+
+ /* Loop over the pool. */
+ pend = pool + POOLSIZE;
+ memcpy(hashbuf, pend - DIGESTLEN, DIGESTLEN );
+ memcpy(hashbuf+DIGESTLEN, pool, BLOCKLEN-DIGESTLEN);
+ _gcry_rmd160_mixblock( &md, hashbuf);
+ memcpy(pool, hashbuf, 20 );
+
+ if (failsafe_digest_valid && pool == rndpool)
+ {
+ for (i=0; i < 20; i++)
+ pool[i] ^= failsafe_digest[i];
+ }
+
+ p = pool;
+ for (n=1; n < POOLBLOCKS; n++)
+ {
+ memcpy (hashbuf, p, DIGESTLEN);
+
+ p += DIGESTLEN;
+ if (p+DIGESTLEN+BLOCKLEN < pend)
+ memcpy (hashbuf+DIGESTLEN, p+DIGESTLEN, BLOCKLEN-DIGESTLEN);
+ else
+ {
+ unsigned char *pp = p + DIGESTLEN;
+
+ for (i=DIGESTLEN; i < BLOCKLEN; i++ )
+ {
+ if ( pp >= pend )
+ pp = pool;
+ hashbuf[i] = *pp++;
+ }
+ }
+
+ _gcry_rmd160_mixblock ( &md, hashbuf);
+ memcpy(p, hashbuf, 20 );
+ }
+
+ /* Our hash implementation does only leave small parts (64 bytes)
+ of the pool on the stack, so it is okay not to require secure
+ memory here. Before we use this pool, it will be copied to the
+ help buffer anyway. */
+ if ( pool == rndpool)
+ {
+ _gcry_rmd160_hash_buffer (failsafe_digest, pool, POOLSIZE);
+ failsafe_digest_valid = 1;
+ }
+
+ _gcry_burn_stack (384); /* for the rmd160_mixblock(), rmd160_hash_buffer */
+}
+
+
+void
+_gcry_rngcsprng_set_seed_file (const char *name)
+{
+ if (seed_file_name)
+ BUG ();
+ seed_file_name = gcry_xstrdup (name);
+}
+
+
+/* Lock an open file identified by file descriptor FD and wait a
+ reasonable time to succeed. With FOR_WRITE set to true a write
+ lock will be taken. FNAME is used only for diagnostics. Returns 0
+ on success or -1 on error. */
+static int
+lock_seed_file (int fd, const char *fname, int for_write)
+{
+#if LOCK_SEED_FILE
+ struct flock lck;
+ struct timeval tv;
+ int backoff=0;
+
+ /* We take a lock on the entire file. */
+ memset (&lck, 0, sizeof lck);
+ lck.l_type = for_write? F_WRLCK : F_RDLCK;
+ lck.l_whence = SEEK_SET;
+
+ while (fcntl (fd, F_SETLK, &lck) == -1)
+ {
+ if (errno != EAGAIN && errno != EACCES)
+ {
+ log_info (_("can't lock `%s': %s\n"), fname, strerror (errno));
+ return -1;
+ }
+
+ if (backoff > 2) /* Show the first message after ~2.25 seconds. */
+ log_info( _("waiting for lock on `%s'...\n"), fname);
+
+ tv.tv_sec = backoff;
+ tv.tv_usec = 250000;
+ select (0, NULL, NULL, NULL, &tv);
+ if (backoff < 10)
+ backoff++ ;
+ }
+#endif /*LOCK_SEED_FILE*/
+ return 0;
+}
+
+
+/* Read in a seed from the random_seed file and return true if this
+ was successful.
+
+ Note: Multiple instances of applications sharing the same random
+ seed file can be started in parallel, in which case they will read
+ out the same pool and then race for updating it (the last update
+ overwrites earlier updates). They will differentiate only by the
+ weak entropy that is added in read_seed_file based on the PID and
+ clock, and up to 16 bytes of weak random non-blockingly. The
+ consequence is that the output of these different instances is
+ correlated to some extent. In the perfect scenario, the attacker
+ can control (or at least guess) the PID and clock of the
+ application, and drain the system's entropy pool to reduce the "up
+ to 16 bytes" above to 0. Then the dependencies of the inital
+ states of the pools are completely known. */
+static int
+read_seed_file (void)
+{
+ int fd;
+ struct stat sb;
+ unsigned char buffer[POOLSIZE];
+ int n;
+
+ assert (pool_is_locked);
+
+ if (!seed_file_name)
+ return 0;
+
+#ifdef HAVE_DOSISH_SYSTEM
+ fd = open( seed_file_name, O_RDONLY | O_BINARY );
+#else
+ fd = open( seed_file_name, O_RDONLY );
+#endif
+ if( fd == -1 && errno == ENOENT)
+ {
+ allow_seed_file_update = 1;
+ return 0;
+ }
+
+ if (fd == -1 )
+ {
+ log_info(_("can't open `%s': %s\n"), seed_file_name, strerror(errno) );
+ return 0;
+ }
+ if (lock_seed_file (fd, seed_file_name, 0))
+ {
+ close (fd);
+ return 0;
+ }
+ if (fstat( fd, &sb ) )
+ {
+ log_info(_("can't stat `%s': %s\n"), seed_file_name, strerror(errno) );
+ close(fd);
+ return 0;
+ }
+ if (!S_ISREG(sb.st_mode) )
+ {
+ log_info(_("`%s' is not a regular file - ignored\n"), seed_file_name );
+ close(fd);
+ return 0;
+ }
+ if (!sb.st_size )
+ {
+ log_info(_("note: random_seed file is empty\n") );
+ close(fd);
+ allow_seed_file_update = 1;
+ return 0;
+ }
+ if (sb.st_size != POOLSIZE )
+ {
+ log_info(_("warning: invalid size of random_seed file - not used\n") );
+ close(fd);
+ return 0;
+ }
+
+ do
+ {
+ n = read( fd, buffer, POOLSIZE );
+ }
+ while (n == -1 && errno == EINTR );
+
+ if (n != POOLSIZE)
+ {
+ log_fatal(_("can't read `%s': %s\n"), seed_file_name,strerror(errno) );
+ close(fd);/*NOTREACHED*/
+ return 0;
+ }
+
+ close(fd);
+
+ add_randomness( buffer, POOLSIZE, RANDOM_ORIGIN_INIT );
+ /* add some minor entropy to the pool now (this will also force a mixing) */
+ {
+ pid_t x = getpid();
+ add_randomness( &x, sizeof(x), RANDOM_ORIGIN_INIT );
+ }
+ {
+ time_t x = time(NULL);
+ add_randomness( &x, sizeof(x), RANDOM_ORIGIN_INIT );
+ }
+ {
+ clock_t x = clock();
+ add_randomness( &x, sizeof(x), RANDOM_ORIGIN_INIT );
+ }
+
+ /* And read a few bytes from our entropy source. By using a level
+ * of 0 this will not block and might not return anything with some
+ * entropy drivers, however the rndlinux driver will use
+ * /dev/urandom and return some stuff - Do not read too much as we
+ * want to be friendly to the scare system entropy resource. */
+ read_random_source ( RANDOM_ORIGIN_INIT, 16, GCRY_WEAK_RANDOM );
+
+ allow_seed_file_update = 1;
+ return 1;
+}
+
+
+void
+_gcry_rngcsprng_update_seed_file (void)
+{
+ unsigned long *sp, *dp;
+ int fd, i;
+
+ /* We do only a basic initialization so that we can lock the pool.
+ This is required to cope with the case that this function is
+ called by some cleanup code at a point where the RNG has never
+ been initialized. */
+ initialize_basics ();
+ lock_pool ();
+
+ if ( !seed_file_name || !rndpool || !pool_filled )
+ {
+ unlock_pool ();
+ return;
+ }
+ if ( !allow_seed_file_update )
+ {
+ unlock_pool ();
+ log_info(_("note: random_seed file not updated\n"));
+ return;
+ }
+
+ /* At this point we know that there is something in the pool and
+ thus we can conclude that the pool has been fully initialized. */
+
+
+ /* Copy the entropy pool to a scratch pool and mix both of them. */
+ for (i=0,dp=(unsigned long*)keypool, sp=(unsigned long*)rndpool;
+ i < POOLWORDS; i++, dp++, sp++ )
+ {
+ *dp = *sp + ADD_VALUE;
+ }
+ mix_pool(rndpool); rndstats.mixrnd++;
+ mix_pool(keypool); rndstats.mixkey++;
+
+#if defined(HAVE_DOSISH_SYSTEM) || defined(__CYGWIN__)
+ fd = open (seed_file_name, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY,
+ S_IRUSR|S_IWUSR );
+#else
+# if LOCK_SEED_FILE
+ fd = open (seed_file_name, O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR );
+# else
+ fd = open (seed_file_name, O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR );
+# endif
+#endif
+
+ if (fd == -1 )
+ log_info (_("can't create `%s': %s\n"), seed_file_name, strerror(errno) );
+ else if (lock_seed_file (fd, seed_file_name, 1))
+ {
+ close (fd);
+ }
+#if LOCK_SEED_FILE
+ else if (ftruncate (fd, 0))
+ {
+ log_info(_("can't write `%s': %s\n"), seed_file_name, strerror(errno));
+ close (fd);
+ }
+#endif /*LOCK_SEED_FILE*/
+ else
+ {
+ do
+ {
+ i = write (fd, keypool, POOLSIZE );
+ }
+ while (i == -1 && errno == EINTR);
+ if (i != POOLSIZE)
+ log_info (_("can't write `%s': %s\n"),seed_file_name, strerror(errno));
+ if (close(fd))
+ log_info (_("can't close `%s': %s\n"),seed_file_name, strerror(errno));
+ }
+
+ unlock_pool ();
+}
+
+
+/* Read random out of the pool. This function is the core of the
+ public random functions. Note that Level GCRY_WEAK_RANDOM is not
+ anymore handled special and in fact is an alias in the API for
+ level GCRY_STRONG_RANDOM. Must be called with the pool already
+ locked. */
+static void
+read_pool (byte *buffer, size_t length, int level)
+{
+ int i;
+ unsigned long *sp, *dp;
+ /* The volatile is there to make sure the compiler does not optimize
+ the code away in case the getpid function is badly attributed.
+ Note that we keep a pid in a static variable as well as in a
+ stack based one; the latter is to detect ill behaving thread
+ libraries, ignoring the pool mutexes. */
+ static volatile pid_t my_pid = (pid_t)(-1);
+ volatile pid_t my_pid2;
+
+ assert (pool_is_locked);
+
+ retry:
+ /* Get our own pid, so that we can detect a fork. */
+ my_pid2 = getpid ();
+ if (my_pid == (pid_t)(-1))
+ my_pid = my_pid2;
+ if ( my_pid != my_pid2 )
+ {
+ /* We detected a plain fork; i.e. we are now the child. Update
+ the static pid and add some randomness. */
+ pid_t x;
+
+ my_pid = my_pid2;
+ x = my_pid;
+ add_randomness (&x, sizeof(x), RANDOM_ORIGIN_INIT);
+ just_mixed = 0; /* Make sure it will get mixed. */
+ }
+
+ assert (pool_is_locked);
+
+ /* Our code does not allow to extract more than POOLSIZE. Better
+ check it here. */
+ if (length > POOLSIZE)
+ {
+ log_bug("too many random bits requested\n");
+ }
+
+ if (!pool_filled)
+ {
+ if (read_seed_file() )
+ pool_filled = 1;
+ }
+
+ /* For level 2 quality (key generation) we always make sure that the
+ pool has been seeded enough initially. */
+ if (level == GCRY_VERY_STRONG_RANDOM && !did_initial_extra_seeding)
+ {
+ size_t needed;
+
+ pool_balance = 0;
+ needed = length - pool_balance;
+ if (needed < POOLSIZE/2)
+ needed = POOLSIZE/2;
+ else if( needed > POOLSIZE )
+ BUG ();
+ read_random_source (RANDOM_ORIGIN_EXTRAPOLL, needed,
+ GCRY_VERY_STRONG_RANDOM);
+ pool_balance += needed;
+ did_initial_extra_seeding = 1;
+ }
+
+ /* For level 2 make sure that there is enough random in the pool. */
+ if (level == GCRY_VERY_STRONG_RANDOM && pool_balance < length)
+ {
+ size_t needed;
+
+ if (pool_balance < 0)
+ pool_balance = 0;
+ needed = length - pool_balance;
+ if (needed > POOLSIZE)
+ BUG ();
+ read_random_source (RANDOM_ORIGIN_EXTRAPOLL, needed,
+ GCRY_VERY_STRONG_RANDOM);
+ pool_balance += needed;
+ }
+
+ /* Make sure the pool is filled. */
+ while (!pool_filled)
+ random_poll();
+
+ /* Always do a fast random poll (we have to use the unlocked version). */
+ do_fast_random_poll();
+
+ /* Mix the pid in so that we for sure won't deliver the same random
+ after a fork. */
+ {
+ pid_t apid = my_pid;
+ add_randomness (&apid, sizeof (apid), RANDOM_ORIGIN_INIT);
+ }
+
+ /* Mix the pool (if add_randomness() didn't it). */
+ if (!just_mixed)
+ {
+ mix_pool(rndpool);
+ rndstats.mixrnd++;
+ }
+
+ /* Create a new pool. */
+ for(i=0,dp=(unsigned long*)keypool, sp=(unsigned long*)rndpool;
+ i < POOLWORDS; i++, dp++, sp++ )
+ *dp = *sp + ADD_VALUE;
+
+ /* Mix both pools. */
+ mix_pool(rndpool); rndstats.mixrnd++;
+ mix_pool(keypool); rndstats.mixkey++;
+
+ /* Read the requested data. We use a read pointer to read from a
+ different position each time. */
+ while (length--)
+ {
+ *buffer++ = keypool[pool_readpos++];
+ if (pool_readpos >= POOLSIZE)
+ pool_readpos = 0;
+ pool_balance--;
+ }
+
+ if (pool_balance < 0)
+ pool_balance = 0;
+
+ /* Clear the keypool. */
+ memset (keypool, 0, POOLSIZE);
+
+ /* We need to detect whether a fork has happened. A fork might have
+ an identical pool and thus the child and the parent could emit
+ the very same random number. This test here is to detect forks
+ in a multi-threaded process. It does not work with all thread
+ implementations in particular not with pthreads. However it is
+ good enough for GNU Pth. */
+ if ( getpid () != my_pid2 )
+ {
+ pid_t x = getpid();
+ add_randomness (&x, sizeof(x), RANDOM_ORIGIN_INIT);
+ just_mixed = 0; /* Make sure it will get mixed. */
+ my_pid = x; /* Also update the static pid. */
+ goto retry;
+ }
+}
+
+
+
+/* Add LENGTH bytes of randomness from buffer to the pool. ORIGIN is
+ used to specify the randomness origin. This is one of the
+ RANDOM_ORIGIN_* values. */
+static void
+add_randomness (const void *buffer, size_t length, enum random_origins origin)
+{
+ const unsigned char *p = buffer;
+ size_t count = 0;
+
+ assert (pool_is_locked);
+
+ rndstats.addbytes += length;
+ rndstats.naddbytes++;
+ while (length-- )
+ {
+ rndpool[pool_writepos++] ^= *p++;
+ count++;
+ if (pool_writepos >= POOLSIZE )
+ {
+ /* It is possible that we are invoked before the pool is
+ filled using an unreliable origin of entropy, for example
+ the fast random poll. To avoid flagging the pool as
+ filled in this case, we track the initial filling state
+ separately. See also the remarks about the seed file. */
+ if (origin >= RANDOM_ORIGIN_SLOWPOLL && !pool_filled)
+ {
+ pool_filled_counter += count;
+ count = 0;
+ if (pool_filled_counter >= POOLSIZE)
+ pool_filled = 1;
+ }
+ pool_writepos = 0;
+ mix_pool(rndpool); rndstats.mixrnd++;
+ just_mixed = !length;
+ }
+ }
+}
+
+
+
+static void
+random_poll()
+{
+ rndstats.slowpolls++;
+ read_random_source (RANDOM_ORIGIN_SLOWPOLL, POOLSIZE/5, GCRY_STRONG_RANDOM);
+}
+
+
+/* Runtime determination of the slow entropy gathering module. */
+static int (*
+getfnc_gather_random (void))(void (*)(const void*, size_t,
+ enum random_origins),
+ enum random_origins, size_t, int)
+{
+ int (*fnc)(void (*)(const void*, size_t, enum random_origins),
+ enum random_origins, size_t, int);
+
+#if USE_RNDLINUX
+ if ( !access (NAME_OF_DEV_RANDOM, R_OK)
+ && !access (NAME_OF_DEV_URANDOM, R_OK))
+ {
+ fnc = _gcry_rndlinux_gather_random;
+ return fnc;
+ }
+#endif
+
+#if USE_RNDEGD
+ if ( _gcry_rndegd_connect_socket (1) != -1 )
+ {
+ fnc = _gcry_rndegd_gather_random;
+ return fnc;
+ }
+#endif
+
+#if USE_RNDUNIX
+ fnc = _gcry_rndunix_gather_random;
+ return fnc;
+#endif
+
+#if USE_RNDW32
+ fnc = _gcry_rndw32_gather_random;
+ return fnc;
+#endif
+
+ log_fatal (_("no entropy gathering module detected\n"));
+
+ return NULL; /*NOTREACHED*/
+}
+
+/* Runtime determination of the fast entropy gathering function.
+ (Currently a compile time method is used.) */
+static void (*
+getfnc_fast_random_poll (void))( void (*)(const void*, size_t,
+ enum random_origins),
+ enum random_origins)
+{
+#if USE_RNDW32
+ return _gcry_rndw32_gather_random_fast;
+#endif
+ return NULL;
+}
+
+
+
+static void
+do_fast_random_poll (void)
+{
+ assert (pool_is_locked);
+
+ rndstats.fastpolls++;
+
+ if (fast_gather_fnc)
+ fast_gather_fnc (add_randomness, RANDOM_ORIGIN_FASTPOLL);
+
+ /* Continue with the generic functions. */
+#if HAVE_GETHRTIME
+ {
+ hrtime_t tv;
+ tv = gethrtime();
+ add_randomness( &tv, sizeof(tv), RANDOM_ORIGIN_FASTPOLL );
+ }
+#elif HAVE_GETTIMEOFDAY
+ {
+ struct timeval tv;
+ if( gettimeofday( &tv, NULL ) )
+ BUG();
+ add_randomness( &tv.tv_sec, sizeof(tv.tv_sec), RANDOM_ORIGIN_FASTPOLL );
+ add_randomness( &tv.tv_usec, sizeof(tv.tv_usec), RANDOM_ORIGIN_FASTPOLL );
+ }
+#elif HAVE_CLOCK_GETTIME
+ { struct timespec tv;
+ if( clock_gettime( CLOCK_REALTIME, &tv ) == -1 )
+ BUG();
+ add_randomness( &tv.tv_sec, sizeof(tv.tv_sec), RANDOM_ORIGIN_FASTPOLL );
+ add_randomness( &tv.tv_nsec, sizeof(tv.tv_nsec), RANDOM_ORIGIN_FASTPOLL );
+ }
+#else /* use times */
+# ifndef HAVE_DOSISH_SYSTEM
+ { struct tms buf;
+ times( &buf );
+ add_randomness( &buf, sizeof buf, RANDOM_ORIGIN_FASTPOLL );
+ }
+# endif
+#endif
+
+#ifdef HAVE_GETRUSAGE
+# ifdef RUSAGE_SELF
+ {
+ struct rusage buf;
+ /* QNX/Neutrino does return ENOSYS - so we just ignore it and add
+ whatever is in buf. In a chroot environment it might not work
+ at all (i.e. because /proc/ is not accessible), so we better
+ ignore all error codes and hope for the best. */
+ getrusage (RUSAGE_SELF, &buf );
+ add_randomness( &buf, sizeof buf, RANDOM_ORIGIN_FASTPOLL );
+ memset( &buf, 0, sizeof buf );
+ }
+# else /*!RUSAGE_SELF*/
+# ifdef __GCC__
+# warning There is no RUSAGE_SELF on this system
+# endif
+# endif /*!RUSAGE_SELF*/
+#endif /*HAVE_GETRUSAGE*/
+
+ /* Time and clock are availabe on all systems - so we better do it
+ just in case one of the above functions didn't work. */
+ {
+ time_t x = time(NULL);
+ add_randomness( &x, sizeof(x), RANDOM_ORIGIN_FASTPOLL );
+ }
+ {
+ clock_t x = clock();
+ add_randomness( &x, sizeof(x), RANDOM_ORIGIN_FASTPOLL );
+ }
+
+ /* If the system features a fast hardware RNG, read some bytes from
+ there. */
+ _gcry_rndhw_poll_fast (add_randomness, RANDOM_ORIGIN_FASTPOLL);
+}
+
+
+/* The fast random pool function as called at some places in
+ libgcrypt. This is merely a wrapper to make sure that this module
+ is initalized and to look the pool. Note, that this function is a
+ NOP unless a random function has been used or _gcry_initialize (1)
+ has been used. We use this hack so that the internal use of this
+ function in cipher_open and md_open won't start filling up the
+ random pool, even if no random will be required by the process. */
+void
+_gcry_rngcsprng_fast_poll (void)
+{
+ initialize_basics ();
+
+ lock_pool ();
+ if (rndpool)
+ {
+ /* Yes, we are fully initialized. */
+ do_fast_random_poll ();
+ }
+ unlock_pool ();
+}
+
+
+
+static void
+read_random_source (enum random_origins orgin, size_t length, int level )
+{
+ if ( !slow_gather_fnc )
+ log_fatal ("Slow entropy gathering module not yet initialized\n");
+
+ if ( slow_gather_fnc (add_randomness, orgin, length, level) < 0)
+ log_fatal ("No way to gather entropy for the RNG\n");
+}
+
+
+static int
+gather_faked (void (*add)(const void*, size_t, enum random_origins),
+ enum random_origins origin, size_t length, int level )
+{
+ static int initialized=0;
+ size_t n;
+ char *buffer, *p;
+
+ (void)add;
+ (void)level;
+
+ if ( !initialized )
+ {
+ log_info(_("WARNING: using insecure random number generator!!\n"));
+ initialized=1;
+#ifdef HAVE_RAND
+ srand( time(NULL)*getpid());
+#else
+ srandom( time(NULL)*getpid());
+#endif
+ }
+
+ p = buffer = gcry_xmalloc( length );
+ n = length;
+#ifdef HAVE_RAND
+ while ( n-- )
+ *p++ = ((unsigned)(1 + (int) (256.0*rand()/(RAND_MAX+1.0)))-1);
+#else
+ while ( n-- )
+ *p++ = ((unsigned)(1 + (int) (256.0*random()/(RAND_MAX+1.0)))-1);
+#endif
+ add_randomness ( buffer, length, origin );
+ gcry_free (buffer);
+ return 0; /* okay */
+}
+
+
+/* Create an unpredicable nonce of LENGTH bytes in BUFFER. */
+void
+_gcry_rngcsprng_create_nonce (void *buffer, size_t length)
+{
+ static unsigned char nonce_buffer[20+8];
+ static int nonce_buffer_initialized = 0;
+ static volatile pid_t my_pid; /* The volatile is there to make sure the
+ compiler does not optimize the code away
+ in case the getpid function is badly
+ attributed. */
+ volatile pid_t apid;
+ unsigned char *p;
+ size_t n;
+ int err;
+
+ /* Make sure we are initialized. */
+ initialize ();
+
+#ifdef USE_RANDOM_DAEMON
+ if (allow_daemon
+ && !_gcry_daemon_create_nonce (daemon_socket_name, buffer, length))
+ return; /* The daemon succeeded. */
+ allow_daemon = 0; /* Daemon failed - switch off. */
+#endif /*USE_RANDOM_DAEMON*/
+
+ /* Acquire the nonce buffer lock. */
+ err = ath_mutex_lock (&nonce_buffer_lock);
+ if (err)
+ log_fatal ("failed to acquire the nonce buffer lock: %s\n",
+ strerror (err));
+
+ apid = getpid ();
+ /* The first time intialize our buffer. */
+ if (!nonce_buffer_initialized)
+ {
+ time_t atime = time (NULL);
+ pid_t xpid = apid;
+
+ my_pid = apid;
+
+ if ((sizeof apid + sizeof atime) > sizeof nonce_buffer)
+ BUG ();
+
+ /* Initialize the first 20 bytes with a reasonable value so that
+ a failure of gcry_randomize won't affect us too much. Don't
+ care about the uninitialized remaining bytes. */
+ p = nonce_buffer;
+ memcpy (p, &xpid, sizeof xpid);
+ p += sizeof xpid;
+ memcpy (p, &atime, sizeof atime);
+
+ /* Initialize the never changing private part of 64 bits. */
+ gcry_randomize (nonce_buffer+20, 8, GCRY_WEAK_RANDOM);
+
+ nonce_buffer_initialized = 1;
+ }
+ else if ( my_pid != apid )
+ {
+ /* We forked. Need to reseed the buffer - doing this for the
+ private part should be sufficient. */
+ gcry_randomize (nonce_buffer+20, 8, GCRY_WEAK_RANDOM);
+ /* Update the pid so that we won't run into here again and
+ again. */
+ my_pid = apid;
+ }
+
+ /* Create the nonce by hashing the entire buffer, returning the hash
+ and updating the first 20 bytes of the buffer with this hash. */
+ for (p = buffer; length > 0; length -= n, p += n)
+ {
+ _gcry_sha1_hash_buffer (nonce_buffer,
+ nonce_buffer, sizeof nonce_buffer);
+ n = length > 20? 20 : length;
+ memcpy (p, nonce_buffer, n);
+ }
+
+
+ /* Release the nonce buffer lock. */
+ err = ath_mutex_unlock (&nonce_buffer_lock);
+ if (err)
+ log_fatal ("failed to release the nonce buffer lock: %s\n",
+ strerror (err));
+
+}
diff --git a/random/random-fips.c b/random/random-fips.c
new file mode 100644
index 00000000..d29f21cc
--- /dev/null
+++ b/random/random-fips.c
@@ -0,0 +1,102 @@
+/* random-fips.c - FIPS style random number generator
+ * 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/>.
+ */
+
+/*
+ FIXME: Explain
+
+
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <errno.h>
+
+#include "g10lib.h"
+#include "random.h"
+#include "rand-internal.h"
+#include "ath.h"
+
+
+
+
+
+/* --- Functions --- */
+
+
+/* Initialize this random subsystem. If FULL is false, this function
+ merely calls the basic initialization of the module and does not do
+ anything more. Doing this is not really required but when running
+ in a threaded environment we might get a race condition
+ otherwise. */
+void
+_gcry_rngfips_initialize (int full)
+{
+}
+
+
+void
+_gcry_rngfips_dump_stats (void)
+{
+}
+
+
+/* This function returns true if no real RNG is available or the
+ quality of the RNG has been degraded for test purposes. */
+int
+_gcry_rngfips_is_faked (void)
+{
+ return 0; /* Faked random is not allowed. */
+}
+
+
+/* Add BUFLEN bytes from BUF to the internal random pool. QUALITY
+ should be in the range of 0..100 to indicate the goodness of the
+ entropy added, or -1 for goodness not known. */
+gcry_error_t
+_gcry_rngfips_add_bytes (const void *buf, size_t buflen, int quality)
+{
+ return 0;
+}
+
+
+/* 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
+ enough for most usage, GCRY_VERY_STRONG_RANDOM is good for key
+ generation stuff but may be very slow. */
+void
+_gcry_rngfips_randomize (void *buffer, size_t length,
+ enum gcry_random_level level)
+{
+ BUG ();
+}
+
+
+/* Create an unpredicable nonce of LENGTH bytes in BUFFER. */
+void
+_gcry_rngfips_create_nonce (void *buffer, size_t length)
+{
+ /* No special nonce support here; divert to the standard random
+ function. */
+ _gcry_rngfips_randomize (buffer, length, GCRY_WEAK_RANDOM);
+}
+
+
diff --git a/random/random.c b/random/random.c
index 3db72961..020c6518 100644
--- a/random/random.c
+++ b/random/random.c
@@ -1,6 +1,5 @@
-/* random.c - random number generator
- * Copyright (C) 1998, 2000, 2001, 2002, 2003,
- * 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
+/* random.c - Random number switch
+ * Copyright (C) 2008 Free Software Foundation, Inc.
*
* This file is part of Libgcrypt.
*
@@ -19,192 +18,21 @@
*/
/*
- This random number generator is modelled after the one described in
- Peter Gutmann's paper: "Software Generation of Practically Strong
- Random Numbers". See also chapter 6 in his book "Cryptographic
- Security Architecture", New York, 2004, ISBN 0-387-95387-6.
+ This module switches between different implementations of random
+ number generators and provides a few help functions.
*/
-
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <errno.h>
-#include <string.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <time.h>
-#ifdef HAVE_GETHRTIME
-#include <sys/times.h>
-#endif
-#ifdef HAVE_GETTIMEOFDAY
-#include <sys/time.h>
-#endif
-#ifdef HAVE_GETRUSAGE
-#include <sys/resource.h>
-#endif
-#ifdef __MINGW32__
-#include <process.h>
-#endif
+
#include "g10lib.h"
-#include "../cipher/rmd.h"
#include "random.h"
#include "rand-internal.h"
-#include "cipher.h" /* Required for the rmd160_hash_buffer() prototype. */
#include "ath.h"
-#ifndef RAND_MAX /* For SunOS. */
-#define RAND_MAX 32767
-#endif
-
-/* Check whether we can lock the seed file read write. */
-#if defined(HAVE_FCNTL) && defined(HAVE_FTRUNCATE) && !defined(HAVE_W32_SYSTEM)
-#define LOCK_SEED_FILE 1
-#else
-#define LOCK_SEED_FILE 0
-#endif
-
-/* Define the constant we use for transforming the pool at read-out. */
-#if SIZEOF_UNSIGNED_LONG == 8
-#define ADD_VALUE 0xa5a5a5a5a5a5a5a5
-#elif SIZEOF_UNSIGNED_LONG == 4
-#define ADD_VALUE 0xa5a5a5a5
-#else
-#error weird size for an unsigned long
-#endif
-
-/* Contstants pertaining to the hash pool. */
-#define BLOCKLEN 64 /* Hash this amount of bytes... */
-#define DIGESTLEN 20 /* ... into a digest of this length (rmd160). */
-/* POOLBLOCKS is the number of digests which make up the pool. */
-#define POOLBLOCKS 30
-/* POOLSIZE must be a multiple of the digest length to make the AND
- operations faster, the size should also be a multiple of unsigned
- long. */
-#define POOLSIZE (POOLBLOCKS*DIGESTLEN)
-#if (POOLSIZE % SIZEOF_UNSIGNED_LONG)
-#error Please make sure that poolsize is a multiple of unsigned long
-#endif
-#define POOLWORDS (POOLSIZE / SIZEOF_UNSIGNED_LONG)
-
-
-/* RNDPOOL is the pool we use to collect the entropy and to stir it
- up. Its allocated size is POOLSIZE+BLOCKLEN. Note that this is
- also an indication on whether the module has been fully
- initialized. */
-static unsigned char *rndpool;
-
-/* KEYPOOL is used as a scratch copy to read out random from RNDPOOL.
- Its allocated size is also POOLSIZE+BLOCKLEN. */
-static unsigned char *keypool;
-
-/* This is the offset into RNDPOOL where the next random bytes are to
- be mixed in. */
-static size_t pool_writepos;
-
-/* When reading data out of KEYPOOL, we start the read at different
- positions. This variable keeps track on where to read next. */
-static size_t pool_readpos;
-
-/* This flag is set to true as soon as the pool has been completely
- filled the first time. This may happen either by rereading a seed
- file or by adding enough entropy. */
-static int pool_filled;
-
-/* This counter is used to track whether the initial seeding has been
- done with enough bytes from a reliable entropy source. */
-static size_t pool_filled_counter;
-
-/* If random of level GCRY_VERY_STRONG_RANDOM has been requested we
- have stricter requirements on what kind of entropy is in the pool.
- In particular POOL_FILLED is not sufficient. Thus we add some
- extra seeding and set this flag to true if the extra seeding has
- been done. */
-static int did_initial_extra_seeding;
-
-/* This variable is used to estimated the amount of fresh entropy
- available in RNDPOOL. */
-static int pool_balance;
-
-/* After a mixing operation this variable will be set to true and
- cleared if new entropy has been added or a remix is required for
- otehr reasons. */
-static int just_mixed;
-
-/* The name of the seed file or NULL if no seed file has been defined.
- The seed file needs to be regsitered at initialiation time. We
- keep a malloced copy here. */
-static char *seed_file_name;
-
-/* If a seed file has been registered and maybe updated on exit this
- flag set. */
-static int allow_seed_file_update;
-
-/* Option flag set at initialiation time to force allocation of the
- pool in secure memory. */
-static int secure_alloc;
-
-/* This function pointer is set to the actual entropy gathering
- function during initailization. After initialization it is
- guaranteed to point to function. (On systems without a random
- gatherer module a dummy function is used).*/
-static int (*slow_gather_fnc)(void (*)(const void*, size_t,
- enum random_origins),
- enum random_origins, size_t, int);
-
-/* This function is set to the actual fast entropy gathering fucntion
- during initialization. If it is NULL, no such function is
- available. */
-static void (*fast_gather_fnc)(void (*)(const void*, size_t,
- enum random_origins),
- enum random_origins);
-
-
-/* Option flag useful for debugging and the test suite. If set
- requests for very strong random are degraded to strong random. Not
- used by regular applications. */
-static int quick_test;
-
-/* On systems without entropy gathering modules, this flag is set to
- indicate that the random generator is not working properly. A
- warning message is issued as well. This is useful only for
- debugging and during development. */
-static int faked_rng;
-
-/* This is the lock we use to protect all pool operations. */
-static ath_mutex_t pool_lock = ATH_MUTEX_INITIALIZER;
-
-/* This is a helper for assert calls. These calls are used to assert
- that functions are called in a locked state. It is not meant to be
- thread-safe but as a method to get aware of missing locks in the
- test suite. */
-static int pool_is_locked;
-
-/* This is the lock we use to protect the buffer used by the nonce
- generation. */
-static ath_mutex_t nonce_buffer_lock = ATH_MUTEX_INITIALIZER;
-
-
-/* We keep some counters in this structure for the sake of the
- _gcry_random_dump_stats () function. */
-static struct
-{
- unsigned long mixrnd;
- unsigned long mixkey;
- unsigned long slowpolls;
- unsigned long fastpolls;
- unsigned long getbytes1;
- unsigned long ngetbytes1;
- unsigned long getbytes2;
- unsigned long ngetbytes2;
- unsigned long addbytes;
- unsigned long naddbytes;
-} rndstats;
-
/* If not NULL a progress function called from certain places and the
opaque value passed along. Registred by
@@ -213,149 +41,13 @@ static void (*progress_cb) (void *,const char*,int,int, int );
static void *progress_cb_data;
-/* --- Stuff pertaining to the random daemon support. --- */
-#ifdef USE_RANDOM_DAEMON
-
-/* If ALLOW_DAEMON is true, the module will try to use the random
- daemon first. If the daemon has failed, this variable is set to
- back to false and the code continues as normal. Note, we don't
- test this flag in a locked state because a wrong value does not
- harm and the trhead will find out itself that the daemon does not
- work and set it (again) to false. */
-static int allow_daemon;
-
-/* During initialization, the user may set a non-default socket name
- for accessing the random daemon. If this value is NULL, the
- default name will be used. */
-static char *daemon_socket_name;
-
-#endif /*USE_RANDOM_DAEMON*/
-
-
-
-/* --- Prototypes --- */
-static void read_pool (byte *buffer, size_t length, int level );
-static void add_randomness (const void *buffer, size_t length,
- enum random_origins origin);
-static void random_poll (void);
-static void do_fast_random_poll (void);
-static int (*getfnc_gather_random (void))(void (*)(const void*, size_t,
- enum random_origins),
- enum random_origins, size_t, int);
-static void (*getfnc_fast_random_poll (void))(void (*)(const void*, size_t,
- enum random_origins),
- enum random_origins);
-static void read_random_source (enum random_origins origin,
- size_t length, int level);
-static int gather_faked (void (*add)(const void*, size_t, enum random_origins),
- enum random_origins, size_t length, int level );
-
/* --- Functions --- */
-/* Basic initialization which is required to initialize mutexes and
- such. It does not run a full initialization so that the filling of
- the random pool can be delayed until it is actually needed. We
- assume that this function is used before any concurrent access
- happens. */
-static void
-initialize_basics(void)
-{
- static int initialized;
- int err;
-
- if (!initialized)
- {
- initialized = 1;
- err = ath_mutex_init (&pool_lock);
- if (err)
- log_fatal ("failed to create the pool lock: %s\n", strerror (err) );
-
- err = ath_mutex_init (&nonce_buffer_lock);
- if (err)
- log_fatal ("failed to create the nonce buffer lock: %s\n",
- strerror (err) );
-
-#ifdef USE_RANDOM_DAEMON
- _gcry_daemon_initialize_basics ();
-#endif /*USE_RANDOM_DAEMON*/
-
- /* Make sure that we are still using the values we have
- traditionally used for the random levels. */
- assert ( GCRY_WEAK_RANDOM == 0
- && GCRY_STRONG_RANDOM == 1
- && GCRY_VERY_STRONG_RANDOM == 2);
- }
-}
-
-/* Take the pool lock. */
-static void
-lock_pool (void)
-{
- int err;
-
- err = ath_mutex_lock (&pool_lock);
- if (err)
- log_fatal ("failed to acquire the pool lock: %s\n", strerror (err));
- pool_is_locked = 1;
-}
-
-/* Release the pool lock. */
-static void
-unlock_pool (void)
-{
- int err;
-
- pool_is_locked = 0;
- err = ath_mutex_unlock (&pool_lock);
- if (err)
- log_fatal ("failed to release the pool lock: %s\n", strerror (err));
-}
-
-
-/* Full initialization of this module. */
-static void
-initialize(void)
-{
- /* Although the basic initialization should have happened already,
- we call it here to make sure that all prerequisites are met. */
- initialize_basics ();
-
- /* Now we can look the pool and complete the initialization if
- necessary. */
- lock_pool ();
- if (!rndpool)
- {
- /* The data buffer is allocated somewhat larger, so that we can
- use this extra space (which is allocated in secure memory) as
- a temporary hash buffer */
- rndpool = (secure_alloc
- ? gcry_xcalloc_secure (1, POOLSIZE + BLOCKLEN)
- : gcry_xcalloc (1, POOLSIZE + BLOCKLEN));
- keypool = (secure_alloc
- ? gcry_xcalloc_secure (1, POOLSIZE + BLOCKLEN)
- : gcry_xcalloc (1, POOLSIZE + BLOCKLEN));
-
- /* Setup the slow entropy gathering function. The code requires
- that this function exists. */
- slow_gather_fnc = getfnc_gather_random ();
- if (!slow_gather_fnc)
- {
- faked_rng = 1;
- slow_gather_fnc = gather_faked;
- }
-
- /* Setup the fast entropy gathering function. */
- fast_gather_fnc = getfnc_fast_random_poll ();
-
- }
- unlock_pool ();
-}
-
-
-/* Used to register a progress callback. */
+/* Used to register a progress callback. This needs to be called
+ before any threads are created. */
void
_gcry_register_random_progress (void (*cb)(void *,const char*,int,int,int),
void *cb_data )
@@ -365,8 +57,8 @@ _gcry_register_random_progress (void (*cb)(void *,const char*,int,int,int),
}
-/* This progress function is currently used by the random modules to give hint
- on how much more entropy is required. */
+/* This progress function is currently used by the random modules to
+ give hints on how much more entropy is required. */
void
_gcry_random_progress (const char *what, int printchar, int current, int total)
{
@@ -375,44 +67,41 @@ _gcry_random_progress (const char *what, int printchar, int current, int total)
}
+
/* Initialize this random subsystem. If FULL is false, this function
- merely calls the initialize and does not do anything more. Doing
- this is not really required but when running in a threaded
- environment we might get a race condition otherwise. */
+ merely calls the basic initialization of the module and does not do
+ anything more. Doing this is not really required but when running
+ in a threaded environment we might get a race condition
+ otherwise. */
void
_gcry_random_initialize (int full)
{
- if (!full)
- initialize_basics ();
+ if ( fips_mode() )
+ _gcry_rngfips_initialize (full);
else
- initialize ();
+ _gcry_rngcsprng_initialize (full);
}
void
-_gcry_random_dump_stats ()
+_gcry_random_dump_stats (void)
{
- /* FIXME: don't we need proper locking here? -mo.
- Yes. However this is usually called during cleanup and thenwe _
- might_ run into problems. Needs to be checked. -wk */
-
- log_info ("random usage: poolsize=%d mixed=%lu polls=%lu/%lu added=%lu/%lu\n"
- " outmix=%lu getlvl1=%lu/%lu getlvl2=%lu/%lu%s\n",
- POOLSIZE, rndstats.mixrnd, rndstats.slowpolls, rndstats.fastpolls,
- rndstats.naddbytes, rndstats.addbytes,
- rndstats.mixkey, rndstats.ngetbytes1, rndstats.getbytes1,
- rndstats.ngetbytes2, rndstats.getbytes2,
- _gcry_rndhw_failed_p()? " (hwrng failed)":"");
+ if ( fips_mode() )
+ _gcry_rngfips_dump_stats ();
+ else
+ _gcry_rngcsprng_dump_stats ();
}
/* This function should be called during initialization and beore
- intialization of this module to palce the random pools into secure
+ intialization of this module to place the random pools into secure
memory. */
void
-_gcry_secure_random_alloc()
+_gcry_secure_random_alloc (void)
{
- secure_alloc = 1;
+ if ( fips_mode() )
+ return; /* Not used; the fips rng is allows in secure mode. */
+ _gcry_rngcsprng_secure_alloc ();
}
@@ -421,21 +110,18 @@ _gcry_secure_random_alloc()
void
_gcry_enable_quick_random_gen (void)
{
- quick_test = 1;
+ if ( fips_mode() )
+ return; /* Not used. */
+ _gcry_rngcsprng_enable_quick_gen ();
}
void
_gcry_set_random_daemon_socket (const char *socketname)
{
-#ifdef USE_RANDOM_DAEMON
- if (daemon_socket_name)
- BUG ();
-
- daemon_socket_name = gcry_xstrdup (socketname);
-#else /*!USE_RANDOM_DAEMON*/
- (void)socketname;
-#endif /*!USE_RANDOM_DAEMON*/
+ if ( fips_mode() )
+ return; /* Not used. */
+ _gcry_rngcsprng_set_daemon_socket (socketname);
}
/* With ONOFF set to 1, enable the use of the daemon. With ONOFF set
@@ -444,31 +130,20 @@ _gcry_set_random_daemon_socket (const char *socketname)
int
_gcry_use_random_daemon (int onoff)
{
-#ifdef USE_RANDOM_DAEMON
- int last;
-
- /* FIXME: This is not really thread safe. */
- last = allow_daemon;
- if (onoff != -1)
- allow_daemon = onoff;
-
- return last;
-#else /*!USE_RANDOM_DAEMON*/
- (void)onoff;
- return 0;
-#endif /*!USE_RANDOM_DAEMON*/
+ if (fips_mode ())
+ return 0; /* Never enabled in fips mode. */
+ return _gcry_rngcsprng_use_daemon (onoff);
}
/* This function returns true if no real RNG is available or the
quality of the RNG has been degraded for test purposes. */
int
-_gcry_random_is_faked()
+_gcry_random_is_faked (void)
{
- /* We need to initialize due to the runtime determination of
- available entropy gather modules. */
- initialize();
- return (faked_rng || quick_test);
+ if (fips_mode ())
+ return 0; /* Never faked in fips mode. */
+ return _gcry_rngcsprng_is_faked ();
}
@@ -478,42 +153,22 @@ _gcry_random_is_faked()
gcry_error_t
gcry_random_add_bytes (const void *buf, size_t buflen, int quality)
{
- size_t nbytes;
- const char *bufptr;
-
- if (quality == -1)
- quality = 35;
- else if (quality > 100)
- quality = 100;
- else if (quality < 0)
- quality = 0;
-
- if (!buf)
- return gpg_error (GPG_ERR_INV_ARG);
-
- if (!buflen || quality < 10)
- return 0; /* Take a shortcut. */
-
- /* Because we don't increment the entropy estimation with FASTPOLL,
- we don't need to take lock that estimation while adding from an
- external source. This limited entropy estimation also means that
- we can't take QUALITY into account. */
- initialize_basics ();
- bufptr = buf;
- while (buflen)
- {
- nbytes = buflen > POOLSIZE? POOLSIZE : buflen;
- lock_pool ();
- if (rndpool)
- add_randomness (bufptr, nbytes, RANDOM_ORIGIN_EXTERNAL);
- unlock_pool ();
- bufptr += nbytes;
- buflen -= nbytes;
- }
- return 0;
+ if (fips_mode ())
+ return 0; /* No need for this in fips mode. */
+ return _gcry_rngcsprng_add_bytes (buf, buflen, quality);
}
-
+
+/* Helper function. */
+static void
+do_randomize (void *buffer, size_t length, enum gcry_random_level level)
+{
+ if (fips_mode ())
+ _gcry_rngfips_randomize (buffer, length, level);
+ else
+ _gcry_rngcsprng_randomize (buffer, length, level);
+}
+
/* The public function to return random data of the quality LEVEL.
Returns a pointer to a newly allocated and randomized buffer of
LEVEL and NBYTES length. Caller must free the buffer. */
@@ -522,11 +177,8 @@ gcry_random_bytes (size_t nbytes, enum gcry_random_level level)
{
void *buffer;
- initialize();
-
buffer = gcry_xmalloc (nbytes);
- gcry_randomize (buffer, nbytes, level);
-
+ do_randomize (buffer, nbytes, level);
return buffer;
}
@@ -535,16 +187,15 @@ gcry_random_bytes (size_t nbytes, enum gcry_random_level level)
this version of the function returns the random in a buffer allocated
in secure memory. Caller must free the buffer. */
void *
-gcry_random_bytes_secure( size_t nbytes, enum gcry_random_level level )
+gcry_random_bytes_secure (size_t nbytes, enum gcry_random_level level)
{
void *buffer;
- initialize();
-
- buffer = secure_alloc ? gcry_xmalloc_secure (nbytes)
- : gcry_xmalloc (nbytes);
- gcry_randomize (buffer, nbytes, level);
-
+ /* Historical note (1.3.0--1.4.1): The buffer was only allocated
+ in secure memory if the pool in random-csprng.c was also set to
+ use secure memory. */
+ buffer = gcry_xmalloc_secure (nbytes);
+ do_randomize (buffer, nbytes, level);
return buffer;
}
@@ -557,741 +208,36 @@ gcry_random_bytes_secure( size_t nbytes, enum gcry_random_level level )
void
gcry_randomize (void *buffer, size_t length, enum gcry_random_level level)
{
- unsigned char *p;
-
- /* Make sure we are initialized. */
- initialize ();
-
- /* Handle our hack used for regression tests of Libgcrypt. */
- if ( quick_test && level > GCRY_STRONG_RANDOM )
- level = GCRY_STRONG_RANDOM;
-
- /* Make sure the level is okay. */
- level &= 3;
-
-#ifdef USE_RANDOM_DAEMON
- if (allow_daemon
- && !_gcry_daemon_randomize (daemon_socket_name, buffer, length, level))
- return; /* The daemon succeeded. */
- allow_daemon = 0; /* Daemon failed - switch off. */
-#endif /*USE_RANDOM_DAEMON*/
-
- /* Acquire the pool lock. */
- lock_pool ();
-
- /* Update the statistics. */
- if (level >= GCRY_VERY_STRONG_RANDOM)
- {
- rndstats.getbytes2 += length;
- rndstats.ngetbytes2++;
- }
- else
- {
- rndstats.getbytes1 += length;
- rndstats.ngetbytes1++;
- }
-
- /* Read the random into the provided buffer. */
- for (p = buffer; length > 0;)
- {
- size_t n;
-
- n = length > POOLSIZE? POOLSIZE : length;
- read_pool (p, n, level);
- length -= n;
- p += n;
- }
-
- /* Release the pool lock. */
- unlock_pool ();
-}
-
-
-
-
-/*
- Mix the pool:
-
- |........blocks*20byte........|20byte|..44byte..|
- <..44byte..> <20byte>
- | |
- | +------+
- +---------------------------|----------+
- v v
- |........blocks*20byte........|20byte|..44byte..|
- <.....64bytes.....>
- |
- +----------------------------------+
- Hash
- v
- |.............................|20byte|..44byte..|
- <20byte><20byte><..44byte..>
- | |
- | +---------------------+
- +-----------------------------+ |
- v v
- |.............................|20byte|..44byte..|
- <.....64byte......>
- |
- +-------------------------+
- Hash
- v
- |.............................|20byte|..44byte..|
- <20byte><20byte><..44byte..>
-
- and so on until we did this for all blocks.
-
- To better protect against implementation errors in this code, we
- xor a digest of the entire pool into the pool before mixing.
-
- Note: this function must only be called with a locked pool.
- */
-static void
-mix_pool(unsigned char *pool)
-{
- static unsigned char failsafe_digest[DIGESTLEN];
- static int failsafe_digest_valid;
-
- unsigned char *hashbuf = pool + POOLSIZE;
- unsigned char *p, *pend;
- int i, n;
- RMD160_CONTEXT md;
-
-#if DIGESTLEN != 20
-#error must have a digest length of 20 for ripe-md-160
-#endif
-
- assert (pool_is_locked);
- _gcry_rmd160_init( &md );
-
- /* Loop over the pool. */
- pend = pool + POOLSIZE;
- memcpy(hashbuf, pend - DIGESTLEN, DIGESTLEN );
- memcpy(hashbuf+DIGESTLEN, pool, BLOCKLEN-DIGESTLEN);
- _gcry_rmd160_mixblock( &md, hashbuf);
- memcpy(pool, hashbuf, 20 );
-
- if (failsafe_digest_valid && pool == rndpool)
- {
- for (i=0; i < 20; i++)
- pool[i] ^= failsafe_digest[i];
- }
-
- p = pool;
- for (n=1; n < POOLBLOCKS; n++)
- {
- memcpy (hashbuf, p, DIGESTLEN);
-
- p += DIGESTLEN;
- if (p+DIGESTLEN+BLOCKLEN < pend)
- memcpy (hashbuf+DIGESTLEN, p+DIGESTLEN, BLOCKLEN-DIGESTLEN);
- else
- {
- unsigned char *pp = p + DIGESTLEN;
-
- for (i=DIGESTLEN; i < BLOCKLEN; i++ )
- {
- if ( pp >= pend )
- pp = pool;
- hashbuf[i] = *pp++;
- }
- }
-
- _gcry_rmd160_mixblock ( &md, hashbuf);
- memcpy(p, hashbuf, 20 );
- }
-
- /* Our hash implementation does only leave small parts (64 bytes)
- of the pool on the stack, so it is okay not to require secure
- memory here. Before we use this pool, it will be copied to the
- help buffer anyway. */
- if ( pool == rndpool)
- {
- _gcry_rmd160_hash_buffer (failsafe_digest, pool, POOLSIZE);
- failsafe_digest_valid = 1;
- }
-
- _gcry_burn_stack (384); /* for the rmd160_mixblock(), rmd160_hash_buffer */
+ do_randomize (buffer, length, level);
}
+/* This function may be used to specify the file to be used as a seed
+ file for the PRNG. This fucntion should be called prior to the
+ initialization of the random module. NAME may not be NULL. */
void
-_gcry_set_random_seed_file( const char *name )
+_gcry_set_random_seed_file (const char *name)
{
- if (seed_file_name)
- BUG ();
- seed_file_name = gcry_xstrdup (name);
-}
-
-
-/* Lock an open file identified by file descriptor FD and wait a
- reasonable time to succeed. With FOR_WRITE set to true a write
- lock will be taken. FNAME is used only for diagnostics. Returns 0
- on success or -1 on error. */
-static int
-lock_seed_file (int fd, const char *fname, int for_write)
-{
-#if LOCK_SEED_FILE
- struct flock lck;
- struct timeval tv;
- int backoff=0;
-
- /* We take a lock on the entire file. */
- memset (&lck, 0, sizeof lck);
- lck.l_type = for_write? F_WRLCK : F_RDLCK;
- lck.l_whence = SEEK_SET;
-
- while (fcntl (fd, F_SETLK, &lck) == -1)
- {
- if (errno != EAGAIN && errno != EACCES)
- {
- log_info (_("can't lock `%s': %s\n"), fname, strerror (errno));
- return -1;
- }
-
- if (backoff > 2) /* Show the first message after ~2.25 seconds. */
- log_info( _("waiting for lock on `%s'...\n"), fname);
-
- tv.tv_sec = backoff;
- tv.tv_usec = 250000;
- select (0, NULL, NULL, NULL, &tv);
- if (backoff < 10)
- backoff++ ;
- }
-#endif /*LOCK_SEED_FILE*/
- return 0;
-}
-
-
-/* Read in a seed from the random_seed file and return true if this
- was successful.
-
- Note: Multiple instances of applications sharing the same random
- seed file can be started in parallel, in which case they will read
- out the same pool and then race for updating it (the last update
- overwrites earlier updates). They will differentiate only by the
- weak entropy that is added in read_seed_file based on the PID and
- clock, and up to 16 bytes of weak random non-blockingly. The
- consequence is that the output of these different instances is
- correlated to some extent. In the perfect scenario, the attacker
- can control (or at least guess) the PID and clock of the
- application, and drain the system's entropy pool to reduce the "up
- to 16 bytes" above to 0. Then the dependencies of the inital
- states of the pools are completely known. */
-static int
-read_seed_file (void)
-{
- int fd;
- struct stat sb;
- unsigned char buffer[POOLSIZE];
- int n;
-
- assert (pool_is_locked);
-
- if (!seed_file_name)
- return 0;
-
-#ifdef HAVE_DOSISH_SYSTEM
- fd = open( seed_file_name, O_RDONLY | O_BINARY );
-#else
- fd = open( seed_file_name, O_RDONLY );
-#endif
- if( fd == -1 && errno == ENOENT)
- {
- allow_seed_file_update = 1;
- return 0;
- }
-
- if (fd == -1 )
- {
- log_info(_("can't open `%s': %s\n"), seed_file_name, strerror(errno) );
- return 0;
- }
- if (lock_seed_file (fd, seed_file_name, 0))
- {
- close (fd);
- return 0;
- }
- if (fstat( fd, &sb ) )
- {
- log_info(_("can't stat `%s': %s\n"), seed_file_name, strerror(errno) );
- close(fd);
- return 0;
- }
- if (!S_ISREG(sb.st_mode) )
- {
- log_info(_("`%s' is not a regular file - ignored\n"), seed_file_name );
- close(fd);
- return 0;
- }
- if (!sb.st_size )
- {
- log_info(_("note: random_seed file is empty\n") );
- close(fd);
- allow_seed_file_update = 1;
- return 0;
- }
- if (sb.st_size != POOLSIZE )
- {
- log_info(_("warning: invalid size of random_seed file - not used\n") );
- close(fd);
- return 0;
- }
-
- do
- {
- n = read( fd, buffer, POOLSIZE );
- }
- while (n == -1 && errno == EINTR );
-
- if (n != POOLSIZE)
- {
- log_fatal(_("can't read `%s': %s\n"), seed_file_name,strerror(errno) );
- close(fd);/*NOTREACHED*/
- return 0;
- }
-
- close(fd);
-
- add_randomness( buffer, POOLSIZE, RANDOM_ORIGIN_INIT );
- /* add some minor entropy to the pool now (this will also force a mixing) */
- {
- pid_t x = getpid();
- add_randomness( &x, sizeof(x), RANDOM_ORIGIN_INIT );
- }
- {
- time_t x = time(NULL);
- add_randomness( &x, sizeof(x), RANDOM_ORIGIN_INIT );
- }
- {
- clock_t x = clock();
- add_randomness( &x, sizeof(x), RANDOM_ORIGIN_INIT );
- }
-
- /* And read a few bytes from our entropy source. By using a level
- * of 0 this will not block and might not return anything with some
- * entropy drivers, however the rndlinux driver will use
- * /dev/urandom and return some stuff - Do not read too much as we
- * want to be friendly to the scare system entropy resource. */
- read_random_source ( RANDOM_ORIGIN_INIT, 16, GCRY_WEAK_RANDOM );
-
- allow_seed_file_update = 1;
- return 1;
+ _gcry_rngcsprng_set_seed_file (name);
}
+/* If a seed file has been setup, this function may be used to write
+ back the random numbers entropy pool. */
void
-_gcry_update_random_seed_file()
-{
- unsigned long *sp, *dp;
- int fd, i;
-
- /* We do only a basic initialization so that we can lock the pool.
- This is required to cope with the case that this function is
- called by some cleanup code at a point where the RNG has never
- been initialized. */
- initialize_basics ();
- lock_pool ();
-
- if ( !seed_file_name || !rndpool || !pool_filled )
- {
- unlock_pool ();
- return;
- }
- if ( !allow_seed_file_update )
- {
- unlock_pool ();
- log_info(_("note: random_seed file not updated\n"));
- return;
- }
-
- /* At this point we know that there is something in the pool and
- thus we can conclude that the pool has been fully initialized. */
-
-
- /* Copy the entropy pool to a scratch pool and mix both of them. */
- for (i=0,dp=(unsigned long*)keypool, sp=(unsigned long*)rndpool;
- i < POOLWORDS; i++, dp++, sp++ )
- {
- *dp = *sp + ADD_VALUE;
- }
- mix_pool(rndpool); rndstats.mixrnd++;
- mix_pool(keypool); rndstats.mixkey++;
-
-#if defined(HAVE_DOSISH_SYSTEM) || defined(__CYGWIN__)
- fd = open (seed_file_name, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY,
- S_IRUSR|S_IWUSR );
-#else
-# if LOCK_SEED_FILE
- fd = open (seed_file_name, O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR );
-# else
- fd = open (seed_file_name, O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR );
-# endif
-#endif
-
- if (fd == -1 )
- log_info (_("can't create `%s': %s\n"), seed_file_name, strerror(errno) );
- else if (lock_seed_file (fd, seed_file_name, 1))
- {
- close (fd);
- }
-#if LOCK_SEED_FILE
- else if (ftruncate (fd, 0))
- {
- log_info(_("can't write `%s': %s\n"), seed_file_name, strerror(errno));
- close (fd);
- }
-#endif /*LOCK_SEED_FILE*/
- else
- {
- do
- {
- i = write (fd, keypool, POOLSIZE );
- }
- while (i == -1 && errno == EINTR);
- if (i != POOLSIZE)
- log_info (_("can't write `%s': %s\n"),seed_file_name, strerror(errno));
- if (close(fd))
- log_info (_("can't close `%s': %s\n"),seed_file_name, strerror(errno));
- }
-
- unlock_pool ();
-}
-
-
-/* Read random out of the pool. This function is the core of the
- public random functions. Note that Level GCRY_WEAK_RANDOM is not
- anymore handled special and in fact is an alias in the API for
- level GCRY_STRONG_RANDOM. Must be called with the pool already
- locked. */
-static void
-read_pool (byte *buffer, size_t length, int level)
+_gcry_update_random_seed_file (void)
{
- int i;
- unsigned long *sp, *dp;
- /* The volatile is there to make sure the compiler does not optimize
- the code away in case the getpid function is badly attributed.
- Note that we keep a pid in a static variable as well as in a
- stack based one; the latter is to detect ill behaving thread
- libraries, ignoring the pool mutexes. */
- static volatile pid_t my_pid = (pid_t)(-1);
- volatile pid_t my_pid2;
-
- assert (pool_is_locked);
-
- retry:
- /* Get our own pid, so that we can detect a fork. */
- my_pid2 = getpid ();
- if (my_pid == (pid_t)(-1))
- my_pid = my_pid2;
- if ( my_pid != my_pid2 )
- {
- /* We detected a plain fork; i.e. we are now the child. Update
- the static pid and add some randomness. */
- pid_t x;
-
- my_pid = my_pid2;
- x = my_pid;
- add_randomness (&x, sizeof(x), RANDOM_ORIGIN_INIT);
- just_mixed = 0; /* Make sure it will get mixed. */
- }
-
- assert (pool_is_locked);
-
- /* Our code does not allow to extract more than POOLSIZE. Better
- check it here. */
- if (length > POOLSIZE)
- {
- log_bug("too many random bits requested\n");
- }
-
- if (!pool_filled)
- {
- if (read_seed_file() )
- pool_filled = 1;
- }
-
- /* For level 2 quality (key generation) we always make sure that the
- pool has been seeded enough initially. */
- if (level == GCRY_VERY_STRONG_RANDOM && !did_initial_extra_seeding)
- {
- size_t needed;
-
- pool_balance = 0;
- needed = length - pool_balance;
- if (needed < POOLSIZE/2)
- needed = POOLSIZE/2;
- else if( needed > POOLSIZE )
- BUG ();
- read_random_source (RANDOM_ORIGIN_EXTRAPOLL, needed,
- GCRY_VERY_STRONG_RANDOM);
- pool_balance += needed;
- did_initial_extra_seeding = 1;
- }
-
- /* For level 2 make sure that there is enough random in the pool. */
- if (level == GCRY_VERY_STRONG_RANDOM && pool_balance < length)
- {
- size_t needed;
-
- if (pool_balance < 0)
- pool_balance = 0;
- needed = length - pool_balance;
- if (needed > POOLSIZE)
- BUG ();
- read_random_source (RANDOM_ORIGIN_EXTRAPOLL, needed,
- GCRY_VERY_STRONG_RANDOM);
- pool_balance += needed;
- }
-
- /* Make sure the pool is filled. */
- while (!pool_filled)
- random_poll();
-
- /* Always do a fast random poll (we have to use the unlocked version). */
- do_fast_random_poll();
-
- /* Mix the pid in so that we for sure won't deliver the same random
- after a fork. */
- {
- pid_t apid = my_pid;
- add_randomness (&apid, sizeof (apid), RANDOM_ORIGIN_INIT);
- }
-
- /* Mix the pool (if add_randomness() didn't it). */
- if (!just_mixed)
- {
- mix_pool(rndpool);
- rndstats.mixrnd++;
- }
-
- /* Create a new pool. */
- for(i=0,dp=(unsigned long*)keypool, sp=(unsigned long*)rndpool;
- i < POOLWORDS; i++, dp++, sp++ )
- *dp = *sp + ADD_VALUE;
-
- /* Mix both pools. */
- mix_pool(rndpool); rndstats.mixrnd++;
- mix_pool(keypool); rndstats.mixkey++;
-
- /* Read the requested data. We use a read pointer to read from a
- different position each time. */
- while (length--)
- {
- *buffer++ = keypool[pool_readpos++];
- if (pool_readpos >= POOLSIZE)
- pool_readpos = 0;
- pool_balance--;
- }
-
- if (pool_balance < 0)
- pool_balance = 0;
-
- /* Clear the keypool. */
- memset (keypool, 0, POOLSIZE);
-
- /* We need to detect whether a fork has happened. A fork might have
- an identical pool and thus the child and the parent could emit
- the very same random number. This test here is to detect forks
- in a multi-threaded process. It does not work with all thread
- implementations in particular not with pthreads. However it is
- good enough for GNU Pth. */
- if ( getpid () != my_pid2 )
- {
- pid_t x = getpid();
- add_randomness (&x, sizeof(x), RANDOM_ORIGIN_INIT);
- just_mixed = 0; /* Make sure it will get mixed. */
- my_pid = x; /* Also update the static pid. */
- goto retry;
- }
-}
-
-
-
-/* Add LENGTH bytes of randomness from buffer to the pool. ORIGIN is
- used to specify the randomness origin. This is one of the
- RANDOM_ORIGIN_* values. */
-static void
-add_randomness (const void *buffer, size_t length, enum random_origins origin)
-{
- const unsigned char *p = buffer;
- size_t count = 0;
-
- assert (pool_is_locked);
+ if (!fips_is_operational ())
+ return;
- rndstats.addbytes += length;
- rndstats.naddbytes++;
- while (length-- )
- {
- rndpool[pool_writepos++] ^= *p++;
- count++;
- if (pool_writepos >= POOLSIZE )
- {
- /* It is possible that we are invoked before the pool is
- filled using an unreliable origin of entropy, for example
- the fast random poll. To avoid flagging the pool as
- filled in this case, we track the initial filling state
- separately. See also the remarks about the seed file. */
- if (origin >= RANDOM_ORIGIN_SLOWPOLL && !pool_filled)
- {
- pool_filled_counter += count;
- count = 0;
- if (pool_filled_counter >= POOLSIZE)
- pool_filled = 1;
- }
- pool_writepos = 0;
- mix_pool(rndpool); rndstats.mixrnd++;
- just_mixed = !length;
- }
- }
+ _gcry_rngcsprng_update_seed_file ();
}
-static void
-random_poll()
-{
- rndstats.slowpolls++;
- read_random_source (RANDOM_ORIGIN_SLOWPOLL, POOLSIZE/5, GCRY_STRONG_RANDOM);
-}
-
-
-/* Runtime determination of the slow entropy gathering module. */
-static int (*
-getfnc_gather_random (void))(void (*)(const void*, size_t,
- enum random_origins),
- enum random_origins, size_t, int)
-{
- int (*fnc)(void (*)(const void*, size_t, enum random_origins),
- enum random_origins, size_t, int);
-
-#if USE_RNDLINUX
- if ( !access (NAME_OF_DEV_RANDOM, R_OK)
- && !access (NAME_OF_DEV_URANDOM, R_OK))
- {
- fnc = _gcry_rndlinux_gather_random;
- return fnc;
- }
-#endif
-
-#if USE_RNDEGD
- if ( _gcry_rndegd_connect_socket (1) != -1 )
- {
- fnc = _gcry_rndegd_gather_random;
- return fnc;
- }
-#endif
-
-#if USE_RNDUNIX
- fnc = _gcry_rndunix_gather_random;
- return fnc;
-#endif
-
-#if USE_RNDW32
- fnc = _gcry_rndw32_gather_random;
- return fnc;
-#endif
-
- log_fatal (_("no entropy gathering module detected\n"));
-
- return NULL; /*NOTREACHED*/
-}
-
-/* Runtime determination of the fast entropy gathering function.
- (Currently a compile time method is used.) */
-static void (*
-getfnc_fast_random_poll (void))( void (*)(const void*, size_t,
- enum random_origins),
- enum random_origins)
-{
-#if USE_RNDW32
- return _gcry_rndw32_gather_random_fast;
-#endif
- return NULL;
-}
-
-
-
-static void
-do_fast_random_poll (void)
-{
- assert (pool_is_locked);
-
- rndstats.fastpolls++;
-
- if (fast_gather_fnc)
- fast_gather_fnc (add_randomness, RANDOM_ORIGIN_FASTPOLL);
-
- /* Continue with the generic functions. */
-#if HAVE_GETHRTIME
- {
- hrtime_t tv;
- tv = gethrtime();
- add_randomness( &tv, sizeof(tv), RANDOM_ORIGIN_FASTPOLL );
- }
-#elif HAVE_GETTIMEOFDAY
- {
- struct timeval tv;
- if( gettimeofday( &tv, NULL ) )
- BUG();
- add_randomness( &tv.tv_sec, sizeof(tv.tv_sec), RANDOM_ORIGIN_FASTPOLL );
- add_randomness( &tv.tv_usec, sizeof(tv.tv_usec), RANDOM_ORIGIN_FASTPOLL );
- }
-#elif HAVE_CLOCK_GETTIME
- { struct timespec tv;
- if( clock_gettime( CLOCK_REALTIME, &tv ) == -1 )
- BUG();
- add_randomness( &tv.tv_sec, sizeof(tv.tv_sec), RANDOM_ORIGIN_FASTPOLL );
- add_randomness( &tv.tv_nsec, sizeof(tv.tv_nsec), RANDOM_ORIGIN_FASTPOLL );
- }
-#else /* use times */
-# ifndef HAVE_DOSISH_SYSTEM
- { struct tms buf;
- times( &buf );
- add_randomness( &buf, sizeof buf, RANDOM_ORIGIN_FASTPOLL );
- }
-# endif
-#endif
-
-#ifdef HAVE_GETRUSAGE
-# ifdef RUSAGE_SELF
- {
- struct rusage buf;
- /* QNX/Neutrino does return ENOSYS - so we just ignore it and add
- whatever is in buf. In a chroot environment it might not work
- at all (i.e. because /proc/ is not accessible), so we better
- ignore all error codes and hope for the best. */
- getrusage (RUSAGE_SELF, &buf );
- add_randomness( &buf, sizeof buf, RANDOM_ORIGIN_FASTPOLL );
- memset( &buf, 0, sizeof buf );
- }
-# else /*!RUSAGE_SELF*/
-# ifdef __GCC__
-# warning There is no RUSAGE_SELF on this system
-# endif
-# endif /*!RUSAGE_SELF*/
-#endif /*HAVE_GETRUSAGE*/
-
- /* Time and clock are availabe on all systems - so we better do it
- just in case one of the above functions didn't work. */
- {
- time_t x = time(NULL);
- add_randomness( &x, sizeof(x), RANDOM_ORIGIN_FASTPOLL );
- }
- {
- clock_t x = clock();
- add_randomness( &x, sizeof(x), RANDOM_ORIGIN_FASTPOLL );
- }
-
- /* If the system features a fast hardware RNG, read some bytes from
- there. */
- _gcry_rndhw_poll_fast (add_randomness, RANDOM_ORIGIN_FASTPOLL);
-}
-
-
/* The fast random pool function as called at some places in
libgcrypt. This is merely a wrapper to make sure that this module
- is initalized and to look the pool. Note, that this function is a
+ is initalized and to lock the pool. Note, that this function is a
NOP unless a random function has been used or _gcry_initialize (1)
has been used. We use this hack so that the internal use of this
function in cipher_open and md_open won't start filling up the
@@ -1299,148 +245,18 @@ do_fast_random_poll (void)
void
_gcry_fast_random_poll (void)
{
- initialize_basics ();
-
- lock_pool ();
- if (rndpool)
- {
- /* Yes, we are fully initialized. */
- do_fast_random_poll ();
- }
- unlock_pool ();
-}
-
-
-
-static void
-read_random_source (enum random_origins orgin, size_t length, int level )
-{
- if ( !slow_gather_fnc )
- log_fatal ("Slow entropy gathering module not yet initialized\n");
+ if (!fips_is_operational ())
+ return;
- if ( slow_gather_fnc (add_randomness, orgin, length, level) < 0)
- log_fatal ("No way to gather entropy for the RNG\n");
+ _gcry_rngcsprng_fast_poll ();
}
-static int
-gather_faked (void (*add)(const void*, size_t, enum random_origins),
- enum random_origins origin, size_t length, int level )
-{
- static int initialized=0;
- size_t n;
- char *buffer, *p;
-
- (void)add;
- (void)level;
-
- if ( !initialized )
- {
- log_info(_("WARNING: using insecure random number generator!!\n"));
- initialized=1;
-#ifdef HAVE_RAND
- srand( time(NULL)*getpid());
-#else
- srandom( time(NULL)*getpid());
-#endif
- }
-
- p = buffer = gcry_xmalloc( length );
- n = length;
-#ifdef HAVE_RAND
- while ( n-- )
- *p++ = ((unsigned)(1 + (int) (256.0*rand()/(RAND_MAX+1.0)))-1);
-#else
- while ( n-- )
- *p++ = ((unsigned)(1 + (int) (256.0*random()/(RAND_MAX+1.0)))-1);
-#endif
- add_randomness ( buffer, length, origin );
- gcry_free (buffer);
- return 0; /* okay */
-}
-
/* Create an unpredicable nonce of LENGTH bytes in BUFFER. */
void
gcry_create_nonce (void *buffer, size_t length)
{
- static unsigned char nonce_buffer[20+8];
- static int nonce_buffer_initialized = 0;
- static volatile pid_t my_pid; /* The volatile is there to make sure the
- compiler does not optimize the code away
- in case the getpid function is badly
- attributed. */
- volatile pid_t apid;
- unsigned char *p;
- size_t n;
- int err;
-
- /* Make sure we are initialized. */
- initialize ();
-
-#ifdef USE_RANDOM_DAEMON
- if (allow_daemon
- && !_gcry_daemon_create_nonce (daemon_socket_name, buffer, length))
- return; /* The daemon succeeded. */
- allow_daemon = 0; /* Daemon failed - switch off. */
-#endif /*USE_RANDOM_DAEMON*/
-
- /* Acquire the nonce buffer lock. */
- err = ath_mutex_lock (&nonce_buffer_lock);
- if (err)
- log_fatal ("failed to acquire the nonce buffer lock: %s\n",
- strerror (err));
-
- apid = getpid ();
- /* The first time intialize our buffer. */
- if (!nonce_buffer_initialized)
- {
- time_t atime = time (NULL);
- pid_t xpid = apid;
-
- my_pid = apid;
-
- if ((sizeof apid + sizeof atime) > sizeof nonce_buffer)
- BUG ();
-
- /* Initialize the first 20 bytes with a reasonable value so that
- a failure of gcry_randomize won't affect us too much. Don't
- care about the uninitialized remaining bytes. */
- p = nonce_buffer;
- memcpy (p, &xpid, sizeof xpid);
- p += sizeof xpid;
- memcpy (p, &atime, sizeof atime);
-
- /* Initialize the never changing private part of 64 bits. */
- gcry_randomize (nonce_buffer+20, 8, GCRY_WEAK_RANDOM);
-
- nonce_buffer_initialized = 1;
- }
- else if ( my_pid != apid )
- {
- /* We forked. Need to reseed the buffer - doing this for the
- private part should be sufficient. */
- gcry_randomize (nonce_buffer+20, 8, GCRY_WEAK_RANDOM);
- /* Update the pid so that we won't run into here again and
- again. */
- my_pid = apid;
- }
-
- /* Create the nonce by hashing the entire buffer, returning the hash
- and updating the first 20 bytes of the buffer with this hash. */
- for (p = buffer; length > 0; length -= n, p += n)
- {
- _gcry_sha1_hash_buffer (nonce_buffer,
- nonce_buffer, sizeof nonce_buffer);
- n = length > 20? 20 : length;
- memcpy (p, nonce_buffer, n);
- }
-
-
- /* Release the nonce buffer lock. */
- err = ath_mutex_unlock (&nonce_buffer_lock);
- if (err)
- log_fatal ("failed to release the nonce buffer lock: %s\n",
- strerror (err));
-
+ _gcry_rngcsprng_create_nonce (buffer, length);
}
+
diff --git a/random/random.h b/random/random.h
index 726a3794..1db189ea 100644
--- a/random/random.h
+++ b/random/random.h
@@ -22,9 +22,10 @@
#include "types.h"
-void _gcry_random_initialize (int full);
void _gcry_register_random_progress (void (*cb)(void *,const char*,int,int,int),
void *cb_data );
+
+void _gcry_random_initialize (int full);
void _gcry_random_dump_stats(void);
void _gcry_secure_random_alloc(void);
void _gcry_enable_quick_random_gen (void);
diff --git a/src/ChangeLog b/src/ChangeLog
index 427e86e6..6e63dd60 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,62 @@
+2008-08-15 Werner Koch <wk@g10code.com>
+
+ * gcrypt.h.in (gcry_cipher_setkey): Replace macro by function.
+ (gcry_cipher_setiv): Ditto.
+ (gcry_cipher_setctr): Ditto.
+ * visibility.c (gcry_cipher_setkey, gcry_cipher_setiv)
+ (gcry_cipher_setctr): New.
+ * visibility.h (gcry_cipher_setkey, gcry_cipher_setiv)
+ (gcry_cipher_setctr): New.
+ * libgcrypt.vers (gcry_cipher_setkey, gcry_cipher_setiv)
+ (gcry_cipher_setctr): New.
+ * libgcrypt.def (gcry_cipher_setkey, gcry_cipher_setiv)
+ (gcry_cipher_setctr): New.
+
+ * hmac256.h, hmac256.c: New.
+ * Makefile.am (hmac256_SOURCES): New.
+ * Makefile.am (bin_PROGRAMS): Add hmac256.
+
+ * gcrypt.h.in (struct gcry_thread_cbs): Change type of OPTION to
+ unsigned int. Although this is a type change it does not make a
+ difference.
+ * ath.c (ath_install): Take the version of the option field in
+ account.
+
+ * visibility.c (gcry_pk_encrypt, gcry_pk_decrypt, gcry_pk_sign)
+ (gcry_pk_verify, gcry_pk_testkey, gcry_pk_genkey)
+ (gcry_pk_get_nbits, gcry_pk_get_keygrip)
+ (gcry_md_open, gcry_md_copy, gcry_md_enable)
+ (gcry_md_write, md_final, gcry_md_ctl, gcry_md_setkey)
+ (gcry_md_hash_buffer, gcry_md_get_algo, gcry_md_info)
+ (gcry_md_is_enabled)
+ (gcry_cipher_open, gcry_cipher_encrypt)
+ (gcry_cipher_decrypt, gcry_cipher_ctl)
+ (gcry_cipher_algo_info): Check whether the library is operational.
+
+ * cipher-proto.h: New.
+ * cipher.h: Include cipher-proto.h.
+ * visibility.h: Remove duplicate macro definitions. Remove
+ gcry_cipher_register, gcry_md_register, gcry_pk_register macros.
+ * visibility.c: Include cipher-proto.h.
+ (gcry_cipher_register): Pass dummy extra args to the internal
+ register function.
+ (gcry_md_register, gcry_pk_register): Ditto.
+ * g10lib.h (struct gcry_module): Add field EXTRASPEC.
+ * module.c (_gcry_module_add): Add arg EXTRASPEC. Changed all
+ callers to pass NULL.
+
+ * fips.c: New.
+ * gcrypt.h.in (GCRYCTL_FIPS_MODE_P): New.
+ * global.c (global_init): Call fips initialization.
+ (_gcry_vcontrol): Add GCRYCTL_FIPS_MODE_P code.
+ (print_config): Add config item fips-mode.
+ (gcry_set_allocation_handler): Do not allow the use of custom
+ allocation handlers.
+ (gcry_set_outofcore_handler): Ditto.
+ (_gcry_get_debug_flag): Do not return any debug flags in fips mode.
+ * misc.c (_gcry_logv): Signal fips error on BUG or FATAL.
+ (_gcry_fatal_error): Ditto.
+
2008-07-05 Werner Koch <wk@g10code.com>
* Makefile.am: Include librandom.la.
diff --git a/src/Makefile.am b/src/Makefile.am
index 046116a2..d9a58457 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -28,7 +28,7 @@ m4data_DATA = libgcrypt.m4
include_HEADERS = gcrypt.h gcrypt-module.h
lib_LTLIBRARIES = libgcrypt.la
-bin_PROGRAMS = dumpsexp
+bin_PROGRAMS = dumpsexp hmac256
if USE_RANDOM_DAEMON
sbin_PROGRAMS = gcryptrnd
bin_PROGRAMS += getrandom
@@ -42,10 +42,12 @@ else
endif
libgcrypt_la_CFLAGS = @GPG_ERROR_CFLAGS@
-libgcrypt_la_SOURCES = g10lib.h visibility.c visibility.h types.h cipher.h \
+libgcrypt_la_SOURCES = g10lib.h visibility.c visibility.h types.h \
+ cipher.h cipher-proto.h \
misc.c global.c sexp.c hwfeatures.c \
stdmem.c stdmem.h secmem.c secmem.h \
- mpi.h missing-string.c module.c \
+ mpi.h missing-string.c module.c fips.c \
+ hmac256.c hmac256.h \
ath.h ath.c
if HAVE_W32_SYSTEM
@@ -103,6 +105,10 @@ libgcrypt_la_LIBADD = \
dumpsexp_SOURCES = dumpsexp.c
dumpsexp_LDADD =
+hmac256_SOURCES = hmac256.c
+hmac256_CFLAGS = -DSTANDALONE
+hmac256_LDADD =
+
if USE_RANDOM_DAEMON
gcryptrnd_SOURCES = gcryptrnd.c
gcryptrnd_CFLAGS = $(GPG_ERROR_CFLAGS) $(PTH_CFLAGS)
diff --git a/src/ath.c b/src/ath.c
index 66fa50ac..edfaada6 100644
--- a/src/ath.c
+++ b/src/ath.c
@@ -52,6 +52,12 @@ static int ops_set;
#define MUTEX_DESTROYED ((ath_mutex_t) 2)
+/* Return the thread type from the option field. */
+#define GET_OPTION(a) ((a) & 0xff)
+/* Return the version number from the option field. */
+#define GET_VERSION(a) (((a) >> 8)& 0xff)
+
+
/* The lock we take while checking for lazy lock initialization. */
static ath_mutex_t check_init_lock = ATH_MUTEX_INITIALIZER;
@@ -81,19 +87,20 @@ ath_install (struct ath_ops *ath_ops, int check_only)
{
if (check_only)
{
- enum ath_thread_option option = ATH_THREAD_OPTION_DEFAULT;
+ unsigned int option = 0;
/* Check if the requested thread option is compatible to the
thread option we are already committed to. */
if (ath_ops)
option = ath_ops->option;
- if (!ops_set && option)
+ if (!ops_set && GET_OPTION (option))
return GPG_ERR_NOT_SUPPORTED;
- if (ops.option == ATH_THREAD_OPTION_USER
- || option == ATH_THREAD_OPTION_USER
- || ops.option != option)
+ if (GET_OPTION (ops.option) == ATH_THREAD_OPTION_USER
+ || GET_OPTION (option) == ATH_THREAD_OPTION_USER
+ || GET_OPTION (ops.option) != GET_OPTION (option)
+ || GET_VERSION (ops.option) != GET_VERSION (option))
return GPG_ERR_NOT_SUPPORTED;
return 0;
diff --git a/src/ath.h b/src/ath.h
index a75c4f1c..3c9e56a0 100644
--- a/src/ath.h
+++ b/src/ath.h
@@ -67,7 +67,13 @@ enum ath_thread_option
struct ath_ops
{
- enum ath_thread_option option;
+ /* The OPTION field encodes the thread model and the version number
+ of this structure.
+ Bits 7 - 0 are used for the thread model
+ Bits 15 - 8 are used for the version number.
+ */
+ unsigned int option;
+
int (*init) (void);
int (*mutex_init) (void **priv);
int (*mutex_destroy) (void *priv);
diff --git a/src/cipher-proto.h b/src/cipher-proto.h
new file mode 100644
index 00000000..4b826c1d
--- /dev/null
+++ b/src/cipher-proto.h
@@ -0,0 +1,83 @@
+/* cipher-proto.h - Internal declarations
+ * 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/>.
+ */
+
+/* This file has been factored out from cipher.h so that it can be
+ used standalone in visibility.c . */
+
+#ifndef G10_CIPHER_PROTO_H
+#define G10_CIPHER_PROTO_H
+
+/* Definition of a function used to report selftest failures.
+ DOMAIN is a string describing the function block:
+ "cipher", "digest", "pubkey or "random",
+ ALGO is the algorithm under test,
+ WHAT is a string describing what has been tested,
+ DESC is a string describing the error. */
+typedef void (*selftest_report_func_t)(const char *domain,
+ int algo,
+ const char *what,
+ const char *errdesc);
+
+/* Definition of the selftest functions. */
+typedef gpg_err_code_t (*selftest_func_t)
+ (int algo, selftest_report_func_t report);
+
+
+/* Extra module specification structures. These are used for internal
+ modules which provide more functions than available through the
+ public algorithm register APIs. */
+typedef struct cipher_extra_spec
+{
+ selftest_func_t selftest;
+} cipher_extra_spec_t;
+
+typedef struct md_extra_spec
+{
+ selftest_func_t selftest;
+} md_extra_spec_t;
+
+typedef struct pk_extra_spec
+{
+ selftest_func_t selftest;
+} pk_extra_spec_t;
+
+
+
+/* The private register functions. */
+gcry_error_t _gcry_cipher_register (gcry_cipher_spec_t *cipher,
+ cipher_extra_spec_t *extraspec,
+ int *algorithm_id,
+ gcry_module_t *module);
+gcry_error_t _gcry_md_register (gcry_md_spec_t *cipher,
+ md_extra_spec_t *extraspec,
+ unsigned int *algorithm_id,
+ gcry_module_t *module);
+gcry_error_t _gcry_pk_register (gcry_pk_spec_t *cipher,
+ pk_extra_spec_t *extraspec,
+ unsigned int *algorithm_id,
+ gcry_module_t *module);
+
+/* The selftest functions. */
+gcry_error_t _gcry_cipher_selftest (int algo, selftest_report_func_t report);
+gcry_error_t _gcry_md_selftest (int algo, selftest_report_func_t report);
+gcry_error_t _gcry_pk_selftest (int algo, selftest_report_func_t report);
+gcry_error_t _gcry_hmac_selftest (int algo, selftest_report_func_t report);
+
+
+#endif /*G10_CIPHER_PROTO_H*/
diff --git a/src/cipher.h b/src/cipher.h
index bec4453c..91b5831f 100644
--- a/src/cipher.h
+++ b/src/cipher.h
@@ -28,6 +28,9 @@
#define PUBKEY_FLAG_NO_BLINDING (1 << 0)
+#include "cipher-proto.h"
+
+
/*-- rmd160.c --*/
void _gcry_rmd160_hash_buffer (void *outbuf,
const void *buffer, size_t length);
@@ -102,6 +105,12 @@ extern gcry_cipher_spec_t _gcry_cipher_spec_camellia128;
extern gcry_cipher_spec_t _gcry_cipher_spec_camellia192;
extern gcry_cipher_spec_t _gcry_cipher_spec_camellia256;
+extern cipher_extra_spec_t _gcry_cipher_extraspec_tripledes;
+extern cipher_extra_spec_t _gcry_cipher_extraspec_aes;
+extern cipher_extra_spec_t _gcry_cipher_extraspec_aes192;
+extern cipher_extra_spec_t _gcry_cipher_extraspec_aes256;
+
+
/* Declarations for the digest specifications. */
extern gcry_md_spec_t _gcry_digest_spec_crc32;
extern gcry_md_spec_t _gcry_digest_spec_crc32_rfc1510;
@@ -117,10 +126,21 @@ extern gcry_md_spec_t _gcry_digest_spec_sha384;
extern gcry_md_spec_t _gcry_digest_spec_tiger;
extern gcry_md_spec_t _gcry_digest_spec_whirlpool;
+extern md_extra_spec_t _gcry_digest_extraspec_sha1;
+extern md_extra_spec_t _gcry_digest_extraspec_sha224;
+extern md_extra_spec_t _gcry_digest_extraspec_sha256;
+extern md_extra_spec_t _gcry_digest_extraspec_sha384;
+extern md_extra_spec_t _gcry_digest_extraspec_sha512;
+
/* Declarations for the pubkey cipher specifications. */
extern gcry_pk_spec_t _gcry_pubkey_spec_rsa;
extern gcry_pk_spec_t _gcry_pubkey_spec_elg;
extern gcry_pk_spec_t _gcry_pubkey_spec_dsa;
extern gcry_pk_spec_t _gcry_pubkey_spec_ecdsa;
+extern pk_extra_spec_t _gcry_pubkey_extraspec_rsa;
+extern pk_extra_spec_t _gcry_pubkey_extraspec_dsa;
+extern pk_extra_spec_t _gcry_pubkey_extraspec_ecdsa;
+
+
#endif /*G10_CIPHER_H*/
diff --git a/src/g10lib.h b/src/g10lib.h
index 82c34427..701656f5 100644
--- a/src/g10lib.h
+++ b/src/g10lib.h
@@ -39,6 +39,7 @@
#include "visibility.h"
#include "types.h"
+
/* Attribute handling macros. */
@@ -211,6 +212,8 @@ struct gcry_module
struct gcry_module **prevp;
void *spec; /* Pointer to the subsystem-specific
specification structure. */
+ void *extraspec; /* Pointer to the subsystem-specific
+ extra specification structure. */
int flags; /* Associated flags. */
int counter; /* Use counter. */
unsigned int mod_id; /* ID of this module. */
@@ -220,9 +223,10 @@ struct gcry_module
#define FLAG_MODULE_DISABLED (1 << 0)
gcry_err_code_t _gcry_module_add (gcry_module_t *entries,
- unsigned int id,
- void *spec,
- gcry_module_t *module);
+ unsigned int id,
+ void *spec,
+ void *extraspec,
+ gcry_module_t *module);
typedef int (*gcry_module_lookup_t) (void *spec, void *data);
@@ -265,4 +269,41 @@ gcry_error_t _gcry_sexp_vbuild (gcry_sexp_t *retsexp, size_t *erroff,
char *_gcry_sexp_nth_string (const gcry_sexp_t list, int number);
+/*-- fips.c --*/
+
+void _gcry_initialize_fips_mode (int force);
+
+int _gcry_fips_mode (void);
+#define fips_mode() _gcry_fips_mode ()
+
+void _gcry_fips_signal_error (const char *srcfile,
+ int srcline,
+ const char *srcfunc,
+ int is_fatal,
+ const char *description);
+#ifdef JNLIB_GCC_M_FUNCTION
+# define fips_signal_error(a) \
+ _gcry_fips_signal_error (__FILE__, __LINE__, __FUNCTION__, 0, (a))
+# define fips_signal_fatal_error(a) \
+ _gcry_fips_signal_error (__FILE__, __LINE__, __FUNCTION__, 1, (a))
+#else
+# define fips_signal_error(a) \
+ _gcry_fips_signal_error (__FILE__, __LINE__, NULL, 0, (a))
+# define fips_signal_fatal_error(a) \
+ _gcry_fips_signal_error (__FILE__, __LINE__, NULL, 1, (a))
+#endif
+
+int _gcry_fips_is_operational (void);
+#define fips_is_operational() (_gcry_fips_is_operational ())
+#define fips_not_operational() (GCRY_GPG_ERR_NOT_OPERATIONAL)
+
+int _gcry_fips_test_operational (void);
+
+void _gcry_fips_run_selftests (void);
+
+void _gcry_fips_noreturn (void);
+#define fips_noreturn() (_gcry_fips_noreturn ())
+
+
+
#endif /* G10LIB_H */
diff --git a/src/gcrypt-module.h b/src/gcrypt-module.h
index 5d0a9ae0..39d39c86 100644
--- a/src/gcrypt-module.h
+++ b/src/gcrypt-module.h
@@ -88,7 +88,7 @@ typedef struct gcry_cipher_spec
/* Register a new cipher module whose specification can be found in
CIPHER. On success, a new algorithm ID is stored in ALGORITHM_ID
- and a pointer representhing this module is stored in MODULE. */
+ and a pointer representing this module is stored in MODULE. */
gcry_error_t gcry_cipher_register (gcry_cipher_spec_t *cipher,
int *algorithm_id,
gcry_module_t *module);
diff --git a/src/gcrypt.h.in b/src/gcrypt.h.in
index 0b9472bb..d2bf589b 100644
--- a/src/gcrypt.h.in
+++ b/src/gcrypt.h.in
@@ -1,6 +1,6 @@
/* gcrypt.h - GNU Cryptographic Library Interface -*- c -*-
Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2006
- 2007 Free Software Foundation, Inc.
+ 2007, 2008 Free Software Foundation, Inc.
This file is part of Libgcrypt.
@@ -46,7 +46,7 @@
#ifdef __cplusplus
extern "C" {
-#if 0 /* keep Emacsens' auto-indent happy */
+#if 0 /* (Keep Emacsens' auto-indent happy.) */
}
#endif
#endif
@@ -170,18 +170,35 @@ gcry_error_t gcry_err_make_from_errno (gcry_err_source_t source, int err);
gcry_err_code_t gcry_error_from_errno (int err);
+/* This enum is deprecated; it is only declared for the sake of
+ complete API compatibility. */
enum gcry_thread_option
{
- GCRY_THREAD_OPTION_DEFAULT = 0,
- GCRY_THREAD_OPTION_USER = 1,
- GCRY_THREAD_OPTION_PTH = 2,
- GCRY_THREAD_OPTION_PTHREAD = 3
- };
+ _GCRY_THREAD_OPTION_DUMMY
+ } _GCRY_GCC_ATTR_DEPRECATED;
+
+
+/* Constants defining the thread model to use. Used with the OPTION
+ field of the struct gcry_thread_cbs. */
+#define GCRY_THREAD_OPTION_DEFAULT 0
+#define GCRY_THREAD_OPTION_USER 1
+#define GCRY_THREAD_OPTION_PTH 2
+#define GCRY_THREAD_OPTION_PTHREAD 3
+
+/* The version number encoded in the OPTION field of the struct
+ gcry_thread_cbs. */
+#define GCRY_THREAD_OPTION_VERSION 0
/* Wrapper for struct ath_ops. */
struct gcry_thread_cbs
{
- enum gcry_thread_option option;
+ /* The OPTION field encodes the thread model and the version number
+ of this structure.
+ Bits 7 - 0 are used for the thread model
+ Bits 15 - 8 are used for the version number.
+ */
+ unsigned int option;
+
int (*init) (void);
int (*mutex_init) (void **priv);
int (*mutex_destroy) (void **priv);
@@ -276,8 +293,9 @@ static ssize_t gcry_pth_write (int fd, const void *buf, size_t nbytes) \
{ return pth_write (fd, buf, nbytes); } \
_GCRY_THREAD_OPTION_PTH_IMPL_NET \
\
-/* FIXME: GNU Pth is missing pth_sendmsg and pth_recvmsg. */ \
-static struct gcry_thread_cbs gcry_threads_pth = { GCRY_THREAD_OPTION_PTH, \
+/* Note: GNU Pth is missing pth_sendmsg and pth_recvmsg. */ \
+static struct gcry_thread_cbs gcry_threads_pth = { \
+ (GCRY_THREAD_OPTION_PTH | (GCRY_THREAD_OPTION_VERSION << 8)), \
gcry_pth_init, gcry_pth_mutex_init, gcry_pth_mutex_destroy, \
gcry_pth_mutex_lock, gcry_pth_mutex_unlock, gcry_pth_read, gcry_pth_write, \
gcry_pth_select, gcry_pth_waitpid, gcry_pth_accept, gcry_pth_connect, \
@@ -310,9 +328,9 @@ static int gcry_pthread_mutex_lock (void **lock) \
static int gcry_pthread_mutex_unlock (void **lock) \
{ return pthread_mutex_unlock ((pthread_mutex_t*)*lock); } \
\
-static struct gcry_thread_cbs gcry_threads_pthread = \
-{ GCRY_THREAD_OPTION_PTHREAD, NULL, \
- gcry_pthread_mutex_init, gcry_pthread_mutex_destroy, \
+static struct gcry_thread_cbs gcry_threads_pthread = { \
+ (GCRY_THREAD_OPTION_PTHREAD | (GCRY_THREAD_OPTION_VERSION << 8)), \
+ NULL, gcry_pthread_mutex_init, gcry_pthread_mutex_destroy, \
gcry_pthread_mutex_lock, gcry_pthread_mutex_unlock, \
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }
@@ -387,7 +405,10 @@ enum gcry_ctl_cmds
GCRYCTL_USE_RANDOM_DAEMON = 50,
GCRYCTL_FAKED_RANDOM_P = 51,
GCRYCTL_SET_RNDEGD_SOCKET = 52,
- GCRYCTL_PRINT_CONFIG = 53
+ GCRYCTL_PRINT_CONFIG = 53,
+ GCRYCTL_OPERATIONAL_P = 54,
+ GCRYCTL_FIPS_MODE_P = 55,
+ GCRYCTL_FORCE_FIPS_MODE = 56
};
/* Perform various operations defined by CMD. */
@@ -525,7 +546,7 @@ gcry_mpi_t gcry_sexp_nth_mpi (gcry_sexp_t list, int number, int mpifmt);
/*******************************************
* *
- * multi precision integer functions *
+ * Multi Precision Integer Functions *
* *
*******************************************/
@@ -533,20 +554,20 @@ gcry_mpi_t gcry_sexp_nth_mpi (gcry_sexp_t list, int number, int mpifmt);
enum gcry_mpi_format
{
GCRYMPI_FMT_NONE= 0,
- GCRYMPI_FMT_STD = 1, /* twos complement stored without length */
- GCRYMPI_FMT_PGP = 2, /* As used by OpenPGP (only defined as unsigned)*/
- GCRYMPI_FMT_SSH = 3, /* As used by SSH (same as 1 but with length)*/
- GCRYMPI_FMT_HEX = 4, /* hex format */
- GCRYMPI_FMT_USG = 5 /* like STD but this is an unsigned one */
+ GCRYMPI_FMT_STD = 1, /* Twos complement stored without length. */
+ GCRYMPI_FMT_PGP = 2, /* As used by OpenPGP (unsigned only). */
+ GCRYMPI_FMT_SSH = 3, /* As used by SSH (like STD but with length). */
+ GCRYMPI_FMT_HEX = 4, /* Hex format. */
+ GCRYMPI_FMT_USG = 5 /* Like STD but unsigned. */
};
/* Flags used for creating big integers. */
enum gcry_mpi_flag
{
- GCRYMPI_FLAG_SECURE = 1, /* Allocate the number in "secure" memory. */
- GCRYMPI_FLAG_OPAQUE = 2 /* The number is not a real one but just a
- way to store some bytes. This is
- useful for encrypted big integers. */
+ GCRYMPI_FLAG_SECURE = 1, /* Allocate the number in "secure" memory. */
+ GCRYMPI_FLAG_OPAQUE = 2 /* The number is not a real one but just
+ a way to store some bytes. This is
+ useful for encrypted big integers. */
};
@@ -710,7 +731,7 @@ void gcry_mpi_clear_flag (gcry_mpi_t a, enum gcry_mpi_flag flag);
int gcry_mpi_get_flag (gcry_mpi_t a, enum gcry_mpi_flag flag);
/* Unless the GCRYPT_NO_MPI_MACROS is used, provide a couple of
- convenience macors for the big integer functions. */
+ convenience macros for the big integer functions. */
#ifndef GCRYPT_NO_MPI_MACROS
#define mpi_new(n) gcry_mpi_new( (n) )
#define mpi_secure_new( n ) gcry_mpi_snew( (n) )
@@ -722,28 +743,28 @@ int gcry_mpi_get_flag (gcry_mpi_t a, enum gcry_mpi_flag flag);
} \
while (0)
-#define mpi_copy( a ) gcry_mpi_copy( (a) )
-#define mpi_set( w, u) gcry_mpi_set( (w), (u) )
-#define mpi_set_ui( w, u) gcry_mpi_set_ui( (w), (u) )
-#define mpi_cmp( u, v ) gcry_mpi_cmp( (u), (v) )
-#define mpi_cmp_ui( u, v ) gcry_mpi_cmp_ui( (u), (v) )
-
-#define mpi_add_ui(w,u,v) gcry_mpi_add_ui((w),(u),(v))
-#define mpi_add(w,u,v) gcry_mpi_add ((w),(u),(v))
-#define mpi_addm(w,u,v,m) gcry_mpi_addm ((w),(u),(v),(m))
-#define mpi_sub_ui(w,u,v) gcry_mpi_sub_ui ((w),(u),(v))
-#define mpi_sub(w,u,v) gcry_mpi_sub ((w),(u),(v))
-#define mpi_subm(w,u,v,m) gcry_mpi_subm ((w),(u),(v),(m))
-#define mpi_mul_ui(w,u,v) gcry_mpi_mul_ui ((w),(u),(v))
-#define mpi_mul_2exp(w,u,v) gcry_mpi_mul_2exp ((w),(u),(v))
-#define mpi_mul(w,u,v) gcry_mpi_mul ((w),(u),(v))
-#define mpi_mulm(w,u,v,m) gcry_mpi_mulm ((w),(u),(v),(m))
-#define mpi_powm(w,b,e,m) gcry_mpi_powm ( (w), (b), (e), (m) )
-#define mpi_tdiv(q,r,a,m) gcry_mpi_div ( (q), (r), (a), (m), 0)
-#define mpi_fdiv(q,r,a,m) gcry_mpi_div ( (q), (r), (a), (m), -1)
-#define mpi_mod(r,a,m) gcry_mpi_mod ((r), (a), (m))
-#define mpi_gcd(g,a,b) gcry_mpi_gcd ( (g), (a), (b) )
-#define mpi_invm(g,a,b) gcry_mpi_invm ( (g), (a), (b) )
+#define mpi_copy( a ) gcry_mpi_copy( (a) )
+#define mpi_set( w, u) gcry_mpi_set( (w), (u) )
+#define mpi_set_ui( w, u) gcry_mpi_set_ui( (w), (u) )
+#define mpi_cmp( u, v ) gcry_mpi_cmp( (u), (v) )
+#define mpi_cmp_ui( u, v ) gcry_mpi_cmp_ui( (u), (v) )
+
+#define mpi_add_ui(w,u,v) gcry_mpi_add_ui((w),(u),(v))
+#define mpi_add(w,u,v) gcry_mpi_add ((w),(u),(v))
+#define mpi_addm(w,u,v,m) gcry_mpi_addm ((w),(u),(v),(m))
+#define mpi_sub_ui(w,u,v) gcry_mpi_sub_ui ((w),(u),(v))
+#define mpi_sub(w,u,v) gcry_mpi_sub ((w),(u),(v))
+#define mpi_subm(w,u,v,m) gcry_mpi_subm ((w),(u),(v),(m))
+#define mpi_mul_ui(w,u,v) gcry_mpi_mul_ui ((w),(u),(v))
+#define mpi_mul_2exp(w,u,v) gcry_mpi_mul_2exp ((w),(u),(v))
+#define mpi_mul(w,u,v) gcry_mpi_mul ((w),(u),(v))
+#define mpi_mulm(w,u,v,m) gcry_mpi_mulm ((w),(u),(v),(m))
+#define mpi_powm(w,b,e,m) gcry_mpi_powm ( (w), (b), (e), (m) )
+#define mpi_tdiv(q,r,a,m) gcry_mpi_div ( (q), (r), (a), (m), 0)
+#define mpi_fdiv(q,r,a,m) gcry_mpi_div ( (q), (r), (a), (m), -1)
+#define mpi_mod(r,a,m) gcry_mpi_mod ((r), (a), (m))
+#define mpi_gcd(g,a,b) gcry_mpi_gcd ( (g), (a), (b) )
+#define mpi_invm(g,a,b) gcry_mpi_invm ( (g), (a), (b) )
#define mpi_get_nbits(a) gcry_mpi_get_nbits ((a))
#define mpi_test_bit(a,b) gcry_mpi_test_bit ((a),(b))
@@ -753,15 +774,15 @@ int gcry_mpi_get_flag (gcry_mpi_t a, enum gcry_mpi_flag flag);
#define mpi_clear_highbit(a,b) gcry_mpi_clear_highbit ((a),(b))
#define mpi_rshift(a,b,c) gcry_mpi_rshift ((a),(b),(c))
-#define mpi_set_opaque(a,b,c) gcry_mpi_set_opaque( (a), (b), (c) )
-#define mpi_get_opaque(a,b) gcry_mpi_get_opaque( (a), (b) )
+#define mpi_set_opaque(a,b,c) gcry_mpi_set_opaque( (a), (b), (c) )
+#define mpi_get_opaque(a,b) gcry_mpi_get_opaque( (a), (b) )
#endif /* GCRYPT_NO_MPI_MACROS */
/************************************
* *
- * symmetric cipher functions *
+ * Symmetric Cipher Functions *
* *
************************************/
@@ -882,32 +903,31 @@ gcry_error_t gcry_cipher_decrypt (gcry_cipher_hd_t h,
void *out, size_t outsize,
const void *in, size_t inlen);
-/* Set key K of length L for the cipher handle H. (We have to cast
- away a const char* here - this catch-all ctl function was probably
- not the best choice) */
-#define gcry_cipher_setkey(h,k,l) gcry_cipher_ctl( (h), GCRYCTL_SET_KEY, \
- (char*)(k), (l) )
+/* Set KEY of length KEYLEN for the cipher handle HD. */
+gcry_error_t gcry_cipher_setkey (gcry_cipher_hd_t hd,
+ const void *key, size_t keylen);
+
+
+/* Set initialization vector IV of length IVLEN for the cipher handle HD. */
+gcry_error_t gcry_cipher_setiv (gcry_cipher_hd_t hd,
+ const void *iv, size_t ivlen);
-/* Set initialization vector K of length L for the cipher handle H. */
-#define gcry_cipher_setiv(h,k,l) gcry_cipher_ctl( (h), GCRYCTL_SET_IV, \
- (char*)(k), (l) )
/* Reset the handle to the state after open. */
#define gcry_cipher_reset(h) gcry_cipher_ctl ((h), GCRYCTL_RESET, NULL, 0)
-/* Perform the the OpenPGP sync operation if this is enabled for the
+/* Perform the OpenPGP sync operation if this is enabled for the
cipher handle H. */
-#define gcry_cipher_sync(h) gcry_cipher_ctl( (h), GCRYCTL_CFB_SYNC, \
- NULL, 0 )
+#define gcry_cipher_sync(h) gcry_cipher_ctl( (h), GCRYCTL_CFB_SYNC, NULL, 0)
/* Enable or disable CTS in future calls to gcry_encrypt(). CBC mode only. */
#define gcry_cipher_cts(h,on) gcry_cipher_ctl( (h), GCRYCTL_SET_CBC_CTS, \
NULL, on )
-/* Set counter for CTR mode. (K,L) must denote a buffer of block size
- length, or (NULL,0) to set the CTR to the all-zero block. */
-#define gcry_cipher_setctr(h,k,l) gcry_cipher_ctl( (h), GCRYCTL_SET_CTR, \
- (char*)(k), (l) )
+/* Set counter for CTR mode. (CTR,CTRLEN) must denote a buffer of
+ block size length, or (NULL,0) to set the CTR to the all-zero block. */
+gpg_error_t gcry_cipher_setctr (gcry_cipher_hd_t hd,
+ const void *ctr, size_t ctrlen);
/* Retrieved the key length used with algorithm A. */
size_t gcry_cipher_get_algo_keylen (int algo);
@@ -930,21 +950,20 @@ gcry_error_t gcry_cipher_list (int *list, int *list_length);
/************************************
* *
- * asymmetric cipher functions *
+ * Asymmetric Cipher Functions *
* *
************************************/
/* The algorithms and their IDs we support. */
enum gcry_pk_algos
{
- GCRY_PK_RSA = 1,
- GCRY_PK_RSA_E = 2, /* deprecated */
- GCRY_PK_RSA_S = 3, /* deprecated */
- GCRY_PK_ELG_E = 16, /* use only for OpenPGP */
+ GCRY_PK_RSA = 1,
+ GCRY_PK_RSA_E = 2, /* (deprecated) */
+ GCRY_PK_RSA_S = 3, /* (deprecated) */
+ GCRY_PK_ELG_E = 16,
GCRY_PK_DSA = 17,
GCRY_PK_ELG = 20,
- GCRY_PK_ECDSA = 301 /* Experimental implementation; not for
- production. */
+ GCRY_PK_ECDSA = 301
};
/* Flags describing usage capabilities of a PK algorithm. */
@@ -1021,7 +1040,7 @@ gcry_error_t gcry_pk_list (int *list, int *list_length);
/************************************
* *
- * cryptograhic hash functions *
+ * Cryptograhic Hash Functions *
* *
************************************/
@@ -1041,22 +1060,20 @@ enum gcry_md_algos
GCRY_MD_SHA512 = 10,
GCRY_MD_SHA224 = 11,
GCRY_MD_MD4 = 301,
- GCRY_MD_CRC32 = 302,
- GCRY_MD_CRC32_RFC1510 = 303,
- GCRY_MD_CRC24_RFC2440 = 304,
+ GCRY_MD_CRC32 = 302,
+ GCRY_MD_CRC32_RFC1510 = 303,
+ GCRY_MD_CRC24_RFC2440 = 304,
GCRY_MD_WHIRLPOOL = 305
};
/* Flags used with the open function. */
enum gcry_md_flags
{
- GCRY_MD_FLAG_SECURE = 1, /* Allocate all buffers in "secure"
- memory. */
- GCRY_MD_FLAG_HMAC = 2 /* Make an HMAC out of this
- algorithm. */
+ GCRY_MD_FLAG_SECURE = 1, /* Allocate all buffers in "secure" memory. */
+ GCRY_MD_FLAG_HMAC = 2 /* Make an HMAC out of this algorithm. */
};
-/* Forward declaration. */
+/* (Forward declaration.) */
struct gcry_md_context;
/* This object is used to hold a handle to a message digest object.
@@ -1210,7 +1227,8 @@ gcry_error_t gcry_md_list (int *list, int *list_length);
-/* Alternative interface for asymetric cryptography. */
+/* Alternative interface for asymmetric cryptography. This interface
+ is deprecated. */
/* The algorithm IDs. */
typedef enum gcry_ac_id
@@ -1584,7 +1602,7 @@ gcry_error_t gcry_ac_name_to_id (const char *name,
/************************************
* *
- * random generating functions *
+ * Random Generating Functions *
* *
************************************/
@@ -1641,7 +1659,12 @@ void gcry_create_nonce (void *buffer, size_t length);
-/* Prime interface. */
+
+/*******************************/
+/* */
+/* Prime Number Functions */
+/* */
+/*******************************/
/* Mode values passed to a gcry_prime_check_func_t. */
#define GCRY_PRIME_CHECK_AT_FINISH 0
@@ -1682,7 +1705,8 @@ gcry_error_t gcry_prime_generate (gcry_mpi_t *prime,
newly allocated MPI in R_G. If START_G is not NULL, use this as
teh start for the search. */
gcry_error_t gcry_prime_group_generator (gcry_mpi_t *r_g,
- gcry_mpi_t prime, gcry_mpi_t *factors,
+ gcry_mpi_t prime,
+ gcry_mpi_t *factors,
gcry_mpi_t start_g);
@@ -1697,14 +1721,14 @@ gcry_error_t gcry_prime_check (gcry_mpi_t x, unsigned int flags);
/************************************
* *
- * miscellaneous stuff *
+ * Miscellaneous Stuff *
* *
************************************/
/* Log levels used by the internal logging facility. */
enum gcry_log_levels
{
- GCRY_LOG_CONT = 0, /* continue the last log line */
+ GCRY_LOG_CONT = 0, /* (Continue the last log line.) */
GCRY_LOG_INFO = 10,
GCRY_LOG_WARN = 20,
GCRY_LOG_ERROR = 30,
@@ -1787,7 +1811,7 @@ int gcry_is_secure (const void *a) _GCRY_GCC_ATTR_PURE;
/* Include support for Libgcrypt modules. */
#include <gcrypt-module.h>
-#if 0 /* keep Emacsens' auto-indent happy */
+#if 0 /* (Keep Emacsens' auto-indent happy.) */
{
#endif
#ifdef __cplusplus
diff --git a/src/global.c b/src/global.c
index abbc0927..de562b38 100644
--- a/src/global.c
+++ b/src/global.c
@@ -1,6 +1,6 @@
/* global.c - global control functions
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003
- * 2004, 2005, 2006 Free Software Foundation, Inc.
+ * 2004, 2005, 2006, 2008 Free Software Foundation, Inc.
*
* This file is part of Libgcrypt.
*
@@ -15,8 +15,7 @@
* 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 <http://www.gnu.org/licenses/>.
*/
#include <config.h>
@@ -28,6 +27,8 @@
#include <ctype.h>
#include <limits.h>
#include <errno.h>
+#include <unistd.h>
+#include <assert.h>
#include "g10lib.h"
#include "cipher.h"
@@ -43,9 +44,15 @@
*/
static unsigned int debug_flags;
+/* gcry_control (GCRYCTL_SET_FIPS_MODE), sets this flag so that the
+ intialization code swicthed fips mode on. */
+static int force_fips_mode;
+
/* Controlled by global_init(). */
static int any_init_done;
+
+
/* Memory management. */
static gcry_handler_alloc_t alloc_func;
@@ -57,8 +64,10 @@ static gcry_handler_no_mem_t outofcore_handler;
static void *outofcore_handler_value;
static int no_secure_memory;
+
+
/* This is our handmade constructor. It gets called by any function
likely to be called at startup. The suggested way for an
application to make sure that this has been called is by using
@@ -72,9 +81,14 @@ global_init (void)
return;
any_init_done = 1;
+ /* Initialize our portable theead/mutex wrapper. */
err = ath_init ();
if (err)
goto fail;
+
+ /* See whether the system is in FIPS mode. This needs to come as
+ early as possible put after the ATH has been initialized. */
+ _gcry_initialize_fips_mode (force_fips_mode);
/* Before we do any other initialization we need to test available
hardware features. */
@@ -90,10 +104,13 @@ global_init (void)
if (err)
goto fail;
#if 0
- /* FIXME? */
- err = _gcry_ac_init ();
- if (err)
- goto fail;
+ /* Hmmm, as of now ac_init does nothing. */
+ if ( !fips_mode () )
+ {
+ err = _gcry_ac_init ();
+ if (err)
+ goto fail;
+ }
#endif
return;
@@ -243,6 +260,7 @@ print_config ( int (*fnc)(FILE *fp, const char *format, ...), FILE *fp)
if ( (hwf & hwflist[i].flag) )
fnc (fp, "%s:", hwflist[i].desc);
fnc (fp, "\n");
+ fnc (fp, "fips-mode:%d:\n", fips_mode () );
}
@@ -267,10 +285,10 @@ _gcry_vcontrol (enum gcry_ctl_cmds cmd, va_list arg_ptr)
break;
case GCRYCTL_FAKED_RANDOM_P:
- /* Return an error if the RNG is faked one (i.e. enabled by
+ /* Return an error if the RNG is faked one (e.g. enabled by
ENABLE_QUICK_RANDOM. */
if (_gcry_random_is_faked ())
- err = GPG_ERR_GENERAL;
+ err = GPG_ERR_GENERAL; /* Use as TRUE value. */
break;
case GCRYCTL_DUMP_RANDOM_STATS:
@@ -324,7 +342,7 @@ _gcry_vcontrol (enum gcry_ctl_cmds cmd, va_list arg_ptr)
case GCRYCTL_USE_SECURE_RNDPOOL:
global_init ();
- _gcry_secure_random_alloc (); /* put random number into secure memory */
+ _gcry_secure_random_alloc (); /* Put random number into secure memory. */
break;
case GCRYCTL_SET_RANDOM_SEED_FILE:
@@ -348,6 +366,7 @@ _gcry_vcontrol (enum gcry_ctl_cmds cmd, va_list arg_ptr)
break;
case GCRYCTL_DISABLE_INTERNAL_LOCKING:
+ /* Not used anymore. */
global_init ();
break;
@@ -358,7 +377,7 @@ _gcry_vcontrol (enum gcry_ctl_cmds cmd, va_list arg_ptr)
case GCRYCTL_INITIALIZATION_FINISHED_P:
if (init_finished)
- err = GPG_ERR_GENERAL;
+ err = GPG_ERR_GENERAL; /* Yes. */
break;
case GCRYCTL_INITIALIZATION_FINISHED:
@@ -367,15 +386,15 @@ _gcry_vcontrol (enum gcry_ctl_cmds cmd, va_list arg_ptr)
are started. It is not really needed but the only way to be
really sure that all initialization for thread-safety has
been done. */
- if (! init_finished)
- {
- global_init ();
- /* Do only a basic random initialization, i.e. init the
- mutexes. */
- _gcry_random_initialize (0);
- init_finished = 1;
- }
- break;
+ if (! init_finished)
+ {
+ global_init ();
+ /* Do only a basic random initialization, i.e. init the
+ mutexes. */
+ _gcry_random_initialize (0);
+ init_finished = 1;
+ }
+ break;
case GCRYCTL_SET_THREAD_CBS:
err = ath_install (va_arg (arg_ptr, void *), any_init_done);
@@ -420,6 +439,40 @@ _gcry_vcontrol (enum gcry_ctl_cmds cmd, va_list arg_ptr)
}
break;
+ case GCRYCTL_OPERATIONAL_P:
+ /* Returns true if the library is in an operational state. This
+ is always true for non-fips mode. */
+ if (_gcry_fips_test_operational ())
+ err = GPG_ERR_GENERAL; /* Used as TRUE value */
+ break;
+
+ case GCRYCTL_FIPS_MODE_P:
+ if (fips_mode ())
+ err = GPG_ERR_GENERAL; /* Used as TRUE value */
+ break;
+
+ case GCRYCTL_FORCE_FIPS_MODE:
+ /* Performing this command puts the library into fips mode. If
+ the library has already been initialized or is already in
+ fips mode, a selftest is triggered. */
+ if (!any_init_done)
+ {
+ /* Not yet intialized at all. Set a flag so that we are put
+ into fips mode during initialization. */
+ force_fips_mode = 1;
+ }
+ else
+ {
+ /* Already initialized. If we are already operational we
+ run a selftest. If not we use the is_operational call to
+ force us into operational state if possible. */
+ if (_gcry_fips_test_operational ())
+ _gcry_fips_run_selftests ();
+ if (_gcry_fips_is_operational ())
+ err = GPG_ERR_GENERAL; /* Used as TRUE value */
+ }
+ break;
+
default:
err = GPG_ERR_INV_OP;
}
@@ -506,6 +559,12 @@ gcry_set_allocation_handler (gcry_handler_alloc_t new_alloc_func,
{
global_init ();
+ if (fips_mode () )
+ {
+ fips_signal_error ("custom allocation handler used");
+ return;
+ }
+
alloc_func = new_alloc_func;
alloc_secure_func = new_alloc_secure_func;
is_secure_func = new_is_secure_func;
@@ -533,10 +592,16 @@ void
gcry_set_outofcore_handler( int (*f)( void*, size_t, unsigned int ),
void *value )
{
- global_init ();
+ global_init ();
- outofcore_handler = f;
- outofcore_handler_value = value;
+ if (fips_mode () )
+ {
+ fips_signal_error ("out of core handler used");
+ return;
+ }
+
+ outofcore_handler = f;
+ outofcore_handler_value = value;
}
static gcry_err_code_t
@@ -813,9 +878,11 @@ gcry_xstrdup (const char *string)
int
-_gcry_get_debug_flag( unsigned int mask )
+_gcry_get_debug_flag (unsigned int mask)
{
- return debug_flags & mask;
+ if ( fips_mode () )
+ return 0;
+ return (debug_flags & mask);
}
diff --git a/src/hmac256.c b/src/hmac256.c
new file mode 100644
index 00000000..9cfffa27
--- /dev/null
+++ b/src/hmac256.c
@@ -0,0 +1,687 @@
+/* hmac256.c - Standalone HMAC implementation
+ * Copyright (C) 2003, 2006, 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/>.
+ */
+
+/*
+ This is a standalone HMAC-SHA-256 implementation based on the code
+ from ../cipher/sha256.c. It is a second implementarion to allow
+ comparing against the standard implementations and to be used for
+ internal consistency checks. It should not be used for sensitive
+ data because no mechanisms to clear the stack etc are used.
+
+ This module may be used standalone and requires only a few
+ standard definitions to be provided in a config.h file.
+
+ Types:
+
+ u32 - unsigned 32 bit type.
+
+ Constants:
+
+ WORDS_BIGENDIAN Defined to 1 on big endian systems.
+ inline If defined, it should yield the keyword used
+ to inline a function.
+ HAVE_U32_TYPEDEF Defined if the u32 type is available.
+ SIZEOF_UNSIGNED_INT Defined to the size in bytes of an unsigned int.
+ SIZEOF_UNSIGNED_LONG Defined to the size in bytes of an unsigned long.
+
+ STANDALONE Compile a test driver similar to the
+ sha1sum tool. This driver uses a self-test
+ identically to the one used by Libcgrypt
+ for testing this included module.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+
+#include "hmac256.h"
+
+
+
+#ifndef HAVE_U32_TYPEDEF
+# undef u32 /* Undef a possible macro with that name. */
+# if SIZEOF_UNSIGNED_INT == 4
+ typedef unsigned int u32;
+# elif SIZEOF_UNSIGNED_LONG == 4
+ typedef unsigned long u32;
+# else
+# error no typedef for u32
+# endif
+# define HAVE_U32_TYPEDEF
+#endif
+
+
+
+
+/* The context used by this module. */
+struct hmac256_context
+{
+ u32 h0, h1, h2, h3, h4, h5, h6, h7;
+ u32 nblocks;
+ int count;
+ int finalized:1;
+ int use_hmac:1;
+ unsigned char buf[64];
+ unsigned char opad[64];
+};
+
+
+/* Rotate a 32 bit word. */
+#if defined(__GNUC__) && defined(__i386__)
+static inline u32
+ror(u32 x, int n)
+{
+ __asm__("rorl %%cl,%0"
+ :"=r" (x)
+ :"0" (x),"c" (n));
+ return x;
+}
+#else
+#define ror(x,n) ( ((x) >> (n)) | ((x) << (32-(n))) )
+#endif
+
+#define my_wipememory2(_ptr,_set,_len) do { \
+ volatile char *_vptr=(volatile char *)(_ptr); \
+ size_t _vlen=(_len); \
+ while(_vlen) { *_vptr=(_set); _vptr++; _vlen--; } \
+ } while(0)
+#define my_wipememory(_ptr,_len) my_wipememory2(_ptr,0,_len)
+
+
+
+
+/*
+ The SHA-256 core: Transform the message X which consists of 16
+ 32-bit-words. See FIPS 180-2 for details.
+ */
+static void
+transform (hmac256_context_t hd, const void *data_arg)
+{
+ const unsigned char *data = data_arg;
+
+#define Cho(x,y,z) (z ^ (x & (y ^ z))) /* (4.2) same as SHA-1's F1 */
+#define Maj(x,y,z) ((x & y) | (z & (x|y))) /* (4.3) same as SHA-1's F3 */
+#define Sum0(x) (ror ((x), 2) ^ ror ((x), 13) ^ ror ((x), 22)) /* (4.4) */
+#define Sum1(x) (ror ((x), 6) ^ ror ((x), 11) ^ ror ((x), 25)) /* (4.5) */
+#define S0(x) (ror ((x), 7) ^ ror ((x), 18) ^ ((x) >> 3)) /* (4.6) */
+#define S1(x) (ror ((x), 17) ^ ror ((x), 19) ^ ((x) >> 10)) /* (4.7) */
+#define R(a,b,c,d,e,f,g,h,k,w) do \
+ { \
+ t1 = (h) + Sum1((e)) + Cho((e),(f),(g)) + (k) + (w); \
+ t2 = Sum0((a)) + Maj((a),(b),(c)); \
+ h = g; \
+ g = f; \
+ f = e; \
+ e = d + t1; \
+ d = c; \
+ c = b; \
+ b = a; \
+ a = t1 + t2; \
+ } while (0)
+
+ static const u32 K[64] =
+ {
+ 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
+ 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
+ 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
+ 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
+ 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
+ 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
+ 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
+ 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
+ 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
+ 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
+ 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
+ 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
+ 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
+ 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
+ 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
+ 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
+ };
+
+ u32 a, b, c, d, e, f, g, h, t1, t2;
+ u32 x[16];
+ u32 w[64];
+ int i;
+
+ a = hd->h0;
+ b = hd->h1;
+ c = hd->h2;
+ d = hd->h3;
+ e = hd->h4;
+ f = hd->h5;
+ g = hd->h6;
+ h = hd->h7;
+
+#ifdef WORDS_BIGENDIAN
+ memcpy (x, data, 64);
+#else /*!WORDS_BIGENDIAN*/
+ {
+ unsigned char *p2;
+
+ for (i=0, p2=(unsigned char*)x; i < 16; i++, p2 += 4 )
+ {
+ p2[3] = *data++;
+ p2[2] = *data++;
+ p2[1] = *data++;
+ p2[0] = *data++;
+ }
+ }
+#endif /*!WORDS_BIGENDIAN*/
+
+ for (i=0; i < 16; i++)
+ w[i] = x[i];
+ for (; i < 64; i++)
+ w[i] = S1(w[i-2]) + w[i-7] + S0(w[i-15]) + w[i-16];
+
+ for (i=0; i < 64; i++)
+ R(a,b,c,d,e,f,g,h,K[i],w[i]);
+
+ hd->h0 += a;
+ hd->h1 += b;
+ hd->h2 += c;
+ hd->h3 += d;
+ hd->h4 += e;
+ hd->h5 += f;
+ hd->h6 += g;
+ hd->h7 += h;
+}
+#undef Cho
+#undef Maj
+#undef Sum0
+#undef Sum1
+#undef S0
+#undef S1
+#undef R
+
+
+/* Finalize the current SHA256 calculation. */
+static void
+finalize (hmac256_context_t hd)
+{
+ u32 t, msb, lsb;
+ unsigned char *p;
+
+ if (hd->finalized)
+ return; /* Silently ignore a finalized context. */
+
+ _gcry_hmac256_update (hd, NULL, 0); /* Flush. */
+
+ t = hd->nblocks;
+ /* Multiply by 64 to make a byte count. */
+ lsb = t << 6;
+ msb = t >> 26;
+ /* Add the count. */
+ t = lsb;
+ if ((lsb += hd->count) < t)
+ msb++;
+ /* Multiply by 8 to make a bit count. */
+ t = lsb;
+ lsb <<= 3;
+ msb <<= 3;
+ msb |= t >> 29;
+
+ if (hd->count < 56)
+ { /* Enough room. */
+ hd->buf[hd->count++] = 0x80; /* pad */
+ while (hd->count < 56)
+ hd->buf[hd->count++] = 0; /* pad */
+ }
+ else
+ { /* Need one extra block. */
+ hd->buf[hd->count++] = 0x80; /* pad character */
+ while (hd->count < 64)
+ hd->buf[hd->count++] = 0;
+ _gcry_hmac256_update (hd, NULL, 0); /* Flush. */;
+ memset (hd->buf, 0, 56 ); /* Zero out next next block. */
+ }
+ /* Append the 64 bit count. */
+ hd->buf[56] = msb >> 24;
+ hd->buf[57] = msb >> 16;
+ hd->buf[58] = msb >> 8;
+ hd->buf[59] = msb;
+ hd->buf[60] = lsb >> 24;
+ hd->buf[61] = lsb >> 16;
+ hd->buf[62] = lsb >> 8;
+ hd->buf[63] = lsb;
+ transform (hd, hd->buf);
+
+ /* Store the digest into hd->buf. */
+ p = hd->buf;
+#ifdef WORDS_BIGENDIAN
+#define X(a) do { *(u32*)p = hd->h##a ; p += 4; } while(0)
+#else /* little endian */
+#define X(a) do { *p++ = hd->h##a >> 24; *p++ = hd->h##a >> 16; \
+ *p++ = hd->h##a >> 8; *p++ = hd->h##a; } while(0)
+#endif
+ X(0);
+ X(1);
+ X(2);
+ X(3);
+ X(4);
+ X(5);
+ X(6);
+ X(7);
+#undef X
+ hd->finalized = 1;
+}
+
+
+
+/* Create a new context. On error NULL is returned and errno is set
+ appropriately. If KEY is given the fucntion computes HMAC using
+ this key; with KEY given as NULL, a plain SHA-256 digest is
+ computed. */
+hmac256_context_t
+_gcry_hmac256_new (const void *key, size_t keylen)
+{
+ hmac256_context_t hd;
+
+ hd = malloc (sizeof *hd);
+ if (!hd)
+ return NULL;
+
+ hd->h0 = 0x6a09e667;
+ hd->h1 = 0xbb67ae85;
+ hd->h2 = 0x3c6ef372;
+ hd->h3 = 0xa54ff53a;
+ hd->h4 = 0x510e527f;
+ hd->h5 = 0x9b05688c;
+ hd->h6 = 0x1f83d9ab;
+ hd->h7 = 0x5be0cd19;
+ hd->nblocks = 0;
+ hd->count = 0;
+ hd->finalized = 0;
+ hd->use_hmac = 0;
+
+ if (key)
+ {
+ int i;
+ unsigned char ipad[64];
+
+ memset (ipad, 0, 64);
+ memset (hd->opad, 0, 64);
+ if (keylen <= 64)
+ {
+ memcpy (ipad, key, keylen);
+ memcpy (hd->opad, key, keylen);
+ }
+ else
+ {
+ hmac256_context_t tmphd;
+
+ tmphd = _gcry_hmac256_new (NULL, 0);
+ if (!tmphd)
+ {
+ free (hd);
+ return NULL;
+ }
+ _gcry_hmac256_update (tmphd, key, keylen);
+ finalize (tmphd);
+ memcpy (ipad, tmphd->buf, 32);
+ memcpy (hd->opad, tmphd->buf, 32);
+ _gcry_hmac256_release (tmphd);
+ }
+ for (i=0; i < 64; i++)
+ {
+ ipad[i] ^= 0x36;
+ hd->opad[i] ^= 0x5c;
+ }
+ hd->use_hmac = 1;
+ _gcry_hmac256_update (hd, ipad, 64);
+ my_wipememory (ipad, 64);
+ }
+
+ return hd;
+}
+
+/* Release a context created by _gcry_hmac256_new. CTX may be NULL
+ in which case the function does nothing. */
+void
+_gcry_hmac256_release (hmac256_context_t ctx)
+{
+ if (ctx)
+ {
+ if (ctx->use_hmac)
+ my_wipememory (ctx->opad, 64);
+ free (ctx);
+ }
+}
+
+
+/* Update the message digest with the contents of BUFFER containing
+ LENGTH bytes. */
+void
+_gcry_hmac256_update (hmac256_context_t hd,
+ const void *buffer, size_t length)
+{
+ const unsigned char *inbuf = buffer;
+
+ if (hd->finalized)
+ return; /* Silently ignore a finalized context. */
+
+ if (hd->count == 64)
+ {
+ /* Flush the buffer. */
+ transform (hd, hd->buf);
+ hd->count = 0;
+ hd->nblocks++;
+ }
+ if (!inbuf)
+ return; /* Only flushing was requested. */
+ if (hd->count)
+ {
+ for (; length && hd->count < 64; length--)
+ hd->buf[hd->count++] = *inbuf++;
+ _gcry_hmac256_update (hd, NULL, 0); /* Flush. */
+ if (!length)
+ return;
+ }
+
+
+ while (length >= 64)
+ {
+ transform (hd, inbuf);
+ hd->count = 0;
+ hd->nblocks++;
+ length -= 64;
+ inbuf += 64;
+ }
+ for (; length && hd->count < 64; length--)
+ hd->buf[hd->count++] = *inbuf++;
+}
+
+
+/* Finalize an operation and return the digest. If R_DLEN is not NULL
+ the length of the digest will be stored at that address. The
+ returned value is valid as long as the context exists. On error
+ NULL is returned. */
+const void *
+_gcry_hmac256_finalize (hmac256_context_t hd, size_t *r_dlen)
+{
+ finalize (hd);
+ if (hd->use_hmac)
+ {
+ hmac256_context_t tmphd;
+
+ tmphd = _gcry_hmac256_new (NULL, 0);
+ if (!tmphd)
+ {
+ free (hd);
+ return NULL;
+ }
+ _gcry_hmac256_update (tmphd, hd->opad, 64);
+ _gcry_hmac256_update (tmphd, hd->buf, 32);
+ finalize (tmphd);
+ memcpy (hd->buf, tmphd->buf, 32);
+ _gcry_hmac256_release (tmphd);
+ }
+ if (r_dlen)
+ *r_dlen = 32;
+ return (void*)hd->buf;
+}
+
+
+#ifdef STANDALONE
+static int
+selftest (void)
+{
+ static struct
+ {
+ const char * const desc;
+ const char * const data;
+ const char * const key;
+ const char const expect[32];
+ } tv[] =
+ {
+ { "data-28 key-4",
+ "what do ya want for nothing?",
+ "Jefe",
+ { 0x5b, 0xdc, 0xc1, 0x46, 0xbf, 0x60, 0x75, 0x4e,
+ 0x6a, 0x04, 0x24, 0x26, 0x08, 0x95, 0x75, 0xc7,
+ 0x5a, 0x00, 0x3f, 0x08, 0x9d, 0x27, 0x39, 0x83,
+ 0x9d, 0xec, 0x58, 0xb9, 0x64, 0xec, 0x38, 0x43 } },
+
+ { "data-9 key-20",
+ "Hi There",
+ "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b"
+ "\x0b\x0b\x0b\x0b",
+ { 0xb0, 0x34, 0x4c, 0x61, 0xd8, 0xdb, 0x38, 0x53,
+ 0x5c, 0xa8, 0xaf, 0xce, 0xaf, 0x0b, 0xf1, 0x2b,
+ 0x88, 0x1d, 0xc2, 0x00, 0xc9, 0x83, 0x3d, 0xa7,
+ 0x26, 0xe9, 0x37, 0x6c, 0x2e, 0x32, 0xcf, 0xf7 } },
+
+ { "data-50 key-20",
+ "\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd"
+ "\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd"
+ "\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd"
+ "\xdd\xdd",
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa",
+ { 0x77, 0x3e, 0xa9, 0x1e, 0x36, 0x80, 0x0e, 0x46,
+ 0x85, 0x4d, 0xb8, 0xeb, 0xd0, 0x91, 0x81, 0xa7,
+ 0x29, 0x59, 0x09, 0x8b, 0x3e, 0xf8, 0xc1, 0x22,
+ 0xd9, 0x63, 0x55, 0x14, 0xce, 0xd5, 0x65, 0xfe } },
+
+ { "data-50 key-26",
+ "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
+ "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
+ "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
+ "\xcd\xcd",
+ "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10"
+ "\x11\x12\x13\x14\x15\x16\x17\x18\x19",
+ { 0x82, 0x55, 0x8a, 0x38, 0x9a, 0x44, 0x3c, 0x0e,
+ 0xa4, 0xcc, 0x81, 0x98, 0x99, 0xf2, 0x08, 0x3a,
+ 0x85, 0xf0, 0xfa, 0xa3, 0xe5, 0x78, 0xf8, 0x07,
+ 0x7a, 0x2e, 0x3f, 0xf4, 0x67, 0x29, 0x66, 0x5b } },
+
+ { "data-54 key-131",
+ "Test Using Larger Than Block-Size Key - Hash Key First",
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa",
+ { 0x60, 0xe4, 0x31, 0x59, 0x1e, 0xe0, 0xb6, 0x7f,
+ 0x0d, 0x8a, 0x26, 0xaa, 0xcb, 0xf5, 0xb7, 0x7f,
+ 0x8e, 0x0b, 0xc6, 0x21, 0x37, 0x28, 0xc5, 0x14,
+ 0x05, 0x46, 0x04, 0x0f, 0x0e, 0xe3, 0x7f, 0x54 } },
+
+ { "data-152 key-131",
+ "This is a test using a larger than block-size key and a larger "
+ "than block-size data. The key needs to be hashed before being "
+ "used by the HMAC algorithm.",
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+ "\xaa\xaa\xaa",
+ { 0x9b, 0x09, 0xff, 0xa7, 0x1b, 0x94, 0x2f, 0xcb,
+ 0x27, 0x63, 0x5f, 0xbc, 0xd5, 0xb0, 0xe9, 0x44,
+ 0xbf, 0xdc, 0x63, 0x64, 0x4f, 0x07, 0x13, 0x93,
+ 0x8a, 0x7f, 0x51, 0x53, 0x5c, 0x3a, 0x35, 0xe2 } },
+
+ { NULL }
+ };
+ int tvidx;
+
+ for (tvidx=0; tv[tvidx].desc; tvidx++)
+ {
+ hmac256_context_t hmachd;
+ const unsigned char *digest;
+ size_t dlen;
+
+ hmachd = _gcry_hmac256_new (tv[tvidx].key, strlen (tv[tvidx].key));
+ if (!hmachd)
+ return -1;
+ _gcry_hmac256_update (hmachd, tv[tvidx].data, strlen (tv[tvidx].data));
+ digest = _gcry_hmac256_finalize (hmachd, &dlen);
+ if (!digest)
+ {
+ _gcry_hmac256_release (hmachd);
+ return -1;
+ }
+ if (dlen != sizeof (tv[tvidx].expect)
+ || memcmp (digest, tv[tvidx].expect, sizeof (tv[tvidx].expect)))
+ {
+ _gcry_hmac256_release (hmachd);
+ return -1;
+ }
+ _gcry_hmac256_release (hmachd);
+ }
+
+ return 0; /* Succeeded. */
+}
+
+
+int
+main (int argc, char **argv)
+{
+ const char *pgm;
+ int last_argc = -1;
+ const char *key;
+ size_t keylen;
+ FILE *fp;
+ hmac256_context_t hd;
+ const unsigned char *digest;
+ char buffer[4096];
+ size_t n, dlen, idx;
+ int use_stdin = 0;
+
+ assert (sizeof (u32) == 4);
+
+ if (argc)
+ {
+ pgm = strrchr (*argv, '/');
+ if (pgm)
+ pgm++;
+ else
+ pgm = *argv;
+ argc--; argv++;
+ }
+ else
+ pgm = "?";
+
+ while (argc && last_argc != argc )
+ {
+ last_argc = argc;
+ if (!strcmp (*argv, "--"))
+ {
+ argc--; argv++;
+ break;
+ }
+ else if (!strcmp (*argv, "--version"))
+ {
+ fputs ("hmac256 (Libgcrypt) " VERSION "\n"
+ "Copyright (C) 2008 Free Software Foundation, Inc.\n"
+ "License LGPLv2.1+: GNU LGPL version 2.1 or later "
+ "<http://gnu.org/licenses/old-licenses/lgpl-2.1.html>\n"
+ "This is free software: you are free to change and "
+ "redistribute it.\n"
+ "There is NO WARRANTY, to the extent permitted by law.\n",
+ stdout);
+ exit (0);
+ }
+ }
+
+ if (argc < 1)
+ {
+ fprintf (stderr, "usage: %s key [filename]\n", pgm);
+ exit (1);
+ }
+
+
+ key = *argv;
+ argc--, argv++;
+ keylen = strlen (key);
+ use_stdin = !argc;
+
+ if (selftest ())
+ {
+ fprintf (stderr, "%s: fatal error: self-test failed\n", pgm);
+ exit (2);
+ }
+
+ for (; argc || use_stdin; argv++, argc--)
+ {
+ const char *fname = use_stdin? "-" : *argv;
+ fp = use_stdin? stdin : fopen (fname, "rb");
+ if (!fp)
+ {
+ fprintf (stderr, "%s: can't open `%s': %s\n",
+ pgm, fname, strerror (errno));
+ exit (1);
+ }
+ hd = _gcry_hmac256_new (key, keylen);
+ if (!hd)
+ {
+ fprintf (stderr, "%s: can't allocate context: %s\n",
+ pgm, strerror (errno));
+ exit (1);
+ }
+ while ( (n = fread (buffer, 1, sizeof buffer, fp)))
+ _gcry_hmac256_update (hd, buffer, n);
+ if (ferror (fp))
+ {
+ fprintf (stderr, "%s: error reading `%s': %s\n",
+ pgm, fname, strerror (errno));
+ exit (1);
+ }
+ if (!use_stdin)
+ fclose (fp);
+
+ digest = _gcry_hmac256_finalize (hd, &dlen);
+ if (!digest)
+ {
+ fprintf (stderr, "%s: error computing HMAC: %s\n",
+ pgm, strerror (errno));
+ exit (1);
+ }
+ for (idx=0; idx < dlen; idx++)
+ printf ("%02x", digest[idx]);
+ _gcry_hmac256_release (hd);
+ if (use_stdin)
+ {
+ putchar ('\n');
+ break;
+ }
+ printf (" %s\n", fname);
+ }
+
+ return 0;
+}
+#endif /*STANDALONE*/
+
+
+/*
+Local Variables:
+compile-command: "cc -Wall -g -I.. -DSTANDALONE -o hmac256 hmac256.c"
+End:
+*/
diff --git a/src/hmac256.h b/src/hmac256.h
new file mode 100644
index 00000000..2f4d1ea4
--- /dev/null
+++ b/src/hmac256.h
@@ -0,0 +1,33 @@
+/* hmac256.h - Declarations for _gcry_hmac256
+ * 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/>.
+ */
+
+#ifndef HMAC256_H
+#define HMAC256_H
+
+
+struct hmac256_context;
+typedef struct hmac256_context *hmac256_context_t;
+
+hmac256_context_t _gcry_hmac256_new (const void *key, size_t keylen);
+void _gcry_hmac256_update (hmac256_context_t hd, const void *buf, size_t len);
+const void *_gcry_hmac256_finalize (hmac256_context_t hd, size_t *r_dlen);
+void _gcry_hmac256_release (hmac256_context_t hd);
+
+
+#endif /*HMAC256_H*/
diff --git a/src/libgcrypt.def b/src/libgcrypt.def
index 6b4821ba..4cf2da9d 100644
--- a/src/libgcrypt.def
+++ b/src/libgcrypt.def
@@ -227,3 +227,9 @@ EXPORTS
gcry_sexp_nth_string @187
+ gcry_cipher_setkey @188
+ gcry_cipher_setiv @189
+ gcry_cipher_setctr @190
+
+
+
diff --git a/src/libgcrypt.vers b/src/libgcrypt.vers
index 6bac4626..a8ef6f77 100644
--- a/src/libgcrypt.vers
+++ b/src/libgcrypt.vers
@@ -1,5 +1,5 @@
# libgcrypt.vers - What symbols to export -*- std -*-
-# Copyright (C) 2002, 2004 Free Software Foundation, Inc.
+# Copyright (C) 2002, 2004, 2008 Free Software Foundation, Inc.
#
# This file is part of Libgcrypt.
#
@@ -50,6 +50,7 @@ GCRYPT_1.2 {
gcry_cipher_info; gcry_cipher_list; gcry_cipher_map_name;
gcry_cipher_mode_from_oid; gcry_cipher_open;
gcry_cipher_register; gcry_cipher_unregister;
+ gcry_cipher_setkey; gcry_cipher_setiv; gcry_cipher_setctr;
gcry_pk_algo_info; gcry_pk_algo_name; gcry_pk_ctl;
gcry_pk_decrypt; gcry_pk_encrypt; gcry_pk_genkey;
@@ -67,7 +68,8 @@ GCRYPT_1.2 {
gcry_ac_data_sign; gcry_ac_data_verify; gcry_ac_id_to_name;
gcry_ac_name_to_id; gcry_ac_list; gcry_ac_data_encode;
gcry_ac_data_decode; gcry_ac_mpi_to_os; gcry_ac_mpi_to_os_alloc;
- gcry_ac_os_to_mpi; gcry_ac_data_encrypt_scheme; gcry_ac_data_decrypt_scheme;
+ gcry_ac_os_to_mpi; gcry_ac_data_encrypt_scheme;
+ gcry_ac_data_decrypt_scheme;
gcry_ac_data_sign_scheme; gcry_ac_data_verify_scheme;
gcry_ac_data_to_sexp; gcry_ac_data_from_sexp;
gcry_ac_io_init; gcry_ac_io_init_va;
diff --git a/src/misc.c b/src/misc.c
index 15dc3649..71c60037 100644
--- a/src/misc.c
+++ b/src/misc.c
@@ -75,9 +75,10 @@ _gcry_fatal_error (int rc, const char *text)
if ( !text ) /* get a default text */
text = gpg_strerror (rc);
- if (fatal_error_handler)
+ if (fatal_error_handler && !fips_mode () )
fatal_error_handler (fatal_error_handler_value, rc, text);
+ fips_signal_fatal_error (text);
write2stderr("\nFatal error: ");
write2stderr(text);
write2stderr("\n");
@@ -132,6 +133,7 @@ _gcry_logv( int level, const char *fmt, va_list arg_ptr )
if ( level == GCRY_LOG_FATAL || level == GCRY_LOG_BUG )
{
+ fips_signal_fatal_error ("internal error (fatal or bug)");
_gcry_secmem_term ();
abort ();
}
diff --git a/src/module.c b/src/module.c
index d99fbcfd..f6a24209 100644
--- a/src/module.c
+++ b/src/module.c
@@ -1,5 +1,5 @@
/* module.c - Module management for libgcrypt.
- * Copyright (C) 2003 Free Software Foundation, Inc.
+ * Copyright (C) 2003, 2008 Free Software Foundation, Inc.
*
* This file is part of Libgcrypt.
*
@@ -14,8 +14,7 @@
* 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 <http://www.gnu.org/licenses/>.
*/
#include <config.h>
@@ -76,7 +75,7 @@ _gcry_module_id_new (gcry_module_t modules, unsigned int *id_new)
it's use-counter set to one. */
gcry_err_code_t
_gcry_module_add (gcry_module_t *entries, unsigned int mod_id,
- void *spec, gcry_module_t *module)
+ void *spec, void *extraspec, gcry_module_t *module)
{
gcry_err_code_t err = 0;
gcry_module_t entry;
@@ -97,6 +96,7 @@ _gcry_module_add (gcry_module_t *entries, unsigned int mod_id,
entry->flags = 0;
entry->counter = 1;
entry->spec = spec;
+ entry->extraspec = extraspec;
entry->mod_id = mod_id;
/* Link it into the list. */
diff --git a/src/visibility.c b/src/visibility.c
index 43f7730f..dd245907 100644
--- a/src/visibility.c
+++ b/src/visibility.c
@@ -1,5 +1,5 @@
/* visibility.c - Wrapper for all public functions.
- * Copyright (C) 2007 Free Software Foundation, Inc.
+ * Copyright (C) 2007, 2008 Free Software Foundation, Inc.
*
* This file is part of Libgcrypt.
*
@@ -22,6 +22,8 @@
#define _GCRY_INCLUDED_BY_VISIBILITY_C
#include "g10lib.h"
+#include "cipher-proto.h"
+
const char *
@@ -489,6 +491,12 @@ gcry_error_t
gcry_cipher_open (gcry_cipher_hd_t *handle,
int algo, int mode, unsigned int flags)
{
+ if (!fips_is_operational ())
+ {
+ *handle = NULL;
+ return gpg_error (fips_not_operational ());
+ }
+
return _gcry_cipher_open (handle, algo, mode, flags);
}
@@ -499,8 +507,39 @@ gcry_cipher_close (gcry_cipher_hd_t h)
}
gcry_error_t
+gcry_cipher_setkey (gcry_cipher_hd_t hd, const void *key, size_t keylen)
+{
+ if (!fips_is_operational ())
+ return gpg_error (fips_not_operational ());
+
+ return _gcry_cipher_setkey (hd, key, keylen);
+}
+
+gcry_error_t
+gcry_cipher_setiv (gcry_cipher_hd_t hd, const void *iv, size_t ivlen)
+{
+ if (!fips_is_operational ())
+ return gpg_error (fips_not_operational ());
+
+ return _gcry_cipher_setiv (hd, iv, ivlen);
+}
+
+gpg_error_t
+gcry_cipher_setctr (gcry_cipher_hd_t hd, const void *ctr, size_t ctrlen)
+{
+ if (!fips_is_operational ())
+ return gpg_error (fips_not_operational ());
+
+ return _gcry_cipher_setctr (hd, ctr, ctrlen);
+}
+
+
+gcry_error_t
gcry_cipher_ctl (gcry_cipher_hd_t h, int cmd, void *buffer, size_t buflen)
{
+ if (!fips_is_operational ())
+ return gpg_error (fips_not_operational ());
+
return _gcry_cipher_ctl (h, cmd, buffer, buflen);
}
@@ -513,6 +552,9 @@ gcry_cipher_info (gcry_cipher_hd_t h, int what, void *buffer, size_t *nbytes)
gcry_error_t
gcry_cipher_algo_info (int algo, int what, void *buffer, size_t *nbytes)
{
+ if (!fips_is_operational ())
+ return gpg_error (fips_not_operational ());
+
return _gcry_cipher_algo_info (algo, what, buffer, nbytes);
}
@@ -539,6 +581,14 @@ gcry_cipher_encrypt (gcry_cipher_hd_t h,
void *out, size_t outsize,
const void *in, size_t inlen)
{
+ if (!fips_is_operational ())
+ {
+ /* Make sure that the plaintext will never make it to OUT. */
+ if (out)
+ memset (out, 0x42, outsize);
+ return gpg_error (fips_not_operational ());
+ }
+
return _gcry_cipher_encrypt (h, out, outsize, in, inlen);
}
@@ -547,8 +597,10 @@ gcry_cipher_decrypt (gcry_cipher_hd_t h,
void *out, size_t outsize,
const void *in, size_t inlen)
{
- return _gcry_cipher_decrypt (h, out, outsize, in, inlen);
+ if (!fips_is_operational ())
+ return gpg_error (fips_not_operational ());
+ return _gcry_cipher_decrypt (h, out, outsize, in, inlen);
}
size_t
@@ -572,36 +624,60 @@ gcry_cipher_list (int *list, int *list_length)
gcry_error_t
gcry_pk_encrypt (gcry_sexp_t *result, gcry_sexp_t data, gcry_sexp_t pkey)
{
+ if (!fips_is_operational ())
+ {
+ *result = NULL;
+ return gpg_error (fips_not_operational ());
+ }
return _gcry_pk_encrypt (result, data, pkey);
}
gcry_error_t
gcry_pk_decrypt (gcry_sexp_t *result, gcry_sexp_t data, gcry_sexp_t skey)
{
+ if (!fips_is_operational ())
+ {
+ *result = NULL;
+ return gpg_error (fips_not_operational ());
+ }
return _gcry_pk_decrypt (result, data, skey);
}
gcry_error_t
gcry_pk_sign (gcry_sexp_t *result, gcry_sexp_t data, gcry_sexp_t skey)
{
+ if (!fips_is_operational ())
+ {
+ *result = NULL;
+ return gpg_error (fips_not_operational ());
+ }
return _gcry_pk_sign (result, data, skey);
}
gcry_error_t
gcry_pk_verify (gcry_sexp_t sigval, gcry_sexp_t data, gcry_sexp_t pkey)
{
+ if (!fips_is_operational ())
+ return gpg_error (fips_not_operational ());
return _gcry_pk_verify (sigval, data, pkey);
}
gcry_error_t
gcry_pk_testkey (gcry_sexp_t key)
{
+ if (!fips_is_operational ())
+ return gpg_error (fips_not_operational ());
return _gcry_pk_testkey (key);
}
gcry_error_t
gcry_pk_genkey (gcry_sexp_t *r_key, gcry_sexp_t s_parms)
{
+ if (!fips_is_operational ())
+ {
+ *r_key = NULL;
+ return gpg_error (fips_not_operational ());
+ }
return _gcry_pk_genkey (r_key, s_parms);
}
@@ -614,6 +690,9 @@ gcry_pk_ctl (int cmd, void *buffer, size_t buflen)
gcry_error_t
gcry_pk_algo_info (int algo, int what, void *buffer, size_t *nbytes)
{
+ if (!fips_is_operational ())
+ return gpg_error (fips_not_operational ());
+
return _gcry_pk_algo_info (algo, what, buffer, nbytes);
}
@@ -632,12 +711,23 @@ gcry_pk_map_name (const char *name)
unsigned int
gcry_pk_get_nbits (gcry_sexp_t key)
{
+ if (!fips_is_operational ())
+ {
+ (void)fips_not_operational ();
+ return 0;
+ }
+
return _gcry_pk_get_nbits (key);
}
unsigned char *
gcry_pk_get_keygrip (gcry_sexp_t key, unsigned char *array)
{
+ if (!fips_is_operational ())
+ {
+ (void)fips_not_operational ();
+ return NULL;
+ }
return _gcry_pk_get_keygrip (key, array);
}
@@ -650,6 +740,12 @@ gcry_pk_list (int *list, int *list_length)
gcry_error_t
gcry_md_open (gcry_md_hd_t *h, int algo, unsigned int flags)
{
+ if (!fips_is_operational ())
+ {
+ *h = NULL;
+ return gpg_error (fips_not_operational ());
+ }
+
return _gcry_md_open (h, algo, flags);
}
@@ -662,12 +758,19 @@ gcry_md_close (gcry_md_hd_t hd)
gcry_error_t
gcry_md_enable (gcry_md_hd_t hd, int algo)
{
+ if (!fips_is_operational ())
+ return gpg_error (fips_not_operational ());
return _gcry_md_enable (hd, algo);
}
gcry_error_t
gcry_md_copy (gcry_md_hd_t *bhd, gcry_md_hd_t ahd)
{
+ if (!fips_is_operational ())
+ {
+ *bhd = NULL;
+ return gpg_error (fips_not_operational ());
+ }
return _gcry_md_copy (bhd, ahd);
}
@@ -680,12 +783,19 @@ gcry_md_reset (gcry_md_hd_t hd)
gcry_error_t
gcry_md_ctl (gcry_md_hd_t hd, int cmd, void *buffer, size_t buflen)
{
+ if (!fips_is_operational ())
+ return gpg_error (fips_not_operational ());
return _gcry_md_ctl (hd, cmd, buffer, buflen);
}
void
gcry_md_write (gcry_md_hd_t hd, const void *buffer, size_t length)
{
+ if (!fips_is_operational ())
+ {
+ (void)fips_not_operational ();
+ return;
+ }
_gcry_md_write (hd, buffer, length);
}
@@ -699,12 +809,23 @@ void
gcry_md_hash_buffer (int algo, void *digest,
const void *buffer, size_t length)
{
+ if (!fips_is_operational ())
+ {
+ (void)fips_not_operational ();
+ fips_signal_error ("called in non-operational state");
+ }
_gcry_md_hash_buffer (algo, digest, buffer, length);
}
int
gcry_md_get_algo (gcry_md_hd_t hd)
{
+ if (!fips_is_operational ())
+ {
+ (void)fips_not_operational ();
+ fips_signal_error ("used in non-operational state");
+ return 0;
+ }
return _gcry_md_get_algo (hd);
}
@@ -717,6 +838,12 @@ gcry_md_get_algo_dlen (int algo)
int
gcry_md_is_enabled (gcry_md_hd_t a, int algo)
{
+ if (!fips_is_operational ())
+ {
+ (void)fips_not_operational ();
+ return 0;
+ }
+
return _gcry_md_is_enabled (a, algo);
}
@@ -729,6 +856,9 @@ gcry_md_is_secure (gcry_md_hd_t a)
gcry_error_t
gcry_md_info (gcry_md_hd_t h, int what, void *buffer, size_t *nbytes)
{
+ if (!fips_is_operational ())
+ return gpg_error (fips_not_operational ());
+
return _gcry_md_info (h, what, buffer, nbytes);
}
@@ -753,6 +883,8 @@ gcry_md_map_name (const char* name)
gcry_error_t
gcry_md_setkey (gcry_md_hd_t hd, const void *key, size_t keylen)
{
+ if (!fips_is_operational ())
+ return gpg_error (fips_not_operational ());
return _gcry_md_setkey (hd, key, keylen);
}
@@ -1053,24 +1185,46 @@ gcry_ac_name_to_id (const char *name, gcry_ac_id_t *algorithm)
void
gcry_randomize (void *buffer, size_t length, enum gcry_random_level level)
{
+ if (!fips_is_operational ())
+ {
+ (void)fips_not_operational ();
+ fips_signal_fatal_error ("called in non-operational state");
+ fips_noreturn ();
+ }
_gcry_randomize (buffer, length, level);
}
gcry_error_t
gcry_random_add_bytes (const void *buffer, size_t length, int quality)
{
+ if (!fips_is_operational ())
+ return gpg_error (fips_not_operational ());
return _gcry_random_add_bytes (buffer, length, quality);
}
void *
gcry_random_bytes (size_t nbytes, enum gcry_random_level level)
{
+ if (!fips_is_operational ())
+ {
+ (void)fips_not_operational ();
+ fips_signal_fatal_error ("called in non-operational state");
+ fips_noreturn ();
+ }
+
return _gcry_random_bytes (nbytes,level);
}
void *
gcry_random_bytes_secure (size_t nbytes, enum gcry_random_level level)
{
+ if (!fips_is_operational ())
+ {
+ (void)fips_not_operational ();
+ fips_signal_fatal_error ("called in non-operational state");
+ fips_noreturn ();
+ }
+
return _gcry_random_bytes_secure (nbytes, level);
}
@@ -1084,6 +1238,12 @@ gcry_mpi_randomize (gcry_mpi_t w,
void
gcry_create_nonce (void *buffer, size_t length)
{
+ if (!fips_is_operational ())
+ {
+ (void)fips_not_operational ();
+ fips_signal_fatal_error ("called in non-operational state");
+ fips_noreturn ();
+ }
_gcry_create_nonce (buffer, length);
}
@@ -1251,7 +1411,7 @@ gcry_error_t
gcry_cipher_register (gcry_cipher_spec_t *cipher, int *algorithm_id,
gcry_module_t *module)
{
- return _gcry_cipher_register (cipher, algorithm_id, module);
+ return _gcry_cipher_register (cipher, NULL, algorithm_id, module);
}
void
@@ -1264,7 +1424,7 @@ gcry_error_t
gcry_pk_register (gcry_pk_spec_t *pubkey, unsigned int *algorithm_id,
gcry_module_t *module)
{
- return _gcry_pk_register (pubkey, algorithm_id, module);
+ return _gcry_pk_register (pubkey, NULL, algorithm_id, module);
}
void
@@ -1277,7 +1437,7 @@ gcry_error_t
gcry_md_register (gcry_md_spec_t *digest, unsigned int *algorithm_id,
gcry_module_t *module)
{
- return _gcry_md_register (digest, algorithm_id, module);
+ return _gcry_md_register (digest, NULL, algorithm_id, module);
}
void
diff --git a/src/visibility.h b/src/visibility.h
index f0350fa2..516c93a7 100644
--- a/src/visibility.h
+++ b/src/visibility.h
@@ -20,7 +20,8 @@
#ifndef GCRY_VISIBILITY_H
#define GCRY_VISIBILITY_H
-/* Redefine all public symbols with an underscore. */
+/* Redefine all public symbols with an underscore unless we already
+ use the underscore prefixed version internally. */
#define gcry_check_version _gcry_check_version
#define gcry_control _gcry_control
@@ -69,16 +70,19 @@
#define gcry_md_map_name _gcry_md_map_name
#define gcry_md_open _gcry_md_open
#define gcry_md_read _gcry_md_read
-#define gcry_md_register _gcry_md_register
+/* gcry_md_register and _gcry_md_register differ. */
+#define gcry_md_unregister _gcry_md_unregister
#define gcry_md_reset _gcry_md_reset
#define gcry_md_setkey _gcry_md_setkey
-#define gcry_md_unregister _gcry_md_unregister
#define gcry_md_write _gcry_md_write
#define gcry_md_debug _gcry_md_debug
#define gcry_cipher_algo_info _gcry_cipher_algo_info
#define gcry_cipher_algo_name _gcry_cipher_algo_name
#define gcry_cipher_close _gcry_cipher_close
+#define gcry_cipher_setkey _gcry_cipher_setkey
+#define gcry_cipher_setiv _gcry_cipher_setiv
+#define gcry_cipher_setctr _gcry_cipher_setctr
#define gcry_cipher_ctl _gcry_cipher_ctl
#define gcry_cipher_decrypt _gcry_cipher_decrypt
#define gcry_cipher_encrypt _gcry_cipher_encrypt
@@ -89,7 +93,7 @@
#define gcry_cipher_map_name _gcry_cipher_map_name
#define gcry_cipher_mode_from_oid _gcry_cipher_mode_from_oid
#define gcry_cipher_open _gcry_cipher_open
-#define gcry_cipher_register _gcry_cipher_register
+/* gcry_cipher_register and _gcry_cipher_register differ. */
#define gcry_cipher_unregister _gcry_cipher_unregister
#define gcry_pk_algo_info _gcry_pk_algo_info
@@ -102,10 +106,10 @@
#define gcry_pk_get_nbits _gcry_pk_get_nbits
#define gcry_pk_list _gcry_pk_list
#define gcry_pk_map_name _gcry_pk_map_name
-#define gcry_pk_register _gcry_pk_register
+/* gcry_pk_register and _gcry_pk_register differ. */
+#define gcry_pk_unregister _gcry_pk_unregister
#define gcry_pk_sign _gcry_pk_sign
#define gcry_pk_testkey _gcry_pk_testkey
-#define gcry_pk_unregister _gcry_pk_unregister
#define gcry_pk_verify _gcry_pk_verify
#define gcry_ac_data_new _gcry_ac_data_new
@@ -224,13 +228,6 @@
#define gcry_mpi_swap _gcry_mpi_swap
#define gcry_mpi_test_bit _gcry_mpi_test_bit
-#define gcry_cipher_register _gcry_cipher_register
-#define gcry_cipher_unregister _gcry_cipher_unregister
-#define gcry_pk_register _gcry_pk_register
-#define gcry_pk_unregister _gcry_pk_unregister
-#define gcry_md_register _gcry_md_register
-#define gcry_md_unregister _gcry_md_unregister
-
/* Include the main header here so that public symbols are mapped to
the internal underscored ones. */
@@ -265,12 +262,15 @@ void gcry_ac_os_to_mpi (gcry_mpi_t mpi, unsigned char *os, size_t os_n);
#ifdef _GCRY_INCLUDED_BY_VISIBILITY_C
/* A macro to flag a function as visible. Note that we take the
- defintion from the mapped name. */
+ definition from the mapped name. */
#ifdef GCRY_USE_VISIBILITY
# define MARK_VISIBLE(name) \
extern __typeof__ (_##name) name __attribute__ ((visibility("default")));
+# define MARK_VISIBLEX(name) \
+ extern __typeof__ (name) name __attribute__ ((visibility("default")));
#else
# define MARK_VISIBLE(name) /* */
+# define MARK_VISIBLEX(name) /* */
#endif
@@ -324,16 +324,19 @@ void gcry_ac_os_to_mpi (gcry_mpi_t mpi, unsigned char *os, size_t os_n);
#undef gcry_md_map_name
#undef gcry_md_open
#undef gcry_md_read
-#undef gcry_md_register
+/* gcry_md_register is not anymore a macro. */
+#undef gcry_md_unregister
#undef gcry_md_reset
#undef gcry_md_setkey
-#undef gcry_md_unregister
#undef gcry_md_write
#undef gcry_md_debug
#undef gcry_cipher_algo_info
#undef gcry_cipher_algo_name
#undef gcry_cipher_close
+#undef gcry_cipher_setkey
+#undef gcry_cipher_setiv
+#undef gcry_cipher_setctr
#undef gcry_cipher_ctl
#undef gcry_cipher_decrypt
#undef gcry_cipher_encrypt
@@ -344,7 +347,7 @@ void gcry_ac_os_to_mpi (gcry_mpi_t mpi, unsigned char *os, size_t os_n);
#undef gcry_cipher_map_name
#undef gcry_cipher_mode_from_oid
#undef gcry_cipher_open
-#undef gcry_cipher_register
+/* gcry_cipher_register is not anymore a macro. */
#undef gcry_cipher_unregister
#undef gcry_pk_algo_info
@@ -357,10 +360,10 @@ void gcry_ac_os_to_mpi (gcry_mpi_t mpi, unsigned char *os, size_t os_n);
#undef gcry_pk_get_nbits
#undef gcry_pk_list
#undef gcry_pk_map_name
-#undef gcry_pk_register
+/* gcry_pk_register is not anymore a macro. */
+#undef gcry_pk_unregister
#undef gcry_pk_sign
#undef gcry_pk_testkey
-#undef gcry_pk_unregister
#undef gcry_pk_verify
#undef gcry_ac_data_new
@@ -479,14 +482,6 @@ void gcry_ac_os_to_mpi (gcry_mpi_t mpi, unsigned char *os, size_t os_n);
#undef gcry_mpi_swap
#undef gcry_mpi_test_bit
-#undef gcry_cipher_register
-#undef gcry_cipher_unregister
-#undef gcry_pk_register
-#undef gcry_pk_unregister
-#undef gcry_md_register
-#undef gcry_md_unregister
-
-
/* Now mark all symbols. */
@@ -538,7 +533,7 @@ MARK_VISIBLE (gcry_md_list)
MARK_VISIBLE (gcry_md_map_name)
MARK_VISIBLE (gcry_md_open)
MARK_VISIBLE (gcry_md_read)
-MARK_VISIBLE (gcry_md_register)
+MARK_VISIBLEX(gcry_md_register)
MARK_VISIBLE (gcry_md_reset)
MARK_VISIBLE (gcry_md_setkey)
MARK_VISIBLE (gcry_md_unregister)
@@ -548,6 +543,9 @@ MARK_VISIBLE (gcry_md_debug)
MARK_VISIBLE (gcry_cipher_algo_info)
MARK_VISIBLE (gcry_cipher_algo_name)
MARK_VISIBLE (gcry_cipher_close)
+MARK_VISIBLE (gcry_cipher_setkey)
+MARK_VISIBLE (gcry_cipher_setiv)
+MARK_VISIBLE (gcry_cipher_setctr)
MARK_VISIBLE (gcry_cipher_ctl)
MARK_VISIBLE (gcry_cipher_decrypt)
MARK_VISIBLE (gcry_cipher_encrypt)
@@ -558,7 +556,7 @@ MARK_VISIBLE (gcry_cipher_list)
MARK_VISIBLE (gcry_cipher_map_name)
MARK_VISIBLE (gcry_cipher_mode_from_oid)
MARK_VISIBLE (gcry_cipher_open)
-MARK_VISIBLE (gcry_cipher_register)
+MARK_VISIBLEX(gcry_cipher_register)
MARK_VISIBLE (gcry_cipher_unregister)
MARK_VISIBLE (gcry_pk_algo_info)
@@ -571,7 +569,7 @@ MARK_VISIBLE (gcry_pk_get_keygrip)
MARK_VISIBLE (gcry_pk_get_nbits)
MARK_VISIBLE (gcry_pk_list)
MARK_VISIBLE (gcry_pk_map_name)
-MARK_VISIBLE (gcry_pk_register)
+MARK_VISIBLEX(gcry_pk_register)
MARK_VISIBLE (gcry_pk_sign)
MARK_VISIBLE (gcry_pk_testkey)
MARK_VISIBLE (gcry_pk_unregister)
@@ -695,13 +693,6 @@ MARK_VISIBLE (gcry_mpi_subm)
MARK_VISIBLE (gcry_mpi_swap)
MARK_VISIBLE (gcry_mpi_test_bit)
-MARK_VISIBLE (gcry_cipher_register)
-MARK_VISIBLE (gcry_cipher_unregister)
-MARK_VISIBLE (gcry_pk_register)
-MARK_VISIBLE (gcry_pk_unregister)
-MARK_VISIBLE (gcry_md_register)
-MARK_VISIBLE (gcry_md_unregister)
-
#undef MARK_VISIBLE
diff --git a/tests/ChangeLog b/tests/ChangeLog
index c0c2ebb7..38e65f30 100644
--- a/tests/ChangeLog
+++ b/tests/ChangeLog
@@ -1,3 +1,17 @@
+2008-08-18 Werner Koch <wk@g10code.com>
+
+ * basic.c (main): Add option --fips.
+
+2008-08-15 Werner Koch <wk@g10code.com>
+
+ * register.c (main): Check for fips mode.
+ (check_run): Take care of fips mode.
+
+ * basic.c (check_cbc_mac_cipher, check_ciphers, check_digests)
+ (check_hmac, check_pubkey): Do not test unavalaible algorithms in
+ fips mode.
+ (main): Check for fips mode.
+
2008-04-22 Werner Koch <wk@g10code.com>
* basic.c (check_one_cipher): Also check in-place encryption.
diff --git a/tests/basic.c b/tests/basic.c
index 3132e5d4..7ae2de25 100644
--- a/tests/basic.c
+++ b/tests/basic.c
@@ -50,6 +50,7 @@ test_spec_pubkey_t;
static int verbose;
static int error_count;
+static int in_fips_mode;
static void
fail (const char *format, ...)
@@ -127,6 +128,14 @@ check_cbc_mac_cipher (void)
for (i = 0; i < sizeof (tv) / sizeof (tv[0]); i++)
{
+ if (gcry_cipher_test_algo (tv[i].algo) && in_fips_mode)
+ {
+ if (verbose)
+ fprintf (stderr, " algorithm %d not available in fips mode\n",
+ tv[i].algo);
+ continue;
+ }
+
err = gcry_cipher_open (&hd,
tv[i].algo,
GCRY_CIPHER_MODE_CBC, GCRY_CIPHER_CBC_MAC);
@@ -1034,6 +1043,13 @@ check_ciphers (void)
fprintf (stderr, "Starting Cipher checks.\n");
for (i = 0; algos[i]; i++)
{
+ if (gcry_cipher_test_algo (algos[i]) && in_fips_mode)
+ {
+ if (verbose)
+ fprintf (stderr, " algorithm %d not available in fips mode\n",
+ algos[i]);
+ continue;
+ }
if (verbose)
fprintf (stderr, " checking %s [%i]\n",
gcry_cipher_algo_name (algos[i]),
@@ -1049,6 +1065,13 @@ check_ciphers (void)
for (i = 0; algos2[i]; i++)
{
+ if (gcry_cipher_test_algo (algos[i]) && in_fips_mode)
+ {
+ if (verbose)
+ fprintf (stderr, " algorithm %d not available in fips mode\n",
+ algos[i]);
+ continue;
+ }
if (verbose)
fprintf (stderr, " checking `%s'\n",
gcry_cipher_algo_name (algos2[i]));
@@ -1294,6 +1317,13 @@ check_digests (void)
for (i = 0; algos[i].md; i++)
{
+ if (gcry_md_test_algo (algos[i].md) && in_fips_mode)
+ {
+ if (verbose)
+ fprintf (stderr, " algorithm %d not available in fips mode\n",
+ algos[i].md);
+ continue;
+ }
if (verbose)
fprintf (stderr, " checking %s [%i] for length %zi\n",
gcry_md_algo_name (algos[i].md),
@@ -1656,6 +1686,13 @@ check_hmac (void)
for (i = 0; algos[i].md; i++)
{
+ if (gcry_md_test_algo (algos[i].md) && in_fips_mode)
+ {
+ if (verbose)
+ fprintf (stderr, " algorithm %d not available in fips mode\n",
+ algos[i].md);
+ continue;
+ }
if (verbose)
fprintf (stderr, " checking %s [%i] for length %zi\n",
gcry_md_algo_name (algos[i].md),
@@ -1968,7 +2005,16 @@ check_pubkey (void)
fprintf (stderr, "Starting public key checks.\n");
for (i = 0; i < sizeof (pubkeys) / sizeof (*pubkeys); i++)
if (pubkeys[i].id)
- check_one_pubkey (i, pubkeys[i]);
+ {
+ if (gcry_pk_test_algo (pubkeys[i].id) && in_fips_mode)
+ {
+ if (verbose)
+ fprintf (stderr, " algorithm %d not available in fips mode\n",
+ pubkeys[i].id);
+ continue;
+ }
+ check_one_pubkey (i, pubkeys[i]);
+ }
if (verbose)
fprintf (stderr, "Completed public key checks.\n");
@@ -1976,7 +2022,16 @@ check_pubkey (void)
fprintf (stderr, "Starting additional public key checks.\n");
for (i = 0; i < sizeof (pubkeys) / sizeof (*pubkeys); i++)
if (pubkeys[i].id)
- check_one_pubkey_new (i);
+ {
+ if (gcry_pk_test_algo (pubkeys[i].id) && in_fips_mode)
+ {
+ if (verbose)
+ fprintf (stderr, " algorithm %d not available in fips mode\n",
+ pubkeys[i].id);
+ continue;
+ }
+ check_one_pubkey_new (i);
+ }
if (verbose)
fprintf (stderr, "Completed additional public key checks.\n");
@@ -1984,13 +2039,41 @@ check_pubkey (void)
int
main (int argc, char **argv)
-{
+{
+ int last_argc = -1;
int debug = 0;
+ int use_fips = 0;
+
+ if (argc)
+ { argc--; argv++; }
+
+ while (argc && last_argc != argc )
+ {
+ last_argc = argc;
+ if (!strcmp (*argv, "--"))
+ {
+ argc--; argv++;
+ break;
+ }
+ else if (!strcmp (*argv, "--verbose"))
+ {
+ verbose = 1;
+ argc--; argv++;
+ }
+ else if (!strcmp (*argv, "--debug"))
+ {
+ verbose = debug = 1;
+ argc--; argv++;
+ }
+ else if (!strcmp (*argv, "--fips"))
+ {
+ use_fips = 1;
+ argc--; argv++;
+ }
+ }
- if (argc > 1 && !strcmp (argv[1], "--verbose"))
- verbose = 1;
- else if (argc > 1 && !strcmp (argv[1], "--debug"))
- verbose = debug = 1;
+ if (use_fips)
+ gcry_control (GCRYCTL_FORCE_FIPS_MODE, 0);
if (!gcry_check_version (GCRYPT_VERSION))
die ("version mismatch\n");
@@ -2005,6 +2088,9 @@ main (int argc, char **argv)
/* No valuable keys are create, so we can speed up our RNG. */
gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
+ if ( gcry_control (GCRYCTL_FIPS_MODE_P, 0) )
+ in_fips_mode = 1;
+
check_ciphers ();
check_aes128_cbc_cts_cipher ();
check_cbc_mac_cipher ();
@@ -2015,6 +2101,10 @@ main (int argc, char **argv)
check_hmac ();
check_pubkey ();
+ /* If we are in fips mode, trigger a selftest. */
+ if (in_fips_mode)
+ gcry_control (GCRYCTL_FORCE_FIPS_MODE, 0);
+
if (verbose)
fprintf (stderr, "\nAll tests completed. Errors: %i\n", error_count);
diff --git a/tests/benchmark.c b/tests/benchmark.c
index 424461ad..f428a15d 100644
--- a/tests/benchmark.c
+++ b/tests/benchmark.c
@@ -992,12 +992,13 @@ main( int argc, char **argv )
if (argc)
{ argc--; argv++; }
- gcry_control (GCRYCTL_DISABLE_SECMEM, 0);
if (!gcry_check_version (GCRYPT_VERSION))
{
fprintf (stderr, PGM ": version mismatch\n");
exit (1);
}
+ gcry_control (GCRYCTL_DISABLE_SECMEM, 0);
+
if (argc && !strcmp (*argv, "--use-random-daemon"))
{
gcry_control (GCRYCTL_USE_RANDOM_DAEMON, 1);
@@ -1048,6 +1049,11 @@ main( int argc, char **argv )
argc--; argv++;
}
}
+ else if (!strcmp (*argv, "--fips"))
+ {
+ argc--; argv++;
+ gcry_control (GCRYCTL_FORCE_FIPS_MODE, 0);
+ }
}
gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
diff --git a/tests/register.c b/tests/register.c
index 49686017..df90fe09 100644
--- a/tests/register.c
+++ b/tests/register.c
@@ -30,6 +30,7 @@
#include "../src/gcrypt.h"
static int verbose;
+static int in_fips_mode;
static void
die (const char *format, ...)
@@ -114,10 +115,21 @@ check_run (void)
int ret;
err = gcry_cipher_register (&cipher_spec_foo, &algorithm, &module);
- assert (! err);
+ if (in_fips_mode)
+ {
+ if (gpg_err_code (err) != GPG_ERR_NOT_SUPPORTED)
+ die ("register cipher failed in fips mode: %s\n", gpg_strerror (err));
+ return;
+ }
+ else
+ {
+ if (err)
+ die ("register cipher failed: %s\n", gpg_strerror (err));
+ }
err = gcry_cipher_open (&h, algorithm, GCRY_CIPHER_MODE_CBC, 0);
- assert (! err);
+ if (err)
+ die ("gcry_cipher_open failed: %s\n", gpg_strerror (err));
err = gcry_cipher_encrypt (h,
(unsigned char *) encrypted, sizeof (encrypted),
@@ -163,8 +175,13 @@ main (int argc, char **argv)
if (debug)
gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1u , 0);
+ if ( gcry_control (GCRYCTL_FIPS_MODE_P, 0) )
+ in_fips_mode = 1;
+
for (; i > 0; i--)
check_run ();
-
- return 0;
+
+ /* In fips mode we let the Makefile skip this test because a PASS
+ would not make much sense with all egistering disabled. */
+ return in_fips_mode? 77:0;
}