Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(168)

Side by Side Diff: net/tools/domain_security_preload_generator/cert_util.cc

Issue 2551153003: Add static domain security state generator tool. (Closed)
Patch Set: Fix iOS? Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "net/tools/domain_security_preload_generator/cert_util.h"
6
7 #include <string>
8
9 #include "base/base64.h"
10 #include "base/files/file_util.h"
11 #include "base/strings/string_util.h"
12 #include "base/strings/stringprintf.h"
13 #include "net/tools/domain_security_preload_generator/spki_hash.h"
14 #include "third_party/boringssl/src/include/openssl/crypto.h"
15
16 using net::transport_security_state::SPKIHash;
17
18 namespace {
19
20 static const char kPEMBeginBlock[] = "-----BEGIN %s-----";
21 static const char kPEMEndBlock[] = "-----END %s-----";
22
23 // Tries to extract the BASE64 encoded DER structure from |pem_input| by looking
24 // for the block type in |expected_block_type|. Only attempts the locate the
25 // first matching block. Other blocks are ignored. Returns true on success and
26 // copies the der structure to |*der_output|. Returns false on error.
27 bool ParsePEM(base::StringPiece pem_input,
28 base::StringPiece expected_block_type,
29 std::string* der_output) {
30 const std::string& block_start =
31 base::StringPrintf(kPEMBeginBlock, expected_block_type.data());
32 const std::string& block_end =
33 base::StringPrintf(kPEMEndBlock, expected_block_type.data());
34
35 size_t block_start_pos = pem_input.find(block_start);
36 if (block_start_pos == std::string::npos)
37 return false;
38 size_t base64_start_pos = block_start_pos + block_start.size();
39
40 size_t block_end_pos = pem_input.find(block_end, base64_start_pos);
41 if (block_end_pos == std::string::npos)
42 return false;
43
44 base::StringPiece base64_encoded =
45 pem_input.substr(base64_start_pos, block_end_pos - base64_start_pos);
46
47 if (!base::Base64Decode(
48 base::CollapseWhitespaceASCII(base64_encoded.as_string(), true),
49 der_output)) {
50 return false;
51 }
52
53 return true;
54 }
55
56 // Attempts to extract the first entry of type |nid| from |*name|. Returns true
57 // if the field exists and was extracted. Returns false when the field was not
58 // found or the data could not be extracted.
59 bool ExtractFieldFromX509Name(X509_NAME* name, int nid, std::string* field) {
60 int index = X509_NAME_get_index_by_NID(name, nid, -1);
61 if (index == -1) {
62 return false;
63 }
64
65 X509_NAME_ENTRY* entry = X509_NAME_get_entry(name, index);
66 if (!entry) {
67 return false;
68 }
69
70 ASN1_STRING* data = X509_NAME_ENTRY_get_data(entry);
71 if (!data) {
72 return false;
73 }
74
75 uint8_t* buffer = nullptr;
76 size_t length = ASN1_STRING_to_UTF8(&buffer, data);
77 field->assign(reinterpret_cast<const char*>(buffer), length);
78 OPENSSL_free(buffer);
79 return true;
80 }
81
82 } // namespace
83
84 bssl::UniquePtr<X509> GetX509CertificateFromPEM(base::StringPiece pem_data) {
85 std::string der;
86 if (!ParsePEM(pem_data, "CERTIFICATE", &der)) {
87 return bssl::UniquePtr<X509>();
88 }
89
90 const uint8_t* der_data = reinterpret_cast<const uint8_t*>(der.c_str());
91 return bssl::UniquePtr<X509>(
92 d2i_X509(NULL, &der_data, base::checked_cast<long>(der.size())));
93 }
94
95 bool ExtractSubjectNameFromCertificate(X509* certificate, std::string* name) {
96 DCHECK(certificate);
97 X509_NAME* subject = X509_get_subject_name(certificate);
98 if (!subject) {
99 return false;
100 }
101
102 std::string result;
103 // Try extracting the common name first.
104 if (!ExtractFieldFromX509Name(subject, NID_commonName, &result) ||
105 result.empty()) {
106 std::string organization;
107 if (!ExtractFieldFromX509Name(subject, NID_organizationName,
108 &organization)) {
109 return false;
110 }
111
112 std::string organizational_unit;
113 if (!ExtractFieldFromX509Name(subject, NID_organizationalUnitName,
114 &organizational_unit)) {
115 return false;
116 }
117 result = organization + " " + organizational_unit;
118 }
119
120 name->assign(result);
121 return true;
122 }
123
124 bool CalculateSPKIHashFromCertificate(X509* certificate, SPKIHash* out_hash) {
125 DCHECK(certificate);
126 bssl::UniquePtr<EVP_PKEY> key(X509_get_pubkey(certificate));
127 if (!key) {
128 return false;
129 }
130
131 uint8_t* spki_der;
132 size_t spki_der_len;
133 bssl::ScopedCBB cbb;
134 if (!CBB_init(cbb.get(), 0) ||
135 !EVP_marshal_public_key(cbb.get(), key.get()) ||
136 !CBB_finish(cbb.get(), &spki_der, &spki_der_len)) {
137 return false;
138 }
139
140 out_hash->CalculateFromBytes(spki_der, spki_der_len);
141 OPENSSL_free(spki_der);
142 return true;
143 }
144
145 bool CalculateSPKIHashFromKey(base::StringPiece pem_key, SPKIHash* out_hash) {
146 std::string der;
147 bool result = ParsePEM(pem_key, "PUBLIC KEY", &der);
148 if (!result) {
149 return false;
150 }
151
152 out_hash->CalculateFromBytes(reinterpret_cast<const uint8_t*>(der.data()),
153 der.size());
154 return true;
155 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698