1/*
2 * Copyright (c) 2000-2004,2006,2011,2013-2014 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// sstransit - Securityd client side transition support.
27//
28#include "sstransit.h"
29#include <security_cdsa_client/cspclient.h>
30#include <security_utilities/mach++.h>
31
32namespace Security {
33namespace SecurityServer {
34
35using MachPlusPlus::check;
36using MachPlusPlus::VMGuard;
37
38//
39// DataOutput helper.
40// This happens "at the end" of a glue method, via the DataOutput destructor.
41//
42DataOutput::~DataOutput()
43{
44	// @@@ Why are we setting up a VMGuard if mData is NULL?
45	VMGuard _(mData, mLength);
46	if (mData)				// was assigned to; IPC returned OK
47		if (mTarget) {		// output CssmData exists
48			if (mTarget->data()) {	// caller provided buffer
49				if (mTarget->length() < mLength)
50					CssmError::throwMe(CSSMERR_CSP_OUTPUT_LENGTH_ERROR);
51				mTarget->length(mLength);	// no allocation; shorten buffer
52			} else {	// allocate buffer
53				*mTarget = CssmData(allocator.malloc(mLength), mLength);
54			}
55			memcpy(mTarget->data(), mData, mLength);
56		}
57}
58
59
60//
61// Copy an AccessCredentials for shipment.
62// In addition, scan the samples for "special" database locking samples
63// and translate certain items for safe shipment. Note that this overwrites
64// part of the CssmList value (CSPHandle -> SS/KeyHandle), but we do it on
65// the COPY, so that's okay.
66//
67DatabaseAccessCredentials::DatabaseAccessCredentials(const AccessCredentials *creds, Allocator &alloc)
68	: Copier<AccessCredentials>(creds, alloc)
69{
70	if (creds) {
71		for (uint32 n = 0; n < value()->samples().length(); n++) {
72			TypedList sample = value()->samples()[n];
73			sample.checkProper();
74			switch (sample.type()) {
75			case CSSM_SAMPLE_TYPE_KEYCHAIN_LOCK:
76				sample.snip();			// skip sample type (snip() advances to next)
77				sample.checkProper();
78				if (sample.type() == CSSM_SAMPLE_TYPE_SYMMETRIC_KEY ||
79					sample.type() == CSSM_SAMPLE_TYPE_ASYMMETRIC_KEY) {
80					secdebug("SSclient", "key sample encountered");
81					// proper form is sample[1] = DATA:CSPHandle, sample[2] = DATA:CSSM_KEY,
82					// sample[3] = auxiliary data (not changed)
83					if (sample.length() != 4
84						|| sample[1].type() != CSSM_LIST_ELEMENT_DATUM
85						|| sample[2].type() != CSSM_LIST_ELEMENT_DATUM
86						|| sample[3].type() != CSSM_LIST_ELEMENT_DATUM)
87						CssmError::throwMe(CSSM_ERRCODE_INVALID_SAMPLE_VALUE);
88					mapKeySample(
89								 sample[1].data(),
90								 *sample[2].data().interpretedAs<CssmKey>(CSSM_ERRCODE_INVALID_SAMPLE_VALUE));
91				}
92				break;
93			case CSSM_SAMPLE_TYPE_KEYCHAIN_CHANGE_LOCK:
94				sample.snip();	// skip sample type
95				sample.checkProper();
96				if (sample.type() == CSSM_SAMPLE_TYPE_SYMMETRIC_KEY ||
97					sample.type() == CSSM_SAMPLE_TYPE_ASYMMETRIC_KEY) {
98					secdebug("SSclient", "key sample encountered");
99					// proper form is sample[1] = DATA:CSPHandle, sample[2] = DATA:CSSM_KEY
100					if (sample.length() != 3
101						|| sample[1].type() != CSSM_LIST_ELEMENT_DATUM
102						|| sample[2].type() != CSSM_LIST_ELEMENT_DATUM)
103							CssmError::throwMe(CSSM_ERRCODE_INVALID_SAMPLE_VALUE);
104					mapKeySample(
105						sample[1].data(),
106						*sample[2].data().interpretedAs<CssmKey>(CSSM_ERRCODE_INVALID_SAMPLE_VALUE));
107				}
108				break;
109			default:
110				break;
111			}
112		}
113	}
114}
115
116void DatabaseAccessCredentials::mapKeySample(CssmData &cspHandleData, CssmKey &key)
117{
118	// We use a CSP passthrough to get the securityd key handle for a (reference) key.
119	// We try the passthrough on everyone, since there's multiple CSP/DL modules
120	// that play games with securityd, and we want to give everyone a chance to play.
121
122	// @@@ can't use CssmClient (it makes its own attachments)
123	CSSM_CC_HANDLE ctx;
124    CSSM_CSP_HANDLE &cspHandle = *cspHandleData.interpretedAs<CSSM_CSP_HANDLE>(CSSM_ERRCODE_INVALID_SAMPLE_VALUE);
125	CssmError::check(CSSM_CSP_CreatePassThroughContext(cspHandle, &key, &ctx));
126	KeyHandle ssKey;
127	CSSM_RETURN passthroughError =
128		CSSM_CSP_PassThrough(ctx, CSSM_APPLESCPDL_CSP_GET_KEYHANDLE, NULL, (void **)&ssKey);
129	CSSM_DeleteContext(ctx);	// ignore error
130	switch (passthroughError) {
131	case CSSM_OK:				// got the passthrough; rewrite the sample
132		assert(sizeof(CSSM_CSP_HANDLE) >= sizeof(KeyHandle));	// future insurance
133		cspHandle = ssKey;
134        cspHandleData.length(sizeof(KeyHandle));
135		secdebug("SSclient", "key sample mapped to key 0x%x", ssKey);
136		return;
137	case CSSMERR_CSP_INVALID_PASSTHROUGH_ID:
138		return;		// CSP didn't understand the callback; leave the sample alone
139	default:
140		CssmError::throwMe(passthroughError);	// error
141	}
142}
143
144
145//
146// Inbound/outbound transit for the elaborate data-access attribute vectors
147//
148DataRetrieval::DataRetrieval(CssmDbRecordAttributeData *&attributes, Allocator &alloc)
149	: Copier<CssmDbRecordAttributeData>(attributes),
150	  mAllocator(alloc), mAttributes(attributes), mAddr(NULL), mBase(NULL), mLength(0)
151{
152}
153
154DataRetrieval::~DataRetrieval()
155{
156	if (mAddr) {
157		relocate(mAddr, mBase);
158		assert(mAttributes->size() == mAddr->size());
159
160		// global (per-record) fields
161		mAttributes->recordType(mAddr->recordType());
162		mAttributes->semanticInformation(mAddr->semanticInformation());
163
164		// transfer data values (but not infos, which we keep in the original vector)
165		for (uint32 n = 0; n < mAttributes->size(); n++)
166			mAttributes->at(n).copyValues(mAddr->at(n), mAllocator);
167	}
168}
169
170
171} // namespace SecurityServer
172} // end namespace Security
173