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() _NOEXCEPT 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 }