libsecurity_codesigning-55004.tar.gz
[apple/libsecurity_codesigning.git] / 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                 unsigned 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         |       stype:INTEGER
198                         { type = atol(stype->getText().c_str()); }
199         ;
200
201
202 //
203 // A single Requirement (untyped)
204 //
205 requirement returns [Requirement *result = NULL]
206         :       result = requirementElement
207                 EOF
208         ;
209
210 requirementElement returns [Requirement *result = NULL]
211                 { Requirement::Maker maker; }
212         :       expr[maker]
213                 { result = maker(); }
214                 ( fluff )*
215         ;
216
217
218 //
219 // Classic recursive expressions
220 // 
221 expr[Maker &maker]
222                 { Maker::Label label(maker); }
223         :       term[maker] ( "or" { maker.insert<ExprOp>(label) = opOr; } term[maker] )*
224         ;
225
226 term[Maker &maker]
227                 { Maker::Label label(maker); }
228         :       primary[maker] ( "and" { maker.insert<ExprOp>(label) = opAnd; } primary[maker] )*
229         ;
230
231 primary[Maker &maker]
232         :       LPAREN expr[maker] RPAREN
233         |       NOT { maker.put(opNot); } primary[maker]
234         |       ( "always" | "true" )
235                         { maker.put(opTrue); }
236         |       ( "never" | "false" )
237                         { maker.put(opFalse); }
238         |       certspec[maker]
239         |       infospec[maker]
240         |       entitlementspec[maker]
241         |       "identifier" { string code; } eql code=identifierString
242                         { maker.ident(code); }
243         |       "cdhash" { SHA1::Digest digest; } eql hash[digest]
244                         { maker.cdhash(digest); }
245         |       LPAREN { string name; } name=identifierString RPAREN
246                         { maker.put(opNamedCode); maker.put(name); }
247         ;
248
249
250 //
251 // Certificate specifications restrict certificates in the signing chain
252 //
253 certspec[Maker &maker]
254         :       "anchor" "apple" appleanchor[maker]
255         |       "anchor" "generic" "apple"              // alternate form
256                         { maker.put(opAppleGenericAnchor); }
257         |       ( "certificate" | "cert" | "anchor" ) "trusted"
258                         { maker.trustedAnchor(); }
259         |       ( "certificate" | "cert" ) { int32_t slot; } slot=certSlot
260                 ( certslotspec[maker, slot] | "trusted" { maker.trustedAnchor(slot); } )
261         |       "anchor" certslotspec[maker, Requirement::anchorCert]
262         ;
263
264 appleanchor[Maker &maker]
265         :       empty
266                         { maker.put(opAppleAnchor); }
267         |       "generic"
268                         { maker.put(opAppleGenericAnchor); }
269 |       |       { string name; } name=identifierString
270                         { maker.put(opNamedAnchor); maker.put(name); }
271         ;
272
273 certslotspec[Maker &maker, int32_t slot]        { string key; }
274         :       eql { SHA1::Digest digest; } certificateDigest[digest]
275             { maker.anchor(slot, digest); }
276         |       key=bracketKey
277                         { certMatchOperation(maker, slot, key); }
278                 match_suffix[maker]
279         ;
280
281
282 //
283 // Info specifications place conditions on entries in the Info.plist
284 //
285 infospec[Maker &maker]          { string key; }
286         :       "info" key=bracketKey
287                         { maker.put(opInfoKeyField); maker.put(key); }
288                 match_suffix[maker]
289         ;
290
291
292 //
293 // Entitlement specifications place conditions on embedded entitlement entries
294 //
295 entitlementspec[Maker &maker]   { string key; }
296         :       "entitlement" key=bracketKey
297                         { maker.put(opEntitlementField); maker.put(key); }
298                 match_suffix[maker]
299         ;
300
301
302 //
303 // Common match operations, written as a syntactic suffix (the operand precedes this)
304 //
305 match_suffix[Maker &maker]
306         :       empty ( "exists" ) ?
307                         { maker.put(matchExists); }
308         |       ( EQL | EQQL )
309                         { MatchOperation mop = matchEqual; string value; }
310                 ( STAR { mop = matchEndsWith; } ) ?
311                 value=datavalue
312                 ( STAR { mop = (mop == matchEndsWith) ? matchContains : matchBeginsWith; } ) ?
313                         { maker.put(mop); maker.put(value); }
314         |       SUBS { string value; } value=datavalue
315                         { maker.put(matchContains); maker.put(value); }
316         |       LESS { string value; } value=datavalue
317                         { maker.put(matchLessThan); maker.put(value); }
318         |       GT { string value; } value=datavalue
319                         { maker.put(matchGreaterThan); maker.put(value); }
320         |       LE { string value; } value=datavalue
321                         { maker.put(matchLessEqual); maker.put(value); }
322         |       GE { string value; } value=datavalue
323                         { maker.put(matchGreaterEqual); maker.put(value); }
324         ;
325
326 bracketKey returns [string key]
327         :       LBRACK key=stringvalue RBRACK
328         ;
329
330 //
331 // A certSlot identifies one certificate from the certificate chain
332 //
333 certSlot returns [int32_t slot = 0]
334         :       s:INTEGER               // counting from the anchor up
335                         { slot = atol(s->getText().c_str()); }
336         |       NEG ss:INTEGER  // counting from the leaf down
337                         { slot = -atol(ss->getText().c_str()); }
338         |       "leaf"                  // the leaf ( == -1)
339                         { slot = Requirement::leafCert; }
340         |       "root"                  // the root ( == 0)
341                         { slot = Requirement::anchorCert; }
342         ;
343
344 // an arbitrary digest value
345 hash[SHA1::Digest digest]
346         :       hash:HASHCONSTANT
347                         { hashString(hash->getText(), digest); }
348         ;
349
350 // various forms to specify a certificate hash
351 certificateDigest[SHA1::Digest digest]
352         :       hash[digest]
353         |       { string path; } path=pathstring
354                         { if (CFRef<CFDataRef> certData = cfLoadFile(path))
355                                 hashOfCertificate(CFDataGetBytePtr(certData), CFDataGetLength(certData), digest);
356                           else
357                                 throw antlr::SemanticException(path + ": not found");
358                         }
359         ;
360
361 // generic data - can be simple string, quoted string, or 0x-style hex
362 datavalue returns [string result]
363         :       result=stringvalue
364         |       hex:HEXCONSTANT { result = hexString(hex->getText()); }
365         ;
366
367 // strings can always be quoted, but DOTKEYs don't need to be
368 stringvalue returns [string result]
369         :       dk:DOTKEY       { result = dk->getText(); }
370         |       s:STRING        { result = s->getText(); }
371         ;
372
373 // pathstrings are like strings, but PATHNAMEs don't need to be quoted either
374 pathstring returns [string result]
375         :       dk:DOTKEY       { result = dk->getText(); }
376         |       s:STRING        { result = s->getText(); }
377         |       pn:PATHNAME     { result = pn->getText(); }
378         ;
379
380 // unique identifier value
381 identifierString returns [string result]
382         :       dk:DOTKEY       { result = dk->getText(); }
383         |       s:STRING        { result = s->getText(); }
384         ;
385
386 // syntactic cavity generators
387 fluff
388         :       SEMI
389         ;
390
391 eql
392         :       EQL
393         |       EQQL
394         |       empty
395         ;
396
397 empty : ;
398
399
400 //
401 // The lexer for the Requirement language.
402 // Really straightforward and conventional.
403 // A subset of strings don't need to be quoted (DOTKEYs). Neither do some simple
404 //  pathnames starting with "/".
405 // Hash values have a special syntax H"abcd" (abcd in straight hex).
406 // Hex constants of the form 0xabcd can have any length; they are carried
407 // around as strings (which are in turn stored as data in the language binary).
408 //
409 class RequirementLexer extends Lexer;
410
411 options {
412         k=2;
413         testLiterals=false;
414 }
415
416 protected
417 IDENT options { testLiterals=true; }
418         :       ( 'A' .. 'Z' | 'a' .. 'z' ) ( 'A' .. 'Z' | 'a' .. 'z' | '0' .. '9' )*
419         ;
420
421 DOTKEY options { testLiterals=true; }
422         :       IDENT ( "." ( IDENT | INTEGER ) )*
423         ;
424
425 PATHNAME
426         :       "/" IDENT ( "/" IDENT )+
427         ;
428
429 HASHCONSTANT
430         :       'H'! '"'! ( HEX )+ '"'!
431         ;
432
433 HEXCONSTANT
434         :       '0'! 'x'! ( HEX )+
435         ;
436
437 STRING
438         :       '"'! ( ( '\\'! '"' ) | ( ~ ( '"' | '\\' ) ) )* '"'!
439         ;
440
441 INTEGER
442         :       ( '0' .. '9' ) +
443         ;
444
445 protected
446 HEX     :       '0' .. '9' | 'a' .. 'f' | 'A' .. 'F' ;
447
448 // operator tokens
449 ARROW   : "=>" ;
450 SEMI    : ';' ;
451 LPAREN  : '(' ;
452 RPAREN  : ')' ;
453 LBRACK  : '[' ;
454 RBRACK  : ']' ;
455 LESS    : '<' ;
456 GT              : '>' ;
457 LE              : "<=" ;
458 GE              : ">=" ;
459 COMMA   : ',' ;
460 EQL             : '=' ;
461 EQQL    : "==" ;
462 SUBS    : '~' ;
463 NEG             : '-' ;
464 NOT             : '!' ;
465 STAR    : '*' ;
466
467
468 //
469 // White spaces
470 //
471 WS      :       ( ' ' | '\n' { newline(); } | '\t' )+
472         { $setType(antlr::Token::SKIP); }
473         ;
474
475 SHELLCOMMENT
476         :       '#' ( ~ '\n' )*
477         { $setType(antlr::Token::SKIP); }
478         ;
479
480 C_COMMENT
481         :       "/*" ( (~'*')|('*'(~'/')) )* "*/"
482         { $setType(antlr::Token::SKIP); }
483         ;
484
485 CPP_COMMENT
486         :       "//" ( ~ '\n' )*
487         { $setType(antlr::Token::SKIP); }
488         ;