]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_codesigning/lib/cdbuilder.cpp
Security-58286.41.2.tar.gz
[apple/security.git] / OSX / libsecurity_codesigning / lib / cdbuilder.cpp
1 /*
2 * Copyright (c) 2006-2012,2014 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 // cdbuilder - constructor for CodeDirectories
26 //
27 #include "cdbuilder.h"
28 #include <security_utilities/memutils.h>
29 #include <cmath>
30
31 using namespace UnixPlusPlus;
32 using LowLevelMemoryUtilities::alignUp;
33
34
35 namespace Security {
36 namespace CodeSigning {
37
38
39 //
40 // Create an (empty) builder
41 //
42 CodeDirectory::Builder::Builder(HashAlgorithm digestAlgorithm)
43 : mFlags(0),
44 mHashType(digestAlgorithm),
45 mPlatform(0),
46 mSpecialSlots(0),
47 mCodeSlots(0),
48 mScatter(NULL),
49 mScatterSize(0),
50 mExecSegOffset(0),
51 mExecSegLimit(0),
52 mExecSegFlags(0),
53 mDir(NULL)
54 {
55 mDigestLength = (uint32_t)MakeHash<Builder>(this)->digestLength();
56 mSpecial = (unsigned char *)calloc(cdSlotMax, mDigestLength);
57 }
58
59 CodeDirectory::Builder::~Builder()
60 {
61 ::free(mSpecial);
62 ::free(mScatter);
63 }
64
65
66 //
67 // Set the source of the main executable (i.e. the code pages)
68 //
69 void CodeDirectory::Builder::executable(string path,
70 size_t pagesize, size_t offset, size_t length)
71 {
72 mExec.close(); // any previously opened one
73 mExec.open(path);
74 mPageSize = pagesize;
75 mExecOffset = offset;
76 mExecLength = length;
77 }
78
79 void CodeDirectory::Builder::reopen(string path, size_t offset, size_t length)
80 {
81 assert(mExec); // already called executable()
82 mExec.close();
83 mExec.open(path);
84 mExecOffset = offset;
85 mExecLength = length;
86 }
87
88
89 //
90 // Set the source for one special slot
91 //
92 void CodeDirectory::Builder::specialSlot(SpecialSlot slot, CFDataRef data)
93 {
94 assert(slot <= cdSlotMax);
95 MakeHash<Builder> hash(this);
96 hash->update(CFDataGetBytePtr(data), CFDataGetLength(data));
97 hash->finish(specialSlot(slot));
98 mFilledSpecialSlots.insert(slot);
99 if (slot >= mSpecialSlots)
100 mSpecialSlots = slot;
101 }
102
103
104 //
105 // Allocate a Scatter vector
106 //
107 CodeDirectory::Scatter *CodeDirectory::Builder::scatter(unsigned count)
108 {
109 mScatterSize = (count + 1) * sizeof(Scatter);
110 if (!(mScatter = (Scatter *)::realloc(mScatter, mScatterSize)))
111 UnixError::throwMe(ENOMEM);
112 ::memset(mScatter, 0, mScatterSize);
113 return mScatter;
114 }
115
116 //
117 // Keep the allocated size of the (static) CodeDirectory consistent with
118 // the version chosen. We dynamically picked the least-needed version
119 // to provide stability of virtual signatures.
120 //
121 size_t CodeDirectory::Builder::fixedSize(const uint32_t version)
122 {
123 size_t cdSize = sizeof(CodeDirectory);
124 if (version < supportsExecSegment)
125 cdSize -= sizeof(mDir->execSegBase) + sizeof(mDir->execSegLimit) + sizeof(mDir->execSegFlags);
126 if (version < supportsCodeLimit64)
127 cdSize -= sizeof(mDir->spare3) + sizeof(mDir->codeLimit64);
128 if (version < supportsTeamID)
129 cdSize -= sizeof(mDir->teamIDOffset);
130
131 return cdSize;
132 }
133
134 //
135 // Calculate the size we'll need for the CodeDirectory as described so far
136 //
137 size_t CodeDirectory::Builder::size(const uint32_t version)
138 {
139 assert(mExec); // must have called executable()
140 if (mExecLength == 0)
141 mExecLength = mExec.fileSize() - mExecOffset;
142
143 // how many code pages?
144 if (mExecLength <= 0) { // no code, no slots
145 mCodeSlots = 0;
146 } else if (mPageSize == 0) { // indefinite - one page
147 mCodeSlots = 1;
148 } else { // finite - calculate from file size
149 mCodeSlots = (mExecLength - 1) / mPageSize + 1;
150 }
151
152 size_t offset = fixedSize(version);
153 size_t offset0 = offset;
154
155 offset += mScatterSize; // scatter vector
156 offset += mIdentifier.size() + 1; // size of identifier (with null byte)
157 if (mTeamID.size())
158 offset += mTeamID.size() + 1; // size of teamID (with null byte)
159 offset += (mCodeSlots + mSpecialSlots) * mDigestLength; // hash vector
160 if (offset <= offset0)
161 UnixError::throwMe(ENOEXEC);
162
163 return offset;
164 }
165
166
167 //
168 // Take everything added to date and wrap it up in a shiny new CodeDirectory.
169 //
170 // Note that this only constructs a CodeDirectory; it does not touch any subsidiary
171 // structures (resource tables, etc.), nor does it create any signature to secure
172 // the CodeDirectory.
173 // The returned CodeDirectory object is yours, and you may modify it as desired.
174 // But the memory layout is set here, so the various sizes and counts should be good
175 // when you call build().
176 // It's up to us to order the dynamic fields as we wish; but note that we currently
177 // don't pad them, and so they should be allocated in non-increasing order of required
178 // alignment. Make sure to keep the code here in sync with the size-calculating code above.
179 //
180 CodeDirectory *CodeDirectory::Builder::build()
181 {
182 assert(mExec); // must have (successfully) called executable()
183 uint32_t version;
184
185 // size and allocate
186 size_t identLength = mIdentifier.size() + 1;
187 size_t teamIDLength = mTeamID.size() + 1;
188
189 // Determine the version
190 if (mExecSegLimit > 0) {
191 version = currentVersion;
192 } else if (mExecLength > UINT32_MAX) {
193 version = supportsCodeLimit64;
194 } else if (mTeamID.size()) {
195 version = supportsTeamID;
196 } else {
197 version = supportsScatter;
198 }
199
200 if (mCodeSlots > UINT32_MAX) // (still limited to 32 bits)
201 MacOSError::throwMe(errSecCSTooBig);
202
203 size_t total = size(version);
204 if (!(mDir = (CodeDirectory *)calloc(1, total))) // initialize to zero
205 UnixError::throwMe(ENOMEM);
206
207 // fill header
208 mDir->initialize(total);
209 mDir->version = version;
210 mDir->flags = mFlags;
211 mDir->nSpecialSlots = (uint32_t)mSpecialSlots;
212 mDir->nCodeSlots = (uint32_t)mCodeSlots;
213 if (mExecLength > UINT32_MAX) {
214 mDir->codeLimit = UINT32_MAX;
215 mDir->codeLimit64 = mExecLength;
216 } else {
217 mDir->codeLimit = uint32_t(mExecLength);
218 }
219 mDir->hashType = mHashType;
220 mDir->platform = mPlatform;
221 mDir->hashSize = mDigestLength;
222 if (mPageSize) {
223 int pglog;
224 assert(frexp(mPageSize, &pglog) == 0.5); // must be power of 2
225 frexp(mPageSize, &pglog);
226 assert(pglog < 256);
227 mDir->pageSize = pglog - 1;
228 } else
229 mDir->pageSize = 0; // means infinite page size
230
231 mDir->execSegBase = mExecSegOffset;
232 mDir->execSegLimit = mExecSegLimit;
233 mDir->execSegFlags = mExecSegFlags;
234
235 // locate and fill flex fields
236 size_t offset = fixedSize(mDir->version);
237
238 if (mScatter) {
239 mDir->scatterOffset = (uint32_t)offset;
240 memcpy(mDir->scatterVector(), mScatter, mScatterSize);
241 offset += mScatterSize;
242 }
243
244 mDir->identOffset = (uint32_t)offset;
245 memcpy(mDir->identifier(), mIdentifier.c_str(), identLength);
246 offset += identLength;
247
248 if (mTeamID.size()) {
249 mDir->teamIDOffset = (uint32_t)offset;
250 memcpy(mDir->teamID(), mTeamID.c_str(), teamIDLength);
251 offset += teamIDLength;
252 }
253 // (add new flexibly-allocated fields here)
254
255 mDir->hashOffset = (uint32_t)(offset + mSpecialSlots * mDigestLength);
256 offset += (mSpecialSlots + mCodeSlots) * mDigestLength;
257 assert(offset == total); // matches allocated size
258
259 (void)offset;
260
261 // fill special slots
262 memset((*mDir)[(int)-mSpecialSlots], 0, mDigestLength * mSpecialSlots);
263 for (size_t slot = 1; slot <= mSpecialSlots; ++slot)
264 memcpy((*mDir)[(int)-slot], specialSlot((SpecialSlot)slot), mDigestLength);
265
266 // fill code slots
267 mExec.seek(mExecOffset);
268 size_t remaining = mExecLength;
269 for (unsigned int slot = 0; slot < mCodeSlots; ++slot) {
270 size_t thisPage = remaining;
271 if (mPageSize)
272 thisPage = min(thisPage, mPageSize);
273 MakeHash<Builder> hasher(this);
274 generateHash(hasher, mExec, (*mDir)[slot], thisPage);
275 remaining -= thisPage;
276 }
277 assert(remaining == 0);
278
279 // all done. Pass ownership to caller
280 return mDir;
281 }
282
283
284 } // CodeSigning
285 } // Security