SecCode.cpp
1 /* 2 * Copyright (c) 2006-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 // SecCode - API frame for SecCode objects. 26 // 27 // Note that some SecCode* functions take SecStaticCodeRef arguments in order to 28 // accept either static or dynamic code references, operating on the respective 29 // StaticCode. Those functions are in SecStaticCode.cpp, not here, despite their name. 30 // 31 #include "cs.h" 32 #include "Code.h" 33 #include "cskernel.h" 34 #include <security_utilities/cfmunge.h> 35 #include <security_utilities/logging.h> 36 #include <xpc/private.h> 37 38 using namespace CodeSigning; 39 40 41 // 42 // CFError user info keys 43 // 44 const CFStringRef kSecCFErrorArchitecture = CFSTR("SecCSArchitecture"); 45 const CFStringRef kSecCFErrorPattern = CFSTR("SecCSPattern"); 46 const CFStringRef kSecCFErrorResourceSeal = CFSTR("SecCSResourceSeal"); 47 const CFStringRef kSecCFErrorResourceAdded = CFSTR("SecCSResourceAdded"); 48 const CFStringRef kSecCFErrorResourceAltered = CFSTR("SecCSResourceAltered"); 49 const CFStringRef kSecCFErrorResourceMissing = CFSTR("SecCSResourceMissing"); 50 const CFStringRef kSecCFErrorResourceSideband = CFSTR("SecCSResourceHasSidebandData"); 51 const CFStringRef kSecCFErrorInfoPlist = CFSTR("SecCSInfoPlist"); 52 const CFStringRef kSecCFErrorGuestAttributes = CFSTR("SecCSGuestAttributes"); 53 const CFStringRef kSecCFErrorRequirementSyntax = CFSTR("SecRequirementSyntax"); 54 const CFStringRef kSecCFErrorPath = CFSTR("SecComponentPath"); 55 56 57 // 58 // CF-standard type code functions 59 // 60 CFTypeID SecCodeGetTypeID(void) 61 { 62 BEGIN_CSAPI 63 return gCFObjects().Code.typeID; 64 END_CSAPI1(_kCFRuntimeNotATypeID) 65 } 66 67 68 // 69 // Get a reference to the calling code. 70 // 71 OSStatus SecCodeCopySelf(SecCSFlags flags, SecCodeRef *selfRef) 72 { 73 BEGIN_CSAPI 74 75 checkFlags(flags); 76 CFRef<CFMutableDictionaryRef> attributes = makeCFMutableDictionary(1, 77 kSecGuestAttributePid, CFTempNumber(getpid()).get()); 78 CodeSigning::Required(selfRef) = SecCode::autoLocateGuest(attributes, flags)->handle(false); 79 80 END_CSAPI 81 } 82 83 84 // 85 // Get the dynamic status of a code. 86 // 87 OSStatus SecCodeGetStatus(SecCodeRef codeRef, SecCSFlags flags, SecCodeStatus *status) 88 { 89 BEGIN_CSAPI 90 91 checkFlags(flags); 92 CodeSigning::Required(status) = SecCode::required(codeRef)->status(); 93 94 END_CSAPI 95 } 96 97 98 // 99 // Change the dynamic status of a code 100 // 101 OSStatus SecCodeSetStatus(SecCodeRef codeRef, SecCodeStatusOperation operation, 102 CFDictionaryRef arguments, SecCSFlags flags) 103 { 104 BEGIN_CSAPI 105 106 checkFlags(flags); 107 SecCode::required(codeRef)->status(operation, arguments); 108 109 END_CSAPI 110 } 111 112 113 // 114 // Get the StaticCode for an Code 115 // 116 OSStatus SecCodeCopyStaticCode(SecCodeRef codeRef, SecCSFlags flags, SecStaticCodeRef *staticCodeRef) 117 { 118 BEGIN_CSAPI 119 120 checkFlags(flags, kSecCSUseAllArchitectures); 121 SecPointer<SecStaticCode> staticCode = SecCode::required(codeRef)->staticCode(); 122 if (flags & kSecCSUseAllArchitectures) 123 if (Universal* macho = staticCode->diskRep()->mainExecutableImage()) // Mach-O main executable 124 if (macho->narrowed()) { 125 // create a new StaticCode comprising the whole fat file 126 RefPointer<DiskRep> rep = DiskRep::bestGuess(staticCode->diskRep()->mainExecutablePath()); 127 staticCode = new SecStaticCode(rep); 128 } 129 CodeSigning::Required(staticCodeRef) = staticCode ? staticCode->handle() : NULL; 130 131 END_CSAPI 132 } 133 134 135 // 136 // Get the host for an Code 137 // 138 OSStatus SecCodeCopyHost(SecCodeRef guestRef, SecCSFlags flags, SecCodeRef *hostRef) 139 { 140 BEGIN_CSAPI 141 142 checkFlags(flags); 143 SecPointer<SecCode> host = SecCode::required(guestRef)->host(); 144 CodeSigning::Required(hostRef) = host ? host->handle() : NULL; 145 146 END_CSAPI 147 } 148 149 150 // 151 // Find a guest by attribute(s) 152 // 153 const CFStringRef kSecGuestAttributeCanonical = CFSTR("canonical"); 154 const CFStringRef kSecGuestAttributeHash = CFSTR("codedirectory-hash"); 155 const CFStringRef kSecGuestAttributeMachPort = CFSTR("mach-port"); 156 const CFStringRef kSecGuestAttributePid = CFSTR("pid"); 157 const CFStringRef kSecGuestAttributeAudit = CFSTR("audit"); 158 const CFStringRef kSecGuestAttributeDynamicCode = CFSTR("dynamicCode"); 159 const CFStringRef kSecGuestAttributeDynamicCodeInfoPlist = CFSTR("dynamicCodeInfoPlist"); 160 const CFStringRef kSecGuestAttributeArchitecture = CFSTR("architecture"); 161 const CFStringRef kSecGuestAttributeSubarchitecture = CFSTR("subarchitecture"); 162 163 #if TARGET_OS_OSX 164 OSStatus SecCodeCopyGuestWithAttributes(SecCodeRef hostRef, 165 CFDictionaryRef attributes, SecCSFlags flags, SecCodeRef *guestRef) 166 { 167 BEGIN_CSAPI 168 169 checkFlags(flags); 170 if (hostRef) { 171 if (SecCode *guest = SecCode::required(hostRef)->locateGuest(attributes)) 172 CodeSigning::Required(guestRef) = guest->handle(false); 173 else 174 return errSecCSNoSuchCode; 175 } else 176 CodeSigning::Required(guestRef) = SecCode::autoLocateGuest(attributes, flags)->handle(false); 177 178 END_CSAPI 179 } 180 181 182 // 183 // Deprecated since 10.6, DO NOT USE. This can be raced. 184 // Use SecCodeCreateWithAuditToken instead. 185 // 186 OSStatus SecCodeCreateWithPID(pid_t pid, SecCSFlags flags, SecCodeRef *processRef) 187 { 188 BEGIN_CSAPI 189 190 checkFlags(flags); 191 if (SecCode *guest = KernelCode::active()->locateGuest(CFTemp<CFDictionaryRef>("{%O=%d}", kSecGuestAttributePid, pid))) 192 CodeSigning::Required(processRef) = guest->handle(false); 193 else 194 return errSecCSNoSuchCode; 195 196 END_CSAPI 197 } 198 199 // 200 // Shorthand for getting the SecCodeRef for a UNIX process 201 // 202 OSStatus SecCodeCreateWithAuditToken(const audit_token_t *audit, 203 SecCSFlags flags, SecCodeRef *processRef) 204 { 205 BEGIN_CSAPI 206 207 checkFlags(flags); 208 CFRef<CFDataRef> auditData = makeCFData(audit, sizeof(audit_token_t)); 209 if (SecCode *guest = KernelCode::active()->locateGuest(CFTemp<CFDictionaryRef>("{%O=%O}", kSecGuestAttributeAudit, auditData.get()))) { 210 CodeSigning::Required(processRef) = guest->handle(false); 211 } else { 212 return errSecCSNoSuchCode; 213 } 214 215 END_CSAPI 216 } 217 218 OSStatus SecCodeCreateWithXPCMessage(xpc_object_t message, SecCSFlags flags, 219 SecCodeRef * __nonnull CF_RETURNS_RETAINED target) 220 { 221 BEGIN_CSAPI 222 223 checkFlags(flags); 224 225 if (xpc_get_type(message) != XPC_TYPE_DICTIONARY) { 226 return errSecCSInvalidObjectRef; 227 } 228 229 xpc_connection_t connection = xpc_dictionary_get_remote_connection(message); 230 if (connection == NULL) { 231 return errSecCSInvalidObjectRef; 232 } 233 234 audit_token_t t = {0}; 235 xpc_connection_get_audit_token(connection, &t); 236 237 return SecCodeCreateWithAuditToken(&t, flags, target); 238 239 END_CSAPI 240 } 241 242 #endif // TARGET_OS_OSX 243 244 245 // 246 // Check validity of an Code 247 // 248 OSStatus SecCodeCheckValidity(SecCodeRef codeRef, SecCSFlags flags, 249 SecRequirementRef requirementRef) 250 { 251 return SecCodeCheckValidityWithErrors(codeRef, flags, requirementRef, NULL); 252 } 253 254 OSStatus SecCodeCheckValidityWithErrors(SecCodeRef codeRef, SecCSFlags flags, 255 SecRequirementRef requirementRef, CFErrorRef *errors) 256 { 257 BEGIN_CSAPI 258 259 checkFlags(flags, 260 kSecCSConsiderExpiration 261 | kSecCSStrictValidate 262 | kSecCSStrictValidateStructure 263 | kSecCSRestrictSidebandData 264 | kSecCSEnforceRevocationChecks 265 | kSecCSAllowNetworkAccess 266 | kSecCSNoNetworkAccess 267 ); 268 SecPointer<SecCode> code = SecCode::required(codeRef); 269 code->checkValidity(flags); 270 if (const SecRequirement *req = SecRequirement::optional(requirementRef)) 271 code->staticCode()->validateRequirement(req->requirement(), errSecCSReqFailed); 272 273 END_CSAPI_ERRORS 274 } 275 276 277 // 278 // Collect suitably laundered information about the code signature of a SecStaticCode 279 // and return it as a CFDictionary. 280 // 281 // This API contracts to return a few pieces of information even for unsigned 282 // code. This means that a SecStaticCodeRef is usable as a basic indentifier 283 // (i.e. handle) for any code out there. 284 // 285 const CFStringRef kSecCodeInfoCertificates = CFSTR("certificates"); 286 const CFStringRef kSecCodeInfoChangedFiles = CFSTR("changed-files"); 287 const CFStringRef kSecCodeInfoCMS = CFSTR("cms"); 288 const CFStringRef kSecCodeInfoDesignatedRequirement = CFSTR("designated-requirement"); 289 const CFStringRef kSecCodeInfoEntitlements = CFSTR("entitlements"); 290 const CFStringRef kSecCodeInfoEntitlementsDict = CFSTR("entitlements-dict"); 291 const CFStringRef kSecCodeInfoFlags = CFSTR("flags"); 292 const CFStringRef kSecCodeInfoFormat = CFSTR("format"); 293 const CFStringRef kSecCodeInfoDigestAlgorithm = CFSTR("digest-algorithm"); 294 const CFStringRef kSecCodeInfoDigestAlgorithms = CFSTR("digest-algorithms"); 295 const CFStringRef kSecCodeInfoPlatformIdentifier = CFSTR("platform-identifier"); 296 const CFStringRef kSecCodeInfoIdentifier = CFSTR("identifier"); 297 const CFStringRef kSecCodeInfoImplicitDesignatedRequirement = CFSTR("implicit-requirement"); 298 const CFStringRef kSecCodeInfoMainExecutable = CFSTR("main-executable"); 299 const CFStringRef kSecCodeInfoPList = CFSTR("info-plist"); 300 const CFStringRef kSecCodeInfoRequirements = CFSTR("requirements"); 301 const CFStringRef kSecCodeInfoRequirementData = CFSTR("requirement-data"); 302 const CFStringRef kSecCodeInfoSource = CFSTR("source"); 303 const CFStringRef kSecCodeInfoStatus = CFSTR("status"); 304 const CFStringRef kSecCodeInfoTeamIdentifier = CFSTR("teamid"); 305 const CFStringRef kSecCodeInfoTime = CFSTR("signing-time"); 306 const CFStringRef kSecCodeInfoTimestamp = CFSTR("signing-timestamp"); 307 const CFStringRef kSecCodeInfoTrust = CFSTR("trust"); 308 const CFStringRef kSecCodeInfoUnique = CFSTR("unique"); 309 const CFStringRef kSecCodeInfoCdHashes = CFSTR("cdhashes"); 310 const CFStringRef kSecCodeInfoCdHashesFull = CFSTR("cdhashes-full"); 311 const CFStringRef kSecCodeInfoRuntimeVersion = CFSTR("runtime-version"); 312 313 const CFStringRef kSecCodeInfoCodeDirectory = CFSTR("CodeDirectory"); 314 const CFStringRef kSecCodeInfoCodeOffset = CFSTR("CodeOffset"); 315 const CFStringRef kSecCodeInfoDiskRepInfo = CFSTR("DiskRepInfo"); 316 const CFStringRef kSecCodeInfoResourceDirectory = CFSTR("ResourceDirectory"); 317 const CFStringRef kSecCodeInfoNotarizationDate = CFSTR("NotarizationDate"); 318 const CFStringRef kSecCodeInfoCMSDigestHashType = CFSTR("CMSDigestHashType"); 319 const CFStringRef kSecCodeInfoCMSDigest = CFSTR("CMSDigest"); 320 const CFStringRef kSecCodeInfoSignatureVersion = CFSTR("SignatureVersion"); 321 322 /* DiskInfoRepInfo types */ 323 const CFStringRef kSecCodeInfoDiskRepVersionPlatform = CFSTR("VersionPlatform"); 324 const CFStringRef kSecCodeInfoDiskRepVersionMin = CFSTR("VersionMin"); 325 const CFStringRef kSecCodeInfoDiskRepVersionSDK = CFSTR("VersionSDK"); 326 const CFStringRef kSecCodeInfoDiskRepNoLibraryValidation = CFSTR("NoLibraryValidation"); 327 328 329 OSStatus SecCodeCopySigningInformation(SecStaticCodeRef codeRef, SecCSFlags flags, 330 CFDictionaryRef *infoRef) 331 { 332 BEGIN_CSAPI 333 334 checkFlags(flags, 335 kSecCSInternalInformation 336 | kSecCSSigningInformation 337 | kSecCSRequirementInformation 338 | kSecCSDynamicInformation 339 | kSecCSContentInformation 340 | kSecCSSkipResourceDirectory 341 | kSecCSCalculateCMSDigest); 342 343 SecPointer<SecStaticCode> code = SecStaticCode::requiredStatic(codeRef); 344 CFRef<CFDictionaryRef> info = code->signingInformation(flags); 345 346 if (flags & kSecCSDynamicInformation) 347 if (SecPointer<SecCode> dcode = SecStaticCode::optionalDynamic(codeRef)) 348 info.take(cfmake<CFDictionaryRef>("{+%O,%O=%u}", info.get(), kSecCodeInfoStatus, dcode->status())); 349 350 CodeSigning::Required(infoRef) = info.yield(); 351 352 END_CSAPI 353 }