/
requirement.h
244 lines (211 loc) · 9.64 KB
/
requirement.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
/*
* Copyright (c) 2006-2012 Apple Inc. All Rights Reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
//
// requirement - Code Requirement Blob description
//
#ifndef _H_REQUIREMENT
#define _H_REQUIREMENT
#include <security_utilities/blob.h>
#include <security_utilities/superblob.h>
#include <security_utilities/debugging_internal.h>
#include <Security/CodeSigning.h>
#include "codedirectory.h"
#include <map>
#include <kern/cs_blobs.h>
namespace Security {
namespace CodeSigning {
//
// Single requirement.
// This is a contiguous binary blob, starting with this header
// and followed by binary expr-code. All links within the blob
// are offset-relative to the start of the header.
// This is designed to be a binary stable format. Note that we restrict
// outselves to 4GB maximum size (4 byte size/offset), and we expect real
// Requirement blobs to be fairly small (a few kilobytes at most).
//
// The "kind" field allows for adding different kinds of Requirements altogether
// in the future. We expect to stay within the framework of "opExpr" requirements,
// but it never hurts to have a way out.
//
class Requirement: public Blob<Requirement, 0xfade0c00> {
public:
class Maker; // makes Requirement blobs
class Context; // evaluation context
class Reader; // structured reader
class Interpreter; // evaluation engine
// different forms of Requirements.
enum Kind {
exprForm = 1, // prefix expr form
lwcrForm = 2, // DER encoded lightweight code requirement form
};
void kind(Kind k) { mKind = k; }
Kind kind() const { return Kind(uint32_t(mKind)); }
// validate this requirement against a code context
void validate(const Context &ctx, OSStatus failure = errSecCSReqFailed) const; // throws on all failures
bool validates(const Context &ctx, OSStatus failure = errSecCSReqFailed) const; // returns on clean miss
// certificate positions (within a standard certificate chain)
static const int leafCert = 0; // index for leaf (first in chain)
static const int anchorCert = -1; // index for anchor (last in chain)
#if defined(TEST_APPLE_ANCHOR)
static const char testAppleAnchorEnv[];
static const SHA1::Digest &testAppleAnchorHash();
#endif //TEST_APPLE_ANCHOR
// common alignment rule for all requirement forms
static const size_t baseAlignment = sizeof(uint32_t); // (we might as well say "four")
// canonical (source) names of Requirement types (matched to SecRequirementType in CSCommon.h)
static const char *const typeNames[];
#if TARGET_OS_OSX
IFDUMP(void dump() const);
#endif
private:
Endian<uint32_t> mKind; // expression kind
};
//
// An interpretation context
//
class Requirement::Context {
protected:
Context()
: certs(NULL), info(NULL), entitlements(NULL), identifier(""), directory(NULL), packageChecksum(NULL), packageAlgorithm(kSecCodeSignatureNoHash), forcePlatform(false),
secureTimestamp(NULL), teamIdentifier(NULL), platformType(0), isSIPProtected(false), onAuthorizedAuthAPFSVolume(false), onSystemVolume(false),
validationCategory(CS_VALIDATION_CATEGORY_INVALID) { }
public:
Context(CFArrayRef certChain, CFDictionaryRef infoDict, CFDictionaryRef entitlementDict, const std::string &ident,
const CodeDirectory *dir, CFDataRef packageChecksum, SecCSDigestAlgorithm packageAlgorithm, bool force_platform, CFDateRef secure_timestamp,
const char *teamID, uint8_t platformType = 0, bool isSIPProtected = false, bool onAuthorizedAuthAPFSVolume = false, bool onSystemVolume = false,
unsigned int validationCategory = CS_VALIDATION_CATEGORY_INVALID)
: certs(certChain), info(infoDict), entitlements(entitlementDict), identifier(ident), directory(dir),
packageChecksum(packageChecksum), packageAlgorithm(packageAlgorithm), forcePlatform(force_platform),
secureTimestamp(secure_timestamp), teamIdentifier(teamID),platformType(platformType),isSIPProtected(isSIPProtected),
onAuthorizedAuthAPFSVolume(onAuthorizedAuthAPFSVolume), onSystemVolume(onSystemVolume), validationCategory(validationCategory) { }
CFArrayRef certs; // certificate chain
CFDictionaryRef info; // Info.plist
CFDictionaryRef entitlements; // entitlement plist
std::string identifier; // signing identifier
const CodeDirectory *directory; // CodeDirectory
CFDataRef packageChecksum; // package checksum
SecCSDigestAlgorithm packageAlgorithm; // package checksum algorithm
bool forcePlatform;
CFDateRef secureTimestamp;
const char *teamIdentifier; // team identifier
uint8_t platformType;
bool isSIPProtected;
bool onAuthorizedAuthAPFSVolume;
bool onSystemVolume;
unsigned int validationCategory;
SecCertificateRef cert(int ix) const; // get a cert from the cert chain (NULL if not found)
unsigned int certCount() const; // length of cert chain (including root)
};
//
// exprForm opcodes.
//
// Opcodes are broken into flags in the (HBO) high byte, and an opcode value
// in the remaining 24 bits. Note that opcodes will remain fairly small
// (almost certainly <60000), so we have the third byte to play around with
// in the future, if needed. For now, small opcodes effective reserve this byte
// as zero.
// The flag byte allows for limited understanding of unknown opcodes. It allows
// the interpreter to use the known opcode parts of the program while semi-creatively
// disregarding the parts it doesn't know about. An unrecognized opcode with zero
// flag byte causes evaluation to categorically fail, since the semantics of such
// an opcode cannot safely be predicted.
//
enum {
// semantic bits or'ed into the opcode
opFlagMask = 0xFF000000, // high bit flags
opGenericFalse = 0x80000000, // has size field; okay to default to false
opGenericSkip = 0x40000000, // has size field; skip and continue
};
enum ExprOp {
opFalse, // unconditionally false
opTrue, // unconditionally true
opIdent, // match canonical code [string]
opAppleAnchor, // signed by Apple as Apple's product
opAnchorHash, // match anchor [cert hash]
opInfoKeyValue, // *legacy* - use opInfoKeyField [key; value]
opAnd, // binary prefix expr AND expr [expr; expr]
opOr, // binary prefix expr OR expr [expr; expr]
opCDHash, // match hash of CodeDirectory directly [cd hash]
opNot, // logical inverse [expr]
opInfoKeyField, // Info.plist key field [string; match suffix]
opCertField, // Certificate field, existence only [cert index; field name; match suffix]
opTrustedCert, // require trust settings to approve one particular cert [cert index]
opTrustedCerts, // require trust settings to approve the cert chain
opCertGeneric, // Certificate component by OID [cert index; oid; match suffix]
opAppleGenericAnchor, // signed by Apple in any capacity
opEntitlementField, // entitlement dictionary field [string; match suffix]
opCertPolicy, // Certificate policy by OID [cert index; oid; match suffix]
opNamedAnchor, // named anchor type
opNamedCode, // named subroutine
opPlatform, // platform constraint [integer]
opNotarized, // has a developer id+ ticket
opCertFieldDate, // extension value as timestamp [cert index; field name; match suffix]
opLegacyDevID, // meets legacy (pre-notarization required) policy
exprOpCount // (total opcode count in use)
};
// match suffix opcodes
enum MatchOperation {
matchExists, // anything but explicit "false" - no value stored
matchEqual, // equal (CFEqual)
matchContains, // partial match (substring)
matchBeginsWith, // partial match (initial substring)
matchEndsWith, // partial match (terminal substring)
matchLessThan, // less than (string with numeric comparison)
matchGreaterThan, // greater than (string with numeric comparison)
matchLessEqual, // less or equal (string with numeric comparison)
matchGreaterEqual, // greater or equal (string with numeric comparison)
matchOn, // on (timestamp comparison)
matchBefore, // before (timestamp comparison)
matchAfter, // after (timestamp comparison)
matchOnOrBefore, // on or before (timestamp comparison)
matchOnOrAfter, // on or after (timestamp comparison)
matchAbsent, // not present (kCFNull)
};
//
// We keep Requirement groups in SuperBlobs, indexed by SecRequirementType
//
typedef SuperBlob<0xfade0c01> Requirements;
//
// Byte order flippers
//
inline CodeSigning::ExprOp h2n(CodeSigning::ExprOp op)
{
uint32_t intOp = (uint32_t) op;
return (CodeSigning::ExprOp) ::h2n(intOp);
}
inline CodeSigning::ExprOp n2h(CodeSigning::ExprOp op)
{
uint32_t intOp = (uint32_t) op;
return (CodeSigning::ExprOp) ::n2h(intOp);
}
inline CodeSigning::MatchOperation h2n(CodeSigning::MatchOperation op)
{
return CodeSigning::MatchOperation(::h2n((uint32_t) op));
}
inline CodeSigning::MatchOperation n2h(CodeSigning::MatchOperation op)
{
return CodeSigning::MatchOperation(::n2h((uint32_t) op));
}
} // CodeSigning
} // Security
#endif //_H_REQUIREMENT