]> git.saurik.com Git - apple/libsecurity_codesigning.git/blob - requirements.grammar
libsecurity_codesigning-32953.tar.gz
[apple/libsecurity_codesigning.git] / requirements.grammar
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 // Requirements Language Grammar
26 //
27 // This file describes two distinct (related) grammars:
28 // Requirement => single requirement (Requirement *)
29 // RequirementSet => set of labeled requirements (Requirements *)
30 // The grammar can "autosense" - i.e. recognize which one it's fed and
31 // return appropriate semantic data.
32 // The semantic data compiled is a malloc'ed BlobCore * - a Requirement
33 // object or a SuperBlob containing multiple Requirements.
34 //
35 header "post_include_hpp" {
36 #include "requirement.h"
37 using namespace CodeSigning;
38 typedef Requirement::Maker Maker;
39 }
40
41 header "post_include_cpp" {
42 #include "requirement.h"
43 #include "reqmaker.h"
44 #include "csutilities.h"
45 #include <security_utilities/cfutilities.h>
46 #include <security_utilities/hashing.h>
47 using namespace CodeSigning;
48 typedef Requirement::Maker Maker;
49 }
50
51 options {
52 language="Cpp";
53 namespace="Security_CodeSigning";
54 namespaceStd="std";
55 namespaceAntlr="antlr";
56 genHashLines=false;
57 }
58
59
60 {
61 //
62 // Collect error messages
63 //
64 void RequirementParser::reportError(const antlr::RecognitionException &ex)
65 {
66 errors += ex.toString() + "\n";
67 }
68
69 void RequirementParser::reportError(const std::string &s)
70 {
71 errors += s + "\n";
72 }
73
74
75 //
76 // Parser helper functions
77 //
78 string RequirementParser::hexString(const string &s)
79 {
80 if (s.size() % 2)
81 throw antlr::SemanticException("odd number of digits");
82 const char *p = s.data();
83 string result;
84 for (unsigned n = 0; n < s.length(); n += 2) {
85 char c;
86 sscanf(p+n, "%2hhx", &c);
87 result.push_back(c);
88 }
89 return result;
90 }
91
92 void RequirementParser::hashString(const string &s, SHA1::Digest hash)
93 {
94 if (s.size() != 2 * SHA1::digestLength)
95 throw antlr::SemanticException("invalid hash length");
96 memcpy(hash, hexString(s).data(), SHA1::digestLength);
97 }
98 }
99
100 class RequirementParser extends Parser;
101
102 options {
103 k=2;
104 }
105
106 {
107 public:
108 std::string errors;
109 void reportError(const antlr::RecognitionException &ex);
110 void reportError(const std::string &s);
111
112 private:
113 static string hexString(const string &s);
114 static void hashString(const string &s, SHA1::Digest hash);
115 }
116
117
118 //
119 // Compound target; compiles single requirements or requirement sets
120 // and returns them as a BlobCore.
121 //
122 autosense returns [BlobCore *result = NULL]
123 : result=requirement
124 | result=requirementSet
125 ;
126
127
128 //
129 // A Requirements Set.
130 //
131 requirementSet returns [Requirements *result = NULL]
132 { Requirements::Maker maker; }
133 : ( { uint32_t t; Requirement *req; }
134 t=requirementType ARROW req=requirementElement
135 { maker.add(t, req); }
136 )+
137 { result = errors.empty() ? maker() : NULL; }
138 EOF
139 ;
140
141 requirementType returns [uint32_t type = kSecInvalidRequirementType]
142 : "guest"
143 { type = kSecGuestRequirementType; }
144 | "host"
145 { type = kSecHostRequirementType; }
146 | "designated"
147 { type = kSecDesignatedRequirementType; }
148 | "library"
149 { type = kSecLibraryRequirementType; }
150 | stype:INTEGER
151 { type = atol(stype->getText().c_str()); }
152 ;
153
154
155 //
156 // A single Requirement (untyped)
157 //
158 requirement returns [Requirement *result = NULL]
159 : result = requirementElement
160 EOF
161 ;
162
163 requirementElement returns [Requirement *result = NULL]
164 { Requirement::Maker maker; }
165 : expr[maker]
166 { result = maker(); }
167 ( fluff )*
168 ;
169
170
171 //
172 // Classic recursive expressions
173 //
174 expr[Maker &maker]
175 { Maker::Label label(maker); }
176 : term[maker] ( "and" { maker.insert<ExprOp>(label) = opAnd; } term[maker] )*
177 ;
178
179 term[Maker &maker]
180 { Maker::Label label(maker); }
181 : primary[maker] ( "or" { maker.insert<ExprOp>(label) = opOr; } primary[maker] )*
182 ;
183
184 primary[Maker &maker]
185 : LPAREN expr[maker] RPAREN
186 | NOT { maker.put(opNot); } primary[maker]
187 | ( "always" | "true" )
188 { maker.put(opTrue); }
189 | ( "never" | "false" )
190 { maker.put(opFalse); }
191 | certspec[maker]
192 | infospec[maker]
193 | "identifier" { string code; } eql code=identifierString
194 { maker.ident(code); }
195 | "cdhash" { SHA1::Digest digest; } hash[digest]
196 { maker.cdhash(digest); }
197 ;
198
199
200 //
201 // Certificate specifications restrict certificates in the signing chain
202 //
203 certspec[Maker &maker]
204 : "anchor" "apple"
205 { maker.put(opAppleAnchor); }
206 | ( "certificate" | "cert" | "anchor" ) "trusted"
207 { maker.trustedAnchor(); }
208 | ( "certificate" | "cert" ) { int slot; } slot=certSlot
209 ( certslotspec[maker, slot] | "trusted" { maker.trustedAnchor(slot); } )
210 | "anchor" certslotspec[maker, Requirement::anchorCert]
211 ;
212
213 certslotspec[Maker &maker, int slot] { string key; }
214 : eql { SHA1::Digest digest; } certificateDigest[digest]
215 { maker.anchor(slot, digest); }
216 | key=bracketKey
217 { maker.put(opCertField); maker.put(slot); maker.put(key); }
218 match_suffix[maker]
219 ;
220
221
222 //
223 // Info specifications place conditions on entries in the Info.plist
224 //
225 infospec[Maker &maker] { string key; }
226 : "info" key=bracketKey
227 { maker.put(opInfoKeyField); maker.put(key); }
228 match_suffix[maker]
229 ;
230
231 match_suffix[Maker &maker]
232 : empty
233 { maker.put(matchExists); }
234 | EQL { string value; } value=datavalue
235 { maker.put(matchEqual); maker.put(value); }
236 | SUBS { string value; } value=datavalue
237 { maker.put(matchContains); maker.put(value); }
238 ;
239
240 bracketKey returns [string key]
241 : LBRACK key=stringvalue RBRACK
242 ;
243
244 //
245 // A certSlot identifiers one certificate from the certificate chain
246 //
247 certSlot returns [int slot]
248 : s:INTEGER // counting from the anchor up
249 { slot = atol(s->getText().c_str()); }
250 | NEG ss:INTEGER // counting from the leaf down
251 { slot = -atol(ss->getText().c_str()); }
252 | "leaf" // the leaf ( == -1)
253 { slot = Requirement::leafCert; }
254 | "root" // the root ( == 0)
255 { slot = Requirement::anchorCert; }
256 ;
257
258 certSlotAnchor returns [int slot]
259 : slot=certSlot
260 | empty // defaults to anchor ( == 0)
261 { slot = Requirement::anchorCert; }
262 ;
263
264 // an arbitrary digest value
265 hash[SHA1::Digest digest]
266 : hash:HASHCONSTANT
267 { hashString(hash->getText(), digest); }
268 ;
269
270 // various forms to specify a certificate hash
271 certificateDigest[SHA1::Digest digest]
272 : hash[digest]
273 | { string path; } path=pathstring
274 { if (CFRef<CFDataRef> certData = cfLoadFile(path))
275 hashOfCertificate(CFDataGetBytePtr(certData), CFDataGetLength(certData), digest);
276 else
277 throw antlr::SemanticException(path + ": not found");
278 }
279 ;
280
281 // generic data - can be simple string, quoted string, or 0x-style hex
282 datavalue returns [string result]
283 : result=stringvalue
284 | hex:HEXCONSTANT { result = hexString(hex->getText()); }
285 ;
286
287 // strings can always be quoted, but DOTKEYs don't need to be
288 stringvalue returns [string result]
289 : dk:DOTKEY { result = dk->getText(); }
290 | s:STRING { result = s->getText(); }
291 ;
292
293 // pathstrings are like strings, but PATHNAMEs don't need to be quoted either
294 pathstring returns [string result]
295 : dk:DOTKEY { result = dk->getText(); }
296 | s:STRING { result = s->getText(); }
297 | pn:PATHNAME { result = pn->getText(); }
298 ;
299
300 // unique identifier value
301 identifierString returns [string result]
302 : dk:DOTKEY { result = dk->getText(); }
303 | s:STRING { result = s->getText(); }
304 ;
305
306 // syntactic cavity generators
307 fluff
308 : SEMI
309 ;
310
311 eql
312 : EQL
313 | empty
314 ;
315
316 empty : ;
317
318
319 //
320 // The lexer for the Requirement language.
321 // Really straightforward and conventional.
322 // A subset of strings don't need to be quoted (DOTKEYs), though the disassembler
323 // will always quote them anyway.
324 // There's a syntax H"abcd" to denote hash values (in hex).
325 //
326 class RequirementLexer extends Lexer;
327
328 options {
329 k=2;
330 testLiterals=false;
331 }
332
333 protected
334 IDENT options { testLiterals=true; }
335 : ( 'A' .. 'Z' | 'a' .. 'z' ) ( 'A' .. 'Z' | 'a' .. 'z' | '0' .. '9' )*
336 ;
337
338 DOTKEY options { testLiterals=true; }
339 : IDENT ( "." IDENT )*
340 ;
341
342 PATHNAME
343 : "/" IDENT ( "/" IDENT )+
344 ;
345
346 HASHCONSTANT
347 : 'H'! '"'! ( HEX )+ '"'!
348 ;
349
350 HEXCONSTANT
351 : '0'! 'x'! ( HEX )+
352 ;
353
354 STRING
355 : '"'! ( ( '\\'! '"' ) | ( ~ ( '"' | '\\' ) ) )* '"'!
356 ;
357
358 INTEGER
359 : ( '0' .. '9' ) +
360 ;
361
362 protected
363 HEX : '0' .. '9' | 'a' .. 'f' | 'A' .. 'F' ;
364
365 // operator tokens
366 ARROW : "=>" ;
367 SEMI : ';' ;
368 LPAREN : '(' ;
369 RPAREN : ')' ;
370 LBRACK : '[' ;
371 RBRACK : ']' ;
372 COMMA : ',' ;
373 EQL : '=' ;
374 SUBS : '~' ;
375 NEG : '-' ;
376 NOT : '!' ;
377
378
379 //
380 // White spaces
381 //
382 WS : ( ' ' | '\n' { newline(); } | '\t' )+
383 { $setType(antlr::Token::SKIP); }
384 ;
385
386 SHELLCOMMENT
387 : '#' ( ~ '\n' )*
388 { $setType(antlr::Token::SKIP); }
389 ;
390
391 C_COMMENT
392 : "/*" ( (~'*')|('*'(~'/')) )* "*/"
393 { $setType(antlr::Token::SKIP); }
394 ;
395
396 CPP_COMMENT
397 : "//" ( ~ '\n' )*
398 { $setType(antlr::Token::SKIP); }
399 ;