]> git.saurik.com Git - apple/security.git/blame - OSX/libsecurity_codesigning/lib/diskimagerep.cpp
Security-57337.60.2.tar.gz
[apple/security.git] / OSX / libsecurity_codesigning / lib / diskimagerep.cpp
CommitLineData
e3d460c9
A
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
34namespace Security {
35namespace CodeSigning {
36
37using Security::n2h;
38using Security::h2n;
39using namespace UnixPlusPlus;
40
41
42static 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//
48struct UDIFSigning {
49 uint64_t fCodeSignatureOffset;
50 uint64_t fCodeSignatureLength;
51};
52
53UDIFSigning& sigFields(UDIFFileHeader& header);
54const UDIFSigning& sigFields(const UDIFFileHeader& header);
55
56UDIFSigning& sigFields(UDIFFileHeader& header)
57{
58 return *(UDIFSigning*)&header.fReserved;
59}
60
61const UDIFSigning& sigFields(const UDIFFileHeader& header)
62{
63 return *(UDIFSigning*)&header.fReserved;
64}
65
66bool 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//
88DiskImageRep::DiskImageRep(const char *path)
89 : SingleDiskRep(path)
90{
91 this->setup();
92}
93
94void 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//
130CFDataRef 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//
144bool 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//
154size_t DiskImageRep::signingLimit()
155{
156 return mEndOfDataOffset;
157}
158
159void 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//
178CFDataRef 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//
192string DiskImageRep::format()
193{
194 return "disk image";
195}
196
197void 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//
208DiskRep::Writer *DiskImageRep::writer()
209{
210 return new Writer(this);
211}
212
213
214//
215// Write a component.
216//
217void 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//
227void 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//
249void DiskImageRep::Writer::addDiscretionary(CodeDirectory::Builder &builder)
250{
251}
252
253
254} // end namespace CodeSigning
255} // end namespace Security