]> git.saurik.com Git - apple/security.git/blame - securityd/src/dbcrypto.cpp
Security-59754.80.3.tar.gz
[apple/security.git] / securityd / src / dbcrypto.cpp
CommitLineData
d8f41ccd
A
1/*
2 * Copyright (c) 2000-2006,2013 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24
25//
26// dbcrypto - cryptographic core for database and key blob cryptography
27//
28#include "dbcrypto.h"
b54c578e 29#include "SecRandom.h"
fa7225c8 30#include <security_utilities/casts.h>
d8f41ccd
A
31#include <securityd_client/ssblob.h>
32#include "server.h" // just for Server::csp()
33#include <security_cdsa_client/genkey.h>
34#include <security_cdsa_client/cryptoclient.h>
35#include <security_cdsa_client/keyclient.h>
36#include <security_cdsa_client/macclient.h>
37#include <security_cdsa_client/wrapkey.h>
38#include <security_cdsa_utilities/cssmendian.h>
39
40using namespace CssmClient;
41using LowLevelMemoryUtilities::fieldOffsetOf;
42
43
44//
45// The CryptoCore constructor doesn't do anything interesting.
46// It just initializes us to "empty".
47//
fa7225c8 48DatabaseCryptoCore::DatabaseCryptoCore(uint32 requestedVersion) : mBlobVersion(CommonBlob::version_MacOS_10_0), mHaveMaster(false), mIsValid(false)
d8f41ccd 49{
fa7225c8
A
50 // If there's a specific version our callers want, give them that. Otherwise, ask CommonBlob what to do.
51 if(requestedVersion == CommonBlob::version_none) {
52 mBlobVersion = CommonBlob::getCurrentVersion();
53 } else {
54 mBlobVersion = requestedVersion;
55 }
d8f41ccd
A
56}
57
58DatabaseCryptoCore::~DatabaseCryptoCore()
59{
60 // key objects take care of themselves
61}
62
63
64//
65// Forget the secrets
66//
67void DatabaseCryptoCore::invalidate()
68{
69 mMasterKey.release();
70 mHaveMaster = false;
71
72 mEncryptionKey.release();
73 mSigningKey.release();
74 mIsValid = false;
75}
76
fa7225c8
A
77//
78// Copy everything from another databasecryptocore
79//
80void DatabaseCryptoCore::initializeFrom(DatabaseCryptoCore& core, uint32 requestedVersion) {
81 if(core.hasMaster()) {
82 mMasterKey = core.mMasterKey;
83 memcpy(mSalt, core.mSalt, sizeof(mSalt));
84 mHaveMaster = core.mHaveMaster;
85 } else {
86 mHaveMaster = false;
87 }
88
89 if(core.isValid()) {
90 importSecrets(core);
91 } else {
92 mIsValid = false;
93 }
94
95 // As the last thing we do, check if we should be changing the version of this blob.
96 if(requestedVersion == CommonBlob::version_none) {
97 mBlobVersion = core.mBlobVersion;
98 } else {
99 mBlobVersion = requestedVersion;
100 }
101}
d8f41ccd
A
102
103//
104// Generate new secrets for this crypto core.
105//
106void DatabaseCryptoCore::generateNewSecrets()
107{
108 // create a random DES3 key
109 GenerateKey desGenerator(Server::csp(), CSSM_ALGID_3DES_3KEY_EDE, 24 * 8);
110 mEncryptionKey = desGenerator(KeySpec(CSSM_KEYUSE_WRAP | CSSM_KEYUSE_UNWRAP,
111 CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_EXTRACTABLE));
112
113 // create a random 20 byte HMAC/SHA1 signing "key"
114 GenerateKey signGenerator(Server::csp(), CSSM_ALGID_SHA1HMAC,
115 sizeof(DbBlob::PrivateBlob::SigningKey) * 8);
116 mSigningKey = signGenerator(KeySpec(CSSM_KEYUSE_SIGN | CSSM_KEYUSE_VERIFY,
117 CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_EXTRACTABLE));
118
119 // secrets established
120 mIsValid = true;
121}
122
123
124CssmClient::Key DatabaseCryptoCore::masterKey()
125{
126 assert(mHaveMaster);
127 return mMasterKey;
128}
129
130
131//
132// Establish the master secret as derived from a passphrase passed in.
133// If a DbBlob is passed, take the salt from it and remember it.
134// If a NULL DbBlob is passed, generate a new (random) salt.
135// Note that the passphrase is NOT remembered; only the master key.
136//
e3d460c9 137void DatabaseCryptoCore::setup(const DbBlob *blob, const CssmData &passphrase, bool copyVersion /* = true */)
d8f41ccd 138{
e3d460c9
A
139 if (blob) {
140 if(copyVersion) {
141 mBlobVersion = blob->version();
142 }
143 memcpy(mSalt, blob->salt, sizeof(mSalt));
79b9da22 144 } else {
b54c578e 145 MacOSError::check(SecRandomCopyBytes(kSecRandomDefault, sizeof(mSalt), mSalt));
79b9da22 146 }
b54c578e 147
d8f41ccd
A
148 mMasterKey = deriveDbMasterKey(passphrase);
149 mHaveMaster = true;
150}
151
152
153//
154// Establish the master secret directly from a master key passed in.
155// We will copy the KeyData (caller still owns its copy).
156// Blob/salt handling as above.
157//
e3d460c9 158void DatabaseCryptoCore::setup(const DbBlob *blob, CssmClient::Key master, bool copyVersion /* = true */)
d8f41ccd
A
159{
160 // pre-screen the key
161 CssmKey::Header header = master.header();
162 if (header.keyClass() != CSSM_KEYCLASS_SESSION_KEY)
163 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS);
164 if (header.algorithm() != CSSM_ALGID_3DES_3KEY_EDE)
165 CssmError::throwMe(CSSMERR_CSP_INVALID_ALGORITHM);
166
167 // accept it
e3d460c9
A
168 if (blob) {
169 if(copyVersion) {
170 mBlobVersion = blob->version();
171 }
172 memcpy(mSalt, blob->salt, sizeof(mSalt));
79b9da22 173 } else {
b54c578e 174 MacOSError::check(SecRandomCopyBytes(kSecRandomDefault, sizeof(mSalt), mSalt));
79b9da22 175 }
d8f41ccd
A
176 mMasterKey = master;
177 mHaveMaster = true;
178}
179
180bool DatabaseCryptoCore::get_encryption_key(CssmOwnedData &data)
181{
182 bool result = false;
183 if (isValid()) {
184 data = mEncryptionKey->keyData();
185 result = true;
186 }
187 return result;
188}
189
190//
191// Given a putative passphrase, determine whether that passphrase
192// properly generates the database's master secret.
193// Return a boolean accordingly. Do not change our state.
194// The database must have a master secret (to compare with).
195// Note that any errors thrown by the cryptography here will actually
196// throw out of validatePassphrase, since they "should not happen" and
197// thus indicate a problem *beyond* (just) a bad passphrase.
198//
199bool DatabaseCryptoCore::validatePassphrase(const CssmData &passphrase)
200{
d8f41ccd 201 CssmClient::Key master = deriveDbMasterKey(passphrase);
fa7225c8
A
202 return validateKey(master);
203}
204
205bool DatabaseCryptoCore::validateKey(const CssmClient::Key& master) {
206 assert(hasMaster());
d8f41ccd
A
207 // to compare master with mMaster, see if they encrypt alike
208 StringData probe
209 ("Now is the time for all good processes to come to the aid of their kernel.");
210 CssmData noRemainder((void *)1, 0); // no cipher overflow
211 Encrypt cryptor(Server::csp(), CSSM_ALGID_3DES_3KEY_EDE);
212 cryptor.mode(CSSM_ALGMODE_CBCPadIV8);
213 cryptor.padding(CSSM_PADDING_PKCS1);
214 uint8 iv[8]; // leave uninitialized; pseudo-random is cool
866f8763
A
215 CssmData ivData = CssmData::wrap(iv);
216 cryptor.initVector(ivData);
d8f41ccd
A
217
218 cryptor.key(master);
219 CssmAutoData cipher1(Server::csp().allocator());
220 cryptor.encrypt(probe, cipher1.get(), noRemainder);
221
222 cryptor.key(mMasterKey);
223 CssmAutoData cipher2(Server::csp().allocator());
224 cryptor.encrypt(probe, cipher2.get(), noRemainder);
225
226 return cipher1 == cipher2;
227}
228
229
230//
231// Encode a database blob from the core.
232//
233DbBlob *DatabaseCryptoCore::encodeCore(const DbBlob &blobTemplate,
234 const CssmData &publicAcl, const CssmData &privateAcl) const
235{
236 assert(isValid()); // must have secrets to work from
237
238 // make a new IV
239 uint8 iv[8];
b54c578e 240 MacOSError::check(SecRandomCopyBytes(kSecRandomDefault, sizeof(iv), iv));
d8f41ccd
A
241
242 // build the encrypted section blob
243 CssmData &encryptionBits = *mEncryptionKey;
244 CssmData &signingBits = *mSigningKey;
245 CssmData incrypt[3];
246 incrypt[0] = encryptionBits;
247 incrypt[1] = signingBits;
248 incrypt[2] = privateAcl;
249 CssmData cryptoBlob, remData;
250 Encrypt cryptor(Server::csp(), CSSM_ALGID_3DES_3KEY_EDE);
251 cryptor.mode(CSSM_ALGMODE_CBCPadIV8);
252 cryptor.padding(CSSM_PADDING_PKCS1);
253 cryptor.key(mMasterKey);
254 CssmData ivd(iv, sizeof(iv)); cryptor.initVector(ivd);
255 cryptor.encrypt(incrypt, 3, &cryptoBlob, 1, remData);
256
257 // allocate the final DbBlob, uh, blob
258 size_t length = sizeof(DbBlob) + publicAcl.length() + cryptoBlob.length();
259 DbBlob *blob = Allocator::standard().malloc<DbBlob>(length);
260
261 // assemble the DbBlob
262 memset(blob, 0x7d, sizeof(DbBlob)); // deterministically fill any alignment gaps
e3d460c9 263 blob->initialize(mBlobVersion);
d8f41ccd
A
264 blob->randomSignature = blobTemplate.randomSignature;
265 blob->sequence = blobTemplate.sequence;
266 blob->params = blobTemplate.params;
267 memcpy(blob->salt, mSalt, sizeof(blob->salt));
268 memcpy(blob->iv, iv, sizeof(iv));
269 memcpy(blob->publicAclBlob(), publicAcl, publicAcl.length());
fa7225c8 270 blob->startCryptoBlob = sizeof(DbBlob) + int_cast<size_t, uint32_t>(publicAcl.length());
d8f41ccd 271 memcpy(blob->cryptoBlob(), cryptoBlob, cryptoBlob.length());
fa7225c8 272 blob->totalLength = blob->startCryptoBlob + int_cast<size_t, uint32_t>(cryptoBlob.length());
d8f41ccd
A
273
274 // sign the blob
275 CssmData signChunk[] = {
276 CssmData(blob->data(), fieldOffsetOf(&DbBlob::blobSignature)),
277 CssmData(blob->publicAclBlob(), publicAcl.length() + cryptoBlob.length())
278 };
279 CssmData signature(blob->blobSignature, sizeof(blob->blobSignature));
e3d460c9
A
280
281 CSSM_ALGORITHMS signingAlgorithm = CSSM_ALGID_SHA1HMAC;
282#if defined(COMPAT_OSX_10_0)
283 if (blob->version() == blob->version_MacOS_10_0)
284 signingAlgorithm = CSSM_ALGID_SHA1HMAC_LEGACY; // BSafe bug compatibility
285#endif
286 GenerateMac signer(Server::csp(), signingAlgorithm);
d8f41ccd
A
287 signer.key(mSigningKey);
288 signer.sign(signChunk, 2, signature);
289 assert(signature.length() == sizeof(blob->blobSignature));
290
291 // all done. Clean up
292 Server::csp()->allocator().free(cryptoBlob);
293 return blob;
294}
295
296
297//
298// Decode a database blob into the core.
299// Throws exceptions if decoding fails.
300// Memory returned in privateAclBlob is allocated and becomes owned by caller.
301//
302void DatabaseCryptoCore::decodeCore(const DbBlob *blob, void **privateAclBlob)
303{
304 assert(mHaveMaster); // must have master key installed
305
306 // try to decrypt the cryptoblob section
307 Decrypt decryptor(Server::csp(), CSSM_ALGID_3DES_3KEY_EDE);
308 decryptor.mode(CSSM_ALGMODE_CBCPadIV8);
309 decryptor.padding(CSSM_PADDING_PKCS1);
310 decryptor.key(mMasterKey);
311 CssmData ivd = CssmData::wrap(blob->iv); decryptor.initVector(ivd);
312 CssmData cryptoBlob = CssmData::wrap(blob->cryptoBlob(), blob->cryptoBlobLength());
313 CssmData decryptedBlob, remData;
314 decryptor.decrypt(cryptoBlob, decryptedBlob, remData);
315 DbBlob::PrivateBlob *privateBlob = decryptedBlob.interpretedAs<DbBlob::PrivateBlob>();
316
317 // tentatively establish keys
318 mEncryptionKey = makeRawKey(privateBlob->encryptionKey,
319 sizeof(privateBlob->encryptionKey), CSSM_ALGID_3DES_3KEY_EDE,
320 CSSM_KEYUSE_WRAP | CSSM_KEYUSE_UNWRAP);
321 mSigningKey = makeRawKey(privateBlob->signingKey,
322 sizeof(privateBlob->signingKey), CSSM_ALGID_SHA1HMAC,
323 CSSM_KEYUSE_SIGN | CSSM_KEYUSE_VERIFY);
324
325 // verify signature on the whole blob
326 CssmData signChunk[] = {
327 CssmData::wrap(blob->data(), fieldOffsetOf(&DbBlob::blobSignature)),
328 CssmData::wrap(blob->publicAclBlob(), blob->publicAclBlobLength() + blob->cryptoBlobLength())
329 };
330 CSSM_ALGORITHMS verifyAlgorithm = CSSM_ALGID_SHA1HMAC;
331#if defined(COMPAT_OSX_10_0)
332 if (blob->version() == blob->version_MacOS_10_0)
333 verifyAlgorithm = CSSM_ALGID_SHA1HMAC_LEGACY; // BSafe bug compatibility
334#endif
335 VerifyMac verifier(Server::csp(), verifyAlgorithm);
336 verifier.key(mSigningKey);
337 verifier.verify(signChunk, 2, CssmData::wrap(blob->blobSignature));
338
339 // all checks out; start extracting fields
340 if (privateAclBlob) {
341 // extract private ACL blob as a separately allocated area
fa7225c8 342 uint32 blobLength = (uint32) decryptedBlob.length() - sizeof(DbBlob::PrivateBlob);
d8f41ccd
A
343 *privateAclBlob = Allocator::standard().malloc(blobLength);
344 memcpy(*privateAclBlob, privateBlob->privateAclBlob(), blobLength);
345 }
346
347 // secrets have been established
e3d460c9 348 mBlobVersion = blob->version();
d8f41ccd
A
349 mIsValid = true;
350 Allocator::standard().free(privateBlob);
351}
352
353
354//
355// Make another DatabaseCryptoCore's operational secrets our own.
356// Intended for keychain synchronization.
357//
358void DatabaseCryptoCore::importSecrets(const DatabaseCryptoCore &src)
359{
360 assert(src.isValid()); // must have called src.decodeCore() first
361 assert(hasMaster());
362 mEncryptionKey = src.mEncryptionKey;
363 mSigningKey = src.mSigningKey;
e3d460c9 364 mBlobVersion = src.mBlobVersion; // make sure we copy over all state
d8f41ccd
A
365 mIsValid = true;
366}
367
368//
369// Encode a key blob
370//
371KeyBlob *DatabaseCryptoCore::encodeKeyCore(const CssmKey &inKey,
372 const CssmData &publicAcl, const CssmData &privateAcl,
373 bool inTheClear) const
374{
375 CssmKey key = inKey;
376 uint8 iv[8];
377 CssmKey wrappedKey;
378
379 if(inTheClear && (privateAcl.Length != 0)) {
380 /* can't store private ACL component in the clear */
381 CssmError::throwMe(CSSMERR_DL_INVALID_ACCESS_CREDENTIALS);
382 }
383
384 // extract and hold some header bits the CSP does not want to see
385 uint32 heldAttributes = key.attributes() & managedAttributes;
386 key.clearAttribute(managedAttributes);
387 key.setAttribute(forcedAttributes);
388
389 if(inTheClear) {
390 /* NULL wrap of public key */
391 WrapKey wrap(Server::csp(), CSSM_ALGID_NONE);
392 wrap(key, wrappedKey, NULL);
393 }
394 else {
395 assert(isValid()); // need our database secrets
396
397 // create new IV
b54c578e 398 MacOSError::check(SecRandomCopyBytes(kSecRandomDefault, sizeof(iv), iv));
d8f41ccd
A
399
400 // use a CMS wrap to encrypt the key
401 WrapKey wrap(Server::csp(), CSSM_ALGID_3DES_3KEY_EDE);
402 wrap.key(mEncryptionKey);
403 wrap.mode(CSSM_ALGMODE_CBCPadIV8);
404 wrap.padding(CSSM_PADDING_PKCS1);
405 CssmData ivd(iv, sizeof(iv)); wrap.initVector(ivd);
406 wrap.add(CSSM_ATTRIBUTE_WRAPPED_KEY_FORMAT,
407 uint32(CSSM_KEYBLOB_WRAPPED_FORMAT_APPLE_CUSTOM));
408 wrap(key, wrappedKey, &privateAcl);
409 }
410
411 // stick the held attribute bits back in
412 key.clearAttribute(forcedAttributes);
413 key.setAttribute(heldAttributes);
414
415 // allocate the final KeyBlob, uh, blob
416 size_t length = sizeof(KeyBlob) + publicAcl.length() + wrappedKey.length();
417 KeyBlob *blob = Allocator::standard().malloc<KeyBlob>(length);
418
419 // assemble the KeyBlob
420 memset(blob, 0, sizeof(KeyBlob)); // fill alignment gaps
e3d460c9 421 blob->initialize(mBlobVersion);
d8f41ccd
A
422 if(!inTheClear) {
423 memcpy(blob->iv, iv, sizeof(iv));
424 }
425 blob->header = key.header();
426 h2ni(blob->header); // endian-correct the header
427 blob->wrappedHeader.blobType = wrappedKey.blobType();
428 blob->wrappedHeader.blobFormat = wrappedKey.blobFormat();
429 blob->wrappedHeader.wrapAlgorithm = wrappedKey.wrapAlgorithm();
430 blob->wrappedHeader.wrapMode = wrappedKey.wrapMode();
431 memcpy(blob->publicAclBlob(), publicAcl, publicAcl.length());
fa7225c8 432 blob->startCryptoBlob = sizeof(KeyBlob) + int_cast<size_t, uint32_t>(publicAcl.length());
d8f41ccd 433 memcpy(blob->cryptoBlob(), wrappedKey.data(), wrappedKey.length());
fa7225c8 434 blob->totalLength = blob->startCryptoBlob + int_cast<size_t, uint32_t>(wrappedKey.length());
d8f41ccd
A
435
436 if(inTheClear) {
437 /* indicate that this is cleartext for decoding */
438 blob->setClearTextSignature();
439 }
440 else {
441 // sign the blob
442 CssmData signChunk[] = {
443 CssmData(blob->data(), fieldOffsetOf(&KeyBlob::blobSignature)),
444 CssmData(blob->publicAclBlob(), blob->publicAclBlobLength() + blob->cryptoBlobLength())
445 };
446 CssmData signature(blob->blobSignature, sizeof(blob->blobSignature));
e3d460c9
A
447
448 CSSM_ALGORITHMS signingAlgorithm = CSSM_ALGID_SHA1HMAC;
449#if defined(COMPAT_OSX_10_0)
450 if (blob->version() == blob->version_MacOS_10_0)
451 signingAlgorithm = CSSM_ALGID_SHA1HMAC_LEGACY; // BSafe bug compatibility
452#endif
453 GenerateMac signer(Server::csp(), signingAlgorithm);
d8f41ccd
A
454 signer.key(mSigningKey);
455 signer.sign(signChunk, 2, signature);
456 assert(signature.length() == sizeof(blob->blobSignature));
457 }
458
459 // all done. Clean up
460 Server::csp()->allocator().free(wrappedKey);
461 return blob;
462}
463
464
465//
466// Decode a key blob
467//
468void DatabaseCryptoCore::decodeKeyCore(KeyBlob *blob,
469 CssmKey &key, void * &pubAcl, void * &privAcl) const
470{
e3d460c9
A
471 // Note that we can't do anything with this key's version().
472
d8f41ccd
A
473 // Assemble the encrypted blob as a CSSM "wrapped key"
474 CssmKey wrappedKey;
475 wrappedKey.KeyHeader = blob->header;
476 h2ni(wrappedKey.KeyHeader);
477 wrappedKey.blobType(blob->wrappedHeader.blobType);
478 wrappedKey.blobFormat(blob->wrappedHeader.blobFormat);
479 wrappedKey.wrapAlgorithm(blob->wrappedHeader.wrapAlgorithm);
480 wrappedKey.wrapMode(blob->wrappedHeader.wrapMode);
481 wrappedKey.KeyData = CssmData(blob->cryptoBlob(), blob->cryptoBlobLength());
482
483 bool inTheClear = blob->isClearText();
484 if(!inTheClear) {
485 // verify signature (check against corruption)
486 assert(isValid()); // need our database secrets
487 CssmData signChunk[] = {
488 CssmData::wrap(blob, fieldOffsetOf(&KeyBlob::blobSignature)),
489 CssmData(blob->publicAclBlob(), blob->publicAclBlobLength() + blob->cryptoBlobLength())
490 };
491 CSSM_ALGORITHMS verifyAlgorithm = CSSM_ALGID_SHA1HMAC;
492 #if defined(COMPAT_OSX_10_0)
493 if (blob->version() == blob->version_MacOS_10_0)
494 verifyAlgorithm = CSSM_ALGID_SHA1HMAC_LEGACY; // BSafe bug compatibility
495 #endif
496 VerifyMac verifier(Server::csp(), verifyAlgorithm);
497 verifier.key(mSigningKey);
498 CssmData signature(blob->blobSignature, sizeof(blob->blobSignature));
499 verifier.verify(signChunk, 2, signature);
500 }
501 /* else signature indicates cleartext */
502
503 // extract and hold some header bits the CSP does not want to see
504 uint32 heldAttributes = n2h(blob->header.attributes()) & managedAttributes;
505
506 CssmData privAclData;
507 if(inTheClear) {
508 /* NULL unwrap */
509 UnwrapKey unwrap(Server::csp(), CSSM_ALGID_NONE);
510 wrappedKey.clearAttribute(managedAttributes); //@@@ shouldn't be needed(?)
511 unwrap(wrappedKey,
512 KeySpec(n2h(blob->header.usage()),
513 (n2h(blob->header.attributes()) & ~managedAttributes) | forcedAttributes),
514 key, &privAclData);
515 }
516 else {
517 // decrypt the key using an unwrapping operation
518 UnwrapKey unwrap(Server::csp(), CSSM_ALGID_3DES_3KEY_EDE);
519 unwrap.key(mEncryptionKey);
520 unwrap.mode(CSSM_ALGMODE_CBCPadIV8);
521 unwrap.padding(CSSM_PADDING_PKCS1);
522 CssmData ivd(blob->iv, sizeof(blob->iv)); unwrap.initVector(ivd);
523 unwrap.add(CSSM_ATTRIBUTE_WRAPPED_KEY_FORMAT,
524 uint32(CSSM_KEYBLOB_WRAPPED_FORMAT_APPLE_CUSTOM));
525 wrappedKey.clearAttribute(managedAttributes); //@@@ shouldn't be needed(?)
526 unwrap(wrappedKey,
527 KeySpec(n2h(blob->header.usage()),
528 (n2h(blob->header.attributes()) & ~managedAttributes) | forcedAttributes),
529 key, &privAclData);
530 }
531
532 // compare retrieved key headers with blob headers (sanity check)
533 // @@@ this should probably be checked over carefully
534 CssmKey::Header &real = key.header();
535 CssmKey::Header &incoming = blob->header;
536 n2hi(incoming);
537
538 if (real.HeaderVersion != incoming.HeaderVersion ||
539 real.cspGuid() != incoming.cspGuid())
540 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY);
541 if (real.algorithm() != incoming.algorithm())
542 CssmError::throwMe(CSSMERR_CSP_INVALID_ALGORITHM);
543
544 // re-insert held bits
545 key.header().KeyAttr |= heldAttributes;
546
547 if(inTheClear && (real.keyClass() != CSSM_KEYCLASS_PUBLIC_KEY)) {
548 /* Spoof - cleartext KeyBlob passed off as private key */
549 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY);
550 }
551
552 // got a valid key: return the pieces
553 pubAcl = blob->publicAclBlob(); // points into blob (shared)
554 privAcl = privAclData; // was allocated by CSP decrypt, else NULL for
555 // cleatext keys
556 // key was set by unwrap operation
557}
558
559
560//
561// Derive the blob-specific database blob encryption key from the passphrase and the salt.
562//
563CssmClient::Key DatabaseCryptoCore::deriveDbMasterKey(const CssmData &passphrase) const
564{
565 // derive an encryption key and IV from passphrase and salt
566 CssmClient::DeriveKey makeKey(Server::csp(),
567 CSSM_ALGID_PKCS5_PBKDF2, CSSM_ALGID_3DES_3KEY_EDE, 24 * 8);
568 makeKey.iterationCount(1000);
569 CssmData salt = CssmData::wrap(mSalt);
570 makeKey.salt(salt);
571 CSSM_PKCS5_PBKDF2_PARAMS params;
572 params.Passphrase = passphrase;
573 params.PseudoRandomFunction = CSSM_PKCS5_PBKDF2_PRF_HMAC_SHA1;
574 CssmData paramData = CssmData::wrap(params);
575 return makeKey(&paramData, KeySpec(CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_DECRYPT,
576 CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_EXTRACTABLE));
577}
578
579
580//
581// Turn raw keybits into a symmetric key in the CSP
582//
583CssmClient::Key DatabaseCryptoCore::makeRawKey(void *data, size_t length,
584 CSSM_ALGORITHMS algid, CSSM_KEYUSE usage)
585{
586 // build a fake key
587 CssmKey key;
588 key.header().BlobType = CSSM_KEYBLOB_RAW;
589 key.header().Format = CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING;
590 key.header().AlgorithmId = algid;
591 key.header().KeyClass = CSSM_KEYCLASS_SESSION_KEY;
592 key.header().KeyUsage = usage;
593 key.header().KeyAttr = 0;
594 key.KeyData = CssmData(data, length);
595
596 // unwrap it into the CSP (but keep it raw)
597 UnwrapKey unwrap(Server::csp(), CSSM_ALGID_NONE);
598 CssmKey unwrappedKey;
599 CssmData descriptiveData;
600 unwrap(key,
601 KeySpec(CSSM_KEYUSE_ANY, CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_EXTRACTABLE),
602 unwrappedKey, &descriptiveData, NULL);
603 return CssmClient::Key(Server::csp(), unwrappedKey);
604}