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#ifndef _H_REQUIREMENT
28#define _H_REQUIREMENT
29
30#include <security_utilities/blob.h>
31#include <security_utilities/superblob.h>
32#include <security_utilities/hashing.h>
33#include <Security/CodeSigning.h>
34#include "codedirectory.h"
35#include <map>
36
37namespace Security {
38namespace CodeSigning {
39
40
41//
42// Single requirement.
43// This is a contiguous binary blob, starting with this header
44// and followed by binary expr-code. All links within the blob
45// are offset-relative to the start of the header.
46// This is designed to be a binary stable format. Note that we restrict
47// outselves to 4GB maximum size (4 byte size/offset), and we expect real
48// Requirement blobs to be fairly small (a few kilobytes at most).
49//
50// The "kind" field allows for adding different kinds of Requirements altogether
51// in the future. We expect to stay within the framework of "opExpr" requirements,
52// but it never hurts to have a way out.
53//
54class Requirement: public Blob<Requirement, 0xfade0c00> {
55public:
56	class Maker;				// makes Requirement blobs
57	class Context;				// evaluation context
58	class Reader;				// structured reader
59	class Interpreter;			// evaluation engine
60
61	// different forms of Requirements. Right now, we only support exprForm ("opExprs")
62	enum Kind {
63		exprForm = 1			// prefix expr form
64	};
65
66	void kind(Kind k) { mKind = k; }
67	Kind kind() const { return Kind(uint32_t(mKind)); }
68
69	// validate this requirement against a code context
70	void validate(const Context &ctx, OSStatus failure = errSecCSReqFailed) const;	// throws on all failures
71	bool validates(const Context &ctx, OSStatus failure = errSecCSReqFailed) const;	// returns on clean miss
72
73	// certificate positions (within a standard certificate chain)
74	static const int leafCert = 0;		// index for leaf (first in chain)
75	static const int anchorCert = -1;	// index for anchor (last in chain)
76
77	// the SHA1 hash of the canonical "Apple Anchor", i.e. the X509 Anchor
78	// that is considered "Apple's anchor certificate", as defined by hashOfCertificate().
79#if defined(TEST_APPLE_ANCHOR)
80	static const char testAppleAnchorEnv[];
81	static const SHA1::Digest &testAppleAnchorHash();
82#endif //TEST_APPLE_ANCHOR
83
84	// common alignment rule for all requirement forms
85	static const size_t baseAlignment = sizeof(uint32_t); // (we might as well say "four")
86
87    // canonical (source) names of Requirement types (matched to SecRequirementType in CSCommon.h)
88    static const char *const typeNames[];
89
90	IFDUMP(void dump() const);
91
92private:
93	Endian<uint32_t> mKind;			// expression kind
94};
95
96
97//
98// An interpretation context
99//
100class Requirement::Context {
101protected:
102	Context()
103		: certs(NULL), info(NULL), entitlements(NULL), identifier(""), directory(NULL) { }
104
105public:
106	Context(CFArrayRef certChain, CFDictionaryRef infoDict, CFDictionaryRef entitlementDict,
107			const std::string &ident, const CodeDirectory *dir)
108		: certs(certChain), info(infoDict), entitlements(entitlementDict), identifier(ident), directory(dir) { }
109
110	CFArrayRef certs;								// certificate chain
111	CFDictionaryRef info;							// Info.plist
112	CFDictionaryRef entitlements;					// entitlement plist
113	std::string identifier;						// signing identifier
114	const CodeDirectory *directory;				// CodeDirectory
115
116	SecCertificateRef cert(int ix) const;			// get a cert from the cert chain (NULL if not found)
117	unsigned int certCount() const;				// length of cert chain (including root)
118};
119
120
121//
122// exprForm opcodes.
123//
124// Opcodes are broken into flags in the (HBO) high byte, and an opcode value
125// in the remaining 24 bits. Note that opcodes will remain fairly small
126// (almost certainly <60000), so we have the third byte to play around with
127// in the future, if needed. For now, small opcodes effective reserve this byte
128// as zero.
129// The flag byte allows for limited understanding of unknown opcodes. It allows
130// the interpreter to use the known opcode parts of the program while semi-creatively
131// disregarding the parts it doesn't know about. An unrecognized opcode with zero
132// flag byte causes evaluation to categorically fail, since the semantics of such
133// an opcode cannot safely be predicted.
134//
135enum {
136	// semantic bits or'ed into the opcode
137	opFlagMask =	 0xFF000000,	// high bit flags
138	opGenericFalse = 0x80000000,	// has size field; okay to default to false
139	opGenericSkip =  0x40000000,	// has size field; skip and continue
140};
141
142enum ExprOp {
143	opFalse,						// unconditionally false
144	opTrue,							// unconditionally true
145	opIdent,						// match canonical code [string]
146	opAppleAnchor,					// signed by Apple as Apple's product
147	opAnchorHash,					// match anchor [cert hash]
148	opInfoKeyValue,					// *legacy* - use opInfoKeyField [key; value]
149	opAnd,							// binary prefix expr AND expr [expr; expr]
150	opOr,							// binary prefix expr OR expr [expr; expr]
151	opCDHash,						// match hash of CodeDirectory directly [cd hash]
152	opNot,							// logical inverse [expr]
153	opInfoKeyField,					// Info.plist key field [string; match suffix]
154	opCertField,					// Certificate field [cert index; field name; match suffix]
155	opTrustedCert,					// require trust settings to approve one particular cert [cert index]
156	opTrustedCerts,					// require trust settings to approve the cert chain
157	opCertGeneric,					// Certificate component by OID [cert index; oid; match suffix]
158	opAppleGenericAnchor,			// signed by Apple in any capacity
159	opEntitlementField,				// entitlement dictionary field [string; match suffix]
160	opCertPolicy,					// Certificate policy by OID [cert index; oid; match suffix]
161	opNamedAnchor,					// named anchor type
162	opNamedCode,					// named subroutine
163	exprOpCount						// (total opcode count in use)
164};
165
166// match suffix opcodes
167enum MatchOperation {
168	matchExists,					// anything but explicit "false" - no value stored
169	matchEqual,						// equal (CFEqual)
170	matchContains,					// partial match (substring)
171	matchBeginsWith,				// partial match (initial substring)
172	matchEndsWith,					// partial match (terminal substring)
173	matchLessThan,					// less than (string with numeric comparison)
174	matchGreaterThan,				// greater than (string with numeric comparison)
175	matchLessEqual,					// less or equal (string with numeric comparison)
176	matchGreaterEqual,				// greater or equal (string with numeric comparison)
177};
178
179
180//
181// We keep Requirement groups in SuperBlobs, indexed by SecRequirementType
182//
183typedef SuperBlob<0xfade0c01> Requirements;
184
185
186//
187// Byte order flippers
188//
189inline CodeSigning::ExprOp h2n(CodeSigning::ExprOp op)
190{
191	uint32_t intOp = (uint32_t) op;
192	return (CodeSigning::ExprOp) ::h2n(intOp);
193}
194
195inline CodeSigning::ExprOp n2h(CodeSigning::ExprOp op)
196{
197	uint32_t intOp = (uint32_t) op;
198	return (CodeSigning::ExprOp) ::n2h(intOp);
199}
200
201
202inline CodeSigning::MatchOperation h2n(CodeSigning::MatchOperation op)
203{
204	return CodeSigning::MatchOperation(::h2n((uint32_t) op));
205}
206
207inline CodeSigning::MatchOperation n2h(CodeSigning::MatchOperation op)
208{
209	return CodeSigning::MatchOperation(::n2h((uint32_t) op));
210}
211
212
213}	// CodeSigning
214}	// Security
215
216#endif //_H_REQUIREMENT
217