| 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 |