]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_keychain/lib/Policies.cpp
Security-57740.60.18.tar.gz
[apple/security.git] / OSX / libsecurity_keychain / lib / Policies.cpp
1 /*
2 * Copyright (c) 2002-2004,2011-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 // 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
36 static
37 CFStringRef SecDERItemCopyOIDDecimalRepresentation(uint8 *oid, size_t oidLen)
38 {
39 if (oidLen == 0)
40 return CFSTR("<NULL>");
41
42 if (oidLen > MAX_OID_SIZE)
43 return CFSTR("Oid too long");
44
45 CFMutableStringRef result = CFStringCreateMutable(kCFAllocatorDefault, 0);
46
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 }
58 CFStringAppendFormat(result, NULL, CFSTR("%u.%u"), x, y);
59
60 unsigned long value = 0;
61 for (x = 1; x < oidLen; ++x)
62 {
63 value = (value << 7) | (oid[x] & 0x7F);
64 /* @@@ value may not span more than 4 bytes. */
65 /* A max number of 20 values is allowed. */
66 if (!(oid[x] & 0x80))
67 {
68 CFStringAppendFormat(result, NULL, CFSTR(".%lu"), value);
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 {
84 // value is as yet unimplemented
85 secinfo("policy", "Policy() this %p", this);
86 }
87
88 Policy::~Policy() throw()
89 {
90 secinfo("policy", "~Policy() this %p", this);
91 }
92
93 void Policy::setValue(const CssmData &value)
94 {
95 StLock<Mutex>_(mMutex);
96 mValue = value;
97 mAuxValue.reset();
98
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 {
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 }
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)
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 }
144 }
145 }
146
147 void Policy::setProperties(CFDictionaryRef properties)
148 {
149 // Set the policy value based on the provided dictionary keys.
150 if (properties == NULL)
151 return;
152
153 if (mOid == CSSMOID_APPLE_TP_SSL ||
154 mOid == CSSMOID_APPLE_TP_EAP ||
155 mOid == CSSMOID_APPLE_TP_IP_SEC ||
156 mOid == CSSMOID_APPLE_TP_APPLEID_SHARING)
157 {
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;
166 options.ServerNameLen = (unsigned)(strlen(buf)+1); // include terminating null
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 }
180 else if (mOid == CSSMOID_APPLE_TP_SMIME ||
181 mOid == CSSMOID_APPLE_TP_ICHAT ||
182 mOid == CSSMOID_APPLE_TP_PASSBOOK_SIGNING)
183 {
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)) {
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 }
203 options.SenderEmail = buf;
204 options.SenderEmailLen = (unsigned)(strlen(buf)+1); // include terminating null
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 }
242 else if (mOid == CSSMOID_APPLE_TP_REVOCATION)
243 {
244 CFNumberRef num = NULL;
245 if (CFDictionaryGetValueIfPresent(properties, (const void *)kSecPolicyRevocationFlags, (const void **)&num)) {
246 CFOptionFlags revocationFlags = 0;
247 if (num) {
248 (void)CFNumberGetValue(num, kCFNumberCFIndexType, &revocationFlags);
249 }
250 const CssmData value((uint8*)&revocationFlags, sizeof(revocationFlags));
251 this->setValue(value);
252 }
253 }
254
255 }
256
257 CFDictionaryRef Policy::properties()
258 {
259 // Builds and returns a dictionary which the caller must release.
260 CFMutableDictionaryRef properties = CFDictionaryCreateMutable(NULL, 0,
261 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
262 if (!properties) return NULL;
263
264 // kSecPolicyOid
265 CFStringRef oidStr = SecDERItemCopyOIDDecimalRepresentation((uint8*)mOid.data(), mOid.length());
266 if (oidStr) {
267 CFDictionarySetValue(properties, (const void *)kSecPolicyOid, (const void *)oidStr);
268 CFRelease(oidStr);
269 }
270
271 // kSecPolicyName
272 if (mAuxValue) {
273 CFStringRef nameStr = CFStringCreateWithBytes(NULL,
274 (const UInt8 *)reinterpret_cast<char*>(mAuxValue.data()),
275 (CFIndex)mAuxValue.length(), kCFStringEncodingUTF8, false);
276 if (nameStr) {
277 if (mOid == CSSMOID_APPLE_TP_PASSBOOK_SIGNING) {
278 CFArrayRef strs = CFStringCreateArrayBySeparatingStrings(kCFAllocatorDefault, nameStr, CFSTR("\t"));
279 if (strs) {
280 CFIndex count = CFArrayGetCount(strs);
281 if (count > 0)
282 CFDictionarySetValue(properties, (const void *)kSecPolicyName, (const void *)CFArrayGetValueAtIndex(strs, 0));
283 if (count > 1)
284 CFDictionarySetValue(properties, (const void *)kSecPolicyTeamIdentifier, (const void *)CFArrayGetValueAtIndex(strs, 1));
285 CFRelease(strs);
286 }
287 }
288 else {
289 CFDictionarySetValue(properties, (const void *)kSecPolicyName, (const void *)nameStr);
290 }
291 CFRelease(nameStr);
292 }
293 }
294
295 // kSecPolicyClient
296 if (mValue) {
297 if (mOid == CSSMOID_APPLE_TP_SSL ||
298 mOid == CSSMOID_APPLE_TP_EAP ||
299 mOid == CSSMOID_APPLE_TP_IP_SEC ||
300 mOid == CSSMOID_APPLE_TP_APPLEID_SHARING)
301 {
302 CSSM_APPLE_TP_SSL_OPTIONS *opts = (CSSM_APPLE_TP_SSL_OPTIONS *)mValue.data();
303 if (opts->Flags & CSSM_APPLE_TP_SSL_CLIENT) {
304 CFDictionarySetValue(properties, (const void *)kSecPolicyClient, (const void *)kCFBooleanTrue);
305 }
306 }
307 }
308
309 // key usage flags (currently only for S/MIME and iChat policies)
310 if (mValue) {
311 if (mOid == CSSMOID_APPLE_TP_SMIME ||
312 mOid == CSSMOID_APPLE_TP_ICHAT)
313 {
314 CSSM_APPLE_TP_SMIME_OPTIONS *opts = (CSSM_APPLE_TP_SMIME_OPTIONS *)mValue.data();
315 CE_KeyUsage usage = opts->IntendedUsage;
316 if (usage & CE_KU_DigitalSignature)
317 CFDictionarySetValue(properties, (const void *)kSecPolicyKU_DigitalSignature, (const void *)kCFBooleanTrue);
318 if (usage & CE_KU_NonRepudiation)
319 CFDictionarySetValue(properties, (const void *)kSecPolicyKU_NonRepudiation, (const void *)kCFBooleanTrue);
320 if (usage & CE_KU_KeyEncipherment)
321 CFDictionarySetValue(properties, (const void *)kSecPolicyKU_KeyEncipherment, (const void *)kCFBooleanTrue);
322 if (usage & CE_KU_DataEncipherment)
323 CFDictionarySetValue(properties, (const void *)kSecPolicyKU_DataEncipherment, (const void *)kCFBooleanTrue);
324 if (usage & CE_KU_KeyAgreement)
325 CFDictionarySetValue(properties, (const void *)kSecPolicyKU_KeyAgreement, (const void *)kCFBooleanTrue);
326 if (usage & CE_KU_KeyCertSign)
327 CFDictionarySetValue(properties, (const void *)kSecPolicyKU_KeyCertSign, (const void *)kCFBooleanTrue);
328 if (usage & CE_KU_CRLSign)
329 CFDictionarySetValue(properties, (const void *)kSecPolicyKU_CRLSign, (const void *)kCFBooleanTrue);
330 if (usage & CE_KU_EncipherOnly)
331 CFDictionarySetValue(properties, (const void *)kSecPolicyKU_EncipherOnly, (const void *)kCFBooleanTrue);
332 if (usage & CE_KU_DecipherOnly)
333 CFDictionarySetValue(properties, (const void *)kSecPolicyKU_DecipherOnly, (const void *)kCFBooleanTrue);
334 }
335 else if (mOid == CSSMOID_APPLE_TP_REVOCATION)
336 {
337 CFOptionFlags *revocationFlagsPtr = (CFOptionFlags *)mValue.data();
338 if (revocationFlagsPtr) {
339 CFNumberRef num = CFNumberCreate(kCFAllocatorDefault, kCFNumberCFIndexType, revocationFlagsPtr);
340 if (num) {
341 CFDictionarySetValue(properties, (const void *)kSecPolicyRevocationFlags, num);
342 CFRelease(num);
343 }
344 }
345 }
346 }
347 return properties;
348 }
349
350
351 bool Policy::operator < (const Policy& other) const
352 {
353 //@@@ inefficient
354 return (oid() < other.oid()) ||
355 (oid() == other.oid() && value() < other.value());
356 }
357
358 bool Policy::operator == (const Policy& other) const
359 {
360 return oid() == other.oid() && value() == other.value();
361 }