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