]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_codesigning/lib/diskimagerep.cpp
Security-59306.101.1.tar.gz
[apple/security.git] / OSX / libsecurity_codesigning / lib / diskimagerep.cpp
1 /*
2 * Copyright (c) 2015 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 // diskimagerep - DiskRep representing a single read-only compressed disk image file
26 //
27 #include "diskimagerep.h"
28 #include "notarization.h"
29 #include "sigblob.h"
30 #include "CodeSigner.h"
31 #include <security_utilities/endian.h>
32 #include <algorithm>
33
34
35 namespace Security {
36 namespace CodeSigning {
37
38 using Security::n2h;
39 using Security::h2n;
40 using namespace UnixPlusPlus;
41
42
43 static const int32_t udifVersion = 4; // supported image file version
44
45
46 //
47 // Temporary hack to imply a fUDIFCryptosigFieldsset at the start of the "reserved" area of an UDIF header
48 //
49 bool DiskImageRep::readHeader(FileDesc& fd, UDIFFileHeader& header)
50 {
51 // the UDIF "header" is in fact the last 512 bytes of the file, with no particular alignment
52 static const size_t headerLength = sizeof(header);
53 size_t length = fd.fileSize();
54 if (length < sizeof(UDIFFileHeader) + sizeof(BlobCore))
55 return false;
56 size_t headerOffset = length - sizeof(UDIFFileHeader);
57 if (fd.read(&header, headerLength, headerOffset) != headerLength)
58 return false;
59 if (n2h(header.fUDIFSignature) != kUDIFSignature)
60 return false;
61 if (n2h(header.fUDIFVersion) != udifVersion) // current as of this writing
62 return false;
63
64 return true;
65 }
66
67
68 //
69 // Object management.
70 //
71 DiskImageRep::DiskImageRep(const char *path)
72 : SingleDiskRep(path), mSigningData(NULL)
73 {
74 this->setup();
75 }
76
77 DiskImageRep::~DiskImageRep()
78 {
79 free((void*)mSigningData);
80 }
81
82 void DiskImageRep::setup()
83 {
84 free((void*)mSigningData);
85 mSigningData = NULL;
86
87 // the UDIF "header" is in fact the last 512 bytes of the file, with no particular alignment
88 if (!readHeader(fd(), this->mHeader))
89 UnixError::throwMe(errSecCSBadDiskImageFormat);
90
91 mHeaderOffset = fd().fileSize() - sizeof(UDIFFileHeader);
92 size_t signatureOffset = size_t(n2h(this->mHeader.fUDIFCodeSignOffset));
93 size_t signatureLength = size_t(n2h(this->mHeader.fUDIFCodeSignLength));
94 this->mHeader.fUDIFCodeSignLength = 0; // blind length (signature covers header)
95 if (signatureOffset == 0) {
96 mEndOfDataOffset = mHeaderOffset;
97 mHeader.fUDIFCodeSignOffset = h2n(mHeaderOffset);
98 return; // unsigned, header prepared for possible signing
99 } else {
100 mEndOfDataOffset = signatureOffset;
101 }
102
103 // read the signature superblob
104 const size_t frameLength = mHeaderOffset - signatureOffset; // room to following header
105 if (EmbeddedSignatureBlob* blob = EmbeddedSignatureBlob::readBlob(fd(), signatureOffset, frameLength)) {
106 if (blob->length() != frameLength
107 || frameLength != signatureLength
108 || !blob->strictValidateBlob(frameLength)) {
109 free(blob);
110 MacOSError::throwMe(errSecCSBadDiskImageFormat);
111 }
112 mSigningData = blob;
113 }
114 }
115
116
117 //
118 // The default binary identification of a SingleDiskRep is the (SHA-1) hash
119 // of the entire file itself.
120 //
121 CFDataRef DiskImageRep::identification()
122 {
123 SHA1 hash; // not security sensitive
124 hash(&mHeader, sizeof(mHeader));
125 SHA1::Digest digest;
126 hash.finish(digest);
127 return makeCFData(digest, sizeof(digest));
128 }
129
130
131 //
132 // Sniffer function for UDIF disk image files.
133 // This just looks for the trailing "header" and its magic number.
134 //
135 bool DiskImageRep::candidate(FileDesc &fd)
136 {
137 UDIFFileHeader header;
138 return readHeader(fd, header) == true;
139 }
140
141
142 //
143 // Signing limit is the start of the (trailing) signature
144 //
145 size_t DiskImageRep::signingLimit()
146 {
147 return mEndOfDataOffset;
148 }
149
150 void DiskImageRep::strictValidate(const CodeDirectory* cd, const ToleratedErrors& tolerated, SecCSFlags flags)
151 {
152 DiskRep::strictValidate(cd, tolerated, flags);
153
154 if (cd) {
155 size_t cd_limit = cd->signingLimit();
156 size_t dr_limit = signingLimit();
157 if (cd_limit != dr_limit && // must cover exactly the entire data
158 cd_limit != fd().fileSize()) // or, for legacy detached sigs, the entire file
159 MacOSError::throwMe(errSecCSSignatureInvalid);
160 }
161 }
162
163
164 //
165 // Retrieve a component from the executable.
166 // Our mCache has mapped the entire file, so we just fish the contents out of
167 // the mapped area as needed.
168 //
169 CFDataRef DiskImageRep::component(CodeDirectory::SpecialSlot slot)
170 {
171 switch (slot) {
172 case cdRepSpecificSlot:
173 return makeCFData(&mHeader, sizeof(mHeader));
174 default:
175 return mSigningData ? mSigningData->component(slot) : NULL;
176 }
177 }
178
179
180 //
181 // Provide a (vaguely) human readable characterization of this code
182 //
183 string DiskImageRep::format()
184 {
185 return "disk image";
186 }
187
188 void DiskImageRep::prepareForSigning(SigningContext& context)
189 {
190 // default to SHA256 unconditionally - we have no legacy issues to worry about
191 if (context.digestAlgorithms().empty())
192 context.setDigestAlgorithm(kSecCodeSignatureHashSHA256);
193 }
194
195
196 //
197 // DiskImageRep::Writers
198 //
199 DiskRep::Writer *DiskImageRep::writer()
200 {
201 return new Writer(this);
202 }
203
204
205 //
206 // Write a component.
207 //
208 void DiskImageRep::Writer::component(CodeDirectory::SpecialSlot slot, CFDataRef data)
209 {
210 assert(slot != cdRepSpecificSlot);
211 EmbeddedSignatureBlob::Maker::component(slot, data);
212 }
213
214
215 //
216 // Append the superblob we built to the cache file.
217 //
218 void DiskImageRep::Writer::flush()
219 {
220 free((void*)mSigningData); // ditch previous blob just in case
221 mSigningData = Maker::make(); // assemble new signature SuperBlob
222
223 // write signature superblob
224 size_t location = rep->mEndOfDataOffset;
225 assert(location);
226 fd().seek(location);
227 fd().writeAll(*mSigningData); // write signature
228
229 // now (re)write disk image header after it
230 UDIFFileHeader fullHeader = rep->mHeader;
231 fullHeader.fUDIFCodeSignOffset = h2n(location);
232 fullHeader.fUDIFCodeSignLength = h2n(mSigningData->length());
233 fd().writeAll(&fullHeader, sizeof(rep->mHeader));
234 fd().truncate(fd().position());
235 }
236
237
238 //
239 // Discretionary manipulations
240 //
241 void DiskImageRep::Writer::addDiscretionary(CodeDirectory::Builder &builder)
242 {
243 }
244
245 void DiskImageRep::registerStapledTicket()
246 {
247 CFRef<CFDataRef> data = NULL;
248 if (mSigningData) {
249 data.take(mSigningData->component(cdTicketSlot));
250 registerStapledTicketInDMG(data);
251 }
252 }
253
254
255 } // end namespace CodeSigning
256 } // end namespace Security