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" 
  28 #include "notarization.h" 
  30 #include "CodeSigner.h" 
  31 #include <security_utilities/endian.h> 
  36 namespace CodeSigning 
{ 
  40 using namespace UnixPlusPlus
; 
  43 static const int32_t udifVersion 
= 4;           // supported image file version 
  47 // Temporary hack to imply a fUDIFCryptosigFieldsset at the start of the "reserved" area of an UDIF header 
  49 bool DiskImageRep::readHeader(FileDesc
& fd
, UDIFFileHeader
& header
) 
  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
)) 
  56         size_t headerOffset 
= length 
- sizeof(UDIFFileHeader
); 
  57         if (fd
.read(&header
, headerLength
, headerOffset
) != headerLength
) 
  59         if (n2h(header
.fUDIFSignature
) != kUDIFSignature
) 
  61         if (n2h(header
.fUDIFVersion
) != udifVersion
)    // current as of this writing 
  71 DiskImageRep::DiskImageRep(const char *path
) 
  77 void DiskImageRep::setup() 
  81         // the UDIF "header" is in fact the last 512 bytes of the file, with no particular alignment 
  82         if (!readHeader(fd(), this->mHeader
)) 
  83                 UnixError::throwMe(errSecCSBadDiskImageFormat
); 
  85         mHeaderOffset 
= fd().fileSize() - sizeof(UDIFFileHeader
); 
  86         size_t signatureOffset 
= size_t(n2h(this->mHeader
.fUDIFCodeSignOffset
)); 
  87         size_t signatureLength 
= size_t(n2h(this->mHeader
.fUDIFCodeSignLength
)); 
  88         this->mHeader
.fUDIFCodeSignLength 
= 0;          // blind length (signature covers header) 
  89         if (signatureOffset 
== 0) { 
  90                 mEndOfDataOffset 
= mHeaderOffset
; 
  91                 mHeader
.fUDIFCodeSignOffset 
= h2n(mHeaderOffset
); 
  92                 return;         // unsigned, header prepared for possible signing 
  94                 mEndOfDataOffset 
= signatureOffset
; 
  97         // read the signature superblob 
  98         const size_t frameLength 
= mHeaderOffset 
- signatureOffset
;             // room to following header 
  99         if (EmbeddedSignatureBlob
* blob 
= EmbeddedSignatureBlob::readBlob(fd(), signatureOffset
, frameLength
)) { 
 100                 if (blob
->length() != frameLength
 
 101                                 || frameLength 
!= signatureLength
 
 102                                 || !blob
->strictValidateBlob(frameLength
)) { 
 104                         MacOSError::throwMe(errSecCSBadDiskImageFormat
); 
 112 // The default binary identification of a SingleDiskRep is the (SHA-1) hash 
 113 // of the entire file itself. 
 115 CFDataRef 
DiskImageRep::identification() 
 117         SHA1 hash
;              // not security sensitive 
 118         hash(&mHeader
, sizeof(mHeader
)); 
 121         return makeCFData(digest
, sizeof(digest
)); 
 126 // Sniffer function for UDIF disk image files. 
 127 // This just looks for the trailing "header" and its magic number. 
 129 bool DiskImageRep::candidate(FileDesc 
&fd
) 
 131         UDIFFileHeader header
; 
 132         return readHeader(fd
, header
) == true; 
 137 // Signing limit is the start of the (trailing) signature 
 139 size_t DiskImageRep::signingLimit() 
 141         return mEndOfDataOffset
; 
 144 void DiskImageRep::strictValidate(const CodeDirectory
* cd
, const ToleratedErrors
& tolerated
, SecCSFlags flags
) 
 146     DiskRep::strictValidate(cd
, tolerated
, flags
); 
 149         size_t cd_limit 
= cd
->signingLimit(); 
 150         size_t dr_limit 
= signingLimit(); 
 151         if (cd_limit 
!= dr_limit 
&&         // must cover exactly the entire data 
 152             cd_limit 
!= fd().fileSize())    // or, for legacy detached sigs, the entire file 
 153             MacOSError::throwMe(errSecCSSignatureInvalid
); 
 159 // Retrieve a component from the executable. 
 160 // Our mCache has mapped the entire file, so we just fish the contents out of 
 161 // the mapped area as needed. 
 163 CFDataRef 
DiskImageRep::component(CodeDirectory::SpecialSlot slot
) 
 166         case cdRepSpecificSlot
: 
 167                 return makeCFData(&mHeader
, sizeof(mHeader
)); 
 169                 return mSigningData 
? mSigningData
->component(slot
) : NULL
; 
 175 // Provide a (vaguely) human readable characterization of this code 
 177 string 
DiskImageRep::format() 
 182 void DiskImageRep::prepareForSigning(SigningContext
& context
) 
 184         // default to SHA256 unconditionally - we have no legacy issues to worry about 
 185         if (context
.digestAlgorithms().empty()) 
 186                 context
.setDigestAlgorithm(kSecCodeSignatureHashSHA256
); 
 191 // DiskImageRep::Writers 
 193 DiskRep::Writer 
*DiskImageRep::writer() 
 195         return new Writer(this); 
 200 // Write a component. 
 202 void DiskImageRep::Writer::component(CodeDirectory::SpecialSlot slot
, CFDataRef data
) 
 204         assert(slot 
!= cdRepSpecificSlot
); 
 205         EmbeddedSignatureBlob::Maker::component(slot
, data
); 
 210 // Append the superblob we built to the cache file. 
 212 void DiskImageRep::Writer::flush() 
 214         delete mSigningData
;                    // ditch previous blob just in case 
 215         mSigningData 
= Maker::make();   // assemble new signature SuperBlob 
 217         // write signature superblob 
 218         size_t location 
= rep
->mEndOfDataOffset
; 
 221         fd().writeAll(*mSigningData
);   // write signature 
 223         // now (re)write disk image header after it 
 224         UDIFFileHeader fullHeader 
= rep
->mHeader
; 
 225         fullHeader
.fUDIFCodeSignOffset 
= h2n(location
); 
 226         fullHeader
.fUDIFCodeSignLength 
= h2n(mSigningData
->length()); 
 227         fd().writeAll(&fullHeader
, sizeof(rep
->mHeader
)); 
 228     fd().truncate(fd().position()); 
 233 // Discretionary manipulations 
 235 void DiskImageRep::Writer::addDiscretionary(CodeDirectory::Builder 
&builder
) 
 239 void DiskImageRep::registerStapledTicket() 
 241         CFRef
<CFDataRef
> data 
= NULL
; 
 243                 data
.take(mSigningData
->component(cdTicketSlot
)); 
 244                 registerStapledTicketInDMG(data
); 
 249 } // end namespace CodeSigning 
 250 } // end namespace Security