OLD | NEW |
| (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 | |
OLD | NEW |