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(¶mData, 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