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

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: Use VFY_VerifyDataDirect as VFY_VerifyData is deprecated. 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[] =
27 "MIIBCgKCAQEAvCKAvYD2OiEAO652XjV/PcNkXFWUhjQvBYcozfdpjBezUKe4gvrfx0Mt1n6roG"
28 "+3E3KApEcVwSCZUM3sFGIJW6SYzdJBtjZO/+guMjBKgahCo2ybM27KsvVTZuAnU4YahR6nOT9K"
29 "d477VGZm+1hUwF45x/VQBgvgitTO4WpVH4sXAOZpoyfmCCVpPBKdjQUs1i6iMd60UlDWIEneca"
30 "D5rSBAEvHdJevV5rg29NaPf8pD3NcQW+Y/UYqFs/P/9gMtyyNPnK0Y55MFjKxSmvdM6Zl6vm5+"
31 "TQrjxhypk/o6pZFdHL1m68xg3IZ0ys/4khyYfVf6YUeeq4C35EiAKpLFGwIDAQAB";
32
33 namespace {
34 bool GetDERFromPEM(const std::string& pem_data,
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<
52 CERTCertificate,
53 ::crypto::NSSDestroyer<CERTCertificate,
54 CERT_DestroyCertificate> >
55 ScopedCERTCertificate;
Ryan Sleevi 2013/08/29 21:30:43 Clang-format messing up again. May be worth filing
mef 2013/08/30 17:07:39 Done.
56 } // namespace crypto
57
58 NetworkingPrivateCrypto::NetworkingPrivateCrypto() {}
59
60 NetworkingPrivateCrypto::~NetworkingPrivateCrypto() {}
61
62 bool NetworkingPrivateCrypto::VerifyCredentials(
63 const std::string& certificate,
64 const std::string& signed_data,
65 const std::string& unsigned_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.
86 std::string ca_key_der;
87 base::Base64Decode(kTrustedCAPublicKeyDER, &ca_key_der);
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()};
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.";
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 hash(unsigned_data) == public(signed_data)
Ryan Sleevi 2013/08/29 21:30:43 This comment doesn't really make sense, especially
mef 2013/08/30 17:07:39 Done.
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*>(signed_data.c_str())),
128 static_cast<unsigned int>(signed_data.size())};
129 verified = VFY_VerifyDataDirect(reinterpret_cast<unsigned char*>(
130 const_cast<char*>(unsigned_data.c_str())), unsigned_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 scoped_ptr<unsigned char[]> rsa_output(new unsigned char[encrypted_length]);
158 SECStatus encrypted = PK11_PubEncryptPKCS1(
159 public_key.get(),
160 rsa_output.get(),
161 reinterpret_cast<unsigned char*>(const_cast<char*>(data.data())),
162 data.length(),
163 NULL);
164 if (encrypted != SECSuccess) {
165 LOG(ERROR) << "Error during encryption.";
166 return false;
167 }
168 encrypted_output->assign(reinterpret_cast<char*>(rsa_output.get()),
169 encrypted_length);
170 return true;
171 }
172
173 bool NetworkingPrivateCrypto::DecryptByteString(
174 const std::string& private_key_pem,
175 const std::string& encrypted_data,
176 std::string* decrypted_output) {
177 crypto::EnsureNSSInit();
178
179 std::string private_key_der;
180 if (!GetDERFromPEM(private_key_pem, "PRIVATE KEY", &private_key_der)) {
181 LOG(ERROR) << "Failed to parse private key PEM.";
182 return false;
183 }
184 std::vector<uint8> private_key_data(private_key_der.begin(),
185 private_key_der.end());
186 scoped_ptr<crypto::RSAPrivateKey> private_key(
187 crypto::RSAPrivateKey::CreateFromPrivateKeyInfo(private_key_data));
188 if (!private_key || !private_key->public_key()) {
189 LOG(ERROR) << "Failed to parse private key DER.";
190 return false;
191 }
192
193 size_t encrypted_length = SECKEY_SignatureLen(private_key->public_key());
194 scoped_ptr<unsigned char[]> rsa_output(new unsigned char[encrypted_length]);
195 unsigned int output_length = 0;
196 SECStatus decrypted =
197 PK11_PrivDecryptPKCS1(private_key->key(),
198 rsa_output.get(),
199 &output_length,
200 encrypted_length,
201 reinterpret_cast<unsigned char*>(
202 const_cast<char*>(encrypted_data.data())),
203 encrypted_data.length());
204 if (decrypted != SECSuccess) {
205 LOG(ERROR) << "Error during encryption.";
206 return false;
207 }
208 decrypted_output->assign(reinterpret_cast<char*>(rsa_output.get()),
209 output_length);
210 return true;
211 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698