2 * Copyright (c) 2015 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
25 // diskimagerep - DiskRep representing a single read-only compressed disk image file
27 #include "diskimagerep.h"
29 #include "CodeSigner.h"
30 #include <security_utilities/endian.h>
35 namespace CodeSigning
{
39 using namespace UnixPlusPlus
;
42 static const int32_t udifVersion
= 4; // supported image file version
46 // Temporary hack to imply a fUDIFCryptosigFieldsset at the start of the "reserved" area of an UDIF header
48 bool DiskImageRep::readHeader(FileDesc
& fd
, UDIFFileHeader
& header
)
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
))
55 size_t headerOffset
= length
- sizeof(UDIFFileHeader
);
56 if (fd
.read(&header
, headerLength
, headerOffset
) != headerLength
)
58 if (n2h(header
.fUDIFSignature
) != kUDIFSignature
)
60 if (n2h(header
.fUDIFVersion
) != udifVersion
) // current as of this writing
70 DiskImageRep::DiskImageRep(const char *path
)
76 void DiskImageRep::setup()
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
);
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
93 mEndOfDataOffset
= signatureOffset
;
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
)) {
103 MacOSError::throwMe(errSecCSBadDiskImageFormat
);
111 // The default binary identification of a SingleDiskRep is the (SHA-1) hash
112 // of the entire file itself.
114 CFDataRef
DiskImageRep::identification()
116 SHA1 hash
; // not security sensitive
117 hash(&mHeader
, sizeof(mHeader
));
120 return makeCFData(digest
, sizeof(digest
));
125 // Sniffer function for UDIF disk image files.
126 // This just looks for the trailing "header" and its magic number.
128 bool DiskImageRep::candidate(FileDesc
&fd
)
130 UDIFFileHeader header
;
131 return readHeader(fd
, header
) == true;
136 // Signing limit is the start of the (trailing) signature
138 size_t DiskImageRep::signingLimit()
140 return mEndOfDataOffset
;
143 void DiskImageRep::strictValidate(const CodeDirectory
* cd
, const ToleratedErrors
& tolerated
, SecCSFlags flags
)
145 DiskRep::strictValidate(cd
, tolerated
, flags
);
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
);
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.
162 CFDataRef
DiskImageRep::component(CodeDirectory::SpecialSlot slot
)
165 case cdRepSpecificSlot
:
166 return makeCFData(&mHeader
, sizeof(mHeader
));
168 return mSigningData
? mSigningData
->component(slot
) : NULL
;
174 // Provide a (vaguely) human readable characterization of this code
176 string
DiskImageRep::format()
181 void DiskImageRep::prepareForSigning(SigningContext
& context
)
183 // default to SHA256 unconditionally - we have no legacy issues to worry about
184 if (context
.digestAlgorithms().empty())
185 context
.setDigestAlgorithm(kSecCodeSignatureHashSHA256
);
190 // DiskImageRep::Writers
192 DiskRep::Writer
*DiskImageRep::writer()
194 return new Writer(this);
199 // Write a component.
201 void DiskImageRep::Writer::component(CodeDirectory::SpecialSlot slot
, CFDataRef data
)
203 assert(slot
!= cdRepSpecificSlot
);
204 EmbeddedSignatureBlob::Maker::component(slot
, data
);
209 // Append the superblob we built to the cache file.
211 void DiskImageRep::Writer::flush()
213 delete mSigningData
; // ditch previous blob just in case
214 mSigningData
= Maker::make(); // assemble new signature SuperBlob
216 // write signature superblob
217 size_t location
= rep
->mEndOfDataOffset
;
220 fd().writeAll(*mSigningData
); // write signature
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());
232 // Discretionary manipulations
234 void DiskImageRep::Writer::addDiscretionary(CodeDirectory::Builder
&builder
)
239 } // end namespace CodeSigning
240 } // end namespace Security