]>
Commit | Line | Data |
---|---|---|
b1ab9ed8 A |
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 | SHA1::Digest anchorHash; | |
72 | hashOfCertificate(ctx.cert(Requirement::anchorCert), anchorHash); | |
313fa17b | 73 | if (isAppleCA(anchorHash) |
b1ab9ed8 A |
74 | #if defined(TEST_APPLE_ANCHOR) |
75 | || !memcmp(anchorHash, Requirement::testAppleAnchorHash(), SHA1::digestLength) | |
76 | #endif | |
77 | ) | |
78 | appleAnchor(); | |
79 | else | |
80 | nonAppleAnchor(); | |
81 | ||
82 | return Maker::make(); | |
83 | } | |
84 | ||
85 | ||
86 | void DRMaker::nonAppleAnchor() | |
87 | { | |
88 | // get the Organization DN element for the leaf | |
89 | CFRef<CFStringRef> leafOrganization; | |
90 | MacOSError::check(SecCertificateCopySubjectComponent(ctx.cert(Requirement::leafCert), | |
91 | &CSSMOID_OrganizationName, &leafOrganization.aref())); | |
92 | ||
93 | // now step up the cert chain looking for the first cert with a different one | |
94 | int slot = Requirement::leafCert; // start at leaf | |
95 | if (leafOrganization) { | |
96 | while (SecCertificateRef ca = ctx.cert(slot+1)) { // NULL if you over-run the anchor slot | |
97 | CFRef<CFStringRef> caOrganization; | |
98 | MacOSError::check(SecCertificateCopySubjectComponent(ca, &CSSMOID_OrganizationName, &caOrganization.aref())); | |
99 | if (!caOrganization || CFStringCompare(leafOrganization, caOrganization, 0) != kCFCompareEqualTo) | |
100 | break; | |
101 | slot++; | |
102 | } | |
103 | if (slot == ctx.certCount() - 1) // went all the way to the anchor... | |
104 | slot = Requirement::anchorCert; // ... so say that | |
105 | } | |
106 | ||
107 | // nail the last cert with the leaf's Organization value | |
108 | SHA1::Digest authorityHash; | |
109 | hashOfCertificate(ctx.cert(slot), authorityHash); | |
110 | this->anchor(slot, authorityHash); | |
111 | } | |
112 | ||
113 | ||
114 | void DRMaker::appleAnchor() | |
115 | { | |
116 | if (isIOSSignature()) { | |
117 | // get the Common Name DN element for the leaf | |
118 | CFRef<CFStringRef> leafCN; | |
119 | MacOSError::check(SecCertificateCopySubjectComponent(ctx.cert(Requirement::leafCert), | |
120 | &CSSMOID_CommonName, &leafCN.aref())); | |
121 | ||
122 | // apple anchor generic and ... | |
123 | this->put(opAnd); | |
124 | this->anchorGeneric(); // apple generic anchor and... | |
125 | // ... leaf[subject.CN] = <leaf's subject> and ... | |
126 | this->put(opAnd); | |
127 | this->put(opCertField); // certificate | |
128 | this->put(0); // leaf | |
129 | this->put("subject.CN"); // [subject.CN] | |
130 | this->put(matchEqual); // = | |
131 | this->putData(leafCN); // <leaf CN> | |
132 | // ... cert 1[field.<marker>] exists | |
133 | this->put(opCertGeneric); // certificate | |
134 | this->put(1); // 1 | |
135 | this->putData(adcSdkMarkerOID.Data, adcSdkMarkerOID.Length); // [field.<marker>] | |
136 | this->put(matchExists); // exists | |
137 | return; | |
138 | } | |
139 | ||
140 | if (isDeveloperIDSignature()) { | |
141 | // get the Organizational Unit DN element for the leaf (it contains the TEAMID) | |
142 | CFRef<CFStringRef> teamID; | |
143 | MacOSError::check(SecCertificateCopySubjectComponent(ctx.cert(Requirement::leafCert), | |
144 | &CSSMOID_OrganizationalUnitName, &teamID.aref())); | |
145 | ||
146 | // apple anchor generic and ... | |
147 | this->put(opAnd); | |
148 | this->anchorGeneric(); // apple generic anchor and... | |
149 | ||
150 | // ... certificate 1[intermediate marker oid] exists and ... | |
151 | this->put(opAnd); | |
152 | this->put(opCertGeneric); // certificate | |
153 | this->put(1); // 1 | |
154 | this->putData(caspianSdkMarker, sizeof(caspianSdkMarker)); | |
155 | this->put(matchExists); // exists | |
156 | ||
157 | // ... certificate leaf[Caspian cert oid] exists and ... | |
158 | this->put(opAnd); | |
159 | this->put(opCertGeneric); // certificate | |
160 | this->put(0); // leaf | |
161 | this->putData(caspianLeafMarker, sizeof(caspianLeafMarker)); | |
162 | this->put(matchExists); // exists | |
163 | ||
164 | // ... leaf[subject.OU] = <leaf's subject> | |
165 | this->put(opCertField); // certificate | |
166 | this->put(0); // leaf | |
167 | this->put("subject.OU"); // [subject.OU] | |
168 | this->put(matchEqual); // = | |
169 | this->putData(teamID); // TEAMID | |
170 | return; | |
171 | } | |
172 | ||
173 | // otherwise, claim this program for Apple Proper | |
174 | this->anchor(); | |
175 | } | |
176 | ||
177 | bool DRMaker::isIOSSignature() | |
178 | { | |
179 | if (ctx.certCount() == 3) // leaf, one intermediate, anchor | |
180 | if (SecCertificateRef intermediate = ctx.cert(1)) // get intermediate | |
181 | if (certificateHasField(intermediate, CssmOid::overlay(adcSdkMarkerOID))) | |
182 | return true; | |
183 | return false; | |
184 | } | |
185 | ||
186 | bool DRMaker::isDeveloperIDSignature() | |
187 | { | |
188 | if (ctx.certCount() == 3) // leaf, one intermediate, anchor | |
189 | if (SecCertificateRef intermediate = ctx.cert(1)) // get intermediate | |
190 | if (certificateHasField(intermediate, CssmOid::overlay(devIdSdkMarkerOID))) | |
191 | return true; | |
192 | return false; | |
193 | } | |
194 | ||
195 | ||
196 | } // end namespace CodeSigning | |
197 | } // end namespace Security |