]>
git.saurik.com Git - apple/libsecurity_codesigning.git/blob - lib/cdbuilder.cpp
6d63525d7decdc5536cd36444cc6564a5250ef28
2 * Copyright (c) 2006 Apple Computer, Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
25 // cdbuilder - constructor for CodeDirectories
27 #include "cdbuilder.h"
28 #include <security_utilities/memutils.h>
31 using namespace UnixPlusPlus
;
32 using LowLevelMemoryUtilities::alignUp
;
36 namespace CodeSigning
{
40 // Create an (empty) builder
42 CodeDirectory::Builder::Builder()
43 : mFlags(0), mSpecialSlots(0), mCodeSlots(0), mScatter(NULL
), mScatterSize(0), mDir(NULL
)
45 memset(mSpecial
, 0, sizeof(mSpecial
));
48 CodeDirectory::Builder::~Builder()
55 // Set the source of the main executable (i.e. the code pages)
57 void CodeDirectory::Builder::executable(string path
,
58 size_t pagesize
, size_t offset
, size_t length
)
60 mExec
.close(); // any previously opened one
67 void CodeDirectory::Builder::reopen(string path
, size_t offset
, size_t length
)
69 assert(mExec
); // already called executable()
78 // Set the source for one special slot
80 void CodeDirectory::Builder::special(size_t slot
, CFDataRef data
)
82 assert(slot
<= cdSlotMax
);
84 hash(CFDataGetBytePtr(data
), CFDataGetLength(data
));
85 hash
.finish(mSpecial
[slot
]);
86 if (slot
>= mSpecialSlots
)
92 // Allocate a Scatter vector
94 CodeDirectory::Scatter
*CodeDirectory::Builder::scatter(unsigned count
)
96 mScatterSize
= (count
+ 1) * sizeof(Scatter
);
97 if (!(mScatter
= (Scatter
*)::realloc(mScatter
, mScatterSize
)))
98 UnixError::throwMe(ENOMEM
);
99 ::memset(mScatter
, 0, mScatterSize
);
105 // Calculate the size we'll need for the CodeDirectory as described so far
107 size_t CodeDirectory::Builder::size()
109 assert(mExec
); // must have called executable()
110 if (mExecLength
== 0)
111 mExecLength
= mExec
.fileSize() - mExecOffset
;
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
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
129 // Take everything added to date and wrap it up in a shiny new CodeDirectory.
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.
141 CodeDirectory
*CodeDirectory::Builder::build()
143 assert(mExec
); // must have (successfully) called executable()
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
);
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
;
162 assert(frexp(mPageSize
, &pglog
) == 0.5); // must be power of 2
163 frexp(mPageSize
, &pglog
);
165 mDir
->pageSize
= pglog
- 1;
167 mDir
->pageSize
= 0; // means infinite page size
169 // locate and fill flex fields
170 size_t offset
= sizeof(CodeDirectory
);
173 mDir
->scatterOffset
= offset
;
174 memcpy(mDir
->scatterVector(), mScatter
, mScatterSize
);
175 offset
+= mScatterSize
;
178 mDir
->identOffset
= offset
;
179 memcpy(mDir
->identifier(), mIdentifier
.c_str(), identLength
);
180 offset
+= identLength
;
182 // (add new flexibly-allocated fields here)
184 mDir
->hashOffset
= offset
+ mSpecialSlots
* Hash::digestLength
;
185 offset
+= (mSpecialSlots
+ mCodeSlots
) * Hash::digestLength
;
186 assert(offset
== total
); // matches allocated size
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
);
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
;
202 // all done. Pass ownership to caller