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