OLD | NEW |
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/chromeos/login/owner_key_utils.h" | 5 #include "chrome/browser/chromeos/login/owner_key_utils.h" |
6 | 6 |
7 #include <keyhi.h> // SECKEY_CreateSubjectPublicKeyInfo() | 7 #include <keyhi.h> // SECKEY_CreateSubjectPublicKeyInfo() |
8 #include <pk11pub.h> | 8 #include <pk11pub.h> |
9 #include <prerror.h> // PR_GetError() | 9 #include <prerror.h> // PR_GetError() |
10 #include <secder.h> // DER_Encode() | 10 #include <secder.h> // DER_Encode() |
11 #include <secmod.h> | 11 #include <secmod.h> |
12 | 12 |
13 #include <limits> | 13 #include <limits> |
14 | 14 |
15 #include "base/file_path.h" | 15 #include "base/file_path.h" |
16 #include "base/file_util.h" | 16 #include "base/file_util.h" |
17 #include "base/logging.h" | 17 #include "base/logging.h" |
18 #include "base/nss_util_internal.h" | 18 #include "base/nss_util_internal.h" |
19 #include "base/nss_util.h" | 19 #include "base/nss_util.h" |
20 #include "base/scoped_ptr.h" | 20 #include "base/scoped_ptr.h" |
21 #include "base/string_util.h" | 21 #include "base/string_util.h" |
22 | 22 |
| 23 namespace chromeos { |
| 24 |
| 25 /////////////////////////////////////////////////////////////////////////// |
| 26 // OwnerKeyUtils |
| 27 |
23 // static | 28 // static |
24 OwnerKeyUtils::Factory* OwnerKeyUtils::factory_ = NULL; | 29 OwnerKeyUtils::Factory* OwnerKeyUtils::factory_ = NULL; |
25 | 30 |
| 31 OwnerKeyUtils::OwnerKeyUtils() {} |
| 32 |
| 33 OwnerKeyUtils::~OwnerKeyUtils() {} |
| 34 |
| 35 /////////////////////////////////////////////////////////////////////////// |
| 36 // OwnerKeyUtilsImpl |
| 37 |
26 class OwnerKeyUtilsImpl : public OwnerKeyUtils { | 38 class OwnerKeyUtilsImpl : public OwnerKeyUtils { |
27 public: | 39 public: |
28 OwnerKeyUtilsImpl(); | 40 OwnerKeyUtilsImpl(); |
29 virtual ~OwnerKeyUtilsImpl(); | 41 virtual ~OwnerKeyUtilsImpl(); |
30 | 42 |
31 bool GenerateKeyPair(SECKEYPrivateKey** private_key_out, | 43 bool GenerateKeyPair(SECKEYPrivateKey** private_key_out, |
32 SECKEYPublicKey** public_key_out); | 44 SECKEYPublicKey** public_key_out); |
33 | 45 |
34 bool ExportPublicKey(SECKEYPublicKey* key, const FilePath& key_file); | 46 bool ExportPublicKeyViaDbus(SECKEYPublicKey* key); |
| 47 |
| 48 bool ExportPublicKeyToFile(SECKEYPublicKey* key, const FilePath& key_file); |
35 | 49 |
36 SECKEYPublicKey* ImportPublicKey(const FilePath& key_file); | 50 SECKEYPublicKey* ImportPublicKey(const FilePath& key_file); |
37 | 51 |
| 52 SECKEYPrivateKey* FindPrivateKey(SECKEYPublicKey* key); |
| 53 |
| 54 void DestroyKeys(SECKEYPrivateKey* private_key, SECKEYPublicKey* public_key); |
| 55 |
| 56 FilePath GetOwnerKeyFilePath(); |
| 57 |
38 private: | 58 private: |
39 // Fills in fields of |key_der| with DER encoded data from a file at | 59 // Fills in fields of |key_der| with DER encoded data from a file at |
40 // |key_file|. The caller must pass in a pointer to an actual SECItem | 60 // |key_file|. The caller must pass in a pointer to an actual SECItem |
41 // struct for |key_der|. |key_der->data| should be initialized to NULL | 61 // struct for |key_der|. |key_der->data| should be initialized to NULL |
42 // and |key_der->len| should be set to 0. | 62 // and |key_der->len| should be set to 0. |
43 // | 63 // |
44 // Upon success, data is stored in key_der->data, and the caller takes | 64 // Upon success, data is stored in key_der->data, and the caller takes |
45 // ownership. Returns false on error. | 65 // ownership. Returns false on error. |
46 // | 66 // |
47 // To free the data, call | 67 // To free the data, call |
48 // SECITEM_FreeItem(key_der, PR_FALSE); | 68 // SECITEM_FreeItem(key_der, PR_FALSE); |
49 static bool ReadDERFromFile(const FilePath& key_file, SECItem* key_der); | 69 static bool ReadDERFromFile(const FilePath& key_file, SECItem* key_der); |
50 | 70 |
51 // The place outside the owner's encrypted home directory where her | 71 static bool EncodePublicKey(SECKEYPublicKey* key, std::string* out); |
| 72 |
| 73 // The file outside the owner's encrypted home directory where her |
52 // key will live. | 74 // key will live. |
53 static const char kOwnerKeyFile[]; | 75 static const char kOwnerKeyFile[]; |
54 | 76 |
55 // Key generation parameters. | 77 // Key generation parameters. |
56 static const uint32 kKeyGenMechanism; // used by PK11_GenerateKeyPair() | 78 static const uint32 kKeyGenMechanism; // used by PK11_GenerateKeyPair() |
57 static const unsigned long kExponent; | 79 static const unsigned long kExponent; |
58 static const int kKeySizeInBits; | 80 static const int kKeySizeInBits; |
59 | 81 |
60 DISALLOW_COPY_AND_ASSIGN(OwnerKeyUtilsImpl); | 82 DISALLOW_COPY_AND_ASSIGN(OwnerKeyUtilsImpl); |
61 }; | 83 }; |
62 | 84 |
63 OwnerKeyUtils::OwnerKeyUtils() {} | 85 // Defined here, instead of up above, because we need OwnerKeyUtilsImpl. |
64 | |
65 OwnerKeyUtils::~OwnerKeyUtils() {} | |
66 | |
67 OwnerKeyUtils* OwnerKeyUtils::Create() { | 86 OwnerKeyUtils* OwnerKeyUtils::Create() { |
68 if (!factory_) | 87 if (!factory_) |
69 return new OwnerKeyUtilsImpl(); | 88 return new OwnerKeyUtilsImpl(); |
70 else | 89 else |
71 return factory_->CreateOwnerKeyUtils(); | 90 return factory_->CreateOwnerKeyUtils(); |
72 } | 91 } |
73 | 92 |
74 // static | 93 // static |
75 const char OwnerKeyUtilsImpl::kOwnerKeyFile[] = "/var/lib/whitelist/owner.key"; | 94 const char OwnerKeyUtilsImpl::kOwnerKeyFile[] = "/var/lib/whitelist/owner.key"; |
76 | 95 |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
140 if (!*private_key_out) { | 159 if (!*private_key_out) { |
141 LOG(INFO) << "Generation of Keypair failed!"; | 160 LOG(INFO) << "Generation of Keypair failed!"; |
142 is_success = false; | 161 is_success = false; |
143 goto failure; | 162 goto failure; |
144 } | 163 } |
145 | 164 |
146 failure: | 165 failure: |
147 if (!is_success) { | 166 if (!is_success) { |
148 LOG(ERROR) << "Owner key generation failed! (NSS error code " | 167 LOG(ERROR) << "Owner key generation failed! (NSS error code " |
149 << PR_GetError() << ")"; | 168 << PR_GetError() << ")"; |
150 // Do cleanups | 169 DestroyKeys(*private_key_out, *public_key_out); |
151 base::AutoNSSWriteLock lock; | 170 *private_key_out = NULL; |
152 if (*private_key_out) { | 171 *public_key_out = NULL; |
153 PK11_DestroyTokenObject((*private_key_out)->pkcs11Slot, | |
154 (*private_key_out)->pkcs11ID); | |
155 SECKEY_DestroyPrivateKey(*private_key_out); | |
156 } | |
157 if (*public_key_out) { | |
158 PK11_DestroyTokenObject((*public_key_out)->pkcs11Slot, | |
159 (*public_key_out)->pkcs11ID); | |
160 SECKEY_DestroyPublicKey(*public_key_out); | |
161 } | |
162 } else { | 172 } else { |
163 LOG(INFO) << "Owner key generation succeeded!"; | 173 LOG(INFO) << "Owner key generation succeeded!"; |
164 } | 174 } |
165 if (slot != NULL) { | 175 if (slot != NULL) { |
166 PK11_FreeSlot(slot); | 176 PK11_FreeSlot(slot); |
167 } | 177 } |
168 | 178 |
169 return is_success; | 179 return is_success; |
170 } | 180 } |
171 | 181 |
172 bool OwnerKeyUtilsImpl::ExportPublicKey(SECKEYPublicKey* key, | 182 bool OwnerKeyUtilsImpl::ExportPublicKeyViaDbus(SECKEYPublicKey* key) { |
173 const FilePath& key_file) { | |
174 DCHECK(key); | 183 DCHECK(key); |
175 SECItem* der; | 184 bool ok = false; |
| 185 |
| 186 std::string to_export; |
| 187 if (!EncodePublicKey(key, &to_export)) { |
| 188 LOG(ERROR) << "Formatting key for export failed!"; |
| 189 return ok; |
| 190 } |
| 191 |
| 192 // TODO(cmasone): send the data over dbus. |
| 193 return ok; |
| 194 } |
| 195 |
| 196 bool OwnerKeyUtilsImpl::ExportPublicKeyToFile(SECKEYPublicKey* key, |
| 197 const FilePath& key_file) { |
| 198 DCHECK(key); |
176 bool ok = false; | 199 bool ok = false; |
177 int safe_file_size = 0; | 200 int safe_file_size = 0; |
178 | 201 |
179 // Instead of exporting/importing the key directly, I'm actually | 202 std::string to_export; |
180 // going to use a SubjectPublicKeyInfo. The reason is because NSS | 203 if (!EncodePublicKey(key, &to_export)) { |
181 // exports functions that encode/decode these kinds of structures, while | 204 LOG(ERROR) << "Formatting key for export failed!"; |
182 // it does not export the ones that deal directly with public keys. | 205 return ok; |
183 der = SECKEY_EncodeDERSubjectPublicKeyInfo(key); | |
184 if (!der) { | |
185 LOG(ERROR) << "Could not encode public key for export!"; | |
186 return false; | |
187 } | 206 } |
188 | 207 |
189 if (der->len > static_cast<uint>(INT_MAX)) { | 208 if (to_export.length() > static_cast<uint>(INT_MAX)) { |
190 LOG(ERROR) << "key is too big! " << der->len; | 209 LOG(ERROR) << "key is too big! " << to_export.length(); |
191 } else { | 210 } else { |
192 safe_file_size = static_cast<int>(der->len); | 211 safe_file_size = static_cast<int>(to_export.length()); |
193 | 212 |
194 ok = (safe_file_size == | 213 ok = (safe_file_size == file_util::WriteFile(key_file, |
195 file_util::WriteFile(key_file, | 214 to_export.c_str(), |
196 reinterpret_cast<char*>(der->data), | 215 safe_file_size)); |
197 der->len)); | |
198 } | 216 } |
199 SECITEM_FreeItem(der, PR_TRUE); | |
200 return ok; | 217 return ok; |
201 } | 218 } |
202 | 219 |
203 SECKEYPublicKey* OwnerKeyUtilsImpl::ImportPublicKey(const FilePath& key_file) { | 220 SECKEYPublicKey* OwnerKeyUtilsImpl::ImportPublicKey(const FilePath& key_file) { |
204 SECItem key_der; | 221 SECItem key_der; |
| 222 key_der.data = NULL; |
| 223 key_der.len = 0; |
205 | 224 |
206 if (!ReadDERFromFile(key_file, &key_der)) { | 225 if (!ReadDERFromFile(key_file, &key_der)) { |
207 PLOG(ERROR) << "Could not read in key from " << key_file.value() << ":"; | 226 PLOG(ERROR) << "Could not read in key from " << key_file.value() << ":"; |
208 return NULL; | 227 return NULL; |
209 } | 228 } |
210 | 229 |
211 // See the comment in ExportPublicKey() for why I wrote a | 230 // See the comment in ExportPublicKey() for why I wrote a |
212 // SubjectPublicKeyInfo to disk instead of a key. | 231 // SubjectPublicKeyInfo to disk instead of a key. |
213 CERTSubjectPublicKeyInfo* spki = | 232 CERTSubjectPublicKeyInfo* spki = |
214 SECKEY_DecodeDERSubjectPublicKeyInfo(&key_der); | 233 SECKEY_DecodeDERSubjectPublicKeyInfo(&key_der); |
215 if (!spki) { | 234 if (!spki) { |
216 LOG(ERROR) << "Could not decode key info: " << PR_GetError(); | 235 LOG(ERROR) << "Could not decode key info: " << PR_GetError(); |
217 SECITEM_FreeItem(&key_der, PR_FALSE); | 236 SECITEM_FreeItem(&key_der, PR_FALSE); |
218 return NULL; | 237 return NULL; |
219 } | 238 } |
220 | 239 |
221 SECKEYPublicKey *public_key = SECKEY_ExtractPublicKey(spki); | 240 SECKEYPublicKey *public_key = SECKEY_ExtractPublicKey(spki); |
222 SECKEY_DestroySubjectPublicKeyInfo(spki); | 241 SECKEY_DestroySubjectPublicKeyInfo(spki); |
223 SECITEM_FreeItem(&key_der, PR_FALSE); | 242 SECITEM_FreeItem(&key_der, PR_FALSE); |
224 return public_key; | 243 return public_key; |
225 } | 244 } |
226 | 245 |
227 // static | 246 // static |
228 bool OwnerKeyUtilsImpl::ReadDERFromFile(const FilePath& key_file, | 247 bool OwnerKeyUtilsImpl::ReadDERFromFile(const FilePath& key_file, |
229 SECItem* key_der) { | 248 SECItem* key_der) { |
230 // I'd use NSS' SECU_ReadDERFromFile() here, but the SECU_* functions are | 249 // I'd use NSS' SECU_ReadDERFromFile() here, but the SECU_* functions are |
231 // considered internal to the NSS command line utils. | 250 // considered internal to the NSS command line utils. |
232 // This code is lifted, in spirit, from the implementation of that function. | 251 // This code is lifted, in spirit, from the implementation of that function. |
233 DCHECK(key_der) << "Don't pass NULL for |key_der|"; | 252 DCHECK(key_der) << "Don't pass NULL for |key_der|"; |
| 253 DCHECK(key_der->data == NULL); |
| 254 DCHECK(key_der->len == 0); |
234 | 255 |
235 // Get the file size (must fit in a 32 bit int for NSS). | 256 // Get the file size (must fit in a 32 bit int for NSS). |
236 int64 file_size; | 257 int64 file_size; |
237 if (!file_util::GetFileSize(key_file, &file_size)) { | 258 if (!file_util::GetFileSize(key_file, &file_size)) { |
238 LOG(ERROR) << "Could not get size of " << key_file.value(); | 259 LOG(ERROR) << "Could not get size of " << key_file.value(); |
239 return false; | 260 return false; |
240 } | 261 } |
241 if (file_size > static_cast<int64>(std::numeric_limits<int>::max())) { | 262 if (file_size > static_cast<int64>(std::numeric_limits<int>::max())) { |
242 LOG(ERROR) << key_file.value() << "is " | 263 LOG(ERROR) << key_file.value() << "is " |
243 << file_size << "bytes!!! Too big!"; | 264 << file_size << "bytes!!! Too big!"; |
(...skipping 14 matching lines...) Expand all Loading... |
258 safe_file_size); | 279 safe_file_size); |
259 | 280 |
260 if (data_read != safe_file_size) { | 281 if (data_read != safe_file_size) { |
261 LOG(ERROR) << "Read the wrong amount of data from the DER encoded key! " | 282 LOG(ERROR) << "Read the wrong amount of data from the DER encoded key! " |
262 << data_read; | 283 << data_read; |
263 SECITEM_FreeItem(key_der, PR_FALSE); | 284 SECITEM_FreeItem(key_der, PR_FALSE); |
264 return false; | 285 return false; |
265 } | 286 } |
266 return true; | 287 return true; |
267 } | 288 } |
| 289 |
| 290 bool OwnerKeyUtilsImpl::EncodePublicKey(SECKEYPublicKey* key, |
| 291 std::string* out) { |
| 292 SECItem* der; |
| 293 |
| 294 // Instead of exporting/importing the key directly, I'm actually |
| 295 // going to use a SubjectPublicKeyInfo. The reason is because NSS |
| 296 // exports functions that encode/decode these kinds of structures, while |
| 297 // it does not export the ones that deal directly with public keys. |
| 298 der = SECKEY_EncodeDERSubjectPublicKeyInfo(key); |
| 299 if (!der) { |
| 300 LOG(ERROR) << "Could not encode public key for export!"; |
| 301 return false; |
| 302 } |
| 303 |
| 304 out->assign(reinterpret_cast<char*>(der->data), der->len); |
| 305 |
| 306 SECITEM_FreeItem(der, PR_TRUE); |
| 307 return true; |
| 308 } |
| 309 |
| 310 SECKEYPrivateKey* OwnerKeyUtilsImpl::FindPrivateKey(SECKEYPublicKey* key) { |
| 311 DCHECK(key); |
| 312 |
| 313 PK11SlotInfo* slot = NULL; |
| 314 SECItem* ck_id = NULL; |
| 315 SECKEYPrivateKey* found = NULL; |
| 316 |
| 317 slot = base::GetDefaultNSSKeySlot(); |
| 318 if (!slot) |
| 319 goto cleanup; |
| 320 |
| 321 ck_id = PK11_MakeIDFromPubKey(&(key->u.rsa.modulus)); |
| 322 if (!ck_id) |
| 323 goto cleanup; |
| 324 |
| 325 found = PK11_FindKeyByKeyID(slot, ck_id, NULL); |
| 326 |
| 327 cleanup: |
| 328 if (slot) |
| 329 PK11_FreeSlot(slot); |
| 330 if (ck_id) |
| 331 SECITEM_FreeItem(ck_id, PR_TRUE); |
| 332 |
| 333 return found; |
| 334 } |
| 335 |
| 336 void OwnerKeyUtilsImpl::DestroyKeys(SECKEYPrivateKey* private_key, |
| 337 SECKEYPublicKey* public_key) { |
| 338 base::AutoNSSWriteLock lock; |
| 339 if (private_key) { |
| 340 PK11_DestroyTokenObject(private_key->pkcs11Slot, private_key->pkcs11ID); |
| 341 SECKEY_DestroyPrivateKey(private_key); |
| 342 } |
| 343 if (public_key) { |
| 344 PK11_DestroyTokenObject(public_key->pkcs11Slot, public_key->pkcs11ID); |
| 345 SECKEY_DestroyPublicKey(public_key); |
| 346 } |
| 347 } |
| 348 |
| 349 FilePath OwnerKeyUtilsImpl::GetOwnerKeyFilePath() { |
| 350 return FilePath(OwnerKeyUtilsImpl::kOwnerKeyFile); |
| 351 } |
| 352 |
| 353 } // namespace chromeos |
OLD | NEW |