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