Add the proper limit to PKCS5_PBKDF2_HMAC.

RFC 8018 states one to avoid cycling - so let's do that.

Change-Id: I7abe0165e37cd35a94f02f889ad49be16a6a6964
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/95931
Commit-Queue: Rudolf Polzer <rpolzer@google.com>
Reviewed-by: David Benjamin <davidben@google.com>
diff --git a/crypto/evp/pbkdf.cc b/crypto/evp/pbkdf.cc
index 6388876..aad9348 100644
--- a/crypto/evp/pbkdf.cc
+++ b/crypto/evp/pbkdf.cc
@@ -16,6 +16,7 @@
 
 #include <string.h>
 
+#include <openssl/err.h>
 #include <openssl/hmac.h>
 
 #include "../internal.h"
@@ -34,6 +35,10 @@
 
   uint32_t i = 1;
   size_t md_len = EVP_MD_size(digest);
+  if (key_len > ((uint64_t{1} << 32) - 1) * md_len) {
+    OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_SECRET_LENGTH);
+    return 0;
+  }
   while (key_len > 0) {
     size_t todo = md_len;
     if (todo > key_len) {
diff --git a/crypto/evp/pbkdf_test.cc b/crypto/evp/pbkdf_test.cc
index d6a321f..5daffa7 100644
--- a/crypto/evp/pbkdf_test.cc
+++ b/crypto/evp/pbkdf_test.cc
@@ -15,6 +15,7 @@
 #include <gtest/gtest.h>
 
 #include <openssl/digest.h>
+#include <openssl/err.h>
 #include <openssl/evp.h>
 
 #include "../internal.h"
@@ -148,3 +149,18 @@
   // the out key.
   EXPECT_EQ(expected_first_byte, key[0]);
 }
+
+#if defined(OPENSSL_64_BIT)
+TEST(PBKDFTest, HugeKeyLen) {
+  static const char kPassword[] = "password";
+  static const uint8_t kSalt[] = {1, 2, 3, 4};
+  // Try a size chosen to clearly exceed the limit of 2^32-1 SHA-1 blocks by 1.
+  // In case the function does not reject this input, it will crash on writing
+  // to the nullptr.
+  EXPECT_FALSE(PKCS5_PBKDF2_HMAC(kPassword, strlen(kPassword), kSalt,
+                                 sizeof(kSalt), 1, EVP_sha1(),
+                                 size_t{SHA_DIGEST_LENGTH} << 32, nullptr));
+  EXPECT_TRUE(
+      ErrorEquals(ERR_get_error(), ERR_LIB_EVP, EVP_R_INVALID_SECRET_LENGTH));
+}
+#endif