1/* 2 * Copyright (c) 2006-2007 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#include <security_cdsa_utilities/cssmdata.h> // OID encoder 29#include <cstdarg> 30 31namespace Security { 32namespace CodeSigning { 33 34using namespace UnixPlusPlus; 35 36 37// 38// Table of reserved words (keywords), generated by ANTLR 39// 40static const char * const keywords[] = { 41#include "RequirementKeywords.h" 42 "", 43 NULL 44}; 45 46 47// 48// Printf to established output channel 49// 50void Dumper::print(const char *format, ...) 51{ 52 char buffer[256]; 53 va_list args; 54 va_start(args, format); 55 vsnprintf(buffer, sizeof(buffer), format, args); 56 va_end(args); 57 mOutput += buffer; 58} 59 60 61// 62// Dump the underlying Requirement program 63// 64void Dumper::dump() 65{ 66 this->expr(); 67 68 // remove any initial space 69 if (mOutput[0] == ' ') 70 mOutput = mOutput.substr(1); 71} 72 73 74// 75// Dump an entire Requirements set, using temporary Dumper objects. 76// 77// This detects single Requirement inputs and dumps them successfully (using 78// single-requirement syntax). No indication of error is returned in this case. 79// 80string Dumper::dump(const Requirements *reqs, bool debug /* = false */) 81{ 82 if (!reqs) { 83 return "# no requirement(s)"; 84 } else if (reqs->magic() == Requirement::typeMagic) { // single requirement 85 return dump((const Requirement *)reqs) + "\n"; 86 } else { 87 string result; 88 for (unsigned n = 0; n < reqs->count(); n++) { 89 char prefix[200]; 90 if (reqs->type(n) < kSecRequirementTypeCount) 91 snprintf(prefix, sizeof(prefix), 92 "%s => ", Requirement::typeNames[reqs->type(n)]); 93 else 94 snprintf(prefix, sizeof(prefix), "/*unknown type*/ %d => ", reqs->type(n)); 95 Dumper dumper(reqs->blob<Requirement>(n), debug); 96 dumper.expr(); 97 result += prefix + dumper.value() + "\n"; 98 } 99 return result; 100 } 101} 102 103string Dumper::dump(const Requirement *req, bool debug /* = false */) 104{ 105 Dumper dumper(req, debug); 106 try { 107 dumper.dump(); 108 return dumper; 109 } catch (const CommonError &err) { 110 if (debug) { 111 char errstr[80]; 112 snprintf(errstr, sizeof(errstr), " !! error %ld !!", (unsigned long)err.osStatus()); 113 return dumper.value() + errstr; 114 } 115 throw; 116 } 117} 118 119string Dumper::dump(const BlobCore *req, bool debug /* = false */) 120{ 121 switch (req->magic()) { 122 case Requirement::typeMagic: 123 return dump(static_cast<const Requirement *>(req), debug); 124 break; 125 case Requirements::typeMagic: 126 return dump(static_cast<const Requirements *>(req), debug); 127 break; 128 default: 129 return "invalid data type"; 130 } 131} 132 133 134// 135// Element dumpers. Output accumulates in internal buffer. 136// 137void 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 opCertGeneric: 203 print("certificate"); certSlot(); print("["); 204 { 205 const unsigned char *data; size_t length; 206 getData(data, length); 207 print("field.%s", CssmOid((unsigned char *)data, length).toOid().c_str()); 208 } 209 print("]"); match(); 210 break; 211 case opCertPolicy: 212 print("certificate"); certSlot(); print("["); 213 { 214 const unsigned char *data; size_t length; 215 getData(data, length); 216 print("policy.%s", CssmOid((unsigned char *)data, length).toOid().c_str()); 217 } 218 print("]"); match(); 219 break; 220 case opTrustedCert: 221 print("certificate"); certSlot(); print("trusted"); 222 break; 223 case opTrustedCerts: 224 print("anchor trusted"); 225 break; 226 case opNamedAnchor: 227 print("anchor apple "); data(); 228 break; 229 case opNamedCode: 230 print("("); data(); print(")"); 231 break; 232 default: 233 if (op & opGenericFalse) { 234 print(" false /* opcode %d */", op & ~opFlagMask); 235 break; 236 } else if (op & opGenericSkip) { 237 print(" /* opcode %d */", op & ~opFlagMask); 238 break; 239 } else { 240 print("OPCODE %d NOT UNDERSTOOD (ending print)", op); 241 return; 242 } 243 } 244} 245 246void Dumper::certSlot() 247{ 248 switch (int32_t slot = get<int32_t>()) { 249 case Requirement::anchorCert: 250 print(" root"); 251 break; 252 case Requirement::leafCert: 253 print(" leaf"); 254 break; 255 default: 256 print(" %d", slot); 257 break; 258 } 259} 260 261void Dumper::match() 262{ 263 switch (MatchOperation op = MatchOperation(get<uint32_t>())) { 264 case matchExists: 265 print(" /* exists */"); 266 break; 267 case matchEqual: 268 print(" = "); data(); 269 break; 270 case matchContains: 271 print(" ~ "); data(); 272 break; 273 case matchBeginsWith: 274 print(" = "); data(); print("*"); 275 break; 276 case matchEndsWith: 277 print(" = *"); data(); 278 break; 279 case matchLessThan: 280 print(" < "); data(); 281 break; 282 case matchGreaterEqual: 283 print(" >= "); data(); 284 break; 285 case matchLessEqual: 286 print(" <= "); data(); 287 break; 288 case matchGreaterThan: 289 print(" > "); data(); 290 break; 291 default: 292 print("MATCH OPCODE %d NOT UNDERSTOOD", op); 293 break; 294 } 295} 296 297void Dumper::hashData() 298{ 299 print("H\""); 300 const unsigned char *data; size_t length; 301 getData(data, length); 302 printBytes(data, length); 303 print("\""); 304} 305 306void Dumper::data(PrintMode bestMode /* = isSimple */, bool dotOkay /* = false */) 307{ 308 const unsigned char *data; size_t length; 309 getData(data, length); 310 for (unsigned n = 0; n < length; n++) 311 if ((isalnum(data[n]) || (data[n] == '.' && dotOkay))) { // simple 312 if (n == 0 && isdigit(data[n])) // unquoted idents can't start with a digit 313 bestMode = isPrintable; 314 } else if (isgraph(data[n]) || isspace(data[n])) { 315 if (bestMode == isSimple) 316 bestMode = isPrintable; 317 } else { 318 bestMode = isBinary; 319 break; // pessimal 320 } 321 322 if (bestMode == isSimple) { 323 string s((const char *)data, length); 324 for (const char * const * k = keywords; *k; k++) 325 if (s == *k) { 326 bestMode = isPrintable; // reserved word; need quotes 327 break; 328 } 329 } 330 331 switch (bestMode) { 332 case isSimple: 333 print("%.*s", length, data); 334 break; 335 case isPrintable: 336 print("\"%.*s\"", length, data); 337 break; 338 default: 339 print("0x"); 340 printBytes(data, length); 341 break; 342 } 343} 344 345void Dumper::printBytes(const Byte *data, size_t length) 346{ 347 for (unsigned n = 0; n < length; n++) 348 print("%02.2x", data[n]); 349} 350 351 352} // CodeSigning 353} // Security 354