]>
Commit | Line | Data |
---|---|---|
7d31e928 | 1 | /* |
f60086fc | 2 | * Copyright (c) 2006-2010 Apple Inc. All Rights Reserved. |
7d31e928 A |
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 | // | |
f60086fc A |
42 | CodeDirectory::Builder::Builder(HashAlgorithm digestAlgorithm) |
43 | : mFlags(0), | |
44 | mHashType(digestAlgorithm), | |
45 | mSpecialSlots(0), | |
46 | mCodeSlots(0), | |
47 | mScatter(NULL), | |
48 | mScatterSize(0), | |
49 | mDir(NULL) | |
7d31e928 | 50 | { |
f60086fc A |
51 | mDigestLength = MakeHash<Builder>(this)->digestLength(); |
52 | mSpecial = (unsigned char *)calloc(cdSlotMax, mDigestLength); | |
d1c1ab47 A |
53 | } |
54 | ||
55 | CodeDirectory::Builder::~Builder() | |
56 | { | |
f60086fc | 57 | ::free(mSpecial); |
d1c1ab47 | 58 | ::free(mScatter); |
7d31e928 A |
59 | } |
60 | ||
61 | ||
62 | // | |
63 | // Set the source of the main executable (i.e. the code pages) | |
64 | // | |
65 | void CodeDirectory::Builder::executable(string path, | |
66 | size_t pagesize, size_t offset, size_t length) | |
67 | { | |
68 | mExec.close(); // any previously opened one | |
69 | mExec.open(path); | |
70 | mPageSize = pagesize; | |
71 | mExecOffset = offset; | |
72 | mExecLength = length; | |
73 | } | |
74 | ||
75 | void CodeDirectory::Builder::reopen(string path, size_t offset, size_t length) | |
76 | { | |
77 | assert(mExec); // already called executable() | |
78 | mExec.close(); | |
79 | mExec.open(path); | |
80 | mExecOffset = offset; | |
81 | mExecLength = length; | |
82 | } | |
83 | ||
84 | ||
85 | // | |
86 | // Set the source for one special slot | |
87 | // | |
f60086fc | 88 | void CodeDirectory::Builder::specialSlot(SpecialSlot slot, CFDataRef data) |
7d31e928 A |
89 | { |
90 | assert(slot <= cdSlotMax); | |
f60086fc A |
91 | MakeHash<Builder> hash(this); |
92 | hash->update(CFDataGetBytePtr(data), CFDataGetLength(data)); | |
93 | hash->finish(specialSlot(slot)); | |
7d31e928 A |
94 | if (slot >= mSpecialSlots) |
95 | mSpecialSlots = slot; | |
96 | } | |
97 | ||
98 | ||
d1c1ab47 A |
99 | // |
100 | // Allocate a Scatter vector | |
101 | // | |
102 | CodeDirectory::Scatter *CodeDirectory::Builder::scatter(unsigned count) | |
103 | { | |
104 | mScatterSize = (count + 1) * sizeof(Scatter); | |
105 | if (!(mScatter = (Scatter *)::realloc(mScatter, mScatterSize))) | |
106 | UnixError::throwMe(ENOMEM); | |
107 | ::memset(mScatter, 0, mScatterSize); | |
108 | return mScatter; | |
109 | } | |
110 | ||
111 | ||
112 | // | |
113 | // Calculate the size we'll need for the CodeDirectory as described so far | |
114 | // | |
7d31e928 A |
115 | size_t CodeDirectory::Builder::size() |
116 | { | |
117 | assert(mExec); // must have called executable() | |
118 | if (mExecLength == 0) | |
119 | mExecLength = mExec.fileSize() - mExecOffset; | |
120 | ||
121 | // how many code pages? | |
122 | if (mPageSize == 0) { // indefinite - one page | |
123 | mCodeSlots = (mExecLength > 0); | |
124 | } else { // finite - calculate from file size | |
125 | mCodeSlots = (mExecLength + mPageSize - 1) / mPageSize; // round up | |
126 | } | |
127 | ||
128 | size_t offset = sizeof(CodeDirectory); | |
d1c1ab47 | 129 | offset += mScatterSize; // scatter vector |
7d31e928 | 130 | offset += mIdentifier.size() + 1; // size of identifier (with null byte) |
f60086fc | 131 | offset += (mCodeSlots + mSpecialSlots) * mDigestLength; // hash vector |
7d31e928 A |
132 | return offset; |
133 | } | |
134 | ||
135 | ||
136 | // | |
137 | // Take everything added to date and wrap it up in a shiny new CodeDirectory. | |
138 | // | |
d1c1ab47 A |
139 | // Note that this only constructs a CodeDirectory; it does not touch any subsidiary |
140 | // structures (resource tables, etc.), nor does it create any signature to secure | |
141 | // the CodeDirectory. | |
142 | // The returned CodeDirectory object is yours, and you may modify it as desired. | |
143 | // But the memory layout is set here, so the various sizes and counts should be good | |
144 | // when you call build(). | |
145 | // It's up to us to order the dynamic fields as we wish; but note that we currently | |
146 | // don't pad them, and so they should be allocated in non-increasing order of required | |
147 | // alignment. Make sure to keep the code here in sync with the size-calculating code above. | |
7d31e928 A |
148 | // |
149 | CodeDirectory *CodeDirectory::Builder::build() | |
150 | { | |
151 | assert(mExec); // must have (successfully) called executable() | |
152 | ||
153 | // size and allocate | |
154 | size_t identLength = mIdentifier.size() + 1; | |
155 | size_t total = size(); | |
156 | if (!(mDir = (CodeDirectory *)calloc(1, total))) // initialize to zero | |
157 | UnixError::throwMe(ENOMEM); | |
158 | ||
159 | // fill header | |
160 | mDir->initialize(total); | |
161 | mDir->version = currentVersion; | |
162 | mDir->flags = mFlags; | |
163 | mDir->nSpecialSlots = mSpecialSlots; | |
164 | mDir->nCodeSlots = mCodeSlots; | |
165 | mDir->codeLimit = mExecLength; | |
f60086fc A |
166 | mDir->hashType = mHashType; |
167 | mDir->hashSize = mDigestLength; | |
7d31e928 A |
168 | if (mPageSize) { |
169 | int pglog; | |
170 | assert(frexp(mPageSize, &pglog) == 0.5); // must be power of 2 | |
171 | frexp(mPageSize, &pglog); | |
172 | assert(pglog < 256); | |
173 | mDir->pageSize = pglog - 1; | |
174 | } else | |
175 | mDir->pageSize = 0; // means infinite page size | |
176 | ||
177 | // locate and fill flex fields | |
178 | size_t offset = sizeof(CodeDirectory); | |
d1c1ab47 A |
179 | |
180 | if (mScatter) { | |
181 | mDir->scatterOffset = offset; | |
182 | memcpy(mDir->scatterVector(), mScatter, mScatterSize); | |
183 | offset += mScatterSize; | |
184 | } | |
185 | ||
7d31e928 A |
186 | mDir->identOffset = offset; |
187 | memcpy(mDir->identifier(), mIdentifier.c_str(), identLength); | |
188 | offset += identLength; | |
189 | ||
190 | // (add new flexibly-allocated fields here) | |
191 | ||
f60086fc A |
192 | mDir->hashOffset = offset + mSpecialSlots * mDigestLength; |
193 | offset += (mSpecialSlots + mCodeSlots) * mDigestLength; | |
7d31e928 A |
194 | assert(offset == total); // matches allocated size |
195 | ||
196 | // fill special slots | |
f60086fc | 197 | memset((*mDir)[-mSpecialSlots], 0, mDigestLength * mSpecialSlots); |
7d31e928 | 198 | for (size_t slot = 1; slot <= mSpecialSlots; ++slot) |
f60086fc | 199 | memcpy((*mDir)[-slot], specialSlot(slot), mDigestLength); |
7d31e928 A |
200 | |
201 | // fill code slots | |
202 | mExec.seek(mExecOffset); | |
203 | size_t remaining = mExecLength; | |
204 | for (unsigned int slot = 0; slot < mCodeSlots; ++slot) { | |
205 | size_t thisPage = min(mPageSize, remaining); | |
f60086fc A |
206 | MakeHash<Builder> hasher(this); |
207 | generateHash(hasher, mExec, (*mDir)[slot], thisPage); | |
7d31e928 A |
208 | remaining -= thisPage; |
209 | } | |
210 | ||
211 | // all done. Pass ownership to caller | |
212 | return mDir; | |
213 | } | |
214 | ||
215 | ||
216 | } // CodeSigning | |
217 | } // Security |