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