/ OSX / libsecurity_codesigning / lib / SecRequirement.cpp
SecRequirement.cpp
  1  /*
  2   * Copyright (c) 2006,2011-2012,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  // SecRequirement - API frame for SecRequirement objects
 26  //
 27  #include "cs.h"
 28  #include "Requirements.h"
 29  #include "reqparser.h"
 30  #include "reqmaker.h"
 31  #include "reqdumper.h"
 32  #include <Security/SecCertificate.h>
 33  #include <security_utilities/cfutilities.h>
 34  
 35  using namespace CodeSigning;
 36  
 37  
 38  //
 39  // CF-standard type code function
 40  //
 41  CFTypeID SecRequirementGetTypeID(void)
 42  {
 43  	BEGIN_CSAPI
 44  	return gCFObjects().Requirement.typeID;
 45      END_CSAPI1(_kCFRuntimeNotATypeID)
 46  }
 47  
 48  
 49  //
 50  // Create a Requirement from data
 51  //
 52  OSStatus SecRequirementCreateWithData(CFDataRef data, SecCSFlags flags,
 53  	SecRequirementRef *requirementRef)
 54  {
 55  	BEGIN_CSAPI
 56  	
 57  	checkFlags(flags);
 58  	CodeSigning::Required(requirementRef) = (new SecRequirement(CFDataGetBytePtr(data), CFDataGetLength(data)))->handle();
 59  
 60  	END_CSAPI
 61  }
 62  	
 63  
 64  //
 65  // Create a Requirement from data in a file
 66  //
 67  OSStatus SecRequirementCreateWithResource(CFURLRef resource, SecCSFlags flags,
 68  	SecRequirementRef *requirementRef)
 69  {
 70  	BEGIN_CSAPI
 71  	
 72  	checkFlags(flags);
 73  	CFRef<CFDataRef> data = cfLoadFile(resource);
 74  	CodeSigning::Required(requirementRef) =
 75  		(new SecRequirement(CFDataGetBytePtr(data), CFDataGetLength(data)))->handle();
 76  
 77  	END_CSAPI
 78  }
 79  
 80  
 81  //
 82  // Create a Requirement from source text (compiling it)
 83  //
 84  OSStatus SecRequirementCreateWithString(CFStringRef text, SecCSFlags flags,
 85  	SecRequirementRef *requirementRef)
 86  {
 87  	return SecRequirementCreateWithStringAndErrors(text, flags, NULL, requirementRef);
 88  }
 89  
 90  OSStatus SecRequirementCreateWithStringAndErrors(CFStringRef text, SecCSFlags flags,
 91  	CFErrorRef *errors, SecRequirementRef *requirementRef)
 92  {
 93  	BEGIN_CSAPI
 94  	
 95  	checkFlags(flags);
 96  	CodeSigning::Required(requirementRef) = (new SecRequirement(parseRequirement(cfString(text)), true))->handle();
 97  
 98  	END_CSAPI_ERRORS
 99  }
100  
101  
102  //
103  // Create a Requirement group.
104  // This is the canonical point where "application group" is defined.
105  //
106  OSStatus SecRequirementCreateGroup(CFStringRef groupName, SecCertificateRef anchorRef,
107  	SecCSFlags flags, SecRequirementRef *requirementRef)
108  {
109  	BEGIN_CSAPI
110  	
111  	checkFlags(flags);
112  	Requirement::Maker maker;
113  	maker.put(opAnd);		// both of...
114  	maker.infoKey("Application-Group", cfString(groupName));
115  	if (anchorRef) {
116  #if TARGET_OS_OSX
117  		CSSM_DATA certData;
118  		MacOSError::check(SecCertificateGetData(anchorRef, &certData));
119  		maker.anchor(0, certData.Data, certData.Length);
120  #else
121          maker.anchor(0, SecCertificateGetBytePtr(anchorRef), SecCertificateGetLength(anchorRef));
122  #endif
123  	} else {
124  		maker.anchor();			// canonical Apple anchor
125  	}
126  	CodeSigning::Required(requirementRef) = (new SecRequirement(maker.make(), true))->handle();
127  
128  	END_CSAPI
129  }
130  
131  
132  //
133  // Extract the stable binary from from a SecRequirementRef
134  //
135  OSStatus SecRequirementCopyData(SecRequirementRef requirementRef, SecCSFlags flags,
136  	CFDataRef *data)
137  {
138  	BEGIN_CSAPI
139  	
140  	const Requirement *req = SecRequirement::required(requirementRef)->requirement();
141  	checkFlags(flags);
142  	CodeSigning::Required(data);
143  	*data = makeCFData(*req);
144  
145  	END_CSAPI
146  }
147  
148  
149  //
150  // Generate source form for a SecRequirement (decompile/disassemble)
151  //
152  OSStatus SecRequirementCopyString(SecRequirementRef requirementRef, SecCSFlags flags,
153  	CFStringRef *text)
154  {
155  	BEGIN_CSAPI
156  	
157  	const Requirement *req = SecRequirement::required(requirementRef)->requirement();
158  	checkFlags(flags);
159  	CodeSigning::Required(text);
160  	*text = makeCFString(Dumper::dump(req));
161  
162  	END_CSAPI
163  }
164  
165  
166  //
167  CFStringRef kSecRequirementKeyInfoPlist = CFSTR("requirement:eval:info");
168  CFStringRef kSecRequirementKeyEntitlements = CFSTR("requirement:eval:entitlements");
169  CFStringRef kSecRequirementKeyIdentifier = CFSTR("requirement:eval:identifier");
170  CFStringRef kSecRequirementKeyPackageChecksum = CFSTR("requirement:eval:package_checksum");
171  CFStringRef kSecRequirementKeyChecksumAlgorithm = CFSTR("requirement:eval:package_checksum_algorithm");
172  CFStringRef kSecRequirementKeySecureTimestamp = CFSTR("requirement:eval:secure_timestamp");
173  CFStringRef kSecRequirementKeyTeamIdentifier = CFSTR("requirement:eval:team_identifier");
174  
175  OSStatus SecRequirementEvaluate(SecRequirementRef requirementRef,
176  	CFArrayRef certificateChain, CFDictionaryRef context,
177  	SecCSFlags flags)
178  {
179  	BEGIN_CSAPI
180  
181  	const Requirement *req = SecRequirement::required(requirementRef)->requirement();
182  	checkFlags(flags);
183  	CodeSigning::Required(certificateChain);
184  
185  	SecCSDigestAlgorithm checksumAlgorithm = kSecCodeSignatureNoHash;
186  	if (context) {
187  		CFRef<CFNumberRef> num = (CFNumberRef)CFDictionaryGetValue(context, kSecRequirementKeyChecksumAlgorithm);
188  		if (num) {
189  			checksumAlgorithm = (SecCSDigestAlgorithm)cfNumber<uint32_t>(num);
190  		}
191  	}
192  
193  	const char *teamID = NULL;
194  	if (context && CFDictionaryGetValue(context, kSecRequirementKeyTeamIdentifier)) {
195  		CFStringRef str = (CFStringRef)CFDictionaryGetValue(context, kSecRequirementKeyTeamIdentifier);
196  		teamID = CFStringGetCStringPtr(str, kCFStringEncodingUTF8);
197  	}
198  
199  	Requirement::Context ctx(certificateChain,		// mandatory
200  		context ? CFDictionaryRef(CFDictionaryGetValue(context, kSecRequirementKeyInfoPlist)) : NULL,
201  		context ? CFDictionaryRef(CFDictionaryGetValue(context, kSecRequirementKeyEntitlements)) : NULL,
202  		(context && CFDictionaryGetValue(context, kSecRequirementKeyIdentifier)) ?
203  			cfString(CFStringRef(CFDictionaryGetValue(context, kSecRequirementKeyIdentifier))) : "",
204  		NULL,	// can't specify a CodeDirectory here
205  		context ? CFDataRef(CFDictionaryGetValue(context, kSecRequirementKeyPackageChecksum)) : NULL,
206          checksumAlgorithm,
207  		false, // can't get forced platform this way
208  		context ? CFDateRef(CFDictionaryGetValue(context, kSecRequirementKeySecureTimestamp)) : NULL,
209  		teamID
210  	);
211  	req->validate(ctx);
212  	
213  	END_CSAPI
214  }
215  
216  
217  //
218  // Assemble a requirement set (as a CFData) from a dictionary of requirement objects.
219  // An empty set is allowed.
220  //
221  OSStatus SecRequirementsCreateFromRequirements(CFDictionaryRef requirements, SecCSFlags flags,
222  	CFDataRef *requirementSet)
223  {
224  	BEGIN_CSAPI
225  	
226  	checkFlags(flags);
227  	if (requirements == NULL)
228  		return errSecCSObjectRequired;
229  	CFIndex count = CFDictionaryGetCount(requirements);
230  	vector<CFNumberRef> keys_vector(count, NULL);
231  	vector<SecRequirementRef> reqs_vector(count, NULL);
232  	CFDictionaryGetKeysAndValues(requirements, (const void **)keys_vector.data(), (const void **)reqs_vector.data());
233  	Requirements::Maker maker;
234  	for (CFIndex n = 0; n < count; n++) {
235  		const Requirement *req = SecRequirement::required(reqs_vector[n])->requirement();
236  		maker.add(cfNumber<Requirements::Type>(keys_vector[n]), req->clone());
237  	}
238  	Requirements *reqset = maker.make();					// malloc'ed
239  	CodeSigning::Required(requirementSet) = makeCFDataMalloc(*reqset);	// takes ownership of reqs
240  
241  	END_CSAPI
242  }
243  
244  
245  //
246  // Break a requirement set (given as a CFData) into its constituent requirements
247  // and return it as a CFDictionary.
248  //
249  OSStatus SecRequirementsCopyRequirements(CFDataRef requirementSet, SecCSFlags flags,
250  	CFDictionaryRef *requirements)
251  {
252  	BEGIN_CSAPI
253  	
254  	checkFlags(flags);
255  	if (requirementSet == NULL)
256  		return errSecCSObjectRequired;
257  	const Requirements *reqs = (const Requirements *)CFDataGetBytePtr(requirementSet);
258  	if (!reqs->validateBlob())
259  		MacOSError::throwMe(errSecCSReqInvalid);
260  	CFRef<CFMutableDictionaryRef> dict = makeCFMutableDictionary();
261  	unsigned count = reqs->count();
262  	for (unsigned n = 0; n < count; n++) {
263  		CFRef<SecRequirementRef> req = (new SecRequirement(reqs->blob<Requirement>(n)))->handle();
264  		CFDictionaryAddValue(dict, CFTempNumber(reqs->type(n)), req);
265  	}
266  	CodeSigning::Required(requirements) = dict.yield();
267  
268  	END_CSAPI
269  }
270  
271  	
272  //
273  // Generically parse a string as some kind of requirement-related source form.
274  // If properly recognized, return the result as a CF object:
275  //	SecRequirementRef for a single requirement
276  //	CFDataRef for a requirement set
277  //
278  OSStatus SecRequirementsCreateWithString(CFStringRef text, SecCSFlags flags,
279  	CFTypeRef *result, CFErrorRef *errors)
280  {
281  	BEGIN_CSAPI
282  	
283  	checkFlags(flags, kSecCSParseRequirement | kSecCSParseRequirementSet);
284  	if (text == NULL || result == NULL)
285  		return errSecCSObjectRequired;
286  	std::string s = cfString(text);
287  	switch (flags & (kSecCSParseRequirement | kSecCSParseRequirementSet)) {
288  	case kSecCSParseRequirement:		// single only
289  		*result = (new SecRequirement(parseRequirement(s), true))->handle();
290  		break;
291  	case kSecCSParseRequirementSet:		// single only
292  		{
293  			const Requirements *reqs = parseRequirements(s);
294  			*result = makeCFDataMalloc(*reqs);
295  			break;
296  		}
297  	case 0:
298  	case kSecCSParseRequirement | kSecCSParseRequirementSet:
299  		{
300  			const BlobCore *any = parseGeneric(s);
301  			if (any->is<Requirement>())
302  				*result = (new SecRequirement(Requirement::specific(any), true))->handle();
303  			else
304  				*result = makeCFDataMalloc(*any);
305  			break;
306  		}
307  	}
308  
309  	END_CSAPI_ERRORS
310  }
311  
312  	
313  //
314  // Convert a SecRequirementRef or a CFDataRef containing a requirement set to text.
315  // Requirement sets will be formatted as multiple lines (one per requirement). They can be empty.
316  // A single requirement will return a single line that is NOT newline-terminated.
317  //
318  OSStatus SecRequirementsCopyString(CFTypeRef input, SecCSFlags flags, CFStringRef *text)
319  {
320  	BEGIN_CSAPI
321  	
322  	checkFlags(flags);
323  	if (input == NULL)
324  		return errSecCSObjectRequired;
325  	if (CFGetTypeID(input) == SecRequirementGetTypeID()) {
326  		return SecRequirementCopyString(SecRequirementRef(input), flags, text);
327  	} else if (CFGetTypeID(input) == CFDataGetTypeID()) {
328  		const Requirements *reqs = (const Requirements *)CFDataGetBytePtr(CFDataRef(input));
329  		if (!reqs->validateBlob(CFDataGetLength(CFDataRef(input))))
330  			return errSecCSReqInvalid;
331  		CodeSigning::Required(text) = makeCFString(Dumper::dump(reqs, false));
332  	} else
333  		return errSecCSInvalidObjectRef;
334  
335  	END_CSAPI
336  }