Chromium Code Reviews| 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..53bb044e6510f42e338b58afbfe115f92d0b9243 |
| --- /dev/null |
| +++ b/net/cert/internal/parsed_certificate.cc |
| @@ -0,0 +1,135 @@ |
| +// 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; |
|
eroman
2016/05/12 18:12:29
nit: curly braces?
mattm
2016/05/13 02:17:36
Done.
|
| + |
| + if (!ParseTbsCertificate(result->tbs_certificate_tlv_, &result->parsed_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. |
|
eroman
2016/05/12 18:12:29
What current consumer is this allowance made for?
mattm
2016/05/13 02:17:36
There are several in tests (PKITS and ours), they
|
| + // 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->parsed_tbs_.subject_tlv, &subject_value) || |
| + !NormalizeName(subject_value, &result->normalized_subject_)) |
| + return nullptr; |
| + der::Input issuer_value; |
| + if (!GetSequenceValue(result->parsed_tbs_.issuer_tlv, &issuer_value) || |
| + !NormalizeName(issuer_value, &result->normalized_issuer_)) |
| + return nullptr; |
|
eroman
2016/05/12 18:12:29
Same question throughout -- if we consider these m
mattm
2016/05/13 02:17:36
yeah, I always forget that. done.
|
| + |
| + // Parse the standard X.509 extensions and remove them from |
| + // |unconsumed_extensions|. |
| + if (result->parsed_tbs_.has_extensions) { |
| + // ParseExtensions() ensures there are no duplicates, and maps the (unique) |
| + // OID to the extension value. |
| + if (!ParseExtensions(result->parsed_tbs_.extensions_tlv, |
| + &result->unconsumed_extensions_)) |
| + return nullptr; |
| + |
| + ParsedExtension extension; |
| + |
| + // Basic constraints. |
| + if (ConsumeExtension(BasicConstraintsOid(), &result->unconsumed_extensions_, |
| + &extension)) { |
| + result->has_basic_constraints_ = true; |
| + if (!ParseBasicConstraints(extension.value, &result->basic_constraints_)) |
| + return nullptr; |
| + } |
| + |
| + // KeyUsage. |
| + if (ConsumeExtension(KeyUsageOid(), &result->unconsumed_extensions_, |
| + &extension)) { |
| + result->has_key_usage_ = true; |
| + if (!ParseKeyUsage(extension.value, &result->key_usage_)) |
| + return nullptr; |
| + } |
| + |
| + // Subject alternative name. |
| + if (ConsumeExtension(SubjectAltNameOid(), &result->unconsumed_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->unconsumed_extensions_, |
| + &extension)) { |
| + result->name_constraints_ = |
| + NameConstraints::CreateFromDer(extension.value, extension.critical); |
| + if (!result->name_constraints_) |
| + return nullptr; |
| + } |
| + } |
| + |
| + 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); |
| +} |
| + |
| +} // namespace net |