]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_codesigning/lib/diskimagerep.cpp
Security-58286.270.3.0.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)
73 {
74 this->setup();
75 }
76
77 void DiskImageRep::setup()
78 {
79 mSigningData = NULL;
80
81 // the UDIF "header" is in fact the last 512 bytes of the file, with no particular alignment
82 if (!readHeader(fd(), this->mHeader))
83 UnixError::throwMe(errSecCSBadDiskImageFormat);
84
85 mHeaderOffset = fd().fileSize() - sizeof(UDIFFileHeader);
86 size_t signatureOffset = size_t(n2h(this->mHeader.fUDIFCodeSignOffset));
87 size_t signatureLength = size_t(n2h(this->mHeader.fUDIFCodeSignLength));
88 this->mHeader.fUDIFCodeSignLength = 0; // blind length (signature covers header)
89 if (signatureOffset == 0) {
90 mEndOfDataOffset = mHeaderOffset;
91 mHeader.fUDIFCodeSignOffset = h2n(mHeaderOffset);
92 return; // unsigned, header prepared for possible signing
93 } else {
94 mEndOfDataOffset = signatureOffset;
95 }
96
97 // read the signature superblob
98 const size_t frameLength = mHeaderOffset - signatureOffset; // room to following header
99 if (EmbeddedSignatureBlob* blob = EmbeddedSignatureBlob::readBlob(fd(), signatureOffset, frameLength)) {
100 if (blob->length() != frameLength
101 || frameLength != signatureLength
102 || !blob->strictValidateBlob(frameLength)) {
103 free(blob);
104 MacOSError::throwMe(errSecCSBadDiskImageFormat);
105 }
106 mSigningData = blob;
107 }
108 }
109
110
111 //
112 // The default binary identification of a SingleDiskRep is the (SHA-1) hash
113 // of the entire file itself.
114 //
115 CFDataRef DiskImageRep::identification()
116 {
117 SHA1 hash; // not security sensitive
118 hash(&mHeader, sizeof(mHeader));
119 SHA1::Digest digest;
120 hash.finish(digest);
121 return makeCFData(digest, sizeof(digest));
122 }
123
124
125 //
126 // Sniffer function for UDIF disk image files.
127 // This just looks for the trailing "header" and its magic number.
128 //
129 bool DiskImageRep::candidate(FileDesc &fd)
130 {
131 UDIFFileHeader header;
132 return readHeader(fd, header) == true;
133 }
134
135
136 //
137 // Signing limit is the start of the (trailing) signature
138 //
139 size_t DiskImageRep::signingLimit()
140 {
141 return mEndOfDataOffset;
142 }
143
144 void DiskImageRep::strictValidate(const CodeDirectory* cd, const ToleratedErrors& tolerated, SecCSFlags flags)
145 {
146 DiskRep::strictValidate(cd, tolerated, flags);
147
148 if (cd) {
149 size_t cd_limit = cd->signingLimit();
150 size_t dr_limit = signingLimit();
151 if (cd_limit != dr_limit && // must cover exactly the entire data
152 cd_limit != fd().fileSize()) // or, for legacy detached sigs, the entire file
153 MacOSError::throwMe(errSecCSSignatureInvalid);
154 }
155 }
156
157
158 //
159 // Retrieve a component from the executable.
160 // Our mCache has mapped the entire file, so we just fish the contents out of
161 // the mapped area as needed.
162 //
163 CFDataRef DiskImageRep::component(CodeDirectory::SpecialSlot slot)
164 {
165 switch (slot) {
166 case cdRepSpecificSlot:
167 return makeCFData(&mHeader, sizeof(mHeader));
168 default:
169 return mSigningData ? mSigningData->component(slot) : NULL;
170 }
171 }
172
173
174 //
175 // Provide a (vaguely) human readable characterization of this code
176 //
177 string DiskImageRep::format()
178 {
179 return "disk image";
180 }
181
182 void DiskImageRep::prepareForSigning(SigningContext& context)
183 {
184 // default to SHA256 unconditionally - we have no legacy issues to worry about
185 if (context.digestAlgorithms().empty())
186 context.setDigestAlgorithm(kSecCodeSignatureHashSHA256);
187 }
188
189
190 //
191 // DiskImageRep::Writers
192 //
193 DiskRep::Writer *DiskImageRep::writer()
194 {
195 return new Writer(this);
196 }
197
198
199 //
200 // Write a component.
201 //
202 void DiskImageRep::Writer::component(CodeDirectory::SpecialSlot slot, CFDataRef data)
203 {
204 assert(slot != cdRepSpecificSlot);
205 EmbeddedSignatureBlob::Maker::component(slot, data);
206 }
207
208
209 //
210 // Append the superblob we built to the cache file.
211 //
212 void DiskImageRep::Writer::flush()
213 {
214 delete mSigningData; // ditch previous blob just in case
215 mSigningData = Maker::make(); // assemble new signature SuperBlob
216
217 // write signature superblob
218 size_t location = rep->mEndOfDataOffset;
219 assert(location);
220 fd().seek(location);
221 fd().writeAll(*mSigningData); // write signature
222
223 // now (re)write disk image header after it
224 UDIFFileHeader fullHeader = rep->mHeader;
225 fullHeader.fUDIFCodeSignOffset = h2n(location);
226 fullHeader.fUDIFCodeSignLength = h2n(mSigningData->length());
227 fd().writeAll(&fullHeader, sizeof(rep->mHeader));
228 fd().truncate(fd().position());
229 }
230
231
232 //
233 // Discretionary manipulations
234 //
235 void DiskImageRep::Writer::addDiscretionary(CodeDirectory::Builder &builder)
236 {
237 }
238
239 void DiskImageRep::registerStapledTicket()
240 {
241 CFRef<CFDataRef> data = NULL;
242 if (mSigningData) {
243 data.take(mSigningData->component(cdTicketSlot));
244 registerStapledTicketInDMG(data);
245 }
246 }
247
248
249 } // end namespace CodeSigning
250 } // end namespace Security