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

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

Issue 23710003: Added NetworkingPrivateCrypto and its unit test. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Change kTrustedCAPublicKeyDER to byte array instead of base64 string. Created 7 years, 3 months 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 | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright 2013 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/browser/extensions/api/networking_private/networking_private_cr ypto.h"
6
7 #include <cert.h>
8 #include <cryptohi.h>
9 #include <keyhi.h>
10 #include <keythi.h>
11 #include <pk11pub.h>
12 #include <sechash.h>
13 #include <secport.h>
14
15 #include "base/base64.h"
16 #include "base/memory/scoped_ptr.h"
17 #include "base/strings/string_number_conversions.h"
18 #include "base/strings/string_util.h"
19 #include "base/strings/stringprintf.h"
20 #include "crypto/nss_util.h"
21 #include "crypto/rsa_private_key.h"
22 #include "crypto/scoped_nss_types.h"
23 #include "net/cert/pem_tokenizer.h"
24 #include "net/cert/x509_certificate.h"
25
26 const unsigned char kTrustedCAPublicKeyDER[] = {
Greg Spencer (Chromium) 2013/08/30 20:40:31 Chris, can you comment on where this key came from
Ryan Sleevi 2013/08/30 20:47:52 That's already the case. It's a manufacturing key.
wiley 2013/09/04 16:00:21 This is a key that was given to us by that team.
27 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xbc, 0x22, 0x80, 0xbd,
28 0x80, 0xf6, 0x3a, 0x21, 0x00, 0x3b, 0xae, 0x76, 0x5e, 0x35, 0x7f, 0x3d, 0xc3,
29 0x64, 0x5c, 0x55, 0x94, 0x86, 0x34, 0x2f, 0x05, 0x87, 0x28, 0xcd, 0xf7, 0x69,
30 0x8c, 0x17, 0xb3, 0x50, 0xa7, 0xb8, 0x82, 0xfa, 0xdf, 0xc7, 0x43, 0x2d, 0xd6,
31 0x7e, 0xab, 0xa0, 0x6f, 0xb7, 0x13, 0x72, 0x80, 0xa4, 0x47, 0x15, 0xc1, 0x20,
32 0x99, 0x50, 0xcd, 0xec, 0x14, 0x62, 0x09, 0x5b, 0xa4, 0x98, 0xcd, 0xd2, 0x41,
33 0xb6, 0x36, 0x4e, 0xff, 0xe8, 0x2e, 0x32, 0x30, 0x4a, 0x81, 0xa8, 0x42, 0xa3,
34 0x6c, 0x9b, 0x33, 0x6e, 0xca, 0xb2, 0xf5, 0x53, 0x66, 0xe0, 0x27, 0x53, 0x86,
35 0x1a, 0x85, 0x1e, 0xa7, 0x39, 0x3f, 0x4a, 0x77, 0x8e, 0xfb, 0x54, 0x66, 0x66,
36 0xfb, 0x58, 0x54, 0xc0, 0x5e, 0x39, 0xc7, 0xf5, 0x50, 0x06, 0x0b, 0xe0, 0x8a,
37 0xd4, 0xce, 0xe1, 0x6a, 0x55, 0x1f, 0x8b, 0x17, 0x00, 0xe6, 0x69, 0xa3, 0x27,
38 0xe6, 0x08, 0x25, 0x69, 0x3c, 0x12, 0x9d, 0x8d, 0x05, 0x2c, 0xd6, 0x2e, 0xa2,
39 0x31, 0xde, 0xb4, 0x52, 0x50, 0xd6, 0x20, 0x49, 0xde, 0x71, 0xa0, 0xf9, 0xad,
40 0x20, 0x40, 0x12, 0xf1, 0xdd, 0x25, 0xeb, 0xd5, 0xe6, 0xb8, 0x36, 0xf4, 0xd6,
41 0x8f, 0x7f, 0xca, 0x43, 0xdc, 0xd7, 0x10, 0x5b, 0xe6, 0x3f, 0x51, 0x8a, 0x85,
42 0xb3, 0xf3, 0xff, 0xf6, 0x03, 0x2d, 0xcb, 0x23, 0x4f, 0x9c, 0xad, 0x18, 0xe7,
43 0x93, 0x05, 0x8c, 0xac, 0x52, 0x9a, 0xf7, 0x4c, 0xe9, 0x99, 0x7a, 0xbe, 0x6e,
44 0x7e, 0x4d, 0x0a, 0xe3, 0xc6, 0x1c, 0xa9, 0x93, 0xfa, 0x3a, 0xa5, 0x91, 0x5d,
45 0x1c, 0xbd, 0x66, 0xeb, 0xcc, 0x60, 0xdc, 0x86, 0x74, 0xca, 0xcf, 0xf8, 0x92,
46 0x1c, 0x98, 0x7d, 0x57, 0xfa, 0x61, 0x47, 0x9e, 0xab, 0x80, 0xb7, 0xe4, 0x48,
47 0x80, 0x2a, 0x92, 0xc5, 0x1b, 0x02, 0x03, 0x01, 0x00, 0x01 };
48
49 namespace {
50
51 // Parses |pem_data| for a PEM block of |pem_type|.
52 // Returns true if a |pem_type| block is found, storing the decoded result in
53 // |der_output|.
54 bool GetDERFromPEM(const std::string& pem_data,
55 const std::string& pem_type,
56 std::string* der_output) {
57 std::vector<std::string> headers;
58 headers.push_back(pem_type);
59 net::PEMTokenizer pem_tok(pem_data, headers);
60 if (!pem_tok.GetNext()) {
61 return false;
62 }
63
64 *der_output = pem_tok.data();
65 return true;
66 }
67
68 } // namespace
69
70
71 NetworkingPrivateCrypto::NetworkingPrivateCrypto() {}
72
73 NetworkingPrivateCrypto::~NetworkingPrivateCrypto() {}
74
75 bool NetworkingPrivateCrypto::VerifyCredentials(
76 const std::string& certificate,
77 const std::string& signature,
78 const std::string& data,
79 const std::string& connected_mac) {
80 crypto::EnsureNSSInit();
81
82 std::string cert_data;
83 if (!GetDERFromPEM(certificate, "CERTIFICATE", &cert_data)) {
84 LOG(ERROR) << "Failed to parse certificate.";
85 return false;
86 }
87 SECItem der_cert;
88 der_cert.type = siDERCertBuffer;
89 der_cert.data = reinterpret_cast<unsigned char*>(
90 const_cast<char*>(cert_data.c_str()));
91 der_cert.len = cert_data.length();
92
93 // Parse into a certificate structure.
94 typedef scoped_ptr_malloc<
95 CERTCertificate,
96 crypto::NSSDestroyer<CERTCertificate,
97 CERT_DestroyCertificate> >
98 ScopedCERTCertificate;
99 ScopedCERTCertificate cert(CERT_NewTempCertificate(
100 CERT_GetDefaultCertDB(), &der_cert, NULL, PR_FALSE, PR_TRUE));
101 if (!cert.get()) {
102 LOG(ERROR) << "Failed to parse certificate.";
103 return false;
104 }
105
106 // Check that the certificate is signed by trusted CA.
107 SECItem trusted_ca_key_der_item;
108 trusted_ca_key_der_item.type = siDERCertBuffer;
109 trusted_ca_key_der_item.data = const_cast<unsigned char*>(
110 kTrustedCAPublicKeyDER),
111 trusted_ca_key_der_item.len = sizeof(kTrustedCAPublicKeyDER);
112 crypto::ScopedSECKEYPublicKey ca_public_key(
113 SECKEY_ImportDERPublicKey(&trusted_ca_key_der_item, CKK_RSA));
114 SECStatus verified = CERT_VerifySignedDataWithPublicKey(
115 &cert->signatureWrap, ca_public_key.get(), NULL);
116 if (verified != SECSuccess) {
117 LOG(ERROR) << "Certificate is not issued by the trusted CA.";
118 return false;
119 }
120
121 // Check that the device listed in the certificate is correct.
122 // Something like evt_e161 001a11ffacdf
123 char* common_name = CERT_GetCommonName(&cert->subject);
124 if (!common_name) {
125 LOG(ERROR) << "Certificate does not have common name.";
126 return false;
127 }
128
129 std::string subject_name(common_name);
130 PORT_Free(common_name);
131 std::string translated_mac;
132 RemoveChars(connected_mac, ":", &translated_mac);
133 if (!EndsWith(subject_name, translated_mac, false)) {
134 LOG(ERROR) << "MAC addresses don't match.";
135 return false;
136 }
137
138 // Make sure that the certificate matches the unsigned data presented.
139 // Verify that the |signature| matches |data|.
140 crypto::ScopedSECKEYPublicKey public_key(CERT_ExtractPublicKey(cert.get()));
141 if (!public_key.get()) {
142 LOG(ERROR) << "Unable to extract public key from certificate.";
143 return false;
144 }
145 SECItem signature_item;
146 signature_item.type = siBuffer;
147 signature_item.data = reinterpret_cast<unsigned char*>(
148 const_cast<char*>(signature.c_str()));
149 signature_item.len = static_cast<unsigned int>(signature.size());
150 verified = VFY_VerifyDataDirect(reinterpret_cast<unsigned char*>(
151 const_cast<char*>(data.c_str())), data.size(),
152 public_key.get(), &signature_item, SEC_OID_PKCS1_RSA_ENCRYPTION,
153 SEC_OID_SHA1, NULL, NULL);
154 if (verified != SECSuccess) {
155 LOG(ERROR) << "Signed blobs did not match.";
156 return false;
157 }
158 return true;
159 }
160
161 bool NetworkingPrivateCrypto::EncryptByteString(const std::string& pub_key_der,
162 const std::string& data,
163 std::string* encrypted_output) {
164 crypto::EnsureNSSInit();
165
166 SECItem pub_key_der_item;
167 pub_key_der_item.type = siDERCertBuffer;
168 pub_key_der_item.data = reinterpret_cast<unsigned char*>(
169 const_cast<char*>(pub_key_der.c_str()));
170 pub_key_der_item.len = pub_key_der.size();
171
172 crypto::ScopedSECKEYPublicKey public_key(SECKEY_ImportDERPublicKey(
173 &pub_key_der_item, CKK_RSA));
174 if (!public_key.get()) {
175 LOG(ERROR) << "Failed to parse public key.";
176 return false;
177 }
178
179 size_t encrypted_length = SECKEY_PublicKeyStrength(public_key.get());
180 // RSAES is defined as operating on messages up to a length of k - 11, where
181 // k is the octet length of the RSA modulus.
182 if (encrypted_length < data.size() + 11) {
183 LOG(ERROR) << "Too much data to encrypt.";
184 return false;
185 }
186
187 scoped_ptr<unsigned char[]> rsa_output(new unsigned char[encrypted_length]);
188 SECStatus encrypted = PK11_PubEncryptPKCS1(
189 public_key.get(),
190 rsa_output.get(),
191 reinterpret_cast<unsigned char*>(const_cast<char*>(data.data())),
192 data.length(),
193 NULL);
194 if (encrypted != SECSuccess) {
195 LOG(ERROR) << "Error during encryption.";
196 return false;
197 }
198 encrypted_output->assign(reinterpret_cast<char*>(rsa_output.get()),
199 encrypted_length);
200 return true;
201 }
202
203 bool NetworkingPrivateCrypto::DecryptByteString(
204 const std::string& private_key_pem,
205 const std::string& encrypted_data,
206 std::string* decrypted_output) {
207 crypto::EnsureNSSInit();
208
209 std::string private_key_der;
210 if (!GetDERFromPEM(private_key_pem, "PRIVATE KEY", &private_key_der)) {
211 LOG(ERROR) << "Failed to parse private key PEM.";
212 return false;
213 }
214 std::vector<uint8> private_key_data(private_key_der.begin(),
215 private_key_der.end());
216 scoped_ptr<crypto::RSAPrivateKey> private_key(
217 crypto::RSAPrivateKey::CreateFromPrivateKeyInfo(private_key_data));
218 if (!private_key || !private_key->public_key()) {
219 LOG(ERROR) << "Failed to parse private key DER.";
220 return false;
221 }
222
223 size_t encrypted_length = SECKEY_SignatureLen(private_key->public_key());
224 scoped_ptr<unsigned char[]> rsa_output(new unsigned char[encrypted_length]);
225 unsigned int output_length = 0;
226 SECStatus decrypted =
227 PK11_PrivDecryptPKCS1(private_key->key(),
228 rsa_output.get(),
229 &output_length,
230 encrypted_length,
231 reinterpret_cast<unsigned char*>(
232 const_cast<char*>(encrypted_data.data())),
233 encrypted_data.length());
234 if (decrypted != SECSuccess) {
235 LOG(ERROR) << "Error during decryption.";
236 return false;
237 }
238 decrypted_output->assign(reinterpret_cast<char*>(rsa_output.get()),
239 output_length);
240 return true;
241 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698