]> git.saurik.com Git - apple/libsecurity_codesigning.git/blob - lib/requirement.h
9d20fc489ced3f2f239b9ddf342541acff9f84ff
[apple/libsecurity_codesigning.git] / lib / requirement.h
1 /*
2 * Copyright (c) 2006-2007 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
37 namespace Security {
38 namespace 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 //
54 class Requirement: public Blob<Requirement, 0xfade0c00> {
55 public:
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 static const SHA1::Digest &appleAnchorHash();
80 #if defined(TEST_APPLE_ANCHOR)
81 static const char testAppleAnchorEnv[];
82 static const SHA1::Digest &testAppleAnchorHash();
83 #endif //TEST_APPLE_ANCHOR
84
85 // common alignment rule for all requirement forms
86 static const size_t baseAlignment = sizeof(uint32_t); // (we might as well say "four")
87
88 // canonical (source) names of Requirement types (matched to SecRequirementType in CSCommon.h)
89 static const char *const typeNames[];
90
91 IFDUMP(void dump() const);
92
93 private:
94 Endian<uint32_t> mKind; // expression kind
95 };
96
97
98 //
99 // An interpretation context
100 //
101 struct Requirement::Context {
102 Context(CFArrayRef certChain, CFDictionaryRef infoDict, CFDictionaryRef entitlementDict, const CodeDirectory *dir)
103 : certs(certChain), info(infoDict), entitlements(entitlementDict), directory(dir) { }
104
105 const CFArrayRef certs; // certificate chain
106 const CFDictionaryRef info; // Info.plist
107 const CFDictionaryRef entitlements; // entitlement plist
108 const CodeDirectory * const directory; // CodeDirectory
109
110 SecCertificateRef cert(int ix) const; // get a cert from the cert chain
111 unsigned int certCount() const; // length of cert chain
112 };
113
114
115 //
116 // exprForm opcodes.
117 //
118 // Opcodes are broken into flags in the (HBO) high byte, and an opcode value
119 // in the remaining 24 bits. Note that opcodes will remain fairly small
120 // (almost certainly <60000), so we have the third byte to play around with
121 // in the future, if needed. For now, small opcodes effective reserve this byte
122 // as zero.
123 // The flag byte allows for limited understanding of unknown opcodes. It allows
124 // the interpreter to use the known opcode parts of the program while semi-creatively
125 // disregarding the parts it doesn't know about. An unrecognized opcode with zero
126 // flag byte causes evaluation to categorically fail, since the semantics of such
127 // an opcode cannot safely be predicted.
128 //
129 enum {
130 // semantic bits or'ed into the opcode
131 opFlagMask = 0xFF000000, // high bit flags
132 opGenericFalse = 0x80000000, // has size field; okay to default to false
133 opGenericSkip = 0x40000000, // has size field; skip and continue
134 };
135
136 enum ExprOp {
137 opFalse, // unconditionally false
138 opTrue, // unconditionally true
139 opIdent, // match canonical code [string]
140 opAppleAnchor, // signed by Apple as Apple's product
141 opAnchorHash, // match anchor [cert hash]
142 opInfoKeyValue, // *legacy* - use opInfoKeyField [key; value]
143 opAnd, // binary prefix expr AND expr [expr; expr]
144 opOr, // binary prefix expr OR expr [expr; expr]
145 opCDHash, // match hash of CodeDirectory directly [cd hash]
146 opNot, // logical inverse [expr]
147 opInfoKeyField, // Info.plist key field [string; match suffix]
148 opCertField, // Certificate field [cert index; field name; match suffix]
149 opTrustedCert, // require trust settings to approve one particular cert [cert index]
150 opTrustedCerts, // require trust settings to approve the cert chain
151 opCertGeneric, // Certificate component by OID [cert index; oid; match suffix]
152 opAppleGenericAnchor, // signed by Apple in any capacity
153 opEntitlementField, // entitlement dictionary field [string; match suffix]
154 opCertPolicy, // Certificate policy by OID [cert index; oid; match suffix]
155 opNamedAnchor, // named anchor type
156 opNamedCode, // named subroutine
157 exprOpCount // (total opcode count in use)
158 };
159
160 // match suffix opcodes
161 enum MatchOperation {
162 matchExists, // anything but explicit "false" - no value stored
163 matchEqual, // equal (CFEqual)
164 matchContains, // partial match (substring)
165 matchBeginsWith, // partial match (initial substring)
166 matchEndsWith, // partial match (terminal substring)
167 matchLessThan, // less than (string with numeric comparison)
168 matchGreaterThan, // greater than (string with numeric comparison)
169 matchLessEqual, // less or equal (string with numeric comparison)
170 matchGreaterEqual, // greater or equal (string with numeric comparison)
171 };
172
173
174 //
175 // We keep Requirement groups in SuperBlobs, indexed by SecRequirementType
176 //
177 typedef SuperBlob<0xfade0c01> Requirements;
178
179
180 //
181 // A helper to deal with the magic merger logic of internal requirements
182 //
183 class InternalRequirements : public Requirements::Maker {
184 public:
185 InternalRequirements() : mReqs(NULL) { }
186 ~InternalRequirements() { ::free((void *)mReqs); }
187 void operator () (const Requirements *given, const Requirements *defaulted);
188 operator const Requirements * () const { return mReqs; }
189
190 private:
191 const Requirements *mReqs;
192 };
193
194
195 //
196 // Byte order flippers
197 //
198 inline CodeSigning::ExprOp h2n(CodeSigning::ExprOp op)
199 {
200 uint32_t intOp = (uint32_t) op;
201 return (CodeSigning::ExprOp) ::h2n(intOp);
202 }
203
204 inline CodeSigning::ExprOp n2h(CodeSigning::ExprOp op)
205 {
206 uint32_t intOp = (uint32_t) op;
207 return (CodeSigning::ExprOp) ::n2h(intOp);
208 }
209
210
211 inline CodeSigning::MatchOperation h2n(CodeSigning::MatchOperation op)
212 {
213 return CodeSigning::MatchOperation(::h2n((uint32_t) op));
214 }
215
216 inline CodeSigning::MatchOperation n2h(CodeSigning::MatchOperation op)
217 {
218 return CodeSigning::MatchOperation(::n2h((uint32_t) op));
219 }
220
221
222 } // CodeSigning
223 } // Security
224
225 #endif //_H_REQUIREMENT