]>
git.saurik.com Git - apple/libsecurity_codesigning.git/blob - lib/cdbuilder.cpp
eac0a4254ad0c6127ed000b1896d05c134ff44d5
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), mDir(NULL
)
45 memset(mSpecial
, 0, sizeof(mSpecial
));
50 // Set the source of the main executable (i.e. the code pages)
52 void CodeDirectory::Builder::executable(string path
,
53 size_t pagesize
, size_t offset
, size_t length
)
55 mExec
.close(); // any previously opened one
62 void CodeDirectory::Builder::reopen(string path
, size_t offset
, size_t length
)
64 assert(mExec
); // already called executable()
73 // Set the source for one special slot
75 void CodeDirectory::Builder::special(size_t slot
, CFDataRef data
)
77 assert(slot
<= cdSlotMax
);
79 hash(CFDataGetBytePtr(data
), CFDataGetLength(data
));
80 hash
.finish(mSpecial
[slot
]);
81 if (slot
>= mSpecialSlots
)
86 size_t CodeDirectory::Builder::size()
88 assert(mExec
); // must have called executable()
90 mExecLength
= mExec
.fileSize() - mExecOffset
;
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
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
107 // Take everything added to date and wrap it up in a shiny new CodeDirectory.
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.
113 CodeDirectory
*CodeDirectory::Builder::build()
115 assert(mExec
); // must have (successfully) called executable()
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
);
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
;
134 assert(frexp(mPageSize
, &pglog
) == 0.5); // must be power of 2
135 frexp(mPageSize
, &pglog
);
137 mDir
->pageSize
= pglog
- 1;
139 mDir
->pageSize
= 0; // means infinite page size
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
;
147 // (add new flexibly-allocated fields here)
149 mDir
->hashOffset
= offset
+ mSpecialSlots
* Hash::digestLength
;
150 offset
+= (mSpecialSlots
+ mCodeSlots
) * Hash::digestLength
;
151 assert(offset
== total
); // matches allocated size
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
);
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
;
167 // all done. Pass ownership to caller