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