зеркало из https://github.com/mozilla/gecko-dev.git
Bug 970542, Part 6: DNSName name constraint tests, r=keeler
--HG-- extra : rebase_source : ec31862fc25cfcba1454ae862a26e7a27513e9b6
This commit is contained in:
Родитель
7dd909b9e5
Коммит
ac1c16b716
|
@ -22,9 +22,11 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
#include "pkix/pkix.h"
|
||||
#include "pkixcheck.h"
|
||||
#include "pkixder.h"
|
||||
#include "pkixgtest.h"
|
||||
#include "pkixtestutil.h"
|
||||
#include "pkixutil.h"
|
||||
|
||||
namespace mozilla { namespace pkix {
|
||||
|
||||
|
@ -1542,3 +1544,269 @@ TEST_P(pkixnames_CheckCertHostname_IPV4_Addresses,
|
|||
INSTANTIATE_TEST_CASE_P(pkixnames_CheckCertHostname_IPV4_ADDRESSES,
|
||||
pkixnames_CheckCertHostname_IPV4_Addresses,
|
||||
testing::ValuesIn(IPV4_ADDRESSES));
|
||||
|
||||
struct NameConstraintParams
|
||||
{
|
||||
ByteString subject;
|
||||
ByteString subjectAltName;
|
||||
ByteString subtrees;
|
||||
Result expectedPermittedSubtreesResult;
|
||||
Result expectedExcludedSubtreesResult;
|
||||
};
|
||||
|
||||
static ByteString
|
||||
PermittedSubtrees(const ByteString& generalSubtrees)
|
||||
{
|
||||
return TLV(der::CONTEXT_SPECIFIC | der::CONSTRUCTED | 0,
|
||||
generalSubtrees);
|
||||
}
|
||||
|
||||
static ByteString
|
||||
ExcludedSubtrees(const ByteString& generalSubtrees)
|
||||
{
|
||||
return TLV(der::CONTEXT_SPECIFIC | der::CONSTRUCTED | 1,
|
||||
generalSubtrees);
|
||||
}
|
||||
|
||||
// Does not encode min or max.
|
||||
static ByteString
|
||||
GeneralSubtree(const ByteString& base)
|
||||
{
|
||||
return TLV(der::SEQUENCE, base);
|
||||
}
|
||||
|
||||
static const NameConstraintParams NAME_CONSTRAINT_PARAMS[] =
|
||||
{
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Edge cases of name constraint absolute vs. relative and subdomain matching
|
||||
// that are not clearly explained in RFC 5280. (See the long comment above
|
||||
// PresentedDNSIDMatchesReferenceDNSID.)
|
||||
|
||||
// Q: Does a presented identifier equal (case insensitive) to the name
|
||||
// constraint match the constraint? For example, does the presented
|
||||
// ID "host.example.com" match a "host.example.com" constraint?
|
||||
{ ByteString(), DNSName("host.example.com"),
|
||||
GeneralSubtree(DNSName("host.example.com")),
|
||||
Success, Result::ERROR_CERT_NOT_IN_NAME_SPACE
|
||||
},
|
||||
{ // This test case is an example from RFC 5280.
|
||||
ByteString(), DNSName("host1.example.com"),
|
||||
GeneralSubtree(DNSName("host.example.com")),
|
||||
Result::ERROR_CERT_NOT_IN_NAME_SPACE, Success
|
||||
},
|
||||
|
||||
// Q: When the name constraint does not start with ".", do subdomain
|
||||
// presented identifiers match it? For example, does the presented
|
||||
// ID "www.host.example.com" match a "host.example.com" constraint?
|
||||
{ // This test case is an example from RFC 5280.
|
||||
ByteString(), DNSName("www.host.example.com"),
|
||||
GeneralSubtree(DNSName( "host.example.com")),
|
||||
Success, Result::ERROR_CERT_NOT_IN_NAME_SPACE
|
||||
},
|
||||
|
||||
// Q: When the name constraint does not start with ".", does a
|
||||
// non-subdomain prefix match it? For example, does "bigfoo.bar.com"
|
||||
// match "foo.bar.com"?
|
||||
{ ByteString(), DNSName("bigfoo.bar.com"),
|
||||
GeneralSubtree(DNSName("foo.bar.com")),
|
||||
Result::ERROR_CERT_NOT_IN_NAME_SPACE, Success
|
||||
},
|
||||
|
||||
// Q: Is a name constraint that starts with "." valid, and if so, what
|
||||
// semantics does it have? For example, does a presented ID of
|
||||
// "www.example.com" match a constraint of ".example.com"? Does a
|
||||
// presented ID of "example.com" match a constraint of ".example.com"?
|
||||
{ ByteString(), DNSName("www.example.com"),
|
||||
GeneralSubtree(DNSName(".example.com")),
|
||||
Success, Result::ERROR_CERT_NOT_IN_NAME_SPACE
|
||||
},
|
||||
{ // Check that we only allow subdomains to match.
|
||||
ByteString(), DNSName("example.com"),
|
||||
GeneralSubtree(DNSName(".example.com")),
|
||||
Result::ERROR_CERT_NOT_IN_NAME_SPACE, Success
|
||||
},
|
||||
{ // Check that we don't get confused and consider "b" == "."
|
||||
ByteString(), DNSName("bexample.com"),
|
||||
GeneralSubtree(DNSName(".example.com")),
|
||||
Result::ERROR_CERT_NOT_IN_NAME_SPACE, Success
|
||||
},
|
||||
|
||||
// Q: Is there a way to prevent subdomain matches?
|
||||
// (This is tested in a different set of tests because it requires a
|
||||
// combination of permittedSubtrees and excludedSubtrees.)
|
||||
|
||||
// Q: Are name constraints allowed to be specified as absolute names?
|
||||
// For example, does a presented ID of "example.com" match a name
|
||||
// constraint of "example.com." and vice versa.
|
||||
//
|
||||
{ ByteString(), DNSName("example.com"),
|
||||
GeneralSubtree(DNSName("example.com.")),
|
||||
Result::ERROR_CERT_NOT_IN_NAME_SPACE, Success,
|
||||
},
|
||||
{ ByteString(), DNSName("example.com."),
|
||||
GeneralSubtree(DNSName("example.com")),
|
||||
Result::ERROR_CERT_NOT_IN_NAME_SPACE, Success,
|
||||
},
|
||||
{ // The presented ID is the same length as the constraint, because the
|
||||
// subdomain is only one character long and because the constraint both
|
||||
// begins and ends with ".".
|
||||
ByteString(), DNSName("p.example.com"),
|
||||
GeneralSubtree(DNSName(".example.com.")),
|
||||
Result::ERROR_CERT_NOT_IN_NAME_SPACE, Success,
|
||||
},
|
||||
{ // Same as previous test case, but using a wildcard presented ID.
|
||||
ByteString(), DNSName("*.example.com"),
|
||||
GeneralSubtree(DNSName(".example.com.")),
|
||||
Result::ERROR_CERT_NOT_IN_NAME_SPACE, Success
|
||||
},
|
||||
|
||||
// Q: Are "" and "." valid DNSName constraints? If so, what do they mean?
|
||||
{ ByteString(), DNSName("example.com"),
|
||||
GeneralSubtree(DNSName("")),
|
||||
Success, Result::ERROR_CERT_NOT_IN_NAME_SPACE
|
||||
},
|
||||
{ ByteString(), DNSName("example.com."),
|
||||
GeneralSubtree(DNSName("")),
|
||||
Success, Result::ERROR_CERT_NOT_IN_NAME_SPACE
|
||||
},
|
||||
{ ByteString(), DNSName("example.com"),
|
||||
GeneralSubtree(DNSName(".")),
|
||||
Result::ERROR_CERT_NOT_IN_NAME_SPACE, Success,
|
||||
},
|
||||
{ ByteString(), DNSName("example.com."),
|
||||
GeneralSubtree(DNSName(".")),
|
||||
Success, Result::ERROR_CERT_NOT_IN_NAME_SPACE
|
||||
},
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Basic CN-ID DNSName constraint tests.
|
||||
|
||||
{ // Empty Name is ignored for DNSName constraints.
|
||||
ByteString(), NO_SAN, GeneralSubtree(DNSName("a.example.com")),
|
||||
Success, Success
|
||||
},
|
||||
{ // Empty CN is ignored for DNSName constraints because it isn't a
|
||||
// syntactically-valid DNSName.
|
||||
//
|
||||
// NSS gives different results.
|
||||
RDN(CN("")), NO_SAN, GeneralSubtree(DNSName("a.example.com")),
|
||||
Success, Success
|
||||
},
|
||||
{ // IP Address is ignored for DNSName constraints.
|
||||
//
|
||||
// NSS gives different results.
|
||||
RDN(CN("1.2.3.4")), NO_SAN, GeneralSubtree(DNSName("a.example.com")),
|
||||
Success, Success
|
||||
},
|
||||
{ // OU has something that looks like a dNSName that matches.
|
||||
RDN(OU("a.example.com")), NO_SAN, GeneralSubtree(DNSName("a.example.com")),
|
||||
Success, Success
|
||||
},
|
||||
{ // OU has something that looks like a dNSName that does not match.
|
||||
RDN(OU("b.example.com")), NO_SAN, GeneralSubtree(DNSName("a.example.com")),
|
||||
Success, Success
|
||||
},
|
||||
{ // NSS gives different results.
|
||||
RDN(CN("Not a DNSName")), NO_SAN, GeneralSubtree(DNSName("a.example.com")),
|
||||
Success, Success
|
||||
},
|
||||
{ RDN(CN("a.example.com")), NO_SAN, GeneralSubtree(DNSName("a.example.com")),
|
||||
Success, Result::ERROR_CERT_NOT_IN_NAME_SPACE
|
||||
},
|
||||
{ RDN(CN("b.example.com")), NO_SAN, GeneralSubtree(DNSName("a.example.com")),
|
||||
Result::ERROR_CERT_NOT_IN_NAME_SPACE, Success
|
||||
},
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Test that constraints are applied to the most specific (last) CN, and only
|
||||
// that CN-ID.
|
||||
|
||||
{ // Name constraint only matches a.example.com, but the most specific CN
|
||||
// (i.e. the CN-ID) is b.example.com. (Two CNs in one RDN.)
|
||||
RDN(CN("a.example.com") + CN("b.example.com")), NO_SAN,
|
||||
GeneralSubtree(DNSName("a.example.com")),
|
||||
Result::ERROR_CERT_NOT_IN_NAME_SPACE, Success
|
||||
},
|
||||
{ // Name constraint only matches a.example.com, but the most specific CN
|
||||
// (i.e. the CN-ID) is b.example.com. (Two CNs in separate RDNs.)
|
||||
RDN(CN("a.example.com")) + RDN(CN("b.example.com")), NO_SAN,
|
||||
GeneralSubtree(DNSName("a.example.com")),
|
||||
Result::ERROR_CERT_NOT_IN_NAME_SPACE, Success
|
||||
},
|
||||
{ // Name constraint only permits b.example.com, and the most specific CN
|
||||
// (i.e. the CN-ID) is b.example.com. (Two CNs in one RDN.)
|
||||
RDN(CN("a.example.com") + CN("b.example.com")), NO_SAN,
|
||||
GeneralSubtree(DNSName("b.example.com")),
|
||||
Success, Result::ERROR_CERT_NOT_IN_NAME_SPACE
|
||||
},
|
||||
{ // Name constraint only permits b.example.com, and the most specific CN
|
||||
// (i.e. the CN-ID) is b.example.com. (Two CNs in separate RDNs.)
|
||||
RDN(CN("a.example.com")) + RDN(CN("b.example.com")), NO_SAN,
|
||||
GeneralSubtree(DNSName("b.example.com")),
|
||||
Success, Result::ERROR_CERT_NOT_IN_NAME_SPACE
|
||||
},
|
||||
};
|
||||
|
||||
class pkixnames_CheckNameConstraints
|
||||
: public ::testing::Test
|
||||
, public ::testing::WithParamInterface<NameConstraintParams>
|
||||
{
|
||||
};
|
||||
|
||||
TEST_P(pkixnames_CheckNameConstraints,
|
||||
NameConstraintsEnforcedforDirectlyIssuedEndEntity)
|
||||
{
|
||||
// Test that name constraints are enforced on a certificate directly issued by
|
||||
// this certificate.
|
||||
|
||||
const NameConstraintParams& param(GetParam());
|
||||
|
||||
ByteString certDER(CreateCert(param.subject, param.subjectAltName));
|
||||
ASSERT_FALSE(ENCODING_FAILED(certDER));
|
||||
Input certInput;
|
||||
ASSERT_EQ(Success, certInput.Init(certDER.data(), certDER.length()));
|
||||
BackCert cert(certInput, EndEntityOrCA::MustBeEndEntity, nullptr);
|
||||
ASSERT_EQ(Success, cert.Init());
|
||||
|
||||
{
|
||||
ByteString nameConstraintsDER(TLV(der::SEQUENCE,
|
||||
PermittedSubtrees(param.subtrees)));
|
||||
Input nameConstraints;
|
||||
ASSERT_EQ(Success,
|
||||
nameConstraints.Init(nameConstraintsDER.data(),
|
||||
nameConstraintsDER.length()));
|
||||
ASSERT_EQ(param.expectedPermittedSubtreesResult,
|
||||
CheckNameConstraints(nameConstraints, cert,
|
||||
KeyPurposeId::id_kp_serverAuth));
|
||||
}
|
||||
{
|
||||
ByteString nameConstraintsDER(TLV(der::SEQUENCE,
|
||||
ExcludedSubtrees(param.subtrees)));
|
||||
Input nameConstraints;
|
||||
ASSERT_EQ(Success,
|
||||
nameConstraints.Init(nameConstraintsDER.data(),
|
||||
nameConstraintsDER.length()));
|
||||
ASSERT_EQ(param.expectedExcludedSubtreesResult,
|
||||
CheckNameConstraints(nameConstraints, cert,
|
||||
KeyPurposeId::id_kp_serverAuth));
|
||||
}
|
||||
{
|
||||
ByteString nameConstraintsDER(TLV(der::SEQUENCE,
|
||||
PermittedSubtrees(param.subtrees) +
|
||||
ExcludedSubtrees(param.subtrees)));
|
||||
Input nameConstraints;
|
||||
ASSERT_EQ(Success,
|
||||
nameConstraints.Init(nameConstraintsDER.data(),
|
||||
nameConstraintsDER.length()));
|
||||
ASSERT_EQ((param.expectedPermittedSubtreesResult == Success &&
|
||||
param.expectedExcludedSubtreesResult == Success)
|
||||
? Success
|
||||
: Result::ERROR_CERT_NOT_IN_NAME_SPACE,
|
||||
CheckNameConstraints(nameConstraints, cert,
|
||||
KeyPurposeId::id_kp_serverAuth));
|
||||
}
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(pkixnames_CheckNameConstraints,
|
||||
pkixnames_CheckNameConstraints,
|
||||
testing::ValuesIn(NAME_CONSTRAINT_PARAMS));
|
Загрузка…
Ссылка в новой задаче