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