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

Side by Side Diff: chrome/common/extensions/api/networking_private/networking_private_crypto.cc

Issue 2464663002: chrome: move networking_private_crypto from common to browser (Closed)
Patch Set: chrome/test Created 4 years, 1 month 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 2014 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 "chrome/common/extensions/api/networking_private/networking_private_cry pto.h"
6
7 #include <stddef.h>
8
9 #include <memory>
10
11 #include "base/logging.h"
12 #include "base/strings/string_util.h"
13 #include "components/cast_certificate/cast_cert_validator.h"
14 #include "crypto/openssl_util.h"
15 #include "crypto/rsa_private_key.h"
16 #include "net/cert/pem_tokenizer.h"
17 #include "third_party/boringssl/src/include/openssl/digest.h"
18 #include "third_party/boringssl/src/include/openssl/evp.h"
19 #include "third_party/boringssl/src/include/openssl/rsa.h"
20 #include "third_party/boringssl/src/include/openssl/x509.h"
21
22 namespace {
23
24 namespace cast_crypto = ::cast_certificate;
25
26 // Parses |pem_data| for a PEM block of |pem_type|.
27 // Returns true if a |pem_type| block is found, storing the decoded result in
28 // |der_output|.
29 bool GetDERFromPEM(const std::string& pem_data,
30 const std::string& pem_type,
31 std::vector<uint8_t>* der_output) {
32 std::vector<std::string> headers;
33 headers.push_back(pem_type);
34 net::PEMTokenizer pem_tokenizer(pem_data, headers);
35 if (!pem_tokenizer.GetNext()) {
36 return false;
37 }
38
39 der_output->assign(pem_tokenizer.data().begin(), pem_tokenizer.data().end());
40 return true;
41 }
42
43 } // namespace
44
45 namespace networking_private_crypto {
46
47 bool VerifyCredentials(
48 const std::string& certificate,
49 const std::vector<std::string>& intermediate_certificates,
50 const std::string& signature,
51 const std::string& data,
52 const std::string& connected_mac) {
53 base::Time now = base::Time::Now();
54 return VerifyCredentialsAtTime(certificate, intermediate_certificates,
55 signature, data, connected_mac, now);
56 }
57
58 bool VerifyCredentialsAtTime(
59 const std::string& certificate,
60 const std::vector<std::string>& intermediate_certificates,
61 const std::string& signature,
62 const std::string& data,
63 const std::string& connected_mac,
64 const base::Time& time) {
65 static const char kErrorPrefix[] = "Device verification failed. ";
66
67 std::vector<std::string> headers;
68 headers.push_back("CERTIFICATE");
69
70 // Convert certificate from PEM to raw DER
71 net::PEMTokenizer pem_tokenizer(certificate, headers);
72 if (!pem_tokenizer.GetNext()) {
73 LOG(ERROR) << kErrorPrefix << "Failed to parse device certificate.";
74 return false;
75 }
76
77 // |certs| is a vector with the DER for all the certificates.
78 std::vector<std::string> certs;
79 certs.push_back(pem_tokenizer.data());
80
81 // Convert intermediate certificates from PEM to raw DER
82 for (size_t idx = 0; idx < intermediate_certificates.size(); ++idx) {
83 net::PEMTokenizer ica_pem_tokenizer(intermediate_certificates[idx],
84 headers);
85 if (ica_pem_tokenizer.GetNext()) {
86 certs.push_back(ica_pem_tokenizer.data());
87 } else {
88 LOG(WARNING) << "Failed to parse intermediate certificates.";
89 }
90 }
91
92 // Note that the device certificate's policy is not enforced here. The goal
93 // is simply to verify that the device belongs to the Cast ecosystem.
94 cast_crypto::CastDeviceCertPolicy unused_policy;
95
96 std::unique_ptr<cast_crypto::CertVerificationContext> verification_context;
97 if (!cast_crypto::VerifyDeviceCert(certs, time, &verification_context,
98 &unused_policy, nullptr,
99 cast_crypto::CRLPolicy::CRL_OPTIONAL)) {
100 LOG(ERROR) << kErrorPrefix << "Failed verifying cast device cert";
101 return false;
102 }
103
104 // Check that the device listed in the certificate is correct.
105 // Something like evt_e161 001a11ffacdf
106 std::string common_name = verification_context->GetCommonName();
107 std::string translated_mac;
108 base::RemoveChars(connected_mac, ":", &translated_mac);
109 if (!base::EndsWith(common_name, translated_mac,
110 base::CompareCase::INSENSITIVE_ASCII)) {
111 LOG(ERROR) << kErrorPrefix << "MAC addresses don't match.";
112 return false;
113 }
114
115 // Use the public key from verified certificate to verify |signature| over
116 // |data|.
117 if (!verification_context->VerifySignatureOverData(signature, data)) {
118 LOG(ERROR) << kErrorPrefix
119 << "Failed verifying signature using cast device cert";
120 return false;
121 }
122 return true;
123 }
124
125 bool EncryptByteString(const std::vector<uint8_t>& pub_key_der,
126 const std::string& data,
127 std::vector<uint8_t>* encrypted_output) {
128 crypto::EnsureOpenSSLInit();
129 crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
130
131 bssl::UniquePtr<RSA> rsa(
132 RSA_public_key_from_bytes(pub_key_der.data(), pub_key_der.size()));
133 if (!rsa || RSA_size(rsa.get()) == 0) {
134 LOG(ERROR) << "Failed to parse public key";
135 return false;
136 }
137
138 encrypted_output->resize(RSA_size(rsa.get()));
139 int encrypted_length = RSA_public_encrypt(
140 data.size(), reinterpret_cast<const uint8_t*>(data.data()),
141 encrypted_output->data(), rsa.get(), RSA_PKCS1_PADDING);
142 if (encrypted_length < 0) {
143 LOG(ERROR) << "Error during decryption";
144 return false;
145 }
146 encrypted_output->resize(encrypted_length);
147 return true;
148 }
149
150 bool DecryptByteString(const std::string& private_key_pem,
151 const std::vector<uint8_t>& encrypted_data,
152 std::string* decrypted_output) {
153 crypto::EnsureOpenSSLInit();
154 crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
155
156 std::vector<uint8_t> private_key_data;
157 if (!GetDERFromPEM(private_key_pem, "PRIVATE KEY", &private_key_data)) {
158 LOG(ERROR) << "Failed to parse private key PEM.";
159 return false;
160 }
161 std::unique_ptr<crypto::RSAPrivateKey> private_key(
162 crypto::RSAPrivateKey::CreateFromPrivateKeyInfo(private_key_data));
163 if (!private_key || !private_key->key()) {
164 LOG(ERROR) << "Failed to parse private key DER.";
165 return false;
166 }
167
168 RSA* rsa = EVP_PKEY_get0_RSA(private_key->key());
169 if (!rsa || RSA_size(rsa) == 0) {
170 LOG(ERROR) << "Failed to get RSA key.";
171 return false;
172 }
173
174 uint8_t* output = reinterpret_cast<uint8_t*>(
175 base::WriteInto(decrypted_output, RSA_size(rsa) + 1));
176 int output_length =
177 RSA_private_decrypt(encrypted_data.size(), &encrypted_data[0], output,
178 rsa, RSA_PKCS1_PADDING);
179 if (output_length < 0) {
180 LOG(ERROR) << "Error during decryption.";
181 return false;
182 }
183 decrypted_output->resize(output_length);
184 return true;
185 }
186
187 } // namespace networking_private_crypto
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698