]>
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 | ||
5c19dc3a | 71 | if (isAppleCA(ctx.cert(Requirement::anchorCert)) |
b1ab9ed8 A |
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 |