| Index: net/cert/internal/parsed_certificate.cc
|
| diff --git a/net/cert/internal/parsed_certificate.cc b/net/cert/internal/parsed_certificate.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..0f836b20eccf3471ac6bff4b08c1f47ad686ceaf
|
| --- /dev/null
|
| +++ b/net/cert/internal/parsed_certificate.cc
|
| @@ -0,0 +1,158 @@
|
| +// Copyright 2016 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include "net/cert/internal/parsed_certificate.h"
|
| +
|
| +#include "net/cert/internal/name_constraints.h"
|
| +#include "net/cert/internal/signature_algorithm.h"
|
| +#include "net/cert/internal/verify_name_match.h"
|
| +#include "net/der/parser.h"
|
| +
|
| +namespace net {
|
| +
|
| +namespace {
|
| +
|
| +WARN_UNUSED_RESULT bool GetSequenceValue(const der::Input& tlv,
|
| + der::Input* value) {
|
| + der::Parser parser(tlv);
|
| + return parser.ReadTag(der::kSequence, value) && !parser.HasMore();
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +ParsedCertificate::ParsedCertificate() {}
|
| +ParsedCertificate::~ParsedCertificate() {}
|
| +
|
| +scoped_refptr<ParsedCertificate> ParsedCertificate::CreateFromCertificateData(
|
| + const uint8_t* data,
|
| + size_t length,
|
| + DataSource source) {
|
| + scoped_refptr<ParsedCertificate> result(new ParsedCertificate);
|
| +
|
| + switch (source) {
|
| + case DataSource::INTERNAL_COPY:
|
| + result->cert_data_.assign(data, data + length);
|
| + result->cert_ =
|
| + der::Input(result->cert_data_.data(), result->cert_data_.size());
|
| + break;
|
| + case DataSource::EXTERNAL_REFERENCE:
|
| + result->cert_ = der::Input(data, length);
|
| + break;
|
| + }
|
| +
|
| + if (!ParseCertificate(result->cert_, &result->tbs_certificate_tlv_,
|
| + &result->signature_algorithm_tlv_,
|
| + &result->signature_value_)) {
|
| + return nullptr;
|
| + }
|
| +
|
| + if (!ParseTbsCertificate(result->tbs_certificate_tlv_, &result->tbs_))
|
| + return nullptr;
|
| +
|
| + // Attempt to parse the signature algorithm contained in the Certificate.
|
| + // Do not give up on failure here, since SignatureAlgorithm::CreateFromDer
|
| + // will fail on valid but unsupported signature algorithms.
|
| + // TODO(mattm): should distinguish between unsupported algorithms and parsing
|
| + // errors.
|
| + result->signature_algorithm_ =
|
| + SignatureAlgorithm::CreateFromDer(result->signature_algorithm_tlv_);
|
| +
|
| + der::Input subject_value;
|
| + if (!GetSequenceValue(result->tbs_.subject_tlv, &subject_value) ||
|
| + !NormalizeName(subject_value, &result->normalized_subject_)) {
|
| + return nullptr;
|
| + }
|
| + der::Input issuer_value;
|
| + if (!GetSequenceValue(result->tbs_.issuer_tlv, &issuer_value) ||
|
| + !NormalizeName(issuer_value, &result->normalized_issuer_)) {
|
| + return nullptr;
|
| + }
|
| +
|
| + // Parse the standard X.509 extensions and remove them from
|
| + // |unparsed_extensions|.
|
| + if (result->tbs_.has_extensions) {
|
| + // ParseExtensions() ensures there are no duplicates, and maps the (unique)
|
| + // OID to the extension value.
|
| + if (!ParseExtensions(result->tbs_.extensions_tlv,
|
| + &result->unparsed_extensions_)) {
|
| + return nullptr;
|
| + }
|
| +
|
| + ParsedExtension extension;
|
| +
|
| + // Basic constraints.
|
| + if (ConsumeExtension(BasicConstraintsOid(), &result->unparsed_extensions_,
|
| + &extension)) {
|
| + result->has_basic_constraints_ = true;
|
| + if (!ParseBasicConstraints(extension.value, &result->basic_constraints_))
|
| + return nullptr;
|
| + }
|
| +
|
| + // KeyUsage.
|
| + if (ConsumeExtension(KeyUsageOid(), &result->unparsed_extensions_,
|
| + &extension)) {
|
| + result->has_key_usage_ = true;
|
| + if (!ParseKeyUsage(extension.value, &result->key_usage_))
|
| + return nullptr;
|
| + }
|
| +
|
| + // Subject alternative name.
|
| + if (ConsumeExtension(SubjectAltNameOid(), &result->unparsed_extensions_,
|
| + &result->subject_alt_names_extension_)) {
|
| + // RFC 5280 section 4.2.1.6:
|
| + // SubjectAltName ::= GeneralNames
|
| + result->subject_alt_names_ = GeneralNames::CreateFromDer(
|
| + result->subject_alt_names_extension_.value);
|
| + if (!result->subject_alt_names_)
|
| + return nullptr;
|
| + // RFC 5280 section 4.1.2.6:
|
| + // If subject naming information is present only in the subjectAltName
|
| + // extension (e.g., a key bound only to an email address or URI), then the
|
| + // subject name MUST be an empty sequence and the subjectAltName extension
|
| + // MUST be critical.
|
| + if (subject_value.Length() == 0 &&
|
| + !result->subject_alt_names_extension_.critical) {
|
| + return nullptr;
|
| + }
|
| + }
|
| +
|
| + // Name constraints.
|
| + if (ConsumeExtension(NameConstraintsOid(), &result->unparsed_extensions_,
|
| + &extension)) {
|
| + result->name_constraints_ =
|
| + NameConstraints::CreateFromDer(extension.value, extension.critical);
|
| + if (!result->name_constraints_)
|
| + return nullptr;
|
| + }
|
| +
|
| + // NOTE: if additional extensions are consumed here, the verification code
|
| + // must be updated to process those extensions, since the
|
| + // VerifyNoUnconsumedCriticalExtensions uses the unparsed_extensions_
|
| + // variable to tell which extensions were processed.
|
| + }
|
| +
|
| + return result;
|
| +}
|
| +
|
| +scoped_refptr<ParsedCertificate> ParsedCertificate::CreateFromCertificateCopy(
|
| + const base::StringPiece& data) {
|
| + return ParsedCertificate::CreateFromCertificateData(
|
| + reinterpret_cast<const uint8_t*>(data.data()), data.size(),
|
| + DataSource::INTERNAL_COPY);
|
| +}
|
| +
|
| +bool ParsedCertificate::CreateAndAddToVector(
|
| + const uint8_t* data,
|
| + size_t length,
|
| + DataSource source,
|
| + std::vector<scoped_refptr<ParsedCertificate>>* chain) {
|
| + scoped_refptr<ParsedCertificate> cert(
|
| + CreateFromCertificateData(data, length, source));
|
| + if (!cert)
|
| + return false;
|
| + chain->push_back(std::move(cert));
|
| + return true;
|
| +}
|
| +
|
| +} // namespace net
|
|
|