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, ¶m_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, ¶m_type, /*out_param_value=*/nullptr, alg); + EXPECT_EQ(OBJ_obj2nid(obj), NID_sha256WithRSAEncryption); + EXPECT_EQ(param_type, V_ASN1_NULL); } } // namespace