2  * Copyright (c) 2014 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  * SecAccessControl.c - CoreFoundation based access control object 
  28 #include <TargetConditionals.h> 
  29 #include <AssertMacros.h> 
  30 #include <Security/SecAccessControl.h> 
  31 #include <Security/SecAccessControlPriv.h> 
  32 #include <Security/SecItem.h> 
  33 #include <Security/SecItemPriv.h> 
  34 #include <utilities/SecCFWrappers.h> 
  35 #include <utilities/SecCFError.h> 
  36 #include <utilities/der_plist.h> 
  37 #include <libaks_acl_cf_keys.h> 
  39 #include <ACMAclDefs.h> 
  41 static CFTypeRef kSecAccessControlKeyProtection 
= CFSTR("prot"); 
  42 static CFTypeRef kSecAccessControlKeyBound 
= CFSTR("bound"); 
  44 struct __SecAccessControl 
{ 
  46     CFMutableDictionaryRef dict
; 
  49 static SecAccessConstraintRef 
SecAccessConstraintCreateValueOfKofN(CFAllocatorRef allocator
, size_t numRequired
, CFArrayRef constraints
, CFErrorRef 
*error
); 
  51 static CFStringRef 
SecAccessControlCopyFormatDescription(CFTypeRef cf
, CFDictionaryRef formatOptions
) { 
  52     SecAccessControlRef access_control 
= (SecAccessControlRef
)cf
; 
  53     return CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("<SecAccessControlRef: %p>"), access_control
); 
  56 static Boolean 
SecAccessControlCompare(CFTypeRef lhs
, CFTypeRef rhs
) { 
  57     SecAccessControlRef laccess_control 
= (SecAccessControlRef
)lhs
; 
  58     SecAccessControlRef raccess_control 
= (SecAccessControlRef
)rhs
; 
  59     return (laccess_control 
== raccess_control
) || CFEqual(laccess_control
->dict
, raccess_control
->dict
); 
  62 static void SecAccessControlDestroy(CFTypeRef cf
) { 
  63     SecAccessControlRef access_control 
= (SecAccessControlRef
)cf
; 
  64     CFReleaseSafe(access_control
->dict
); 
  67 CFGiblisWithCompareFor(SecAccessControl
); 
  69 static CFMutableDictionaryRef 
SecAccessControlGetMutableConstraints(SecAccessControlRef access_control
) { 
  70     CFMutableDictionaryRef constraints 
= (CFMutableDictionaryRef
)CFDictionaryGetValue(access_control
->dict
, kAKSKeyAcl
); 
  73         CFMutableDictionaryRef newConstraints 
= CFDictionaryCreateMutableForCFTypes(CFGetAllocator(access_control
)); 
  74         CFDictionarySetValue(access_control
->dict
, kAKSKeyAcl
, newConstraints
); 
  75         CFRelease(newConstraints
); 
  77         constraints 
= (CFMutableDictionaryRef
)CFDictionaryGetValue(access_control
->dict
, kAKSKeyAcl
); 
  83 SecAccessControlRef 
SecAccessControlCreate(CFAllocatorRef allocator
, CFErrorRef 
*error
) { 
  84     SecAccessControlRef access_control 
= CFTypeAllocate(SecAccessControl
, struct __SecAccessControl
, allocator
); 
  85         if (!access_control
) { 
  86         SecError(errSecAllocate
, error
, CFSTR("allocate memory for SecAccessControl")); 
  90     access_control
->dict 
= CFDictionaryCreateMutableForCFTypes(allocator
); 
  91     return access_control
; 
  93 #if TARGET_OS_IPHONE || (!RC_HIDE_J79 && !RC_HIDE_J80) 
  94 static CFDataRef 
_getEmptyData() { 
  95     static CFMutableDataRef emptyData 
= NULL
; 
  96     static dispatch_once_t onceToken
; 
  98     dispatch_once(&onceToken
, ^{ 
  99         emptyData 
= CFDataCreateMutable(kCFAllocatorDefault
, 0); 
 106 SecAccessControlRef 
SecAccessControlCreateWithFlags(CFAllocatorRef allocator
, CFTypeRef protection
, 
 107                                                     SecAccessControlCreateFlags flags
, CFErrorRef 
*error
) { 
 108     SecAccessControlRef access_control 
= NULL
; 
 109     CFTypeRef constraint 
= NULL
; 
 110     CFMutableArrayRef constraints 
= NULL
; 
 112     require_quiet(access_control 
= SecAccessControlCreate(allocator
, error
), errOut
); 
 114     if (!SecAccessControlSetProtection(access_control
, protection
, error
)) 
 118 #if TARGET_OS_IPHONE || (!RC_HIDE_J79 && !RC_HIDE_J80) 
 119         bool or = (flags 
& kSecAccessControlOr
) ? true : false; 
 120         bool and = (flags 
& kSecAccessControlAnd
) ? true : false; 
 123             SecError(errSecParam
, error
, CFSTR("only one logical operation can be set")); 
 127         SecAccessControlCreateFlags maskedFlags 
= flags 
& (kSecAccessControlTouchIDAny 
| kSecAccessControlTouchIDCurrentSet
); 
 128         if (maskedFlags 
&& maskedFlags 
!= kSecAccessControlTouchIDAny 
&& maskedFlags 
!= kSecAccessControlTouchIDCurrentSet
) { 
 129             SecError(errSecParam
, error
, CFSTR("only one bio constraint can be set")); 
 133         if (flags 
& kSecAccessControlUserPresence 
&& flags 
& ~(kSecAccessControlUserPresence 
| kSecAccessControlApplicationPassword 
| kSecAccessControlPrivateKeyUsage
)) { 
 135         if (flags 
& kSecAccessControlUserPresence 
&& flags 
!= kSecAccessControlUserPresence
) { 
 137             SecError(errSecParam
, error
, CFSTR("kSecAccessControlUserPresence can be combined only with kSecAccessControlApplicationPassword and kSecAccessControlPrivateKeyUsage")); 
 141         constraints 
= CFArrayCreateMutable(allocator
, 0, &kCFTypeArrayCallBacks
); 
 143         if (flags 
& kSecAccessControlUserPresence
) { 
 144             require_quiet(constraint 
= SecAccessConstraintCreatePolicy(allocator
, CFSTR(kACMPolicyDeviceOwnerAuthentication
), error
), errOut
); 
 145             CFArrayAppendValue(constraints
, constraint
); 
 146             CFReleaseNull(constraint
); 
 149         if (flags 
& kSecAccessControlDevicePasscode
) { 
 150             require_quiet(constraint 
= SecAccessConstraintCreatePasscode(allocator
), errOut
); 
 151             CFArrayAppendValue(constraints
, constraint
); 
 152             CFReleaseNull(constraint
); 
 155 #if TARGET_OS_IPHONE || (!RC_HIDE_J79 && !RC_HIDE_J80) 
 156         if (flags 
& kSecAccessControlTouchIDAny
) { 
 157             require_quiet(constraint 
= SecAccessConstraintCreateTouchIDAny(allocator
, _getEmptyData()), errOut
); 
 158             CFArrayAppendValue(constraints
, constraint
); 
 159             CFReleaseNull(constraint
); 
 162         if (flags 
& kSecAccessControlTouchIDCurrentSet
) { 
 163             require_quiet(constraint 
= SecAccessConstraintCreateTouchIDCurrentSet(allocator
, _getEmptyData(), _getEmptyData()), errOut
); 
 164             CFArrayAppendValue(constraints
, constraint
); 
 165             CFReleaseNull(constraint
); 
 168         if (flags 
& kSecAccessControlApplicationPassword
) { 
 169             SecAccessControlSetRequirePassword(access_control
, true); 
 172         CFIndex constraints_count 
= CFArrayGetCount(constraints
); 
 173 #if TARGET_OS_IPHONE || (!RC_HIDE_J79 && !RC_HIDE_J80) 
 174         if (constraints_count 
> 1) { 
 175             require_quiet(constraint 
= SecAccessConstraintCreateValueOfKofN(allocator
, or?1:constraints_count
, constraints
, error
), errOut
); 
 176             if (flags 
& kSecAccessControlPrivateKeyUsage
) { 
 177                 require_quiet(SecAccessControlAddConstraintForOperation(access_control
, kAKSKeyOpSign
, constraint
, error
), errOut
); 
 178                 require_quiet(SecAccessControlAddConstraintForOperation(access_control
, kAKSKeyOpComputeKey
, constraint
, error
), errOut
); 
 179                 require_quiet(SecAccessControlAddConstraintForOperation(access_control
, kAKSKeyOpAttest
, kCFBooleanTrue
, error
), errOut
); 
 182                 require_quiet(SecAccessControlAddConstraintForOperation(access_control
, kAKSKeyOpDecrypt
, constraint
, error
), errOut
); 
 183                 require_quiet(SecAccessControlAddConstraintForOperation(access_control
, kAKSKeyOpEncrypt
, kCFBooleanTrue
, error
), errOut
); 
 185             require_quiet(SecAccessControlAddConstraintForOperation(access_control
, kAKSKeyOpDelete
, kCFBooleanTrue
, error
), errOut
); 
 186             CFReleaseNull(constraint
); 
 189         if (constraints_count 
== 1) { 
 190 #if TARGET_OS_IPHONE || (!RC_HIDE_J79 && !RC_HIDE_J80) 
 191             if (flags 
& kSecAccessControlPrivateKeyUsage
) { 
 192                 require_quiet(SecAccessControlAddConstraintForOperation(access_control
, kAKSKeyOpSign
, CFArrayGetValueAtIndex(constraints
, 0), error
), errOut
); 
 193                 require_quiet(SecAccessControlAddConstraintForOperation(access_control
, kAKSKeyOpComputeKey
, CFArrayGetValueAtIndex(constraints
, 0), error
), errOut
); 
 194                 require_quiet(SecAccessControlAddConstraintForOperation(access_control
, kAKSKeyOpAttest
, kCFBooleanTrue
, error
), errOut
); 
 198                 require_quiet(SecAccessControlAddConstraintForOperation(access_control
, kAKSKeyOpDecrypt
, CFArrayGetValueAtIndex(constraints
, 0), error
), errOut
); 
 199                 require_quiet(SecAccessControlAddConstraintForOperation(access_control
, kAKSKeyOpEncrypt
, kCFBooleanTrue
, error
), errOut
); 
 200 #if TARGET_OS_IPHONE || (!RC_HIDE_J79 && !RC_HIDE_J80) 
 203             require_quiet(SecAccessControlAddConstraintForOperation(access_control
, kAKSKeyOpDelete
, kCFBooleanTrue
, error
), errOut
); 
 205 #if TARGET_OS_IPHONE || (!RC_HIDE_J79 && !RC_HIDE_J80) 
 206             if (flags 
& kSecAccessControlPrivateKeyUsage
) { 
 207                 require_quiet(SecAccessControlAddConstraintForOperation(access_control
, kAKSKeyOpSign
, kCFBooleanTrue
, error
), errOut
); 
 208                 require_quiet(SecAccessControlAddConstraintForOperation(access_control
, kAKSKeyOpComputeKey
, kCFBooleanTrue
, error
), errOut
); 
 209                 require_quiet(SecAccessControlAddConstraintForOperation(access_control
, kAKSKeyOpAttest
, kCFBooleanTrue
, error
), errOut
); 
 210                 require_quiet(SecAccessControlAddConstraintForOperation(access_control
, kAKSKeyOpDelete
, kCFBooleanTrue
, error
), errOut
); 
 214                 require_quiet(SecAccessControlAddConstraintForOperation(access_control
, kAKSKeyOpDefaultAcl
, kCFBooleanTrue
, error
), errOut
); 
 215 #if TARGET_OS_IPHONE || (!RC_HIDE_J79 && !RC_HIDE_J80) 
 220         CFReleaseNull(constraints
); 
 223         require_quiet(SecAccessControlAddConstraintForOperation(access_control
, kAKSKeyOpDefaultAcl
, kCFBooleanTrue
, error
), errOut
); 
 226     return access_control
; 
 229     CFReleaseSafe(access_control
); 
 230     CFReleaseSafe(constraints
); 
 231     CFReleaseSafe(constraint
); 
 235 CFTypeRef 
SecAccessControlGetProtection(SecAccessControlRef access_control
) { 
 236     return CFDictionaryGetValue(access_control
->dict
, kSecAccessControlKeyProtection
); 
 239 static bool checkItemInArray(CFTypeRef item
, const CFTypeRef 
*values
, CFIndex count
, CFStringRef errMessage
, CFErrorRef 
*error
) { 
 240     for (CFIndex i 
= 0; i 
< count
; i
++) { 
 241         if (CFEqualSafe(item
, values
[i
])) { 
 245     return SecError(errSecParam
, error
, errMessage
, item
); 
 248 #define CheckItemInArray(item, values, msg) \ 
 250     const CFTypeRef vals[] = values; \ 
 251     if (!checkItemInArray(item, vals, sizeof(vals)/sizeof(*vals), CFSTR(msg), error)) { \ 
 256 #define ItemArray(...) { __VA_ARGS__ } 
 259 bool SecAccessControlSetProtection(SecAccessControlRef access_control
, CFTypeRef protection
, CFErrorRef 
*error
) { 
 260     if (!protection 
|| CFGetTypeID(protection
) != CFDictionaryGetTypeID()) { 
 261         // Verify protection type. 
 262         CheckItemInArray(protection
, ItemArray(kSecAttrAccessibleAlwaysPrivate
, kSecAttrAccessibleAfterFirstUnlock
, 
 263                                                kSecAttrAccessibleWhenUnlocked
, kSecAttrAccessibleAlwaysThisDeviceOnlyPrivate
, 
 264                                                kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly
, 
 265                                                kSecAttrAccessibleWhenUnlockedThisDeviceOnly
, 
 266                                                kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly
), 
 267                          "SecAccessControl: invalid protection %@"); 
 270     // Protection valid, use it. 
 271     CFDictionarySetValue(access_control
->dict
, kSecAccessControlKeyProtection
, protection
); 
 275 SecAccessConstraintRef 
SecAccessConstraintCreatePolicy(CFAllocatorRef allocator
, CFTypeRef policy
, CFErrorRef 
*error
) { 
 276     return CFDictionaryCreateMutableForCFTypesWith(allocator
, CFSTR(kACMKeyAclConstraintPolicy
), policy
, NULL
); 
 279 SecAccessConstraintRef 
SecAccessConstraintCreatePasscode(CFAllocatorRef allocator
) { 
 280     return CFDictionaryCreateMutableForCFTypesWith(allocator
, CFSTR(kACMKeyAclConstraintUserPasscode
), kCFBooleanTrue
, NULL
); 
 283 SecAccessConstraintRef 
SecAccessConstraintCreateTouchIDAny(CFAllocatorRef allocator
, CFDataRef catacombUUID
) { 
 284     CFMutableDictionaryRef bioDict 
= CFDictionaryCreateMutableForCFTypesWith(allocator
, CFSTR(kACMKeyAclParamBioCatacombUUID
), catacombUUID
, NULL
); 
 285     SecAccessConstraintRef constraint 
= CFDictionaryCreateMutableForCFTypesWith(allocator
, CFSTR(kACMKeyAclConstraintBio
), bioDict
, NULL
); 
 286     CFReleaseSafe(bioDict
); 
 290 SecAccessConstraintRef 
SecAccessConstraintCreateTouchIDCurrentSet(CFAllocatorRef allocator
, CFDataRef catacombUUID
, CFDataRef bioDbHash
) { 
 291     CFMutableDictionaryRef bioDict 
= CFDictionaryCreateMutableForCFTypesWith(allocator
, CFSTR(kACMKeyAclParamBioCatacombUUID
), catacombUUID
, NULL
); 
 292     CFDictionarySetValue(bioDict
, CFSTR(kACMKeyAclParamBioDatabaseHash
), bioDbHash
); 
 293     SecAccessConstraintRef constraint 
= CFDictionaryCreateMutableForCFTypesWith(allocator
, CFSTR(kACMKeyAclConstraintBio
), bioDict
, NULL
); 
 294     CFReleaseSafe(bioDict
); 
 298 static SecAccessConstraintRef 
SecAccessConstraintCreateValueOfKofN(CFAllocatorRef allocator
, size_t numRequired
, CFArrayRef constraints
, CFErrorRef 
*error
) { 
 299     CFNumberRef k 
= CFNumberCreateWithCFIndex(allocator
, numRequired
); 
 300     CFMutableDictionaryRef kofn 
= CFDictionaryCreateMutableForCFTypesWith(allocator
, CFSTR(kACMKeyAclParamKofN
), k
, NULL
); 
 303     /* Populate kofn dictionary with constraint keys from the array. note that for now we just ignore any additional 
 304        constraint parameters, but we might err-out if some parameter is found, since we cannot propagate parameteres 
 305        into k-of-n dictionary. */ 
 306     const CFTypeRef keysToCopy
[] = { CFSTR(kACMKeyAclConstraintBio
), CFSTR(kACMKeyAclConstraintPolicy
), 
 307         CFSTR(kACMKeyAclConstraintUserPasscode
) }; 
 308     SecAccessConstraintRef constraint
; 
 309     CFArrayForEachC(constraints
, constraint
) { 
 310         require_quiet(isDictionary(constraint
), errOut
); 
 312         for (CFIndex i 
= 0; i 
< (CFIndex
)(sizeof(keysToCopy
) / sizeof(keysToCopy
[0])); i
++) { 
 313             CFTypeRef value 
= CFDictionaryGetValue(constraint
, keysToCopy
[i
]); 
 315                 CFDictionarySetValue(kofn
, keysToCopy
[i
], value
); 
 320         require_quiet(found
, errOut
); 
 326     SecError(errSecParam
, error
, CFSTR("SecAccessControl: invalid constraint for k-of-n")); 
 331 SecAccessConstraintRef 
SecAccessConstraintCreateKofN(CFAllocatorRef allocator
, size_t numRequired
, CFArrayRef constraints
, CFErrorRef 
*error
) { 
 332     SecAccessConstraintRef valueOfKofN 
=  SecAccessConstraintCreateValueOfKofN(allocator
, numRequired
, constraints
, error
); 
 333     require_quiet(valueOfKofN
, errOut
); 
 335     SecAccessConstraintRef constraint 
= CFDictionaryCreateMutableForCFTypesWith(allocator
, CFSTR(kACMKeyAclConstraintKofN
), valueOfKofN
, NULL
); 
 336     CFReleaseSafe(valueOfKofN
); 
 343 bool SecAccessControlAddConstraintForOperation(SecAccessControlRef access_control
, CFTypeRef operation
, CFTypeRef constraint
, CFErrorRef 
*error
) { 
 344     CheckItemInArray(operation
, ItemArray(kAKSKeyOpEncrypt
, kAKSKeyOpDecrypt
, 
 345 #if TARGET_OS_IPHONE || (!RC_HIDE_J79 && !RC_HIDE_J80) 
 346                                           kAKSKeyOpSign
, kAKSKeyOpAttest
, kAKSKeyOpComputeKey
, 
 348                                           kAKSKeyOpSync
, kAKSKeyOpDefaultAcl
, kAKSKeyOpDelete
), 
 349                      "SecAccessControl: invalid operation %@"); 
 350     if (!isDictionary(constraint
) && !CFEqual(constraint
, kCFBooleanTrue
) && !CFEqual(constraint
, kCFBooleanFalse
) ) { 
 351         return SecError(errSecParam
, error
, CFSTR("invalid constraint")); 
 354     CFMutableDictionaryRef constraints 
= SecAccessControlGetMutableConstraints(access_control
); 
 355     CFDictionarySetValue(constraints
, operation
, constraint
); 
 359 SecAccessConstraintRef 
SecAccessControlGetConstraint(SecAccessControlRef access_control
, CFTypeRef operation
) { 
 360     CFMutableDictionaryRef ops 
= (CFMutableDictionaryRef
)CFDictionaryGetValue(access_control
->dict
, kAKSKeyAcl
); 
 361     if (!ops 
|| CFDictionaryGetCount(ops
) == 0) 
 362         // No ACL is present, this means that everything is allowed. 
 363         return kCFBooleanTrue
; 
 365     SecAccessConstraintRef constraint 
= CFDictionaryGetValue(ops
, operation
); 
 367         constraint 
= CFDictionaryGetValue(ops
, kAKSKeyOpDefaultAcl
); 
 372 CFDataRef 
SecAccessControlCopyConstraintData(SecAccessControlRef access_control
, CFTypeRef operation
) { 
 373     SecAccessConstraintRef constraint 
= SecAccessControlGetConstraint(access_control
, operation
); 
 375     size_t len 
= der_sizeof_plist(constraint
, NULL
); 
 376     CFMutableDataRef encoded 
= CFDataCreateMutable(0, len
); 
 377     CFDataSetLength(encoded
, len
); 
 378     uint8_t *der_end 
= CFDataGetMutableBytePtr(encoded
); 
 379     const uint8_t *der 
= der_end
; 
 381     der_end 
= der_encode_plist(constraint
, NULL
, der
, der_end
); 
 383         CFReleaseNull(encoded
); 
 388 CFDictionaryRef 
SecAccessControlGetConstraints(SecAccessControlRef access_control
) { 
 389     return CFDictionaryGetValue(access_control
->dict
, kAKSKeyAcl
); 
 392 void SecAccessControlSetConstraints(SecAccessControlRef access_control
, CFDictionaryRef constraints
) { 
 393     CFMutableDictionaryRef mutableConstraints 
= CFDictionaryCreateMutableCopy(CFGetAllocator(access_control
), 0, constraints
); 
 394     CFDictionarySetValue(access_control
->dict
, kAKSKeyAcl
, mutableConstraints
); 
 395     CFReleaseSafe(mutableConstraints
); 
 398 void SecAccessControlSetRequirePassword(SecAccessControlRef access_control
, bool require
) { 
 399     CFMutableDictionaryRef constraints 
= SecAccessControlGetMutableConstraints(access_control
); 
 400     CFDictionarySetValue(constraints
, kAKSKeyAclParamRequirePasscode
, require
?kCFBooleanTrue
:kCFBooleanFalse
); 
 403 bool SecAccessControlGetRequirePassword(SecAccessControlRef access_control
) { 
 404     CFMutableDictionaryRef acl 
= (CFMutableDictionaryRef
)CFDictionaryGetValue(access_control
->dict
, kAKSKeyAcl
); 
 406         return CFEqualSafe(CFDictionaryGetValue(acl
, kAKSKeyAclParamRequirePasscode
), kCFBooleanTrue
); 
 412 void SecAccessControlSetBound(SecAccessControlRef access_control
, bool bound
) { 
 413     CFDictionarySetValue(access_control
->dict
, kSecAccessControlKeyBound
, bound 
? kCFBooleanTrue 
: kCFBooleanFalse
); 
 416 bool SecAccessControlIsBound(SecAccessControlRef access_control
) { 
 417     CFTypeRef bound 
= CFDictionaryGetValue(access_control
->dict
, kSecAccessControlKeyBound
); 
 418     return bound 
!= NULL 
&& CFEqualSafe(bound
, kCFBooleanTrue
); 
 421 CFDataRef 
SecAccessControlCopyData(SecAccessControlRef access_control
) { 
 422     size_t len 
= der_sizeof_plist(access_control
->dict
, NULL
); 
 423     CFMutableDataRef encoded 
= CFDataCreateMutable(0, len
); 
 424     CFDataSetLength(encoded
, len
); 
 425     uint8_t *der_end 
= CFDataGetMutableBytePtr(encoded
); 
 426     const uint8_t *der 
= der_end
; 
 428     der_end 
= der_encode_plist(access_control
->dict
, NULL
, der
, der_end
); 
 430         CFReleaseNull(encoded
); 
 435 SecAccessControlRef 
SecAccessControlCreateFromData(CFAllocatorRef allocator
, CFDataRef data
, CFErrorRef 
*error
) { 
 436     SecAccessControlRef access_control
; 
 437     require_quiet(access_control 
= SecAccessControlCreate(allocator
, error
), errOut
); 
 439     CFPropertyListRef plist
; 
 440     const uint8_t *der 
= CFDataGetBytePtr(data
); 
 441     const uint8_t *der_end 
= der 
+ CFDataGetLength(data
); 
 442     require_quiet(der 
= der_decode_plist(0, kCFPropertyListMutableContainers
, &plist
, error
, der
, der_end
), errOut
); 
 443     if (der 
!= der_end
) { 
 444         SecError(errSecDecode
, error
, CFSTR("trailing garbage at end of SecAccessControl data")); 
 448     CFReleaseSafe(access_control
->dict
); 
 449     access_control
->dict 
= (CFMutableDictionaryRef
)plist
; 
 450     return access_control
; 
 453     CFReleaseSafe(access_control
);