1/*
2 * Copyright (c) 2000-2001,2011,2013-2014 Apple Inc. All Rights Reserved.
3 *
4 * The contents of this file constitute Original Code as defined in and are
5 * subject to the Apple Public Source License Version 1.2 (the 'License').
6 * You may not use this file except in compliance with the License. Please obtain
7 * a copy of the License at http://www.apple.com/publicsource and read it before
8 * using this file.
9 *
10 * This Original Code and all software distributed under the License are
11 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS
12 * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT
13 * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14 * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the
15 * specific language governing rights and limitations under the License.
16 */
17
18
19//
20// osxsigner - MacOS X's standard code signing algorithm.
21//
22#include <security_cdsa_utilities/osxverifier.h>
23#include <security_utilities/unix++.h>
24#include <security_utilities/hashing.h>
25#include <security_utilities/memutils.h>
26#include <security_utilities/debugging.h>
27#include <security_codesigning/requirement.h>
28#include <security_codesigning/reqdumper.h>		// debug only
29
30
31using namespace CodeSigning;
32
33
34namespace Security {
35
36
37//
38// Create a Verifier from a code object.
39//
40// This does not add any auxiliary information blobs. You can do that
41// by calling add() after construction, of course.
42//
43OSXVerifier::OSXVerifier(OSXCode *code)
44{
45	mPath = code->canonicalPath();
46	secdebug("codesign", "building verifier for %s", mPath.c_str());
47
48	// build new-style verifier
49	CFRef<SecStaticCodeRef> staticCode = code->codeRef();
50	switch (OSStatus rc = SecCodeCopyDesignatedRequirement(staticCode,
51			kSecCSDefaultFlags, &mRequirement.aref())) {
52	case errSecSuccess:
53		secdebug("codesign", "  is signed; canonical requirement loaded");
54		break;
55	case errSecCSUnsigned:
56		secdebug("codesign", "  is unsigned; no requirement");
57		break;
58	default:
59		MacOSError::throwMe(rc);
60	}
61
62	// build old-style verifier
63	makeLegacyHash(code, mLegacyHash);
64	secdebug("codesign", "  hash generated");
65}
66
67
68//
69// Create a Verifier from hash, path, and requirement.
70// Again, this has no auxiliary data when constructed.
71//
72OSXVerifier::OSXVerifier(const SHA1::Byte *hash, const std::string &path)
73	: mPath(path)
74{
75	secdebug("codesign", "building verifier from hash %p and path=%s", hash, path.c_str());
76	if (hash)
77		memcpy(mLegacyHash, hash, sizeof(mLegacyHash));
78	else
79		memset(mLegacyHash, 0, sizeof(mLegacyHash));
80}
81
82
83OSXVerifier::~OSXVerifier()
84{
85	secdebug("codesign", "%p verifier destroyed", this);
86}
87
88
89//
90// Add an auxiliary comment blob.
91// Note that we only allow one auxiliary blob for each magic number.
92//
93void OSXVerifier::add(const BlobCore *blob)
94{
95	if (blob->is<Requirement>()) {
96#if defined(NDEBUG)
97		secdebug("codesign", "%p verifier adds requirement", this);
98#else
99		secdebug("codesign", "%p verifier adds requirement %s", this,
100			Dumper::dump(Requirement::specific(blob), true).c_str());
101#endif //NDEBUG
102		MacOSError::check(SecRequirementCreateWithData(CFTempData(*blob),
103			kSecCSDefaultFlags, &mRequirement.aref()));
104	} else {
105		secdebug("codesign", "%p verifier adds blob (0x%x,%zd)",
106			this, blob->magic(), blob->length());
107		BlobCore * &slot = mAuxiliary[blob->magic()];
108		if (slot)
109			::free(slot);
110		slot = blob->clone();
111	}
112}
113
114
115//
116// Find a comment blob, by magic number
117//
118const BlobCore *OSXVerifier::find(BlobCore::Magic magic)
119{
120	AuxMap::const_iterator it = mAuxiliary.find(magic);
121	return (it == mAuxiliary.end()) ? NULL : it->second;
122}
123
124
125void OSXVerifier::makeLegacyHash(OSXCode *code, SHA1::Digest digest)
126{
127	secdebug("codesign", "calculating legacy hash for %s", code->canonicalPath().c_str());
128	UnixPlusPlus::AutoFileDesc fd(code->executablePath(), O_RDONLY);
129	char buffer[legacyHashLimit];
130	size_t size = fd.read(buffer, legacyHashLimit);
131	SHA1 hash;
132	hash(buffer, size);
133	hash.finish(digest);
134}
135
136
137//
138// The AuxMap helper class provides a map-to-Blob-pointers with automatic memory management.
139//
140OSXVerifier::AuxMap::AuxMap(const OSXVerifier::AuxMap &src)
141{
142	for (const_iterator it = src.begin(); it != src.end(); it++)
143		this->insert(*it);
144}
145
146OSXVerifier::AuxMap::~AuxMap()
147{
148	for (const_iterator it = this->begin(); it != this->end(); ++it)
149		::free(it->second);
150}
151
152
153#if DEBUGDUMP
154
155void OSXVerifier::dump() const
156{
157	static const SHA1::Digest nullDigest = { 0 };
158	if (!memcmp(mLegacyHash, nullDigest, sizeof(mLegacyHash))) {
159		Debug::dump("(no hash)");
160	} else {
161		Debug::dump("oldHash=");
162		Debug::dumpData(mLegacyHash, sizeof(mLegacyHash));
163	}
164	if (mRequirement) {
165		CFRef<CFDataRef> reqData;
166		if (!SecRequirementCopyData(mRequirement, 0, &reqData.aref())) {
167			Debug::dump(" Requirement =>");
168			((const Requirement *)CFDataGetBytePtr(reqData))->dump();
169		}
170	} else {
171		Debug::dump(" NO REQ");
172	}
173}
174
175#endif //DEBUGDUMP
176
177} // end namespace Security
178