Limit PEM data to 1 GiB.

There should be no single PEM block of this size in existence. This limit
however guards against possible integer overflows in other moduels. A
PEM block larger than this will be skipped by libpki (which has no way
to report errors to begin with), and return ERR_R_OVERFLOW from
libcrypto.

Update-Note: if you hit this, try reducing the size of your PEM blocks.

Change-Id: I99962d363b54f40e963793f15f0dcda56a6a6964
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/94967
Reviewed-by: Xiangfei Ding <xfding@google.com>
Presubmit-BoringSSL-Verified: boringssl-scoped@luci-project-accounts.iam.gserviceaccount.com <boringssl-scoped@luci-project-accounts.iam.gserviceaccount.com>
Commit-Queue: Rudolf Polzer <rpolzer@google.com>
diff --git a/crypto/pem/pem_lib.cc b/crypto/pem/pem_lib.cc
index bbe9abd..3fb8515 100644
--- a/crypto/pem/pem_lib.cc
+++ b/crypto/pem/pem_lib.cc
@@ -628,6 +628,14 @@
         return false;
       }
       size_t new_len = out_len + i;
+      if (new_len > INT_MAX / 2) {
+        // Arbitrarily limit PEM data to INT_MAX / 2 bytes, which "ought to be
+        // enough for anyone". Hardens against possible integer overflows
+        // downstream.
+        OPENSSL_PUT_ERROR(PEM, ERR_R_OVERFLOW);
+        failed = true;
+        return false;
+      }
       if (!BUF_MEM_grow(out, new_len + 1)) {
         OPENSSL_PUT_ERROR(PEM, ERR_R_MALLOC_FAILURE);
         failed = true;
diff --git a/include/openssl/pem.h b/include/openssl/pem.h
index 5a4c2ab..0e49162 100644
--- a/include/openssl/pem.h
+++ b/include/openssl/pem.h
@@ -38,6 +38,9 @@
 // This library contains functions for reading and writing data encoded in PEM
 // format. This format originated in Privacy-Enhanced Mail (RFC 1421).
 //
+// As an exception to RFC 1421, generally PEM data is limited to 1 GiB by this
+// library. This limit should not affect anyone in practice.
+//
 // TODO(crbug.com/42290574): Finish documenting this header.
 
 
diff --git a/pki/pem.cc b/pki/pem.cc
index 54a7595..c5f84bc 100644
--- a/pki/pem.cc
+++ b/pki/pem.cc
@@ -16,6 +16,7 @@
 #include "string_util.h"
 
 #include <array>
+#include <limits>
 #include <string_view>
 
 namespace {
@@ -81,6 +82,14 @@
       pos_ = footer_pos + it->footer.size();
       block_type_ = it->type;
 
+      // Arbitrarily limit PEM data to INT_MAX / 2 bytes, which "ought to be
+      // enough for anyone". Hardens against possible integer overflows
+      // downstream.
+      if (footer_pos - data_begin > static_cast<std::string_view::size_type>(
+                                        std::numeric_limits<int>::max() / 2)) {
+        return false;
+      }
+
       // Remove whitespace from the base64 data.
       std::string_view encoded =
           str_.substr(data_begin, footer_pos - data_begin);