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 |