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