SecStaticCode.cpp
1 /* 2 * Copyright (c) 2006-2007,2011-2015 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 // SecStaticCode - API frame for SecStaticCode objects 26 // 27 #include "cs.h" 28 #include "StaticCode.h" 29 #include <security_utilities/cfmunge.h> 30 #include <security_utilities/logging.h> 31 #include <fcntl.h> 32 #include <dirent.h> 33 34 using namespace CodeSigning; 35 36 37 // 38 // CF-standard type code function 39 // 40 CFTypeID SecStaticCodeGetTypeID(void) 41 { 42 BEGIN_CSAPI 43 return gCFObjects().StaticCode.typeID; 44 END_CSAPI1(_kCFRuntimeNotATypeID) 45 } 46 47 48 // 49 // Create an StaticCode directly from disk path. 50 // 51 OSStatus SecStaticCodeCreateWithPath(CFURLRef path, SecCSFlags flags, SecStaticCodeRef *staticCodeRef) 52 { 53 BEGIN_CSAPI 54 55 checkFlags(flags, kSecCSForceOnlineNotarizationCheck); 56 CodeSigning::Required(staticCodeRef) = (new SecStaticCode(DiskRep::bestGuess(cfString(path).c_str()), flags))->handle(); 57 58 END_CSAPI 59 } 60 61 const CFStringRef kSecCodeAttributeArchitecture = CFSTR("architecture"); 62 const CFStringRef kSecCodeAttributeSubarchitecture =CFSTR("subarchitecture"); 63 const CFStringRef kSecCodeAttributeBundleVersion = CFSTR("bundleversion"); 64 const CFStringRef kSecCodeAttributeUniversalFileOffset = CFSTR("UniversalFileOffset"); 65 66 OSStatus SecStaticCodeCreateWithPathAndAttributes(CFURLRef path, SecCSFlags flags, CFDictionaryRef attributes, 67 SecStaticCodeRef *staticCodeRef) 68 { 69 BEGIN_CSAPI 70 71 checkFlags(flags, kSecCSForceOnlineNotarizationCheck); 72 DiskRep::Context ctx; 73 std::string version; // holds memory placed into ctx 74 if (attributes) { 75 std::string archName; 76 int archNumber, subarchNumber, offset; 77 if (cfscan(attributes, "{%O=%d}", kSecCodeAttributeUniversalFileOffset, &offset)) { 78 ctx.offset = offset; 79 } else if (cfscan(attributes, "{%O=%s}", kSecCodeAttributeArchitecture, &archName)) { 80 ctx.arch = Architecture(archName.c_str()); 81 } else if (cfscan(attributes, "{%O=%d,%O=%d}", 82 kSecCodeAttributeArchitecture, &archNumber, kSecCodeAttributeSubarchitecture, &subarchNumber)) 83 ctx.arch = Architecture(archNumber, subarchNumber); 84 else if (cfscan(attributes, "{%O=%d}", kSecCodeAttributeArchitecture, &archNumber)) 85 ctx.arch = Architecture(archNumber); 86 if (cfscan(attributes, "{%O=%s}", kSecCodeAttributeBundleVersion, &version)) 87 ctx.version = version.c_str(); 88 } 89 90 CodeSigning::Required(staticCodeRef) = (new SecStaticCode(DiskRep::bestGuess(cfString(path).c_str(), &ctx), flags))->handle(); 91 92 END_CSAPI 93 } 94 95 96 // 97 // Check static validity of a StaticCode 98 // 99 OSStatus SecStaticCodeCheckValidity(SecStaticCodeRef staticCodeRef, SecCSFlags flags, 100 SecRequirementRef requirementRef) 101 { 102 return SecStaticCodeCheckValidityWithErrors(staticCodeRef, flags, requirementRef, NULL); 103 } 104 105 OSStatus SecStaticCodeCheckValidityWithErrors(SecStaticCodeRef staticCodeRef, SecCSFlags flags, 106 SecRequirementRef requirementRef, CFErrorRef *errors) 107 { 108 BEGIN_CSAPI 109 110 checkFlags(flags, 111 kSecCSReportProgress 112 | kSecCSCheckAllArchitectures 113 | kSecCSDoNotValidateExecutable 114 | kSecCSDoNotValidateResources 115 | kSecCSConsiderExpiration 116 | kSecCSEnforceRevocationChecks 117 | kSecCSNoNetworkAccess 118 | kSecCSCheckNestedCode 119 | kSecCSStrictValidate 120 | kSecCSStrictValidateStructure 121 | kSecCSRestrictSidebandData 122 | kSecCSCheckGatekeeperArchitectures 123 | kSecCSRestrictSymlinks 124 | kSecCSRestrictToAppLike 125 | kSecCSUseSoftwareSigningCert 126 | kSecCSValidatePEH 127 | kSecCSSingleThreaded 128 | kSecCSApplyEmbeddedPolicy 129 | kSecCSSkipRootVolumeExceptions 130 | kSecCSSkipXattrFiles 131 | kSecCSAllowNetworkAccess 132 ); 133 134 if (errors) 135 flags |= kSecCSFullReport; // internal-use flag 136 137 #if !TARGET_OS_OSX 138 flags |= kSecCSApplyEmbeddedPolicy; 139 #endif 140 141 SecPointer<SecStaticCode> code = SecStaticCode::requiredStatic(staticCodeRef); 142 code->setValidationFlags(flags); 143 const SecRequirement *req = SecRequirement::optional(requirementRef); 144 DTRACK(CODESIGN_EVAL_STATIC, code, (char*)code->mainExecutablePath().c_str()); 145 code->staticValidate(flags, req); 146 147 // Everything checked out correctly but we need to make sure that when 148 // we validated the code directory, we trusted the signer. We defer this 149 // until now because the caller may still trust the signer via a 150 // provisioning profile so if we prematurely throw an error when validating 151 // the directory, we potentially skip resource validation even though the 152 // caller will go on to trust the signature 153 // <rdar://problem/6075501> Applications that are validated against a provisioning profile do not have their resources checked 154 if ((flags & kSecCSApplyEmbeddedPolicy) && code->trustedSigningCertChain() == false) { 155 return CSError::cfError(errors, errSecCSSignatureUntrusted); 156 } 157 158 159 END_CSAPI_ERRORS 160 } 161 162 OSStatus SecStaticCodeValidateResourceWithErrors(SecStaticCodeRef staticCodeRef, CFURLRef resourcePath, SecCSFlags flags, CFErrorRef *errors) 163 { 164 BEGIN_CSAPI 165 166 checkFlags(flags, 167 kSecCSCheckAllArchitectures 168 | kSecCSConsiderExpiration 169 | kSecCSEnforceRevocationChecks 170 | kSecCSNoNetworkAccess 171 | kSecCSStrictValidate 172 | kSecCSStrictValidateStructure 173 | kSecCSRestrictSidebandData 174 | kSecCSCheckGatekeeperArchitectures 175 | kSecCSSkipRootVolumeExceptions 176 | kSecCSAllowNetworkAccess 177 | kSecCSFastExecutableValidation 178 ); 179 180 SecPointer<SecStaticCode> code = SecStaticCode::requiredStatic(staticCodeRef); 181 code->setValidationFlags(flags); 182 code->staticValidateResource(cfString(resourcePath), flags, NULL); 183 184 END_CSAPI_ERRORS 185 } 186 187 // 188 // ==================================================================================== 189 // 190 // The following API functions are called SecCode* but accept both SecCodeRef and 191 // SecStaticCodeRef arguments, operating on the implied SecStaticCodeRef as appropriate. 192 // Hence they're here, rather than in SecCode.cpp. 193 // 194 195 196 // 197 // Retrieve location information for an StaticCode. 198 // 199 OSStatus SecCodeCopyPath(SecStaticCodeRef staticCodeRef, SecCSFlags flags, CFURLRef *path) 200 { 201 BEGIN_CSAPI 202 203 checkFlags(flags); 204 SecPointer<SecStaticCode> staticCode = SecStaticCode::requiredStatic(staticCodeRef); 205 CodeSigning::Required(path) = staticCode->copyCanonicalPath(); 206 207 END_CSAPI 208 } 209 210 211 // 212 // Fetch or make up a designated requirement 213 // 214 OSStatus SecCodeCopyDesignatedRequirement(SecStaticCodeRef staticCodeRef, SecCSFlags flags, 215 SecRequirementRef *requirementRef) 216 { 217 BEGIN_CSAPI 218 219 checkFlags(flags); 220 const Requirement *req = 221 SecStaticCode::requiredStatic(staticCodeRef)->designatedRequirement(); 222 CodeSigning::Required(requirementRef) = (new SecRequirement(req))->handle(); 223 224 END_CSAPI 225 } 226 227 228 // 229 // Fetch a particular internal requirement, if present 230 // 231 OSStatus SecCodeCopyInternalRequirement(SecStaticCodeRef staticCodeRef, SecRequirementType type, 232 SecCSFlags flags, SecRequirementRef *requirementRef) 233 { 234 BEGIN_CSAPI 235 236 checkFlags(flags); 237 const Requirement *req = 238 SecStaticCode::requiredStatic(staticCodeRef)->internalRequirement(type); 239 CodeSigning::Required(requirementRef) = req ? (new SecRequirement(req))->handle() : NULL; 240 241 END_CSAPI 242 } 243 244 245 // 246 // Record for future use a detached code signature. 247 // 248 OSStatus SecCodeSetDetachedSignature(SecStaticCodeRef codeRef, CFDataRef signature, 249 SecCSFlags flags) 250 { 251 BEGIN_CSAPI 252 253 checkFlags(flags); 254 SecPointer<SecStaticCode> code = SecStaticCode::requiredStatic(codeRef); 255 256 code->detachedSignature(signature); // ... and pass it to the code 257 code->resetValidity(); 258 259 END_CSAPI 260 } 261 262 263 // 264 // Attach a code signature to a kernel memory mapping for page-in validation. 265 // 266 OSStatus SecCodeMapMemory(SecStaticCodeRef codeRef, SecCSFlags flags) 267 { 268 BEGIN_CSAPI 269 270 checkFlags(flags); 271 SecPointer<SecStaticCode> code = SecStaticCode::requiredStatic(codeRef); 272 if (const CodeDirectory *cd = code->codeDirectory(false)) { 273 if (code->isDetached()) { 274 // Detached signatures need to attach their code directory from memory. 275 fsignatures args = { static_cast<off_t>(code->diskRep()->signingBase()), (void *)cd, cd->length() }; 276 UnixError::check(::fcntl(code->diskRep()->fd(), F_ADDSIGS, &args)); 277 } else { 278 // All other signatures can simply point to the signature in the main executable. 279 Universal *execImage = code->diskRep()->mainExecutableImage(); 280 if (execImage == NULL) { 281 MacOSError::throwMe(errSecCSNoMainExecutable); 282 } 283 284 unique_ptr<MachO> arch(execImage->architecture()); 285 if (arch.get() == NULL) { 286 MacOSError::throwMe(errSecCSNoMainExecutable); 287 } 288 289 size_t signatureOffset = arch->signingOffset(); 290 size_t signatureLength = arch->signingLength(); 291 if (signatureOffset == 0) { 292 MacOSError::throwMe(errSecCSUnsigned); 293 } 294 295 fsignatures args = { 296 static_cast<off_t>(code->diskRep()->signingBase()), 297 (void *)signatureOffset, 298 signatureLength, 299 }; 300 UnixError::check(::fcntl(code->diskRep()->fd(), F_ADDFILESIGS, &args)); 301 } 302 } else { 303 MacOSError::throwMe(errSecCSUnsigned); 304 } 305 306 END_CSAPI 307 } 308 309 310 // 311 // Attach a callback block to a code object 312 // 313 OSStatus SecStaticCodeSetCallback(SecStaticCodeRef codeRef, SecCSFlags flags, SecCodeCallback *old, SecCodeCallback monitor) 314 { 315 BEGIN_CSAPI 316 317 checkFlags(flags); 318 SecStaticCode *code = SecStaticCode::requiredStatic(codeRef); 319 if (old) 320 *old = code->monitor(); 321 code->setMonitor(monitor); 322 323 END_CSAPI 324 } 325 326 327 OSStatus SecStaticCodeSetValidationConditions(SecStaticCodeRef codeRef, CFDictionaryRef conditions) 328 { 329 BEGIN_CSAPI 330 331 checkFlags(0); 332 SecStaticCode *code = SecStaticCode::requiredStatic(codeRef); 333 code->setValidationModifiers(conditions); 334 335 END_CSAPI 336 } 337 338 339 // 340 // Set cancellation flag on a static code object. 341 // 342 OSStatus SecStaticCodeCancelValidation(SecStaticCodeRef codeRef, SecCSFlags flags) 343 { 344 BEGIN_CSAPI 345 346 checkFlags(0); 347 SecStaticCode *code = SecStaticCode::requiredStatic(codeRef); 348 code->cancelValidation(); 349 350 END_CSAPI 351 } 352 353 354 // 355 // Retrieve a component object for a special slot directly. 356 // 357 CFDataRef SecCodeCopyComponent(SecCodeRef codeRef, int slot, CFDataRef hash) 358 { 359 BEGIN_CSAPI 360 361 SecStaticCode* code = SecStaticCode::requiredStatic(codeRef); 362 return code->copyComponent(slot, hash); 363 364 END_CSAPI1(NULL) 365 } 366 367 // 368 // Updates the flags to indicate whether this object wants to enable online notarization checks. 369 // 370 OSStatus SecStaticCodeEnableOnlineNotarizationCheck(SecStaticCodeRef codeRef, Boolean enable) 371 { 372 BEGIN_CSAPI 373 374 SecStaticCode* code = SecStaticCode::requiredStatic(codeRef); 375 SecCSFlags flags = code->getFlags(); 376 if (enable) { 377 flags = addFlags(flags, kSecCSForceOnlineNotarizationCheck); 378 } else { 379 flags = clearFlags(flags, kSecCSForceOnlineNotarizationCheck); 380 } 381 code->setFlags(flags); 382 383 END_CSAPI 384 } 385 386 // 387 // Validate a single plain file's resource seal against a memory copy. 388 // This will fail for any other file type (symlink, directory, nested code, etc. etc.) 389 // 390 OSStatus SecCodeValidateFileResource(SecStaticCodeRef codeRef, CFStringRef relativePath, CFDataRef fileData, SecCSFlags flags) 391 { 392 BEGIN_CSAPI 393 394 checkFlags(0); 395 if (fileData == NULL) 396 MacOSError::throwMe(errSecCSObjectRequired); 397 SecStaticCode *code = SecStaticCode::requiredStatic(codeRef); 398 code->validatePlainMemoryResource(cfString(relativePath), fileData, flags); 399 400 END_CSAPI 401 402 }