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

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: Code cleanup and more unit tests. 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 char kTrustedCAPublicKeyDER[] =
Greg Spencer (Chromium) 2013/08/30 18:38:17 What is the origin of this CA key, and why is it h
mef 2013/08/30 20:07:17 Actually I'm not sure. I took it from original cod
27 "MIIBCgKCAQEAvCKAvYD2OiEAO652XjV/PcNkXFWUhjQvBYcozfdpjBezUKe4gvrfx0Mt1n6roG"
28 "+3E3KApEcVwSCZUM3sFGIJW6SYzdJBtjZO/+guMjBKgahCo2ybM27KsvVTZuAnU4YahR6nOT9K"
29 "d477VGZm+1hUwF45x/VQBgvgitTO4WpVH4sXAOZpoyfmCCVpPBKdjQUs1i6iMd60UlDWIEneca"
30 "D5rSBAEvHdJevV5rg29NaPf8pD3NcQW+Y/UYqFs/P/9gMtyyNPnK0Y55MFjKxSmvdM6Zl6vm5+"
31 "TQrjxhypk/o6pZFdHL1m68xg3IZ0ys/4khyYfVf6YUeeq4C35EiAKpLFGwIDAQAB";
32
33 namespace {
Ryan Sleevi 2013/08/30 18:40:26 nit: line break between 33/34.
mef 2013/08/30 20:07:17 Done.
34 bool GetDERFromPEM(const std::string& pem_data,
Greg Spencer (Chromium) 2013/08/30 18:38:17 Document what this function does, and what the par
Ryan Sleevi 2013/08/30 18:40:26 nit: Add comment. // Parses |pem_data| for a PEM
mef 2013/08/30 20:07:17 Done.
mef 2013/08/30 20:07:17 Done.
35 const std::string& pem_type,
36 std::string* der_output) {
37 std::vector<std::string> headers;
38 headers.push_back(pem_type);
39 net::PEMTokenizer pem_tok(pem_data, headers);
40 if (!pem_tok.GetNext()) {
41 return false;
42 }
43
44 *der_output = pem_tok.data();
45 return true;
46 }
47
48 } // namespace
49
50 namespace crypto {
51 typedef scoped_ptr_malloc<
Greg Spencer (Chromium) 2013/08/30 18:38:17 Document what this typedef is used for, and why it
mef 2013/08/30 20:07:17 Removed per Ryan's suggestion.
52 CERTCertificate,
53 crypto::NSSDestroyer<CERTCertificate,
Greg Spencer (Chromium) 2013/08/30 18:38:17 If this is in the crypto namespace, you don't need
mef 2013/08/30 20:07:17 Done.
54 CERT_DestroyCertificate> >
55 ScopedCERTCertificate;
56 } // namespace crypto
Ryan Sleevi 2013/08/30 18:40:26 Don't stick this into crypto - you don't need to.
mef 2013/08/30 20:07:17 Done.
57
58 NetworkingPrivateCrypto::NetworkingPrivateCrypto() {}
59
60 NetworkingPrivateCrypto::~NetworkingPrivateCrypto() {}
61
62 bool NetworkingPrivateCrypto::VerifyCredentials(
63 const std::string& certificate,
64 const std::string& signature,
65 const std::string& data,
66 const std::string& connected_mac) {
67 crypto::EnsureNSSInit();
68
69 std::string cert_data;
70 if (!GetDERFromPEM(certificate, "CERTIFICATE", &cert_data)) {
71 LOG(ERROR) << "Failed to parse certificate.";
72 return false;
73 }
74 SECItem der_cert = {
75 siDERCertBuffer,
76 reinterpret_cast<unsigned char*>(const_cast<char*>(cert_data.c_str())),
77 cert_data.length()};
78 // Parse into a certificate structure.
79 crypto::ScopedCERTCertificate cert(CERT_NewTempCertificate(
80 CERT_GetDefaultCertDB(), &der_cert, NULL, PR_FALSE, PR_TRUE));
81 if (!cert.get()) {
82 LOG(ERROR) << "Failed to parse certificate.";
83 return false;
84 }
85 // Check that the certificate is signed by trusted CA.
Ryan Sleevi 2013/08/30 18:40:26 A little judicious use of vertical whitespace woul
86 std::string ca_key_der;
87 base::Base64Decode(kTrustedCAPublicKeyDER, &ca_key_der);
Greg Spencer (Chromium) 2013/08/30 18:38:17 Couldn't you just do this once, and store it for n
Ryan Sleevi 2013/08/30 18:40:26 Since this is a fixed constant, it'd be much bette
mef 2013/08/30 20:07:17 I was thinking about that, but couldn't think of a
mef 2013/08/30 20:07:17 I could, but realistically this is not performance
Greg Spencer (Chromium) 2013/08/30 20:11:17 I like Ryan's idea better of just storing the DER
mef 2013/08/30 20:37:00 Done.
88 SECItem trusted_ca_key_der_item = {
89 siDERCertBuffer,
90 reinterpret_cast<unsigned char*>(const_cast<char*>(ca_key_der.c_str())),
91 ca_key_der.size()};
Ryan Sleevi 2013/08/30 18:40:26 style nit: this style of initializing a SECItem i
mef 2013/08/30 20:07:17 D'Oh, I've found this style of initializing and co
92 crypto::ScopedSECKEYPublicKey ca_public_key(
93 SECKEY_ImportDERPublicKey(&trusted_ca_key_der_item, CKK_RSA));
94 SECStatus verified = CERT_VerifySignedDataWithPublicKey(
95 &cert->signatureWrap, ca_public_key.get(), NULL);
96 if (verified != SECSuccess) {
97 LOG(ERROR) << "Certificate is not issued by trusted CA.";
Greg Spencer (Chromium) 2013/08/30 18:38:17 "by the trusted CA"?
mef 2013/08/30 20:07:17 Done.
98 return false;
99 }
100
101 // Check that the device listed in the certificate is correct.
102 // Something like evt_e161 001a11ffacdf
103 char* common_name = CERT_GetCommonName(&cert->subject);
104 if (!common_name) {
105 LOG(ERROR) << "Certificate does not have common name.";
106 return false;
107 }
108
109 std::string subject_name(common_name);
110 PORT_Free(common_name);
111 std::string translated_mac;
112 RemoveChars(connected_mac, ":", &translated_mac);
113 if (!EndsWith(subject_name, translated_mac, false)) {
114 LOG(ERROR) << "MAC addresses don't match.";
115 return false;
116 }
117
118 // Make sure that the certificate matches the unsigned data presented.
119 // Verify that the |signature| matches |data|.
120 crypto::ScopedSECKEYPublicKey public_key(CERT_ExtractPublicKey(cert.get()));
121 if (!public_key.get()) {
122 LOG(ERROR) << "Unable to extract public key from certificate.";
123 return false;
124 }
125 SECItem signature_item = {
126 siBuffer,
127 reinterpret_cast<unsigned char*>(const_cast<char*>(signature.c_str())),
128 static_cast<unsigned int>(signature.size())};
129 verified = VFY_VerifyDataDirect(reinterpret_cast<unsigned char*>(
130 const_cast<char*>(data.c_str())), data.size(),
131 public_key.get(), &signature_item, SEC_OID_PKCS1_RSA_ENCRYPTION,
132 SEC_OID_SHA1, NULL, NULL);
133 if (verified != SECSuccess) {
134 LOG(ERROR) << "Signed blobs did not match.";
135 return false;
136 }
137 return true;
138 }
139
140 bool NetworkingPrivateCrypto::EncryptByteString(const std::string& pub_key_der,
141 const std::string& data,
142 std::string* encrypted_output) {
143 crypto::EnsureNSSInit();
144
145 SECItem pub_key_der_item = {
146 siDERCertBuffer,
147 reinterpret_cast<unsigned char*>(const_cast<char*>(pub_key_der.c_str())),
148 pub_key_der.size()};
149 crypto::ScopedSECKEYPublicKey public_key(SECKEY_ImportDERPublicKey(
150 &pub_key_der_item, CKK_RSA));
151 if (!public_key.get()) {
152 LOG(ERROR) << "Failed to parse public key.";
153 return false;
154 }
155
156 size_t encrypted_length = SECKEY_SignatureLen(public_key.get());
157 if (encrypted_length < data.size() + 13) {
Ryan Sleevi 2013/08/30 18:40:26 Why are you using "13" here. This deserves a comme
mef 2013/08/30 20:07:17 Done.
158 LOG(ERROR) << "Too much data to encrypt.";
159 return false;
160 }
161
162 scoped_ptr<unsigned char[]> rsa_output(new unsigned char[encrypted_length]);
163 SECStatus encrypted = PK11_PubEncryptPKCS1(
164 public_key.get(),
165 rsa_output.get(),
166 reinterpret_cast<unsigned char*>(const_cast<char*>(data.data())),
167 data.length(),
168 NULL);
169 if (encrypted != SECSuccess) {
170 LOG(ERROR) << "Error during encryption.";
171 return false;
172 }
173 encrypted_output->assign(reinterpret_cast<char*>(rsa_output.get()),
174 encrypted_length);
175 return true;
176 }
177
178 bool NetworkingPrivateCrypto::DecryptByteString(
179 const std::string& private_key_pem,
180 const std::string& encrypted_data,
181 std::string* decrypted_output) {
182 crypto::EnsureNSSInit();
183
184 std::string private_key_der;
185 if (!GetDERFromPEM(private_key_pem, "PRIVATE KEY", &private_key_der)) {
186 LOG(ERROR) << "Failed to parse private key PEM.";
187 return false;
188 }
189 std::vector<uint8> private_key_data(private_key_der.begin(),
190 private_key_der.end());
191 scoped_ptr<crypto::RSAPrivateKey> private_key(
192 crypto::RSAPrivateKey::CreateFromPrivateKeyInfo(private_key_data));
193 if (!private_key || !private_key->public_key()) {
194 LOG(ERROR) << "Failed to parse private key DER.";
195 return false;
196 }
197
198 size_t encrypted_length = SECKEY_SignatureLen(private_key->public_key());
199 scoped_ptr<unsigned char[]> rsa_output(new unsigned char[encrypted_length]);
200 unsigned int output_length = 0;
201 SECStatus decrypted =
202 PK11_PrivDecryptPKCS1(private_key->key(),
203 rsa_output.get(),
204 &output_length,
205 encrypted_length,
206 reinterpret_cast<unsigned char*>(
207 const_cast<char*>(encrypted_data.data())),
208 encrypted_data.length());
209 if (decrypted != SECSuccess) {
210 LOG(ERROR) << "Error during decryption.";
211 return false;
212 }
213 decrypted_output->assign(reinterpret_cast<char*>(rsa_output.get()),
214 output_length);
215 return true;
216 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698