//
// 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;
}
Exemplo n.º 2
0
//
// 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;
}