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