aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNick Mathewson <nickm@torproject.org>2020-03-17 10:45:03 -0400
committerNick Mathewson <nickm@torproject.org>2020-03-17 10:45:03 -0400
commit9163781039b96e859fc102f003a274e9716cc02d (patch)
treeb4c388080dda6861a96184456692ec0933114755
parentdd6e2277e0d336f3d519f88d792b832d04e2c323 (diff)
parentf958b537abc1285dd627c03f091dc94a5d17995a (diff)
downloadtor-9163781039b96e859fc102f003a274e9716cc02d.tar.gz
tor-9163781039b96e859fc102f003a274e9716cc02d.zip
Merge branch 'trove_2020_002_035' into trove_2020_002_041
-rw-r--r--src/lib/crypt_ops/crypto_rsa_nss.c2
-rw-r--r--src/lib/crypt_ops/crypto_rsa_openssl.c57
-rw-r--r--src/test/test_crypto.c15
3 files changed, 68 insertions, 6 deletions
diff --git a/src/lib/crypt_ops/crypto_rsa_nss.c b/src/lib/crypt_ops/crypto_rsa_nss.c
index c716126f95..fd8fda486e 100644
--- a/src/lib/crypt_ops/crypto_rsa_nss.c
+++ b/src/lib/crypt_ops/crypto_rsa_nss.c
@@ -736,7 +736,7 @@ crypto_pk_asn1_decode_private(const char *str, size_t len, int max_bits)
if (output) {
const int bits = SECKEY_PublicKeyStrengthInBits(output->pubkey);
- if (max_bits > 0 && bits > max_bits) {
+ if (max_bits >= 0 && bits > max_bits) {
log_info(LD_CRYPTO, "Private key longer than expected.");
crypto_pk_free(output);
output = NULL;
diff --git a/src/lib/crypt_ops/crypto_rsa_openssl.c b/src/lib/crypt_ops/crypto_rsa_openssl.c
index 0db25f3473..6f3ac6fde6 100644
--- a/src/lib/crypt_ops/crypto_rsa_openssl.c
+++ b/src/lib/crypt_ops/crypto_rsa_openssl.c
@@ -33,6 +33,7 @@ ENABLE_GCC_WARNING(redundant-decls)
#include "lib/encoding/binascii.h"
#include <string.h>
+#include <stdbool.h>
/** Declaration for crypto_pk_t structure. */
struct crypto_pk_t
@@ -564,6 +565,56 @@ crypto_pk_asn1_encode_private(const crypto_pk_t *pk, char *dest,
return len;
}
+/** Check whether any component of a private key is too large in a way that
+ * seems likely to make verification too expensive. Return true if it's too
+ * long, and false otherwise. */
+static bool
+rsa_private_key_too_long(RSA *rsa, int max_bits)
+{
+ const BIGNUM *n, *e, *p, *q, *d, *dmp1, *dmq1, *iqmp;
+#ifdef OPENSSL_1_1_API
+ n = RSA_get0_n(rsa);
+ e = RSA_get0_e(rsa);
+ p = RSA_get0_p(rsa);
+ q = RSA_get0_q(rsa);
+ d = RSA_get0_d(rsa);
+ dmp1 = RSA_get0_dmp1(rsa);
+ dmq1 = RSA_get0_dmq1(rsa);
+ iqmp = RSA_get0_iqmp(rsa);
+
+ if (RSA_bits(rsa) > max_bits)
+ return true;
+#else
+ n = rsa->n;
+ e = rsa->e;
+ p = rsa->p;
+ q = rsa->q;
+ d = rsa->d;
+ dmp1 = rsa->dmp1;
+ dmq1 = rsa->dmq1;
+ iqmp = rsa->iqmp;
+#endif
+
+ if (n && BN_num_bits(n) > max_bits)
+ return true;
+ if (e && BN_num_bits(e) > max_bits)
+ return true;
+ if (p && BN_num_bits(p) > max_bits)
+ return true;
+ if (q && BN_num_bits(q) > max_bits)
+ return true;
+ if (d && BN_num_bits(d) > max_bits)
+ return true;
+ if (dmp1 && BN_num_bits(dmp1) > max_bits)
+ return true;
+ if (dmq1 && BN_num_bits(dmq1) > max_bits)
+ return true;
+ if (iqmp && BN_num_bits(iqmp) > max_bits)
+ return true;
+
+ return false;
+}
+
/** Decode an ASN.1-encoded private key from <b>str</b>; return the result on
* success and NULL on failure.
*
@@ -584,11 +635,7 @@ crypto_pk_asn1_decode_private(const char *str, size_t len, int max_bits)
crypto_openssl_log_errors(LOG_WARN,"decoding private key");
return NULL;
}
-#ifdef OPENSSL_1_1_API
- if (max_bits >= 0 && RSA_bits(rsa) > max_bits) {
-#else
- if (max_bits >= 0 && rsa->n && BN_num_bits(rsa->n) > max_bits) {
-#endif
+ if (max_bits >= 0 && rsa_private_key_too_long(rsa, max_bits)) {
log_info(LD_CRYPTO, "Private key longer than expected.");
RSA_free(rsa);
return NULL;
diff --git a/src/test/test_crypto.c b/src/test/test_crypto.c
index 6bdce81b3e..d1c652f058 100644
--- a/src/test/test_crypto.c
+++ b/src/test/test_crypto.c
@@ -1349,6 +1349,21 @@ test_crypto_pk_bad_size(void *arg)
pk2 = crypto_pk_asn1_decode_private(buf, n, 1020);
tt_assert(! pk2);
+ /* Set the max bit count one bit smaller: we should refuse to decode the
+ key.*/
+ pk2 = crypto_pk_asn1_decode_private(buf, n, 1023);
+ tt_assert(! pk2);
+
+ /* Correct size: should work. */
+ pk2 = crypto_pk_asn1_decode_private(buf, n, 1024);
+ tt_assert(pk2);
+ crypto_pk_free(pk2);
+
+ /* One bit larger: should work. */
+ pk2 = crypto_pk_asn1_decode_private(buf, n, 1025);
+ tt_assert(pk2);
+ crypto_pk_free(pk2);
+
/* Set the max bit count larger: it should decode fine. */
pk2 = crypto_pk_asn1_decode_private(buf, n, 2048);
tt_assert(pk2);