]> git.saurik.com Git - apple/security.git/blame - OSX/libsecurity_codesigning/lib/diskimagerep.cpp
Security-59306.140.5.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"
79b9da22 28#include "notarization.h"
e3d460c9
A
29#include "sigblob.h"
30#include "CodeSigner.h"
31#include <security_utilities/endian.h>
32#include <algorithm>
33
34
35namespace Security {
36namespace CodeSigning {
37
38using Security::n2h;
39using Security::h2n;
40using namespace UnixPlusPlus;
41
42
43static 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//
e3d460c9
A
49bool 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//
71DiskImageRep::DiskImageRep(const char *path)
b3971512 72 : SingleDiskRep(path), mSigningData(NULL)
e3d460c9
A
73{
74 this->setup();
75}
76
b3971512
A
77DiskImageRep::~DiskImageRep()
78{
79 free((void*)mSigningData);
80}
81
e3d460c9
A
82void DiskImageRep::setup()
83{
b3971512 84 free((void*)mSigningData);
e3d460c9
A
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);
fa7225c8
A
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)
e3d460c9
A
95 if (signatureOffset == 0) {
96 mEndOfDataOffset = mHeaderOffset;
fa7225c8 97 mHeader.fUDIFCodeSignOffset = h2n(mHeaderOffset);
e3d460c9
A
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)) {
fa7225c8
A
106 if (blob->length() != frameLength
107 || frameLength != signatureLength
108 || !blob->strictValidateBlob(frameLength)) {
e3d460c9
A
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//
121CFDataRef 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//
135bool 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//
145size_t DiskImageRep::signingLimit()
146{
147 return mEndOfDataOffset;
148}
149
150void 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//
169CFDataRef 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//
183string DiskImageRep::format()
184{
185 return "disk image";
186}
187
188void 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//
199DiskRep::Writer *DiskImageRep::writer()
200{
201 return new Writer(this);
202}
203
204
205//
206// Write a component.
207//
208void 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//
218void DiskImageRep::Writer::flush()
219{
b3971512 220 free((void*)mSigningData); // ditch previous blob just in case
e3d460c9
A
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;
fa7225c8
A
231 fullHeader.fUDIFCodeSignOffset = h2n(location);
232 fullHeader.fUDIFCodeSignLength = h2n(mSigningData->length());
e3d460c9 233 fd().writeAll(&fullHeader, sizeof(rep->mHeader));
fa7225c8 234 fd().truncate(fd().position());
e3d460c9
A
235}
236
237
238//
239// Discretionary manipulations
240//
241void DiskImageRep::Writer::addDiscretionary(CodeDirectory::Builder &builder)
242{
243}
244
79b9da22
A
245void DiskImageRep::registerStapledTicket()
246{
247 CFRef<CFDataRef> data = NULL;
248 if (mSigningData) {
249 data.take(mSigningData->component(cdTicketSlot));
250 registerStapledTicketInDMG(data);
251 }
252}
253
e3d460c9
A
254
255} // end namespace CodeSigning
256} // end namespace Security