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 ;