1/*
2 * Copyright (c) 2006-2012 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// requirement - Code Requirement Blob description
26//
27#include "requirement.h"
28#include "reqinterp.h"
29#include "codesigning_dtrace.h"
30#include <security_utilities/errors.h>
31#include <security_utilities/unix++.h>
32#include <security_utilities/logging.h>
33#include <security_utilities/cfutilities.h>
34#include <security_utilities/hashing.h>
35
36#ifdef DEBUGDUMP
37#include <security_codesigning/reqdumper.h>
38#endif
39
40namespace Security {
41namespace CodeSigning {
42
43
44//
45// Canonical names for requirement types
46//
47const char *const Requirement::typeNames[] = {
48	"invalid",
49	"host",
50	"guest",
51	"designated",
52	"library",
53	"plugin",
54};
55
56
57//
58// validate a requirement against a code context
59//
60void Requirement::validate(const Requirement::Context &ctx, OSStatus failure /* = errSecCSReqFailed */) const
61{
62	if (!this->validates(ctx, failure))
63		MacOSError::throwMe(failure);
64}
65
66bool Requirement::validates(const Requirement::Context &ctx, OSStatus failure /* = errSecCSReqFailed */) const
67{
68	CODESIGN_EVAL_REQINT_START((void*)this, (int)this->length());
69	switch (kind()) {
70	case exprForm:
71		if (Requirement::Interpreter(this, &ctx).evaluate()) {
72			CODESIGN_EVAL_REQINT_END(this, 0);
73			return true;
74		} else {
75			CODESIGN_EVAL_REQINT_END(this, failure);
76			return false;
77		}
78	default:
79		CODESIGN_EVAL_REQINT_END(this, errSecCSReqUnsupported);
80		MacOSError::throwMe(errSecCSReqUnsupported);
81	}
82}
83
84
85//
86// Retrieve one certificate from the cert chain.
87// Positive and negative indices can be used:
88//    [ leaf, intermed-1, ..., intermed-n, anchor ]
89//        0       1       ...     -2         -1
90// Returns NULL if unavailable for any reason.
91//
92SecCertificateRef Requirement::Context::cert(int ix) const
93{
94	if (certs) {
95		if (ix < 0)
96			ix += certCount();
97		if (ix >= CFArrayGetCount(certs))
98		    return NULL;
99		if (CFTypeRef element = CFArrayGetValueAtIndex(certs, ix))
100			return SecCertificateRef(element);
101	}
102	return NULL;
103}
104
105unsigned int Requirement::Context::certCount() const
106{
107	if (certs)
108		return (unsigned int)CFArrayGetCount(certs);
109	else
110		return 0;
111}
112
113
114//
115// Produce the hash of a fake Apple root (only if compiled for internal testing)
116//
117#if defined(TEST_APPLE_ANCHOR)
118
119const char Requirement::testAppleAnchorEnv[] = "TEST_APPLE_ANCHOR";
120
121const SHA1::Digest &Requirement::testAppleAnchorHash()
122{
123	static bool tried = false;
124	static SHA1::Digest testHash;
125	if (!tried) {
126		// see if we have one configured
127		if (const char *path = getenv(testAppleAnchorEnv))
128			try {
129				UnixPlusPlus::FileDesc fd(path);
130				char buffer[2048];		// arbitrary limit
131				size_t size = fd.read(buffer, sizeof(buffer));
132				SHA1 hash;
133				hash(buffer, size);
134				hash.finish(testHash);
135				Syslog::alert("ACCEPTING TEST AUTHORITY %s FOR APPLE CODE IDENTITY", path);
136			} catch (...) { }
137		tried = true;
138	}
139	return testHash;		// will be zeroes (no match) if not configured
140}
141
142#endif //TEST_APPLE_ANCHOR
143
144
145//
146// Debug dump support
147//
148#ifdef DEBUGDUMP
149
150void Requirement::dump() const
151{
152	Debug::dump("%s\n", Dumper::dump(this).c_str());
153}
154
155#endif //DEBUGDUMP
156
157
158}	// CodeSigning
159}	// Security
160