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