// // Memory allocators for CssmHeap objects. // This implementation stores a pointer to the allocator used into memory // *after* the object's proper storage block. This allows the usual free() // functions to safely free our (hidden) pointer without knowing about it. // An allocator argument of NULL is interpreted as the standard allocator. // void *CssmHeap::operator new (size_t size, Allocator *alloc) throw(std::bad_alloc) { if (alloc == NULL) alloc = &Allocator::standard(); size = alignUp(size, alignof_template<Allocator *>()); size_t totalSize = size + sizeof(Allocator *); void *addr = alloc->malloc(totalSize); *(Allocator **)increment(addr, size) = alloc; return addr; }
// // Iterate through load commands // const load_command *MachOBase::nextCommand(const load_command *command) const { using LowLevelMemoryUtilities::increment; command = increment<const load_command>(command, flip(command->cmdsize)); if (command >= mEndCommands) // end of load commands return NULL; if (increment(command, sizeof(load_command)) > mEndCommands || increment(command, flip(command->cmdsize)) > mEndCommands) UnixError::throwMe(ENOEXEC); return command; }
void CSPFullPluginSession::Writer::use(size_t used) { assert(used <= currentSize); written += used; if (used < currentSize) { currentBuffer = increment(currentBuffer, used); currentSize -= used; } else { if (vec < lastVec) { useData(vec++); // use next vector buffer } else if (vec == lastVec && remData) { useData(remData); // use remainder buffer vec++; // mark used #if !defined(NDEBUG) && 0 } else if (vec == lastVec) { vec++; } else if (vec > lastVec) { assert(false); // 2nd try to overflow end #endif /* !NDEBUG */ } else { currentBuffer = NULL; // no more output buffer currentSize = 0; } } }
void *SensitiveAllocator::realloc(void *addr, size_t newSize) throw(std::bad_alloc) { size_t oldSize = malloc_size(addr); if (newSize < oldSize) memset(increment(addr, newSize), 0, oldSize - newSize); return DefaultAllocator::realloc(addr, newSize); }
void FileDesc::writeAll(const void *addr, size_t length) { while (length > 0) { size_t size = write(addr, length); addr = increment(addr, size); length -= size; } }
// // Encode a database blob from the core. // DbBlob *DatabaseCryptoCore::encodeCore(const DbBlob &blobTemplate, const CssmData &publicAcl, const CssmData &privateAcl) const { assert(isValid()); // must have secrets to work from // make a new IV uint8 iv[8]; Server::active().random(iv); // build the encrypted section blob CssmData &encryptionBits = *mEncryptionKey; CssmData &signingBits = *mSigningKey; CssmData incrypt[3]; incrypt[0] = encryptionBits; incrypt[1] = signingBits; incrypt[2] = privateAcl; CssmData cryptoBlob, remData; Encrypt cryptor(Server::csp(), CSSM_ALGID_3DES_3KEY_EDE); cryptor.mode(CSSM_ALGMODE_CBCPadIV8); cryptor.padding(CSSM_PADDING_PKCS1); cryptor.key(mMasterKey); CssmData ivd(iv, sizeof(iv)); cryptor.initVector(ivd); cryptor.encrypt(incrypt, 3, &cryptoBlob, 1, remData); // allocate the final DbBlob, uh, blob size_t length = sizeof(DbBlob) + publicAcl.length() + cryptoBlob.length(); DbBlob *blob = Allocator::standard().malloc<DbBlob>(length); // assemble the DbBlob memset(blob, 0x7d, sizeof(DbBlob)); // deterministically fill any alignment gaps blob->initialize(); blob->randomSignature = blobTemplate.randomSignature; blob->sequence = blobTemplate.sequence; blob->params = blobTemplate.params; memcpy(blob->salt, mSalt, sizeof(blob->salt)); memcpy(blob->iv, iv, sizeof(iv)); memcpy(blob->publicAclBlob(), publicAcl, publicAcl.length()); blob->startCryptoBlob = sizeof(DbBlob) + publicAcl.length(); memcpy(blob->cryptoBlob(), cryptoBlob, cryptoBlob.length()); blob->totalLength = blob->startCryptoBlob + cryptoBlob.length(); // sign the blob CssmData signChunk[] = { CssmData(blob->data(), fieldOffsetOf(&DbBlob::blobSignature)), CssmData(blob->publicAclBlob(), publicAcl.length() + cryptoBlob.length()) }; CssmData signature(blob->blobSignature, sizeof(blob->blobSignature)); GenerateMac signer(Server::csp(), CSSM_ALGID_SHA1HMAC_LEGACY); signer.key(mSigningKey); signer.sign(signChunk, 2, signature); assert(signature.length() == sizeof(blob->blobSignature)); // all done. Clean up Server::csp()->allocator().free(cryptoBlob); return blob; }
// // Waiting (repeating) I/O // size_t FileDesc::readAll(void *addr, size_t length) { size_t total = 0; while (length > 0 && !atEnd()) { size_t size = read(addr, length); addr = increment(addr, size); length -= size; total += size; } return total; }
void CSPFullPluginSession::Writer::put(void *addr, size_t size) { while (size > 0) { void *p; size_t sz; nextBlock(p, sz); if (size < sz) sz = size; // cap transfer memcpy(p, addr, sz); use(sz); addr = increment(addr, sz); size -= sz; } }
// // Decode a database blob into the core. // Throws exceptions if decoding fails. // Memory returned in privateAclBlob is allocated and becomes owned by caller. // void DatabaseCryptoCore::decodeCore(const DbBlob *blob, void **privateAclBlob) { assert(mHaveMaster); // must have master key installed // try to decrypt the cryptoblob section Decrypt decryptor(Server::csp(), CSSM_ALGID_3DES_3KEY_EDE); decryptor.mode(CSSM_ALGMODE_CBCPadIV8); decryptor.padding(CSSM_PADDING_PKCS1); decryptor.key(mMasterKey); CssmData ivd = CssmData::wrap(blob->iv); decryptor.initVector(ivd); CssmData cryptoBlob = CssmData::wrap(blob->cryptoBlob(), blob->cryptoBlobLength()); CssmData decryptedBlob, remData; decryptor.decrypt(cryptoBlob, decryptedBlob, remData); DbBlob::PrivateBlob *privateBlob = decryptedBlob.interpretedAs<DbBlob::PrivateBlob>(); // tentatively establish keys mEncryptionKey = makeRawKey(privateBlob->encryptionKey, sizeof(privateBlob->encryptionKey), CSSM_ALGID_3DES_3KEY_EDE, CSSM_KEYUSE_WRAP | CSSM_KEYUSE_UNWRAP); mSigningKey = makeRawKey(privateBlob->signingKey, sizeof(privateBlob->signingKey), CSSM_ALGID_SHA1HMAC, CSSM_KEYUSE_SIGN | CSSM_KEYUSE_VERIFY); // verify signature on the whole blob CssmData signChunk[] = { CssmData::wrap(blob->data(), fieldOffsetOf(&DbBlob::blobSignature)), CssmData::wrap(blob->publicAclBlob(), blob->publicAclBlobLength() + blob->cryptoBlobLength()) }; CSSM_ALGORITHMS verifyAlgorithm = CSSM_ALGID_SHA1HMAC; #if defined(COMPAT_OSX_10_0) if (blob->version() == blob->version_MacOS_10_0) verifyAlgorithm = CSSM_ALGID_SHA1HMAC_LEGACY; // BSafe bug compatibility #endif VerifyMac verifier(Server::csp(), verifyAlgorithm); verifier.key(mSigningKey); verifier.verify(signChunk, 2, CssmData::wrap(blob->blobSignature)); // all checks out; start extracting fields if (privateAclBlob) { // extract private ACL blob as a separately allocated area uint32 blobLength = (uint32) decryptedBlob.length() - sizeof(DbBlob::PrivateBlob); *privateAclBlob = Allocator::standard().malloc(blobLength); memcpy(*privateAclBlob, privateBlob->privateAclBlob(), blobLength); } // secrets have been established mBlobVersion = blob->version(); mIsValid = true; Allocator::standard().free(privateBlob); }
// // Decode a key blob // void DatabaseCryptoCore::decodeKeyCore(KeyBlob *blob, CssmKey &key, void * &pubAcl, void * &privAcl) const { // Assemble the encrypted blob as a CSSM "wrapped key" CssmKey wrappedKey; wrappedKey.KeyHeader = blob->header; h2ni(wrappedKey.KeyHeader); wrappedKey.blobType(blob->wrappedHeader.blobType); wrappedKey.blobFormat(blob->wrappedHeader.blobFormat); wrappedKey.wrapAlgorithm(blob->wrappedHeader.wrapAlgorithm); wrappedKey.wrapMode(blob->wrappedHeader.wrapMode); wrappedKey.KeyData = CssmData(blob->cryptoBlob(), blob->cryptoBlobLength()); bool inTheClear = blob->isClearText(); if(!inTheClear) { // verify signature (check against corruption) assert(isValid()); // need our database secrets CssmData signChunk[] = { CssmData::wrap(blob, fieldOffsetOf(&KeyBlob::blobSignature)), CssmData(blob->publicAclBlob(), blob->publicAclBlobLength() + blob->cryptoBlobLength()) }; CSSM_ALGORITHMS verifyAlgorithm = CSSM_ALGID_SHA1HMAC; #if defined(COMPAT_OSX_10_0) if (blob->version() == blob->version_MacOS_10_0) verifyAlgorithm = CSSM_ALGID_SHA1HMAC_LEGACY; // BSafe bug compatibility #endif VerifyMac verifier(Server::csp(), verifyAlgorithm); verifier.key(mSigningKey); CssmData signature(blob->blobSignature, sizeof(blob->blobSignature)); verifier.verify(signChunk, 2, signature); } /* else signature indicates cleartext */ // extract and hold some header bits the CSP does not want to see uint32 heldAttributes = n2h(blob->header.attributes()) & managedAttributes; CssmData privAclData; if(inTheClear) { /* NULL unwrap */ UnwrapKey unwrap(Server::csp(), CSSM_ALGID_NONE); wrappedKey.clearAttribute(managedAttributes); //@@@ shouldn't be needed(?) unwrap(wrappedKey, KeySpec(n2h(blob->header.usage()), (n2h(blob->header.attributes()) & ~managedAttributes) | forcedAttributes), key, &privAclData); } else { // decrypt the key using an unwrapping operation UnwrapKey unwrap(Server::csp(), CSSM_ALGID_3DES_3KEY_EDE); unwrap.key(mEncryptionKey); unwrap.mode(CSSM_ALGMODE_CBCPadIV8); unwrap.padding(CSSM_PADDING_PKCS1); CssmData ivd(blob->iv, sizeof(blob->iv)); unwrap.initVector(ivd); unwrap.add(CSSM_ATTRIBUTE_WRAPPED_KEY_FORMAT, uint32(CSSM_KEYBLOB_WRAPPED_FORMAT_APPLE_CUSTOM)); wrappedKey.clearAttribute(managedAttributes); //@@@ shouldn't be needed(?) unwrap(wrappedKey, KeySpec(n2h(blob->header.usage()), (n2h(blob->header.attributes()) & ~managedAttributes) | forcedAttributes), key, &privAclData); } // compare retrieved key headers with blob headers (sanity check) // @@@ this should probably be checked over carefully CssmKey::Header &real = key.header(); CssmKey::Header &incoming = blob->header; n2hi(incoming); if (real.HeaderVersion != incoming.HeaderVersion || real.cspGuid() != incoming.cspGuid()) CssmError::throwMe(CSSMERR_CSP_INVALID_KEY); if (real.algorithm() != incoming.algorithm()) CssmError::throwMe(CSSMERR_CSP_INVALID_ALGORITHM); // re-insert held bits key.header().KeyAttr |= heldAttributes; if(inTheClear && (real.keyClass() != CSSM_KEYCLASS_PUBLIC_KEY)) { /* Spoof - cleartext KeyBlob passed off as private key */ CssmError::throwMe(CSSMERR_CSP_INVALID_KEY); } // got a valid key: return the pieces pubAcl = blob->publicAclBlob(); // points into blob (shared) privAcl = privAclData; // was allocated by CSP decrypt, else NULL for // cleatext keys // key was set by unwrap operation }
// // Encode a key blob // KeyBlob *DatabaseCryptoCore::encodeKeyCore(const CssmKey &inKey, const CssmData &publicAcl, const CssmData &privateAcl, bool inTheClear) const { CssmKey key = inKey; uint8 iv[8]; CssmKey wrappedKey; if(inTheClear && (privateAcl.Length != 0)) { /* can't store private ACL component in the clear */ CssmError::throwMe(CSSMERR_DL_INVALID_ACCESS_CREDENTIALS); } // extract and hold some header bits the CSP does not want to see uint32 heldAttributes = key.attributes() & managedAttributes; key.clearAttribute(managedAttributes); key.setAttribute(forcedAttributes); if(inTheClear) { /* NULL wrap of public key */ WrapKey wrap(Server::csp(), CSSM_ALGID_NONE); wrap(key, wrappedKey, NULL); } else { assert(isValid()); // need our database secrets // create new IV Server::active().random(iv); // use a CMS wrap to encrypt the key WrapKey wrap(Server::csp(), CSSM_ALGID_3DES_3KEY_EDE); wrap.key(mEncryptionKey); wrap.mode(CSSM_ALGMODE_CBCPadIV8); wrap.padding(CSSM_PADDING_PKCS1); CssmData ivd(iv, sizeof(iv)); wrap.initVector(ivd); wrap.add(CSSM_ATTRIBUTE_WRAPPED_KEY_FORMAT, uint32(CSSM_KEYBLOB_WRAPPED_FORMAT_APPLE_CUSTOM)); wrap(key, wrappedKey, &privateAcl); } // stick the held attribute bits back in key.clearAttribute(forcedAttributes); key.setAttribute(heldAttributes); // allocate the final KeyBlob, uh, blob size_t length = sizeof(KeyBlob) + publicAcl.length() + wrappedKey.length(); KeyBlob *blob = Allocator::standard().malloc<KeyBlob>(length); // assemble the KeyBlob memset(blob, 0, sizeof(KeyBlob)); // fill alignment gaps blob->initialize(); if(!inTheClear) { memcpy(blob->iv, iv, sizeof(iv)); } blob->header = key.header(); h2ni(blob->header); // endian-correct the header blob->wrappedHeader.blobType = wrappedKey.blobType(); blob->wrappedHeader.blobFormat = wrappedKey.blobFormat(); blob->wrappedHeader.wrapAlgorithm = wrappedKey.wrapAlgorithm(); blob->wrappedHeader.wrapMode = wrappedKey.wrapMode(); memcpy(blob->publicAclBlob(), publicAcl, publicAcl.length()); blob->startCryptoBlob = sizeof(KeyBlob) + publicAcl.length(); memcpy(blob->cryptoBlob(), wrappedKey.data(), wrappedKey.length()); blob->totalLength = blob->startCryptoBlob + wrappedKey.length(); if(inTheClear) { /* indicate that this is cleartext for decoding */ blob->setClearTextSignature(); } else { // sign the blob CssmData signChunk[] = { CssmData(blob->data(), fieldOffsetOf(&KeyBlob::blobSignature)), CssmData(blob->publicAclBlob(), blob->publicAclBlobLength() + blob->cryptoBlobLength()) }; CssmData signature(blob->blobSignature, sizeof(blob->blobSignature)); GenerateMac signer(Server::csp(), CSSM_ALGID_SHA1HMAC_LEGACY); //@@@!!! CRUD signer.key(mSigningKey); signer.sign(signChunk, 2, signature); assert(signature.length() == sizeof(blob->blobSignature)); } // all done. Clean up Server::csp()->allocator().free(wrappedKey); return blob; }
void CssmHeap::operator delete (void *addr, size_t size) throw() { void *end = increment(addr, alignUp(size, alignof_template<Allocator *>())); (*(Allocator **)end)->free(addr); }