chromium/chromeos/ash/components/network/onc/onc_certificate_pattern.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 <stddef.h>

#include <utility>

#include "base/containers/contains.h"
#include "base/values.h"
#include "components/onc/onc_constants.h"
#include "net/cert/x509_certificate.h"
#include "net/cert/x509_util_nss.h"

namespace ash {

namespace {

bool GetAsListOfStrings(const base::Value::List& value,
                        std::vector<std::string>* result) {
  result->clear();
  result->reserve(value.size());
  for (const auto& entry : value) {
    if (!entry.is_string())
      return false;
    result->push_back(entry.GetString());
  }

  return true;
}

}  // namespace

////////////////////////////////////////////////////////////////////////////////
// OncCertificatePattern

OncCertificatePattern::OncCertificatePattern() = default;

OncCertificatePattern::OncCertificatePattern(
    const OncCertificatePattern& other) = default;

OncCertificatePattern::OncCertificatePattern(OncCertificatePattern&& other) =
    default;

OncCertificatePattern::~OncCertificatePattern() = default;

OncCertificatePattern& OncCertificatePattern::operator=(
    const OncCertificatePattern& rhs) = default;
OncCertificatePattern& OncCertificatePattern::operator=(
    OncCertificatePattern&& rhs) = default;

bool OncCertificatePattern::Empty() const {
  return pem_encoded_issuer_cas_.empty() && issuer_pattern_.Empty() &&
         subject_pattern_.Empty();
}

bool OncCertificatePattern::Matches(
    const net::X509Certificate& certificate,
    const std::string& pem_encoded_issuer_ca) const {
  if (!issuer_pattern_.Empty() &&
      !issuer_pattern_.Matches(certificate.issuer())) {
    return false;
  }
  if (!subject_pattern_.Empty() &&
      !subject_pattern_.Matches(certificate.subject())) {
    return false;
  }
  if (!pem_encoded_issuer_cas_.empty() &&
      !base::Contains(pem_encoded_issuer_cas_, pem_encoded_issuer_ca)) {
    return false;
  }
  return true;
}

// static
std::optional<OncCertificatePattern>
OncCertificatePattern::ReadFromONCDictionary(const base::Value::Dict& dict) {
  // All of these are optional.
  const base::Value::List* pem_encoded_issuer_cas_value =
      dict.FindList(onc::client_cert::kIssuerCAPEMs);
  std::vector<std::string> pem_encoded_issuer_cas;
  if (pem_encoded_issuer_cas_value &&
      !GetAsListOfStrings(*pem_encoded_issuer_cas_value,
                          &pem_encoded_issuer_cas)) {
    return std::nullopt;
  }

  const base::Value::List* enrollment_uri_list_value =
      dict.FindList(onc::client_cert::kEnrollmentURI);
  std::vector<std::string> enrollment_uri_list;
  if (enrollment_uri_list_value &&
      !GetAsListOfStrings(*enrollment_uri_list_value, &enrollment_uri_list)) {
    return std::nullopt;
  }

  auto issuer_pattern =
      certificate_matching::CertificatePrincipalPattern::ParseFromOptionalDict(
          dict.FindDict(onc::client_cert::kIssuer),
          onc::client_cert::kCommonName, onc::client_cert::kLocality,
          onc::client_cert::kOrganization,
          onc::client_cert::kOrganizationalUnit);
  auto subject_pattern =
      certificate_matching::CertificatePrincipalPattern::ParseFromOptionalDict(
          dict.FindDict(onc::client_cert::kSubject),
          onc::client_cert::kCommonName, onc::client_cert::kLocality,
          onc::client_cert::kOrganization,
          onc::client_cert::kOrganizationalUnit);

  return OncCertificatePattern(pem_encoded_issuer_cas, issuer_pattern,
                               subject_pattern, enrollment_uri_list);
}

OncCertificatePattern::OncCertificatePattern(
    std::vector<std::string> pem_encoded_issuer_cas,
    certificate_matching::CertificatePrincipalPattern issuer_pattern,
    certificate_matching::CertificatePrincipalPattern subject_pattern,
    std::vector<std::string> enrollment_uri_list)
    : pem_encoded_issuer_cas_(std::move(pem_encoded_issuer_cas)),
      issuer_pattern_(std::move(issuer_pattern)),
      subject_pattern_(std::move(subject_pattern)),
      enrollment_uri_list_(std::move(enrollment_uri_list)) {}

}  // namespace ash