chromium/chromeos/ash/components/network/onc/onc_certificate_pattern_unittest.cc

// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chromeos/ash/components/network/onc/onc_certificate_pattern.h"

#include <string>

#include "base/json/json_reader.h"
#include "base/values.h"
#include "net/cert/x509_certificate.h"
#include "net/test/cert_test_util.h"
#include "net/test/test_data_directory.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace ash {

namespace {
constexpr char kFakePemEncodedIssuer[] = "PEM-ENCODED-ISSUER";

class OncCertificatePatternTest : public testing::Test {
 public:
  OncCertificatePatternTest() = default;

  OncCertificatePatternTest(const OncCertificatePatternTest&) = delete;
  OncCertificatePatternTest& operator=(const OncCertificatePatternTest&) =
      delete;

  ~OncCertificatePatternTest() override = default;

  void SetUp() override {
    cert_ =
        net::ImportCertFromFile(net::GetTestCertsDirectory(), "client_1.pem");
    ASSERT_TRUE(cert_);
  }

  void TearDown() override { cert_.reset(); }

 protected:
  scoped_refptr<net::X509Certificate> cert_;
};

}  // namespace

TEST_F(OncCertificatePatternTest, EmptyPattern) {
  OncCertificatePattern pattern;
  EXPECT_TRUE(pattern.Empty());

  EXPECT_TRUE(pattern.Matches(*cert_, kFakePemEncodedIssuer));
}

TEST_F(OncCertificatePatternTest, ParsePatternFromOnc) {
  const char* pattern_json = R"(
    {
      "Issuer": {
        "CommonName": "Issuer CN",
        "Locality": "Issuer L",
        "Organization": "Issuer O",
        "OrganizationalUnit": "Issuer OU",
      },
      "Subject": {
        "CommonName": "Subject CN",
        "Locality": "Subject L",
        "Organization": "Subject O",
        "OrganizationalUnit": "Subject OU",
      },
      "IssuerCAPEMs": [ "PEM1", "PEM2" ]
    })";
  auto parsed_json = base::JSONReader::ReadAndReturnValueWithError(
      pattern_json, base::JSON_ALLOW_TRAILING_COMMAS);
  ASSERT_TRUE(parsed_json.has_value()) << parsed_json.error().message;

  auto pattern =
      OncCertificatePattern::ReadFromONCDictionary(parsed_json->GetDict());
  ASSERT_TRUE(pattern);
  EXPECT_FALSE(pattern.value().Empty());

  EXPECT_EQ("Issuer CN", pattern.value().issuer_pattern().common_name());
  EXPECT_EQ("Issuer L", pattern.value().issuer_pattern().locality());
  EXPECT_EQ("Issuer O", pattern.value().issuer_pattern().organization());
  EXPECT_EQ("Issuer OU", pattern.value().issuer_pattern().organization_unit());
  EXPECT_EQ("Subject CN", pattern.value().subject_pattern().common_name());
  EXPECT_EQ("Subject L", pattern.value().subject_pattern().locality());
  EXPECT_EQ("Subject O", pattern.value().subject_pattern().organization());
  EXPECT_EQ("Subject OU",
            pattern.value().subject_pattern().organization_unit());
  EXPECT_THAT(pattern.value().pem_encoded_issuer_cas(),
              testing::ElementsAre("PEM1", "PEM2"));
}

TEST_F(OncCertificatePatternTest, PatternMatchingIssuer) {
  // Note: We're only testing matching of "CommonName", assuming that matching
  // of the other principal fields is verified by the tests for
  // |certificate_matching::CertificatePrincipalPattern|.
  const char* pattern_json = R"(
    {
      "Issuer": {
        "CommonName": "B CA"
      }
    })";
  auto parsed_json = base::JSONReader::ReadAndReturnValueWithError(
      pattern_json, base::JSON_ALLOW_TRAILING_COMMAS);
  ASSERT_TRUE(parsed_json.has_value()) << parsed_json.error().message;

  {
    auto pattern =
        OncCertificatePattern::ReadFromONCDictionary(parsed_json->GetDict());
    ASSERT_TRUE(pattern);
    EXPECT_FALSE(pattern.value().Empty());

    EXPECT_TRUE(pattern.value().Matches(*cert_, kFakePemEncodedIssuer));
  }

  {
    base::Value::Dict* issuer = parsed_json->GetDict().FindDict("Issuer");
    ASSERT_TRUE(issuer);
    issuer->Set("CommonName", "SomeOtherCA");

    auto pattern =
        OncCertificatePattern::ReadFromONCDictionary(parsed_json->GetDict());
    ASSERT_TRUE(pattern);
    EXPECT_FALSE(pattern.value().Matches(*cert_, kFakePemEncodedIssuer));
  }
}

TEST_F(OncCertificatePatternTest, PatternMatchingSubject) {
  // Note: We're only testing matching of "CommonName", assuming that matching
  // of the other principal fields is verified by the tests for
  // |certificate_matching::CertificatePrincipalPattern|.
  const char* pattern_json = R"(
    {
      "Subject": {
        "CommonName": "Client Cert A"
      }
    })";
  auto parsed_json = base::JSONReader::ReadAndReturnValueWithError(
      pattern_json, base::JSON_ALLOW_TRAILING_COMMAS);
  ASSERT_TRUE(parsed_json.has_value()) << parsed_json.error().message;

  {
    auto pattern =
        OncCertificatePattern::ReadFromONCDictionary(parsed_json->GetDict());
    ASSERT_TRUE(pattern);
    EXPECT_FALSE(pattern.value().Empty());

    EXPECT_TRUE(pattern.value().Matches(*cert_, kFakePemEncodedIssuer));
  }

  {
    base::Value::Dict* issuer = parsed_json->GetDict().FindDict("Subject");
    ASSERT_TRUE(issuer);
    issuer->Set("CommonName", "B CA");

    auto pattern =
        OncCertificatePattern::ReadFromONCDictionary(parsed_json->GetDict());
    ASSERT_TRUE(pattern);
    EXPECT_FALSE(pattern.value().Matches(*cert_, kFakePemEncodedIssuer));
  }
}

TEST_F(OncCertificatePatternTest, PatternMatchingIssuerCAPEM) {
  constexpr char kPatternJson[] = R"(
    {
      "IssuerCAPEMs": ["PEM-ENCODED-ISSUER"]
    })";
  auto parsed_json = base::JSONReader::ReadAndReturnValueWithError(
      kPatternJson, base::JSON_ALLOW_TRAILING_COMMAS);
  ASSERT_TRUE(parsed_json.has_value()) << parsed_json.error().message;

  auto pattern =
      OncCertificatePattern::ReadFromONCDictionary(parsed_json->GetDict());
  ASSERT_TRUE(pattern);
  EXPECT_FALSE(pattern.value().Empty());

  EXPECT_TRUE(pattern.value().Matches(*cert_, kFakePemEncodedIssuer));
  EXPECT_FALSE(pattern.value().Matches(*cert_, "OtherIssuer"));
}

}  // namespace ash