]> git.saurik.com Git - apple/libsecurity_codesigning.git/blob - lib/cdbuilder.cpp
eac0a4254ad0c6127ed000b1896d05c134ff44d5
[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), mDir(NULL)
44 {
45 memset(mSpecial, 0, sizeof(mSpecial));
46 }
47
48
49 //
50 // Set the source of the main executable (i.e. the code pages)
51 //
52 void CodeDirectory::Builder::executable(string path,
53 size_t pagesize, size_t offset, size_t length)
54 {
55 mExec.close(); // any previously opened one
56 mExec.open(path);
57 mPageSize = pagesize;
58 mExecOffset = offset;
59 mExecLength = length;
60 }
61
62 void CodeDirectory::Builder::reopen(string path, size_t offset, size_t length)
63 {
64 assert(mExec); // already called executable()
65 mExec.close();
66 mExec.open(path);
67 mExecOffset = offset;
68 mExecLength = length;
69 }
70
71
72 //
73 // Set the source for one special slot
74 //
75 void CodeDirectory::Builder::special(size_t slot, CFDataRef data)
76 {
77 assert(slot <= cdSlotMax);
78 Hash hash;
79 hash(CFDataGetBytePtr(data), CFDataGetLength(data));
80 hash.finish(mSpecial[slot]);
81 if (slot >= mSpecialSlots)
82 mSpecialSlots = slot;
83 }
84
85
86 size_t CodeDirectory::Builder::size()
87 {
88 assert(mExec); // must have called executable()
89 if (mExecLength == 0)
90 mExecLength = mExec.fileSize() - mExecOffset;
91
92 // how many code pages?
93 if (mPageSize == 0) { // indefinite - one page
94 mCodeSlots = (mExecLength > 0);
95 } else { // finite - calculate from file size
96 mCodeSlots = (mExecLength + mPageSize - 1) / mPageSize; // round up
97 }
98
99 size_t offset = sizeof(CodeDirectory);
100 offset += mIdentifier.size() + 1; // size of identifier (with null byte)
101 offset += (mCodeSlots + mSpecialSlots) * Hash::digestLength; // hash vector
102 return offset;
103 }
104
105
106 //
107 // Take everything added to date and wrap it up in a shiny new CodeDirectory.
108 //
109 // Note that this doesn't include or generate the signature. You're free to
110 // modify the result. But this function determines the memory layout, so the
111 // sizes and counts should be correct on entry.
112 //
113 CodeDirectory *CodeDirectory::Builder::build()
114 {
115 assert(mExec); // must have (successfully) called executable()
116
117 // size and allocate
118 size_t identLength = mIdentifier.size() + 1;
119 size_t total = size();
120 if (!(mDir = (CodeDirectory *)calloc(1, total))) // initialize to zero
121 UnixError::throwMe(ENOMEM);
122
123 // fill header
124 mDir->initialize(total);
125 mDir->version = currentVersion;
126 mDir->flags = mFlags;
127 mDir->nSpecialSlots = mSpecialSlots;
128 mDir->nCodeSlots = mCodeSlots;
129 mDir->codeLimit = mExecLength;
130 mDir->hashSize = Hash::digestLength;
131 mDir->hashType = cdHashTypeDefault;
132 if (mPageSize) {
133 int pglog;
134 assert(frexp(mPageSize, &pglog) == 0.5); // must be power of 2
135 frexp(mPageSize, &pglog);
136 assert(pglog < 256);
137 mDir->pageSize = pglog - 1;
138 } else
139 mDir->pageSize = 0; // means infinite page size
140
141 // locate and fill flex fields
142 size_t offset = sizeof(CodeDirectory);
143 mDir->identOffset = offset;
144 memcpy(mDir->identifier(), mIdentifier.c_str(), identLength);
145 offset += identLength;
146
147 // (add new flexibly-allocated fields here)
148
149 mDir->hashOffset = offset + mSpecialSlots * Hash::digestLength;
150 offset += (mSpecialSlots + mCodeSlots) * Hash::digestLength;
151 assert(offset == total); // matches allocated size
152
153 // fill special slots
154 memset((*mDir)[-mSpecialSlots], 0, mDir->hashSize * mSpecialSlots);
155 for (size_t slot = 1; slot <= mSpecialSlots; ++slot)
156 memcpy((*mDir)[-slot], &mSpecial[slot], Hash::digestLength);
157
158 // fill code slots
159 mExec.seek(mExecOffset);
160 size_t remaining = mExecLength;
161 for (unsigned int slot = 0; slot < mCodeSlots; ++slot) {
162 size_t thisPage = min(mPageSize, remaining);
163 hash(mExec, (*mDir)[slot], thisPage);
164 remaining -= thisPage;
165 }
166
167 // all done. Pass ownership to caller
168 return mDir;
169 }
170
171
172 } // CodeSigning
173 } // Security