Use rapidjson::kParseIterativeFlag when parsing JSON keysets.

This makes sure that the stack size remains constant while parsing.

PiperOrigin-RevId: 623736071
Change-Id: I76fdf60f2a754afceae97bada6ce242ed4dc6e8c
(cherry picked from commit 570e4156e80fd0673a735986537cb15a452606b4)
diff --git a/tink/BUILD.bazel b/tink/BUILD.bazel
index 6e68067..27515b8 100644
--- a/tink/BUILD.bazel
+++ b/tink/BUILD.bazel
@@ -364,8 +364,6 @@
         ":keyset_reader",
         "//proto:tink_cc_proto",
         "//tink/util:enums",
-        "//tink/util:errors",
-        "//tink/util:protobuf_helper",
         "//tink/util:status",
         "//tink/util:statusor",
         "@com_google_absl//absl/memory",
@@ -852,9 +850,11 @@
     srcs = ["core/json_keyset_reader_test.cc"],
     deps = [
         ":json_keyset_reader",
+        ":keyset_reader",
         "//proto:aes_eax_cc_proto",
         "//proto:aes_gcm_cc_proto",
         "//proto:tink_cc_proto",
+        "//tink/util:statusor",
         "//tink/util:test_matchers",
         "//tink/util:test_util",
         "@com_google_absl//absl/strings",
diff --git a/tink/CMakeLists.txt b/tink/CMakeLists.txt
index 9f8db69..45aa936 100644
--- a/tink/CMakeLists.txt
+++ b/tink/CMakeLists.txt
@@ -342,8 +342,6 @@
     absl::strings
     rapidjson
     tink::util::enums
-    tink::util::errors
-    tink::util::protobuf_helper
     tink::util::status
     tink::util::statusor
     tink::proto::tink_cc_proto
@@ -795,8 +793,10 @@
     core/json_keyset_reader_test.cc
   DEPS
     tink::core::json_keyset_reader
+    tink::core::keyset_reader
     gmock
     absl::strings
+    tink::util::statusor
     tink::util::test_matchers
     tink::util::test_util
     tink::proto::aes_eax_cc_proto
diff --git a/tink/core/json_keyset_reader.cc b/tink/core/json_keyset_reader.cc
index 43f6a94..f93b6a5 100644
--- a/tink/core/json_keyset_reader.cc
+++ b/tink/core/json_keyset_reader.cc
@@ -28,6 +28,9 @@
 #include "absl/strings/str_cat.h"
 #include "include/rapidjson/document.h"
 #include "include/rapidjson/error/en.h"
+#include "include/rapidjson/rapidjson.h"
+#include "include/rapidjson/reader.h"
+#include "tink/keyset_reader.h"
 #include "tink/util/enums.h"
 #include "tink/util/status.h"
 #include "tink/util/statusor.h"
@@ -252,7 +255,8 @@
     serialized_keyset = &serialized_keyset_from_stream;
   }
   rapidjson::Document json_doc(rapidjson::kObjectType);
-  if (json_doc.Parse(serialized_keyset->c_str()).HasParseError()) {
+  if (json_doc.Parse<rapidjson::kParseIterativeFlag>(serialized_keyset->c_str())
+          .HasParseError()) {
     return util::Status(
         absl::StatusCode::kInvalidArgument,
         absl::StrCat(
@@ -278,7 +282,8 @@
     serialized_keyset = &serialized_keyset_from_stream;
   }
   rapidjson::Document json_doc;
-  if (json_doc.Parse(serialized_keyset->c_str()).HasParseError()) {
+  if (json_doc.Parse<rapidjson::kParseIterativeFlag>(serialized_keyset->c_str())
+          .HasParseError()) {
     return util::Status(
         absl::StatusCode::kInvalidArgument,
         absl::StrCat("Invalid JSON EncryptedKeyset: Error (offset ",
diff --git a/tink/core/json_keyset_reader_test.cc b/tink/core/json_keyset_reader_test.cc
index 9dff5be..1af3235 100644
--- a/tink/core/json_keyset_reader_test.cc
+++ b/tink/core/json_keyset_reader_test.cc
@@ -27,11 +27,13 @@
 #include "gtest/gtest.h"
 #include "absl/strings/escaping.h"
 #include "absl/strings/substitute.h"
+#include "tink/util/statusor.h"
 #include "tink/util/test_matchers.h"
 #include "tink/util/test_util.h"
 #include "proto/aes_eax.pb.h"
 #include "proto/aes_gcm.pb.h"
 #include "proto/tink.pb.h"
+#include "tink/keyset_reader.h"
 
 namespace crypto {
 namespace tink {
@@ -395,6 +397,23 @@
   EXPECT_THAT(read_result, Not(IsOk()));
 }
 
+
+TEST_F(JsonKeysetReaderTest, parseRecursiveJsonStringFails) {
+  std::string recursive_json;
+  for (int i = 0; i < 1000000; i++) {
+    recursive_json.append("{\"a\":");
+  }
+  recursive_json.append("1");
+  for (int i = 0; i < 1000000; i++) {
+    recursive_json.append("}");
+  }
+  util::StatusOr<std::unique_ptr<KeysetReader>> reader =
+      JsonKeysetReader::New(recursive_json);
+  ASSERT_THAT(reader, IsOk());
+  util::StatusOr<std::unique_ptr<Keyset>> keyset = (*reader)->Read();
+  EXPECT_THAT(keyset, Not(IsOk()));
+}
+
 }  // namespace
 }  // namespace tink
 }  // namespace crypto