[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#989678: marked as done (unblock: nettle/3.7.3-1)



Your message dated Sat, 12 Jun 2021 10:08:06 +0000
with message-id <E1ls0Yg-0008UX-Vi@respighi.debian.org>
and subject line unblock nettle
has caused the Debian Bug report #989678,
regarding unblock: nettle/3.7.3-1
to be marked as done.

This means that you claim that the problem has been dealt with.
If this is not the case it is now your responsibility to reopen the
Bug report if necessary, and/or fix the problem forthwith.

(NB: If you are a system administrator and have no idea what this
message is talking about, this may indicate a serious mail system
misconfiguration somewhere. Please contact owner@bugs.debian.org
immediately.)


-- 
989678: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=989678
Debian Bug Tracking System
Contact owner@bugs.debian.org with problems
--- Begin Message ---
Package: release.debian.org
Severity: normal
User: release.debian.org@packages.debian.org
Usertags: unblock

Can I get a pre-approval and unblock for nettle 3.7.3-1? This is a pure bugfix release addressing only CVE-2021-3580, possible DOS vulnerability on invalid (zero 
or too large) input to RSA decryption functions.

(It also improves test coverage.)

https://security-tracker.debian.org/tracker/CVE-2021-3580
https://bugs.debian.org/989631

unblock nettle/3.7.3-1
 ChangeLog                        |  36 +++++++++++++++++++++++
 NEWS                             |  38 ++++++++++++++++++++++++
 configure                        |  22 +++++++-------
 configure.ac                     |   6 ++--
 debian/changelog                 |   7 +++++
 nettle.pdf                       | Bin 651264 -> 651264 bytes
 pkcs1-sec-decrypt.c              |   8 +++--
 rsa-decrypt-tr.c                 |  11 ++++---
 rsa-decrypt.c                    |  10 +++++++
 rsa-internal.h                   |   4 +--
 rsa-sec-decrypt.c                |  13 +++++++--
 rsa-sign-tr.c                    |  61 +++++++++++++++++++--------------------
 rsa.h                            |   5 ++--
 testsuite/rsa-encrypt-test.c     |  40 ++++++++++++++++++++++++-
 testsuite/rsa-sec-decrypt-test.c |  17 ++++++++++-
 15 files changed, 216 insertions(+), 62 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index bb169e8..4787cff 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,39 @@
+2021-05-22  Niels Möller  <nisse@lysator.liu.se>
+
+	* configure.ac: Bump package version, to 3.7.3.
+	(LIBNETTLE_MINOR): Bump minor number, to 8.4.
+	(LIBHOGWEED_MINOR): Bump minor number, to 6.4.
+
+2021-05-17  Niels Möller  <nisse@lysator.liu.se>
+
+	* rsa-decrypt-tr.c (rsa_decrypt_tr): Check up-front that input is
+	in range.
+	* rsa-sec-decrypt.c (rsa_sec_decrypt): Likewise.
+	* rsa-decrypt.c (rsa_decrypt): Likewise.
+	* testsuite/rsa-encrypt-test.c (test_main): Add tests with input > n.
+
+2021-05-14  Niels Möller  <nisse@lysator.liu.se>
+
+	* rsa-sign-tr.c (rsa_sec_blind): Delete mn argument.
+	(_rsa_sec_compute_root_tr): Delete mn argument, instead require
+	that input size matches key size. Rearrange use of temporary
+	storage, to support in-place operation, x == m. Update all
+	callers.
+
+	* rsa-decrypt-tr.c (rsa_decrypt_tr): Make zero-padded copy of
+	input, for calling _rsa_sec_compute_root_tr.
+	* rsa-sec-decrypt.c (rsa_sec_decrypt): Likewise.
+
+	* testsuite/rsa-encrypt-test.c (test_main): Test calling all of
+	rsa_decrypt, rsa_decrypt_tr, and rsa_sec_decrypt with zero input.
+
+2021-05-06  Niels Möller  <nisse@lysator.liu.se>
+
+	* pkcs1-sec-decrypt.c (_pkcs1_sec_decrypt): Check that message
+	length is valid, for given key size.
+	* testsuite/rsa-sec-decrypt-test.c (test_main): Add test cases for
+	calls to rsa_sec_decrypt specifying a too large message length.
+
 2021-03-21  Niels Möller  <nisse@lysator.liu.se>
 
 	* NEWS: NEWS entries for 3.7.2.
diff --git a/NEWS b/NEWS
index 897527c..4a55da8 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,41 @@
+NEWS for the Nettle 3.7.3 release
+
+	This is bugfix release, fixing bugs that could make the RSA
+	decryption functions crash on invalid inputs.
+
+	Upgrading to the new version is strongly recommended. For
+	applications that want to support older versions of Nettle,
+	the bug can be worked around by adding a check that the RSA
+	ciphertext is in the range 0 < ciphertext < n, before
+	attempting to decrypt it.
+
+	Thanks to Paul Schaub and Justus Winter for reporting these
+	problems.
+
+	The new version is intended to be fully source and binary
+	compatible with Nettle-3.6. The shared library names are
+	libnettle.so.8.4 and libhogweed.so.6.4, with sonames
+	libnettle.so.8 and libhogweed.so.6.
+
+	Bug fixes:
+
+	* Fix crash for zero input to rsa_sec_decrypt and
+	  rsa_decrypt_tr. Potential denial of service vector.
+
+	* Ensure that all of rsa_decrypt_tr and rsa_sec_decrypt return
+	  failure for out of range inputs, instead of either crashing,
+	  or silently reducing input modulo n. Potential denial of
+	  service vector.
+
+	* Ensure that rsa_decrypt returns failure for out of range
+	  inputs, instead of silently reducing input modulo n.
+
+	* Ensure that rsa_sec_decrypt returns failure if the message
+	  size is too large for the given key. Unlike the other bugs,
+	  this would typically be triggered by invalid local
+	  configuration, rather than by processing untrusted remote
+	  data.
+
 NEWS for the Nettle 3.7.2 release
 
 	This is a bugfix release, fixing a bug in ECDSA signature
diff --git a/configure b/configure
index 9dc199b..500bd92 100755
--- a/configure
+++ b/configure
@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.69 for nettle 3.7.2.
+# Generated by GNU Autoconf 2.69 for nettle 3.7.3.
 #
 # Report bugs to <nettle-bugs@lists.lysator.liu.se>.
 #
@@ -580,8 +580,8 @@ MAKEFLAGS=
 # Identity of this package.
 PACKAGE_NAME='nettle'
 PACKAGE_TARNAME='nettle'
-PACKAGE_VERSION='3.7.2'
-PACKAGE_STRING='nettle 3.7.2'
+PACKAGE_VERSION='3.7.3'
+PACKAGE_STRING='nettle 3.7.3'
 PACKAGE_BUGREPORT='nettle-bugs@lists.lysator.liu.se'
 PACKAGE_URL=''
 
@@ -1343,7 +1343,7 @@ if test "$ac_init_help" = "long"; then
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
-\`configure' configures nettle 3.7.2 to adapt to many kinds of systems.
+\`configure' configures nettle 3.7.3 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1409,7 +1409,7 @@ fi
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of nettle 3.7.2:";;
+     short | recursive ) echo "Configuration of nettle 3.7.3:";;
    esac
   cat <<\_ACEOF
 
@@ -1531,7 +1531,7 @@ fi
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-nettle configure 3.7.2
+nettle configure 3.7.3
 generated by GNU Autoconf 2.69
 
 Copyright (C) 2012 Free Software Foundation, Inc.
@@ -2175,7 +2175,7 @@ cat >config.log <<_ACEOF
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by nettle $as_me 3.7.2, which was
+It was created by nettle $as_me 3.7.3, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   $ $0 $@
@@ -2560,10 +2560,10 @@ ac_config_headers="$ac_config_headers config.h"
 
 
 LIBNETTLE_MAJOR=8
-LIBNETTLE_MINOR=3
+LIBNETTLE_MINOR=4
 
 LIBHOGWEED_MAJOR=6
-LIBHOGWEED_MINOR=3
+LIBHOGWEED_MINOR=4
 
 MAJOR_VERSION=`echo $PACKAGE_VERSION | sed 's/^\([^.]*\)\..*/\1/'`
 MINOR_VERSION=`echo $PACKAGE_VERSION | sed 's/^[^.]*\.\([0-9]*\).*/\1/'`
@@ -8142,7 +8142,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 ac_log="
-This file was extended by nettle $as_me 3.7.2, which was
+This file was extended by nettle $as_me 3.7.3, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -8208,7 +8208,7 @@ _ACEOF
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
 ac_cs_version="\\
-nettle config.status 3.7.2
+nettle config.status 3.7.3
 configured by $0, generated by GNU Autoconf 2.69,
   with options \\"\$ac_cs_config\\"
 
diff --git a/configure.ac b/configure.ac
index 9b2c153..f4d9e90 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2,7 +2,7 @@ dnl -*- mode: shell-script; sh-indentation: 2; -*-
 
 dnl Process this file with autoconf to produce a configure script.
 
-AC_INIT([nettle], [3.7.2], [nettle-bugs@lists.lysator.liu.se])
+AC_INIT([nettle], [3.7.3], [nettle-bugs@lists.lysator.liu.se])
 AC_PREREQ(2.61)
 AC_CONFIG_SRCDIR([arcfour.c])
 # Needed to stop autoconf from looking for files in parent directories.
@@ -11,10 +11,10 @@ AC_CONFIG_AUX_DIR([.])
 AC_CONFIG_HEADER([config.h])
 
 LIBNETTLE_MAJOR=8
-LIBNETTLE_MINOR=3
+LIBNETTLE_MINOR=4
 
 LIBHOGWEED_MAJOR=6
-LIBHOGWEED_MINOR=3
+LIBHOGWEED_MINOR=4
 
 dnl Note double square brackets, for extra m4 quoting.
 MAJOR_VERSION=`echo $PACKAGE_VERSION | sed 's/^\([[^.]]*\)\..*/\1/'`
diff --git a/debian/changelog b/debian/changelog
index 37928ba..b1820ea 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,10 @@
+nettle (3.7.3-1) unstable; urgency=high
+
+  * New upstream release fixing bugs that could make the RSA decryption
+    functions crash on invalid inputs [CVE-2021-3580] (Closes: #989631).
+
+ -- Magnus Holmgren <holmgren@debian.org>  Thu, 10 Jun 2021 08:51:41 +0200
+
 nettle (3.7.2-3) unstable; urgency=medium
 
   * libnettle8.symbols: Drop two more (internal) symbols from armel and
diff --git a/nettle.pdf b/nettle.pdf
index 14ffd94..1eae00d 100644
Binary files a/nettle.pdf and b/nettle.pdf differ
diff --git a/pkcs1-sec-decrypt.c b/pkcs1-sec-decrypt.c
index 4f13080..942a2bd 100644
--- a/pkcs1-sec-decrypt.c
+++ b/pkcs1-sec-decrypt.c
@@ -63,7 +63,9 @@ _pkcs1_sec_decrypt (size_t length, uint8_t *message,
   volatile int ok;
   size_t i, t;
 
-  assert (padded_message_length >= length);
+  /* Message independent branch */
+  if (length + 11 > padded_message_length)
+    return 0;
 
   t = padded_message_length - length - 1;
 
@@ -99,8 +101,8 @@ _pkcs1_sec_decrypt_variable(size_t *length, uint8_t *message,
 
   /* length is discovered in a side-channel silent way.
    * not_found goes to 0 when the terminator is found.
-   * offset strts at 3 as it includes the terminator and
-   * the fomat bytes already */
+   * offset starts at 3 as it includes the terminator and
+   * the format bytes already */
   offset = 3;
   for (i = 2; i < padded_message_length; i++)
     {
diff --git a/rsa-decrypt-tr.c b/rsa-decrypt-tr.c
index 0224c0b..4a9e9d7 100644
--- a/rsa-decrypt-tr.c
+++ b/rsa-decrypt-tr.c
@@ -52,14 +52,17 @@ rsa_decrypt_tr(const struct rsa_public_key *pub,
   mp_size_t key_limb_size;
   int res;
 
-  key_limb_size = NETTLE_OCTET_SIZE_TO_LIMB_SIZE(key->size);
+  /* First check that input is in range. */
+  if (mpz_sgn (gibberish) < 0 || mpz_cmp (gibberish, pub->n) >= 0)
+    return 0;
+
+  key_limb_size = mpz_size(pub->n);
 
   TMP_GMP_ALLOC (m, key_limb_size);
   TMP_GMP_ALLOC (em, key->size);
+  mpz_limbs_copy(m, gibberish, key_limb_size);
 
-  res = _rsa_sec_compute_root_tr (pub, key, random_ctx, random, m,
-				  mpz_limbs_read(gibberish),
-				  mpz_size(gibberish));
+  res = _rsa_sec_compute_root_tr (pub, key, random_ctx, random, m, m);
 
   mpn_get_base256 (em, key->size, m, key_limb_size);
 
diff --git a/rsa-decrypt.c b/rsa-decrypt.c
index 7681439..540d8ba 100644
--- a/rsa-decrypt.c
+++ b/rsa-decrypt.c
@@ -48,6 +48,16 @@ rsa_decrypt(const struct rsa_private_key *key,
   int res;
 
   mpz_init(m);
+
+  /* First check that input is in range. Since we don't have the
+     public key available here, we need to reconstruct n. */
+  mpz_mul (m, key->p, key->q);
+  if (mpz_sgn (gibberish) < 0 || mpz_cmp (gibberish, m) >= 0)
+    {
+      mpz_clear (m);
+      return 0;
+    }
+
   rsa_compute_root(key, m, gibberish);
 
   res = pkcs1_decrypt (key->size, m, length, message);
diff --git a/rsa-internal.h b/rsa-internal.h
index b828e45..f66a7df 100644
--- a/rsa-internal.h
+++ b/rsa-internal.h
@@ -78,11 +78,11 @@ _rsa_sec_compute_root(const struct rsa_private_key *key,
                       mp_limb_t *scratch);
 
 /* Safe side-channel silent variant, using RSA blinding, and checking the
- * result after CRT. */
+ * result after CRT. In-place calls, with x == m, is allowed. */
 int
 _rsa_sec_compute_root_tr(const struct rsa_public_key *pub,
 			 const struct rsa_private_key *key,
 			 void *random_ctx, nettle_random_func *random,
-			 mp_limb_t *x, const mp_limb_t *m, size_t mn);
+			 mp_limb_t *x, const mp_limb_t *m);
 
 #endif /* NETTLE_RSA_INTERNAL_H_INCLUDED */
diff --git a/rsa-sec-decrypt.c b/rsa-sec-decrypt.c
index 6866e7c..4c98958 100644
--- a/rsa-sec-decrypt.c
+++ b/rsa-sec-decrypt.c
@@ -55,12 +55,19 @@ rsa_sec_decrypt(const struct rsa_public_key *pub,
   TMP_GMP_DECL (em, uint8_t);
   int res;
 
+  /* First check that input is in range. */
+  if (mpz_sgn (gibberish) < 0 || mpz_cmp (gibberish, pub->n) >= 0)
+    return 0;
+
   TMP_GMP_ALLOC (m, mpz_size(pub->n));
   TMP_GMP_ALLOC (em, key->size);
 
-  res = _rsa_sec_compute_root_tr (pub, key, random_ctx, random, m,
-				  mpz_limbs_read(gibberish),
-				  mpz_size(gibberish));
+  /* We need a copy because m can be shorter than key_size,
+   * but _rsa_sec_compute_root_tr expect all inputs to be
+   * normalized to a key_size long buffer length */
+  mpz_limbs_copy(m, gibberish, mpz_size(pub->n));
+
+  res = _rsa_sec_compute_root_tr (pub, key, random_ctx, random, m, m);
 
   mpn_get_base256 (em, key->size, m, mpz_size(pub->n));
 
diff --git a/rsa-sign-tr.c b/rsa-sign-tr.c
index f824c4c..9e137c7 100644
--- a/rsa-sign-tr.c
+++ b/rsa-sign-tr.c
@@ -131,35 +131,34 @@ int
 _rsa_sec_compute_root_tr(const struct rsa_public_key *pub,
 			 const struct rsa_private_key *key,
 			 void *random_ctx, nettle_random_func *random,
-			 mp_limb_t *x, const mp_limb_t *m, size_t mn)
+			 mp_limb_t *x, const mp_limb_t *m)
 {
+  mp_size_t nn;
   mpz_t mz;
   mpz_t xz;
   int res;
 
-  mpz_init(mz);
   mpz_init(xz);
 
-  mpn_copyi(mpz_limbs_write(mz, mn), m, mn);
-  mpz_limbs_finish(mz, mn);
+  nn = mpz_size (pub->n);
 
-  res = rsa_compute_root_tr(pub, key, random_ctx, random, xz, mz);
+  res = rsa_compute_root_tr(pub, key, random_ctx, random, xz,
+			    mpz_roinit_n(mz, m, nn));
 
   if (res)
-    mpz_limbs_copy(x, xz, mpz_size(pub->n));
+    mpz_limbs_copy(x, xz, nn);
 
-  mpz_clear(mz);
   mpz_clear(xz);
   return res;
 }
 #else
 /* Blinds m, by computing c = m r^e (mod n), for a random r. Also
-   returns the inverse (ri), for use by rsa_unblind. */
+   returns the inverse (ri), for use by rsa_unblind. Must have c != m,
+   no in-place operation.*/
 static void
 rsa_sec_blind (const struct rsa_public_key *pub,
                void *random_ctx, nettle_random_func *random,
-               mp_limb_t *c, mp_limb_t *ri, const mp_limb_t *m,
-               mp_size_t mn)
+               mp_limb_t *c, mp_limb_t *ri, const mp_limb_t *m)
 {
   const mp_limb_t *ep = mpz_limbs_read (pub->e);
   const mp_limb_t *np = mpz_limbs_read (pub->n);
@@ -177,15 +176,15 @@ rsa_sec_blind (const struct rsa_public_key *pub,
 
   /* c = m*(r^e) mod n */
   itch = mpn_sec_powm_itch(nn, ebn, nn);
-  i2 = mpn_sec_mul_itch(nn, mn);
+  i2 = mpn_sec_mul_itch(nn, nn);
   itch = MAX(itch, i2);
-  i2 = mpn_sec_div_r_itch(nn + mn, nn);
+  i2 = mpn_sec_div_r_itch(2*nn, nn);
   itch = MAX(itch, i2);
   i2 = mpn_sec_invert_itch(nn);
   itch = MAX(itch, i2);
 
-  TMP_GMP_ALLOC (tp, nn + mn + itch);
-  scratch = tp + nn + mn;
+  TMP_GMP_ALLOC (tp, 2*nn  + itch);
+  scratch = tp + 2*nn;
 
   /* ri = r^(-1) */
   do
@@ -198,9 +197,8 @@ rsa_sec_blind (const struct rsa_public_key *pub,
   while (!mpn_sec_invert (ri, tp, np, nn, 2 * nn * GMP_NUMB_BITS, scratch));
 
   mpn_sec_powm (c, rp, nn, ep, ebn, np, nn, scratch);
-  /* normally mn == nn, but m can be smaller in some cases */
-  mpn_sec_mul (tp, c, nn, m, mn, scratch);
-  mpn_sec_div_r (tp, nn + mn, np, nn, scratch);
+  mpn_sec_mul (tp, c, nn, m, nn, scratch);
+  mpn_sec_div_r (tp, 2*nn, np, nn, scratch);
   mpn_copyi(c, tp, nn);
 
   TMP_GMP_FREE (r);
@@ -208,7 +206,7 @@ rsa_sec_blind (const struct rsa_public_key *pub,
   TMP_GMP_FREE (tp);
 }
 
-/* m = c ri mod n */
+/* m = c ri mod n. Allows x == c. */
 static void
 rsa_sec_unblind (const struct rsa_public_key *pub,
                  mp_limb_t *x, mp_limb_t *ri, const mp_limb_t *c)
@@ -299,7 +297,7 @@ int
 _rsa_sec_compute_root_tr(const struct rsa_public_key *pub,
 			 const struct rsa_private_key *key,
 			 void *random_ctx, nettle_random_func *random,
-			 mp_limb_t *x, const mp_limb_t *m, size_t mn)
+			 mp_limb_t *x, const mp_limb_t *m)
 {
   TMP_GMP_DECL (c, mp_limb_t);
   TMP_GMP_DECL (ri, mp_limb_t);
@@ -307,7 +305,7 @@ _rsa_sec_compute_root_tr(const struct rsa_public_key *pub,
   size_t key_limb_size;
   int ret;
 
-  key_limb_size = NETTLE_OCTET_SIZE_TO_LIMB_SIZE(key->size);
+  key_limb_size = mpz_size(pub->n);
 
   /* mpz_powm_sec handles only odd moduli. If p, q or n is even, the
      key is invalid and rejected by rsa_private_key_prepare. However,
@@ -321,19 +319,18 @@ _rsa_sec_compute_root_tr(const struct rsa_public_key *pub,
     }
 
   assert(mpz_size(pub->n) == key_limb_size);
-  assert(mn <= key_limb_size);
 
   TMP_GMP_ALLOC (c, key_limb_size);
   TMP_GMP_ALLOC (ri, key_limb_size);
   TMP_GMP_ALLOC (scratch, _rsa_sec_compute_root_itch(key));
 
-  rsa_sec_blind (pub, random_ctx, random, x, ri, m, mn);
+  rsa_sec_blind (pub, random_ctx, random, c, ri, m);
 
-  _rsa_sec_compute_root(key, c, x, scratch);
+  _rsa_sec_compute_root(key, x, c, scratch);
 
-  ret = rsa_sec_check_root(pub, c, x);
+  ret = rsa_sec_check_root(pub, x, c);
 
-  rsa_sec_unblind(pub, x, ri, c);
+  rsa_sec_unblind(pub, x, ri, x);
 
   cnd_mpn_zero(1 - ret, x, key_limb_size);
 
@@ -357,17 +354,17 @@ rsa_compute_root_tr(const struct rsa_public_key *pub,
 		    mpz_t x, const mpz_t m)
 {
   TMP_GMP_DECL (l, mp_limb_t);
+  mp_size_t nn = mpz_size(pub->n);
   int res;
 
-  mp_size_t l_size = NETTLE_OCTET_SIZE_TO_LIMB_SIZE(key->size);
-  TMP_GMP_ALLOC (l, l_size);
+  TMP_GMP_ALLOC (l, nn);
+  mpz_limbs_copy(l, m, nn);
 
-  res = _rsa_sec_compute_root_tr (pub, key, random_ctx, random, l,
-				  mpz_limbs_read(m), mpz_size(m));
+  res = _rsa_sec_compute_root_tr (pub, key, random_ctx, random, l, l);
   if (res) {
-    mp_limb_t *xp = mpz_limbs_write (x, l_size);
-    mpn_copyi (xp, l, l_size);
-    mpz_limbs_finish (x, l_size);
+    mp_limb_t *xp = mpz_limbs_write (x, nn);
+    mpn_copyi (xp, l, nn);
+    mpz_limbs_finish (x, nn);
   }
 
   TMP_GMP_FREE (l);
diff --git a/rsa.h b/rsa.h
index 3b10155..2dd35a2 100644
--- a/rsa.h
+++ b/rsa.h
@@ -428,13 +428,14 @@ rsa_sec_decrypt(const struct rsa_public_key *pub,
 	        size_t length, uint8_t *message,
 	        const mpz_t gibberish);
 
-/* Compute x, the e:th root of m. Calling it with x == m is allowed. */
+/* Compute x, the e:th root of m. Calling it with x == m is allowed.
+   It is required that 0 <= m < n. */
 void
 rsa_compute_root(const struct rsa_private_key *key,
 		 mpz_t x, const mpz_t m);
 
 /* Safer variant, using RSA blinding, and checking the result after
-   CRT. */
+   CRT. It is required that 0 <= m < n. */
 int
 rsa_compute_root_tr(const struct rsa_public_key *pub,
 		    const struct rsa_private_key *key,
diff --git a/testsuite/rsa-encrypt-test.c b/testsuite/rsa-encrypt-test.c
index 87525f7..d1a440f 100644
--- a/testsuite/rsa-encrypt-test.c
+++ b/testsuite/rsa-encrypt-test.c
@@ -19,10 +19,12 @@ test_main(void)
   uint8_t after;
 
   mpz_t gibberish;
+  mpz_t bad_input;
 
   rsa_private_key_init(&key);
   rsa_public_key_init(&pub);
   mpz_init(gibberish);
+  mpz_init(bad_input);
 
   knuth_lfib_init(&lfib, 17);
   
@@ -101,6 +103,42 @@ test_main(void)
   ASSERT(decrypted[decrypted_length] == after);
   ASSERT(decrypted[0] == 'A');
 
+  /* Test zero input. */
+  mpz_set_ui (bad_input, 0);
+  decrypted_length = msg_length;
+  ASSERT(!rsa_decrypt(&key, &decrypted_length, decrypted, bad_input));
+  ASSERT(!rsa_decrypt_tr(&pub, &key,
+			 &lfib, (nettle_random_func *) knuth_lfib_random,
+			 &decrypted_length, decrypted, bad_input));
+  ASSERT(!rsa_sec_decrypt(&pub, &key,
+			  &lfib, (nettle_random_func *) knuth_lfib_random,
+			  decrypted_length, decrypted, bad_input));
+  ASSERT(decrypted_length == msg_length);
+
+  /* Test input that is slightly larger than n */
+  mpz_add(bad_input, gibberish, pub.n);
+  decrypted_length = msg_length;
+  ASSERT(!rsa_decrypt(&key, &decrypted_length, decrypted, bad_input));
+  ASSERT(!rsa_decrypt_tr(&pub, &key,
+			 &lfib, (nettle_random_func *) knuth_lfib_random,
+			 &decrypted_length, decrypted, bad_input));
+  ASSERT(!rsa_sec_decrypt(&pub, &key,
+			  &lfib, (nettle_random_func *) knuth_lfib_random,
+			  decrypted_length, decrypted, bad_input));
+  ASSERT(decrypted_length == msg_length);
+
+  /* Test input that is considerably larger than n */
+  mpz_mul_2exp (bad_input, pub.n, 100);
+  mpz_add (bad_input, bad_input, gibberish);
+  decrypted_length = msg_length;
+  ASSERT(!rsa_decrypt(&key, &decrypted_length, decrypted, bad_input));
+  ASSERT(!rsa_decrypt_tr(&pub, &key,
+			 &lfib, (nettle_random_func *) knuth_lfib_random,
+			 &decrypted_length, decrypted, bad_input));
+  ASSERT(!rsa_sec_decrypt(&pub, &key,
+			  &lfib, (nettle_random_func *) knuth_lfib_random,
+			  decrypted_length, decrypted, bad_input));
+  ASSERT(decrypted_length == msg_length);
 
   /* Test invalid key. */
   mpz_add_ui (key.q, key.q, 2);
@@ -112,6 +150,6 @@ test_main(void)
   rsa_private_key_clear(&key);
   rsa_public_key_clear(&pub);
   mpz_clear(gibberish);
+  mpz_clear(bad_input);
   free(decrypted);
 }
-  
diff --git a/testsuite/rsa-sec-decrypt-test.c b/testsuite/rsa-sec-decrypt-test.c
index fb0ed3a..3419322 100644
--- a/testsuite/rsa-sec-decrypt-test.c
+++ b/testsuite/rsa-sec-decrypt-test.c
@@ -55,6 +55,7 @@ rsa_decrypt_for_test(const struct rsa_public_key *pub,
 #endif
 
 #define PAYLOAD_SIZE 50
+#define DECRYPTED_SIZE 256
 void
 test_main(void)
 {
@@ -63,7 +64,7 @@ test_main(void)
   struct knuth_lfib_ctx random_ctx;
 
   uint8_t plaintext[PAYLOAD_SIZE];
-  uint8_t decrypted[PAYLOAD_SIZE];
+  uint8_t decrypted[DECRYPTED_SIZE];
   uint8_t verifybad[PAYLOAD_SIZE];
   unsigned n_size = 1024;
   mpz_t gibberish;
@@ -99,6 +100,20 @@ test_main(void)
                                     PAYLOAD_SIZE, decrypted, gibberish) == 1);
       ASSERT (MEMEQ (PAYLOAD_SIZE, plaintext, decrypted));
 
+      ASSERT (pub.size > 10);
+      ASSERT (pub.size <= DECRYPTED_SIZE);
+
+      /* Check that too large message length is rejected, largest
+	 valid size is pub.size - 11. */
+      ASSERT (!rsa_decrypt_for_test (&pub, &key, &random_ctx,
+				     (nettle_random_func *) knuth_lfib_random,
+				     pub.size - 10, decrypted, gibberish));
+
+      /* This case used to result in arithmetic underflow and a crash. */
+      ASSERT (!rsa_decrypt_for_test (&pub, &key, &random_ctx,
+				     (nettle_random_func *) knuth_lfib_random,
+				     pub.size, decrypted, gibberish));
+
       /* bad one */
       memcpy(decrypted, verifybad, PAYLOAD_SIZE);
       nettle_mpz_random_size(garbage, &random_ctx,

--- End Message ---
--- Begin Message ---
Unblocked.

--- End Message ---

Reply to: