reqdumper.cpp
1 /* 2 * Copyright (c) 2006-2007,2011-2013 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 // reqdumper - Requirement un-parsing (disassembly) 26 // 27 #include "reqdumper.h" 28 #if TARGET_OS_OSX 29 #include <security_cdsa_utilities/cssmdata.h> // OID encoder 30 #endif 31 #include <cstdarg> 32 33 namespace Security { 34 namespace CodeSigning { 35 36 using namespace UnixPlusPlus; 37 38 39 // 40 // Table of reserved words (keywords), generated by ANTLR 41 // 42 static const char * const keywords[] = { 43 #include "RequirementKeywords.h" 44 "", 45 NULL 46 }; 47 48 49 // 50 // Printf to established output channel 51 // 52 void Dumper::print(const char *format, ...) 53 { 54 char buffer[256]; 55 va_list args; 56 va_start(args, format); 57 vsnprintf(buffer, sizeof(buffer), format, args); 58 va_end(args); 59 mOutput += buffer; 60 } 61 62 63 // 64 // Dump the underlying Requirement program 65 // 66 void Dumper::dump() 67 { 68 this->expr(); 69 70 // remove any initial space 71 if (mOutput[0] == ' ') 72 mOutput = mOutput.substr(1); 73 } 74 75 76 // 77 // Dump an entire Requirements set, using temporary Dumper objects. 78 // 79 // This detects single Requirement inputs and dumps them successfully (using 80 // single-requirement syntax). No indication of error is returned in this case. 81 // 82 string Dumper::dump(const Requirements *reqs, bool debug /* = false */) 83 { 84 if (!reqs) { 85 return "# no requirement(s)"; 86 } else if (reqs->magic() == Requirement::typeMagic) { // single requirement 87 return dump((const Requirement *)reqs) + "\n"; 88 } else { 89 string result; 90 for (unsigned n = 0; n < reqs->count(); n++) { 91 char prefix[200]; 92 if (reqs->type(n) < kSecRequirementTypeCount) 93 snprintf(prefix, sizeof(prefix), 94 "%s => ", Requirement::typeNames[reqs->type(n)]); 95 else 96 snprintf(prefix, sizeof(prefix), "/*unknown type*/ %d => ", reqs->type(n)); 97 Dumper dumper(reqs->blob<Requirement>(n), debug); 98 dumper.expr(); 99 result += prefix + dumper.value() + "\n"; 100 } 101 return result; 102 } 103 } 104 105 string Dumper::dump(const Requirement *req, bool debug /* = false */) 106 { 107 Dumper dumper(req, debug); 108 try { 109 dumper.dump(); 110 return dumper; 111 } catch (const CommonError &err) { 112 if (debug) { 113 char errstr[80]; 114 snprintf(errstr, sizeof(errstr), " !! error %ld !!", (unsigned long)err.osStatus()); 115 return dumper.value() + errstr; 116 } 117 throw; 118 } 119 } 120 121 string Dumper::dump(const BlobCore *req, bool debug /* = false */) 122 { 123 switch (req->magic()) { 124 case Requirement::typeMagic: 125 return dump(static_cast<const Requirement *>(req), debug); 126 case Requirements::typeMagic: 127 return dump(static_cast<const Requirements *>(req), debug); 128 default: 129 return "invalid data type"; 130 } 131 } 132 133 134 // 135 // Element dumpers. Output accumulates in internal buffer. 136 // 137 void Dumper::expr(SyntaxLevel level) 138 { 139 if (mDebug) 140 print("/*@0x%x*/", pc()); 141 ExprOp op = ExprOp(get<uint32_t>()); 142 switch (op & ~opFlagMask) { 143 case opFalse: 144 print("never"); 145 break; 146 case opTrue: 147 print("always"); 148 break; 149 case opIdent: 150 print("identifier "); 151 data(); 152 break; 153 case opAppleAnchor: 154 print("anchor apple"); 155 break; 156 case opAppleGenericAnchor: 157 print("anchor apple generic"); 158 break; 159 case opAnchorHash: 160 print("certificate"); certSlot(); print(" = "); hashData(); 161 break; 162 case opInfoKeyValue: 163 if (mDebug) 164 print("/*legacy*/"); 165 print("info["); dotString(); print("] = "); data(); 166 break; 167 case opAnd: 168 if (level < slAnd) 169 print("("); 170 expr(slAnd); 171 print(" and "); 172 expr(slAnd); 173 if (level < slAnd) 174 print(")"); 175 break; 176 case opOr: 177 if (level < slOr) 178 print("("); 179 expr(slOr); 180 print(" or "); 181 expr(slOr); 182 if (level < slOr) 183 print(")"); 184 break; 185 case opNot: 186 print("! "); 187 expr(slPrimary); 188 break; 189 case opCDHash: 190 print("cdhash "); 191 hashData(); 192 break; 193 case opInfoKeyField: 194 print("info["); dotString(); print("]"); match(); 195 break; 196 case opEntitlementField: 197 print("entitlement["); dotString(); print("]"); match(); 198 break; 199 case opCertField: 200 print("certificate"); certSlot(); print("["); dotString(); print("]"); match(); 201 break; 202 case opCertFieldDate: 203 print("certificate"); certSlot(); print("["); 204 #if TARGET_OS_OSX 205 { 206 const unsigned char *data; size_t length; 207 getData(data, length); 208 print("timestamp.%s", CssmOid((unsigned char *)data, length).toOid().c_str()); 209 } 210 #endif 211 case opCertGeneric: 212 print("certificate"); certSlot(); print("["); 213 #if TARGET_OS_OSX 214 { 215 const unsigned char *data; size_t length; 216 getData(data, length); 217 print("field.%s", CssmOid((unsigned char *)data, length).toOid().c_str()); 218 } 219 #endif 220 print("]"); match(); 221 break; 222 case opCertPolicy: 223 print("certificate"); certSlot(); print("["); 224 #if TARGET_OS_OSX 225 { 226 const unsigned char *data; size_t length; 227 getData(data, length); 228 print("policy.%s", CssmOid((unsigned char *)data, length).toOid().c_str()); 229 } 230 #endif 231 print("]"); match(); 232 break; 233 case opTrustedCert: 234 print("certificate"); certSlot(); print("trusted"); 235 break; 236 case opTrustedCerts: 237 print("anchor trusted"); 238 break; 239 case opNamedAnchor: 240 print("anchor apple "); data(); 241 break; 242 case opNamedCode: 243 print("("); data(); print(")"); 244 break; 245 case opPlatform: 246 print("platform = %d", get<int32_t>()); 247 break; 248 case opNotarized: 249 print("notarized"); 250 break; 251 case opLegacyDevID: 252 print("legacy"); 253 break; 254 default: 255 if (op & opGenericFalse) { 256 print(" false /* opcode %d */", op & ~opFlagMask); 257 break; 258 } else if (op & opGenericSkip) { 259 print(" /* opcode %d */", op & ~opFlagMask); 260 break; 261 } else { 262 print("OPCODE %d NOT UNDERSTOOD (ending print)", op); 263 return; 264 } 265 } 266 } 267 268 void Dumper::certSlot() 269 { 270 switch (int32_t slot = get<int32_t>()) { 271 case Requirement::anchorCert: 272 print(" root"); 273 break; 274 case Requirement::leafCert: 275 print(" leaf"); 276 break; 277 default: 278 print(" %d", slot); 279 break; 280 } 281 } 282 283 void Dumper::match() 284 { 285 switch (MatchOperation op = MatchOperation(get<uint32_t>())) { 286 case matchExists: 287 print(" /* exists */"); 288 break; 289 case matchAbsent: 290 print(" absent "); 291 break; 292 case matchEqual: 293 print(" = "); data(); 294 break; 295 case matchContains: 296 print(" ~ "); data(); 297 break; 298 case matchBeginsWith: 299 print(" = "); data(); print("*"); 300 break; 301 case matchEndsWith: 302 print(" = *"); data(); 303 break; 304 case matchLessThan: 305 print(" < "); data(); 306 break; 307 case matchGreaterEqual: 308 print(" >= "); data(); 309 break; 310 case matchLessEqual: 311 print(" <= "); data(); 312 break; 313 case matchGreaterThan: 314 print(" > "); data(); 315 break; 316 case matchOn: 317 print(" = "); timestamp(); 318 break; 319 case matchBefore: 320 print(" < "); timestamp(); 321 break; 322 case matchAfter: 323 print(" > "); timestamp(); 324 break; 325 case matchOnOrBefore: 326 print(" <= "); timestamp(); 327 break; 328 case matchOnOrAfter: 329 print(" >= "); timestamp(); 330 break; 331 default: 332 print("MATCH OPCODE %d NOT UNDERSTOOD", op); 333 break; 334 } 335 } 336 337 void Dumper::hashData() 338 { 339 print("H\""); 340 const unsigned char *data; size_t length; 341 getData(data, length); 342 printBytes(data, length); 343 print("\""); 344 } 345 346 void Dumper::data(PrintMode bestMode /* = isSimple */, bool dotOkay /* = false */) 347 { 348 const unsigned char *data; size_t length; 349 getData(data, length); 350 for (unsigned n = 0; n < length; n++) 351 if ((isalnum(data[n]) || (data[n] == '.' && dotOkay))) { // simple 352 if (n == 0 && isdigit(data[n])) // unquoted idents can't start with a digit 353 bestMode = isPrintable; 354 } else if (isgraph(data[n]) || isspace(data[n])) { 355 if (bestMode == isSimple) 356 bestMode = isPrintable; 357 } else { 358 bestMode = isBinary; 359 break; // pessimal 360 } 361 362 if (bestMode == isSimple) { 363 string s((const char *)data, length); 364 for (const char * const * k = keywords; *k; k++) 365 if (s == *k) { 366 bestMode = isPrintable; // reserved word; need quotes 367 break; 368 } 369 } 370 371 switch (bestMode) { 372 case isSimple: 373 print("%.*s", (int)length, data); 374 break; 375 case isPrintable: 376 print("\""); 377 for (unsigned n = 0; n < length; n++) 378 switch (data[n]) { 379 case '\\': 380 case '"': 381 print("\\%c", data[n]); 382 break; 383 default: 384 print("%c", data[n]); 385 break; 386 } 387 print("\""); 388 break; 389 default: 390 print("0x"); 391 printBytes(data, length); 392 break; 393 } 394 } 395 396 void Dumper::timestamp() 397 { 398 CFAbsoluteTime at = static_cast<CFAbsoluteTime>(get<int64_t>()); 399 CFRef<CFDateRef> date = CFDateCreate(NULL, at); 400 401 CFRef<CFStringRef> str = CFCopyDescription(date); 402 403 print("<%s>", cfString(str).c_str()); 404 } 405 406 void Dumper::printBytes(const Byte *data, size_t length) 407 { 408 for (unsigned n = 0; n < length; n++) 409 print("%02.2x", data[n]); 410 } 411 412 413 } // CodeSigning 414 } // Security