diff --git a/.gitignore b/.gitignore
index 1f3b92b92d6b25fd8050f0e2803cf369a9667c59..830ba6789e1b70470f78e5a5de4b50bf0d818ed1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -50,6 +50,7 @@ core
 /ecc-384.h
 /ecc-521.h
 /ecc-25519.h
+/version.h
 /nettle.aux
 /nettle.cp
 /nettle.cps
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index f839416350294650f755de27e3ec66cae1fa9648..6cfc1dcbf452cfc5f921b351a408870f1a3c7c0e 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -4,27 +4,40 @@ before_script:
  - yum install -y git make autoconf libtool automake gettext-devel glibc-devel gcc valgrind libasan-static libgcc.i686 glibc-devel.i686
 
 # See http://doc.gitlab.com/ce/ci/yaml/ for documentation.
-Build and Check (x86-64):
+build/x86-64:
   script:
   - yum install -y gmp-devel
   - ./.bootstrap &&
-    ./configure --disable-documentation && make -j4 &&
+    ./configure --enable-fat --disable-documentation && make -j4 &&
     make check -j4
   tags:
   - shared
   except:
   - tags
-Build and Check (x86):
+build/x86:
   script:
   - yum install -y gmp-devel.i686
   - ./.bootstrap &&
-    PKG_CONFIG_PATH="/usr/lib/pkgconfig/" CFLAGS="-O2 -g -m32" LDFLAGS="-m32" ./configure --build=i686-redhat-linux --disable-documentation && make -j4 &&
+    PKG_CONFIG_PATH="/usr/lib/pkgconfig/" CFLAGS="-O2 -g -m32" LDFLAGS="-m32" ./configure --build=i686-redhat-linux --enable-fat --disable-documentation && make -j4 &&
     make check -j4
   tags:
   - shared
   except:
   - tags
-Build and Check with mini-gmp:
+build/aarch64:
+  before_script:
+  - /bin/true
+  script:
+  - ./.bootstrap &&
+    ./configure --enable-fat --disable-documentation && make -j4 &&
+    make check -j4
+  tags:
+  - aarch64
+  only:
+  - branches@gnutls/nettle
+  except:
+  - tags
+build/mini-gmp:
   script:
   - ./.bootstrap &&
     ./configure --disable-documentation --enable-mini-gmp && make -j4 &&
@@ -33,8 +46,8 @@ Build and Check with mini-gmp:
   - shared
   except:
   - tags
-Build and Check with ubsan:
-  image: fedora:24
+build/ubsan:
+  image: fedora:26
   script:
   - yum install -y gmp-devel libubsan-static libubsan
   - ./.bootstrap && 
@@ -44,7 +57,8 @@ Build and Check with ubsan:
   - shared
   except:
   - tags
-Build and Check with asan:
+build/asan:
+  image: fedora:26
   script:
   - yum install -y gmp-devel
   - ./.bootstrap && 
@@ -54,3 +68,20 @@ Build and Check with asan:
   - shared
   except:
   - tags
+build/static-analyzers:
+  image: fedora:26
+  script:
+  - yum install -y gmp-devel clang compiler-rt cppcheck clang-analyzer
+  - ./.bootstrap
+  - scan-build ./configure --disable-documentation
+  - scan-build --status-bugs -o scan-build-lib make -j$(nproc)
+  tags:
+  - shared
+  except:
+  - tags
+  artifacts:
+    expire_in: 1 week
+    when: on_failure
+    paths:
+      - scan-build-lib/*
+
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000000000000000000000000000000000000..92200abcaf3fd67881b37b0199aaa58653b7ba4a
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,21 @@
+# nettle -- Information about our contribution rules
+
+# Test suite:
+
+   New functionality should be accompanied by a test case which verifies
+its correctness, on successful use of the new functionality, as well as on
+failure cases. The nettle test suite is run on "make check".
+
+# Continuous Integration (CI)
+
+We utilize a continuous integration systems, using gitlab-ci.
+
+This is run on a repository mirror at:
+https://gitlab.com/gnutls/nettle
+
+# Sending patches
+
+Please do not utilize the gitlab web interfaces. They are not
+being followed on. Please send your patches to nettle-bugs@lists.lysator.liu.se
+
+
diff --git a/ChangeLog b/ChangeLog
index cf37b0b159a0feba3c4bd53dc207a806e51b164b..0b98d74190030fe03ba812e6c4609357eb164032 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -44,6 +44,220 @@
 	(nettle_hashes): ... old name.
 	(nettle_get_hashes): New function.
 
+2017-10-16  Niels Möller  <nisse@lysator.liu.se>
+
+	CFB support, contributed by Dmitry Eremin-Solenikov.
+	* cfb.c (cfb_encrypt, cfb_decrypt): New file, new functions.
+	* cfb.h: New header file.
+	(CFB_CTX, CFB_SET_IV, CFB_ENCRYPT, CFB_DECRYPT): New macros.
+	* Makefile.in (nettle_SOURCES): Add cfb.c.
+	(HEADERS): Add cfb.h.
+	* testsuite/cfb-test.c: New test case.
+	* testsuite/testutils.c (test_cipher_cfb): New function.
+	* nettle.texinfo (CFB): Documentation.
+
+2017-10-16  Niels Möller  <nisse@lysator.liu.se>
+
+	* aclocal.m4 (GMP_PROG_CC_FOR_BUILD): Add -g when compiling with
+	gcc.
+
+2017-09-24  Niels Möller  <nisse@lysator.liu.se>
+
+	* tools/pkcs1-conv.c (base64_decode_in_place): New helper
+	function.
+	(decode_base64): Use it.
+
+	* sexp-transport-format.c (base64_encode_in_place): New helper
+	function.
+	(sexp_transport_vformat): Use it.
+
+	* testsuite/base64-test.c (test_fuzz_once): Update to use char
+	type where appropriate.
+	(test_main): Use helper functions base64_encode_in_place and
+	base64_decode_in_place (copied to this file).
+
+	* testsuite/testutils.c (tstring_data): Use uint8_t for data
+	argument.
+	* testsuite/testutils.h (SDATA): Use US macro to cast data
+	argument.
+
+2017-09-14  Niels Möller  <nisse@lysator.liu.se>
+
+	* hkdf.c: Delete unneeded includes. Use Nettle licensing notice.
+	* hkdf.h: Include only nettle-types.h, not nettle-meta.h.
+
+	* ecc-mod.c (ecc_mod): Workaround to silence a false positive from
+	the clang static analyzer.
+
+2017-09-12  Niels Möller  <nisse@lysator.liu.se>
+
+	* testsuite/testutils.h (mpn_zero_p): Avoid redefining mpn_zero_p
+	when building with mini-gmp. Since the mini-gmp update, this
+	function is defined by mini-gmp, causing link errors if nettle is
+	configured with --enable-mini-gmp --disable-shared. Reported by
+	Tim Rühsen.
+
+2017-09-09  Daiki Ueno  <dueno@redhat.com>
+
+	* testsuite/ecc-mul-g-test.c (test_main): Fixed mpn_cmp call.
+	* testsuite/ecc-mul-a-test.c (test_main): Likewise.
+	* eccdata.c (ecc_point_out): Write to given stream, instead of
+	stderr.
+	* eccdata.c (output_curve): In curve448, the bit size of the order
+	is slightly smaller than the one of p's. Adjust ecc_Bmodq_shifted
+	accordingly.
+
+2017-09-09  Niels Möller  <nisse@lysator.liu.se>
+
+	* mini-gmp.c: Updated mini-gmp from the gmp repository, latest
+	change from 2017-07-23.
+	* mini-gmp.h: Likewise.
+
+2017-09-06  Niels Möller  <nisse@lysator.liu.se>
+
+	* hkdf.c (hkdf_expand): Eliminate a (signed) ssize_t variable, use
+	break rather than return at loop termination.
+
+2017-09-06  Niels Möller  <nisse@lysator.liu.se>
+
+	HKDF implementation, contributed by Nikos Mavrogiannopoulos.
+	* hkdf.c (hkdf_extract, hkdf_expand): New file, new functions.
+	* hkdf.h: New file.
+	* Makefile.in (nettle_SOURCES): Add hkdf.c.
+	(HEADERS): Add hkdf.h.
+	* testsuite/hkdf-test.c: Tests for hkdf-sha256 and hkdf-sha1.
+	* testsuite/Makefile.in (TS_NETTLE_SOURCES): Added hkdf-test.c.
+	* nettle.texinfo (Key derivation functions): Document HKDF.
+
+2017-09-04  Andreas Schneider  <asn@samba.org>
+
+	* fat-arm.c: Add missing define for _GNU_SOURCE.
+
+2017-08-27  Niels Möller  <nisse@lysator.liu.se>
+
+	* configure.ac (GMP_NUMB_BITS): Set to dummy value "n/a" in
+	mini-gmp builds.
+	(NUMB_BITS): New substituted variable which always holds the
+	configured value.
+	* Makefile.in (GMP_NUMB_BITS): Renamed variable...
+	(NUMB_BITS): ...new name
+	* config.make.in: Update corresponding substitution.
+
+2017-08-26  Niels Möller  <nisse@lysator.liu.se>
+
+	* ecc-mod-inv.c (ecc_mod_inv): Add missing assert. Fixes a
+	"dead increment" warning from the clang static analyzer.
+
+2017-08-26  Niels Möller  <nisse@lysator.liu.se>
+
+	* examples/nettle-openssl.c (struct openssl_cipher_ctx): New
+	struct. Use everywhere, instead of typing EVP_CIPHER_CTX pointers
+	directly.
+
+	* configure.ac: Update openssl-related tests. Checks for
+	cipher-specific headers are replaced by a check for openssl/evp.h,
+	and the check for the BF_ecb_encrypt function is replaced by a
+	check for EVP_CIPHER_CTX_new.
+
+2017-08-03  Daniel P. Berrange  <berrange@redhat.com>
+
+	* examples/nettle-openssl.c: Rewritten to use openssl's EVP APIs.
+	The older cipher-specific functions always use openssl's generic
+	software implementation, while the EVP functions enables
+	platform-specific code, e.g., using the x86 AES-NI instructions.
+	(nettle_openssl_init): New function.
+
+2017-07-18  Niels Möller  <nisse@lysator.liu.se>
+
+	* ecc-add-eh.c (ecc_add_eh): Fix in-place operation by reordering
+	two multiplies. Previously, in-place operation resulted in an
+	invalid call to mpn_mul with overlapping operands. Reported by
+	Sergei Trofimovich.
+
+2017-06-09  Niels Möller  <nisse@lysator.liu.se>
+
+	* pss.c (pss_verify_mgf1): Check for m being too large, fixing an
+	assertion failure for certain invalid signatures. Based on a patch
+	contributed by Daiki Ueno.
+
+	* testsuite/rsa-pss-sign-tr-test.c (test_main): Add test case
+	contributed by Daiki Ueno. Problem originally found by oss-fuzz,
+	see https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=2132.
+	That problem report is currently embargoed, but will hopefully be
+	public in a month or two.
+
+2017-05-23  Niels Möller  <nisse@lysator.liu.se>
+
+	Rework the previous change, which had the unintended effect of
+	always regenerating .test-rules.make after ./configure is run.
+	* testsuite/Makefile.in (test-rules.stamp): New stamp file target,
+	depend on Makefile.in, and run $(MAKE) test-rules.
+	(.test-rules.make): Add a level of indirection, by depending on
+	test-rules.stamp.
+
+2017-05-20  Niels Möller  <nisse@lysator.liu.se>
+
+	* testsuite/Makefile.in (test-rules): Use $(srddir)/-prefix for
+	.test-rules.make target, and change dependency from Makefile.in to
+	Makefile.
+
+2017-05-17  Nikos Mavrogiannopoulos  <nmav@redhat.com>
+
+	* testsuite/Makefile.in: Ensure .test-rules.make is regenerated
+	when Makefile.in is modified.
+
+2017-04-09  Niels Möller  <nisse@lysator.liu.se>
+
+	* testsuite/dlopen-test.c (main): Call dlclose, to fix memory leak
+	on success.
+
+	* testsuite/pss-test.c: Delete magic to let valgrind to check if
+	pss_encode_mgf1 is side-channel silent with respect to the salt
+	and digest inputs. It turns out that the most significant bits of
+	the padded bignum, and hence its size, depends on these inputs.
+	Which results in a data-dependent branch in the normalization code
+	of at the end of gmp's mpz_import.
+
+2017-04-04  Niels Möller  <nisse@lysator.liu.se>
+
+	* pss.c (pss_verify_mgf1): Use const for input mpz_t argument.
+	(pss_encode_mgf1): Avoid unnecessary memset and xor operations.
+
+	Merged RSA-PSS support, contributed by Daiki Ueno.
+	* pss-mgf1.h, pss.h: New header files.
+	* pss-mgf1.c (pss_mgf1): New file and function.
+	* pss.c (pss_encode_mgf1, pss_verify_mgf1): New file and
+	functions.
+	* rsa-verify.c (_rsa_verify_recover): New function.
+	* rsa-pss-sha256-sign-tr.c: (rsa_pss_sha256_sign_digest_tr): New
+	file and function.
+	* rsa-pss-sha256-verify.c (rsa_pss_sha256_verify_digest): New
+	file and function.
+	* rsa-pss-sha512-sign-tr.c (rsa_pss_sha384_sign_digest_tr)
+	(rsa_pss_sha512_sign_digest_tr): New file and functions.
+	* rsa-pss-sha512-verify.c (rsa_pss_sha384_verify_digest)
+	(rsa_pss_sha512_verify_digest): New file and functions.
+	* rsa.h: Prototypes for new functions.
+	* testsuite/rsa-pss-sign-tr-test.c: New test case.
+	* testsuite/pss-test.c: New test case.
+	* testsuite/pss-mgf1-test.c: New test case.
+	* Makefile.in, testsuite/Makefile.in: Added new files.
+	* nettle.texinfo: Documentation of rsa-pss functions.
+
+2017-03-20  Niels Möller  <nisse@lysator.liu.se>
+
+	* nettle-internal.h (NETTLE_MAX_HASH_CONTEXT_SIZE): New constant.
+	* testsuite/meta-hash-test.c (test_main): Add sanity check for
+	NETTLE_MAX_HASH_CONTEXT_SIZE.
+
+	* tools/nettle-hash.c (list_algorithms): Also display the internal
+	context size.
+
+2017-01-03  Nikos Mavrogiannopoulos <nmav@redhat.com>
+
+	* ecdsa-verify.c (ecdsa_verify): Eliminated memory leak on error
+	path.
+
 2016-10-10  Niels Möller  <nisse@lysator.liu.se>
 
 	* write-be32.c (_nettle_write_be32): Use const for source argument.
diff --git a/Makefile.in b/Makefile.in
index 5288662290bffb45b120136146d0a0a5b8aa219d..6a0c13ecfde03eb8f418ec531cdbda1efc4e3d96 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -91,7 +91,7 @@ nettle_SOURCES = aes-decrypt-internal.c aes-decrypt.c \
 		 camellia256-set-decrypt-key.c \
 		 camellia256-meta.c \
 		 cast128.c cast128-meta.c cbc.c \
-		 ccm.c ccm-aes128.c ccm-aes192.c ccm-aes256.c \
+		 ccm.c ccm-aes128.c ccm-aes192.c ccm-aes256.c cfb.c \
 		 chacha-crypt.c chacha-core-internal.c \
 		 chacha-poly1305.c chacha-poly1305-meta.c \
 		 chacha-set-key.c chacha-set-nonce.c \
@@ -106,7 +106,7 @@ nettle_SOURCES = aes-decrypt-internal.c aes-decrypt.c \
 		 gosthash94.c gosthash94-meta.c \
 		 hmac.c hmac-md5.c hmac-ripemd160.c hmac-sha1.c \
 		 hmac-sha224.c hmac-sha256.c hmac-sha384.c hmac-sha512.c \
-		 knuth-lfib.c \
+		 knuth-lfib.c hkdf.c \
 		 md2.c md2-meta.c md4.c md4-meta.c \
 		 md5.c md5-compress.c md5-compat.c md5-meta.c \
 		 memeql-sec.c memxor.c memxor3.c \
@@ -145,12 +145,15 @@ hogweed_SOURCES = sexp.c sexp-format.c \
 		  pkcs1.c pkcs1-encrypt.c pkcs1-decrypt.c \
 		  pkcs1-rsa-digest.c pkcs1-rsa-md5.c pkcs1-rsa-sha1.c \
 		  pkcs1-rsa-sha256.c pkcs1-rsa-sha512.c \
+		  pss.c pss-mgf1.c \
 		  rsa.c rsa-sign.c rsa-sign-tr.c rsa-verify.c \
 		  rsa-pkcs1-sign.c rsa-pkcs1-sign-tr.c rsa-pkcs1-verify.c \
 		  rsa-md5-sign.c rsa-md5-sign-tr.c rsa-md5-verify.c \
 		  rsa-sha1-sign.c rsa-sha1-sign-tr.c rsa-sha1-verify.c \
 		  rsa-sha256-sign.c rsa-sha256-sign-tr.c rsa-sha256-verify.c \
 		  rsa-sha512-sign.c rsa-sha512-sign-tr.c rsa-sha512-verify.c \
+		  rsa-pss-sha256-sign-tr.c rsa-pss-sha256-verify.c \
+		  rsa-pss-sha512-sign-tr.c rsa-pss-sha512-verify.c \
 		  rsa-encrypt.c rsa-decrypt.c rsa-decrypt-tr.c \
 		  rsa-keygen.c rsa-blind.c \
 		  rsa2sexp.c sexp2rsa.c \
@@ -186,18 +189,18 @@ OPT_SOURCES = fat-x86_64.c fat-arm.c mini-gmp.c
 
 HEADERS = aes.h arcfour.h arctwo.h asn1.h blowfish.h \
 	  base16.h base64.h bignum.h buffer.h camellia.h cast128.h \
-	  cbc.h ccm.h chacha.h chacha-poly1305.h ctr.h \
+	  cbc.h ccm.h cfb.h chacha.h chacha-poly1305.h ctr.h \
 	  curve25519.h des.h des-compat.h dsa.h dsa-compat.h eax.h \
 	  ecc-curve.h ecc.h ecdsa.h eddsa.h \
 	  gcm.h gosthash94.h hmac.h \
-	  knuth-lfib.h \
+	  knuth-lfib.h hkdf.h \
 	  macros.h \
 	  md2.h md4.h \
 	  md5.h md5-compat.h \
 	  memops.h memxor.h \
 	  nettle-meta.h nettle-types.h \
 	  pbkdf2.h \
-	  pgp.h pkcs1.h realloc.h ripemd160.h rsa.h \
+	  pgp.h pkcs1.h pss.h pss-mgf1.h realloc.h ripemd160.h rsa.h \
 	  salsa20.h sexp.h \
 	  serpent.h sha.h sha1.h sha2.h sha3.h twofish.h \
 	  umac.h yarrow.h poly1305.h
@@ -218,7 +221,7 @@ DISTFILES = $(SOURCES) $(HEADERS) getopt.h getopt_int.h \
 	libnettle.map.in libhogweed.map.in \
 	config.guess config.sub install-sh texinfo.tex \
 	config.h.in config.m4.in config.make.in	Makefile.in \
-	README AUTHORS COPYING.LESSERv3 COPYINGv2 COPYINGv3 \
+	README CONTRIBUTING.md AUTHORS COPYING.LESSERv3 COPYINGv2 COPYINGv3 \
 	INSTALL NEWS TODO ChangeLog \
 	nettle.pc.in hogweed.pc.in \
 	$(des_headers) descore.README \
@@ -324,7 +327,7 @@ des.$(OBJEXT): des.c des.h $(des_headers)
 #	k =  7, c = 6, 320 entries, ~15 KB
 #	k =  9, c = 7, 512 entries, ~24 KB
 ecc-192.h: eccdata.stamp
-	./eccdata$(EXEEXT_FOR_BUILD) 192 7 6 $(GMP_NUMB_BITS) > $@T && mv $@T $@
+	./eccdata$(EXEEXT_FOR_BUILD) 192 7 6 $(NUMB_BITS) > $@T && mv $@T $@
 # Some possible choices for 224:
 #	k = 18, c = 4,  64 entries,  ~4 KB
 #	k = 24, c = 6, 128 entries,  ~8 KB
@@ -332,7 +335,7 @@ ecc-192.h: eccdata.stamp
 #	k =  8, c = 6, 320 entries, ~20 KB
 #	k = 10, c = 7, 512 entries, ~32 KB
 ecc-224.h: eccdata.stamp
-	./eccdata$(EXEEXT_FOR_BUILD) 224 12 6 $(GMP_NUMB_BITS) > $@T && mv $@T $@
+	./eccdata$(EXEEXT_FOR_BUILD) 224 12 6 $(NUMB_BITS) > $@T && mv $@T $@
 # Some possible choices for 256:
 #	k = 20, c = 4,  64 entries,  ~4 KB
 #	k = 27, c = 6, 128 entries,  ~8 KB
@@ -340,7 +343,7 @@ ecc-224.h: eccdata.stamp
 #	k =  9, c = 6, 320 entries, ~20 KB
 #	k = 12, c = 7, 512 entries, ~32 KB
 ecc-256.h: eccdata.stamp
-	./eccdata$(EXEEXT_FOR_BUILD) 256 14 6 $(GMP_NUMB_BITS) > $@T && mv $@T $@
+	./eccdata$(EXEEXT_FOR_BUILD) 256 14 6 $(NUMB_BITS) > $@T && mv $@T $@
 # Some possible choices for 384:
 #	k = 31, c = 4,  64 entries,  ~6 KB
 #	k = 41, c = 6, 128 entries, ~12 KB
@@ -348,7 +351,7 @@ ecc-256.h: eccdata.stamp
 #	k = 14, c = 6, 320 entries, ~30 KB
 #	k = 18, c = 7, 512 entries, ~48 KB
 ecc-384.h: eccdata.stamp
-	./eccdata$(EXEEXT_FOR_BUILD) 384 41 6 $(GMP_NUMB_BITS) > $@T && mv $@T $@
+	./eccdata$(EXEEXT_FOR_BUILD) 384 41 6 $(NUMB_BITS) > $@T && mv $@T $@
 # Some possible choices for 521:
 #	k = 42, c = 4,  64 entries,  ~9 KB
 #	k = 56, c = 6, 128 entries, ~18 KB
@@ -356,10 +359,10 @@ ecc-384.h: eccdata.stamp
 #	k = 19, c = 6, 320 entries, ~44 KB
 #	k = 24, c = 7, 512 entries, ~70 KB
 ecc-521.h: eccdata.stamp
-	./eccdata$(EXEEXT_FOR_BUILD) 521 56 6 $(GMP_NUMB_BITS) > $@T && mv $@T $@
+	./eccdata$(EXEEXT_FOR_BUILD) 521 56 6 $(NUMB_BITS) > $@T && mv $@T $@
 
 ecc-25519.h: eccdata.stamp
-	./eccdata$(EXEEXT_FOR_BUILD) 255 14 6 $(GMP_NUMB_BITS) > $@T && mv $@T $@
+	./eccdata$(EXEEXT_FOR_BUILD) 255 14 6 $(NUMB_BITS) > $@T && mv $@T $@
 
 eccdata.stamp: eccdata.c
 	$(MAKE) eccdata$(EXEEXT_FOR_BUILD)
diff --git a/README b/README
index ca873a3ff0eec64abc963d5509341c26f703e5b2..8355739b4faf1b50a080081fe602200bb63a67be 100644
--- a/README
+++ b/README
@@ -42,6 +42,8 @@ Read the manual. Mail me if you have any questions or suggestions.
 You may want to subscribe to the nettle-bugs mailing list. See
 <URL: http://lists.lysator.liu.se/mailman/listinfo/nettle-bugs>.
 
+See CONTRIBUTING.md for information on contibuting patches.
+
 
 Happy hacking,
 /Niels Möller <nisse@lysator.liu.se>
diff --git a/aclocal.m4 b/aclocal.m4
index debcf9c7dacbc5a680db69a8583b1890af4a342c..783dbc492b5c9dce437d4ac0aa431e7120ed2318 100644
--- a/aclocal.m4
+++ b/aclocal.m4
@@ -526,7 +526,7 @@ else
     fi
   fi
   if test "$CC_FOR_BUILD" = gcc ; then
-    CC_FOR_BUILD="$CC_FOR_BUILD -O"
+    CC_FOR_BUILD="$CC_FOR_BUILD -O -g"
   fi
 fi
 
diff --git a/aes-set-key-internal.c b/aes-set-key-internal.c
index 9b515bfd4346797b618accee2266bb24faabf596..88728d85499d0a60a648eac4065a90d05c48a117 100644
--- a/aes-set-key-internal.c
+++ b/aes-set-key-internal.c
@@ -39,6 +39,7 @@
 #endif
 
 #include "aes-internal.h"
+#include <assert.h>
 #include "macros.h"
 
 void
@@ -52,6 +53,7 @@ _aes_set_key(unsigned nr, unsigned nk,
   unsigned lastkey, i;
   uint32_t t;
 
+  assert(nk != 0);
   lastkey = (AES_BLOCK_SIZE/4) * (nr + 1);
   
   for (i=0, rp = rcon; i<nk; i++)
diff --git a/arm/ecc-521-modp.asm b/arm/ecc-521-modp.asm
index c311a891f967f39db1cd96216651caed12e43eb8..3fba23963d2c715583bfbabf185219df342239e1 100644
--- a/arm/ecc-521-modp.asm
+++ b/arm/ecc-521-modp.asm
@@ -91,7 +91,7 @@ PROLOGUE(nettle_ecc_521_modp)
 	adcs	F0, F0, F3, lsr #9
 	C Copy low 9 bits to H, then shift right including carry
 	and	H, F0, T0
-	rrx	F0, F0
+	mov	F0, F0, rrx
 	lsr	F0, F0, #8
 	C Add in F1 = rp[33], with weight 2^1056 = 2^14
 	adds	F0, F0, F1, lsl #14
diff --git a/base16-decode.c b/base16-decode.c
index 28acc40480f17b79242cadad379d653efb2d50c0..fc33123677bed32d9f80f16e5ae0ee35a64fe2b2 100644
--- a/base16-decode.c
+++ b/base16-decode.c
@@ -66,14 +66,16 @@ hex_decode_table[0x80] =
 int
 base16_decode_single(struct base16_decode_ctx *ctx,
 		     uint8_t *dst,
-		     uint8_t src)
+		     char src)
 {
+  /* Avoid signed char for indexing. */
+  unsigned char usrc = src;
   int digit;
 
-  if (src >= 0x80)
+  if (usrc >= 0x80)
     return -1;
 
-  digit = hex_decode_table[src];
+  digit = hex_decode_table[usrc];
   switch (digit)
     {
     case -1:
@@ -104,7 +106,7 @@ base16_decode_update(struct base16_decode_ctx *ctx,
 		     size_t *dst_length,
 		     uint8_t *dst,
 		     size_t src_length,
-		     const uint8_t *src)
+		     const char *src)
 {
   size_t done;
   size_t i;
diff --git a/base16-encode.c b/base16-encode.c
index 297491ad4f0ee6d955dc210bba36652975c7bd06..9c7f0b1ed017c54678257c50d9f574825bc506b8 100644
--- a/base16-encode.c
+++ b/base16-encode.c
@@ -45,7 +45,7 @@ hex_digits[16] = "0123456789abcdef";
 
 /* Encodes a single byte. Always stores two digits in dst[0] and dst[1]. */
 void
-base16_encode_single(uint8_t *dst,
+base16_encode_single(char *dst,
 		     uint8_t src)
 {
   dst[0] = DIGIT(src/0x10);
@@ -54,7 +54,7 @@ base16_encode_single(uint8_t *dst,
 
 /* Always stores BASE16_ENCODE_LENGTH(length) digits in dst. */
 void
-base16_encode_update(uint8_t *dst,
+base16_encode_update(char *dst,
 		     size_t length,
 		     const uint8_t *src)
 {
diff --git a/base16-meta.c b/base16-meta.c
index a2a109068bc3d8fd3a19494909ef04c1a14ddb1e..a7789c50afa3290fa302d0392f569ddc112683ed 100644
--- a/base16-meta.c
+++ b/base16-meta.c
@@ -59,7 +59,7 @@ base16_encode_init(void *ctx UNUSED)
 
 static nettle_armor_encode_update_func base16_encode_update_wrapper;
 static size_t
-base16_encode_update_wrapper(void *ctx UNUSED, uint8_t *dst,
+base16_encode_update_wrapper(void *ctx UNUSED, char *dst,
 			     size_t length, const uint8_t *src)
 {
   base16_encode_update(dst, length, src);
@@ -71,7 +71,7 @@ base16_encode_update_wrapper(void *ctx UNUSED, uint8_t *dst,
 
 static nettle_armor_encode_final_func base16_encode_final;
 static size_t
-base16_encode_final(void *ctx UNUSED, uint8_t *dst UNUSED)
+base16_encode_final(void *ctx UNUSED, char *dst UNUSED)
 {
   return 0;
 }
diff --git a/base16.h b/base16.h
index 2579c0efa661a24d758559a6bd0601cbda660948..755e6ed321eb87b6b90cbd9843c4fc7dddb214c6 100644
--- a/base16.h
+++ b/base16.h
@@ -56,12 +56,12 @@ extern "C" {
 
 /* Encodes a single byte. Always stores two digits in dst[0] and dst[1]. */
 void
-base16_encode_single(uint8_t *dst,
+base16_encode_single(char *dst,
 		     uint8_t src);
 
 /* Always stores BASE16_ENCODE_LENGTH(length) digits in dst. */
 void
-base16_encode_update(uint8_t *dst,
+base16_encode_update(char *dst,
 		     size_t length,
 		     const uint8_t *src);
 
@@ -86,7 +86,7 @@ base16_decode_init(struct base16_decode_ctx *ctx);
 int
 base16_decode_single(struct base16_decode_ctx *ctx,
 		     uint8_t *dst,
-		     uint8_t src);
+		     char src);
 
 /* Returns 1 on success, 0 on error. DST should point to an area of
  * size at least BASE16_DECODE_LENGTH(length). The amount of data
@@ -97,7 +97,7 @@ base16_decode_update(struct base16_decode_ctx *ctx,
 		     size_t *dst_length,
 		     uint8_t *dst,
 		     size_t src_length,
-		     const uint8_t *src);
+		     const char *src);
 
 /* Returns 1 on success. */
 int
diff --git a/base64-decode.c b/base64-decode.c
index 337ea3953d6ab6d2f0f1c30f635f5609d90e63c1..b993117ad8eb111ec2000d3102ff08c115e32ab7 100644
--- a/base64-decode.c
+++ b/base64-decode.c
@@ -73,9 +73,9 @@ base64_decode_init(struct base64_decode_ctx *ctx)
 int
 base64_decode_single(struct base64_decode_ctx *ctx,
 		     uint8_t *dst,
-		     uint8_t src)
+		     char src)
 {
-  int data = ctx->table[src];
+  int data = ctx->table[(uint8_t) src];
 
   switch(data)
     {
@@ -122,7 +122,7 @@ base64_decode_update(struct base64_decode_ctx *ctx,
 		     size_t *dst_length,
 		     uint8_t *dst,
 		     size_t src_length,
-		     const uint8_t *src)
+		     const char *src)
 {
   size_t done;
   size_t i;
diff --git a/base64-encode.c b/base64-encode.c
index f23115a9ff9bb8655ec2bef77232af847ced723c..42fa016d7191fa3ecdd7d47c00ee0a39c9ffc010 100644
--- a/base64-encode.c
+++ b/base64-encode.c
@@ -41,11 +41,11 @@
 #define ENCODE(alphabet,x) ((alphabet)[0x3F & (x)])
 
 static void
-encode_raw(const uint8_t *alphabet,
-	   uint8_t *dst, size_t length, const uint8_t *src)
+encode_raw(const char *alphabet,
+	   char *dst, size_t length, const uint8_t *src)
 {
   const uint8_t *in = src + length;
-  uint8_t *out = dst + BASE64_ENCODE_RAW_LENGTH(length);
+  char *out = dst + BASE64_ENCODE_RAW_LENGTH(length);
 
   unsigned left_over = length % 3;
 
@@ -83,19 +83,19 @@ encode_raw(const uint8_t *alphabet,
   assert(out == dst);
 }
 
-static const uint8_t base64_encode_table[64] =
+static const char base64_encode_table[64] =
   "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
   "abcdefghijklmnopqrstuvwxyz"
   "0123456789+/";
 
 void
-base64_encode_raw(uint8_t *dst, size_t length, const uint8_t *src)
+base64_encode_raw(char *dst, size_t length, const uint8_t *src)
 {
   encode_raw(base64_encode_table, dst, length, src);
 }
 
 void
-base64_encode_group(uint8_t *dst, uint32_t group)
+base64_encode_group(char *dst, uint32_t group)
 {
   *dst++ = ENCODE(base64_encode_table, (group >> 18));
   *dst++ = ENCODE(base64_encode_table, (group >> 12));
@@ -113,7 +113,7 @@ base64_encode_init(struct base64_encode_ctx *ctx)
 /* Encodes a single byte. */
 size_t
 base64_encode_single(struct base64_encode_ctx *ctx,
-		     uint8_t *dst,
+		     char *dst,
 		     uint8_t src)
 {
   unsigned done = 0;
@@ -138,7 +138,7 @@ base64_encode_single(struct base64_encode_ctx *ctx,
  * area of size at least BASE64_ENCODE_LENGTH(length). */
 size_t
 base64_encode_update(struct base64_encode_ctx *ctx,
-		     uint8_t *dst,
+		     char *dst,
 		     size_t length,
 		     const uint8_t *src)
 {
@@ -181,7 +181,7 @@ base64_encode_update(struct base64_encode_ctx *ctx,
  * BASE64_ENCODE_FINAL_SIZE */
 size_t
 base64_encode_final(struct base64_encode_ctx *ctx,
-		    uint8_t *dst)
+		    char *dst)
 {
   unsigned done = 0;
   unsigned bits = ctx->bits;
diff --git a/base64.h b/base64.h
index 79194bd4f6ed5b818984f50a29e24342d6191b6f..8e69adb1dbe916488d04054231ccc7ae0e7f0839 100644
--- a/base64.h
+++ b/base64.h
@@ -73,7 +73,7 @@ extern "C" {
 
 struct base64_encode_ctx
 {
-  const uint8_t *alphabet; /* Alphabet to use for encoding */
+  const char *alphabet;    /* Alphabet to use for encoding */
   unsigned short word;     /* Leftover bits */
   unsigned char bits;      /* Number of bits, always 0, 2, or 4. */
 };
@@ -89,14 +89,14 @@ base64url_encode_init(struct base64_encode_ctx *ctx);
 /* Encodes a single byte. Returns amount of output (always 1 or 2). */
 size_t
 base64_encode_single(struct base64_encode_ctx *ctx,
-		     uint8_t *dst,
+		     char *dst,
 		     uint8_t src);
 
 /* Returns the number of output characters. DST should point to an
  * area of size at least BASE64_ENCODE_LENGTH(length). */
 size_t
 base64_encode_update(struct base64_encode_ctx *ctx,
-		     uint8_t *dst,
+		     char *dst,
 		     size_t length,
 		     const uint8_t *src);
 
@@ -104,18 +104,20 @@ base64_encode_update(struct base64_encode_ctx *ctx,
  * BASE64_ENCODE_FINAL_LENGTH */
 size_t
 base64_encode_final(struct base64_encode_ctx *ctx,
-		    uint8_t *dst);
+		    char *dst);
 
 /* Lower level functions */
 
 /* Encodes a string in one go, including any padding at the end.
  * Generates exactly BASE64_ENCODE_RAW_LENGTH(length) bytes of output.
- * Supports overlapped operation, if src <= dst. */
+ * Supports overlapped operation, if src <= dst. FIXME: Use of overlap
+ * is deprecated, if needed there should be a separate public fucntion
+ * to do that.*/
 void
-base64_encode_raw(uint8_t *dst, size_t length, const uint8_t *src);
+base64_encode_raw(char *dst, size_t length, const uint8_t *src);
 
 void
-base64_encode_group(uint8_t *dst, uint32_t group);
+base64_encode_group(char *dst, uint32_t group);
 
 
 /* Base64 decoding */
@@ -147,7 +149,7 @@ base64url_decode_init(struct base64_decode_ctx *ctx);
 int
 base64_decode_single(struct base64_decode_ctx *ctx,
 		     uint8_t *dst,
-		     uint8_t src);
+		     char src);
 
 /* Returns 1 on success, 0 on error. DST should point to an area of
  * size at least BASE64_DECODE_LENGTH(length). The amount of data
@@ -157,7 +159,7 @@ base64_decode_update(struct base64_decode_ctx *ctx,
 		     size_t *dst_length,
 		     uint8_t *dst,
 		     size_t src_length,
-		     const uint8_t *src);
+		     const char *src);
 
 /* Returns 1 on success. */
 int
diff --git a/base64url-encode.c b/base64url-encode.c
index 6af33fb893d66e42df69d245362ae9337e60a552..d30044ea8686626d83b972ce666c1ffe7fb278f3 100644
--- a/base64url-encode.c
+++ b/base64url-encode.c
@@ -38,7 +38,7 @@
 void
 base64url_encode_init(struct base64_encode_ctx *ctx)
 {
-  static const uint8_t base64url_encode_table[64] =
+  static const char base64url_encode_table[64] =
     "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
     "abcdefghijklmnopqrstuvwxyz"
     "0123456789-_";
diff --git a/cfb.c b/cfb.c
new file mode 100644
index 0000000000000000000000000000000000000000..82cf18f4d9c6e25c60ccb2e75158f4ad1fc13eef
--- /dev/null
+++ b/cfb.c
@@ -0,0 +1,165 @@
+/* cfb.c
+
+   Cipher feedback mode.
+
+   Copyright (C) 2015, 2017 Dmitry Eremin-Solenikov
+   Copyright (C) 2001, 2011 Niels Möller
+
+   This file is part of GNU Nettle.
+
+   GNU Nettle is free software: you can redistribute it and/or
+   modify it under the terms of either:
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at your
+       option) any later version.
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at your
+       option) any later version.
+
+   or both in parallel, as here.
+
+   GNU Nettle is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see http://www.gnu.org/licenses/.
+*/
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "cfb.h"
+
+#include "memxor.h"
+#include "nettle-internal.h"
+
+void
+cfb_encrypt(const void *ctx, nettle_cipher_func *f,
+	    size_t block_size, uint8_t *iv,
+	    size_t length, uint8_t *dst,
+	    const uint8_t *src)
+{
+  uint8_t *p;
+  TMP_DECL(buffer, uint8_t, NETTLE_MAX_CIPHER_BLOCK_SIZE);
+
+  TMP_ALLOC(buffer, block_size);
+
+  if (src != dst)
+    {
+      for (p = iv; length >= block_size; p = dst, dst += block_size, src += block_size, length -= block_size)
+	{
+	  f(ctx, block_size, dst, p);
+	  memxor(dst, src, block_size);
+	}
+    }
+  else
+    {
+      for (p = iv; length >= block_size; p = dst, dst += block_size, src += block_size, length -= block_size)
+	{
+	  f(ctx, block_size, buffer, p);
+	  memxor(dst, buffer, block_size);
+	}
+    }
+
+  if (p != iv)
+    memcpy(iv, p, block_size);
+
+  if (length)
+    {
+      f(ctx, block_size, buffer, iv);
+      memxor3(dst, buffer, src, length);
+      /* We do not care about updating IV here. This is the last call in
+       * message sequence and one has to set IV afterwards anyway */
+    }
+}
+
+/* Don't allocate any more space than this on the stack */
+#define CFB_BUFFER_LIMIT 512
+
+void
+cfb_decrypt(const void *ctx, nettle_cipher_func *f,
+	    size_t block_size, uint8_t *iv,
+	    size_t length, uint8_t *dst,
+	    const uint8_t *src)
+{
+  if (src != dst)
+    {
+      size_t left = length % block_size;
+
+      length -= left;
+      if (length > 0)
+	{
+	  /* Decrypt in ECB mode */
+	  f(ctx, block_size, dst, iv);
+	  f(ctx, length - block_size, dst + block_size, src);
+	  memcpy(iv, src + length - block_size, block_size);
+	  memxor(dst, src, length);
+	}
+
+      if (left > 0)
+	{
+	  TMP_DECL(buffer, uint8_t, NETTLE_MAX_CIPHER_BLOCK_SIZE);
+	  TMP_ALLOC(buffer, block_size);
+
+	  f(ctx, block_size, buffer, iv);
+	  memxor3(dst + length, src + length, buffer, left);
+	}
+    }
+  else
+    {
+      /* For in-place CFB, we decrypt into a temporary buffer of size
+       * at most CFB_BUFFER_LIMIT, and process that amount of data at
+       * a time. */
+
+      /* NOTE: We assume that block_size <= CFB_BUFFER_LIMIT */
+
+      TMP_DECL(buffer, uint8_t, CFB_BUFFER_LIMIT);
+      TMP_DECL(initial_iv, uint8_t, NETTLE_MAX_CIPHER_BLOCK_SIZE);
+
+      size_t buffer_size;
+      size_t left;
+
+      buffer_size = CFB_BUFFER_LIMIT - (CFB_BUFFER_LIMIT % block_size);
+
+      TMP_ALLOC(buffer, buffer_size);
+      TMP_ALLOC(initial_iv, block_size);
+
+      left = length % block_size;
+      length -= left;
+
+      while (length > 0)
+	{
+	  size_t part = length > buffer_size ? buffer_size : length;
+
+	  /* length is greater that zero and is divided by block_size, so it is
+	   * not less than block_size. So does part */
+
+	  f(ctx, block_size, buffer, iv);
+	  f(ctx, part - block_size, buffer + block_size, src);
+	  memcpy(iv, src + part - block_size, block_size);
+	  memxor(dst, buffer, part);
+
+	  length -= part;
+	  src += part;
+	  dst += part;
+	}
+
+      if (left > 0)
+	{
+	  f(ctx, block_size, buffer, iv);
+	  memxor(dst, buffer, left);
+	}
+    }
+}
diff --git a/cfb.h b/cfb.h
new file mode 100644
index 0000000000000000000000000000000000000000..16660df9b8ab8077b94052cd34e26a8b8296f3ac
--- /dev/null
+++ b/cfb.h
@@ -0,0 +1,87 @@
+/* cfb.h
+
+   Cipher feedback mode.
+
+   Copyright (C) 2015, 2017 Dmitry Eremin-Solenikov
+   Copyright (C) 2001 Niels Möller
+
+   This file is part of GNU Nettle.
+
+   GNU Nettle is free software: you can redistribute it and/or
+   modify it under the terms of either:
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at your
+       option) any later version.
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at your
+       option) any later version.
+
+   or both in parallel, as here.
+
+   GNU Nettle is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see http://www.gnu.org/licenses/.
+*/
+
+#ifndef NETTLE_CFB_H_INCLUDED
+#define NETTLE_CFB_H_INCLUDED
+
+#include "nettle-types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Name mangling */
+#define cfb_encrypt nettle_cfb_encrypt
+#define cfb_decrypt nettle_cfb_decrypt
+
+void
+cfb_encrypt(const void *ctx, nettle_cipher_func *f,
+	    size_t block_size, uint8_t *iv,
+	    size_t length, uint8_t *dst,
+	    const uint8_t *src);
+
+void
+cfb_decrypt(const void *ctx, nettle_cipher_func *f,
+	    size_t block_size, uint8_t *iv,
+	    size_t length, uint8_t *dst,
+	    const uint8_t *src);
+
+#define CFB_CTX(type, size) \
+{ type ctx; uint8_t iv[size]; }
+
+#define CFB_SET_IV(ctx, data) \
+memcpy((ctx)->iv, (data), sizeof((ctx)->iv))
+
+/* NOTE: Avoid using NULL, as we don't include anything defining it. */
+#define CFB_ENCRYPT(self, f, length, dst, src)		\
+  (0 ? ((f)(&(self)->ctx, ~(size_t) 0,			\
+	    (uint8_t *) 0, (const uint8_t *) 0))	\
+   : cfb_encrypt((void *) &(self)->ctx,			\
+		 (nettle_cipher_func *) (f),		\
+		 sizeof((self)->iv), (self)->iv,	\
+		 (length), (dst), (src)))
+
+#define CFB_DECRYPT(self, f, length, dst, src)		\
+  (0 ? ((f)(&(self)->ctx, ~(size_t) 0,			\
+	    (uint8_t *) 0, (const uint8_t *) 0))	\
+   : cfb_decrypt((void *) &(self)->ctx,			\
+		 (nettle_cipher_func *) (f),		\
+		 sizeof((self)->iv), (self)->iv,	\
+		 (length), (dst), (src)))
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* NETTLE_CFB_H_INCLUDED */
diff --git a/config.make.in b/config.make.in
index 2981379a143899a4998e8c0e95ada041e4c54913..af2068ce34254bfb912039c387a18d091ede12a3 100644
--- a/config.make.in
+++ b/config.make.in
@@ -46,7 +46,7 @@ LIBHOGWEED_FORLINK = @LIBHOGWEED_FORLINK@
 LIBHOGWEED_LIBS = @LIBHOGWEED_LIBS@
 LIBHOGWEED_LINK = @LIBHOGWEED_LINK@
 
-GMP_NUMB_BITS = @GMP_NUMB_BITS@
+NUMB_BITS = @NUMB_BITS@
 
 AR = @AR@
 ARFLAGS = cru
diff --git a/configure.ac b/configure.ac
index 1d1951b5cf35d19bdad0eb39fe65ad56e3e47a99..45ef50e127ab49b186b25545392f0615174ffe37 100644
--- a/configure.ac
+++ b/configure.ac
@@ -185,7 +185,7 @@ AC_HEADER_TIME
 AC_CHECK_SIZEOF(long)
 AC_CHECK_SIZEOF(size_t)
 
-AC_CHECK_HEADERS([openssl/blowfish.h openssl/des.h openssl/cast.h openssl/aes.h openssl/ecdsa.h],,
+AC_CHECK_HEADERS([openssl/evp.h openssl/ecdsa.h],,
 [enable_openssl=no
  break])
 
@@ -268,7 +268,16 @@ if test "x$enable_public_key" = "xyes" ; then
   fi
 fi
 
-GMP_NUMB_BITS="$nettle_cv_gmp_numb_bits"
+# Substituted in Makefile, passed on to the eccdata command.
+NUMB_BITS="$nettle_cv_gmp_numb_bits"
+AC_SUBST([NUMB_BITS])
+
+# Substituted in version.h, used only with mini-gmp.
+if test "x$enable_mini_gmp" = "xyes" ; then
+  GMP_NUMB_BITS="$NUMB_BITS"
+else
+  GMP_NUMB_BITS="n/a"
+fi
 AC_SUBST([GMP_NUMB_BITS])
 
 # Figure out ABI. Currently, configurable only by setting CFLAGS.
@@ -876,7 +885,7 @@ OPENSSL_LIBFLAGS=''
 
 # Check for openssl's libcrypto (used only for benchmarking)
 if test x$enable_openssl = xyes ; then
-  AC_CHECK_LIB(crypto, BF_ecb_encrypt,
+  AC_CHECK_LIB(crypto, EVP_CIPHER_CTX_new,
     [OPENSSL_LIBFLAGS='-lcrypto'],
     [enable_openssl=no])
 fi
diff --git a/ecc-add-eh.c b/ecc-add-eh.c
index a16be4cb849973a3a50ddd39012647011b569ae6..c07ff49a8c2969e48acab70753c11235fd3233ca 100644
--- a/ecc-add-eh.c
+++ b/ecc-add-eh.c
@@ -98,8 +98,8 @@ ecc_add_eh (const struct ecc_curve *ecc,
   ecc_modp_mul (ecc, x3, B, z1);
 
   /* y3 */
-  ecc_modp_mul (ecc, B, F, C); /* ! */
-  ecc_modp_mul (ecc, y3, B, z1);
+  ecc_modp_mul (ecc, B, F, z1); /* ! */
+  ecc_modp_mul (ecc, y3, B, C); /* Clobbers z1 in case r == p. */
 
   /* z3 */
   ecc_modp_mul (ecc, B, F, G);
diff --git a/ecc-mod-inv.c b/ecc-mod-inv.c
index f65c9da42d9982c811d514a02cab3ad2a2ab9f1d..8cfd2e3b8c1f696178f48a927854d2f91517474f 100644
--- a/ecc-mod-inv.c
+++ b/ecc-mod-inv.c
@@ -145,6 +145,7 @@ ecc_mod_inv (const struct ecc_modulo *m,
       cnd_swap (swap, up, vp, n);
       cy = cnd_sub_n (odd, up, vp, n);
       cy -= cnd_add_n (cy, up, m->m, n);
+      assert (cy == 0);
 
       cy = mpn_rshift (ap, ap, n, 1);
       assert (cy == 0);
diff --git a/ecc-mod.c b/ecc-mod.c
index 5fee4c68c46c7365ba2b4fd7c4bcbb86443a241e..4e77f0c0e8a88244419704143c73ae2d9148e759 100644
--- a/ecc-mod.c
+++ b/ecc-mod.c
@@ -51,7 +51,7 @@ ecc_mod (const struct ecc_modulo *m, mp_limb_t *rp)
   mp_size_t i;
   unsigned shift;
 
-  assert (sn > 0);
+  assert (bn < mn);
 
   /* FIXME: Could use mpn_addmul_2. */
   /* Eliminate sn limbs at a time */
@@ -72,6 +72,12 @@ ecc_mod (const struct ecc_modulo *m, mp_limb_t *rp)
     }
   else
     {
+      /* The loop below always runs at least once. But the analyzer
+	 doesn't realize that, and complains about hi being used later
+	 on without a well defined value. */
+#ifdef __clang_analyzer__
+      hi = 0;
+#endif
       while (rn >= 2 * mn - bn)
 	{
 	  rn -= sn;
diff --git a/ecc.h b/ecc.h
index c67ccdc34483c1a88498afdba504ba4e962aab8e..93fc9e8795a912f885ac78dc94fdbe5c4587cc93 100644
--- a/ecc.h
+++ b/ecc.h
@@ -121,8 +121,8 @@ ecc_point_mul_g (struct ecc_point *r, const struct ecc_scalar *n);
   
 /* Points on a curve are represented as arrays of mp_limb_t, with
    curve-specific representation. For the secp curves, we use Jacobian
-   coordinates (possibly in Montgomery for for mod multiplication).
-   For curve25519 we use homogeneous coordiantes on an equivalent
+   coordinates (possibly in Montgomery form for mod multiplication).
+   For curve25519 we use homogeneous coordinates on an equivalent
    Edwards curve. The suffix "_h" denotes this internal
    representation.
    
diff --git a/eccdata.c b/eccdata.c
index 9533d7835c08997d5b7e14a1117ef6cfbf76f087..97a6194116e6f99ccce27c8bda3280e889ffaaaf 100644
--- a/eccdata.c
+++ b/eccdata.c
@@ -694,11 +694,11 @@ ecc_point_out (FILE *f, const struct ecc_point *p)
     fprintf (f, "zero");
   else
     {
-	fprintf (stderr, "(");
-	mpz_out_str (stderr, 16, p->x);
-	fprintf (stderr, ",\n     ");
-	mpz_out_str (stderr, 16, (p)->y);
-	fprintf (stderr, ")");
+	fprintf (f, "(");
+	mpz_out_str (f, 16, p->x);
+	fprintf (f, ",\n     ");
+	mpz_out_str (f, 16, (p)->y);
+	fprintf (f, ")");
     }
 }
 #define ASSERT_EQUAL(p, q) do {						\
@@ -1014,16 +1014,19 @@ output_curve (const struct ecc_curve *ecc, unsigned bits_per_limb)
 	      exit (EXIT_FAILURE);
 	    }
 	}
+    }
+  else
+    printf ("#define ecc_Bmodp_shifted ecc_Bmodp\n");
+
+  if (bits < limb_size * bits_per_limb)
+    {
       mpz_set_ui (t, 0);
-      mpz_setbit (t, ecc->bit_size);
+      mpz_setbit (t, bits);
       mpz_sub (t, t, ecc->q);      
       output_bignum ("ecc_Bmodq_shifted", t, limb_size, bits_per_limb);      
     }
   else
-    {
-      printf ("#define ecc_Bmodp_shifted ecc_Bmodp\n");
-      printf ("#define ecc_Bmodq_shifted ecc_Bmodq\n");
-    }
+    printf ("#define ecc_Bmodq_shifted ecc_Bmodq\n");
 
   mpz_add_ui (t, ecc->p, 1);
   mpz_fdiv_q_2exp (t, t, 1);
diff --git a/ecdsa-verify.c b/ecdsa-verify.c
index 05c174ec573fd4db2cb41ed71768422cb6d0d6b8..ab8e19f33e23402cb9c6e127a7ab1579927755a7 100644
--- a/ecdsa-verify.c
+++ b/ecdsa-verify.c
@@ -52,7 +52,7 @@ ecdsa_verify (const struct ecc_point *pub,
   /* For ECC_MUL_A_WBITS == 0, at most 1512 bytes. With
      ECC_MUL_A_WBITS == 4, currently needs 67 * ecc->size, at most
      4824 bytes. Don't use stack allocation for this. */
-  mp_limb_t *scratch = gmp_alloc_limbs (itch);
+  mp_limb_t *scratch;
   int res;
 
 #define rp scratch
@@ -62,6 +62,8 @@ ecdsa_verify (const struct ecc_point *pub,
   if (mpz_sgn (signature->r) <= 0 || mpz_size (signature->r) > size
       || mpz_sgn (signature->s) <= 0 || mpz_size (signature->s) > size)
     return 0;
+
+  scratch = gmp_alloc_limbs (itch);
   
   mpz_limbs_copy (rp, signature->r, size);
   mpz_limbs_copy (sp, signature->s, size);
diff --git a/examples/base16dec.c b/examples/base16dec.c
index 7071456713ab368b0cc2596f0575cc2ee5cc4b14..1185b3e1bf8f5195b29dd5db6bdadab461f61319 100644
--- a/examples/base16dec.c
+++ b/examples/base16dec.c
@@ -58,7 +58,7 @@ int
 main(int argc UNUSED, char **argv UNUSED)
 {
   /* "buffer" will hold the bytes from disk: */
-  uint8_t * buffer = xalloc (CHUNK_SIZE);
+  char * buffer = xalloc (CHUNK_SIZE);
 
   /* "result" will hold bytes before output: */
   uint8_t * result = xalloc (DECODED_SIZE);
diff --git a/examples/base16enc.c b/examples/base16enc.c
index 02e4f2808fa82573be2f8a2c2140ec6cd085f995..6ac08e1dd0ceea548db1d4cf2205a3272105e2e5 100644
--- a/examples/base16enc.c
+++ b/examples/base16enc.c
@@ -70,7 +70,7 @@ main(int argc UNUSED, char **argv UNUSED)
       /* "buffer" will hold the bytes from disk: */
       uint8_t buffer[CHUNK_SIZE];
       /* "result" will hold bytes before output: */
-      uint8_t result[ENCODED_SIZE + 1];
+      char result[ENCODED_SIZE + 1];
       unsigned nbytes; /* Number of bytes read from stdin */
       int encoded_bytes; /* Total number of bytes encoded per iteration */
       
diff --git a/examples/base64dec.c b/examples/base64dec.c
index 624de628f89b78a7146727f20ab764efc6367561..d05d924a5f9a508e26dac6fce5d2e50682bf6a23 100644
--- a/examples/base64dec.c
+++ b/examples/base64dec.c
@@ -58,7 +58,7 @@ int
 main(int argc UNUSED, char **argv UNUSED)
 {
   /* "buffer" will hold the bytes from disk: */
-  uint8_t * buffer = xalloc (CHUNK_SIZE);
+  char * buffer = xalloc (CHUNK_SIZE);
 
   /* "result" will hold bytes before output: */
   uint8_t * result = xalloc (DECODED_SIZE);
diff --git a/examples/base64enc.c b/examples/base64enc.c
index f8ba829bb772f2c38b1d33224aced8ea7b01a3a1..cc6010cc15acb4a0c4727f6cbb5acdd910f3b66e 100644
--- a/examples/base64enc.c
+++ b/examples/base64enc.c
@@ -72,7 +72,7 @@ main(int argc UNUSED, char **argv UNUSED)
       /* "buffer" will hold the bytes from disk: */
       uint8_t buffer[CHUNK_SIZE];
       /* "result" is the result vector: */
-      uint8_t result[ENCODED_SIZE + BASE64_ENCODE_FINAL_LENGTH + 1];
+      char result[ENCODED_SIZE + BASE64_ENCODE_FINAL_LENGTH + 1];
       unsigned nbytes; /* Number of bytes read from stdin */
       int encoded_bytes; /* total number of bytes encoded per iteration */
       nbytes = fread(buffer,1,CHUNK_SIZE,stdin);
diff --git a/examples/hogweed-benchmark.c b/examples/hogweed-benchmark.c
index 3fabe20719a3ac52958695febfddf0f757f6eed7..ebce9034125bbcb9f8d872900c90deae7c6846a6 100644
--- a/examples/hogweed-benchmark.c
+++ b/examples/hogweed-benchmark.c
@@ -612,7 +612,10 @@ bench_openssl_ecdsa_init (unsigned size)
 
   /* This curve isn't supported in this build of openssl */
   if (ctx->key == NULL)
-    return NULL;
+    {
+      free(ctx);
+      return NULL;
+    }
 
   if (!EC_KEY_generate_key( ctx->key))
     die ("Openssl EC_KEY_generate_key failed.\n");
diff --git a/examples/nettle-benchmark.c b/examples/nettle-benchmark.c
index c00486cc232281784eda0031ec7c9a367233023f..11f6270919349cc8ab8717fd579a08b24e9727c3 100644
--- a/examples/nettle-benchmark.c
+++ b/examples/nettle-benchmark.c
@@ -723,6 +723,10 @@ main(int argc, char **argv)
   int c;
   const char *alg;
 
+#if WITH_OPENSSL
+  nettle_openssl_init();
+#endif
+
   const struct nettle_hash *hashes[] =
     {
       &nettle_md2, &nettle_md4, &nettle_md5,
diff --git a/examples/nettle-openssl.c b/examples/nettle-openssl.c
index 86c5321c6dbb37db3d4df158b5f9361d92948c7d..b549ba54939baf783b9ad346564c61247d02744e 100644
--- a/examples/nettle-openssl.c
+++ b/examples/nettle-openssl.c
@@ -2,7 +2,8 @@
 
    Glue that's used only by the benchmark, and subject to change.
 
-   Copyright (C) 2002 Niels Möller
+   Copyright (C) 2002, 2017 Niels Möller
+   Copyright (C) 2017 Red Hat, Inc.
 
    This file is part of GNU Nettle.
 
@@ -45,17 +46,69 @@
 
 #include <assert.h>
 
-#include <openssl/aes.h>
-#include <openssl/blowfish.h>
-#include <openssl/des.h>
-#include <openssl/cast.h>
-#include <openssl/rc4.h>
+#include <openssl/conf.h>
+#include <openssl/evp.h>
+#include <openssl/err.h>
 
 #include <openssl/md5.h>
 #include <openssl/sha.h>
 
 #include "nettle-internal.h"
 
+/* We use Openssl's EVP api for all openssl ciphers. This API selects
+   platform-specific implementations if appropriate, e.g., using x86
+   AES-NI instructions. */
+struct openssl_cipher_ctx {
+  EVP_CIPHER_CTX *evp;
+};
+
+void
+nettle_openssl_init(void)
+{
+  ERR_load_crypto_strings();
+  OpenSSL_add_all_algorithms();
+#if OPENSSL_VERSION_NUMBER >= 0x1010000
+  CONF_modules_load_file(NULL, NULL, 0);
+#else
+  OPENSSL_config(NULL);
+#endif
+}
+
+static void
+openssl_evp_set_encrypt_key(void *p, const uint8_t *key,
+			    const EVP_CIPHER *cipher)
+{
+  struct openssl_cipher_ctx *ctx = p;
+  ctx->evp = EVP_CIPHER_CTX_new();
+  assert(EVP_EncryptInit_ex(ctx->evp, cipher, NULL, key, NULL) == 1);
+  EVP_CIPHER_CTX_set_padding(ctx->evp, 0);
+}
+static void
+openssl_evp_set_decrypt_key(void *p, const uint8_t *key,
+			    const EVP_CIPHER *cipher)
+{
+  struct openssl_cipher_ctx *ctx = p;
+  ctx->evp = EVP_CIPHER_CTX_new();
+  assert(EVP_DecryptInit_ex(ctx->evp, cipher, NULL, key, NULL) == 1);
+  EVP_CIPHER_CTX_set_padding(ctx->evp, 0);
+}
+
+static void
+openssl_evp_encrypt(const void *p, size_t length,
+		    uint8_t *dst, const uint8_t *src)
+{
+  const struct openssl_cipher_ctx *ctx = p;
+  int len;
+  assert(EVP_EncryptUpdate(ctx->evp, dst, &len, src, length) == 1);
+}
+static void
+openssl_evp_decrypt(const void *p, size_t length,
+		    uint8_t *dst, const uint8_t *src)
+{
+  const struct openssl_cipher_ctx *ctx = p;
+  int len;
+  assert(EVP_DecryptUpdate(ctx->evp, dst, &len, src, length) == 1);
+}
 
 /* AES */
 static nettle_set_key_func openssl_aes128_set_encrypt_key;
@@ -64,273 +117,152 @@ static nettle_set_key_func openssl_aes192_set_encrypt_key;
 static nettle_set_key_func openssl_aes192_set_decrypt_key;
 static nettle_set_key_func openssl_aes256_set_encrypt_key;
 static nettle_set_key_func openssl_aes256_set_decrypt_key;
+
 static void
 openssl_aes128_set_encrypt_key(void *ctx, const uint8_t *key)
 {
-  AES_set_encrypt_key(key, 128, ctx);
+  openssl_evp_set_encrypt_key(ctx, key, EVP_aes_128_ecb());
 }
 static void
 openssl_aes128_set_decrypt_key(void *ctx, const uint8_t *key)
 {
-  AES_set_decrypt_key(key, 128, ctx);
+  openssl_evp_set_decrypt_key(ctx, key, EVP_aes_128_ecb());
 }
 
 static void
 openssl_aes192_set_encrypt_key(void *ctx, const uint8_t *key)
 {
-  AES_set_encrypt_key(key, 192, ctx);
+  openssl_evp_set_encrypt_key(ctx, key, EVP_aes_192_ecb());
 }
 static void
 openssl_aes192_set_decrypt_key(void *ctx, const uint8_t *key)
 {
-  AES_set_decrypt_key(key, 192, ctx);
+  openssl_evp_set_decrypt_key(ctx, key, EVP_aes_192_ecb());
 }
 
 static void
 openssl_aes256_set_encrypt_key(void *ctx, const uint8_t *key)
 {
-  AES_set_encrypt_key(key, 256, ctx);
+  openssl_evp_set_encrypt_key(ctx, key, EVP_aes_256_ecb());
 }
 static void
 openssl_aes256_set_decrypt_key(void *ctx, const uint8_t *key)
 {
-  AES_set_decrypt_key(key, 256, ctx);
-}
-
-static nettle_cipher_func openssl_aes_encrypt;
-static void
-openssl_aes_encrypt(const void *ctx, size_t length,
-		    uint8_t *dst, const uint8_t *src)
-{
-  assert (!(length % AES_BLOCK_SIZE));
-  while (length)
-    {
-      AES_ecb_encrypt(src, dst, ctx, AES_ENCRYPT);
-      length -= AES_BLOCK_SIZE;
-      dst += AES_BLOCK_SIZE;
-      src += AES_BLOCK_SIZE;
-    }
-}
-
-static nettle_cipher_func openssl_aes_decrypt;
-static void
-openssl_aes_decrypt(const void *ctx, size_t length,
-		    uint8_t *dst, const uint8_t *src)
-{
-  assert (!(length % AES_BLOCK_SIZE));
-  while (length)
-    {
-      AES_ecb_encrypt(src, dst, ctx, AES_DECRYPT);
-      length -= AES_BLOCK_SIZE;
-      dst += AES_BLOCK_SIZE;
-      src += AES_BLOCK_SIZE;
-    }
+  openssl_evp_set_decrypt_key(ctx, key, EVP_aes_256_ecb());
 }
 
 const struct nettle_cipher
 nettle_openssl_aes128 = {
-  "openssl aes128", sizeof(AES_KEY),
+  "openssl aes128", sizeof(struct openssl_cipher_ctx),
   16, 16,
   openssl_aes128_set_encrypt_key, openssl_aes128_set_decrypt_key,
-  openssl_aes_encrypt, openssl_aes_decrypt
+  openssl_evp_encrypt, openssl_evp_decrypt
 };
 
 const struct nettle_cipher
 nettle_openssl_aes192 = {
-  "openssl aes192", sizeof(AES_KEY),
-  /* Claim no block size, so that the benchmark doesn't try CBC mode
-   * (as openssl cipher + nettle cbc is somewhat pointless to
-   * benchmark). */
+  "openssl aes192", sizeof(struct openssl_cipher_ctx),
   16, 24,
   openssl_aes192_set_encrypt_key, openssl_aes192_set_decrypt_key,
-  openssl_aes_encrypt, openssl_aes_decrypt
+  openssl_evp_encrypt, openssl_evp_decrypt
 };
 
 const struct nettle_cipher
 nettle_openssl_aes256 = {
-  "openssl aes256", sizeof(AES_KEY),
-  /* Claim no block size, so that the benchmark doesn't try CBC mode
-   * (as openssl cipher + nettle cbc is somewhat pointless to
-   * benchmark). */
+  "openssl aes256", sizeof(struct openssl_cipher_ctx),
   16, 32,
   openssl_aes256_set_encrypt_key, openssl_aes256_set_decrypt_key,
-  openssl_aes_encrypt, openssl_aes_decrypt
+  openssl_evp_encrypt, openssl_evp_decrypt
 };
 
 /* Arcfour */
-static nettle_set_key_func openssl_arcfour128_set_key;
 static void
-openssl_arcfour128_set_key(void *ctx, const uint8_t *key)
+openssl_arcfour128_set_encrypt_key(void *ctx, const uint8_t *key)
 {
-  RC4_set_key(ctx, 16, key);
+  openssl_evp_set_encrypt_key(ctx, key, EVP_rc4());
 }
 
-static nettle_crypt_func openssl_arcfour_crypt;
 static void
-openssl_arcfour_crypt(void *ctx, size_t length,
-		      uint8_t *dst, const uint8_t *src)
+openssl_arcfour128_set_decrypt_key(void *ctx, const uint8_t *key)
 {
-  RC4(ctx, length, src, dst);
+  openssl_evp_set_decrypt_key(ctx, key, EVP_rc4());
 }
 
 const struct nettle_aead
 nettle_openssl_arcfour128 = {
-  "openssl arcfour128", sizeof(RC4_KEY),
+  "openssl arcfour128", sizeof(struct openssl_cipher_ctx),
   1, 16, 0, 0,
-  openssl_arcfour128_set_key,
-  openssl_arcfour128_set_key,
+  openssl_arcfour128_set_encrypt_key,
+  openssl_arcfour128_set_decrypt_key,
   NULL, NULL,
-  openssl_arcfour_crypt,
-  openssl_arcfour_crypt,
+  (nettle_crypt_func *)openssl_evp_encrypt,
+  (nettle_crypt_func *)openssl_evp_decrypt,
   NULL,  
 };
 
 /* Blowfish */
-static nettle_set_key_func openssl_bf128_set_key;
-static void
-openssl_bf128_set_key(void *ctx, const uint8_t *key)
-{
-  BF_set_key(ctx, 16, key);
-}
-
-static nettle_cipher_func openssl_bf_encrypt;
 static void
-openssl_bf_encrypt(const void *ctx, size_t length,
-		   uint8_t *dst, const uint8_t *src)
+openssl_bf128_set_encrypt_key(void *ctx, const uint8_t *key)
 {
-  assert (!(length % BF_BLOCK));
-  while (length)
-    {
-      BF_ecb_encrypt(src, dst, ctx, BF_ENCRYPT);
-      length -= BF_BLOCK;
-      dst += BF_BLOCK;
-      src += BF_BLOCK;
-    }
+  openssl_evp_set_encrypt_key(ctx, key, EVP_bf_ecb());
 }
 
-static nettle_cipher_func openssl_bf_decrypt;
 static void
-openssl_bf_decrypt(const void *ctx, size_t length,
-		   uint8_t *dst, const uint8_t *src)
+openssl_bf128_set_decrypt_key(void *ctx, const uint8_t *key)
 {
-  assert (!(length % BF_BLOCK));
-  while (length)
-    {
-      BF_ecb_encrypt(src, dst, ctx, BF_DECRYPT);
-      length -= BF_BLOCK;
-      dst += BF_BLOCK;
-      src += BF_BLOCK;
-    }
+  openssl_evp_set_decrypt_key(ctx, key, EVP_bf_ecb());
 }
 
 const struct nettle_cipher
 nettle_openssl_blowfish128 = {
-  "openssl bf128", sizeof(BF_KEY),
+  "openssl bf128", sizeof(struct openssl_cipher_ctx),
   8, 16,
-  openssl_bf128_set_key, openssl_bf128_set_key,
-  openssl_bf_encrypt, openssl_bf_decrypt
+  openssl_bf128_set_encrypt_key, openssl_bf128_set_decrypt_key,
+  openssl_evp_encrypt, openssl_evp_decrypt
 };
 
 
 /* DES */
-static nettle_set_key_func openssl_des_set_key;
 static void
-openssl_des_set_key(void *ctx, const uint8_t *key)
+openssl_des_set_encrypt_key(void *ctx, const uint8_t *key)
 {
-  /* Not sure what "unchecked" means. We want to ignore parity bits,
-     but it would still make sense to check for weak keys. */
-  /* Explicit cast used as I don't want to care about openssl's broken
-     array typedefs DES_cblock and const_DES_cblock. */
-  DES_set_key_unchecked( (void *) key, ctx);
+  openssl_evp_set_encrypt_key(ctx, key, EVP_des_ecb());
 }
 
-#define DES_BLOCK_SIZE 8
-
-static nettle_cipher_func openssl_des_encrypt;
-static void
-openssl_des_encrypt(const void *ctx, size_t length,
-		    uint8_t *dst, const uint8_t *src)
-{
-  assert (!(length % DES_BLOCK_SIZE));
-  while (length)
-    {
-      DES_ecb_encrypt((void *) src, (void *) dst,
-		      (void *) ctx, DES_ENCRYPT);
-      length -= DES_BLOCK_SIZE;
-      dst += DES_BLOCK_SIZE;
-      src += DES_BLOCK_SIZE;
-    }
-}
-
-static nettle_cipher_func openssl_des_decrypt;
 static void
-openssl_des_decrypt(const void *ctx, size_t length,
-		    uint8_t *dst, const uint8_t *src)
+openssl_des_set_decrypt_key(void *ctx, const uint8_t *key)
 {
-  assert (!(length % DES_BLOCK_SIZE));
-  while (length)
-    {
-      DES_ecb_encrypt((void *) src, (void *) dst,
-		      (void *) ctx, DES_DECRYPT);
-      length -= DES_BLOCK_SIZE;
-      dst += DES_BLOCK_SIZE;
-      src += DES_BLOCK_SIZE;
-    }
+  openssl_evp_set_decrypt_key(ctx, key, EVP_des_ecb());
 }
 
 const struct nettle_cipher
 nettle_openssl_des = {
-  "openssl des", sizeof(DES_key_schedule),
+  "openssl des", sizeof(struct openssl_cipher_ctx),
   8, 8,
-  openssl_des_set_key, openssl_des_set_key,
-  openssl_des_encrypt, openssl_des_decrypt
+  openssl_des_set_encrypt_key, openssl_des_set_decrypt_key,
+  openssl_evp_encrypt, openssl_evp_decrypt
 };
 
 
 /* Cast128 */
-static nettle_set_key_func openssl_cast128_set_key;
-static void
-openssl_cast128_set_key(void *ctx, const uint8_t *key)
-{
-  CAST_set_key(ctx, 16, key);
-}
-
-static nettle_cipher_func openssl_cast_encrypt;
 static void
-openssl_cast_encrypt(const void *ctx, size_t length,
-		     uint8_t *dst, const uint8_t *src)
+openssl_cast128_set_encrypt_key(void *ctx, const uint8_t *key)
 {
-  assert (!(length % CAST_BLOCK));
-  while (length)
-    {
-      CAST_ecb_encrypt(src, dst, ctx, CAST_ENCRYPT);
-      length -= CAST_BLOCK;
-      dst += CAST_BLOCK;
-      src += CAST_BLOCK;
-    }
+  openssl_evp_set_encrypt_key(ctx, key, EVP_cast5_ecb());
 }
 
-static nettle_cipher_func openssl_cast_decrypt;
 static void
-openssl_cast_decrypt(const void *ctx, size_t length,
-		     uint8_t *dst, const uint8_t *src)
+openssl_cast128_set_decrypt_key(void *ctx, const uint8_t *key)
 {
-  assert (!(length % CAST_BLOCK));
-  while (length)
-    {
-      CAST_ecb_encrypt(src, dst, ctx, CAST_DECRYPT);
-      length -= CAST_BLOCK;
-      dst += CAST_BLOCK;
-      src += CAST_BLOCK;
-    }
+  openssl_evp_set_decrypt_key(ctx, key, EVP_cast5_ecb());
 }
 
 const struct nettle_cipher
 nettle_openssl_cast128 = {
-  "openssl cast128", sizeof(CAST_KEY),
-  8, CAST_KEY_LENGTH,
-  openssl_cast128_set_key, openssl_cast128_set_key,
-  openssl_cast_encrypt, openssl_cast_decrypt
+  "openssl cast128", sizeof(struct openssl_cipher_ctx),
+  8, 16,
+  openssl_cast128_set_encrypt_key, openssl_cast128_set_decrypt_key,
+  openssl_evp_encrypt, openssl_evp_decrypt
 };
 
 /* Hash functions */
diff --git a/fat-arm.c b/fat-arm.c
index 1156499d6e908f107501607ecb99c7a769d9e822..d52b1439f2d88991c26b5a4b00f76ff45a8203df 100644
--- a/fat-arm.c
+++ b/fat-arm.c
@@ -29,6 +29,8 @@
    not, see http://www.gnu.org/licenses/.
 */
 
+#define _GNU_SOURCE
+
 #if HAVE_CONFIG_H
 # include "config.h"
 #endif
diff --git a/hkdf.c b/hkdf.c
new file mode 100644
index 0000000000000000000000000000000000000000..2d7336a58c000c34560d411e9fbbd09d526dfa8a
--- /dev/null
+++ b/hkdf.c
@@ -0,0 +1,84 @@
+/* hkdf.c
+
+   Copyright (C) 2017 Red Hat, Inc.
+
+   Author: Nikos Mavrogiannopoulos
+
+   This file is part of GNU Nettle.
+
+   GNU Nettle is free software: you can redistribute it and/or
+   modify it under the terms of either:
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at your
+       option) any later version.
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at your
+       option) any later version.
+
+   or both in parallel, as here.
+
+   GNU Nettle is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see http://www.gnu.org/licenses/.
+ */
+
+/* Functions for the HKDF handling.
+ */
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "hkdf.h"
+
+/* hkdf_extract: Outputs a PRK of digest_size
+ */
+void
+hkdf_extract(void *mac_ctx,
+	     nettle_hash_update_func *update,
+	     nettle_hash_digest_func *digest,
+	     size_t digest_size,
+	     size_t secret_size, const uint8_t *secret,
+	     uint8_t *dst)
+{
+  update(mac_ctx, secret_size, secret);
+  digest(mac_ctx, digest_size, dst);
+}
+
+/* hkdf_expand: Outputs an arbitrary key of size specified by length
+ */
+void
+hkdf_expand(void *mac_ctx,
+	    nettle_hash_update_func *update,
+	    nettle_hash_digest_func *digest,
+	    size_t digest_size,
+	    size_t info_size, const uint8_t *info,
+	    size_t length, uint8_t *dst)
+{
+  uint8_t i = 1;
+
+  if (!length)
+    return;
+
+  for (;; dst += digest_size, length -= digest_size, i++)
+    {
+      update(mac_ctx, info_size, info);
+      update(mac_ctx, 1, &i);
+      if (length <= digest_size)
+	break;
+
+      digest(mac_ctx, digest_size, dst);
+      update(mac_ctx, digest_size, dst);
+    }
+
+  digest(mac_ctx, length, dst);
+}
diff --git a/hkdf.h b/hkdf.h
new file mode 100644
index 0000000000000000000000000000000000000000..43b16ad4171f91c28f22a0fb2814f1870dd03591
--- /dev/null
+++ b/hkdf.h
@@ -0,0 +1,67 @@
+/* hkdf.h
+
+   TLS PRF code (RFC-5246, RFC-2246).
+
+   Copyright (C) 2017 Red Hat, Inc.
+
+   This file is part of GNU Nettle.
+
+   GNU Nettle is free software: you can redistribute it and/or
+   modify it under the terms of either:
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at your
+       option) any later version.
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at your
+       option) any later version.
+
+   or both in parallel, as here.
+
+   GNU Nettle is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see http://www.gnu.org/licenses/.
+*/
+
+#ifndef NETTLE_HKDF_H_INCLUDED
+#define NETTLE_HKDF_H_INCLUDED
+
+#include "nettle-types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Namespace mangling */
+#define hkdf_extract nettle_hkdf_extract
+#define hkdf_expand nettle_hkdf_expand
+
+void
+hkdf_extract(void *mac_ctx,
+	     nettle_hash_update_func *update,
+	     nettle_hash_digest_func *digest,
+	     size_t digest_size,
+	     size_t secret_size, const uint8_t *secret,
+	     uint8_t *dst);
+
+void
+hkdf_expand(void *mac_ctx,
+	    nettle_hash_update_func *update,
+	    nettle_hash_digest_func *digest,
+	    size_t digest_size,
+	    size_t info_size, const uint8_t *info,
+	    size_t length, uint8_t *dst);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* NETTLE_HKDF_H_INCLUDED */
diff --git a/mini-gmp.c b/mini-gmp.c
index acbe1becd8718cc2fa4f39241b8c5efeae8f44a6..d4d257c4ca35a54d048a90c63d6b158cc5283783 100644
--- a/mini-gmp.c
+++ b/mini-gmp.c
@@ -2,7 +2,7 @@
 
    Contributed to the GNU project by Niels Möller
 
-Copyright 1991-1997, 1999-2014 Free Software Foundation, Inc.
+Copyright 1991-1997, 1999-2017 Free Software Foundation, Inc.
 
 This file is part of the GNU MP Library.
 
@@ -69,8 +69,16 @@ see https://www.gnu.org/licenses/.  */
 #define GMP_MIN(a, b) ((a) < (b) ? (a) : (b))
 #define GMP_MAX(a, b) ((a) > (b) ? (a) : (b))
 
+#define GMP_CMP(a,b) (((a) > (b)) - ((a) < (b)))
+
+/* Return non-zero if xp,xsize and yp,ysize overlap.
+   If xp+xsize<=yp there's no overlap, or if yp+ysize<=xp there's no
+   overlap.  If both these are false, there's an overlap. */
+#define GMP_MPN_OVERLAP_P(xp, xsize, yp, ysize)				\
+  ((xp) + (xsize) > (yp) && (yp) + (ysize) > (xp))
+
 #define gmp_assert_nocarry(x) do { \
-    mp_limb_t __cy = x;		   \
+    mp_limb_t __cy = (x);	   \
     assert (__cy == 0);		   \
   } while (0)
 
@@ -264,12 +272,12 @@ gmp_default_alloc (size_t size)
 static void *
 gmp_default_realloc (void *old, size_t old_size, size_t new_size)
 {
-  mp_ptr p;
+  void * p;
 
   p = realloc (old, new_size);
 
   if (!p)
-    gmp_die("gmp_default_realoc: Virtual memory exhausted.");
+    gmp_die("gmp_default_realloc: Virtual memory exhausted.");
 
   return p;
 }
@@ -322,14 +330,14 @@ mp_set_memory_functions (void *(*alloc_func) (size_t),
 static mp_ptr
 gmp_xalloc_limbs (mp_size_t size)
 {
-  return gmp_xalloc (size * sizeof (mp_limb_t));
+  return (mp_ptr) gmp_xalloc (size * sizeof (mp_limb_t));
 }
 
 static mp_ptr
 gmp_xrealloc_limbs (mp_ptr old, mp_size_t size)
 {
   assert (size > 0);
-  return (*gmp_reallocate_func) (old, 0, size * sizeof (mp_limb_t));
+  return (mp_ptr) (*gmp_reallocate_func) (old, 0, size * sizeof (mp_limb_t));
 }
 
 
@@ -346,7 +354,7 @@ mpn_copyi (mp_ptr d, mp_srcptr s, mp_size_t n)
 void
 mpn_copyd (mp_ptr d, mp_srcptr s, mp_size_t n)
 {
-  while (n-- > 0)
+  while (--n >= 0)
     d[n] = s[n];
 }
 
@@ -373,20 +381,22 @@ mpn_cmp4 (mp_srcptr ap, mp_size_t an, mp_srcptr bp, mp_size_t bn)
 static mp_size_t
 mpn_normalized_size (mp_srcptr xp, mp_size_t n)
 {
-  for (; n > 0 && xp[n-1] == 0; n--)
-    ;
+  while (n > 0 && xp[n-1] == 0)
+    --n;
   return n;
 }
 
-#define mpn_zero_p(xp, n) (mpn_normalized_size ((xp), (n)) == 0)
+int
+mpn_zero_p(mp_srcptr rp, mp_size_t n)
+{
+  return mpn_normalized_size (rp, n) == 0;
+}
 
 void
 mpn_zero (mp_ptr rp, mp_size_t n)
 {
-  mp_size_t i;
-
-  for (i = 0; i < n; i++)
-    rp[i] = 0;
+  while (--n >= 0)
+    rp[n] = 0;
 }
 
 mp_limb_t
@@ -452,7 +462,7 @@ mpn_sub_1 (mp_ptr rp, mp_srcptr ap, mp_size_t n, mp_limb_t b)
     {
       mp_limb_t a = ap[i];
       /* Carry out */
-      mp_limb_t cy = a < b;;
+      mp_limb_t cy = a < b;
       rp[i] = a - b;
       b = cy;
     }
@@ -572,23 +582,24 @@ mpn_mul (mp_ptr rp, mp_srcptr up, mp_size_t un, mp_srcptr vp, mp_size_t vn)
 {
   assert (un >= vn);
   assert (vn >= 1);
+  assert (!GMP_MPN_OVERLAP_P(rp, un + vn, up, un));
+  assert (!GMP_MPN_OVERLAP_P(rp, un + vn, vp, vn));
 
   /* We first multiply by the low order limb. This result can be
      stored, not added, to rp. We also avoid a loop for zeroing this
      way. */
 
   rp[un] = mpn_mul_1 (rp, up, un, vp[0]);
-  rp += 1, vp += 1, vn -= 1;
 
   /* Now accumulate the product of up[] and the next higher limb from
      vp[]. */
 
-  while (vn >= 1)
+  while (--vn >= 1)
     {
+      rp += 1, vp += 1;
       rp[un] = mpn_addmul_1 (rp, up, un, vp[0]);
-      rp += 1, vp += 1, vn -= 1;
     }
-  return rp[un - 1];
+  return rp[un];
 }
 
 void
@@ -608,7 +619,6 @@ mpn_lshift (mp_ptr rp, mp_srcptr up, mp_size_t n, unsigned int cnt)
 {
   mp_limb_t high_limb, low_limb;
   unsigned int tnc;
-  mp_size_t i;
   mp_limb_t retval;
 
   assert (n >= 1);
@@ -623,7 +633,7 @@ mpn_lshift (mp_ptr rp, mp_srcptr up, mp_size_t n, unsigned int cnt)
   retval = low_limb >> tnc;
   high_limb = (low_limb << cnt);
 
-  for (i = n; --i != 0;)
+  while (--n != 0)
     {
       low_limb = *--up;
       *--rp = high_limb | (low_limb >> tnc);
@@ -639,7 +649,6 @@ mpn_rshift (mp_ptr rp, mp_srcptr up, mp_size_t n, unsigned int cnt)
 {
   mp_limb_t high_limb, low_limb;
   unsigned int tnc;
-  mp_size_t i;
   mp_limb_t retval;
 
   assert (n >= 1);
@@ -651,7 +660,7 @@ mpn_rshift (mp_ptr rp, mp_srcptr up, mp_size_t n, unsigned int cnt)
   retval = (high_limb << tnc);
   low_limb = high_limb >> cnt;
 
-  for (i = n; --i != 0;)
+  while (--n != 0)
     {
       high_limb = *up++;
       *rp++ = low_limb | (high_limb << tnc);
@@ -702,24 +711,68 @@ mpn_scan0 (mp_srcptr ptr, mp_bitcnt_t bit)
 			  i, ptr, i, GMP_LIMB_MAX);
 }
 
+void
+mpn_com (mp_ptr rp, mp_srcptr up, mp_size_t n)
+{
+  while (--n >= 0)
+    *rp++ = ~ *up++;
+}
+
+mp_limb_t
+mpn_neg (mp_ptr rp, mp_srcptr up, mp_size_t n)
+{
+  while (*up == 0)
+    {
+      *rp = 0;
+      if (!--n)
+	return 0;
+      ++up; ++rp;
+    }
+  *rp = - *up;
+  mpn_com (++rp, ++up, --n);
+  return 1;
+}
+
 
 /* MPN division interface. */
+
+/* The 3/2 inverse is defined as
+
+     m = floor( (B^3-1) / (B u1 + u0)) - B
+*/
 mp_limb_t
 mpn_invert_3by2 (mp_limb_t u1, mp_limb_t u0)
 {
-  mp_limb_t r, p, m;
-  unsigned ul, uh;
-  unsigned ql, qh;
+  mp_limb_t r, p, m, ql;
+  unsigned ul, uh, qh;
 
-  /* First, do a 2/1 inverse. */
-  /* The inverse m is defined as floor( (B^2 - 1 - u1)/u1 ), so that 0 <
-   * B^2 - (B + m) u1 <= u1 */
   assert (u1 >= GMP_LIMB_HIGHBIT);
 
+  /* For notation, let b denote the half-limb base, so that B = b^2.
+     Split u1 = b uh + ul. */
   ul = u1 & GMP_LLIMB_MASK;
   uh = u1 >> (GMP_LIMB_BITS / 2);
 
+  /* Approximation of the high half of quotient. Differs from the 2/1
+     inverse of the half limb uh, since we have already subtracted
+     u0. */
   qh = ~u1 / uh;
+
+  /* Adjust to get a half-limb 3/2 inverse, i.e., we want
+
+     qh' = floor( (b^3 - 1) / u) - b = floor ((b^3 - b u - 1) / u
+         = floor( (b (~u) + b-1) / u),
+
+     and the remainder
+
+     r = b (~u) + b-1 - qh (b uh + ul)
+       = b (~u - qh uh) + b-1 - qh ul
+
+     Subtraction of qh ul may underflow, which implies adjustments.
+     But by normalization, 2 u >= B > qh ul, so we need to adjust by
+     at most 2.
+  */
+
   r = ((~u1 - (mp_limb_t) qh * uh) << (GMP_LIMB_BITS / 2)) | GMP_LLIMB_MASK;
 
   p = (mp_limb_t) qh * ul;
@@ -737,11 +790,19 @@ mpn_invert_3by2 (mp_limb_t u1, mp_limb_t u0)
     }
   r -= p;
 
-  /* Do a 3/2 division (with half limb size) */
+  /* Low half of the quotient is
+
+       ql = floor ( (b r + b-1) / u1).
+
+     This is a 3/2 division (on half-limbs), for which qh is a
+     suitable inverse. */
+
   p = (r >> (GMP_LIMB_BITS / 2)) * qh + r;
+  /* Unlike full-limb 3/2, we can add 1 without overflow. For this to
+     work, it is essential that ql is a full mp_limb_t. */
   ql = (p >> (GMP_LIMB_BITS / 2)) + 1;
 
-  /* By the 3/2 method, we don't need the high half limb. */
+  /* By the 3/2 trick, we don't need the high half limb. */
   r = (r << (GMP_LIMB_BITS / 2)) + GMP_LLIMB_MASK - ql * u1;
 
   if (r >= (p << (GMP_LIMB_BITS / 2)))
@@ -756,6 +817,8 @@ mpn_invert_3by2 (mp_limb_t u1, mp_limb_t u0)
       r -= u1;
     }
 
+  /* Now m is the 2/1 invers of u1. If u0 > 0, adjust it to become a
+     3/2 inverse. */
   if (u0 > 0)
     {
       mp_limb_t th, tl;
@@ -876,7 +939,7 @@ mpn_div_qr_1_preinv (mp_ptr qp, mp_srcptr np, mp_size_t nn,
 
   d = inv->d1;
   di = inv->di;
-  while (nn-- > 0)
+  while (--nn >= 0)
     {
       mp_limb_t q;
 
@@ -1160,7 +1223,7 @@ mpn_get_str_bits (unsigned char *sp, unsigned bits, mp_srcptr up, mp_size_t un)
   unsigned char mask;
   size_t sn, j;
   mp_size_t i;
-  int shift;
+  unsigned shift;
 
   sn = ((un - 1) * GMP_LIMB_BITS + mpn_limb_size_in_base_2 (up[un-1])
 	+ bits - 1) / bits;
@@ -1301,6 +1364,8 @@ mpn_set_str_bits (mp_ptr rp, const unsigned char *sp, size_t sn,
   return rn;
 }
 
+/* Result is usually normalized, except for all-zero input, in which
+   case a single zero limb is written at *RP, and 1 is returned. */
 static mp_size_t
 mpn_set_str_other (mp_ptr rp, const unsigned char *sp, size_t sn,
 		   mp_limb_t b, const struct mpn_base_info *info)
@@ -1310,16 +1375,18 @@ mpn_set_str_other (mp_ptr rp, const unsigned char *sp, size_t sn,
   unsigned k;
   size_t j;
 
+  assert (sn > 0);
+
   k = 1 + (sn - 1) % info->exp;
 
   j = 0;
   w = sp[j++];
-  for (; --k > 0; )
+  while (--k != 0)
     w = w * b + sp[j++];
 
   rp[0] = w;
 
-  for (rn = (w > 0); j < sn;)
+  for (rn = 1; j < sn;)
     {
       mp_limb_t cy;
 
@@ -1362,9 +1429,11 @@ mpn_set_str (mp_ptr rp, const unsigned char *sp, size_t sn, int base)
 void
 mpz_init (mpz_t r)
 {
-  r->_mp_alloc = 1;
+  static const mp_limb_t dummy_limb = 0xc1a0;
+
+  r->_mp_alloc = 0;
   r->_mp_size = 0;
-  r->_mp_d = gmp_xalloc_limbs (1);
+  r->_mp_d = (mp_ptr) &dummy_limb;
 }
 
 /* The utility of this function is a bit limited, since many functions
@@ -1385,15 +1454,19 @@ mpz_init2 (mpz_t r, mp_bitcnt_t bits)
 void
 mpz_clear (mpz_t r)
 {
-  gmp_free (r->_mp_d);
+  if (r->_mp_alloc)
+    gmp_free (r->_mp_d);
 }
 
-static void *
+static mp_ptr
 mpz_realloc (mpz_t r, mp_size_t size)
 {
   size = GMP_MAX (size, 1);
 
-  r->_mp_d = gmp_xrealloc_limbs (r->_mp_d, size);
+  if (r->_mp_alloc)
+    r->_mp_d = gmp_xrealloc_limbs (r->_mp_d, size);
+  else
+    r->_mp_d = gmp_xalloc_limbs (size);
   r->_mp_alloc = size;
 
   if (GMP_ABS (r->_mp_size) > size)
@@ -1416,7 +1489,7 @@ mpz_set_si (mpz_t r, signed long int x)
   else /* (x < 0) */
     {
       r->_mp_size = -1;
-      r->_mp_d[0] = GMP_NEG_CAST (unsigned long int, x);
+      MPZ_REALLOC (r, 1)[0] = GMP_NEG_CAST (unsigned long int, x);
     }
 }
 
@@ -1426,7 +1499,7 @@ mpz_set_ui (mpz_t r, unsigned long int x)
   if (x > 0)
     {
       r->_mp_size = 1;
-      r->_mp_d[0] = x;
+      MPZ_REALLOC (r, 1)[0] = x;
     }
   else
     r->_mp_size = 0;
@@ -1475,14 +1548,12 @@ mpz_fits_slong_p (const mpz_t u)
 {
   mp_size_t us = u->_mp_size;
 
-  if (us == 0)
-    return 1;
-  else if (us == 1)
+  if (us == 1)
     return u->_mp_d[0] < GMP_LIMB_HIGHBIT;
   else if (us == -1)
     return u->_mp_d[0] <= GMP_LIMB_HIGHBIT;
   else
-    return 0;
+    return (us == 0);
 }
 
 int
@@ -1496,14 +1567,11 @@ mpz_fits_ulong_p (const mpz_t u)
 long int
 mpz_get_si (const mpz_t u)
 {
-  mp_size_t us = u->_mp_size;
-
-  if (us > 0)
-    return (long) (u->_mp_d[0] & ~GMP_LIMB_HIGHBIT);
-  else if (us < 0)
-    return (long) (- u->_mp_d[0] | GMP_LIMB_HIGHBIT);
+  if (u->_mp_size < 0)
+    /* This expression is necessary to properly handle 0x80000000 */
+    return -1 - (long) ((u->_mp_d[0] - 1) & ~GMP_LIMB_HIGHBIT);
   else
-    return 0;
+    return (long) (mpz_get_ui (u) & ~GMP_LIMB_HIGHBIT);
 }
 
 unsigned long int
@@ -1536,7 +1604,7 @@ mpz_realloc2 (mpz_t x, mp_bitcnt_t n)
 mp_srcptr
 mpz_limbs_read (mpz_srcptr x)
 {
-  return x->_mp_d;;
+  return x->_mp_d;
 }
 
 mp_ptr
@@ -1716,9 +1784,7 @@ mpz_cmp_d (const mpz_t x, double d)
 int
 mpz_sgn (const mpz_t u)
 {
-  mp_size_t usize = u->_mp_size;
-
-  return (usize > 0) - (usize < 0);
+  return GMP_CMP (u->_mp_size, 0);
 }
 
 int
@@ -1733,13 +1799,7 @@ mpz_cmp_si (const mpz_t u, long v)
   else if (usize >= 0)
     return 1;
   else /* usize == -1 */
-    {
-      mp_limb_t ul = u->_mp_d[0];
-      if ((mp_limb_t)GMP_NEG_CAST (unsigned long int, v) < ul)
-	return -1;
-      else
-	return (mp_limb_t)GMP_NEG_CAST (unsigned long int, v) > ul;
-    }
+    return GMP_CMP (GMP_NEG_CAST (mp_limb_t, v), u->_mp_d[0]);
 }
 
 int
@@ -1752,10 +1812,7 @@ mpz_cmp_ui (const mpz_t u, unsigned long v)
   else if (usize < 0)
     return -1;
   else
-    {
-      mp_limb_t ul = (usize > 0) ? u->_mp_d[0] : 0;
-      return (ul > v) - (ul < v);
-    }
+    return GMP_CMP (mpz_get_ui (u), v);
 }
 
 int
@@ -1775,15 +1832,10 @@ mpz_cmp (const mpz_t a, const mpz_t b)
 int
 mpz_cmpabs_ui (const mpz_t u, unsigned long v)
 {
-  mp_size_t un = GMP_ABS (u->_mp_size);
-  mp_limb_t ul;
-
-  if (un > 1)
+  if (GMP_ABS (u->_mp_size) > 1)
     return 1;
-
-  ul = (un == 1) ? u->_mp_d[0] : 0;
-
-  return (ul > v) - (ul < v);
+  else
+    return GMP_CMP (mpz_get_ui (u), v);
 }
 
 int
@@ -1796,18 +1848,14 @@ mpz_cmpabs (const mpz_t u, const mpz_t v)
 void
 mpz_abs (mpz_t r, const mpz_t u)
 {
-  if (r != u)
-    mpz_set (r, u);
-
+  mpz_set (r, u);
   r->_mp_size = GMP_ABS (r->_mp_size);
 }
 
 void
 mpz_neg (mpz_t r, const mpz_t u)
 {
-  if (r != u)
-    mpz_set (r, u);
-
+  mpz_set (r, u);
   r->_mp_size = -r->_mp_size;
 }
 
@@ -1833,7 +1881,7 @@ mpz_abs_add_ui (mpz_t r, const mpz_t a, unsigned long b)
   an = GMP_ABS (a->_mp_size);
   if (an == 0)
     {
-      r->_mp_d[0] = b;
+      MPZ_REALLOC (r, 1)[0] = b;
       return b > 0;
     }
 
@@ -1852,14 +1900,15 @@ static mp_size_t
 mpz_abs_sub_ui (mpz_t r, const mpz_t a, unsigned long b)
 {
   mp_size_t an = GMP_ABS (a->_mp_size);
-  mp_ptr rp = MPZ_REALLOC (r, an);
+  mp_ptr rp;
 
   if (an == 0)
     {
-      rp[0] = b;
+      MPZ_REALLOC (r, 1)[0] = b;
       return -(b > 0);
     }
-  else if (an == 1 && a->_mp_d[0] < b)
+  rp = MPZ_REALLOC (r, an);
+  if (an == 1 && a->_mp_d[0] < b)
     {
       rp[0] = b - a->_mp_d[0];
       return -1;
@@ -2077,8 +2126,7 @@ mpz_mul_2exp (mpz_t r, const mpz_t u, mp_bitcnt_t bits)
   else
     mpn_copyd (rp + limbs, u->_mp_d, un);
 
-  while (limbs > 0)
-    rp[--limbs] = 0;
+  mpn_zero (rp, limbs);
 
   r->_mp_size = (u->_mp_size < 0) ? - rn : rn;
 }
@@ -2331,7 +2379,6 @@ mpz_div_q_2exp (mpz_t q, const mpz_t u, mp_bitcnt_t bit_index,
 
   if (qn <= 0)
     qn = 0;
-
   else
     {
       qp = MPZ_REALLOC (q, qn);
@@ -2385,16 +2432,9 @@ mpz_div_r_2exp (mpz_t r, const mpz_t u, mp_bitcnt_t bit_index,
 	{
 	  /* Have to negate and sign extend. */
 	  mp_size_t i;
-	  mp_limb_t cy;
 
-	  for (cy = 1, i = 0; i < un; i++)
-	    {
-	      mp_limb_t s = ~u->_mp_d[i] + cy;
-	      cy = s < cy;
-	      rp[i] = s;
-	    }
-	  assert (cy == 0);
-	  for (; i < rn - 1; i++)
+	  gmp_assert_nocarry (! mpn_neg (rp, u->_mp_d, un));
+	  for (i = un; i < rn - 1; i++)
 	    rp[i] = GMP_LIMB_MAX;
 
 	  rp[rn-1] = mask;
@@ -2419,23 +2459,13 @@ mpz_div_r_2exp (mpz_t r, const mpz_t u, mp_bitcnt_t bit_index,
       if (mode == ((us > 0) ? GMP_DIV_CEIL : GMP_DIV_FLOOR)) /* us != 0 here. */
 	{
 	  /* If r != 0, compute 2^{bit_count} - r. */
-	  mp_size_t i;
+	  mpn_neg (rp, rp, rn);
 
-	  for (i = 0; i < rn && rp[i] == 0; i++)
-	    ;
-	  if (i < rn)
-	    {
-	      /* r > 0, need to flip sign. */
-	      rp[i] = ~rp[i] + 1;
-	      while (++i < rn)
-		rp[i] = ~rp[i];
-
-	      rp[rn-1] &= mask;
+	  rp[rn-1] &= mask;
 
-	      /* us is not used for anything else, so we can modify it
-		 here to indicate flipped sign. */
-	      us = -us;
-	    }
+	  /* us is not used for anything else, so we can modify it
+	     here to indicate flipped sign. */
+	  us = -us;
 	}
     }
   rn = mpn_normalized_size (rp, rn);
@@ -2550,7 +2580,7 @@ mpz_div_qr_ui (mpz_t q, mpz_t r,
 
   if (r)
     {
-      r->_mp_d[0] = rl;
+      MPZ_REALLOC (r, 1)[0] = rl;
       r->_mp_size = rs;
     }
   if (q)
@@ -3074,9 +3104,7 @@ void
 mpz_ui_pow_ui (mpz_t r, unsigned long blimb, unsigned long e)
 {
   mpz_t b;
-  mpz_init_set_ui (b, blimb);
-  mpz_pow_ui (r, b, e);
-  mpz_clear (b);
+  mpz_pow_ui (r, mpz_roinit_n (b, &blimb, 1), e);
 }
 
 void
@@ -3148,7 +3176,7 @@ mpz_powm (mpz_t r, const mpz_t b, const mpz_t e, const mpz_t m)
     }
   mpz_init_set_ui (tr, 1);
 
-  while (en-- > 0)
+  while (--en >= 0)
     {
       mp_limb_t w = e->_mp_d[en];
       mp_limb_t bit;
@@ -3188,9 +3216,7 @@ void
 mpz_powm_ui (mpz_t r, const mpz_t b, unsigned long elimb, const mpz_t m)
 {
   mpz_t e;
-  mpz_init_set_ui (e, elimb);
-  mpz_powm (r, b, e, m);
-  mpz_clear (e);
+  mpz_powm (r, b, mpz_roinit_n (e, &elimb, 1), m);
 }
 
 /* x=trunc(y^(1/z)), r=y-x^z */
@@ -3215,12 +3241,8 @@ mpz_rootrem (mpz_t x, mpz_t r, const mpz_t y, unsigned long z)
   }
 
   mpz_init (u);
-  {
-    mp_bitcnt_t tb;
-    tb = mpz_sizeinbase (y, 2) / z + 1;
-    mpz_init2 (t, tb);
-    mpz_setbit (t, tb);
-  }
+  mpz_init (t);
+  mpz_setbit (t, mpz_sizeinbase (y, 2) / z + 1);
 
   if (z == 2) /* simplify sqrt loop: z-1 == 1 */
     do {
@@ -3333,7 +3355,7 @@ void
 mpz_fac_ui (mpz_t x, unsigned long n)
 {
   mpz_set_ui (x, n + (n == 0));
-  for (;n > 2;)
+  while (n > 2)
     mpz_mul_ui (x, x, --n);
 }
 
@@ -3504,7 +3526,7 @@ mpz_tstbit (const mpz_t d, mp_bitcnt_t bit_index)
 	 must be complemented. */
       if (shift > 0 && (w << (GMP_LIMB_BITS - shift)) > 0)
 	return bit ^ 1;
-      while (limb_index-- > 0)
+      while (--limb_index >= 0)
 	if (d->_mp_d[limb_index] > 0)
 	  return bit ^ 1;
     }
@@ -3647,7 +3669,7 @@ mpz_and (mpz_t r, const mpz_t u, const mpz_t v)
   /* If the smaller input is positive, higher limbs don't matter. */
   rn = vx ? un : vn;
 
-  rp = MPZ_REALLOC (r, rn + rc);
+  rp = MPZ_REALLOC (r, rn + (mp_size_t) rc);
 
   up = u->_mp_d;
   vp = v->_mp_d;
@@ -3720,7 +3742,7 @@ mpz_ior (mpz_t r, const mpz_t u, const mpz_t v)
      don't matter. */
   rn = vx ? vn : un;
 
-  rp = MPZ_REALLOC (r, rn + rc);
+  rp = MPZ_REALLOC (r, rn + (mp_size_t) rc);
 
   up = u->_mp_d;
   vp = v->_mp_d;
@@ -3789,7 +3811,7 @@ mpz_xor (mpz_t r, const mpz_t u, const mpz_t v)
   vx = -vc;
   rx = -rc;
 
-  rp = MPZ_REALLOC (r, un + rc);
+  rp = MPZ_REALLOC (r, un + (mp_size_t) rc);
 
   up = u->_mp_d;
   vp = v->_mp_d;
@@ -3999,7 +4021,7 @@ mpz_sizeinbase (const mpz_t u, int base)
   size_t ndigits;
 
   assert (base >= 2);
-  assert (base <= 36);
+  assert (base <= 62);
 
   un = GMP_ABS (u->_mp_size);
   if (un == 0)
@@ -4049,23 +4071,26 @@ mpz_get_str (char *sp, int base, const mpz_t u)
   mp_size_t un;
   size_t i, sn;
 
-  if (base >= 0)
+  digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+  if (base > 1)
     {
-      digits = "0123456789abcdefghijklmnopqrstuvwxyz";
+      if (base <= 36)
+	digits = "0123456789abcdefghijklmnopqrstuvwxyz";
+      else if (base > 62)
+	return NULL;
     }
+  else if (base >= -1)
+    base = 10;
   else
     {
       base = -base;
-      digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+      if (base > 36)
+	return NULL;
     }
-  if (base <= 1)
-    base = 10;
-  if (base > 36)
-    return NULL;
 
   sn = 1 + mpz_sizeinbase (u, base);
   if (!sp)
-    sp = gmp_xalloc (1 + sn);
+    sp = (char *) gmp_xalloc (1 + sn);
 
   un = GMP_ABS (u->_mp_size);
 
@@ -4109,14 +4134,14 @@ mpz_get_str (char *sp, int base, const mpz_t u)
 int
 mpz_set_str (mpz_t r, const char *sp, int base)
 {
-  unsigned bits;
+  unsigned bits, value_of_a;
   mp_size_t rn, alloc;
   mp_ptr rp;
-  size_t sn;
+  size_t dn;
   int sign;
   unsigned char *dp;
 
-  assert (base == 0 || (base >= 2 && base <= 36));
+  assert (base == 0 || (base >= 2 && base <= 62));
 
   while (isspace( (unsigned char) *sp))
     sp++;
@@ -4126,18 +4151,17 @@ mpz_set_str (mpz_t r, const char *sp, int base)
 
   if (base == 0)
     {
-      if (*sp == '0')
+      if (sp[0] == '0')
 	{
-	  sp++;
-	  if (*sp == 'x' || *sp == 'X')
+	  if (sp[1] == 'x' || sp[1] == 'X')
 	    {
 	      base = 16;
-	      sp++;
+	      sp += 2;
 	    }
-	  else if (*sp == 'b' || *sp == 'B')
+	  else if (sp[1] == 'b' || sp[1] == 'B')
 	    {
 	      base = 2;
-	      sp++;
+	      sp += 2;
 	    }
 	  else
 	    base = 8;
@@ -4146,49 +4170,63 @@ mpz_set_str (mpz_t r, const char *sp, int base)
 	base = 10;
     }
 
-  sn = strlen (sp);
-  dp = gmp_xalloc (sn + (sn == 0));
+  if (!*sp)
+    {
+      r->_mp_size = 0;
+      return -1;
+    }
+  dp = (unsigned char *) gmp_xalloc (strlen (sp));
 
-  for (sn = 0; *sp; sp++)
+  value_of_a = (base > 36) ? 36 : 10;
+  for (dn = 0; *sp; sp++)
     {
       unsigned digit;
 
       if (isspace ((unsigned char) *sp))
 	continue;
-      if (*sp >= '0' && *sp <= '9')
+      else if (*sp >= '0' && *sp <= '9')
 	digit = *sp - '0';
       else if (*sp >= 'a' && *sp <= 'z')
-	digit = *sp - 'a' + 10;
+	digit = *sp - 'a' + value_of_a;
       else if (*sp >= 'A' && *sp <= 'Z')
 	digit = *sp - 'A' + 10;
       else
 	digit = base; /* fail */
 
-      if (digit >= base)
+      if (digit >= (unsigned) base)
 	{
 	  gmp_free (dp);
 	  r->_mp_size = 0;
 	  return -1;
 	}
 
-      dp[sn++] = digit;
+      dp[dn++] = digit;
     }
 
+  if (!dn)
+    {
+      gmp_free (dp);
+      r->_mp_size = 0;
+      return -1;
+    }
   bits = mpn_base_power_of_two_p (base);
 
   if (bits > 0)
     {
-      alloc = (sn * bits + GMP_LIMB_BITS - 1) / GMP_LIMB_BITS;
+      alloc = (dn * bits + GMP_LIMB_BITS - 1) / GMP_LIMB_BITS;
       rp = MPZ_REALLOC (r, alloc);
-      rn = mpn_set_str_bits (rp, dp, sn, bits);
+      rn = mpn_set_str_bits (rp, dp, dn, bits);
     }
   else
     {
       struct mpn_base_info info;
       mpn_get_base_info (&info, base);
-      alloc = (sn + info.exp - 1) / info.exp;
+      alloc = (dn + info.exp - 1) / info.exp;
       rp = MPZ_REALLOC (r, alloc);
-      rn = mpn_set_str_other (rp, dp, sn, base, &info);
+      rn = mpn_set_str_other (rp, dp, dn, base, &info);
+      /* Normalization, needed for all-zero input. */
+      assert (rn > 0);
+      rn -= rp[rn-1] == 0;
     }
   assert (rn <= alloc);
   gmp_free (dp);
diff --git a/mini-gmp.h b/mini-gmp.h
index c043ca7e661b9ad413b37a811229b6f7ad74ae59..bb5c6371d93e66e28519c627f893b8d474146a57 100644
--- a/mini-gmp.h
+++ b/mini-gmp.h
@@ -1,6 +1,6 @@
 /* mini-gmp, a minimalistic implementation of a GNU GMP subset.
 
-Copyright 2011-2014 Free Software Foundation, Inc.
+Copyright 2011-2015 Free Software Foundation, Inc.
 
 This file is part of the GNU MP Library.
 
@@ -82,6 +82,7 @@ void mpn_copyd (mp_ptr, mp_srcptr, mp_size_t);
 void mpn_zero (mp_ptr, mp_size_t);
 
 int mpn_cmp (mp_srcptr, mp_srcptr, mp_size_t);
+int mpn_zero_p (mp_srcptr, mp_size_t);
 
 mp_limb_t mpn_add_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
 mp_limb_t mpn_add_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
@@ -107,6 +108,9 @@ mp_limb_t mpn_rshift (mp_ptr, mp_srcptr, mp_size_t, unsigned int);
 mp_bitcnt_t mpn_scan0 (mp_srcptr, mp_bitcnt_t);
 mp_bitcnt_t mpn_scan1 (mp_srcptr, mp_bitcnt_t);
 
+void mpn_com (mp_ptr, mp_srcptr, mp_size_t);
+mp_limb_t mpn_neg (mp_ptr, mp_srcptr, mp_size_t);
+
 mp_bitcnt_t mpn_popcount (mp_srcptr, mp_size_t);
 
 mp_limb_t mpn_invert_3by2 (mp_limb_t, mp_limb_t);
diff --git a/misc/plan.html b/misc/plan.html
index 71ddba3a6331ec6748b433a9077758c60a69e149..99be07d5b5c78429d2afdb4a1f9c2356b26dd2c6 100644
--- a/misc/plan.html
+++ b/misc/plan.html
@@ -12,9 +12,9 @@
 </head>
 <body>
   <h1> Nettle release plans </h1>
-  <p> This is an attempt at defining a development target for
-    Nettle-3.3, inspired by similar pages for recent GMP releases.
-    [Last updated 2016-09-19]</p>
+  <p> This is an attempt at defining a development target for the next
+    release of Nettle, inspired by similar pages for recent GMP
+    releases. [Last updated 2017-10-01]</p>
   <p class='should'>
     This really ought to be done before release
   </p>
@@ -28,21 +28,36 @@
     Leave for some later release!
   </p>
 
-  <h1> Plans for nettle-3.3 </h1>
+  <h1> Plans for nettle-3.4 </h1>
+
+  <h2> Bug fixes </h2>
+  <p class='should'> Fix issues with sizes of objects like the
+    nettle_hashes array and the ecc_curve structs accidentally leaking
+    into the ABI. Fix by another level of indirection, with a function
+    call to return the start address.
+  </p>
 
   <h2> New features </h2>
   <p class='postponed'>
     Add larger "safe" curves, e.g., M-383, curve41417, curve448 and
-    E-521.
+    E-521. (curve448 in progress, on its own branch).
   </p>
+
   <p class='postponed'>
     Add functions for converting ECC points to and from ANSI x9.62.
   </p>
-  <p class='done'>
-    Use side-channel silent mpz_powm_sec for RSA and DSA.
+
+  <p class='postponed'>
+    Support for the Skein hash function.
   </p>
-  <p class='done'>
-    Side-channel silent memeql_sec.
+
+  <p class='postponed'>
+    Support for more GOST standard algorithms.
+  </p>
+
+  <p class='wish'>
+    Support for CFB mode (patch by Dmitry Eremin-Solenikov posted on
+    the list).
   </p>
 
   <h2> Optimizations </h2>
@@ -58,42 +73,43 @@
   </p>
   
   <h2> Miscellaneous </h2>
-  <p class='done'> Use GMP-5 functions unconditionally. </p>
   <p class='postponed'>
     Use more functions from GMP-6 and later, when available:
     mpn_sec_add_1, mpn_sec_tabselect, mpn_sec_invert, mpn_cnd_swap,
     ...
   </p>
 
-  <h2> Documentation </h2>
-  <p class='done'>
-    Document memeql_sec.
+  <p class='done'> Change base16 and base64 interfaces to use char
+    for encoded data, and fix remaining pointer-signedness warnings.
   </p>
   
+  <h2> Documentation </h2>
+
+  
   <h2> Build system </h2>
-  <p class='postponed'>
-    Update AX_CREATE_STDINT_H to the latest version.
+  <p class='should'>
+    Delete AX_CREATE_STDINT_H, use stdint.h unconditionally.
   </p>
   
   <h2> Testing </h2>
   <p> Since xenofarm isn't up and running, do some manual testing:
   </p>
   <ul>
-    <li class='done'> x86_64-linux-gnu</li>
-    <li class='done'> x86-linux-gnu</li>
-    <li class='done'> x86_64-freebsd</li>
-    <li class='done'> x86-w*ndows (using cross compiler and wine)</li>
-    <li class='done'> x86_64-w*ndows (using cross compiler and wine)</li>
+    <li class='should'> x86_64-linux-gnu</li>
+    <li class='should'> x86-linux-gnu</li>
+    <li class='should'> x86_64-freebsd</li>
+    <li class='should'> x86-w*ndows (using cross compiler and wine)</li>
+    <li class='should'> x86_64-w*ndows (using cross compiler and wine)</li>
     <li class='should'> x86-darwin (needs help from Nettle users)</li>
     <li class='should'> x86_64-darwin (needs help from Nettle users)</li>
     <li class='should'> armv5-linux-gnu (qemu)</li>
-    <li class='done'> armv7-linux-gnu (qemu)</li>
+    <li class='should'> armv7-linux-gnu (qemu)</li>
     <li class='should'> armv8-linux-gnu (qemu)</li>
     <li class='should'> ppc64-linux-gnu (qemu)</li>
     <li class='should'> ppc32-linux-gnu (qemu)</li>
-    <li class='done'> mips64-linux-gnu (qemu)</li>
+    <li class='should'> mips64-linux-gnu (qemu)</li>
     <li class='should'> mips32-linux-gnu (qemu)</li>
-    <li class='done'> m68k-linux-gnu (aranym)</li>
+    <li class='should'> m68k-linux-gnu (aranym)</li>
     <li class='wish'> armv7-android </li>
   </ul>
 
diff --git a/nettle-internal.h b/nettle-internal.h
index 4e3098bbdec38afaaa3e4bd3d9289b124f66b05d..0b0d25c90efa16d1ebfb6fdab2db22a71075a232 100644
--- a/nettle-internal.h
+++ b/nettle-internal.h
@@ -54,6 +54,7 @@
 /* Arbitrary limits which apply to systems that don't have alloca */
 #define NETTLE_MAX_HASH_BLOCK_SIZE 128
 #define NETTLE_MAX_HASH_DIGEST_SIZE 64
+#define NETTLE_MAX_HASH_CONTEXT_SIZE (sizeof(struct sha3_224_ctx))
 #define NETTLE_MAX_SEXP_ASSOC 17
 #define NETTLE_MAX_CIPHER_BLOCK_SIZE 32
 
@@ -78,6 +79,7 @@ extern const struct nettle_aead nettle_salsa20r12;
 
 /* Glue to openssl, for comparative benchmarking. Code in
  * examples/nettle-openssl.c. */
+extern void nettle_openssl_init(void);
 extern const struct nettle_cipher nettle_openssl_aes128;
 extern const struct nettle_cipher nettle_openssl_aes192;
 extern const struct nettle_cipher nettle_openssl_aes256;
diff --git a/nettle-types.h b/nettle-types.h
index 475937d20d47e38b9a34239c2a794c4aba1cabd4..84c375d2e6d49608fe7c5cecb0412d04228c0eca 100644
--- a/nettle-types.h
+++ b/nettle-types.h
@@ -89,17 +89,17 @@ typedef size_t nettle_armor_length_func(size_t length);
 typedef void nettle_armor_init_func(void *ctx);
 
 typedef size_t nettle_armor_encode_update_func(void *ctx,
-					       uint8_t *dst,
+					       char *dst,
 					       size_t src_length,
 					       const uint8_t *src);
 
-typedef size_t nettle_armor_encode_final_func(void *ctx, uint8_t *dst);
+typedef size_t nettle_armor_encode_final_func(void *ctx, char *dst);
 
 typedef int nettle_armor_decode_update_func(void *ctx,
 					    size_t *dst_length,
 					    uint8_t *dst,
 					    size_t src_length,
-					    const uint8_t *src);
+					    const char *src);
 
 typedef int nettle_armor_decode_final_func(void *ctx);
 
diff --git a/nettle.texinfo b/nettle.texinfo
index 9cfaf43ae3fda719133e75429da83eb512995d06..23eed3357d063600dbcfdcd265754fa11a8a3e02 100644
--- a/nettle.texinfo
+++ b/nettle.texinfo
@@ -93,6 +93,7 @@ Cipher modes
 
 * CBC::                         
 * CTR::                         
+* CFB::
 * GCM::                         
 * CCM::                         
 
@@ -1884,21 +1885,23 @@ a message that is larger than the cipher's block size. As explained in
 processing them independently with the block cipher (Electronic Code
 Book mode, @acronym{ECB}), leaks information.
 
-Besides @acronym{ECB}, Nettle provides a two other modes of operation:
-Cipher Block Chaining (@acronym{CBC}), Counter mode (@acronym{CTR}), and
-a couple of @acronym{AEAD} modes (@pxref{Authenticated encryption}).
-@acronym{CBC} is widely used, but there are a few subtle issues of
-information leakage, see, e.g.,
+Besides @acronym{ECB}, Nettle provides several other modes of operation:
+Cipher Block Chaining (@acronym{CBC}), Counter mode (@acronym{CTR}), Cipher
+Feedback (@acronym{CFB}) and a couple of @acronym{AEAD} modes
+(@pxref{Authenticated encryption}).  @acronym{CBC} is widely used, but
+there are a few subtle issues of information leakage, see, e.g.,
 @uref{http://www.kb.cert.org/vuls/id/958563, @acronym{SSH} @acronym{CBC}
 vulnerability}. Today, @acronym{CTR} is usually preferred over @acronym{CBC}.
 
-Modes like @acronym{CBC} and @acronym{CTR} provide @emph{no} message
-authentication, and should always be used together with a @acronym{MAC}
-(@pxref{Keyed hash functions}) or signature to authenticate the message.
+Modes like @acronym{CBC}, @acronym{CTR} and @acronym{CFB} provide @emph{no}
+message authentication, and should always be used together with a
+@acronym{MAC} (@pxref{Keyed hash functions}) or signature to authenticate
+the message.
 
 @menu
 * CBC::                         
 * CTR::                         
+* CFB::
 @end menu
 
 @node CBC, CTR, Cipher modes, Cipher modes
@@ -1994,7 +1997,7 @@ These macros use some tricks to make the compiler display a warning if
 the types of @var{f} and @var{ctx} don't match, e.g. if you try to use
 an @code{struct aes_ctx} context with the @code{des_encrypt} function.
 
-@node CTR, , CBC, Cipher modes
+@node CTR, CFB, CBC, Cipher modes
 @comment  node-name,  next,  previous,  up
 @subsection Counter mode
 
@@ -2070,6 +2073,91 @@ last three arguments define the source and destination area for the
 operation.
 @end deffn
 
+@node CFB, , CTR, Cipher modes
+@comment  node-name,  next,  previous,  up
+@subsection Cipher Feedback mode
+
+@cindex Cipher Feedback Mode
+@cindex CFB Mode
+
+Cipher Feedback mode (@acronym{CFB}) being a close relative to both
+@acronym{CBC} mode and @acronym{CTR} mode borrows some characteristics
+from stream ciphers.
+
+The message is divided into @code{n} blocks @code{M_1},@dots{}
+@code{M_n}, where @code{M_n} is of size @code{m} which may be smaller
+than the block size. Except for the last block, all the message blocks
+must be of size equal to the cipher's block size.
+
+If @code{E_k} is the encryption function of a block cipher, @code{IV} is
+the initialization vector, then the @code{n} plaintext blocks are
+transformed into @code{n} ciphertext blocks @code{C_1},@dots{}
+@code{C_n} as follows:
+
+@example
+C_1 = E_k(IV) XOR M_1
+C_2 = E_k(C_1) XOR M_2
+
+@dots{}
+
+C_(n-1) = E_k(C_(n - 2)) XOR M_(n-1)
+C_n = E_k(C_(n - 1)) [1..m] XOR M_n
+@end example
+
+Nettle's includes two functions for applying a block cipher in Cipher
+Feedback (@acronym{CFB}) mode, one for encryption and one for
+decryption. These functions uses @code{void *} to pass cipher contexts
+around.
+
+@deftypefun {void} cfb_encrypt (const void *@var{ctx}, nettle_cipher_func *@var{f}, size_t @var{block_size}, uint8_t *@var{iv}, size_t @var{length}, uint8_t *@var{dst}, const uint8_t *@var{src})
+@deftypefunx {void} cfb_decrypt (const void *@var{ctx}, nettle_cipher_func *@var{f}, size_t @var{block_size}, uint8_t *@var{iv}, size_t @var{length}, uint8_t *@var{dst}, const uint8_t *@var{src})
+
+Applies the encryption or decryption function @var{f} in @acronym{CFB}
+mode. The final ciphertext block processed is copied into @var{iv}
+before returning, so that a large message can be processed by a sequence
+of calls to @code{cfb_encrypt}. Note that for @acronym{CFB} mode
+internally uses encryption only function and hence @var{f} should always
+be the encryption function for the underlying block cipher.
+
+When a message is encrypted using a sequence of calls to
+@code{cfb_encrypt}, all but the last call @emph{must} use a length that
+is a multiple of the block size.
+@end deftypefun
+
+Like for @acronym{CBC}, there are also a couple of helper macros.
+
+@deffn Macro CFB_CTX (@var{context_type}, @var{block_size})
+Expands to
+@example
+@{
+   context_type ctx;
+   uint8_t iv[block_size];
+@}
+@end example
+@end deffn
+
+@deffn Macro CFB_SET_IV(@var{ctx}, @var{iv})
+First argument is a pointer to a context struct as defined by
+@code{CFB_CTX}, and the second is a pointer to an initialization vector
+that is copied into that context.
+@end deffn
+
+@deffn Macro CFB_ENCRYPT (@var{ctx}, @var{f}, @var{length}, @var{dst}, @var{src})
+A simpler way to invoke @code{cfb_encrypt}. The first argument is a
+pointer to a context struct as defined by @code{CFB_CTX}, and the second
+argument is an encryption function following Nettle's conventions. The
+last three arguments define the source and destination area for the
+operation.
+@end deffn
+
+@deffn Macro CFB_DECRYPT (@var{ctx}, @var{f}, @var{length}, @var{dst}, @var{src})
+A simpler way to invoke @code{cfb_decrypt}. The first argument is a
+pointer to a context struct as defined by @code{CFB_CTX}, and the second
+argument is an encryption function following Nettle's conventions. The
+last three arguments define the source and destination area for the
+operation.
+@end deffn
+
 @node Authenticated encryption, Keyed hash functions, Cipher modes, Reference
 @comment  node-name,  next,  previous,  up
 
@@ -3366,12 +3454,7 @@ processing a new message.
 @node Key derivation functions, Public-key algorithms, Keyed hash functions, Reference
 @comment  node-name,  next,  previous,  up
 @section Key derivation Functions
-
 @cindex Key Derivation Function
-@cindex Password Based Key Derivation Function
-@cindex PKCS #5
-@cindex KDF
-@cindex PBKDF
 
 A @dfn{key derivation function} (@acronym{KDF}) is a function that from
 a given symmetric key derives other symmetric keys.  A sub-class of KDFs
@@ -3380,7 +3463,51 @@ which take as input a password or passphrase, and its purpose is
 typically to strengthen it and protect against certain pre-computation
 attacks by using salting and expensive computation.
 
+@subsection HKDF: HMAC-based Extract-and-Expand
+@cindex HKDF
+
+HKDF is a key derivation function used as a building block of
+higher-level protocols like TLS 1.3. It is a derivation function
+based on HMAC described in @cite{RFC 5869},
+and is split into two logical modules, called 'extract' and 'expand'.
+The extract module takes an initial secret and a random
+salt to "extract" a fixed-length pseudorandom key (PRK). The second stage
+takes as input the previous PRK and some informational data (e.g.,
+text) and expands them into multiple keys.
+
+Nettle's @acronym{HKDF} functions are defined in
+@file{<nettle/hkdf.h>}.  There are two abstract functions for the extract
+and expand operations that operate on any HMAC implemented via the @code{nettle_hash_update_func},
+and @code{nettle_hash_digest_func} interfaces.
+
+@deftypefun void hkdf_extract (void *mac_ctx, nettle_hash_update_func *update, nettle_hash_digest_func *digest, size_t digest_size,size_t secret_size, const uint8_t *secret, uint8_t *dst)
+Extract a Pseudorandom Key (PRK) from a secret and a salt according
+to HKDF. The HMAC must have been initialized, with its key being the
+salt for the Extract operation. This function will call the
+@var{update} and @var{digest} functions passing the @var{mac_ctx}
+context parameter as an argument in order to compute digest of size
+@var{digest_size}.  Inputs are the secret @var{secret} of length
+@var{secret_length}. The output length is fixed to @var{digest_size} octets,
+thus the output buffer @var{dst} must have room for at least @var{digest_size} octets.
+@end deftypefun
+
+@deftypefun void hkdf_expand (void *mac_ctx, nettle_hash_update_func *update, nettle_hash_digest_func *digest, size_t digest_size, size_t info_size, const uint8_t *info, size_t length, uint8_t *dst)
+Expand a Pseudorandom Key (PRK) to an arbitrary size according to HKDF.
+The HMAC must have been initialized, with its key being the
+PRK from the Extract operation. This function will call the
+@var{update} and @var{digest} functions passing the @var{mac_ctx}
+context parameter as an argument in order to compute digest of size
+@var{digest_size}.  Inputs are the info @var{info} of length
+@var{info_length}, and the desired derived output length @var{length}.
+The output buffer is @var{dst} which must have room for at least @var{length} octets.
+@end deftypefun
+
+
 @subsection @acronym{PBKDF2}
+@cindex Password Based Key Derivation Function
+@cindex PKCS #5
+@cindex KDF
+@cindex PBKDF
 The most well known PBKDF is the @code{PKCS #5 PBKDF2} described in
 @cite{RFC 2898} which uses a pseudo-random function such as
 @acronym{HMAC-SHA1}.
@@ -3770,6 +3897,43 @@ of the digest together with an object identifier for the used hash
 algorithm.
 @end deftypefun
 
+While the above functions for the RSA signature operations use the
+@cite{PKCS#1} padding scheme, Nettle also provides the variants based on
+the PSS padding scheme, specified in @cite{RFC 3447}.  These variants
+take advantage of a randomly choosen salt value, which could enhance the
+security by causing output to be different for equivalent inputs.
+However, assuming the same security level as inverting the @acronym{RSA}
+algorithm, a longer salt value does not always mean a better security
+@uref{http://www.iacr.org/archive/eurocrypt2002/23320268/coron.pdf}.
+The typical choices of the length are between 0 and the digest size of
+the underlying hash function.
+
+Creating an RSA signature with the PSS padding scheme is done with one
+of the following functions:
+
+@deftypefun int rsa_pss_sha256_sign_digest_tr(const struct rsa_public_key *@var{pub}, const struct rsa_private_key *@var{key}, void *@var{random_ctx}, nettle_random_func *@var{random}, size_t @var{salt_length}, const uint8_t *@var{salt}, const uint8_t *@var{digest}, mpz_t @var{signature})
+@deftypefunx int rsa_pss_sha384_sign_digest_tr(const struct rsa_public_key *@var{pub}, const struct rsa_private_key *@var{key}, void *@var{random_ctx}, nettle_random_func *@var{random}, size_t @var{salt_length}, const uint8_t *@var{salt}, const uint8_t *@var{digest}, mpz_t @var{signature})
+@deftypefunx int rsa_pss_sha512_sign_digest_tr(const struct rsa_public_key *@var{pub}, const struct rsa_private_key *@var{key}, void *@var{random_ctx}, nettle_random_func *@var{random}, size_t @var{salt_length}, const uint8_t *@var{salt}, const uint8_t *@var{digest}, mpz_t @var{signature})
+Creates a signature using the PSS padding scheme. @var{salt} should
+point to a salt string of size @var{salt_length}. @var{digest} should
+point to a digest of size @code{SHA256_DIGEST_SIZE},
+@code{SHA384_DIGEST_SIZE}, or @code{SHA512_DIGEST_SIZE}respectively. The
+signature is stored in @var{signature} (which must have been
+@code{mpz_init}:ed earlier).
+Returns one on success, or zero on failure.
+@end deftypefun
+
+Verifying an RSA signature with the PSS padding scheme is done with one
+of the following functions:
+
+@deftypefun int rsa_pss_sha256_verify_digest (const struct rsa_public_key *@var{key}, size_t @var{salt_length}, const uint8_t *@var{digest}, const mpz_t @var{signature})
+@deftypefunx int rsa_pss_sha384_verify_digest (const struct rsa_public_key *@var{key}, size_t @var{salt_length}, const uint8_t *@var{digest}, const mpz_t @var{signature})
+@deftypefunx int rsa_pss_sha512_verify_digest (const struct rsa_public_key *@var{key}, size_t @var{salt_length}, const uint8_t *@var{digest}, const mpz_t @var{signature})
+Returns 1 if the signature is valid, or 0 if it isn't. @var{digest}
+should point to a digest of size @code{SHA256_DIGEST_SIZE},
+@code{SHA384_DIGEST_SIZE}, or @code{SHA512_DIGEST_SIZE} respectively.
+@end deftypefun
+
 The following function is used to encrypt a clear text message using RSA.
 @deftypefun int rsa_encrypt (const struct rsa_public_key *@var{key}, void *@var{random_ctx}, nettle_random_func *@var{random}, size_t @var{length}, const uint8_t *@var{cleartext}, mpz_t @var{ciphertext})
 Returns 1 on success, 0 on failure. If the message is too long then this
diff --git a/pgp-encode.c b/pgp-encode.c
index fc78e7f66302c29f8180da91ddbad81c663f2b9a..c051f9e44e15cbc3c61a5377eb88b4f70b77e344 100644
--- a/pgp-encode.c
+++ b/pgp-encode.c
@@ -371,8 +371,8 @@ pgp_armor(struct nettle_buffer *buffer,
        length -= BINARY_PER_LINE, data += BINARY_PER_LINE)
     {
       unsigned done;
-      uint8_t *p
-	= nettle_buffer_space(buffer, TEXT_PER_LINE);
+      char *p
+	= (char *) nettle_buffer_space(buffer, TEXT_PER_LINE);
       
       if (!p)
 	return 0;
@@ -393,8 +393,8 @@ pgp_armor(struct nettle_buffer *buffer,
 	+ BASE64_ENCODE_FINAL_LENGTH;
       unsigned done;
       
-      uint8_t *p
-	= nettle_buffer_space(buffer, text_size);
+      char *p
+	= (char *) nettle_buffer_space(buffer, text_size);
       if (!p)
 	return 0;
 
@@ -412,7 +412,7 @@ pgp_armor(struct nettle_buffer *buffer,
     return 0;
 
   {
-    uint8_t *p = nettle_buffer_space(buffer, 4);
+    char *p = (char *) nettle_buffer_space(buffer, 4);
     if (!p)
       return 0;
     base64_encode_group(p, crc);
diff --git a/pss-mgf1.c b/pss-mgf1.c
new file mode 100644
index 0000000000000000000000000000000000000000..67df5570f2c6d789966869366fdcaf39dcd86a55
--- /dev/null
+++ b/pss-mgf1.c
@@ -0,0 +1,73 @@
+/* pss-mgf1.c
+
+   PKCS#1 mask generation function 1, used in RSA-PSS (RFC-3447).
+
+   Copyright (C) 2017 Daiki Ueno
+
+   This file is part of GNU Nettle.
+
+   GNU Nettle is free software: you can redistribute it and/or
+   modify it under the terms of either:
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at your
+       option) any later version.
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at your
+       option) any later version.
+
+   or both in parallel, as here.
+
+   GNU Nettle is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see http://www.gnu.org/licenses/.
+*/
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "pss-mgf1.h"
+
+#include <assert.h>
+#include <string.h>
+
+#include "nettle-internal.h"
+#include "macros.h"
+
+void
+pss_mgf1(const void *seed, const struct nettle_hash *hash,
+	 size_t length, uint8_t *mask)
+{
+  TMP_DECL(h, uint8_t, NETTLE_MAX_HASH_DIGEST_SIZE);
+  TMP_DECL(state, uint8_t, NETTLE_MAX_HASH_CONTEXT_SIZE);
+  size_t i;
+  uint8_t c[4];
+
+  TMP_ALLOC(h, hash->digest_size);
+  TMP_ALLOC(state, hash->context_size);
+
+  for (i = 0;;
+       i++, mask += hash->digest_size, length -= hash->digest_size)
+    {
+      WRITE_UINT32(c, i);
+
+      memcpy(state, seed, hash->context_size);
+      hash->update(state, 4, c);
+
+      if (length <= hash->digest_size)
+	{
+	  hash->digest(state, length, mask);
+	  return;
+	}
+      hash->digest(state, hash->digest_size, mask);
+    }
+}
diff --git a/pss-mgf1.h b/pss-mgf1.h
new file mode 100644
index 0000000000000000000000000000000000000000..4a29c10811849907a4d998b825080213e7832ef9
--- /dev/null
+++ b/pss-mgf1.h
@@ -0,0 +1,58 @@
+/* pss-mgf1.h
+
+   PKCS#1 mask generation function 1, used in RSA-PSS (RFC-3447).
+
+   Copyright (C) 2017 Daiki Ueno
+
+   This file is part of GNU Nettle.
+
+   GNU Nettle is free software: you can redistribute it and/or
+   modify it under the terms of either:
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at your
+       option) any later version.
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at your
+       option) any later version.
+
+   or both in parallel, as here.
+
+   GNU Nettle is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see http://www.gnu.org/licenses/.
+*/
+
+#ifndef NETTLE_PSS_MGF1_H_INCLUDED
+#define NETTLE_PSS_MGF1_H_INCLUDED
+
+#include "nettle-meta.h"
+
+#include "sha1.h"
+#include "sha2.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/* Namespace mangling */
+#define pss_mgf1 nettle_pss_mgf1
+
+void
+pss_mgf1(const void *seed, const struct nettle_hash *hash,
+	 size_t length, uint8_t *mask);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* NETTLE_PSS_MGF1_H_INCLUDED */
diff --git a/pss.c b/pss.c
new file mode 100644
index 0000000000000000000000000000000000000000..88125c064ef1ea3727a4f5a570ec609f75dbdf9b
--- /dev/null
+++ b/pss.c
@@ -0,0 +1,198 @@
+/* pss.c
+
+   PKCS#1 RSA-PSS padding (RFC-3447).
+
+   Copyright (C) 2017 Daiki Ueno
+
+   This file is part of GNU Nettle.
+
+   GNU Nettle is free software: you can redistribute it and/or
+   modify it under the terms of either:
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at your
+       option) any later version.
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at your
+       option) any later version.
+
+   or both in parallel, as here.
+
+   GNU Nettle is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see http://www.gnu.org/licenses/.
+*/
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <assert.h>
+#include <string.h>
+
+#include "pss.h"
+#include "pss-mgf1.h"
+
+#include "bignum.h"
+#include "gmp-glue.h"
+
+#include "memxor.h"
+#include "nettle-internal.h"
+
+/* Masks to clear the leftmost N bits.  */
+static const uint8_t pss_masks[8] = {
+  0xFF, 0x7F, 0x3F, 0x1F, 0xF, 0x7, 0x3, 0x1
+};
+
+static const uint8_t pss_pad[8] = {0, 0, 0, 0, 0, 0, 0, 0};
+
+/* Format the PKCS#1 PSS padding for given salt and digest, using
+ * pss_mgf1() as the mask generation function.
+ *
+ * The encoded messsage is stored in M, and the consistency can be
+ * checked with pss_verify_mgf1(), which takes the encoded message,
+ * the length of salt, and the digest.  */
+int
+pss_encode_mgf1(mpz_t m, size_t bits,
+		const struct nettle_hash *hash,
+		size_t salt_length, const uint8_t *salt,
+		const uint8_t *digest)
+{
+  TMP_GMP_DECL(em, uint8_t);
+  TMP_DECL(state, uint8_t, NETTLE_MAX_HASH_CONTEXT_SIZE);
+  size_t key_size = (bits + 7) / 8;
+  size_t j;
+
+  TMP_GMP_ALLOC(em, key_size);
+  TMP_ALLOC(state, hash->context_size);
+
+  if (key_size < hash->digest_size + salt_length + 2)
+    {
+      TMP_GMP_FREE(em);
+      return 0;
+    }
+
+  /* Compute M'.  */
+  hash->init(state);
+  hash->update(state, sizeof(pss_pad), pss_pad);
+  hash->update(state, hash->digest_size, digest);
+  hash->update(state, salt_length, salt);
+
+  /* Store H in EM, right after maskedDB.  */
+  hash->digest(state, hash->digest_size, em + key_size - hash->digest_size - 1);
+
+  /* Compute dbMask.  */
+  hash->init(state);
+  hash->update(state, hash->digest_size, em + key_size - hash->digest_size - 1);
+
+  pss_mgf1(state, hash, key_size - hash->digest_size - 1, em);
+
+  /* Compute maskedDB and store it in front of H in EM.  */
+  j = key_size - salt_length - hash->digest_size - 2;
+
+  em[j++] ^= 1;
+  memxor(em + j, salt, salt_length);
+  j += salt_length;
+
+  /* Store the trailer field following H.  */
+  j += hash->digest_size;
+  em[j] = 0xbc;
+
+  /* Clear the leftmost 8 * emLen - emBits of the leftmost octet in EM.  */
+  *em &= pss_masks[(8 * key_size - bits)];
+
+  nettle_mpz_set_str_256_u(m, key_size, em);
+  TMP_GMP_FREE(em);
+  return 1;
+}
+
+/* Check the consistency of given PKCS#1 PSS encoded message, created
+ * with pss_encode_mgf1().
+ *
+ * Returns 1 if the encoded message is consistent, 0 if it is
+ * inconsistent.  */
+int
+pss_verify_mgf1(const mpz_t m, size_t bits,
+		const struct nettle_hash *hash,
+		size_t salt_length,
+		const uint8_t *digest)
+{
+  TMP_GMP_DECL(em, uint8_t);
+  TMP_DECL(h2, uint8_t, NETTLE_MAX_HASH_DIGEST_SIZE);
+  TMP_DECL(state, uint8_t, NETTLE_MAX_HASH_CONTEXT_SIZE);
+  uint8_t *h, *db, *salt;
+  size_t key_size = (bits + 7) / 8;
+  size_t j;
+  int ret = 0;
+
+  /* Allocate twice the key size to store the intermediate data DB
+   * following the EM value.  */
+  TMP_GMP_ALLOC(em, key_size * 2);
+
+  TMP_ALLOC(h2, hash->digest_size);
+  TMP_ALLOC(state, hash->context_size);
+
+  if (key_size < hash->digest_size + salt_length + 2)
+    goto cleanup;
+
+  if (mpz_sizeinbase(m, 2) > bits)
+    goto cleanup;
+
+  nettle_mpz_get_str_256(key_size, em, m);
+
+  /* Check the trailer field.  */
+  if (em[key_size - 1] != 0xbc)
+    goto cleanup;
+
+  /* Extract H.  */
+  h = em + (key_size - hash->digest_size - 1);
+
+  /* The leftmost 8 * emLen - emBits bits of the leftmost octet of EM
+   * must all equal to zero. Always true here, thanks to the above
+   * check on the bit size of m. */
+  assert((*em & ~pss_masks[(8 * key_size - bits)]) == 0);
+
+  /* Compute dbMask.  */
+  hash->init(state);
+  hash->update(state, hash->digest_size, h);
+
+  db = em + key_size;
+  pss_mgf1(state, hash, key_size - hash->digest_size - 1, db);
+
+  /* Compute DB.  */
+  memxor(db, em, key_size - hash->digest_size - 1);
+
+  *db &= pss_masks[(8 * key_size - bits)];
+  for (j = 0; j < key_size - salt_length - hash->digest_size - 2; j++)
+    if (db[j] != 0)
+      goto cleanup;
+
+  /* Check the octet right after PS is 0x1.  */
+  if (db[j] != 0x1)
+    goto cleanup;
+  salt = db + j + 1;
+
+  /* Compute H'.  */
+  hash->init(state);
+  hash->update(state, sizeof(pss_pad), pss_pad);
+  hash->update(state, hash->digest_size, digest);
+  hash->update(state, salt_length, salt);
+  hash->digest(state, hash->digest_size, h2);
+
+  /* Check if H' = H.  */
+  if (memcmp(h2, h, hash->digest_size) != 0)
+    goto cleanup;
+
+  ret = 1;
+ cleanup:
+  TMP_GMP_FREE(em);
+  return ret;
+}
diff --git a/pss.h b/pss.h
new file mode 100644
index 0000000000000000000000000000000000000000..7627cfe918fe8b27540ce54d49e33f7991b15e70
--- /dev/null
+++ b/pss.h
@@ -0,0 +1,65 @@
+/* pss.h
+
+   PKCS#1 RSA-PSS (RFC-3447).
+
+   Copyright (C) 2017 Daiki Ueno
+
+   This file is part of GNU Nettle.
+
+   GNU Nettle is free software: you can redistribute it and/or
+   modify it under the terms of either:
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at your
+       option) any later version.
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at your
+       option) any later version.
+
+   or both in parallel, as here.
+
+   GNU Nettle is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see http://www.gnu.org/licenses/.
+*/
+
+#ifndef NETTLE_PSS_H_INCLUDED
+#define NETTLE_PSS_H_INCLUDED
+
+#include "nettle-types.h"
+#include "bignum.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/* Namespace mangling */
+#define pss_encode_mgf1 nettle_pss_encode_mgf1
+#define pss_verify_mgf1 nettle_pss_verify_mgf1
+
+int
+pss_encode_mgf1(mpz_t m, size_t bits,
+		const struct nettle_hash *hash,
+		size_t salt_length, const uint8_t *salt,
+		const uint8_t *digest);
+
+int
+pss_verify_mgf1(const mpz_t m, size_t bits,
+		const struct nettle_hash *hash,
+		size_t salt_length,
+		const uint8_t *digest);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* NETTLE_PSS_H_INCLUDED */
diff --git a/rsa-pss-sha256-sign-tr.c b/rsa-pss-sha256-sign-tr.c
new file mode 100644
index 0000000000000000000000000000000000000000..b17e40ededa9a5c4e1c8c8a2ad931b499ed56688
--- /dev/null
+++ b/rsa-pss-sha256-sign-tr.c
@@ -0,0 +1,64 @@
+/* rsa-pss-sha256-sign-tr.c
+
+   Signatures using RSA and SHA-256, with PSS padding.
+
+   Copyright (C) 2017 Daiki Ueno
+
+   This file is part of GNU Nettle.
+
+   GNU Nettle is free software: you can redistribute it and/or
+   modify it under the terms of either:
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at your
+       option) any later version.
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at your
+       option) any later version.
+
+   or both in parallel, as here.
+
+   GNU Nettle is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see http://www.gnu.org/licenses/.
+*/
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "rsa.h"
+
+#include "bignum.h"
+#include "pss.h"
+
+int
+rsa_pss_sha256_sign_digest_tr(const struct rsa_public_key *pub,
+			      const struct rsa_private_key *key,
+			      void *random_ctx, nettle_random_func *random,
+			      size_t salt_length, const uint8_t *salt,
+			      const uint8_t *digest,
+			      mpz_t s)
+{
+  mpz_t m;
+  int res;
+
+  mpz_init (m);
+
+  res = (pss_encode_mgf1(m, mpz_sizeinbase(pub->n, 2) - 1, &nettle_sha256,
+			 salt_length, salt, digest)
+	 && rsa_compute_root_tr (pub, key,
+				 random_ctx, random,
+				 s, m));
+
+  mpz_clear (m);
+  return res;
+}
diff --git a/rsa-pss-sha256-verify.c b/rsa-pss-sha256-verify.c
new file mode 100644
index 0000000000000000000000000000000000000000..81bc4e68a986472b51b1b4b2f4d864b9338f53ec
--- /dev/null
+++ b/rsa-pss-sha256-verify.c
@@ -0,0 +1,60 @@
+/* rsa-pss-sha256-verify.c
+
+   Verifying signatures created with RSA and SHA-256, with PSS padding.
+
+   Copyright (C) 2017 Daiki Ueno
+
+   This file is part of GNU Nettle.
+
+   GNU Nettle is free software: you can redistribute it and/or
+   modify it under the terms of either:
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at your
+       option) any later version.
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at your
+       option) any later version.
+
+   or both in parallel, as here.
+
+   GNU Nettle is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see http://www.gnu.org/licenses/.
+*/
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "rsa.h"
+
+#include "bignum.h"
+#include "pss.h"
+
+int
+rsa_pss_sha256_verify_digest(const struct rsa_public_key *key,
+			     size_t salt_length,
+			     const uint8_t *digest,
+			     const mpz_t signature)
+{
+  int res;
+  mpz_t m;
+
+  mpz_init (m);
+
+  res = (_rsa_verify_recover(key, m, signature) &&
+	 pss_verify_mgf1(m, mpz_sizeinbase(key->n, 2) - 1, &nettle_sha256,
+			 salt_length, digest));
+
+  mpz_clear (m);
+  return res;
+}
diff --git a/rsa-pss-sha512-sign-tr.c b/rsa-pss-sha512-sign-tr.c
new file mode 100644
index 0000000000000000000000000000000000000000..59536d6dac1f2b976df69a13674528c5634a46ff
--- /dev/null
+++ b/rsa-pss-sha512-sign-tr.c
@@ -0,0 +1,87 @@
+/* rsa-pss-sha512-sign-tr.c
+
+   Signatures using RSA and SHA-384/SHA-512, with PSS padding.
+
+   Copyright (C) 2017 Daiki Ueno
+
+   This file is part of GNU Nettle.
+
+   GNU Nettle is free software: you can redistribute it and/or
+   modify it under the terms of either:
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at your
+       option) any later version.
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at your
+       option) any later version.
+
+   or both in parallel, as here.
+
+   GNU Nettle is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see http://www.gnu.org/licenses/.
+*/
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "rsa.h"
+
+#include "bignum.h"
+#include "pss.h"
+
+int
+rsa_pss_sha384_sign_digest_tr(const struct rsa_public_key *pub,
+			      const struct rsa_private_key *key,
+			      void *random_ctx, nettle_random_func *random,
+			      size_t salt_length, const uint8_t *salt,
+			      const uint8_t *digest,
+			      mpz_t s)
+{
+  mpz_t m;
+  int res;
+
+  mpz_init (m);
+
+  res = (pss_encode_mgf1(m, mpz_sizeinbase(pub->n, 2) - 1, &nettle_sha384,
+			 salt_length, salt, digest)
+	 && rsa_compute_root_tr (pub, key,
+				 random_ctx, random,
+				 s, m));
+
+  mpz_clear (m);
+  return res;
+}
+
+int
+rsa_pss_sha512_sign_digest_tr(const struct rsa_public_key *pub,
+			      const struct rsa_private_key *key,
+			      void *random_ctx, nettle_random_func *random,
+			      size_t salt_length, const uint8_t *salt,
+			      const uint8_t *digest,
+			      mpz_t s)
+{
+  mpz_t m;
+  int res;
+
+  mpz_init (m);
+
+  res = (pss_encode_mgf1(m, mpz_sizeinbase(pub->n, 2) - 1, &nettle_sha512,
+			 salt_length, salt, digest)
+	 && rsa_compute_root_tr (pub, key,
+				 random_ctx, random,
+				 s, m));
+
+  mpz_clear (m);
+  return res;
+}
diff --git a/rsa-pss-sha512-verify.c b/rsa-pss-sha512-verify.c
new file mode 100644
index 0000000000000000000000000000000000000000..34f8e81d1cc555be45ce9fb6e884fa6c24603ae6
--- /dev/null
+++ b/rsa-pss-sha512-verify.c
@@ -0,0 +1,79 @@
+/* rsa-pss-sha512-verify.c
+
+   Verifying signatures created with RSA and SHA-384/SHA-512, with PSS padding.
+
+   Copyright (C) 2017 Daiki Ueno
+
+   This file is part of GNU Nettle.
+
+   GNU Nettle is free software: you can redistribute it and/or
+   modify it under the terms of either:
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at your
+       option) any later version.
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at your
+       option) any later version.
+
+   or both in parallel, as here.
+
+   GNU Nettle is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see http://www.gnu.org/licenses/.
+*/
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "rsa.h"
+
+#include "bignum.h"
+#include "pss.h"
+
+int
+rsa_pss_sha384_verify_digest(const struct rsa_public_key *key,
+			     size_t salt_length,
+			     const uint8_t *digest,
+			     const mpz_t signature)
+{
+  int res;
+  mpz_t m;
+
+  mpz_init (m);
+
+  res = (_rsa_verify_recover(key, m, signature) &&
+	 pss_verify_mgf1(m, mpz_sizeinbase(key->n, 2) - 1, &nettle_sha384,
+			 salt_length, digest));
+
+  mpz_clear (m);
+  return res;
+}
+
+int
+rsa_pss_sha512_verify_digest(const struct rsa_public_key *key,
+			     size_t salt_length,
+			     const uint8_t *digest,
+			     const mpz_t signature)
+{
+  int res;
+  mpz_t m;
+
+  mpz_init (m);
+
+  res = (_rsa_verify_recover(key, m, signature) &&
+	 pss_verify_mgf1(m, mpz_sizeinbase(key->n, 2) - 1, &nettle_sha512,
+			 salt_length, digest));
+
+  mpz_clear (m);
+  return res;
+}
diff --git a/rsa-verify.c b/rsa-verify.c
index 07715e2bf1ac3f3db32e4eeb970c5e540ee606ad..43a55d213d35b80d9ab55ac227dc726ccd89eb38 100644
--- a/rsa-verify.c
+++ b/rsa-verify.c
@@ -62,3 +62,17 @@ _rsa_verify(const struct rsa_public_key *key,
 
   return res;
 }
+
+int
+_rsa_verify_recover(const struct rsa_public_key *key,
+		    mpz_t m,
+		    const mpz_t s)
+{
+  if ( (mpz_sgn(s) <= 0)
+       || (mpz_cmp(s, key->n) >= 0) )
+    return 0;
+
+  mpz_powm(m, s, key->e, key->n);
+
+  return 1;
+}
diff --git a/rsa.h b/rsa.h
index 6d2574bc93a1dfd4046332e466beaa40c75a7042..2143fcd2ad6c04486bf978195e2fea7458583fd1 100644
--- a/rsa.h
+++ b/rsa.h
@@ -79,6 +79,12 @@ extern "C" {
 #define rsa_sha512_sign_digest nettle_rsa_sha512_sign_digest
 #define rsa_sha512_sign_digest_tr nettle_rsa_sha512_sign_digest_tr
 #define rsa_sha512_verify_digest nettle_rsa_sha512_verify_digest
+#define rsa_pss_sha256_sign_digest_tr nettle_rsa_pss_sha256_sign_digest_tr
+#define rsa_pss_sha256_verify_digest nettle_rsa_pss_sha256_verify_digest
+#define rsa_pss_sha384_sign_digest_tr nettle_rsa_pss_sha384_sign_digest_tr
+#define rsa_pss_sha384_verify_digest nettle_rsa_pss_sha384_verify_digest
+#define rsa_pss_sha512_sign_digest_tr nettle_rsa_pss_sha512_sign_digest_tr
+#define rsa_pss_sha512_verify_digest nettle_rsa_pss_sha512_verify_digest
 #define rsa_encrypt nettle_rsa_encrypt
 #define rsa_decrypt nettle_rsa_decrypt
 #define rsa_decrypt_tr nettle_rsa_decrypt_tr
@@ -93,6 +99,7 @@ extern "C" {
 #define rsa_keypair_from_der nettle_rsa_keypair_from_der
 #define rsa_keypair_to_openpgp nettle_rsa_keypair_to_openpgp
 #define _rsa_verify _nettle_rsa_verify
+#define _rsa_verify_recover _nettle_rsa_verify_recover
 #define _rsa_check_size _nettle_rsa_check_size
 #define _rsa_blind _nettle_rsa_blind
 #define _rsa_unblind _nettle_rsa_unblind
@@ -341,6 +348,49 @@ rsa_sha512_verify_digest(const struct rsa_public_key *key,
 			 const uint8_t *digest,
 			 const mpz_t signature);
 
+/* PSS style signatures */
+int
+rsa_pss_sha256_sign_digest_tr(const struct rsa_public_key *pub,
+			      const struct rsa_private_key *key,
+			      void *random_ctx, nettle_random_func *random,
+			      size_t salt_length, const uint8_t *salt,
+			      const uint8_t *digest,
+			      mpz_t s);
+
+int
+rsa_pss_sha256_verify_digest(const struct rsa_public_key *key,
+			     size_t salt_length,
+			     const uint8_t *digest,
+			     const mpz_t signature);
+
+int
+rsa_pss_sha384_sign_digest_tr(const struct rsa_public_key *pub,
+			      const struct rsa_private_key *key,
+			      void *random_ctx, nettle_random_func *random,
+			      size_t salt_length, const uint8_t *salt,
+			      const uint8_t *digest,
+			      mpz_t s);
+
+int
+rsa_pss_sha384_verify_digest(const struct rsa_public_key *key,
+			     size_t salt_length,
+			     const uint8_t *digest,
+			     const mpz_t signature);
+
+int
+rsa_pss_sha512_sign_digest_tr(const struct rsa_public_key *pub,
+			      const struct rsa_private_key *key,
+			      void *random_ctx, nettle_random_func *random,
+			      size_t salt_length, const uint8_t *salt,
+			      const uint8_t *digest,
+			      mpz_t s);
+
+int
+rsa_pss_sha512_verify_digest(const struct rsa_public_key *key,
+			     size_t salt_length,
+			     const uint8_t *digest,
+			     const mpz_t signature);
+
 
 /* RSA encryption, using PKCS#1 */
 /* These functions uses the v1.5 padding. What should the v2 (OAEP)
@@ -480,6 +530,11 @@ _rsa_verify(const struct rsa_public_key *key,
 	    const mpz_t m,
 	    const mpz_t s);
 
+int
+_rsa_verify_recover(const struct rsa_public_key *key,
+		    mpz_t m,
+		    const mpz_t s);
+
 size_t
 _rsa_check_size(mpz_t n);
 
diff --git a/sexp-transport-format.c b/sexp-transport-format.c
index c9946a70a85d34358162b9b10b351d77a1dc3921..4f83f8888c8abab42088da8a17f83e34696fdc0b 100644
--- a/sexp-transport-format.c
+++ b/sexp-transport-format.c
@@ -40,6 +40,12 @@
 #include "base64.h"
 #include "buffer.h"
 
+static inline void
+base64_encode_in_place (size_t length, uint8_t *data)
+{
+  base64_encode_raw ((char *) data, length, data);
+}
+
 size_t
 sexp_transport_vformat(struct nettle_buffer *buffer,
 		       const char *format, va_list args)
@@ -68,8 +74,7 @@ sexp_transport_vformat(struct nettle_buffer *buffer,
       if (!nettle_buffer_space(buffer, base64_length - length))
 	return 0;
 
-      base64_encode_raw(buffer->contents + start,
-			length, buffer->contents + start);
+      base64_encode_in_place(length, buffer->contents + start);
       
       if (!NETTLE_BUFFER_PUTC(buffer, '}'))
 	return 0;
diff --git a/sexp-transport.c b/sexp-transport.c
index 8736478a22b26e80c8cd8de075f6680595c4a298..1a34db7129b0d0ef251ddd5f1e9834c753e6546e 100644
--- a/sexp-transport.c
+++ b/sexp-transport.c
@@ -84,7 +84,7 @@ sexp_transport_iterator_first(struct sexp_iterator *iterator,
 	  base64_decode_init(&ctx);
 	  
 	  if (base64_decode_update(&ctx, &coded_length, input + out,
-				   end - in, input + in)
+				   end - in, (const char*) (input + in))
 	      && base64_decode_final(&ctx))
 	    {	  
 	      out += coded_length;
diff --git a/testsuite/.gitignore b/testsuite/.gitignore
index 8e5521b42978a165975190eb14d368c38c1673e7..5db4e789eb02f8ffe25414ff1cd50bafe2785658 100644
--- a/testsuite/.gitignore
+++ b/testsuite/.gitignore
@@ -12,39 +12,61 @@
 /cast128-test
 /cbc-test
 /ccm-test
+/cfb-test
+/chacha-poly1305-test
+/chacha-test
 /ctr-test
+/curve25519-dh-test
 /cxx-test
 /des-compat-test
 /des-test
 /des3-test
+/dlopen-test
 /dsa-keygen-test
 /dsa-test
+/eax-test
+/ecc-add-test
+/ecc-dup-test
 /ecc-mod-test
 /ecc-modinv-test
 /ecc-mul-a-test
 /ecc-mul-g-test
 /ecc-redc-test
+/ecc-sqrt-test
+/ecdh-test
 /ecdsa-keygen-test
 /ecdsa-sign-test
 /ecdsa-verify-test
+/ed25519-test
+/eddsa-compress-test
+/eddsa-sign-test
+/eddsa-verify-test
 /gcm-test
 /gosthash94-test
+/hkdf-test
 /hmac-test
 /knuth-lfib-test
 /md2-test
 /md4-test
 /md5-compat-test
 /md5-test
+/memeql-test
 /memxor-test
+/meta-aead-test
 /meta-armor-test
 /meta-cipher-test
 /meta-hash-test
 /pbkdf2-test
 /pkcs1-test
+/poly1305-test
+/pss-mgf1-test
+/pss-test
 /random-prime-test
 /ripemd160-test
 /rsa-encrypt-test
 /rsa-keygen-test
+/rsa-pss-sign-tr-test
+/rsa-sign-tr-test
 /rsa-test
 /rsa2sexp-test
 /salsa20-test
@@ -62,9 +84,12 @@
 /sha3-512-test
 /sha3-permute-test
 /sha384-test
+/sha512-224-test
+/sha512-256-test
 /sha512-test
 /twofish-test
 /umac-test
+/version-test
 /yarrow-test
 
 /test.in
diff --git a/testsuite/.test-rules.make b/testsuite/.test-rules.make
index b263e1fdd40e999ed81fa1db9dde8130571a114f..1f78031031042abfc5395aa330d95f1bd571eb17 100644
--- a/testsuite/.test-rules.make
+++ b/testsuite/.test-rules.make
@@ -58,6 +58,9 @@ gosthash94-test$(EXEEXT): gosthash94-test.$(OBJEXT)
 ripemd160-test$(EXEEXT): ripemd160-test.$(OBJEXT)
 	$(LINK) ripemd160-test.$(OBJEXT) $(TEST_OBJS) -o ripemd160-test$(EXEEXT)
 
+hkdf-test$(EXEEXT): hkdf-test.$(OBJEXT)
+	$(LINK) hkdf-test.$(OBJEXT) $(TEST_OBJS) -o hkdf-test$(EXEEXT)
+
 salsa20-test$(EXEEXT): salsa20-test.$(OBJEXT)
 	$(LINK) salsa20-test.$(OBJEXT) $(TEST_OBJS) -o salsa20-test$(EXEEXT)
 
@@ -112,6 +115,9 @@ knuth-lfib-test$(EXEEXT): knuth-lfib-test.$(OBJEXT)
 cbc-test$(EXEEXT): cbc-test.$(OBJEXT)
 	$(LINK) cbc-test.$(OBJEXT) $(TEST_OBJS) -o cbc-test$(EXEEXT)
 
+cfb-test$(EXEEXT): cfb-test.$(OBJEXT)
+	$(LINK) cfb-test.$(OBJEXT) $(TEST_OBJS) -o cfb-test$(EXEEXT)
+
 ctr-test$(EXEEXT): ctr-test.$(OBJEXT)
 	$(LINK) ctr-test.$(OBJEXT) $(TEST_OBJS) -o ctr-test$(EXEEXT)
 
@@ -157,6 +163,9 @@ yarrow-test$(EXEEXT): yarrow-test.$(OBJEXT)
 pbkdf2-test$(EXEEXT): pbkdf2-test.$(OBJEXT)
 	$(LINK) pbkdf2-test.$(OBJEXT) $(TEST_OBJS) -o pbkdf2-test$(EXEEXT)
 
+pss-mgf1-test$(EXEEXT): pss-mgf1-test.$(OBJEXT)
+	$(LINK) pss-mgf1-test.$(OBJEXT) $(TEST_OBJS) -o pss-mgf1-test$(EXEEXT)
+
 sexp-test$(EXEEXT): sexp-test.$(OBJEXT)
 	$(LINK) sexp-test.$(OBJEXT) $(TEST_OBJS) -o sexp-test$(EXEEXT)
 
@@ -178,9 +187,15 @@ random-prime-test$(EXEEXT): random-prime-test.$(OBJEXT)
 pkcs1-test$(EXEEXT): pkcs1-test.$(OBJEXT)
 	$(LINK) pkcs1-test.$(OBJEXT) $(TEST_OBJS) -o pkcs1-test$(EXEEXT)
 
+pss-test$(EXEEXT): pss-test.$(OBJEXT)
+	$(LINK) pss-test.$(OBJEXT) $(TEST_OBJS) -o pss-test$(EXEEXT)
+
 rsa-sign-tr-test$(EXEEXT): rsa-sign-tr-test.$(OBJEXT)
 	$(LINK) rsa-sign-tr-test.$(OBJEXT) $(TEST_OBJS) -o rsa-sign-tr-test$(EXEEXT)
 
+rsa-pss-sign-tr-test$(EXEEXT): rsa-pss-sign-tr-test.$(OBJEXT)
+	$(LINK) rsa-pss-sign-tr-test.$(OBJEXT) $(TEST_OBJS) -o rsa-pss-sign-tr-test$(EXEEXT)
+
 rsa-test$(EXEEXT): rsa-test.$(OBJEXT)
 	$(LINK) rsa-test.$(OBJEXT) $(TEST_OBJS) -o rsa-test$(EXEEXT)
 
diff --git a/testsuite/Makefile.in b/testsuite/Makefile.in
index 790b3c78eedf644be3bfd3c1c3adbafe0daba83d..3117d66def795717733a775482c9c6642418be2d 100644
--- a/testsuite/Makefile.in
+++ b/testsuite/Makefile.in
@@ -17,7 +17,7 @@ TS_NETTLE_SOURCES = aes-test.c arcfour-test.c arctwo-test.c \
 		    des-test.c des3-test.c des-compat-test.c \
 		    md2-test.c md4-test.c md5-test.c md5-compat-test.c \
 		    memeql-test.c memxor-test.c gosthash94-test.c \
-		    ripemd160-test.c \
+		    ripemd160-test.c hkdf-test.c \
 		    salsa20-test.c \
 		    sha1-test.c sha224-test.c sha256-test.c \
 		    sha384-test.c sha512-test.c sha512-224-test.c sha512-256-test.c \
@@ -25,17 +25,18 @@ TS_NETTLE_SOURCES = aes-test.c arcfour-test.c arctwo-test.c \
 		    sha3-384-test.c sha3-512-test.c \
 		    serpent-test.c twofish-test.c version-test.c \
 		    knuth-lfib-test.c \
-		    cbc-test.c ctr-test.c gcm-test.c eax-test.c ccm-test.c \
+		    cbc-test.c cfb-test.c ctr-test.c gcm-test.c eax-test.c ccm-test.c \
 		    poly1305-test.c chacha-poly1305-test.c \
 		    hmac-test.c umac-test.c \
 		    meta-hash-test.c meta-cipher-test.c\
 		    meta-aead-test.c meta-armor-test.c \
-		    buffer-test.c yarrow-test.c pbkdf2-test.c
+		    buffer-test.c yarrow-test.c pbkdf2-test.c pss-mgf1-test.c
 
 TS_HOGWEED_SOURCES = sexp-test.c sexp-format-test.c \
 		     rsa2sexp-test.c sexp2rsa-test.c \
 		     bignum-test.c random-prime-test.c \
-		     pkcs1-test.c rsa-sign-tr-test.c \
+		     pkcs1-test.c pss-test.c rsa-sign-tr-test.c \
+		     rsa-pss-sign-tr-test.c \
 		     rsa-test.c rsa-encrypt-test.c rsa-keygen-test.c \
 		     dsa-test.c dsa-keygen-test.c \
 		     curve25519-dh-test.c \
@@ -66,6 +67,7 @@ EXTRA_TARGETS = $(EXTRA_SOURCES:.c=$(EXEEXT))
 SOURCES = $(TS_SOURCES) $(EXTRA_SOURCES) testutils.c dlopen-test.c
 
 DISTFILES = $(SOURCES) $(CXX_SOURCES) Makefile.in .test-rules.make \
+	    test-rules.stamp \
 	    $(TS_SH) setup-env teardown-env \
 	    gold-bug.txt testutils.h sha3.awk
 
@@ -107,6 +109,14 @@ test-rules:
 	  echo ; \
 	done) > $(srcdir)/.test-rules.make
 
+$(srcdir)/.test-rules.make: $(srcdir)/test-rules.stamp
+
+# Updates the stamp file *first*, so that this rule isn't triggered
+# again and again by the recursive $(MAKE).
+$(srcdir)/test-rules.stamp: Makefile.in
+	echo stamp > $(srcdir)/test-rules.stamp
+	$(MAKE) test-rules
+
 include $(srcdir)/.test-rules.make
 
 $(TARGETS) $(EXTRA_TARGETS): testutils.$(OBJEXT) ../nettle-internal.$(OBJEXT) \
diff --git a/testsuite/base64-test.c b/testsuite/base64-test.c
index f366a413843731a19916e1d9121831e2f993e809..cc45c471459ceda266938ecddc901ef36153bb7d 100644
--- a/testsuite/base64-test.c
+++ b/testsuite/base64-test.c
@@ -9,7 +9,7 @@ test_fuzz_once(struct base64_encode_ctx *encode,
 {
   size_t base64_len = BASE64_ENCODE_RAW_LENGTH (size);
   size_t out_len;
-  uint8_t *base64 = xalloc (base64_len + 2);
+  char *base64 = xalloc (base64_len + 2);
   uint8_t *decoded = xalloc (size + 2);
 
   *base64++ = 0x12;
@@ -66,6 +66,20 @@ test_fuzz(void)
     }
 }
 
+static inline void
+base64_encode_in_place (size_t length, uint8_t *data)
+{
+  base64_encode_raw ((char *) data, length, data);
+}
+
+static inline int
+base64_decode_in_place (struct base64_decode_ctx *ctx, size_t *dst_length,
+			size_t length, uint8_t *data)
+{
+  return base64_decode_update (ctx, dst_length,
+			       data, length, (const char *) data);
+}
+
 void
 test_main(void)
 {
@@ -111,12 +125,12 @@ test_main(void)
     size_t dst_length;
     
     ASSERT(BASE64_ENCODE_RAW_LENGTH(5) == 8);
-    base64_encode_raw(buffer, 5, buffer);
+    base64_encode_in_place(5, buffer);
     ASSERT(MEMEQ(9, buffer, "SGVsbG8=x"));
 
     base64_decode_init(&ctx);
     dst_length = 0; /* Output parameter only. */
-    ASSERT(base64_decode_update(&ctx, &dst_length, buffer, 8, buffer));
+    ASSERT(base64_decode_in_place(&ctx, &dst_length, 8, buffer));
     ASSERT(dst_length == 5);
     
     ASSERT(MEMEQ(9, buffer, "HelloG8=x"));
diff --git a/testsuite/cfb-test.c b/testsuite/cfb-test.c
new file mode 100644
index 0000000000000000000000000000000000000000..b59bee225bf87d03fe7bfa05256ee2c651eb1a24
--- /dev/null
+++ b/testsuite/cfb-test.c
@@ -0,0 +1,287 @@
+#include "testutils.h"
+#include "aes.h"
+#include "cfb.h"
+#include "knuth-lfib.h"
+
+/* Test with more data and inplace decryption, to check that the
+ * cfb_decrypt buffering works. */
+#define CFB_BULK_DATA 10000
+
+static void
+test_cfb_bulk(void)
+{
+  struct knuth_lfib_ctx random;
+
+  uint8_t clear[CFB_BULK_DATA];
+
+  uint8_t cipher[CFB_BULK_DATA + 1];
+
+  const uint8_t *key = H("966c7bf00bebe6dc 8abd37912384958a"
+			 "743008105a08657d dcaad4128eee38b3");
+
+  const uint8_t *start_iv = H("11adbff119749103 207619cfa0e8d13a");
+  const uint8_t *end_iv = H("1fd0a9189b8480b7 b06a2b36ef5943ba");
+
+  struct CFB_CTX(struct aes_ctx, AES_BLOCK_SIZE) aes;
+
+  knuth_lfib_init(&random, CFB_BULK_DATA);
+  knuth_lfib_random(&random, CFB_BULK_DATA, clear);
+
+  /* Byte that should not be overwritten */
+  cipher[CFB_BULK_DATA] = 17;
+
+  aes_set_encrypt_key(&aes.ctx, 32, key);
+  CFB_SET_IV(&aes, start_iv);
+
+  CFB_ENCRYPT(&aes, aes_encrypt, CFB_BULK_DATA, cipher, clear);
+
+  ASSERT(cipher[CFB_BULK_DATA] == 17);
+
+  if (verbose)
+    {
+      printf("IV after bulk encryption: ");
+      print_hex(AES_BLOCK_SIZE, aes.iv);
+      printf("\n");
+    }
+
+  ASSERT(MEMEQ(AES_BLOCK_SIZE, aes.iv, end_iv));
+
+  /* Decrypt, in place */
+  aes_set_encrypt_key(&aes.ctx, 32, key);
+  CFB_SET_IV(&aes, start_iv);
+  CFB_DECRYPT(&aes, aes_encrypt, CFB_BULK_DATA, cipher, cipher);
+
+  ASSERT(cipher[CFB_BULK_DATA] == 17);
+
+  if (verbose)
+    {
+      printf("IV after bulk decryption: ");
+      print_hex(AES_BLOCK_SIZE, aes.iv);
+      printf("\n");
+    }
+
+  ASSERT (MEMEQ(AES_BLOCK_SIZE, aes.iv, end_iv));
+  ASSERT (MEMEQ(CFB_BULK_DATA, clear, cipher));
+}
+
+void
+test_main(void)
+{
+  /* From NIST spec 800-38a on AES modes.
+   *
+   * F.3  CFB Example Vectors
+   * F.3.13 CFB128-AES128.Encrypt
+   */
+
+  /* Intermediate values, blocks input to AES:
+   *
+   *   000102030405060708090a0b0c0d0e0f
+   *   3b3fd92eb72dad20333449f8e83cfb4a
+   *   c8a64537a0b3a93fcde3cdad9f1ce58b
+   *   26751f67a3cbb140b1808cf187a4f4df
+   */
+  test_cipher_cfb(&nettle_aes128,
+		  SHEX("2b7e151628aed2a6abf7158809cf4f3c"),
+		  SHEX("6bc1bee22e409f96e93d7e117393172a"
+		       "ae2d8a571e03ac9c9eb76fac45af8e51"
+		       "30c81c46a35ce411e5fbc1191a0a52ef"
+		       "f69f2445df4f9b17ad2b417be66c3710"),
+		  SHEX("3b3fd92eb72dad20333449f8e83cfb4a"
+		       "c8a64537a0b3a93fcde3cdad9f1ce58b"
+		       "26751f67a3cbb140b1808cf187a4f4df"
+		       "c04b05357c5d1c0eeac4c66f9ff7f2e6"),
+		  SHEX("000102030405060708090a0b0c0d0e0f"));
+
+  /* F.3.15 CFB128-AES192.Encrypt */
+
+  /* Intermediate values, blocks input to AES:
+   *
+   *   000102030405060708090a0b0c0d0e0f
+   *   cdc80d6fddf18cab34c25909c99a4174
+   *   67ce7f7f81173621961a2b70171d3d7a
+   *   2e1e8a1dd59b88b1c8e60fed1efac4c9
+   */
+
+  test_cipher_cfb(&nettle_aes192,
+		  SHEX("8e73b0f7da0e6452c810f32b809079e5"
+		       "62f8ead2522c6b7b"),
+		  SHEX("6bc1bee22e409f96e93d7e117393172a"
+		       "ae2d8a571e03ac9c9eb76fac45af8e51"
+		       "30c81c46a35ce411e5fbc1191a0a52ef"
+		       "f69f2445df4f9b17ad2b417be66c3710"),
+		  SHEX("cdc80d6fddf18cab34c25909c99a4174"
+		       "67ce7f7f81173621961a2b70171d3d7a"
+		       "2e1e8a1dd59b88b1c8e60fed1efac4c9"
+		       "c05f9f9ca9834fa042ae8fba584b09ff"),
+		  SHEX("000102030405060708090a0b0c0d0e0f"));
+
+  /* F.3.17 CFB128-AES256.Encrypt */
+
+  /* Intermediate values, blcoks input to AES:
+   *
+   *   000102030405060708090a0b0c0d0e0f
+   *   dc7e84bfda79164b7ecd8486985d3860
+   *   39ffed143b28b1c832113c6331e5407b
+   *   df10132415e54b92a13ed0a8267ae2f9
+   */
+
+  test_cipher_cfb(&nettle_aes256,
+		  SHEX("603deb1015ca71be2b73aef0857d7781"
+		       "1f352c073b6108d72d9810a30914dff4"),
+		  SHEX("6bc1bee22e409f96e93d7e117393172a"
+		       "ae2d8a571e03ac9c9eb76fac45af8e51"
+		       "30c81c46a35ce411e5fbc1191a0a52ef"
+		       "f69f2445df4f9b17ad2b417be66c3710"),
+		  SHEX("dc7e84bfda79164b7ecd8486985d3860"
+		       "39ffed143b28b1c832113c6331e5407b"
+		       "df10132415e54b92a13ed0a8267ae2f9"
+		       "75a385741ab9cef82031623d55b1e471"),
+		  SHEX("000102030405060708090a0b0c0d0e0f"));
+
+  test_cfb_bulk();
+}
+
+/*
+F.3.13 CFB128-AES128.Encrypt
+Key 2b7e151628aed2a6abf7158809cf4f3c
+IV 000102030405060708090a0b0c0d0e0f
+Segment #1
+Input Block 000102030405060708090a0b0c0d0e0f
+Output Block 50fe67cc996d32b6da0937e99bafec60
+Plaintext 6bc1bee22e409f96e93d7e117393172a
+Ciphertext 3b3fd92eb72dad20333449f8e83cfb4a
+Segment #2
+Input Block 3b3fd92eb72dad20333449f8e83cfb4a
+Output Block 668bcf60beb005a35354a201dab36bda
+Plaintext ae2d8a571e03ac9c9eb76fac45af8e51
+Ciphertext c8a64537a0b3a93fcde3cdad9f1ce58b
+Segment #3
+Input Block c8a64537a0b3a93fcde3cdad9f1ce58b
+Output Block 16bd032100975551547b4de89daea630
+Plaintext 30c81c46a35ce411e5fbc1191a0a52ef
+Ciphertext 26751f67a3cbb140b1808cf187a4f4df
+Segment #4
+Input Block 26751f67a3cbb140b1808cf187a4f4df
+Output Block 36d42170a312871947ef8714799bc5f6
+Plaintext f69f2445df4f9b17ad2b417be66c3710
+Ciphertext c04b05357c5d1c0eeac4c66f9ff7f2e6
+F.3.14 CFB128-AES128.Decrypt
+Key 2b7e151628aed2a6abf7158809cf4f3c
+IV 000102030405060708090a0b0c0d0e0f
+Segment #1
+Input Block 000102030405060708090a0b0c0d0e0f
+Output Block 50fe67cc996d32b6da0937e99bafec60
+Ciphertext 3b3fd92eb72dad20333449f8e83cfb4a
+Plaintext 6bc1bee22e409f96e93d7e117393172a
+Segment #2
+Input Block 3b3fd92eb72dad20333449f8e83cfb4a
+Output Block 668bcf60beb005a35354a201dab36bda
+Ciphertext c8a64537a0b3a93fcde3cdad9f1ce58b
+Plaintext ae2d8a571e03ac9c9eb76fac45af8e51
+Segment #3
+Input Block c8a64537a0b3a93fcde3cdad9f1ce58b
+Output Block 16bd032100975551547b4de89daea630
+Ciphertext 26751f67a3cbb140b1808cf187a4f4df
+Plaintext 30c81c46a35ce411e5fbc1191a0a52ef
+Segment #4
+Input Block 26751f67a3cbb140b1808cf187a4f4df
+Output Block 36d42170a312871947ef8714799bc5f6
+Ciphertext c04b05357c5d1c0eeac4c66f9ff7f2e6
+Plaintext f69f2445df4f9b17ad2b417be66c3710
+F.3.15 CFB128-AES192.Encrypt
+Key 	 8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b
+000102030405060708090a0b0c0d0e0f
+Segment #1
+50
+IV
+Input Block 000102030405060708090a0b0c0d0e0f
+Output Block a609b38df3b1133dddff2718ba09565e
+Plaintext 6bc1bee22e409f96e93d7e117393172a
+Ciphertext cdc80d6fddf18cab34c25909c99a4174
+Segment #2
+Input Block cdc80d6fddf18cab34c25909c99a4174
+Output Block c9e3f5289f149abd08ad44dc52b2b32b
+Plaintext ae2d8a571e03ac9c9eb76fac45af8e51
+Ciphertext 67ce7f7f81173621961a2b70171d3d7a
+Segment #3
+Input Block 67ce7f7f81173621961a2b70171d3d7a
+Output Block 1ed6965b76c76ca02d1dcef404f09626
+Plaintext 30c81c46a35ce411e5fbc1191a0a52ef
+Ciphertext 2e1e8a1dd59b88b1c8e60fed1efac4c9
+Segment #4
+Input Block 2e1e8a1dd59b88b1c8e60fed1efac4c9
+Output Block 36c0bbd976ccd4b7ef85cec1be273eef
+Plaintext f69f2445df4f9b17ad2b417be66c3710
+Ciphertext c05f9f9ca9834fa042ae8fba584b09ff
+F.3.16 CFB128-AES192.Decrypt
+Key 8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b
+IV 000102030405060708090a0b0c0d0e0f
+Segment #1
+Input Block 000102030405060708090a0b0c0d0e0f
+Output Block a609b38df3b1133dddff2718ba09565e
+Ciphertext cdc80d6fddf18cab34c25909c99a4174
+Plaintext 6bc1bee22e409f96e93d7e117393172a
+Segment #2
+Input Block cdc80d6fddf18cab34c25909c99a4174
+Output Block c9e3f5289f149abd08ad44dc52b2b32b
+Ciphertext 67ce7f7f81173621961a2b70171d3d7a
+Plaintext ae2d8a571e03ac9c9eb76fac45af8e51
+Segment #3
+Input Block 67ce7f7f81173621961a2b70171d3d7a
+Output Block 1ed6965b76c76ca02d1dcef404f09626
+Ciphertext 2e1e8a1dd59b88b1c8e60fed1efac4c9
+Plaintext 30c81c46a35ce411e5fbc1191a0a52ef
+Segment #4
+Input Block 2e1e8a1dd59b88b1c8e60fed1efac4c9
+Output Block 36c0bbd976ccd4b7ef85cec1be273eef
+Ciphertext c05f9f9ca9834fa042ae8fba584b09ff
+Plaintext f69f2445df4f9b17ad2b417be66c3710
+F.3.17 CFB128-AES256.Encrypt
+Key 603deb1015ca71be2b73aef0857d7781
+1f352c073b6108d72d9810a30914dff4
+IV 000102030405060708090a0b0c0d0e0f
+Segment #1
+Input Block 000102030405060708090a0b0c0d0e0f
+Output Block b7bf3a5df43989dd97f0fa97ebce2f4a
+Plaintext 6bc1bee22e409f96e93d7e117393172a
+Ciphertext dc7e84bfda79164b7ecd8486985d3860
+Segment #2
+Input Block dc7e84bfda79164b7ecd8486985d3860
+Output Block 97d26743252b1d54aca653cf744ace2a
+Plaintext ae2d8a571e03ac9c9eb76fac45af8e51
+Ciphertext 39ffed143b28b1c832113c6331e5407b
+Segment #3
+Input Block 39ffed143b28b1c832113c6331e5407b
+Output Block efd80f62b6b9af8344c511b13c70b016
+Plaintext 30c81c46a35ce411e5fbc1191a0a52ef
+Ciphertext df10132415e54b92a13ed0a8267ae2f9
+Segment #4
+Input Block df10132415e54b92a13ed0a8267ae2f9
+Output Block 833ca131c5f655ef8d1a2346b3ddd361
+Plaintext f69f2445df4f9b17ad2b417be66c3710
+Ciphertext 75a385741ab9cef82031623d55b1e471
+F.3.18 CFB128-AES256.Decrypt
+Key 603deb1015ca71be2b73aef0857d7781
+1f352c073b6108d72d9810a30914dff4
+IV 000102030405060708090a0b0c0d0e0f
+Segment #1
+Input Block 000102030405060708090a0b0c0d0e0f
+Output Block b7bf3a5df43989dd97f0fa97ebce2f4a
+Ciphertext dc7e84bfda79164b7ecd8486985d3860
+Plaintext 6bc1bee22e409f96e93d7e117393172a
+Segment #2
+Input Block dc7e84bfda79164b7ecd8486985d3860
+Output Block 97d26743252b1d54aca653cf744ace2a
+Ciphertext 39ffed143b28b1c832113c6331e5407b
+Plaintext ae2d8a571e03ac9c9eb76fac45af8e51
+Segment #3
+Input Block 39ffed143b28b1c832113c6331e5407b
+Output Block efd80f62b6b9af8344c511b13c70b016
+Ciphertext df10132415e54b92a13ed0a8267ae2f9
+Plaintext 30c81c46a35ce411e5fbc1191a0a52ef
+Segment #4
+Input Block df10132415e54b92a13ed0a8267ae2f9
+Output Block 833ca131c5f655ef8d1a2346b3ddd361
+Ciphertext 75a385741ab9cef82031623d55b1e471
+Plaintext f69f2445df4f9b17ad2b417be66c3710
+*/
diff --git a/testsuite/dlopen-test.c b/testsuite/dlopen-test.c
index 23ff25ade5a3f687759d47c9af79a5a07a6f955e..99d3535be16896a91d9864c75c9e550aeec322bd 100644
--- a/testsuite/dlopen-test.c
+++ b/testsuite/dlopen-test.c
@@ -28,6 +28,7 @@ main (int argc UNUSED, char **argv UNUSED)
       fprintf (stderr, "unexpected nettle version\n");
       FAIL ();
     }
+  dlclose (handle);
   return EXIT_SUCCESS;
 #else
   SKIP();
diff --git a/testsuite/ecc-mul-a-test.c b/testsuite/ecc-mul-a-test.c
index b206b8484e0a34c9ee5672d415c7c957ea161c35..245016aafc78085f99a2451abfeba5bcddac2023 100644
--- a/testsuite/ecc-mul-a-test.c
+++ b/testsuite/ecc-mul-a-test.c
@@ -26,7 +26,7 @@ test_main (void)
       ecc->mul (ecc, p, n, ecc->g, scratch);
       ecc->h_to_a (ecc, 0, p, p, scratch);
 
-      if (mpn_cmp (p, ecc->g, 2*size != 0))
+      if (mpn_cmp (p, ecc->g, 2*size) != 0)
 	die ("curve %d: ecc->mul with n = 1 failed.\n", ecc->p.bit_size);
 
       for (n[0] = 2; n[0] <= 4; n[0]++)
diff --git a/testsuite/ecc-mul-g-test.c b/testsuite/ecc-mul-g-test.c
index 1c4d0c05af0d66e1207af7012b3b4f7375cd0fdb..272394847f3a913705142dee82bc3a47b17505ed 100644
--- a/testsuite/ecc-mul-g-test.c
+++ b/testsuite/ecc-mul-g-test.c
@@ -25,7 +25,7 @@ test_main (void)
       ecc->mul_g (ecc, p, n, scratch);
       ecc->h_to_a (ecc, 0, p, p, scratch);
 
-      if (mpn_cmp (p, ecc->g, 2*size != 0))
+      if (mpn_cmp (p, ecc->g, 2*size) != 0)
 	{
 	  fprintf (stderr, "ecc->mul_g with n = 1 failed.\n");
 	  abort ();
diff --git a/testsuite/hkdf-test.c b/testsuite/hkdf-test.c
new file mode 100644
index 0000000000000000000000000000000000000000..80f4c8132676b883f8adc421c8e5a223f0962b25
--- /dev/null
+++ b/testsuite/hkdf-test.c
@@ -0,0 +1,143 @@
+#include "testutils.h"
+#include "hkdf.h"
+#include "hmac.h"
+
+static void
+test_hkdf_sha256(const struct tstring *ikm,
+		 const struct tstring *salt,
+		 const struct tstring *info,
+		 const struct tstring *extract_output,
+		 const struct tstring *expand_output)
+{
+  struct hmac_sha256_ctx ctx;
+  uint8_t prk[SHA256_DIGEST_SIZE];
+  uint8_t *buffer = xalloc(expand_output->length);
+
+  hmac_sha256_set_key(&ctx, salt->length, salt->data);
+  hkdf_extract(&ctx,
+	       (nettle_hash_update_func*) hmac_sha256_update,
+	       (nettle_hash_digest_func*) hmac_sha256_digest,
+	       SHA256_DIGEST_SIZE,
+	       ikm->length, ikm->data, prk);
+
+  if (MEMEQ(SHA256_DIGEST_SIZE, prk, extract_output->data) == 0)
+    {
+      fprintf(stdout, "\nGot:\n");
+      print_hex(SHA256_DIGEST_SIZE, prk);
+      fprintf(stdout, "\nExpected:\n");
+      print_hex(extract_output->length, extract_output->data);
+      abort();
+    }
+
+  hmac_sha256_set_key(&ctx, SHA256_DIGEST_SIZE, prk);
+  hkdf_expand(&ctx,
+	      (nettle_hash_update_func*) hmac_sha256_update,
+	      (nettle_hash_digest_func*) hmac_sha256_digest,
+	      SHA256_DIGEST_SIZE,
+	      info->length, info->data,
+	      expand_output->length, buffer);
+
+  if (MEMEQ(expand_output->length, expand_output->data, buffer) == 0)
+    {
+      fprintf(stdout, "\nGot:\n");
+      print_hex(expand_output->length, buffer);
+      fprintf(stdout, "\nExpected:\n");
+      print_hex(expand_output->length, expand_output->data);
+      abort();
+    }
+  free(buffer);
+}
+
+static void
+test_hkdf_sha1(const struct tstring *ikm,
+	       const struct tstring *salt,
+	       const struct tstring *info,
+	       const struct tstring *extract_output,
+	       const struct tstring *expand_output)
+{
+  struct hmac_sha1_ctx ctx;
+  uint8_t prk[SHA1_DIGEST_SIZE];
+  uint8_t *buffer = xalloc(expand_output->length);
+
+  hmac_sha1_set_key(&ctx, salt->length, salt->data);
+  hkdf_extract(&ctx,
+	       (nettle_hash_update_func*) hmac_sha1_update,
+	       (nettle_hash_digest_func*) hmac_sha1_digest,
+	       SHA1_DIGEST_SIZE,
+	       ikm->length, ikm->data,
+	       prk);
+
+  if (MEMEQ(SHA1_DIGEST_SIZE, prk, extract_output->data) == 0)
+    {
+      fprintf(stdout, "\nGot:\n");
+      print_hex(SHA1_DIGEST_SIZE, prk);
+      fprintf(stdout, "\nExpected:\n");
+      print_hex(extract_output->length, extract_output->data);
+      abort();
+    }
+
+  hmac_sha1_set_key(&ctx, SHA1_DIGEST_SIZE, prk);
+  hkdf_expand(&ctx,
+	      (nettle_hash_update_func*) hmac_sha1_update,
+	      (nettle_hash_digest_func*) hmac_sha1_digest,
+	      SHA1_DIGEST_SIZE,
+	      info->length, info->data,
+	      expand_output->length, buffer);
+
+  if (MEMEQ(expand_output->length, expand_output->data, buffer) == 0)
+    {
+      fprintf(stdout, "\nGot:\n");
+      print_hex(expand_output->length, buffer);
+      fprintf(stdout, "\nExpected:\n");
+      print_hex(expand_output->length, expand_output->data);
+      abort();
+    }
+  free(buffer);
+}
+
+void
+test_main(void)
+{
+  /* HKDF test vectors from RFC5869 */
+  test_hkdf_sha256(SHEX("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"),
+	SHEX("000102030405060708090a0b0c"),
+	SHEX("f0f1f2f3f4f5f6f7f8f9"),
+	SHEX("077709362c2e32df0ddc3f0dc47bba6390b6c73bb50f9c3122ec844ad7c2b3e5"),
+	SHEX("3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c5bf34007208d5b887185865"));
+
+  test_hkdf_sha256(SHEX("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f"),
+	SHEX("606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeaf"),
+	SHEX("b0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"),
+	SHEX("06a6b88c5853361a06104c9ceb35b45cef760014904671014a193f40c15fc244"),
+	SHEX("b11e398dc80327a1c8e7f78c596a49344f012eda2d4efad8a050cc4c19afa97c59045a99cac7827271cb41c65e590e09da3275600c2f09b8367793a9aca3db71cc30c58179ec3e87c14c01d5c1f3434f1d87"));
+
+  test_hkdf_sha256(SHEX("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"),
+	SDATA(""),
+	SDATA(""),
+	SHEX("19ef24a32c717b167f33a91d6f648bdf96596776afdb6377ac434c1c293ccb04"),
+	SHEX("8da4e775a563c18f715f802a063c5a31b8a11f5c5ee1879ec3454e5f3c738d2d9d201395faa4b61a96c8"));
+
+  test_hkdf_sha1(SHEX("0b0b0b0b0b0b0b0b0b0b0b"),
+	SHEX("000102030405060708090a0b0c"),
+	SHEX("f0f1f2f3f4f5f6f7f8f9"),
+	SHEX("9b6c18c432a7bf8f0e71c8eb88f4b30baa2ba243"),
+	SHEX("085a01ea1b10f36933068b56efa5ad81a4f14b822f5b091568a9cdd4f155fda2c22e422478d305f3f896"));
+
+  test_hkdf_sha1(SHEX("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f"),
+	SHEX("606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeaf"),
+	SHEX("b0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"),
+	SHEX("8adae09a2a307059478d309b26c4115a224cfaf6"),
+	SHEX("0bd770a74d1160f7c9f12cd5912a06ebff6adcae899d92191fe4305673ba2ffe8fa3f1a4e5ad79f3f334b3b202b2173c486ea37ce3d397ed034c7f9dfeb15c5e927336d0441f4c4300e2cff0d0900b52d3b4"));
+
+  test_hkdf_sha1(SHEX("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"),
+	SDATA(""),
+	SDATA(""),
+	SHEX("da8c8a73c7fa77288ec6f5e7c297786aa0d32d01"),
+	SHEX("0ac1af7002b3d761d1e55298da9d0506b9ae52057220a306e07b6b87e8df21d0ea00033de03984d34918"));
+
+  test_hkdf_sha1(SHEX("0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c"),
+	SHEX(""),
+	SHEX(""),
+	SHEX("2adccada18779e7c2077ad2eb19d3f3e731385dd"),
+	SHEX("2c91117204d745f3500d636a62f64f0ab3bae548aa53d423b0d1f27ebba6f5e5673a081d70cce7acfc48"));
+}
diff --git a/testsuite/meta-hash-test.c b/testsuite/meta-hash-test.c
index afc715049a62764183464fc7a58f37e2de299eea..4754f66596eed64f8a7921d320d9d16b7f628875 100644
--- a/testsuite/meta-hash-test.c
+++ b/testsuite/meta-hash-test.c
@@ -1,6 +1,8 @@
 #include "testutils.h"
 #include "nettle-internal.h"
 #include "nettle-meta.h"
+/* For NETTLE_MAX_HASH_CONTEXT_SIZE */
+#include "sha3.h"
 
 const char* hashes[] = {
   "md2",
@@ -28,9 +30,9 @@ test_main(void)
     ASSERT(nettle_lookup_hash(hashes[i]) != NULL);
   }
 
-  while (NULL != nettle_hashes[i])
-    i++;
-  ASSERT(i == count); /* we are not missing testing any hashes */
-  for (i = 0; NULL != nettle_hashes[i]; i++)
+  for (i = 0; NULL != nettle_hashes[i]; i++) {
     ASSERT(nettle_hashes[i]->digest_size <= NETTLE_MAX_HASH_DIGEST_SIZE);
+    ASSERT(nettle_hashes[i]->context_size <= NETTLE_MAX_HASH_CONTEXT_SIZE);
+  }
+  ASSERT(i == count); /* we are not missing testing any hashes */
 }
diff --git a/testsuite/pss-mgf1-test.c b/testsuite/pss-mgf1-test.c
new file mode 100644
index 0000000000000000000000000000000000000000..640500b5d27698e011e86a2943f6bcf083278c89
--- /dev/null
+++ b/testsuite/pss-mgf1-test.c
@@ -0,0 +1,36 @@
+#include "testutils.h"
+#include "pss-mgf1.h"
+
+void
+test_main(void)
+{
+  struct sha1_ctx sha1ctx;
+  struct sha256_ctx sha256ctx;
+  const struct tstring *seed, *expected;
+  uint8_t mask[120];
+
+  /* From ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1d2-vec.zip */
+  seed = SHEX("df1a896f9d8bc816d97cd7a2c43bad54"
+	      "6fbe8cfe");
+  expected = SHEX("66e4672e836ad121ba244bed6576b867d9a447c28a6e66a5b87dee"
+		  "7fbc7e65af5057f86fae8984d9ba7f969ad6fe02a4d75f7445fefd"
+		  "d85b6d3a477c28d24ba1e3756f792dd1dce8ca94440ecb5279ecd3"
+		  "183a311fc89739a96643136e8b0f465e87a4535cd4c59b10028d");
+  sha1_init(&sha1ctx);
+  sha1_update(&sha1ctx, seed->length, seed->data);
+  pss_mgf1(&sha1ctx, &nettle_sha1, expected->length, mask);
+  ASSERT(MEMEQ (expected->length, mask, expected->data));
+
+  /* Test with our own data.  */
+  seed = SDATA("abc");
+  expected = SHEX("cf2db1ac9867debdf8ce91f99f141e5544bf26ca36b3fd4f8e4035"
+		  "eec42cab0d46c386ebccef82ba0bb0b095aaa5548b03cdff695187"
+		  "1c6fb505af68af688332f885d324a47d2145a3d8392c37978d7dc9"
+		  "84c95728950c4cf3de6becc59e60ea506951bd40e6de3863095064"
+		  "3ab2edbb47dc66cb54beb2d1");
+
+  sha256_init(&sha256ctx);
+  sha256_update(&sha256ctx, seed->length, seed->data);
+  pss_mgf1(&sha256ctx, &nettle_sha256, expected->length, mask);
+  ASSERT(MEMEQ (expected->length, mask, expected->data));
+}
diff --git a/testsuite/pss-test.c b/testsuite/pss-test.c
new file mode 100644
index 0000000000000000000000000000000000000000..f6ba697c6773d6790537cae8087af2b17402c211
--- /dev/null
+++ b/testsuite/pss-test.c
@@ -0,0 +1,86 @@
+#include "testutils.h"
+
+#include "pss.h"
+
+void
+test_main(void)
+{
+  struct tstring *salt;
+  struct tstring *digest;
+  mpz_t m;
+  mpz_t expected;
+
+  /* From ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1d2-vec.zip */
+  mpz_init(m);
+  mpz_init(expected);
+
+  salt = SHEX("e3b5d5d002c1bce50c2b65ef88a188d83bce7e61");
+  digest = SHEX("37b66ae0445843353d47ecb0b4fd14c110e62d6a");
+  ASSERT(pss_encode_mgf1(m, 1024, &nettle_sha1,
+			 salt->length, salt->data, digest->data));
+
+  mpz_set_str(expected,
+	      "66e4672e836ad121ba244bed6576b867d9a447c28a6e66a5b87dee"
+	      "7fbc7e65af5057f86fae8984d9ba7f969ad6fe02a4d75f7445fefd"
+	      "d85b6d3a477c28d24ba1e3756f792dd1dce8ca94440ecb5279ecd3"
+	      "183a311fc896da1cb39311af37ea4a75e24bdbfd5c1da0de7cecdf"
+	      "1a896f9d8bc816d97cd7a2c43bad546fbe8cfebc", 16);
+
+  ASSERT(mpz_cmp(m, expected) == 0);
+
+  mpz_add_ui(m, m, 2);
+  ASSERT(!pss_verify_mgf1(m, 1024, &nettle_sha1, salt->length, digest->data));
+
+  mpz_sub_ui(m, m, 2);
+  ASSERT(pss_verify_mgf1(m, 1024, &nettle_sha1, salt->length, digest->data));
+
+  mpz_clear(m);
+  mpz_clear(expected);
+
+  /* Test with our own data.  */
+  mpz_init(m);
+  mpz_init(expected);
+
+  salt = SHEX("11223344556677889900");
+  /* From sha256-test.c */
+  digest = SHEX("ba7816bf8f01cfea 414140de5dae2223"
+		"b00361a396177a9c b410ff61f20015ad");
+
+  mpz_set_str(expected,
+	      "76b9a52705c8382c5367732f993184eff340b6305c9f73e7e308c8"
+	      "004fcc15cbbaab01e976bae4b774628595379a2d448a36b3ea6fa8"
+	      "353b97eeea7bdac93b4b7807ac98cd4b3bebfb31f3718e1dd3625f"
+	      "227fbb8696606498e7070e21c3cbbd7386ea20eb81ac7927e0c6d1"
+	      "d7788826a63af767f301bcc05dd65b00da862cbc", 16);
+
+  /* Try bad salt */
+  salt->data[6] = 0x00;
+  ASSERT(pss_encode_mgf1(m, 1024, &nettle_sha256,
+			 salt->length, salt->data, digest->data));
+  ASSERT(mpz_cmp(m, expected) != 0);
+
+  /* Try the good salt */
+  salt->data[6] = 0x77;
+  ASSERT(pss_encode_mgf1(m, 1024, &nettle_sha256,
+			 salt->length, salt->data, digest->data));
+  ASSERT(mpz_cmp(m, expected) == 0);
+
+  /* Try bad message */
+  mpz_add_ui(m, m, 2);
+  ASSERT(!pss_verify_mgf1(m, 1024, &nettle_sha256, salt->length, digest->data));
+
+  /* Try the good message */
+  mpz_sub_ui(m, m, 2);
+  ASSERT(pss_verify_mgf1(m, 1024, &nettle_sha256, salt->length, digest->data));
+
+  /* Try bad digest */
+  digest->data[17] = 0x00;
+  ASSERT(!pss_verify_mgf1(m, 1024, &nettle_sha256, salt->length, digest->data));
+
+  /* Try the good digest */
+  digest->data[17] = 0x03;
+  ASSERT(pss_verify_mgf1(m, 1024, &nettle_sha256, salt->length, digest->data));
+
+  mpz_clear(m);
+  mpz_clear(expected);
+}
diff --git a/testsuite/rsa-pss-sign-tr-test.c b/testsuite/rsa-pss-sign-tr-test.c
new file mode 100644
index 0000000000000000000000000000000000000000..6dfba734c6b758daea2d7dd16f1edd61000d4582
--- /dev/null
+++ b/testsuite/rsa-pss-sign-tr-test.c
@@ -0,0 +1,356 @@
+#include "testutils.h"
+#include "knuth-lfib.h"
+#include "nettle-internal.h"
+
+#define SALT "This is a magic salt"
+#define MSG1 "None so blind as those who will not see"
+#define MSG2 "Fortune knocks once at every man's door"
+
+typedef int (*test_pss_sign_tr_func) (const struct rsa_public_key *pub,
+				      const struct rsa_private_key *key,
+				      void *random_ctx, nettle_random_func *random,
+				      size_t salt_length, const uint8_t *salt,
+				      const uint8_t *digest,
+				      mpz_t s);
+
+typedef int (*test_pss_verify_func) (const struct rsa_public_key *key,
+				     size_t salt_length,
+				     const uint8_t *digest,
+				     const mpz_t signature);
+
+static void
+test_rsa_pss_sign_tr(struct rsa_public_key *pub,
+		     struct rsa_private_key *key,
+		     test_pss_sign_tr_func sign_tr_func,
+		     test_pss_verify_func verify_func,
+		     void *ctx, const struct nettle_hash *hash,
+		     size_t salt_length, const uint8_t *salt,
+		     size_t length, const uint8_t *message,
+		     mpz_t expected)
+{
+  mpz_t signature;
+  struct knuth_lfib_ctx lfib;
+  uint8_t digest[NETTLE_MAX_HASH_DIGEST_SIZE];
+  uint8_t bad_digest[NETTLE_MAX_HASH_DIGEST_SIZE];
+
+  knuth_lfib_init(&lfib, 1111);
+
+  hash->init(ctx);
+  hash->update(ctx, length, message);
+  hash->digest(ctx, hash->digest_size, digest);
+
+  mpz_init(signature);
+
+  mpz_set_ui (signature, 17);
+  /* Try bad private key */
+  mpz_add_ui(key->p, key->p, 2);
+
+  ASSERT(!sign_tr_func(pub, key,
+		       &lfib, (nettle_random_func *) knuth_lfib_random,
+		       salt_length, salt,
+		       digest, signature));
+
+  mpz_sub_ui(key->p, key->p, 2);
+
+  ASSERT(!mpz_cmp_ui(signature, 17));
+
+  /* Try the good private key */
+  ASSERT(sign_tr_func(pub, key,
+		      &lfib, (nettle_random_func *) knuth_lfib_random,
+		      salt_length, salt,
+		      digest, signature));
+
+  if (verbose)
+    {
+      fprintf(stderr, "rsa-pss-tr signature: ");
+      mpz_out_str(stderr, 16, signature);
+      fprintf(stderr, "\nrsa-pss-tr expected: ");
+      mpz_out_str(stderr, 16, expected);
+      fprintf(stderr, "\n");
+    }
+
+  ASSERT (mpz_cmp(signature, expected) == 0);
+
+  /* Try bad digest */
+  memset(bad_digest, 0x17, sizeof(bad_digest));
+  ASSERT (!verify_func(pub, salt_length, bad_digest, signature));
+
+  /* Try the good digest */
+  ASSERT (verify_func(pub, salt_length, digest, signature));
+
+  /* Try bad signature */
+  mpz_combit(signature, 17);
+  ASSERT (!verify_func(pub, salt_length, digest, signature));
+
+  mpz_clear(signature);
+}
+
+
+void
+test_main(void)
+{
+  struct rsa_public_key pub;
+  struct rsa_private_key key;
+  struct sha256_ctx sha256ctx;
+  struct sha384_ctx sha384ctx;
+  struct sha512_ctx sha512ctx;
+  mpz_t p1;
+  mpz_t q1;
+  struct tstring *salt;
+  struct tstring *msg;
+
+  mpz_t expected;
+
+  mpz_init(expected);
+
+  mpz_init(p1);
+  mpz_init(q1);
+
+  rsa_private_key_init(&key);
+  rsa_public_key_init(&pub);
+
+  test_rsa_set_key_1(&pub, &key);
+
+  /* Test signatures */
+  mpz_set_str(expected,
+	      "25e6ce0cc00e917e177a09cb4dfd843d104c179b71aded60e68ebc"
+	      "ca2cabb1e51502adf28e53fa7ede42619f21a1162755b9658edf88"
+	      "a038bb4fea2bb73306fb384d5785c1a8c98a255277c91a4f88ddd3"
+	      "52ebdc78f71f7e62b7a870dac4ab25f1004453457e831a1572f7c9"
+	      "23fcc48e3b69db582127d14471c7195dce", 16);
+
+  test_rsa_pss_sign_tr(&pub, &key,
+		       rsa_pss_sha256_sign_digest_tr,
+		       rsa_pss_sha256_verify_digest,
+		       &sha256ctx, &nettle_sha256,
+		       LDATA(SALT), LDATA(MSG1), expected);
+
+  mpz_set_str(expected,
+	      "52f4393ccc92b5672dd3cfd8624765d3a4cdb50c7a92060c33b4663"
+	      "fa545b32ce56ec8cd44fe9720df301906ae40921e844b6d80331194"
+	      "972f98e309c937c887c53da940778f29d52dd9489e6016a07e9aa16"
+	      "b1ea8fefc0860ad69068ad6f94a4b0c8fc8a0797b08c58cf4a8df90"
+	      "ee1375feedf7bf73f16ebb2d1cc7e4", 16);
+
+  test_rsa_pss_sign_tr(&pub, &key,
+		       rsa_pss_sha256_sign_digest_tr,
+		       rsa_pss_sha256_verify_digest,
+		       &sha256ctx, &nettle_sha256,
+		       LDATA(SALT), LDATA(MSG2), expected);
+
+  /* 777-bit key, generated by
+   *
+   *   lsh-keygen -a rsa -l 777 -f advanced-hex
+   *
+   * Interesting because the size of n doesn't equal the sum of the
+   * sizes of p and q.
+   *
+   * (private-key (rsa-pkcs1
+   *        (n #013b04440e3eef25 d51c738d508a7fa8 b3445180c342af0f
+   *            4cb5a789047300e2 cfc5c5450974cfc2 448aeaaa7f43c374
+   *            c9a3b038b181f2d1 0f1a2327fd2c087b a49bf1086969fd2c
+   *            d1df3fd69f81fa4b 162cc8bbb363fc95 b7b24b9c53d0c67e
+   *            f52b#)
+   *        (e #3f1a012d#)
+   *        (d #f9bae89dacca6cca c21e0412b4df8355 6fe7c5322bbae8ad
+   *            3f11494fd12bc076 d4a7da3050fe109d 2074db09cc6a93b4
+   *            745479522558379e a0ddfa74f86c9e9e a22c3b0e93d51447
+   *            0feb38105dd35395 63b91ee32776f40c 67b2a175690f7abb
+   *            25#)
+   *        (p #0b73c990eeda0a2a 2c26416052c85560 0c5c0f5ce86a8326
+   *            166acea91786237a 7ff884e66dbfdd3a ab9d9801414c1506
+   *            8b#)
+   *        (q #1b81c19a62802a41 9c99283331b0badb 08eb0c25ffce0fbf
+   *            50017850036f32f3 2132a845b91a5236 61f7b451d587383f
+   *            e1#)
+   *        (a #0a912fc93a6cca6b 3521725a3065b3be 3c9745e29c93303d
+   *            7d29316c6cafa4a2 89945f964fcdea59 1f9d248b0b6734be
+   *            c9#)
+   *        (b #1658eca933251813 1eb19c77aba13d73 e0b8f4ce986d7615
+   *            764c6b0b03c18146 46b7f332c43e05c5 351e09006979ca5b
+   *            05#)
+   *        (c #0114720dace7b27f 2bf2850c1804869f 79a0aad0ec02e6b4
+   *            05e1831619db2f10 bb9b6a8fd5c95df2 eb78f303ea0c0cc8
+   *            06#)))
+   */
+
+  mpz_set_str(pub.n,
+	      "013b04440e3eef25" "d51c738d508a7fa8" "b3445180c342af0f"
+	      "4cb5a789047300e2" "cfc5c5450974cfc2" "448aeaaa7f43c374"
+	      "c9a3b038b181f2d1" "0f1a2327fd2c087b" "a49bf1086969fd2c"
+	      "d1df3fd69f81fa4b" "162cc8bbb363fc95" "b7b24b9c53d0c67e"
+	      "f52b", 16);
+
+  mpz_set_str(pub.e, "3f1a012d", 16);
+
+  ASSERT (rsa_public_key_prepare(&pub));
+
+  mpz_set_str(key.p,
+	      "0b73c990eeda0a2a" "2c26416052c85560" "0c5c0f5ce86a8326"
+	      "166acea91786237a" "7ff884e66dbfdd3a" "ab9d9801414c1506"
+	      "8b", 16);
+
+  mpz_set_str(key.q,
+	      "1b81c19a62802a41" "9c99283331b0badb" "08eb0c25ffce0fbf"
+	      "50017850036f32f3" "2132a845b91a5236" "61f7b451d587383f"
+	      "e1", 16);
+
+  mpz_set_str(key.a,
+	      "0a912fc93a6cca6b" "3521725a3065b3be" "3c9745e29c93303d"
+	      "7d29316c6cafa4a2" "89945f964fcdea59" "1f9d248b0b6734be"
+	      "c9", 16);
+
+  mpz_set_str(key.b,
+	      "1658eca933251813" "1eb19c77aba13d73" "e0b8f4ce986d7615"
+	      "764c6b0b03c18146" "46b7f332c43e05c5" "351e09006979ca5b"
+	      "05", 16);
+
+  mpz_set_str(key.c,
+	      "0114720dace7b27f" "2bf2850c1804869f" "79a0aad0ec02e6b4"
+	      "05e1831619db2f10" "bb9b6a8fd5c95df2" "eb78f303ea0c0cc8"
+	      "06", 16);
+
+  ASSERT (rsa_private_key_prepare(&key));
+  ASSERT (pub.size == key.size);
+
+  /* Test signatures */
+  mpz_set_str(expected,
+	      "1a4d28331341cabf7ac85bc59a58d439b7ec2c607c6a74e35b5909"
+	      "1dfa3d9de9fde93e4a431f0f768bec07c39995d253209f86e3dc84"
+	      "037ecd5d23d963fab4fa8a001e018d82cb19d743a94ba7dc7a821e"
+	      "87b72e67a0fe058f956208f7060dc104", 16);
+
+  test_rsa_pss_sign_tr(&pub, &key,
+		       rsa_pss_sha256_sign_digest_tr,
+		       rsa_pss_sha256_verify_digest,
+		       &sha256ctx, &nettle_sha256,
+		       LDATA(SALT), LDATA(MSG1), expected);
+
+  /* From FIPS 186-2 */
+  mpz_set_str(pub.n,
+	      "be499b5e7f06c83f" "a0293e31465c8eb6" "b58af920bae52a7b"
+	      "5b9bfeb7aa72db12" "64112eb3fd431d31" "a2a7e50941566929"
+	      "494a0e891ed56139" "18b4b51b0d1fb977" "83b26acf7d0f384c"
+	      "fb35f4d2824f5dd3" "80623a26bf180b63" "961c619dcdb20cae"
+	      "406f22f6e276c80a" "37259490cfeb72c1" "a71a84f1846d3308"
+	      "77ba3e3101ec9c7b" , 16);
+
+  mpz_set_str(pub.e, "11", 16);
+
+  ASSERT (rsa_public_key_prepare(&pub));
+
+  mpz_set_str(key.p,
+	      "e7a80c5d211c06ac" "b900939495f26d36" "5fc2b4825b75e356"
+	      "f89003eaa5931e6b" "e5c3f7e6a633ad59" "db6289d06c354c23"
+	      "5e739a1e3f3d39fb" "40d1ffb9cb44288f", 16);
+
+  mpz_set_str(key.q,
+	      "d248aa248000f720" "258742da67b71194" "0c8f76e1ecd52b67"
+	      "a6ffe1e49354d66f" "f84fa601804743f5" "838da2ed4693a5a2"
+	      "8658d6528cc1803b" "f6c8dc73c5230b55", 16);
+
+  mpz_set_str(key.d,
+	      "0d0f17362bdad181" "db4e1fe03e8de1a3" "208989914e14bf26"
+	      "9558826bfa20faf4" "b68dba6bb989a01f" "03a21c44665dc5f6"
+	      "48cb5b59b954eb10" "77a80263bd22cdfb" "88d39164b7404f4f"
+	      "1106ee01cf60b776" "95748d8fdaf9fd42" "8963fe75144010b1"
+	      "934c8e26a8823967" "2cf49b3422a07c4d" "834ba208d570fe40"
+	      "8e7095c90547e68d", 16);
+
+  /* a = d % (p-1) */
+  mpz_sub_ui(p1, key.p, 1);
+  mpz_fdiv_r(key.a, key.d, p1);
+  mpz_clear(p1);
+
+  /* b = d % (q-1) */
+  mpz_sub_ui(q1, key.q, 1);
+  mpz_fdiv_r(key.b, key.d, q1);
+  mpz_clear(q1);
+
+  /* c = q^{-1} (mod p) */
+  mpz_invert(key.c, key.q, key.p);
+
+  ASSERT (rsa_private_key_prepare(&key));
+  ASSERT (pub.size == key.size);
+
+  mpz_set_str(expected,
+	      "11e169f2fd40b07641b9768a2ab19965fb6c27f10fcf0323fcc6d1"
+	      "2eb4f1c06b330ddaa1ea504407afa29de9ebe0374fe9d1e7d0ffbd"
+	      "5fc1cf3a3446e4145415d2ab24f789b3464c5c43a256bbc1d692cf"
+	      "7f04801dac5bb401a4a03ab7d5728a860c19e1a4dc797ca542c820"
+	      "3cec2e601eb0c51f567f2eda022b0b9ebddeeefa", 16);
+
+  salt = SHEX("11223344555432167890");
+  msg = SHEX("c7f5270fca725f9bd19f519a8d7cca3cc5c079024029f3bae510f9"
+	     "b02140fe238908e4f6c18f07a89c687c8684669b1f1db2baf9251a"
+	     "3c829faccb493084e16ec9e28d58868074a5d6221667dd6e528d16"
+	     "fe2c9f3db4cfaf6c4dce8c8439af38ceaaaa9ce2ecae7bc8f4a5a5"
+	     "5e3bf96df9cd575c4f9cb327951b8cdfe4087168");
+
+  test_rsa_pss_sign_tr(&pub, &key,
+		       rsa_pss_sha256_sign_digest_tr,
+		       rsa_pss_sha256_verify_digest,
+		       &sha256ctx, &nettle_sha256,
+		       salt->length, salt->data, msg->length, msg->data,
+		       expected);
+
+  mpz_set_str(expected,
+	      "b281ad934b2775c0cba5fb10aa574d2ed85c7f99b942b78e497024"
+	      "80069362ed394baded55e56cfcbe7b0b8d2217a05a60e1acd725cb"
+	      "09060dfac585bc2132b99b41cdbd530c69d17cdbc84bc6b9830fc7"
+	      "dc8e1b2412cfe06dcf8c1a0cc3453f93f25ebf10cb0c90334fac57"
+	      "3f449138616e1a194c67f44efac34cc07a526267", 16);
+
+  test_rsa_pss_sign_tr(&pub, &key,
+		       rsa_pss_sha384_sign_digest_tr,
+		       rsa_pss_sha384_verify_digest,
+		       &sha384ctx, &nettle_sha384,
+		       salt->length, salt->data, msg->length, msg->data,
+		       expected);
+  mpz_set_str(expected,
+	      "8ffc38f9b820ef6b080fd2ec7de5626c658d79056f3edf610a295b"
+	      "7b0546f73e01ffdf4d0070ebf79c33fd86c2d608be9438b3d420d0"
+	      "9535b97cd3d846ecaf8f6551cdf93197e9f8fb048044473ab41a80"
+	      "1e9f7fc983c62b324361dade9f71a65952bd35c59faaa4d6ff462f"
+	      "68a6c4ec0b428aa47336f2178aeb276136563b7d", 16);
+
+  test_rsa_pss_sign_tr(&pub, &key,
+		       rsa_pss_sha512_sign_digest_tr,
+		       rsa_pss_sha512_verify_digest,
+		       &sha512ctx, &nettle_sha512,
+		       salt->length, salt->data, msg->length, msg->data,
+		       expected);
+
+  /* The public key n for this test is of size k = 1017 bits, and the
+     pss "em" value is limited to k - 1 = 1016 bits or 127 octets. The
+     alleged signature below results in a 1017 bit number during the
+     signature verification, which is too large, and used to result in
+     an assertion failure when attempting to convert the number to a
+     127 octet string.
+  */
+  mpz_set_str(pub.n,
+	      "1d64559685aad3490e976b48aacf442ecee847268f882341eafe78"
+	      "a0ca4ef88f66edbaf55b70e5285cc117aa9ceb322a4227c17e9e89"
+	      "27bf38e5672faecf79e2983d92766fbb6624522f072ae0e4e46d37"
+	      "052ce1e5745c2dd8fd67de3862e4711161e359b96bda85911ebf4e"
+	      "6ce1bea625970269c77004a3cb03f9c382c5f79", 16);
+  mpz_set_str(pub.e, "10001", 16);
+
+  ASSERT (rsa_public_key_prepare(&pub));
+
+  msg = SHEX("7f85e4909ff7bb29536e540a53031ef03ddcb129e553a43273fa1f"
+	     "ed28c22a8b57c7bde101ff746f335ba69b29642019");
+  /* Alleged signature, resulting in a too large m. */
+  mpz_set_str(expected,
+	      "000000000000000000000000000000000000000000000000000000"
+	      "000000000000000000000000000000000000000000000005ffff05"
+	      "000000000000000000000000000000000000000000000000000000"
+	      "000000000000000000000000000000000000000000000000000000"
+	      "0000000000000000000000000000000000000000", 16);
+
+  ASSERT(!rsa_pss_sha384_verify_digest(&pub, 48, msg->data, expected));
+
+  rsa_private_key_clear(&key);
+  rsa_public_key_clear(&pub);
+  mpz_clear(expected);
+}
diff --git a/testsuite/test-rules.stamp b/testsuite/test-rules.stamp
new file mode 100644
index 0000000000000000000000000000000000000000..859afb1de85951b27719cf567ac9821b9b8c51e0
--- /dev/null
+++ b/testsuite/test-rules.stamp
@@ -0,0 +1 @@
+stamp
diff --git a/testsuite/testutils.c b/testsuite/testutils.c
index 6f897617cadbd23077a5adbeac91d73c671140e5..6ce13c4e59f1df77e93cf8c77effc6d23a5b6c70 100644
--- a/testsuite/testutils.c
+++ b/testsuite/testutils.c
@@ -4,6 +4,7 @@
 
 #include "base16.h"
 #include "cbc.h"
+#include "cfb.h"
 #include "ctr.h"
 #include "knuth-lfib.h"
 #include "macros.h"
@@ -62,7 +63,7 @@ tstring_clear(void)
 }
 
 struct tstring *
-tstring_data(size_t length, const char *data)
+tstring_data(size_t length, const uint8_t *data)
 {
   struct tstring *s = tstring_alloc (length);
   memcpy (s->data, data, length);
@@ -244,6 +245,184 @@ test_cipher_cbc(const struct nettle_cipher *cipher,
   free(iv);
 }
 
+void
+test_cipher_cfb(const struct nettle_cipher *cipher,
+		const struct tstring *key,
+		const struct tstring *cleartext,
+		const struct tstring *ciphertext,
+		const struct tstring *iiv)
+{
+  void *ctx = xalloc(cipher->context_size);
+  uint8_t *data, *data2;
+  uint8_t *iv = xalloc(cipher->block_size);
+  size_t length;
+
+  ASSERT (cleartext->length == ciphertext->length);
+  length = cleartext->length;
+
+  ASSERT (key->length == cipher->key_size);
+  ASSERT (iiv->length == cipher->block_size);
+
+  data = xalloc(length);
+  data2 = xalloc(length);
+
+  cipher->set_encrypt_key(ctx, key->data);
+  memcpy(iv, iiv->data, cipher->block_size);
+
+  cfb_encrypt(ctx, cipher->encrypt,
+	      cipher->block_size, iv,
+	      length, data, cleartext->data);
+
+  if (!MEMEQ(length, data, ciphertext->data))
+    {
+      fprintf(stderr, "CFB encrypt failed:\nInput:");
+      tstring_print_hex(cleartext);
+      fprintf(stderr, "\nOutput: ");
+      print_hex(length, data);
+      fprintf(stderr, "\nExpected:");
+      tstring_print_hex(ciphertext);
+      fprintf(stderr, "\n");
+      FAIL();
+    }
+  cipher->set_encrypt_key(ctx, key->data);
+  memcpy(iv, iiv->data, cipher->block_size);
+
+  cfb_decrypt(ctx, cipher->encrypt,
+	      cipher->block_size, iv,
+	      length, data2, data);
+
+  if (!MEMEQ(length, data2, cleartext->data))
+    {
+      fprintf(stderr, "CFB decrypt failed:\nInput:");
+      tstring_print_hex(ciphertext);
+      fprintf(stderr, "\nOutput: ");
+      print_hex(length, data2);
+      fprintf(stderr, "\nExpected:");
+      tstring_print_hex(cleartext);
+      fprintf(stderr, "\n");
+      FAIL();
+    }
+  cipher->set_encrypt_key(ctx, key->data);
+  memcpy(iv, iiv->data, cipher->block_size);
+  memcpy(data, cleartext->data, length);
+
+  cfb_encrypt(ctx, cipher->encrypt,
+	      cipher->block_size, iv,
+	      length, data, data);
+
+  if (!MEMEQ(length, data, ciphertext->data))
+    {
+      fprintf(stderr, "CFB inplace encrypt failed:\nInput:");
+      tstring_print_hex(cleartext);
+      fprintf(stderr, "\nOutput: ");
+      print_hex(length, data);
+      fprintf(stderr, "\nExpected:");
+      tstring_print_hex(ciphertext);
+      fprintf(stderr, "\n");
+      FAIL();
+    }
+  cipher->set_encrypt_key(ctx, key->data);
+  memcpy(iv, iiv->data, cipher->block_size);
+
+  cfb_decrypt(ctx, cipher->encrypt,
+	      cipher->block_size, iv,
+	      length, data, data);
+
+  if (!MEMEQ(length, data, cleartext->data))
+    {
+      fprintf(stderr, "CFB inplace decrypt failed:\nInput:");
+      tstring_print_hex(ciphertext);
+      fprintf(stderr, "\nOutput: ");
+      print_hex(length, data);
+      fprintf(stderr, "\nExpected:");
+      tstring_print_hex(cleartext);
+      fprintf(stderr, "\n");
+      FAIL();
+    }
+
+  /* Repeat all tests with incomplete last block */
+  length -= 1;
+
+  cipher->set_encrypt_key(ctx, key->data);
+  memcpy(iv, iiv->data, cipher->block_size);
+
+  cfb_encrypt(ctx, cipher->encrypt,
+	      cipher->block_size, iv,
+	      length, data, cleartext->data);
+
+  if (!MEMEQ(length, data, ciphertext->data))
+    {
+      fprintf(stderr, "CFB encrypt failed:\nInput:");
+      print_hex(length, cleartext->data);
+      fprintf(stderr, "\nOutput: ");
+      print_hex(length, data);
+      fprintf(stderr, "\nExpected:");
+      print_hex(length, ciphertext->data);
+      fprintf(stderr, "\n");
+      FAIL();
+    }
+  cipher->set_encrypt_key(ctx, key->data);
+  memcpy(iv, iiv->data, cipher->block_size);
+
+  cfb_decrypt(ctx, cipher->encrypt,
+	      cipher->block_size, iv,
+	      length, data2, data);
+
+  if (!MEMEQ(length, data2, cleartext->data))
+    {
+      fprintf(stderr, "CFB decrypt failed:\nInput:");
+      print_hex(length, ciphertext->data);
+      fprintf(stderr, "\nOutput: ");
+      print_hex(length, data2);
+      fprintf(stderr, "\nExpected:");
+      print_hex(length, cleartext->data);
+      fprintf(stderr, "\n");
+      FAIL();
+    }
+  cipher->set_encrypt_key(ctx, key->data);
+  memcpy(iv, iiv->data, cipher->block_size);
+  memcpy(data, cleartext->data, length);
+
+  cfb_encrypt(ctx, cipher->encrypt,
+	      cipher->block_size, iv,
+	      length, data, data);
+
+  if (!MEMEQ(length, data, ciphertext->data))
+    {
+      fprintf(stderr, "CFB inplace encrypt failed:\nInput:");
+      print_hex(length, cleartext->data);
+      fprintf(stderr, "\nOutput: ");
+      print_hex(length, data);
+      fprintf(stderr, "\nExpected:");
+      print_hex(length, ciphertext->data);
+      fprintf(stderr, "\n");
+      FAIL();
+    }
+  cipher->set_encrypt_key(ctx, key->data);
+  memcpy(iv, iiv->data, cipher->block_size);
+
+  cfb_decrypt(ctx, cipher->encrypt,
+	      cipher->block_size, iv,
+	      length, data, data);
+
+  if (!MEMEQ(length, data, cleartext->data))
+    {
+      fprintf(stderr, "CFB inplace decrypt failed:\nInput:");
+      print_hex(length, ciphertext->data);
+      fprintf(stderr, "\nOutput: ");
+      print_hex(length, data);
+      fprintf(stderr, "\nExpected:");
+      print_hex(length, cleartext->data);
+      fprintf(stderr, "\n");
+      FAIL();
+    }
+
+  free(ctx);
+  free(data);
+  free(data2);
+  free(iv);
+}
+
 void
 test_cipher_ctr(const struct nettle_cipher *cipher,
 		const struct tstring *key,
@@ -566,7 +745,7 @@ test_armor(const struct nettle_armor *armor,
            const char *ascii)
 {
   size_t ascii_length = strlen(ascii);
-  uint8_t *buffer = xalloc(1 + ascii_length);
+  char *buffer = xalloc(1 + ascii_length);
   uint8_t *check = xalloc(1 + armor->decode_length(ascii_length));
   void *encode = xalloc(armor->encode_context_size);
   void *decode = xalloc(armor->decode_context_size);
diff --git a/testsuite/testutils.h b/testsuite/testutils.h
index 7c44772b7748d07397304c838c087897112f1cc9..fbbba7b9fab5cabb34eb50f44eeb9a4d6002ae0f 100644
--- a/testsuite/testutils.h
+++ b/testsuite/testutils.h
@@ -60,7 +60,7 @@ void
 tstring_clear(void);
 
 struct tstring *
-tstring_data(size_t length, const char *data);
+tstring_data(size_t length, const uint8_t *data);
 
 struct tstring *
 tstring_hex(const char *hex);
@@ -122,6 +122,13 @@ test_cipher_cbc(const struct nettle_cipher *cipher,
 		const struct tstring *ciphertext,
 		const struct tstring *iv);
 
+void
+test_cipher_cfb(const struct nettle_cipher *cipher,
+		const struct tstring *key,
+		const struct tstring *cleartext,
+		const struct tstring *ciphertext,
+		const struct tstring *iv);
+
 void
 test_cipher_ctr(const struct nettle_cipher *cipher,
 		const struct tstring *key,
@@ -163,13 +170,6 @@ test_armor(const struct nettle_armor *armor,
            const char *ascii);
 
 #if WITH_HOGWEED
-#ifndef mpn_zero_p
-int
-mpn_zero_p (mp_srcptr ap, mp_size_t n);
-#endif
-
-void
-mpn_out_str (FILE *f, int base, const mp_limb_t *xp, mp_size_t xn);
 
 #if NETTLE_USE_MINI_GMP
 typedef struct knuth_lfib_ctx gmp_randstate_t[1];
@@ -180,8 +180,20 @@ void mpz_urandomb (mpz_t r, struct knuth_lfib_ctx *ctx, mp_bitcnt_t bits);
 /* This is cheating */
 #define mpz_rrandomb mpz_urandomb
 
+/* mini-gmp defines this function (in the GMP library, it was added in
+   gmp in version 6.1.0). */
+#define mpn_zero_p mpn_zero_p
+
 #endif /* NETTLE_USE_MINI_GMP */
 
+#ifndef mpn_zero_p
+int
+mpn_zero_p (mp_srcptr ap, mp_size_t n);
+#endif
+
+void
+mpn_out_str (FILE *f, int base, const mp_limb_t *xp, mp_size_t xn);
+
 mp_limb_t *
 xalloc_limbs (mp_size_t n);
 
@@ -281,7 +293,7 @@ test_ecc_mul_h (unsigned curve, unsigned n, const mp_limb_t *p);
 #define LDUP(x) strlen(x), strdup(x)
 
 #define SHEX(x) (tstring_hex(x))
-#define SDATA(x) ((const struct tstring *)tstring_data(LLENGTH(x), x))
+#define SDATA(x) ((const struct tstring *)tstring_data(LLENGTH(x), US(x)))
 #define H(x) (SHEX(x)->data)
 
 #define MEMEQ(length, a, b) (!memcmp((a), (b), (length)))
diff --git a/tools/input.c b/tools/input.c
index 18a9dff5c5659382bac92e2080ffdb72df49772c..90e41a29058e83b5dbde988a11628e428fcb7b8b 100644
--- a/tools/input.c
+++ b/tools/input.c
@@ -90,7 +90,7 @@ sexp_get_char(struct sexp_input *input)
 	 * character at a time. */
 	if (!input->coding->decode_update(&input->state,
 					  &done, &input->c,
-					  1, &input->c))
+					  1, (const char*) &input->c))
 	  die("Invalid coded data.\n");
 	
 	if (done)
diff --git a/tools/nettle-hash.c b/tools/nettle-hash.c
index d7d4ce2e719d41d158b58f5b6061594accd78e15..24199921feada35e717f17780d09849da7d0dbc0 100644
--- a/tools/nettle-hash.c
+++ b/tools/nettle-hash.c
@@ -53,11 +53,11 @@ list_algorithms (void)
 {
   unsigned i;
   const struct nettle_hash *alg;
-  printf ("%10s digestsize (internal block size), in units of octets\n", "name");
+  printf ("%10s digestsize (internal block size, context size), in units of octets\n", "name");
 
   for (i = 0; (alg = nettle_hashes[i]); i++)
-    printf ("%10s %d (%d)\n",
-	    alg->name, alg->digest_size, alg->block_size);
+    printf ("%10s %d (%d, %d)\n",
+	    alg->name, alg->digest_size, alg->block_size, alg->context_size);
 };
 
 /* Also in examples/io.c */
diff --git a/tools/nettle-pbkdf2.c b/tools/nettle-pbkdf2.c
index c9e4d11c5604d5640b75a40202222c9ca255adf3..1f0a3015ad3c7fd18f016b9e1a4d4d9b10e27ad1 100644
--- a/tools/nettle-pbkdf2.c
+++ b/tools/nettle-pbkdf2.c
@@ -73,7 +73,7 @@ main (int argc, char **argv)
   size_t password_length;
   uint8_t *output;
   size_t salt_length;
-  uint8_t *salt;
+  char *salt;
   int raw = 0;
   int hex_salt = 0;
   int c;
@@ -141,7 +141,7 @@ main (int argc, char **argv)
       return EXIT_FAILURE;
     }
 
-  salt = (uint8_t *) strdup (argv[0]);
+  salt = strdup (argv[0]);
   salt_length = strlen(argv[0]);
   
   if (hex_salt)
@@ -150,7 +150,7 @@ main (int argc, char **argv)
 
       base16_decode_init (&base16);
       if (!base16_decode_update (&base16,
-				 &salt_length, salt,
+				 &salt_length, (uint8_t *) salt,
 				 salt_length, salt)
 	  || !base16_decode_final (&base16))
 	die ("Invalid salt (expecting hex encoding).\n");
@@ -165,7 +165,7 @@ main (int argc, char **argv)
 
   output = xalloc (output_length);
   pbkdf2_hmac_sha256 (password_length, (const uint8_t *) password,
-		      iterations, salt_length, salt,
+		      iterations, salt_length, (const uint8_t*) salt,
 		      output_length, output);
 
   free (salt);
diff --git a/tools/output.c b/tools/output.c
index 02e43d58547c56f82a2d6374206e102f7c9ee9e8..80a44a97c468652ad97716e59e8953c317406dcc 100644
--- a/tools/output.c
+++ b/tools/output.c
@@ -114,7 +114,7 @@ sexp_put_char(struct sexp_output *output, uint8_t c)
   if (output->coding)
     {
       /* Two is enough for both base16 and base64. */
-      uint8_t encoded[2];
+      char encoded[2];
       unsigned done;
 
       unsigned i;
@@ -183,7 +183,7 @@ void
 sexp_put_code_end(struct sexp_output *output)
 {
   /* Enough for both hex and base64 */
-  uint8_t encoded[BASE64_ENCODE_FINAL_LENGTH];
+  char encoded[BASE64_ENCODE_FINAL_LENGTH];
   unsigned done;
 
   assert(output->coding);
@@ -194,7 +194,7 @@ sexp_put_code_end(struct sexp_output *output)
   
   output->coding = NULL;
 
-  sexp_put_data(output, done, encoded);
+  sexp_put_data(output, done, (const uint8_t*) encoded);
 }
 
 void
diff --git a/tools/pkcs1-conv.c b/tools/pkcs1-conv.c
index 9e346858b18273ba37cb38a8a658cd071ad169b0..efd6528a4ab4401f73a30f48603752723cc5ef32 100644
--- a/tools/pkcs1-conv.c
+++ b/tools/pkcs1-conv.c
@@ -244,6 +244,14 @@ read_pem(struct nettle_buffer *buffer, FILE *f,
     }
 }
 
+static inline int
+base64_decode_in_place (struct base64_decode_ctx *ctx, size_t *dst_length,
+			size_t length, uint8_t *data)
+{
+  return base64_decode_update (ctx, dst_length,
+			       data, length, (const char *) data);
+}
+
 static int
 decode_base64(struct nettle_buffer *buffer,
 	      size_t start, size_t *length)
@@ -253,9 +261,8 @@ decode_base64(struct nettle_buffer *buffer,
   base64_decode_init(&ctx);
 
   /* Decode in place */
-  if (base64_decode_update(&ctx,
-			   length, buffer->contents + start,
-			   *length, buffer->contents + start)
+  if (base64_decode_in_place(&ctx, length,
+			     *length, buffer->contents + start)
       && base64_decode_final(&ctx))
     return 1;