2 * Copyright (c) 2002-2004,2011-2015 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
25 // Policy.cpp - Working with Policies
27 #include <security_keychain/Policies.h>
28 #include <security_utilities/debugging.h>
29 #include <Security/oidsalg.h>
30 #include <sys/param.h>
32 /* Oids longer than this are considered invalid. */
33 #define MAX_OID_SIZE 32
35 //%%FIXME: need to use a common copy of this utility function
37 CFStringRef
SecDERItemCopyOIDDecimalRepresentation(uint8
*oid
, size_t oidLen
)
40 return CFSTR("<NULL>");
42 if (oidLen
> MAX_OID_SIZE
)
43 return CFSTR("Oid too long");
45 CFMutableStringRef result
= CFStringCreateMutable(kCFAllocatorDefault
, 0);
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;
54 // Handle special case for large y if x = 2
58 CFStringAppendFormat(result
, NULL
, CFSTR("%u.%u"), x
, y
);
60 unsigned long value
= 0;
61 for (x
= 1; x
< oidLen
; ++x
)
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. */
68 CFStringAppendFormat(result
, NULL
, CFSTR(".%lu"), value
);
76 using namespace KeychainCore
;
78 Policy::Policy(TP supportingTp
, const CssmOid
&policyOid
)
80 mOid(Allocator::standard(), policyOid
),
81 mValue(Allocator::standard()),
82 mAuxValue(Allocator::standard())
84 // value is as yet unimplemented
85 secinfo("policy", "Policy() this %p", this);
88 Policy::~Policy() _NOEXCEPT
90 secinfo("policy", "~Policy() this %p", this);
93 void Policy::setValue(const CssmData
&value
)
95 StLock
<Mutex
>_(mMutex
);
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
)
105 CSSM_APPLE_TP_SSL_OPTIONS
*opts
= (CSSM_APPLE_TP_SSL_OPTIONS
*)value
.data();
106 if (opts
->Version
== CSSM_APPLE_TP_SSL_OPTS_VERSION
)
108 if (opts
->ServerNameLen
> 0)
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());
117 // Clear the embedded pointer!
118 mValue
.get().interpretedAs
<CSSM_APPLE_TP_SSL_OPTIONS
>()->ServerName
=
119 reinterpret_cast<char*>(NULL
);
123 else if (mOid
== CSSMOID_APPLE_TP_SMIME
||
124 mOid
== CSSMOID_APPLE_TP_ICHAT
||
125 mOid
== CSSMOID_APPLE_TP_PASSBOOK_SIGNING
)
127 CSSM_APPLE_TP_SMIME_OPTIONS
*opts
= (CSSM_APPLE_TP_SMIME_OPTIONS
*)value
.data();
128 if (opts
->Version
== CSSM_APPLE_TP_SMIME_OPTS_VERSION
)
130 if (opts
->SenderEmailLen
> 0)
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());
139 // Clear the embedded pointer!
140 mValue
.get().interpretedAs
<CSSM_APPLE_TP_SMIME_OPTIONS
>()->SenderEmail
=
141 reinterpret_cast<char*>(NULL
);
147 void Policy::setProperties(CFDictionaryRef properties
)
149 // Set the policy value based on the provided dictionary keys.
150 if (properties
== NULL
)
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
)
158 CSSM_APPLE_TP_SSL_OPTIONS options
= { CSSM_APPLE_TP_SSL_OPTS_VERSION
, 0, NULL
, 0 };
160 CFStringRef nameStr
= NULL
;
161 if (CFDictionaryGetValueIfPresent(properties
, (const void *)kSecPolicyName
, (const void **)&nameStr
)) {
162 buf
= (char *)malloc(MAXPATHLEN
);
164 if (CFStringGetCString(nameStr
, buf
, MAXPATHLEN
, kCFStringEncodingUTF8
)) {
165 options
.ServerName
= buf
;
166 options
.ServerNameLen
= (unsigned)(strlen(buf
)+1); // include terminating null
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
;
175 const CssmData
value((uint8
*)&options
, sizeof(options
));
176 this->setValue(value
);
180 else if (mOid
== CSSMOID_APPLE_TP_SMIME
||
181 mOid
== CSSMOID_APPLE_TP_ICHAT
||
182 mOid
== CSSMOID_APPLE_TP_PASSBOOK_SIGNING
)
184 CSSM_APPLE_TP_SMIME_OPTIONS options
= { CSSM_APPLE_TP_SMIME_OPTS_VERSION
, 0, 0, NULL
};
186 CFStringRef nameStr
= NULL
;
187 if (CFDictionaryGetValueIfPresent(properties
, (const void *)kSecPolicyName
, (const void **)&nameStr
)) {
188 buf
= (char *)malloc(MAXPATHLEN
);
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
);
195 if (CFStringGetCString(teamIDStr
, buf2
, MAXPATHLEN
, kCFStringEncodingUTF8
)) {
196 /* append tab separator and team identifier */
197 strlcat(buf
, "\t", MAXPATHLEN
);
198 strlcat(buf
, buf2
, MAXPATHLEN
);
203 options
.SenderEmail
= buf
;
204 options
.SenderEmailLen
= (unsigned)(strlen(buf
)+1); // include terminating null
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
;
237 const CssmData
value((uint8
*)&options
, sizeof(options
));
238 this->setValue(value
);
242 else if (mOid
== CSSMOID_APPLE_TP_REVOCATION
)
244 CFNumberRef num
= NULL
;
245 if (CFDictionaryGetValueIfPresent(properties
, (const void *)kSecPolicyRevocationFlags
, (const void **)&num
)) {
246 CFOptionFlags revocationFlags
= 0;
248 (void)CFNumberGetValue(num
, kCFNumberCFIndexType
, &revocationFlags
);
250 const CssmData
value((uint8
*)&revocationFlags
, sizeof(revocationFlags
));
251 this->setValue(value
);
257 CFDictionaryRef
Policy::properties()
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
;
265 CFStringRef oidStr
= SecDERItemCopyOIDDecimalRepresentation((uint8
*)mOid
.data(), mOid
.length());
267 CFDictionarySetValue(properties
, (const void *)kSecPolicyOid
, (const void *)oidStr
);
273 CFStringRef nameStr
= CFStringCreateWithBytes(NULL
,
274 (const UInt8
*)reinterpret_cast<char*>(mAuxValue
.data()),
275 (CFIndex
)mAuxValue
.length(), kCFStringEncodingUTF8
, false);
277 if (mOid
== CSSMOID_APPLE_TP_PASSBOOK_SIGNING
) {
278 CFArrayRef strs
= CFStringCreateArrayBySeparatingStrings(kCFAllocatorDefault
, nameStr
, CFSTR("\t"));
280 CFIndex count
= CFArrayGetCount(strs
);
282 CFDictionarySetValue(properties
, (const void *)kSecPolicyName
, (const void *)CFArrayGetValueAtIndex(strs
, 0));
284 CFDictionarySetValue(properties
, (const void *)kSecPolicyTeamIdentifier
, (const void *)CFArrayGetValueAtIndex(strs
, 1));
289 CFDictionarySetValue(properties
, (const void *)kSecPolicyName
, (const void *)nameStr
);
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
)
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
);
309 // key usage flags (currently only for S/MIME and iChat policies)
311 if (mOid
== CSSMOID_APPLE_TP_SMIME
||
312 mOid
== CSSMOID_APPLE_TP_ICHAT
)
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
);
335 else if (mOid
== CSSMOID_APPLE_TP_REVOCATION
)
337 CFOptionFlags
*revocationFlagsPtr
= (CFOptionFlags
*)mValue
.data();
338 if (revocationFlagsPtr
) {
339 CFNumberRef num
= CFNumberCreate(kCFAllocatorDefault
, kCFNumberCFIndexType
, revocationFlagsPtr
);
341 CFDictionarySetValue(properties
, (const void *)kSecPolicyRevocationFlags
, num
);
351 bool Policy::operator < (const Policy
& other
) const
354 return (oid() < other
.oid()) ||
355 (oid() == other
.oid() && value() < other
.value());
358 bool Policy::operator == (const Policy
& other
) const
360 return oid() == other
.oid() && value() == other
.value();