]>
Commit | Line | Data |
---|---|---|
b1ab9ed8 | 1 | /* |
427c49bc A |
2 | * Copyright (c) 2002-2004,2012 Apple Inc. All Rights Reserved. |
3 | * | |
b1ab9ed8 | 4 | * @APPLE_LICENSE_HEADER_START@ |
427c49bc | 5 | * |
b1ab9ed8 A |
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. | |
427c49bc | 12 | * |
b1ab9ed8 A |
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. | |
427c49bc | 20 | * |
b1ab9ed8 A |
21 | * @APPLE_LICENSE_HEADER_END@ |
22 | */ | |
23 | ||
24 | // | |
25 | // Policy.cpp - Working with Policies | |
26 | // | |
27 | #include <security_keychain/Policies.h> | |
28 | #include <security_utilities/debugging.h> | |
29 | #include <Security/oidsalg.h> | |
30 | #include <sys/param.h> | |
31 | ||
32 | /* Oids longer than this are considered invalid. */ | |
33 | #define MAX_OID_SIZE 32 | |
34 | ||
35 | //%%FIXME: need to use a common copy of this utility function | |
427c49bc | 36 | static |
b1ab9ed8 A |
37 | CFStringRef SecDERItemCopyOIDDecimalRepresentation(uint8 *oid, size_t oidLen) |
38 | { | |
39 | if (oidLen == 0) | |
427c49bc A |
40 | return CFSTR("<NULL>"); |
41 | ||
b1ab9ed8 | 42 | if (oidLen > MAX_OID_SIZE) |
427c49bc A |
43 | return CFSTR("Oid too long"); |
44 | ||
45 | CFMutableStringRef result = CFStringCreateMutable(kCFAllocatorDefault, 0); | |
46 | ||
b1ab9ed8 A |
47 | // The first two levels are encoded into one byte, since the root level |
48 | // has only 3 nodes (40*x + y). However if x = joint-iso-itu-t(2) then | |
49 | // y may be > 39, so we have to add special-case handling for this. | |
50 | uint32_t x = oid[0] / 40; | |
51 | uint32_t y = oid[0] % 40; | |
52 | if (x > 2) | |
53 | { | |
54 | // Handle special case for large y if x = 2 | |
55 | y += (x - 2) * 40; | |
56 | x = 2; | |
57 | } | |
427c49bc A |
58 | CFStringAppendFormat(result, NULL, CFSTR("%u.%u"), x, y); |
59 | ||
60 | unsigned long value = 0; | |
b1ab9ed8 A |
61 | for (x = 1; x < oidLen; ++x) |
62 | { | |
63 | value = (value << 7) | (oid[x] & 0x7F); | |
427c49bc A |
64 | /* @@@ value may not span more than 4 bytes. */ |
65 | /* A max number of 20 values is allowed. */ | |
b1ab9ed8 A |
66 | if (!(oid[x] & 0x80)) |
67 | { | |
427c49bc | 68 | CFStringAppendFormat(result, NULL, CFSTR(".%lu"), value); |
b1ab9ed8 A |
69 | value = 0; |
70 | } | |
71 | } | |
72 | return result; | |
73 | } | |
74 | ||
75 | ||
76 | using namespace KeychainCore; | |
77 | ||
78 | Policy::Policy(TP supportingTp, const CssmOid &policyOid) | |
79 | : mTp(supportingTp), | |
80 | mOid(Allocator::standard(), policyOid), | |
81 | mValue(Allocator::standard()), | |
82 | mAuxValue(Allocator::standard()) | |
83 | { | |
427c49bc | 84 | // value is as yet unimplemented |
b1ab9ed8 A |
85 | secdebug("policy", "Policy() this %p", this); |
86 | } | |
87 | ||
88 | Policy::~Policy() throw() | |
89 | { | |
90 | secdebug("policy", "~Policy() this %p", this); | |
91 | } | |
92 | ||
93 | void Policy::setValue(const CssmData &value) | |
94 | { | |
95 | StLock<Mutex>_(mMutex); | |
427c49bc A |
96 | mValue = value; |
97 | mAuxValue.reset(); | |
b1ab9ed8 | 98 | |
427c49bc A |
99 | // Certain policy values may contain an embedded pointer. Ask me how I feel about that. |
100 | if (mOid == CSSMOID_APPLE_TP_SSL || | |
101 | mOid == CSSMOID_APPLE_TP_EAP || | |
102 | mOid == CSSMOID_APPLE_TP_IP_SEC || | |
103 | mOid == CSSMOID_APPLE_TP_APPLEID_SHARING) | |
104 | { | |
105 | CSSM_APPLE_TP_SSL_OPTIONS *opts = (CSSM_APPLE_TP_SSL_OPTIONS *)value.data(); | |
106 | if (opts->Version == CSSM_APPLE_TP_SSL_OPTS_VERSION) | |
107 | { | |
b1ab9ed8 A |
108 | if (opts->ServerNameLen > 0) |
109 | { | |
110 | // Copy auxiliary data, then update the embedded pointer to reference our copy | |
111 | mAuxValue.copy(const_cast<char*>(opts->ServerName), opts->ServerNameLen); | |
112 | mValue.get().interpretedAs<CSSM_APPLE_TP_SSL_OPTIONS>()->ServerName = | |
113 | reinterpret_cast<char*>(mAuxValue.data()); | |
114 | } | |
115 | else | |
116 | { | |
117 | // Clear the embedded pointer! | |
118 | mValue.get().interpretedAs<CSSM_APPLE_TP_SSL_OPTIONS>()->ServerName = | |
119 | reinterpret_cast<char*>(NULL); | |
120 | } | |
121 | } | |
427c49bc A |
122 | } |
123 | else if (mOid == CSSMOID_APPLE_TP_SMIME || | |
124 | mOid == CSSMOID_APPLE_TP_ICHAT || | |
125 | mOid == CSSMOID_APPLE_TP_PASSBOOK_SIGNING) | |
126 | { | |
127 | CSSM_APPLE_TP_SMIME_OPTIONS *opts = (CSSM_APPLE_TP_SMIME_OPTIONS *)value.data(); | |
128 | if (opts->Version == CSSM_APPLE_TP_SMIME_OPTS_VERSION) | |
b1ab9ed8 A |
129 | { |
130 | if (opts->SenderEmailLen > 0) | |
131 | { | |
132 | // Copy auxiliary data, then update the embedded pointer to reference our copy | |
133 | mAuxValue.copy(const_cast<char*>(opts->SenderEmail), opts->SenderEmailLen); | |
134 | mValue.get().interpretedAs<CSSM_APPLE_TP_SMIME_OPTIONS>()->SenderEmail = | |
135 | reinterpret_cast<char*>(mAuxValue.data()); | |
136 | } | |
137 | else | |
138 | { | |
139 | // Clear the embedded pointer! | |
140 | mValue.get().interpretedAs<CSSM_APPLE_TP_SMIME_OPTIONS>()->SenderEmail = | |
141 | reinterpret_cast<char*>(NULL); | |
142 | } | |
143 | } | |
427c49bc | 144 | } |
b1ab9ed8 A |
145 | } |
146 | ||
147 | void Policy::setProperties(CFDictionaryRef properties) | |
148 | { | |
149 | // Set the policy value based on the provided dictionary keys. | |
427c49bc A |
150 | if (properties == NULL) |
151 | return; | |
152 | ||
b1ab9ed8 | 153 | if (mOid == CSSMOID_APPLE_TP_SSL || |
427c49bc A |
154 | mOid == CSSMOID_APPLE_TP_EAP || |
155 | mOid == CSSMOID_APPLE_TP_IP_SEC || | |
b1ab9ed8 | 156 | mOid == CSSMOID_APPLE_TP_APPLEID_SHARING) |
427c49bc | 157 | { |
b1ab9ed8 A |
158 | CSSM_APPLE_TP_SSL_OPTIONS options = { CSSM_APPLE_TP_SSL_OPTS_VERSION, 0, NULL, 0 }; |
159 | char *buf = NULL; | |
160 | CFStringRef nameStr = NULL; | |
161 | if (CFDictionaryGetValueIfPresent(properties, (const void *)kSecPolicyName, (const void **)&nameStr)) { | |
162 | buf = (char *)malloc(MAXPATHLEN); | |
163 | if (buf) { | |
164 | if (CFStringGetCString(nameStr, buf, MAXPATHLEN, kCFStringEncodingUTF8)) { | |
165 | options.ServerName = buf; | |
427c49bc | 166 | options.ServerNameLen = (unsigned)(strlen(buf)+1); // include terminating null |
b1ab9ed8 A |
167 | } |
168 | } | |
169 | } | |
170 | CFBooleanRef clientRef = NULL; | |
171 | if (CFDictionaryGetValueIfPresent(properties, (const void *)kSecPolicyClient, (const void **)&clientRef) | |
172 | && CFBooleanGetValue(clientRef) == true) | |
173 | options.Flags |= CSSM_APPLE_TP_SSL_CLIENT; | |
174 | ||
175 | const CssmData value((uint8*)&options, sizeof(options)); | |
176 | this->setValue(value); | |
177 | ||
178 | if (buf) free(buf); | |
179 | } | |
427c49bc A |
180 | else if (mOid == CSSMOID_APPLE_TP_SMIME || |
181 | mOid == CSSMOID_APPLE_TP_ICHAT || | |
182 | mOid == CSSMOID_APPLE_TP_PASSBOOK_SIGNING) | |
183 | { | |
b1ab9ed8 A |
184 | CSSM_APPLE_TP_SMIME_OPTIONS options = { CSSM_APPLE_TP_SMIME_OPTS_VERSION, 0, 0, NULL }; |
185 | char *buf = NULL; | |
186 | CFStringRef nameStr = NULL; | |
187 | if (CFDictionaryGetValueIfPresent(properties, (const void *)kSecPolicyName, (const void **)&nameStr)) { | |
188 | buf = (char *)malloc(MAXPATHLEN); | |
189 | if (buf) { | |
190 | if (CFStringGetCString(nameStr, buf, MAXPATHLEN, kCFStringEncodingUTF8)) { | |
427c49bc A |
191 | CFStringRef teamIDStr = NULL; |
192 | if (CFDictionaryGetValueIfPresent(properties, (const void *)kSecPolicyTeamIdentifier, (const void **)&teamIDStr)) { | |
193 | char *buf2 = (char *)malloc(MAXPATHLEN); | |
194 | if (buf2) { | |
195 | if (CFStringGetCString(teamIDStr, buf2, MAXPATHLEN, kCFStringEncodingUTF8)) { | |
196 | /* append tab separator and team identifier */ | |
197 | strlcat(buf, "\t", MAXPATHLEN); | |
198 | strlcat(buf, buf2, MAXPATHLEN); | |
199 | } | |
200 | free(buf2); | |
201 | } | |
202 | } | |
b1ab9ed8 | 203 | options.SenderEmail = buf; |
427c49bc | 204 | options.SenderEmailLen = (unsigned)(strlen(buf)+1); // include terminating null |
b1ab9ed8 A |
205 | } |
206 | } | |
207 | } | |
208 | CFBooleanRef kuRef = NULL; | |
209 | if (CFDictionaryGetValueIfPresent(properties, (const void *)kSecPolicyKU_DigitalSignature, (const void **)&kuRef) | |
210 | && CFBooleanGetValue(kuRef) == true) | |
211 | options.IntendedUsage |= CE_KU_DigitalSignature; | |
212 | if (CFDictionaryGetValueIfPresent(properties, (const void *)kSecPolicyKU_NonRepudiation, (const void **)&kuRef) | |
213 | && CFBooleanGetValue(kuRef) == true) | |
214 | options.IntendedUsage |= CE_KU_NonRepudiation; | |
215 | if (CFDictionaryGetValueIfPresent(properties, (const void *)kSecPolicyKU_KeyEncipherment, (const void **)&kuRef) | |
216 | && CFBooleanGetValue(kuRef) == true) | |
217 | options.IntendedUsage |= CE_KU_KeyEncipherment; | |
218 | if (CFDictionaryGetValueIfPresent(properties, (const void *)kSecPolicyKU_DataEncipherment, (const void **)&kuRef) | |
219 | && CFBooleanGetValue(kuRef) == true) | |
220 | options.IntendedUsage |= CE_KU_DataEncipherment; | |
221 | if (CFDictionaryGetValueIfPresent(properties, (const void *)kSecPolicyKU_KeyAgreement, (const void **)&kuRef) | |
222 | && CFBooleanGetValue(kuRef) == true) | |
223 | options.IntendedUsage |= CE_KU_KeyAgreement; | |
224 | if (CFDictionaryGetValueIfPresent(properties, (const void *)kSecPolicyKU_KeyCertSign, (const void **)&kuRef) | |
225 | && CFBooleanGetValue(kuRef) == true) | |
226 | options.IntendedUsage |= CE_KU_KeyCertSign; | |
227 | if (CFDictionaryGetValueIfPresent(properties, (const void *)kSecPolicyKU_CRLSign, (const void **)&kuRef) | |
228 | && CFBooleanGetValue(kuRef) == true) | |
229 | options.IntendedUsage |= CE_KU_CRLSign; | |
230 | if (CFDictionaryGetValueIfPresent(properties, (const void *)kSecPolicyKU_EncipherOnly, (const void **)&kuRef) | |
231 | && CFBooleanGetValue(kuRef) == true) | |
232 | options.IntendedUsage |= CE_KU_EncipherOnly; | |
233 | if (CFDictionaryGetValueIfPresent(properties, (const void *)kSecPolicyKU_DecipherOnly, (const void **)&kuRef) | |
234 | && CFBooleanGetValue(kuRef) == true) | |
235 | options.IntendedUsage |= CE_KU_DecipherOnly; | |
236 | ||
237 | const CssmData value((uint8*)&options, sizeof(options)); | |
238 | this->setValue(value); | |
239 | ||
240 | if (buf) free(buf); | |
241 | } | |
427c49bc | 242 | |
b1ab9ed8 A |
243 | } |
244 | ||
245 | CFDictionaryRef Policy::properties() | |
246 | { | |
247 | // Builds and returns a dictionary which the caller must release. | |
b1ab9ed8 A |
248 | CFMutableDictionaryRef properties = CFDictionaryCreateMutable(NULL, 0, |
249 | &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); | |
250 | if (!properties) return NULL; | |
427c49bc | 251 | |
b1ab9ed8 A |
252 | // kSecPolicyOid |
253 | CFStringRef oidStr = SecDERItemCopyOIDDecimalRepresentation((uint8*)mOid.data(), mOid.length()); | |
254 | if (oidStr) { | |
255 | CFDictionarySetValue(properties, (const void *)kSecPolicyOid, (const void *)oidStr); | |
256 | CFRelease(oidStr); | |
257 | } | |
427c49bc | 258 | |
b1ab9ed8 | 259 | // kSecPolicyName |
427c49bc | 260 | if (mAuxValue) { |
b1ab9ed8 A |
261 | CFStringRef nameStr = CFStringCreateWithBytes(NULL, |
262 | (const UInt8 *)reinterpret_cast<char*>(mAuxValue.data()), | |
263 | (CFIndex)mAuxValue.length(), kCFStringEncodingUTF8, false); | |
264 | if (nameStr) { | |
427c49bc A |
265 | if (mOid == CSSMOID_APPLE_TP_PASSBOOK_SIGNING) { |
266 | CFArrayRef strs = CFStringCreateArrayBySeparatingStrings(kCFAllocatorDefault, nameStr, CFSTR("\t")); | |
267 | if (strs) { | |
268 | CFIndex count = CFArrayGetCount(strs); | |
269 | if (count > 0) | |
270 | CFDictionarySetValue(properties, (const void *)kSecPolicyName, (const void *)CFArrayGetValueAtIndex(strs, 0)); | |
271 | if (count > 1) | |
272 | CFDictionarySetValue(properties, (const void *)kSecPolicyTeamIdentifier, (const void *)CFArrayGetValueAtIndex(strs, 1)); | |
273 | CFRelease(strs); | |
274 | } | |
275 | } | |
276 | else { | |
277 | CFDictionarySetValue(properties, (const void *)kSecPolicyName, (const void *)nameStr); | |
278 | } | |
b1ab9ed8 A |
279 | CFRelease(nameStr); |
280 | } | |
281 | } | |
427c49bc | 282 | |
b1ab9ed8 A |
283 | // kSecPolicyClient |
284 | if (mValue) { | |
285 | if (mOid == CSSMOID_APPLE_TP_SSL || | |
286 | mOid == CSSMOID_APPLE_TP_EAP || | |
287 | mOid == CSSMOID_APPLE_TP_IP_SEC || | |
288 | mOid == CSSMOID_APPLE_TP_APPLEID_SHARING) | |
289 | { | |
290 | CSSM_APPLE_TP_SSL_OPTIONS *opts = (CSSM_APPLE_TP_SSL_OPTIONS *)mValue.data(); | |
291 | if (opts->Flags & CSSM_APPLE_TP_SSL_CLIENT) { | |
292 | CFDictionarySetValue(properties, (const void *)kSecPolicyClient, (const void *)kCFBooleanTrue); | |
293 | } | |
294 | } | |
295 | } | |
427c49bc | 296 | |
b1ab9ed8 A |
297 | // key usage flags (currently only for S/MIME and iChat policies) |
298 | if (mValue) { | |
299 | if (mOid == CSSMOID_APPLE_TP_SMIME || | |
300 | mOid == CSSMOID_APPLE_TP_ICHAT) | |
301 | { | |
302 | CSSM_APPLE_TP_SMIME_OPTIONS *opts = (CSSM_APPLE_TP_SMIME_OPTIONS *)mValue.data(); | |
303 | CE_KeyUsage usage = opts->IntendedUsage; | |
304 | if (usage & CE_KU_DigitalSignature) | |
305 | CFDictionarySetValue(properties, (const void *)kSecPolicyKU_DigitalSignature, (const void *)kCFBooleanTrue); | |
306 | if (usage & CE_KU_NonRepudiation) | |
307 | CFDictionarySetValue(properties, (const void *)kSecPolicyKU_NonRepudiation, (const void *)kCFBooleanTrue); | |
308 | if (usage & CE_KU_KeyEncipherment) | |
309 | CFDictionarySetValue(properties, (const void *)kSecPolicyKU_KeyEncipherment, (const void *)kCFBooleanTrue); | |
310 | if (usage & CE_KU_DataEncipherment) | |
311 | CFDictionarySetValue(properties, (const void *)kSecPolicyKU_DataEncipherment, (const void *)kCFBooleanTrue); | |
312 | if (usage & CE_KU_KeyAgreement) | |
313 | CFDictionarySetValue(properties, (const void *)kSecPolicyKU_KeyAgreement, (const void *)kCFBooleanTrue); | |
314 | if (usage & CE_KU_KeyCertSign) | |
315 | CFDictionarySetValue(properties, (const void *)kSecPolicyKU_KeyCertSign, (const void *)kCFBooleanTrue); | |
316 | if (usage & CE_KU_CRLSign) | |
317 | CFDictionarySetValue(properties, (const void *)kSecPolicyKU_CRLSign, (const void *)kCFBooleanTrue); | |
318 | if (usage & CE_KU_EncipherOnly) | |
319 | CFDictionarySetValue(properties, (const void *)kSecPolicyKU_EncipherOnly, (const void *)kCFBooleanTrue); | |
320 | if (usage & CE_KU_DecipherOnly) | |
321 | CFDictionarySetValue(properties, (const void *)kSecPolicyKU_DecipherOnly, (const void *)kCFBooleanTrue); | |
322 | } | |
323 | } | |
324 | return properties; | |
325 | } | |
326 | ||
327 | ||
328 | bool Policy::operator < (const Policy& other) const | |
329 | { | |
330 | //@@@ inefficient | |
427c49bc A |
331 | return (oid() < other.oid()) || |
332 | (oid() == other.oid() && value() < other.value()); | |
b1ab9ed8 A |
333 | } |
334 | ||
335 | bool Policy::operator == (const Policy& other) const | |
336 | { | |
337 | return oid() == other.oid() && value() == other.value(); | |
338 | } |