Fix and test other self-assignment cases in crypto/x509

These all used to work, by virtue of us internally making a copy of the
object before setting it. Now that we copy in-place, we need some extra
checks.

Change-Id: I5e0a7bf017cb4f4bb705a8776683b6f60bc66c4e
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/82287
Auto-Submit: David Benjamin <davidben@google.com>
Reviewed-by: Lily Chen <chlily@google.com>
Commit-Queue: David Benjamin <davidben@google.com>
diff --git a/crypto/asn1/asn1_lib.cc b/crypto/asn1/asn1_lib.cc
index ececcdc..16cc512 100644
--- a/crypto/asn1/asn1_lib.cc
+++ b/crypto/asn1/asn1_lib.cc
@@ -204,6 +204,9 @@
   if (str == NULL) {
     return 0;
   }
+  if (dst == str) {
+    return 1;
+  }
   if (!ASN1_STRING_set(dst, str->data, str->length)) {
     return 0;
   }
diff --git a/crypto/x509/x509_test.cc b/crypto/x509/x509_test.cc
index 445dc51..c137682 100644
--- a/crypto/x509/x509_test.cc
+++ b/crypto/x509/x509_test.cc
@@ -1798,8 +1798,12 @@
   bssl::UniquePtr<X509_NAME> issuer_name = MakeTestName(issuer);
   bssl::UniquePtr<X509_NAME> subject_name = MakeTestName(subject);
   bssl::UniquePtr<X509> cert(X509_new());
+  bssl::UniquePtr<ASN1_INTEGER> serial(ASN1_INTEGER_new());
   if (issuer_name == nullptr || subject_name == nullptr || cert == nullptr ||
+      serial == nullptr ||  //
       !X509_set_version(cert.get(), X509_VERSION_3) ||
+      !ASN1_INTEGER_set_uint64(serial.get(), 42) ||
+      !X509_set_serialNumber(cert.get(), serial.get()) ||
       !X509_set_issuer_name(cert.get(), issuer_name.get()) ||
       !X509_set_subject_name(cert.get(), subject_name.get()) ||
       !X509_set_pubkey(cert.get(), key) ||
@@ -9136,30 +9140,65 @@
                    /*intermediates=*/{}, /*crls=*/{}));
 }
 
-// Test that |X509_set_subject_name| on an |X509_NAME| that was already the
-// subject did not break.
-TEST(X509Test, SelfSetSubjectAndIssuer) {
-  bssl::UniquePtr<EVP_PKEY> key = PrivateKeyFromPEM(kP256Key);
+// Test that no-op self-assignments on |X509| fields work.
+TEST(X509Test, SelfAssignFields) {
+  // Test with an RSA key, so that the signature algorithm contains an explicit
+  // NULL parameter (i.e. a non-nullptr |ASN1_TYPE| containing an ASN.1 NULL
+  // value), rather than an omitted parameter (i.e. a nullptr |ASN1_TYPE|). This
+  // exercises |X509_set1_signature_algo| better.
+  bssl::UniquePtr<EVP_PKEY> key = PrivateKeyFromPEM(kRSAKey);
   ASSERT_TRUE(key);
   bssl::UniquePtr<X509> cert =
       MakeTestCert("Issuer", "Subject", key.get(), /*is_ca=*/true);
+  EXPECT_TRUE(X509_sign(cert.get(), key.get(), EVP_sha256()));
 
   EXPECT_TRUE(
       X509_set_issuer_name(cert.get(), X509_get_issuer_name(cert.get())));
-  EXPECT_TRUE(
-      X509_set_subject_name(cert.get(), X509_get_subject_name(cert.get())));
-
   const X509_NAME *issuer = X509_get_issuer_name(cert.get());
   EXPECT_EQ(X509_NAME_entry_count(issuer), 1);
   const X509_NAME_ENTRY *entry = X509_NAME_get_entry(issuer, 0);
   EXPECT_EQ(OBJ_obj2nid(X509_NAME_ENTRY_get_object(entry)), NID_commonName);
   EXPECT_EQ("Issuer", ASN1StringAsView(X509_NAME_ENTRY_get_data(entry)));
 
+  EXPECT_TRUE(
+      X509_set_subject_name(cert.get(), X509_get_subject_name(cert.get())));
   const X509_NAME *subject = X509_get_subject_name(cert.get());
   EXPECT_EQ(X509_NAME_entry_count(subject), 1);
   entry = X509_NAME_get_entry(subject, 0);
   EXPECT_EQ(OBJ_obj2nid(X509_NAME_ENTRY_get_object(entry)), NID_commonName);
   EXPECT_EQ("Subject", ASN1StringAsView(X509_NAME_ENTRY_get_data(entry)));
+
+  std::string not_before_old(ASN1StringAsView(X509_get0_notBefore(cert.get())));
+  EXPECT_TRUE(X509_set1_notBefore(cert.get(), X509_get0_notBefore(cert.get())));
+  EXPECT_EQ(ASN1StringAsView(X509_get0_notBefore(cert.get())), not_before_old);
+
+  std::string not_after_old(ASN1StringAsView(X509_get0_notAfter(cert.get())));
+  EXPECT_TRUE(X509_set1_notAfter(cert.get(), X509_get0_notAfter(cert.get())));
+  EXPECT_EQ(ASN1StringAsView(X509_get0_notAfter(cert.get())), not_after_old);
+
+  long serial_old = ASN1_INTEGER_get(X509_get0_serialNumber(cert.get()));
+  EXPECT_TRUE(
+      X509_set_serialNumber(cert.get(), X509_get0_serialNumber(cert.get())));
+  EXPECT_EQ(ASN1_INTEGER_get(X509_get0_serialNumber(cert.get())), serial_old);
+
+  // X509_set1_signature_algo sets both the TBSCertificate and Certificate copy
+  // of the signature algorithm.
+  EXPECT_TRUE(
+      X509_set1_signature_algo(cert.get(), X509_get0_tbs_sigalg(cert.get())));
+  const ASN1_OBJECT *obj;
+  int param_type;
+  X509_ALGOR_get0(&obj, &param_type, /*out_param_value=*/nullptr,
+                  X509_get0_tbs_sigalg(cert.get()));
+  EXPECT_EQ(OBJ_obj2nid(obj), NID_sha256WithRSAEncryption);
+  EXPECT_EQ(param_type, V_ASN1_NULL);
+
+  const X509_ALGOR *alg;
+  X509_get0_signature(nullptr, &alg, cert.get());
+  EXPECT_TRUE(X509_set1_signature_algo(cert.get(), alg));
+  X509_get0_signature(nullptr, &alg, cert.get());
+  X509_ALGOR_get0(&obj, &param_type, /*out_param_value=*/nullptr, alg);
+  EXPECT_EQ(OBJ_obj2nid(obj), NID_sha256WithRSAEncryption);
+  EXPECT_EQ(param_type, V_ASN1_NULL);
 }
 
 }  // namespace