From 24138403c1a7014199d657257fa39c017203301c Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: Oct 31 2019 07:24:05 +0000 Subject: import libgcrypt-1.5.3-14.el7 --- diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d8163ee --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +SOURCES/libgcrypt-1.5.3-hobbled.tar.xz diff --git a/.libgcrypt.metadata b/.libgcrypt.metadata new file mode 100644 index 0000000..568c04b --- /dev/null +++ b/.libgcrypt.metadata @@ -0,0 +1 @@ +62f720c9d305035d5fee880db052e903ea6510cd SOURCES/libgcrypt-1.5.3-hobbled.tar.xz diff --git a/SOURCES/hobble-libgcrypt b/SOURCES/hobble-libgcrypt new file mode 100755 index 0000000..1062d6e --- /dev/null +++ b/SOURCES/hobble-libgcrypt @@ -0,0 +1,9 @@ +#!/bin/sh + +# Quit out if anything fails. +set -e -x + +# Clean out patent-or-otherwise-encumbered code. +# EC: ????????? ??/??/2015 + +rm -f cipher/ecc.c diff --git a/SOURCES/libgcrypt-1.5.0-leak.patch b/SOURCES/libgcrypt-1.5.0-leak.patch new file mode 100644 index 0000000..5f0d191 --- /dev/null +++ b/SOURCES/libgcrypt-1.5.0-leak.patch @@ -0,0 +1,73 @@ +diff -up libgcrypt-1.5.0/cipher/elgamal.c.leak libgcrypt-1.5.0/cipher/elgamal.c +--- libgcrypt-1.5.0/cipher/elgamal.c.leak 2011-02-04 20:09:38.000000000 +0100 ++++ libgcrypt-1.5.0/cipher/elgamal.c 2012-12-03 14:51:10.743067964 +0100 +@@ -641,7 +641,10 @@ elg_generate_ext (int algo, unsigned int + } + + if (xvalue) +- ec = generate_using_x (&sk, nbits, xvalue, retfactors); ++ { ++ ec = generate_using_x (&sk, nbits, xvalue, retfactors); ++ gcry_mpi_release(xvalue); ++ } + else + { + generate (&sk, nbits, retfactors); +diff -up libgcrypt-1.5.0/cipher/primegen.c.leak libgcrypt-1.5.0/cipher/primegen.c +--- libgcrypt-1.5.0/cipher/primegen.c.leak 2012-04-05 15:37:52.000000000 +0200 ++++ libgcrypt-1.5.0/cipher/primegen.c 2012-12-03 14:44:14.610010867 +0100 +@@ -1198,10 +1198,7 @@ gcry_prime_group_generator (gcry_mpi_t * + gcry_mpi_t prime, gcry_mpi_t *factors, + gcry_mpi_t start_g) + { +- gcry_mpi_t tmp = gcry_mpi_new (0); +- gcry_mpi_t b = gcry_mpi_new (0); +- gcry_mpi_t pmin1 = gcry_mpi_new (0); +- gcry_mpi_t g = start_g? gcry_mpi_copy (start_g) : gcry_mpi_set_ui (NULL, 3); ++ gcry_mpi_t tmp, b, pmin1, g; + int first = 1; + int i, n; + +@@ -1214,6 +1211,11 @@ gcry_prime_group_generator (gcry_mpi_t * + if (n < 2) + return gpg_error (GPG_ERR_INV_ARG); + ++ tmp = gcry_mpi_new (0); ++ b = gcry_mpi_new (0); ++ pmin1 = gcry_mpi_new (0); ++ g = start_g? gcry_mpi_copy (start_g) : gcry_mpi_set_ui (NULL, 3); ++ + /* Extra sanity check - usually disabled. */ + /* mpi_set (tmp, factors[0]); */ + /* for(i = 1; i < n; i++) */ +diff -up libgcrypt-1.5.0/cipher/pubkey.c.leak libgcrypt-1.5.0/cipher/pubkey.c +--- libgcrypt-1.5.0/cipher/pubkey.c.leak 2011-06-13 12:23:50.000000000 +0200 ++++ libgcrypt-1.5.0/cipher/pubkey.c 2012-12-03 15:23:42.377183489 +0100 +@@ -2853,6 +2853,8 @@ gcry_pk_encrypt (gcry_sexp_t *r_ciph, gc + + REGISTER_DEFAULT_PUBKEYS; + ++ init_encoding_ctx (&ctx, PUBKEY_OP_ENCRYPT, gcry_pk_get_nbits (s_pkey)); ++ + /* Get the key. */ + rc = sexp_to_key (s_pkey, 0, NULL, &pkey, &module); + if (rc) +@@ -2873,7 +2875,6 @@ gcry_pk_encrypt (gcry_sexp_t *r_ciph, gc + algo_elems = pubkey->elements_enc; + + /* Get the stuff we want to encrypt. */ +- init_encoding_ctx (&ctx, PUBKEY_OP_ENCRYPT, gcry_pk_get_nbits (s_pkey)); + rc = sexp_data_to_mpi (s_data, &data, &ctx); + if (rc) + goto leave; +diff -up libgcrypt-1.5.0/src/hmac256.c.leak libgcrypt-1.5.0/src/hmac256.c +--- libgcrypt-1.5.0/src/hmac256.c.leak 2011-02-04 20:17:33.000000000 +0100 ++++ libgcrypt-1.5.0/src/hmac256.c 2012-12-03 15:37:36.504955809 +0100 +@@ -435,7 +435,6 @@ _gcry_hmac256_finalize (hmac256_context_ + tmphd = _gcry_hmac256_new (NULL, 0); + if (!tmphd) + { +- free (hd); + return NULL; + } + _gcry_hmac256_update (tmphd, hd->opad, 64); diff --git a/SOURCES/libgcrypt-1.5.0-noecc.patch b/SOURCES/libgcrypt-1.5.0-noecc.patch new file mode 100644 index 0000000..7905c71 --- /dev/null +++ b/SOURCES/libgcrypt-1.5.0-noecc.patch @@ -0,0 +1,12 @@ +diff -up libgcrypt-1.5.0/tests/Makefile.noecc libgcrypt-1.5.0/tests/Makefile +--- libgcrypt-1.5.0/tests/Makefile.in.noecc 2011-07-21 15:34:33.000000000 +0200 ++++ libgcrypt-1.5.0/tests/Makefile.in 2011-07-21 15:39:35.000000000 +0200 +@@ -57,7 +57,7 @@ TESTS = version$(EXEEXT) t-mpi-bit$(EXEE + ac-data$(EXEEXT) basic$(EXEEXT) mpitests$(EXEEXT) \ + tsexp$(EXEEXT) keygen$(EXEEXT) pubkey$(EXEEXT) hmac$(EXEEXT) \ + keygrip$(EXEEXT) fips186-dsa$(EXEEXT) aeswrap$(EXEEXT) \ +- curves$(EXEEXT) t-kdf$(EXEEXT) pkcs1v2$(EXEEXT) \ ++ t-kdf$(EXEEXT) pkcs1v2$(EXEEXT) \ + $(am__EXEEXT_1) benchmark$(EXEEXT) + + # random.c uses fork() thus a test for W32 does not make any sense. diff --git a/SOURCES/libgcrypt-1.5.0-tests.patch b/SOURCES/libgcrypt-1.5.0-tests.patch new file mode 100644 index 0000000..277438f --- /dev/null +++ b/SOURCES/libgcrypt-1.5.0-tests.patch @@ -0,0 +1,214 @@ +diff -up libgcrypt-1.5.0/cipher/dsa.c.tests libgcrypt-1.5.0/cipher/dsa.c +--- libgcrypt-1.5.0/cipher/dsa.c.tests 2011-06-13 12:24:46.000000000 +0200 ++++ libgcrypt-1.5.0/cipher/dsa.c 2011-07-20 16:44:51.000000000 +0200 +@@ -479,22 +479,21 @@ generate_fips186 (DSA_secret_key *sk, un + initial_seed.seed = gcry_sexp_nth_data (initial_seed.sexp, 1, + &initial_seed.seedlen); + } +- +- /* Fixme: Enable 186-3 after it has been approved and after fixing +- the generation function. */ +- /* if (use_fips186_2) */ +- (void)use_fips186_2; +- ec = _gcry_generate_fips186_2_prime (nbits, qbits, +- initial_seed.seed, ++ ++ if (use_fips186_2) ++ ec = _gcry_generate_fips186_2_prime (nbits, qbits, ++ initial_seed.seed, + initial_seed.seedlen, + &prime_q, &prime_p, + r_counter, + r_seed, r_seedlen); +- /* else */ +- /* ec = _gcry_generate_fips186_3_prime (nbits, qbits, NULL, 0, */ +- /* &prime_q, &prime_p, */ +- /* r_counter, */ +- /* r_seed, r_seedlen, NULL); */ ++ else ++ ec = _gcry_generate_fips186_3_prime (nbits, qbits, ++ initial_seed.seed, ++ initial_seed.seedlen, ++ &prime_q, &prime_p, ++ r_counter, ++ r_seed, r_seedlen, NULL); + gcry_sexp_release (initial_seed.sexp); + if (ec) + goto leave; +diff -up libgcrypt-1.5.0/cipher/primegen.c.tests libgcrypt-1.5.0/cipher/primegen.c +--- libgcrypt-1.5.0/cipher/primegen.c.tests 2011-03-28 14:19:52.000000000 +0200 ++++ libgcrypt-1.5.0/cipher/primegen.c 2011-07-21 14:36:03.000000000 +0200 +@@ -1647,7 +1647,7 @@ _gcry_generate_fips186_3_prime (unsigned + gpg_err_code_t ec; + unsigned char seed_help_buffer[256/8]; /* Used to hold a generated SEED. */ + unsigned char *seed_plus; /* Malloced buffer to hold SEED+x. */ +- unsigned char digest[256/8]; /* Helper buffer for SHA-1 digest. */ ++ unsigned char digest[256/8]; /* Helper buffer for SHA-x digest. */ + gcry_mpi_t val_2 = NULL; /* Helper for the prime test. */ + gcry_mpi_t tmpval = NULL; /* Helper variable. */ + int hashalgo; /* The id of the Approved Hash Function. */ +@@ -1737,7 +1737,7 @@ _gcry_generate_fips186_3_prime (unsigned + } + gcry_mpi_release (prime_q); prime_q = NULL; + ec = gpg_err_code (gcry_mpi_scan (&prime_q, GCRYMPI_FMT_USG, +- value_u, sizeof value_u, NULL)); ++ value_u, qbits/8, NULL)); + if (ec) + goto leave; + mpi_set_highbit (prime_q, qbits-1 ); +@@ -1782,11 +1782,11 @@ _gcry_generate_fips186_3_prime (unsigned + if (seed_plus[i]) + break; + } +- gcry_md_hash_buffer (GCRY_MD_SHA1, digest, seed_plus, seedlen); ++ gcry_md_hash_buffer (hashalgo, digest, seed_plus, seedlen); + + gcry_mpi_release (tmpval); tmpval = NULL; + ec = gpg_err_code (gcry_mpi_scan (&tmpval, GCRYMPI_FMT_USG, +- digest, sizeof digest, NULL)); ++ digest, qbits/8, NULL)); + if (ec) + goto leave; + if (value_j == value_n) +@@ -1822,11 +1822,11 @@ _gcry_generate_fips186_3_prime (unsigned + } + + /* Step 12: Save p, q, counter and seed. */ +- log_debug ("fips186-3 pbits p=%u q=%u counter=%d\n", ++/* log_debug ("fips186-3 pbits p=%u q=%u counter=%d\n", + mpi_get_nbits (prime_p), mpi_get_nbits (prime_q), counter); + log_printhex("fips186-3 seed:", seed, seedlen); + log_mpidump ("fips186-3 prime p", prime_p); +- log_mpidump ("fips186-3 prime q", prime_q); ++ log_mpidump ("fips186-3 prime q", prime_q); */ + if (r_q) + { + *r_q = prime_q; +diff -up libgcrypt-1.5.0/cipher/rsa.c.tests libgcrypt-1.5.0/cipher/rsa.c +--- libgcrypt-1.5.0/cipher/rsa.c.tests 2011-06-10 10:53:41.000000000 +0200 ++++ libgcrypt-1.5.0/cipher/rsa.c 2011-07-21 14:36:59.000000000 +0200 +@@ -388,7 +388,7 @@ generate_x931 (RSA_secret_key *sk, unsig + + *swapped = 0; + +- if (e_value == 1) /* Alias for a secure value. */ ++ if (e_value == 1 || e_value == 0) /* Alias for a secure value. */ + e_value = 65537; + + /* Point 1 of section 4.1: k = 1024 + 256s with S >= 0 */ +diff -up libgcrypt-1.5.0/random/random-fips.c.tests libgcrypt-1.5.0/random/random-fips.c +--- libgcrypt-1.5.0/random/random-fips.c.tests 2011-07-20 16:40:59.000000000 +0200 ++++ libgcrypt-1.5.0/random/random-fips.c 2011-07-20 16:40:59.000000000 +0200 +@@ -691,6 +691,7 @@ get_random (void *buffer, size_t length, + + check_guards (rng_ctx); + ++ reinitialize: + /* Initialize the cipher handle and thus setup the key if needed. */ + if (!rng_ctx->cipher_hd) + { +@@ -710,13 +711,11 @@ get_random (void *buffer, size_t length, + if (rng_ctx->key_init_pid != getpid () + || rng_ctx->seed_init_pid != getpid ()) + { +- /* We are in a child of us. Because we have no way yet to do +- proper re-initialization (including self-checks etc), the +- only chance we have is to bail out. Obviusly a fork/exec +- won't harm because the exec overwrites the old image. */ +- fips_signal_error ("fork without proper re-initialization " +- "detected in RNG"); +- goto bailout; ++ /* Just reinitialize the key & seed. */ ++ gcry_cipher_close(rng_ctx->cipher_hd); ++ rng_ctx->cipher_hd = NULL; ++ rng_ctx->is_seeded = 0; ++ goto reinitialize; + } + + if (x931_aes_driver (buffer, length, rng_ctx)) +diff -up libgcrypt-1.5.0/tests/ac.c.tests libgcrypt-1.5.0/tests/ac.c +--- libgcrypt-1.5.0/tests/ac.c.tests 2011-02-04 20:18:20.000000000 +0100 ++++ libgcrypt-1.5.0/tests/ac.c 2011-07-20 16:40:59.000000000 +0200 +@@ -150,6 +150,9 @@ main (int argc, char **argv) + if (!gcry_check_version (GCRYPT_VERSION)) + die ("version mismatch\n"); + gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0); ++ if (gcry_fips_mode_active()) ++ /* ac not functional in the fips mode, skip it */ ++ return 77; + if (debug) + gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1u , 0); + /* No valuable keys are create, so we can speed up our RNG. */ +diff -up libgcrypt-1.5.0/tests/ac-data.c.tests libgcrypt-1.5.0/tests/ac-data.c +--- libgcrypt-1.5.0/tests/ac-data.c.tests 2011-02-04 20:18:20.000000000 +0100 ++++ libgcrypt-1.5.0/tests/ac-data.c 2011-07-20 16:40:59.000000000 +0200 +@@ -198,6 +198,9 @@ main (int argc, char **argv) + if (!gcry_check_version (GCRYPT_VERSION)) + die ("version mismatch\n"); + gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0); ++ if (gcry_fips_mode_active()) ++ /* ac not functional in the fips mode, skip it */ ++ return 77; + if (debug) + gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1u , 0); + +diff -up libgcrypt-1.5.0/tests/ac-schemes.c.tests libgcrypt-1.5.0/tests/ac-schemes.c +--- libgcrypt-1.5.0/tests/ac-schemes.c.tests 2011-02-04 20:18:20.000000000 +0100 ++++ libgcrypt-1.5.0/tests/ac-schemes.c 2011-07-20 16:40:59.000000000 +0200 +@@ -338,6 +338,9 @@ main (int argc, char **argv) + if (! gcry_check_version (GCRYPT_VERSION)) + die ("version mismatch\n"); + gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0); ++ if (gcry_fips_mode_active()) ++ /* ac not functional in the fips mode, skip it */ ++ return 77; + if (debug) + gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1u, 0); + +diff -up libgcrypt-1.5.0/tests/keygen.c.tests libgcrypt-1.5.0/tests/keygen.c +--- libgcrypt-1.5.0/tests/keygen.c.tests 2011-02-04 20:18:20.000000000 +0100 ++++ libgcrypt-1.5.0/tests/keygen.c 2011-07-21 14:39:03.000000000 +0200 +@@ -148,12 +148,12 @@ check_rsa_keys (void) + } + + if (verbose) +- fprintf (stderr, "creating 1536 bit DSA key\n"); ++ fprintf (stderr, "creating 2048 bit DSA key\n"); + rc = gcry_sexp_new (&keyparm, + "(genkey\n" + " (dsa\n" +- " (nbits 4:1536)\n" +- " (qbits 3:224)\n" ++ " (nbits 4:2048)\n" ++ " (qbits 3:256)\n" + " ))", 0, 1); + if (rc) + die ("error creating S-expression: %s\n", gpg_strerror (rc)); +@@ -190,11 +190,11 @@ check_rsa_keys (void) + + + if (verbose) +- fprintf (stderr, "creating 512 bit RSA key with e=257\n"); ++ fprintf (stderr, "creating 1024 bit RSA key with e=257\n"); + rc = gcry_sexp_new (&keyparm, + "(genkey\n" + " (rsa\n" +- " (nbits 3:512)\n" ++ " (nbits 4:1024)\n" + " (rsa-use-e 3:257)\n" + " ))", 0, 1); + if (rc) +@@ -208,11 +208,11 @@ check_rsa_keys (void) + gcry_sexp_release (key); + + if (verbose) +- fprintf (stderr, "creating 512 bit RSA key with default e\n"); ++ fprintf (stderr, "creating 1024 bit RSA key with default secure e\n"); + rc = gcry_sexp_new (&keyparm, + "(genkey\n" + " (rsa\n" +- " (nbits 3:512)\n" ++ " (nbits 4:1024)\n" + " (rsa-use-e 1:0)\n" + " ))", 0, 1); + if (rc) diff --git a/SOURCES/libgcrypt-1.5.0-use-fipscheck.patch b/SOURCES/libgcrypt-1.5.0-use-fipscheck.patch new file mode 100644 index 0000000..1cef010 --- /dev/null +++ b/SOURCES/libgcrypt-1.5.0-use-fipscheck.patch @@ -0,0 +1,87 @@ +diff -up libgcrypt-1.5.0/src/fips.c.use-fipscheck libgcrypt-1.5.0/src/fips.c +--- libgcrypt-1.5.0/src/fips.c.use-fipscheck 2011-02-04 20:17:33.000000000 +0100 ++++ libgcrypt-1.5.0/src/fips.c 2011-07-20 16:17:21.000000000 +0200 +@@ -570,23 +570,48 @@ run_random_selftests (void) + return !!err; + } + ++static int ++get_library_path(const char *libname, const char *symbolname, char *path, size_t pathlen) ++{ ++ Dl_info info; ++ void *dl, *sym; ++ int rv = -1; ++ ++ dl = dlopen(libname, RTLD_LAZY); ++ if (dl == NULL) { ++ return -1; ++ } ++ ++ sym = dlsym(dl, symbolname); ++ ++ if (sym != NULL && dladdr(sym, &info)) { ++ strncpy(path, info.dli_fname, pathlen-1); ++ path[pathlen-1] = '\0'; ++ rv = 0; ++ } ++ ++ dlclose(dl); ++ ++ return rv; ++} ++ + /* Run an integrity check on the binary. Returns 0 on success. */ + static int + check_binary_integrity (void) + { + #ifdef ENABLE_HMAC_BINARY_CHECK + gpg_error_t err; +- Dl_info info; ++ char libpath[4096]; + unsigned char digest[32]; + int dlen; + char *fname = NULL; +- const char key[] = "What am I, a doctor or a moonshuttle conductor?"; +- +- if (!dladdr ("gcry_check_version", &info)) ++ const char key[] = "orboDeJITITejsirpADONivirpUkvarP"; ++ ++ if (get_library_path ("libgcrypt.so.11", "gcry_check_version", libpath, sizeof(libpath))) + err = gpg_error_from_syserror (); + else + { +- dlen = _gcry_hmac256_file (digest, sizeof digest, info.dli_fname, ++ dlen = _gcry_hmac256_file (digest, sizeof digest, libpath, + key, strlen (key)); + if (dlen < 0) + err = gpg_error_from_syserror (); +@@ -594,7 +619,7 @@ check_binary_integrity (void) + err = gpg_error (GPG_ERR_INTERNAL); + else + { +- fname = gcry_malloc (strlen (info.dli_fname) + 1 + 5 + 1 ); ++ fname = gcry_malloc (strlen (libpath) + 1 + 5 + 1 ); + if (!fname) + err = gpg_error_from_syserror (); + else +@@ -603,7 +628,7 @@ check_binary_integrity (void) + char *p; + + /* Prefix the basename with a dot. */ +- strcpy (fname, info.dli_fname); ++ strcpy (fname, libpath); + p = strrchr (fname, '/'); + if (p) + p++; +diff -up libgcrypt-1.5.0/src/Makefile.in.use-fipscheck libgcrypt-1.5.0/src/Makefile.in +--- libgcrypt-1.5.0/src/Makefile.in.use-fipscheck 2011-06-29 10:58:01.000000000 +0200 ++++ libgcrypt-1.5.0/src/Makefile.in 2011-07-20 16:19:33.000000000 +0200 +@@ -375,7 +375,7 @@ libgcrypt_la_LIBADD = $(gcrypt_res) \ + ../cipher/libcipher.la \ + ../random/librandom.la \ + ../mpi/libmpi.la \ +- ../compat/libcompat.la $(GPG_ERROR_LIBS) ++ ../compat/libcompat.la $(GPG_ERROR_LIBS) -ldl + + dumpsexp_SOURCES = dumpsexp.c + dumpsexp_CFLAGS = $(arch_gpg_error_cflags) diff --git a/SOURCES/libgcrypt-1.5.1-use-poll.patch b/SOURCES/libgcrypt-1.5.1-use-poll.patch new file mode 100644 index 0000000..f6ed0b7 --- /dev/null +++ b/SOURCES/libgcrypt-1.5.1-use-poll.patch @@ -0,0 +1,82 @@ +diff -up libgcrypt-1.5.1/random/rndlinux.c.use-poll libgcrypt-1.5.1/random/rndlinux.c +--- libgcrypt-1.5.1/random/rndlinux.c.use-poll 2013-03-20 15:33:26.504867356 +0100 ++++ libgcrypt-1.5.1/random/rndlinux.c 2013-03-20 15:37:24.999944048 +0100 +@@ -32,6 +32,7 @@ + #include + #include + #include ++#include + #include "types.h" + #include "g10lib.h" + #include "rand-internal.h" +@@ -142,49 +143,37 @@ _gcry_rndlinux_gather_random (void (*add + } + + /* Enter the read loop. */ +- delay = 0; /* Start with 0 seconds so that we do no block on the ++ delay = 100; /* Start with 0 seconds so that we do no block on the + first iteration and in turn call the progress function + before blocking. To give the OS a better chance to + return with something we will actually use 100ms. */ + while (length) + { +- fd_set rfds; +- struct timeval tv; + int rc; ++ struct pollfd pfd; + +- /* If the system has no limit on the number of file descriptors +- and we encounter an fd which is larger than the fd_set size, +- we don't use the select at all. The select code is only used +- to emit progress messages. A better solution would be to +- fall back to poll() if available. */ +-#ifdef FD_SETSIZE +- if (fd < FD_SETSIZE) +-#endif ++ pfd.fd = fd; ++ pfd.events = POLLIN; ++ ++ if ( !(rc=poll(&pfd, 1, delay)) ) + { +- FD_ZERO(&rfds); +- FD_SET(fd, &rfds); +- tv.tv_sec = delay; +- tv.tv_usec = delay? 0 : 100000; +- if ( !(rc=select(fd+1, &rfds, NULL, NULL, &tv)) ) +- { +- if (!any_need_entropy || last_so_far != (want - length) ) +- { +- last_so_far = want - length; +- _gcry_random_progress ("need_entropy", 'X', +- (int)last_so_far, (int)want); +- any_need_entropy = 1; +- } +- delay = 3; /* Use 3 seconds henceforth. */ +- continue; +- } +- else if( rc == -1 ) ++ if (!any_need_entropy || last_so_far != (want - length) ) + { +- log_error ("select() error: %s\n", strerror(errno)); +- if (!delay) +- delay = 1; /* Use 1 second if we encounter an error before ++ last_so_far = want - length; ++ _gcry_random_progress ("need_entropy", 'X', ++ (int)last_so_far, (int)want); ++ any_need_entropy = 1; ++ } ++ delay = 3000; /* Use 3 seconds henceforth. */ ++ continue; ++ } ++ else if( rc == -1 ) ++ { ++ log_error ("poll() error: %s\n", strerror(errno)); ++ if (!delay) ++ delay = 1000; /* Use 1 second if we encounter an error before + we have ever blocked. */ +- continue; +- } ++ continue; + } + + do diff --git a/SOURCES/libgcrypt-1.5.2-aliasing.patch b/SOURCES/libgcrypt-1.5.2-aliasing.patch new file mode 100644 index 0000000..db0e0e0 --- /dev/null +++ b/SOURCES/libgcrypt-1.5.2-aliasing.patch @@ -0,0 +1,30 @@ +diff -up libgcrypt-1.5.2/cipher/Makefile.am.aliasing libgcrypt-1.5.2/cipher/Makefile.am +--- libgcrypt-1.5.2/cipher/Makefile.am.aliasing 2013-04-18 16:49:13.000000000 +0200 ++++ libgcrypt-1.5.2/cipher/Makefile.am 2013-04-25 21:48:57.867465215 +0200 +@@ -81,3 +81,9 @@ tiger.o: $(srcdir)/tiger.c + + tiger.lo: $(srcdir)/tiger.c + `echo $(LTCOMPILE) -c $(srcdir)/tiger.c | $(o_flag_munging) ` ++ ++rijndael.o: $(srcdir)/rijndael.c ++ `echo $(COMPILE) -fno-strict-aliasing -c $(srcdir)/rijndael.c ` ++ ++rijndael.lo: $(srcdir)/rijndael.c ++ `echo $(LTCOMPILE) -fno-strict-aliasing -c $(srcdir)/rijndael.c ` +diff -up libgcrypt-1.5.2/cipher/Makefile.in.aliasing libgcrypt-1.5.2/cipher/Makefile.in +--- libgcrypt-1.5.2/cipher/Makefile.in.aliasing 2013-04-18 17:06:03.000000000 +0200 ++++ libgcrypt-1.5.2/cipher/Makefile.in 2013-04-25 21:48:59.164493610 +0200 +@@ -638,6 +638,12 @@ tiger.o: $(srcdir)/tiger.c + tiger.lo: $(srcdir)/tiger.c + `echo $(LTCOMPILE) -c $(srcdir)/tiger.c | $(o_flag_munging) ` + ++rijndael.o: $(srcdir)/rijndael.c ++ `echo $(COMPILE) -fno-strict-aliasing -c $(srcdir)/rijndael.c ` ++ ++rijndael.lo: $(srcdir)/rijndael.c ++ `echo $(LTCOMPILE) -fno-strict-aliasing -c $(srcdir)/rijndael.c ` ++ + # Tell versions [3.59,3.63) of GNU make to not export all variables. + # Otherwise a system limit (for SysV at least) may be exceeded. + .NOEXPORT: +diff -up libgcrypt-1.5.2/cipher/rijndael.c.aliasing libgcrypt-1.5.2/cipher/rijndael.c diff --git a/SOURCES/libgcrypt-1.5.2-mpicoder-gccopt.patch b/SOURCES/libgcrypt-1.5.2-mpicoder-gccopt.patch new file mode 100644 index 0000000..c374709 --- /dev/null +++ b/SOURCES/libgcrypt-1.5.2-mpicoder-gccopt.patch @@ -0,0 +1,102 @@ +diff -up libgcrypt-1.5.2/mpi/mpicoder.c.gccopt libgcrypt-1.5.2/mpi/mpicoder.c +--- libgcrypt-1.5.2/mpi/mpicoder.c.gccopt 2013-04-18 16:48:42.000000000 +0200 ++++ libgcrypt-1.5.2/mpi/mpicoder.c 2013-06-20 10:24:57.241510589 +0200 +@@ -555,16 +555,16 @@ gcry_mpi_print (enum gcry_mpi_format for + extra=1; + } + +- if (buffer && n > len) +- { +- /* The provided buffer is too short. */ +- gcry_free (tmp); +- return gcry_error (GPG_ERR_TOO_SHORT); +- } + if (buffer) + { + unsigned char *s = buffer; + ++ if (n > len) ++ { ++ /* The provided buffer is too short. */ ++ gcry_free (tmp); ++ return gcry_error (GPG_ERR_TOO_SHORT); ++ } + if (extra) + *s++ = 0; + memcpy (s, tmp, n-extra); +@@ -580,12 +580,12 @@ gcry_mpi_print (enum gcry_mpi_format for + /* Note: We ignore the sign for this format. */ + /* FIXME: for performance reasons we should put this into + mpi_aprint because we can then use the buffer directly. */ +- if (buffer && n > len) +- return gcry_error (GPG_ERR_TOO_SHORT); + if (buffer) + { + unsigned char *tmp; + ++ if (n > len) ++ return gcry_error (GPG_ERR_TOO_SHORT); + tmp = _gcry_mpi_get_buffer (a, &n, NULL); + if (!tmp) + return gpg_error_from_syserror (); +@@ -603,14 +603,13 @@ gcry_mpi_print (enum gcry_mpi_format for + if( a->sign ) + return gcry_error (GPG_ERR_INV_ARG); + +- if (buffer && n+2 > len) +- return gcry_error (GPG_ERR_TOO_SHORT); +- + if (buffer) + { + unsigned char *tmp; + unsigned char *s = buffer; + ++ if (n+2 > len) ++ return gcry_error (GPG_ERR_TOO_SHORT); + s[0] = nbits >> 8; + s[1] = nbits; + +@@ -641,16 +640,16 @@ gcry_mpi_print (enum gcry_mpi_format for + extra=1; + } + +- if (buffer && n+4 > len) +- { +- gcry_free(tmp); +- return gcry_error (GPG_ERR_TOO_SHORT); +- } +- + if (buffer) + { + unsigned char *s = buffer; + ++ if (n+4 > len) ++ { ++ gcry_free(tmp); ++ return gcry_error (GPG_ERR_TOO_SHORT); ++ } ++ + *s++ = n >> 24; + *s++ = n >> 16; + *s++ = n >> 8; +@@ -677,15 +676,15 @@ gcry_mpi_print (enum gcry_mpi_format for + if (!n || (*tmp & 0x80)) + extra = 2; + +- if (buffer && 2*n + extra + !!a->sign + 1 > len) +- { +- gcry_free(tmp); +- return gcry_error (GPG_ERR_TOO_SHORT); +- } + if (buffer) + { + unsigned char *s = buffer; + ++ if (2*n + extra + !!a->sign + 1 > len) ++ { ++ gcry_free(tmp); ++ return gcry_error (GPG_ERR_TOO_SHORT); ++ } + if (a->sign) + *s++ = '-'; + if (extra) diff --git a/SOURCES/libgcrypt-1.5.3-ath-reinstall.patch b/SOURCES/libgcrypt-1.5.3-ath-reinstall.patch new file mode 100644 index 0000000..88421ba --- /dev/null +++ b/SOURCES/libgcrypt-1.5.3-ath-reinstall.patch @@ -0,0 +1,133 @@ +diff -up libgcrypt-1.5.3/src/ath.c.ath-reinstall libgcrypt-1.5.3/src/ath.c +--- libgcrypt-1.5.3/src/ath.c.ath-reinstall 2013-07-25 11:10:04.000000000 +0200 ++++ libgcrypt-1.5.3/src/ath.c 2017-02-28 14:37:15.267668432 +0100 +@@ -36,7 +36,7 @@ + #include + + #include "ath.h" +- ++#include "g10lib.h" + + + /* The interface table. */ +@@ -45,6 +45,13 @@ static struct ath_ops ops; + /* True if we should use the external callbacks. */ + static int ops_set; + ++struct lock_list ++{ ++ ath_mutex_t *lock; ++ struct lock_list *next; ++}; ++ ++static struct lock_list *reinstallable_locks; + + /* For the dummy interface. */ + #define MUTEX_UNLOCKED ((ath_mutex_t) 0) +@@ -62,6 +69,50 @@ static int ops_set; + /* The lock we take while checking for lazy lock initialization. */ + static ath_mutex_t check_init_lock = ATH_MUTEX_INITIALIZER; + ++static void ++add_reinstallable_lock(ath_mutex_t *lock) ++{ ++ struct lock_list *ll, *new, **ptr; ++ ++ new = gcry_calloc(1, sizeof(*new)); ++ if (!new) ++ abort(); ++ ++ for (ll = reinstallable_locks, ptr = &reinstallable_locks; ll != NULL; ptr = &ll->next, ll = ll->next) ++ { ++ if (ll->lock == lock) ++ { ++ gcry_free(new); ++ return; ++ } ++ } ++ ++ new->lock = lock; ++ *ptr = new; ++} ++ ++static void ++remove_reinstallable_lock(ath_mutex_t *lock) ++{ ++ struct lock_list *ll, **ptr; ++ ++ for (ll = reinstallable_locks, ptr = &reinstallable_locks; ll != NULL; ptr = &ll->next, ll = ll->next) ++ { ++ if (ll->lock == lock) ++ { ++ *ptr = ll->next; ++ gcry_free(ll); ++ /* we do not store duplicates */ ++ return; ++ } ++ } ++ ++#ifndef NDEBUG ++ /* lock not found, should not happen */ ++ abort(); ++#endif ++} ++ + int + ath_init (void) + { +@@ -85,7 +136,9 @@ ath_init (void) + gpg_err_code_t + ath_install (struct ath_ops *ath_ops, int check_only) + { +- if (check_only) ++ gpg_err_code_t err = 0; ++ ++ if (check_only && ops_set) + { + unsigned int option = 0; + +@@ -119,7 +172,25 @@ ath_install (struct ath_ops *ath_ops, in + else + ops_set = 0; + +- return 0; ++ if (ops_set && reinstallable_locks) ++ { ++ struct lock_list *ll; ++ ++ ath_init(); ++ for (ll = reinstallable_locks; ll != NULL;) ++ { ++ struct lock_list *prev; ++ ++ if (ath_mutex_init(ll->lock)) ++ err = GPG_ERR_NOT_SUPPORTED; ++ prev = ll; ++ ll = ll->next; ++ gcry_free(prev); ++ } ++ reinstallable_locks = NULL; ++ } ++ ++ return err; + } + + +@@ -143,6 +214,8 @@ ath_mutex_init (ath_mutex_t *lock) + { + if (ops_set) + return mutex_init (lock, 0); ++ else ++ add_reinstallable_lock(lock); + + #ifndef NDEBUG + *lock = MUTEX_UNLOCKED; +@@ -168,6 +241,8 @@ ath_mutex_destroy (ath_mutex_t *lock) + (*ops.mutex_unlock) (&check_init_lock); + return (*ops.mutex_destroy) (lock); + } ++ else ++ remove_reinstallable_lock(lock); + + #ifndef NDEBUG + assert (*lock == MUTEX_UNLOCKED); diff --git a/SOURCES/libgcrypt-1.5.3-drbg-cavs.patch b/SOURCES/libgcrypt-1.5.3-drbg-cavs.patch new file mode 100644 index 0000000..51ae70d --- /dev/null +++ b/SOURCES/libgcrypt-1.5.3-drbg-cavs.patch @@ -0,0 +1,972 @@ +diff -up libgcrypt-1.5.3/random/drbg.c.drbg-cavs libgcrypt-1.5.3/random/drbg.c +--- libgcrypt-1.5.3/random/drbg.c.drbg-cavs 2017-02-28 14:28:55.695906569 +0100 ++++ libgcrypt-1.5.3/random/drbg.c 2017-02-28 14:28:55.700906686 +0100 +@@ -2130,6 +2130,16 @@ gcry_drbg_cavs_test (struct gcry_drbg_te + if (ret) + goto outbuf; + ++ if (test->entropyrsd) ++ { ++ gcry_drbg_string_fill (&testentropy, test->entropyrsd, ++ test->entropyrsdlen); ++ gcry_drbg_string_fill (&addtl, test->addtlrsd, ++ test->addtlrsdlen); ++ if (gcry_drbg_reseed (drbg, &addtl)) ++ goto outbuf; ++ } ++ + gcry_drbg_string_fill (&addtl, test->addtla, test->addtllen); + if (test->entpra) + { +diff -up libgcrypt-1.5.3/random/random.h.drbg-cavs libgcrypt-1.5.3/random/random.h +--- libgcrypt-1.5.3/random/random.h.drbg-cavs 2017-02-28 14:28:55.686906357 +0100 ++++ libgcrypt-1.5.3/random/random.h 2017-02-28 14:28:55.700906686 +0100 +@@ -69,6 +69,10 @@ struct gcry_drbg_test_vector + size_t perslen; + unsigned char *expected; + size_t expectedlen; ++ unsigned char *entropyrsd; ++ size_t entropyrsdlen; ++ unsigned char *addtlrsd; ++ size_t addtlrsdlen; + }; + + gpg_err_code_t gcry_drbg_cavs_test (struct gcry_drbg_test_vector *test, +diff -up libgcrypt-1.5.3/tests/cavs_driver.pl.drbg-cavs libgcrypt-1.5.3/tests/cavs_driver.pl +--- libgcrypt-1.5.3/tests/cavs_driver.pl.drbg-cavs 2017-02-28 14:28:55.674906074 +0100 ++++ libgcrypt-1.5.3/tests/cavs_driver.pl 2017-02-28 14:41:46.086048300 +0100 +@@ -192,15 +192,17 @@ my $rsa_derive; + # Sign a message with RSA + # $1: data to be signed in hex form + # $2: Hash algo +-# $3: Key file in PEM format with the private key ++# $3: PSS flag ++# $4: Key file in PEM format with the private key + # return: digest in hex format + my $rsa_sign; + + # Verify a message with RSA + # $1: data to be verified in hex form + # $2: hash algo +-# $3: file holding the public RSA key in PEM format +-# $4: file holding the signature in binary form ++# $3: PSS flag ++# $4: file holding the public RSA key in PEM format ++# $5: file holding the signature in binary form + # return: 1 == verified / 0 == not verified + my $rsa_verify; + +@@ -329,6 +331,8 @@ my $rsa_keygen; + + my $rsa_keygen_kat; + ++my $drbg_kat; ++ + ################################################################ + ##### OpenSSL interface functions + ################################################################ +@@ -350,9 +354,10 @@ sub openssl_encdec($$$$$) { + return bin2hex($data); + } + +-sub openssl_rsa_sign($$$) { ++sub openssl_rsa_sign($$$$) { + my $data = shift; + my $cipher = shift; ++ my $pss = shift; # unsupported + my $keyfile = shift; + + $data=hex2bin($data); +@@ -365,6 +370,7 @@ sub openssl_rsa_sign($$$) { + sub openssl_rsa_verify($$$$) { + my $data = shift; + my $cipher = shift; ++ my $pss = shift; # unsupported + my $keyfile = shift; + my $sigfile = shift; + +@@ -497,27 +503,38 @@ sub libgcrypt_rsa_keygen_kat($$$$) { + } + + +-sub libgcrypt_rsa_sign($$$) { ++sub libgcrypt_rsa_sign($$$$) { + my $data = shift; + my $hashalgo = shift; ++ my $pss = shift; + my $keyfile = shift; + + die "ARCFOUR not available for RSA" if $opt{'R'}; + ++ if ($pss) { ++ return pipe_through_program($data, ++ "fipsdrv --pss --algo $hashalgo --key $keyfile rsa-sign"); ++ } + return pipe_through_program($data, + "fipsdrv --pkcs1 --algo $hashalgo --key $keyfile rsa-sign"); + } + +-sub libgcrypt_rsa_verify($$$$) { ++sub libgcrypt_rsa_verify($$$$$) { + my $data = shift; + my $hashalgo = shift; ++ my $pss = shift; + my $keyfile = shift; + my $sigfile = shift; + + die "ARCFOUR not available for RSA" if $opt{'R'}; ++ ++ if ($pss) { ++ $data = pipe_through_program($data, ++ "fipsdrv --pss --algo $hashalgo --key $keyfile --signature $sigfile rsa-verify"); ++ } else { + $data = pipe_through_program($data, + "fipsdrv --pkcs1 --algo $hashalgo --key $keyfile --signature $sigfile rsa-verify"); +- ++ } + # Parse through the output information + return ($data =~ /GOOD signature/); + } +@@ -543,6 +560,16 @@ sub libgcrypt_hash($$) { + return pipe_through_program($pt, $program); + } + ++sub libgcrypt_hash_mct($$) { ++ my $pt = shift; ++ my $hashalgo = shift; ++ ++ my $program = "fipsdrv --algo $hashalgo --loop digest"; ++ die "ARCFOUR not available for hashes" if $opt{'R'}; ++ ++ return pipe_through_program($pt, $program); ++} ++ + sub libgcrypt_state_cipher($$$$$) { + my $cipher = shift; + my $enc = (shift) ? "encrypt": "decrypt"; +@@ -693,6 +720,35 @@ sub libgcrypt_dsa_verify($$$$) { + return ($ret =~ /GOOD signature/); + } + ++sub libgcrypt_drbg_kat($$$$$$$$$$$$$$$$$) { ++ my $mode = shift; ++ my $cipher = shift; ++ my $pr = shift; ++ my $ent = shift; ++ my $entlen = shift; ++ my $nonce = shift; ++ my $noncelen = shift; ++ my $entrs = shift; ++ my $addtlrs = shift; ++ my $entpra = shift; ++ my $entprb = shift; ++ my $addtla = shift; ++ my $addtlb = shift; ++ my $addtllen = shift; ++ my $pers = shift; ++ my $perslen = shift; ++ my $expectedlen = shift; ++ ++ my $entprlen = $entlen; ++ ++ # concatenate entropy and nonce ++ $ent .= $nonce; ++ $entlen = $entlen + $noncelen; ++ ++ return lc(pipe_through_program("$mode\n$pr\n$entlen\n$ent\n$perslen\n$pers\n$expectedlen\n$addtllen\n$entrs\n$addtlrs\n$addtla\n$addtlb\n$entprlen\n$entpra\n$entprb\n", "./fipsdrv --algo $cipher drbg")); ++} ++ ++ + ######### End of libgcrypt implementation ################ + + ################################################################ +@@ -1468,13 +1524,17 @@ sub hash_mct($$) { + my $md0=$pt; + my $md1=$pt; + my $md2=$pt; +- for (my $i=0; $i<1000; ++$i) { +- #print STDERR "outer loop $j; inner loop $i\n"; +- my $mi= $md0 . $md1 . $md2; +- $md0=$md1; +- $md1=$md2; +- $md2 = &$hash($mi, $cipher); +- $md2 =~ s/\n//; ++ if ($opt{'I'} && $opt{'I'} eq 'libgcrypt') { ++ $md2 = &libgcrypt_hash_mct($pt, $cipher); ++ } else { ++ for (my $i=0; $i<1000; ++$i) { ++ #print STDERR "outer loop $j; inner loop $i\n"; ++ my $mi= $md0 . $md1 . $md2; ++ $md0=$md1; ++ $md1=$md2; ++ $md2 = &$hash($mi, $cipher); ++ $md2 =~ s/\n//; ++ } + } + $out .= "MD = $md2\n\n"; + $pt=$md2; +@@ -1483,21 +1543,65 @@ sub hash_mct($$) { + return $out; + } + ++sub drbg_kat_driver($$$$$$$$$$$$$$$$$) { ++ my $mode = shift; ++ my $cipher = shift; ++ my $pr = shift; ++ my $ent = shift; ++ my $entlen = shift; ++ my $nonce = shift; ++ my $noncelen = shift; ++ my $entrs = shift; ++ my $addtlrs = shift; ++ my $entpra = shift; ++ my $entprb = shift; ++ my $addtla = shift; ++ my $addtlb = shift; ++ my $addtllen = shift; ++ my $pers = shift; ++ my $perslen = shift; ++ my $expectedlen = shift; ++ ++ my $out = ""; ++ ++ $out .= "ReturnedBits = " . &$drbg_kat($mode, ++ $cipher, ++ $pr, ++ $ent, ++ $entlen, ++ $nonce, ++ $noncelen, ++ $entrs, ++ $addtlrs, ++ $entpra, ++ $entprb, ++ $addtla, ++ $addtlb, ++ $addtllen, ++ $pers, ++ $perslen, ++ $expectedlen) . "\n"; ++ ++ return $out; ++} ++ + # RSA SigGen test + # $1: Message to be signed in hex form + # $2: Hash algorithm +-# $3: file name with RSA key in PEM form ++# $3: Use PSS ++# $4: file name with RSA key in PEM form + # return: string formatted as expected by CAVS +-sub rsa_siggen($$$) { ++sub rsa_siggen($$$$) { + my $data = shift; + my $cipher = shift; ++ my $pss = shift; + my $keyfile = shift; + + my $out = ""; + + $out .= "SHAAlg = $cipher\n"; + $out .= "Msg = $data\n"; +- $out .= "S = " . &$rsa_sign($data, lc($cipher), $keyfile) . "\n"; ++ $out .= "S = " . &$rsa_sign($data, lc($cipher), $pss, $keyfile) . "\n"; + + return $out; + } +@@ -1505,13 +1609,15 @@ sub rsa_siggen($$$) { + # RSA SigVer test + # $1: Message to be verified in hex form + # $2: Hash algoritm +-# $3: Signature of message in hex form +-# $4: n of the RSA key in hex in hex form +-# $5: e of the RSA key in hex in hex form ++# $3: Use PSS ++# $4: Signature of message in hex form ++# $5: n of the RSA key in hex in hex form ++# $6: e of the RSA key in hex in hex form + # return: string formatted as expected by CAVS +-sub rsa_sigver($$$$$) { ++sub rsa_sigver($$$$$$) { + my $data = shift; + my $cipher = shift; ++ my $pss = shift; + my $signature = shift; + my $n = shift; + my $e = shift; +@@ -1534,7 +1640,7 @@ sub rsa_sigver($$$$$) { + print FH hex2bin($signature); + close FH; + +- $out .= "Result = " . (&$rsa_verify($data, lc($cipher), $keyfile, $sigfile) ? "P\n" : "F\n"); ++ $out .= "Result = " . (&$rsa_verify($data, lc($cipher), $pss, $keyfile, $sigfile) ? "P\n" : "F\n"); + + unlink($keyfile); + unlink($sigfile); +@@ -1905,13 +2011,14 @@ sub rsa_keygen_driver($$) { + # $2 p in hex form + # $3 q in hex form + # return: string formatted as expected by CAVS +-sub rsa_keygen_kat_driver($$$) { ++sub rsa_keygen_kat_driver($$$$) { + my $mod = shift; ++ my $e = shift; + my $p = shift; + my $q = shift; + + my $out = ""; +- my $ret = &$rsa_keygen_kat($mod, $p, $q); ++ my $ret = &$rsa_keygen_kat($mod, $e, $p, $q); + my ($Result) = split(/\n/, $ret); + die "Return value does not contain all expected values of Result for rsa_keygen_kat" + if (!defined($Result)); +@@ -1999,8 +2106,24 @@ sub parse($$) { + my $xq1 = ""; + my $xq2 = ""; + my $Xq = ""; ++ my $pr = 0; ++ my $ent = ""; ++ my $entlen = 0; ++ my $nonce = ""; ++ my $noncelen = 0; ++ my $entrs = ""; ++ my $addtlrs = ""; ++ my $entpra = "x"; ++ my $entprb = "x"; ++ my $addtla = "x"; ++ my $addtlb = "x"; ++ my $addtllen = 0; ++ my $pers = ""; ++ my $perslen = 0; ++ my $expectedlen = 0; + + my $mode = ""; ++ my $pss = 0; + + open(IN, "<$infile"); + while() { +@@ -2029,7 +2152,7 @@ sub parse($$) { + + ##### Extract cipher + # XXX there may be more - to be added +- if ($tmpline =~ /^#.*(CBC|ECB|OFB|CFB|SHA-|SigGen|SigVer|RC4VS|ANSI X9\.31|Hash sizes tested|PQGGen|KeyGen RSA|KeyGen - Random Probably Prime|KeyPair|PQGVer)/) { ++ if ($tmpline =~ /^#.*(CBC|ECB|OFB|CFB|SHA-|SigGen|SigVer|RC4VS|ANSI X9\.31|Hash sizes tested|PQGGen|KeyGen RSA|KeyGen - Random Probably Prime|KeyPair|PQGVer|DRBG800-90A)/) { + if ($tmpline =~ /CBC/) { $mode="cbc"; } + elsif ($tmpline =~ /ECB/) { $mode="ecb"; } + elsif ($tmpline =~ /OFB/) { $mode="ofb"; } +@@ -2078,7 +2201,11 @@ sub parse($$) { + + if ($tt == 0) { + ##### Identify the test type +- if ($tmpline =~ /KeyGen - Random Probably Prime Known Answer Test/) { ++ if ($tmpline =~ /DRBG800-90A/) { ++ $tt = 20; ++ die "Interface function drbg_kat for DRBG KAT not defined for tested library" ++ if (!defined($drbg_kat)); ++ } elsif ($tmpline =~ /KeyGen - Random Probably Prime Known Answer Test/) { + $tt = 19; + die "Interface function rsa_keygen_kat for RSA key generation KAT not defined for tested library" + if (!defined($rsa_keygen_kat)); +@@ -2123,10 +2250,16 @@ sub parse($$) { + die "Interface function state_rng for RNG KAT not defined for tested library" + if (!defined($state_rng)); + } elsif ($tmpline =~ /SigVer/ ) { ++ if ($tmpline =~ /RSASSA-PSS/) { ++ $pss = 1; ++ } + $tt = 6; + die "Interface function rsa_verify or gen_rsakey for RSA verification not defined for tested library" + if (!defined($rsa_verify) || !defined($gen_rsakey)); + } elsif ($tmpline =~ /SigGen/ ) { ++ if ($tmpline =~ /RSASSA-PSS/) { ++ $pss = 1; ++ } + $tt = 5; + die "Interface function rsa_sign or gen_rsakey for RSA sign not defined for tested library" + if (!defined($rsa_sign) || !defined($gen_rsakey)); +@@ -2252,7 +2385,7 @@ sub parse($$) { + $out .= "G = " . $pqg{'G'} . "\n\n"; + } + } +- elsif ($line =~ /^\[mod\s*=\s*(.*)\]$/) { # found in RSA requests ++ elsif ($line =~ /^\[mod\s*=\s*(.*)\]/) { # found in RSA requests + $modulus = $1; + $out .= $line . "\n\n"; # print it + # generate the private key with given bit length now +@@ -2277,10 +2410,21 @@ sub parse($$) { + $n=$1; + } + elsif ($line =~ /^e\s*=\s*(.*)/) { # found in RSA requests +- $e=$1; + if ($tt == 19) { ++ if ($modulus ne "" && ++ $e ne "" && ++ $prandom ne "") { ++ $out .= rsa_keygen_kat_driver($modulus, ++ $e, ++ $prandom, ++ "00"); ++ $prandom = ""; ++ $qrandom = ""; ++ $e = ""; ++ } + $out .= $line . "\n"; # print it + } ++ $e=$1; + } + elsif ($line =~ /^S\s*=\s*(.*)/) { # found in RSA requests + die "S seen twice - input file crap" if ($signature ne ""); +@@ -2306,6 +2450,89 @@ sub parse($$) { + if ($tlen ne ""); + $tlen=$1; + } ++ elsif ($tt == 20) { ++ if ($line =~ /Hash_DRBG/) { # HASH DRBG request ++ $mode = "hash"; ++ } ++ elsif ($line =~ /HMAC_DRBG/) { # HMAC DRBG request ++ $mode = "hmac"; ++ } ++ elsif ($line =~ /CTR_DRBG/) { # CTR DRBG request ++ $mode = "ctr"; ++ } ++ elsif ($line =~ /^\[SHA-1\]/) { ++ $cipher= "sha-1"; ++ } ++ elsif ($line =~ /^\[SHA-256\]/) { ++ $cipher= "sha-256"; ++ } ++ elsif ($line =~ /^\[SHA-384\]/) { ++ $cipher= "sha-384"; ++ } ++ elsif ($line =~ /^\[SHA-512\]/) { ++ $cipher= "sha-512"; ++ } ++ elsif ($line =~ /^\[AES-128 use df\]/) { ++ $cipher= "aes-128"; ++ } ++ elsif ($line =~ /^\[AES-192 use df\]/) { ++ $cipher= "aes-192"; ++ } ++ elsif ($line =~ /^\[AES-256 use df\]/) { ++ $cipher= "aes-256"; ++ } ++ elsif ($line =~ /^\[PredictionResistance\s*=\s*True\]/) { ++ $pr = 1; ++ } ++ elsif ($line =~ /^\[PredictionResistance\s*=\s*False\]/) { ++ $pr = 0; ++ } ++ elsif ($line =~ /^\[EntropyInputLen\s*=\s*(.*)\]/) { ++ $entlen = $1; ++ } ++ elsif ($line =~ /^\[NonceLen\s*=\s*(.*)\]/) { ++ $noncelen = $1; ++ } ++ elsif ($line =~ /^\[PersonalizationStringLen\s*=\s*(.*)\]/) { ++ $perslen = $1; ++ } ++ elsif ($line =~ /^\[AdditionalInputLen\s*=\s*(.*)\]/) { ++ $addtllen = $1; ++ } ++ elsif ($line =~ /^\[ReturnedBitsLen\s*=\s*(.*)\]/) { ++ $expectedlen = $1; ++ } ++ elsif ($line =~ /^EntropyInput\s*=\s*(.*)/) { ++ $ent = $1; ++ } ++ elsif ($line =~ /^EntropyInputReseed\s*=\s*(.*)/) { ++ $entrs = $1; ++ } ++ elsif ($line =~ /^Nonce\s*=\s*(.*)/) { ++ $nonce = $1; ++ } ++ elsif ($line =~ /^PersonalizationString\s*=\s*(.*)/) { ++ $pers = $1; ++ } ++ elsif ($line =~ /^AdditionalInput\s*=\s*(.*)/) { ++ if ($addtla eq "x") { ++ $addtla = $1; ++ } else { ++ $addtlb = $1; ++ } ++ } ++ elsif ($line =~ /^EntropyInputPR\s*=\s*(.*)/) { ++ if ($entpra eq "x") { ++ $entpra = $1; ++ } else { ++ $entprb = $1; ++ } ++ } ++ elsif ($line =~ /^AdditionalInputReseed\s*=\s*(.*)/) { ++ $addtlrs = $1; ++ } ++ $out .= $line . "\n"; # print it ++ } + elsif ($line =~ /^N\s*=\s*(.*)/) { #DSA KeyPair + die "N seen twice - check input file" + if ($capital_n); +@@ -2396,10 +2623,6 @@ sub parse($$) { + $qrandom = $1; + $out .= $line . "\n"; # print it + } +- elsif ($tt == 19 && $line =~ /^ / && $qrandom eq "") { #RSA key gen KAT +- $qrandom = "00"; +- $out .= $line . "\n"; # print it +- } + else { + $out .= $line . "\n"; + } +@@ -2442,13 +2665,13 @@ sub parse($$) { + } + elsif ($tt == 5) { + if ($pt ne "" && $cipher ne "" && $rsa_keyfile ne "") { +- $out .= rsa_siggen($pt, $cipher, $rsa_keyfile); ++ $out .= rsa_siggen($pt, $cipher, $pss, $rsa_keyfile); + $pt = ""; + } + } + elsif ($tt == 6) { + if ($pt ne "" && $cipher ne "" && $signature ne "" && $n ne "" && $e ne "") { +- $out .= rsa_sigver($pt, $cipher, $signature, $n, $e); ++ $out .= rsa_sigver($pt, $cipher, $pss, $signature, $n, $e); + $pt = ""; + $signature = ""; + } +@@ -2635,6 +2858,37 @@ sub parse($$) { + $e = ""; + } + } ++ elsif ($tt == 20) { ++ if (($pr == 1 && $entpra ne "x" && $entprb ne "x") || ++ ($pr == 0 && $addtla ne "x" && $addtlb ne "x")) { ++ $out .= drbg_kat_driver($mode, ++ $cipher, ++ $pr, ++ $ent, ++ $entlen, ++ $nonce, ++ $noncelen, ++ $entrs, ++ $addtlrs, ++ $entpra, ++ $entprb, ++ $addtla, ++ $addtlb, ++ $addtllen, ++ $pers, ++ $perslen, ++ $expectedlen); ++ $entpra = "x"; ++ $entprb = "x"; ++ $addtla = "x"; ++ $addtlb = "x"; ++ $ent = ""; ++ $nonce = ""; ++ $pers = ""; ++ $entrs = ""; ++ $addtlrs = ""; ++ } ++ } + elsif ($tt > 0) { + die "Test case $tt not defined"; + } +@@ -2701,6 +2955,7 @@ sub main() { + $dsa_genpubkey = \&libgcrypt_dsa_genpubkey; + $rsa_keygen = \&libgcrypt_rsa_keygen; + $rsa_keygen_kat = \&libgcrypt_rsa_keygen_kat; ++ $drbg_kat = \&libgcrypt_drbg_kat; + } else { + die "Invalid interface option given"; + } +diff -up libgcrypt-1.5.3/tests/fipsdrv.c.drbg-cavs libgcrypt-1.5.3/tests/fipsdrv.c +--- libgcrypt-1.5.3/tests/fipsdrv.c.drbg-cavs 2017-02-28 14:28:55.674906074 +0100 ++++ libgcrypt-1.5.3/tests/fipsdrv.c 2017-02-28 14:43:28.320456712 +0100 +@@ -22,6 +22,7 @@ + #endif + #include + #include ++#include + #include + #include + #include +@@ -893,8 +894,10 @@ print_mpi_line (gcry_mpi_t a, int no_lz) + die ("gcry_mpi_aprint failed: %s\n", gpg_strerror (err)); + + p = buf; +- while (*p) +- *p++ = tolower(*p); ++ while (*p) { ++ *p = tolower(*p); ++ ++p; ++ } + p = buf; + if (no_lz && p[0] == '0' && p[1] == '0' && p[2]) + p += 2; +@@ -1256,6 +1259,46 @@ run_digest (int digest_algo, const void + gcry_md_close (hd); + } + ++/* Run inner loop of digest mct operation. */ ++static void ++run_digest_mct_loop (int digest_algo, const void *data, size_t datalen, int iter) ++{ ++ gpg_error_t err; ++ gcry_md_hd_t hd; ++ const unsigned char *digest; ++ unsigned int digestlen; ++ int i; ++ unsigned char *buf; ++ ++ err = gcry_md_open (&hd, digest_algo, 0); ++ if (err) ++ die ("gcry_md_open failed for algo %d: %s\n", ++ digest_algo, gpg_strerror (err)); ++ ++ digestlen = gcry_md_get_algo_dlen (digest_algo); ++ if (digestlen != datalen) ++ die ("Unexpected seed size %u for Hash mct algo %d\n", datalen, digest_algo); ++ ++ buf = malloc (3*datalen); ++ if (!buf) ++ die ("Buffer allocation failed\n"); ++ ++ memcpy (buf, data, datalen); ++ memcpy (buf + datalen, data, datalen); ++ memcpy (buf + 2*datalen, data, datalen); ++ ++ for (i = 0; i < iter; ++i) ++ { ++ gcry_md_reset (hd); ++ gcry_md_write (hd, buf, 3*datalen); ++ digest = gcry_md_read (hd, digest_algo); ++ memmove (buf, buf + datalen, 2*datalen); ++ memcpy (buf + 2*datalen, digest, datalen); ++ } ++ print_buffer (digest, digestlen); ++ gcry_md_close (hd); ++} ++ + + /* Run a HMAC operation. */ + static void +@@ -1403,7 +1446,7 @@ run_rsa_keygen (const void *data, size_t + gcry_sexp_release (l1); + if (!mpi) + die ("parameter %c missing in private-key\n", parmlist[idx]); +- print_mpi_line (mpi, 1); ++ print_mpi_line (mpi, parmlist[idx] != 'd'); + gcry_mpi_release (mpi); + } + +@@ -1592,7 +1635,7 @@ run_rsa_gen (int keysize, int pubexp) + encoded KEYFILE and the hash algorithm HASHALGO. */ + static void + run_rsa_sign (const void *data, size_t datalen, +- int hashalgo, int pkcs1, const char *keyfile) ++ int hashalgo, int pkcs1, int pss, const char *keyfile) + + { + gpg_error_t err; +@@ -1616,6 +1659,20 @@ run_rsa_sign (const void *data, size_t d + gcry_md_algo_name (hashalgo), + (int)hashsize, hash); + } ++ else if (pss) ++ { ++ unsigned char hash[64]; ++ unsigned int hashsize; ++ ++ hashsize = gcry_md_get_algo_dlen (hashalgo); ++ if (!hashsize || hashsize > sizeof hash) ++ die ("digest too long for buffer or unknown hash algorithm\n"); ++ gcry_md_hash_buffer (hashalgo, hash, data, datalen); ++ err = gcry_sexp_build (&s_data, NULL, ++ "(data (flags pss)(hash %s %b))", ++ gcry_md_algo_name (hashalgo), ++ (int)hashsize, hash); ++ } + else + { + gcry_mpi_t tmp; +@@ -1683,7 +1740,7 @@ run_rsa_sign (const void *data, size_t d + binary signature in SIGFILE. */ + static void + run_rsa_verify (const void *data, size_t datalen, int hashalgo, int pkcs1, +- const char *keyfile, const char *sigfile) ++ int pss, const char *keyfile, const char *sigfile) + + { + gpg_error_t err; +@@ -1703,6 +1760,20 @@ run_rsa_verify (const void *data, size_t + gcry_md_algo_name (hashalgo), + (int)hashsize, hash); + } ++ else if (pss) ++ { ++ unsigned char hash[64]; ++ unsigned int hashsize; ++ ++ hashsize = gcry_md_get_algo_dlen (hashalgo); ++ if (!hashsize || hashsize > sizeof hash) ++ die ("digest too long for buffer or unknown hash algorithm\n"); ++ gcry_md_hash_buffer (hashalgo, hash, data, datalen); ++ err = gcry_sexp_build (&s_data, NULL, ++ "(data (flags pss)(hash %s %b))", ++ gcry_md_algo_name (hashalgo), ++ (int)hashsize, hash); ++ } + else + { + gcry_mpi_t tmp; +@@ -2220,7 +2291,150 @@ run_dsa_verify (const void *data, size_t + gcry_sexp_release (s_data); + } + ++struct gcry_drbg_test_vector ++{ ++ uint32_t flags; ++ unsigned char *entropy; ++ size_t entropylen; ++ unsigned char *entpra; ++ unsigned char *entprb; ++ size_t entprlen; ++ unsigned char *addtla; ++ unsigned char *addtlb; ++ size_t addtllen; ++ unsigned char *pers; ++ size_t perslen; ++ unsigned char *expected; ++ size_t expectedlen; ++ unsigned char *entropyrsd; ++ size_t entropyrsdlen; ++ unsigned char *addtlrsd; ++ size_t addtlrsdlen; ++ }; ++ ++static uint32_t ++decode_drbg_flags(const char *algo, const char *mode, const char *pr) ++{ ++ uint32_t flags = 0; ++ ++ if (*pr == '1') ++ flags = GCRY_DRBG_PREDICTION_RESIST; ++ ++ if (!strcmp(algo, "sha-1")) ++ flags |= GCRY_DRBG_HASHSHA1; ++ else if (!strcmp(algo, "sha-256")) ++ flags |= GCRY_DRBG_HASHSHA256; ++ else if (!strcmp(algo, "sha-384")) ++ flags |= GCRY_DRBG_HASHSHA384; ++ else if (!strcmp(algo, "sha-512")) ++ flags |= GCRY_DRBG_HASHSHA512; ++ else if (!strcmp(algo, "aes-128")) ++ flags |= GCRY_DRBG_SYM128; ++ else if (!strcmp(algo, "aes-192")) ++ flags |= GCRY_DRBG_SYM192; ++ else if (!strcmp(algo, "aes-256")) ++ flags |= GCRY_DRBG_SYM256; ++ ++ if (!strcmp(mode, "hmac")) ++ flags |= GCRY_DRBG_HMAC; ++ else if (!strcmp(mode, "ctr")) ++ flags |= GCRY_DRBG_CTRAES; ++ ++ return flags; ++} ++ ++static void ++run_drbg_test (const char *algo, void *data, size_t datalen) ++{ ++ char *ptr = data; ++ char *mode; ++ char *pr; ++ char *entlen; ++ char *ent; ++ char *perslen; ++ char *pers; ++ char *expectedlen; ++ char *addtllen; ++ char *entrsd; ++ char *addtlrsd; ++ char *addtla; ++ char *addtlb; ++ char *entprlen; ++ char *entpra; ++ char *entprb; ++ unsigned char *buf; ++ size_t len; ++ struct gcry_drbg_test_vector vect; ++ ++ mode = strsep(&ptr, "\n"); ++ pr = strsep(&ptr, "\n"); ++ entlen = strsep(&ptr, "\n"); ++ ent = strsep(&ptr, "\n"); ++ perslen = strsep(&ptr, "\n"); ++ pers = strsep(&ptr, "\n"); ++ expectedlen = strsep(&ptr, "\n"); ++ addtllen = strsep(&ptr, "\n"); ++ entrsd = strsep(&ptr, "\n"); ++ addtlrsd = strsep(&ptr, "\n"); ++ addtla = strsep(&ptr, "\n"); ++ addtlb = strsep(&ptr, "\n"); ++ entprlen = strsep(&ptr, "\n"); ++ entpra = strsep(&ptr, "\n"); ++ entprb = strsep(&ptr, "\n"); ++ ++ if (entprb == NULL) { ++ fprintf(stderr, "ERROR - Missing input data\n"); ++ return; ++ } ++ ++ vect.flags = decode_drbg_flags(algo, mode, pr); ++ ++ vect.entropy = hex2buffer(ent, &len); ++ vect.entropylen = atoi(entlen) / 8; ++ if (len != vect.entropylen) { ++ fprintf(stderr, "ERROR - inconsistent input data\n"); ++ return; ++ } ++ vect.pers = hex2buffer(pers, &len); ++ vect.perslen = atoi(perslen) / 8; ++ if (len != vect.perslen) { ++ fprintf(stderr, "ERROR - inconsistent input data\n"); ++ return; ++ } ++ vect.expectedlen = atoi(expectedlen) / 8; ++ vect.expected = NULL; ++ vect.addtlrsdlen = vect.addtllen = atoi(addtllen) / 8; ++ vect.addtla = hex2buffer(addtla, &len); ++ vect.addtlb = hex2buffer(addtlb, &len); ++ vect.entropyrsdlen = vect.entprlen = atoi(entprlen) / 8; ++ vect.entpra = hex2buffer(entpra, &len); ++ vect.entprb = hex2buffer(entprb, &len); ++ if (*entrsd != '\0') { ++ vect.entropyrsd = hex2buffer(entrsd, &len); ++ if (len != vect.entropyrsdlen) { ++ fprintf(stderr, "ERROR - inconsistent input data\n"); ++ return; ++ } ++ if (*addtlrsd != '\0') { ++ vect.addtlrsd = hex2buffer(addtlrsd, &len); ++ if (len != vect.addtlrsdlen) { ++ fprintf(stderr, "ERROR - inconsistent input data\n"); ++ return; ++ } ++ } else { ++ vect.addtlrsd = NULL; ++ } ++ } else { ++ vect.entropyrsd = NULL; ++ vect.addtlrsd = NULL; ++ } ++ ++ buf = gcry_xmalloc(vect.expectedlen); + ++ gcry_control(75, &vect, buf); ++ ++ print_data_line(buf, vect.expectedlen); ++} + + + static void +@@ -2251,6 +2465,7 @@ usage (int show_help) + " --signature NAME Take signature from file NAME\n" + " --chunk N Read in chunks of N bytes (implies --binary)\n" + " --pkcs1 Use PKCS#1 encoding\n" ++ " --pss Use PKCS#1 PSS encoding\n" + " --mct-server Run a monte carlo test server\n" + " --loop Enable random loop mode\n" + " --progress Print pogress indicators\n" +@@ -2268,6 +2483,7 @@ main (int argc, char **argv) + int no_fips = 0; + int progress = 0; + int use_pkcs1 = 0; ++ int use_pss = 0; + const char *mode_string; + const char *key_string = NULL; + const char *iv_string = NULL; +@@ -2398,6 +2614,11 @@ main (int argc, char **argv) + use_pkcs1 = 1; + argc--; argv++; + } ++ else if (!strcmp (*argv, "--pss")) ++ { ++ use_pss = 1; ++ argc--; argv++; ++ } + else if (!strcmp (*argv, "--mct-server")) + { + mct_server = 1; +@@ -2414,7 +2635,10 @@ main (int argc, char **argv) + usage (0); + mode_string = *argv; + +- if (!strcmp (mode_string, "rsa-derive")) ++ if (!strcmp (mode_string, "rsa-derive") || ++ !strcmp (mode_string, "rsa-keygen") || ++ !strcmp (mode_string, "rsa-keygen-kat") || ++ !strcmp(mode_string, "drbg")) + binary_input = 1; + + if (argc == 2 && strcmp (argv[1], "-")) +@@ -2557,7 +2781,14 @@ main (int argc, char **argv) + if (!data) + die ("no data available (do not use --chunk)\n"); + +- run_digest (algo, data, datalen); ++ if (loop_mode) ++ { ++ run_digest_mct_loop (algo, data, datalen, 1000); ++ } ++ else ++ { ++ run_digest (algo, data, datalen); ++ } + } + else if (!strcmp (mode_string, "random")) + { +@@ -2602,6 +2833,12 @@ main (int argc, char **argv) + + deinit_external_rng_test (context); + } ++ else if (!strcmp (mode_string, "drbg")) ++ { ++ if (!algo_string) ++ die ("--algo required in this mode\n"); ++ run_drbg_test (algo_string, data, datalen); ++ } + else if (!strcmp (mode_string, "hmac-sha")) + { + int algo; +@@ -2679,7 +2916,7 @@ main (int argc, char **argv) + if (!data) + die ("no data available (do not use --chunk)\n"); + +- run_rsa_sign (data, datalen, algo, use_pkcs1, key_string); ++ run_rsa_sign (data, datalen, algo, use_pkcs1, use_pss, key_string); + + } + else if (!strcmp (mode_string, "rsa-verify")) +@@ -2702,7 +2939,7 @@ main (int argc, char **argv) + if (access (signature_string, R_OK)) + die ("option --signature needs to specify an existing file\n"); + +- run_rsa_verify (data, datalen, algo, use_pkcs1, key_string, ++ run_rsa_verify (data, datalen, algo, use_pkcs1, use_pss, key_string, + signature_string); + + } +@@ -2783,12 +3020,6 @@ main (int argc, char **argv) + + gcry_free (data); + +- /* Because Libgcrypt does not enforce FIPS mode in all cases we let +- the process die if Libgcrypt is not anymore in FIPS mode after +- the actual operation. */ +- if (!no_fips && !gcry_fips_mode_active ()) +- die ("FIPS mode is not anymore active\n"); +- + if (verbose) + fputs (PGM ": ready\n", stderr); + diff --git a/SOURCES/libgcrypt-1.5.3-drbg-init.patch b/SOURCES/libgcrypt-1.5.3-drbg-init.patch new file mode 100644 index 0000000..c27fdef --- /dev/null +++ b/SOURCES/libgcrypt-1.5.3-drbg-init.patch @@ -0,0 +1,23 @@ +diff -up libgcrypt-1.5.3/random/drbg.c.drbg-init libgcrypt-1.5.3/random/drbg.c +--- libgcrypt-1.5.3/random/drbg.c.drbg-init 2017-02-28 14:28:55.000000000 +0100 ++++ libgcrypt-1.5.3/random/drbg.c 2017-02-28 15:15:54.401291408 +0100 +@@ -1820,12 +1820,16 @@ _gcry_drbg_randomize (void *buffer, size + enum gcry_random_level level) + { + (void) level; +- gcry_drbg_lock (); + if (NULL == gcry_drbg) + { +- fips_signal_error ("DRBG is not initialized"); +- goto bailout; ++ _gcry_drbg_init(1); ++ if (NULL == gcry_drbg) ++ { ++ log_fatal ("DRBG is not initialized\n"); ++ goto bailout; ++ } + } ++ gcry_drbg_lock (); + + /* As reseeding changes the entire state of the DRBG, including any + * key, either a re-init or a reseed is sufficient for a fork */ diff --git a/SOURCES/libgcrypt-1.5.3-drbg.patch b/SOURCES/libgcrypt-1.5.3-drbg.patch new file mode 100644 index 0000000..e75f7bf --- /dev/null +++ b/SOURCES/libgcrypt-1.5.3-drbg.patch @@ -0,0 +1,2699 @@ +diff -up libgcrypt-1.5.3/random/drbg.c.drbg libgcrypt-1.5.3/random/drbg.c +--- libgcrypt-1.5.3/random/drbg.c.drbg 2014-09-26 17:00:16.050215868 +0200 ++++ libgcrypt-1.5.3/random/drbg.c 2014-09-26 17:15:41.576110018 +0200 +@@ -0,0 +1,2352 @@ ++/* ++ * DRBG: Deterministic Random Bits Generator ++ * Based on NIST Recommended DRBG from NIST SP800-90A with the following ++ * properties: ++ * * CTR DRBG with DF with AES-128, AES-192, AES-256 cores ++ * * Hash DRBG with DF with SHA-1, SHA-256, SHA-384, SHA-512 cores ++ * * HMAC DRBG with DF with SHA-1, SHA-256, SHA-384, SHA-512 cores ++ * * with and without prediction resistance ++ * ++ * Copyright Stephan Mueller , 2014 ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, and the entire permission notice in its entirety, ++ * including the disclaimer of warranties. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. The name of the author may not be used to endorse or promote ++ * products derived from this software without specific prior ++ * written permission. ++ * ++ * ALTERNATIVELY, this product may be distributed under the terms of ++ * LGPLv2+, in which case the provisions of the LGPL are ++ * required INSTEAD OF the above restrictions. (This clause is ++ * necessary due to a potential bad interaction between the LGPL and ++ * the restrictions contained in a BSD-style copyright.) ++ * ++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED ++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF ++ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE ++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT ++ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR ++ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF ++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE ++ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH ++ * DAMAGE. ++ * ++ * ++ * gcry_control GCRYCTL_DRBG_REINIT ++ * ================================ ++ * This control request re-initializes the DRBG completely, i.e. the entire ++ * state of the DRBG is zeroized (with two exceptions listed in ++ * GCRYCTL_DRBG_SET_ENTROPY). ++ * ++ * The control request takes the following values which influences how the DRBG ++ * is re-initialized: ++ * * u32 flags: This variable specifies the DRBG type to be used for the ++ * next initialization. If set to 0, the previous DRBG type is ++ * used for the initialization. The DRBG type is an OR of the ++ * mandatory flags of the requested DRBG strength and DRBG ++ * cipher type. Optionally, the prediction resistance flag ++ * can be ORed into the flags variable. For example: ++ * - CTR-DRBG with AES-128 without prediction resistance: ++ * DRBG_CTRAES128 ++ * - HMAC-DRBG with SHA-512 with prediction resistance: ++ * DRBG_HMACSHA512 | DRBG_PREDICTION_RESIST ++ * * struct gcry_drbg_string *pers: personalization string to be used for ++ * initialization. ++ * The variable of flags is independent from the pers/perslen variables. If ++ * flags is set to 0 and perslen is set to 0, the current DRBG type is ++ * completely reset without using a personalization string. ++ * ++ * DRBG Usage ++ * ========== ++ * The SP 800-90A DRBG allows the user to specify a personalization string ++ * for initialization as well as an additional information string for each ++ * random number request. The following code fragments show how a caller ++ * uses the kernel crypto API to use the full functionality of the DRBG. ++ * ++ * Usage without any additional data ++ * --------------------------------- ++ * gcry_randomize(outbuf, OUTLEN, GCRY_STRONG_RANDOM); ++ * ++ * ++ * Usage with personalization string during initialization ++ * ------------------------------------------------------- ++ * struct gcry_drbg_string pers; ++ * char personalization[11] = "some-string"; ++ * ++ * gcry_drbg_string_fill(&pers, personalization, strlen(personalization)); ++ * // The reset completely re-initializes the DRBG with the provided ++ * // personalization string without changing the DRBG type ++ * ret = gcry_control(GCRYCTL_DRBG_REINIT, 0, &pers); ++ * gcry_randomize(outbuf, OUTLEN, GCRY_STRONG_RANDOM); ++ * ++ * ++ * Usage with additional information string during random number request ++ * --------------------------------------------------------------------- ++ * struct gcry_drbg_string addtl; ++ * char addtl_string[11] = "some-string"; ++ * ++ * gcry_drbg_string_fill(&addtl, addtl_string, strlen(addtl_string)); ++ * // The following call is a wrapper to gcry_randomize() and returns ++ * // the same error codes. ++ * gcry_randomize_drbg(outbuf, OUTLEN, GCRY_STRONG_RANDOM, &addtl); ++ * ++ * ++ * Usage with personalization and additional information strings ++ * ------------------------------------------------------------- ++ * Just mix both scenarios above. ++ * ++ * ++ * Switch the DRBG type to some other type ++ * --------------------------------------- ++ * // Switch to CTR DRBG AES-128 without prediction resistance ++ * ret = gcry_control(GCRYCTL_DRBG_REINIT, DRBG_NOPR_CTRAES128, NULL); ++ * gcry_randomize(outbuf, OUTLEN, GCRY_STRONG_RANDOM); ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include "g10lib.h" ++#include "random.h" ++#include "rand-internal.h" ++#include "../cipher/bithelp.h" ++#include "ath.h" ++ ++/****************************************************************** ++ * Common data structures ++ ******************************************************************/ ++ ++struct gcry_drbg_state; ++ ++struct gcry_drbg_core ++{ ++ u32 flags; /* flags for the cipher */ ++ ushort statelen; /* maximum state length */ ++ ushort blocklen_bytes; /* block size of output in bytes */ ++ int backend_cipher; /* libgcrypt backend cipher */ ++}; ++ ++struct gcry_drbg_state_ops ++{ ++ gpg_err_code_t (*update) (struct gcry_drbg_state * drbg, ++ struct gcry_drbg_string * seed, int reseed); ++ gpg_err_code_t (*generate) (struct gcry_drbg_state * drbg, ++ unsigned char *buf, unsigned int buflen, ++ struct gcry_drbg_string * addtl); ++}; ++ ++/* DRBG test data */ ++struct gcry_drbg_test_data ++{ ++ struct gcry_drbg_string *testentropy; /* TEST PARAMETER: test entropy */ ++ int fail_seed_source:1; /* if set, the seed function will return an error */ ++}; ++ ++ ++struct gcry_drbg_state ++{ ++ unsigned char *V; /* internal state 10.1.1.1 1a) */ ++ unsigned char *C; /* hash: static value 10.1.1.1 1b) ++ * hmac / ctr: key */ ++ size_t reseed_ctr; /* Number of RNG requests since last reseed -- ++ * 10.1.1.1 1c) */ ++ unsigned char *scratchpad; /* some memory the DRBG can use for its ++ * operation -- allocated during init */ ++ int seeded:1; /* DRBG fully seeded? */ ++ int pr:1; /* Prediction resistance enabled? */ ++ int fips_primed:1; /* Continuous test primed? */ ++ unsigned char *prev; /* previous output value of gcry_drbg_blocklen ++ * for FIPS 140-2 continuous test */ ++ /* Taken from libgcrypt ANSI X9.31 DRNG: We need to keep track of the ++ * process which did the initialization so that we can detect a fork. ++ * The volatile modifier is required so that the compiler does not ++ * optimize it away in case the getpid function is badly attributed. */ ++ pid_t seed_init_pid; ++ const struct gcry_drbg_state_ops *d_ops; ++ const struct gcry_drbg_core *core; ++ struct gcry_drbg_test_data *test_data; ++}; ++ ++enum gcry_drbg_prefixes ++{ ++ DRBG_PREFIX0 = 0x00, ++ DRBG_PREFIX1, ++ DRBG_PREFIX2, ++ DRBG_PREFIX3 ++}; ++ ++#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) ++ ++/*************************************************************** ++ * Backend cipher definitions available to DRBG ++ ***************************************************************/ ++ ++static const struct gcry_drbg_core gcry_drbg_cores[] = { ++ /* Hash DRBGs */ ++ {GCRY_DRBG_HASHSHA1, 55, 20, GCRY_MD_SHA1}, ++ {GCRY_DRBG_HASHSHA256, 55, 32, GCRY_MD_SHA256}, ++ {GCRY_DRBG_HASHSHA384, 111, 48, GCRY_MD_SHA384}, ++ {GCRY_DRBG_HASHSHA512, 111, 64, GCRY_MD_SHA512}, ++ /* HMAC DRBGs */ ++ {GCRY_DRBG_HASHSHA1 | GCRY_DRBG_HMAC, 20, 20, GCRY_MD_SHA1}, ++ {GCRY_DRBG_HASHSHA256 | GCRY_DRBG_HMAC, 32, 32, GCRY_MD_SHA256}, ++ {GCRY_DRBG_HASHSHA384 | GCRY_DRBG_HMAC, 48, 48, GCRY_MD_SHA384}, ++ {GCRY_DRBG_HASHSHA512 | GCRY_DRBG_HMAC, 64, 64, GCRY_MD_SHA512}, ++ /* block ciphers */ ++ {GCRY_DRBG_CTRAES | GCRY_DRBG_SYM128, 32, 16, GCRY_CIPHER_AES128}, ++ {GCRY_DRBG_CTRAES | GCRY_DRBG_SYM192, 40, 16, GCRY_CIPHER_AES192}, ++ {GCRY_DRBG_CTRAES | GCRY_DRBG_SYM256, 48, 16, GCRY_CIPHER_AES256}, ++}; ++ ++static gpg_err_code_t gcry_drbg_sym (struct gcry_drbg_state *drbg, ++ const unsigned char *key, ++ unsigned char *outval, ++ const struct gcry_drbg_string *buf); ++static gpg_err_code_t gcry_drbg_hmac (struct gcry_drbg_state *drbg, ++ const unsigned char *key, ++ unsigned char *outval, ++ const struct gcry_drbg_string *buf); ++ ++/****************************************************************** ++ ****************************************************************** ++ ****************************************************************** ++ * Generic DRBG code ++ ****************************************************************** ++ ****************************************************************** ++ ******************************************************************/ ++ ++/****************************************************************** ++ * Generic helper functions ++ ******************************************************************/ ++ ++/* Byte swap for 32-bit and 64-bit integers. */ ++static inline u32 ++_gcry_bswap32(u32 x) ++{ ++ return ((rol(x, 8) & 0x00ff00ffL) | (ror(x, 8) & 0xff00ff00L)); ++} ++ ++#ifdef HAVE_U64_TYPEDEF ++static inline u64 ++_gcry_bswap64(u64 x) ++{ ++ return ((u64)_gcry_bswap32(x) << 32) | (_gcry_bswap32(x >> 32)); ++} ++#endif ++ ++/* Endian dependent byte swap operations. */ ++#ifdef WORDS_BIGENDIAN ++# define le_bswap32(x) _gcry_bswap32(x) ++# define be_bswap32(x) ((u32)(x)) ++# ifdef HAVE_U64_TYPEDEF ++# define le_bswap64(x) _gcry_bswap64(x) ++# define be_bswap64(x) ((u64)(x)) ++# endif ++#else ++# define le_bswap32(x) ((u32)(x)) ++# define be_bswap32(x) _gcry_bswap32(x) ++# ifdef HAVE_U64_TYPEDEF ++# define le_bswap64(x) ((u64)(x)) ++# define be_bswap64(x) _gcry_bswap64(x) ++# endif ++#endif ++ ++#define xcalloc_secure(a,b) gcry_xcalloc_secure((a),(b)) ++#define xfree(a) _gcry_free(a) ++ ++#if 0 ++#define dbg(x) do { log_debug x; } while(0) ++#else ++#define dbg(x) ++#endif ++ ++static inline ushort ++gcry_drbg_statelen (struct gcry_drbg_state *drbg) ++{ ++ if (drbg && drbg->core) ++ return drbg->core->statelen; ++ return 0; ++} ++ ++static inline ushort ++gcry_drbg_blocklen (struct gcry_drbg_state *drbg) ++{ ++ if (drbg && drbg->core) ++ return drbg->core->blocklen_bytes; ++ return 0; ++} ++ ++static inline ushort ++gcry_drbg_keylen (struct gcry_drbg_state *drbg) ++{ ++ if (drbg && drbg->core) ++ return (drbg->core->statelen - drbg->core->blocklen_bytes); ++ return 0; ++} ++ ++static inline size_t ++gcry_drbg_max_request_bytes (void) ++{ ++ /* SP800-90A requires the limit 2**19 bits, but we return bytes */ ++ return (1 << 16); ++} ++ ++static inline size_t ++gcry_drbg_max_addtl (void) ++{ ++ /* SP800-90A requires 2**35 bytes additional info str / pers str */ ++#ifdef __LP64__ ++ return (1UL << 35); ++#else ++ /* ++ * SP800-90A allows smaller maximum numbers to be returned -- we ++ * return SIZE_MAX - 1 to allow the verification of the enforcement ++ * of this value in gcry_drbg_healthcheck_sanity. ++ */ ++ return (SIZE_MAX - 1); ++#endif ++} ++ ++static inline size_t ++gcry_drbg_max_requests (void) ++{ ++ /* SP800-90A requires 2**48 maximum requests before reseeding */ ++#ifdef __LP64__ ++ return (1UL << 48); ++#else ++ return SIZE_MAX; ++#endif ++} ++ ++/* ++ * Return strength of DRBG according to SP800-90A section 8.4 ++ * ++ * flags: DRBG flags reference ++ * ++ * Return: normalized strength value or 32 as a default to counter ++ * programming errors ++ */ ++static inline unsigned short ++gcry_drbg_sec_strength (u32 flags) ++{ ++ if ((flags & GCRY_DRBG_HASHSHA1) || (flags & GCRY_DRBG_SYM128)) ++ return 16; ++ else if (flags & GCRY_DRBG_SYM192) ++ return 24; ++ else if ((flags & GCRY_DRBG_SYM256) || (flags & GCRY_DRBG_HASHSHA256) || ++ (flags & GCRY_DRBG_HASHSHA384) || (flags & GCRY_DRBG_HASHSHA512)) ++ return 32; ++ else ++ return 32; ++} ++ ++/* ++ * FIPS 140-2 continuous self test ++ * The test is performed on the result of one round of the output ++ * function. Thus, the function implicitly knows the size of the ++ * buffer. ++ * ++ * @drbg DRBG handle ++ * @buf output buffer of random data to be checked ++ * ++ * return: ++ * false on error ++ * true on success ++ */ ++static gpg_err_code_t ++gcry_drbg_fips_continuous_test (struct gcry_drbg_state *drbg, ++ const unsigned char *buf) ++{ ++ gpg_err_code_t ret = 0; ++ /* skip test if we test the overall system */ ++ if (drbg->test_data) ++ return 1; ++ /* only perform test in FIPS mode */ ++ if (0 == fips_mode ()) ++ return 1; ++ if (!drbg->fips_primed) ++ { ++ /* Priming of FIPS test */ ++ memcpy (drbg->prev, buf, gcry_drbg_blocklen (drbg)); ++ drbg->fips_primed = 1; ++ /* return false due to priming, i.e. another round is needed */ ++ return 0; ++ } ++ ret = memcmp (drbg->prev, buf, gcry_drbg_blocklen (drbg)); ++ memcpy (drbg->prev, buf, gcry_drbg_blocklen (drbg)); ++ /* the test shall pass when the two compared values are not equal */ ++ return ret != 0; ++} ++ ++/* ++ * Convert an integer into a byte representation of this integer. ++ * The byte representation is big-endian ++ * ++ * @val value to be converted ++ * @buf buffer holding the converted integer -- caller must ensure that ++ * buffer size is at least 32 bit ++ */ ++static inline void ++gcry_drbg_cpu_to_be32 (u32 val, unsigned char *buf) ++{ ++ struct s ++ { ++ u32 conv; ++ }; ++ struct s *conversion = (struct s *) buf; ++ ++ conversion->conv = be_bswap32 (val); ++} ++ ++static void ++gcry_drbg_add_buf (unsigned char *dst, size_t dstlen, ++ unsigned char *add, size_t addlen) ++{ ++ /* implied: dstlen > addlen */ ++ unsigned char *dstptr, *addptr; ++ unsigned int remainder = 0; ++ size_t len = addlen; ++ ++ dstptr = dst + (dstlen - 1); ++ addptr = add + (addlen - 1); ++ while (len) ++ { ++ remainder += *dstptr + *addptr; ++ *dstptr = remainder & 0xff; ++ remainder >>= 8; ++ len--; ++ dstptr--; ++ addptr--; ++ } ++ len = dstlen - addlen; ++ while (len && remainder > 0) ++ { ++ remainder = *dstptr + 1; ++ *dstptr = remainder & 0xff; ++ remainder >>= 8; ++ len--; ++ dstptr--; ++ } ++} ++ ++/* Helper variables for read_cb(). ++ * ++ * The _gcry_rnd*_gather_random interface does not allow to provide a ++ * data pointer. Thus we need to use a global variable for ++ * communication. However, the then required locking is anyway a good ++ * idea because it does not make sense to have several readers of (say ++ * /dev/random). It is easier to serve them one after the other. */ ++static unsigned char *read_cb_buffer; /* The buffer. */ ++static size_t read_cb_size; /* Size of the buffer. */ ++static size_t read_cb_len; /* Used length. */ ++ ++/* Callback for generating seed from kernel device. */ ++static void ++gcry_drbg_read_cb (const void *buffer, size_t length, ++ enum random_origins origin) ++{ ++ const unsigned char *p = buffer; ++ ++ (void) origin; ++ gcry_assert (read_cb_buffer); ++ ++ /* Note that we need to protect against gatherers returning more ++ * than the requested bytes (e.g. rndw32). */ ++ while (length-- && read_cb_len < read_cb_size) ++ read_cb_buffer[read_cb_len++] = *p++; ++} ++ ++static inline int ++gcry_drbg_get_entropy (struct gcry_drbg_state *drbg, unsigned char *buffer, ++ size_t len) ++{ ++ int rc = 0; ++ ++ /* Perform testing as defined in 11.3.2 */ ++ if (drbg->test_data && drbg->test_data->fail_seed_source) ++ return -1; ++ ++ read_cb_buffer = buffer; ++ read_cb_size = len; ++ read_cb_len = 0; ++#if USE_RNDLINUX ++ rc = _gcry_rndlinux_gather_random (gcry_drbg_read_cb, 0, len, ++ GCRY_VERY_STRONG_RANDOM); ++#elif USE_RNDUNIX ++ rc = _gcry_rndunix_gather_random (read_cb, 0, length, ++ GCRY_VERY_STRONG_RANDOM); ++#elif USE_RNDW32 ++ do ++ { ++ rc = _gcry_rndw32_gather_random (read_cb, 0, length, ++ GCRY_VERY_STRONG_RANDOM); ++ } ++ while (rc >= 0 && read_cb_len < read_cb_size); ++#else ++ rc = -1; ++#endif ++ return rc; ++} ++ ++/****************************************************************** ++ * CTR DRBG callback functions ++ ******************************************************************/ ++ ++/* BCC function for CTR DRBG as defined in 10.4.3 */ ++static gpg_err_code_t ++gcry_drbg_ctr_bcc (struct gcry_drbg_state *drbg, ++ unsigned char *out, const unsigned char *key, ++ struct gcry_drbg_string *in) ++{ ++ gpg_err_code_t ret = GPG_ERR_GENERAL; ++ struct gcry_drbg_string *curr = in; ++ size_t inpos = curr->len; ++ const unsigned char *pos = curr->buf; ++ struct gcry_drbg_string data; ++ ++ gcry_drbg_string_fill (&data, out, gcry_drbg_blocklen (drbg)); ++ ++ /* 10.4.3 step 1 */ ++ memset (out, 0, gcry_drbg_blocklen (drbg)); ++ ++ /* 10.4.3 step 2 / 4 */ ++ while (inpos) ++ { ++ short cnt = 0; ++ /* 10.4.3 step 4.1 */ ++ for (cnt = 0; cnt < gcry_drbg_blocklen (drbg); cnt++) ++ { ++ out[cnt] ^= *pos; ++ pos++; ++ inpos--; ++ /* the following branch implements the linked list ++ * iteration. If we are at the end of the current data ++ * set, we have to start using the next data set if ++ * available -- the inpos value always points to the ++ * current byte and will be zero if we have processed ++ * the last byte of the last linked list member */ ++ if (0 == inpos) ++ { ++ curr = curr->next; ++ if (NULL != curr) ++ { ++ pos = curr->buf; ++ inpos = curr->len; ++ } ++ else ++ { ++ inpos = 0; ++ break; ++ } ++ } ++ } ++ /* 10.4.3 step 4.2 */ ++ ret = gcry_drbg_sym (drbg, key, out, &data); ++ if (ret) ++ return ret; ++ /* 10.4.3 step 2 */ ++ } ++ return 0; ++} ++ ++ ++/* ++ * scratchpad usage: gcry_drbg_ctr_update is interlinked with gcry_drbg_ctr_df ++ * (and gcry_drbg_ctr_bcc, but this function does not need any temporary buffers), ++ * the scratchpad is used as follows: ++ * gcry_drbg_ctr_update: ++ * temp ++ * start: drbg->scratchpad ++ * length: gcry_drbg_statelen(drbg) + gcry_drbg_blocklen(drbg) ++ * note: the cipher writing into this variable works ++ * blocklen-wise. Now, when the statelen is not a multiple ++ * of blocklen, the generateion loop below "spills over" ++ * by at most blocklen. Thus, we need to give sufficient ++ * memory. ++ * df_data ++ * start: drbg->scratchpad + ++ * gcry_drbg_statelen(drbg) + ++ * gcry_drbg_blocklen(drbg) ++ * length: gcry_drbg_statelen(drbg) ++ * ++ * gcry_drbg_ctr_df: ++ * pad ++ * start: df_data + gcry_drbg_statelen(drbg) ++ * length: gcry_drbg_blocklen(drbg) ++ * iv ++ * start: pad + gcry_drbg_blocklen(drbg) ++ * length: gcry_drbg_blocklen(drbg) ++ * temp ++ * start: iv + gcry_drbg_blocklen(drbg) ++ * length: gcry_drbg_satelen(drbg) + gcry_drbg_blocklen(drbg) ++ * note: temp is the buffer that the BCC function operates ++ * on. BCC operates blockwise. gcry_drbg_statelen(drbg) ++ * is sufficient when the DRBG state length is a multiple ++ * of the block size. For AES192 (and maybe other ciphers) ++ * this is not correct and the length for temp is ++ * insufficient (yes, that also means for such ciphers, ++ * the final output of all BCC rounds are truncated). ++ * Therefore, add gcry_drbg_blocklen(drbg) to cover all ++ * possibilities. ++ */ ++ ++/* Derivation Function for CTR DRBG as defined in 10.4.2 */ ++static gpg_err_code_t ++gcry_drbg_ctr_df (struct gcry_drbg_state *drbg, unsigned char *df_data, ++ size_t bytes_to_return, struct gcry_drbg_string *addtl) ++{ ++ gpg_err_code_t ret = GPG_ERR_GENERAL; ++ unsigned char L_N[8]; ++ /* S3 is input */ ++ struct gcry_drbg_string S1, S2, S4, cipherin; ++ struct gcry_drbg_string *tempstr = addtl; ++ unsigned char *pad = df_data + gcry_drbg_statelen (drbg); ++ unsigned char *iv = pad + gcry_drbg_blocklen (drbg); ++ unsigned char *temp = iv + gcry_drbg_blocklen (drbg); ++ size_t padlen = 0; ++ unsigned int templen = 0; ++ /* 10.4.2 step 7 */ ++ unsigned int i = 0; ++ /* 10.4.2 step 8 */ ++ const unsigned char *K = (unsigned char *) ++ "\x00\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\x1a\x1b\x1c\x1d\x1e\x1f"; ++ unsigned char *X; ++ size_t generated_len = 0; ++ size_t inputlen = 0; ++ ++ memset (pad, 0, gcry_drbg_blocklen (drbg)); ++ memset (iv, 0, gcry_drbg_blocklen (drbg)); ++ memset (temp, 0, gcry_drbg_statelen (drbg)); ++ ++ /* 10.4.2 step 1 is implicit as we work byte-wise */ ++ ++ /* 10.4.2 step 2 */ ++ if ((512 / 8) < bytes_to_return) ++ return GPG_ERR_INV_ARG; ++ ++ /* 10.4.2 step 2 -- calculate the entire length of all input data */ ++ for (; NULL != tempstr; tempstr = tempstr->next) ++ inputlen += tempstr->len; ++ gcry_drbg_cpu_to_be32 (inputlen, &L_N[0]); ++ ++ /* 10.4.2 step 3 */ ++ gcry_drbg_cpu_to_be32 (bytes_to_return, &L_N[4]); ++ ++ /* 10.4.2 step 5: length is size of L_N, input_string, one byte, padding */ ++ padlen = (inputlen + sizeof (L_N) + 1) % (gcry_drbg_blocklen (drbg)); ++ /* wrap the padlen appropriately */ ++ if (padlen) ++ padlen = gcry_drbg_blocklen (drbg) - padlen; ++ /* pad / padlen contains the 0x80 byte and the following zero bytes, so ++ * add one for byte for 0x80 */ ++ padlen++; ++ pad[0] = 0x80; ++ ++ /* 10.4.2 step 4 -- first fill the linked list and then order it */ ++ gcry_drbg_string_fill (&S1, iv, gcry_drbg_blocklen (drbg)); ++ gcry_drbg_string_fill (&S2, L_N, sizeof (L_N)); ++ gcry_drbg_string_fill (&S4, pad, padlen); ++ S1.next = &S2; ++ S2.next = addtl; ++ ++ /* Splice in addtl between S2 and S4 -- we place S4 at the end of the ++ * input data chain. As this code is only triggered when addtl is not ++ * NULL, no NULL checks are necessary.*/ ++ tempstr = addtl; ++ while (tempstr->next) ++ tempstr = tempstr->next; ++ tempstr->next = &S4; ++ ++ /* 10.4.2 step 9 */ ++ while (templen < (gcry_drbg_keylen (drbg) + (gcry_drbg_blocklen (drbg)))) ++ { ++ /* 10.4.2 step 9.1 - the padding is implicit as the buffer ++ * holds zeros after allocation -- even the increment of i ++ * is irrelevant as the increment remains within length of i */ ++ gcry_drbg_cpu_to_be32 (i, iv); ++ /* 10.4.2 step 9.2 -- BCC and concatenation with temp */ ++ ret = gcry_drbg_ctr_bcc (drbg, temp + templen, K, &S1); ++ if (ret) ++ goto out; ++ /* 10.4.2 step 9.3 */ ++ i++; ++ templen += gcry_drbg_blocklen (drbg); ++ } ++ ++ /* 10.4.2 step 11 */ ++ /* implicit key len with seedlen - blocklen according to table 3 */ ++ X = temp + (gcry_drbg_keylen (drbg)); ++ gcry_drbg_string_fill (&cipherin, X, gcry_drbg_blocklen (drbg)); ++ ++ /* 10.4.2 step 12: overwriting of outval */ ++ ++ /* 10.4.2 step 13 */ ++ while (generated_len < bytes_to_return) ++ { ++ short blocklen = 0; ++ /* 10.4.2 step 13.1 */ ++ /* the truncation of the key length is implicit as the key ++ * is only gcry_drbg_blocklen in size -- check for the implementation ++ * of the cipher function callback */ ++ ret = gcry_drbg_sym (drbg, temp, X, &cipherin); ++ if (ret) ++ goto out; ++ blocklen = (gcry_drbg_blocklen (drbg) < ++ (bytes_to_return - generated_len)) ? ++ gcry_drbg_blocklen (drbg) : (bytes_to_return - generated_len); ++ /* 10.4.2 step 13.2 and 14 */ ++ memcpy (df_data + generated_len, X, blocklen); ++ generated_len += blocklen; ++ } ++ ++ ret = 0; ++ ++out: ++ memset (iv, 0, gcry_drbg_blocklen (drbg)); ++ memset (temp, 0, gcry_drbg_statelen (drbg)); ++ memset (pad, 0, gcry_drbg_blocklen (drbg)); ++ return ret; ++} ++ ++/* ++ * update function of CTR DRBG as defined in 10.2.1.2 ++ * ++ * The reseed variable has an enhanced meaning compared to the update ++ * functions of the other DRBGs as follows: ++ * 0 => initial seed from initialization ++ * 1 => reseed via gcry_drbg_seed ++ * 2 => first invocation from gcry_drbg_ctr_update when addtl is present. In ++ * this case, the df_data scratchpad is not deleted so that it is ++ * available for another calls to prevent calling the DF function ++ * again. ++ * 3 => second invocation from gcry_drbg_ctr_update. When the update function ++ * was called with addtl, the df_data memory already contains the ++ * DFed addtl information and we do not need to call DF again. ++ */ ++static gpg_err_code_t ++gcry_drbg_ctr_update (struct gcry_drbg_state *drbg, ++ struct gcry_drbg_string *addtl, int reseed) ++{ ++ gpg_err_code_t ret = GPG_ERR_GENERAL; ++ /* 10.2.1.2 step 1 */ ++ unsigned char *temp = drbg->scratchpad; ++ unsigned char *df_data = drbg->scratchpad + ++ gcry_drbg_statelen (drbg) + gcry_drbg_blocklen (drbg); ++ unsigned char *temp_p, *df_data_p; /* pointer to iterate over buffers */ ++ unsigned int len = 0; ++ struct gcry_drbg_string cipherin; ++ unsigned char prefix = DRBG_PREFIX1; ++ ++ memset (temp, 0, gcry_drbg_statelen (drbg) + gcry_drbg_blocklen (drbg)); ++ if (3 > reseed) ++ memset (df_data, 0, gcry_drbg_statelen (drbg)); ++ ++ /* 10.2.1.3.2 step 2 and 10.2.1.4.2 step 2 */ ++ /* TODO use reseed variable to avoid re-doing DF operation */ ++ (void) reseed; ++ if (addtl && 0 < addtl->len) ++ { ++ ret = ++ gcry_drbg_ctr_df (drbg, df_data, gcry_drbg_statelen (drbg), addtl); ++ if (ret) ++ goto out; ++ } ++ ++ gcry_drbg_string_fill (&cipherin, drbg->V, gcry_drbg_blocklen (drbg)); ++ /* 10.2.1.3.2 step 2 and 3 -- are already covered as we memset(0) ++ * all memory during initialization */ ++ while (len < (gcry_drbg_statelen (drbg))) ++ { ++ /* 10.2.1.2 step 2.1 */ ++ gcry_drbg_add_buf (drbg->V, gcry_drbg_blocklen (drbg), &prefix, 1); ++ /* 10.2.1.2 step 2.2 */ ++ /* using target of temp + len: 10.2.1.2 step 2.3 and 3 */ ++ ret = gcry_drbg_sym (drbg, drbg->C, temp + len, &cipherin); ++ if (ret) ++ goto out; ++ /* 10.2.1.2 step 2.3 and 3 */ ++ len += gcry_drbg_blocklen (drbg); ++ } ++ ++ /* 10.2.1.2 step 4 */ ++ temp_p = temp; ++ df_data_p = df_data; ++ for (len = 0; len < gcry_drbg_statelen (drbg); len++) ++ { ++ *temp_p ^= *df_data_p; ++ df_data_p++; ++ temp_p++; ++ } ++ ++ /* 10.2.1.2 step 5 */ ++ memcpy (drbg->C, temp, gcry_drbg_keylen (drbg)); ++ /* 10.2.1.2 step 6 */ ++ memcpy (drbg->V, temp + gcry_drbg_keylen (drbg), gcry_drbg_blocklen (drbg)); ++ ret = 0; ++ ++out: ++ memset (temp, 0, gcry_drbg_statelen (drbg) + gcry_drbg_blocklen (drbg)); ++ if (2 != reseed) ++ memset (df_data, 0, gcry_drbg_statelen (drbg)); ++ return ret; ++} ++ ++/* ++ * scratchpad use: gcry_drbg_ctr_update is called independently from ++ * gcry_drbg_ctr_extract_bytes. Therefore, the scratchpad is reused ++ */ ++/* Generate function of CTR DRBG as defined in 10.2.1.5.2 */ ++static gpg_err_code_t ++gcry_drbg_ctr_generate (struct gcry_drbg_state *drbg, ++ unsigned char *buf, unsigned int buflen, ++ struct gcry_drbg_string *addtl) ++{ ++ gpg_err_code_t ret = 0; ++ unsigned int len = 0; ++ struct gcry_drbg_string data; ++ unsigned char prefix = DRBG_PREFIX1; ++ ++ memset (drbg->scratchpad, 0, gcry_drbg_blocklen (drbg)); ++ ++ /* 10.2.1.5.2 step 2 */ ++ if (addtl && 0 < addtl->len) ++ { ++ addtl->next = NULL; ++ ret = gcry_drbg_ctr_update (drbg, addtl, 2); ++ if (ret) ++ return ret; ++ } ++ ++ /* 10.2.1.5.2 step 4.1 */ ++ gcry_drbg_add_buf (drbg->V, gcry_drbg_blocklen (drbg), &prefix, 1); ++ gcry_drbg_string_fill (&data, drbg->V, gcry_drbg_blocklen (drbg)); ++ while (len < buflen) ++ { ++ unsigned int outlen = 0; ++ /* 10.2.1.5.2 step 4.2 */ ++ ret = gcry_drbg_sym (drbg, drbg->C, drbg->scratchpad, &data); ++ if (ret) ++ goto out; ++ outlen = (gcry_drbg_blocklen (drbg) < (buflen - len)) ? ++ gcry_drbg_blocklen (drbg) : (buflen - len); ++ if (!gcry_drbg_fips_continuous_test (drbg, drbg->scratchpad)) ++ { ++ /* 10.2.1.5.2 step 6 */ ++ gcry_drbg_add_buf (drbg->V, gcry_drbg_blocklen (drbg), &prefix, 1); ++ continue; ++ } ++ /* 10.2.1.5.2 step 4.3 */ ++ memcpy (buf + len, drbg->scratchpad, outlen); ++ len += outlen; ++ /* 10.2.1.5.2 step 6 */ ++ if (len < buflen) ++ gcry_drbg_add_buf (drbg->V, gcry_drbg_blocklen (drbg), &prefix, 1); ++ } ++ ++ /* 10.2.1.5.2 step 6 */ ++ if (addtl) ++ addtl->next = NULL; ++ ret = gcry_drbg_ctr_update (drbg, addtl, 3); ++ ++out: ++ memset (drbg->scratchpad, 0, gcry_drbg_blocklen (drbg)); ++ return ret; ++} ++ ++static struct gcry_drbg_state_ops gcry_drbg_ctr_ops = { ++ gcry_drbg_ctr_update, ++ gcry_drbg_ctr_generate, ++}; ++ ++/****************************************************************** ++ * HMAC DRBG callback functions ++ ******************************************************************/ ++ ++static gpg_err_code_t ++gcry_drbg_hmac_update (struct gcry_drbg_state *drbg, ++ struct gcry_drbg_string *seed, int reseed) ++{ ++ gpg_err_code_t ret = GPG_ERR_GENERAL; ++ int i = 0; ++ struct gcry_drbg_string seed1, seed2, cipherin; ++ ++ if (!reseed) ++ /* 10.1.2.3 step 2 already implicitly covered with ++ * the initial memset(0) of drbg->C */ ++ memset (drbg->V, 1, gcry_drbg_statelen (drbg)); ++ ++ /* build linked list which implements the concatenation and fill ++ * first part*/ ++ gcry_drbg_string_fill (&seed1, drbg->V, gcry_drbg_statelen (drbg)); ++ /* buffer will be filled in for loop below with one byte */ ++ gcry_drbg_string_fill (&seed2, NULL, 1); ++ seed1.next = &seed2; ++ /* seed may be NULL */ ++ seed2.next = seed; ++ ++ gcry_drbg_string_fill (&cipherin, drbg->V, gcry_drbg_statelen (drbg)); ++ /* we execute two rounds of V/K massaging */ ++ for (i = 2; 0 < i; i--) ++ { ++ /* first round uses 0x0, second 0x1 */ ++ unsigned char prefix = DRBG_PREFIX0; ++ if (1 == i) ++ prefix = DRBG_PREFIX1; ++ /* 10.1.2.2 step 1 and 4 -- concatenation and HMAC for key */ ++ seed2.buf = &prefix; ++ ret = gcry_drbg_hmac (drbg, drbg->C, drbg->C, &seed1); ++ if (ret) ++ return ret; ++ ++ /* 10.1.2.2 step 2 and 5 -- HMAC for V */ ++ ret = gcry_drbg_hmac (drbg, drbg->C, drbg->V, &cipherin); ++ if (ret) ++ return ret; ++ ++ /* 10.1.2.2 step 3 */ ++ if (!seed || 0 == seed->len) ++ return ret; ++ } ++ return 0; ++} ++ ++/* generate function of HMAC DRBG as defined in 10.1.2.5 */ ++static gpg_err_code_t ++gcry_drbg_hmac_generate (struct gcry_drbg_state *drbg, ++ unsigned char *buf, ++ unsigned int buflen, struct gcry_drbg_string *addtl) ++{ ++ gpg_err_code_t ret = 0; ++ unsigned int len = 0; ++ struct gcry_drbg_string data; ++ ++ /* 10.1.2.5 step 2 */ ++ if (addtl && 0 < addtl->len) ++ { ++ addtl->next = NULL; ++ ret = gcry_drbg_hmac_update (drbg, addtl, 1); ++ if (ret) ++ return ret; ++ } ++ ++ gcry_drbg_string_fill (&data, drbg->V, gcry_drbg_statelen (drbg)); ++ while (len < buflen) ++ { ++ unsigned int outlen = 0; ++ /* 10.1.2.5 step 4.1 */ ++ ret = gcry_drbg_hmac (drbg, drbg->C, drbg->V, &data); ++ if (ret) ++ return ret; ++ outlen = (gcry_drbg_blocklen (drbg) < (buflen - len)) ? ++ gcry_drbg_blocklen (drbg) : (buflen - len); ++ if (!gcry_drbg_fips_continuous_test (drbg, drbg->V)) ++ continue; ++ ++ /* 10.1.2.5 step 4.2 */ ++ memcpy (buf + len, drbg->V, outlen); ++ len += outlen; ++ } ++ ++ /* 10.1.2.5 step 6 */ ++ if (addtl) ++ addtl->next = NULL; ++ ret = gcry_drbg_hmac_update (drbg, addtl, 1); ++ ++ return ret; ++} ++ ++static struct gcry_drbg_state_ops gcry_drbg_hmac_ops = { ++ gcry_drbg_hmac_update, ++ gcry_drbg_hmac_generate, ++}; ++ ++/****************************************************************** ++ * Hash DRBG callback functions ++ ******************************************************************/ ++ ++/* ++ * scratchpad usage: as gcry_drbg_hash_update and gcry_drbg_hash_df are used ++ * interlinked, the scratchpad is used as follows: ++ * gcry_drbg_hash_update ++ * start: drbg->scratchpad ++ * length: gcry_drbg_statelen(drbg) ++ * gcry_drbg_hash_df: ++ * start: drbg->scratchpad + gcry_drbg_statelen(drbg) ++ * length: gcry_drbg_blocklen(drbg) ++ */ ++/* Derivation Function for Hash DRBG as defined in 10.4.1 */ ++static gpg_err_code_t ++gcry_drbg_hash_df (struct gcry_drbg_state *drbg, ++ unsigned char *outval, size_t outlen, ++ struct gcry_drbg_string *entropy) ++{ ++ gpg_err_code_t ret = 0; ++ size_t len = 0; ++ unsigned char input[5]; ++ unsigned char *tmp = drbg->scratchpad + gcry_drbg_statelen (drbg); ++ struct gcry_drbg_string data1; ++ ++ memset (tmp, 0, gcry_drbg_blocklen (drbg)); ++ ++ /* 10.4.1 step 3 */ ++ input[0] = 1; ++ gcry_drbg_cpu_to_be32 ((outlen * 8), &input[1]); ++ ++ /* 10.4.1 step 4.1 -- concatenation of data for input into hash */ ++ gcry_drbg_string_fill (&data1, input, 5); ++ data1.next = entropy; ++ ++ /* 10.4.1 step 4 */ ++ while (len < outlen) ++ { ++ short blocklen = 0; ++ /* 10.4.1 step 4.1 */ ++ ret = gcry_drbg_hmac (drbg, NULL, tmp, &data1); ++ if (ret) ++ goto out; ++ /* 10.4.1 step 4.2 */ ++ input[0]++; ++ blocklen = (gcry_drbg_blocklen (drbg) < (outlen - len)) ? ++ gcry_drbg_blocklen (drbg) : (outlen - len); ++ memcpy (outval + len, tmp, blocklen); ++ len += blocklen; ++ } ++ ++out: ++ memset (tmp, 0, gcry_drbg_blocklen (drbg)); ++ return ret; ++} ++ ++/* update function for Hash DRBG as defined in 10.1.1.2 / 10.1.1.3 */ ++static gpg_err_code_t ++gcry_drbg_hash_update (struct gcry_drbg_state *drbg, ++ struct gcry_drbg_string *seed, int reseed) ++{ ++ gpg_err_code_t ret = 0; ++ struct gcry_drbg_string data1, data2; ++ unsigned char *V = drbg->scratchpad; ++ unsigned char prefix = DRBG_PREFIX1; ++ ++ memset (drbg->scratchpad, 0, gcry_drbg_statelen (drbg)); ++ if (!seed) ++ return GPG_ERR_INV_ARG; ++ ++ if (reseed) ++ { ++ /* 10.1.1.3 step 1: string length is concatenation of ++ * 1 byte, V and seed (which is concatenated entropy/addtl ++ * input) ++ */ ++ memcpy (V, drbg->V, gcry_drbg_statelen (drbg)); ++ gcry_drbg_string_fill (&data1, &prefix, 1); ++ gcry_drbg_string_fill (&data2, V, gcry_drbg_statelen (drbg)); ++ data1.next = &data2; ++ data2.next = seed; ++ } ++ else ++ { ++ gcry_drbg_string_fill (&data1, seed->buf, seed->len); ++ data1.next = seed->next; ++ } ++ ++ /* 10.1.1.2 / 10.1.1.3 step 2 and 3 */ ++ ret = gcry_drbg_hash_df (drbg, drbg->V, gcry_drbg_statelen (drbg), &data1); ++ if (ret) ++ goto out; ++ ++ /* 10.1.1.2 / 10.1.1.3 step 4 -- concatenation */ ++ prefix = DRBG_PREFIX0; ++ gcry_drbg_string_fill (&data1, &prefix, 1); ++ gcry_drbg_string_fill (&data2, drbg->V, gcry_drbg_statelen (drbg)); ++ data1.next = &data2; ++ /* 10.1.1.2 / 10.1.1.3 step 4 -- df operation */ ++ ret = gcry_drbg_hash_df (drbg, drbg->C, gcry_drbg_statelen (drbg), &data1); ++ ++out: ++ memset (drbg->scratchpad, 0, gcry_drbg_statelen (drbg)); ++ return ret; ++} ++ ++/* processing of additional information string for Hash DRBG */ ++static gpg_err_code_t ++gcry_drbg_hash_process_addtl (struct gcry_drbg_state *drbg, ++ struct gcry_drbg_string *addtl) ++{ ++ gpg_err_code_t ret = 0; ++ struct gcry_drbg_string data1, data2; ++ struct gcry_drbg_string *data3; ++ unsigned char prefix = DRBG_PREFIX2; ++ ++ /* this is value w as per documentation */ ++ memset (drbg->scratchpad, 0, gcry_drbg_blocklen (drbg)); ++ ++ /* 10.1.1.4 step 2 */ ++ if (!addtl || 0 == addtl->len) ++ return 0; ++ ++ /* 10.1.1.4 step 2a -- concatenation */ ++ gcry_drbg_string_fill (&data1, &prefix, 1); ++ gcry_drbg_string_fill (&data2, drbg->V, gcry_drbg_statelen (drbg)); ++ data3 = addtl; ++ data1.next = &data2; ++ data2.next = data3; ++ data3->next = NULL; ++ /* 10.1.1.4 step 2a -- cipher invocation */ ++ ret = gcry_drbg_hmac (drbg, NULL, drbg->scratchpad, &data1); ++ if (ret) ++ goto out; ++ ++ /* 10.1.1.4 step 2b */ ++ gcry_drbg_add_buf (drbg->V, gcry_drbg_statelen (drbg), ++ drbg->scratchpad, gcry_drbg_blocklen (drbg)); ++ ++out: ++ memset (drbg->scratchpad, 0, gcry_drbg_blocklen (drbg)); ++ return ret; ++} ++ ++/* ++ * Hashgen defined in 10.1.1.4 ++ */ ++static gpg_err_code_t ++gcry_drbg_hash_hashgen (struct gcry_drbg_state *drbg, ++ unsigned char *buf, unsigned int buflen) ++{ ++ gpg_err_code_t ret = 0; ++ unsigned int len = 0; ++ unsigned char *src = drbg->scratchpad; ++ unsigned char *dst = drbg->scratchpad + gcry_drbg_statelen (drbg); ++ struct gcry_drbg_string data; ++ unsigned char prefix = DRBG_PREFIX1; ++ ++ /* use the scratchpad as a lookaside buffer */ ++ memset (src, 0, gcry_drbg_statelen (drbg)); ++ memset (dst, 0, gcry_drbg_blocklen (drbg)); ++ ++ /* 10.1.1.4 step hashgen 2 */ ++ memcpy (src, drbg->V, gcry_drbg_statelen (drbg)); ++ ++ gcry_drbg_string_fill (&data, src, gcry_drbg_statelen (drbg)); ++ while (len < buflen) ++ { ++ unsigned int outlen = 0; ++ /* 10.1.1.4 step hashgen 4.1 */ ++ ret = gcry_drbg_hmac (drbg, NULL, dst, &data); ++ if (ret) ++ goto out; ++ outlen = (gcry_drbg_blocklen (drbg) < (buflen - len)) ? ++ gcry_drbg_blocklen (drbg) : (buflen - len); ++ if (!gcry_drbg_fips_continuous_test (drbg, dst)) ++ { ++ gcry_drbg_add_buf (src, gcry_drbg_statelen (drbg), &prefix, 1); ++ continue; ++ } ++ /* 10.1.1.4 step hashgen 4.2 */ ++ memcpy (buf + len, dst, outlen); ++ len += outlen; ++ /* 10.1.1.4 hashgen step 4.3 */ ++ if (len < buflen) ++ gcry_drbg_add_buf (src, gcry_drbg_statelen (drbg), &prefix, 1); ++ } ++ ++out: ++ memset (drbg->scratchpad, 0, ++ (gcry_drbg_statelen (drbg) + gcry_drbg_blocklen (drbg))); ++ return ret; ++} ++ ++/* generate function for Hash DRBG as defined in 10.1.1.4 */ ++static gpg_err_code_t ++gcry_drbg_hash_generate (struct gcry_drbg_state *drbg, ++ unsigned char *buf, unsigned int buflen, ++ struct gcry_drbg_string *addtl) ++{ ++ gpg_err_code_t ret = 0; ++ unsigned char prefix = DRBG_PREFIX3; ++ struct gcry_drbg_string data1, data2; ++ union ++ { ++ unsigned char req[8]; ++ u64 req_int; ++ } u; ++ ++ /* ++ * scratchpad usage: gcry_drbg_hash_process_addtl uses the scratchpad, but ++ * fully completes before returning. Thus, we can reuse the scratchpad ++ */ ++ /* 10.1.1.4 step 2 */ ++ ret = gcry_drbg_hash_process_addtl (drbg, addtl); ++ if (ret) ++ return ret; ++ /* 10.1.1.4 step 3 -- invocation of the Hashgen function defined in ++ * 10.1.1.4 */ ++ ret = gcry_drbg_hash_hashgen (drbg, buf, buflen); ++ if (ret) ++ return ret; ++ ++ /* this is the value H as documented in 10.1.1.4 */ ++ memset (drbg->scratchpad, 0, gcry_drbg_blocklen (drbg)); ++ /* 10.1.1.4 step 4 */ ++ gcry_drbg_string_fill (&data1, &prefix, 1); ++ gcry_drbg_string_fill (&data2, drbg->V, gcry_drbg_statelen (drbg)); ++ data1.next = &data2; ++ ret = gcry_drbg_hmac (drbg, NULL, drbg->scratchpad, &data1); ++ if (ret) ++ goto out; ++ ++ /* 10.1.1.4 step 5 */ ++ gcry_drbg_add_buf (drbg->V, gcry_drbg_statelen (drbg), ++ drbg->scratchpad, gcry_drbg_blocklen (drbg)); ++ gcry_drbg_add_buf (drbg->V, gcry_drbg_statelen (drbg), drbg->C, ++ gcry_drbg_statelen (drbg)); ++ u.req_int = be_bswap64 (drbg->reseed_ctr); ++ gcry_drbg_add_buf (drbg->V, gcry_drbg_statelen (drbg), u.req, ++ sizeof (u.req)); ++ ++out: ++ memset (drbg->scratchpad, 0, gcry_drbg_blocklen (drbg)); ++ return ret; ++} ++ ++/* ++ * scratchpad usage: as update and generate are used isolated, both ++ * can use the scratchpad ++ */ ++static struct gcry_drbg_state_ops gcry_drbg_hash_ops = { ++ gcry_drbg_hash_update, ++ gcry_drbg_hash_generate, ++}; ++ ++/****************************************************************** ++ * Functions common for DRBG implementations ++ ******************************************************************/ ++ ++/* ++ * Seeding or reseeding of the DRBG ++ * ++ * @drbg: DRBG state struct ++ * @pers: personalization / additional information buffer ++ * @reseed: 0 for initial seed process, 1 for reseeding ++ * ++ * return: ++ * 0 on success ++ * error value otherwise ++ */ ++static gpg_err_code_t ++gcry_drbg_seed (struct gcry_drbg_state *drbg, struct gcry_drbg_string *pers, ++ int reseed) ++{ ++ gpg_err_code_t ret = 0; ++ unsigned char *entropy = NULL; ++ size_t entropylen = 0; ++ struct gcry_drbg_string data1; ++ ++ /* 9.1 / 9.2 / 9.3.1 step 3 */ ++ if (pers && pers->len > (gcry_drbg_max_addtl ())) ++ { ++ dbg (("DRBG: personalization string too long %lu\n", pers->len)); ++ return GPG_ERR_INV_ARG; ++ } ++ if (drbg->test_data && drbg->test_data->testentropy) ++ { ++ gcry_drbg_string_fill (&data1, drbg->test_data->testentropy->buf, ++ drbg->test_data->testentropy->len); ++ dbg (("DRBG: using test entropy\n")); ++ } ++ else ++ { ++ /* Gather entropy equal to the security strength of the DRBG. ++ * With a derivation function, a nonce is required in addition ++ * to the entropy. A nonce must be at least 1/2 of the security ++ * strength of the DRBG in size. Thus, entropy * nonce is 3/2 ++ * of the strength. The consideration of a nonce is only ++ * applicable during initial seeding. */ ++ entropylen = gcry_drbg_sec_strength (drbg->core->flags); ++ if (!entropylen) ++ return GPG_ERR_GENERAL; ++ if (0 == reseed) ++ /* make sure we round up strength/2 in ++ * case it is not divisible by 2 */ ++ entropylen = ((entropylen + 1) / 2) * 3; ++ dbg (("DRBG: (re)seeding with %lu bytes of entropy\n", entropylen)); ++ entropy = xcalloc_secure (1, entropylen); ++ if (!entropy) ++ return GPG_ERR_ENOMEM; ++ ret = gcry_drbg_get_entropy (drbg, entropy, entropylen); ++ if (ret) ++ goto out; ++ gcry_drbg_string_fill (&data1, entropy, entropylen); ++ } ++ ++ /* concatenation of entropy with personalization str / addtl input) ++ * the variable pers is directly handed by the caller, check its ++ * contents whether it is appropriate */ ++ if (pers && pers->buf && 0 < pers->len && NULL == pers->next) ++ { ++ data1.next = pers; ++ dbg (("DRBG: using personalization string\n")); ++ } ++ ++ ret = drbg->d_ops->update (drbg, &data1, reseed); ++ dbg (("DRBG: state updated with seed\n")); ++ if (ret) ++ goto out; ++ drbg->seeded = 1; ++ /* 10.1.1.2 / 10.1.1.3 step 5 */ ++ drbg->reseed_ctr = 1; ++ ++out: ++ xfree (entropy); ++ return ret; ++} ++ ++/************************************************************************* ++ * exported interfaces ++ *************************************************************************/ ++ ++/* ++ * DRBG generate function as required by SP800-90A - this function ++ * generates random numbers ++ * ++ * @drbg DRBG state handle ++ * @buf Buffer where to store the random numbers -- the buffer must already ++ * be pre-allocated by caller ++ * @buflen Length of output buffer - this value defines the number of random ++ * bytes pulled from DRBG ++ * @addtl Additional input that is mixed into state, may be NULL -- note ++ * the entropy is pulled by the DRBG internally unconditionally ++ * as defined in SP800-90A. The additional input is mixed into ++ * the state in addition to the pulled entropy. ++ * ++ * return: generated number of bytes ++ */ ++static gpg_err_code_t ++gcry_drbg_generate (struct gcry_drbg_state *drbg, ++ unsigned char *buf, unsigned int buflen, ++ struct gcry_drbg_string *addtl) ++{ ++ gpg_err_code_t ret = GPG_ERR_INV_ARG; ++ ++ if (0 == buflen || !buf) ++ { ++ dbg (("DRBG: no buffer provided\n")); ++ return ret; ++ } ++ if (addtl && NULL == addtl->buf && 0 < addtl->len) ++ { ++ dbg (("DRBG: wrong format of additional information\n")); ++ return ret; ++ } ++ ++ /* 9.3.1 step 2 */ ++ if (buflen > (gcry_drbg_max_request_bytes ())) ++ { ++ dbg (("DRBG: requested random numbers too large %u\n", buflen)); ++ return ret; ++ } ++ /* 9.3.1 step 3 is implicit with the chosen DRBG */ ++ /* 9.3.1 step 4 */ ++ if (addtl && addtl->len > (gcry_drbg_max_addtl ())) ++ { ++ dbg (("DRBG: additional information string too long %lu\n", ++ addtl->len)); ++ return ret; ++ } ++ /* 9.3.1 step 5 is implicit with the chosen DRBG */ ++ /* 9.3.1 step 6 and 9 supplemented by 9.3.2 step c -- the spec is a ++ * bit convoluted here, we make it simpler */ ++ if ((gcry_drbg_max_requests ()) < drbg->reseed_ctr) ++ drbg->seeded = 0; ++ ++ if (drbg->pr || !drbg->seeded) ++ { ++ dbg (("DRBG: reseeding before generation (prediction resistance: %s, state %s)\n", drbg->pr ? "true" : "false", drbg->seeded ? "seeded" : "unseeded")); ++ /* 9.3.1 steps 7.1 through 7.3 */ ++ ret = gcry_drbg_seed (drbg, addtl, 1); ++ if (ret) ++ return ret; ++ /* 9.3.1 step 7.4 */ ++ addtl = NULL; ++ } ++ ++ if (addtl && addtl->buf) ++ { ++ dbg (("DRBG: using additional information string\n")); ++ } ++ ++ /* 9.3.1 step 8 and 10 */ ++ ret = drbg->d_ops->generate (drbg, buf, buflen, addtl); ++ ++ /* 10.1.1.4 step 6, 10.1.2.5 step 7, 10.2.1.5.2 step 7 */ ++ drbg->reseed_ctr++; ++ if (ret) ++ return ret; ++ ++ /* 11.3.3 -- re-perform self tests after some generated random ++ * numbers, the chosen value after which self test is performed ++ * is arbitrary, but it should be reasonable */ ++ /* Here we do not perform the self tests because of the following ++ * reasons: it is mathematically impossible that the initial self tests ++ * were successfully and the following are not. If the initial would ++ * pass and the following would not, the system integrity is violated. ++ * In this case, the entire system operation is questionable and it ++ * is unlikely that the integrity violation only affects to the ++ * correct operation of the DRBG. ++ */ ++#if 0 ++ if (drbg->reseed_ctr && !(drbg->reseed_ctr % 4096)) ++ { ++ dbg (("DRBG: start to perform self test\n")); ++ ret = gcry_drbg_healthcheck (); ++ if (ret) ++ { ++ log_fatal (("DRBG: self test failed\n")); ++ return ret; ++ } ++ else ++ { ++ dbg (("DRBG: self test successful\n")); ++ } ++ } ++#endif ++ ++ return ret; ++} ++ ++/* ++ * Wrapper around gcry_drbg_generate which can pull arbitrary long strings ++ * from the DRBG without hitting the maximum request limitation. ++ * ++ * Parameters: see gcry_drbg_generate ++ * Return codes: see gcry_drbg_generate -- if one gcry_drbg_generate request fails, ++ * the entire gcry_drbg_generate_long request fails ++ */ ++static gpg_err_code_t ++gcry_drbg_generate_long (struct gcry_drbg_state *drbg, ++ unsigned char *buf, unsigned int buflen, ++ struct gcry_drbg_string *addtl) ++{ ++ gpg_err_code_t ret = 0; ++ unsigned int slice = 0; ++ unsigned char *buf_p = buf; ++ unsigned len = 0; ++ do ++ { ++ unsigned int chunk = 0; ++ slice = ((buflen - len) / gcry_drbg_max_request_bytes ()); ++ chunk = slice ? gcry_drbg_max_request_bytes () : (buflen - len); ++ ret = gcry_drbg_generate (drbg, buf_p, chunk, addtl); ++ if (ret) ++ return ret; ++ buf_p += chunk; ++ len += chunk; ++ } ++ while (slice > 0 && (len < buflen)); ++ return ret; ++} ++ ++/* ++ * DRBG uninstantiate function as required by SP800-90A - this function ++ * frees all buffers and the DRBG handle ++ * ++ * @drbg DRBG state handle ++ * ++ * return ++ * 0 on success ++ */ ++static gpg_err_code_t ++gcry_drbg_uninstantiate (struct gcry_drbg_state *drbg) ++{ ++ if (!drbg) ++ return GPG_ERR_INV_ARG; ++ xfree (drbg->V); ++ drbg->V = NULL; ++ xfree (drbg->C); ++ drbg->C = NULL; ++ drbg->reseed_ctr = 0; ++ xfree (drbg->scratchpad); ++ drbg->scratchpad = NULL; ++ drbg->seeded = 0; ++ drbg->pr = 0; ++ drbg->fips_primed = 0; ++ xfree (drbg->prev); ++ drbg->prev = NULL; ++ drbg->seed_init_pid = 0; ++ return 0; ++} ++ ++/* ++ * DRBG instantiation function as required by SP800-90A - this function ++ * sets up the DRBG handle, performs the initial seeding and all sanity ++ * checks required by SP800-90A ++ * ++ * @drbg memory of state -- if NULL, new memory is allocated ++ * @pers Personalization string that is mixed into state, may be NULL -- note ++ * the entropy is pulled by the DRBG internally unconditionally ++ * as defined in SP800-90A. The additional input is mixed into ++ * the state in addition to the pulled entropy. ++ * @coreref reference to core ++ * @flags Flags defining the requested DRBG type and cipher type. The flags ++ * are defined in drbg.h and may be XORed. Beware, if you XOR multiple ++ * cipher types together, the code picks the core on a first come first ++ * serve basis as it iterates through the available cipher cores and ++ * uses the one with the first match. The minimum required flags are: ++ * cipher type flag ++ * ++ * return ++ * 0 on success ++ * error value otherwise ++ */ ++static gpg_err_code_t ++gcry_drbg_instantiate (struct gcry_drbg_state *drbg, ++ struct gcry_drbg_string *pers, int coreref, int pr) ++{ ++ gpg_err_code_t ret = GPG_ERR_ENOMEM; ++ unsigned int sb_size = 0; ++ ++ if (!drbg) ++ return GPG_ERR_INV_ARG; ++ ++ dbg (("DRBG: Initializing DRBG core %d with prediction resistance %s\n", ++ coreref, pr ? "enabled" : "disabled")); ++ drbg->core = &gcry_drbg_cores[coreref]; ++ drbg->pr = pr; ++ drbg->seeded = 0; ++ if (drbg->core->flags & GCRY_DRBG_HMAC) ++ drbg->d_ops = &gcry_drbg_hmac_ops; ++ else if (drbg->core->flags & GCRY_DRBG_HASH_MASK) ++ drbg->d_ops = &gcry_drbg_hash_ops; ++ else if (drbg->core->flags & GCRY_DRBG_CTR_MASK) ++ drbg->d_ops = &gcry_drbg_ctr_ops; ++ else ++ return GPG_ERR_GENERAL; ++ /* 9.1 step 1 is implicit with the selected DRBG type -- see ++ * gcry_drbg_sec_strength() */ ++ ++ /* 9.1 step 2 is implicit as caller can select prediction resistance ++ * and the flag is copied into drbg->flags -- ++ * all DRBG types support prediction resistance */ ++ ++ /* 9.1 step 4 is implicit in gcry_drbg_sec_strength */ ++ ++ /* no allocation of drbg as this is done by the kernel crypto API */ ++ drbg->V = xcalloc_secure (1, gcry_drbg_statelen (drbg)); ++ if (!drbg->V) ++ goto err; ++ drbg->C = xcalloc_secure (1, gcry_drbg_statelen (drbg)); ++ if (!drbg->C) ++ goto err; ++ drbg->prev = xcalloc_secure (1, gcry_drbg_blocklen (drbg)); ++ if (!drbg->prev) ++ goto err; ++ drbg->fips_primed = 0; ++ /* scratchpad is only generated for CTR and Hash */ ++ if (drbg->core->flags & GCRY_DRBG_HMAC) ++ sb_size = 0; ++ else if (drbg->core->flags & GCRY_DRBG_CTR_MASK) ++ sb_size = gcry_drbg_statelen (drbg) + gcry_drbg_blocklen (drbg) + /* temp */ ++ gcry_drbg_statelen (drbg) + /* df_data */ ++ gcry_drbg_blocklen (drbg) + /* pad */ ++ gcry_drbg_blocklen (drbg) + /* iv */ ++ gcry_drbg_statelen (drbg) + gcry_drbg_blocklen (drbg); /* temp */ ++ else ++ sb_size = gcry_drbg_statelen (drbg) + gcry_drbg_blocklen (drbg); ++ ++ if (0 < sb_size) ++ { ++ drbg->scratchpad = xcalloc_secure (1, sb_size); ++ if (!drbg->scratchpad) ++ goto err; ++ } ++ dbg (("DRBG: state allocated with scratchpad size %u bytes\n", sb_size)); ++ ++ /* 9.1 step 6 through 11 */ ++ ret = gcry_drbg_seed (drbg, pers, 0); ++ if (ret) ++ goto err; ++ ++ dbg (("DRBG: core %d %s prediction resistance successfully initialized\n", ++ coreref, pr ? "with" : "without")); ++ return 0; ++ ++err: ++ gcry_drbg_uninstantiate (drbg); ++ return ret; ++} ++ ++/* ++ * DRBG reseed function as required by SP800-90A ++ * ++ * @drbg DRBG state handle ++ * @addtl Additional input that is mixed into state, may be NULL -- note ++ * the entropy is pulled by the DRBG internally unconditionally ++ * as defined in SP800-90A. The additional input is mixed into ++ * the state in addition to the pulled entropy. ++ * ++ * return ++ * 0 on success ++ * error value otherwise ++ */ ++static gpg_err_code_t ++gcry_drbg_reseed (struct gcry_drbg_state *drbg, ++ struct gcry_drbg_string *addtl) ++{ ++ gpg_err_code_t ret = 0; ++ ret = gcry_drbg_seed (drbg, addtl, 1); ++ return ret; ++} ++ ++/****************************************************************** ++ ****************************************************************** ++ ****************************************************************** ++ * libgcrypt integration code ++ ****************************************************************** ++ ****************************************************************** ++ ******************************************************************/ ++ ++/*************************************************************** ++ * libgcrypt backend functions to the RNG API code ++ ***************************************************************/ ++ ++/* global state variable holding the current instance of the DRBG -- the ++ * default DRBG type is defined in _gcry_gcry_drbg_init */ ++static struct gcry_drbg_state *gcry_drbg = NULL; ++ ++/* This is the lock we use to serialize access to this RNG. */ ++static ath_mutex_t drbg_lock; ++ ++static inline void ++gcry_drbg_lock (void) ++{ ++ int my_errno; ++ ++ my_errno = ath_mutex_lock (&drbg_lock); ++ if (my_errno) ++ log_fatal ("failed to acquire the RNG lock: %s\n", strerror (my_errno)); ++} ++ ++static inline void ++gcry_drbg_unlock (void) ++{ ++ int my_errno; ++ ++ my_errno = ath_mutex_unlock (&drbg_lock); ++ if (my_errno) ++ log_fatal ("failed to release the RNG lock: %s\n", strerror (my_errno)); ++} ++ ++/* Basic initialization is required to initialize mutexes and ++ do a few checks on the implementation. */ ++static void ++basic_initialization (void) ++{ ++ static int initialized; ++ int my_errno; ++ ++ if (initialized) ++ return; ++ initialized = 1; ++ ++ my_errno = ath_mutex_init (&drbg_lock); ++ if (my_errno) ++ log_fatal ("failed to create the RNG lock: %s\n", strerror (my_errno)); ++} ++ ++/****** helper functions where lock must be held by caller *****/ ++ ++/* Check whether given flags are known to point to an applicable DRBG */ ++static gpg_err_code_t ++gcry_drbg_algo_available (u32 flags, int *coreref) ++{ ++ int i = 0; ++ for (i = 0; ARRAY_SIZE (gcry_drbg_cores) > i; i++) ++ { ++ if ((gcry_drbg_cores[i].flags & GCRY_DRBG_CIPHER_MASK) == ++ (flags & GCRY_DRBG_CIPHER_MASK)) ++ { ++ *coreref = i; ++ return 0; ++ } ++ } ++ return GPG_ERR_GENERAL; ++} ++ ++static gpg_err_code_t ++_gcry_drbg_init_internal (u32 flags, struct gcry_drbg_string *pers) ++{ ++ gpg_err_code_t ret = 0; ++ static u32 oldflags = 0; ++ int coreref = 0; ++ int pr = 0; ++ ++ /* If a caller provides 0 as flags, use the flags of the previous ++ * initialization, otherwise use the current flags and remember them ++ * for the next invocation ++ */ ++ if (0 == flags) ++ flags = oldflags; ++ else ++ oldflags = flags; ++ ++ ret = gcry_drbg_algo_available (flags, &coreref); ++ if (ret) ++ return ret; ++ ++ if (NULL != gcry_drbg) ++ { ++ gcry_drbg_uninstantiate (gcry_drbg); ++ } ++ else ++ { ++ gcry_drbg = xcalloc_secure (1, sizeof (struct gcry_drbg_state)); ++ if (!gcry_drbg) ++ return GPG_ERR_ENOMEM; ++ } ++ if (flags & GCRY_DRBG_PREDICTION_RESIST) ++ pr = 1; ++ ret = gcry_drbg_instantiate (gcry_drbg, pers, coreref, pr); ++ if (ret) ++ fips_signal_error ("DRBG cannot be initialized"); ++ else ++ gcry_drbg->seed_init_pid = getpid (); ++ return ret; ++} ++ ++/************* calls available to common RNG code **************/ ++ ++/* ++ * Initialize one DRBG invoked by the libgcrypt API ++ */ ++void ++_gcry_drbg_init (int full) ++{ ++ (void) full; /* ignore for now */ ++ /* default DRBG */ ++ u32 flags = GCRY_DRBG_NOPR_HMACSHA256; ++ basic_initialization (); ++ gcry_drbg_lock (); ++ _gcry_drbg_init_internal (flags, NULL); ++ gcry_drbg_unlock (); ++} ++ ++/* ++ * Backend handler function for GCRYCTL_DRBG_REINIT ++ * ++ * Select a different DRBG type and initialize it. ++ * Function checks whether requested DRBG type exists and returns an error in ++ * case it does not. In case of an error, the previous instantiated DRBG is ++ * left untouched and alive. Thus, in case of an error, a DRBG is always ++ * available, even if it is not the chosen one. ++ * ++ * Re-initialization will be performed in any case regardless whether flags ++ * or personalization string are set. ++ * ++ * If flags == 0, do not change current DRBG ++ * If personalization string is NULL or its length is 0, re-initialize without ++ * personalization string ++ */ ++gpg_err_code_t ++_gcry_drbg_reinit (u32 flags, struct gcry_drbg_string *pers) ++{ ++ gpg_err_code_t ret = GPG_ERR_GENERAL; ++ dbg (("DRBG: reinitialize internal DRBG state with flags %u\n", flags)); ++ gcry_drbg_lock (); ++ ret = _gcry_drbg_init_internal (flags, pers); ++ gcry_drbg_unlock (); ++ return ret; ++} ++ ++/* Print some statistics about the RNG. */ ++void ++_gcry_drbg_dump_stats (void) ++{ ++ /* Not yet implemented. */ ++ /* Maybe dumping of reseed counter? */ ++} ++ ++/* This function returns true if no real RNG is available or the ++ * quality of the RNG has been degraded for test purposes. */ ++int ++_gcry_drbg_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_drbg_add_bytes (const void *buf, size_t buflen, int quality) ++{ ++ gpg_err_code_t ret = 0; ++ struct gcry_drbg_string seed; ++ (void) quality; ++ if (NULL == gcry_drbg) ++ return GPG_ERR_GENERAL; ++ gcry_drbg_string_fill (&seed, (unsigned char *) buf, buflen); ++ gcry_drbg_lock (); ++ ret = gcry_drbg_reseed (gcry_drbg, &seed); ++ gcry_drbg_unlock (); ++ return ret; ++} ++ ++/* This function is to be used for all types of random numbers, including ++ * nonces ++ */ ++void ++_gcry_drbg_randomize (void *buffer, size_t length, ++ enum gcry_random_level level) ++{ ++ (void) level; ++ gcry_drbg_lock (); ++ if (NULL == gcry_drbg) ++ { ++ fips_signal_error ("DRBG is not initialized"); ++ goto bailout; ++ } ++ ++ /* As reseeding changes the entire state of the DRBG, including any ++ * key, either a re-init or a reseed is sufficient for a fork */ ++ if (gcry_drbg->seed_init_pid != getpid ()) ++ { ++ /* We are in a child of us. Perform a reseeding. */ ++ if (gcry_drbg_reseed (gcry_drbg, NULL)) ++ { ++ fips_signal_error ("reseeding upon fork failed"); ++ log_fatal ("severe error getting random\n"); ++ goto bailout; ++ } ++ gcry_drbg->seed_init_pid = getpid (); ++ } ++ /* potential integer overflow is covered by gcry_drbg_generate which ++ * ensures that length cannot overflow an unsigned int */ ++ if (0 < length) ++ { ++ if (!buffer) ++ goto bailout; ++ if (gcry_drbg_generate_long ++ (gcry_drbg, buffer, (unsigned int) length, NULL)) ++ log_fatal ("No random numbers generated\n"); ++ } ++ else ++ { ++ struct gcry_drbg_gen *data = (struct gcry_drbg_gen *) buffer; ++ /* catch NULL pointer */ ++ if (!data || !data->outbuf) ++ { ++ fips_signal_error ("No output buffer provided"); ++ goto bailout; ++ } ++ if (gcry_drbg_generate_long (gcry_drbg, data->outbuf, data->outlen, ++ data->addtl)) ++ log_fatal ("No random numbers generated\n"); ++ } ++bailout: ++ gcry_drbg_unlock (); ++ return; ++ ++} ++ ++/*************************************************************** ++ * Self-test code ++ ***************************************************************/ ++ ++/* ++ * Test vectors from ++ * http://csrc.nist.gov/groups/STM/cavp/documents/drbg/drbgtestvectors.zip ++ */ ++struct gcry_drbg_test_vector gcry_drbg_test_pr[] = { ++ { ++ .flags = (GCRY_DRBG_PR_HASHSHA256), ++ .entropy = (unsigned char *) ++ "\x5d\xf2\x14\xbc\xf6\xb5\x4e\x0b\xf0\x0d\x6f\x2d" ++ "\xe2\x01\x66\x7b\xd0\xa4\x73\xa4\x21\xdd\xb0\xc0" ++ "\x51\x79\x09\xf4\xea\xa9\x08\xfa\xa6\x67\xe0\xe1" ++ "\xd1\x88\xa8\xad\xee\x69\x74\xb3\x55\x06\x9b\xf6", ++ .entropylen = 48, ++ .entpra = (unsigned char *) ++ "\xef\x48\x06\xa2\xc2\x45\xf1\x44\xfa\x34\x2c\xeb" ++ "\x8d\x78\x3c\x09\x8f\x34\x72\x20\xf2\xe7\xfd\x13" ++ "\x76\x0a\xf6\xdc\x3c\xf5\xc0\x15", ++ .entprb = (unsigned char *) ++ "\x4b\xbe\xe5\x24\xed\x6a\x2d\x0c\xdb\x73\x5e\x09" ++ "\xf9\xad\x67\x7c\x51\x47\x8b\x6b\x30\x2a\xc6\xde" ++ "\x76\xaa\x55\x04\x8b\x0a\x72\x95", ++ .entprlen = 32, ++ .expected = (unsigned char *) ++ "\x3b\x14\x71\x99\xa1\xda\xa0\x42\xe6\xc8\x85\x32" ++ "\x70\x20\x32\x53\x9a\xbe\xd1\x1e\x15\xef\xfb\x4c" ++ "\x25\x6e\x19\x3a\xf0\xb9\xcb\xde\xf0\x3b\xc6\x18" ++ "\x4d\x85\x5a\x9b\xf1\xe3\xc2\x23\x03\x93\x08\xdb" ++ "\xa7\x07\x4b\x33\x78\x40\x4d\xeb\x24\xf5\x6e\x81" ++ "\x4a\x1b\x6e\xa3\x94\x52\x43\xb0\xaf\x2e\x21\xf4" ++ "\x42\x46\x8e\x90\xed\x34\x21\x75\xea\xda\x67\xb6" ++ "\xe4\xf6\xff\xc6\x31\x6c\x9a\x5a\xdb\xb3\x97\x13" ++ "\x09\xd3\x20\x98\x33\x2d\x6d\xd7\xb5\x6a\xa8\xa9" ++ "\x9a\x5b\xd6\x87\x52\xa1\x89\x2b\x4b\x9c\x64\x60" ++ "\x50\x47\xa3\x63\x81\x16\xaf\x19", ++ .expectedlen = 128, ++ .addtla = (unsigned char *) ++ "\xbe\x13\xdb\x2a\xe9\xa8\xfe\x09\x97\xe1\xce\x5d" ++ "\xe8\xbb\xc0\x7c\x4f\xcb\x62\x19\x3f\x0f\xd2\xad" ++ "\xa9\xd0\x1d\x59\x02\xc4\xff\x70", ++ .addtlb = (unsigned char *) ++ "\x6f\x96\x13\xe2\xa7\xf5\x6c\xfe\xdf\x66\xe3\x31" ++ "\x63\x76\xbf\x20\x27\x06\x49\xf1\xf3\x01\x77\x41" ++ "\x9f\xeb\xe4\x38\xfe\x67\x00\xcd", ++ .addtllen = 32, ++ .pers = NULL, ++ .perslen = 0, ++ }, ++ { ++ .flags = (GCRY_DRBG_PR_HMACSHA256), ++ .entropy = (unsigned char *) ++ "\x13\x54\x96\xfc\x1b\x7d\x28\xf3\x18\xc9\xa7\x89" ++ "\xb6\xb3\xc8\x72\xac\x00\xd4\x59\x36\x25\x05\xaf" ++ "\xa5\xdb\x96\xcb\x3c\x58\x46\x87\xa5\xaa\xbf\x20" ++ "\x3b\xfe\x23\x0e\xd1\xc7\x41\x0f\x3f\xc9\xb3\x67", ++ .entropylen = 48, ++ .entpra = (unsigned char *) ++ "\xe2\xbd\xb7\x48\x08\x06\xf3\xe1\x93\x3c\xac\x79" ++ "\xa7\x2b\x11\xda\xe3\x2e\xe1\x91\xa5\x02\x19\x57" ++ "\x20\x28\xad\xf2\x60\xd7\xcd\x45", ++ .entprb = (unsigned char *) ++ "\x8b\xd4\x69\xfc\xff\x59\x95\x95\xc6\x51\xde\x71" ++ "\x68\x5f\xfc\xf9\x4a\xab\xec\x5a\xcb\xbe\xd3\x66" ++ "\x1f\xfa\x74\xd3\xac\xa6\x74\x60", ++ .entprlen = 32, ++ .expected = (unsigned char *) ++ "\x1f\x9e\xaf\xe4\xd2\x46\xb7\x47\x41\x4c\x65\x99" ++ "\x01\xe9\x3b\xbb\x83\x0c\x0a\xb0\xc1\x3a\xe2\xb3" ++ "\x31\x4e\xeb\x93\x73\xee\x0b\x26\xc2\x63\xa5\x75" ++ "\x45\x99\xd4\x5c\x9f\xa1\xd4\x45\x87\x6b\x20\x61" ++ "\x40\xea\x78\xa5\x32\xdf\x9e\x66\x17\xaf\xb1\x88" ++ "\x9e\x2e\x23\xdd\xc1\xda\x13\x97\x88\xa5\xb6\x5e" ++ "\x90\x14\x4e\xef\x13\xab\x5c\xd9\x2c\x97\x9e\x7c" ++ "\xd7\xf8\xce\xea\x81\xf5\xcd\x71\x15\x49\x44\xce" ++ "\x83\xb6\x05\xfb\x7d\x30\xb5\x57\x2c\x31\x4f\xfc" ++ "\xfe\x80\xb6\xc0\x13\x0c\x5b\x9b\x2e\x8f\x3d\xfc" ++ "\xc2\xa3\x0c\x11\x1b\x80\x5f\xf3", ++ .expectedlen = 128, ++ .addtla = NULL, ++ .addtlb = NULL, ++ .addtllen = 0, ++ .pers = (unsigned char *) ++ "\x64\xb6\xfc\x60\xbc\x61\x76\x23\x6d\x3f\x4a\x0f" ++ "\xe1\xb4\xd5\x20\x9e\x70\xdd\x03\x53\x6d\xbf\xce" ++ "\xcd\x56\x80\xbc\xb8\x15\xc8\xaa", ++ .perslen = 32, ++ }, ++ { ++ .flags = (GCRY_DRBG_PR_CTRAES128), ++ .entropy = (unsigned char *) ++ "\x92\x89\x8f\x31\xfa\x1c\xff\x6d\x18\x2f\x26\x06" ++ "\x43\xdf\xf8\x18\xc2\xa4\xd9\x72\xc3\xb9\xb6\x97", ++ .entropylen = 24, ++ .entpra = (unsigned char *) ++ "\x20\x72\x8a\x06\xf8\x6f\x8d\xd4\x41\xe2\x72\xb7" ++ "\xc4\x2c\xe8\x10", ++ .entprb = (unsigned char *) ++ "\x3d\xb0\xf0\x94\xf3\x05\x50\x33\x17\x86\x3e\x22" ++ "\x08\xf7\xa5\x01", ++ .entprlen = 16, ++ .expected = (unsigned char *) ++ "\x5a\x35\x39\x87\x0f\x4d\x22\xa4\x09\x24\xee\x71" ++ "\xc9\x6f\xac\x72\x0a\xd6\xf0\x88\x82\xd0\x83\x28" ++ "\x73\xec\x3f\x93\xd8\xab\x45\x23\xf0\x7e\xac\x45" ++ "\x14\x5e\x93\x9f\xb1\xd6\x76\x43\x3d\xb6\xe8\x08" ++ "\x88\xf6\xda\x89\x08\x77\x42\xfe\x1a\xf4\x3f\xc4" ++ "\x23\xc5\x1f\x68", ++ .expectedlen = 64, ++ .addtla = (unsigned char *) ++ "\x1a\x40\xfa\xe3\xcc\x6c\x7c\xa0\xf8\xda\xba\x59" ++ "\x23\x6d\xad\x1d", ++ .addtlb = (unsigned char *) ++ "\x9f\x72\x76\x6c\xc7\x46\xe5\xed\x2e\x53\x20\x12" ++ "\xbc\x59\x31\x8c", ++ .addtllen = 16, ++ .pers = (unsigned char *) ++ "\xea\x65\xee\x60\x26\x4e\x7e\xb6\x0e\x82\x68\xc4" ++ "\x37\x3c\x5c\x0b", ++ .perslen = 16, ++ }, ++}; ++ ++struct gcry_drbg_test_vector gcry_drbg_test_nopr[] = { ++ { ++ .flags = GCRY_DRBG_NOPR_HASHSHA256, ++ .entropy = (unsigned char *) ++ "\x73\xd3\xfb\xa3\x94\x5f\x2b\x5f\xb9\x8f\xf6\x9c" ++ "\x8a\x93\x17\xae\x19\xc3\x4c\xc3\xd6\xca\xa3\x2d" ++ "\x16\xfc\x42\xd2\x2d\xd5\x6f\x56\xcc\x1d\x30\xff" ++ "\x9e\x06\x3e\x09\xce\x58\xe6\x9a\x35\xb3\xa6\x56", ++ .entropylen = 48, ++ .expected = (unsigned char *) ++ "\x71\x7b\x93\x46\x1a\x40\xaa\x35\xa4\xaa\xc5\xe7" ++ "\x6d\x5b\x5b\x8a\xa0\xdf\x39\x7d\xae\x71\x58\x5b" ++ "\x3c\x7c\xb4\xf0\x89\xfa\x4a\x8c\xa9\x5c\x54\xc0" ++ "\x40\xdf\xbc\xce\x26\x81\x34\xf8\xba\x7d\x1c\xe8" ++ "\xad\x21\xe0\x74\xcf\x48\x84\x30\x1f\xa1\xd5\x4f" ++ "\x81\x42\x2f\xf4\xdb\x0b\x23\xf8\x73\x27\xb8\x1d" ++ "\x42\xf8\x44\x58\xd8\x5b\x29\x27\x0a\xf8\x69\x59" ++ "\xb5\x78\x44\xeb\x9e\xe0\x68\x6f\x42\x9a\xb0\x5b" ++ "\xe0\x4e\xcb\x6a\xaa\xe2\xd2\xd5\x33\x25\x3e\xe0" ++ "\x6c\xc7\x6a\x07\xa5\x03\x83\x9f\xe2\x8b\xd1\x1c" ++ "\x70\xa8\x07\x59\x97\xeb\xf6\xbe", ++ .expectedlen = 128, ++ .addtla = (unsigned char *) ++ "\xf4\xd5\x98\x3d\xa8\xfc\xfa\x37\xb7\x54\x67\x73" ++ "\xc7\xc3\xdd\x47\x34\x71\x02\x5d\xc1\xa0\xd3\x10" ++ "\xc1\x8b\xbd\xf5\x66\x34\x6f\xdd", ++ .addtlb = (unsigned char *) ++ "\xf7\x9e\x6a\x56\x0e\x73\xe9\xd9\x7a\xd1\x69\xe0" ++ "\x6f\x8c\x55\x1c\x44\xd1\xce\x6f\x28\xcc\xa4\x4d" ++ "\xa8\xc0\x85\xd1\x5a\x0c\x59\x40", ++ .addtllen = 32, ++ .pers = NULL, ++ .perslen = 0, ++ }, ++ { ++ .flags = GCRY_DRBG_NOPR_HMACSHA256, ++ .entropy = (unsigned char *) ++ "\x8d\xf0\x13\xb4\xd1\x03\x52\x30\x73\x91\x7d\xdf" ++ "\x6a\x86\x97\x93\x05\x9e\x99\x43\xfc\x86\x54\x54" ++ "\x9e\x7a\xb2\x2f\x7c\x29\xf1\x22\xda\x26\x25\xaf" ++ "\x2d\xdd\x4a\xbc\xce\x3c\xf4\xfa\x46\x59\xd8\x4e", ++ .entropylen = 48, ++ .expected = (unsigned char *) ++ "\xb9\x1c\xba\x4c\xc8\x4f\xa2\x5d\xf8\x61\x0b\x81" ++ "\xb6\x41\x40\x27\x68\xa2\x09\x72\x34\x93\x2e\x37" ++ "\xd5\x90\xb1\x15\x4c\xbd\x23\xf9\x74\x52\xe3\x10" ++ "\xe2\x91\xc4\x51\x46\x14\x7f\x0d\xa2\xd8\x17\x61" ++ "\xfe\x90\xfb\xa6\x4f\x94\x41\x9c\x0f\x66\x2b\x28" ++ "\xc1\xed\x94\xda\x48\x7b\xb7\xe7\x3e\xec\x79\x8f" ++ "\xbc\xf9\x81\xb7\x91\xd1\xbe\x4f\x17\x7a\x89\x07" ++ "\xaa\x3c\x40\x16\x43\xa5\xb6\x2b\x87\xb8\x9d\x66" ++ "\xb3\xa6\x0e\x40\xd4\xa8\xe4\xe9\xd8\x2a\xf6\xd2" ++ "\x70\x0e\x6f\x53\x5c\xdb\x51\xf7\x5c\x32\x17\x29" ++ "\x10\x37\x41\x03\x0c\xcc\x3a\x56", ++ .expectedlen = 128, ++ .addtla = NULL, ++ .addtlb = NULL, ++ .addtllen = 0, ++ .pers = (unsigned char *) ++ "\xb5\x71\xe6\x6d\x7c\x33\x8b\xc0\x7b\x76\xad\x37" ++ "\x57\xbb\x2f\x94\x52\xbf\x7e\x07\x43\x7a\xe8\x58" ++ "\x1c\xe7\xbc\x7c\x3a\xc6\x51\xa9", ++ .perslen = 32, ++ }, ++ { ++ .flags = GCRY_DRBG_NOPR_CTRAES128, ++ .entropy = (unsigned char *) ++ "\xc0\x70\x1f\x92\x50\x75\x8f\xcd\xf2\xbe\x73\x98" ++ "\x80\xdb\x66\xeb\x14\x68\xb4\xa5\x87\x9c\x2d\xa6", ++ .entropylen = 24, ++ .expected = (unsigned char *) ++ "\x97\xc0\xc0\xe5\xa0\xcc\xf2\x4f\x33\x63\x48\x8a" ++ "\xdb\x13\x0a\x35\x89\xbf\x80\x65\x62\xee\x13\x95" ++ "\x7c\x33\xd3\x7d\xf4\x07\x77\x7a\x2b\x65\x0b\x5f" ++ "\x45\x5c\x13\xf1\x90\x77\x7f\xc5\x04\x3f\xcc\x1a" ++ "\x38\xf8\xcd\x1b\xbb\xd5\x57\xd1\x4a\x4c\x2e\x8a" ++ "\x2b\x49\x1e\x5c", ++ .expectedlen = 64, ++ .addtla = (unsigned char *) ++ "\xf9\x01\xf8\x16\x7a\x1d\xff\xde\x8e\x3c\x83\xe2" ++ "\x44\x85\xe7\xfe", ++ .addtlb = (unsigned char *) ++ "\x17\x1c\x09\x38\xc2\x38\x9f\x97\x87\x60\x55\xb4" ++ "\x82\x16\x62\x7f", ++ .addtllen = 16, ++ .pers = (unsigned char *) ++ "\x80\x08\xae\xe8\xe9\x69\x40\xc5\x08\x73\xc7\x9f" ++ "\x8e\xcf\xe0\x02", ++ .perslen = 16, ++ }, ++}; ++ ++ ++/* ++ * Tests implement the CAVS test approach as documented in ++ * http://csrc.nist.gov/groups/STM/cavp/documents/drbg/DRBGVS.pdf ++ */ ++ ++/* ++ * CAVS test ++ * ++ * This function is not static as it is needed for as a private API ++ * call for the CAVS test tool. ++ */ ++gpg_err_code_t ++gcry_drbg_cavs_test (struct gcry_drbg_test_vector *test, unsigned char *buf) ++{ ++ gpg_err_code_t ret = 0; ++ struct gcry_drbg_state *drbg = NULL; ++ struct gcry_drbg_test_data test_data; ++ struct gcry_drbg_string addtl, pers, testentropy; ++ int coreref = 0; ++ int pr = 0; ++ ++ ret = gcry_drbg_algo_available (test->flags, &coreref); ++ if (ret) ++ goto outbuf; ++ ++ drbg = gcry_xcalloc (1, sizeof (struct gcry_drbg_state)); ++ if (!drbg) ++ { ++ ret = GPG_ERR_ENOMEM; ++ goto outbuf; ++ } ++ ++ if (test->flags & GCRY_DRBG_PREDICTION_RESIST) ++ pr = 1; ++ ++ test_data.testentropy = &testentropy; ++ gcry_drbg_string_fill (&testentropy, test->entropy, test->entropylen); ++ drbg->test_data = &test_data; ++ gcry_drbg_string_fill (&pers, test->pers, test->perslen); ++ ret = gcry_drbg_instantiate (drbg, &pers, coreref, pr); ++ if (ret) ++ goto outbuf; ++ ++ gcry_drbg_string_fill (&addtl, test->addtla, test->addtllen); ++ if (test->entpra) ++ { ++ gcry_drbg_string_fill (&testentropy, test->entpra, test->entprlen); ++ drbg->test_data = &test_data; ++ } ++ gcry_drbg_generate_long (drbg, buf, test->expectedlen, &addtl); ++ ++ gcry_drbg_string_fill (&addtl, test->addtlb, test->addtllen); ++ if (test->entprb) ++ { ++ gcry_drbg_string_fill (&testentropy, test->entprb, test->entprlen); ++ drbg->test_data = &test_data; ++ } ++ gcry_drbg_generate_long (drbg, buf, test->expectedlen, &addtl); ++ gcry_drbg_uninstantiate (drbg); ++ ++outbuf: ++ xfree (drbg); ++ return ret; ++} ++ ++/* ++ * Invoke the CAVS test and perform the final check whether the ++ * calculated random value matches the expected one. ++ * ++ * This function is not static as it is needed for as a private API ++ * call for the CAVS test tool. ++ */ ++gpg_err_code_t ++gcry_drbg_healthcheck_one (struct gcry_drbg_test_vector * test) ++{ ++ gpg_err_code_t ret = GPG_ERR_ENOMEM; ++ unsigned char *buf = gcry_xcalloc (1, test->expectedlen); ++ if (!buf) ++ return GPG_ERR_ENOMEM; ++ ++ ret = gcry_drbg_cavs_test (test, buf); ++ ret = memcmp (test->expected, buf, test->expectedlen); ++ ++ xfree (buf); ++ return ret; ++} ++ ++/* ++ * Tests as defined in 11.3.2 in addition to the cipher tests: testing ++ * of the error handling. ++ * ++ * Note, testing the reseed counter is not done as an automatic reseeding ++ * is performed in gcry_drbg_generate when the reseed counter is too large. ++ */ ++static gpg_err_code_t ++gcry_drbg_healthcheck_sanity (struct gcry_drbg_test_vector *test) ++{ ++ unsigned int len = 0; ++ struct gcry_drbg_state *drbg = NULL; ++ gpg_err_code_t ret = GPG_ERR_GENERAL; ++ gpg_err_code_t tmpret = GPG_ERR_GENERAL; ++ struct gcry_drbg_test_data test_data; ++ struct gcry_drbg_string addtl, testentropy; ++ int coreref = 0; ++ unsigned char *buf = NULL; ++ size_t max_addtllen, max_request_bytes; ++ ++ /* only perform test in FIPS mode */ ++ if (0 == fips_mode ()) ++ return 0; ++ ++ buf = gcry_xcalloc (1, test->expectedlen); ++ if (!buf) ++ return GPG_ERR_ENOMEM; ++ tmpret = gcry_drbg_algo_available (test->flags, &coreref); ++ if (tmpret) ++ goto outbuf; ++ drbg = gcry_xcalloc (1, sizeof (struct gcry_drbg_state)); ++ if (!drbg) ++ goto outbuf; ++ ++ /* if the following tests fail, it is likely that there is a buffer ++ * overflow and we get a SIGSEV */ ++ ret = gcry_drbg_instantiate (drbg, NULL, coreref, 1); ++ if (ret) ++ goto outbuf; ++ max_addtllen = gcry_drbg_max_addtl (); ++ max_request_bytes = gcry_drbg_max_request_bytes (); ++ /* overflow addtllen with additonal info string */ ++ gcry_drbg_string_fill (&addtl, test->addtla, (max_addtllen + 1)); ++ len = gcry_drbg_generate (drbg, buf, test->expectedlen, &addtl); ++ if (len) ++ goto outdrbg; ++ ++ /* overflow max_bits */ ++ len = gcry_drbg_generate (drbg, buf, (max_request_bytes + 1), NULL); ++ if (len) ++ goto outdrbg; ++ gcry_drbg_uninstantiate (drbg); ++ ++ /* test failing entropy source as defined in 11.3.2 */ ++ test_data.testentropy = NULL; ++ test_data.fail_seed_source = 1; ++ drbg->test_data = &test_data; ++ tmpret = gcry_drbg_instantiate (drbg, NULL, coreref, 0); ++ if (!tmpret) ++ goto outdrbg; ++ test_data.fail_seed_source = 0; ++ ++ test_data.testentropy = &testentropy; ++ gcry_drbg_string_fill (&testentropy, test->entropy, test->entropylen); ++ /* overflow max addtllen with personalization string */ ++ tmpret = gcry_drbg_instantiate (drbg, &addtl, coreref, 0); ++ if (!tmpret) ++ goto outdrbg; ++ ++ dbg (("DRBG: Sanity tests for failure code paths successfully completed\n")); ++ ret = 0; ++ ++outdrbg: ++ gcry_drbg_uninstantiate (drbg); ++outbuf: ++ xfree (buf); ++ xfree (drbg); ++ return ret; ++} ++ ++/* ++ * DRBG Healthcheck function as required in SP800-90A ++ * ++ * return: ++ * 0 on success (all tests pass) ++ * >0 on error (return code indicate the number of failures) ++ */ ++static int ++gcry_drbg_healthcheck (void) ++{ ++ int ret = 0; ++ ret += gcry_drbg_healthcheck_one (&gcry_drbg_test_nopr[0]); ++ ret += gcry_drbg_healthcheck_one (&gcry_drbg_test_nopr[1]); ++ ret += gcry_drbg_healthcheck_one (&gcry_drbg_test_nopr[2]); ++ ret += gcry_drbg_healthcheck_one (&gcry_drbg_test_pr[0]); ++ ret += gcry_drbg_healthcheck_one (&gcry_drbg_test_pr[1]); ++ ret += gcry_drbg_healthcheck_one (&gcry_drbg_test_pr[2]); ++ ret += gcry_drbg_healthcheck_sanity (&gcry_drbg_test_nopr[0]); ++ return ret; ++} ++ ++/* Run the self-tests. */ ++gcry_error_t ++_gcry_drbg_selftest (selftest_report_func_t report) ++{ ++ gcry_err_code_t ec; ++ const char *errtxt = NULL; ++ gcry_drbg_lock (); ++ if (0 != gcry_drbg_healthcheck ()) ++ errtxt = "RNG output does not match known value"; ++ gcry_drbg_unlock (); ++ if (report && errtxt) ++ report ("random", 0, "KAT", errtxt); ++ ec = errtxt ? GPG_ERR_SELFTEST_FAILED : 0; ++ return gpg_error (ec); ++} ++ ++/*************************************************************** ++ * Cipher invocations requested by DRBG ++ ***************************************************************/ ++ ++static gpg_err_code_t ++gcry_drbg_hmac (struct gcry_drbg_state *drbg, const unsigned char *key, ++ unsigned char *outval, const struct gcry_drbg_string *buf) ++{ ++ gpg_error_t err; ++ gcry_md_hd_t hd; ++ ++ if (key) ++ { ++ err = ++ _gcry_md_open (&hd, drbg->core->backend_cipher, GCRY_MD_FLAG_HMAC); ++ if (err) ++ return err; ++ err = _gcry_md_setkey (hd, key, gcry_drbg_statelen (drbg)); ++ if (err) ++ return err; ++ } ++ else ++ { ++ err = _gcry_md_open (&hd, drbg->core->backend_cipher, 0); ++ if (err) ++ return err; ++ } ++ for (; NULL != buf; buf = buf->next) ++ _gcry_md_write (hd, buf->buf, buf->len); ++ gcry_md_final (hd); ++ memcpy (outval, _gcry_md_read (hd, drbg->core->backend_cipher), ++ gcry_drbg_blocklen (drbg)); ++ _gcry_md_close (hd); ++ return 0; ++} ++ ++static gpg_err_code_t ++gcry_drbg_sym (struct gcry_drbg_state *drbg, const unsigned char *key, ++ unsigned char *outval, const struct gcry_drbg_string *buf) ++{ ++ gpg_error_t err; ++ gcry_cipher_hd_t hd; ++ ++ if (gcry_drbg_blocklen (drbg) != ++ _gcry_cipher_get_algo_blklen (drbg->core->backend_cipher)) ++ return -GPG_ERR_NO_ERROR; ++ if (gcry_drbg_blocklen (drbg) < buf->len) ++ return -GPG_ERR_NO_ERROR; ++ err = ++ _gcry_cipher_open (&hd, drbg->core->backend_cipher, GCRY_CIPHER_MODE_ECB, ++ 0); ++ if (err) ++ return err; ++ err = _gcry_cipher_setkey (hd, key, gcry_drbg_keylen (drbg)); ++ if (err) ++ { ++ _gcry_cipher_close (hd); ++ return err; ++ } ++ /* in is only component */ ++ _gcry_cipher_encrypt (hd, outval, gcry_drbg_blocklen (drbg), buf->buf, ++ buf->len); ++ _gcry_cipher_close (hd); ++ return 0; ++} +diff -up libgcrypt-1.5.3/random/Makefile.am.drbg libgcrypt-1.5.3/random/Makefile.am +--- libgcrypt-1.5.3/random/Makefile.am.drbg 2013-07-25 11:10:04.000000000 +0200 ++++ libgcrypt-1.5.3/random/Makefile.am 2014-09-26 17:00:16.051215890 +0200 +@@ -35,6 +35,7 @@ random.c random.h \ + rand-internal.h \ + random-csprng.c \ + random-fips.c \ ++drbg.c \ + rndhw.c + + if USE_RANDOM_DAEMON +diff -up libgcrypt-1.5.3/random/Makefile.in.drbg libgcrypt-1.5.3/random/Makefile.in +--- libgcrypt-1.5.3/random/Makefile.in.drbg 2013-07-25 11:22:44.000000000 +0200 ++++ libgcrypt-1.5.3/random/Makefile.in 2014-09-26 17:00:16.051215890 +0200 +@@ -91,10 +91,10 @@ CONFIG_CLEAN_VPATH_FILES = + LTLIBRARIES = $(noinst_LTLIBRARIES) + am__DEPENDENCIES_1 = + am__librandom_la_SOURCES_DIST = random.c random.h rand-internal.h \ +- random-csprng.c random-fips.c rndhw.c random-daemon.c ++ random-csprng.c random-fips.c drbg.c rndhw.c random-daemon.c + @USE_RANDOM_DAEMON_TRUE@am__objects_1 = random-daemon.lo + am_librandom_la_OBJECTS = random.lo random-csprng.lo random-fips.lo \ +- rndhw.lo $(am__objects_1) ++ drbg.lo rndhw.lo $(am__objects_1) + librandom_la_OBJECTS = $(am_librandom_la_OBJECTS) + DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) + depcomp = $(SHELL) $(top_srcdir)/depcomp +@@ -283,7 +283,7 @@ GCRYPT_MODULES = @GCRYPT_RANDOM@ + librandom_la_DEPENDENCIES = $(GCRYPT_MODULES) + librandom_la_LIBADD = $(GCRYPT_MODULES) + librandom_la_SOURCES = random.c random.h rand-internal.h \ +- random-csprng.c random-fips.c rndhw.c $(am__append_1) ++ random-csprng.c random-fips.c drbg.c rndhw.c $(am__append_1) + EXTRA_librandom_la_SOURCES = \ + rndlinux.c \ + rndegd.c \ +@@ -346,6 +346,7 @@ distclean-compile: + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/random-csprng.Plo@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/random-daemon.Plo@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/random-fips.Plo@am__quote@ ++@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/drbg.Plo@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/random.Plo@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rndegd.Plo@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rndhw.Plo@am__quote@ +diff -up libgcrypt-1.5.3/random/rand-internal.h.drbg libgcrypt-1.5.3/random/rand-internal.h +--- libgcrypt-1.5.3/random/rand-internal.h.drbg 2013-07-25 11:10:04.000000000 +0200 ++++ libgcrypt-1.5.3/random/rand-internal.h 2014-09-26 17:00:16.051215890 +0200 +@@ -91,6 +91,15 @@ gcry_err_code_t _gcry_rngfips_run_extern + char *buffer, size_t buflen); + void _gcry_rngfips_deinit_external_test (void *context); + ++/* drbg-gcry.h */ ++void _gcry_drbg_init(int full); ++void _gcry_drbg_close_fds(void); ++void _gcry_drbg_dump_stats(void); ++int _gcry_drbg_is_faked (void); ++gcry_error_t _gcry_drbg_add_bytes (const void *buf, size_t buflen, int quality); ++void _gcry_drbg_randomize (void *buffer, size_t length, ++ enum gcry_random_level level); ++gcry_error_t _gcry_drbg_selftest (selftest_report_func_t report); + + + +diff -up libgcrypt-1.5.3/random/random.c.drbg libgcrypt-1.5.3/random/random.c +--- libgcrypt-1.5.3/random/random.c.drbg 2013-07-25 11:10:04.000000000 +0200 ++++ libgcrypt-1.5.3/random/random.c 2014-09-26 17:00:16.051215890 +0200 +@@ -76,7 +76,7 @@ void + _gcry_random_initialize (int full) + { + if (fips_mode ()) +- _gcry_rngfips_initialize (full); ++ _gcry_drbg_init (full); + else + _gcry_rngcsprng_initialize (full); + } +@@ -86,7 +86,7 @@ void + _gcry_random_dump_stats (void) + { + if (fips_mode ()) +- _gcry_rngfips_dump_stats (); ++ _gcry_drbg_dump_stats (); + else + _gcry_rngcsprng_dump_stats (); + } +@@ -145,7 +145,7 @@ int + _gcry_random_is_faked (void) + { + if (fips_mode ()) +- return _gcry_rngfips_is_faked (); ++ return _gcry_drbg_is_faked (); + else + return _gcry_rngcsprng_is_faked (); + } +@@ -169,7 +169,7 @@ static void + do_randomize (void *buffer, size_t length, enum gcry_random_level level) + { + if (fips_mode ()) +- _gcry_rngfips_randomize (buffer, length, level); ++ _gcry_drbg_randomize (buffer, length, level); + else + _gcry_rngcsprng_randomize (buffer, length, level); + } +@@ -266,7 +266,7 @@ void + gcry_create_nonce (void *buffer, size_t length) + { + if (fips_mode ()) +- _gcry_rngfips_create_nonce (buffer, length); ++ _gcry_drbg_randomize (buffer, length, GCRY_WEAK_RANDOM); + else + _gcry_rngcsprng_create_nonce (buffer, length); + } +@@ -278,7 +278,7 @@ gpg_error_t + _gcry_random_selftest (selftest_report_func_t report) + { + if (fips_mode ()) +- return _gcry_rngfips_selftest (report); ++ return _gcry_drbg_selftest (report); + else + return 0; /* No selftests yet. */ + } +@@ -294,13 +294,7 @@ _gcry_random_init_external_test (void ** + const void *seed, size_t seedlen, + const void *dt, size_t dtlen) + { +- (void)flags; +- if (fips_mode ()) +- return _gcry_rngfips_init_external_test (r_context, flags, key, keylen, +- seed, seedlen, +- dt, dtlen); +- else +- return GPG_ERR_NOT_SUPPORTED; ++ return GPG_ERR_NOT_SUPPORTED; + } + + /* Get BUFLEN bytes from the RNG using the test CONTEXT and store them +@@ -308,16 +302,12 @@ _gcry_random_init_external_test (void ** + gcry_err_code_t + _gcry_random_run_external_test (void *context, char *buffer, size_t buflen) + { +- if (fips_mode ()) +- return _gcry_rngfips_run_external_test (context, buffer, buflen); +- else +- return GPG_ERR_NOT_SUPPORTED; ++ return GPG_ERR_NOT_SUPPORTED; + } + + /* Release the test CONTEXT. */ + void + _gcry_random_deinit_external_test (void *context) + { +- if (fips_mode ()) +- _gcry_rngfips_deinit_external_test (context); ++ return; + } +diff -up libgcrypt-1.5.3/random/random.h.drbg libgcrypt-1.5.3/random/random.h +--- libgcrypt-1.5.3/random/random.h.drbg 2013-07-25 11:10:04.000000000 +0200 ++++ libgcrypt-1.5.3/random/random.h 2014-09-26 17:00:16.051215890 +0200 +@@ -51,7 +51,29 @@ gcry_err_code_t _gcry_random_run_externa + char *buffer, size_t buflen); + void _gcry_random_deinit_external_test (void *context); + ++/*-- drbg.c --*/ ++gpg_err_code_t _gcry_drbg_reinit (u32 flags, struct gcry_drbg_string *pers); ++/* private interfaces for testing of DRBG */ ++struct gcry_drbg_test_vector ++{ ++ u32 flags; ++ unsigned char *entropy; ++ size_t entropylen; ++ unsigned char *entpra; ++ unsigned char *entprb; ++ size_t entprlen; ++ unsigned char *addtla; ++ unsigned char *addtlb; ++ size_t addtllen; ++ unsigned char *pers; ++ size_t perslen; ++ unsigned char *expected; ++ size_t expectedlen; ++}; + ++gpg_err_code_t gcry_drbg_cavs_test (struct gcry_drbg_test_vector *test, ++ unsigned char *buf); ++gpg_err_code_t gcry_drbg_healthcheck_one (struct gcry_drbg_test_vector *test); + /*-- rndegd.c --*/ + gpg_error_t _gcry_rndegd_set_socket_name (const char *name); + +diff -up libgcrypt-1.5.3/src/gcrypt.h.in.drbg libgcrypt-1.5.3/src/gcrypt.h.in +--- libgcrypt-1.5.3/src/gcrypt.h.in.drbg 2013-07-25 11:10:04.000000000 +0200 ++++ libgcrypt-1.5.3/src/gcrypt.h.in 2014-09-26 17:16:30.965224999 +0200 +@@ -423,7 +423,9 @@ enum gcry_ctl_cmds + GCRYCTL_SELFTEST = 57, + /* Note: 58 .. 62 are used internally. */ + GCRYCTL_DISABLE_HWF = 63, +- GCRYCTL_SET_ENFORCED_FIPS_FLAG = 64 ++ GCRYCTL_SET_ENFORCED_FIPS_FLAG = 64, ++ GCRYCTL_DRBG_REINIT = 74 ++ /* Note: 75 is used internally */ + }; + + /* Perform various operations defined by CMD. */ +@@ -1907,6 +1909,109 @@ int gcry_is_secure (const void *a) _GCRY + /* Return true if Libgcrypt is in FIPS mode. */ + #define gcry_fips_mode_active() !!gcry_control (GCRYCTL_FIPS_MODE_P, 0) + ++/* DRBG input data structure for DRBG generate with additional information ++ * string */ ++struct gcry_drbg_gen { ++ unsigned char *outbuf; /* output buffer for random numbers */ ++ unsigned int outlen; /* size of output buffer */ ++ struct gcry_drbg_string *addtl; /* input buffer for ++ * additional information string */ ++}; ++ ++/* ++ * Concatenation Helper and string operation helper ++ * ++ * SP800-90A requires the concatenation of different data. To avoid copying ++ * buffers around or allocate additional memory, the following data structure ++ * is used to point to the original memory with its size. In addition, it ++ * is used to build a linked list. The linked list defines the concatenation ++ * of individual buffers. The order of memory block referenced in that ++ * linked list determines the order of concatenation. ++ */ ++/* DRBG string definition */ ++struct gcry_drbg_string { ++ const unsigned char *buf; ++ size_t len; ++ struct gcry_drbg_string *next; ++}; ++ ++#define gcry_drbg_string_fill(s, b, l) \ ++do { \ ++ (s)->buf = (b); \ ++ (s)->len = (l); \ ++ (s)->next = NULL; \ ++} while (0) ++ ++/* this is a wrapper function for users of libgcrypt */ ++#define gcry_randomize_drbg(ob, ol, lvl, add) \ ++do { \ ++ struct gcry_drbg_gen genbuf; \ ++ genbuf.outbuf = (unsigned char *)(ob); \ ++ genbuf.outlen = (ol); \ ++ genbuf.addtl = (add); \ ++ gcry_randomize(&genbuf, 0, (lvl)); \ ++} while (0) ++ ++/* ++ * DRBG flags bitmasks ++ * ++ * 31 (B) 28 19 (A) 0 ++ * +-+-+-+--------+---+-----------+-----+ ++ * |~|~|u|~~~~~~~~| 3 | 2 | 1 | ++ * +-+-+-+--------+- -+-----------+-----+ ++ * ctl flg| |drbg use selection flags ++ * ++ */ ++ ++/* internal state control flags (B) */ ++#define GCRY_DRBG_PREDICTION_RESIST ((u_int32_t)1<<28) ++ ++/* CTR type modifiers (A.1)*/ ++#define GCRY_DRBG_CTRAES ((u_int32_t)1<<0) ++#define GCRY_DRBG_CTRSERPENT ((u_int32_t)1<<1) ++#define GCRY_DRBG_CTRTWOFISH ((u_int32_t)1<<2) ++#define GCRY_DRBG_CTR_MASK (GCRY_DRBG_CTRAES | GCRY_DRBG_CTRSERPENT | GCRY_DRBG_CTRTWOFISH) ++ ++/* HASH type modifiers (A.2)*/ ++#define GCRY_DRBG_HASHSHA1 ((u_int32_t)1<<4) ++#define GCRY_DRBG_HASHSHA224 ((u_int32_t)1<<5) ++#define GCRY_DRBG_HASHSHA256 ((u_int32_t)1<<6) ++#define GCRY_DRBG_HASHSHA384 ((u_int32_t)1<<7) ++#define GCRY_DRBG_HASHSHA512 ((u_int32_t)1<<8) ++#define GCRY_DRBG_HASH_MASK (GCRY_DRBG_HASHSHA1 | GCRY_DRBG_HASHSHA224 | \ ++ GCRY_DRBG_HASHSHA256 | GCRY_DRBG_HASHSHA384 | \ ++ GCRY_DRBG_HASHSHA512) ++/* type modifiers (A.3)*/ ++#define GCRY_DRBG_HMAC ((u_int32_t)1<<12) ++#define GCRY_DRBG_SYM128 ((u_int32_t)1<<13) ++#define GCRY_DRBG_SYM192 ((u_int32_t)1<<14) ++#define GCRY_DRBG_SYM256 ((u_int32_t)1<<15) ++#define GCRY_DRBG_TYPE_MASK (GCRY_DRBG_HMAC | GCRY_DRBG_SYM128 | GCRY_DRBG_SYM192 | \ ++ GCRY_DRBG_SYM256) ++#define GCRY_DRBG_CIPHER_MASK (GCRY_DRBG_CTR_MASK | GCRY_DRBG_HASH_MASK | GCRY_DRBG_TYPE_MASK) ++ ++#define GCRY_DRBG_PR_CTRAES128 (GCRY_DRBG_PREDICTION_RESIST | GCRY_DRBG_CTRAES | GCRY_DRBG_SYM128) ++#define GCRY_DRBG_PR_CTRAES192 (GCRY_DRBG_PREDICTION_RESIST | GCRY_DRBG_CTRAES | GCRY_DRBG_SYM192) ++#define GCRY_DRBG_PR_CTRAES256 (GCRY_DRBG_PREDICTION_RESIST | GCRY_DRBG_CTRAES | GCRY_DRBG_SYM256) ++#define GCRY_DRBG_NOPR_CTRAES128 (GCRY_DRBG_CTRAES | GCRY_DRBG_SYM128) ++#define GCRY_DRBG_NOPR_CTRAES192 (GCRY_DRBG_CTRAES | GCRY_DRBG_SYM192) ++#define GCRY_DRBG_NOPR_CTRAES256 (GCRY_DRBG_CTRAES | GCRY_DRBG_SYM256) ++#define GCRY_DRBG_PR_HASHSHA1 (GCRY_DRBG_PREDICTION_RESIST | GCRY_DRBG_HASHSHA1) ++#define GCRY_DRBG_PR_HASHSHA256 (GCRY_DRBG_PREDICTION_RESIST | GCRY_DRBG_HASHSHA256) ++#define GCRY_DRBG_PR_HASHSHA384 (GCRY_DRBG_PREDICTION_RESIST | GCRY_DRBG_HASHSHA384) ++#define GCRY_DRBG_PR_HASHSHA512 (GCRY_DRBG_PREDICTION_RESIST | GCRY_DRBG_HASHSHA512) ++#define GCRY_DRBG_NOPR_HASHSHA1 (GCRY_DRBG_HASHSHA1) ++#define GCRY_DRBG_NOPR_HASHSHA256 (GCRY_DRBG_HASHSHA256) ++#define GCRY_DRBG_NOPR_HASHSHA384 (GCRY_DRBG_HASHSHA384) ++#define GCRY_DRBG_NOPR_HASHSHA512 (GCRY_DRBG_HASHSHA512) ++#define GCRY_DRBG_PR_HMACSHA1 (GCRY_DRBG_PREDICTION_RESIST | GCRY_DRBG_HASHSHA1 | GCRY_DRBG_HMAC) ++#define GCRY_DRBG_PR_HMACSHA256 (GCRY_DRBG_PREDICTION_RESIST | GCRY_DRBG_HASHSHA256 | GCRY_DRBG_HMAC) ++#define GCRY_DRBG_PR_HMACSHA384 (GCRY_DRBG_PREDICTION_RESIST | GCRY_DRBG_HASHSHA384 | GCRY_DRBG_HMAC) ++#define GCRY_DRBG_PR_HMACSHA512 (GCRY_DRBG_PREDICTION_RESIST | GCRY_DRBG_HASHSHA512 | GCRY_DRBG_HMAC) ++#define GCRY_DRBG_NOPR_HMACSHA1 (GCRY_DRBG_HASHSHA1 | GCRY_DRBG_HMAC) ++#define GCRY_DRBG_NOPR_HMACSHA256 (GCRY_DRBG_HASHSHA256 | GCRY_DRBG_HMAC) ++#define GCRY_DRBG_NOPR_HMACSHA384 (GCRY_DRBG_HASHSHA384 | GCRY_DRBG_HMAC) ++#define DRBG_NOPR_HMACSHA512 (GCRY_DRBG_HASHSHA512 | GCRY_DRBG_HMAC) + + /* Include support for Libgcrypt modules. */ + #include +diff -up libgcrypt-1.5.3/src/global.c.drbg libgcrypt-1.5.3/src/global.c +--- libgcrypt-1.5.3/src/global.c.drbg 2013-07-25 11:10:04.000000000 +0200 ++++ libgcrypt-1.5.3/src/global.c 2014-09-26 17:00:16.052215913 +0200 +@@ -609,6 +609,28 @@ _gcry_vcontrol (enum gcry_ctl_cmds cmd, + err = GPG_ERR_GENERAL; + break; + ++ case GCRYCTL_DRBG_REINIT: ++ { ++ u32 flags = va_arg (arg_ptr, u32); ++ struct gcry_drbg_string *pers = va_arg (arg_ptr, ++ struct gcry_drbg_string *); ++ err = _gcry_drbg_reinit(flags, pers); ++ } ++ break; ++ ++ case 75: ++ { ++ struct gcry_drbg_test_vector *test = ++ va_arg (arg_ptr, struct gcry_drbg_test_vector *); ++ unsigned char *buf = va_arg (arg_ptr, unsigned char *); ++ ++ if (buf) ++ err = gcry_drbg_cavs_test (test, buf); ++ else ++ err = gcry_drbg_healthcheck_one (test); ++ } ++ break; ++ + default: + err = GPG_ERR_INV_OP; + } diff --git a/SOURCES/libgcrypt-1.5.3-fips-cavs.patch b/SOURCES/libgcrypt-1.5.3-fips-cavs.patch new file mode 100644 index 0000000..5cbe8b8 --- /dev/null +++ b/SOURCES/libgcrypt-1.5.3-fips-cavs.patch @@ -0,0 +1,1451 @@ +diff -up libgcrypt-1.5.3/cipher/dsa.c.cavs libgcrypt-1.5.3/cipher/dsa.c +--- libgcrypt-1.5.3/cipher/dsa.c.cavs 2014-09-26 17:45:38.429674771 +0200 ++++ libgcrypt-1.5.3/cipher/dsa.c 2014-09-26 17:45:38.433674862 +0200 +@@ -479,7 +479,6 @@ generate_fips186 (DSA_secret_key *sk, un + initial_seed.seed = gcry_sexp_nth_data (initial_seed.sexp, 1, + &initial_seed.seedlen); + } +- + if (use_fips186_2) + ec = _gcry_generate_fips186_2_prime (nbits, qbits, + initial_seed.seed, +@@ -487,13 +486,22 @@ generate_fips186 (DSA_secret_key *sk, un + &prime_q, &prime_p, + r_counter, + r_seed, r_seedlen); +- else ++ else if (!domain->p || !domain->q) + ec = _gcry_generate_fips186_3_prime (nbits, qbits, + initial_seed.seed, + initial_seed.seedlen, + &prime_q, &prime_p, + r_counter, + r_seed, r_seedlen, NULL); ++ else ++ { ++ /* Domain parameters p and q are given; use them. */ ++ prime_p = mpi_copy (domain->p); ++ prime_q = mpi_copy (domain->q); ++ gcry_assert (mpi_get_nbits (prime_p) == nbits); ++ gcry_assert (mpi_get_nbits (prime_q) == qbits); ++ ec = 0; ++ } + gcry_sexp_release (initial_seed.sexp); + if (ec) + goto leave; +@@ -784,13 +792,12 @@ dsa_generate_ext (int algo, unsigned int + gcry_sexp_release (l1); + gcry_sexp_release (domainsexp); + +- /* Check that all domain parameters are available. */ +- if (!domain.p || !domain.q || !domain.g) ++ /* Check that p and q domain parameters are available. */ ++ if (!domain.p || !domain.q || (!domain.g && !use_fips186)) + { + gcry_mpi_release (domain.p); + gcry_mpi_release (domain.q); + gcry_mpi_release (domain.g); +- gcry_sexp_release (deriveparms); + return GPG_ERR_MISSING_VALUE; + } + +diff -up libgcrypt-1.5.3/tests/cavs_driver.pl.cavs libgcrypt-1.5.3/tests/cavs_driver.pl +--- libgcrypt-1.5.3/tests/cavs_driver.pl.cavs 2013-05-22 18:02:55.000000000 +0200 ++++ libgcrypt-1.5.3/tests/cavs_driver.pl 2014-10-21 09:38:34.250691408 +0200 +@@ -1,9 +1,11 @@ + #!/usr/bin/env perl + # +-# $Id: cavs_driver.pl 1497 2009-01-22 14:01:29Z smueller $ ++# $Id: cavs_driver.pl 2124 2010-12-20 07:56:30Z smueller $ + # + # CAVS test driver (based on the OpenSSL driver) + # Written by: Stephan Müller ++# Werner Koch (libgcrypt interface) ++# Tomas Mraz (addition of DSA2) + # Copyright (c) atsec information security corporation + # + # Permission is hereby granted, free of charge, to any person obtaining a copy +@@ -85,13 +87,16 @@ + # T[CBC|CFB??|ECB|OFB]varkey + # T[CBC|CFB??|ECB|OFB]invperm + # T[CBC|CFB??|ECB|OFB]vartext ++# WARNING: TDES in CFB and OFB mode problems see below + # + # ANSI X9.31 RNG + # ANSI931_AES128MCT + # ANSI931_AES128VST + # +-# DSA ++# DSA2 + # PQGGen ++# PQGVer ++# KeyPair + # SigGen + # SigVer + # +@@ -101,6 +106,36 @@ + # RC4PltBD + # RC4REGT + # ++# ++# TDES MCT for CFB and OFB: ++# ------------------------- ++# The inner loop cannot be handled by this script. If you want to have tests ++# for these cipher types, implement your own inner loop and add it to ++# crypto_mct. ++# ++# the value $next_source in crypto_mct is NOT set by the standard implementation ++# of this script. It would need to be set as follows for these two (code take ++# from fipsdrv.c from libgcrypt - the value input at the end will contain the ++# the value for $next_source: ++# ++# ... inner loop ... ++# ... ++# get_current_iv (hd, last_iv, blocklen); ++# ... encrypt / decrypt (input is the data to be en/decrypted and output is the ++# result of operation) ... ++# if (encrypt_mode && (cipher_mode == GCRY_CIPHER_MODE_CFB)) ++# memcpy (input, last_iv, blocklen); ++# else if (cipher_mode == GCRY_CIPHER_MODE_OFB) ++# memcpy (input, last_iv, blocklen); ++# else if (!encrypt_mode && cipher_mode == GCRY_CIPHER_MODE_CFB) ++# { ++# /* Reconstruct the output vector. */ ++# int i; ++# for (i=0; i < blocklen; i++) ++# input[i] ^= output[i]; ++# } ++# ... inner loop ends ... ++# ==> now, the value of input is to be put into $next_source + + use strict; + use warnings; +@@ -226,6 +261,8 @@ my $hmac; + # Generate the P, Q, G, Seed, counter, h (value used to generate g) values + # for DSA + # $1: modulus size ++# $2: q size ++# $3: seed (might be empty string) + # return: string with the calculated values in hex format, where each value + # is separated from the previous with a \n in the following order: + # P\n +@@ -236,6 +273,19 @@ my $hmac; + # h + my $dsa_pqggen; + ++# Generate the G value from P and Q ++# for DSA ++# $1: modulus size ++# $2: q size ++# $3: P in hex form ++# $4: Q in hex form ++# return: string with the calculated values in hex format, where each value ++# is separated from the previous with a \n in the following order: ++# P\n ++# Q\n ++# G\n ++my $dsa_ggen; ++ + # + # Generate an DSA public key from the provided parameters: + # $1: Name of file to create +@@ -255,16 +305,30 @@ my $dsa_verify; + + # generate a new DSA key with the following properties: + # PEM format +-# $1 keyfile name +-# return: file created, hash with keys of P, Q, G in hex format ++# $1: modulus size ++# $2: q size ++# $3 keyfile name ++# return: file created with key, string with values of P, Q, G in hex format + my $gen_dsakey; + ++# generate a new DSA private key XY parameters in domain: ++# PEM format ++# $1: P in hex form ++# $2: Q in hex form ++# $3: G in hex form ++# return: string with values of X, Y in hex format ++my $gen_dsakey_domain; ++ + # Sign a message with DSA + # $1: data to be signed in hex form + # $2: Key file in PEM format with the private key + # return: hash of digest information in hex format with Y, R, S as keys + my $dsa_sign; + ++my $rsa_keygen; ++ ++my $rsa_keygen_kat; ++ + ################################################################ + ##### OpenSSL interface functions + ################################################################ +@@ -404,6 +468,35 @@ sub libgcrypt_rsa_derive($$$$$$$$) { + } + + ++sub libgcrypt_rsa_keygen($) { ++ my $n = shift; ++ my $sexp; ++ ++ $n = sprintf ("%u", $n); ++ $sexp = "(genkey(rsa(nbits " . sprintf ("%u:%s", length($n), $n) . ")))\n"; ++ ++ return pipe_through_program($sexp, "fipsdrv rsa-keygen"); ++} ++ ++ ++sub libgcrypt_rsa_keygen_kat($$$$) { ++ my $n = shift; ++ my $e = shift; ++ my $p = shift; ++ my $q = shift; ++ my $sexp; ++ ++ $n = sprintf ("%u", $n); ++ $sexp = "(genkey(rsa(nbits " . sprintf ("%u:%s", length($n), $n) . ")" ++ . "(test-parms" ++ . "(e #$e#)" ++ . "(p #$p#)" ++ . "(q #$q#))))\n"; ++ ++ return pipe_through_program($sexp, "fipsdrv rsa-keygen-kat"); ++} ++ ++ + sub libgcrypt_rsa_sign($$$) { + my $data = shift; + my $hashalgo = shift; +@@ -500,17 +593,32 @@ sub libgcrypt_hmac($$$$) { + return pipe_through_program($msg, $program); + } + +-sub libgcrypt_dsa_pqggen($) { ++sub libgcrypt_dsa_pqggen($$$) { ++ my $mod = shift; ++ my $qsize = shift; ++ my $seed = shift; ++ ++ my $program = "fipsdrv --keysize $mod --qsize $qsize dsa-pqg-gen"; ++ return pipe_through_program($seed, $program); ++} ++ ++sub libgcrypt_dsa_ggen($$$$) { + my $mod = shift; ++ my $qsize = shift; ++ my $p = shift; ++ my $q = shift; ++ my $domain = "(domain (p #$p#)(q #$q#))"; + +- my $program = "fipsdrv --keysize $mod dsa-pqg-gen"; ++ my $program = "fipsdrv --keysize $mod --qsize $qsize --key \'$domain\' dsa-g-gen"; + return pipe_through_program("", $program); + } + +-sub libgcrypt_gen_dsakey($) { ++sub libgcrypt_gen_dsakey($$$) { ++ my $mod = shift; ++ my $qsize = shift; + my $file = shift; + +- my $program = "fipsdrv --keysize 1024 --key $file dsa-gen"; ++ my $program = "fipsdrv --keysize $mod --qsize $qsize --key $file dsa-gen"; + my $tmp; + my %ret; + +@@ -519,10 +627,21 @@ sub libgcrypt_gen_dsakey($) { + $tmp = pipe_through_program("", $program); + die "dsa key gen failed: file $file not created" if (! -f $file); + +- @ret{'P', 'Q', 'G', 'Seed', 'c', 'H'} = split(/\n/, $tmp); ++ @ret{'P', 'Q', 'G'} = split(/\n/, $tmp); + return %ret; + } + ++sub libgcrypt_gen_dsakey_domain($$$) { ++ my $p = shift; ++ my $q = shift; ++ my $g = shift; ++ my $domain = "(domain (p #$p#)(q #$q#)(g #$g#))"; ++ ++ my $program = "fipsdrv --key '$domain' dsa-gen-key"; ++ ++ return pipe_through_program("", $program); ++} ++ + sub libgcrypt_dsa_genpubkey($$$$$) { + my $filename = shift; + my $p = shift; +@@ -1139,7 +1258,7 @@ sub hmac_kat($$$$) { + $out .= "Tlen = $tlen\n"; + $out .= "Key = $key\n"; + $out .= "Msg = $msg\n"; +- $out .= "Mac = " . &$hmac($key, $tlen, $msg, $hashtype{$tlen}) . "\n"; ++ $out .= "Mac = " . lc(&$hmac($key, $tlen, $msg, $hashtype{$tlen})) . "\n"; + + return $out; + } +@@ -1205,7 +1324,7 @@ sub crypto_mct($$$$$$$$) { + } + my ($CO, $CI); + my $cipher_imp = &$state_cipher($cipher, $enc, $bufsize, $key1, $iv); +- $cipher_imp = &$state_cipher_des($cipher, $enc, $bufsize, $key1, $iv) if($cipher =~ /des/); ++ $cipher_imp = &$state_cipher_des($cipher, $enc, $bufsize, $key1, $iv) if($cipher =~ /des/ && defined($state_cipher_des)); + my $pid = open2($CO, $CI, $cipher_imp); + + my $calc_data = $iv; # CT[j] +@@ -1213,8 +1332,8 @@ sub crypto_mct($$$$$$$$) { + my $old_old_calc_data; # CT[j-2] + my $next_source; + +- # TDES inner loop implements logic within driver +- if ($cipher =~ /des/) { ++ # TDES inner loop implements logic within driver of libgcrypt ++ if ($cipher =~ /des/ && $opt{'I'} && $opt{'I'} eq 'libgcrypt' ) { + # Need to provide a dummy IV in case of ECB mode. + my $iv_arg = (defined($iv) && $iv ne "") + ? bin2hex($iv) +@@ -1238,6 +1357,10 @@ sub crypto_mct($$$$$$$$) { + $line = <$CO>; + } else { + for (my $j = 0; $j < $iloop; ++$j) { ++ if ($cipher =~ /des-ede3-ofb/ || ++ (!$enc && $cipher =~ /des-ede3-cfb/)) { ++ die "Implementation lacks support for TDES OFB and TDES CFB in encryption mode - the problem is that we would need to extract the IV of the last round of encryption which would be the input for the next round - see comments in this script for implementation requirements"; ++ } + $old_old_calc_data = $old_calc_data; + $old_calc_data = $calc_data; + +@@ -1429,7 +1552,7 @@ sub rsa_sigver($$$$$) { + # $7 xq2 + # $8 Xq + # return: string formatted as expected by CAVS +-sub rsa_keygen($$$$$$$$) { ++sub rsa_keygen_x931($$$$$$$$) { + my $modulus = shift; + my $e = shift; + my $xp1 = shift; +@@ -1503,21 +1626,23 @@ sub rngx931($$$$) { + return $out; + } + +-# DSA PQGGen test ++# DSA PQGen test + # $1 modulus size +-# $2 number of rounds to perform the test ++# $2 q size ++# $3 number of rounds to perform the test + # return: string formatted as expected by CAVS +-sub dsa_pqggen_driver($$) { ++sub dsa_pqgen_driver($$$) { + my $mod = shift; ++ my $qsize = shift; + my $rounds = shift; + + my $out = ""; + for(my $i=0; $i<$rounds; $i++) { +- my $ret = &$dsa_pqggen($mod); ++ my $ret = &$dsa_pqggen($mod, $qsize, ""); + my ($P, $Q, $G, $Seed, $c, $H) = split(/\n/, $ret); +- die "Return value does not contain all expected values of P, Q, G, Seed, c, H for dsa_pqggen" +- if (!defined($P) || !defined($Q) || !defined($G) || +- !defined($Seed) || !defined($c) || !defined($H)); ++ die "Return value does not contain all expected values of P, Q, Seed, c for dsa_pqggen" ++ if (!defined($P) || !defined($Q) || ++ !defined($Seed) || !defined($c)); + + # now change the counter to decimal as CAVS wants decimal + # counter value although all other is HEX +@@ -1525,15 +1650,166 @@ sub dsa_pqggen_driver($$) { + + $out .= "P = $P\n"; + $out .= "Q = $Q\n"; +- $out .= "G = $G\n"; +- $out .= "Seed = $Seed\n"; +- $out .= "c = $c\n"; +- $out .= "H = $H\n\n"; ++ $out .= "domain_parameter_seed = $Seed\n"; ++ $out .= "counter = $c\n\n"; + } + + return $out; + } + ++# DSA GGen test ++# $1 modulus size ++# $2 q size ++# $3 p in hex form ++# $4 q in hex form ++# return: string formatted as expected by CAVS ++sub dsa_ggen_driver($$$$) { ++ my $mod = shift; ++ my $qsize = shift; ++ my $p = shift; ++ my $q = shift; ++ ++ my $out = ""; ++ my $ret = &$dsa_ggen($mod, $qsize, $p, $q); ++ my ($P, $Q, $G) = split(/\n/, $ret); ++ die "Return value does not contain all expected values of P, Q, G for dsa_ggen" ++ if (!defined($P) || !defined($Q) || !defined($G)); ++ ++ $out .= "G = $G\n\n"; ++ ++ return $out; ++} ++ ++sub hexcomp($$) { ++ my $a = lc shift; ++ my $b = lc shift; ++ ++ if (length $a < length $b) { ++ my $c = $a; ++ $a = $b; ++ $b = $a; ++ } ++ ++ while (length $b < length $a) { ++ $b = "00$b"; ++ } ++ ++ return $a eq $b; ++} ++ ++# DSA PQVer test ++# $1 modulus size ++# $2 q size ++# $3 p in hex form ++# $4 q in hex form ++# $5 seed in hex form ++# $6 c decimal counter ++# return: string formatted as expected by CAVS ++sub dsa_pqver_driver($$$$$$) { ++ my $mod = shift; ++ my $qsize = shift; ++ my $p = shift; ++ my $q = shift; ++ my $seed = shift; ++ my $c = shift; ++ ++ my $out = ""; ++ my $ret = &$dsa_pqggen($mod, $qsize, $seed); ++ my ($P, $Q, $G, $seed2, $c2, $h2) = split(/\n/, $ret); ++ die "Return value does not contain all expected values of P, Q, G, seed, c for dsa_pqggen" ++ if (!defined($P) || !defined($Q) || !defined($G) || ++ !defined($seed2) || !defined($c2)); ++ ++ $c2 = hex($c2); ++ ++ $out .= "Seed = $seed\n"; ++ $out .= "c = $c\n"; ++ ++ if (hexcomp($P, $p) && hexcomp($Q, $q) && hexcomp($seed, $seed2) && $c == $c2) { ++ $out .= "Result = P\n\n"; ++ } ++ else { ++ $out .= "Result = F\n\n"; ++ } ++ return $out; ++} ++ ++# DSA PQGVer test ++# $1 modulus size ++# $2 q size ++# $3 p in hex form ++# $4 q in hex form ++# $5 g in hex form ++# $6 seed in hex form ++# $7 c decimal counter ++# $8 h in hex form ++# return: string formatted as expected by CAVS ++sub dsa_pqgver_driver($$$$$$$$) { ++ my $mod = shift; ++ my $qsize = shift; ++ my $p = shift; ++ my $q = shift; ++ my $g = shift; ++ my $seed = shift; ++ my $c = shift; ++ my $h = shift; ++ ++ my $out = ""; ++ my $ret = &$dsa_pqggen($mod, $qsize, $seed); ++ my ($P, $Q, $G, $seed2, $c2, $h2) = split(/\n/, $ret); ++ die "Return value does not contain all expected values of P, Q, G, seed, c, H for dsa_pqggen" ++ if (!defined($P) || !defined($Q) || !defined($G) || ++ !defined($seed2) || !defined($c2) || !defined($h2)); ++ ++ ++ ++ $out .= "Seed = $seed\n"; ++ $out .= "c = $c\n"; ++ $out .= "H = $h\n"; ++ ++ $c2 = hex($c2); ++ ++ if (hexcomp($P, $p) && hexcomp($Q, $q) && hexcomp($G, $g) && hexcomp($seed, $seed2) && ++ $c == $c2 && hex($h) == hex($h2)) { ++ $out .= "Result = P\n\n"; ++ } ++ else { ++ $out .= "Result = F\n\n"; ++ } ++ ++ return $out; ++} ++ ++# DSA Keypair test ++# $1 modulus size ++# $2 q size ++# $3 number of rounds to perform the test ++# return: string formatted as expected by CAVS ++sub dsa_keypair_driver($$$) { ++ my $mod = shift; ++ my $qsize = shift; ++ my $rounds = shift; ++ ++ my $out = ""; ++ my $tmpkeyfile = "dsa_siggen.tmp.$$"; ++ my %pqg = &$gen_dsakey($mod, $qsize, $tmpkeyfile); ++ $out .= "P = " . $pqg{'P'} . "\n"; ++ $out .= "Q = " . $pqg{'Q'} . "\n"; ++ $out .= "G = " . $pqg{'G'} . "\n\n"; ++ unlink($tmpkeyfile); ++ ++ for(my $i=0; $i<$rounds; $i++) { ++ my $ret = &$gen_dsakey_domain($pqg{'P'}, $pqg{'Q'}, $pqg{'G'}); ++ my ($X, $Y) = split(/\n/, $ret); ++ die "Return value does not contain all expected values of X, Y for gen_dsakey_domain" ++ if (!defined($X) || !defined($Y)); ++ ++ $out .= "X = $X\n"; ++ $out .= "Y = $Y\n\n"; ++ } ++ ++ return $out; ++} + + # DSA SigGen test + # $1: Message to be signed in hex form +@@ -1598,6 +1874,53 @@ sub dsa_sigver($$$$$$$$) { + return $out; + } + ++# RSA Keygen RPP test ++# $1 modulus size ++# $2 number of rounds to perform the test ++# return: string formatted as expected by CAVS ++sub rsa_keygen_driver($$) { ++ my $mod = shift; ++ my $rounds = shift; ++ ++ my $out = ""; ++ ++ for(my $i=0; $i<$rounds; $i++) { ++ my $ret = &$rsa_keygen($mod); ++ my ($e, $p, $q, $n, $d) = split(/\n/, $ret); ++ die "Return value does not contain all expected values of e, p, q, n, d for rsa_keygen" ++ if (!defined($e) || !defined($p) || !defined($q) || !defined($n) || !defined($d)); ++ ++ $out .= "e = $e\n"; ++ $out .= "p = $p\n"; ++ $out .= "q = $q\n"; ++ $out .= "n = $n\n"; ++ $out .= "d = $d\n\n"; ++ } ++ ++ return $out; ++} ++ ++# RSA RPP Keygen KAT test ++# $1 modulus size ++# $2 p in hex form ++# $3 q in hex form ++# return: string formatted as expected by CAVS ++sub rsa_keygen_kat_driver($$$) { ++ my $mod = shift; ++ my $p = shift; ++ my $q = shift; ++ ++ my $out = ""; ++ my $ret = &$rsa_keygen_kat($mod, $p, $q); ++ my ($Result) = split(/\n/, $ret); ++ die "Return value does not contain all expected values of Result for rsa_keygen_kat" ++ if (!defined($Result)); ++ ++ $out .= "Result = $Result\n\n"; ++ return $out; ++} ++ ++ + ############################################################## + # Parser of input file and generator of result file + # +@@ -1658,12 +1981,18 @@ sub parse($$) { + my $klen = ""; + my $tlen = ""; + my $modulus = ""; ++ my $qsize = ""; + my $capital_n = 0; ++ my $num = 0; + my $capital_p = ""; + my $capital_q = ""; + my $capital_g = ""; + my $capital_y = ""; + my $capital_r = ""; ++ my $capital_h = ""; ++ my $c = ""; ++ my $prandom = ""; ++ my $qrandom = ""; + my $xp1 = ""; + my $xp2 = ""; + my $Xp = ""; +@@ -1700,7 +2029,7 @@ sub parse($$) { + + ##### Extract cipher + # XXX there may be more - to be added +- if ($tmpline =~ /^#.*(CBC|ECB|OFB|CFB|SHA-|SigGen|SigVer|RC4VS|ANSI X9\.31|Hash sizes tested|PQGGen|KeyGen RSA)/) { ++ if ($tmpline =~ /^#.*(CBC|ECB|OFB|CFB|SHA-|SigGen|SigVer|RC4VS|ANSI X9\.31|Hash sizes tested|PQGGen|KeyGen RSA|KeyGen - Random Probably Prime|KeyPair|PQGVer)/) { + if ($tmpline =~ /CBC/) { $mode="cbc"; } + elsif ($tmpline =~ /ECB/) { $mode="ecb"; } + elsif ($tmpline =~ /OFB/) { $mode="ofb"; } +@@ -1749,7 +2078,23 @@ sub parse($$) { + + if ($tt == 0) { + ##### Identify the test type +- if ($tmpline =~ /KeyGen RSA \(X9\.31\)/) { ++ if ($tmpline =~ /KeyGen - Random Probably Prime Known Answer Test/) { ++ $tt = 19; ++ die "Interface function rsa_keygen_kat for RSA key generation KAT not defined for tested library" ++ if (!defined($rsa_keygen_kat)); ++ } elsif ($tmpline =~ /KeyGen - Random Probably Prime Test/) { ++ $tt = 18; ++ die "Interface function rsa_keygen for RSA key generation not defined for tested library" ++ if (!defined($rsa_keygen)); ++ } elsif ($tmpline =~ /PQGVer/) { ++ $tt = 16; ++ die "Interface function for DSA PQGVer testing not defined for tested library" ++ if (!defined($dsa_pqggen)); ++ } elsif ($tmpline =~ /KeyPair/) { ++ $tt = 14; ++ die "Interface function dsa_keygen for DSA key generation not defined for tested library" ++ if (!defined($gen_dsakey_domain)); ++ } elsif ($tmpline =~ /KeyGen RSA \(X9\.31\)/) { + $tt = 13; + die "Interface function rsa_derive for RSA key generation not defined for tested library" + if (!defined($rsa_derive)); +@@ -1760,11 +2105,11 @@ sub parse($$) { + } elsif ($tmpline =~ /SigGen/ && $opt{'D'}) { + $tt = 11; + die "Interface function dsa_sign or gen_dsakey for DSA sign not defined for tested library" +- if (!defined($dsa_sign) || !defined($gen_rsakey)); ++ if (!defined($dsa_sign) || !defined($gen_dsakey)); + } elsif ($tmpline =~ /PQGGen/) { + $tt = 10; + die "Interface function for DSA PQGGen testing not defined for tested library" +- if (!defined($dsa_pqggen)); ++ if (!defined($dsa_pqggen) || !defined($dsa_ggen)); + } elsif ($tmpline =~ /Hash sizes tested/) { + $tt = 9; + die "Interface function hmac for HMAC testing not defined for tested library" +@@ -1792,7 +2137,7 @@ sub parse($$) { + } elsif ($tmpline =~ /Monte|MCT|Carlo/) { + $tt = 2; + die "Interface function state_cipher for Stateful Cipher operation defined for tested library" +- if (!defined($state_cipher) || !defined($state_cipher_des)); ++ if (!defined($state_cipher) && !defined($state_cipher_des)); + } elsif ($cipher =~ /^sha/) { + $tt = 3; + die "Interface function hash for Hashing not defined for tested library" +@@ -1875,18 +2220,44 @@ sub parse($$) { + die "Msg/Seed seen twice - input file crap" if ($pt ne ""); + $pt=$2; + } +- elsif ($line =~ /^\[mod\s*=\s*(.*)\]$/) { # found in RSA requests ++ elsif ($line =~ /^\[A.2.1\s.*\]$/) { # found in DSA2 PQGGen request ++ $out .= $line . "\n"; # print it ++ if ($tt == 10) { ++ # now generate G from PQ ++ $tt = 15; ++ } ++ } ++ elsif ($line =~ /^\[A.2.2\s.*\]$/) { # found in DSA2 PQGVer request ++ $out .= $line . "\n"; # print it ++ if ($tt == 16) { ++ # now verify PQG ++ $tt = 17; ++ } ++ } ++ elsif ($line =~ /^\[mod\s*=\s*L=([0-9]*),\s*N=([0-9]*).*\]$/) { # found in DSA2 requests + $modulus = $1; ++ $qsize = $2; + $out .= $line . "\n\n"; # print it ++ # clear eventual PQG ++ $capital_p = ""; ++ $capital_q = ""; ++ $capital_g = ""; + # generate the private key with given bit length now + # as we have the required key length in bit + if ($tt == 11) { + $dsa_keyfile = "dsa_siggen.tmp.$$"; +- my %pqg = &$gen_dsakey($dsa_keyfile); ++ my %pqg = &$gen_dsakey($modulus, $qsize, $dsa_keyfile); + $out .= "P = " . $pqg{'P'} . "\n"; + $out .= "Q = " . $pqg{'Q'} . "\n"; +- $out .= "G = " . $pqg{'G'} . "\n"; +- } elsif ( $tt == 5 ) { ++ $out .= "G = " . $pqg{'G'} . "\n\n"; ++ } ++ } ++ elsif ($line =~ /^\[mod\s*=\s*(.*)\]$/) { # found in RSA requests ++ $modulus = $1; ++ $out .= $line . "\n\n"; # print it ++ # generate the private key with given bit length now ++ # as we have the required key length in bit ++ if ( $tt == 5 ) { + # XXX maybe a secure temp file name is better here + # but since it is not run on a security sensitive + # system, I hope that this is fine +@@ -1907,6 +2278,9 @@ sub parse($$) { + } + elsif ($line =~ /^e\s*=\s*(.*)/) { # found in RSA requests + $e=$1; ++ if ($tt == 19) { ++ $out .= $line . "\n"; # print it ++ } + } + elsif ($line =~ /^S\s*=\s*(.*)/) { # found in RSA requests + die "S seen twice - input file crap" if ($signature ne ""); +@@ -1932,11 +2306,16 @@ sub parse($$) { + if ($tlen ne ""); + $tlen=$1; + } +- elsif ($line =~ /^N\s*=\s*(.*)/) { #DSA PQGGen ++ elsif ($line =~ /^N\s*=\s*(.*)/) { #DSA KeyPair + die "N seen twice - check input file" + if ($capital_n); + $capital_n = $1; + } ++ elsif ($line =~ /^Num\s*=\s*(.*)/) { #DSA PQGGen ++ die "Num seen twice - check input file" ++ if ($num); ++ $num = $1; ++ } + elsif ($line =~ /^P\s*=\s*(.*)/) { #DSA SigVer + die "P seen twice - check input file" + if ($capital_p); +@@ -1965,6 +2344,16 @@ sub parse($$) { + if ($capital_r); + $capital_r = $1; + } ++ elsif ($line =~ /^H\s*=\s*(.*)/) { #DSA PQGVer ++ die "H seen twice - check input file" ++ if ($capital_h); ++ $capital_h = $1; ++ } ++ elsif ($line =~ /^c\s*=\s*(.*)/) { #DSA PQGVer ++ die "c seen twice - check input file" ++ if ($c); ++ $c = $1; ++ } + elsif ($line =~ /^xp1\s*=\s*(.*)/) { #RSA key gen + die "xp1 seen twice - check input file" + if ($xp1); +@@ -1995,6 +2384,22 @@ sub parse($$) { + if ($Xq); + $Xq = $1; + } ++ elsif ($line =~ /^prandom\s*=\s*(.*)/) { #RSA key gen KAT ++ die "prandom seen twice - check input file" ++ if ($prandom); ++ $prandom = $1; ++ $out .= $line . "\n"; # print it ++ } ++ elsif ($line =~ /^qrandom\s*=\s*(.*)/) { #RSA key gen KAT ++ die "qrandom seen twice - check input file" ++ if ($qrandom); ++ $qrandom = $1; ++ $out .= $line . "\n"; # print it ++ } ++ elsif ($tt == 19 && $line =~ /^ / && $qrandom eq "") { #RSA key gen KAT ++ $qrandom = "00"; ++ $out .= $line . "\n"; # print it ++ } + else { + $out .= $line . "\n"; + } +@@ -2074,11 +2479,10 @@ sub parse($$) { + } + } + elsif ($tt == 10) { +- if ($modulus ne "" && $capital_n > 0) { +- $out .= dsa_pqggen_driver($modulus, $capital_n); +- #$mod is not resetted +- $capital_n = 0; +- } ++ if ($modulus ne "" && $qsize ne "" && $num > 0) { ++ $out .= dsa_pqgen_driver($modulus, $qsize, $num); ++ $num = 0; ++ } + } + elsif ($tt == 11) { + if ($pt ne "" && $dsa_keyfile ne "") { +@@ -2124,7 +2528,7 @@ sub parse($$) { + $xq1 ne "" && + $xq2 ne "" && + $Xq ne "") { +- $out .= rsa_keygen($modulus, ++ $out .= rsa_keygen_x931($modulus, + $e, + $xp1, + $xp2, +@@ -2141,6 +2545,96 @@ sub parse($$) { + $Xq = ""; + } + } ++ elsif ($tt == 14) { ++ if ($modulus ne "" && ++ $qsize ne "" && ++ $capital_n > 0) { ++ $out .= dsa_keypair_driver($modulus, ++ $qsize, ++ $capital_n); ++ $capital_n = 0; ++ } ++ } ++ elsif ($tt == 15) { ++ if ($modulus ne "" && ++ $qsize ne "" && ++ $capital_p ne "" && ++ $capital_q ne "") { ++ $out .= dsa_ggen_driver($modulus, ++ $qsize, ++ $capital_p, ++ $capital_q); ++ $capital_p = ""; ++ $capital_q = ""; ++ $num--; ++ } ++ } ++ elsif ($tt == 16) { ++ if ($modulus ne "" && ++ $qsize ne "" && ++ $capital_p ne "" && ++ $capital_q ne "" && ++ $pt ne "" && ++ $c ne "") { ++ $out .= dsa_pqver_driver($modulus, ++ $qsize, ++ $capital_p, ++ $capital_q, ++ $pt, ++ $c); ++ $capital_p = ""; ++ $capital_q = ""; ++ $pt = ""; ++ $c = ""; ++ } ++ } ++ elsif ($tt == 17) { ++ if ($modulus ne "" && ++ $qsize ne "" && ++ $capital_p ne "" && ++ $capital_q ne "" && ++ $capital_g ne "" && ++ $pt ne "" && ++ $c ne "" && ++ $capital_h ne "") { ++ $out .= dsa_pqgver_driver($modulus, ++ $qsize, ++ $capital_p, ++ $capital_q, ++ $capital_g, ++ $pt, ++ $c, ++ $capital_h); ++ $capital_p = ""; ++ $capital_q = ""; ++ $capital_g = ""; ++ $pt = ""; ++ $c = ""; ++ $capital_h = ""; ++ } ++ } ++ elsif ($tt == 18) { ++ if ($modulus ne "" && ++ $capital_n > 0) { ++ $out .= rsa_keygen_driver($modulus, ++ $capital_n); ++ $capital_n = 0; ++ } ++ } ++ elsif ($tt == 19) { ++ if ($modulus ne "" && ++ $e ne "" && ++ $prandom ne "" && ++ $qrandom ne "") { ++ $out .= rsa_keygen_kat_driver($modulus, ++ $e, ++ $prandom, ++ $qrandom); ++ $prandom = ""; ++ $qrandom = ""; ++ $e = ""; ++ } ++ } + elsif ($tt > 0) { + die "Test case $tt not defined"; + } +@@ -2199,10 +2693,14 @@ sub main() { + $state_rng = \&libgcrypt_state_rng; + $hmac = \&libgcrypt_hmac; + $dsa_pqggen = \&libgcrypt_dsa_pqggen; ++ $dsa_ggen = \&libgcrypt_dsa_ggen; + $gen_dsakey = \&libgcrypt_gen_dsakey; ++ $gen_dsakey_domain = \&libgcrypt_gen_dsakey_domain; + $dsa_sign = \&libgcrypt_dsa_sign; + $dsa_verify = \&libgcrypt_dsa_verify; + $dsa_genpubkey = \&libgcrypt_dsa_genpubkey; ++ $rsa_keygen = \&libgcrypt_rsa_keygen; ++ $rsa_keygen_kat = \&libgcrypt_rsa_keygen_kat; + } else { + die "Invalid interface option given"; + } +diff -up libgcrypt-1.5.3/tests/cavs_tests.sh.cavs libgcrypt-1.5.3/tests/cavs_tests.sh +--- libgcrypt-1.5.3/tests/cavs_tests.sh.cavs 2013-05-22 18:02:55.000000000 +0200 ++++ libgcrypt-1.5.3/tests/cavs_tests.sh 2014-09-26 17:45:38.434674884 +0200 +@@ -55,7 +55,7 @@ function run_one_test () { + [ -d "$respdir" ] || mkdir "$respdir" + [ -f "$rspfile" ] && rm "$rspfile" + +- if echo "$reqfile" | grep '/DSA/req/' >/dev/null 2>/dev/null; then ++ if echo "$reqfile" | grep '/DSA.\?/req/' >/dev/null 2>/dev/null; then + dflag="-D" + fi + +diff -up libgcrypt-1.5.3/tests/fipsdrv.c.cavs libgcrypt-1.5.3/tests/fipsdrv.c +--- libgcrypt-1.5.3/tests/fipsdrv.c.cavs 2013-07-25 11:10:04.000000000 +0200 ++++ libgcrypt-1.5.3/tests/fipsdrv.c 2014-10-21 09:30:30.796777225 +0200 +@@ -893,6 +893,9 @@ print_mpi_line (gcry_mpi_t a, int no_lz) + die ("gcry_mpi_aprint failed: %s\n", gpg_strerror (err)); + + p = buf; ++ while (*p) ++ *p++ = tolower(*p); ++ p = buf; + if (no_lz && p[0] == '0' && p[1] == '0' && p[2]) + p += 2; + +@@ -1346,6 +1349,69 @@ run_rsa_derive (const void *data, size_t + } + + ++/* Generate RSA key using the S-expression in (DATA,DATALEN). This ++ S-expression is used directly as input to gcry_pk_genkey. The ++ result is printed to stdout with one parameter per line in hex ++ format and in this order: e, p, q, n, d. */ ++static void ++run_rsa_keygen (const void *data, size_t datalen, int test) ++{ ++ gpg_error_t err; ++ gcry_sexp_t s_keyspec, s_key, s_top, l1; ++ gcry_mpi_t mpi; ++ const char *parmlist; ++ int idx; ++ ++ if (!datalen) ++ err = gpg_error (GPG_ERR_NO_DATA); ++ else ++ err = gcry_sexp_new (&s_keyspec, data, datalen, 1); ++ if (err) ++ die ("gcry_sexp_new failed for RSA key generation: %s\n", ++ gpg_strerror (err)); ++ ++ err = gcry_pk_genkey (&s_key, s_keyspec); ++ ++ gcry_sexp_release (s_keyspec); ++ ++ if (test) { ++ if (err) ++ printf("F\n"); ++ else { ++ gcry_sexp_release (s_key); ++ printf("P\n"); ++ } ++ return; ++ } ++ ++ if (err) ++ die ("gcry_pk_genkey failed for RSA: %s\n", gpg_strerror (err)); ++ ++ parmlist = "epqnd"; ++ ++ /* Parse and print the parameters. */ ++ l1 = gcry_sexp_find_token (s_key, "private-key", 0); ++ s_top = gcry_sexp_find_token (l1, "rsa", 0); ++ gcry_sexp_release (l1); ++ if (!s_top) ++ die ("private-key part not found in result\n"); ++ ++ for (idx=0; parmlist[idx]; idx++) ++ { ++ l1 = gcry_sexp_find_token (s_top, parmlist+idx, 1); ++ mpi = gcry_sexp_nth_mpi (l1, 1, GCRYMPI_FMT_USG); ++ gcry_sexp_release (l1); ++ if (!mpi) ++ die ("parameter %c missing in private-key\n", parmlist[idx]); ++ print_mpi_line (mpi, 1); ++ gcry_mpi_release (mpi); ++ } ++ ++ gcry_sexp_release (s_top); ++ gcry_sexp_release (s_key); ++} ++ ++ + + static size_t + compute_tag_length (size_t n) +@@ -1675,14 +1741,14 @@ run_rsa_verify (const void *data, size_t + /* Generate a DSA key of size KEYSIZE and return the complete + S-expression. */ + static gcry_sexp_t +-dsa_gen (int keysize) ++dsa_gen (int keysize, int qsize) + { + gpg_error_t err; + gcry_sexp_t keyspec, key; + + err = gcry_sexp_build (&keyspec, NULL, +- "(genkey (dsa (nbits %d)(use-fips186-2)))", +- keysize); ++ "(genkey (dsa (nbits %d)(qbits %d)(use-fips186)))", ++ keysize, qsize); + if (err) + die ("gcry_sexp_build failed for DSA key generation: %s\n", + gpg_strerror (err)); +@@ -1700,7 +1766,7 @@ dsa_gen (int keysize) + /* Generate a DSA key of size KEYSIZE and return the complete + S-expression. */ + static gcry_sexp_t +-dsa_gen_with_seed (int keysize, const void *seed, size_t seedlen) ++dsa_gen_with_seed (int keysize, int qsize, const void *seed, size_t seedlen) + { + gpg_error_t err; + gcry_sexp_t keyspec, key; +@@ -1709,10 +1775,11 @@ dsa_gen_with_seed (int keysize, const vo + "(genkey" + " (dsa" + " (nbits %d)" +- " (use-fips186-2)" ++ " (qbits %d)" ++ " (use-fips186)" + " (derive-parms" + " (seed %b))))", +- keysize, (int)seedlen, seed); ++ keysize, qsize, (int)seedlen, seed); + if (err) + die ("gcry_sexp_build failed for DSA key generation: %s\n", + gpg_strerror (err)); +@@ -1720,6 +1787,37 @@ dsa_gen_with_seed (int keysize, const vo + err = gcry_pk_genkey (&key, keyspec); + if (err) + die ("gcry_pk_genkey failed for DSA: %s\n", gpg_strerror (err)); ++ ++ gcry_sexp_release (keyspec); ++ ++ return key; ++} ++ ++/* Generate a DSA key with specified domain parameters and return the complete ++ S-expression. */ ++static gcry_sexp_t ++dsa_gen_key (const char *domain) ++{ ++ gpg_error_t err; ++ gcry_sexp_t keyspec, key, domspec; ++ ++ err = gcry_sexp_new (&domspec, domain, strlen(domain), 0); ++ if (err) ++ die ("gcry_sexp_build failed for domain spec: %s\n", ++ gpg_strerror (err)); ++ ++ err = gcry_sexp_build (&keyspec, NULL, ++ "(genkey" ++ " (dsa" ++ " (use-fips186)" ++ " %S))", ++ domspec); ++ if (err) ++ die ("gcry_sexp_build failed for DSA key generation: %s\n", ++ gpg_strerror (err)); ++ err = gcry_pk_genkey (&key, keyspec); ++ if (err) ++ die ("gcry_pk_genkey failed for DSA: %s\n", gpg_strerror (err)); + + gcry_sexp_release (keyspec); + +@@ -1732,7 +1830,7 @@ dsa_gen_with_seed (int keysize, const vo + with one parameter per line in hex format using this order: p, q, + g, seed, counter, h. */ + static void +-print_dsa_domain_parameters (gcry_sexp_t key) ++print_dsa_domain_parameters (gcry_sexp_t key, int print_misc) + { + gcry_sexp_t l1, l2; + gcry_mpi_t mpi; +@@ -1768,6 +1866,9 @@ print_dsa_domain_parameters (gcry_sexp_t + } + gcry_sexp_release (l1); + ++ if (!print_misc) ++ return; ++ + /* Extract the seed values. */ + l1 = gcry_sexp_find_token (key, "misc-key-info", 0); + if (!l1) +@@ -1819,38 +1920,106 @@ print_dsa_domain_parameters (gcry_sexp_t + } + + +-/* Generate DSA domain parameters for a modulus size of KEYSIZE. The ++/* Print just the XY private key parameters. KEY ++ is the complete key as returned by dsa_gen. We print to stdout ++ with one parameter per line in hex format using this order: x, y. */ ++static void ++print_dsa_xy (gcry_sexp_t key) ++{ ++ gcry_sexp_t l1, l2; ++ gcry_mpi_t mpi; ++ int idx; ++ ++ l1 = gcry_sexp_find_token (key, "private-key", 0); ++ if (!l1) ++ die ("private key not found in genkey result\n"); ++ ++ l2 = gcry_sexp_find_token (l1, "dsa", 0); ++ if (!l2) ++ die ("returned private key not formed as expected\n"); ++ gcry_sexp_release (l1); ++ l1 = l2; ++ ++ /* Extract the parameters from the S-expression and print them to stdout. */ ++ for (idx=0; "xy"[idx]; idx++) ++ { ++ l2 = gcry_sexp_find_token (l1, "xy"+idx, 1); ++ if (!l2) ++ die ("no %c parameter in returned public key\n", "xy"[idx]); ++ mpi = gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG); ++ if (!mpi) ++ die ("no value for %c parameter in returned private key\n","xy"[idx]); ++ gcry_sexp_release (l2); ++ if (standalone_mode) ++ printf ("%c = ", "XY"[idx]); ++ print_mpi_line (mpi, 1); ++ gcry_mpi_release (mpi); ++ } ++ ++ gcry_sexp_release (l1); ++} ++ ++ ++/* Generate DSA pq domain parameters for a modulus size of KEYSIZE. The + result is printed to stdout with one parameter per line in hex +- format and in this order: p, q, g, seed, counter, h. If SEED is ++ format and in this order: p, q, seed, counter. If SEED is + not NULL this seed value will be used for the generation. */ + static void +-run_dsa_pqg_gen (int keysize, const void *seed, size_t seedlen) ++run_dsa_pqg_gen (int keysize, int qsize, const void *seed, size_t seedlen) + { + gcry_sexp_t key; + + if (seed) +- key = dsa_gen_with_seed (keysize, seed, seedlen); ++ key = dsa_gen_with_seed (keysize, qsize, seed, seedlen); + else +- key = dsa_gen (keysize); +- print_dsa_domain_parameters (key); ++ key = dsa_gen (keysize, qsize); ++ print_dsa_domain_parameters (key, 1); ++ gcry_sexp_release (key); ++} ++ ++ ++/* Generate DSA domain parameters for a modulus size of KEYSIZE. The ++ result is printed to stdout with one parameter per line in hex ++ format and in this order: p, q, g, seed, counter, h. If SEED is ++ not NULL this seed value will be used for the generation. */ ++static void ++run_dsa_g_gen (int keysize, int qsize, const char *domain) ++{ ++ gcry_sexp_t key; ++ ++ key = dsa_gen_key (domain); ++ print_dsa_domain_parameters (key, 0); ++ gcry_sexp_release (key); ++} ++ ++/* Generate a DSA key with specified domain parameters ++ and print the XY values. */ ++static void ++run_dsa_gen_key (const char *domain) ++{ ++ gcry_sexp_t key; ++ ++ key = dsa_gen_key (domain); ++ print_dsa_xy (key); ++ + gcry_sexp_release (key); + } + + + /* Generate a DSA key of size of KEYSIZE and write the private key to + FILENAME. Also write the parameters to stdout in the same way as +- run_dsa_pqg_gen. */ ++ run_dsa_g_gen. */ + static void +-run_dsa_gen (int keysize, const char *filename) ++run_dsa_gen (int keysize, int qsize, const char *filename) + { + gcry_sexp_t key, private_key; + FILE *fp; + +- key = dsa_gen (keysize); ++ key = dsa_gen (keysize, qsize); + private_key = gcry_sexp_find_token (key, "private-key", 0); + if (!private_key) + die ("private key not found in genkey result\n"); +- print_dsa_domain_parameters (key); ++ print_dsa_domain_parameters (key, 1); + + fp = fopen (filename, "wb"); + if (!fp) +@@ -1863,6 +2032,53 @@ run_dsa_gen (int keysize, const char *fi + } + + ++static int ++dsa_hash_from_key(gcry_sexp_t s_key) ++{ ++ gcry_sexp_t l1, l2; ++ gcry_mpi_t q; ++ unsigned int qbits; ++ ++ l1 = gcry_sexp_find_token (s_key, "public-key", 0); ++ if (!l1) ++ { ++ l1 = gcry_sexp_find_token (s_key, "private-key", 0); ++ if (!l1) ++ die ("neither private nor public key found in the loaded key\n"); ++ } ++ ++ l2 = gcry_sexp_find_token (l1, "dsa", 0); ++ if (!l2) ++ die ("public key not formed as expected - no dsa\n"); ++ gcry_sexp_release (l1); ++ l1 = l2; ++ ++ l2 = gcry_sexp_find_token (l1, "q", 0); ++ if (!l2) ++ die ("public key not formed as expected - no q\n"); ++ gcry_sexp_release (l1); ++ l1 = l2; ++ ++ q = gcry_sexp_nth_mpi (l1, 1, GCRYMPI_FMT_USG); ++ if (!q) ++ die ("public key not formed as expected - no mpi in q\n"); ++ qbits = gcry_mpi_get_nbits(q); ++ gcry_sexp_release(l1); ++ gcry_mpi_release(q); ++ switch(qbits) ++ { ++ case 160: ++ return GCRY_MD_SHA1; ++ case 224: ++ return GCRY_MD_SHA224; ++ case 256: ++ return GCRY_MD_SHA256; ++ default: ++ die("bad number bits (%d) of q in key\n", qbits); ++ } ++ return GCRY_MD_NONE; ++} ++ + + /* Sign DATA of length DATALEN using the key taken from the S-expression + encoded KEYFILE. */ +@@ -1872,11 +2088,16 @@ run_dsa_sign (const void *data, size_t d + { + gpg_error_t err; + gcry_sexp_t s_data, s_key, s_sig, s_tmp, s_tmp2; +- char hash[20]; ++ char hash[128]; + gcry_mpi_t tmpmpi; ++ int algo; + +- gcry_md_hash_buffer (GCRY_MD_SHA1, hash, data, datalen); +- err = gcry_mpi_scan (&tmpmpi, GCRYMPI_FMT_USG, hash, 20, NULL); ++ s_key = read_sexp_from_file (keyfile); ++ algo = dsa_hash_from_key(s_key); ++ ++ gcry_md_hash_buffer (algo, hash, data, datalen); ++ err = gcry_mpi_scan (&tmpmpi, GCRYMPI_FMT_USG, hash, ++ gcry_md_get_algo_dlen(algo), NULL); + if (!err) + { + err = gcry_sexp_build (&s_data, NULL, +@@ -1887,8 +2108,6 @@ run_dsa_sign (const void *data, size_t d + die ("gcry_sexp_build failed for DSA data input: %s\n", + gpg_strerror (err)); + +- s_key = read_sexp_from_file (keyfile); +- + err = gcry_pk_sign (&s_sig, s_data, s_key); + if (err) + { +@@ -1964,13 +2183,18 @@ run_dsa_verify (const void *data, size_t + { + gpg_error_t err; + gcry_sexp_t s_data, s_key, s_sig; +- char hash[20]; ++ char hash[128]; + gcry_mpi_t tmpmpi; ++ int algo; ++ ++ s_key = read_sexp_from_file (keyfile); ++ algo = dsa_hash_from_key(s_key); + +- gcry_md_hash_buffer (GCRY_MD_SHA1, hash, data, datalen); ++ gcry_md_hash_buffer (algo, hash, data, datalen); + /* Note that we can't simply use %b with HASH to build the + S-expression, because that might yield a negative value. */ +- err = gcry_mpi_scan (&tmpmpi, GCRYMPI_FMT_USG, hash, 20, NULL); ++ err = gcry_mpi_scan (&tmpmpi, GCRYMPI_FMT_USG, hash, ++ gcry_md_get_algo_dlen(algo), NULL); + if (!err) + { + err = gcry_sexp_build (&s_data, NULL, +@@ -1981,7 +2205,6 @@ run_dsa_verify (const void *data, size_t + die ("gcry_sexp_build failed for DSA data input: %s\n", + gpg_strerror (err)); + +- s_key = read_sexp_from_file (keyfile); + s_sig = read_sexp_from_file (sigfile); + + err = gcry_pk_verify (s_sig, s_data, s_key); +@@ -2014,7 +2237,7 @@ usage (int show_help) + "Run a crypto operation using hex encoded input and output.\n" + "MODE:\n" + " encrypt, decrypt, digest, random, hmac-sha,\n" +- " rsa-{derive,gen,sign,verify}, dsa-{pqg-gen,gen,sign,verify}\n" ++ " rsa-{derive,gen,sign,verify}, dsa-{pq-gen,g-gen,gen,sign,verify}\n" + "OPTIONS:\n" + " --verbose Print additional information\n" + " --binary Input and output is in binary form\n" +@@ -2024,6 +2247,7 @@ usage (int show_help) + " --dt DT Use the hex encoded DT for the RNG\n" + " --algo NAME Use algorithm NAME\n" + " --keysize N Use a keysize of N bits\n" ++ " --qize N Use a DSA q parameter size of N bits\n" + " --signature NAME Take signature from file NAME\n" + " --chunk N Read in chunks of N bytes (implies --binary)\n" + " --pkcs1 Use PKCS#1 encoding\n" +@@ -2050,6 +2274,7 @@ main (int argc, char **argv) + const char *dt_string = NULL; + const char *algo_string = NULL; + const char *keysize_string = NULL; ++ const char *qsize_string = NULL; + const char *signature_string = NULL; + FILE *input; + void *data; +@@ -2143,6 +2368,14 @@ main (int argc, char **argv) + keysize_string = *argv; + argc--; argv++; + } ++ else if (!strcmp (*argv, "--qsize")) ++ { ++ argc--; argv++; ++ if (!argc) ++ usage (0); ++ qsize_string = *argv; ++ argc--; argv++; ++ } + else if (!strcmp (*argv, "--signature")) + { + argc--; argv++; +@@ -2406,6 +2639,18 @@ main (int argc, char **argv) + die ("no data available (do not use --chunk)\n"); + run_rsa_derive (data, datalen); + } ++ else if (!strcmp (mode_string, "rsa-keygen")) ++ { ++ if (!data) ++ die ("no data available (do not use --chunk)\n"); ++ run_rsa_keygen (data, datalen, 0); ++ } ++ else if (!strcmp (mode_string, "rsa-keygen-kat")) ++ { ++ if (!data) ++ die ("no data available (do not use --chunk)\n"); ++ run_rsa_keygen (data, datalen, 1); ++ } + else if (!strcmp (mode_string, "rsa-gen")) + { + int keysize; +@@ -2463,23 +2708,49 @@ main (int argc, char **argv) + } + else if (!strcmp (mode_string, "dsa-pqg-gen")) + { +- int keysize; ++ int keysize, qsize; + + keysize = keysize_string? atoi (keysize_string) : 0; + if (keysize < 1024 || keysize > 3072) + die ("invalid keysize specified; needs to be 1024 .. 3072\n"); +- run_dsa_pqg_gen (keysize, datalen? data:NULL, datalen); ++ qsize = qsize_string? atoi (qsize_string) : 0; ++ if (qsize < 160 || qsize > 256) ++ die ("invalid qsize specified; needs to be 160 .. 256\n"); ++ run_dsa_pqg_gen (keysize, qsize, datalen? data:NULL, datalen); ++ } ++ else if (!strcmp (mode_string, "dsa-g-gen")) ++ { ++ int keysize, qsize; ++ ++ keysize = keysize_string? atoi (keysize_string) : 0; ++ if (keysize < 1024 || keysize > 3072) ++ die ("invalid keysize specified; needs to be 1024 .. 3072\n"); ++ qsize = qsize_string? atoi (qsize_string) : 0; ++ if (qsize < 160 || qsize > 256) ++ die ("invalid qsize specified; needs to be 160 .. 256\n"); ++ if (!key_string) ++ die ("option --key containing pq domain parameters is required in this mode\n"); ++ run_dsa_g_gen (keysize, qsize, key_string); ++ } ++ else if (!strcmp (mode_string, "dsa-gen-key")) ++ { ++ if (!key_string) ++ die ("option --key containing pqg domain parameters is required in this mode\n"); ++ run_dsa_gen_key (key_string); + } + else if (!strcmp (mode_string, "dsa-gen")) + { +- int keysize; ++ int keysize, qsize; + + keysize = keysize_string? atoi (keysize_string) : 0; + if (keysize < 1024 || keysize > 3072) + die ("invalid keysize specified; needs to be 1024 .. 3072\n"); ++ qsize = qsize_string? atoi (qsize_string) : 0; ++ if (qsize < 160 || qsize > 256) ++ die ("invalid qsize specified; needs to be 160 .. 256\n"); + if (!key_string) + die ("option --key is required in this mode\n"); +- run_dsa_gen (keysize, key_string); ++ run_dsa_gen (keysize, qsize, key_string); + } + else if (!strcmp (mode_string, "dsa-sign")) + { diff --git a/SOURCES/libgcrypt-1.5.3-fips-cfgrandom.patch b/SOURCES/libgcrypt-1.5.3-fips-cfgrandom.patch new file mode 100644 index 0000000..9585bf3 --- /dev/null +++ b/SOURCES/libgcrypt-1.5.3-fips-cfgrandom.patch @@ -0,0 +1,142 @@ +diff -up libgcrypt-1.5.3/random/drbg.c.cfgrandom libgcrypt-1.5.3/random/drbg.c +--- libgcrypt-1.5.3/random/drbg.c.cfgrandom 2014-10-30 16:42:49.000000000 +0100 ++++ libgcrypt-1.5.3/random/drbg.c 2014-10-30 16:46:57.291800433 +0100 +@@ -485,8 +485,11 @@ gcry_drbg_get_entropy (struct gcry_drbg_ + read_cb_size = len; + read_cb_len = 0; + #if USE_RNDLINUX ++ _gcry_rndlinux_gather_random (gcry_drbg_read_cb, 0, len, ++ -1); ++ read_cb_len = 0; + rc = _gcry_rndlinux_gather_random (gcry_drbg_read_cb, 0, len, +- GCRY_VERY_STRONG_RANDOM); ++ GCRY_STRONG_RANDOM); + #elif USE_RNDUNIX + rc = _gcry_rndunix_gather_random (read_cb, 0, length, + GCRY_VERY_STRONG_RANDOM); +diff -up libgcrypt-1.5.3/random/random-fips.c.cfgrandom libgcrypt-1.5.3/random/random-fips.c +--- libgcrypt-1.5.3/random/random-fips.c.cfgrandom 2014-10-30 16:42:49.942216405 +0100 ++++ libgcrypt-1.5.3/random/random-fips.c 2014-10-30 16:42:49.970217037 +0100 +@@ -27,10 +27,10 @@ + There are 3 random context which map to the different levels of + random quality: + +- Generator Seed and Key Kernel entropy (init/reseed) +- ------------------------------------------------------------ +- GCRY_VERY_STRONG_RANDOM /dev/random 256/128 bits +- GCRY_STRONG_RANDOM /dev/random 256/128 bits ++ Generator Seed and Key Kernel entropy (init/reseed) ++ --------------------------------------------------------------------------------------- ++ GCRY_VERY_STRONG_RANDOM /etc/gcrypt/rngseed+/dev/urandom 256/128 bits ++ GCRY_STRONG_RANDOM /etc/gcrypt/rngseed+/dev/urandom 256/128 bits + gcry_create_nonce GCRY_STRONG_RANDOM n/a + + All random generators return their data in 128 bit blocks. If the +@@ -40,8 +40,10 @@ + (SEED_TTL) output blocks; the re-seeding is disabled in test mode. + + The GCRY_VERY_STRONG_RANDOM and GCRY_STRONG_RANDOM generators are +- keyed and seeded from the /dev/random device. Thus these +- generators may block until the kernel has collected enough entropy. ++ keyed and seeded with data that is loaded from the /etc/gcrypt/rngseed ++ if the device or symlink to device exists xored with the data ++ from the /dev/urandom device. This allows the system administrator ++ to always seed the RNGs from /dev/random if it is required. + + The gcry_create_nonce generator is keyed and seeded from the + GCRY_STRONG_RANDOM generator. It may also block if the +@@ -560,9 +562,13 @@ get_entropy (size_t nbytes) + entropy_collect_buffer_len = 0; + + #if USE_RNDLINUX ++ _gcry_rndlinux_gather_random (entropy_collect_cb, 0, ++ X931_AES_KEYLEN, ++ -1); ++ entropy_collect_buffer_len = 0; + rc = _gcry_rndlinux_gather_random (entropy_collect_cb, 0, + X931_AES_KEYLEN, +- GCRY_VERY_STRONG_RANDOM); ++ GCRY_STRONG_RANDOM); + #elif USE_RNDW32 + do + { +diff -up libgcrypt-1.5.3/random/rndlinux.c.cfgrandom libgcrypt-1.5.3/random/rndlinux.c +--- libgcrypt-1.5.3/random/rndlinux.c.cfgrandom 2014-10-30 16:42:49.949216563 +0100 ++++ libgcrypt-1.5.3/random/rndlinux.c 2014-10-30 16:42:49.971217059 +0100 +@@ -37,7 +37,9 @@ + #include "g10lib.h" + #include "rand-internal.h" + +-static int open_device ( const char *name ); ++#define NAME_OF_CFG_RNGSEED "/etc/gcrypt/rngseed" ++ ++static int open_device ( const char *name, int fatal ); + + + static int +@@ -58,13 +60,17 @@ set_cloexec_flag (int fd) + * Used to open the /dev/random devices (Linux, xBSD, Solaris (if it exists)). + */ + static int +-open_device ( const char *name ) ++open_device ( const char *name, int fatal ) + { + int fd; + + fd = open ( name, O_RDONLY ); + if ( fd == -1 ) +- log_fatal ("can't open %s: %s\n", name, strerror(errno) ); ++ { ++ if (! fatal) ++ return fd; ++ log_fatal ("can't open %s: %s\n", name, strerror(errno) ); ++ } + + if (set_cloexec_flag (fd)) + log_error ("error setting FD_CLOEXEC on fd %d: %s\n", +@@ -93,6 +99,7 @@ _gcry_rndlinux_gather_random (void (*add + { + static int fd_urandom = -1; + static int fd_random = -1; ++ static int fd_configured = -1; + int fd; + int n; + byte buffer[768]; +@@ -101,6 +108,7 @@ _gcry_rndlinux_gather_random (void (*add + size_t last_so_far = 0; + int any_need_entropy = 0; + int delay; ++ size_t orig_length = length; + + /* First read from a hardware source. However let it account only + for up to 50% of the requested bytes. */ +@@ -111,16 +119,26 @@ _gcry_rndlinux_gather_random (void (*add + length -= n_hw; + + /* Open the requested device. */ ++ ++ if (level == -1) ++ { ++ if (fd_configured == -1) ++ fd_configured = open_device ( NAME_OF_CFG_RNGSEED, 0 ); ++ fd = fd_configured; ++ if (fd == -1) ++ return -1; ++ } ++ + if (level >= 2) + { + if( fd_random == -1 ) +- fd_random = open_device ( NAME_OF_DEV_RANDOM ); ++ fd_random = open_device ( NAME_OF_DEV_RANDOM, 1 ); + fd = fd_random; + } +- else ++ else if (level != -1) + { + if( fd_urandom == -1 ) +- fd_urandom = open_device ( NAME_OF_DEV_URANDOM ); ++ fd_urandom = open_device ( NAME_OF_DEV_URANDOM, 1 ); + fd = fd_urandom; + } + diff --git a/SOURCES/libgcrypt-1.5.3-fips-ctor.patch b/SOURCES/libgcrypt-1.5.3-fips-ctor.patch new file mode 100644 index 0000000..ad483bf --- /dev/null +++ b/SOURCES/libgcrypt-1.5.3-fips-ctor.patch @@ -0,0 +1,72 @@ +diff -up libgcrypt-1.5.3/cipher/md.c.fips-ctor libgcrypt-1.5.3/cipher/md.c +--- libgcrypt-1.5.3/cipher/md.c.fips-ctor 2013-07-25 11:10:03.000000000 +0200 ++++ libgcrypt-1.5.3/cipher/md.c 2014-12-12 15:32:35.464515238 +0100 +@@ -570,11 +570,8 @@ md_enable (gcry_md_hd_t hd, int algorith + + if (!err && algorithm == GCRY_MD_MD5 && fips_mode ()) + { +- _gcry_inactivate_fips_mode ("MD5 used"); + if (_gcry_enforced_fips_mode () ) + { +- /* We should never get to here because we do not register +- MD5 in enforced fips mode. But better throw an error. */ + err = GPG_ERR_DIGEST_ALGO; + } + } +diff -up libgcrypt-1.5.3/src/global.c.fips-ctor libgcrypt-1.5.3/src/global.c +--- libgcrypt-1.5.3/src/global.c.fips-ctor 2014-12-12 15:32:35.463515215 +0100 ++++ libgcrypt-1.5.3/src/global.c 2014-12-12 16:46:33.424883301 +0100 +@@ -140,6 +140,34 @@ global_init (void) + } + + ++#ifndef FIPS_MODULE_PATH ++#define FIPS_MODULE_PATH "/etc/system-fips" ++#endif ++ ++void __attribute__ ((constructor)) _gcry_global_constructor (void) ++{ ++ int rv; ++ ++ rv = access (FIPS_MODULE_PATH, F_OK); ++ if (rv < 0 && errno != ENOENT) ++ rv = 0; ++ ++ if (!rv) ++ { ++ int no_secmem_save; ++ ++ /* it should be always 0 at this point but let's keep on the safe side */ ++ no_secmem_save = no_secure_memory; ++ no_secure_memory = 1; ++ /* force selftests */ ++ global_init (); ++ if (fips_mode ()) ++ _gcry_random_initialize (1); ++ _gcry_fips_run_selftests (0); ++ no_secure_memory = no_secmem_save; ++ } ++} ++ + /* This function is called by the macro fips_is_operational and makes + sure that the minimal initialization has been done. This is far + from a perfect solution and hides problems with an improper +@@ -500,8 +528,7 @@ _gcry_vcontrol (enum gcry_ctl_cmds cmd, + + case GCRYCTL_FIPS_MODE_P: + if (fips_mode () +- && !_gcry_is_fips_mode_inactive () +- && !no_secure_memory) ++ && !_gcry_is_fips_mode_inactive ()) + err = GPG_ERR_GENERAL; /* Used as TRUE value */ + break; + +@@ -600,7 +627,7 @@ _gcry_vcontrol (enum gcry_ctl_cmds cmd, + break; + + case GCRYCTL_SET_ENFORCED_FIPS_FLAG: +- if (!any_init_done) ++ if (fips_mode ()) + { + /* Not yet intialized at all. Set the enforced fips mode flag */ + _gcry_set_enforced_fips_mode (); diff --git a/SOURCES/libgcrypt-1.5.3-fips-reqs.patch b/SOURCES/libgcrypt-1.5.3-fips-reqs.patch new file mode 100644 index 0000000..a32ab36 --- /dev/null +++ b/SOURCES/libgcrypt-1.5.3-fips-reqs.patch @@ -0,0 +1,359 @@ +diff -up libgcrypt-1.5.3/cipher/dsa.c.fips-reqs libgcrypt-1.5.3/cipher/dsa.c +--- libgcrypt-1.5.3/cipher/dsa.c.fips-reqs 2014-11-12 17:05:01.000000000 +0100 ++++ libgcrypt-1.5.3/cipher/dsa.c 2014-11-14 14:32:23.751354070 +0100 +@@ -55,42 +55,86 @@ typedef struct + } dsa_domain_t; + + +-/* A sample 1024 bit DSA key used for the selftests. */ ++/* A sample 2048 bit DSA key used for the selftests. */ + static const char sample_secret_key[] = + "(private-key" + " (dsa" +-" (p #00AD7C0025BA1A15F775F3F2D673718391D00456978D347B33D7B49E7F32EDAB" +-" 96273899DD8B2BB46CD6ECA263FAF04A28903503D59062A8865D2AE8ADFB5191" +-" CF36FFB562D0E2F5809801A1F675DAE59698A9E01EFE8D7DCFCA084F4C6F5A44" +-" 44D499A06FFAEA5E8EF5E01F2FD20A7B7EF3F6968AFBA1FB8D91F1559D52D8777B#)" +-" (q #00EB7B5751D25EBBB7BD59D920315FD840E19AEBF9#)" +-" (g #1574363387FDFD1DDF38F4FBE135BB20C7EE4772FB94C337AF86EA8E49666503" +-" AE04B6BE81A2F8DD095311E0217ACA698A11E6C5D33CCDAE71498ED35D13991E" +-" B02F09AB40BD8F4C5ED8C75DA779D0AE104BC34C960B002377068AB4B5A1F984" +-" 3FBA91F537F1B7CAC4D8DD6D89B0D863AF7025D549F9C765D2FC07EE208F8D15#)" +-" (y #64B11EF8871BE4AB572AA810D5D3CA11A6CDBC637A8014602C72960DB135BF46" +-" A1816A724C34F87330FC9E187C5D66897A04535CC2AC9164A7150ABFA8179827" +-" 6E45831AB811EEE848EBB24D9F5F2883B6E5DDC4C659DEF944DCFD80BF4D0A20" +-" 42CAA7DC289F0C5A9D155F02D3D551DB741A81695B74D4C8F477F9C7838EB0FB#)" +-" (x #11D54E4ADBD3034160F2CED4B7CD292A4EBF3EC0#)))"; +-/* A sample 1024 bit DSA key used for the selftests (public only). */ ++" (p #a85378d8fd3f8d72ec7418080da21317e43ec4b62ba8c862" ++" 3b7e4d04441dd1a0658662596493ca8e9e8fbb7e34aaddb6" ++" 2e5d67b6d09a6e61b769e7c352aa2b10e20ca0636963b552" ++" 3e86470decbbeda027e797e7b67635d4d49c30700e74af8a" ++" 0ff156a801af57a26e7078f1d82f74908ecb6d07e70b3503" ++" eed94fa32cf17a7fc3d6cf40dc7b00830e6a2566dc073e34" ++" 3312517c6aa5152b4bfecd2e551fee346318a153423c996b" ++" 0d5dcb9102aedd38798616f1f1e0d6c403525b1f9b3d4dc7" ++" 66de2dfc4a56d7b8ba5963d60f3e16318870ad436952e557" ++" 65374eab85e8ec17d6b9a4547b9b5f2752f3105be809b23a" ++" 2c8d7469db02e24d592394a7dba069e9#)" ++" (q #d277044e50f5a4e3f510a50a0b84fdffbca047ed27602056" ++" 7441a0a5#)" ++" (g #13d754e21fd241655da891c522a65a72a89bdc64ec9b54a8" ++" 21ed4a898b490e0c4fcb72192a4a20f541f3f2925399f0ba" ++" ecf929aafbf79dfe4332393b32cd2e2fcf272f32a627434a" ++" 0df242b75b414df372121e53a553f222f836b000f016485b" ++" 6bd0898451801dcd8de64cd5365696ffc532d528c506620a" ++" 942a0305046d8f1876341f1e570bc3974ba6b9a438e97023" ++" 02a2e6e67bfd06d32bc679962271d7b40cd72f386e64e0d7" ++" ef86ca8ca5d14228dc2a4f16e3189886b5990674f4200f3a" ++" 4cf65a3f0ddba1fa672dff2f5e143d10e4e97ae84f6da095" ++" 35d5b9df259181a79b63b069e949972b02ba36b3586aab7e" ++" 45f322f82e4e85ca3ab85591b3c2a966#)" ++" (y #2452f3ccbe9ed5ca7dc74c602b99226e8f2fab38e7d7ddfb" ++" 75539b17155e9fcfd1aba564eb8535d812c9c2dcf9728444" ++" 1bc482243624c7f457580c1c38a57c46c457392470edb52c" ++" b5a6e03fe6287bb6f49a42a2065a054f030839df1fd3149c" ++" 4ca0531dd8ca8aaa9cc7337193387348336118224545e88c" ++" 80ffd8765d74360333ccab9972779b6525a65bdd0d10c675" ++" c109bbd3e5be4d72ef6eba6e438d5226237db888379c5fcc" ++" 47a3847ff63711baed6d03afe81e694a413b680bd38ab490" ++" 3f8370a707ef551d4941026d9579d691de8edaa16105eb9d" ++" ba3c2f4c1bec508275aa0207e251b5eccb286a4b01d449d3" ++" 0acb673717a0d2fb3b50c893f7dab14f#)" ++" (x #0c4b3089d1b862cb3c436491f0915470c52796e3acbee800" ++" ec55f6cc#)))"; ++/* A sample 2048 bit DSA key used for the selftests (public only). */ + static const char sample_public_key[] = + "(public-key" + " (dsa" +-" (p #00AD7C0025BA1A15F775F3F2D673718391D00456978D347B33D7B49E7F32EDAB" +-" 96273899DD8B2BB46CD6ECA263FAF04A28903503D59062A8865D2AE8ADFB5191" +-" CF36FFB562D0E2F5809801A1F675DAE59698A9E01EFE8D7DCFCA084F4C6F5A44" +-" 44D499A06FFAEA5E8EF5E01F2FD20A7B7EF3F6968AFBA1FB8D91F1559D52D8777B#)" +-" (q #00EB7B5751D25EBBB7BD59D920315FD840E19AEBF9#)" +-" (g #1574363387FDFD1DDF38F4FBE135BB20C7EE4772FB94C337AF86EA8E49666503" +-" AE04B6BE81A2F8DD095311E0217ACA698A11E6C5D33CCDAE71498ED35D13991E" +-" B02F09AB40BD8F4C5ED8C75DA779D0AE104BC34C960B002377068AB4B5A1F984" +-" 3FBA91F537F1B7CAC4D8DD6D89B0D863AF7025D549F9C765D2FC07EE208F8D15#)" +-" (y #64B11EF8871BE4AB572AA810D5D3CA11A6CDBC637A8014602C72960DB135BF46" +-" A1816A724C34F87330FC9E187C5D66897A04535CC2AC9164A7150ABFA8179827" +-" 6E45831AB811EEE848EBB24D9F5F2883B6E5DDC4C659DEF944DCFD80BF4D0A20" +-" 42CAA7DC289F0C5A9D155F02D3D551DB741A81695B74D4C8F477F9C7838EB0FB#)))"; +- ++" (p #a85378d8fd3f8d72ec7418080da21317e43ec4b62ba8c862" ++" 3b7e4d04441dd1a0658662596493ca8e9e8fbb7e34aaddb6" ++" 2e5d67b6d09a6e61b769e7c352aa2b10e20ca0636963b552" ++" 3e86470decbbeda027e797e7b67635d4d49c30700e74af8a" ++" 0ff156a801af57a26e7078f1d82f74908ecb6d07e70b3503" ++" eed94fa32cf17a7fc3d6cf40dc7b00830e6a2566dc073e34" ++" 3312517c6aa5152b4bfecd2e551fee346318a153423c996b" ++" 0d5dcb9102aedd38798616f1f1e0d6c403525b1f9b3d4dc7" ++" 66de2dfc4a56d7b8ba5963d60f3e16318870ad436952e557" ++" 65374eab85e8ec17d6b9a4547b9b5f2752f3105be809b23a" ++" 2c8d7469db02e24d592394a7dba069e9#)" ++" (q #d277044e50f5a4e3f510a50a0b84fdffbca047ed27602056" ++" 7441a0a5#)" ++" (g #13d754e21fd241655da891c522a65a72a89bdc64ec9b54a8" ++" 21ed4a898b490e0c4fcb72192a4a20f541f3f2925399f0ba" ++" ecf929aafbf79dfe4332393b32cd2e2fcf272f32a627434a" ++" 0df242b75b414df372121e53a553f222f836b000f016485b" ++" 6bd0898451801dcd8de64cd5365696ffc532d528c506620a" ++" 942a0305046d8f1876341f1e570bc3974ba6b9a438e97023" ++" 02a2e6e67bfd06d32bc679962271d7b40cd72f386e64e0d7" ++" ef86ca8ca5d14228dc2a4f16e3189886b5990674f4200f3a" ++" 4cf65a3f0ddba1fa672dff2f5e143d10e4e97ae84f6da095" ++" 35d5b9df259181a79b63b069e949972b02ba36b3586aab7e" ++" 45f322f82e4e85ca3ab85591b3c2a966#)" ++" (y #2452f3ccbe9ed5ca7dc74c602b99226e8f2fab38e7d7ddfb" ++" 75539b17155e9fcfd1aba564eb8535d812c9c2dcf9728444" ++" 1bc482243624c7f457580c1c38a57c46c457392470edb52c" ++" b5a6e03fe6287bb6f49a42a2065a054f030839df1fd3149c" ++" 4ca0531dd8ca8aaa9cc7337193387348336118224545e88c" ++" 80ffd8765d74360333ccab9972779b6525a65bdd0d10c675" ++" c109bbd3e5be4d72ef6eba6e438d5226237db888379c5fcc" ++" 47a3847ff63711baed6d03afe81e694a413b680bd38ab490" ++" 3f8370a707ef551d4941026d9579d691de8edaa16105eb9d" ++" ba3c2f4c1bec508275aa0207e251b5eccb286a4b01d449d3" ++" 0acb673717a0d2fb3b50c893f7dab14f#)))"; + + + +@@ -1046,14 +1090,14 @@ dsa_get_nbits (int algo, gcry_mpi_t *pke + */ + + static const char * +-selftest_sign_1024 (gcry_sexp_t pkey, gcry_sexp_t skey) ++selftest_sign (gcry_sexp_t pkey, gcry_sexp_t skey) + { + static const char sample_data[] = + "(data (flags raw)" +- " (value #a0b1c2d3e4f500102030405060708090a1b2c3d4#))"; ++ " (value #a0b1c2d3e4f500102030405060708090a1b2c3d4f1e2d3c4b5a6978879605142#))"; + static const char sample_data_bad[] = + "(data (flags raw)" +- " (value #a0b1c2d3e4f510102030405060708090a1b2c3d4#))"; ++ " (value #a0b1c2d3e4f500102030405060708090a1b2c3d401e2d3c4b5a6978879605142#))"; + + const char *errtxt = NULL; + gcry_error_t err; +@@ -1131,7 +1175,7 @@ selftests_dsa (selftest_report_func_t re + } + + what = "sign"; +- errtxt = selftest_sign_1024 (pkey, skey); ++ errtxt = selftest_sign (pkey, skey); + if (errtxt) + goto failed; + +diff -up libgcrypt-1.5.3/cipher/rsa.c.fips-reqs libgcrypt-1.5.3/cipher/rsa.c +--- libgcrypt-1.5.3/cipher/rsa.c.fips-reqs 2014-11-12 17:05:01.299387339 +0100 ++++ libgcrypt-1.5.3/cipher/rsa.c 2014-11-14 14:06:00.099602441 +0100 +@@ -52,33 +52,57 @@ typedef struct + } RSA_secret_key; + + +-/* A sample 1024 bit RSA key used for the selftests. */ ++/* A sample 2048 bit RSA key used for the selftests. */ + static const char sample_secret_key[] = + "(private-key" + " (rsa" +-" (n #00e0ce96f90b6c9e02f3922beada93fe50a875eac6bcc18bb9a9cf2e84965caa" +-" 2d1ff95a7f542465c6c0c19d276e4526ce048868a7a914fd343cc3a87dd74291" +-" ffc565506d5bbb25cbac6a0e2dd1f8bcaab0d4a29c2f37c950f363484bf269f7" +-" 891440464baf79827e03a36e70b814938eebdc63e964247be75dc58b014b7ea251#)" ++" (n #00c9d56d9d90db43d602ed9688138ab2bf6ea10610b27837a714a8ffdd00" ++" ddb493a045cc9690edada9ddc4d6ca0cf0ed4f725e21499a1812158f905a" ++" dbb63399a3e6b4f0c4972126bbe3baf2ffa072da89638e8b3e089d922abe" ++" 16e14315fc57c71f0911671ca996d18b3e8093c159d06d39f2ac95cc1075" ++" e93124d143af68524be716d749656f26c086adc0070ac1e12f8785863bdc" ++" 5a99bee9f9b9e98227510415ab060e765a288d92bdc5b57ba8df4e47a2c1" ++" e752bf47f762e03a6f4d6a4d4ed4b95969fab214c1eee62f95cd9472aee4" ++" db189ac4cd70bdee3116b74965ac40190eb56d83f136bb082f2e4e9262a4" ++" ff50db2045a2eb167af2d528c1fd4e0371#)" + " (e #010001#)" +-" (d #046129f2489d71579be0a75fe029bd6cdb574ebf57ea8a5b0fda942cab943b11" +-" 7d7bb95e5d28875e0f9fc5fcc06a72f6d502464dabded78ef6b716177b83d5bd" +-" c543dc5d3fed932e59f5897e92e6f58a0f33424106a3b6fa2cbf877510e4ac21" +-" c3ee47851e97d12996222ac3566d4ccb0b83d164074abf7de655fc2446da1781#)" +-" (p #00e861b700e17e8afe6837e7512e35b6ca11d0ae47d8b85161c67baf64377213" +-" fe52d772f2035b3ca830af41d8a4120e1c1c70d12cc22f00d28d31dd48a8d424f1#)" +-" (q #00f7a7ca5367c661f8e62df34f0d05c10c88e5492348dd7bddc942c9a8f369f9" +-" 35a07785d2db805215ed786e4285df1658eed3ce84f469b81b50d358407b4ad361#)" +-" (u #304559a9ead56d2309d203811a641bb1a09626bc8eb36fffa23c968ec5bd891e" +-" ebbafc73ae666e01ba7c8990bae06cc2bbe10b75e69fcacb353a6473079d8e9b#)))"; +-/* A sample 1024 bit RSA key used for the selftests (public only). */ ++" (d #03b1e24a94e50ab21f8619701ec97679be2cf8f733c9331d9e2974dba721" ++" 27e5def480290e78a769f96b19d28397a284868fb614ca9b1fb3a0d7efed" ++" df41451204ce71aceba659f6ed15964ebb317712364e1cfaf2fded77d658" ++" 8561acc49c97c2d7efe75f1534b35bd4f6561e1f468b45590db34553d4d0" ++" c2cb4d806b74e1b2c52740462538865d9792b0aefbbf7b9827f4b3badcb3" ++" 5adab638266a2d2fb8422a7a19142e08848e56af77a66c39b2afafa2e15b" ++" 1a7e4ed1f2c7ed350678c0465d86472af97371b13ef5058662f835ef9087" ++" f6cca8281bbf1b6b155c737b33d9e443350df85e7cc3b507231fb839f41f" ++" 02c654b29017f35d69007c70e13ba0e5#)" ++" (p #00ccbe7b096906ee45bf884738a8f817e5b6ba6755e3e8058bb8e253d68e" ++" ef2ce74f4af74e268d850b3fecc31cd4ebec6ac8722a257dfda67796f01e" ++" cd2857f83730756bbdd47b0c87c56c8740a5bb272c78c9745a545b0b306f" ++" 444afa71e4216166f9ee65de7c04d7fda9155b7fe27aba698672a6068d9b" ++" 9055609e4c5da9b655#)" ++" (q #00fc5c6e16ce1f037bcdf7b372b28f1672b856aef7cd67d84e7d07afd543" ++" 26c335be438f4e2f1c434e6bd2b2ec526d97522bcc5c3a6bf414c674da66" ++" 381c7a3f842fe3f95ab865694606a33779b2a15b58ed5ea75f8c6566bbd1" ++" 2436e637a73d49778a8c34d86929f34d5822b05124b640a886590ab7ba5c" ++" 97da57e836da7a9cad#)" ++" (u #2396c191175e0a83d2dc7b69b2591d3358523f18c709501cb9a1bb4ca238" ++" 404c9a8efe9c9092d0719f899950911f348b745311114a70e2f730d88c80" ++" e1cc9ff163171a7d67294ccb4e747be03e9e2ff4678fecb95c001e7ea27b" ++" 92c96f4ce40ef94863cd50225dbfb69d01336af450be86984fca3f3afacf" ++" 0740c4aaadaebebf#)))"; ++/* A sample 2048 bit RSA key used for the selftests (public only). */ + static const char sample_public_key[] = + "(public-key" + " (rsa" +-" (n #00e0ce96f90b6c9e02f3922beada93fe50a875eac6bcc18bb9a9cf2e84965caa" +-" 2d1ff95a7f542465c6c0c19d276e4526ce048868a7a914fd343cc3a87dd74291" +-" ffc565506d5bbb25cbac6a0e2dd1f8bcaab0d4a29c2f37c950f363484bf269f7" +-" 891440464baf79827e03a36e70b814938eebdc63e964247be75dc58b014b7ea251#)" ++" (n #00c9d56d9d90db43d602ed9688138ab2bf6ea10610b27837a714a8ffdd00" ++" ddb493a045cc9690edada9ddc4d6ca0cf0ed4f725e21499a1812158f905a" ++" dbb63399a3e6b4f0c4972126bbe3baf2ffa072da89638e8b3e089d922abe" ++" 16e14315fc57c71f0911671ca996d18b3e8093c159d06d39f2ac95cc1075" ++" e93124d143af68524be716d749656f26c086adc0070ac1e12f8785863bdc" ++" 5a99bee9f9b9e98227510415ab060e765a288d92bdc5b57ba8df4e47a2c1" ++" e752bf47f762e03a6f4d6a4d4ed4b95969fab214c1eee62f95cd9472aee4" ++" db189ac4cd70bdee3116b74965ac40190eb56d83f136bb082f2e4e9262a4" ++" ff50db2045a2eb167af2d528c1fd4e0371#)" + " (e #010001#)))"; + + +@@ -1379,20 +1403,35 @@ compute_keygrip (gcry_md_hd_t md, gcry_s + */ + + static const char * +-selftest_sign_1024 (gcry_sexp_t pkey, gcry_sexp_t skey) ++selftest_sign (gcry_sexp_t pkey, gcry_sexp_t skey) + { + static const char sample_data[] = + "(data (flags pkcs1)" +- " (hash sha1 #11223344556677889900aabbccddeeff10203040#))"; ++ " (hash sha256 #11223344556677889900aabbccddeeffa0b0c0d0102030405060708090a1b1c1#))"; + static const char sample_data_bad[] = + "(data (flags pkcs1)" +- " (hash sha1 #11223344556677889900aabbccddeeff80203040#))"; ++ " (hash sha256 #11223344556677889900aabbccddeeffa0b0c0d0102030405060708091a1b1c1#))"; ++ static const char signature_ka[] = ++ "(sig-val \n" ++ " (rsa \n" ++ " (s #0B12D55738B099D401C81BEEDA54E045B4B7D9CDA5A8769E9C484F696A58912A" ++ "1E5DE7E5A2D181DA15A5C254D802AB75F1056E27406850AC7BE310BC32D2CED8" ++ "6697FE84508F7EFFF4D147C52E955A0873EF2F52ED71F2FC9C3C12D4045CB643" ++ "70158378E1494D8FBAD2248B9B64233D2CC2C1932B0531E539DEB07434B76D3B" ++ "6959E8A37E33B234C0C8C2C8FB1D00939239C9C491B2EBEED77BF952B597E11B" ++ "D4ED0C103D2B88BC78B4E505CF9D8D08B585CE3688D4FBE83ED58D1E1341AC4D" ++ "7C5EFF3CBC565CC7AE61C2F568426763A5239D31C1FFFD366984901679A343C4" ++ "01BB778BBA5E533B7875BA658A19AA9E56170F4A28E4322BF1621175FB06463E#)\n" ++ " )\n" ++ " )\n"; + + const char *errtxt = NULL; + gcry_error_t err; + gcry_sexp_t data = NULL; + gcry_sexp_t data_bad = NULL; + gcry_sexp_t sig = NULL; ++ char buf[1024]; ++ size_t len; + + err = gcry_sexp_sscan (&data, NULL, + sample_data, strlen (sample_data)); +@@ -1411,6 +1450,12 @@ selftest_sign_1024 (gcry_sexp_t pkey, gc + errtxt = "signing failed"; + goto leave; + } ++ len = gcry_sexp_sprint (sig, GCRYSEXP_FMT_ADVANCED, buf, sizeof(buf)); ++ if (len != sizeof (signature_ka) - 1 || memcmp (buf, signature_ka, len) != 0) ++ { ++ errtxt = "signature KAT failed"; ++ goto leave; ++ } + err = gcry_pk_verify (sig, data, pkey); + if (err) + { +@@ -1467,11 +1512,11 @@ extract_a_from_sexp (gcry_sexp_t encr_da + + + static const char * +-selftest_encr_1024 (gcry_sexp_t pkey, gcry_sexp_t skey) ++selftest_encr (gcry_sexp_t pkey, gcry_sexp_t skey) + { + const char *errtxt = NULL; + gcry_error_t err; +- const unsigned int nbits = 1000; /* Encrypt 1000 random bits. */ ++ const unsigned int nbits = 2000; /* Encrypt 2000 random bits. */ + gcry_mpi_t plaintext = NULL; + gcry_sexp_t plain = NULL; + gcry_sexp_t encr = NULL; +@@ -1594,12 +1639,12 @@ selftests_rsa (selftest_report_func_t re + } + + what = "sign"; +- errtxt = selftest_sign_1024 (pkey, skey); ++ errtxt = selftest_sign (pkey, skey); + if (errtxt) + goto failed; + + what = "encrypt"; +- errtxt = selftest_encr_1024 (pkey, skey); ++ errtxt = selftest_encr (pkey, skey); + if (errtxt) + goto failed; + +diff -up libgcrypt-1.5.3/random/drbg.c.fips-reqs libgcrypt-1.5.3/random/drbg.c +--- libgcrypt-1.5.3/random/drbg.c.fips-reqs 2014-11-12 17:05:01.000000000 +0100 ++++ libgcrypt-1.5.3/random/drbg.c 2014-11-14 14:45:33.820190218 +0100 +@@ -390,6 +390,9 @@ gcry_drbg_fips_continuous_test (struct g + ret = memcmp (drbg->prev, buf, gcry_drbg_blocklen (drbg)); + memcpy (drbg->prev, buf, gcry_drbg_blocklen (drbg)); + /* the test shall pass when the two compared values are not equal */ ++ if (ret == 0) ++ fips_signal_error ("duplicate block returned by DRBG"); ++ + return ret != 0; + } + +diff -up libgcrypt-1.5.3/src/visibility.c.fips-reqs libgcrypt-1.5.3/src/visibility.c +--- libgcrypt-1.5.3/src/visibility.c.fips-reqs 2013-07-25 11:10:04.000000000 +0200 ++++ libgcrypt-1.5.3/src/visibility.c 2014-11-12 17:05:27.251973230 +0100 +@@ -1217,6 +1217,9 @@ gcry_kdf_derive (const void *passphrase, + unsigned long iterations, + size_t keysize, void *keybuffer) + { ++ if (!fips_is_operational ()) ++ return gpg_error (fips_not_operational ()); ++ + return _gcry_kdf_derive (passphrase, passphraselen, algo, hashalgo, + salt, saltlen, iterations, keysize, keybuffer); + } +@@ -1271,6 +1274,13 @@ void + gcry_mpi_randomize (gcry_mpi_t w, + unsigned int nbits, 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_mpi_randomize (w, nbits, level); + } + +@@ -1296,6 +1306,9 @@ gcry_prime_generate (gcry_mpi_t *prime, + gcry_random_level_t random_level, + unsigned int flags) + { ++ if (!fips_is_operational ()) ++ return gpg_error (fips_not_operational ()); ++ + return _gcry_prime_generate (prime, prime_bits, factor_bits, factors, + cb_func, cb_arg, random_level, flags); + } diff --git a/SOURCES/libgcrypt-1.5.3-fips-test.patch b/SOURCES/libgcrypt-1.5.3-fips-test.patch new file mode 100644 index 0000000..cd80494 --- /dev/null +++ b/SOURCES/libgcrypt-1.5.3-fips-test.patch @@ -0,0 +1,18 @@ +diff -up libgcrypt-1.5.3/tests/basic.c.fips-test libgcrypt-1.5.3/tests/basic.c +--- libgcrypt-1.5.3/tests/basic.c.fips-test 2014-09-26 17:36:41.620556071 +0200 ++++ libgcrypt-1.5.3/tests/basic.c 2014-09-26 17:36:43.317594382 +0200 +@@ -563,6 +563,14 @@ check_ctr_cipher (void) + if (!tv[i].algo) + continue; + ++ 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 (&hde, tv[i].algo, GCRY_CIPHER_MODE_CTR, 0); + if (!err) + err = gcry_cipher_open (&hdd, tv[i].algo, GCRY_CIPHER_MODE_CTR, 0); diff --git a/SOURCES/libgcrypt-1.5.3-pbkdf-speedup.patch b/SOURCES/libgcrypt-1.5.3-pbkdf-speedup.patch new file mode 100644 index 0000000..7017367 --- /dev/null +++ b/SOURCES/libgcrypt-1.5.3-pbkdf-speedup.patch @@ -0,0 +1,32 @@ +diff -up libgcrypt-1.5.3/cipher/kdf.c.pbkdf-speedup libgcrypt-1.5.3/cipher/kdf.c +--- libgcrypt-1.5.3/cipher/kdf.c.pbkdf-speedup 2014-01-21 15:49:22.676638703 +0100 ++++ libgcrypt-1.5.3/cipher/kdf.c 2014-01-21 15:52:40.115047218 +0100 +@@ -172,19 +172,21 @@ pkdf2 (const void *passphrase, size_t pa + return ec; + } + ++ ec = gpg_err_code (gcry_md_setkey (md, passphrase, passphraselen)); ++ if (ec) ++ { ++ gcry_md_close (md); ++ gcry_free (sbuf); ++ return ec; ++ } ++ + /* Step 3 and 4. */ + memcpy (sbuf, salt, saltlen); + for (lidx = 1; lidx <= l; lidx++) + { + for (iter = 0; iter < iterations; iter++) + { +- ec = gpg_err_code (gcry_md_setkey (md, passphrase, passphraselen)); +- if (ec) +- { +- gcry_md_close (md); +- gcry_free (sbuf); +- return ec; +- } ++ gcry_md_reset (md); + if (!iter) /* Compute U_1: */ + { + sbuf[saltlen] = (lidx >> 24); diff --git a/SOURCES/libgcrypt-1.5.3-rng-predictable.patch b/SOURCES/libgcrypt-1.5.3-rng-predictable.patch new file mode 100644 index 0000000..6e1d730 --- /dev/null +++ b/SOURCES/libgcrypt-1.5.3-rng-predictable.patch @@ -0,0 +1,141 @@ +diff -up libgcrypt-1.5.3/random/random-csprng.c.rng-predictable libgcrypt-1.5.3/random/random-csprng.c +--- libgcrypt-1.5.3/random/random-csprng.c.rng-predictable 2015-08-11 14:31:35.904275580 +0200 ++++ libgcrypt-1.5.3/random/random-csprng.c 2016-08-17 23:35:15.691980751 +0200 +@@ -561,41 +561,46 @@ _gcry_rngcsprng_randomize (void *buffer, + + + /* +- 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. ++ * Mix the 600 byte pool. Note that the 64 byte scratch area directly ++ * follows the pool. The numbers in the diagram give the number of ++ * bytes. ++ * <................600...............> <.64.> ++ * pool |------------------------------------| |------| ++ * <20><.24.> <20> ++ * | | +-----+ ++ * +-----|-------------------------------|-+ ++ * +-------------------------------|-|-+ ++ * v v v ++ * |------| ++ * ++ * +---------------------------------------+ ++ * v ++ * <20> ++ * pool' |------------------------------------| ++ * <20><20><.24.> ++ * +---|-----|---------------------------+ ++ * +-----|---------------------------|-+ ++ * +---------------------------|-|-+ ++ * v v v ++ * |------| ++ * ++ * | ++ * +-----------------------------------+ ++ * v ++ * <20> ++ * pool'' |------------------------------------| ++ * <20><20><20><.24.> ++ * +---|-----|-----------------------+ ++ * +-----|-----------------------|-+ ++ * +-----------------------|-|-+ ++ * v v v ++ * ++ * and so on until we did this for all 30 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) +@@ -615,32 +620,30 @@ mix_pool(unsigned char *pool) + gcry_assert (pool_is_locked); + _gcry_rmd160_init( &md ); + +- /* Loop over the pool. */ ++ /* pool_0 -> pool'. */ + pend = pool + POOLSIZE; +- memcpy(hashbuf, pend - DIGESTLEN, DIGESTLEN ); +- memcpy(hashbuf+DIGESTLEN, pool, BLOCKLEN-DIGESTLEN); +- _gcry_rmd160_mixblock( &md, hashbuf); +- memcpy(pool, hashbuf, 20 ); ++ memcpy (hashbuf, pend - DIGESTLEN, DIGESTLEN); ++ memcpy (hashbuf+DIGESTLEN, pool, BLOCKLEN-DIGESTLEN); ++ _gcry_rmd160_mixblock (&md, hashbuf); ++ memcpy (pool, hashbuf, DIGESTLEN); + + if (failsafe_digest_valid && pool == rndpool) + { +- for (i=0; i < 20; i++) ++ for (i=0; i < DIGESTLEN; i++) + pool[i] ^= failsafe_digest[i]; + } + ++ /* Loop for the remaining iterations. */ + 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); ++ if (p + BLOCKLEN < pend) ++ memcpy (hashbuf, p, BLOCKLEN); + else + { +- unsigned char *pp = p + DIGESTLEN; ++ unsigned char *pp = p; + +- for (i=DIGESTLEN; i < BLOCKLEN; i++ ) ++ for (i=0; i < BLOCKLEN; i++ ) + { + if ( pp >= pend ) + pp = pool; +@@ -648,8 +651,9 @@ mix_pool(unsigned char *pool) + } + } + +- _gcry_rmd160_mixblock ( &md, hashbuf); +- memcpy(p, hashbuf, 20 ); ++ _gcry_rmd160_mixblock (&md, hashbuf); ++ p += DIGESTLEN; ++ memcpy (p, hashbuf, DIGESTLEN); + } + + /* Our hash implementation does only leave small parts (64 bytes) diff --git a/SOURCES/libgcrypt-1.5.3-rsa-fips-keygen.patch b/SOURCES/libgcrypt-1.5.3-rsa-fips-keygen.patch new file mode 100644 index 0000000..3d074d7 --- /dev/null +++ b/SOURCES/libgcrypt-1.5.3-rsa-fips-keygen.patch @@ -0,0 +1,374 @@ +diff -up libgcrypt-1.5.3/cipher/primegen.c.fips-keygen libgcrypt-1.5.3/cipher/primegen.c +--- libgcrypt-1.5.3/cipher/primegen.c.fips-keygen 2014-10-21 15:05:59.434189992 +0200 ++++ libgcrypt-1.5.3/cipher/primegen.c 2014-10-21 15:05:59.458190534 +0200 +@@ -1189,6 +1189,22 @@ gcry_prime_check (gcry_mpi_t x, unsigned + return gcry_error (err); + } + ++/* Check whether the number X is prime according to FIPS 186-4 table C.2. */ ++gpg_err_code_t ++_gcry_fips186_4_prime_check (gcry_mpi_t x, unsigned int bits) ++{ ++ gpg_err_code_t ec = GPG_ERR_NO_ERROR; ++ gcry_mpi_t val_2 = mpi_alloc_set_ui (2); /* Used by the Fermat test. */ ++ ++ /* We use 5 or 4 rounds as specified in table C.2 */ ++ if (! check_prime (x, val_2, bits > 1024 ? 4 : 5, NULL, NULL)) ++ ec = GPG_ERR_NO_PRIME; ++ ++ mpi_free (val_2); ++ ++ return ec; ++} ++ + /* Find a generator for PRIME where the factorization of (prime-1) is + in the NULL terminated array FACTORS. Return the generator as a + newly allocated MPI in R_G. If START_G is not NULL, use this as s +diff -up libgcrypt-1.5.3/cipher/rsa.c.fips-keygen libgcrypt-1.5.3/cipher/rsa.c +--- libgcrypt-1.5.3/cipher/rsa.c.fips-keygen 2014-10-21 15:05:59.423189744 +0200 ++++ libgcrypt-1.5.3/cipher/rsa.c 2014-10-21 15:12:45.200350340 +0200 +@@ -328,6 +328,279 @@ generate_std (RSA_secret_key *sk, unsign + } + + ++/**************** ++ * Generate a key pair with a key of size NBITS. ++ * USE_E = 0 let Libcgrypt decide what exponent to use. ++ * = 1 request the use of a "secure" exponent; this is required by some ++ * specification to be 65537. ++ * > 2 Use this public exponent. If the given exponent ++ * is not odd one is internally added to it. ++ * TESTPARMS: If set, do not generate but test whether the p,q is probably prime ++ * Returns key with zeroes to not break code calling this function. ++ * TRANSIENT_KEY: If true, generate the primes using the standard RNG. ++ * Returns: 2 structures filled with all needed values ++ */ ++static gpg_err_code_t ++generate_fips (RSA_secret_key *sk, unsigned int nbits, unsigned long use_e, ++ gcry_sexp_t testparms, int transient_key) ++{ ++ gcry_mpi_t p, q; /* the two primes */ ++ gcry_mpi_t d; /* the private key */ ++ gcry_mpi_t u; ++ gcry_mpi_t p1, q1; ++ gcry_mpi_t n; /* the public key */ ++ gcry_mpi_t e; /* the exponent */ ++ gcry_mpi_t g; ++ gcry_mpi_t minp; ++ gcry_mpi_t diff, mindiff; ++ gcry_random_level_t random_level; ++ unsigned int pbits = nbits/2; ++ unsigned int i; ++ int pqswitch; ++ gpg_err_code_t ec = GPG_ERR_NO_PRIME; ++ ++ if (nbits < 1024 || (nbits & 0x1FF)) ++ return GPG_ERR_INV_VALUE; ++ if (_gcry_enforced_fips_mode() && nbits != 2048 && nbits != 3072) ++ return GPG_ERR_INV_VALUE; ++ ++ /* The random quality depends on the transient_key flag. */ ++ random_level = transient_key ? GCRY_STRONG_RANDOM : GCRY_VERY_STRONG_RANDOM; ++ ++ if (testparms) ++ { ++ /* Parameters to derive the key are given. */ ++ /* Note that we explicitly need to setup the values of tbl ++ because some compilers (e.g. OpenWatcom, IRIX) don't allow ++ to initialize a structure with automatic variables. */ ++ struct { const char *name; gcry_mpi_t *value; } tbl[] = { ++ { "e" }, ++ { "p" }, ++ { "q" }, ++ { NULL } ++ }; ++ int idx; ++ gcry_sexp_t oneparm; ++ ++ tbl[0].value = &e; ++ tbl[1].value = &p; ++ tbl[2].value = &q; ++ ++ for (idx=0; tbl[idx].name; idx++) ++ { ++ oneparm = gcry_sexp_find_token (testparms, tbl[idx].name, 0); ++ if (oneparm) ++ { ++ *tbl[idx].value = gcry_sexp_nth_mpi (oneparm, 1, ++ GCRYMPI_FMT_USG); ++ gcry_sexp_release (oneparm); ++ } ++ } ++ for (idx=0; tbl[idx].name; idx++) ++ if (!*tbl[idx].value) ++ break; ++ if (tbl[idx].name) ++ { ++ /* At least one parameter is missing. */ ++ for (idx=0; tbl[idx].name; idx++) ++ gcry_mpi_release (*tbl[idx].value); ++ return GPG_ERR_MISSING_VALUE; ++ } ++ } ++ else ++ { ++ if (use_e < 65537) ++ use_e = 65537; /* This is the smallest value allowed by FIPS */ ++ ++ e = mpi_alloc( (32+BITS_PER_MPI_LIMB-1)/BITS_PER_MPI_LIMB ); ++ ++ use_e |= 1; /* make sure this is odd */ ++ mpi_set_ui (e, use_e); ++ ++ p = gcry_mpi_snew (pbits); ++ q = gcry_mpi_snew (pbits); ++ } ++ ++ n = gcry_mpi_new (nbits); ++ d = gcry_mpi_snew (nbits); ++ u = gcry_mpi_snew (nbits); ++ ++ /* prepare approximate minimum p and q */ ++ minp = gcry_mpi_new (pbits); ++ mpi_set_ui (minp, 0xB504F334); ++ gcry_mpi_lshift (minp, minp, pbits - 32); ++ ++ /* prepare minimum p and q difference */ ++ diff = gcry_mpi_new (pbits); ++ mindiff = gcry_mpi_new (pbits - 99); ++ mpi_set_ui (mindiff, 1); ++ gcry_mpi_lshift (mindiff, mindiff, pbits - 100); ++ ++ p1 = gcry_mpi_snew (pbits); ++ q1 = gcry_mpi_snew (pbits); ++ g = gcry_mpi_snew (pbits); ++ ++retry: ++ /* generate p and q */ ++ for (i = 0; i < 5 * pbits; i++) ++ { ++ ploop: ++ if (!testparms) ++ { ++ gcry_mpi_randomize (p, pbits, random_level); ++ } ++ if (mpi_cmp (p, minp) < 0) ++ { ++ if (testparms) goto err; ++ goto ploop; ++ } ++ ++ mpi_sub_ui (p1, p, 1); ++ if (gcry_mpi_gcd (g, p1, e)) ++ { ++ if (_gcry_fips186_4_prime_check (p, pbits) != GPG_ERR_NO_ERROR) ++ { ++ /* not a prime */ ++ if (testparms) goto err; ++ } ++ else ++ break; ++ } ++ else if (testparms) goto err; ++ } ++ if (i >= 5 * pbits) ++ goto err; ++ ++ for (i = 0; i < 5 * pbits; i++) ++ { ++ qloop: ++ if (!testparms) ++ { ++ gcry_mpi_randomize (q, pbits, random_level); ++ } ++ if (mpi_cmp (q, minp) < 0) ++ { ++ if (testparms) goto err; ++ goto qloop; ++ } ++ if (mpi_cmp (p, q) > 0) ++ { ++ pqswitch = 1; ++ mpi_sub (diff, p, q); ++ } ++ else ++ { ++ pqswitch = 0; ++ mpi_sub (diff, q, p); ++ } ++ if (mpi_cmp (diff, mindiff) < 0) ++ { ++ if (testparms) goto err; ++ goto qloop; ++ } ++ ++ mpi_sub_ui (q1, q, 1); ++ if (gcry_mpi_gcd (g, q1, e)) ++ { ++ if (_gcry_fips186_4_prime_check (q, pbits) != GPG_ERR_NO_ERROR) ++ { ++ /* not a prime */ ++ if (testparms) goto err; ++ } ++ else ++ break; ++ } ++ else if (testparms) goto err; ++ } ++ if (i >= 5 * pbits) ++ goto err; ++ ++ if (testparms) ++ { ++ mpi_clear (p); ++ mpi_clear (q); ++ } ++ else ++ { ++ gcry_mpi_t f; ++ ++ if (pqswitch) ++ { ++ gcry_mpi_t tmp; ++ ++ tmp = p; ++ p = q; ++ q = tmp; ++ } ++ ++ f = gcry_mpi_snew (nbits); ++ ++ /* calculate the modulus */ ++ mpi_mul(n, p, q); ++ ++ /* calculate the secret key d = e^1 mod phi */ ++ gcry_mpi_gcd (g, p1, q1); ++ mpi_fdiv_q (f, p1, g); ++ mpi_mul (f, f, q1); ++ ++ mpi_invm (d, e, f); ++ ++ gcry_mpi_release (f); ++ ++ if (mpi_get_nbits (d) < pbits) goto retry; ++ ++ /* calculate the inverse of p and q (used for chinese remainder theorem)*/ ++ mpi_invm(u, p, q ); ++ } ++ ++ ec = 0; ++ ++ if( DBG_CIPHER ) ++ { ++ log_mpidump(" p= ", p ); ++ log_mpidump(" q= ", q ); ++ log_mpidump(" n= ", n ); ++ log_mpidump(" e= ", e ); ++ log_mpidump(" d= ", d ); ++ log_mpidump(" u= ", u ); ++ } ++ ++err: ++ ++ gcry_mpi_release (p1); ++ gcry_mpi_release (q1); ++ gcry_mpi_release (g); ++ gcry_mpi_release (minp); ++ gcry_mpi_release (mindiff); ++ gcry_mpi_release (diff); ++ ++ sk->n = n; ++ sk->e = e; ++ sk->p = p; ++ sk->q = q; ++ sk->d = d; ++ sk->u = u; ++ ++ /* Now we can test our keys. */ ++ if (ec || (!testparms && test_keys (sk, nbits - 64))) ++ { ++ gcry_mpi_release (sk->n); sk->n = NULL; ++ gcry_mpi_release (sk->e); sk->e = NULL; ++ gcry_mpi_release (sk->p); sk->p = NULL; ++ gcry_mpi_release (sk->q); sk->q = NULL; ++ gcry_mpi_release (sk->d); sk->d = NULL; ++ gcry_mpi_release (sk->u); sk->u = NULL; ++ if (!ec) ++ { ++ fips_signal_error ("self-test after key generation failed"); ++ return GPG_ERR_SELFTEST_FAILED; ++ } ++ } ++ ++ return ec; ++} ++ ++ + /* Helper for generate_x931. */ + static gcry_mpi_t + gen_x931_parm_xp (unsigned int nbits) +@@ -812,7 +1085,7 @@ rsa_generate_ext (int algo, unsigned int + } + } + +- if (deriveparms || use_x931 || fips_mode ()) ++ if (deriveparms || use_x931) + { + int swapped; + ec = generate_x931 (&sk, nbits, evalue, deriveparms, &swapped); +@@ -841,8 +1114,14 @@ rsa_generate_ext (int algo, unsigned int + transient_key = 1; + gcry_sexp_release (l1); + } ++ deriveparms = (genparms? ++ gcry_sexp_find_token (genparms, "test-parms", 0) : NULL); + /* Generate. */ +- ec = generate_std (&sk, nbits, evalue, transient_key); ++ if (deriveparms || fips_mode()) ++ ec = generate_fips (&sk, nbits, evalue, deriveparms, transient_key); ++ else ++ ec = generate_std (&sk, nbits, evalue, transient_key); ++ gcry_sexp_release (deriveparms); + } + + if (!ec) +diff -up libgcrypt-1.5.3/src/g10lib.h.fips-keygen libgcrypt-1.5.3/src/g10lib.h +--- libgcrypt-1.5.3/src/g10lib.h.fips-keygen 2013-07-25 11:10:04.000000000 +0200 ++++ libgcrypt-1.5.3/src/g10lib.h 2014-10-21 15:05:59.459190556 +0200 +@@ -195,6 +195,9 @@ gpg_err_code_t _gcry_generate_fips186_3_ + int *r_counter, + void **r_seed, size_t *r_seedlen, int *r_hashalgo); + ++gpg_err_code_t _gcry_fips186_4_prime_check ++ (const gcry_mpi_t x, unsigned int bits); ++ + + /* Replacements of missing functions (missing-string.c). */ + #ifndef HAVE_STPCPY +diff -up libgcrypt-1.5.3/tests/keygen.c.fips-keygen libgcrypt-1.5.3/tests/keygen.c +--- libgcrypt-1.5.3/tests/keygen.c.fips-keygen 2014-10-21 15:05:59.424189766 +0200 ++++ libgcrypt-1.5.3/tests/keygen.c 2014-10-21 15:05:59.459190556 +0200 +@@ -190,12 +190,12 @@ check_rsa_keys (void) + + + if (verbose) +- fprintf (stderr, "creating 1024 bit RSA key with e=257\n"); ++ fprintf (stderr, "creating 1024 bit RSA key with e=65539\n"); + rc = gcry_sexp_new (&keyparm, + "(genkey\n" + " (rsa\n" + " (nbits 4:1024)\n" +- " (rsa-use-e 3:257)\n" ++ " (rsa-use-e 5:65539)\n" + " ))", 0, 1); + if (rc) + die ("error creating S-expression: %s\n", gpg_strerror (rc)); +@@ -204,7 +204,7 @@ check_rsa_keys (void) + if (rc) + die ("error generating RSA key: %s\n", gpg_strerror (rc)); + +- check_generated_rsa_key (key, 257); ++ check_generated_rsa_key (key, 65539); + gcry_sexp_release (key); + + if (verbose) diff --git a/SOURCES/libgcrypt-1.5.3-urandom-only.patch b/SOURCES/libgcrypt-1.5.3-urandom-only.patch new file mode 100644 index 0000000..6ced5fb --- /dev/null +++ b/SOURCES/libgcrypt-1.5.3-urandom-only.patch @@ -0,0 +1,38 @@ +diff -up libgcrypt-1.5.3/random/random-csprng.c.urandom-only libgcrypt-1.5.3/random/random-csprng.c +--- libgcrypt-1.5.3/random/random-csprng.c.urandom-only 2013-07-25 11:10:04.000000000 +0200 ++++ libgcrypt-1.5.3/random/random-csprng.c 2015-04-10 10:31:39.797534903 +0200 +@@ -855,7 +855,7 @@ _gcry_rngcsprng_update_seed_file (void) + if ( !allow_seed_file_update ) + { + unlock_pool (); +- log_info(_("note: random_seed file not updated\n")); ++ /* log_info(_("note: random_seed file not updated\n")); */ + return; + } + +@@ -1120,8 +1120,7 @@ getfnc_gather_random (void))(void (*)(co + enum random_origins, size_t, int); + + #if USE_RNDLINUX +- if ( !access (NAME_OF_DEV_RANDOM, R_OK) +- && !access (NAME_OF_DEV_URANDOM, R_OK)) ++ if (!access (NAME_OF_DEV_URANDOM, R_OK)) + { + fnc = _gcry_rndlinux_gather_random; + return fnc; +diff -up libgcrypt-1.5.3/random/rndlinux.c.urandom-only libgcrypt-1.5.3/random/rndlinux.c +--- libgcrypt-1.5.3/random/rndlinux.c.urandom-only 2014-12-12 16:51:56.000000000 +0100 ++++ libgcrypt-1.5.3/random/rndlinux.c 2015-04-10 10:34:13.615111926 +0200 +@@ -132,7 +132,11 @@ _gcry_rndlinux_gather_random (void (*add + if (level >= 2) + { + if( fd_random == -1 ) +- fd_random = open_device ( NAME_OF_DEV_RANDOM, 1 ); ++ /* We try to open /dev/random first but in case the open fails ++ we gracefully retry with /dev/urandom. */ ++ fd_random = open_device ( NAME_OF_DEV_RANDOM, 0 ); ++ if (fd_random == -1) ++ fd_random = open_device ( NAME_OF_DEV_URANDOM, 1 ); + fd = fd_random; + } + else if (level != -1) diff --git a/SOURCES/libgcrypt-1.5.3-whirlpool-bug.patch b/SOURCES/libgcrypt-1.5.3-whirlpool-bug.patch new file mode 100644 index 0000000..f64c94f --- /dev/null +++ b/SOURCES/libgcrypt-1.5.3-whirlpool-bug.patch @@ -0,0 +1,28 @@ +diff -up libgcrypt-1.5.3/cipher/whirlpool.c.whirlpool-bug libgcrypt-1.5.3/cipher/whirlpool.c +--- libgcrypt-1.5.3/cipher/whirlpool.c.whirlpool-bug 2013-05-22 18:02:54.000000000 +0200 ++++ libgcrypt-1.5.3/cipher/whirlpool.c 2014-01-21 15:45:51.308919415 +0100 +@@ -56,6 +56,7 @@ typedef struct { + unsigned char buffer[BLOCK_SIZE]; + size_t count; + unsigned char length[32]; ++ int bug; + } whirlpool_context_t; + + +@@ -1185,6 +1186,7 @@ whirlpool_init (void *ctx) + whirlpool_context_t *context = ctx; + + memset (context, 0, sizeof (*context)); ++ context->bug = secure_getenv("GCRYPT_WHIRLPOOL_BUG") != NULL; + } + + +@@ -1316,7 +1318,7 @@ whirlpool_add (whirlpool_context_t *cont + buffer_n--; + } + whirlpool_add (context, NULL, 0); +- if (!buffer_n) ++ if (context->bug && !buffer_n) + /* Done. */ + return; + } diff --git a/SOURCES/wk@g10code.com b/SOURCES/wk@g10code.com new file mode 100644 index 0000000..5e193e3 --- /dev/null +++ b/SOURCES/wk@g10code.com @@ -0,0 +1,2007 @@ +Login: wk Name: Werner Koch +No project. +No plan. +Public key: + pub 1024D/5B0358A2 1999-03-15 [expires: 2011-07-11] + uid Werner Koch + uid Werner Koch + uid Werner Koch + uid Werner Koch + sub 1024D/010A57ED 2004-03-21 [expires: 2007-12-31] + sub 2048R/C3680A6E 2006-01-01 [expires: 2007-12-31] + + pub 1024R/1CE0C630 2006-01-01 [expires: 2008-12-31] + uid Werner Koch (dist sig) + + pub 1024R/37D92FFB 2003-11-17 [expires: 2009-12-31] + uid g10 Code (code signing key 1) + + pub 1024D/57548DCD 1998-07-07 [expired: 2005-12-31] + uid Werner Koch (gnupg sig) + + +5B0358A2 is my main key. +1CE0C630 is used to sign software distributions. +37D92FFB is used to sign certain source files. +57548DCD was used to sign GNU crypto software; + it has been superseded by 1CE0C630. + +Please note that I use a subkey for signing messages; some old OpenPGP +implementations may not be able to check such a signature. The primary +key is stored at a more or less secure place and only used on a spare +laptop which is not connected to any network. If you find a key +certified by this one, you can be sure that I personally met this +person and checked the name part of the user ID against an official +looking passport or another suitable photo id. My signature does not +say anything about the email address (I merely check that the address +looks plausible). + + +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1.4.7 (GNU/Linux) + +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 +Ooh6BBMRAgA6BQJEXmVkMxpodHRwOi8vd3d3LnNjLWRlbHBoaW4tZXNjaHdlaWxl +ci5kZS9wZ3AvaW5kZXguaHRtbAAKCRC0deIHurWCKcwdAJ4hvG79xMFKtYL0GGP8 +WuvvxnMnzQCfZUjHFhMNMGgrCPthD6oeNaw2FxCIRgQTEQIABgUCRFz9JwAKCRCK +o2Kv6XIyzVjaAJ9MSW3iP1fUZqr7xdbj/PLkHLzJeACfZNe6IgDrJk9E3a/8IKZi +E4iYtqWIRgQTEQIABgUCRFz9LwAKCRCn31hycNRMI+EXAKDRHf6ZRUGa6T7Uosgx +huo5I3sK6gCfRxthF9FN1SXK11O+tjRS1mwN0JaIYwQTEQIAGwUCNxrPkAUJDMl8 +gAMLCgMDFQMCAxYCAQIXgAASCRBd4kmWWwNYogdlR1BHAAEBXcIAnjv7ON5AiwzC +LBwm9h9ywufXJQuVAJ9RMq6lpPqnDly6UCKz+kGt0EplyIhmBBMRAgAeAwsKAwMV +AwIDFgIBAheAAhkBBQJAXdnoBQkTa4v/ABIHZUdQRwABAQkQXeJJllsDWKLs0gCg +y5RdOqhFvwUFYWj+dHb4LGt7xi0AoKduFxGMuM/loPShQnjvk/VVFesAiF4EExEC +AB4DCwoDAxUDAgMWAgECF4ACGQEFAkBd2egFCRNri/8ACgkQXeJJllsDCRDs0gCg +y5RdOqhFvwUFYWj+dHb4LGt7xi0AoKduFxGMuM/loPShQnjvk/VVFesAiQEVAwUQ +O0HCUNImKUTOasbBAQFLZwgAkgMC/ximskOjL/CxghgdkSWkDFdpEr3XYhzUdLes +WgN4AM28mGZZKA9la7dXXRrKYkxhX8mpL4C3Q9LnrafP+Zn1c8mTuNIxX86j7iZA +IksoZ4D2csN8NSMYT9pKK6jZP1IOckCFBBI0W/yMGUGulDitWj4TwIArf2xQkV73 +//////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////// +/////////////////////////////////////////////4hGBBMRAgAGBQJDRBuk +AAoJEOrUtZD2iZvAafoAoKReCbMFRrpwzb2tS7M6iHDbN9E+AJoDy8nLf8A4f/EV +m8OJWOf1pPKQGIhGBBARAgAGBQJEBYJRAAoJEG9dWWgc1S3oeAEAoJ5eVEYwpcqY +78oHQ+2EWJ2R06BjAJ9mWcCCynLCjGXBJoYq6YLVaFCIFIhGBBARAgAGBQJEBgo0 +AAoJEJrJ0ixjXGNLQMMAoIh/01hmpfi1faVNvL22r7ihJjZNAJ9D9+xBrz0F2TMg +YmUjGBlCIcwS2ohMBBIRAgAMBQJEBisnBYMGUqnBAAoJEN/mV5IylcXNlHAAoLcf +b8fPerFL+kZ/yqTlqUFFW/FuAKC2IZto5Zu7WYDUrn28L1sh2LZe/IhMBBIRAgAM +BQJEBitnBYMGUqmBAAoJEKDlFb85iAlULdYAoOSbU4vrwlbc3XzB5hJVNFjbNYOe +AJ9pvj47lRFbnCyttUM2oKQiwW5AyohjBBMRAgAjAheAAhkBBQkTa4v/BQJCWUBy +BQsHCgMCAxUCAwMWAgECHgEACgkQXeJJllsDCRA6xwCfV3paxYsk7KQmrtOUxNmZ +b004OQoAn3uq9imOpgxqsXhXaLfz5IqZu5O7iJwEEwECAAYFAkQNdeYACgkQ/dJ0 +ek5GOmql+gQAmRKGvqN8lINhyZL1ClLN9+X5BTOGyxi6Fb8SBBqElGbHVJwLncxn +LmElgudpGPyAS1wZ+9aymUjUkPyVltA/lw6AzkLfqlFGG2MnOVi3WejwcyhSbL+L +XJ3N6CLRpVajI5j8+mHWe9Cdo2NGwMHfgIg7xeZOgeJZixPEe3Zhvh2JAhwEEAEC +AAYFAkQPSIoACgkQGioH6hxXudmtvRAAiX8daFke18xh6V0P3tFtkzZo3xCGfqus +uoAHmgByNeZmhoFLyA+UgUUGJTKiLOIgVxmcZ5srr61I0dsY95iE/LCzzcqWsfWC +mbr/3d/nrhPa31rGfucT95wxC4SeOXxBhfmd0muB/ZRhqGnHE1VXPHuDYBF70Z9J +Sy3Tpdcx6eDvG/rfY2qUqiLn5wi2EG6EyAUJNXJ0GMcv2qoBGvOITtBpvnQJAniy +120ig36q/SCggdM2nr+UIDnLBo+p4gvmfqLEZ3S4z/RCApKfoqFOiWK7P7N42My/ +iQyZAEn/kjiCm1s470LMqXAJZC20e7ZxJoLxputm1Nd4LL8oP0n6xYQiOXxgsRzK +abBb8ZYHoYujGEMcODqXSEvsES7kP2DMenYBwmT/ceqk41VCV4w4eYQscDCuVm0/ +oxoqlcplLPaoptyvES0VjlLwW8LeMzc3AMPOnxYamBvMYlBpoN2VmG5dDbnFCPtc +o9LPuMYfBh+KWQ4m7tQbwP689bcR1d85hyBZIRBkojz3C8FRZQZcs6VK5n8tKV63 +YsDSacbfcoFEN54uOeVZsLEqR9vCG98g4/nxcGWwveXY/9nyqw8HaeFxisl0xkmK +sP+KqPNt2dfdqBi1PjNhO0NmViCa68kJRwWkdkOtxIaKYab7w454D7A+YwaX8ptM +m3jwFqX5bUOJAiIEEAECAAwFAkQFDZkFgwZTx08ACgkQbjbvGsyNqzDkcBAAhZmu +EA5Pk1Dzd1QYLex2ZoN/XrXaZZ3WpcKlQSPvz5uuW9PV7lh8ixgHCTPZPh1EvrKl +aVtgciIxlUSPQTAdTVdDK9V/zUhV918GG1KpWvaf+cgCv2kdF/V9+iNQhrpPPxuw +J1TfByzSfqdHyIuXrao2BzhdMtXPf3wFY6CtFKCZ+FoShsV2Fl3SsJRpxz0JnqJY +N9njPTIYCrrR1Np+u5CcMO4e2erl0IXaffDQmeJMZFJ1fiZwJIpyZYOS61T2kUz4 +6Y7RkV0kO0nWuQiv6UAAmr1DlE9WtpdbqJVDTFQUW39o2kfOBXQrHz1NqfVxu4/a +sNCMmp/yK6RK3paN6AyD0Jhm1ipAOySNsVsMbvWZ1q9rlaPWscCslcJVw0t30a7t +U/DtQtF0nL8HJE8fdRXaKihHlCxU8UEhKDjM+R9wMPDkDdaY03jz7e+2N1lVQqQG +VAGvNkUBdpaOqwwtJDoAF8OeBfJX+zFS9whvBSQjPimxnQ9B+qdZwTuO3uFrGrXS +dtCGKsrrwXOZnJNU4lNK8BxPUQwGtgAEj/5zPLb4T4Lxsm9aDiHwFuYR2AQuO79Q +68CbMGYr4i7JdSudLg8hHsBQT8ZweBBbUu+Qym2xGPMGbUOmeiIkNP6mlyY8TQG7 +5ZdfHr7/NExOtgzwPicrmz6RB5GuO30iMiMeqSSJAiIEEAECAAwFAkQFESIFgwZT +w8YACgkQHRqO3OFAoFTM5A//aNCnL0pwr+ZWsFiuCt5J8nqN2V7VeRoT2WdKF5HL +pIrlLLozUdd8S0Zi9u7PO8GLD9QOUGc4y+LnSTpDHb8u4t9OYrRNAocp6gIZmxjG +5KuLPSUBc9ct27p/G0yIpgtgECCP55fY1XRAhkNnXWLVzsueEFdhPieO0gPqeVqP +zfT+oDhx+bLVH0YtFxOYDeV2NewtUpuBnr4ZNRD0WrhW5F8yecuwqeFsF6YTHMsA +L96xmlzNe3wx0I+qvWP3qHGWZs9DBMroBXL9BhpyzWA2079YSUC2dwxwnGAVSAbY ++c4bHr3On/GL0nhfwiyaD+8zSYAOey3xgYKJeGIWSA7TvcRic83khBroQN5JLK3D +N+jM3JJqhj0zX/9kz29z7Up1cbnhJAEJKvPMhTh8VRafxHkYYMYqru+W+kkuHupC +YgoJu2DeInhclmDjiE8CKW18w5jNjr7zH6tN8P6dnOazUeJyevBfipXEGLA3TT2j +VFbf9zU7Cb7DaxMrqBaOSUpvp0LQkFT/weiyivKaMIyZ38HxNdfFAi4dTEFLHX+s +osZWUZEODZ1rxBmAyP3A/F75YJolHmoZc4w72d3QD4HGeVD/3cWnREu/wvdko/2F +ZACO8UvUAAP4UhXn9QO3a0+tFmCzkTuE+uuVrnfpT2a/4nRiJ4QADy0zwpTT9DPA +HZ+IRgQQEQIABgUCREihIgAKCRAFi1rNRBxfge9RAJ9elNg4P6EYwz1GpslAJj06 +Fq7VYQCdGtSSX7L2xWY45o0QUEfU0nQVh0mIRgQQEQIABgUCREjJ+QAKCRCnL/Zs +Qr1kXRdpAJ9QH3CweThQQgRcKs51pa6ig43RvwCeNdI5Nb+4SMtOEn+vCZZkbkkZ +TZaIRgQQEQIABgUCRFsJZQAKCRB/3j6P8z4/xk2AAJ4wsIbdZzp82lspsNIhHurH +VwUjgACfXS1Jg0jHmufMTiJSSd73hpD2mZKIRgQQEQIABgUCRGCHvQAKCRD9AQSw +4jPImI7/AKCyxcVN5/xT6dsgrzxbi/nXuHLNegCcD98a67j7vpc2SujQQHzY2IFv +rWWIRgQQEQIABgUCRGCItQAKCRD9AQSw4jPImHp8AJ9XcTvscy3DOWTayYxhHC/q +VDKb0gCbBd5nO24QFPTZyXcDoXIR0hgm14CIRgQTEQIABgUCRE/tdQAKCRA/0h0q +mjpVWG8XAJ9+ukhr7X2AcbdJuxDSRCwyUmYO1wCffLzymfNFEzhtNOZtaQF1bAHl +v3OITAQQEQIADAUCRF3UigWDBfsAXgAKCRBbqJPk7D6Y33KuAJ9RAKZvdGKCczUu ++oNwzVggwGE+qACg02JOmubDdtMdXDmj/uKkqmafukqITAQQEQIADAUCRF8XTgWD +Bfm9mgAKCRC8EAnaDpclP/ebAJ9ONfFPcQ8MAds2/dYUmViFlAIKKgCgkDyxYaAY +eCh89VLSpsbbymWNDFmITAQSEQIADAUCRF22QgWDBfsepgAKCRAyNS1FZ/eCZB3D +AJ9KBPUTTAcmJLEQ+fOcWNOJwpF2JACfaUv3jKhFU5tMS1cemDujhEiF89CI3AQQ +AQIABgUCRFC2nQAKCRDR2VIECemh1RMWBf0aP1ofgRg0fXsVu0wVJIN1H7n+uOIY +WEVnPf/ZvtXAmr1P9koiOAl24jEWnpZA6hxzsC1zWEmGi0Zw96EhuFusDesRoQIE +ZnNh92qm4uk0hJ0S2JItWs2H2wxc9oGAJOAICqxO80gDBJICwqqMdbevRgwHFmgc +cMYpnE6YSrXgPVgC+dQNKBiPpm4HOL86EEMzD2blzqk5YSngn7efbDwWtDSABQby +9QCRptwKQYOzHCi4gaK/g8I9K9dJf5IFXSyJARwEEAECAAYFAkRbcFcACgkQZ02H +1ZEZDvnSNAf8CLIb+JRnGn8LqL/RmX51Ds8pPzOtmgwWNgDf5pIZm5jTtZH5o7z0 +qZ5FLBFok64+Gtusjh3q/RONlvZH7wF4Tg07Hsx13t8Ie3wNrhfjkScpEDK0UtOf +FzOICVZTqjIVrex04yxDO+yV7reBm4AsWsqIEfOrwKY3cEiHpGd5/lC+wHIk9WxJ +LbwjachXEwVnILZLHWZFFVXLYJigHwQjyu2keZZqx2tQcS6woZR8+XMy7WVD4D+D +Db/BcWNjiSsqbwaH1FFqOqRpkOuHwt7JLxsdXavmRRkve8bIICb+SaM5Fy9/YYKT +TcfT7WZ+KhcKSq95wxKWnSFAbILVzFvIAoicBBMBAgAGBQJElY7IAAoJENwG3M95 +JPpzBwMD/2VB1PQa9R5MbuIFSHXQztimwz6joPetCi7fmJczzTYGCg7PdEprwJQq +H3dmAGieogM/o5NuuV2SGMdIDao3cYhCLFAQtIHCCMVQovqcDR5gSyDpD1j86x31 +OU7lMb6/YKoTcOTsoQ/zshz9I3stwo2gH6n84ZpskH5JR6iw9LgaiEYEEBECAAYF +AkS9USsACgkQxKXVjqqse7z4uwCfSobUmYCrjQx18yvZI2MMVIZCSnkAnjvQJfqP +XmH2Po11vZMNiRIX8hmDiEYEEBECAAYFAkS9OqsACgkQOOnzljbgEa9T0QCcCGOA +6GP6/I9Qp9CO3JU2k2gSi4wAoKiUukIn5lcTF7yrbiw5ZYZg5LiWiEYEEBECAAYF +AkTCe2sACgkQQggFxokHT60sKgCgnK85XyCxKr4itQm1t9ycMcYCO4wAnjMiXOIv +dR1bzKum0oCd7XAgkCtaiEYEEBECAAYFAkSNRFUACgkQp6+YGoOsM0qlWgCghjwM +VOscLRd9u4vRAW3EK7shbVQAn3YjbCUTJdUkM+NIE8CRT3+0vQhAiEYEEBECAAYF +AkVXpxMACgkQ9LSwzHl+v6s6AwCeIMTlicVjKpG+5bmJF3lU8d4EsasAnjdIZ//X +QTCVlBWswexfk+fnOGxfiEwEExECAAwFAkTKoAoFgwWONN4ACgkQDQUpyRODzWtt +HgCeM1Lxur1xrAH8yGJHmmjVZrYWgWoAoIDCzJbJzfIdRC3b2ltUMuJj9rW2iLwE +EAECAAYFAkVbQNQACgkQ7aIelLVlcW9CzQT8DE/+9x8eHNJRYPMpXRp5Y6K3idr8 +ZR5qwGCe8HejIX2pRnQ1rLfOerofNu067dhsaJ0Zg0O30K+QFgfFLT3WKVszGJGq +GWxGYFAcof0dc0I5KUxWY4uUe9TjWILdbIKJuo5Lpu8AqGcCQHHd68GY8KyH1eTQ +L/R5xNkuCqCrgP6LzVzF1RnnmbDwkQ/Yv+/dfx0x6aRRhe86l3fcoEVXHYhbBBMR +AgAbBQI27UjqBQkMyXyAAwsKAwMVAwIDFgIBAheAAAoJEF3iSZZbA1iitdYAn1IJ +bSJ46kvsBjq8X44hoybDZlbWAKCS2jR5Z+CmMC5WDqNepHXAe3alA4hGBBARAgAG +BQJF7HurAAoJEM/oSL/8Z4Wi+XoAoM2fLIgxw1153EnODrrHXDJ77k3mAKCUenHB +3eaF/Kh22kX1wHKAuaZbbohGBBARAgAGBQJF7eQvAAoJEHe+WRN3SdnZs/AAnAvH +b0KGLdRdjXYeblfUmO3Fhq1DAJ9ZJ3fwyt8ziybro7B/sa7Rob9C94hGBBARAgAG +BQI3NyPFAAoJEPbu3yAYS8TZh2UAoJVmzw85yHJzsXQ1vpO2IAPfv59NAJ9WY0oi +Yqb3q1MSxBRwG0gViNCJ7YhGBBARAgAGBQI3OvmjAAoJEHUPZJXInZM+hosAnRnt +Ckj/70shGTPxgpUF74zA+EbzAKCcMkyHXIz2W0Isw3gDt27Z9ggsE4hGBBARAgAG +BQI4FA4ZAAoJEGAHkIBzx/NPiNoAnR3kwD7rJhHzdm3ZIo6VtYKcQbxqAJ9ZMy+z +IO7QuKapasNn1d5EVMtWuYhGBBARAgAGBQI4KmIeAAoJEOPyWFQSjw55D5AAoJs5 +OxzJSdYdKsOjh8jLQxOESOE6AJ4vgpvtNaR384dBJxUE7yxNTPT7aIhGBBARAgAG +BQI5yjsOAAoJECu7Q6bwnq8Krl8An21vcRhdgB0GpAT2pIetcSpgvFhBAJ908rX2 +Oaq048SI9h2RSjeULkKWEohGBBARAgAGBQI5yosvAAoJEBemQW33lI/aJm0An2EG +MaYqXTBgcWzXfI2y/UQ5h95zAKCE5mZwycF86Rzbki2PKN3OWIR184hGBBARAgAG +BQI5yp13AAoJEDX2YXxROu/ZXu4AoIEI7IxYY2iDtZVh3z7rJ9HanYUWAJ96zltF +0noeuFfaPlSLR9i2Z4JjQIhGBBARAgAGBQI5yzIoAAoJEFGs9q11voCXCFYAn0Ua +tBtnwnGThaHsvbmRgJFnLSrEAKC8OpVIXXmQ4FC6wwuzkESJOwpzLYhGBBARAgAG +BQI5z6dSAAoJEJFazEWo9ML9CKsAn1hjHomefMrLmQgD/SLF92inEj7XAKCZ6NQj +jowDIaFo1Ih3LYC2V/foE4hGBBARAgAGBQI50N/VAAoJEG8ji8JP2loMXyMAn2/x +njAA/MPOIauf2lEDAr1alGKgAJ9O0irlmLGSxFLj1iIGGNMqAcicb4hGBBARAgAG +BQI50gqxAAoJEL/hIGVrIUiavIwAn3X9tHarNyFjjx4BTHWG+VRflpCVAJ9Oarr8 +hwd17oPHLMVoOkcEn0AUwYhGBBARAgAGBQI6TMtFAAoJEO1Ggcm/Pfm0VK0AoOmq +M6WIghAz1QB3ueP/P6uPBSz/AJ4r4hvX48SJz2kigfi10ZkI3Noy2YhGBBARAgAG +BQI6iYHfAAoJEGKIBNsg/Gz2BmoAoIDLKhiTetSbjkJGOTIim+FD0KQcAJ4jWMEG +/oZRMyRe6pzxAodDAMavDohGBBARAgAGBQI6wQjUAAoJELdWp4yIKmxLt9IAnRLE +nhbSeSs4g+ZfwrwIVWbfZZ0FAJ0a5m1fB5J3V6d/gzaERILHGZP65YhGBBARAgAG +BQI6wdEpAAoJENLwolOfiErIj5IAnjhWsrezZHMpsEwtlCjY48rpDQ7wAKC6v2zk +zWRArc7WCDA0Nla82d5uiohGBBARAgAGBQI69XmLAAoJEOwOr3E2d4Al3a0AoJZS +Mehtg5CkhigYWAoLMssBQVy1AJ9jyRqwjqL9C0vIwjA9l6OE+6n7I4hGBBARAgAG +BQI69ZsBAAoJECwYoCq0xfN/hOAAn32uMmiej4+LhWWO3Vbojn5LqExPAJ4iHcNA +1ZBwbsZTafTwIJYc7chPqIhGBBARAgAGBQI7RW07AAoJEOd14yTbQbOHsd8An1yz +zbHDOFMbZstP7eWIIPZQ1hEAAJ0d/T/XibRHgbTD32xBmHNdAAao5IhGBBARAgAG +BQI7RdkAAAoJECP6tfsIFswbiYAAniGpPgPfCIXlUqMFxuCeo8wQON/TAJ9iBQPB +AfxJENa5+zhJhTV/vjzWcohGBBARAgAGBQI7RfEWAAoJECeGwkR/ikAX0sIAmgL5 +u6S/i4qGI/6CgwUNaSQI/lKjAJ9dFvESq2G5TGeC9dUdkzvcTrxZ+ohGBBARAgAG +BQI7SA8WAAoJEAYGnPKWlFfwy1gAoIn2x7UoudCcZkq9fFqH3lXFXAF1AKCbPfWh ++v7fYJDt+Go144iEMXNKjIhGBBARAgAGBQI7SCdfAAoJENdZXTdLcpYlMeYAoIG4 +Rtbs73YBzWPKAreHHOk3x1ERAKCbkcPKtpG87Z7fE0OJo4kyDXAV84hGBBARAgAG +BQI7ScGgAAoJEFCP02O8k2g5D44AnA0iUFGQQT/+Tr1uPENwVJFJEUkJAJ9TI6nu +FkxRBAPByuYfig3KkdGmSIhGBBARAgAGBQI7ShVXAAoJEJYkg+FWYsc0mAoAniab +ffCzKtNqvVtWyuYj1LwpHLEmAJ9XahXKF3LV1ZzI+d8/M3wGltAXMIhGBBARAgAG +BQI7SxcHAAoJEA6nVrUUSEP1zBkAnR9bvbZrVGGNxMVS3U/x9iCEAlNzAKCOvWOG +de0Q4eAY9oJicJhAJnw8G4hGBBARAgAGBQI7TBfKAAoJENcNX1hgPNB49psAn2s7 +nWGUjJkFjvOcWb4NLkwd64WUAJ9w0sq718SKZr9AnJwbVELuTdtZEohGBBARAgAG +BQI7UbllAAoJEOQ7FTzLRn4nGywAnjaUSTkvQGe6u24V9rASYJSi5aE7AKC5uRU5 +2OogMknz2WZcAFXhOszCcIhGBBARAgAGBQI7UsQ/AAoJEDv2CcaLr829RewAn1af +L4cQFgnkWTdyJ5b2C68RU54OAJ9UDuvg90FI1/tGETWd7aWQ00nekIhGBBARAgAG +BQI7V0JfAAoJEHkWLzb39qrZJTcAn3IOE7LNwvTX+jYsjgB4VzuCS4bZAJ9OeSB2 ++ItiDuU0C0kItLZOJLWVX4hGBBARAgAGBQI7ZzpZAAoJEMALDTYh5T69nGoAoNOy +DdfzGl5/vMneDXKff+9t4BAYAJ4zQqBgAHHG7wglRNvbFwTQL1KPDIhGBBARAgAG +BQI7mESOAAoJEJAtvZGMOKkKasAAn3MgeJKyRasnh6Cs0WA6lvCQ1Hb3AJ9qWt1A +3ijOxVXvC4AkMs9DHDOCaohGBBARAgAGBQI8B/tdAAoJENrSsF1fPDGFRfIAnjKG +GhTe7/1Q5rmLfhtQVw8c3LrrAJ0fHwHCMgY0n3wdMhCMGgOzvV+2cYhGBBARAgAG +BQI8CBHSAAoJEGpYgt+EQEYCfc4An0tStG0TlUgfvcF+IPsRBNKYRAE6AJ93rUiz +BOYc7IrCETI1LBmwQ3u/mohGBBARAgAGBQI8I7VUAAoJEERyU/QK/Qyo7/kAmwRN +5UTM8isU2z1Hfb/pwfBFar+HAJ9A8T5ACJLq4gLsLTowsqUwzcncsYhGBBARAgAG +BQI8XatAAAoJEO7w2zSzISYDcL8AnjHNEJjktHLSTl9SfWtw1pDMlHX+AJ94iLJW +e7LZDDotVXchOX0dmA7zRYhGBBARAgAGBQI8cOPjAAoJEBjNJaUi84rzZZ4Ani3Z +JEZHMh1SrbZemfSEBMRPoGjbAJ0ZKPuwUDruY1zHxmq4NaxNsw4bBYhGBBARAgAG +BQI8cScSAAoJELHEcxc+e0tz5CcAoN6nqXU7IjSrhmAumtUZSWUwapIhAJ9husqb +wqVgC+Ny1mzG8sn/62MUqIhGBBARAgAGBQI8cUGCAAoJEDoapjWQmlQGL2wAoM/Z +l86P5wuuJsdNyBYC/KBbgQISAKC/dTSC18RmK5GjpzPtgottFLwN2YhGBBARAgAG +BQI8c3iDAAoJEKPgudJ6NPreSe0AoKUgoBkPHjHn77A7BdA5RGc7gBzaAKCtUxcL +iu2aMFECclqdbSg7TQ28d4hGBBARAgAGBQI8foHzAAoJEI47c57dK8yd/3YAoJwz +Jy52t8j7JMXlX99sA20xy8X9AJ41gsOJX2GrktC7phr/bhzfT2hK4YhGBBARAgAG +BQI8gGPBAAoJENeDa2wM2SDnRD4AoLeQ4mX0RZL8wD3nEQwiKd6TnVMJAJ449Qgx +Pis4NkYivWe90DPAdCeHa4hGBBARAgAGBQI8gXeZAAoJEP97262ZQ+PfpZsAn0vW +qc/oBB7EVehC0uDbQi76ybEZAJ9wHsaYrHT/vCsKJYnicGlT4rTdoIhGBBARAgAG +BQI8jMwkAAoJEIW5kHXCkQ5BqIgAmgKq8F5+pH92g+8LLNa4EJqwrSSiAKCFOron +6MQbm6dvmI1upI255BTA9IhGBBARAgAGBQI8lzQ6AAoJEKHoAnDadDOWhq4AniwU +UPAgFczzvDk89kzBamCyGxa3AKCtqiaqI5hdvkx7RQh89IYYgQHpDYhGBBARAgAG +BQI8lzY4AAoJEINou1lm+8GMc8cAn3K2eck8I5/UodUv8i9zASgbPLsVAJ9KQuBo +CLG22sXH9UAOQGMBYj3DxIhGBBARAgAGBQI8sTgxAAoJECV7eU7GbKA9KVYAn0yC +fPDhTRZZ1BaDWXpg3W3eGahLAJ9cuWcgpeUmJKhUxolbZILSCBISu4hGBBARAgAG +BQI8sYLgAAoJEHrriu1HOknJwYAAn1JUK6w1G+/G/dyRL04QP39WWp5CAJ4uOPGc +WoMz454/7x998iteGoJ6tIhGBBARAgAGBQI8sY+DAAoJEKHFknzOXc4OKooAnR64 +2KrjbtmqYVoIBuRNBuswluTBAJ9TUCZipExFLG2p21TgcdRucL2JHohGBBARAgAG +BQI8soc7AAoJEFZRM6RQ1Ku5PfYAnjCXOSrwtoAB4AlY7+h5+wCoGPqzAJ0RSK47 +p29Uoe++eNlEaFgFZrjzdIhGBBARAgAGBQI88iBUAAoJEF9fNO6guz3r/T4An3Ft +eQ9nEuFE5J9dQUqp/qYKwOCiAKCsyw3O/F9zhQ81V0zr5PFfPTrIRohGBBARAgAG +BQI9bhyMAAoJECjG9WuBfDVoTz0AmgKaxb4IBBwU1Ufils5tGd5fYoyyAJwMNkLS +dTJZ89HLTcEicDkTPO/wEYhGBBARAgAGBQI9hEZLAAoJENQ8swWV/so0s8gAoI1C +i9wh9lGHIhAGq2VPR9GWCCFkAJwOiNWidBYFohdm3f44FmgS9o7XeIhGBBARAgAG +BQI9heVOAAoJEHWXOhDW0ISm7f4An25SkqiaIaoWhWsLVz7PE19VKmP7AJ46sLpo +RTeGAAHs9+oCLUwfQcXJiYhGBBARAgAGBQI+NwZiAAoJEJEIIZ7c3okKnhgAn0ss +iItbz54kDqvMS34Iw8RZJFRGAKCUhWx/Loa8ATGvGjiEZIzfbkXWNohGBBARAgAG +BQJFw8E9AAoJEI6qh0Q5KZ0x9aUAnRH3Am3KgMUSVESSGNrcPoedERQfAJ9dQHjn +N0aUe9tve7Q9LhV6GLFmRYhGBBARAgAGBQJFw8FIAAoJEPpEYiHEJCXtFn4AoONK +25yb2NNe2E1iX4JD6o49OYuyAKCWANajeEtPJPZl92cI+J3mf95c9IhGBBARAgAG +BQJFw8FRAAoJENQGMhwHT16EZrkAnRIN5dDSCkglQ2Np+U5yhcWZklHzAJ9Jd59z +z/N2Y2xwmnw3UsSAgBvZKIhGBBARAgAGBQJFw8FYAAoJEC0JcXhKCKrfPTwAn3JW +FQ92VKe9lFsOEafQvkspSV7yAJ97j7dfPPsMl4nr/vA0JsuxhymL5ohGBBARAgAG +BQJF6vbAAAoJEE44UvTDfB0JHeIAmQEfdsSzRZbzKOLcEZhboeuuwUQMAKDA2j8I +/9v8LC9JQvz2zgOi/aFYA4hGBBIRAgAGBQI9BFveAAoJEI/xGsXf6A+y79gAn1AA +l5dIQ3xnhHWxo4SGv4UmmQq5AJsFeEnXiZwaF1dtlQRHpJk38xyhxIhGBBMRAgAG +BQI8r1OKAAoJEOqcZuq5+NbZhHsAmweBWes+nZkidnqQSHXqEvChyzYRAJ9mXFAy +n7haVVQ7lf2zIaY22xyUSIhGBBMRAgAGBQI9BbMDAAoJEKFjDI904LdmuOoAnRcE +ls3xJsrr3455jT8wsr3TtkdnAKCUZdSG5f9oT143p5dX9PKUC04WQIhGBBMRAgAG +BQI9BkQfAAoJECm+XSJo/VSfBRwAnA43cgjzFo0m61yglRYw7bmqZeNvAJ0UiO3t +VWESXFXRpqwLZrt+tBq0KYhGBBMRAgAGBQI9if0nAAoJEO+Cd8r+mR6YOKIAoI/A +ZZWEyREObBetkHdqvaNhTSfHAJ9iv+86cvTPzooPsiGKH2jfuX51FIhGBBMRAgAG +BQI+MpIjAAoJEGqrWicBf1a9TJoAn3DXzjpuv8KB6RLbhVYGF71IdLRuAJ0UzwcH +XphxVYjqIzSdIJVnJP/OHIhGBBMRAgAGBQJFWDxNAAoJEFT0YWrrvC8mnaoAnipW +WPVkP9awoBdE5ER7lDPFW4gdAJ9SUcy8250qLpN7nPFS7iXto7XmZ4hMBBARAgAM +BQI9ARP/BYMGtbFqAAoJEBQRON2j5F1mrY0AnRfegzNpHa3kxm1kyo0zE7sAdwLW +AKDsUxREaMlAp+507Lnw+EKcSJCQoohMBBARAgAMBQI9hgLlBYMGMMKEAAoJEFPi +hU4L4fDj/pYAn0y40X1YoUTUEPzFSLh7bXrF/7P+AJ9WQbYfBthLwn4jlNiqDo5d +zGVCeIhMBBIRAgAMBQI+XnGLBYMFWFPeAAoJEFBeiEci519LoAMAoJ2eTZwVid4/ +f+7Jc4OSMv6VOlHrAKC2jSYlIFX4Pod7j+L1CYbpvdT/24hMBBIRAgAMBQI/ewk6 +BYMEO7wvAAoJEFuz9RlYFnkav2QAni+pVSpBNYhYgv2KJ5Qcy6jQHVZIAKCAR/FW +A1y0SIAacn0ncHNWMU3gw4hMBBMRAgAMBQI9B00XBYMGr3hSAAoJEDxiytjk1DJN +iDIAn1F5GX5mazBSImDvBf52kDAbP/eFAJ9l639rmiEmKz7nSG0ZMWJvkdja2YhM +BBMRAgAMBQI9eHiyBYMGPky3AAoJENAanBlNdmzeq7gAoItrhY4eEstCo8ne+tHb +36Wv/Y7TAJ4x8j0NLR2EqkmQw/amkL2/xdz5TIhMBBMRAgAMBQI9eTETBYMGPZRW +AAoJEHBcU4nVwbNYWpUAoIkeRk0seH0gqpIpM6zjjlwKJw1XAJ0RUNd3ZpIy3Ecu +BPG8S7ZvMT8gHYhMBBMRAgAMBQI9g63zBYMGMxd2AAoJEALW7SHjLE9LoM0AmgOd +Ep8nrvNp7YdIpDVZ8xw+FtHgAJwPVsRgZpqb1mDquSzk8tn1Xtj/hIhMBBMRAgAM +BQI9hfwKBYMGMMlfAAoJEPVrJqOmOZ5z2XIAn1L8TV46FmBLAGCc98/jFg3hq3yU +AJ97JVxfXHndjgDd2IGGTU5SAu1FGohMBBMRAgAMBQI9iBDkBYMGLrSFAAoJEINl +y9zdTU7+0FQAoK/gvz+4Khg7qWEwttY5dO5j3xv3AKC2fc5Jq9WBega+7M1CpLEm +p+n8LYhMBBMRAgAMBQI9iDsABYMGLoppAAoJEB29XnWDmeG7ljMAn39GGHRWe4HX +Naowmnlw4Qny3tDgAJ9Tibmf3ihpPotFf0nC6TjC5/0ggohMBBMRAgAMBQI9tsGe +BYMGAAPLAAoJEFZBJvIp8ZvR8ooAn2jW48iJR2APXAL/LC5M+bh0aE3uAJ0cgz3w +BYgT2WYcCTQ5ZkxAqJVy/4hMBBMRAgAMBQI+9iKdBYMEwKLMAAoJEKH27pQkC0w9 +tU0An3CrstzBIyUa4pAwYCraSD9WrdnEAJsEZWTXijk9FCeETbdqYgB6kw+O4IhM +BBMRAgAMBQI+9s+8BYMEv/WtAAoJEAWLWs1EHF+B/44An2kF1vi746CWnFTWK3cY +V1GMdmvuAKDEFf8vs43J2jUW2Ux+rp6uHwQweYhMBBMRAgAMBQI/BauXBYMEsRnS +AAoJEE64NOjizPAPidcAoJrnKT/a3NTY8zxwxTXEKJEW6f0RAJ0b3LVv/AMA2h/2 +7UIz7V4EBgm6z4kAlQMFEDuB4BNSrOsu06QsYQEB6AYD/iRZgJ2U+hTGt879PPwL +W1y7dQFbjMHqbyyM7eml9ZbC+m+jqNvMsniFCR5qvStMgbXuUZGGpd41mL5+vqF0 +wwM00nBQe+rr5grY2oMPCSEJRNtHEamOsbc4GP59nrwbUhA7MKPSrPCvh9bvh+XQ +7MSlar9eVBkqvnYmKdaKI1ioiQEVAwUQN0Pe01KAV0R2U0AdAQHIcQf/Ykx+DvUa +CLIYlMrEIDKZ3J/aPbJ8frAjvzYkrgFZXhzQT9Xfyr6OkhiyWKFX23yzzDVcrmeI +xovCUI7IFY6QM/d5yHr4Y8+18HdyaUvaFLz3o9ZnVp1AeAJ5CkHzfufnrKPRpOzg +vXFqttJVPbaVTAyJTo/Bh0fZGHyeHwW83QhmxuWfac6PveoA1DM1+Wax5QoXVeHh +yTzIutF3ivpqaHEBUB9xgVEk3jN0svdyaGCS3QANmXMDBecSPB0cfLtK8AmTV5w0 +4D2kWw4lu+fO593Vp+z8Jsbvwj7QkOGDvlnY3Crx4qOwqqI7TPP+8bnJZKd1m9aR +NbPcPdvXGvUh3YkBFQMFEDnKmFYaT4ZLvt9IMQEBgzsIAI6Cghnj5vIe4NnnTWBq +LKz0zHGfDzQjBE1zGaM4AmxHeaFr6LUWmZ7Wtgmco/7uYDqxO8/F0djzbbXp7h1Q +4ouctCsGmk0ddv8K6fVSetcC8v+M53J8fwvTcIPzLvWNmzEvBLi9eslja5umMaa1 +rGmmMuxtudTSO3LHl3FZ7gKMM5upPKLxMAgKlZeLOxFImzUEArg4B+InVHa+NdHw +56VGpab7BmH9cKobPd0W41O6TRGi5p5c/MxEh2Gnr/iaTFQH58P441qfe8cgrmpe ++ca3P2o/d2p66G71P7Eigg27Xg81vcWMo6mRrtp6Z/qwUeIlB2X/Y/4JcE9D1Zx/ +43+IRgQQEQIABgUCRe3bAQAKCRDRlQx2FhPo1W/MAJ4q/wKzyldDyA5ulwP75lUt +oVvZFwCeP2cZ/AsKHNKhpRPXATo2yEuh0hCIRgQQEQIABgUCRe34DwAKCRDemKiK +LdsArALbAJ9qjRySsTZ6mUBgGUn/5DmluHQ6WwCgrOEvwgZ5l3TNaewOCGFsJdp1 +a7GIawQTEQIAIwIXgAIZAQULBwoDAgMVAgMDFgIBAh4BBQJGtcWFBQkXLil/ABIH +ZUdQRwABAQkQXeJJllsDWKJBTACfQI8TnuVIxE88u2napOMyUfoWZSMAn2t47LUM +uyDEHRcYvEBiP/SRVvsrtBxXZXJuZXIgS29jaCA8d2tAZzEwY29kZS5jb20+iEYE +EBECAAYFAkCnUqEACgkQt+hxIz4tn22dOACgjeYArERuayyqZmozCahsgUyPihMA +n0PkgZDTwKgSw690xdLuR2rWJrPQiEYEExECAAYFAkDa3nAACgkQRTxFSQIw1gIZ +CQCg/jjaczO/s9GkLq/kftPN8A6kLr8AoPwGlVzoq5yWxhgCkEMfV+KItmDViEwE +EBECAAwFAkC/Rz8FgwmZjakACgkQ2S0k392WXIP5uwCfTlmW1u9U3nck5mCo6DeT +HNTmUvkAn2jnjXhvqKoLfS2ERRwQlFFAw6NRiEwEEBECAAwFAkDbVF4Fgwl9gIoA +CgkQ9ijrk0dDIGxiBQCeJIrdN0kFT16KL4COSILMmcjVxygAni6OinWWNJqCk+k+ +BNIvKpm+QKm2iEwEEBECAAwFAkDxIncFgwlnsnEACgkQkvv9V4b8pZK7gACgwOU8 +kI9ZBzryS+HxAeWEo4WjeC8Anjl67/wgPGr4XAS/XA1xmWzRwZiPiEwEEhECAAwF +AkCn2cEFgwmw+ycACgkQt5wosOl/hW1B0wCgiQGkFQEonh2cRtw1xXowakWqx/EA +njp2Du5T+xpOdf4O+JwV5DmtKqW+iEwEExECAAwFAkDcUg4Fgwl8gtoACgkQzQ+c +om69o1nN6gCfUXjD5LUESFXa08Px3pbfXidXAuAAoMJ1/H/oFgcer7t+tACN2vC8 +GGYsiEwEExECAAwFAkDkGbAFgwl0uzgACgkQHckf8471INHpVQCfV67np1keBn20 +I5JABN5Swm51B+EAnRxMBVbypQcppBhdWnxQadrjhHVqiEwEExECAAwFAkDuoKIF +gwlqNEYACgkQyA90Wa3Cns2o+wCgjBXhs2mEn9HFs5F8WR4AdTpWp0UAnj/Qls/Z +Rkcy/RAfAN12XgHOkpyciQEcBBMBAgAGBQJBCbyrAAoJEDP9cVf+zmZObXQH/Ari +1HO19gpBVVhiXet244TWsSe0UQ/fJXQfmqQiU+tc2LePaGA6JQQE0OAWm4n2tLPs +hncZwgaU/YiVP06JwbClpsC2gHzVLyskqTMj5sEsIrYnXEmyUh2OTYU7W74qMu7W +C7dFlhpg9zdsRNdea0QIjaHmE1rO8PD5BLUlMiSqv++GXdNj0kDGIvA0FaffSmGH +yRHO9EmHUQjnzi9FVvudNJ3o9imemgSyQltfIBz4FXZAs+T3miPnYzB4YAMU2/e6 +7JSrZYf0fUo/cyfA1F5PL77ChB8vOhscczIGvhxwLi4qWo6YFxn6SSYSPGslNEAt +6W7aq5SGlHtrS1yoXFKITAQTEQIADAUCQQ2nmQWDCUstTwAKCRArqCYCws6AmVYN +AJ97sTutwUKf3G4vlGH0wNVW54AljgCggvoJ1kiWCD0u38cbZ0MWDA/BuQaITAQT +EQIADAUCQRi7jAWDCUAZXAAKCRDVbigPid+NqwYUAKDJMU5Pc0w6jsM5vG6ViL5a +1iuKpQCfVjvjSGLh9Z4HICfmqhSPxut/bimITAQTEQIADAUCQSIxmgWDCTajTgAK +CRD4WZCwJIrrc7u/AJ48G0zmByG5ULeBcAw7uvUD+V7voACggwzSirrC6IedP91Q +AbznwLDT23SITAQQEQIADAUCQKhkvgWDCbBwKgAKCRASCWOdEUqoXF+eAJ9tdhKw +G0wzmFxQKyeb0i/IKYyGAACeO0N7ur7lxb8mbMTeKWUH67x9z0OITAQSEQIADAUC +QYTotgWDCNPsMgAKCRAYoMyNVwaktA75AKCxz4D9I71tjvz66XYpT7tIJzO2rwCd +FudPQbQecl1Bgx9+ssXkieDZ8/mIRgQQEQIABgUCQYPTmAAKCRD2iL9hpWJ7YSSG +AKDnzacy8VJNcNv890XT6RlMFBMIZACbBISRrsQzM7OgLER59l34ZCYR1xeIRgQT +EQIABgUCQYT5FwAKCRDdkeRRL5WCwVf8AJ9FgF6zBFZMc51ziAt5/FRVIZuPzACc +DcJYQXcxA4iklDkpIUsTbXTiHmuJAaIEEwECAAwFAkGFFhIFgwjTvtYACgkQ0mRm +ERmTqq0ZKQv/SpqLNjcjH6HA2P5QA3ywaE8tg0ZKc8KAvIsxx4HIk/t+kX3pOvLr +AhixUCxd2W24LrASwM2MhzvgUJ24BzQd+Gcnli7dyIn8O9H/++VucTWmn5HKxV/t +XcJU3EuA519IF3vq2CS1x9uyH5H6opHgm1aOiOQRP5cA6sINg2Pw/ec3EfPNg71Q +dIGw3OubjpEEU3G0ROHScPGaDN+7qLa+lLChExuL/f1UaUck1igDuK1Vl9nHwV5s +kD0pyKtEMa1Zyh+xSFZZ+dADYr5qE8jH43TFXO7GMpmhduRIL4sXDNqhgVQTo5wW +wGRRjjRCEI0ohZRfeRJlVRaujpa7AyW1ACRcb7TdrBKGClyKrNnej46ujzOYygRI +mX1zmhRa4h8nAem+vDtSsCtxkt1/ptw6MeUmoa/ZdJEkjF6JS0uCE+tkXymo3uPn +zIv3hALs+xAuxGRyAYun1pK/zs7tfMZT2eXI5LvBHnqlA8KWlM7y2bpySq4qHtPm +MiqezNWHa3jJiEwEExECAAwFAkGA8OwFgwjX4/wACgkQsYn2tNI6QchEuQCeN/pb +bqMBzHuAfWO/g9QfmlmVIW0An2WQXrXoE3xnVp2C85BtML2phOWPiEwEExECAAwF +AkGEAf8FgwjU0ukACgkQTjypAm4rQ9yB6ACfYnJx27fjxYsq+5UfQEemQt2VO3cA +nApE8yUw0B3ZpqCyfRo8JQIb/cJUiEwEExECAAwFAkGEvnwFgwjUFmwACgkQTbPZ +7n9FhNqFGgCeNgwyzTJY1OABEu/EoBXEUOENxdMAnA6Ul/yxKQihc39VvKQfpdwP +GUhRiEkEExECAAkFAkGD3AUCBwAACgkQQSganqDijRh6lQCgmgm1rqgdF3qYuDQn +/S1vFxggwpIAn1htaL3fD6o4LnT/8BIm6K6tPGPWiEwEExECAAwFAkGE6B8FgwjT +7MkACgkQLMilaHDIrOVJxQCeIJI+GgF1UfUOjkYsjkq260Q72OUAoL0ekc/ixpvh +4Vs0j1q9Wx0fpQUwiEwEExECAAwFAkGFXLkFgwjTeC8ACgkQT6RVPNdrU1mZHgCg +q9+wyMgDr96Ism0gY9OxSqMA+88Ani8EIVnKhI6trTzgZLZDrZ5pdzDuiEwEExEC +AAwFAkGEkIoFgwjURF4ACgkQlPH09zrL0iMiigCcCIbdWZPauTvF4Pn724WxH6Qe +d5EAmwcodEzOE/rElE7fqScRmudd8Ur7iEwEExECAAwFAkGFVkIFgwjTfqYACgkQ +qI/9z8xhHubw1wCfWLT8UnjyRQIuxGPPWjtGVeezdP4An2GJa9XsZW3yv2eOPAsP +93+npZtdiEwEExECAAwFAkGFRwQFgwjTjeQACgkQDecnbV4Fd/JDbACfW5h+kLB3 +Y0wokkr/sxy8RFXwp9kAnjMs2yoVbG2ZbkHQV2ZODRF66zuMiEYEEBECAAYFAkGG +D60ACgkQ6gnEQD//YGyIWQCgruyF9KSG2GuqPVQIsizCCV8rjPcAnRQsBzfw9QLM +960FP64YWUCqhYkYiEwEExECAAwFAkGG8eAFgwjR4wgACgkQbHYXjKDtmC3wYACg +1f05WHi83tg/PMHoBkqlngdDIuIAoK7KZ/to5FrkfNphn6Zo0fozB1n0iEwEExEC +AAwFAkGHwbsFgwjREy0ACgkQVm02LO4Jd+iS0wCfbUWuTf4DZrjdua5kNdfvk65g +ojgAoLHPPvTdAlVKacX/rnPD7c36LfuYiEwEExECAAwFAkGH6+oFgwjQ6P4ACgkQ +TTx8oVVPtMYoQQCfXmZAzk9EjL3qPz50zZgSUO8l3m4An0Xoqn603NHFaHfbBKdt +WGijlgl5iEwEExECAAwFAkGMPFkFgwjMmI8ACgkQiSG13M0VqIMbDQCfSxC8XNls +eJ9VQ50GJ66KwSDljmMAn33ApYFWTs8qa/EBIQSgqPlVEBO/iEYEExECAAYFAkGN +FPwACgkQ+C5cwEsrK56k8QCguxJO7l5effxWbaYOgeVko8HiQ80AoKSJGsOZGx1n +vQRKeRK/7DrZbB2piEwEExECAAwFAkGc8GEFgwi75IcACgkQV5nlLYTPmpDPdACf +bASh9WQ47r2zzcVcjlfbvsz2VvgAn0KtwOo73pm3e7aPO/mYlLsP4V9iiEwEExEC +AAwFAkGSMFkFgwjGpI8ACgkQ/2R3A0yRcenRkgCbB5vYhB0cv0S9X1y54Ci1KmaM +DNkAnjeOH5rAZQsOQZXoDJPzHNrjYpLciEwEExECAAwFAkGZWWUFgwi/e4MACgkQ +SvFUKpY6VLAkgACgiL8te7hejTXfDXRIOAZeVzd76/cAoJbmj0tdYt2QGc3j/4yM +nmXrKPC/iEYEExECAAYFAkGqFTYACgkQztt/8ZMtg2MVMgCfZevJcAcVXa4hUUJS +jkWo0j/b9MkAn2HZC4sNs9nMN1PvX95Ge39wfBEKiEwEEBECAAwFAkGsm40Fgwis +OVsACgkQLEmBxMM0hsB4NgCeLxvQw1g9MSpWY9+2VbSK/4vNd4EAnicGGKdS3Zy4 +8E4GBZr62ZmWjr/iiEwEEBECAAwFAkHCEoIFgwiWwmYACgkQGFnQH2d7oezd+QCe +JzuPIHb2H/PX1R9NYqC6z+63wFsAmgJUX4Ei+WzKGs2r8LVtIo03nc/niEwEEBEC +AAwFAkHCKOAFgwiWrAgACgkQgcL36+ITtpJ6eQCfQ5aTW9WLJNVWTdp4fi618YDd +nNEAn36Vz84EsZ0gpO0Je9S+geCrffj6iEwEEBECAAwFAkHCKTAFgwiWq7gACgkQ +a3Ds2V3D9HOXdgCg91Pqo7tiv00Je9XoTIJq82ug6gsAn2Q37v0WzuggX1xyzDSR +7oxz77owiEwEEBECAAwFAkIi82wFgwg14XwACgkQ2KgHx8zsInvpsgCfdHcjOaK7 +aK1MBAYBaWwkK4rfd7kAoKxblxsQzllz7sLvFbK7xG2ipuNJiEwEEBECAAwFAkIo +ngEFgwgwNucACgkQLADuUthSlVgXawCcCbstExBnVkd/fHvatuzJ3sJ0g0gAn1t1 +CmnaMwV/HVQlUhfqefYlVN3giEwEEhECAAwFAkGxhHAFgwinUHgACgkQAVLWA9/q +xLltoQCg24DNLxMnSOcPFPCNLTPkyyjyQu4AoIe0tZDEDS7mvM6RQaHREvCuFIOZ +iEwEExECAAwFAkGqMckFgwiuox8ACgkQdDpVTOTwh9cWbgCfaMETpI9v6LZgWuTC +zE7DceGsuW8AoIcBSwWGF0XkXpRYcvXfjvAg57+piEwEExECAAwFAkGrJUQFgwit +r6QACgkQzop515gBbccEhwCfZhBXUVoNKDbW5mpYGxfKrMfScIgAnj0XoOlYmWWN +N1hlKoSQrZSvh4FFiEwEExECAAwFAkG3PJoFgwihmE4ACgkQEfLcQ8rmNEIRiwCg +pAzSttJZSiGIffSr4/dixsFUVxAAoIwnyzPthchrUSMR10AvPAu8Czm9iEwEExEC +AAwFAkG4HyoFgwigtb4ACgkQ5Vyxg0d4n7u8mQCfdQ++3anppXuhZp6cQIp1DCCz +56AAnRA9B/n9ah1wL+IMjoBhFvgSW7JLiEwEExECAAwFAkG4K9cFgwigqREACgkQ +4We9YdVB4USYCgCeLsm06Ov/Yoi9lfn4UB0IX3qwBFgAoIPEVT2gGxQYua51y70p +jVYG6t4eiEwEExECAAwFAkG4Wg0FgwigetsACgkQBMQfNs0khKmYzACfZgUeTlim +mFrhBDEV6SsslxvVIGUAoKZR9c4+kfE0+BJ069AUZBkkeRKGiEwEExECAAwFAkG5 +dt4FgwifXgoACgkQPrq84hvwIdMBbgCeJhjUvC1klrCPhWqKhyfoKJE+hWYAnits +OnNDnjkKDdKta+mrdL23iPD5iEwEExECAAwFAkHCqnIFgwiWKnYACgkQPG1Ayb4v +CvZS9ACfROLs6kU6Z93eoFUJl5H1M3U/L3sAoIgAGfCxQ3sADvFiYg11GTGnDzff +iEwEExECAAwFAkHq47IFgwht8TYACgkQvdkzt4X+wX/UgACfeM81+Z/SliH++ZzO +my5ZR9ljTo8AnA5DGAsPAbdU7j1NN0NXUg53dNvkiEwEExECAAwFAkIIjHoFgwhQ +SG4ACgkQIqUcje1P4MASOwCeLyBkToAQ+3Bvup4B9POq1xipZNgAnAui9pLAdwaG +AZ8w5PFxuS2GoXxEiQIiBBABAgAMBQJBwiluBYMIlqt6AAoJEKrj5s5moURoJfgP +/iRGZnx4Oxi4qvDw5LTJQrc8j2TjDIEbFRCa4kqBcVEBsKRSkBMe9GHpleq5YVJV +uCRrLdx9sYt9laJPtMDP6Td6JVK2b8yTzymqVN+7alSrT/lumokX3O38v+LZpj/T +fQDiXmCwRxwKx3LkXUVdA9tgYVO+O08nHyEyy0AbvrUeFo6Jv8DY7yN3t/x6VkwZ +JO5u2wUnX8rY+jqzL/fKUmV+j8XOC+pMliO7gg+wiurjgPeTiRAMxqFTZbiTpytC +dxXvDbCoLTPGa5ki4KKjXDK9gbd7L+mM1+s56ZK4D+CaY3fy4Ekz68RAg+dR0myV +z0fZ4fitUoURBm6pST4dR3BVCEkp/BoyZKIaPg95emG0VzpreWp+GyI37uU6fOTR +1EwLFkQyAuMgLqkaq4nrXTOxgZFv++JcNSWI0Emh3sJ44dEfrnf/TRT1pqqHUqbY +d74Faa1m34rPDXRhSbyijHT8TpeUTgQvyn8s/W6/y9tobNNXFfk0iv2BWGuc5UMc +de2UVnFq2Dtku5I2QrqiKqxHbKfGTbKyZNATPKLbRQXGcfwgKxTJHIQNsmVt7BA+ +0lGeSelXpCGxQDptXK3JhgDdGQmpIOiMSACDPksv5mGbVO3P1xzDEljr9l6/OVJw +2sXE+fOZqi19Y+AWKzTIX48tkZO5/+CyyPzJgwBaGG0EiEYEExECAAYFAkIrN0cA +CgkQi0rEgawecV4jeQCdF+GUDJuQnCaFZqw6sNgZtol0UncAn1/VQvGDB0Or+JIt +HnUlCU98URNXiEwEExECAAwFAkGTrb0FgwjFJysACgkQ1mvqN8E/x7b7ygCaAyFq +MIKTMqQYuQ7hnGpMTx7FPmoAoJtfYoL1pFmVZ5Mhwkv9GFUee+HHiEwEExECAAwF +AkI2qnwFgwgiKmwACgkQ1cW3Q8Sn6j4gRACfQWmnt2z+J0tB79JQ50hNEVrYuKEA +oNAe1Y5xlLlDTSKJmnwjqnN0qaeriGMEExECACMCGwMCHgECF4AFCRNri/8FAkJZ +QHoFCwcKAwIDFQIDAxYCAQAKCRBd4kmWWwNYouXsAJ9nbkvbiJZvNlzwBL98x7YB ++u9fsgCfXE6vHv6DJk7Eh9CY+Gcdn6kCG8iITAQTEQIADAUCQiH+PQWDCDbWqwAK +CRDI2LksT3FGBT++AJ0YXuDdQkG9gLCd2GtU8U9mfoVhkQCeMEy9jGnsYm9H4uZO +h5Qmhfq4CnSITAQQEQIADAUCQiKA7gWDCDZT+gAKCRABxevYytjzo/hzAKC5qGd9 +qp9ZhihcmE8DXM0SRf0YAQCfQeLE1NJbgQ2jR7PNfTeSjumM6h6ITAQQEQIADAUC +QlONiwWDCAVHXQAKCRCW8016T/SGNQ0+AJ9ElmV4Cr+P/i1t6TgDf+WGBcmFrQCf +VpOjPRunwdJ/Y0GNbV669//hVkKITAQQEQIADAUCQpiOgAWDB8BGaAAKCRBNtucb +gGGoMG5SAKDIGnMHLyTs4rOOJisowYhZmqIyJgCeMd0d3Ojp0pxX4nd5/iGXdVwu +oN+ITAQSEQIADAUCQpYCpAWDB8LSRAAKCRCLlilD/CQ/POExAKCP6uvHPe0mBOua +HeDf7mshxYQRRgCeMo4WPMYv/tLIWWl6GHRdreg7r1aIgwQTEQIAQwUCQpWcwwWD +B8M4JTYaaHR0cDovL3d3dy52YW5oZXVzZGVuLmNvbS9wZ3Ata2V5LXNpZ25pbmct +cG9saWN5Lmh0bWwACgkQMBkOjB8o2K41QACeM8dkTb6oa86Q6RFgCaoIUxfD164A +niWvx0c+DTLzF40fwzqtKzBlp4dPiEYEEBECAAYFAkK6u70ACgkQHuBMgSRdZNRJ +JACfXkE6A31wuvpD2EfHi/sm2m3PlIwAoKvIqARunnuDjET8cpyOBtVOw/EeiEwE +EBECAAwFAkK9MmEFgweboocACgkQr2QksT29OyBNEACfbNEfltwRZ1RmZEkt9ZTw +OJSli5gAn3brUt3vc1JIxs8dlkwHV1fSJpH8iEwEEBECAAwFAkK9RW4Fgwebj3oA +CgkQ62zWxYk/rQd1UACgwJNmfL/Cs6bYMFPC1dRrNsf2GtAAnR6K37k2u63FX1lb +g4aSMLCcNviCiEYEEBECAAYFAkLQQZYACgkQWp20Ay6vTYBSnQCfStOrSvXsitfn +XHqS3nELWI9RVYwAn0g9x2ITbWAua/rx5t6YYLSduG5UiEYEEBECAAYFAkL2hiQA +CgkQic1LIWB1WeYKQACgxQLr6OPEtGuH4jCezv8goZ5hBA0AnA5k53eyGYXnbESu +LD9hfIgq9NegiEYEEBECAAYFAkL2jQ0ACgkQ1U6uS8mYcLH9uQCdFOloQMppwhQy +a4zvgrXaqDtaZBEAn2UhMGeO/7laTY+EkaOc0yWp1GCEiEwEEBECAAwFAkLlBZcF +gwdzz1EACgkQg2E6UBaCfQMWAwCgk0N+XcWaLDssH7wYu0EtOFW1kKUAn3Vq83yr +mg+F4TvieNmPhhqTP6W2iEYEExECAAYFAkLXaWIACgkQ38wGmSzEVdkS9ACgyXwp +lqKIDsyExNmuVkPUS1ld2HcAoJ5nKOY69/aMJMTABBH9tFyS4IUNiEwEEBECAAwF +AkLinZ0Fgwd2N0sACgkQ9D5yZjzIjAkhqgCgj/Uy+2Xvfw9FAwPdWSaC+o4AVUEA +oIvJ06LeJppo5EQqEt1mc8bYV1UjiEYEEBECAAYFAkL2U+oACgkQF4k5uXLdWDiF +nACfRaNxule5PGrfk8fkbzn3kF3z7HYAn1PJnIAlgYyhYDexETbeUykY+9GhiEwE +EhECAAwFAkLrbeoFgwdtZv4ACgkQwm9wFgHGy4MQfQCffyaecfqcThyxP9FNgZ2U +z4pBwAEAnjMFgtk5JN6gZ+Ztgqe+YyYrGvvuiEwEEhECAAwFAkLw+X4Fgwdn22oA +CgkQWNqWrwuQEUHBCgCgn3XtRj5qJxudfYkec540HnkoerEAnR2x0A8LAA49rsbh +CiLZlmTaaD67iEwEEhECAAwFAkL5sgwFgwdfItwACgkQ4hLd7psgZbfpmgCfT7Dp +lZrJNYP+jrldo14GO0v6fhIAn1YoULZuHQRmoQrsivlktn+DqE0viJwEEAECAAYF +AkMgr9AACgkQtGuSO22KvnH+kwQAvGUpmszwbYYMOOUmi5UTGjr+x1o7dXn2bQWI +dH0F4BfShvyvd3qBhb5OGrK8YFB7+cHJDD0A7NER+MZ5H/KnISdLyWA26y26EMDR +eou/dzasj3oWmfullh2ojIdCxzoB4VImXcQY1+Ui7d9a6y47inK9sMzK4pwt1PKt +ncBRu7yIRgQQEQIABgUCQyCwBQAKCRDFr3dKWFELWsr5AKDAC86WauiBT14jR5On +VnGnsoLRAACgjz2G91FPaDTx/m2uv3A8ztOUjpyITAQQEQIADAUCQyFMcQWDBzeI +dwAKCRAUqdRorfCKfwAGAJ4x76O8eVQAZ+ih39kA+LC3UoenFQCghSxjTY8eXfYm +bqv5JDsqpw8uvKWITAQTEQIADAUCQyGVQwWDBzc/pQAKCRC/69PGQc8DIlKCAJ48 +XCT4C5MEr2aGFSCVLw8yH4ATkQCfaGKSDz5JMkZZrulf6e9jbL4BvKmITAQQEQIA +DAUCQyN1TQWDBzVfmwAKCRCboJNrWjX9QlGNAJwLQeoR9MHMZMHjqR7bCtZFzhUj +QwCfToKGN6pqjOyCLvN7IQ2z7h2LkhOITAQQEQIADAUCQyN4BQWDBzVc4wAKCRAx +SLvvHu8m9ICtAJ0ZEDO5jWXB2WNTegwQyxtux80NKgCeK+5Wc0fx6k7pYpFEr8FD +27kT+EeITAQQEQIADAUCQyihNAWDBzAztAAKCRBJPvuOXWT4cIHtAJ9H/1j+01em +eRh+RaIbco3zA4/WSQCeI4bFDknxR3voTopq9KIMqyfH2LWISwQQEQIADAUCQyCo +RQWDBzgsowAKCRBsZO143jTvodBmAKCRj57Ry/Wj+QjnkIcY59xWkflc/gCWKqc6 +pOMWE+qXmcXH7/krMsmigIhMBBARAgAMBQJDIJ3pBYMHODb/AAoJEJT+3vmtNrUV +EqMAn2tfB5vASh1oiO58GdTVglwpxemTAJ4vMTAblcWzgebLUzm5wR+YWHWcyIhM +BBMRAgAMBQJDIKH3BYMHODLxAAoJEDA62eiAWc/cml8AoKPycGLkXCR5CLnzowu5 +RanuMzUmAJ4536g4hlcWwD0UlNDwUS2Si7+PpIhMBBMRAgAMBQJDJCP5BYMHNLDv +AAoJEHw0FqlEG6/3TzgAnR3zrBg3GhFvB+SCDgzVN04/OsJaAJ9RUl3WAyG3FCXo +dMKFGbjf0xwip4iiBBABAgAMBQJDJcl+BYMHMwtqAAoJEA348Hf+CljYb8YD/1rm +o9voXxBwcaaRAJ4yfRcbcm/HLiPh0/dmCu0wTymHxSpdZ5SvZzOfjukfqaKtn8Tm +ZFureVqdxtH0OBZZRyTyF+Gjk9ZVsTr61Dm4YM/H+ysJ4+eA6sAdeMPgC6wclg9/ +gi+WWVJtS7V3nrrhhvuJ+c19ZkdWKPaMz8Dm5EmjiEYEEBECAAYFAkNfjG8ACgkQ +5XoO79RjNtoAlACgvh0c/n14UuqSdhEdEYcIJa0I26MAoILg4M/a6XfYbAtVVpZr +DSBXdcUgiEwEExECAAwFAkNaAYIFgwb+02YACgkQM6232ZYRYVUJHgCfRWmbDkQr +vSP8VGvFRvv6yKqHOakAnirYhae+s2l7cz8i4c+p5/SS1AlhiEwEExECAAwFAkPT +bagFgwaFZ0AACgkQ5klUNHCsE9U6OQCfa19P0RExXxaWVzJr6uLzKP++g84AoII4 +kV7AALq9A77nWuXDojWnRko6iEYEEBECAAYFAkQFyuAACgkQ9Jgd/vNmD1MSmQCb +BDaC+ZKLDTgsnORWMhSuJwOVYEEAnA5xDXtgFTTmKdq9DzqTNNJYooBNiEYEEBEC +AAYFAkQGZN0ACgkQIIdHgCGsbMSo1wCfbfphH6CbnURMom7x+zWto4yrZOgAoM6M +fGeeWNKrBHJVFRloz6nBymqliEYEEBECAAYFAkQH63kACgkQ3HeLB051S+1XdwCd +F+gqQw9bVEQAv4Owg4O+PhjN8f0An3TH5zy+qfXlJXjNyvsRqR0QdCmZiJwEEwEC +AAYFAkQNdgcACgkQpOAUxG0aO7HojQQAhNhnA+DQVFiTuFsjOCl+IgeLqpVmZbD8 +Xl+KsoxedLDNtmnlAae7sJYqoFG71ohsYe7IK/9aQVtgdg1E0zo6+3LZ0z80+a0o +vYJqCrz4eQGDvPIHijRCy6Fq5XAxkZlKQzjMf6TO/RTdW8OJaf6Bq7GOZUr+In42 +2tNL09GQxRGJARwEEAECAAYFAkQG/cgACgkQ+fnDJwmNErN2BAgAvTZL4s77EgNX +G0EXvxlWGLx2nE5/p/XvRM609nQ8EAN/MA62y3UsEDlD02O6s2QpNEJGo+pSNdjd +rl0PDlF26JMVBwSwu32INFpkRhF5MWVSLABcumZBCHSkrRFNg5K9JPl/Ro6WVMs0 +52B9bUJIDc0FFJBVul6Cn8+sIkMTwO8SR8NHP0kUM2vPR1YeqTmrOEl2KT2OAjNQ +kvdUwmIVSsOQDx1TAhxe6xW0Fw0yJdptptqb7hnfj1CDHJjI/gfPV0jQsph9Yswr +vbPJfyfVZTkHiFmvaO/lxskRd3VVuY5ypMBdTmjLff6OUsAOj7wgrW/2lt29scbS +/h45ff62W4hGBBARAgAGBQJEKFdaAAoJEBH0xB6z+64zdUQAoJb2xLqGoCYadYF+ +EPTR8jtjBa1/AJ4nx+fHCKL0hKhLw24Pcud4cIxruYh6BBMRAgA6BQJEXmVAMxpo +dHRwOi8vd3d3LnNjLWRlbHBoaW4tZXNjaHdlaWxlci5kZS9wZ3AvaW5kZXguaHRt +bAAKCRCUj9ag4Q9QLk9yAKCrgj4tmqYZILNsxBDRoE2R7RFrfgCffb9k6Qh7bgjE +5z4d4J2JUYw1BmWIegQTEQIAOgUCRF5lZDMaaHR0cDovL3d3dy5zYy1kZWxwaGlu +LWVzY2h3ZWlsZXIuZGUvcGdwL2luZGV4Lmh0bWwACgkQtHXiB7q1gim7sQCgtNMb +kY+sT/f96U6cdwKJ7KJWmDMAn1lb/18BvTBt6SswNkjeZhNLe8HGiEYEExECAAYF +AkRc/SoACgkQiqNir+lyMs2qsACgj/FAXhQvFhCZatkr7qBCZFZi6UoAnjMyYanz +0Wham0ijrvH+POQuCKAOiEYEExECAAYFAkRc/TAACgkQp99YcnDUTCNgawCgxXQA +JhUO7Tdm7H24ppREANvrbVUAoLoBqUJjt1fxL0as+Bd7EIlMIIBwiGQEExECACQC +GwMGCwkIBwMCAxUCAwMWAgECHgECF4AFAkBd2fAFCRNri/8ACgkQXeJJllsDWKKt +2wCcDKNSTwgetpsMsBunlUrWw7HeUHcAn1Xlgp78HK4lRrhixrXWfkSCMzztiEYE +ExECAAYFAkNEG6QACgkQ6tS1kPaJm8CkLgCgjDYho969Plzpsry4gseTcvuJKn4A +njHztuclj6xEtiNi4fGGnvBYwsHDiEYEEBECAAYFAkQFglgACgkQb11ZaBzVLegG +TACeIjz0GchlygV1o/V0x4n1YRNrTf8AniulsCb2794jkbZcto6bKu0dvEuTiEYE +EBECAAYFAkQGCjQACgkQmsnSLGNcY0sWlwCgsctDOVPkeE+gomU0ss+KL4xVVsIA +oIykgUl8KUhwM6Q6ao4oDUAGuigriEwEEhECAAwFAkQGKycFgwZSqcEACgkQ3+ZX +kjKVxc3tagCdGRXffmqZnoc1y1LwzybdY8Eb2KkAoOqq45pa+1o8CY/05sTB9FOe +8FTjiEwEEhECAAwFAkQGK2cFgwZSqYEACgkQoOUVvzmICVSOKQCdGvyzSMVbLqao +vnQ8snuByodCJQ4An03szhMEVn9ZxpTkQQTaOx8E6SaviJwEEwECAAYFAkQNdeoA +CgkQ/dJ0ek5GOmrgowQAnzaCLzdqYkS9phkQs9nkIYjxCp/gmHCjqT0YwjS+LakE +In+URfDz80FCk1boXKDK6cF9fKieviwMlfDeymQFL05ROTBp0TtmVf1DXOzZSlDj +xaHHE9J+g87Xau7KJiJO1QiRk/8nMide8cLk4/9q+7v3rrJCLsXbX3VJDIYBMOCJ +AhwEEAECAAYFAkQPSJYACgkQGioH6hxXudn0rRAAgqzfBFuEnNCyqXu53IN5pGNA +fns0xf0SiwTkd4kixkxptAMEu+2AXkRqao9C9Gb9+dNrwzKRnKOt4GBEMKVHKxwy +LGzjss045fHvokNa7rvqIGMwZUXoqO/Nq6NeJXjCOtq67fOVGaWJgLoTrQl2rVAS +czA9025TtyhNnAL7J9Hd8ejwBOWms3Li2kXsSt+Uahp51Ji8qdDLB4iWCk6M6f99 +7dMS0gDIXsDEx1Vnqhx+NC7vJBkzvkV+9zWKmLK4Rk8X4gtcFlAjhBQMwf6045JJ +3KKfOcPfL7lxOp3Kep0Wu1Xbujh9gPiSM08qsvxPOGF8WiUfnEDJQz1EspqhorjQ +ciyP0C50rCe9YOTZEhPAxYn1Joa97GairZltw+sIUOobn4Rqh7hFQh59s0cncH62 +71XOZneJjZk9MgJWm13emNCuEXeb3GbIJzl7qgkQM7aNP62uKo6urT4Uyse8AVUp +fOwE/FvHSB+wIpt45R8Q33mRt4o7HwviPfbXE4l0QPWl1CZsbpBEjkBMHnDggFLE +1qY5WJAyRwRPZnE2uUlbVUI4a5ro8m3IzJArEci5AKdyCZ7K3RBlO7H19s+x7Nq1 +Tnc+xItH8MLGV3XRKKpULi5jlGkE6JVPIev/5etTNhW3ytNc8YActAVV8REE7FWT +Hhn7YjdgaB5cB1hvvxeJAiIEEAECAAwFAkQFDZkFgwZTx08ACgkQbjbvGsyNqzCm +JQ/+PX+TdvwduAAXMdVP6uTcpeCate28Rx7H+MSb1ueQdEWijv68K63ELO8FFsb9 +qb3QOypx3qjJsjMHP42ywPY2jc+DStyAk+8+EaBX0NAhaPivHsgj+7iFPttFPA+B +M8mQql7nnvH6HSYekVUb9pd8Dir/8JQp9uQbgXrlHl+bXs8k0DCMHfWJwgUiy0oU +NgqMWqyFPUfLvo4fzf5jnLjxxyh70GwasiXplJX3VxbxFXuJDjS5X0lRmDqx6jsB +ZnFIKS1IG71gH8qW3bnfbzxvLPKAkVaJotRjlFksOky0H3BdGrxY6wjqjZtgbHUl +sabVHPCcYHnjhGcobQTbc0S5vdGMBInIYg/hXC8bcXzXGgjJnNS2GKt4CGAA3Slu +Cxzyz2kIgL8aDtt3fyqC2eVoP9Qnw1GdyrrIEDMhb22LA8c1VY419vXYLp5C5jps +nPFUARmg0f7Un43/DG+0TV7VTT/ZMRELgeGZ8YrLTMpPdOnXV8DGZfpUAXj5fJ0Y +3rafj953GZLs0/hHmeZnj4P7oTaOKXQdJVYBOUsyORaX2akoE2rPMc/6fLC20qKE +eXuOoeREQX/uigzMRkS1fZT0coKtrl18DoPr1IyHq4BIellVhk03YG3vr/oKCo6S +qbCPGFV8UBpBn4pnb2lwESYsEODxIXguI2SHU2alYB7s6W6JAiIEEAECAAwFAkQF +ESIFgwZTw8YACgkQHRqO3OFAoFSZ2hAAtBOio22e1n/uT1XzaSg7V6Bs5BEKOHnN +GLKrntNfeZvJun24PBzZnQeJZIfkVdkKm1uv6e3d4B9Hv1F/f2sb5AYUq3RKqOXk +IKg4aNV1w/Mnon4+VNUq4FE4doi2exaSEmWrNoSs4QNXwWXQBuN+fUhUzlaRs8g7 +IOkTgEqeS2WpX63F7GqQyeoH9HwbYJWg8RyXH27ZBsm0aBafrN1XJ5IDIo8aZ0us +VtZoiAb86ymTrEfDhldnL4nG+CDJURSwcly6rgFHvo/l5DS0VF6X2M5ZJjp8ghM+ +NEZM4TkAxS2gvoAyagh/PQCMq8VXwfvFDhSw5E/NcrDrbiRGVnsOW67v4t5AxqrK +q2SAOd0h/z7mler2vrfrAltWc3vAl81OQNH02zzQRYtHizk/8gwpX01+/3eAgzN6 +v0tBruNwDULsgr/imNXQgG4TErxTE1Sx3eALhFybPA2ce+Od0ZWKJWDjJUuWJP0b +PQByEtHC7pknYN5FTxS+v6t9HBH2QOLwLY2UcuVvZNztrpHcAEhdu9oLIEQeXqaU +9ah+9MDD2M8ntmW864gacelAmFrkujOFQ/TMQRU7f3ttupDFExst/jYmnDXiU/7Y +u8sXAwAf+svGyZ3AILNtEmuzFUkjlK0GQItyK5ZfQ5reyncaaSLJcoE9SZU6wTJq +SPbLjJkWjnGIRgQQEQIABgUCREihKQAKCRAFi1rNRBxfgdElAJ0TEc/rMAUxLmEd +Pd7D1zKK+TImYgCfUuWcmjJ5bK5LkpE3ArkC5Qx2mhmIRgQQEQIABgUCREjJ/QAK +CRCnL/ZsQr1kXdVuAJ9Xaa9HTr1u0p59TK3aDeyzcMhgIQCfSUVDGu/mnaR5o/UB +5W6r4Z8+6DKIRgQQEQIABgUCRFsJZQAKCRB/3j6P8z4/xm1rAJ4zyJKiljgk2RiG +/X+w7hBpmCFGKQCgqWAH6dUwVP45AxpamVPvKZHknHSIRgQQEQIABgUCRGCHygAK +CRD9AQSw4jPImNSzAKCrRu+/tnGv/JoPRcjLDIxTgJy5UwCgvtbD+4rAsMiHP3Hs +99vpbKF/oFGIRgQTEQIABgUCRE/tdQAKCRA/0h0qmjpVWMz+AJ4vhWL0yH6Lhgpx +67MjBOWjsyltyQCeMtJT+8Q4BbRtKOGqmdAM2YU1I2iITAQQEQIADAUCRF3UigWD +BfsAXgAKCRBbqJPk7D6Y34fAAKDgH96/0zdktkGPyfNjfrEMvCHk8gCeJMe6QQfM +I8pTnEtKNzQRdWXEIVCITAQQEQIADAUCRF8XTgWDBfm9mgAKCRC8EAnaDpclPzgN +AJ0Q/hUqqpydYwAsisUDRiQ2V61YrQCfbn410oswpOWdvrlaHiZ4Molpi++ITAQS +EQIADAUCRF22QgWDBfsepgAKCRAyNS1FZ/eCZDHTAJ4poseKzcWwhfVChHKUhkEV +2cfCWACfRa0RsK3BqVjtHshBlED/wfHQUJSI3AQQAQIABgUCRFC2ogAKCRDR2VIE +Cemh1f+NBf4qBoeHsQ/XRB1Tvu00+xPuskX50oV88JnJb+0whE4FuZApjzIJ/PC/ +oxYu35qkE7fJ2Yuz3kHIjQSLerIX5GLKUv+HQcbSh8iF1Ru16Q1Vh2Qxx6+eia/T +p2EcaqPxsQeG4j0n7bojz12i8NuClZPCTf3gtS33sApHm3u9UxRmJlXGgKd4bfk0 +hITCxPwVJvkI73j5bJV/1OA+pq0aFTdeLXdRRIzzpeEIVPuBRW3tPmW05GKsYCBC +F7g80BpGzIOJARwEEAECAAYFAkRbcFcACgkQZ02H1ZEZDvkz0wgAvLzYHXOYF3yz +k3/rxnW7kbw3tE2dVpKWI5SHC2ttGdToCIlhm2gTBlPUG5t73XXIU3gldn+n5ys4 +gXI+G8mqNkfoOWvmev3IxQ/IyPcf0Rncire7kXyUZOrgNVGqh7ML425n2Tcqt5y7 +EvXLMa+3635+2LqYrUQKuUWwBllHLeA004fk71zvtYUDi6DD0idm3OVYuHaKLkVN +SfYTS3vzV+tOHvhaE1g7SNn1F7hssmG2ZB8KNI5r4hvAZnQ3YBSpvKa1wtHEjCz5 +BYocepbvh82d7DOk0UnGhVQBwybDuMpBAAtBc9Un0WLQu8NYA+90lhzsH/Yahbbv +Hn53gLyaG4icBBMBAgAGBQJElY7IAAoJENwG3M95JPpz8rMD/jcSqPB2Hg0EIbOk +GBxcosKeeOSFSwt0pRcpgfE2hVdUQtC7LB0DuGS9iRZfssvlSGfAeNGYTg3/wmjQ +LXW19Cv0KkQZtgf+oZMIY7Y/pQRfknvo3dPhN2HOjww2OTw+M4wSVusLQ0K4IImO +rLwwpd9tU2w0FOYW0BSNpjTYvLCoiEYEEBECAAYFAkS9UTAACgkQxKXVjqqse7wF +igCdFm25J6/2RCOsDei+Rn9GgYtXp38AnRjU3xD1sLVvdmtRBxlWIbxbU31NiEYE +EBECAAYFAkS9Os0ACgkQOOnzljbgEa+urACgoAXY/ZbGzpegZj/NB6m+oke0yQgA +oLB3Azqec5YwASNr1qYG4CmDLwxUiEYEEBECAAYFAkTCe3AACgkQQggFxokHT62+ +zQCgo7WiloETU27FIwbZ4hC4p7JX27AAoIzriN1/Vgiv11B9e/SPS/FJVtNQiEYE +EBECAAYFAkSNRGcACgkQp6+YGoOsM0qMhQCfWjOe+Sork+MqCpgK7Kk0jT6cB6AA +oJLajq72kMy1vGqOxpa+S7HWTqHAiEYEEBECAAYFAkVXpxUACgkQ9LSwzHl+v6tl +VgCeOgccXHclswT2GfCbz4aR8eo1oAcAn1m7qlWfgUnXjuos3O3NCy1nQZB2iEYE +EBECAAYFAkXse7AACgkQz+hIv/xnhaLWCQCgqR/D1hrBZKdrfe0RrhWxAUwmSY4A +oJDDbQSwlTS3vxN8mDIHVPFkJbo4iEYEEBECAAYFAkXt5D0ACgkQd75ZE3dJ2dla +ZACcD2VGVAf8HN6WDZEQdpfj8UU/ChgAoI8DF0QENzVNZ1h8b/CkmTSNNlYniEYE +EBECAAYFAkXDwT0ACgkQjqqHRDkpnTGbpACfeWu/HREjh5JIipF4dm5UvvigTi0A +njKzSkFYtykVa8zTqs0qO3+ccbB+iEYEEBECAAYFAkXDwUgACgkQ+kRiIcQkJe1J +hgCg6WAVzmkN6ogSTlaAp2YndfPS6IoAn07y6mFNfpjkrkKOVFQ4CsW2fkjIiEYE +EBECAAYFAkXDwVEACgkQ1AYyHAdPXoQMCACg0NuzOa62RHAjqQb9TVK1R5ieFY4A +niK82pcr9WPceRoRv+qaVtG65oSQiEYEEBECAAYFAkXDwVgACgkQLQlxeEoIqt8G +QACeMZ6OCkmknlP94JUuErXwnPQ8GlkAnifZ5tlSiq0tGhbUZu+aEIuhiwjfiEYE +EBECAAYFAkXq9sYACgkQTjhS9MN8HQm9AwCfRlxO7ZPW21pSwmxK00Qdt524PUgA +n203/xRA5X6gItj5JGY7ClML/89BiEYEExECAAYFAkVYPE0ACgkQVPRhauu8LyaW +VwCcCXxBQLPD0T0Q0BHtWf1et4ZFhHsAoIDmUcBV6ivz0xfV+frfF4F7lny5iEYE +EBECAAYFAkXt2wcACgkQ0ZUMdhYT6NUvEACggy4LTFVynfrNQ0/b9XQ3X4XeqP8A +n0QyOlyGn6UXlrId5rDjQUGOD8NViEYEEBECAAYFAkXt+BUACgkQ3pioii3bAKym +0ACgioqXaG/g+uu0SxnUTPJq+jTzcyAAniJbgn04w7W/ptifmxUecR7W0dfuiGME +ExECACMCGwMCHgECF4AFCwcKAwIDFQIDAxYCAQUCRrXFkQUJFy4pfwAKCRBd4kmW +WwNYomksAJ4q+Lv3fDvzDJl4JcOmzWHPsPg2QQCdHcj5DwCCM7YnRLiE58ApHdrg +11S0C1dlcm5lciBLb2NoiEYEEBECAAYFAjc3I8UACgkQ9u7fIBhLxNmHZQCglWbP +DznIcnOxdDW+k7YgA9+/n00An1ZjSiJipverUxLEFHAbSBWI0IntiEYEEBECAAYF +Ajc6+aMACgkQdQ9klcidkz6GiwCdGe0KSP/vSyEZM/GClQXvjMD4RvMAoJwyTIdc +jPZbQizDeAO3btn2CCwTiEYEEBECAAYFAjgUDhkACgkQYAeQgHPH80+I2gCdHeTA +PusmEfN2bdkijpW1gpxBvGoAn1kzL7Mg7tC4pqlqw2fV3kRUy1a5iEYEEBECAAYF +AjgqYh4ACgkQ4/JYVBKPDnkPkACgmzk7HMlJ1h0qw6OHyMtDE4RI4ToAni+Cm+01 +pHfzh0EnFQTvLE1M9PtoiEYEEBECAAYFAjnKOw4ACgkQK7tDpvCerwquXwCfbW9x +GF2AHQakBPakh61xKmC8WEEAn3TytfY5qrTjxIj2HZFKN5QuQpYSiEYEEBECAAYF +AjnKiy8ACgkQF6ZBbfeUj9ombQCfYQYxpipdMGBxbNd8jbL9RDmH3nMAoITmZnDJ +wXzpHNuSLY8o3c5YhHXziEYEEBECAAYFAjnKnXcACgkQNfZhfFE679le7gCggQjs +jFhjaIO1lWHfPusn0dqdhRYAn3rOW0XSeh64V9o+VItH2LZngmNAiEYEEBECAAYF +AjnLMigACgkQUaz2rXW+gJcIVgCfRRq0G2fCcZOFoey9uZGAkWctKsQAoLw6lUhd +eZDgULrDC7OQRIk7CnMtiEYEEBECAAYFAjnPp1IACgkQkVrMRaj0wv0IqwCfWGMe +iZ58ysuZCAP9IsX3aKcSPtcAoJno1COOjAMhoWjUiHctgLZX9+gTiEYEEBECAAYF +AjnQ39UACgkQbyOLwk/aWgxfIwCfb/GeMAD8w84hq5/aUQMCvVqUYqAAn07SKuWY +sZLEUuPWIgYY0yoByJxviEYEEBECAAYFAjnSCrEACgkQv+EgZWshSJq8jACfdf20 +dqs3IWOPHgFMdYb5VF+WkJUAn05quvyHB3Xug8csxWg6RwSfQBTBiEYEEBECAAYF +AjpMy0UACgkQ7UaByb89+bRUrQCg6aozpYiCEDPVAHe54/8/q48FLP8AniviG9fj +xInPaSKB+LXRmQjc2jLZiEYEEBECAAYFAjqJgd8ACgkQYogE2yD8bPYGagCggMsq +GJN61JuOQkY5MiKb4UPQpBwAniNYwQb+hlEzJF7qnPECh0MAxq8OiEYEEBECAAYF +AjrBCNQACgkQt1anjIgqbEu30gCdEsSeFtJ5KziD5l/CvAhVZt9lnQUAnRrmbV8H +kndXp3+DNoREgscZk/rliEYEEBECAAYFAjrB0SkACgkQ0vCiU5+ISsiPkgCeOFay +t7NkcymwTC2UKNjjyukNDvAAoLq/bOTNZECtztYIMDQ2VrzZ3m6KiEYEEBECAAYF +Ajr1eYsACgkQ7A6vcTZ3gCXdrQCgllIx6G2DkKSGKBhYCgsyywFBXLUAn2PJGrCO +ov0LS8jCMD2Xo4T7qfsjiEYEEBECAAYFAjr1mwEACgkQLBigKrTF83+E4ACffa4y +aJ6Pj4uFZY7dVuiOfkuoTE8AniIdw0DVkHBuxlNp9PAglhztyE+oiEYEEBECAAYF +AjtFbTsACgkQ53XjJNtBs4ex3wCfXLPNscM4Uxtmy0/t5Ygg9lDWEQAAnR39P9eJ +tEeBtMPfbEGYc10ABqjkiEYEEBECAAYFAjtF2QAACgkQI/q1+wgWzBuJgACeIak+ +A98IheVSowXG4J6jzBA439MAn2IFA8EB/EkQ1rn7OEmFNX++PNZyiEYEEBECAAYF +AjtF8RYACgkQJ4bCRH+KQBfSwgCaAvm7pL+LioYj/oKDBQ1pJAj+UqMAn10W8RKr +YblMZ4L11R2TO9xOvFn6iEYEEBECAAYFAjtIDxYACgkQBgac8paUV/DLWACgifbH +tSi50JxmSr18WofeVcVcAXUAoJs99aH6/t9gkO34ajXjiIQxc0qMiEYEEBECAAYF +AjtIJ18ACgkQ11ldN0tyliUx5gCggbhG1uzvdgHNY8oCt4cc6TfHUREAoJuRw8q2 +kbztnt8TQ4mjiTINcBXziEYEEBECAAYFAjtJwaAACgkQUI/TY7yTaDkPjgCcDSJQ +UZBBP/5OvW48Q3BUkUkRSQkAn1Mjqe4WTFEEA8HK5h+KDcqR0aZIiEYEEBECAAYF +AjtKFVcACgkQliSD4VZixzSYCgCeJpt98LMq02q9W1bK5iPUvCkcsSYAn1dqFcoX +ctXVnMj53z8zfAaW0BcwiEYEEBECAAYFAjtLFwcACgkQDqdWtRRIQ/XMGQCdH1u9 +tmtUYY3ExVLdT/H2IIQCU3MAoI69Y4Z17RDh4Bj2gmJwmEAmfDwbiEYEEBECAAYF +AjtMF8oACgkQ1w1fWGA80Hj2mwCfazudYZSMmQWO85xZvg0uTB3rhZQAn3DSyrvX +xIpmv0CcnBtUQu5N21kSiEYEEBECAAYFAjtRuWUACgkQ5DsVPMtGficbLACeNpRJ +OS9AZ7q7bhX2sBJglKLloTsAoLm5FTnY6iAySfPZZlwAVeE6zMJwiEYEEBECAAYF +AjtSxD8ACgkQO/YJxouvzb1F7ACfVp8vhxAWCeRZN3InlvYLrxFTng4An1QO6+D3 +QUjX+0YRNZ3tpZDTSd6QiEYEEBECAAYFAjtXQl8ACgkQeRYvNvf2qtklNwCfcg4T +ss3C9Nf6NiyOAHhXO4JLhtkAn055IHb4i2IO5TQLSQi0tk4ktZVfiEYEEBECAAYF +AjtnOlkACgkQwAsNNiHlPr2cagCg07IN1/MaXn+8yd4Ncp9/723gEBgAnjNCoGAA +ccbvCCVE29sXBNAvUo8MiEYEEBECAAYFAjuYRI4ACgkQkC29kYw4qQpqwACfcyB4 +krJFqyeHoKzRYDqW8JDUdvcAn2pa3UDeKM7FVe8LgCQyz0McM4JqiEYEEBECAAYF +AjwH+10ACgkQ2tKwXV88MYVF8gCeMoYaFN7v/VDmuYt+G1BXDxzcuusAnR8fAcIy +BjSffB0yEIwaA7O9X7ZxiEYEEBECAAYFAjwIEdIACgkQaliC34RARgJ9zgCfS1K0 +bROVSB+9wX4g+xEE0phEAToAn3etSLME5hzsisIRMjUsGbBDe7+aiEYEEBECAAYF +AjwjtVQACgkQRHJT9Ar9DKjv+QCbBE3lRMzyKxTbPUd9v+nB8EVqv4cAn0DxPkAI +kuriAuwtOjCypTDNydyxiEYEEBECAAYFAjxdq0AACgkQ7vDbNLMhJgNwvwCeMc0Q +mOS0ctJOX1J9a3DWkMyUdf4An3iIslZ7stkMOi1VdyE5fR2YDvNFiEYEEBECAAYF +Ajxw4+MACgkQGM0lpSLzivNlngCeLdkkRkcyHVKttl6Z9IQExE+gaNsAnRko+7BQ +Ou5jXMfGarg1rE2zDhsFiEYEEBECAAYFAjxxJxIACgkQscRzFz57S3PkJwCg3qep +dTsiNKuGYC6a1RlJZTBqkiEAn2G6ypvCpWAL43LWbMbyyf/rYxSoiEYEEBECAAYF +AjxxQYIACgkQOhqmNZCaVAYvbACgz9mXzo/nC64mx03IFgL8oFuBAhIAoL91NILX +xGYrkaOnM+2Ci20UvA3ZiEYEEBECAAYFAjxzeIMACgkQo+C50no0+t5J7QCgpSCg +GQ8eMefvsDsF0DlEZzuAHNoAoK1TFwuK7ZowUQJyWp1tKDtNDbx3iEYEEBECAAYF +Ajx+gfMACgkQjjtznt0rzJ3/dgCgnDMnLna3yPskxeVf32wDbTHLxf0AnjWCw4lf +YauS0LumGv9uHN9PaErhiEYEEBECAAYFAjyAY8EACgkQ14NrbAzZIOdEPgCgt5Di +ZfRFkvzAPecRDCIp3pOdUwkAnjj1CDE+Kzg2RiK9Z73QM8B0J4driEYEEBECAAYF +AjyBd5kACgkQ/3vbrZlD49+lmwCfS9apz+gEHsRV6ELS4NtCLvrJsRkAn3Aexpis +dP+8KwolieJwaVPitN2giEYEEBECAAYFAjyMzCQACgkQhbmQdcKRDkGoiACaAqrw +Xn6kf3aD7wss1rgQmrCtJKIAoIU6uifoxBubp2+YjW6kjbnkFMD0iEYEEBECAAYF +AjyXNDoACgkQoegCcNp0M5aGrgCeLBRQ8CAVzPO8OTz2TMFqYLIbFrcAoK2qJqoj +mF2+THtFCHz0hhiBAekNiEYEEBECAAYFAjyXNjgACgkQg2i7WWb7wYxzxwCfcrZ5 +yTwjn9Sh1S/yL3MBKBs8uxUAn0pC4GgIsbbaxcf1QA5AYwFiPcPEiEYEEBECAAYF +AjyxODEACgkQJXt5TsZsoD0pVgCfTIJ88OFNFlnUFoNZemDdbd4ZqEsAn1y5ZyCl +5SYkqFTGiVtkgtIIEhK7iEYEEBECAAYFAjyxguAACgkQeuuK7Uc6ScnBgACfUlQr +rDUb78b93JEvThA/f1ZankIAni448ZxagzPjnj/vH33yK14agnq0iEYEEBECAAYF +Ajyxj4MACgkQocWSfM5dzg4qigCdHrjYquNu2aphWggG5E0G6zCW5MEAn1NQJmKk +TEUsbanbVOBx1G5wvYkeiEYEEBECAAYFAjyyhzsACgkQVlEzpFDUq7k99gCeMJc5 +KvC2gAHgCVjv6Hn7AKgY+rMAnRFIrjunb1Sh77542URoWAVmuPN0iEYEEBECAAYF +AjzyIFQACgkQX1807qC7Pev9PgCfcW15D2cS4UTkn11BSqn+pgrA4KIAoKzLDc78 +X3OFDzVXTOvk8V89OshGiEYEEBECAAYFAj1uHIwACgkQKMb1a4F8NWhPPQCaAprF +vggEHBTVR+KWzm0Z3l9ijLIAnAw2QtJ1Mlnz0ctNwSJwORM87/ARiEYEEBECAAYF +Aj2ERksACgkQ1DyzBZX+yjSzyACgjUKL3CH2UYciEAarZU9H0ZYIIWQAnA6I1aJ0 +FgWiF2bd/jgWaBL2jtd4iEYEEBECAAYFAj2F5U4ACgkQdZc6ENbQhKbt/gCfblKS +qJohqhaFawtXPs8TX1UqY/sAnjqwumhFN4YAAez36gItTB9BxcmJiEYEEBECAAYF +Aj43BmIACgkQkQghntzeiQqeGACfSyyIi1vPniQOq8xLfgjDxFkkVEYAoJSFbH8u +hrwBMa8aOIRkjN9uRdY2iEYEEBECAAYFAj+Q/gkACgkQdt8qX2QD4/2oiwCfbZU8 +0h75YoE0cx5+E/ytzozrwxQAnjtYw4qDSX22n9sMhPW1CO8XZdXdiEYEEBECAAYF +AkCXK/YACgkQs9OWc5ZoRwHECACdHr0sI25gaWa1+uBYpkF3h7EWAnsAn31wzQoC +tVuJnd7dqqxn6nFacEHLiEYEEBECAAYFAkCnUqEACgkQt+hxIz4tn23BmgCfbd5O +5fC/zDHoS4VjKyQW39li0pwAnRaNn2SP7ThVdF7xjlueyhqPPvUPiEYEEhECAAYF +Aj0EW94ACgkQj/Eaxd/oD7Lv2ACfUACXl0hDfGeEdbGjhIa/hSaZCrkAmwV4SdeJ +nBoXV22VBEekmTfzHKHEiEYEExECAAYFAjyvU4oACgkQ6pxm6rn41tmEewCbB4FZ +6z6dmSJ2epBIdeoS8KHLNhEAn2ZcUDKfuFpVVDuV/bMhpjbbHJRIiEYEExECAAYF +Aj0FswMACgkQoWMMj3Tgt2a46gCdFwSWzfEmyuvfjnmNPzCyvdO2R2cAoJRl1Ibl +/2hPXjenl1f08pQLThZAiEYEExECAAYFAj0GRB8ACgkQKb5dImj9VJ8FHACcDjdy +CPMWjSbrXKCVFjDtuapl428AnRSI7e1VYRJcVdGmrAtmu360GrQpiEYEExECAAYF +Aj2J/ScACgkQ74J3yv6ZHpg4ogCgj8BllYTJEQ5sF62Qd2q9o2FNJ8cAn2K/7zpy +9M/Oig+yIYofaN+5fnUUiEYEExECAAYFAj4ykiMACgkQaqtaJwF/Vr1MmgCfcNfO +Om6/woHpEtuFVgYXvUh0tG4AnRTPBwdemHFViOojNJ0glWck/84ciEYEExECAAYF +Aj/F5joACgkQnkDjEAAKq6SChgCfViT5D2pKjVM9g+s3P+riRxshF3wAn0G9MGUz +O1YnhpTDmS7/I2WrLT36iEYEExECAAYFAj/QvIgACgkQ9MN1Y319OPMyOACgnMDI +EYY31K8RDRdITRYPyzg0aPMAnjkHIZ2QZ5cbeFv5LIQiAt/8WUluiEYEExECAAYF +AkDa3nAACgkQRTxFSQIw1gIEmQCgmo4Laf3buzEbtM746FMJeqy9aY0AniIpYHTJ +gFn20iSIwYlJ5JiNoWk3iEsEEhECAAwFAkCn2cEFgwmw+ycACgkQt5wosOl/hW1+ +GQCgxL4gvRYl/yXAZkXQztRWe1Ia4kYAmP8KsKNrVcT3k4XXah2XYPMN7CCITAQQ +EQIADAUCPQET/wWDBrWxagAKCRAUETjdo+RdZq2NAJ0X3oMzaR2t5MZtZMqNMxO7 +AHcC1gCg7FMURGjJQKfudOy58PhCnEiQkKKITAQQEQIADAUCPYYC5QWDBjDChAAK +CRBT4oVOC+Hw4/6WAJ9MuNF9WKFE1BD8xUi4e216xf+z/gCfVkG2HwbYS8J+I5TY +qg6OXcxlQniITAQQEQIADAUCP45usAWDBChWuQAKCRAKYuU0N6eRSQYxAKCmKHZy +5EYupyF671eAWW+lvnSS0gCeLMwyTHhyp8FqbJGfmDkEcURKFv6ITAQQEQIADAUC +P5J4BwWDBCRNYgAKCRDvy83/YfBbjOkoAJ9vyA2+SFX9sR1S1L9teAAzjxExrACe +MadTGJ3+vmBbybQzMcuOq9GA/8iITAQQEQIADAUCQL9HPwWDCZmNqQAKCRDZLSTf +3ZZcgzxlAJ94ZJIXvViFSYBCuTiwGH8JViHWVACfeF0eysjY5OZ+aOTjeEOOZ1tj +luaITAQQEQIADAUCQNtUXgWDCX2AigAKCRD2KOuTR0MgbAUIAJ4zEBlRY1zow2Rn +VnlJyV8+Zega2QCffe1gFTh83WIngScIyI9NSEcsNLqITAQQEQIADAUCQPEidwWD +CWeycQAKCRCS+/1Xhvylkt/8AJ4qxfg3sSNOlrujmtPxRQUISxWCnQCePI4fRvNx +zIXcP8AlFD/QW1Y66OiITAQSEQIADAUCPl5xiwWDBVhT3gAKCRBQXohHIudfS6AD +AKCdnk2cFYneP3/uyXODkjL+lTpR6wCgto0mJSBV+D6He4/i9QmG6b3U/9uITAQS +EQIADAUCP3sJOgWDBDu8LwAKCRBbs/UZWBZ5Gr9kAJ4vqVUqQTWIWIL9iieUHMuo +0B1WSACggEfxVgNctEiAGnJ9J3BzVjFN4MOITAQSEQIADAUCP4/uPwWDBCbXKgAK +CRAospXD9G6tuzd8AKCcP407jZCo64f6Ydsj2POiuw8X6gCeIdx30Zx8jzTtA9/C +WnzzqP29btmITAQSEQIADAUCP565+wWDBBgLbgAKCRDKsy6J6grA5DRrAJwLEBZB +jIKbb/ymMaPiu/U3ZykNzgCdED1+XXMe/3/RUsiTRvI0FdjtEXqITAQTEQIADAUC +PQdNFwWDBq94UgAKCRA8YsrY5NQyTYgyAJ9ReRl+ZmswUiJg7wX+dpAwGz/3hQCf +Zet/a5ohJis+50htGTFib5HY2tmITAQTEQIADAUCPXh4sgWDBj5MtwAKCRDQGpwZ +TXZs3qu4AKCLa4WOHhLLQqPJ3vrR29+lr/2O0wCeMfI9DS0dhKpJkMP2ppC9v8Xc ++UyITAQTEQIADAUCPXkxEwWDBj2UVgAKCRBwXFOJ1cGzWFqVAKCJHkZNLHh9IKqS +KTOs445cCicNVwCdEVDXd2aSMtxHLgTxvEu2bzE/IB2ITAQTEQIADAUCPYOt8wWD +BjMXdgAKCRAC1u0h4yxPS6DNAJoDnRKfJ67zae2HSKQ1WfMcPhbR4ACcD1bEYGaa +m9Zg6rks5PLZ9V7Y/4SITAQTEQIADAUCPYX8CgWDBjDJXwAKCRD1ayajpjmec9ly +AJ9S/E1eOhZgSwBgnPfP4xYN4at8lACfeyVcX1x53Y4A3diBhk1OUgLtRRqITAQT +EQIADAUCPYgQ5AWDBi60hQAKCRCDZcvc3U1O/tBUAKCv4L8/uCoYO6lhMLbWOXTu +Y98b9wCgtn3OSavVgXoGvuzNQqSxJqfp/C2ITAQTEQIADAUCPYg7AAWDBi6KaQAK +CRAdvV51g5nhu5YzAJ9/Rhh0VnuB1zWqMJp5cOEJ8t7Q4ACfU4m5n94oaT6LRX9J +wuk4wuf9IIKITAQTEQIADAUCPbbBngWDBgADywAKCRBWQSbyKfGb0fKKAJ9o1uPI +iUdgD1wC/ywuTPm4dGhN7gCdHIM98AWIE9lmHAk0OWZMQKiVcv+ITAQTEQIADAUC +PvYinQWDBMCizAAKCRCh9u6UJAtMPbVNAJ9wq7LcwSMlGuKQMGAq2kg/Vq3ZxACb +BGVk14o5PRQnhE23amIAepMPjuCITAQTEQIADAUCPvbPvAWDBL/1rQAKCRAFi1rN +RBxfgf+OAJ9pBdb4u+OglpxU1it3GFdRjHZr7gCgxBX/L7ONydo1FtlMfq6erh8E +MHmITAQTEQIADAUCPwCeWgWDBLYnDwAKCRAyjNaz68J1FaxZAJ9Pcr30X/EtYYmQ +43XxaI+egwjqCACggnySjSlQCJ1i8FsI6Y7gxJSFH7mITAQTEQIADAUCPwWrlwWD +BLEZ0gAKCRBOuDTo4szwD4nXAKCa5yk/2tzU2PM8cMU1xCiRFun9EQCdG9y1b/wD +ANof9u1CM+1eBAYJus+ITAQTEQIADAUCP4+UeAWDBCcw8QAKCRBsdheMoO2YLRmb +AJ9e3VofuPQhcKigyc2RnXVGhNsBuwCg5IOmh2+CLIMlqNljiHGNrppBJyqITAQT +EQIADAUCP5BBPgWDBCaEKwAKCRDs5+pfa9v3dgHdAJwJtQJr8RLOiKXB5jfrO7sc +GbHDYACeKTNZV9sWZloRjJE3cY684glpGLSITAQTEQIADAUCP5BTGAWDBCZyUQAK +CRCdCKgM7ZCNah0bAJ9YalTNX4jyQt4/KOX8Dbz0sovDjQCdEAwRdGOcDBjMuf96 +WvcniwCM2AeITAQTEQIADAUCP5BtvgWDBCZXqwAKCRCVLFYjbKds9NDpAJ90vu3d +OjGIwjFEwsnsFvNoMknQ4QCeJ1vLTVyOLc0jr/EJ+G2sbPEYoqqITAQTEQIADAUC +P5EaJwWDBCWrQgAKCRDjpo3KppjamQenAJ9RludXwb623B84iQeVDnN1tCCN1QCe +M7KFktG2G52kiH4CtdvNxKrQqLSITAQTEQIADAUCP5KauQWDBCQqsAAKCRC1qZ97 +20UtJx51AJ97pZsy9jjfAekIOXZEW6ufIbMX/gCgjHk/XOEQBKRo4mEiEEcXUFDC +g4+ITAQTEQIADAUCP5Mq2wWDBCOajgAKCRCtIBqBlDpfDnT6AJ93guwhwKsysCXU +j1Wl0KJA1tENQwCguKm5HVJEddhwFv8Le5ciGmDnBHiITAQTEQIADAUCP5QF5wWD +BCK/ggAKCRA6JSu9nSRLVQh3AJ4gMeJmROax54nhlYkYret8zNciUwCeIzFGKkwf +8MG9/G8hS2mJNuwC1ayITAQTEQIADAUCP5UJmgWDBCG7zwAKCRBMMvkImd2UaI03 +AKDTq3siME3Ug+UXLorMu6jQm+SxPgCgrMZoxFjCraNIqSbkHlGhaZfWhEaITAQT +EQIADAUCP5WRRAWDBCE0JQAKCRAbJ9dS+kmmGp20AJ9opauNO0RwohwSdSQ7/Suy +wmcmVgCfX7KoofMwOO2ICavDXjhy0el+nxeITAQTEQIADAUCP5wyawWDBBqS/gAK +CRA2AlZTq+CxBg62AJ0cLAuRBJtNZ965pbSXhm7LbGAHeACgv9292klqEJtMd0Sw +Mj15EjzJoYiITAQTEQIADAUCQNxSDgWDCXyC2gAKCRDND5yibr2jWYSXAKDKFv8S +7k+dyzPbxlAuoVyJbsDO6gCeMmWWouMPUuCDiAHyj2ZiEhiyrgmITAQTEQIADAUC +QOQZsAWDCXS7OAAKCRAdyR/zjvUg0f06AJ9Ev31lB/7hWWzm4NVBSK4sCK20GgCc +DVLwfhgVU/ezePrnn/ZQNyibd66IYwQTEQIAGwUCNu1I6gUJDMl8gAMLCgMDFQMC +AxYCAQIXgAASCRBd4kmWWwNYogdlR1BHAAEBtdYAn1IJbSJ46kvsBjq8X44hoybD +ZlbWAKCS2jR5Z+CmMC5WDqNepHXAe3alA4kAlQMFEDuB4BNSrOsu06QsYQEB6AYD +/iRZgJ2U+hTGt879PPwLW1y7dQFbjMHqbyyM7eml9ZbC+m+jqNvMsniFCR5qvStM +gbXuUZGGpd41mL5+vqF0wwM00nBQe+rr5grY2oMPCSEJRNtHEamOsbc4GP59nrwb +UhA7MKPSrPCvh9bvh+XQ7MSlar9eVBkqvnYmKdaKI1ioiKIEEwECAAwFAj+WOcoF +gwQgi58ACgkQ4WdUde/jR62JlQP+N3YY93o16UtsuXFobwn0fTiEI5V+PDkE9b5Z +VDr2E+do3bhERbgol6j5LQQ2vrn+BMfj42hiLQPHbHQDo1QyqlwpK/CBKt8r0i3m +14ZqiB9sciGnLVQK1ZTBMzNs3loZEOO5W6d1ynxTGzcO/pxsPVmwerJxs9kmaxOj +zkicWbaJARUDBRA3Q97TUoBXRHZTQB0BAchxB/9iTH4O9RoIshiUysQgMpncn9o9 +snx+sCO/NiSuAVleHNBP1d/Kvo6SGLJYoVfbfLPMNVyuZ4jGi8JQjsgVjpAz93nI +evhjz7Xwd3JpS9oUvPej1mdWnUB4AnkKQfN+5+eso9Gk7OC9cWq20lU9tpVMDIlO +j8GHR9kYfJ4fBbzdCGbG5Z9pzo+96gDUMzX5ZrHlChdV4eHJPMi60XeK+mpocQFQ +H3GBUSTeM3Sy93JoYJLdAA2ZcwMF5xI8HRx8u0rwCZNXnDTgPaRbDiW7587n3dWn +7Pwmxu/CPtCQ4YO+WdjcKvHio7CqojtM8/7xuclkp3Wb1pE1s9w929ca9SHdiQEV +AwUQOcqYVhpPhku+30gxAQGDOwgAjoKCGePm8h7g2edNYGosrPTMcZ8PNCMETXMZ +ozgCbEd5oWvotRaZnta2CZyj/u5gOrE7z8XR2PNttenuHVDii5y0KwaaTR12/wrp +9VJ61wLy/4zncnx/C9Nwg/Mu9Y2bMS8EuL16yWNrm6YxprWsaaYy7G251NI7cseX +cVnuAowzm6k8ovEwCAqVl4s7EUibNQQCuDgH4idUdr410fDnpUalpvsGYf1wqhs9 +3RbjU7pNEaLmnlz8zESHYaev+JpMVAfnw/jjWp97xyCual75xrc/aj93anrobvU/ +sSKCDbteDzW9xYyjqZGu2npn+rBR4iUHZf9j/glwT0PVnH/jf4kCIgQSAQIADAUC +P8yfvgWDA+olqwAKCRDYwgoJWiRXz0OCEACNCPskc7m7duoBwLTw5AwYgNox0XKo +Qi2X+Tipv8J9Acwy+Wbno5NLyH6dSuNS+V4vCxHGVaY7xS5CKa7iSJ8XzRgX0JPV +AC8fSlXI9fhSu/wg2z19a2y1QUUe3GYPLsapEsVk5GfcBqWW7WHmQD2BQrfR+uBK +jj8ruaAZL4At8V2bv0K8A5J2whETQLub6tSXwN3EWhdSVpRsoQn1rSIBuI5d5Z07 +sEUS3ypVI9jPSRYOTwvQjtfT/PcrigcBbtVIEtyjMfTttWgtuW2cJ9u2kim5oTDN +iQQEPlP521MHRmad1hU1z098Wo9AhSPxZDK8/XHv/hbvI5HeD1ydkR1uBmijtLAT +wNQ8rwFLJiKeB9i9C5OC3Mxlx5xNr2I566TI+ZyaMO7HBqBw7fQqgLS/loFvPdou +jzssjhacWNs+NRcO1imOZokm0IX2FOUPekyY+D42s1MQqw3VnddZWtPDBEOuDNUu +3nPyEnbKHSoQdOjEkx1OfQu3Aau227R5aoNFEFvNTrQkfpr7MKiexPa7pnQn8Ovo +ASAbIEwnkcEf5s7n2vbPVEGnO4cOb52/zMh2BWkFsrRp1z3+JA4doDTfI5/aLd59 +jDYrUtYtNuqqFLdh3wpc5f4zJBiYxP04LaLDje5zudlEZSDr6zJfBbieCVrXQhJ1 +522vVXv7wSDln4kBHAQTAQIABgUCQQm8qgAKCRAz/XFX/s5mTrURB/9GUhTUyJUC +Wg4MrQUruZQNjYQRxB/s8f57zAf+i94Qp1vlfnGmwWUaf0pqJtMpqMJEPd08Ehdv +xTz4dnOY+cTH9X6tZFMqSX5PSTi0bbT2oBIXL913Iw3joRRPeETgc9tZQHBrgXGh +s82h0HxXw/oAiAsPOiibIu8r2D7JhOzD5S+JKfIWIWsFAgcyQTgDQjoIL3LrcB7p +AmUDlQF9746dEhon1cgY5pn2mStb9BmEWyQWOaPi7OWb+SGCDAAzeNWD1BbHsME9 +g0eZ2ZmJTyBk2fnDTL4ga5lyi9ACRzrtywSDUGeanfhOcKM4onFhQQrNccUsFyWv +IeJkLPJfYySTiEwEExECAAwFAkENp5kFgwlLLU8ACgkQK6gmAsLOgJkgrwCfSnWg +A74uG11T8fAfX9ydAUJU2nIAnA2iQrW3wCpoVcPHta3pA7AgSy1OiEwEExECAAwF +AkEiMZoFgwk2o04ACgkQ+FmQsCSK63MHpgCfbI+x0F43mVjuYH9x75SBB8xX62YA +njdVEXOlJ5zGwzGMQQRvhsl4A0ZriEwEEBECAAwFAkCoZL4FgwmwcCoACgkQEglj +nRFKqFyRfwCeLMs/2xu844NRFZnsfyZqmM6nrZ4AoII4PrRQ2bTXCSRquIAbKKVS +mNCpiEwEEhECAAwFAkGE6LYFgwjT7DIACgkQGKDMjVcGpLSMfwCguvt1VXNNOwTt ++G8IaHegL/HKnr0AoKauzSZ7Aq4oqNpaqz8vjDHvC6rpiEUEEBECAAYFAkGD05gA +CgkQ9oi/YaVie2HDkACY2ltP58r6yt2xXVGEEaAwUU11EgCghgAhfALotSGYZtRJ +tQ0vJt8TwBeITAQTEQIADAUCQYDw7AWDCNfj/AAKCRCxifa00jpByMsjAJ9xoUvw +HdCrTUStZZeH09ZLzsw9BACeKtR7STIUWRpjLI7JpvrU8LL84BuITAQTEQIADAUC +QYQB/wWDCNTS6QAKCRBOPKkCbitD3DKnAJ9jxfE7KXqILRgMKQrQc7z2PwBEsgCf +RtCsIsW9kyO/meLeaESpR3q78fuITAQTEQIADAUCQYS+fAWDCNQWbAAKCRBNs9nu +f0WE2uIjAJwMkleJYoAA8wZRCR84E4aEfA4CaACfbIzYIZ0PW+bvTQUQXvgaYbe/ +KbSISQQTEQIACQUCQYPcBQIHAAAKCRBBKBqeoOKNGJ//AKCMgnS5OVhpAisl9s+n +GcLYpnRqCQCgk2cbBc+o0EisSNl4zRwlsJWlNjWITAQTEQIADAUCQYToHwWDCNPs +yQAKCRAsyKVocMis5RgMAKC/kLjySXt8sT611FLfHn8osc9/HwCeNlQAqB5HgTZr +9G86V4cJ3ZrtLluITAQTEQIADAUCQYVcuQWDCNN4LwAKCRBPpFU812tTWeM9AJ9y +IqNHnm1qw4FDTECKcMrn/N6+MwCfWzp6GKkgGSrilEd6tP5dvl07jZGITAQTEQIA +DAUCQYSQigWDCNREXgAKCRCU8fT3OsvSI6G4AJkB2TDVVkOZnO2FjDkw6NDTKdnL +6gCfZPwzN1BsmP8dTnFSVgR1gX7pXJiITAQTEQIADAUCQYVWQgWDCNN+pgAKCRCo +j/3PzGEe5p7WAJ0bw/UjTVnFHJXC3DE6U2VTqizKvACfYLGpNvoNacjH+SpGU8ST +QJFwKaCITAQTEQIADAUCQYVHBAWDCNON5AAKCRAN5ydtXgV38l1PAJwKnPVaD6TC +E6QLNyFsz1cNStf33ACeJJBCSh5k7ZKnyxT2ZuzbEXylmzSIRgQQEQIABgUCQYYP +qAAKCRDqCcRAP/9gbKkhAJ9BslntaM00WnDA3ASUif+zU2JSJACfaFzFnixQJYyE +aD+kDlwob3MiXCWITAQTEQIADAUCQYfBuwWDCNETLQAKCRBWbTYs7gl36JFCAJ95 +KY68gAsi6WfNtkfLhG6BBH6d5QCgirc/IEr9yXpxl/OEUNbfCca++giITAQTEQIA +DAUCQYfr6gWDCNDo/gAKCRBNPHyhVU+0xi9DAJ9f0VlmH917bnWapcM/cIndw5Ae +kwCgsZYTbwiSfbmXBvqGmNt7bPHuj6CITAQTEQIADAUCQYw8WQWDCMyYjwAKCRCJ +IbXczRWogwpeAJ0fP2Mpau62+T30QvLvMdc24JtSFQCfbGa6Uvpvp4aGjVlHU00D +8iAkYzWIRgQTEQIABgUCQY0U/AAKCRD4LlzASysrnntVAKCb8oWOwdMhp/aplHoG +W5pv8sWk+QCbBiyRs7fUPDPZZk7B+3gs4yqpsLOITAQTEQIADAUCQZzwYQWDCLvk +hwAKCRBXmeUthM+akBMpAJ9vGDrEAF/vosLl+igjQBkdVuHyWwCfUgx4E3MUznyE +QCcWAoeTFAmM+IqITAQTEQIADAUCQZIwWQWDCMakjwAKCRD/ZHcDTJFx6Y6BAJ49 +ketS9mbvkg43Wv10LVLu9RP/ZQCfWcqxNf5B9nnfz534Swk0m+IKjCSITAQTEQIA +DAUCQZlZZQWDCL97gwAKCRBK8VQqljpUsKmnAKCyheW90s5jIo4wsqoS1ZbCfFRz +bACgpaYZ85fkVenMqH5t/AeNEOfQX/mIRgQTEQIABgUCQaoVNgAKCRDO23/xky2D +Y6y+AKCYepkU1ktnW8SukTGrcqAwRCmoIQCfXD5W/B5uKYDEfhlErhOFImPD1e2I +SwQTEQIADAUCQerjsgWDCG3xNgAKCRC92TO3hf7Bfw8UAJjYqD/zuVRLdu1uCZbL +BGFuVP6kAJ4pgjY/zP5hWXaSl+L5+oEClfb+/YhMBBARAgAMBQJBrJuNBYMIrDlb +AAoJECxJgcTDNIbARj0AnA7N0c4Ns1o2y27RybNckjso1A3XAJoDseQ5VYuYTOKr +x4uXV4zVBeAHcYhMBBARAgAMBQJBwhKCBYMIlsJmAAoJEBhZ0B9ne6Hs5OAAn1yH +Oz6XSUAJNPC5LQtb2hit35ZiAJ9ApmeXEdYE6zgRT3jZrjir/EhMzIhMBBARAgAM +BQJBwijgBYMIlqwIAAoJEIHC9+viE7aSN4YAnA/NFK5EtShDIEdO/EtLLJ7IoRxo +AJ90DeOjyzeFsvgw1hwbC/ZLqK+WPYhMBBARAgAMBQJBwikwBYMIlqu4AAoJEGtw +7Nldw/Rz/BUAoIpDsq64H5BN+XxTg0Cm4gXPB4YqAJ93UxNgU4SS2sxSvaMueIeP +HLOuJ4hMBBARAgAMBQJCIvNsBYMINeF8AAoJENioB8fM7CJ7/gwAnik7rlwNgCPc +pLzF3sdevzvOxffaAKDhBcX7S3oLb0p36iJqIEVX1b+f0YhMBBARAgAMBQJCKJ4B +BYMIMDbnAAoJECwA7lLYUpVYBRQAn2YzlQGyrvie8kjl4uperz9/kdssAJ9ZeQgm +1Dj6KBMofCjwz3kI5cSmlohMBBIRAgAMBQJBsYRwBYMIp1B4AAoJEAFS1gPf6sS5 +9m0AnjTIpKrVOGXAPwwEmqiK1Vh6E4qaAJwPQSRv0VroLjnEuC7k1ytTXIJFRYhM +BBMRAgAMBQJBqjHJBYMIrqMfAAoJEHQ6VUzk8IfXS6MAn1b2h4coFheuA3mNstHR +IHFq9ROiAJ45k+V2FvQoWJz3aVb3W8tVcgYXS4hMBBMRAgAMBQJBqyVEBYMIra+k +AAoJEM6KedeYAW3HK58AninBow4efQ8Ii+vCVMmcUZI/wbnuAJ9028GcLlmaHSVW +sFYK2YfI01cvTohMBBMRAgAMBQJBtzyaBYMIoZhOAAoJEBHy3EPK5jRCRGQAoI3W +osJGFXaxJeMhtJHIrzl4ONY7AJ9hWMYKlMieQZdpHbWZTOsiCJjy+4hMBBMRAgAM +BQJBuB8qBYMIoLW+AAoJEOVcsYNHeJ+74vwAoIoCeGH3M/bycKeykI+yeaXI78Hd +AKCCd63fz06xMBvjJsG8YdldyIVWC4hMBBMRAgAMBQJBuCvXBYMIoKkRAAoJEOFn +vWHVQeFEyH4AnRNFwQQ37Rz0LS5nOuxLaOaRUJcqAJsGzzqdi6YXSEvHVQxJSIaw +36YdJ4hMBBMRAgAMBQJBuFoNBYMIoHrbAAoJEATEHzbNJISp7Q8AnR1G2I3agHt6 +eg2IOQzPXNMwkQK6AKCcmjlAmYDLC30kG3IHuN9yclRbLIhMBBMRAgAMBQJBuXbe +BYMIn14KAAoJED66vOIb8CHTqvEAn0L0IqrwpcpT1O0eijqWjuwEz/PeAJ9/QXQN +Ippz1e7+BA3k/xUWGxRpzIhMBBMRAgAMBQJBwqpyBYMIlip2AAoJEDxtQMm+Lwr2 +wL0AniPqOWABEeev+hFFfxzO7Jeli/A4AKCCNzSrsY7ucWEfuvtN2KVfnJfl4ohM +BBMRAgAMBQJCCIx6BYMIUEhuAAoJECKlHI3tT+DADxQAoKn6T6Q8lNgY9Nu10ZVx +LMU3/3GIAKC5VPmhh5KfHzoFIeNTOXJG/nVNXokCIgQQAQIADAUCQcIpbgWDCJar +egAKCRCq4+bOZqFEaNKoD/kBxrf+A7YtQviSiSheWwm4jzFHqU1GziVnx9lqmpjG +Ff49WgkVxI/KA64+gQNuuIlnHWgFFvNsJ8kH9AtVzSAu8dT6s8DXu0ZnwHI3LdTN +hh/4cNRJsUEIi6j0MWw2m76bK2WJXS0K1YxmNkRBiOdUzt8KXjX55+gjQ+Y2R+xQ +YA+vvAx7+smPk0rm+iWTM1fSUEXZp1+tAfC9J1lI9sGx0pLMr0JeY0Gd2i92UL+y +GG1MECEyA1M1vxe9dGM8QUrRYR/qi1uefPUs3dPdsLwTiGZZk9WaQcks+wmAZ6TT +pN/b+5nfbrUWDjJDSe7E5X+9JM07OcCePA1kQiBVe44DEdCgbLZlt3ao/XgZNRxP +FEEdQGrscwSwMUnOq6i5Hwm3y1olH6CjN0s14hfU9tkudAJY0reTsVm5UN8vBe09 +I17DQ2Jb8kAohE21gFgOLM1Rk8oO9QEuLK8EKv9xWStOgGKXnKz5ZV8ZiBmMgM0i +ESs//9L1jqRTOVjOjkTSkBkFwVnS7BvSM9BTgU3dEls0i1iAkQkSl3wOixysnCfW +MHgX2CTnQZZjs+3TPkswWtl/ZgPdqcFBGctYGOL3qHdylFQWs6dNIsyGhu6nDESM +jkhQtTeCIlsxBKHTnm7C3MWuL5+PdmonxYfrkal8GVv3CCGGAtkYMHPIHcZyVeF/ +mIhMBBMRAgAMBQJBk629BYMIxScrAAoJENZr6jfBP8e2AVsAoKR3MfZ+Kpd6Kcvg +Ts/cCeRlpynpAKCDmw8VBhga70t30XZYhUnmPmQVsYhMBBMRAgAMBQJCNqp8BYMI +IipsAAoJENXFt0PEp+o+6fkAn2VjI9bSV5E/wq+alHEOjEXHtNHHAJ9K8bXfx5kG +/EMfDrAt/DtPcYJ1CohMBBMRAgAMBQJCIf49BYMINtarAAoJEMjYuSxPcUYFd14A +ni5vzEoG4gM6dwiWUf490IatIw2BAJ911L/lVgLLiSIafk02F3OoVIT43ohMBBAR +AgAMBQJCIoDuBYMINlP6AAoJEAHF69jK2POjuHUAn3bZ17H2pOTQ5RZPwflDaI56 +ZxXVAJ9UGcqwfql043be5/Ur1X06IBG2/IhMBBARAgAMBQJCU42LBYMIBUddAAoJ +EJbzTXpP9IY1OoIAoLTuWw/NW8fzZOKjEmUKCiY8sFujAJ0aqkuG+CpDi0Pdhgv9 +dyaM8zhnwIhMBBARAgAMBQJCmI6ABYMHwEZoAAoJEE225xuAYagwpNwAn038PEqZ +4JeypuFY7GRDxhTJuzJJAJ9k7ucqhZADqXVoc5BGi717B0IeJYhMBBIRAgAMBQJC +lgKkBYMHwtJEAAoJEIuWKUP8JD88GcUAnRyOmvlFE+EgK5mKPPKhaUIxIItEAJwP +IT8/DGMp9rjDGHLpPIivUv7QGIiDBBMRAgBDBQJClZzDBYMHwzglNhpodHRwOi8v +d3d3LnZhbmhldXNkZW4uY29tL3BncC1rZXktc2lnbmluZy1wb2xpY3kuaHRtbAAK +CRAwGQ6MHyjYrrWTAJ0TDJOB+fY11o6HcbIqhNG+PnwCQQCfY2WGFLbCP8M4MJPB +2K+YMOlUff6IRgQQEQIABgUCQrq7vQAKCRAe4EyBJF1k1MxFAKCqSb/8ZhpMf5Wk +h3S4YNPWjdjGpgCgsSfRL5/BUaS3WG0iwBGWPVTLm1+ITAQQEQIADAUCQr0yYQWD +B5uihwAKCRCvZCSxPb07IGcAAJ0WBhMS+0h1IytXNVkR8LPorAA6ngCePLLGeTK4 +WMeuinFDuGakfzmYRTKITAQQEQIADAUCQr1FbgWDB5uPegAKCRDrbNbFiT+tB15S +AJ9bVuCFqCPeE+tWe4YqEvJZtCJ1KACgmoyS72NSmLSL2qBQthTrnO31IWSIRgQQ +EQIABgUCQtBBlgAKCRBanbQDLq9NgE+XAJ0X13N0QQ4Dqo1xhJFpCma8X9cW7ACf +SkrXnKhjVbxUZhfZfH+arJON28qIRgQQEQIABgUCQvaGJAAKCRCJzUshYHVZ5gSD +AKCy7NLRML3GUdfmatVkfJ6bbkyYzQCeIqZYvCWRaO62nwUkrtHWeVn4YoGIRgQQ +EQIABgUCQvaNDQAKCRDVTq5LyZhwsegXAKCHvcHNwB3prOBdNWdkVuOoSMxXRACf +QwGlFJVFdIvsv0Mt1DEBpjeqk9qITAQQEQIADAUCQuUFlwWDB3PPUQAKCRCDYTpQ +FoJ9Awv7AJ4l9p4K17osQzVWkoOL5Cdu+RFyyQCeLOGb4rE5qE+QBvKNdYYU0aGF +QeGIRgQTEQIABgUCQtNUDwAKCRDfzAaZLMRV2d2IAKDVOdKomGy42wOuIliIDUjB +JDrH3ACgggk7OONHvOy95qiJsd62gHaILrWITAQQEQIADAUCQuKdnQWDB3Y3SwAK +CRD0PnJmPMiMCfD4AJ9b8uVV5VtHqhcN7Hy+5Vj2pua19gCeI3Z9Ssgbqmps34Rd +Z1Wt81EaN7qIRgQQEQIABgUCQvZT6gAKCRAXiTm5ct1YOA5TAJ0ek7qCSn33zq72 +5dFKmmApjgQ63wCfVSfXISqqYy95pNpzkNKyClelXzWITAQSEQIADAUCQutt6gWD +B21m/gAKCRDCb3AWAcbLg8ZhAJ9GjNV6hwo/My2vqWxB4JlwzbErpgCgjyozjM/q +SMFh26dVy+59xJU/nOKITAQSEQIADAUCQvD5fgWDB2fbagAKCRBY2pavC5ARQTO2 +AJ0eI0FkQfjrju80hIH6uYlj20mZRQCgvhkfxc8tP8RNdNZyn0hr2uZliZ+ITAQS +EQIADAUCQvmyDAWDB18i3AAKCRDiEt3umyBltxd0AJ945N9DAos87C+B/49mbLJ/ +WgkpWQCeMax/gmJO35XskfVpsK9J30RXRL2InAQQAQIABgUCQyCv0AAKCRC0a5I7 +bYq+cV5uA/9UAgGKyGzHBFRzr52z7CHiNmm168PA+o5S9y9TF/2n+2jmBm3qoY30 +24GL/XdOxLAWecjj0X3ZOeA1oONFI/mbCMD6T7bT4fmlTLfQcSPGiMoSAdbKWCKF +7YBzsJJu1k8It2lP7NEjf8+SJIgjCVngYAYO7gXBeIhDzjj2gp21ZYhGBBARAgAG +BQJDILAFAAoJEMWvd0pYUQta9zgAoJtxC4p6v9O/RNr3ugjSjuWWZfghAKC9/h/1 +8PwIqoVMKiUuYndDYo0SXYhMBBARAgAMBQJDIUxxBYMHN4h3AAoJEBSp1Git8Ip/ +xZwAnRHVnCadUFQM341BNs+7OHu5p68zAKCOZcgJLFbxOzD13fYz98/Gy2sbY4hM +BBMRAgAMBQJDIZVDBYMHNz+lAAoJEL/r08ZBzwMiDIUAoOyG2vdPDHx2YTbLPaV+ +4jsqtc4MAJ9F8nfCP99Z/+JTch3rKgWkLi2ovYhMBBARAgAMBQJDI3VNBYMHNV+b +AAoJEJugk2taNf1CsmgAoLmV/zQXM7K+JntozG1/eXFBS6vgAKCSjDXGE0sz8KLg +tHV8ZsMD4IkYPohMBBARAgAMBQJDI3gFBYMHNVzjAAoJEDFIu+8e7yb0EScAn2+s +gAl07YjPjS6axYQp0C79NUMLAJ0TQqZq1rlmIioyfjId64QOA1Pkw4hMBBARAgAM +BQJDKKE0BYMHMDO0AAoJEEk++45dZPhwHGsAn3XR7Qv8MQoYhMW1/tnYoWPn7ZXm +AKDbh09ir7I20Mi5UB36tvAvetf+TYhMBBARAgAMBQJDIJ3pBYMHODb/AAoJEJT+ +3vmtNrUVE1kAnjfUoHZiEbaGrL3VHksxgifLGnLgAJ498MeO4kO9R87+EnDZYHK0 +fFMeE4hMBBARAgAMBQJDIKhFBYMHOCyjAAoJEGxk7XjeNO+hxPMAn3iMsjHDY9BU +Rxw2L8S+7FvBbZ44AJ9BZe+sKNwrgm4Vd1H29pV8xpNzUYhMBBMRAgAMBQJDIKH3 +BYMHODLxAAoJEDA62eiAWc/cPNYAnA3+W8mLCuZv8aqvuRE1tmCyAtt5AJ4xqohe +9C6a7t8d/cDM7HepmJsxy4hMBBMRAgAMBQJDJCP5BYMHNLDvAAoJEHw0FqlEG6/3 +PjsAnRdZahoPcOU/AjSlqxl9v0oS6BRRAJ4kMlTD8RqKCnWybISf0HUa/j8g/4ii +BBABAgAMBQJDJcl+BYMHMwtqAAoJEA348Hf+CljYwoQD+QEn5r4ngyDRIcaWKcy1 +i+zEhBBbsQVpla90jM1BCcmpNM/71vrZwekOdh/a+6FYUoir9J2NjjHGQBK08uEs +QChnvvW4PGodTELh8Z85ooL5HJmVfzmN2gG0oKh4qrNoalZidgNsO4I8hk/xgTXB +7WJUHGCRFYN7ir7GYjUggfPFiEYEEBECAAYFAkNfjG4ACgkQ5XoO79RjNtpO6wCf +UB/3gkAhn8b2LSlUC1l8JJ/hqnkAoN5aTQEc/tc5LUq1AgSnHiCVPhrIiEwEExEC +AAwFAkPTbagFgwaFZ0AACgkQ5klUNHCsE9V2zQCgzkut4Nc+lbI9B22bynL2Y6nK +yMUAnjyLudX4A3A0KUsZn8PZ1hSnBY8ZiEYEEBECAAYFAkQFytwACgkQ9Jgd/vNm +D1M0ZQCeNMkLbWzJKyTHI0K0RBTLpWaJfOEAoIBbTLBDooQLOk30HerHkHmxwCiq +iEYEEBECAAYFAkQGZN0ACgkQIIdHgCGsbMTMXwCghGM37FHu/5AxG5/qXIq1PbW6 +5O4AmwdLE2OTC6+CbJtDwFW0vqXoQMKxiEYEEBECAAYFAkQH63kACgkQ3HeLB051 +S+3vGwCfWlGCEvkmjJgxYN1Gi8SkGkdQUfYAoOlKetRNM1Ja6x9rNuYGVwgU2YB/ +iJwEEwECAAYFAkQNdgYACgkQpOAUxG0aO7EZowQAkdtUOmOGm1HBQu7NBKncx2pt +NzIUUMNmn2lAXLB65dB+4iDjY70uuGARfDbAUF2O1I9VxZMK54nsA6eRs8RdZ7Ur +5IkHoBr4LyvkYx5IsdqzyT8m/5T4K7kT+gDxzR8Jjb1U8s5ZhMlRyhCLRtp9JDwI +2FbSaCkowI5hjsD8fm+JARwEEAECAAYFAkQG/cgACgkQ+fnDJwmNErO9MAf/ZpJE ++ZYPMThTVK+faygoqXJLGjCsTLf5OAKrvefM1LiB6Gx6CGU/nQKe2mJt4eC45VbV +SAdd65KcXdCdgYt3U+t3+if+FmqDDgofNM9i/2rWvnyb2ExNEOQb+ol2PS7rSs9W +e92+8IhaaTxkDmd905eoXVmEx+kaxS8DYskT856BQxNVTUVdmznNayE1GCroaAqo +qXg4qQcumvRajfYYtGKQGrejSmmaLOgfoTXMC8Wmae22CBD9VMPWlnoeqjtAudBc +mOtfo97ujQurvxq3hJnyxDdq+xKKXP39QEIIujRdMgA/W3sdPV8oTnns7MEOEGqP +KBX+/kb/rTVDFRAOPYhGBBARAgAGBQJEKFdaAAoJEBH0xB6z+64zhtQAnReWnha7 +l1rvH2qKpDDD5HCIFOpKAJsGGGv/6WnZxoTEzbKdmHxO40mReYhGBBMRAgAGBQJE +XP0qAAoJEIqjYq/pcjLN3qAAnRGdHEY8HrmS09ITQ/S0utQsfKqjAJ490qoLeX1G +3WfiSR8LWr67cK3RO4hGBBMRAgAGBQJEXP0xAAoJEKffWHJw1EwjPqgAoI1oRXYw +NKE7KIi+vsClHG3eWxk7AKDn0nhQ8GKBen6AFcGwPPzaIOCl4IhGBBMRAgAGBQJD +RBukAAoJEOrUtZD2iZvAJ64An0d999TYuIbuA+Jna9e7pIVt5siOAJwNykt/zttA +wm74mL6CaKX6io68eIhGBBARAgAGBQJEBYJYAAoJEG9dWWgc1S3oYp8AoMcB1tdm +RSVI7MW1UBSZE1M6D2HSAKC99gRHBYroBd+acHYp6GlfJdO5j4hGBBARAgAGBQJE +Bgo0AAoJEJrJ0ixjXGNLUXgAoN/eGtbGjZJPkCNnKMpYhpiDplc2AJ97PYkGRlUA +/jUCUqU1HMZPvPTCBIhMBBIRAgAMBQJEBisnBYMGUqnBAAoJEN/mV5IylcXNMSUA +oM+XSeK25/CceiiYl6+j/GVrf/ZEAJ44x1xyDjITeGnQ0XU38nrZ8P5JdYhMBBIR +AgAMBQJEBitnBYMGUqmBAAoJEKDlFb85iAlU1t4An37J47WV25DgUtjZ/QZ33AMP +60r4AJ95E6lAZkRO7Mo7y6oo61uONUqv44icBBMBAgAGBQJEDXXqAAoJEP3SdHpO +RjpqiWID/3NC4K0HYRky7d8wxch1KtlmqoWuuEGY5/eVZt985g42eD9W81Xa+hoi +S2Xf+bw3ZzVVtgeR1a75alakJ8QpOVJVXKfiI2f2S2sQYQ2f6VJZethgKXp0tla0 +Cesc2HVkVj7/8ZpKeEtjY4P+nzBYWC/ryiDxcYWQRB4LExuRaGaHiQIcBBABAgAG +BQJED0iVAAoJEBoqB+ocV7nZkhgP/j9pbZhf6HOUIwJvPbD5OUqDioRo6Iveev/I +lKY2NOBY6FSNhUc9O4RGxE0IMtVV6tuyCv1omdBdwgx8s+MYPqTQ9phNM+DK7DGV +5agwZaEkH/DB3B7w000/oZYgxj5MR4rgqrhHztKriqCbXjHijAKlnMlrsrYTTvzv ++q/Auhncilt47zoveQPEANqienWWVUI6ijjZh4pMZ/C2Bseek3UkBUgyW/uPJCRP +PkDjGE0+6XeLiTKMOnjmvZEoGJq58AAKhE10iPugt+7dW1ABil6rwm/jasqLFbms +DPG57AoyTmo+jmcEarnFl5HAM0sHque+i8XAkmG51dLCnndUmtrRgyJ9vGSRsava +tH9bVRW6pH5pRISE+bPNMatbowoKHGW13SG18WxggCvojFyqOtj4mQdqDertNLBZ +lEuTVYqKttkxdV08/0Sb+em+tvSDdLkDFZyGDVzX1tC7lCkFiYAPhh7RGhcTqrHr +RC8yU3roEFnjOZdYiokE/Yqrlc/Vkx4WPk3QXOusTkuCIYo6miwC7/nD3QyitDh4 +iwaphHkJ6kMtM9FuLwvtMZ2DyFvdNrrqQWtQGV4aPsG+xNJ13g7w89FDItz57N7Y +xwdnTLiglCGUbLS+a0AxxNYqnOlUnY8k86KTRbY9Gn1nVkr6PPJIcLsfGh0/kVML +Z9YNgmgHiQIiBBABAgAMBQJEBQ2ZBYMGU8dPAAoJEG427xrMjaswKkMP+gN7Njms +8ThD6iNUAlBOOUeb4E4O0sv1YdDFi/0mAvnzjOBkywyPLMSWiuUozldhkGgw0yET +FLJ2LFMKjMsnJ8jaz0v9FGUyYkTwYQ5zEE8DWohHvpzEUaYN7DKEQJpqjRr/xV8Z +OhV+ozLWHQGX1neWzs9JAI96e6aaQLcn2IrUoT+094SJ7aDv81TLdQD/7IrZrUOL +GkzyuPq/7VLY3zpzsQl8Wg2pwA8rxpQSnF1faFEWrMhsWV0D+mdTt9IZqyksR/kq +rgkKfcFwO8l+KnZrb5MW0Yx2xoxEJIxL9D5U1VTLyIGb+kLUxOSZ2l0uaBLBpvfV +N8Lv8uKMYNs3pM/8/i8lR2QzaWp+XhnnO65dHi9V4QSb8A03NHJCD0vvQaTHbon1 ++dnTwYywZN0L8xIveBlW1SjcJrSkEUY679wKeSUDYGjEjUnijpT8nHC2nmDtDwSx +aBDvZDyeeCwCR5VixMC3OouwSpsQDxnMeVb7fqka5WLehhth2aWCT9gTK9sVeC8k +6qMOm/GjNMRDISA7J2tJXDLRLe7+Ga7Nv/oVFOb7/K+LS/qlu+gDIu3lmCc+zWnZ +pDEJ+jzrQB5+1VOyFK46MCHP8dUZP9E7xlJDfsZo7j/vLpnDYsHl62MgLe6t+kRD +kI30E4O5bgzUvEKb+N2rEaP/9DpYPh29nKl2iQIiBBABAgAMBQJEBREiBYMGU8PG +AAoJEB0ajtzhQKBUMKsQAIccrd9HIYJqH5+DeS0stdWOEcZ7Vj4yIKM4nfME5li0 +/VT97HskqBBKU9OofCitdQbrSN6+GCkqW9RQLZAwk04fsZMOhxBq1xa6M3Mf0fB/ +aeq4XoOQ/o2DseOvpYwuPnwtIEKy+btWqbhNWMW1//JpIPBjkhN5fOYKNESnKs+a +F5OwNvXOx/b5IKVfXzq01T/Db11Tbkeek+GIk5n5SUdBX/BqPJJ8xHMTTbuBugnD +DaefHa57MsWq+EnKDv/WDwmMdG3zVPV/h7vkyfztw6be52LCb5MbvZUKtqc4m+LE +8fdDzo2JZd55nNqZA5zkou5gvjYqkEkchY7IrOqNF/Tw9J6qH+2dUITbhKGDA+lY +LTFermjVLOTkXomjdCibdyJn8J8fRghj6nVoiUBPu2n3N/ks5GCaQ2QlKAS8JIwq +xTGW89OwzviJWi/D6KPlkq7ZqIQIbHu3tAhLsujSoyW4OsNyiXG4+Prs92wpXupX +I3gDCZd9Ip/aPtcKTdXPFdGoEg7TwSvQVCxZo8ZxqyHzoFoC+nQcGFJt1uP22VVU +Uz4JeEB67St+2+Ve334V4y9HJ0R+wdHxUAQdSpwARgm6GaygZeqOH3EJ1VO3iRNi +/84zbWfWm4HW5KB6sHfMHL5iS6y7fnXNKGYmvmh1UlHORhL8SwbI+iacZT/i1KR7 +iEYEEBECAAYFAkRIoSkACgkQBYtazUQcX4FaAACgna/Uo5shsZrb/Wvb6GTFtgG1 +ahkAoI9GhTHnw87+wDc6DLMi1XqtKKqpiEYEEBECAAYFAkRIyf0ACgkQpy/2bEK9 +ZF20YQCfZwjbh+78sBcUx7Cmgubeh11vfUsAnioDXgcu1a3SAJRyN8bNBwA8b1+8 +iEYEEBECAAYFAkRbCWUACgkQf94+j/M+P8ZIRgCdFnRdJiYV36ltrJKCDPw7fSBf +w9oAoI/t+yOUaIto0sIIz+SRLz9JVRsgiEYEEBECAAYFAkRgh8oACgkQ/QEEsOIz +yJhleACgwjG6lnyEPFvFMSao2MMrWOwlRXEAoJoD++s3cUp37TS6nFSHMUNKPIfP +iEYEExECAAYFAkRP7XUACgkQP9IdKpo6VVjzxgCglZUus9zNtYV/oy7VassWKTdr +VisAoLjGY1PPmmd6tD9SeCEVPdO8tUA5iEwEEBECAAwFAkRd1IoFgwX7AF4ACgkQ +W6iT5Ow+mN9gGACghe7DhSkAu9q7YYCKBkn9Qf72/mMAn0bmcEDPL9HJbJCsRKD0 +fJICnxUQiEwEEBECAAwFAkRfF04FgwX5vZoACgkQvBAJ2g6XJT+KOACfZ9+/pP1U +3DqeSnYxSHhd7ok+XW8AoLBB+W/tda7q3WS8D4s7aAFg8Vi9iEwEEhECAAwFAkRd +tkIFgwX7HqYACgkQMjUtRWf3gmRNRACggx7OyFYyH0UrjJVAf6KU8hCy2vcAn1Cr +uSzN1QWb/QUfJd+nwB5kBO/UiNwEEAECAAYFAkRQtqIACgkQ0dlSBAnpodWC7gYA +lfbh6eetnO5Ow0owZlUWgKtwID980bBjWlRr96iRMB2f18tNNIuVwhLUIIF7myal +sDp3rLcCrtBmdZnAxvmJiGVvMkjO9Bu1mQc2ZvMs5TvPk1wDGzfmkpSQN6mggwYu +gAbtyiUUJ4JCANn8CwuPEtenrjpkT96T9CTepC0GV0bLfv0YIIpsqZ/8nfIwXDAu +A/LJawvXm1RXK48VTBSpuBmm6QXC4LQyvWgp9+QIQcpoGuzeTno0W5ieKC3jRLVZ +iQEcBBABAgAGBQJEW3BXAAoJEGdNh9WRGQ75MVwH/30INi9nn1TOW+viXt6yMZvu +BWYLsd9DEstr7lk2/Z+WSrtL8EBGk8Ql9g15eik/5dr+RGhYIAnkqcZILiU+hOny +q8juHclic9LShXmp9nQgl6TQrEXqJl0ZuxiStwhmGNysYinR/VKV+sHsWFQGiA70 +vB3fnW5rLDjyXhkFDpb/FAxFdn/Q7tjiEuJeu9THFnCzTvefDPSMu4mH3JVp8v2D +B9SUMigJG87ptBLWJxM7C851a613qzfOCwqbizSkBfCY+YKoUQxZXYgSnDd7o1Sr +WjAURfo94wEY6w3CQgValsuPfAxgRSMC70zt7+swzOqv93SGp4nzeD38nL6IItOI +nAQTAQIABgUCRJWOyAAKCRDcBtzPeST6c46+A/9opADZ3jKtRoxJuzL09JXnYlGJ +E5FpFSCs/m87asigQtqZU2S0DqF/bZ0UqR+1rwkv3IVykg99S4FjaYxc708xglqs +chcX3386twiy5KB1SDXmTZ7d/tklJn2eJynyBCLnh0/w08ijf8bmAqwwZc4m9TZ7 +GivP5GMWIvDcF8D51YhGBBARAgAGBQJEvTrNAAoJEDjp85Y24BGvVTAAnRiSdKbe +Qxk69mnsl8vmv4cOj2U1AKC0R1kTnI4VGf0NFjbnfqSaMPfT84hGBBARAgAGBQJE +wntwAAoJEEIIBcaJB0+tRGwAnilDar71HtNqIUXMyidO/V2bs7P/AJ0Tm2tuic5W +bbRObvyH8CzCcLViN4hGBBARAgAGBQJEjURnAAoJEKevmBqDrDNKAvsAoJNKLU2c +wX995QRM5K6tOw0V0gCvAKCAMvex50/FNQtWCjM6FYQhV9eTWIhGBBARAgAGBQJF +V6cVAAoJEPS0sMx5fr+rjnwAnRoZriBEXLKu+0e+DfD/vPVKTuCpAJ9W/dJVFesd +Ydvf2R8sVucmAKNjwYiBBBMRAgBBBQJFW1kyOhpodHRwOi8vd3d3LmZhYnJpemlv +dGFyaXp6by5vcmcvZG9jdW1lbnRpL2dwZy1zaWduLXBvbGljeS8ACgkQMjV6RfHo +5uSTZgCg3lHgDeEh4qwys9thqLwnNCz4nmoAoL8J/waoD8wxdGTefn9Kv22rU6ZM +iEYEEBECAAYFAkXse7AACgkQz+hIv/xnhaJIVACgjhIIFFyQ0uDhTOa8ImzupVd9 +9YYAn2uTkBnk9iSJm71qfs4Iu1LOvvKXiEYEEBECAAYFAkXt5D0ACgkQd75ZE3dJ +2dmEVwCeJgdRu5Ni/xStvaoQcxrOCx/knbEAoJdyrhE92y/5vlouhwK33NlOm1IS +iEYEEBECAAYFAkXDwT0ACgkQjqqHRDkpnTEhgACfQWRjxiNPo6YmjLbHOUgjF+RO +8nwAnihqF6P3Gdi7daIVTVSRa2Ia4ihriEYEEBECAAYFAkXDwUgACgkQ+kRiIcQk +Je2mfACg6p9lx3RNENpNaMhOaBRyAmXf0BsAn36apAhkjBrVZAaCrfHElgl1SsGE +iEYEEBECAAYFAkXDwVEACgkQ1AYyHAdPXoTxxwCg0GzM7dJmuddR46W99BuAPVLX +t9sAoK7dduLTQOdPmba5tCPGUQ2g6eaIiEYEEBECAAYFAkXDwVgACgkQLQlxeEoI +qt8ukQCfbKG3JLBwrHY/f7qc477HPJQXLdQAn3yHpYokpCsXxsszP//H4o2hLlq9 +iEYEEBECAAYFAkXq9sYACgkQTjhS9MN8HQmnbACfdV4/4tmiFOg14OzZOHqWo2+Q +jDAAoIs6qLFQtxyPhtMhzOaf27lOpHB2iEYEExECAAYFAkVYPE0ACgkQVPRhauu8 +LyYHUwCgnjbzsFKjk8GdtCPLxLnmyO0AAz8An2bszA71hnvtLgzQrIVf8mbc3pLZ +iEYEEBECAAYFAkXt2wcACgkQ0ZUMdhYT6NWcOQCeLtaRo4tzAYQo3DuXU2vpcflB +b3YAniNnNGWqXSahYoquHUQ/IUD8iCN5iEYEEBECAAYFAkXt+BUACgkQ3pioii3b +AKwxxgCfZbOiEAKcfo6Dk9wXXyVPMGLXE6UAn0FBnlwRjzVsG8QR4oTUjWS5L9E/ +iGMEExECABsDCwoDAxUDAgMWAgECF4AFAka1xZEFCRcuKX8AEgdlR1BHAAEBCRBd +4kmWWwNYokHUAKCKSLq+i1yHrG8ZXqJRk+d4SyanGwCeKFwqqRr3tbae+m4iK+Ec +yY+BR2a0HVdlcm5lciBLb2NoIDx3ZXJuZXJAZnNmZS5vcmc+iGMEExECACMCGwMF +CRNri/8CHgECF4AFAkJZQHoFCwcKAwIDFQIDAxYCAQAKCRBd4kmWWwNYovxpAJ0f +tTtETxhK8aKfIok/+43wNbQASwCfSFCPuVKTNHpv4JJ79feDCtfxxLGITAQSEQIA +DAUCQvmyDAWDB18i3AAKCRDiEt3umyBltyi2AJ9vQod9BNEKmH7IsQGKPDSmnzuI +RQCdGaBGlA0R0Bjjldv0vEBtcbVB/BmInAQQAQIABgUCQyCv0AAKCRC0a5I7bYq+ +cY0kA/0U+JNuaHih2INmjGtIyNtn0uLR5OVxpFDy9fvh1A/PQIcnv6Cznf0+/1EO +pC8dO6HWQxs6d1n1ZK1yDPc3boyLjxLLxuWd6B4xM7HsjqvBvW2fvVFcpPioawST +63swdZIWdvz5c7a3SOSipeuepxyutXLiLfcCB5HviXbCkYf4+ohGBBARAgAGBQJD +ILAFAAoJEMWvd0pYUQtaHroAoPk4cr3Cd0eUk1ceNnoBMeP+281CAKDjuLEpyr2S +4txh6EvT+jz0PfWJVohMBBARAgAMBQJDIUxxBYMHN4h3AAoJEBSp1Git8Ip/wbMA +oJemraY1wFzUJAWsY3D4bFxLppX5AKCA+jLM2kD/5oRZbIqSzGtkok9ZY4hMBBMR +AgAMBQJDIZVDBYMHNz+lAAoJEL/r08ZBzwMi8KkAoJ0FJADGDhigHpm7dLEoRUa+ +ZpxFAKDFQvGvWe8G3qCzb/LIdyzfIJ0hzohMBBARAgAMBQJDI3VNBYMHNV+bAAoJ +EJugk2taNf1CygoAoNAK8rnU1FUY7ZJzCgw+ZjtzL3jEAKDIwfErE8XTv5PP0sJM +CUJhxf7r4ohMBBARAgAMBQJDI3gFBYMHNVzjAAoJEDFIu+8e7yb0pT4An37QJM1Z +P++YHev7oYJknn57POoKAJ9lOdPWCuFuiCdPM9L4CvAUAeGd1IhMBBARAgAMBQJD +KKE0BYMHMDO0AAoJEEk++45dZPhw6PYAoJf6zUL8WFtgMLXr7gYeknvv8MJ7AKCL +XLi8Tu2SzTIc/PeFUqoLeSUoH4hMBBARAgAMBQJDIJ3pBYMHODb/AAoJEJT+3vmt +NrUVuFoAn3oCb9Z5+SeuRbBf3F4jy7oXa4ZEAJwIVmjnLrfaQvYWsNmTOK9Ao/Qy +TohMBBARAgAMBQJDIKhFBYMHOCyjAAoJEGxk7XjeNO+hJh4AnREqzDeFWvNqKJgz +LY5MMDPmqE8rAJ4khVpKsCn4zTTL88oIg4d7Q52gSohMBBMRAgAMBQJDIKH3BYMH +ODLxAAoJEDA62eiAWc/cOX0An1VJdoTDlAW2y4cxBiiqPbvwYzhPAJ9SFl+1uI/T +6PadAFhV1le5/NSTB4hMBBMRAgAMBQJDJCP5BYMHNLDvAAoJEHw0FqlEG6/3e/YA +n0xTVNplMGLfwL21U4uztcQo0C+9AJ9XF8ORPSTU3jzv6j7q+kBRwZpz2oiiBBAB +AgAMBQJDJcl+BYMHMwtqAAoJEA348Hf+CljYLmQD/2aFAfI9tLHiBvHkYX/GOJ5V +9bOhh5/9y1ldbd7mJZhYm4gkTxd/4TeO+iOFj4OjjcvGYfQo6O/B7n3M/VVNcpdJ +Cd+GjUvqVucwtEJu/Zlejx6T2zAjxpZxhVAk9U1iQ+tVC7ld+PEnLoHDsEI1cjuO +SDVEh4S836xlym5CtQGBiEYEEBECAAYFAkNfjG8ACgkQ5XoO79RjNtr/CQCgvQam +DsV4gii8XMn7N5nViO1J2mUAoO4AtHtN2l2Imsrv+y4W8wtpFyKEiEwEExECAAwF +AkPTbagFgwaFZ0AACgkQ5klUNHCsE9WrtwCfSFV3kQnpq8TEP5Sd15JR6zHawLkA +nj7OzbtoOwobgeWTB6NrVOh45wvHiEYEEBECAAYFAkQFyuAACgkQ9Jgd/vNmD1NS +6wCgjFSuWKUMECj8lq751xuRhdES0BIAnj4nvo+sxUykCpiNdGmD/kv8BR76iEYE +EBECAAYFAkQGZN0ACgkQIIdHgCGsbMShDwCeLNGiHENHdyi4L+ZDohBWpUvzlLYA +n3Uz1vuofNQ3JakVjyVqOFESowMYiEYEEBECAAYFAkQH63kACgkQ3HeLB051S+3p +LACguWszxmfMO1IxV+HtYaxfhhogv1YAoIUPRfY0bNGfJbcpeQfr+CcDT3hziJwE +EwECAAYFAkQNdgcACgkQpOAUxG0aO7HMBAQAlr0rX9d3DVtkoWDnJqjtxd2AEGIv +epBd3bH4vxgaxlKHO8qF9QRJk3TMpp+AketiERWexrwsu3HRsINee/9gb6lkVkxS +uTcSfn/NXT1fFLxyCEzxyhiC9nwKObj3JPOMRnJiPsET30aZ+K9/yfiuUfEUrDly +gZy6OfFa/jY04eKJARwEEAECAAYFAkQG/cgACgkQ+fnDJwmNErObegf+JtFCMTbg +ewZ4R+qmz7WWB1i4zOPCRe6O99EexdcXSOAHZ4r3oLiXMZEcjCQKZ5Wpz1TDqsob +VkyW65Ws5UwbiTs1WO/WI10dHdp9Vrv+ALhsx32amwMV37qrA9RCoBIU0QQFVTMk +Y1W4iLT0Myd/0C0VCHfMrV1S43ZPDQaC7V3yh1KCpZzjhZGTIKJSvckWjyTsUW2F +vCusCakX2P/GoSs0oF5s0mSl3BvlbkxlI2ZzE1bNfVIpqSDR8jT1r87cwTJkEH57 +e3PrO3DEbiQTHjbyuwD9kNTTnV2oGvVWPF/FvsFBk+fln1yECv6SIpALU1/zVzG/ +wZyP4MwTIOb4NIhGBBARAgAGBQJEKFdaAAoJEBH0xB6z+64zBhUAoJ6kWu5gDqHB +Z8Wan0YynEZi6tKyAJsHBacxx6UNYPENlVXlb0xl+kssa4h6BBMRAgA6BQJEXmVA +MxpodHRwOi8vd3d3LnNjLWRlbHBoaW4tZXNjaHdlaWxlci5kZS9wZ3AvaW5kZXgu +aHRtbAAKCRCUj9ag4Q9QLulZAJ992LLlu7wU5sJddqnffDzPoKh69QCgoX8QzBEi +SZjLKSrALwLCTYI/akSIegQTEQIAOgUCRF5lZDMaaHR0cDovL3d3dy5zYy1kZWxw +aGluLWVzY2h3ZWlsZXIuZGUvcGdwL2luZGV4Lmh0bWwACgkQtHXiB7q1gikU0QCf +ZM81Hr4p7ZPwxMZW+TVcRdaSIjoAoMq7mN4xSLtRsB/lGlFLhc1O4soLiEYEExEC +AAYFAkRc/SoACgkQiqNir+lyMs3HBACfb7fa3KzNGB9Oma3KDWeC42feCzAAoIfF +w3OXxtigxx8+AowiXGsZmqI+iEYEExECAAYFAkRc/TEACgkQp99YcnDUTCOrZQCg +gV7PoPMl1d+gvPTiuUAZm8UG/dYAn3PlOcTP4vxayC7OGSkoDA8Dut+KiEYEExEC +AAYFAkNEG6QACgkQ6tS1kPaJm8DI0ACfRfci8SHm+sQpjzKqr0zxfJT5yF0AnA37 +mn7nQyY28SJ2sddCo/f1JhvAiEYEEBECAAYFAkQFglgACgkQb11ZaBzVLeiG9wCf +aX6+h8bpMOraCn/sH1yQb6aI34EAoLzx4H6lGdyqnQTYiLXSrBTrto/niEYEEBEC +AAYFAkQGCjQACgkQmsnSLGNcY0vZ4wCgvBjcB5ABcNYRMEFSWsClxhaRAqUAmwUv +MA9NWdLk0pcUndbE3w70B5hUiEwEEhECAAwFAkQGKycFgwZSqcEACgkQ3+ZXkjKV +xc2qMwCfdew+RX+7ultYmO0Y8gRoLJzjBfgAn1UkZILe3+NKZBJTd1ZowJQiljHI +iEwEEhECAAwFAkQGK2cFgwZSqYEACgkQoOUVvzmICVQuFwCgqbjde48qPvUqLEip +he/zFq6pqgAAn1dXi6z+1s+bHavwCQK/q+3K5gdHiJwEEwECAAYFAkQNdesACgkQ +/dJ0ek5GOmrWRgQAoFF9IdTs5vX5OIDKIHW+d4aJfPg6w91SKkfpElDxNqZuk3rA +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 +nj+zW9f9Z2M0K2r+gldEC2Ew2yTl +=I1gH +-----END PGP PUBLIC KEY BLOCK----- diff --git a/SPECS/libgcrypt.spec b/SPECS/libgcrypt.spec new file mode 100644 index 0000000..b9016e0 --- /dev/null +++ b/SPECS/libgcrypt.spec @@ -0,0 +1,499 @@ +Name: libgcrypt +Version: 1.5.3 +Release: 14%{?dist} +URL: http://www.gnupg.org/ +Source0: libgcrypt-%{version}-hobbled.tar.xz +# The original libgcrypt sources now contain potentially patented ECC +# cipher support. We have to remove it in the tarball we ship with +# the hobble-libgcrypt script. +#Source0: ftp://ftp.gnupg.org/gcrypt/libgcrypt/libgcrypt-%{version}.tar.bz2 +#Source1: ftp://ftp.gnupg.org/gcrypt/libgcrypt/libgcrypt-%{version}.tar.bz2.sig +Source2: wk@g10code.com +Source3: hobble-libgcrypt +# do not run the ecc curves test +Patch1: libgcrypt-1.5.0-noecc.patch +# make FIPS hmac compatible with fipscheck - non upstreamable +Patch2: libgcrypt-1.5.0-use-fipscheck.patch +# fix tests in the FIPS mode, fix the FIPS-186-3 DSA keygen +Patch5: libgcrypt-1.5.0-tests.patch +# make the FIPS-186-3 DSA CAVS testable +Patch7: libgcrypt-1.5.3-fips-cavs.patch +# fix for memory leaks an other errors found by Coverity scan +Patch9: libgcrypt-1.5.0-leak.patch +# use poll instead of select when gathering randomness +Patch11: libgcrypt-1.5.1-use-poll.patch +# compile rijndael with -fno-strict-aliasing +Patch12: libgcrypt-1.5.2-aliasing.patch +# slight optimalization of mpicoder.c to silence Valgrind (#968288) +Patch13: libgcrypt-1.5.2-mpicoder-gccopt.patch +# pbkdf2 speedup - upstream +Patch15: libgcrypt-1.5.3-pbkdf-speedup.patch +# fix bug in whirlpool implementation (for backwards compatibility +# with files generated with buggy version set environment +# varible GCRYPT_WHIRLPOOL_BUG +Patch16: libgcrypt-1.5.3-whirlpool-bug.patch +# FIPS DRBG +Patch17: libgcrypt-1.5.3-drbg.patch +# Run the FIPS mode initialization in the shared library constructor +Patch18: libgcrypt-1.5.3-fips-ctor.patch +# Make it possible to run the test suite in the FIPS mode +Patch19: libgcrypt-1.5.3-fips-test.patch +# Make the FIPS RSA keygen to be FIPS 186-4 compliant +Patch20: libgcrypt-1.5.3-rsa-fips-keygen.patch +# add configurable source of RNG seed and seed by default +# from /dev/urandom in the FIPS mode +Patch21: libgcrypt-1.5.3-fips-cfgrandom.patch +# update the selftests for new FIPS requirements +Patch22: libgcrypt-1.5.3-fips-reqs.patch +# use only urandom if /dev/random cannot be opened +Patch24: libgcrypt-1.5.3-urandom-only.patch +# fix predictable PRNG output +Patch26: libgcrypt-1.5.3-rng-predictable.patch +# add drgb cavs test +Patch27: libgcrypt-1.5.3-drbg-cavs.patch +# allow reinitialization of ath in the FIPS mode +Patch28: libgcrypt-1.5.3-ath-reinstall.patch +# allow auto-initialization of drbg +Patch29: libgcrypt-1.5.3-drbg-init.patch + +%define gcrylibdir %{_libdir} + +# Technically LGPLv2.1+, but Fedora's table doesn't draw a distinction. +# Documentation and some utilities are GPLv2+ licensed. These files +# are in the devel subpackage. +License: LGPLv2+ +Summary: A general-purpose cryptography library +BuildRequires: gawk, libgpg-error-devel >= 1.4, pkgconfig +BuildRequires: fipscheck +# This is needed only when patching the .texi doc. +BuildRequires: texinfo +Group: System Environment/Libraries + +%package devel +Summary: Development files for the %{name} package +License: LGPLv2+ and GPLv2+ +Group: Development/Libraries +Requires(pre): /sbin/install-info +Requires(post): /sbin/install-info +Requires: libgpg-error-devel +Requires: %{name} = %{version}-%{release} + +%description +Libgcrypt is a general purpose crypto library based on the code used +in GNU Privacy Guard. This is a development version. + +%description devel +Libgcrypt is a general purpose crypto library based on the code used +in GNU Privacy Guard. This package contains files needed to develop +applications using libgcrypt. + +%prep +%setup -q +%{SOURCE3} +%patch1 -p1 -b .noecc +%patch2 -p1 -b .use-fipscheck +%patch5 -p1 -b .tests +%patch7 -p1 -b .cavs +%patch9 -p1 -b .leak +%patch11 -p1 -b .use-poll +%patch12 -p1 -b .aliasing +%patch13 -p1 -b .gccopt +%patch15 -p1 -b .pbkdf-speedup +%patch16 -p1 -b .whirlpool-bug +%patch17 -p1 -b .drbg +%patch18 -p1 -b .fips-ctor +%patch19 -p1 -b .fips-test +%patch20 -p1 -b .fips-keygen +%patch21 -p1 -b .cfgrandom +%patch22 -p1 -b .fips-reqs +%patch24 -p1 -b .urandom-only +%patch26 -p1 -b .rng-predictable +%patch27 -p1 -b .drbg-cavs +%patch28 -p1 -b .ath-reinstall +%patch29 -p1 -b .drbg-init + +%build +%configure --disable-static \ +%ifarch sparc64 + --disable-asm \ +%endif + --enable-noexecstack \ + --enable-hmac-binary-check \ + --enable-pubkey-ciphers='dsa elgamal rsa' \ + --disable-O-flag-munging +make %{?_smp_mflags} + +%check +fipshmac src/.libs/libgcrypt.so.?? +make check + +# Add generation of HMAC checksums of the final stripped binaries +%define __spec_install_post \ + %{?__debug_package:%{__debug_install_post}} \ + %{__arch_install_post} \ + %{__os_install_post} \ + fipshmac $RPM_BUILD_ROOT%{gcrylibdir}/*.so.?? \ +%{nil} + +%install +make install DESTDIR=$RPM_BUILD_ROOT + +# Change /usr/lib64 back to /usr/lib. This saves us from having to patch the +# script to "know" that -L/usr/lib64 should be suppressed, and also removes +# a file conflict between 32- and 64-bit versions of this package. +# Also replace my_host with none. +sed -i -e 's,^libdir="/usr/lib.*"$,libdir="/usr/lib",g' $RPM_BUILD_ROOT/%{_bindir}/libgcrypt-config +sed -i -e 's,^my_host=".*"$,my_host="none",g' $RPM_BUILD_ROOT/%{_bindir}/libgcrypt-config + +rm -f ${RPM_BUILD_ROOT}/%{_infodir}/dir ${RPM_BUILD_ROOT}/%{_libdir}/*.la +/sbin/ldconfig -n $RPM_BUILD_ROOT/%{_libdir} + +%if "%{gcrylibdir}" != "%{_libdir}" +# Relocate the shared libraries to %{gcrylibdir}. +mkdir -p $RPM_BUILD_ROOT%{gcrylibdir} +for shlib in $RPM_BUILD_ROOT%{_libdir}/*.so* ; do + if test -L "$shlib" ; then + rm "$shlib" + else + mv "$shlib" $RPM_BUILD_ROOT%{gcrylibdir}/ + fi +done + +# Overwrite development symlinks. +pushd $RPM_BUILD_ROOT/%{_libdir} +for shlib in %{gcrylibdir}/lib*.so.* ; do + shlib=`echo "$shlib" | sed -e 's,//,/,g'` + target=`basename "$shlib" | sed -e 's,\.so.*,,g'`.so + ln -sf $shlib $target +done +popd + +# Add soname symlink. +/sbin/ldconfig -n $RPM_BUILD_ROOT/%{_lib}/ +%endif + + +# Create /etc/gcrypt (hardwired, not dependent on the configure invocation) so +# that _someone_ owns it. +mkdir -p -m 755 $RPM_BUILD_ROOT/etc/gcrypt + +%post -p /sbin/ldconfig + +%postun -p /sbin/ldconfig + +%post devel +[ -f %{_infodir}/gcrypt.info.gz ] && \ + /sbin/install-info %{_infodir}/gcrypt.info.gz %{_infodir}/dir +exit 0 + +%preun devel +if [ $1 = 0 -a -f %{_infodir}/gcrypt.info.gz ]; then + /sbin/install-info --delete %{_infodir}/gcrypt.info.gz %{_infodir}/dir +fi +exit 0 + +%files +%defattr(-,root,root,-) +%dir /etc/gcrypt +%{gcrylibdir}/libgcrypt.so.* +%{gcrylibdir}/.libgcrypt.so.*.hmac +%doc COPYING.LIB AUTHORS NEWS THANKS + +%files devel +%defattr(-,root,root,-) +%{_bindir}/%{name}-config +%{_bindir}/dumpsexp +%{_bindir}/hmac256 +%{_includedir}/* +%{_libdir}/*.so +%{_datadir}/aclocal/* + +%{_infodir}/gcrypt.info* +%doc COPYING + +%changelog +* Tue Feb 28 2017 Tomáš Mráz 1.5.3-14 +- add DRBG CAVS driver and other necessary CAVS driver updates (#1172568) +- allow ath reinitialization in FIPS mode +- allow for auto-initialization of DRBG + +* Tue Oct 25 2016 Tomáš Mráz 1.5.3-13.1 +- fix CVE-2016-6313 - predictable PRNG output (#1366105) + +* Fri Apr 10 2015 Tomáš Mráz 1.5.3-13 +- touch only urandom in the selftest and when /dev/random is + unavailable for example by SELinux confinement +- fix the RSA selftest key (p q swap) + +* Wed Jan 14 2015 Tomáš Mráz 1.5.3-12 +- use macros instead of inline functions in the public header + +* Fri Dec 12 2014 Tomáš Mráz 1.5.3-11 +- do not initialize secure memory during the selftest + +* Fri Nov 14 2014 Tomáš Mráz 1.5.3-10 +- update the selftests for the new FIPS requirements + +* Fri Oct 31 2014 Tomáš Mráz 1.5.3-9 +- apply the fips-cfgrandom change also to the drbg seeding + +* Tue Oct 21 2014 Tomáš Mráz 1.5.3-7 +- make the RSA keygen to be compliant to FIPS 186-4 in + FIPS mode + +* Fri Sep 26 2014 Tomáš Mráz 1.5.3-5 +- add FIPS DRBG implementation +- run the FIPS POST tests in shared library constructor +- make it possible to run the test suite in the FIPS mode + +* Fri Jan 24 2014 Daniel Mach - 1.5.3-4 +- Mass rebuild 2014-01-24 + +* Tue Jan 21 2014 Tomáš Mráz 1.5.3-3 +- fix a bug in the Whirlpool hash implementation +- speed up the PBKDF2 computation + +* Fri Dec 27 2013 Daniel Mach - 1.5.3-2 +- Mass rebuild 2013-12-27 + +* Fri Jul 26 2013 Tomáš Mráz 1.5.3-1 +- new upstream version fixing cache side-channel attack on RSA private keys + +* Thu Jun 20 2013 Tomáš Mráz 1.5.2-3 +- silence false error detected by valgrind (#968288) + +* Thu Apr 25 2013 Tomáš Mráz 1.5.2-2 +- silence strict aliasing warning in Rijndael +- apply UsrMove +- spec file cleanups + +* Fri Apr 19 2013 Tomáš Mráz 1.5.2-1 +- new upstream version + +* Wed Mar 20 2013 Tomas Mraz 1.5.1-1 +- new upstream version + +* Tue Mar 5 2013 Tomas Mraz 1.5.0-11 +- use poll() instead of select() when gathering randomness (#913773) + +* Thu Feb 14 2013 Fedora Release Engineering - 1.5.0-10 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_19_Mass_Rebuild + +* Thu Jan 3 2013 Tomas Mraz 1.5.0-9 +- allow empty passphrase in PBKDF2 needed for cryptsetup (=891266) + +* Mon Dec 3 2012 Tomas Mraz 1.5.0-8 +- fix multilib conflict in libgcrypt-config +- fix minor memory leaks and other bugs found by Coverity scan + +* Thu Jul 19 2012 Fedora Release Engineering - 1.5.0-6 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_18_Mass_Rebuild + +* Thu Apr 5 2012 Tomas Mraz 1.5.0-5 +- Correctly rebuild the info documentation + +* Wed Apr 4 2012 Tomas Mraz 1.5.0-4 +- Add GCRYCTL_SET_ENFORCED_FIPS_FLAG command + +* Fri Jan 13 2012 Fedora Release Engineering - 1.5.0-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_17_Mass_Rebuild + +* Mon Aug 15 2011 Kalev Lember 1.5.0-2 +- Rebuilt for rpm bug #728707 + +* Thu Jul 21 2011 Tomas Mraz 1.5.0-1 +- new upstream version + +* Mon Jun 20 2011 Tomas Mraz 1.4.6-4 +- Always xor seed from /dev/urandom over /etc/gcrypt/rngseed + +* Mon May 30 2011 Tomas Mraz 1.4.6-3 +- Make the FIPS-186-3 DSA implementation CAVS testable +- add configurable source of RNG seed /etc/gcrypt/rngseed + in the FIPS mode (#700388) + +* Fri Feb 11 2011 Tomas Mraz 1.4.6-1 +- new upstream version with minor changes + +* Mon Feb 07 2011 Fedora Release Engineering - 1.4.5-7 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_15_Mass_Rebuild + +* Fri Feb 4 2011 Tomas Mraz 1.4.5-6 +- fix a bug in the fips-186-3 dsa parameter generation code + +* Tue Feb 1 2011 Tomas Mraz 1.4.5-5 +- use /dev/urandom for seeding in the FIPS mode +- make the tests to pass in the FIPS mode also fixing + the FIPS-186-3 DSA keygen + +* Sun Feb 14 2010 Rex Dieter 1.4.5-4 +- FTBFS libgcrypt-1.4.5-3.fc13: ImplicitDSOLinking (#564973) + +* Wed Feb 3 2010 Tomas Mraz 1.4.5-3 +- drop the S390 build workaround as it is no longer needed +- additional spec file cleanups for merge review (#226008) + +* Mon Dec 21 2009 Tomas Mraz 1.4.5-1 +- workaround for build on S390 (#548825) +- spec file cleanups +- upgrade to new minor upstream release + +* Tue Aug 11 2009 Tomas Mraz 1.4.4-8 +- fix warning when installed with --excludedocs (#515961) + +* Fri Jul 24 2009 Fedora Release Engineering - 1.4.4-7 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_12_Mass_Rebuild + +* Thu Jun 18 2009 Tomas Mraz 1.4.4-6 +- and now really apply the padlock patch + +* Wed Jun 17 2009 Tomas Mraz 1.4.4-5 +- fix VIA padlock RNG inline assembly call (#505724) + +* Thu Mar 5 2009 Tomas Mraz 1.4.4-4 +- with the integrity verification check the library needs to link to libdl + (#488702) + +* Tue Mar 3 2009 Tomas Mraz 1.4.4-3 +- add hmac FIPS integrity verification check + +* Wed Feb 25 2009 Fedora Release Engineering - 1.4.4-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_11_Mass_Rebuild + +* Fri Jan 30 2009 Tomas Mraz 1.4.4-1 +- update to 1.4.4 +- do not abort when the fips mode kernel flag is inaccessible + due to permissions (#470219) +- hobble the library to drop the ECC support + +* Mon Oct 20 2008 Dennis Gilmore 1.4.3-2 +- disable asm on sparc64 + +* Thu Sep 18 2008 Nalin Dahyabhai 1.4.3-1 +- update to 1.4.3 +- own /etc/gcrypt + +* Mon Sep 15 2008 Nalin Dahyabhai +- invoke make with %%{?_smp_mflags} to build faster on multi-processor + systems (Steve Grubb) + +* Mon Sep 8 2008 Nalin Dahyabhai 1.4.2-1 +- update to 1.4.2 + +* Tue Apr 29 2008 Nalin Dahyabhai 1.4.1-1 +- update to 1.4.1 +- bump libgpgerror-devel requirement to 1.4, matching the requirement enforced + by the configure script + +* Thu Apr 3 2008 Joe Orton 1.4.0-3 +- add patch from upstream to fix severe performance regression + in entropy gathering + +* Tue Feb 19 2008 Fedora Release Engineering - 1.4.0-2 +- Autorebuild for GCC 4.3 + +* Mon Dec 10 2007 Nalin Dahyabhai - 1.4.0-1 +- update to 1.4.0 + +* Tue Oct 16 2007 Nalin Dahyabhai - 1.2.4-6 +- use ldconfig to build the soname symlink for packaging along with the + shared library (#334731) + +* Wed Aug 22 2007 Nalin Dahyabhai - 1.2.4-5 +- add missing gawk buildrequirement +- switch from explicitly specifying the /dev/random RNG to just verifying + that the non-LGPL ones were disabled by the configure script + +* Thu Aug 16 2007 Nalin Dahyabhai - 1.2.4-4 +- clarify license +- force use of the linux /dev/random RNG, to avoid accidentally falling back + to others which would affect the license of the resulting library + +* Mon Jul 30 2007 Nalin Dahyabhai - 1.2.4-3 +- disable static libraries (part of #249815) + +* Fri Jul 27 2007 Nalin Dahyabhai - 1.2.4-2 +- move libgcrypt shared library to /%%{_lib} (#249815) + +* Tue Feb 6 2007 Nalin Dahyabhai - 1.2.4-1 +- update to 1.2.4 + +* Mon Jan 22 2007 Nalin Dahyabhai - 1.2.3-2 +- make use of install-info more failsafe (Ville Skyttä, #223705) + +* Fri Sep 1 2006 Nalin Dahyabhai - 1.2.3-1 +- update to 1.2.3 + +* Wed Jul 12 2006 Jesse Keating - 1.2.2-3.1 +- rebuild + +* Mon Jun 05 2006 Jesse Keating 1.2.2-3 +- Added missing buildreq pkgconfig + +* Tue May 16 2006 Nalin Dahyabhai 1.2.2-2 +- remove file conflicts in libgcrypt-config by making the 64-bit version + think the libraries are in /usr/lib (which is wrong, but which it also + prunes from the suggest --libs output, so no harm done, hopefully) + +* Fri Feb 10 2006 Jesse Keating - 1.2.2-1.2.1 +- bump again for double-long bug on ppc(64) + +* Tue Feb 07 2006 Jesse Keating - 1.2.2-1.2 +- rebuilt for new gcc4.1 snapshot and glibc changes + +* Fri Dec 09 2005 Jesse Keating +- rebuilt + +* Wed Oct 5 2005 Nalin Dahyabhai 1.2.2-1 +- update to 1.2.2 + +* Wed Mar 16 2005 Nalin Dahyabhai 1.2.1-1 +- update to 1.2.1 + +* Fri Jul 30 2004 Florian La Roche +- another try to package the symlink + +* Tue Jun 15 2004 Elliot Lee +- rebuilt + +* Sun May 2 2004 Bill Nottingham - 1.2.0-1 +- update to official 1.2.0 + +* Fri Apr 16 2004 Bill Nottingham - 1.1.94-1 +- update to 1.1.94 + +* Tue Mar 02 2004 Elliot Lee +- rebuilt + +* Sat Feb 21 2004 Florian La Roche +- add symlinks to shared libs at compile time + +* Fri Feb 13 2004 Elliot Lee +- rebuilt + +* Wed Jun 04 2003 Elliot Lee +- rebuilt + +* Thu Mar 20 2003 Jeff Johnson 1.1.12-1 +- upgrade to 1.1.12 (beta). + +* Fri Jun 21 2002 Tim Powers +- automated rebuild + +* Sun May 26 2002 Tim Powers +- automated rebuild + +* Tue May 21 2002 Jeff Johnson +- update to 1.1.7 +- change license to LGPL. +- include splint annotations patch. +- install info pages. + +* Tue Apr 2 2002 Nalin Dahyabhai 1.1.6-1 +- update to 1.1.6 + +* Thu Jan 10 2002 Nalin Dahyabhai 1.1.5-1 +- fix the Source tag so that it's a real URL + +* Thu Dec 20 2001 Nalin Dahyabhai +- initial package