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