1/* 2 * Copyright (c) 2002-2004,2011-2014 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 36static 37CFStringRef 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 76using namespace KeychainCore; 77 78Policy::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 secdebug("policy", "Policy() this %p", this); 86} 87 88Policy::~Policy() throw() 89{ 90 secdebug("policy", "~Policy() this %p", this); 91} 92 93void 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 147void 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 243} 244 245CFDictionaryRef Policy::properties() 246{ 247 // Builds and returns a dictionary which the caller must release. 248 CFMutableDictionaryRef properties = CFDictionaryCreateMutable(NULL, 0, 249 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 250 if (!properties) return NULL; 251 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 } 258 259 // kSecPolicyName 260 if (mAuxValue) { 261 CFStringRef nameStr = CFStringCreateWithBytes(NULL, 262 (const UInt8 *)reinterpret_cast<char*>(mAuxValue.data()), 263 (CFIndex)mAuxValue.length(), kCFStringEncodingUTF8, false); 264 if (nameStr) { 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 } 279 CFRelease(nameStr); 280 } 281 } 282 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 } 296 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 328bool Policy::operator < (const Policy& other) const 329{ 330 //@@@ inefficient 331 return (oid() < other.oid()) || 332 (oid() == other.oid() && value() < other.value()); 333} 334 335bool Policy::operator == (const Policy& other) const 336{ 337 return oid() == other.oid() && value() == other.value(); 338} 339