/*
 * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
 * 
 * @APPLE_LICENSE_HEADER_START@
 * 
 * This file contains Original Code and/or Modifications of Original Code
 * as defined in and that are subject to the Apple Public Source License
 * Version 2.0 (the 'License'). You may not use this file except in
 * compliance with the License. Please obtain a copy of the License at
 * http://www.opensource.apple.com/apsl/ and read it before using this
 * file.
 * 
 * The Original Code and all software distributed under the License are
 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
 * Please see the License for the specific language governing rights and
 * limitations under the License.
 * 
 * @APPLE_LICENSE_HEADER_END@
 */


//
// localkey - Key objects that store a local CSSM key object
//
#include "localkey.h"
#include "server.h"
#include "database.h"
#include <security_cdsa_utilities/acl_any.h>


//
// Create a Key from an explicit CssmKey.
//
LocalKey::LocalKey(Database &db, const CssmKey &newKey, CSSM_KEYATTR_FLAGS moreAttributes)
	: Key(db), mDigest(Server::csp().allocator())
{
	mValidKey = true;
	setup(newKey, moreAttributes);
    secdebug("SSkey", "%p (handle 0x%lx) created from key alg=%ld use=0x%lx attr=0x%lx db=%p",
        this, handle(), mKey.header().algorithm(), mKey.header().usage(), mAttributes, &db);
}


LocalKey::LocalKey(Database &db, CSSM_KEYATTR_FLAGS attributes)
	: Key(db), mValidKey(false), mAttributes(attributes), mDigest(Server::csp().allocator())
{
}


//
// Set up the CssmKey part of this Key according to instructions.
//
void LocalKey::setup(const CssmKey &newKey, CSSM_KEYATTR_FLAGS moreAttributes)
{
	mKey = CssmClient::Key(Server::csp(), newKey, false);
    CssmKey::Header &header = mKey->header();
    
	// copy key header
	header = newKey.header();
    mAttributes = (header.attributes() & ~forcedAttributes) | moreAttributes;
	
	// apply initial values of derived attributes (these are all in managedAttributes)
    if (!(mAttributes & CSSM_KEYATTR_EXTRACTABLE))
        mAttributes |= CSSM_KEYATTR_NEVER_EXTRACTABLE;
    if (mAttributes & CSSM_KEYATTR_SENSITIVE)
        mAttributes |= CSSM_KEYATTR_ALWAYS_SENSITIVE;

    // verify internal/external attribute separation
    assert((header.attributes() & managedAttributes) == forcedAttributes);
}


LocalKey::~LocalKey()
{
    secdebug("SSkey", "%p destroyed", this);
}


void LocalKey::setOwner(const AclEntryPrototype *owner)
{
	// establish initial ACL; reinterpret empty (null-list) owner as NULL for resilence's sake
	if (owner && !owner->subject().empty())
		acl().cssmSetInitial(*owner);					// specified
	else
		acl().cssmSetInitial(new AnyAclSubject());		// defaulted
}


LocalDatabase &LocalKey::database() const
{
	return referent<LocalDatabase>();
}


//
// Retrieve the actual CssmKey value for the key object.
// This will decode its blob if needed (and appropriate).
//
CssmClient::Key LocalKey::keyValue()
{
    if (!mValidKey) {
		getKey();
		mValidKey = true;
	}
    return mKey;
}


//
// Return external key attributees
//
CSSM_KEYATTR_FLAGS LocalKey::attributes()
{
	return mAttributes;
}


//
// Return a key's handle and header in external form
//
void LocalKey::returnKey(Handle &h, CssmKey::Header &hdr)
{
    // return handle
    h = this->handle();
	
	// obtain the key header, from the valid key or the blob if no valid key
	if (mValidKey) {
		hdr = mKey.header();
	} else {
		getHeader(hdr);
	}
    
    // adjust for external attributes
	hdr.clearAttribute(forcedAttributes);
    hdr.setAttribute(mAttributes);
}


//
// Generate the canonical key digest.
// This is defined by a CSP feature that we invoke here.
//
const CssmData &LocalKey::canonicalDigest()
{
	if (!mDigest) {
		CssmClient::PassThrough ctx(Server::csp());
		ctx.key(keyValue());
		CssmData *digest = NULL;
		ctx(CSSM_APPLECSP_KEYDIGEST, (const void *)NULL, &digest);
		assert(digest);
		mDigest.set(*digest);	// takes ownership of digest data
		Server::csp().allocator().free(digest);	// the CssmData itself
	}
	return mDigest.get();
}


//
// Default getKey/getHeader calls - should never be called
//
void LocalKey::getKey()
{
	assert(false);
}

void LocalKey::getHeader(CssmKey::Header &)
{
	assert(false);
}


//
// Form a KeySpec with checking and masking
//
LocalKey::KeySpec::KeySpec(CSSM_KEYUSE usage, CSSM_KEYATTR_FLAGS attrs)
	: CssmClient::KeySpec(usage, (attrs & ~managedAttributes) | forcedAttributes)
{
	if (attrs & generatedAttributes)
		CssmError::throwMe(CSSMERR_CSP_INVALID_KEYATTR_MASK);
}

LocalKey::KeySpec::KeySpec(CSSM_KEYUSE usage, CSSM_KEYATTR_FLAGS attrs, const CssmData &label)
	: CssmClient::KeySpec(usage, (attrs & ~managedAttributes) | forcedAttributes, label)
{
	if (attrs & generatedAttributes)
		CssmError::throwMe(CSSMERR_CSP_INVALID_KEYATTR_MASK);
}
