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// cs_verify - codesign verification operations 26// 27#include "codesign.h" 28#include <Security/SecStaticCodePriv.h> 29#include <Security/SecRequirementPriv.h> 30#include <Security/SecCodePriv.h> 31 32using namespace UnixPlusPlus; 33 34 35static void displayGuestChain(SecCodeRef code); 36 37 38// 39// One-time preparation 40// 41SecRequirementRef testReqs; // external requirement (compiled) 42 43 44void prepareToVerify() 45{ 46 if (testReq) 47 testReqs = readRequirement(testReq); 48} 49 50 51// 52// Verify a code object's signature on disk. 53// This also provides for live verification on processes (only). 54// 55void verify(const char *target) 56{ 57 CFRef<SecCodeRef> code = dynamicCodePath(target); // set if the target is dynamic 58 CFCopyRef<SecStaticCodeRef> staticCode; 59 if (code) 60 MacOSError::check(SecCodeCopyStaticCode(code, kSecCSDefaultFlags, &staticCode.aref())); 61 else 62 staticCode.take(staticCodePath(target, architecture, bundleVersion)); 63 if (detached) { 64 if (CFRef<CFDataRef> dsig = cfLoadFile(detached)) 65 MacOSError::check(SecCodeSetDetachedSignature(staticCode, dsig, kSecCSDefaultFlags)); 66 else 67 fail("%s: cannot load detached signature", detached); 68 } 69 70 MacOSError::check(SecStaticCodeSetCallback(staticCode, kSecCSDefaultFlags, NULL, ^(SecStaticCodeRef code, CFStringRef stage, CFDictionaryRef info) { 71 if (code != staticCode) { 72 CFRef<CFURLRef> path; 73 MacOSError::check(SecCodeCopyPath(code, kSecCSDefaultFlags, &path.aref())); 74 note(2, "--%s:%s", cfString(stage).c_str(), cfString(path).c_str()); 75 } 76 return CFTypeRef(NULL); 77 })); 78 79 if (code) { 80 ErrorCheck check; 81 check(SecCodeCheckValidityWithErrors(code, kSecCSDefaultFlags, NULL, check)); 82 note(1, "%s: dynamically valid", target); 83 } 84 if (!code || verbose > 0) { // validate statically if static input or verbose dynamic 85 ErrorCheck check; 86 check(SecStaticCodeCheckValidityWithErrors(staticCode, staticVerifyOptions, NULL, check)); 87 if (staticVerifyOptions & kSecCSBasicValidateOnly) 88 note(1, "%s: valid on disk (not all contents verified)", target); 89 else 90 note(1, "%s: valid on disk", target); 91 } 92 MacOSError::check(SecStaticCodeSetCallback(staticCode, kSecCSDefaultFlags, NULL, NULL)); 93 94 if (verbose > 0) { // self-check designated requirement 95 CFRef<SecRequirementRef> designated = NULL; 96 OSStatus rc; 97 if ((rc = SecCodeCopyDesignatedRequirement(staticCode, kSecCSDefaultFlags, &designated.aref()))) { 98 cssmPerror(target, rc); 99 fail("%s: cannot retrieve designated requirement", target); 100 } else if ((rc = SecStaticCodeCheckValidity(staticCode, kSecCSBasicValidateOnly, designated))) { 101 note(0, "%s: does not satisfy its designated Requirement", target); 102 if (!exitcode) 103 exitcode = exitNoverify; 104 } else 105 note(1, "%s: satisfies its Designated Requirement", target); 106 } 107 108 if (testReqs) { // check explicit test requirement 109 if (OSStatus rc = SecStaticCodeCheckValidity(staticCode, staticVerifyOptions, testReqs)) { 110 if (numericErrors) 111 printf("%ld\n", long(errSecCSReqFailed)); 112 cssmPerror("test-requirement", rc); 113 if (!exitcode) 114 exitcode = exitNoverify; 115 } else { 116 note(1, "%s: explicit requirement satisfied", target); 117 } 118 } 119} 120 121 122// 123// Build and display the hosting chain for some running code. 124// This won't work for static (file path) arguments. 125// 126void hostinginfo(const char *target) 127{ 128 CFRef<SecCodeRef> code = dynamicCodePath(target); 129 if (!code) 130 fail("%s: not a dynamic code specification", target); 131 132 do { 133 CFDictionary info(noErr); 134 MacOSError::check(SecCodeCopySigningInformation(code, kSecCSDynamicInformation, &info.aref())); 135 printf("%s", cfString(info.get<CFURLRef>(kSecCodeInfoMainExecutable)).c_str()); 136 if (verbose > 0) { 137 printf("\t"); 138 if (info.get<CFStringRef>(kSecCodeInfoIdentifier)) 139 printf("("); 140 else 141 printf("UNSIGNED ("); 142 if (CFNumberRef state = info.get<CFNumberRef>(kSecCodeInfoStatus)) { 143 uint32_t status = cfNumber(state); 144 if (status & kSecCodeStatusValid) 145 printf("valid"); 146 else 147 printf("INVALID"); 148 if (status & kSecCodeStatusKill) 149 printf(" kill"); 150 if (status & kSecCodeStatusHard) 151 printf(" hard"); 152 if (status & ~(kSecCodeStatusValid | kSecCodeStatusKill | kSecCodeStatusHard)) // unrecognized flag 153 printf(" 0x%x", status); 154 } else 155 printf("UNKNOWN"); 156 printf(")"); 157 } 158 printf("\n"); 159 CFRef<SecCodeRef> host; 160 MacOSError::check(SecCodeCopyHost(code, kSecCSDefaultFlags, &host.aref())); 161 code = host; 162 } while (code); 163} 164