Test ASN1_STRING_set_by_NID with built-in NIDs. Change-Id: I58a3fba79b03058aaff37bb3e83f971a4ecd2e99 Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/49767 Reviewed-by: Adam Langley <agl@google.com>
diff --git a/crypto/asn1/a_strnid.c b/crypto/asn1/a_strnid.c index 299d03b..62c2f5d 100644 --- a/crypto/asn1/a_strnid.c +++ b/crypto/asn1/a_strnid.c
@@ -122,15 +122,13 @@ * Now the tables and helper functions for the string table: */ -/* size limits: this stuff is taken straight from RFC 3280 */ - +/* See RFC 5280. */ #define ub_name 32768 #define ub_common_name 64 #define ub_locality_name 128 #define ub_state_name 128 #define ub_organization_name 64 #define ub_organization_unit_name 64 -#define ub_title 64 #define ub_email_address 128 #define ub_serial_number 64
diff --git a/crypto/asn1/asn1_test.cc b/crypto/asn1/asn1_test.cc index 49a0c27..3a039bf 100644 --- a/crypto/asn1/asn1_test.cc +++ b/crypto/asn1/asn1_test.cc
@@ -1037,6 +1037,126 @@ } } +TEST(ASN1Test, StringByNID) { + // |ASN1_mbstring_*| tests above test most of the interactions with |inform|, + // so all tests below use UTF-8. + const struct { + int nid; + std::string in; + int expected_type; + std::string expected; + } kTests[] = { + // Although DirectoryString and PKCS9String allow many types of strings, + // we prefer UTF8String. + {NID_commonName, "abc", V_ASN1_UTF8STRING, "abc"}, + {NID_commonName, "\xe2\x98\x83", V_ASN1_UTF8STRING, "\xe2\x98\x83"}, + {NID_localityName, "abc", V_ASN1_UTF8STRING, "abc"}, + {NID_stateOrProvinceName, "abc", V_ASN1_UTF8STRING, "abc"}, + {NID_organizationName, "abc", V_ASN1_UTF8STRING, "abc"}, + {NID_organizationalUnitName, "abc", V_ASN1_UTF8STRING, "abc"}, + {NID_pkcs9_unstructuredName, "abc", V_ASN1_UTF8STRING, "abc"}, + {NID_pkcs9_challengePassword, "abc", V_ASN1_UTF8STRING, "abc"}, + {NID_pkcs9_unstructuredAddress, "abc", V_ASN1_UTF8STRING, "abc"}, + {NID_givenName, "abc", V_ASN1_UTF8STRING, "abc"}, + {NID_givenName, "abc", V_ASN1_UTF8STRING, "abc"}, + {NID_givenName, "abc", V_ASN1_UTF8STRING, "abc"}, + {NID_surname, "abc", V_ASN1_UTF8STRING, "abc"}, + {NID_initials, "abc", V_ASN1_UTF8STRING, "abc"}, + {NID_name, "abc", V_ASN1_UTF8STRING, "abc"}, + + // Some attribute types use a particular string type. + {NID_countryName, "US", V_ASN1_PRINTABLESTRING, "US"}, + {NID_pkcs9_emailAddress, "example@example.com", V_ASN1_IA5STRING, + "example@example.com"}, + {NID_serialNumber, "1234", V_ASN1_PRINTABLESTRING, "1234"}, + {NID_friendlyName, "abc", V_ASN1_BMPSTRING, + std::string({'\0', 'a', '\0', 'b', '\0', 'c'})}, + {NID_dnQualifier, "US", V_ASN1_PRINTABLESTRING, "US"}, + {NID_domainComponent, "com", V_ASN1_IA5STRING, "com"}, + {NID_ms_csp_name, "abc", V_ASN1_BMPSTRING, + std::string({'\0', 'a', '\0', 'b', '\0', 'c'})}, + + // Unknown NIDs default to UTF8String. + {NID_rsaEncryption, "abc", V_ASN1_UTF8STRING, "abc"}, + }; + for (const auto &t : kTests) { + SCOPED_TRACE(t.nid); + SCOPED_TRACE(t.in); + + // Test allocating a new object. + bssl::UniquePtr<ASN1_STRING> str(ASN1_STRING_set_by_NID( + nullptr, reinterpret_cast<const uint8_t *>(t.in.data()), t.in.size(), + MBSTRING_UTF8, t.nid)); + ASSERT_TRUE(str); + EXPECT_EQ(t.expected_type, ASN1_STRING_type(str.get())); + EXPECT_EQ(Bytes(t.expected), Bytes(ASN1_STRING_get0_data(str.get()), + ASN1_STRING_length(str.get()))); + + // Test writing into an existing object. + str.reset(ASN1_STRING_new()); + ASSERT_TRUE(str); + ASN1_STRING *old_str = str.get(); + ASSERT_TRUE(ASN1_STRING_set_by_NID( + &old_str, reinterpret_cast<const uint8_t *>(t.in.data()), t.in.size(), + MBSTRING_UTF8, t.nid)); + ASSERT_EQ(old_str, str.get()); + EXPECT_EQ(t.expected_type, ASN1_STRING_type(str.get())); + EXPECT_EQ(Bytes(t.expected), Bytes(ASN1_STRING_get0_data(str.get()), + ASN1_STRING_length(str.get()))); + } + + const struct { + int nid; + std::string in; + } kInvalidTests[] = { + // DirectoryString forbids empty inputs. + {NID_commonName, ""}, + {NID_localityName, ""}, + {NID_stateOrProvinceName, ""}, + {NID_organizationName, ""}, + {NID_organizationalUnitName, ""}, + {NID_pkcs9_unstructuredName, ""}, + {NID_pkcs9_challengePassword, ""}, + {NID_pkcs9_unstructuredAddress, ""}, + {NID_givenName, ""}, + {NID_givenName, ""}, + {NID_givenName, ""}, + {NID_surname, ""}, + {NID_initials, ""}, + {NID_name, ""}, + + // Test upper bounds from RFC 5280. + {NID_name, std::string(32769, 'a')}, + {NID_commonName, std::string(65, 'a')}, + {NID_localityName, std::string(129, 'a')}, + {NID_stateOrProvinceName, std::string(129, 'a')}, + {NID_organizationName, std::string(65, 'a')}, + {NID_organizationalUnitName, std::string(65, 'a')}, + {NID_pkcs9_emailAddress, std::string(256, 'a')}, + {NID_serialNumber, std::string(65, 'a')}, + + // X520countryName must be exactly two characters. + {NID_countryName, "A"}, + {NID_countryName, "AAA"}, + + // Some string types cannot represent all codepoints. + {NID_countryName, "\xe2\x98\x83"}, + {NID_pkcs9_emailAddress, "\xe2\x98\x83"}, + {NID_serialNumber, "\xe2\x98\x83"}, + {NID_dnQualifier, "\xe2\x98\x83"}, + {NID_domainComponent, "\xe2\x98\x83"}, + }; + for (const auto &t : kInvalidTests) { + SCOPED_TRACE(t.nid); + SCOPED_TRACE(t.in); + bssl::UniquePtr<ASN1_STRING> str(ASN1_STRING_set_by_NID( + nullptr, reinterpret_cast<const uint8_t *>(t.in.data()), t.in.size(), + MBSTRING_UTF8, t.nid)); + EXPECT_FALSE(str); + ERR_clear_error(); + } +} + // Test that multi-string types correctly encode negative ENUMERATED. // Multi-string types cannot contain INTEGER, so we only test ENUMERATED. TEST(ASN1Test, NegativeEnumeratedMultistring) {