/ OSX / libsecurity_codesigning / requirements.grammar
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  	;