]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_codesigning/requirements.grammar
Security-58286.251.4.tar.gz
[apple/security.git] / OSX / libsecurity_codesigning / requirements.grammar
1 /*
2 * Copyright (c) 2006-2008 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 //
33 // The semantic data compiled is a malloc'ed BlobCore * - a Requirement
34 // object or a SuperBlob containing multiple Requirements.
35 //
36 // Errors are indicated to the caller by accumulating error message strings
37 // in the errors member variable. Any non-empty error value indicates failure.
38 // Presence of semantic data is not a reliable indication of success.
39 //
40 header "post_include_hpp" {
41 #include "requirement.h"
42 using namespace CodeSigning;
43 typedef Requirement::Maker Maker;
44 }
45
46 header "post_include_cpp" {
47 #include "requirement.h"
48 #include "reqmaker.h"
49 #include "csutilities.h"
50 #include <security_utilities/cfutilities.h>
51 #include <security_utilities/hashing.h>
52 #include <security_cdsa_utilities/cssmdata.h> // OID coding
53 using namespace CodeSigning;
54 typedef Requirement::Maker Maker;
55 }
56
57 options {
58 language="Cpp";
59 namespace="Security_CodeSigning";
60 namespaceStd="std";
61 namespaceAntlr="antlr";
62 genHashLines=false;
63 }
64
65
66 {
67 //
68 // Collect error messages.
69 // Note that the immediate caller takes the absence of collected error messages
70 // to indicate compilation success.
71 //
72 void RequirementParser::reportError(const antlr::RecognitionException &ex)
73 {
74 errors += ex.toString() + "\n";
75 }
76
77 void RequirementParser::reportError(const std::string &s)
78 {
79 errors += s + "\n";
80 }
81
82
83 //
84 // Parser helper functions
85 //
86 string RequirementParser::hexString(const string &s)
87 {
88 if (s.size() % 2)
89 throw antlr::SemanticException("odd number of digits");
90 const char *p = s.data();
91 string result;
92 for (unsigned n = 0; n < s.length(); n += 2) {
93 char c;
94 sscanf(p+n, "%2hhx", &c);
95 result.push_back(c);
96 }
97 return result;
98 }
99
100 void RequirementParser::hashString(const string &s, SHA1::Digest hash)
101 {
102 if (s.size() != 2 * SHA1::digestLength)
103 throw antlr::SemanticException("invalid hash length");
104 memcpy(hash, hexString(s).data(), SHA1::digestLength);
105 }
106
107 static const char *matchPrefix(const string &key, const char *prefix)
108 {
109 size_t pLength = strlen(prefix);
110 if (!key.compare(0, pLength, prefix, 0, pLength))
111 return key.c_str() + pLength;
112 else
113 return NULL;
114 }
115
116 void RequirementParser::certMatchOperation(Maker &maker, int32_t slot, string key)
117 {
118 if (matchPrefix(key, "subject.")) {
119 maker.put(opCertField);
120 maker.put(slot);
121 maker.put(key);
122 } else if (const char *oids = matchPrefix(key, "field.")) {
123 maker.put(opCertGeneric);
124 maker.put(slot);
125 CssmAutoData oid(Allocator::standard()); oid.fromOid(oids);
126 maker.putData(oid.data(), oid.length());
127 } else if (const char *oids = matchPrefix(key, "extension.")) {
128 maker.put(opCertGeneric);
129 maker.put(slot);
130 CssmAutoData oid(Allocator::standard()); oid.fromOid(oids);
131 maker.putData(oid.data(), oid.length());
132 } else if (const char *oids = matchPrefix(key, "policy.")) {
133 maker.put(opCertPolicy);
134 maker.put(slot);
135 CssmAutoData oid(Allocator::standard()); oid.fromOid(oids);
136 maker.putData(oid.data(), oid.length());
137 } else {
138 throw antlr::SemanticException(key + ": unrecognized certificate field");
139 }
140 }
141 }
142
143
144 class RequirementParser extends Parser;
145
146 options {
147 k=2;
148 }
149
150 {
151 public:
152 std::string errors;
153 void reportError(const antlr::RecognitionException &ex);
154 void reportError(const std::string &s);
155
156 private:
157 static string hexString(const string &s);
158 static void hashString(const string &s, SHA1::Digest hash);
159 void certMatchOperation(Maker &maker, int32_t slot, string key);
160 }
161
162
163 //
164 // Compound target; compiles single requirements or requirement sets
165 // and returns them as a BlobCore.
166 //
167 autosense returns [BlobCore *result = NULL]
168 : result=requirement
169 | result=requirementSet
170 ;
171
172
173 //
174 // A Requirements Set.
175 //
176 requirementSet returns [Requirements *result = NULL]
177 { Requirements::Maker maker; }
178 : ( { uint32_t t; Requirement *req; }
179 t=requirementType ARROW req=requirementElement
180 { maker.add(t, req); }
181 )+
182 { result = errors.empty() ? maker() : NULL; }
183 EOF
184 ;
185
186 requirementType returns [uint32_t type = kSecInvalidRequirementType]
187 : "guest"
188 { type = kSecGuestRequirementType; }
189 | "host"
190 { type = kSecHostRequirementType; }
191 | "designated"
192 { type = kSecDesignatedRequirementType; }
193 | "library"
194 { type = kSecLibraryRequirementType; }
195 | "plugin"
196 { type = kSecPluginRequirementType; }
197 | type=integer
198 ;
199
200
201 //
202 // A single Requirement (untyped)
203 //
204 requirement returns [Requirement *result = NULL]
205 : result = requirementElement
206 EOF
207 ;
208
209 requirementElement returns [Requirement *result = NULL]
210 { Requirement::Maker maker; }
211 : expr[maker]
212 { result = maker(); }
213 ( fluff )*
214 ;
215
216
217 //
218 // Classic recursive expressions
219 //
220 expr[Maker &maker]
221 { Maker::Label label(maker); }
222 : term[maker] ( "or" { maker.insert<ExprOp>(label) = opOr; } term[maker] )*
223 ;
224
225 term[Maker &maker]
226 { Maker::Label label(maker); }
227 : primary[maker] ( "and" { maker.insert<ExprOp>(label) = opAnd; } primary[maker] )*
228 ;
229
230 primary[Maker &maker]
231 : LPAREN expr[maker] RPAREN
232 | NOT { maker.put(opNot); } primary[maker]
233 | ( "always" | "true" )
234 { maker.put(opTrue); }
235 | ( "never" | "false" )
236 { maker.put(opFalse); }
237 | certspec[maker]
238 | infospec[maker]
239 | entitlementspec[maker]
240 | "identifier" { string code; } eql code=identifierString
241 { maker.ident(code); }
242 | "cdhash" { SHA1::Digest digest; } eql hash[digest]
243 { maker.cdhash(digest); }
244 | "platform" { int32_t ident; } eql ident=integer
245 { maker.platform(ident); }
246 | "notarized"
247 { maker.put(opNotarized); }
248 | LPAREN { string name; } name=identifierString RPAREN
249 { maker.put(opNamedCode); maker.put(name); }
250 ;
251
252
253 //
254 // Certificate specifications restrict certificates in the signing chain
255 //
256 certspec[Maker &maker]
257 : "anchor" "apple" appleanchor[maker]
258 | "anchor" "generic" "apple" // alternate form
259 { maker.put(opAppleGenericAnchor); }
260 | ( "certificate" | "cert" | "anchor" ) "trusted"
261 { maker.trustedAnchor(); }
262 | ( "certificate" | "cert" ) { int32_t slot; } slot=certSlot
263 ( certslotspec[maker, slot] | "trusted" { maker.trustedAnchor(slot); } )
264 | "anchor" certslotspec[maker, Requirement::anchorCert]
265 ;
266
267 appleanchor[Maker &maker]
268 : empty
269 { maker.put(opAppleAnchor); }
270 | "generic"
271 { maker.put(opAppleGenericAnchor); }
272 | { string name; } name=identifierString
273 { maker.put(opNamedAnchor); maker.put(name); }
274 ;
275
276 certslotspec[Maker &maker, int32_t slot] { string key; }
277 : eql { SHA1::Digest digest; } certificateDigest[digest]
278 { maker.anchor(slot, digest); }
279 | key=bracketKey
280 { certMatchOperation(maker, slot, key); }
281 match_suffix[maker]
282 ;
283
284
285 //
286 // Info specifications place conditions on entries in the Info.plist
287 //
288 infospec[Maker &maker] { string key; }
289 : "info" key=bracketKey
290 { maker.put(opInfoKeyField); maker.put(key); }
291 match_suffix[maker]
292 ;
293
294
295 //
296 // Entitlement specifications place conditions on embedded entitlement entries
297 //
298 entitlementspec[Maker &maker] { string key; }
299 : "entitlement" key=bracketKey
300 { maker.put(opEntitlementField); maker.put(key); }
301 match_suffix[maker]
302 ;
303
304
305 //
306 // Common match operations, written as a syntactic suffix (the operand precedes this)
307 //
308 match_suffix[Maker &maker]
309 : empty ( "exists" ) ?
310 { maker.put(matchExists); }
311 | ( EQL | EQQL )
312 { MatchOperation mop = matchEqual; string value; }
313 ( STAR { mop = matchEndsWith; } ) ?
314 value=datavalue
315 ( STAR { mop = (mop == matchEndsWith) ? matchContains : matchBeginsWith; } ) ?
316 { maker.put(mop); maker.put(value); }
317 | SUBS { string value; } value=datavalue
318 { maker.put(matchContains); maker.put(value); }
319 | LESS { string value; } value=datavalue
320 { maker.put(matchLessThan); maker.put(value); }
321 | GT { string value; } value=datavalue
322 { maker.put(matchGreaterThan); maker.put(value); }
323 | LE { string value; } value=datavalue
324 { maker.put(matchLessEqual); maker.put(value); }
325 | GE { string value; } value=datavalue
326 { maker.put(matchGreaterEqual); maker.put(value); }
327 ;
328
329 bracketKey returns [string key]
330 : LBRACK key=stringvalue RBRACK
331 ;
332
333 //
334 // A certSlot identifies one certificate from the certificate chain
335 //
336 certSlot returns [int32_t slot = 0]
337 : slot=integer // counting from the anchor up
338 | NEG slot=integer // counting from the leaf down
339 { slot = -slot; }
340 | "leaf" // the leaf ( == -1)
341 { slot = Requirement::leafCert; }
342 | "root" // the root ( == 0)
343 { slot = Requirement::anchorCert; }
344 ;
345
346 // an arbitrary digest value
347 hash[SHA1::Digest digest]
348 : hash:HASHCONSTANT
349 { hashString(hash->getText(), digest); }
350 ;
351
352 // various forms to specify a certificate hash
353 certificateDigest[SHA1::Digest digest]
354 : hash[digest]
355 | { string path; } path=pathstring
356 { if (CFRef<CFDataRef> certData = cfLoadFile(path))
357 hashOfCertificate(CFDataGetBytePtr(certData), CFDataGetLength(certData), digest);
358 else
359 throw antlr::SemanticException(path + ": not found");
360 }
361 ;
362
363 // generic data - can be simple string, quoted string, or 0x-style hex
364 datavalue returns [string result]
365 : result=stringvalue
366 | hex:HEXCONSTANT { result = hexString(hex->getText()); }
367 ;
368
369 // strings can always be quoted, but DOTKEYs don't need to be
370 stringvalue returns [string result]
371 : dk:DOTKEY { result = dk->getText(); }
372 | s:STRING { result = s->getText(); }
373 ;
374
375 // pathstrings are like strings, but PATHNAMEs don't need to be quoted either
376 pathstring returns [string result]
377 : dk:DOTKEY { result = dk->getText(); }
378 | s:STRING { result = s->getText(); }
379 | pn:PATHNAME { result = pn->getText(); }
380 ;
381
382 // unique identifier value
383 identifierString returns [string result]
384 : dk:DOTKEY { result = dk->getText(); }
385 | s:STRING { result = s->getText(); }
386 ;
387
388 // 32-bit integer
389 integer returns [int32_t result]
390 : s:INTEGER { result = int32_t(atol(s->getText().c_str())); }
391 ;
392
393 // syntactic cavity generators
394 fluff
395 : SEMI
396 ;
397
398 eql
399 : EQL
400 | EQQL
401 | empty
402 ;
403
404 empty : ;
405
406
407 //
408 // The lexer for the Requirement language.
409 // Really straightforward and conventional.
410 // A subset of strings don't need to be quoted (DOTKEYs). Neither do some simple
411 // pathnames starting with "/".
412 // Hash values have a special syntax H"abcd" (abcd in straight hex).
413 // Hex constants of the form 0xabcd can have any length; they are carried
414 // around as strings (which are in turn stored as data in the language binary).
415 //
416 class RequirementLexer extends Lexer;
417
418 options {
419 k=2;
420 testLiterals=false;
421
422 // Pass through valid UTF-8 (which excludes hex C0-C1 and F5-FF),
423 // but also exclude ASCII control characters below 0x20 (space).
424 // Byte ranges according to Unicode 11.0, paragraph 3.9 D92.
425 charVocabulary='\000'..'\277' | '\302'..'\364';
426 }
427
428 protected
429 IDENT options { testLiterals=true; }
430 : ( 'A' .. 'Z' | 'a' .. 'z' ) ( 'A' .. 'Z' | 'a' .. 'z' | '0' .. '9' )*
431 ;
432
433 DOTKEY options { testLiterals=true; }
434 : IDENT ( "." ( IDENT | INTEGER ) )*
435 ;
436
437 PATHNAME
438 : "/" IDENT ( "/" IDENT )+
439 ;
440
441 HASHCONSTANT
442 : 'H'! '"'! ( HEX )+ '"'!
443 ;
444
445 HEXCONSTANT
446 : '0'! 'x'! ( HEX )+
447 ;
448
449 STRING
450 : '"'! ( ( '\\'! '"' ) | ( ~ ( '"' | '\\' ) ) )* '"'!
451 ;
452
453 INTEGER
454 : ( '0' .. '9' ) +
455 ;
456
457 protected
458 HEX : '0' .. '9' | 'a' .. 'f' | 'A' .. 'F' ;
459
460 // operator tokens
461 ARROW : "=>" ;
462 SEMI : ';' ;
463 LPAREN : '(' ;
464 RPAREN : ')' ;
465 LBRACK : '[' ;
466 RBRACK : ']' ;
467 LESS : '<' ;
468 GT : '>' ;
469 LE : "<=" ;
470 GE : ">=" ;
471 COMMA : ',' ;
472 EQL : '=' ;
473 EQQL : "==" ;
474 SUBS : '~' ;
475 NEG : '-' ;
476 NOT : '!' ;
477 STAR : '*' ;
478
479
480 //
481 // White spaces
482 //
483 WS : ( ' ' | '\n' { newline(); } | '\t' )+
484 { $setType(antlr::Token::SKIP); }
485 ;
486
487 SHELLCOMMENT
488 : '#' ( ~ '\n' )*
489 { $setType(antlr::Token::SKIP); }
490 ;
491
492 C_COMMENT
493 : "/*" ( (~'*')|('*'(~'/')) )* "*/"
494 { $setType(antlr::Token::SKIP); }
495 ;
496
497 CPP_COMMENT
498 : "//" ( ~ '\n' )*
499 { $setType(antlr::Token::SKIP); }
500 ;