Accept invalid "v3" CSRs.

Although not defined, older versions of certbot use numeric value 2,
which would be a hypothetical v3(2). See
https://github.com/certbot/certbot/pull/9334. Accept these for
compatibility.

Bug: 467
Change-Id: I47cc64503569992595bdb42baa6333058d560242
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/53229
Reviewed-by: Bob Beck <bbe@google.com>
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/crypto/x509/t_req.c b/crypto/x509/t_req.c
index b9090b9..154fb75 100644
--- a/crypto/x509/t_req.c
+++ b/crypto/x509/t_req.c
@@ -105,7 +105,9 @@
   }
   if (!(cflag & X509_FLAG_NO_VERSION)) {
     l = X509_REQ_get_version(x);
-    assert(l == X509_REQ_VERSION_1);
+    // Only zero, |X509_REQ_VERSION_1|, is valid but our parser accepts some
+    // invalid values for compatibility.
+    assert(0 <= l && l <= 2);
     if (BIO_printf(bio, "%8sVersion: %ld (0x%lx)\n", "", l + 1,
                    (unsigned long)l) <= 0) {
       goto err;
diff --git a/crypto/x509/x509_test.cc b/crypto/x509/x509_test.cc
index fe4a775..425d745 100644
--- a/crypto/x509/x509_test.cc
+++ b/crypto/x509/x509_test.cc
@@ -2936,6 +2936,17 @@
 -----END CERTIFICATE REQUEST-----
 )";
 
+// kV3CSRPEM is a v3 CSR. CSR versions only go up to v1.
+static const char kV3CSRPEM[] = R"(
+-----BEGIN CERTIFICATE REQUEST-----
+MIHJMHECAQIwDzENMAsGA1UEAwwEVGVzdDBZMBMGByqGSM49AgEGCCqGSM49AwEH
+A0IABJjsayyAQod1J7UJYNT8AH4WWxLdKV0ozhrIz6hCzBAze7AqXWOSH8G+1EWC
+pSfL3oMQNtBdJS0kpXXaUqEAgTSgADAKBggqhkjOPQQDAgNIADBFAiAUXVaEYATg
+4Cc917T73KBImxh6xyhsA5pKuYpq1S4m9wIhAK+G93HR4ur7Ghel6+zUTvIAsj9e
+rsn4lSYsqI4OI4ei
+-----END CERTIFICATE REQUEST-----
+)";
+
 // Test that the library enforces versions are valid and match the fields
 // present.
 TEST(X509Test, InvalidVersion) {
@@ -2955,6 +2966,10 @@
   EXPECT_FALSE(CRLFromPEM(kV3CRLPEM));
   EXPECT_FALSE(CSRFromPEM(kV2CSRPEM));
 
+  // kV3CSRPEM is invalid but, for now, we accept it. See
+  // https://github.com/certbot/certbot/pull/9334
+  EXPECT_TRUE(CSRFromPEM(kV3CSRPEM));
+
   bssl::UniquePtr<X509> x509(X509_new());
   ASSERT_TRUE(x509);
   EXPECT_FALSE(X509_set_version(x509.get(), -1));
diff --git a/crypto/x509/x_req.c b/crypto/x509/x_req.c
index 4ddeaea..f7faf39 100644
--- a/crypto/x509/x_req.c
+++ b/crypto/x509/x_req.c
@@ -82,7 +82,11 @@
   }
 
   if (operation == ASN1_OP_D2I_POST) {
-    if (ASN1_INTEGER_get(rinf->version) != X509_REQ_VERSION_1) {
+    // The only defined CSR version is v1(0). For compatibility, we also accept
+    // a hypothetical v3(2). Although not defined, older versions of certbot
+    // use it. See https://github.com/certbot/certbot/pull/9334.
+    long version = ASN1_INTEGER_get(rinf->version);
+    if (version != X509_REQ_VERSION_1 && version != 2) {
       OPENSSL_PUT_ERROR(X509, X509_R_INVALID_VERSION);
       return 0;
     }
diff --git a/include/openssl/x509.h b/include/openssl/x509.h
index 945355f..526765f 100644
--- a/include/openssl/x509.h
+++ b/include/openssl/x509.h
@@ -396,7 +396,9 @@
 #define X509_REQ_VERSION_1 0
 
 // X509_REQ_get_version returns the numerical value of |req|'s version. This
-// will always be |X509_REQ_VERSION_1|.
+// will always be |X509_REQ_VERSION_1| for valid CSRs. For compatibility,
+// |d2i_X509_REQ| also accepts some invalid version numbers, in which case this
+// function may return other values.
 OPENSSL_EXPORT long X509_REQ_get_version(const X509_REQ *req);
 
 // X509_REQ_get_subject_name returns |req|'s subject name. Note this function is