/ OSX / libsecurity_codesigning / lib / drmaker.cpp
drmaker.cpp
  1  /*
  2   * Copyright (c) 2012 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  // drmaker - create automatic Designated Requirements
 26  //
 27  #include "drmaker.h"
 28  #include "csutilities.h"
 29  #include <Security/oidsbase.h>
 30  #include <Security/SecCertificatePriv.h>
 31  //#include <Security/cssmapplePriv.h>
 32  
 33  namespace Security {
 34  namespace CodeSigning {
 35  
 36  
 37  static const uint8_t adcSdkMarker[] = { APPLE_EXTENSION_OID, 2, 1 };		// iOS intermediate marker
 38  const CSSM_DATA adcSdkMarkerOID = { sizeof(adcSdkMarker), (uint8_t *)adcSdkMarker };
 39  
 40  static const uint8_t caspianSdkMarker[] = { APPLE_EXTENSION_OID, 2, 6 }; // Caspian intermediate marker
 41  const CSSM_DATA devIdSdkMarkerOID = { sizeof(caspianSdkMarker), (uint8_t *)caspianSdkMarker };
 42  static const uint8_t caspianLeafMarker[] = { APPLE_EXTENSION_OID, 1, 13 }; // Caspian leaf certificate marker
 43  const CSSM_DATA devIdLeafMarkerOID = { sizeof(caspianLeafMarker), (uint8_t *)caspianLeafMarker };
 44  
 45  
 46  
 47  DRMaker::DRMaker(const Requirement::Context &context)
 48  	: ctx(context)
 49  {
 50  }
 51  
 52  DRMaker::~DRMaker()
 53  {
 54  }
 55  
 56  
 57  //
 58  // Generate the default (implicit) Designated Requirement for this StaticCode.
 59  // This is a heuristic of sorts, and may change over time (for the better, we hope).
 60  //
 61  Requirement *DRMaker::make()
 62  {
 63  	// we can't make an explicit DR for a (proposed) ad-hoc signing because that requires the CodeDirectory (which we ain't got yet)
 64  	if (ctx.certCount() == 0)
 65  		return NULL;
 66  
 67  	// always require the identifier
 68  	this->put(opAnd);
 69  	this->ident(ctx.identifier);
 70  	
 71  	if (isAppleCA(ctx.cert(Requirement::anchorCert))
 72  #if	defined(TEST_APPLE_ANCHOR)
 73  		|| !memcmp(anchorHash, Requirement::testAppleAnchorHash(), SHA1::digestLength)
 74  #endif
 75  		)
 76  		appleAnchor();
 77  	else
 78  		nonAppleAnchor();
 79  	
 80  	return Maker::make();
 81  }
 82  
 83  
 84  void DRMaker::nonAppleAnchor()
 85  {
 86  	// get the Organization DN element for the leaf
 87  	CFRef<CFStringRef> leafOrganization;
 88  	MacOSError::check(SecCertificateCopySubjectComponent(ctx.cert(Requirement::leafCert),
 89  		&CSSMOID_OrganizationName, &leafOrganization.aref()));
 90  
 91  	// now step up the cert chain looking for the first cert with a different one
 92  	int slot = Requirement::leafCert;						// start at leaf
 93  	if (leafOrganization) {
 94  		while (SecCertificateRef ca = ctx.cert(slot+1)) {		// NULL if you over-run the anchor slot
 95  			CFRef<CFStringRef> caOrganization;
 96  			MacOSError::check(SecCertificateCopySubjectComponent(ca, &CSSMOID_OrganizationName, &caOrganization.aref()));
 97  			if (!caOrganization || CFStringCompare(leafOrganization, caOrganization, 0) != kCFCompareEqualTo)
 98  				break;
 99  			slot++;
100  		}
101  		if (slot == ctx.certCount() - 1)		// went all the way to the anchor...
102  			slot = Requirement::anchorCert;					// ... so say that
103  	}
104  	
105  	// nail the last cert with the leaf's Organization value
106  	SHA1::Digest authorityHash;
107  	hashOfCertificate(ctx.cert(slot), authorityHash);
108  	this->anchor(slot, authorityHash);
109  }
110  
111  
112  void DRMaker::appleAnchor()
113  {
114  	if (isIOSSignature()) {
115  		// get the Common Name DN element for the leaf
116  		CFRef<CFStringRef> leafCN;
117  		MacOSError::check(SecCertificateCopySubjectComponent(ctx.cert(Requirement::leafCert),
118  			&CSSMOID_CommonName, &leafCN.aref()));
119  		
120  		// apple anchor generic and ...
121  		this->put(opAnd);
122  		this->anchorGeneric();			// apple generic anchor and...
123  		// ... leaf[subject.CN] = <leaf's subject> and ...
124  		this->put(opAnd);
125  		this->put(opCertField);			// certificate
126  		this->put(0);					// leaf
127  		this->put("subject.CN");		// [subject.CN]
128  		this->put(matchEqual);			// =
129  		this->putData(leafCN);			// <leaf CN>
130  		// ... cert 1[field.<marker>] exists
131  		this->put(opCertGeneric);		// certificate
132  		this->put(1);					// 1
133  		this->putData(adcSdkMarkerOID.Data, adcSdkMarkerOID.Length); // [field.<marker>]
134  		this->put(matchExists);			// exists
135  		return;
136  	}
137  	
138  	if (isDeveloperIDSignature()) {
139  		// get the Organizational Unit DN element for the leaf (it contains the TEAMID)
140  		CFRef<CFStringRef> teamID;
141  		MacOSError::check(SecCertificateCopySubjectComponent(ctx.cert(Requirement::leafCert),
142  			&CSSMOID_OrganizationalUnitName, &teamID.aref()));
143  
144  		// apple anchor generic and ...
145  		this->put(opAnd);
146  		this->anchorGeneric();			// apple generic anchor and...
147  		
148  		// ... certificate 1[intermediate marker oid] exists and ...
149  		this->put(opAnd);
150  		this->put(opCertGeneric);		// certificate
151  		this->put(1);					// 1
152  		this->putData(caspianSdkMarker, sizeof(caspianSdkMarker));
153  		this->put(matchExists);			// exists
154  		
155  		// ... certificate leaf[Caspian cert oid] exists and ...
156  		this->put(opAnd);
157  		this->put(opCertGeneric);		// certificate
158  		this->put(0);					// leaf
159  		this->putData(caspianLeafMarker, sizeof(caspianLeafMarker));
160  		this->put(matchExists);			// exists
161  
162  		// ... leaf[subject.OU] = <leaf's subject>
163  		this->put(opCertField);			// certificate
164  		this->put(0);					// leaf
165  		this->put("subject.OU");		// [subject.OU]
166  		this->put(matchEqual);			// =
167  		this->putData(teamID);			// TEAMID
168  		return;
169  	}
170  
171  	// otherwise, claim this program for Apple Proper
172  	this->anchor();
173  }
174  
175  bool DRMaker::isIOSSignature()
176  {
177  	if (ctx.certCount() == 3)		// leaf, one intermediate, anchor
178  		if (SecCertificateRef intermediate = ctx.cert(1)) // get intermediate
179  			if (certificateHasField(intermediate, CssmOid::overlay(adcSdkMarkerOID)))
180  				return true;
181  	return false;
182  }
183  
184  bool DRMaker::isDeveloperIDSignature()
185  {
186  	if (ctx.certCount() == 3)		// leaf, one intermediate, anchor
187  		if (SecCertificateRef intermediate = ctx.cert(1)) // get intermediate
188  			if (certificateHasField(intermediate, CssmOid::overlay(devIdSdkMarkerOID)))
189  				return true;
190  	return false;
191  }
192  
193  
194  } // end namespace CodeSigning
195  } // end namespace Security