]> git.saurik.com Git - apple/security.git/blob - libsecurity_codesigning/lib/cdbuilder.cpp
Security-55163.44.tar.gz
[apple/security.git] / libsecurity_codesigning / lib / cdbuilder.cpp
1 /*
2 * Copyright (c) 2006-2010 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 mSpecialSlots(0),
46 mCodeSlots(0),
47 mScatter(NULL),
48 mScatterSize(0),
49 mDir(NULL)
50 {
51 mDigestLength = MakeHash<Builder>(this)->digestLength();
52 mSpecial = (unsigned char *)calloc(cdSlotMax, mDigestLength);
53 }
54
55 CodeDirectory::Builder::~Builder()
56 {
57 ::free(mSpecial);
58 ::free(mScatter);
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 //
88 void CodeDirectory::Builder::specialSlot(SpecialSlot slot, CFDataRef data)
89 {
90 assert(slot <= cdSlotMax);
91 MakeHash<Builder> hash(this);
92 hash->update(CFDataGetBytePtr(data), CFDataGetLength(data));
93 hash->finish(specialSlot(slot));
94 if (slot >= mSpecialSlots)
95 mSpecialSlots = slot;
96 }
97
98
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 //
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);
129 offset += mScatterSize; // scatter vector
130 offset += mIdentifier.size() + 1; // size of identifier (with null byte)
131 offset += (mCodeSlots + mSpecialSlots) * mDigestLength; // hash vector
132 return offset;
133 }
134
135
136 //
137 // Take everything added to date and wrap it up in a shiny new CodeDirectory.
138 //
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.
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;
166 mDir->hashType = mHashType;
167 mDir->hashSize = mDigestLength;
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);
179
180 if (mScatter) {
181 mDir->scatterOffset = offset;
182 memcpy(mDir->scatterVector(), mScatter, mScatterSize);
183 offset += mScatterSize;
184 }
185
186 mDir->identOffset = offset;
187 memcpy(mDir->identifier(), mIdentifier.c_str(), identLength);
188 offset += identLength;
189
190 // (add new flexibly-allocated fields here)
191
192 mDir->hashOffset = offset + mSpecialSlots * mDigestLength;
193 offset += (mSpecialSlots + mCodeSlots) * mDigestLength;
194 assert(offset == total); // matches allocated size
195
196 // fill special slots
197 memset((*mDir)[-mSpecialSlots], 0, mDigestLength * mSpecialSlots);
198 for (size_t slot = 1; slot <= mSpecialSlots; ++slot)
199 memcpy((*mDir)[-slot], specialSlot(slot), mDigestLength);
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);
206 MakeHash<Builder> hasher(this);
207 generateHash(hasher, mExec, (*mDir)[slot], thisPage);
208 remaining -= thisPage;
209 }
210
211 // all done. Pass ownership to caller
212 return mDir;
213 }
214
215
216 } // CodeSigning
217 } // Security