1/*
2 * Copyright (c) 2000-2001,2008,2011-2012 Apple Inc. All Rights Reserved.
3 *
4 * The contents of this file constitute Original Code as defined in and are
5 * subject to the Apple Public Source License Version 1.2 (the 'License').
6 * You may not use this file except in compliance with the License. Please obtain
7 * a copy of the License at http://www.apple.com/publicsource and read it before
8 * using this file.
9 *
10 * This Original Code and all software distributed under the License are
11 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS
12 * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT
13 * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14 * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the
15 * specific language governing rights and limitations under the License.
16 */
17
18
19//
20// SSCSPDLSession.cpp - Security Server CSP/DL session.
21//
22#include "SSCSPDLSession.h"
23
24#include "CSPDLPlugin.h"
25#include "SSKey.h"
26
27
28#ifndef SECURITYSERVER_ACL_EDITS
29
30#include <security_cdsa_client/aclclient.h>
31#include <security_keychain/Access.h>
32#include <security_keychain/TrustedApplication.h>
33#include <security_utilities/seccfobject.h>
34
35//
36// ClientSessionKey - Lightweight wrapper for a KeyHandle that is also an CssmClient::AclBearer
37//
38class ClientSessionKey: public CssmClient::AclBearer
39{
40public:
41	ClientSessionKey(SecurityServer::ClientSession &clientSession, SecurityServer::KeyHandle keyHandle);
42	~ClientSessionKey();
43
44	// Acl manipulation
45	virtual void getAcl(AutoAclEntryInfoList &aclInfos,
46		const char *selectionTag = NULL) const;
47	virtual void changeAcl(const CSSM_ACL_EDIT &aclEdit,
48		const CSSM_ACCESS_CREDENTIALS *cred = NULL);
49
50	// Acl owner manipulation
51	virtual void getOwner(AutoAclOwnerPrototype &owner) const;
52	virtual void changeOwner(const CSSM_ACL_OWNER_PROTOTYPE &newOwner,
53		const CSSM_ACCESS_CREDENTIALS *cred = NULL);
54
55
56private:
57	SecurityServer::ClientSession &mClientSession;
58	SecurityServer::KeyHandle mKeyHandle;
59};
60
61#endif //!SECURITYSERVER_ACL_EDITS
62
63
64using namespace SecurityServer;
65
66//
67// SSCSPDLSession -- Security Server CSP session
68//
69SSCSPDLSession::SSCSPDLSession()
70{
71}
72
73
74//
75// Reference Key management
76//
77void
78SSCSPDLSession::makeReferenceKey(SSCSPSession &session, KeyHandle inKeyHandle,
79								 CssmKey &outKey, SSDatabase &inSSDatabase,
80								 uint32 inKeyAttr, const CssmData *inKeyLabel)
81{
82	new SSKey(session, inKeyHandle, outKey, inSSDatabase, inKeyAttr,
83			  inKeyLabel);
84}
85
86SSKey &
87SSCSPDLSession::lookupKey(const CssmKey &inKey)
88{
89	/* for now we only allow ref keys */
90	if(inKey.blobType() != CSSM_KEYBLOB_REFERENCE) {
91		CssmError::throwMe(CSSMERR_CSP_INVALID_KEY);
92	}
93
94	/* fetch key (this is just mapping the value in inKey.KeyData to an SSKey) */
95	SSKey &theKey = find<SSKey>(inKey);
96
97	#ifdef someday
98	/*
99	 * Make sure caller hasn't changed any crucial header fields.
100	 * Some fields were changed by makeReferenceKey, so make a local copy....
101	 */
102	CSSM_KEYHEADER localHdr = cssmKey.KeyHeader;
103	get binKey-like thing from SSKey, maybe SSKey should keep a copy of
104	hdr...but that's' not supersecure....;
105
106	localHdr.BlobType = binKey->mKeyHeader.BlobType;
107	localHdr.Format = binKey->mKeyHeader.Format;
108	if(memcmp(&localHdr, &binKey->mKeyHeader, sizeof(CSSM_KEYHEADER))) {
109		CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_REFERENCE);
110	}
111	#endif
112	return theKey;
113}
114
115// Notification we receive when the acl on a key has changed.  We should write it back to disk if it's persistent.
116void
117SSCSPDLSession::didChangeKeyAcl(SecurityServer::ClientSession &clientSession,
118	KeyHandle keyHandle, CSSM_ACL_AUTHORIZATION_TAG tag)
119{
120	SSKey *theKey = NULL;
121
122	{
123		// Lookup the SSKey for the KeyHandle
124		StLock<Mutex> _(mKeyMapLock);
125		KeyMap::const_iterator it;
126		KeyMap::const_iterator end = mKeyMap.end();
127		for (it = mKeyMap.begin(); it != end; ++it)
128		{
129			SSKey *aKey = dynamic_cast<SSKey *>(it->second);
130			if (aKey->optionalKeyHandle() == keyHandle)
131			{
132				// Write the key to disk if it's persistent.
133				theKey = aKey;
134				break;
135			}
136		}
137	}
138
139	if (theKey)
140	{
141		theKey->didChangeAcl();
142	}
143	else
144	{
145		// @@@ Should we really throw here or just continue without updating the ACL?  In reality this should never happen, so let's at least log it and throw.
146		secdebug("keyacl", "SSCSPDLSession::didChangeKeyAcl() keyHandle: %lu not found in map", (unsigned long)keyHandle);
147		CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_REFERENCE);
148	}
149}
150
151void
152SSCSPDLSession::didChangeKeyAclCallback(void *context, SecurityServer::ClientSession &clientSession,
153	SecurityServer::KeyHandle key, CSSM_ACL_AUTHORIZATION_TAG tag)
154{
155	reinterpret_cast<SSCSPDLSession *>(context)->didChangeKeyAcl(clientSession, key, tag);
156}
157
158#ifndef SECURITYSERVER_ACL_EDITS
159//
160// ClientSessionKey - Lightweight wrapper for a KeyHandle that is also an CssmClient::AclBearer
161//
162ClientSessionKey::ClientSessionKey(ClientSession &clientSession, SecurityServer::KeyHandle keyHandle) :
163	mClientSession(clientSession),
164	mKeyHandle(keyHandle)
165{
166}
167
168ClientSessionKey::~ClientSessionKey()
169{
170}
171
172void
173ClientSessionKey::getAcl(AutoAclEntryInfoList &aclInfos,
174	const char *selectionTag) const
175{
176	secdebug("keyacl", "ClientSessionKey::getAcl() keyHandle: %u", mKeyHandle);
177	aclInfos.allocator(mClientSession.returnAllocator);
178	mClientSession.getKeyAcl(mKeyHandle, selectionTag,
179		*static_cast<uint32 *>(aclInfos),
180		*reinterpret_cast<AclEntryInfo **>(static_cast<CSSM_ACL_ENTRY_INFO_PTR *>(aclInfos)));
181}
182
183void
184ClientSessionKey::changeAcl(const CSSM_ACL_EDIT &aclEdit,
185	const CSSM_ACCESS_CREDENTIALS *cred)
186{
187	secdebug("keyacl", "ClientSessionKey::changeAcl() keyHandle: %u", mKeyHandle);
188	mClientSession.changeKeyAcl(mKeyHandle, AccessCredentials::overlay(*cred), AclEdit::overlay(aclEdit));
189}
190
191void
192ClientSessionKey::getOwner(AutoAclOwnerPrototype &owner) const
193{
194	secdebug("keyacl", "ClientSessionKey::getOwner() keyHandle: %u", mKeyHandle);
195	owner.allocator(mClientSession.returnAllocator);
196	mClientSession.getKeyOwner(mKeyHandle,
197		*reinterpret_cast<AclOwnerPrototype *>(static_cast<CSSM_ACL_OWNER_PROTOTYPE *>(owner)));
198}
199
200void
201ClientSessionKey::changeOwner(const CSSM_ACL_OWNER_PROTOTYPE &newOwner,
202	const CSSM_ACCESS_CREDENTIALS *cred)
203{
204	secdebug("keyacl", "ClientSessionKey::changeOwner() keyHandle: %u", mKeyHandle);
205	mClientSession.changeKeyOwner(mKeyHandle, AccessCredentials::overlay(*cred), AclOwnerPrototype::overlay(newOwner));
206}
207
208#endif // !SECURITYSERVER_ACL_EDITS
209