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